From 1a29bd2033a723b702b005c0e793f655a7643dda Mon Sep 17 00:00:00 2001 From: lumenwrites Date: Sat, 3 Jun 2023 04:01:11 +0100 Subject: [PATCH] Index Node Essentials link shortcodes. --- godot-node-essentials | 1 + package-lock.json | 9 +++++++++ package.json | 1 + src/index.ts | 47 ++++++++++++++++++++++++++++++++++++------- src/utils.ts | 9 +++++++++ 5 files changed, 60 insertions(+), 7 deletions(-) create mode 120000 godot-node-essentials diff --git a/godot-node-essentials b/godot-node-essentials new file mode 120000 index 0000000..b8869ec --- /dev/null +++ b/godot-node-essentials @@ -0,0 +1 @@ +/Users/ray/projects/GDSchool/courses/godot-node-essentials \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 552262f..da62e23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "dotenv": "^16.0.3", "fs-extra": "^11.1.1", "gray-matter": "^4.0.3", + "slugify": "^1.6.6", "zip-a-folder": "^1.1.5" }, "devDependencies": { @@ -963,6 +964,14 @@ "node": ">=4" } }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index 93b47de..ae48b22 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dotenv": "^16.0.3", "fs-extra": "^11.1.1", "gray-matter": "^4.0.3", + "slugify": "^1.6.6", "zip-a-folder": "^1.1.5" } } diff --git a/src/index.ts b/src/index.ts index fcd6786..80b0307 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,10 +3,10 @@ dotenv.config() import fs from 'fs-extra' import path from 'path' import matter from 'gray-matter' -import { copyFiles, readText, saveText, ensureDirExists, readJson, saveJson } from './utils' +import { copyFiles, readText, saveText, ensureDirExists, readJson, saveJson, slugify } from './utils' import { zip } from 'zip-a-folder' -const WORKING_DIR = process.cwd() // + '/course-content' // '/learn-to-code-with-godot' // + '/course-content' // + '/godot-node-essentials' // + `/learn-to-code-from-zero-test` +const WORKING_DIR = process.cwd() + '/godot-node-essentials' // + '/course-content' // '/learn-to-code-with-godot' // + '/course-content' // + '/godot-node-essentials' // + `/learn-to-code-from-zero-test` const CONTENT_DIR = `${WORKING_DIR}/content-gdschool` const OUTPUT_DIR = `${WORKING_DIR}/content-gdschool-processed` const RELEASES_DIR = `${WORKING_DIR}/content-gdschool-releases` @@ -21,7 +21,7 @@ async function main() { copyFiles(CONTENT_DIR, OUTPUT_DIR) // Find all code files in Godot project folders, so that I can later use them to replace include shortcodes inside codeblocks const codeFiles = indexCodeFiles() - + const lessonFiles = indexLessonFiles() // needed to create links with shortcodes like {{ link lesson-slug subheading }} // Process the content of the landing page courseIndexText = rewriteImagePaths(courseIndexText, `/courses/${courseFrontmatter.slug}`) saveText(`${OUTPUT_DIR}/_index.md`, courseIndexText) @@ -50,7 +50,7 @@ async function main() { lessonText = processCodeblocks(lessonText, lessonFileName, codeFiles) // let lessonUrl = `/course/${courseFrontmatter.slug}/${sectionFrontmatter.slug}/${lessonFrontmatter.slug}` - lessonText = rewriteLinks(lessonText, `/course/${courseFrontmatter.slug}`) + lessonText = rewriteLinks(lessonText, `/course/${courseFrontmatter.slug}`, lessonFiles) // Saving the processed lesson, in place. saveText(lessonFilePath, lessonText) @@ -74,13 +74,19 @@ function parseConfig(config) { } // -function rewriteLinks(lessonText, courseUrl) { +function rewriteLinks(lessonText, courseUrl, lessonFiles) { // TODO - some links have anchor tags linking to subheadings, like {{ link Lesson subheading }} // const linkRegex = /{{\s*link\s+([^\s{}]+)\s*}}/g const linkRegex = /{{\s*link\s+([\w-]+)\s*([\w-]*)\s*}}/g + // In the future, we should have shortcodes like {{ link lesson-slug subheading }} + // Then, we'd replace such shortcodes with links like this: [Lesson Title](/course/section-slug/lesson-slug#subheading) + // But, the way Node Essentails course is written, the shortcodes are like this: {{ link LessonFileName subheading }} lessonText = lessonText.replace(linkRegex, (match, fileName, headingSlug) => { - const modifiedLink = `[${fileName}](${courseUrl}/${fileName}/${fileName})}` + const lesson = lessonFiles.find((lesson) => lesson.fileName === fileName) + let fullPath = `${courseUrl}/${lesson.sectionSlug}/${lesson.slug}` + if (headingSlug) fullPath += `#${headingSlug}` + const modifiedLink = `[${fileName}](${fullPath})` return modifiedLink }) return lessonText @@ -220,7 +226,6 @@ function indexCodeFiles() { // const folderName = currentPath.split('/').at(-1) // if (config.ignoreDirs && config.ignoreDirs.includes(folderName)) return if (['.gd', '.shader'].includes(fileExt)) { - console.log('YES') if (['.shader'].includes(fileExt)) console.log('Found shader', fileName) // console.log(godotProjectFolder, filePath); codeFiles.push({ @@ -236,6 +241,34 @@ function indexCodeFiles() { return codeFiles } +// To create links with shortcodes like {{ link lesson-slug subheading }} +function indexLessonFiles() { + let allLessons = [] + const sectionFolderNames = fs.readdirSync(CONTENT_DIR) + for (let sectionFolderName of sectionFolderNames) { + if (['images', '.DS_Store', '_index.md'].includes(sectionFolderName)) continue + const sectionFolderPath = `${CONTENT_DIR}/${sectionFolderName}` + const sectionIndex = readText(`${sectionFolderPath}/_index.md`) + const { data: sectionFrontmatter } = matter(sectionIndex) + const lessonFileNames = fs.readdirSync(sectionFolderPath) + for (let lessonFileName of lessonFileNames) { + const lessonFilePath = `${sectionFolderPath}/${lessonFileName}` + if (fs.lstatSync(lessonFilePath).isDirectory()) continue + if (['.DS_Store'].includes(lessonFileName)) continue + let lessonText = readText(lessonFilePath) + const { data: frontmatter, content } = matter(lessonText) + let lesson = { + slug: slugify(frontmatter.title), // frontmatter.slug, + sectionSlug: sectionFrontmatter.slug, + fileName: lessonFileName.replace('.md', ''), + } + allLessons.push(lesson) + } + } + console.log('Indexed lessons', allLessons); + return allLessons +} + function searchFiles(currentPath, callback) { const files = fs.readdirSync(currentPath) for (let fileName of files) { diff --git a/src/utils.ts b/src/utils.ts index 7592054..6913467 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,14 @@ import fs from 'fs-extra' import path from 'path' +import slugifyLib from 'slugify' + +export function slugify(str) { + return slugifyLib(str, { + replacement: '-', + lower: true, + strict: true, + }) +} export async function loopOverFolders(parentFolderPath, callback) { const folderNames = fs.readdirSync(parentFolderPath)