diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json index f7b54eba9..f411d811f 100644 --- a/packages/mermaid/package.json +++ b/packages/mermaid/package.json @@ -36,7 +36,7 @@ "docs:verify": "pnpm docs:code && ts-node-esm src/docs.mts --verify", "docs:pre:vitepress": "rimraf src/vitepress && pnpm docs:code && ts-node-esm src/docs.mts --vitepress", "docs:build:vitepress": "pnpm docs:pre:vitepress && vitepress build src/vitepress", - "docs:dev": "pnpm docs:pre:vitepress && vitepress dev src/vitepress", + "docs:dev": "pnpm docs:pre:vitepress && concurrently \"vitepress dev src/vitepress\" \"ts-node-esm src/docs.mts --watch --vitepress\"", "docs:serve": "pnpm docs:build:vitepress && vitepress serve src/vitepress", "release": "pnpm build", "lint": "eslint --cache --ignore-path .gitignore . && pnpm lint:jison && prettier --check .", @@ -88,10 +88,12 @@ "@types/express": "4.17.14", "@types/jsdom": "20.0.0", "@types/lodash": "4.14.186", + "@types/micromatch": "^4.0.2", "@types/prettier": "2.7.1", "@types/stylis": "4.0.2", "@typescript-eslint/eslint-plugin": "5.41.0", "@typescript-eslint/parser": "5.41.0", + "chokidar": "^3.5.3", "concurrently": "7.5.0", "coveralls": "3.1.1", "cypress": "10.11.0", @@ -114,6 +116,7 @@ "js-base64": "3.7.2", "jsdom": "20.0.2", "lint-staged": "13.0.3", + "micromatch": "^4.0.5", "moment": "2.29.4", "path-browserify": "1.0.1", "prettier": "2.7.1", @@ -138,4 +141,4 @@ "**/*.css", "**/*.scss" ] -} +} \ No newline at end of file diff --git a/packages/mermaid/src/docs.mts b/packages/mermaid/src/docs.mts index 96f5e9024..f44400a1b 100644 --- a/packages/mermaid/src/docs.mts +++ b/packages/mermaid/src/docs.mts @@ -30,7 +30,7 @@ * @todo Write a test file for this. (Will need to be able to deal .mts file. Jest has trouble with * it.) */ -import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'; +import { readFileSync, writeFileSync, mkdirSync, existsSync, rmSync, rmdirSync } from 'fs'; import { exec } from 'child_process'; import { globby } from 'globby'; import { JSDOM } from 'jsdom'; @@ -38,6 +38,8 @@ import type { Code, Root } from 'mdast'; import { posix, dirname, relative } from 'path'; import prettier from 'prettier'; import { remark } from 'remark'; +import chokidar from 'chokidar'; +import mm from 'micromatch'; // @ts-ignore No typescript declaration file import flatmap from 'unist-util-flatmap'; @@ -47,6 +49,7 @@ const MERMAID_MAJOR_VERSION = ( const verifyOnly: boolean = process.argv.includes('--verify'); const git: boolean = process.argv.includes('--git'); +const watch: boolean = process.argv.includes('--watch'); const vitepress: boolean = process.argv.includes('--vitepress'); const noHeader: boolean = process.argv.includes('--noHeader') || vitepress; @@ -246,11 +249,15 @@ const transformHtml = (filename: string) => { copyTransformedContents(filename, !verifyOnly, formattedHTML); }; -const getFilesFromGlobs = async (globs: string[]): Promise => { +const getGlobs = (globs: string[]): string[] => { globs.push('!**/dist'); if (!vitepress) { globs.push('!**/.vitepress', '!**/vite.config.ts', '!src/docs/index.md'); } + return globs; +}; + +const getFilesFromGlobs = async (globs: string[]): Promise => { return await globby(globs, { dot: true }); }; @@ -263,15 +270,18 @@ const getFilesFromGlobs = async (globs: string[]): Promise => { const sourceDirGlob = posix.join('.', SOURCE_DOCS_DIR, '**'); const action = verifyOnly ? 'Verifying' : 'Transforming'; - const mdFiles = await getFilesFromGlobs([posix.join(sourceDirGlob, '*.md')]); + const mdFileGlobs = getGlobs([posix.join(sourceDirGlob, '*.md')]); + const mdFiles = await getFilesFromGlobs(mdFileGlobs); console.log(`${action} ${mdFiles.length} markdown files...`); mdFiles.forEach(transformMarkdown); - const htmlFiles = await getFilesFromGlobs([posix.join(sourceDirGlob, '*.html')]); + const htmlFileGlobs = getGlobs([posix.join(sourceDirGlob, '*.html')]); + const htmlFiles = await getFilesFromGlobs(htmlFileGlobs); console.log(`${action} ${htmlFiles.length} html files...`); htmlFiles.forEach(transformHtml); - const otherFiles = await getFilesFromGlobs([sourceDirGlob, '!**/*.md', '!**/*.html']); + const otherFileGlobs = getGlobs([sourceDirGlob, '!**/*.md', '!**/*.html']); + const otherFiles = await getFilesFromGlobs(otherFileGlobs); console.log(`${action} ${otherFiles.length} other files...`); otherFiles.forEach((file: string) => { copyTransformedContents(file, !verifyOnly); // no transformation @@ -287,4 +297,32 @@ const getFilesFromGlobs = async (globs: string[]): Promise => { exec(`git add ${FINAL_DOCS_DIR}`); } } + + if (watch) { + console.log(`Watching for changes in ${SOURCE_DOCS_DIR}`); + + const matcher = (globs: string[]) => (file: string) => mm.every(file, globs); + const isMd = matcher(mdFileGlobs); + const isHtml = matcher(htmlFileGlobs); + const isOther = matcher(otherFileGlobs); + + chokidar + .watch(SOURCE_DOCS_DIR) + // Delete files from the final docs dir if they are deleted from the source dir + .on('unlink', (file: string) => rmSync(changeToFinalDocDir(file))) + .on('unlinkDir', (file: string) => rmdirSync(changeToFinalDocDir(file))) + .on('all', (event, path) => { + // Ignore other events. + if (!['add', 'change'].includes(event)) { + return; + } + if (isMd(path)) { + transformMarkdown(path); + } else if (isHtml(path)) { + transformHtml(path); + } else if (isOther(path)) { + copyTransformedContents(path, true); + } + }); + } })(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b11d52da..8290fdc4e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -166,10 +166,12 @@ importers: '@types/express': 4.17.14 '@types/jsdom': 20.0.0 '@types/lodash': 4.14.186 + '@types/micromatch': ^4.0.2 '@types/prettier': 2.7.1 '@types/stylis': 4.0.2 '@typescript-eslint/eslint-plugin': 5.41.0 '@typescript-eslint/parser': 5.41.0 + chokidar: ^3.5.3 concurrently: 7.5.0 coveralls: 3.1.1 cypress: 10.11.0 @@ -200,6 +202,7 @@ importers: khroma: ^2.0.0 lint-staged: 13.0.3 lodash: ^4.17.21 + micromatch: ^4.0.5 moment: 2.29.4 moment-mini: ^2.24.0 non-layered-tidy-tree-layout: ^2.0.2 @@ -239,10 +242,12 @@ importers: '@types/express': 4.17.14 '@types/jsdom': 20.0.0 '@types/lodash': 4.14.186 + '@types/micromatch': 4.0.2 '@types/prettier': 2.7.1 '@types/stylis': 4.0.2 '@typescript-eslint/eslint-plugin': 5.41.0_huremdigmcnkianavgfk3x6iou '@typescript-eslint/parser': 5.41.0_wyqvi574yv7oiwfeinomdzmc3m + chokidar: 3.5.3 concurrently: 7.5.0 coveralls: 3.1.1 cypress: 10.11.0 @@ -265,6 +270,7 @@ importers: js-base64: 3.7.2 jsdom: 20.0.2 lint-staged: 13.0.3 + micromatch: 4.0.5 moment: 2.29.4 path-browserify: 1.0.1 prettier: 2.7.1 @@ -2302,6 +2308,10 @@ packages: '@types/node': 18.11.8 dev: true + /@types/braces/3.0.1: + resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==} + dev: true + /@types/cacheable-request/6.0.2: resolution: {integrity: sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==} dependencies: @@ -2616,6 +2626,12 @@ packages: '@types/unist': 2.0.6 dev: true + /@types/micromatch/4.0.2: + resolution: {integrity: sha512-oqXqVb0ci19GtH0vOA/U2TmHTcRY9kuZl4mqUxe0QmJAlIW13kzhuK5pi1i9+ngav8FjpSb9FVS/GE00GLX1VA==} + dependencies: + '@types/braces': 3.0.1 + dev: true + /@types/mime/3.0.1: resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} dev: true