Skip to content

Commit

Permalink
Merge pull request #51 from DenizUgur/main
Browse files Browse the repository at this point in the history
Specification coverage component enhancements
  • Loading branch information
podborski authored Aug 31, 2023
2 parents 45aa833 + 3943e86 commit 15fb8e6
Show file tree
Hide file tree
Showing 20 changed files with 22,261 additions and 12,461 deletions.
2 changes: 1 addition & 1 deletion conformance-search/src/components/Input/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import clsx from "clsx";
import Fuse from "fuse.js";
import { useEffect, useRef, useState } from "react";
import { useEvent, useIntersection } from "react-use";
import { normalizeResultScores } from "@/lib/utils";
import { normalizeResultScores } from "@/utils";
import { Chip } from "@/components";
import { FuseSearchWithScore } from "@/types";

Expand Down
33 changes: 21 additions & 12 deletions conformance-search/src/components/SpecsCovered.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import clsx from "clsx";
import { Coverage } from "@/types/json";
import { addOrdinalSuffix } from "@/utils";
import { FaExternalLinkAlt } from "react-icons/fa";
import { spec_info as specs } from "../../data/coverage.json";

export default function SpecsCovered({
Expand All @@ -14,24 +16,31 @@ export default function SpecsCovered({
<div className={clsx("border-b-2 px-3 py-2", !compact && "text-lg")}>
<b>{specs.length}</b> specifications covered
</div>
<div className="max-h-[250px] max-w-xl divide-y-1 overflow-y-auto">
<div className="flex max-h-[250px] max-w-xl cursor-pointer flex-col divide-y-1 overflow-y-auto">
{specs.map((info: Coverage["spec_info"][0]) => (
<div
<a
key={info.ISO}
className={clsx(
"truncate px-3 py-2 font-light hover:bg-gray-100",
"group flex items-center justify-between gap-2 truncate px-3 py-2 font-light hover:bg-gray-100",
compact && "!py-1 text-sm font-normal"
)}
href={info.link}
rel="noreferrer"
target="_blank"
>
ISO/IEC {info.ISO} (<span className="font-bold">{info.name}</span>): ver
{info.version}
{info.amendmends &&
info.amendmends.length > 0 &&
`, ${info.amendmends.join(", ")}`}
{info.corrigenda &&
info.corrigenda.length > 0 &&
`, ${info.corrigenda.join(", ")}`}
</div>
<span>
ISO/IEC {info.ISO}:{info.date} (
<span className="font-bold">{info.name}</span>):{" "}
{addOrdinalSuffix(info.version)} Edition{" "}
{info.amendmends &&
info.amendmends.length > 0 &&
`, ${info.amendmends.join(", ")}`}
{info.corrigenda &&
info.corrigenda.length > 0 &&
`, ${info.corrigenda.join(", ")}`}
</span>
<FaExternalLinkAlt className="text-xs opacity-0 transition-opacity duration-200 group-hover:opacity-100" />
</a>
))}
</div>
</div>
Expand Down
71 changes: 70 additions & 1 deletion conformance-search/src/lib/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,76 @@ import {
SearchResultRefined
} from "@/types";
import { Dictionary, FileMetadata, Files, Hierarchy } from "@/types/json";
import { collectMatchingBranches, crawlBranches } from "./utils";

/**
* This will go through the given hierarchies and collect all the branches that match the given filter.
* We terminate each branch at the first match. So that next filter can start from that branch.
* @param filter - the filter to match
* @param hierarchies - the hierarchies to search
* @param matches - the matches found so far
*/
function collectMatchingBranches(
filter: Filter,
hierarchies: Hierarchy[],
matches: Hierarchy[] = []
) {
// Basically, we will start from the root, and go down the tree. If we encounter a node that matches the filter, we will keep the descedants of that node in a list (preserving the branch) and continue to other branches.
const { type, value } = filter;

// * go through hierarchies
hierarchies.forEach((hierarchy) => {
Object.keys(hierarchy).forEach((key) => {
const [keyFourcc, keyType] = key.split(":");

let found = false;
if (type === "fourcc") {
if (keyFourcc === value) {
matches.push(hierarchy[key]);
found = true;
}
} else if (type === "type") {
if (keyType === value) {
matches.push(hierarchy[key]);
found = true;
}
}

if (Object.keys(hierarchy[key]).length > 0 && !found) {
collectMatchingBranches(filter, [hierarchy[key]], matches);
}
});
});

return matches;
}

/**
* This goes through the given hierarchies and collects all unique the fourccs, types and tuples.
* @param branches - the hierarchies to crawl
*/
function crawlBranches(
branches: Hierarchy[],
fourccs: string[] = [],
types: string[] = [],
tuples: string[] = []
) {
branches.forEach((branch) => {
Object.keys(branch).forEach((key) => {
const box = branch[key];
const [boxFourcc, boxType] = key.split(":");

if (!fourccs.includes(boxFourcc)) fourccs.push(boxFourcc);
if (!types.includes(boxType)) types.push(boxType);
if (!tuples.includes(key)) tuples.push(key);

if (Object.keys(box).length > 0) {
crawlBranches([box], fourccs, types, tuples);
}
});
});

return { fourccs, types, tuples };
}

class Database {
static instance: Database;
Expand Down
2 changes: 1 addition & 1 deletion conformance-search/src/lib/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import hash from "object-hash";

import { Box, Feature, FileSearchResult, Filter, SearchResult, SearchResultRefined } from "@/types";
import { Files } from "@/types/json";
import { normalizeResultScores } from "@/utils";
import Database from "./database";
import { normalizeResultScores } from "./utils";

/**
* This is the list of filter options
Expand Down
108 changes: 0 additions & 108 deletions conformance-search/src/lib/utils.ts

This file was deleted.

2 changes: 2 additions & 0 deletions conformance-search/src/types/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export type Coverage = {
ISO: string;
name: string;
version: number;
date: number;
link: string;
amendmends?: Array<string>;
corrigenda?: Array<string>;
}>;
Expand Down
58 changes: 58 additions & 0 deletions conformance-search/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { FuseSearchWithScore } from "@/types";

/**
* Normalize the scores of the given results.
* @param results - the results to normalize
*/
function normalizeResultScores<T>(results: FuseSearchWithScore<T>[], threshold = 0.2) {
let normalizedResults = results;
if (results.length === 1) {
normalizedResults = results.map((result) => ({
...result,
actualScore: result.score,
score: 0
}));
} else if (results.length > 1) {
const minScore = results[0].score;
const maxScore = results[results.length - 1].score;

if (minScore === maxScore) {
normalizedResults = results.map((result) => ({
...result,
actualScore: result.score,
score: minScore < threshold ? 0 : 1
}));
} else {
normalizedResults = results.map((result) => ({
...result,
actualScore: result.score,
score: ((result.score || 0) - minScore) / (maxScore - minScore)
}));
}
}

return normalizedResults;
}

/**
* Add ordinal suffix to the given number.
* @param num - the number to add the suffix to
* @link https://stackoverflow.com/a/15397495
*/
function addOrdinalSuffix(num: number) {
const dString = String(num);
const last = +dString.slice(-2);
if (last > 3 && last < 21) return `${num}th`;
switch (last % 10) {
case 1:
return `${num}st`;
case 2:
return `${num}nd`;
case 3:
return `${num}rd`;
default:
return `${num}th`;
}
}

export { normalizeResultScores, addOrdinalSuffix };
Loading

0 comments on commit 15fb8e6

Please sign in to comment.