You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
ts-puzzles/sitemap-parser/src/createSitemap.ts

40 lines
1.8 KiB

import { ApiResponse, Sitemap } from './types';
type Subtree = {
name: string;
id: number;
children: Sitemap[];
};
// alternatively, for full TS experience, if I had more time I'd also implement parsing in TS so that this declaration would look like:
// export const createSitemap = <TResponse extends ApiResponse>(apiResponse: TResponse): Sitemap<TResponse> => {
// and calling e.g. `createSitemap(const sample data json)` would return value with type `const sample sitemap`, rather than just general sitemap
export const createSitemap = (apiResponse: ApiResponse): Sitemap | null => {
const subtrees = new Map<number, Subtree>(
apiResponse.map(({ id, slug }) => [
id,
{ id, name: slug, children: [] },
]),
);
let root: Subtree | null = null;
for (const entry of apiResponse) {
if (entry.parent === null) {
if (root) {
throw new Error(
`Multiple root nodes found (${root.id} and ${entry.id})`,
);
}
// We can be sure that `get` returns value: `entry.id` exists because that's how we initialized subtrees in the beginning
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
root = subtrees.get(entry.id)!;
} else if (subtrees.has(entry.parent)) {
// We can be sure that both `get`s return values because:
// 1. We just checked that `entry.parent` is an existing id;
// 2. `entry.id` exists because that's how we initialized subtrees in the beginning
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
subtrees.get(entry.parent)!.children.push(subtrees.get(entry.id)!);
}
}
return root;
};