From 4f136591f374c1c701610d6f5e660e96be106548 Mon Sep 17 00:00:00 2001 From: DARSAN Date: Fri, 15 Nov 2024 18:41:30 +0530 Subject: [PATCH] Breadcrumb support added to CLI Method - closes #17 --- .richiejs | 5 +- README.md | 2 +- bin/richieMaker.ts | 134 ++++++++++++----------- intellisense/richiejs-config-schema.json | 5 + lib/aggregator.ts | 8 +- lib/options.ts | 3 + lib/utilities.ts | 9 +- richie.ts | 65 ++++++----- test/main.test.ts | 2 +- 9 files changed, 126 insertions(+), 107 deletions(-) diff --git a/.richiejs b/.richiejs index a59f5b2..a5e2123 100644 --- a/.richiejs +++ b/.richiejs @@ -213,6 +213,7 @@ "restaurant": false, "recipe": true }, - "isProductVar": true + "isProductVar": true, + "breadcrumb":false } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 47c2e6e..798b4c5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-![Richi JS logo](./logo/rjs-icon.svg) +![Richi JS logo](./logo/logo.png) # Richie JS - Powerful SEO Tool for Generating Rich Results diff --git a/bin/richieMaker.ts b/bin/richieMaker.ts index aa4f44b..204deb0 100644 --- a/bin/richieMaker.ts +++ b/bin/richieMaker.ts @@ -62,68 +62,69 @@ export async function makeRichie( new Promise((resolve, reject) => { readFile(file, { encoding: "utf8" }) .then((htmlText) => { - const neededRichies: richies[] = - richieTypeAcquisition(htmlText); - - neededRichies.forEach((richieName) => { - const dest = join( - process.cwd(), - options.destDir ?? "", - dirname(relative(process.cwd(), file)), - basename(file), - ); - - try { - //make dir - mkdirSync(dirname(dest)); - } catch (err: any) { - /* console.log(err.code); */ - } - - //carousal handler - if ( - richieCarousals.includes(richieName) || - richieName === "product" - ) { - switch (richieName) { - case "recipe": - if (isCarousals.recipe) { - richieName = "crecipe"; - } - break; - case "movie": - if (isCarousals.movie) { - richieName = "cmovie"; - } - break; - case "restaurant": - if (isCarousals.restaurant) { - richieName = "crestaurant"; - } - break; - case "course": - if (isCarousals.course) { - richieName = "ccourse"; - } - break; - case "product": - if (preference.isProductVar) { - richieName = "productwv"; - } - break; - } + let neededRichies: richies[] = richieTypeAcquisition(htmlText); + + const dest = join( + process.cwd(), + options.destDir ?? "", + dirname(relative(process.cwd(), file)), + basename(file), + ); + + try { + //make dir + mkdirSync(dirname(dest), { recursive: true }); + } catch (err: any) { + console.log(err); + process.exit(1); + } + + neededRichies = neededRichies.map((richieName: richies) => { + switch (richieName) { + case "recipe": + if (isCarousals.recipe) { + return "crecipe"; + } + return richieName; + + case "movie": + if (isCarousals.movie) { + return "cmovie"; + } + return richieName; + + case "restaurant": + if (isCarousals.restaurant) { + return "crestaurant"; + } + return richieName; + + case "course": + if (isCarousals.course) { + return "ccourse"; + } + return richieName; + + case "product": + if (preference.isProductVar) { + return "productwv"; + } + return richieName; + + default: + return richieName; } // - - richie(richieName, file, dest) - .then(() => { - resolve(); - }) - .catch((err) => { - reject(err); - }); }); + + richie(neededRichies, file, dest) + .then(() => { + resolve(); + }) + .catch((err) => { + reject(err); + }); }) .catch((err) => { reject(err); @@ -135,21 +136,22 @@ export async function makeRichie( await Promise.all(concurrentOPS); } -// File type acquisition based on artifacts +// File type acquisition based on content function richieTypeAcquisition(htmlText: string): richies[] { const availableTypes: richies[] = []; //a=len(2) - const noIDTypes: richies[] = ["breadcrumb", "searchbox"]; + /* const noIDTypes: richies[] = ["breadcrumb", "searchbox"]; */ //b=len(5) a+b = 7 - const IDTypesVars: richies[] = [ + /* Identifiable by content but controlled by configuration file */ + /* const IDTypesVars: richies[] = [ "crecipe", "cmovie", - "course", + "ccourse", "crestaurant", "productwv", - ]; + ]; */ //c=len(13) a+b+c = 20 const IDTypesRecord: Partial> = { @@ -183,5 +185,11 @@ function richieTypeAcquisition(htmlText: string): richies[] { } }); + /* breadcrumb controlled by configfile */ + if (preference.breadcrumb) { + availableTypes.push("breadcrumb"); + } + /* */ + return availableTypes; } diff --git a/intellisense/richiejs-config-schema.json b/intellisense/richiejs-config-schema.json index deaa94e..b8ae0e7 100644 --- a/intellisense/richiejs-config-schema.json +++ b/intellisense/richiejs-config-schema.json @@ -931,6 +931,11 @@ "type": "boolean", "default": false, "markdownDescription": "[Guide Link](https://cresteem.com/opensource/richie-js)" + }, + "breadcrumb":{ + "type": "boolean", + "default": false, + "markdownDescription": "[Guide Link](https://cresteem.com/opensource/richie-js)" } } } diff --git a/lib/aggregator.ts b/lib/aggregator.ts index a05c0f8..27a2ef6 100644 --- a/lib/aggregator.ts +++ b/lib/aggregator.ts @@ -216,15 +216,12 @@ export function breadCrumb(htmlPath: string): breadCrumbListOptions { const levelCounts: number = sourceIsIndex ? pathTree.length - 1 : pathTree.length; - /* In first iteration no need to check file existance */ - let firstIteration: boolean = true; - let realLevel: number = levelCounts; //to track real chronological level according to web protocol for (let i: number = 0; i < levelCounts; i++) { /* assume in first iteration file always exist so skip existance check */ - if (firstIteration) { + if (i === 0) { let itemUrl: string = pathTree.join(sep); const preserveBasename: boolean = sourceIsIndex ? false : true; @@ -242,9 +239,6 @@ export function breadCrumb(htmlPath: string): breadCrumbListOptions { /* if source is index pop two times otherwise pop one time*/ //EX: L1/L2/L3/index.html => L1/L2 if (sourceIsIndex) pathTree.pop(); - - //switching flag for next iterations - firstIteration = false; } else { //check if index html is available for each levels // L1/L2 => L1/L2/index.html diff --git a/lib/options.ts b/lib/options.ts index c77dce3..7114433 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -801,6 +801,9 @@ export interface configurationOptions { recipe: boolean; }; isProductVar: boolean; + + //15/11/2024 + breadcrumb: boolean; }; } diff --git a/lib/utilities.ts b/lib/utilities.ts index b258185..4a4daa0 100644 --- a/lib/utilities.ts +++ b/lib/utilities.ts @@ -292,9 +292,12 @@ export function combineAggregateRatings( export function createJsonLD( innerDataObject: Record, ): string { - const jsonLD = ``; + const jsonLD = + innerDataObject ? + `` + : ""; return jsonLD; } diff --git a/richie.ts b/richie.ts index 395e1e4..0830286 100644 --- a/richie.ts +++ b/richie.ts @@ -30,8 +30,8 @@ import { richieOPS, richies, } from "./lib/options"; -import { createJsonLD, writeOutput } from "./lib/utilities"; import { sweep } from "./lib/sweeper"; +import { createJsonLD, writeOutput } from "./lib/utilities"; const functionMap: Record = { article: { @@ -117,7 +117,7 @@ const functionMap: Record = { }; export async function richie( - richieName: richies, + richieNames: richies[], filepath: string, destinationPath: string = "", ): Promise { @@ -126,40 +126,45 @@ export async function richie( const source: string = await readFile(filepath, { encoding: "utf8" }); - //standardize parameters - const aggregatorParams: string[] | boolean = - richieGroupA.includes(richieName) ? [source] - : richieGroupB.includes(richieName) ? [source, filepath] - : richieGroupC.includes(richieName) ? [filepath] - : false; + let richResultSnippets: string = ""; + let cleanSource: string | null = null; return new Promise(async (resolve, reject) => { - if (!aggregatorParams) { - reject(new Error("Unsupported Richie name")); - } else { - const aggregator: Function = functionMap[richieName].aggregator; - const serializer: Function = functionMap[richieName].serializer; + for (const richieName of richieNames) { + //standardize parameters + const aggregatorParams: string[] | boolean = + richieGroupA.includes(richieName) ? [source] + : richieGroupB.includes(richieName) ? [source, filepath] + : richieGroupC.includes(richieName) ? [filepath] + : false; - const aggregatedData = await aggregator(...aggregatorParams); + if (!aggregatorParams) { + reject(new Error("Unsupported Richie name")); + } else { + const aggregator: Function = functionMap[richieName].aggregator; + const serializer: Function = functionMap[richieName].serializer; - const serializerParams: any[] = - richieName === "productwv" ? - [...Object.values(aggregatedData)] // [productMeta,variesBy] - : richieName === "product" ? - [Object.values(aggregatedData)[0]] // [productMeta] - : [aggregatedData]; + const aggregatedData = await aggregator(...aggregatorParams); - const serializedData = serializer(...serializerParams); - const richResultSnippet = createJsonLD(serializedData); - const cleanSource = sweep(richieName, source); + const serializerParams: any[] = + richieName === "productwv" ? + [...Object.values(aggregatedData)] // [productMeta,variesBy] + : richieName === "product" ? + [Object.values(aggregatedData)[0]] // [productMeta] + : [aggregatedData]; - writeOutput(cleanSource, destinationFile, richResultSnippet) - .then(() => { - resolve(); - }) - .catch((error) => { - reject(error); - }); + const serializedData = serializer(...serializerParams); + richResultSnippets += createJsonLD(serializedData); + cleanSource = sweep(richieName, cleanSource ?? source); + } } + + writeOutput(cleanSource as string, destinationFile, richResultSnippets) + .then(() => { + resolve(); + }) + .catch((error) => { + reject(error); + }); }); } diff --git a/test/main.test.ts b/test/main.test.ts index 3c142c8..42e363b 100644 --- a/test/main.test.ts +++ b/test/main.test.ts @@ -86,7 +86,7 @@ function runAll(): Promise { //nothing to do } finally { //make op dir - mkdirSync(opfolder); + mkdirSync(opfolder, { recursive: true }); } const testOps: Promise[] = [];