diff --git a/scripts/markdown.js b/scripts/markdown.js index 5c106ad1..3aaa0f79 100644 --- a/scripts/markdown.js +++ b/scripts/markdown.js @@ -7,10 +7,7 @@ function capitalize(s) { } function normalizeName(name) { - return name - .split("_") - .map((name) => capitalize(name)) - .join(" "); + return name.split("_").map(capitalize).join(" "); } export function renderMarkdown(solution, file) { @@ -19,6 +16,9 @@ export function renderMarkdown(solution, file) { // Convert Markdown to HTML const htmlContent = marked(content); + const solutionId = basename(solution, extname(solution)); + const fileId = basename(file, extname(file)); + // Wrap the HTML content with the necessary HTML and CSS const htmlTemplate = ` @@ -27,9 +27,8 @@ export function renderMarkdown(solution, file) { - TigerGraph - ${normalizeName( - basename(solution, extname(solution)) - )} - ${normalizeName(basename(file, extname(file)))} + TigerGraph - ${normalizeName(solutionId)} - ${normalizeName(fileId)} + + + } + + - + + +
${htmlContent}
diff --git a/scripts/script.js b/scripts/script.js index e3e6b3bd..6846b07c 100644 --- a/scripts/script.js +++ b/scripts/script.js @@ -85,7 +85,7 @@ async function syncFolder(folder, cacheControl = disableCacheControl) { Prefix: folder, }) .promise(); - const conents = result.Contents; + const conents = result.Contents || []; // delete all remote file not existed on local for (let content of conents) { @@ -119,7 +119,7 @@ function getAllSolutions() { return metaFiles.map((file) => file.slice(0, -"/meta/meta.yml".length)); } -// Find a case-insensitive Readme.md file in the solution root + function findReadmeFile(solutionDir) { try { const files = fs.readdirSync(solutionDir); @@ -163,16 +163,14 @@ async function getSolution(dir) { await syncFolder(`${dir}/model`); await syncFolder(`${dir}/doc`); - const insightsFiles = await globSync(`${dir}/meta/Insights*.json`); + const insightsFiles = globSync(`${dir}/meta/Insights*.json`); content.metadata.hasInsights = insightsFiles.length > 0; - const markdownFiles = globSync([ - `${dir}/model/**/*.md`, - `${dir}/doc/**/*.md`, - ]); + const markdownFiles = globSync([`${dir}/model/**/*.md`, `${dir}/doc/**/*.md`]); const htmlFiles = []; for (let markdownFile of markdownFiles) { const html = renderMarkdown(dir, markdownFile); + const htmlFile = path.join( path.dirname(markdownFile), path.basename(markdownFile, path.extname(markdownFile)) + ".html" @@ -196,7 +194,7 @@ async function getSolution(dir) { } } - // Handle root-level README (case-insensitive) + const readmeFile = findReadmeFile(dir); if (readmeFile) { const html = renderMarkdown(dir, readmeFile); @@ -216,7 +214,6 @@ async function getSolution(dir) { try { const data = await s3.upload(params).promise(); console.log(`${htmlFile} => ${data.Location}`); - // Expose README link separately content.metadata.readme = data.Location; } catch (error) { console.error("Error uploading html file:", error); @@ -256,9 +253,7 @@ function concatFilesForQuery(files, lastFiles, graphName, is_library) { content += `INSTALL QUERY ALL\n`; } - const lastFileContents = lastFiles.map((file) => - fs.readFileSync(file, "utf8") - ); + const lastFileContents = lastFiles.map((file) => fs.readFileSync(file, "utf8")); for (let i = 0; i < lastFiles.length; i++) { content += "#File: " + lastFiles[i] + "\n"; content += lastFileContents[i]; @@ -278,9 +273,7 @@ function concatFilesForLastFile(lastFiles, graphName, is_library) { } let content = `USE GRAPH ${graphName}\n`; - const lastFileContents = lastFiles.map((file) => - fs.readFileSync(file, "utf8") - ); + const lastFileContents = lastFiles.map((file) => fs.readFileSync(file, "utf8")); for (let i = 0; i < lastFiles.length; i++) { content += lastFileContents[i]; content += "\n"; @@ -294,9 +287,7 @@ function concatFilesForLastFile(lastFiles, graphName, is_library) { function concatLoadingFiles(files) { const fileContents = files .map((file) => fs.readFileSync(file, "utf8")) - .map((content) => - content.replaceAll("tigergraph-solution-kits", getBucketName()) - ); + .map((content) => content.replaceAll("tigergraph-solution-kits", getBucketName())); let content = ""; for (let i = 0; i < files.length; i++) { @@ -321,28 +312,25 @@ async function getSolutionDetail(dir, first, last, graphName, is_library) { styleJSON = fs.readFileSync(`${dir}/meta/style.json`, "utf8"); } catch (error) {} - const queryFiles = globSync([ - `${dir}/queries/*.gsql`, - `${dir}/queries/*/*.gsql`, - ]); + const queryFiles = globSync([`${dir}/queries/*.gsql`, `${dir}/queries/*/*.gsql`]); const firstFiles = []; for (let file of first) { - const path = `${dir}/queries/${file}`; - if (queryFiles.includes(path)) { - firstFiles.push(path); + const p = `${dir}/queries/${file}`; + if (queryFiles.includes(p)) { + firstFiles.push(p); } } const lastFiles = []; for (let file of last) { - const path = `${dir}/queries/${file}`; - if (queryFiles.includes(path)) { - lastFiles.push(path); + const p = `${dir}/queries/${file}`; + if (queryFiles.includes(p)) { + lastFiles.push(p); } } const middleFiles = queryFiles.filter( - (file) => !firstFiles.includes(file) && !lastFiles.includes(file) + (f) => !firstFiles.includes(f) && !lastFiles.includes(f) ); const query = concatFilesForQuery( @@ -360,7 +348,7 @@ async function getSolutionDetail(dir, first, last, graphName, is_library) { const resetFiles = globSync(`${dir}/reset/*.gsql`); const reset = concatFiles(resetFiles); - const insightsFiles = await globSync(`${dir}/meta/Insights*.json`); + const insightsFiles = globSync(`${dir}/meta/Insights*.json`); const insightsApplications = []; for (let insightsFile of insightsFiles) { const application = JSON.parse(fs.readFileSync(`${insightsFile}`, "utf8")); @@ -383,9 +371,7 @@ async function main() { const solutions = getAllSolutions(); const metadataList = []; for (let solution of solutions) { - const { metadata, queries: { first, last } = {} } = await getSolution( - solution - ); + const { metadata, queries: { first, last } = {} } = await getSolution(solution); if (metadata.production === false) { console.log("hide solution", metadata.name); @@ -393,7 +379,7 @@ async function main() { } metadataList.push({ - ...metadata, + ...metadata, // includes metadata.images, metadata.docLinks, and ADDED metadata.readme when present path: solution, }); @@ -404,6 +390,7 @@ async function main() { metadata.graph, metadata.is_library ); + const params = { ...commonBucketConfig, Key: `${solution}/meta.json`, @@ -460,28 +447,16 @@ async function main() { main(); -// Debug code -// function decodeSolution(path) { -// const file = fs.readFileSync(path, "utf8"); -// const content = JSON.parse(file); -// const { schema, query, sampleLoadingJob, reset } = content; -// console.log(schema); -// console.log(query); -// console.log(sampleLoadingJob); -// console.log(reset); -// } - async function generateFileForImportSolution() { const dir = "solution_metadata"; const list_data = []; - fs.mkdirSync(dir); + // (small safety: allow reruns without throwing) + fs.mkdirSync(dir, { recursive: true }); const solutions = getAllSolutions(); const metadataList = []; for (let solution of solutions) { - const { metadata, queries: { first, last } = {} } = await getSolution( - solution - ); + const { metadata, queries: { first, last } = {} } = await getSolution(solution); if (metadata.production === false) { console.log("hide solution", metadata.name); @@ -498,8 +473,7 @@ async function generateFileForImportSolution() { // strip aws s3 url prefix if (metadata.icon) { - metadata.icon = - dir + "/" + metadata.icon.slice(metadata.icon.indexOf(solution)); + metadata.icon = dir + "/" + metadata.icon.slice(metadata.icon.indexOf(solution)); } if (metadata.images) { metadata.images = metadata.images.map((image) => { @@ -513,8 +487,8 @@ async function generateFileForImportSolution() { initQuery: solutionDetails.lastQuery, }); - if (!solutionDetails.is_library) { - // https://tigergraph-solution-kits-prod.s3.us-west-1.amazonaws.com/financial_crime/application_fraud/4.x/solution_with_data.tar.gz + + if (!metadata.is_library) { const solution_with_data = `https://tigergraph-solution-kits-prod.s3.us-west-1.amazonaws.com/${solution}/4.x/solution_with_data.tar.gz`; const solution_without_data = `https://tigergraph-solution-kits-prod.s3.us-west-1.amazonaws.com/${solution}/4.x/solution_without_data.tar.gz`; list_data.push({ @@ -529,23 +503,14 @@ async function generateFileForImportSolution() { // copy images and icon fs.mkdirSync(`${dir}/${solution}/meta`, { recursive: true }); if (fs.existsSync(`${solution}/meta/icon.png`)) { - fs.copyFileSync( - `${solution}/meta/icon.png`, - `${dir}/${solution}/meta/icon.png` - ); + fs.copyFileSync(`${solution}/meta/icon.png`, `${dir}/${solution}/meta/icon.png`); } else if (fs.existsSync(`${solution}/meta/icon.jpg`)) { - fs.copyFileSync( - `${solution}/meta/icon.jpg`, - `${dir}/${solution}/meta/icon.jpg` - ); + fs.copyFileSync(`${solution}/meta/icon.jpg`, `${dir}/${solution}/meta/icon.jpg`); } else if (fs.existsSync(`${solution}/meta/icon.svg`)) { - fs.copyFileSync( - `${solution}/meta/icon.svg`, - `${dir}/${solution}/meta/icon.svg` - ); + fs.copyFileSync(`${solution}/meta/icon.svg`, `${dir}/${solution}/meta/icon.svg`); } if (fs.existsSync(`${solution}/meta/images`)) { - fs.mkdirSync(`${dir}/${solution}/meta/images`); + fs.mkdirSync(`${dir}/${solution}/meta/images`, { recursive: true }); const images = globSync([`${solution}/meta/images/*`]); for (let image of images) { const fileName = path.basename(image); @@ -554,15 +519,7 @@ async function generateFileForImportSolution() { } } - fs.writeFileSync( - `${dir}/solution_list.json`, - JSON.stringify(metadataList, null, 2) - ); - fs.writeFileSync( - `${dir}/solution_data.json`, - JSON.stringify(list_data, null, 2) - ); + fs.writeFileSync(`${dir}/solution_list.json`, JSON.stringify(metadataList, null, 2)); + fs.writeFileSync(`${dir}/solution_data.json`, JSON.stringify(list_data, null, 2)); } -// generate meta data for import solution, used by https://dl.tigergraph.com/?tab=solution -// generateFileForImportSolution();