diff --git a/.eslintignore b/.eslintignore index f09ec93e09..0bba8b612d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ lib *.min.js +public diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 5cf305a804..0000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,78 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -name: "CodeQL" - -on: - push: - branches: [master] - pull_request: - # The branches below must be a subset of the branches above - branches: [master] - schedule: - - cron: '0 9 * * 3' - -permissions: - contents: read - -jobs: - analyze: - permissions: - actions: read # for github/codeql-action/init to get workflow details - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/autobuild to send a status report - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['javascript'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # âšī¸ Command-line programs to run using the OS shell. - # đ https://git.io/JvXDl - - # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 45313ef65a..ee5fa10bf0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,11 +9,11 @@ permissions: contents: read jobs: - Test: + UnitTests: strategy: matrix: # lowest verison here should also be in `engines` field - node_version: [16, 18, 'lts/*', '*'] + node_version: [18, "lts/*", "*"] runs-on: ubuntu-latest steps: - name: Checkout Code @@ -25,31 +25,14 @@ jobs: check-latest: true - name: Install Dependencies run: npm ci + - name: Build đī¸ + run: npm run build - name: Run Unit Tests đŠđŊâđģ run: npm run test:unit - name: Run Spec Tests đŠđŊâđģ run: npm run test:specs - - name: Run UMD Tests đŠđŊâđģ - run: npm run test:umd - - name: Run Types Tests đŠđŊâđģ - run: npm run test:types - - Lint: - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - name: Install Node - uses: actions/setup-node@v4 - with: - node-version: 'lts/*' - - name: Install Dependencies - run: npm ci - - name: Lint ⨠- run: npm run test:lint - Build: - name: Build and Test Types + OtherTests: runs-on: ubuntu-latest steps: - name: Checkout Code @@ -57,18 +40,22 @@ jobs: - name: Install Node uses: actions/setup-node@v4 with: - node-version: 'lts/*' + node-version: "lts/*" - name: Install Dependencies run: npm ci - name: Build đī¸ run: npm run build + - name: Run UMD Tests đŠđŊâđģ + run: npm run test:umd - name: Run Types Tests đŠđŊâđģ run: npm run test:types + - name: Lint ⨠+ run: npm run test:lint Release: permissions: contents: write - needs: [Test, Lint, Build] + needs: [UnitTests, OtherTests] if: | github.ref == 'refs/heads/master' && github.event.repository.fork == false @@ -79,7 +66,7 @@ jobs: - name: Install Node uses: actions/setup-node@v4 with: - node-version: 'lts/*' + node-version: "lts/*" - name: Install Dependencies run: npm ci - name: Build đī¸ diff --git a/.gitignore b/.gitignore index 233666f3ca..6dedd8e232 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store .vercel +.vscode node_modules/ test/compiled_tests public diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 46453cb8c5..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "cSpell.words": [ - "commonmark", - "markedjs", - "titleize", - "uglifyjs", - "vuln" - ] -} diff --git a/package-lock.json b/package-lock.json index 020f576c5b..5f5f82a35c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ }, "devDependencies": { "@arethetypeswrong/cli": "^0.13.1", - "@markedjs/html-differ": "^4.0.2", + "@markedjs/testutils": "9.1.5-0", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", "@semantic-release/commit-analyzer": "^11.1.0", @@ -32,9 +32,7 @@ "eslint-plugin-import": "^2.29.0", "eslint-plugin-n": "^16.2.0", "eslint-plugin-promise": "^6.1.1", - "front-matter": "^4.0.2", "highlight.js": "^11.9.0", - "jasmine": "^5.1.0", "markdown-it": "13.0.2", "marked-highlight": "^2.0.6", "marked-man": "^2.0.0", @@ -44,11 +42,10 @@ "semantic-release": "^22.0.7", "titleize": "^4.0.0", "ts-expect": "^1.3.0", - "ts-node": "^10.9.1", "typescript": "5.2.2" }, "engines": { - "node": ">= 16" + "node": ">= 18" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -258,28 +255,6 @@ "node": ">=0.1.90" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "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", @@ -369,102 +344,6 @@ "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -550,6 +429,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@markedjs/testutils": { + "version": "9.1.5-0", + "resolved": "https://registry.npmjs.org/@markedjs/testutils/-/testutils-9.1.5-0.tgz", + "integrity": "sha512-cQ//6dq/bZt4TxI2WJUVYxuxwaI7JMCa9InV0jSaBaKtyvWJlEFG+iAtCKWkpR7WxUiAZa9jWtxg2+g59gSOzA==", + "dev": true, + "dependencies": { + "@markedjs/html-differ": "^4.0.2", + "front-matter": "^4.0.2", + "marked": "^9.1.5", + "marked-repo": "https://github.com/markedjs/marked/tarball/v9.1.5" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -763,16 +654,6 @@ "@octokit/openapi-types": "^18.0.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/@pnpm/network.ca-file": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", @@ -1590,30 +1471,6 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, "node_modules/@types/estree": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", @@ -1632,13 +1489,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "dev": true, - "peer": true - }, "node_modules/@types/normalize-package-data": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz", @@ -1947,15 +1797,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", @@ -2039,12 +1880,6 @@ "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", "dev": true }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2577,12 +2412,6 @@ "node": ">=14" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -2885,12 +2714,6 @@ "readable-stream": "^2.0.2" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -3901,34 +3724,6 @@ "is-callable": "^1.1.3" } }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", - "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -4921,89 +4716,6 @@ "node": ">=10.13" } }, - "node_modules/jackspeak": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", - "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jasmine": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.1.0.tgz", - "integrity": "sha512-prmJlC1dbLhti4nE4XAPDWmfJesYO15sjGXVp7Cs7Ym5I9Xtwa/hUHxxJXjnpfLO72+ySttA0Ztf8g/RiVnUKw==", - "dev": true, - "dependencies": { - "glob": "^10.2.2", - "jasmine-core": "~5.1.0" - }, - "bin": { - "jasmine": "bin/jasmine.js" - } - }, - "node_modules/jasmine-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.1.0.tgz", - "integrity": "sha512-bFMMwpKuTZXCuGd51yClFobw5SOtad1kmdWnYO8dNwYV8i01Xj0C2+nyQpSKl1EKxiPfyd1ZgBl/rsusL3aS6w==", - "dev": true - }, - "node_modules/jasmine/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/jasmine/node_modules/glob": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.6.tgz", - "integrity": "sha512-U/rnDpXJGF414QQQZv5uVsabTVxMSwzS5CH0p3DRCIV6ownl4f7PzGnkGmvlum2wB+9RlJWJZ6ACU1INnBqiPA==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2", - "path-scurry": "^1.7.0" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jasmine/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/java-properties": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", @@ -5239,12 +4951,6 @@ "node": ">=10" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "node_modules/markdown-it": { "version": "13.0.2", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz", @@ -5274,9 +4980,9 @@ } }, "node_modules/marked": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.2.tgz", - "integrity": "sha512-qoKMJqK0w6vkLk8+KnKZAH6neUZSNaQqVZ/h2yZ9S7CbLuFHyS2viB0jnqcWF9UKjwsAbMrQtnQhdmdvOVOw9w==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.5.tgz", + "integrity": "sha512-14QG3shv8Kg/xc0Yh6TNkMj90wXH9mmldi5941I2OevfJ/FQAFLEwtwU2/FfgSAOMlWHrEukWSGQf8MiVYNG2A==", "dev": true, "bin": { "marked": "bin/marked.js" @@ -5307,6 +5013,20 @@ "marked-man": "bin/marked-man.js" } }, + "node_modules/marked-repo": { + "name": "marked", + "version": "9.1.5", + "resolved": "https://github.com/markedjs/marked/tarball/v9.1.5", + "integrity": "sha512-ESYdlhsf+u82SDP6V229Dms0llLuzqDPkym0eX8B4kUI3HTTtD0u1fPYmfk8vdsvTQOYAdCI6H/UuWrHFhCjcg==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 16" + } + }, "node_modules/marked-terminal": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.0.0.tgz", @@ -5424,15 +5144,6 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, - "node_modules/minipass": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", - "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -9278,31 +8989,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/path-scurry": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", - "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", - "dev": true, - "dependencies": { - "lru-cache": "^9.1.1", - "minipass": "^5.0.0 || ^6.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", - "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -10510,21 +10196,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string.prototype.repeat": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz", @@ -10588,19 +10259,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -10830,58 +10488,6 @@ "integrity": "sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ==", "dev": true }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/tsconfig-paths": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", @@ -11101,12 +10707,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -11211,57 +10811,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -11352,15 +10901,6 @@ "node": ">=12" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 35cb86014b..4b3263d3d8 100644 --- a/package.json +++ b/package.json @@ -50,8 +50,8 @@ "html" ], "devDependencies": { + "@markedjs/testutils": "9.1.5-0", "@arethetypeswrong/cli": "^0.13.1", - "@markedjs/html-differ": "^4.0.2", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", "@semantic-release/commit-analyzer": "^11.1.0", @@ -70,9 +70,7 @@ "eslint-plugin-import": "^2.29.0", "eslint-plugin-n": "^16.2.0", "eslint-plugin-promise": "^6.1.1", - "front-matter": "^4.0.2", "highlight.js": "^11.9.0", - "jasmine": "^5.1.0", "markdown-it": "13.0.2", "marked-highlight": "^2.0.6", "marked-man": "^2.0.0", @@ -82,14 +80,13 @@ "semantic-release": "^22.0.7", "titleize": "^4.0.0", "ts-expect": "^1.3.0", - "ts-node": "^10.9.1", "typescript": "5.2.2" }, "scripts": { - "test": "npm run build && cross-env NODE_OPTIONS=--loader=ts-node/esm jasmine --config=jasmine.json", + "test": "npm run build && npm run test:specs && npm run test:unit", "test:all": "npm test && npm run test:umd && npm run test:types && npm run test:lint", - "test:unit": "npm test -- test/unit/**/*-spec.js", - "test:specs": "npm test -- test/specs/**/*-spec.js", + "test:unit": "node --test --test-reporter=spec test/unit", + "test:specs": "node --test --test-reporter=spec test/run-spec-tests.js", "test:lint": "eslint .", "test:redos": "node test/recheck.js > vuln.js", "test:types": "tsc --project tsconfig-type-test.json && attw -P --exclude-entrypoints ./bin/marked ./marked.min.js", @@ -106,6 +103,6 @@ "rollup": "rollup -c rollup.config.js" }, "engines": { - "node": ">= 16" + "node": ">= 18" } } diff --git a/test/.eslintrc.json b/test/.eslintrc.json index 8926cc0d7f..3d143d1fb2 100644 --- a/test/.eslintrc.json +++ b/test/.eslintrc.json @@ -22,7 +22,6 @@ "no-var": "error" }, "env": { - "node": true, - "jasmine": true + "node": true } } diff --git a/test/bench.js b/test/bench.js index 355b6021cf..e878a333cc 100644 --- a/test/bench.js +++ b/test/bench.js @@ -1,7 +1,6 @@ -import { dirname, resolve } from 'path'; -import { fileURLToPath } from 'url'; -import { isEqual } from './helpers/html-differ.js'; -import { loadFiles } from './helpers/load.js'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { htmlIsEqual, getTests } from '@markedjs/testutils'; import { marked as cjsMarked } from '../lib/marked.cjs'; import { marked as esmMarked } from '../lib/marked.esm.js'; @@ -13,9 +12,9 @@ let marked; /** * Load specs */ -export function load() { +export async function load() { const dir = resolve(__dirname, './specs/commonmark'); - const sections = loadFiles(dir); + const sections = await getTests(dir); let specs = []; for (const section in sections) { @@ -30,7 +29,7 @@ export function load() { */ export async function runBench(options) { options = options || {}; - const specs = load(); + const specs = await load(); const tests = {}; // Non-GFM, Non-pedantic @@ -55,24 +54,24 @@ export async function runBench(options) { tests['esm marked'] = esmMarked.parse; try { - tests.commonmark = (await (async() => { + tests.commonmark = await (async() => { const { Parser, HtmlRenderer } = await import('commonmark'); const parser = new Parser(); const writer = new HtmlRenderer(); return function(text) { return writer.render(parser.parse(text)); }; - })()); + })(); } catch (e) { console.error('Could not bench commonmark. (Error: %s)', e.message); } try { - tests['markdown-it'] = (await (async() => { + tests['markdown-it'] = await (async() => { const MarkdownIt = (await import('markdown-it')).default; const md = new MarkdownIt(); return md.render.bind(md); - })()); + })(); } catch (e) { console.error('Could not bench markdown-it. (Error: %s)', e.message); } @@ -92,7 +91,11 @@ export async function bench(tests, specs) { console.log(); for (let i = 0; i < specs.length; i++) { const spec = specs[i]; - process.stdout.write(`${(i * 100 / specs.length).toFixed(1).padStart(5)}% ${i.toString().padStart(specs.length.toString().length)} of ${specs.length}\r`); + process.stdout.write( + `${((i * 100) / specs.length).toFixed(1).padStart(5)}% ${i + .toString() + .padStart(specs.length.toString().length)} of ${specs.length}\r` + ); for (const name in tests) { const test = tests[name]; const before = process.hrtime.bigint(); @@ -101,13 +104,18 @@ export async function bench(tests, specs) { } const after = process.hrtime.bigint(); stats[name].elapsed += after - before; - stats[name].correct += (await isEqual(spec.html, await test(spec.markdown)) ? 1 : 0); + stats[name].correct += (await htmlIsEqual( + spec.html, + await test(spec.markdown) + )) + ? 1 + : 0; } } for (const name in tests) { const ms = prettyElapsedTime(stats[name].elapsed); - const percent = (stats[name].correct / specs.length * 100).toFixed(2); + const percent = ((stats[name].correct / specs.length) * 100).toFixed(2); console.log(`${name} completed in ${ms}ms and passed ${percent}%`); } } @@ -121,7 +129,7 @@ function parseArg(argv) { const options = {}; const orphans = []; - function getarg() { + function getArg() { let arg = argv.shift(); if (arg.indexOf('--') === 0) { @@ -135,9 +143,11 @@ function parseArg(argv) { } else if (arg[0] === '-') { if (arg.length > 2) { // e.g. -abc - argv = arg.substring(1).split('').map(ch => { - return `-${ch}`; - }).concat(argv); + argv = arg + .substring(1) + .split('') + .map((ch) => `-${ch}`) + .concat(argv); arg = argv.shift(); } else { // e.g. -a @@ -152,7 +162,7 @@ function parseArg(argv) { const defaults = marked.getDefaults(); while (argv.length) { - const arg = getarg(); + const arg = getArg(); if (arg.indexOf('--') === 0) { const opt = camelize(arg.replace(/^--(no-)?/, '')); if (!defaults.hasOwnProperty(opt)) { @@ -160,13 +170,10 @@ function parseArg(argv) { } options.marked = options.marked || {}; if (arg.indexOf('--no-') === 0) { - options.marked[opt] = typeof defaults[opt] !== 'boolean' - ? null - : false; + options.marked[opt] = typeof defaults[opt] !== 'boolean' ? null : false; } else { - options.marked[opt] = typeof defaults[opt] !== 'boolean' - ? argv.shift() - : true; + options.marked[opt] = + typeof defaults[opt] !== 'boolean' ? argv.shift() : true; } } else { orphans.push(arg); @@ -176,7 +183,7 @@ function parseArg(argv) { if (orphans.length > 0) { console.error(); console.error('The following arguments are not used:'); - orphans.forEach(arg => console.error(` ${arg}`)); + orphans.forEach((arg) => console.error(` ${arg}`)); console.error(); } diff --git a/test/helpers/helpers.js b/test/helpers/helpers.js deleted file mode 100644 index 50515f79ec..0000000000 --- a/test/helpers/helpers.js +++ /dev/null @@ -1,56 +0,0 @@ -import { Marked, setOptions, getDefaults } from '../../src/marked.ts'; -import { isEqual, firstDiff } from './html-differ.js'; -import { strictEqual } from 'assert'; - -beforeEach(() => { - setOptions(getDefaults()); - setOptions({ silent: true }); - - jasmine.addAsyncMatchers({ - toRender: () => { - return { - compare: async(spec, expected) => { - const marked = new Marked(); - const result = {}; - const actual = marked.parse(spec.markdown, spec.options); - result.pass = await isEqual(expected, actual); - - if (result.pass) { - result.message = `${spec.markdown}\n------\n\nExpected: Should Fail`; - } else { - const diff = await firstDiff(actual, expected); - result.message = `Expected: ${diff.expected}\n Actual: ${diff.actual}`; - } - return result; - } - }; - }, - toEqualHtml: () => { - return { - compare: async(actual, expected) => { - const result = {}; - result.pass = await isEqual(expected, actual); - - if (result.pass) { - result.message = `Expected '${actual}' not to equal '${expected}'`; - } else { - const diff = await firstDiff(actual, expected); - result.message = `Expected: ${diff.expected}\n Actual: ${diff.actual}`; - } - return result; - } - }; - }, - toRenderExact: () => ({ - compare: async(spec, expected) => { - const marked = new Marked(); - const result = {}; - const actual = marked.parse(spec.markdown, spec.options); - - result.pass = strictEqual(expected, actual) === undefined; - - return result; - } - }) - }); -}); diff --git a/test/helpers/html-differ.js b/test/helpers/html-differ.js deleted file mode 100644 index d8176f4fe8..0000000000 --- a/test/helpers/html-differ.js +++ /dev/null @@ -1,38 +0,0 @@ -import { HtmlDiffer } from '@markedjs/html-differ'; -const htmlDiffer = new HtmlDiffer({ - ignoreSelfClosingSlash: true, - ignoreComments: false -}); - -export const isEqual = htmlDiffer.isEqual.bind(htmlDiffer); -export async function firstDiff(actual, expected, padding) { - padding = padding || 30; - const diffHtml = await htmlDiffer.diffHtml(actual, expected); - const result = diffHtml.reduce((obj, diff) => { - if (diff.added) { - if (obj.firstIndex === null) { - obj.firstIndex = obj.expected.length; - } - obj.expected += diff.value; - } else if (diff.removed) { - if (obj.firstIndex === null) { - obj.firstIndex = obj.actual.length; - } - obj.actual += diff.value; - } else { - obj.actual += diff.value; - obj.expected += diff.value; - } - - return obj; - }, { - firstIndex: null, - actual: '', - expected: '' - }); - - return { - actual: result.actual.substring(result.firstIndex - padding, result.firstIndex + padding), - expected: result.expected.substring(result.firstIndex - padding, result.firstIndex + padding) - }; -} diff --git a/test/helpers/load.js b/test/helpers/load.js deleted file mode 100644 index bdae88e6dd..0000000000 --- a/test/helpers/load.js +++ /dev/null @@ -1,93 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import fm from 'front-matter'; -import { createRequire } from 'module'; - -const require = createRequire(import.meta.url); - -export function outputCompletionTable(title, specs) { - let longestName = 0; - let maxSpecs = 0; - - for (const section in specs) { - longestName = Math.max(section.length, longestName); - maxSpecs = Math.max(specs[section].total, maxSpecs); - } - - const maxSpecsLen = ('' + maxSpecs).length; - const spaces = maxSpecsLen * 2 + longestName + 11; - - console.log('-'.padEnd(spaces + 4, '-')); - console.log(`| ${title.padStart(Math.ceil((spaces + title.length) / 2)).padEnd(spaces)} |`); - console.log(`| ${' '.padEnd(spaces)} |`); - for (const section in specs) { - console.log(`| ${section.padEnd(longestName)} ${('' + specs[section].pass).padStart(maxSpecsLen)} of ${('' + specs[section].total).padStart(maxSpecsLen)} ${(100 * specs[section].pass / specs[section].total).toFixed().padStart(4)}% |`); - } - console.log('-'.padEnd(spaces + 4, '-')); - console.log(); -} - -export function loadFiles(dir) { - const files = fs.readdirSync(dir); - - return files.reduce((obj, file) => { - const ext = path.extname(file); - const name = path.basename(file, ext); - const absFile = path.join(dir, file); - let specs; - - switch (ext) { - case '.md': { - const content = fm(fs.readFileSync(absFile, 'utf8')); - const skip = content.attributes.skip; - delete content.attributes.skip; - const only = content.attributes.only; - delete content.attributes.only; - specs = [{ - section: name, - markdown: content.body, - html: fs.readFileSync(absFile.replace(/[^.]+$/, 'html'), 'utf8'), - options: content.attributes, - only, - skip - }]; - break; - } - case '.cjs': - case '.json': { - try { - specs = require(absFile); - } catch (err) { - console.log(`Error loading ${absFile}`); - throw err; - } - if (!Array.isArray(specs)) { - specs = [specs]; - } - break; - } - default: - return obj; - } - - for (let i = 0; i < specs.length; i++) { - const spec = specs[i]; - if (!spec.section) { - spec.section = `${name}[${i}]`; - } - if (!obj[spec.section]) { - obj[spec.section] = { - total: 0, - pass: 0, - specs: [] - }; - } - - obj[spec.section].total++; - obj[spec.section].pass += spec.shouldFail ? 0 : 1; - obj[spec.section].specs.push(spec); - } - - return obj; - }, {}); -} diff --git a/test/run-spec-tests.js b/test/run-spec-tests.js new file mode 100644 index 0000000000..d42bfcb9f8 --- /dev/null +++ b/test/run-spec-tests.js @@ -0,0 +1,50 @@ +import { Marked } from '../lib/marked.esm.js'; +import { getTests, runTests, outputCompletionTable } from '@markedjs/testutils'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +function parse(markdown, options) { + const marked = new Marked(options); + return marked.parse(markdown); +} + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const [commonMarkTests, gfmTests, newTests, originalTests, redosTests] = + await getTests([ + resolve(__dirname, './specs/commonmark'), + resolve(__dirname, './specs/gfm'), + resolve(__dirname, './specs/new'), + resolve(__dirname, './specs/original'), + resolve(__dirname, './specs/redos') + ]); + +outputCompletionTable('CommonMark', commonMarkTests); +runTests({ + tests: commonMarkTests, + parse, + defaultMarkedOptions: { gfm: false, pedantic: false } +}); + +outputCompletionTable('GFM', gfmTests); +runTests({ + tests: gfmTests, + parse, + defaultMarkedOptions: { gfm: true, pedantic: false } +}); + +runTests({ + tests: newTests, + parse +}); + +runTests({ + tests: originalTests, + parse, + defaultMarkedOptions: { gfm: false, pedantic: true } +}); + +runTests({ + tests: redosTests, + parse +}); diff --git a/test/specs/gfm/gfm.0.29.json b/test/specs/gfm/gfm.0.29.json index 50c4ac8d09..9d403a9a8b 100644 --- a/test/specs/gfm/gfm.0.29.json +++ b/test/specs/gfm/gfm.0.29.json @@ -61,8 +61,8 @@ }, { "section": "[extension] Strikethrough", - "html": "
Hi Hello, world!
Hi Hello, there world!
This will ~~~not~~~ strike.
", + "markdown": "This will ~~~not~~~ strike.", + "example": 493 + }, { "section": "[extension] Autolinks", "html": "", "markdown": "www.commonmark.org", - "example": 621 + "example": 622 }, { "section": "[extension] Autolinks", "html": "Visit www.commonmark.org/help for more information.
", "markdown": "Visit www.commonmark.org/help for more information.", - "example": 622 + "example": 623 }, { "section": "[extension] Autolinks", "html": "Visit www.commonmark.org.
\nVisit www.commonmark.org/a.b.
", "markdown": "Visit www.commonmark.org.\n\nVisit www.commonmark.org/a.b.", - "example": 623 + "example": 624 }, { "section": "[extension] Autolinks", "html": "www.google.com/search?q=Markup+(business)
\nwww.google.com/search?q=Markup+(business)))
\n(www.google.com/search?q=Markup+(business))
\n(www.google.com/search?q=Markup+(business)
", "markdown": "www.google.com/search?q=Markup+(business)\n\nwww.google.com/search?q=Markup+(business)))\n\n(www.google.com/search?q=Markup+(business))\n\n(www.google.com/search?q=Markup+(business)", - "example": 624 + "example": 625 }, { "section": "[extension] Autolinks", "html": "www.google.com/search?q=(business))+ok
", "markdown": "www.google.com/search?q=(business))+ok", - "example": 625 + "example": 626 }, { "section": "[extension] Autolinks", "html": "www.google.com/search?q=commonmark&hl=en
\nwww.google.com/search?q=commonmark&hl;
", "markdown": "www.google.com/search?q=commonmark&hl=en\n\nwww.google.com/search?q=commonmark&hl;", - "example": 626 + "example": 627 }, { "section": "[extension] Autolinks", "html": "", "markdown": "www.commonmark.org/he(Visit https://encrypted.google.com/search?q=Markup+(business))
", "markdown": "http://commonmark.org\n\n(Visit https://encrypted.google.com/search?q=Markup+(business))", - "example": 628 + "example": 629 }, { "section": "[extension] Autolinks", "html": "", "markdown": "foo@bar.baz", - "example": 629 + "example": 630 }, { "section": "[extension] Autolinks", "html": "hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.
", "markdown": "hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.", - "example": 630 + "example": 631 }, { "section": "[extension] Autolinks", "html": "\n\na.b-c_d@a.b-
\na.b-c_d@a.b_
", "markdown": "a.b-c_d@a.b\n\na.b-c_d@a.b.\n\na.b-c_d@a.b-\n\na.b-c_d@a.b_", - "example": 631 + "example": 632 + }, + { + "section": "[extension] Autolinks", + "html": "\n\n\n\nmailto:a.b-c_d@a.b-
\nmailto:a.b-c_d@a.b_
\n\n", + "markdown": "mailto:foo@bar.baz\n\nmailto:a.b-c_d@a.b\n\nmailto:a.b-c_d@a.b.\n\nmailto:a.b-c_d@a.b/\n\nmailto:a.b-c_d@a.b-\n\nmailto:a.b-c_d@a.b_\n\nxmpp:foo@bar.baz\n\nxmpp:foo@bar.baz.", + "example": 633, + "shouldFail": true + }, + { + "section": "[extension] Autolinks", + "html": "\n\n", + "markdown": "xmpp:foo@bar.baz/txt\n\nxmpp:foo@bar.baz/txt@bin\n\nxmpp:foo@bar.baz/txt@bin.com", + "example": 634, + "shouldFail": true + }, + { + "section": "[extension] Autolinks", + "html": "", + "markdown": "xmpp:foo@bar.baz/txt/bin", + "example": 635, + "shouldFail": true }, { "section": "[extension] Disallowed Raw HTML", "html": "<title> <style>
\n\n <xmp> is disallowed. <XMP> is also disallowed.\n", "markdown": "