diff --git a/.eslintignore b/.eslintignore index d525538fd8..1122886a22 100644 --- a/.eslintignore +++ b/.eslintignore @@ -37,6 +37,10 @@ packages/core/src/lib/markdown-it/plugins/* # --- packages/core end --- +# --- packages/cli --- +packages/cli/dist/**/*.js +# --- packages/cli end --- + !.eslintrc.js # --- packages/vue-components --- @@ -48,4 +52,4 @@ packages/vue-components/src/utils/utils.js # --- packages/vue-components end --- -dangerfile.js \ No newline at end of file +dangerfile.js diff --git a/.gitignore b/.gitignore index 354522f152..8d1f6fa8cc 100644 --- a/.gitignore +++ b/.gitignore @@ -107,6 +107,12 @@ packages/core/index.js packages/core/src/lib/progress/*.js # --- packages/core end --- +# Manual type definitions need to be included +!packages/cli/src/lib/live-server/index.d.ts + # Nx for Lerna .nx/cache -.nx/workspace-data \ No newline at end of file +.nx/workspace-data + +# Build folder +dist/ diff --git a/docs/devGuide/development/settingUp.md b/docs/devGuide/development/settingUp.md index 9f3dbd08bf..f01ae3074e 100644 --- a/docs/devGuide/development/settingUp.md +++ b/docs/devGuide/development/settingUp.md @@ -41,12 +41,12 @@ We recommend the **WebStorm IDE** or **VS Code** for working with MarkBind code. 1. **Fork and clone** the MarkBind repo. -1. **Bind your cloned version of MarkBind to your console** by navigating to the cloned `packages/cli` folder and running `npm link` - 1. **Install dependencies** by running - `npm run setup` + `npm run setup` in the **root folder** of your cloned repo. +1. **Bind your cloned version of MarkBind to your console** by navigating to the cloned `packages/cli` folder and running `npm link` + 1. **Congratulations!** Now you are ready to start modifying MarkBind code. diff --git a/docs/devGuide/development/workflow.md b/docs/devGuide/development/workflow.md index c1bdc895a1..121cc783f2 100644 --- a/docs/devGuide/development/workflow.md +++ b/docs/devGuide/development/workflow.md @@ -39,6 +39,7 @@ The sections below has more information about various stages of submitting a PR. **1. Using the docs as a development environment**, with: * the lazy reload`-o`lazy reload`-o` option to speed up page building * the `-d` developer option. (see [below](#editing-frontend-features)) + * the project-bundled `tsx` as a [TypeScript runner](https://nodejs.org/en/learn/typescript/run) {.mb-3} diff --git a/docs/images/debugger/WebStorm_1.png b/docs/images/debugger/WebStorm_1.png index e08aadaef3..c8f7526900 100644 Binary files a/docs/images/debugger/WebStorm_1.png and b/docs/images/debugger/WebStorm_1.png differ diff --git a/package-lock.json b/package-lock.json index 9f5433e4cb..a5c2eca0de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "stylelint": "^16.2.1", "stylelint-config-recommended-vue": "^1.5.0", "stylelint-config-standard": "^36.0.0", + "tsx": "^4.21.0", "typescript": "^5.3.3", "walk-sync": "^2.0.2" } @@ -2103,6 +2104,448 @@ "tslib": "^2.4.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -7221,12 +7664,16 @@ } }, "node_modules/binaryextensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", - "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, "engines": { - "node": ">=0.8" + "node": ">=4" }, "funding": { "url": "https://bevry.me/fund" @@ -10177,10 +10624,11 @@ } }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -10326,6 +10774,23 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/editorconfig": { "version": "0.15.3", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", @@ -10424,6 +10889,17 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -10649,6 +11125,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -11558,11 +12076,27 @@ "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" }, "node_modules/figlet": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz", - "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.10.0.tgz", + "integrity": "sha512-aktIwEZZ6Gp9AWdMXW4YCi0J2Ahuxo67fNJRUIWD81w8pQ0t9TS8FFpbl27ChlTLF06VkwjDesZSzEVzN75rzA==", + "license": "MIT", + "dependencies": { + "commander": "^14.0.0" + }, + "bin": { + "figlet": "bin/index.js" + }, "engines": { - "node": ">= 0.4.0" + "node": ">= 17.0.0" + } + }, + "node_modules/figlet/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" } }, "node_modules/figures": { @@ -11975,10 +12509,11 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -12235,6 +12770,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.13.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.5.tgz", + "integrity": "sha512-v4/4xAEpBRp6SvCkWhnGCaLkJf9IwWzrsygJPxD/+p2/xPE3C5m2fA9FD0Ry9tG+Rqqq3gBzHSl6y1/T9V/tMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -13811,16 +14359,18 @@ } }, "node_modules/istextorbinary": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-3.3.0.tgz", - "integrity": "sha512-Tvq1W6NAcZeJ8op+Hq7tdZ434rqnMx4CCZ7H0ff83uEloDvVbqAwaMTZcafKGJT0VHkYzuXUiCY4hlXQg6WfoQ==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", "dev": true, + "license": "Artistic-2.0", "dependencies": { - "binaryextensions": "^2.2.0", - "textextensions": "^3.2.0" + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" }, "engines": { - "node": ">=8" + "node": ">=4" }, "funding": { "url": "https://bevry.me/fund" @@ -19658,6 +20208,16 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -21799,12 +22359,16 @@ "dev": true }, "node_modules/textextensions": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-3.3.0.tgz", - "integrity": "sha512-mk82dS8eRABNbeVJrEiN5/UMSCliINAuz8mkUwH4SwslkNP//gbEzlWNS5au0z5Dpx40SQxzqZevZkn+WYJ9Dw==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, "engines": { - "node": ">=8" + "node": ">=4" }, "funding": { "url": "https://bevry.me/fund" @@ -22217,6 +22781,26 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/tuf-js": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", @@ -22620,6 +23204,19 @@ "node": ">= 0.8" } }, + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/vue": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.11.tgz", @@ -23643,7 +24240,7 @@ "chokidar": "^3.3.0", "colors": "1.4.0", "commander": "^8.1.0", - "figlet": "^1.2.4", + "figlet": "^1.9.4", "find-up": "^4.1.0", "fs-extra": "^9.0.1", "live-server": "1.2.1", @@ -23653,13 +24250,14 @@ "winston-daily-rotate-file": "^3.10.0" }, "bin": { - "markbind": "index.js" + "markbind": "dist/index.js" }, "devDependencies": { + "@types/lodash": "^4.14.181", "@types/url-parse": "^1.4.8", - "diff": "^4.0.1", + "diff": "^8.0.3", "ignore": "^5.1.4", - "istextorbinary": "^3.3.0", + "istextorbinary": "^9.5.0", "jest": "^29.7.0", "memfs": "^4.56.2", "walk-sync": "^2.0.2" @@ -29635,6 +30233,188 @@ "tslib": "^2.4.0" } }, + "@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "dev": true, + "optional": true + }, + "@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "dev": true, + "optional": true + }, "@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -35385,10 +36165,13 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "binaryextensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", - "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", - "dev": true + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "requires": { + "editions": "^6.21.0" + } }, "bindings": { "version": "1.5.0", @@ -37514,9 +38297,9 @@ "dev": true }, "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", "dev": true }, "diff-sequences": { @@ -37628,6 +38411,15 @@ "safe-buffer": "^5.0.1" } }, + "editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "requires": { + "version-range": "^4.15.0" + } + }, "editorconfig": { "version": "0.15.3", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", @@ -37707,6 +38499,16 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, "end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -37882,6 +38684,40 @@ "is-symbol": "^1.0.2" } }, + "esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, "escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -38580,9 +39416,19 @@ "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" }, "figlet": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz", - "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==" + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.10.0.tgz", + "integrity": "sha512-aktIwEZZ6Gp9AWdMXW4YCi0J2Ahuxo67fNJRUIWD81w8pQ0t9TS8FFpbl27ChlTLF06VkwjDesZSzEVzN75rzA==", + "requires": { + "commander": "^14.0.0" + }, + "dependencies": { + "commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==" + } + } }, "figures": { "version": "3.2.0", @@ -38889,9 +39735,9 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "optional": true }, "function-bind": { @@ -39070,6 +39916,15 @@ "get-intrinsic": "^1.1.1" } }, + "get-tsconfig": { + "version": "4.13.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.5.tgz", + "integrity": "sha512-v4/4xAEpBRp6SvCkWhnGCaLkJf9IwWzrsygJPxD/+p2/xPE3C5m2fA9FD0Ry9tG+Rqqq3gBzHSl6y1/T9V/tMQ==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -40184,13 +41039,14 @@ } }, "istextorbinary": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-3.3.0.tgz", - "integrity": "sha512-Tvq1W6NAcZeJ8op+Hq7tdZ434rqnMx4CCZ7H0ff83uEloDvVbqAwaMTZcafKGJT0VHkYzuXUiCY4hlXQg6WfoQ==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", "dev": true, "requires": { - "binaryextensions": "^2.2.0", - "textextensions": "^3.2.0" + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" } }, "jackspeak": { @@ -41523,18 +42379,19 @@ "requires": { "@markbind/core": "6.2.0", "@markbind/core-web": "6.2.0", + "@types/lodash": "^4.14.181", "@types/url-parse": "^1.4.8", "chalk": "^3.0.0", "cheerio": "^0.22.0", "chokidar": "^3.3.0", "colors": "1.4.0", "commander": "^8.1.0", - "diff": "^4.0.1", - "figlet": "^1.2.4", + "diff": "^8.0.3", + "figlet": "^1.9.4", "find-up": "^4.1.0", "fs-extra": "^9.0.1", "ignore": "^5.1.4", - "istextorbinary": "^3.3.0", + "istextorbinary": "^9.5.0", "jest": "^29.7.0", "live-server": "1.2.1", "lodash": "^4.17.15", @@ -45587,6 +46444,12 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -47165,10 +48028,13 @@ "dev": true }, "textextensions": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-3.3.0.tgz", - "integrity": "sha512-mk82dS8eRABNbeVJrEiN5/UMSCliINAuz8mkUwH4SwslkNP//gbEzlWNS5au0z5Dpx40SQxzqZevZkn+WYJ9Dw==", - "dev": true + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", + "dev": true, + "requires": { + "editions": "^6.21.0" + } }, "thingies": { "version": "2.5.0", @@ -47468,6 +48334,17 @@ } } }, + "tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "requires": { + "esbuild": "~0.27.0", + "fsevents": "~2.3.3", + "get-tsconfig": "^4.7.5" + } + }, "tuf-js": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", @@ -47747,6 +48624,12 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, + "version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true + }, "vue": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.11.tgz", diff --git a/package.json b/package.json index 19c51c4e26..c2fa1f34b7 100644 --- a/package.json +++ b/package.json @@ -5,22 +5,22 @@ "packages/*" ], "scripts": { - "prebuild:backend": "npm run clean", - "build:backend": "tsc --noEmitOnError", "build:web": "cd packages/core-web && npm run build", - "build:dg": "cd docs && ../packages/cli/index.js build -s dg-site.json", - "build:ug": "cd docs && ../packages/cli/index.js build -s ug-site.json", - "build:docs": "cd docs && node ../packages/cli/index.js build --baseUrl", - "deploy:dg": "cd docs && ../packages/cli/index.js deploy -s dg-site.json --ci", - "deploy:ug": "cd docs && ../packages/cli/index.js deploy -s ug-site.json --ci", - "deploy:netlify": "npm run setup && npm run build:web && cd docs && node ../packages/cli/index.js build --baseUrl", - "clean": "node ./scripts/clean.js", + "prebuild:backend": "npm run clean", + "build:backend": "tsc --build", + "build:dg": "cd docs && node ../packages/cli/dist/index.js build -s dg-site.json", + "build:ug": "cd docs && node ../packages/cli/dist/index.js build -s ug-site.json", + "build:docs": "cd docs && node ../packages/cli/dist/index.js build --baseUrl", + "deploy:dg": "cd docs && node ../packages/cli/dist/index.js deploy -s dg-site.json --ci", + "deploy:ug": "cd docs && node ../packages/cli/dist/index.js deploy -s ug-site.json --ci", + "deploy:netlify": "npm run setup && npm run build:web && cd docs && node ../packages/cli/dist/index.js build --baseUrl", + "clean": "tsc --build --clean && node ./scripts/clean.js", "csslint": "stylelint **/*.css **/*.vue", "csslintfix": "stylelint **/*.css **/*.vue --fix", - "dev": "tsc --watch", + "dev": "tsc --build --watch", "lint": "eslint . --ext .js,.ts,.vue && npm run csslint", "lintfix": "eslint . --ext .js,.ts,.vue --fix && npm run csslintfix", - "setup": "npm ci && npm run clean && lerna run prepare", + "setup": "npm ci && npm run build:backend", "test": "npm run lint && lerna run test --stream", "updatetest": "lerna run updatetest --stream" }, @@ -41,6 +41,7 @@ "stylelint-config-recommended-vue": "^1.5.0", "stylelint-config-standard": "^36.0.0", "typescript": "^5.3.3", - "walk-sync": "^2.0.2" + "walk-sync": "^2.0.2", + "tsx": "^4.21.0" } } diff --git a/packages/cli/index.js b/packages/cli/index.ts similarity index 90% rename from packages/cli/index.js rename to packages/cli/index.ts index 12b3f6bcb3..244a172d3f 100755 --- a/packages/cli/index.js +++ b/packages/cli/index.ts @@ -1,15 +1,13 @@ #!/usr/bin/env node // Entry file for MarkBind project -const program = require('commander'); - -const logger = require('./src/util/logger'); -const { build } = require('./src/cmd/build'); -const { deploy } = require('./src/cmd/deploy'); -const { init } = require('./src/cmd/init'); -const { serve } = require('./src/cmd/serve'); - -const CLI_VERSION = require('./package.json').version; +import { program } from 'commander'; +import * as logger from './src/util/logger'; +import { build } from './src/cmd/build'; +import { deploy } from './src/cmd/deploy'; +import { init } from './src/cmd/init'; +import { serve } from './src/cmd/serve'; +import { version as CLI_VERSION } from './package.json'; process.title = 'MarkBind'; process.stdout.write( @@ -19,6 +17,7 @@ process.stdout.write( function printHeader() { logger.logo(); logger.log(` v${CLI_VERSION}`); + return ''; } program diff --git a/packages/cli/package.json b/packages/cli/package.json index e9246f10d1..ff06211231 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -12,17 +12,21 @@ ], "homepage": "https://markbind.org", "license": "MIT", - "main": "index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "bin": { - "markbind": "./index.js" + "markbind": "./dist/index.js" }, + "files": ["dist/", "README.md"], "repository": { "type": "git", "url": "https://github.com/MarkBind/markbind.git" }, "scripts": { - "test": "jest --colors && cd test/functional && node test.js", - "updatetest": "cd test/functional && node updatetest.js" + "test": "jest --colors && cd test/functional && node ../../dist/test/functional/test.js", + "updatetest": "cd test/functional && node updatetest.js", + "build": "tsc", + "dev": "tsc --watch" }, "dependencies": { "@markbind/core": "6.2.0", @@ -32,7 +36,7 @@ "chokidar": "^3.3.0", "colors": "1.4.0", "commander": "^8.1.0", - "figlet": "^1.2.4", + "figlet": "^1.9.4", "find-up": "^4.1.0", "fs-extra": "^9.0.1", "live-server": "1.2.1", @@ -42,10 +46,11 @@ "winston-daily-rotate-file": "^3.10.0" }, "devDependencies": { + "@types/lodash": "^4.14.181", "@types/url-parse": "^1.4.8", - "diff": "^4.0.1", + "diff": "^8.0.3", "ignore": "^5.1.4", - "istextorbinary": "^3.3.0", + "istextorbinary": "^9.5.0", "jest": "^29.7.0", "memfs": "^4.56.2", "walk-sync": "^2.0.2" diff --git a/packages/cli/src/cmd/build.js b/packages/cli/src/cmd/build.js deleted file mode 100755 index 438f9f7c8f..0000000000 --- a/packages/cli/src/cmd/build.js +++ /dev/null @@ -1,45 +0,0 @@ -const path = require('path'); - -const { Site } = require('@markbind/core'); - -const cliUtil = require('../util/cliUtil'); -const logger = require('../util/logger'); - -const _ = {}; -_.isBoolean = require('lodash/isBoolean'); - -function build(userSpecifiedRoot, output, options) { - // if --baseUrl contains no arguments (options.baseUrl === true) then set baseUrl to empty string - const baseUrl = _.isBoolean(options.baseUrl) ? '' : options.baseUrl; - - let rootFolder; - try { - rootFolder = cliUtil.findRootFolder(userSpecifiedRoot, options.siteConfig); - } catch (error) { - logger.error(error.message); - logger.error('This directory does not appear to contain a valid MarkBind site. ' - + 'Check that you are running the command in the correct directory!\n' - + '\n' - + 'To create a new MarkBind site, run:\n' - + ' markbind init'); - cliUtil.cleanupFailedMarkbindBuild(userSpecifiedRoot); - process.exitCode = 1; - process.exit(); - } - - const defaultOutputRoot = path.join(rootFolder, '_site'); - const outputFolder = output ? path.resolve(process.cwd(), output) : defaultOutputRoot; - new Site(rootFolder, outputFolder, undefined, undefined, options.siteConfig) - .generate(baseUrl) - .then(() => { - logger.info('Build success!'); - }) - .catch((error) => { - logger.error(error.message); - process.exitCode = 1; - }); -} - -module.exports = { - build, -}; diff --git a/packages/cli/src/cmd/build.ts b/packages/cli/src/cmd/build.ts new file mode 100755 index 0000000000..eb499b2ed6 --- /dev/null +++ b/packages/cli/src/cmd/build.ts @@ -0,0 +1,50 @@ +import path from 'path'; +import { Site } from '@markbind/core'; +import isBoolean from 'lodash/isBoolean'; +import isError from 'lodash/isError'; +import * as cliUtil from '../util/cliUtil'; +import * as logger from '../util/logger'; + +const _ = { + isBoolean, + isError, +}; + +function build(userSpecifiedRoot: string, output: string, options: any) { + // if --baseUrl contains no arguments (options.baseUrl === true) then set baseUrl to empty string + const baseUrl = _.isBoolean(options.baseUrl) ? '' : options.baseUrl; + + let rootFolder; + try { + rootFolder = cliUtil.findRootFolder(userSpecifiedRoot, options.siteConfig); + } catch (error) { + if (_.isError(error)) { + logger.error(error.message); + logger.error('This directory does not appear to contain a valid MarkBind site. ' + + 'Check that you are running the command in the correct directory!\n' + + '\n' + + 'To create a new MarkBind site, run:\n' + + ' markbind init'); + } else { + logger.error(`Unknown error occurred: ${error}`); + } + cliUtil.cleanupFailedMarkbindBuild(); + process.exitCode = 1; + process.exit(); + } + + const defaultOutputRoot = path.join(rootFolder, '_site'); + const outputFolder = output ? path.resolve(process.cwd(), output) : defaultOutputRoot; + new Site(rootFolder, outputFolder, '', undefined, options.siteConfig, + false, false, () => {}) + .generate(baseUrl) + .then(() => { + logger.info('Build success!'); + }) + .catch((error) => { + logger.error(error.message); + process.exitCode = 1; + }); +} + +export { build }; diff --git a/packages/cli/src/cmd/deploy.js b/packages/cli/src/cmd/deploy.ts similarity index 55% rename from packages/cli/src/cmd/deploy.js rename to packages/cli/src/cmd/deploy.ts index 317ff21ff4..dde6b13554 100755 --- a/packages/cli/src/cmd/deploy.js +++ b/packages/cli/src/cmd/deploy.ts @@ -1,21 +1,28 @@ -const path = require('path'); +import path from 'path'; +import { Site } from '@markbind/core'; +import isError from 'lodash/isError'; +import * as cliUtil from '../util/cliUtil'; +import * as logger from '../util/logger'; -const { Site } = require('@markbind/core'); - -const cliUtil = require('../util/cliUtil'); -const logger = require('../util/logger'); +const _ = { + isError, +}; -function deploy(userSpecifiedRoot, options) { +function deploy(userSpecifiedRoot: string, options: any) { let rootFolder; try { rootFolder = cliUtil.findRootFolder(userSpecifiedRoot, options.siteConfig); } catch (error) { - logger.error(error.message); - logger.error('This directory does not appear to contain a valid MarkBind site. ' - + 'Check that you are running the command in the correct directory!\n' - + '\n' - + 'To create a new MarkBind site, run:\n' - + ' markbind init'); + if (_.isError(error)) { + logger.error(error.message); + logger.error('This directory does not appear to contain a valid MarkBind site. ' + + 'Check that you are running the command in the correct directory!\n' + + '\n' + + 'To create a new MarkBind site, run:\n' + + ' markbind init'); + } else { + logger.error(`Unknown error occurred: ${error}`); + } process.exitCode = 1; process.exit(); } @@ -23,9 +30,10 @@ function deploy(userSpecifiedRoot, options) { // Choose to build or not build depending on --no-build flag // We cannot chain generate and deploy while calling generate conditionally, so we split with if-else - const site = new Site(rootFolder, outputFolder, undefined, undefined, options.siteConfig); + const site = new Site(rootFolder, outputFolder, '', undefined, options.siteConfig, + false, false, () => {}); if (options.build) { - site.generate() + site.generate(undefined) .then(() => { logger.info('Build success!'); site.deploy(options.ci) @@ -49,6 +57,4 @@ function deploy(userSpecifiedRoot, options) { } } -module.exports = { - deploy, -}; +export { deploy }; diff --git a/packages/cli/src/cmd/init.js b/packages/cli/src/cmd/init.ts similarity index 50% rename from packages/cli/src/cmd/init.js rename to packages/cli/src/cmd/init.ts index 9b68980ede..3aaa3fb96c 100755 --- a/packages/cli/src/cmd/init.js +++ b/packages/cli/src/cmd/init.ts @@ -1,11 +1,16 @@ -const fs = require('fs-extra'); -const path = require('path'); +import fs from 'fs-extra'; +import path from 'path'; +import isError from 'lodash/isError'; -const { Template } = require('@markbind/core'); +import { Template } from '@markbind/core'; -const logger = require('../util/logger'); +import * as logger from '../util/logger'; -async function init(root, options) { +const _ = { + isError, +}; + +async function init(root: string, options: any) { const rootFolder = path.resolve(root || process.cwd()); if (options.convert) { @@ -21,7 +26,11 @@ async function init(root, options) { await template.init(); logger.info('Initialization success.'); } catch (error) { - logger.error(`Failed to initialize site with given template with error: ${error.message}`); + if (_.isError(error)) { + logger.error(`Failed to initialize site with given template with error: ${error.message}`); + } else { + logger.error(`Failed to initialize site with given template with error: ${error}`); + } process.exitCode = 1; } @@ -31,12 +40,14 @@ async function init(root, options) { await template.convert(); logger.info('Conversion success.'); } catch (error) { - logger.error(error.message); + if (_.isError(error)) { + logger.error(error.message); + } else { + logger.error(`Unknown error occurred: ${error}`); + } process.exitCode = 1; } } } -module.exports = { - init, -}; +export { init }; diff --git a/packages/cli/src/cmd/serve.js b/packages/cli/src/cmd/serve.ts similarity index 75% rename from packages/cli/src/cmd/serve.js rename to packages/cli/src/cmd/serve.ts index c051e5924b..a2f4453c05 100755 --- a/packages/cli/src/cmd/serve.js +++ b/packages/cli/src/cmd/serve.ts @@ -1,40 +1,45 @@ -const chokidar = require('chokidar'); -const path = require('path'); -const readline = require('readline'); +import chokidar from 'chokidar'; +import path from 'path'; +import readline from 'readline'; +import isError from 'lodash/isError'; -const { Site } = require('@markbind/core'); -const { pageVueServerRenderer } = require('@markbind/core/src/Page/PageVueServerRenderer'); +import { Site } from '@markbind/core'; +import { pageVueServerRenderer } from '@markbind/core/src/Page/PageVueServerRenderer'; -const fsUtil = require('@markbind/core/src/utils/fsUtil'); -const { INDEX_MARKDOWN_FILE } = require('@markbind/core/src/Site/constants'); +import * as fsUtil from '@markbind/core/src/utils/fsUtil'; +import { INDEX_MARKDOWN_FILE } from '@markbind/core/src/Site/constants'; -const cliUtil = require('../util/cliUtil'); -const liveServer = require('../lib/live-server'); -const logger = require('../util/logger'); -const { +import * as cliUtil from '../util/cliUtil'; +import liveServer from '../lib/live-server'; +import * as logger from '../util/logger'; +import { addHandler, changeHandler, lazyReloadMiddleware, removeHandler, -} = require('../util/serveUtil'); +} from '../util/serveUtil'; -const { +import { isValidServeHost, isIPAddressZero, -} = require('../util/ipUtil'); +} from '../util/ipUtil'; -function questionAsync(question) { +const _ = { + isError, +}; + +function questionAsync(question: string): Promise { const readlineInterface = readline.createInterface({ input: process.stdin, output: process.stdout }); return new Promise((resolve) => { - readlineInterface.question(question, (response) => { + readlineInterface.question(question, (response: string) => { readlineInterface.close(); resolve(response); }); }); } -function serve(userSpecifiedRoot, options) { +function serve(userSpecifiedRoot: string, options: any) { if (options.dev) { logger.useDebugConsole(); } @@ -49,13 +54,17 @@ function serve(userSpecifiedRoot, options) { process.exit(); } } catch (error) { - logger.error(error.message); - logger.error('This directory does not appear to contain a valid MarkBind site. ' - + 'Check that you are running the command in the correct directory!\n' - + '\n' - + 'To create a new MarkBind site, run:\n' - + ' markbind init'); - cliUtil.cleanupFailedMarkbindBuild(userSpecifiedRoot); + if (_.isError(error)) { + logger.error(error.message); + logger.error('This directory does not appear to contain a valid MarkBind site. ' + + 'Check that you are running the command in the correct directory!\n' + + '\n' + + 'To create a new MarkBind site, run:\n' + + ' markbind init'); + } else { + logger.error(`Unknown error occurred: ${error}`); + } + cliUtil.cleanupFailedMarkbindBuild(); process.exitCode = 1; process.exit(); } @@ -82,7 +91,7 @@ function serve(userSpecifiedRoot, options) { options.backgroundBuild, reloadAfterBackgroundBuild); // server config - const serverConfig = { + const serverConfig: any = { open: options.open, logLevel: 0, root: outputFolder, @@ -124,7 +133,7 @@ function serve(userSpecifiedRoot, options) { const getMiddlewares = webpackDevConfig.clientEntry; getMiddlewares(`${config.baseUrl}/markbind`) - .forEach(middleware => serverConfig.middleware.push(middleware)); + .forEach((middleware: any) => serverConfig.middleware.push(middleware)); } if (onePagePath) { @@ -135,7 +144,7 @@ function serve(userSpecifiedRoot, options) { serverConfig.open = serverConfig.open && `${config.baseUrl}/`; } - return site.generate(); + return site.generate(''); }) .then(() => { const watcher = chokidar.watch(rootFolder, { @@ -165,11 +174,15 @@ function serve(userSpecifiedRoot, options) { }); }) .catch((error) => { - logger.error(error.message); + if (_.isError(error)) { + logger.error(error.message); + } else { + logger.error(`Unknown error occurred: ${error}`); + } process.exitCode = 1; }); } -module.exports = { +export { serve, }; diff --git a/packages/cli/src/lib/live-server/index.d.ts b/packages/cli/src/lib/live-server/index.d.ts new file mode 100644 index 0000000000..6c4ce61623 --- /dev/null +++ b/packages/cli/src/lib/live-server/index.d.ts @@ -0,0 +1,47 @@ +// Type definitions for live-server 1.2 +// Project: https://github.com/tapio/live-server#readme +// Definitions by: Josh Cummings +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/** + * The live-server start params. + */ +export interface LiveServerParams { + /** Set the server port. Defaults to 8080. */ + port?: number | undefined; + /** Set the address to bind to. Defaults to 0.0.0.0 or process.env.IP. */ + host?: string | undefined; + /** Set root directory that's being served. Defaults to cwd. */ + root?: string | undefined; + /** When false, it won't load your browser by default. */ + open?: boolean | undefined; + /** Comma-separated string for paths to ignore. */ + ignore?: string | undefined; + /** When set, serve this file (server root relative) for every 404 (useful for single-page applications). */ + file?: string | undefined; + /** Waits for all changes, before reloading. Defaults to 0 sec. */ + wait?: number | undefined; + /** Mount a directory to a route. */ + mount?: string[][] | undefined; + /** 0 = errors only, 1 = some, 2 = lots */ + logLevel?: 0 | 1 | 2 | undefined; + /** Takes an array of Connect-compatible middleware that are injected into the server middleware stack. */ + middleware?: Array<(req: any, res: any, next: any) => void> | undefined; +} + +/** + * Start live-server. + */ +// CHANGED: return type from void => Server +export function start(params: LiveServerParams): Server; + +/** + * Shutdown live-server. + */ +export function shutdown(): void; + +// CHANGED: add reloadActiveTabs export +export function reloadActiveTabs(): void; + +// CHANGED: add getActiveUrls export +export function getActiveUrls(): string[] diff --git a/packages/cli/src/util/cliUtil.js b/packages/cli/src/util/cliUtil.js deleted file mode 100644 index 6b743ddfce..0000000000 --- a/packages/cli/src/util/cliUtil.js +++ /dev/null @@ -1,53 +0,0 @@ -const findUp = require('find-up'); -const fs = require('fs-extra'); -const path = require('path'); -const { SITE_CONFIG_NAME } = require('@markbind/core/src/Site/constants'); - -const DIR_NOT_EMPTY_ERROR_CODE = 'ENOTEMPTY'; - -function tryDeleteFolder(pathName) { - if (!fs.pathExistsSync(pathName)) { - return; - } - try { - fs.rmdirSync(pathName); - } catch (error) { - // If directory is not empty, fail silently - if (error.code !== DIR_NOT_EMPTY_ERROR_CODE) { - // Warn for other unexpected errors - // Use `console` instead of logger as we don't want to create a new logger instance - // that might pollute the working directory again. - // eslint-disable-next-line no-console - console.warn(`WARNING: Failed to delete directory ${pathName}: ${error.message}`); - } - } -} - -module.exports = { - findRootFolder: (userSpecifiedRoot, siteConfigPath = SITE_CONFIG_NAME) => { - if (userSpecifiedRoot) { - const resolvedUserSpecifiedRoot = path.resolve(userSpecifiedRoot); - const expectedConfigPath = path.join(resolvedUserSpecifiedRoot, siteConfigPath); - if (!fs.existsSync(expectedConfigPath)) { - throw new Error(`Config file not found at user specified root ${resolvedUserSpecifiedRoot}`); - } - return resolvedUserSpecifiedRoot; - } - - const currentWorkingDir = process.cwd(); - // Enforces findUp uses value of process.cwd() to determine starting dir - // This allows us to define starting dir when testing by mocking process.cwd() - const foundConfigPath = findUp.sync(siteConfigPath, { cwd: currentWorkingDir }); - if (!foundConfigPath) { - throw new Error(`No config file found in parent directories of ${currentWorkingDir}`); - } - return path.dirname(foundConfigPath); - }, - cleanupFailedMarkbindBuild: () => { - const markbindDir = path.join(process.cwd(), '_markbind'); - const logsDir = path.join(markbindDir, 'logs'); - - tryDeleteFolder(logsDir); - tryDeleteFolder(markbindDir); - }, -}; diff --git a/packages/cli/src/util/cliUtil.ts b/packages/cli/src/util/cliUtil.ts new file mode 100644 index 0000000000..3dd702d199 --- /dev/null +++ b/packages/cli/src/util/cliUtil.ts @@ -0,0 +1,64 @@ +import findUp from 'find-up'; +import fs from 'fs-extra'; +import path from 'path'; +import isString from 'lodash/isString'; + +import { SITE_CONFIG_NAME } from '@markbind/core/src/Site/constants'; + +const DIR_NOT_EMPTY_ERROR_CODE = 'ENOTEMPTY'; + +function hasErrorCodeAndMessage(err: any): err is { code: string, message: string } { + return isString(err.code) && isString(err.message); +} + +function tryDeleteFolder(pathName: string) { + if (!fs.pathExistsSync(pathName)) { + return; + } + try { + fs.rmdirSync(pathName); + } catch (error) { + if (hasErrorCodeAndMessage(error)) { + // If directory is not empty, fail silently + if (error.code !== DIR_NOT_EMPTY_ERROR_CODE) { + // Warn for other unexpected errors + // Use `console` instead of logger as we don't want to create a new logger instance + // that might pollute the working directory again. + // eslint-disable-next-line no-console + console.warn(`WARNING: Failed to delete directory ${pathName}: ${error.message}`); + } + } else { + // eslint-disable-next-line no-console + console.warn(`WARNING: Failed to delete directory ${pathName}: Unknown err ${error}`); + } + } +} + +export function findRootFolder( + userSpecifiedRoot: string, siteConfigPath: string = SITE_CONFIG_NAME): string { + if (userSpecifiedRoot) { + const resolvedUserSpecifiedRoot = path.resolve(userSpecifiedRoot); + const expectedConfigPath = path.join(resolvedUserSpecifiedRoot, siteConfigPath); + if (!fs.existsSync(expectedConfigPath)) { + throw new Error(`Config file not found at user specified root ${resolvedUserSpecifiedRoot}`); + } + return resolvedUserSpecifiedRoot; + } + + const currentWorkingDir = process.cwd(); + // Enforces findUp uses value of process.cwd() to determine starting dir + // This allows us to define starting dir when testing by mocking process.cwd() + const foundConfigPath = findUp.sync(siteConfigPath, { cwd: currentWorkingDir }); + if (!foundConfigPath) { + throw new Error(`No config file found in parent directories of ${currentWorkingDir}`); + } + return path.dirname(foundConfigPath); +} + +export function cleanupFailedMarkbindBuild() { + const markbindDir = path.join(process.cwd(), '_markbind'); + const logsDir = path.join(markbindDir, 'logs'); + + tryDeleteFolder(logsDir); + tryDeleteFolder(markbindDir); +} diff --git a/packages/cli/src/util/ipUtil.js b/packages/cli/src/util/ipUtil.ts similarity index 88% rename from packages/cli/src/util/ipUtil.js rename to packages/cli/src/util/ipUtil.ts index 47f3affb79..6fa2a6b6af 100644 --- a/packages/cli/src/util/ipUtil.js +++ b/packages/cli/src/util/ipUtil.ts @@ -4,7 +4,7 @@ * * Credits to Danail Gabenski */ -const isIpv4Address = (address) => { +const isIpv4Address = (address: string): boolean => { const patternForIpV4 = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/; return patternForIpV4.test(address); @@ -16,7 +16,7 @@ const isIpv4Address = (address) => { * * Credits to David M. Syzdek */ -const isIpv6Address = (address) => { +const isIpv6Address = (address: string): boolean => { const patternForIpV6 = new RegExp( '^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}' + '|([0-9a-fA-F]{1,4}:){1,7}:' @@ -38,7 +38,7 @@ const isIpv6Address = (address) => { return patternForIpV6.test(address); }; -function isValidServeHost(address) { +function isValidServeHost(address: string): boolean { if (address === 'localhost') { return true; } @@ -46,14 +46,14 @@ function isValidServeHost(address) { return isIpv4Address(address) || isIpv6Address(address); } -function isIPAddressZero(address) { +function isIPAddressZero(address: string): boolean { const patternForIPv4Zero = /^0(\.0)*$/; const patternForIPv6Zero = /^([0]{0,4}:){0,7}([0]{0,4}){0,1}$/; return patternForIPv4Zero.test(address) || patternForIPv6Zero.test(address); } -module.exports = { +export { isValidServeHost, isIPAddressZero, }; diff --git a/packages/cli/src/util/logger.js b/packages/cli/src/util/logger.ts similarity index 50% rename from packages/cli/src/util/logger.js rename to packages/cli/src/util/logger.ts index 693cc83e45..83c4e60158 100644 --- a/packages/cli/src/util/logger.js +++ b/packages/cli/src/util/logger.ts @@ -1,9 +1,8 @@ -const chalk = require('chalk'); -const figlet = require('figlet'); -const DailyRotateFile = require('winston-daily-rotate-file'); -const winston = require('winston'); +import chalk from 'chalk'; +import figlet from 'figlet'; -const coreLogger = require('@markbind/core/src/utils/logger'); +import * as winston from 'winston'; +import 'winston-daily-rotate-file'; // @markbind/core's consoleTransport but with level: info const consoleTransport = new (winston.transports.Console)({ @@ -14,19 +13,17 @@ const consoleTransport = new (winston.transports.Console)({ showLevel: true, }); -function useDebugConsole() { +function useDebugConsole(): void { consoleTransport.level = 'debug'; } -const dailyRotateFileTransport = new DailyRotateFile({ +const dailyRotateFileTransport = new winston.transports.DailyRotateFile({ datePattern: 'YYYY-MM-DD', dirname: '_markbind/logs', filename: 'markbind-%DATE%.log', handleExceptions: true, - humanReadableUnhandledException: true, level: 'debug', maxFiles: 5, - showLevel: true, }); // Reconfigure the default instance logger winston provides with DailyRotateFile for markbind-cli @@ -38,14 +35,19 @@ winston.configure({ ], }); -module.exports = { - error: coreLogger.error, - warn: coreLogger.warn, - info: coreLogger.info, - verbose: coreLogger.verbose, - debug: coreLogger.debug, - /* eslint-disable no-console */ - log: console.log, - logo: () => console.log(chalk.cyan(figlet.textSync('MarkBind', { horizontalLayout: 'full' }))), +export { + error, + warn, + info, + verbose, + debug, +} from '@markbind/core/src/utils/logger'; + +export { useDebugConsole, }; + +// eslint-disable-next-line no-console +export const logo = () => console.log(chalk.cyan(figlet.textSync('MarkBind', { horizontalLayout: 'full' }))); +// eslint-disable-next-line no-console +export const log = (msg: string) => console.log(msg); diff --git a/packages/cli/src/util/serveUtil.js b/packages/cli/src/util/serveUtil.js deleted file mode 100755 index 81b21d6c21..0000000000 --- a/packages/cli/src/util/serveUtil.js +++ /dev/null @@ -1,110 +0,0 @@ -const fs = require('fs-extra'); -const path = require('path'); - -const fsUtil = require('@markbind/core/src/utils/fsUtil'); -const { - LAZY_LOADING_SITE_FILE_NAME, -} = require('@markbind/core/src/Site/constants'); - -const liveServer = require('../lib/live-server'); -const logger = require('./logger'); - -const syncOpenedPages = (site) => { - logger.info('Synchronizing opened pages list before reload'); - const normalizedActiveUrls = liveServer.getActiveUrls().map((url) => { - const completeUrl = path.extname(url) === '' ? path.join(url, 'index') : url; - return fsUtil.removeExtension(completeUrl); - }); - site.changeCurrentOpenedPages(normalizedActiveUrls); -}; - -const addHandler = (site, onePagePath) => (filePath) => { - logger.info(`[${new Date().toLocaleTimeString()}] Reload for file add: ${filePath}`); - if (onePagePath) { - syncOpenedPages(site); - } - Promise.resolve().then(async () => { - if (site.isFilepathAPage(filePath) || site.isDependencyOfPage(filePath)) { - return site.rebuildSourceFiles(); - } - return site.buildAsset(filePath); - }).catch((err) => { - logger.error(err.message); - }); -}; - -const changeHandler = (site, onePagePath) => (filePath) => { - logger.info(`[${new Date().toLocaleTimeString()}] Reload for file change: ${filePath}`); - if (onePagePath) { - syncOpenedPages(site); - } - Promise.resolve().then(async () => { - if (path.basename(filePath) === path.basename(site.siteConfigPath)) { - return site.reloadSiteConfig(); - } - if (site.isDependencyOfPage(filePath)) { - return site.rebuildAffectedSourceFiles(filePath); - } - return site.buildAsset(filePath); - }).catch((err) => { - logger.error(err.message); - }); -}; - -const removeHandler = (site, onePagePath) => (filePath) => { - logger.info(`[${new Date().toLocaleTimeString()}] Reload for file deletion: ${filePath}`); - if (onePagePath) { - syncOpenedPages(site); - } - Promise.resolve().then(async () => { - if (site.isFilepathAPage(filePath) || site.isDependencyOfPage(filePath)) { - return site.rebuildSourceFiles(); - } - return site.removeAsset(filePath); - }).catch((err) => { - logger.error(err.message); - }); -}; - -const lazyReloadMiddleware = (site, rootFolder, config) => (req, res, next) => { - const urlExtension = path.posix.extname(req.url); - - const hasEndingSlash = req.url.endsWith('/'); - const hasNoExtension = urlExtension === ''; - const isHtmlFileRequest = urlExtension === '.html' || hasEndingSlash || hasNoExtension; - - if (!isHtmlFileRequest || req.url.endsWith('._include_.html')) { - next(); - return; - } - - if (hasNoExtension && !hasEndingSlash) { - // Urls of type 'host/userGuide' - check if 'userGuide' is a raw file or does not exist - const diskFilePath = path.resolve(rootFolder, req.url); - if (!fs.existsSync(diskFilePath) || !(fs.statSync(diskFilePath).isDirectory())) { - // Request for a raw file - next(); - return; - } - } - - const urlWithoutBaseUrl = req.url.replace(config.baseUrl, ''); - // Map 'hostname/userGuide/' and 'hostname/userGuide' to hostname/userGuide/index. - const urlWithIndex = (hasNoExtension || hasEndingSlash) - ? path.posix.join(urlWithoutBaseUrl, 'index') - : urlWithoutBaseUrl; - const urlWithoutExtension = fsUtil.removeExtension(urlWithIndex); - - const didInitiateRebuild = site.changeCurrentPage(urlWithoutExtension); - if (didInitiateRebuild) { - req.url = fsUtil.ensurePosix(path.join(config.baseUrl || '/', LAZY_LOADING_SITE_FILE_NAME)); - } - next(); -}; - -module.exports = { - addHandler, - changeHandler, - lazyReloadMiddleware, - removeHandler, -}; diff --git a/packages/cli/src/util/serveUtil.ts b/packages/cli/src/util/serveUtil.ts new file mode 100755 index 0000000000..37c54322aa --- /dev/null +++ b/packages/cli/src/util/serveUtil.ts @@ -0,0 +1,140 @@ +import fs from 'fs-extra'; +import path from 'path'; + +import * as fsUtil from '@markbind/core/src/utils/fsUtil'; +import { + LAZY_LOADING_SITE_FILE_NAME, +} from '@markbind/core/src/Site/constants'; + +import * as liveServer from '../lib/live-server'; +import * as logger from './logger'; + +/** + * Synchronizes opened pages list before reload + * @param site The site instance + */ +const syncOpenedPages = (site: any): void => { + logger.info('Synchronizing opened pages list before reload'); + const normalizedActiveUrls = liveServer.getActiveUrls().map((url: string) => { + const completeUrl = path.extname(url) === '' ? path.join(url, 'index') : url; + return fsUtil.removeExtension(completeUrl); + }); + site.changeCurrentOpenedPages(normalizedActiveUrls); +}; + +/** + * Handler for file addition events + * @param site The site instance + * @param onePagePath Flag indicating if one page mode is enabled + * @returns Function that handles the file addition + */ +const addHandler = (site: any, onePagePath?: boolean) => (filePath: string): void => { + logger.info(`[${new Date().toLocaleTimeString()}] Reload for file add: ${filePath}`); + if (onePagePath) { + syncOpenedPages(site); + } + Promise.resolve().then(async () => { + if (site.isFilepathAPage(filePath) || site.isDependencyOfPage(filePath)) { + return site.rebuildSourceFiles(); + } + return site.buildAsset(filePath); + }).catch((err: Error) => { + logger.error(err.message); + }); +}; + +/** + * Handler for file change events + * @param site The site instance + * @param onePagePath Flag indicating if one page mode is enabled + * @returns Function that handles the file change + */ +const changeHandler = (site: any, onePagePath?: boolean) => (filePath: string): void => { + logger.info(`[${new Date().toLocaleTimeString()}] Reload for file change: ${filePath}`); + if (onePagePath) { + syncOpenedPages(site); + } + Promise.resolve().then(async () => { + if (path.basename(filePath) === path.basename(site.siteConfigPath)) { + return site.reloadSiteConfig(); + } + if (site.isDependencyOfPage(filePath)) { + return site.rebuildAffectedSourceFiles(filePath); + } + return site.buildAsset(filePath); + }).catch((err: Error) => { + logger.error(err.message); + }); +}; + +/** + * Handler for file removal events + * @param site The site instance + * @param onePagePath Flag indicating if one page mode is enabled + * @returns Function that handles the file removal + */ +const removeHandler = (site: any, onePagePath?: boolean) => (filePath: string): void => { + logger.info(`[${new Date().toLocaleTimeString()}] Reload for file deletion: ${filePath}`); + if (onePagePath) { + syncOpenedPages(site); + } + Promise.resolve().then(async () => { + if (site.isFilepathAPage(filePath) || site.isDependencyOfPage(filePath)) { + return site.rebuildSourceFiles(); + } + return site.removeAsset(filePath); + }).catch((err: Error) => { + logger.error(err.message); + }); +}; + +/** + * Middleware for lazy reloading + * @param site The site instance + * @param rootFolder The root folder of the site + * @param config The site configuration + * @returns Middleware function + */ +const lazyReloadMiddleware + = (site: any, rootFolder: string, config: any) => (req: any, res: any, next: any) => { + const urlExtension = path.posix.extname(req.url); + + const hasEndingSlash = req.url.endsWith('/'); + const hasNoExtension = urlExtension === ''; + const isHtmlFileRequest = urlExtension === '.html' || hasEndingSlash || hasNoExtension; + + if (!isHtmlFileRequest || req.url.endsWith('._include_.html')) { + next(); + return; + } + + if (hasNoExtension && !hasEndingSlash) { + // Urls of type 'host/userGuide' - check if 'userGuide' is a raw file or does not exist + const diskFilePath = path.resolve(rootFolder, req.url); + if (!fs.existsSync(diskFilePath) || !(fs.statSync(diskFilePath).isDirectory())) { + // Request for a raw file + next(); + return; + } + } + + const urlWithoutBaseUrl = req.url.replace(config.baseUrl, ''); + // Map 'hostname/userGuide/' and 'hostname/userGuide' to hostname/userGuide/index. + const urlWithIndex = (hasNoExtension || hasEndingSlash) + ? path.posix.join(urlWithoutBaseUrl, 'index') + : urlWithoutBaseUrl; + const urlWithoutExtension = fsUtil.removeExtension(urlWithIndex); + + const didInitiateRebuild = site.changeCurrentPage(urlWithoutExtension); + if (didInitiateRebuild) { + req.url = fsUtil.ensurePosix(path.join(config.baseUrl || '/', LAZY_LOADING_SITE_FILE_NAME)); + } + next(); + }; + +export { + addHandler, + changeHandler, + lazyReloadMiddleware, + removeHandler, +}; diff --git a/packages/cli/test/functional/.eslintrc.js b/packages/cli/test/functional/.eslintrc.js index c38aa97590..30e9070e6f 100644 --- a/packages/cli/test/functional/.eslintrc.js +++ b/packages/cli/test/functional/.eslintrc.js @@ -2,4 +2,7 @@ module.exports = { env: { browser: true, }, + rules: { + 'import/no-extraneous-dependencies': 'off', + }, }; diff --git a/packages/cli/test/functional/test.js b/packages/cli/test/functional/test.ts similarity index 62% rename from packages/cli/test/functional/test.js rename to packages/cli/test/functional/test.ts index be264d8ccb..2cb9580579 100644 --- a/packages/cli/test/functional/test.js +++ b/packages/cli/test/functional/test.ts @@ -1,33 +1,34 @@ -const path = require('path'); -const fs = require('fs-extra'); -const { execSync } = require('child_process'); - -const { compare } = require('./testUtil/compare'); - -const { cleanupConvert } = require('./testUtil/cleanup'); - -const logger = require('../../../core/src/utils/logger'); - -const { +import path from 'path'; +import fs from 'fs-extra'; +import { execSync } from 'child_process'; +import isError from 'lodash/isError'; +import * as logger from '@markbind/core/src/utils/logger'; +import { ExecSyncOptions } from 'node:child_process'; +import { compare } from './testUtil/compare'; +import { cleanupConvert } from './testUtil/cleanup'; +import { testSites, testConvertSites, testTemplateSites, plantumlGeneratedFilesForTestSites, plantumlGeneratedFilesForConvertSites, plantumlGeneratedFilesForTemplateSites, -} = require('./testSites'); +} from './testSites'; -/* eslint-disable no-console */ +const _ = { isError }; +// Path to the compiled CLI executable +const CLI_PATH = path.resolve(__dirname, '../../index'); -function printFailedMessage(err, siteName) { +/* eslint-disable no-console */ +function printFailedMessage(err: Error, siteName: string) { console.log(err); console.log(`Test result: ${siteName} FAILED`); } -process.env.TEST_MODE = true; +process.env.TEST_MODE = 'true'; process.env.FORCE_COLOR = '3'; -const execOptions = { +const execOptions: ExecSyncOptions = { stdio: ['inherit', 'inherit', 'inherit'], }; @@ -51,11 +52,15 @@ expectedErrors.forEach((error, index) => { testSites.forEach((siteName) => { console.log(`Running ${siteName} tests`); try { - execSync(`node ../../index.js build ${siteName}`, execOptions); + execSync(`node ${CLI_PATH} build ${siteName}`, execOptions); const siteIgnoredFiles = plantumlGeneratedFilesForTestSites[siteName]; compare(siteName, 'expected', '_site', siteIgnoredFiles); } catch (err) { - printFailedMessage(err, siteName); + if (_.isError(err)) { + printFailedMessage(err, siteName); + } else { + console.error(`Unknown error for site ${siteName} occurred: ${err}`); + } process.exit(1); } }); @@ -65,16 +70,20 @@ testConvertSites.forEach((sitePath) => { const nonMarkBindSitePath = path.join(sitePath, 'non_markbind_site'); const siteName = sitePath.split('/')[1]; try { - execSync(`node ../../index.js init ${nonMarkBindSitePath} -c`, execOptions); - execSync(`node ../../index.js build ${nonMarkBindSitePath}`, execOptions); + execSync(`node ${CLI_PATH} init ${nonMarkBindSitePath} -c`, execOptions); + execSync(`node ${CLI_PATH} build ${nonMarkBindSitePath}`, execOptions); const siteIgnoredFiles = plantumlGeneratedFilesForConvertSites[siteName]; compare(sitePath, 'expected', 'non_markbind_site/_site', siteIgnoredFiles); } catch (err) { - printFailedMessage(err, sitePath); - cleanupConvert(path.resolve(__dirname, sitePath)); + if (_.isError(err)) { + printFailedMessage(err, sitePath); + } else { + console.error(`Unknown error for site ${sitePath} occurred: ${err}`); + } + cleanupConvert(sitePath); process.exit(1); } - cleanupConvert(path.resolve(__dirname, sitePath)); + cleanupConvert(sitePath); }); testTemplateSites.forEach((templateAndSitePath) => { @@ -85,21 +94,25 @@ testTemplateSites.forEach((templateAndSitePath) => { console.log(`Running ${sitePath} tests`); try { - execSync(`node ../../index.js init ${siteCreationTempPath} --template ${flag}`, execOptions); - execSync(`node ../../index.js build ${siteCreationTempPath}`, execOptions); + execSync(`node ${CLI_PATH} init ${siteCreationTempPath} --template ${flag}`, execOptions); + execSync(`node ${CLI_PATH} build ${siteCreationTempPath}`, execOptions); const siteIgnoredFiles = plantumlGeneratedFilesForTemplateSites[siteName]; compare(sitePath, 'expected', 'tmp/_site', siteIgnoredFiles); } catch (err) { - printFailedMessage(err, sitePath); - fs.removeSync(path.resolve(__dirname, siteCreationTempPath)); + if (_.isError(err)) { + printFailedMessage(err, sitePath); + } else { + console.error(`Unknown error for site ${sitePath} occurred: ${err}`); + } + fs.removeSync(siteCreationTempPath); process.exit(1); } - fs.removeSync(path.resolve(__dirname, siteCreationTempPath)); + fs.removeSync(siteCreationTempPath); }); function testEmptyDirectoryBuild() { const siteRootName = 'test_site_empty'; - const siteRootPath = path.join(__dirname, siteRootName); + const siteRootPath = path.join('./', siteRootName); const emptySiteName = 'empty_dir'; const emptySitePath = path.join(siteRootPath, emptySiteName); @@ -107,7 +120,7 @@ function testEmptyDirectoryBuild() { const expectedSiteName = 'expected'; const expectedSitePath = path.join(siteRootPath, expectedSiteName); - const execOptionsWithCwd = { + const execOptionsWithCwd: ExecSyncOptions = { stdio: ['inherit', 'inherit', 'inherit'], cwd: emptySitePath, // Set the working directory to testEmptyPath }; @@ -121,7 +134,7 @@ function testEmptyDirectoryBuild() { // Try to build in empty directory (should fail with specific error) try { - execSync(`node ../../../../index.js build ${emptySitePath}`, execOptionsWithCwd); + execSync(`node ${CLI_PATH} build ${emptySitePath}`, execOptionsWithCwd); printFailedMessage(new Error('Expected build to fail but it succeeded'), siteRootName); process.exit(1); } catch (err) { @@ -129,7 +142,11 @@ function testEmptyDirectoryBuild() { try { compare(siteRootName, 'expected', 'empty_dir', [], true); } catch (compareErr) { - printFailedMessage(compareErr, siteRootName); + if (_.isError(compareErr)) { + printFailedMessage(compareErr, siteRootName); + } else { + console.error(`Unknown error for site ${siteRootName} occurred: ${compareErr}`); + } // Reset test_site_empty/empty_dir fs.emptyDirSync(emptySitePath); process.exit(1); diff --git a/packages/cli/test/functional/testSites.js b/packages/cli/test/functional/testSites.ts similarity index 79% rename from packages/cli/test/functional/testSites.js rename to packages/cli/test/functional/testSites.ts index 198744c0a9..acadffe75c 100644 --- a/packages/cli/test/functional/testSites.js +++ b/packages/cli/test/functional/testSites.ts @@ -1,3 +1,8 @@ +// Type definitions for plantuml generated files +interface PlantumlGeneratedFiles { + [key: string]: string[]; +} + const testSites = [ 'test_site', 'test_site_algolia_plugin', @@ -22,7 +27,7 @@ const testTemplateSites = [ // these files create git diffs every time they are generated, // we decided to not commit them to the repository. // However, we still want to verify that they are present. -const plantumlGeneratedFilesForTestSites = { +const plantumlGeneratedFilesForTestSites: PlantumlGeneratedFiles = { test_site: [ '9c9e77fc0a983cb6b592e65733787bec.png', 'inline-output.png', @@ -37,13 +42,13 @@ const plantumlGeneratedFilesForTestSites = { ], }; -const plantumlGeneratedFilesForConvertSites = {}; +const plantumlGeneratedFilesForConvertSites: PlantumlGeneratedFiles = {}; -const plantumlGeneratedFilesForTemplateSites = { +const plantumlGeneratedFilesForTemplateSites: PlantumlGeneratedFiles = { test_project: ['diagrams/example.png'], }; -module.exports = { +export { testSites, testConvertSites, testTemplateSites, diff --git a/packages/cli/test/functional/testUtil/cleanup.js b/packages/cli/test/functional/testUtil/cleanup.ts similarity index 91% rename from packages/cli/test/functional/testUtil/cleanup.js rename to packages/cli/test/functional/testUtil/cleanup.ts index a41c8846e9..4be8769a67 100644 --- a/packages/cli/test/functional/testUtil/cleanup.js +++ b/packages/cli/test/functional/testUtil/cleanup.ts @@ -1,7 +1,7 @@ const fs = require('fs-extra'); const path = require('path'); -function cleanupConvert(siteName) { +function cleanupConvert(siteName: string) { const directoriesToRemove = [ path.join(siteName, 'non_markbind_site/_markbind'), path.join(siteName, 'non_markbind_site/_site'), @@ -20,6 +20,6 @@ function cleanupConvert(siteName) { }); } -module.exports = { +export { cleanupConvert, }; diff --git a/packages/cli/test/functional/testUtil/compare.js b/packages/cli/test/functional/testUtil/compare.ts similarity index 82% rename from packages/cli/test/functional/testUtil/compare.js rename to packages/cli/test/functional/testUtil/compare.ts index 38a6d788c7..ed11a4ad3e 100644 --- a/packages/cli/test/functional/testUtil/compare.js +++ b/packages/cli/test/functional/testUtil/compare.ts @@ -1,13 +1,13 @@ -const fs = require('fs'); -const path = require('path'); -const ignore = require('ignore'); -const walkSync = require('walk-sync'); -const { isBinary } = require('istextorbinary'); -const diffChars = require('./diffChars'); +import fs from 'fs'; +import path from 'path'; +import ignore from 'ignore'; +import walkSync from 'walk-sync'; +import { isBinary } from 'istextorbinary'; +import isEqual from 'lodash/isEqual'; +import intersection from 'lodash/intersection'; +import { diffCharsAndPrint as diffChars } from './diffChars'; -const _ = {}; -_.isEqual = require('lodash/isEqual'); -_.intersection = require('lodash/intersection'); +const _ = { isEqual, intersection }; // List of file patterns to ignore during content diff comparison. // Either binary files or files not recognized correctly by the istextorbinary package. @@ -20,8 +20,8 @@ const TEST_BLACKLIST = ignore().add([ const CRLF_REGEX = /\r\n/g; -function _readFileSync(...paths) { - return fs.readFileSync(path.resolve(...paths), 'utf8'); +function _readFileSync(...paths: string[]) { + return fs.readFileSync(path.resolve(...paths)); } /** @@ -29,7 +29,7 @@ function _readFileSync(...paths) { * @param {string[]} filePaths - List of file paths * @returns {string[]} Filtered list without *.page-vue-render.js files */ -function filterPageVueRenderFiles(filePaths) { +function filterPageVueRenderFiles(filePaths: string[]) { return filePaths.filter(p => !p.endsWith('.page-vue-render.js')); } @@ -38,7 +38,7 @@ function filterPageVueRenderFiles(filePaths) { * @param {string} dirPath - Existing directory path to analyze * @returns {string[]} Sorted array of relative directory paths */ -function getDirectoryStructure(dirPath) { +function getDirectoryStructure(dirPath: string) { const allPaths = walkSync(dirPath, { directories: true, globs: ['**/*'] }); return allPaths .filter(p => fs.statSync(path.join(dirPath, p)) @@ -59,8 +59,8 @@ function getDirectoryStructure(dirPath) { * @param {string[]} ignoredPaths - Specify any paths to ignore for comparison, but still check for existence. * @param {boolean} compareDirectories - Whether to compare directory structures (default: false) */ -function compare(root, expectedSiteRelativePath = 'expected', siteRelativePath = '_site', - ignoredPaths = [], compareDirectories = false) { +function compare(root: string, expectedSiteRelativePath = 'expected', siteRelativePath = '_site', + ignoredPaths: string[] = [], compareDirectories = false) { const expectedDirectory = path.join(root, expectedSiteRelativePath); const actualDirectory = path.join(root, siteRelativePath); @@ -113,17 +113,21 @@ function compare(root, expectedSiteRelativePath = 'expected', siteRelativePath = continue; } - const expected = _readFileSync(expectedDirectory, expectedFilePath) - .replace(CRLF_REGEX, '\n'); - const actual = _readFileSync(actualDirectory, actualFilePath) - .replace(CRLF_REGEX, '\n'); - - if (isBinary(null, expected)) { + const expectedBuf = _readFileSync(expectedDirectory, expectedFilePath); + if (isBinary(null, expectedBuf)) { // eslint-disable-next-line no-console console.warn(`Unrecognised file extension ${expectedFilePath} contains null characters, skipping`); continue; } + // Get actual string content for comparison + const expected = expectedBuf + .toString('utf8') + .replace(CRLF_REGEX, '\n'); + const actual = _readFileSync(actualDirectory, actualFilePath) + .toString('utf8') + .replace(CRLF_REGEX, '\n'); + const hasDiff = diffChars(expected, actual, expectedFilePath); error = error || hasDiff; } @@ -134,6 +138,6 @@ function compare(root, expectedSiteRelativePath = 'expected', siteRelativePath = } } -module.exports = { +export { compare, }; diff --git a/packages/cli/test/functional/testUtil/diffChars.js b/packages/cli/test/functional/testUtil/diffChars.ts similarity index 54% rename from packages/cli/test/functional/testUtil/diffChars.js rename to packages/cli/test/functional/testUtil/diffChars.ts index 52399363a9..cf33829f6f 100644 --- a/packages/cli/test/functional/testUtil/diffChars.js +++ b/packages/cli/test/functional/testUtil/diffChars.ts @@ -1,5 +1,5 @@ -const jsdiff = require('diff'); -const DiffPrinter = require('./diffPrinter'); +import { ChangeObject, diffChars } from 'diff'; +import { DiffPrinter } from './diffPrinter'; /** * Checks for any diffs between expected.html and actual.html, @@ -9,9 +9,9 @@ const DiffPrinter = require('./diffPrinter'); * @param {string} filePathName * @returns {boolean} if diff was found */ -const diffCharsAndPrint = (expected, actual, filePathName) => { - const diffParts = jsdiff.diffChars(expected, actual); - const isDiff = part => part.added || part.removed; +const diffCharsAndPrint = (expected: string, actual: string, filePathName: string) => { + const diffParts = diffChars(expected, actual); + const isDiff = ((part: ChangeObject) => part.added || part.removed); const hasDiff = diffParts.some(isDiff); if (hasDiff) { DiffPrinter.printDiffFoundMessage(filePathName); @@ -20,4 +20,4 @@ const diffCharsAndPrint = (expected, actual, filePathName) => { return hasDiff; }; -module.exports = diffCharsAndPrint; +export { diffCharsAndPrint }; diff --git a/packages/cli/test/functional/testUtil/diffPrinter.js b/packages/cli/test/functional/testUtil/diffPrinter.ts similarity index 87% rename from packages/cli/test/functional/testUtil/diffPrinter.js rename to packages/cli/test/functional/testUtil/diffPrinter.ts index 3cef6514ad..e7b4a9f8b8 100644 --- a/packages/cli/test/functional/testUtil/diffPrinter.js +++ b/packages/cli/test/functional/testUtil/diffPrinter.ts @@ -1,18 +1,26 @@ +import { ChangeObject } from 'diff'; + const chalk = require('chalk'); const EMPTY_LINE = '|-------------------empty-line-------------------|'; const CONSECUTIVE_NEWLINE_REGEX = /\n{2,}/g; const WHITESPACE_REGEX = /\s+/g; +interface Printable { + value: string, + diff: boolean, + toPrint?: boolean +} + class DiffPrinter { /** * Replaces all newlines except the first with EMPTY_LINE. */ - static prependNewLines(match) { + static prependNewLines(match: string) { return `\n${match.replace('\n', '').split('\n').join(`${EMPTY_LINE}\n`)}`; } - static formatNewLines(value, prevVal, nextVal) { + static formatNewLines(value: string, prevVal: string, nextVal: string) { let printValue; printValue = value.replace(CONSECUTIVE_NEWLINE_REGEX, this.prependNewLines); @@ -41,8 +49,8 @@ class DiffPrinter { * @param {Array} diffObjects array of change objects returned by jsdiff#diffWords * @returns {Array} change objects where their value contains a single line */ - static generateLineParts(diffObjects) { - const parts = []; + static generateLineParts(diffObjects: ChangeObject[]) { + const parts: Printable[] = []; diffObjects.forEach(({ value, added, removed }, i) => { let printValue = value; if (added || removed) { @@ -76,7 +84,7 @@ class DiffPrinter { * @param {Array} lineParts array of line objects after being split * into lines by DiffPrinter#generateLineParts */ - static setPartsToPrint(lineParts) { + static setPartsToPrint(lineParts: Printable[]) { lineParts.forEach((linePart, i) => { if (linePart.diff) { for (let j = -3; j <= 3; j += 1) { @@ -87,7 +95,7 @@ class DiffPrinter { }); } - static printDiffFoundMessage(filePath) { + static printDiffFoundMessage(filePath: string) { const message = chalk.grey(`\n-------------------------------------\nDiff found in ${filePath}\n\n`); process.stderr.write(message); } @@ -98,7 +106,7 @@ class DiffPrinter { * @param {Array} lineParts array of line objects after being set for printing * in DiffPrinter#setPartsToPrint */ - static printLineParts(lineParts) { + static printLineParts(lineParts: Printable[]) { lineParts.forEach((linePart, i) => { const prevPart = lineParts[i - 1]; if (linePart.toPrint) { @@ -114,11 +122,11 @@ class DiffPrinter { * Prints diff with ANSI Escape Codes for colour * @param {Array} parts array of change of objects as returned by jsdiff#diffWords */ - static printDiff(parts) { + static printDiff(parts: ChangeObject[]) { const lineParts = this.generateLineParts(parts); this.setPartsToPrint(lineParts); this.printLineParts(lineParts); } } -module.exports = DiffPrinter; +export { DiffPrinter }; diff --git a/packages/cli/test/functional/updatetest.js b/packages/cli/test/functional/updatetest.ts similarity index 65% rename from packages/cli/test/functional/updatetest.js rename to packages/cli/test/functional/updatetest.ts index 5494da16fd..ec31b07dcd 100644 --- a/packages/cli/test/functional/updatetest.js +++ b/packages/cli/test/functional/updatetest.ts @@ -1,26 +1,28 @@ -const path = require('path'); -const fs = require('fs-extra'); -const { execSync } = require('child_process'); +import path from 'path'; +import fs from 'fs-extra'; +import { execSync } from 'child_process'; +import isError from 'lodash/isError'; +import { ExecSyncOptions } from 'node:child_process'; +import { cleanupConvert } from './testUtil/cleanup'; -const { cleanupConvert } = require('./testUtil/cleanup'); - -const { +import { testSites, testConvertSites, testTemplateSites, -} = require('./testSites'); +} from './testSites'; -/* eslint-disable no-console */ +const _ = { isError }; -function printFailedMessage(err, siteName) { +/* eslint-disable no-console */ +function printFailedMessage(err: string, siteName: string) { console.log(err); console.log(`Failed to update: ${siteName}`); } -process.env.TEST_MODE = true; +process.env.TEST_MODE = String(true); process.env.FORCE_COLOR = '3'; -const execOptions = { +const execOptions: ExecSyncOptions = { stdio: ['inherit', 'inherit', 'inherit'], }; @@ -29,7 +31,11 @@ testSites.forEach((siteName) => { try { execSync(`node ../../index.js build ${siteName} ${siteName}/expected`, execOptions); } catch (err) { - printFailedMessage(err, siteName); + if (_.isError(err)) { + printFailedMessage(err.message, siteName); + } else { + console.error(`Unknown error occurred ${err} for site ${siteName}`); + } process.exit(1); } }); @@ -42,7 +48,11 @@ testConvertSites.forEach((siteName) => { execSync(`node ../../index.js init ${nonMarkBindSitePath} -c`, execOptions); execSync(`node ../../index.js build ${nonMarkBindSitePath} ${expectedOutputDirectory}`, execOptions); } catch (err) { - printFailedMessage(err, siteName); + if (_.isError(err)) { + printFailedMessage(err.message, siteName); + } else { + console.error(`Unknown error occurred ${err} for site ${siteName}`); + } cleanupConvert(path.resolve(__dirname, siteName)); process.exit(1); } @@ -60,7 +70,11 @@ testTemplateSites.forEach((templateAndSitePath) => { execSync(`node ../../index.js init ${siteCreationTempPath} --template ${flag}`, execOptions); execSync(`node ../../index.js build ${siteCreationTempPath} ${expectedOutputDirectory}`, execOptions); } catch (err) { - printFailedMessage(err, sitePath); + if (_.isError(err)) { + printFailedMessage(err.message, sitePath); + } else { + console.error(`Unknown error occurred ${err} for site ${sitePath}`); + } fs.removeSync(path.resolve(__dirname, siteCreationTempPath)); process.exit(1); } diff --git a/packages/cli/test/unit/cliUtil.test.js b/packages/cli/test/unit/cliUtil.test.ts similarity index 98% rename from packages/cli/test/unit/cliUtil.test.js rename to packages/cli/test/unit/cliUtil.test.ts index 1c85a49735..1d4a4c8bf7 100644 --- a/packages/cli/test/unit/cliUtil.test.js +++ b/packages/cli/test/unit/cliUtil.test.ts @@ -2,7 +2,7 @@ const fs = require('fs'); const path = require('path'); const { SITE_JSON_DEFAULT } = require('@markbind/core/test/unit/utils/data'); -const cliUtil = require('../../src/util/cliUtil'); +const cliUtil = require('../../dist/src/util/cliUtil'); jest.mock('fs'); jest.mock('process'); diff --git a/packages/cli/test/unit/ipUtil.test.js b/packages/cli/test/unit/ipUtil.test.ts similarity index 96% rename from packages/cli/test/unit/ipUtil.test.js rename to packages/cli/test/unit/ipUtil.test.ts index 50a7b34137..50f2c9ce3a 100644 --- a/packages/cli/test/unit/ipUtil.test.js +++ b/packages/cli/test/unit/ipUtil.test.ts @@ -1,4 +1,4 @@ -const { isValidServeHost, isIPAddressZero } = require('../../src/util/ipUtil'); +const { isValidServeHost, isIPAddressZero } = require('../../dist/src/util/ipUtil'); describe('isValidServeHost', () => { test('returns true for localhost', () => { diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json new file mode 100644 index 0000000000..f7d8fe5e15 --- /dev/null +++ b/packages/cli/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig_base.json", + "exclude": ["node_modules", "**/*.test.ts", "dist", "**/*.test.js", "test/**/*.js", "**/__mocks__", "coverage"], + "references": [ + { "path": "../core/tsconfig.json" } + ], + "compilerOptions": { + "outDir": "./dist", + "allowJs": true, + } +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 77ea88399b..c34078c7eb 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -1,4 +1,7 @@ { "extends": "../../tsconfig_base.json", - "exclude": ["node_modules", "**/*.test.ts"] + "exclude": ["node_modules", "**/*.test.ts"], + "compilerOptions": { + "composite": true, + }, } diff --git a/tsconfig.json b/tsconfig.json index de8717f81b..dd96e2de98 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,10 @@ { "extends": "./tsconfig_base.json", - "exclude": ["**/node_modules", "**/*.test.ts"] + "exclude": ["**/node_modules", "**/*.test.ts"], + // Prevent just `tsc` from building files - always use `tsc --build` + "files": [], + "references": [ + { "path": "./packages/cli/tsconfig.json" }, + { "path": "./packages/core/tsconfig.json" } + ] } diff --git a/tsconfig_base.json b/tsconfig_base.json index 89b7e27cfd..18609eaf77 100644 --- a/tsconfig_base.json +++ b/tsconfig_base.json @@ -10,6 +10,7 @@ "declarationMap": true, "forceConsistentCasingInFileNames": true, "newLine": "lf", - "skipLibCheck": true + "skipLibCheck": true, + "resolveJsonModule": true } }