diff --git a/.eslintignore b/.eslintignore index 09e033074..956c7ea05 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1389,6 +1389,7 @@ packages/tools/updateMarkdownDoc.js packages/tools/utils/discourse.js packages/tools/utils/loadSponsors.js packages/tools/utils/translation.js +packages/tools/validateFilenames.js packages/tools/website/build.js packages/tools/website/buildTranslations.js packages/tools/website/processDocs.test.js diff --git a/.gitignore b/.gitignore index 04ab9f7f9..38f234baa 100644 --- a/.gitignore +++ b/.gitignore @@ -1368,6 +1368,7 @@ packages/tools/updateMarkdownDoc.js packages/tools/utils/discourse.js packages/tools/utils/loadSponsors.js packages/tools/utils/translation.js +packages/tools/validateFilenames.js packages/tools/website/build.js packages/tools/website/buildTranslations.js packages/tools/website/processDocs.test.js diff --git a/lint-staged.config.js b/lint-staged.config.js index 4b350298d..799e354dd 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -23,5 +23,6 @@ module.exports = { '*.{js,jsx,ts,tsx,task2}': 'yarn spellcheck', '*.{js,jsx,ts,tsx,task3}': 'yarn packageJsonLint', '*.{js,jsx,ts,tsx,task4}': 'yarn linter-precommit', - '*.{md,mdx}': 'yarn spellcheck', + '*.{md,mdx,task5}': 'yarn spellcheck', + '*.{md,mdx,task6}': 'yarn validateFilenames', }; diff --git a/package.json b/package.json index 714edc4f1..46ac51a4e 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc", "updateNews": "node ./packages/tools/website/updateNews", "updatePluginTypes": "./packages/generator-joplin/updateTypes.sh", + "validateFilenames": "node ./packages/tools/validateFilenames.js", "watch": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 999 run watch", "watchWebsite": "nodemon --delay 1 --watch Assets/WebsiteAssets --watch packages/tools/website --watch packages/tools/website/utils --watch packages/doc-builder/build --ext md,ts,js,mustache,css,tsx,gif,png,svg --exec \"node packages/tools/website/build.js && http-server --port 8077 ../joplin-website/docs -a localhost\"" }, diff --git a/packages/tools/validateFilenames.ts b/packages/tools/validateFilenames.ts new file mode 100644 index 000000000..8d37a5bd9 --- /dev/null +++ b/packages/tools/validateFilenames.ts @@ -0,0 +1,35 @@ +// This is used to validate the Markdown filenames. The updateNews script uses the filename as the +// Discourse external_id, however that ID does not support certain characters, such as ".". + +import { getRootDir } from '@joplin/utils'; +import { fileExtension } from '@joplin/utils/path'; +import { readdir } from 'fs/promises'; +import { filename } from '@joplin/lib/path-utils'; + +const supportedExtensions = ['md', 'mdx']; +const allowedRegex = '^[a-zA-Z0-9_-]+$'; + +const main = async () => { + const readmeDir = `${await getRootDir()}/readme`; + + const filePaths = await readdir(readmeDir, { recursive: true }); + + for (const filePath of filePaths) { + try { + const ext = fileExtension(filePath); + if (!supportedExtensions.includes(ext.toLowerCase())) continue; + if (!supportedExtensions.includes(ext)) throw new Error(`Invalid extension case (Supported extensions: ${JSON.stringify(supportedExtensions)})`); + const name = filename(filePath); + if (!name.match(new RegExp(allowedRegex))) throw new Error(`File format not allowed (Allowed characters: ${allowedRegex})`); + } catch (error) { + console.info(`Invalid filename: "${filePath}":`, error.message); + process.exit(1); + } + } +}; + +main().catch((error) => { + console.error('Fatal error'); + console.error(error); + process.exit(1); +});