Skip to content

Instantly share code, notes, and snippets.

@petrosmm
Last active February 16, 2023 03:12
Show Gist options
  • Save petrosmm/4b9818eecda6df6bf8d2b7e82c2993a3 to your computer and use it in GitHub Desktop.
Save petrosmm/4b9818eecda6df6bf8d2b7e82c2993a3 to your computer and use it in GitHub Desktop.
route builder sample for directus; used when item in questions are linked but self-referencing
#!/usr/bin/env node
// basic commands
// cls && tsc cli.ts --esModuleInterop true --outDir build && node build/cli.js
// REM && pause
import fetch from "node-fetch";
import _ from "lodash";
import Enumerable from "node-enumerable";
interface RootResult {
data: DataResult[];
}
interface DataResult {
uuid: string;
url: string;
title: string;
parentUuid: string;
parent_page_to: DataResult[];
routePieces: string[];
routePiecesAll: string[];
localUuid: string;
localUuidPieces: string[];
}
let initialResults: DataResult[] = [];
let results: DataResult[] = [];
export const main = async (): Promise<void> => {
var path = `/items/pages?fields=uuid,url,title,parent_page_to.url,parent_page_to.title,parent_page_to.uuid`;
var host = "http://localhost:8055";
let rawResult = (await fetch(new URL(host + path).href, {
method: `get`,
// body: JSON.stringify({ email, password, mode: `json` }),
headers: {
"Content-Type": `application/json`,
},
}) as unknown as Response).json();
rawResult.then((p: RootResult) => {
purgeDupes(p);
}).then(() => {
flattenItems(initialResults);
deNestItems(initialResults);
emancipateChildren(results)
.then(() => {
results.forEach((item, index) => {
item.routePiecesAll = item.routePiecesAll ?? [];
item.parentUuid = item.parentUuid ?? null;
item.localUuid = generateUUID();
item.localUuidPieces = item.localUuidPieces ?? [];
});
var duplicateIds = [];
results.forEach((item, index) => {
let multipleResults = results.filter(p => p.uuid == item.uuid);
if (multipleResults.length > 1) {
// delete item;
let hasProperItem = multipleResults.some(p => (p.parentUuid == null || p.parentUuid == undefined));
if (hasProperItem) {
let _result = results.filter(p => p.uuid !== undefined
&& p.uuid == multipleResults[0]?.uuid
&& (p.parentUuid == undefined || p.parentUuid == null))[0];
duplicateIds.push(_result.localUuid);
}
}
});
duplicateIds = Array.from(new Set(duplicateIds));
results = results.filter(p => !(duplicateIds.includes(p.localUuid)));
results = Enumerable.from(results)
.orderBy(p => p?.parentUuid == null ? 0 : 1)
.thenBy(p => p?.parent_page_to?.length > 0 ? 2 : 3)
.toArray();
traverseAncestors(results);
populateRoutes(results);
displayResults(results);
});
// end
});
};
if (require.main === module) {
main().catch((error) => {
console.error(error);
process.exit(1);
});
} else {
throw new Error(`This should be the main module.`);
}
function purgeDupes(input: RootResult) {
return new Promise<void>((resolve, reject) => {
initialResults = input.data;
initialResults.forEach((value, index) => {
purgeEachNested(value, null /* value.url */, value.uuid);
});
resolve();
});
}
function purgeEachNested(value: DataResult, _parentUrl: string, _parentUuid: string) {
let childPages = value.parent_page_to?.length > 0 ? value.parent_page_to : [];
_.remove(initialResults, p => p.uuid == value.uuid && p.parent_page_to?.length == 0);
childPages.forEach(child => {
child.parentUuid = _parentUuid;
// recursive
purgeEachNested(child, null /* child.parentUrl */, child.parentUuid);
});
}
function flattenItems(items: DataResult[]) {
return new Promise<void>((resolve, reject) => {
items.forEach(p => {
flattenEachNested(p);
});
resolve();
});
}
function flattenEachNested(value: DataResult) {
let childPages = value.parent_page_to?.length > 0 ? value.parent_page_to : [];
childPages.forEach(child => {
// recursive
flattenEachNested(child);
});
}
function deNestItems(items: DataResult[]) {
return new Promise<void>((resolve, reject) => {
items.forEach(item => {
deNestEachItem(item);
});
resolve();
});
}
function deNestEachItem(value: DataResult) {
let childPages = value.parent_page_to?.length > 0 ? value.parent_page_to : [];
results.push(value);
childPages.forEach(child => {
// recursive
deNestEachItem(child);
});
}
function emancipateChildren(items: DataResult[]) {
return new Promise<void>((resolve, reject) => {
items.forEach(item => {
delete item?.parent_page_to;
});
resolve();
});
}
class lookup {
static byLocalUuid(input: string): DataResult {
return results.find(p => p.localUuid == input);
}
static byUuid(input: string): DataResult {
return results.find(p => p.uuid == input);
}
}
function displayResults(results: DataResult[]) {
console.log('\r\n\r\n' + 'starting result display');
results.forEach((item, index) => {
console.log(item);
});
}
/** @deprecated */
function splice(
input: DataResult[],
// predicate: (value: T, index: number, array: DataResult[]) => value is DataResult
predicate: (p: DataResult) => boolean
) {
while (input.findIndex(predicate) > -1) {
let index = input.findIndex(predicate);
let result = input.splice(index, 1);
results.push(result[0]);
}
return results;
}
function generateUUID() { // Public Domain/MIT
let d = new Date().getTime();//Timestamp
let d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || 0;//Time in microseconds since page-load or 0 if unsupported
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = Math.random() * 16;//random number between 0 and 16
if (d > 0) {//Use timestamp until depleted
r = (d + r) % 16 | 0;
d = Math.floor(d / 16);
} else {//Use microseconds since page-load if supported
r = (d2 + r) % 16 | 0;
d2 = Math.floor(d2 / 16);
}
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
function traverseAncestors(items: DataResult[]) {
items.forEach(item => {
traverseAncestorsEach(item, item.localUuid);
});
}
function traverseAncestorsEach(value: DataResult, carryUuid: string) {
let target = value as DataResult;
do {
let parent = lookup.byUuid(target.parentUuid);
if (parent == null) {
target = null;
} else {
value.localUuidPieces.unshift(parent.localUuid);
target = parent;
}
} while (target != null);
}
function populateRoutes(items: DataResult[]) {
return new Promise<void>((resolve, reject) => {
// populate uuids
items.forEach(item => {
if (item.localUuidPieces.length > 0) {
item.localUuidPieces.forEach(_p => {
let _route = lookup.byLocalUuid(_p).url;
item.routePiecesAll.push(_route);
});
item.routePiecesAll.push(item.url);
}
});
results = items;
resolve();
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment