diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 60a7ab258..950d7aff3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,14 +20,15 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v6.0.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: submodules: recursive + persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v4.35.5 + uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 with: languages: 'javascript' - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4.35.5 + uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index cac5a1083..bc0145c3c 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v3.1.0 + uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0 with: github-token: '${{ secrets.GITHUB_TOKEN }}' - name: Enable auto-merge for Dependabot PRs diff --git a/.github/workflows/nodejs-test.yml b/.github/workflows/nodejs-test.yml index 1085811b1..c46ea92d3 100644 --- a/.github/workflows/nodejs-test.yml +++ b/.github/workflows/nodejs-test.yml @@ -18,11 +18,12 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: submodules: recursive + persist-credentials: false - name: Use Node.js ${{ matrix.node }} - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: lts/* cache: npm @@ -46,27 +47,31 @@ jobs: - lts/* steps: - - uses: actions/checkout@v6.0.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: submodules: recursive + persist-credentials: false - name: Use Node.js ${{ matrix.node }} - uses: actions/setup-node@v6.4.0 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ matrix.node }} cache: npm - run: npm ci - run: npm run build --if-present + - name: Run smoke tests + run: node scripts/smoke-test.js + - name: Run unit tests run: npm run unit-tests - if: matrix.node != env.NODE_COV + if: matrix.node != env.NODE_COV && matrix.node != 18 - name: Run unit tests with coverage run: npm run unit-tests-coverage if: matrix.node == env.NODE_COV - name: Run Coveralls - uses: coverallsapp/github-action@v2.3.7 + uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7 if: matrix.node == env.NODE_COV continue-on-error: true with: diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 7f99894b2..d67fc47ae 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -4,13 +4,17 @@ on: branches: - master +permissions: {} + jobs: deploy: name: Deploy to GitHub Pages runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-node@v6.4.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: lts/* cache: npm @@ -18,7 +22,7 @@ jobs: - name: Build docs run: npm run build:docs - name: Deploy - uses: peaceiris/actions-gh-pages@v4.1.0 + uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # v4.1.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: docs/build diff --git a/scripts/smoke-test.js b/scripts/smoke-test.js new file mode 100644 index 000000000..1f4d73dba --- /dev/null +++ b/scripts/smoke-test.js @@ -0,0 +1,105 @@ +/* eslint-disable no-console */ +import assert from 'node:assert/strict'; + +const checks = [ + { + name: 'parse5', + async run() { + const { parse, parseFragment, serialize, defaultTreeAdapter } = await import('parse5'); + const doc = parse('
hi
'); + assert.ok(doc, 'parse() returned a document'); + const fragment = parseFragment('hi
', { treeAdapter: adapter }); + assert.ok(doc, 'parse() with htmlparser2 adapter returned a document'); + }, + }, + { + name: 'parse5-sax-parser', + async run() { + const { SAXParser } = await import('parse5-sax-parser'); + const parser = new SAXParser(); + const tags = []; + parser.on('startTag', (tag) => tags.push(tag.tagName)); + await new Promise((resolve, reject) => { + parser.on('finish', resolve); + parser.on('error', reject); + parser.end('hello
'); + }); + assert.deepEqual(tags, ['p'], 'SAXParser emitted expected startTag'); + }, + }, + { + name: 'parse5-parser-stream', + async run() { + const { ParserStream } = await import('parse5-parser-stream'); + const stream = new ParserStream(); + await new Promise((resolve, reject) => { + stream.on('finish', resolve); + stream.on('error', reject); + stream.end('hello
'); + }); + assert.ok(stream.document, 'ParserStream produced a document'); + }, + }, + { + name: 'parse5-plain-text-conversion-stream', + async run() { + const { PlainTextConversionStream } = await import('parse5-plain-text-conversion-stream'); + const stream = new PlainTextConversionStream(); + await new Promise((resolve, reject) => { + stream.on('finish', resolve); + stream.on('error', reject); + stream.end('hello world'); + }); + assert.ok(stream.document, 'PlainTextConversionStream produced a document'); + }, + }, + { + name: 'parse5-html-rewriting-stream', + async run() { + const { RewritingStream } = await import('parse5-html-rewriting-stream'); + const stream = new RewritingStream(); + let output = ''; + stream.on('data', (chunk) => { + output += chunk; + }); + await new Promise((resolve, reject) => { + stream.on('finish', resolve); + stream.on('error', reject); + stream.end('hello
'); + }); + assert.equal(output, 'hello
', 'RewritingStream passed content through'); + }, + }, +]; + +let failures = 0; +for (const { name, run } of checks) { + try { + await run(); + console.log(`ok - ${name}`); + } catch (error) { + failures++; + console.error(`not ok - ${name}`); + console.error(error); + } +} + +if (failures > 0) { + console.error(`\n${failures} smoke test(s) failed`); + // eslint-disable-next-line unicorn-x/no-process-exit + process.exit(1); +} + +console.log(`\nAll ${checks.length} smoke tests passed`);