From 91c89deb49da33c23e2456b63d951f00f604120d Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Tue, 21 Apr 2026 22:22:46 -0400 Subject: [PATCH 01/28] Add design spec for oxlint migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In-place rewrite of the action-eslint composite action to run oxlint through reviewdog instead of eslint. Captures input renames, the new oxlint→rdjsonl converter, file additions/deletions, and testing plan. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-04-21-oxlint-migration-design.md | 231 ++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-21-oxlint-migration-design.md diff --git a/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md b/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md new file mode 100644 index 0000000..d6b6810 --- /dev/null +++ b/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md @@ -0,0 +1,231 @@ +# Design: Migrate `action-eslint` to oxlint + +**Status:** approved (spec) +**Date:** 2026-04-21 + +## Summary + +In-place rewrite of this composite GitHub Action to run [oxlint](https://oxc.rs/docs/guide/usage/linter.html) with reviewdog instead of eslint. All eslint-specific code, inputs, tests, documentation, and the bundled `eslint-formatter-rdjson` are removed. This is a breaking change for existing consumers; there is no backward-compatibility shim. + +## Motivation + +Users of the action want to run oxlint — a faster Rust-based linter — through the same reviewdog integration this action provides. Rather than maintain two parallel actions, the repo is being repurposed. + +## Non-goals + +- Supporting both eslint and oxlint from the same action. +- Preserving input names for backward compatibility. +- Renaming the GitHub repository itself (that is an operational step outside this design). +- Releasing / version-tagging (handled by release tooling). + +## Architecture + +Composite action with a single bash entrypoint (`script.sh`) invoked by `action.yml`. The entrypoint: + +1. Installs reviewdog from its release script (unchanged from current behavior). +2. Verifies oxlint is available via `npx --no-install -c 'oxlint --version'`; if absent, runs `npm install` to pick up the consumer's declared `devDependencies`. +3. Pipes `oxlint --format=json ` through a small Node converter (`oxlint-to-rdjsonl.js`) into `reviewdog -f=rdjsonl`. + +The converter is the only new moving part. Everything else is renames and deletions. + +## Components + +### `action.yml` + +**Renamed inputs:** +- `eslint_flags` → `oxlint_flags` (default `.`) +- `tool_name` default: `eslint` → `oxlint` + +**Removed inputs:** +- `node_options` — oxlint is a Rust binary; `NODE_OPTIONS` has no effect. Dropping the input is cleaner than keeping a no-op. + +**Unchanged inputs:** +`github_token`, `level`, `reporter`, `filter_mode`, `fail_level`, `fail_on_error`, `reviewdog_flags`, `workdir`. + +**Env plumbing:** `INPUT_ESLINT_FLAGS` → `INPUT_OXLINT_FLAGS`. `NODE_OPTIONS` removed from `env:`. + +**Metadata:** `name` and `description` reworded for oxlint. Branding (`alert-octagon`, `blue`) unchanged. + +### `script.sh` + +Mirror of current structure, with eslint calls replaced: + +```sh +#!/bin/sh +cd "${GITHUB_WORKSPACE}/${INPUT_WORKDIR}" || exit 1 + +TEMP_PATH="$(mktemp -d)" +PATH="${TEMP_PATH}:$PATH" +export REVIEWDOG_GITHUB_API_TOKEN="${INPUT_GITHUB_TOKEN}" + +echo '::group::🐶 Installing reviewdog ...' +curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s -- -b "${TEMP_PATH}" "${REVIEWDOG_VERSION}" 2>&1 +echo '::endgroup::' + +npx --no-install -c 'oxlint --version' 2>/dev/null +if [ $? -ne 0 ]; then + echo '::group:: Running `npm install` to install oxlint ...' + set -e + npm install + set +e + echo '::endgroup::' +fi + +echo "oxlint version:$(npx --no-install -c 'oxlint --version')" + +echo '::group:: Running oxlint with reviewdog 🐶 ...' +npx --no-install -c "oxlint --format=json ${INPUT_OXLINT_FLAGS:-.}" \ + | node "${GITHUB_ACTION_PATH}/oxlint-to-rdjsonl.js" \ + | reviewdog -f=rdjsonl \ + -name="${INPUT_TOOL_NAME}" \ + -reporter="${INPUT_REPORTER:-github-pr-review}" \ + -filter-mode="${INPUT_FILTER_MODE}" \ + -fail-level="${INPUT_FAIL_LEVEL}" \ + -fail-on-error="${INPUT_FAIL_ON_ERROR}" \ + -level="${INPUT_LEVEL}" \ + ${INPUT_REVIEWDOG_FLAGS} + +reviewdog_rc=$? +echo '::endgroup::' +exit $reviewdog_rc +``` + +Pipefail is not enabled (matches current behavior). Reviewdog's exit code is the action's exit code. + +### `oxlint-to-rdjsonl.js` + +Stdin-to-stdout converter. Node built-ins only; no devDeps. + +**Input:** oxlint's JSON output — a JSON array of diagnostics rendered by miette's `JSONReportHandler`: + +```json +{ + "message": "...", + "code": "eslint(no-unused-vars)", + "severity": "error" | "warning" | "advice", + "url": "https://oxc.rs/...", + "help": "...", + "filename": "path/to/file.js", + "labels": [{ "span": { "offset": 123, "length": 5 } }] +} +``` + +**Output:** rdjsonl — one JSON object per line: + +```json +{"message":"...","location":{"path":"path/to/file.js","range":{"start":{"line":10,"column":5},"end":{"line":10,"column":10}}},"severity":"ERROR","code":{"value":"no-unused-vars","url":"https://oxc.rs/..."},"source":{"name":"oxlint","url":"https://oxc.rs/docs/guide/usage/linter.html"}} +``` + +**Transform rules:** + +| Input field | Output field | Notes | +|---|---|---| +| `message` | `message` | Pass through | +| `severity` | `severity` | `error` → `ERROR`, `warning` → `WARNING`, `advice` → `INFO` | +| `code` | `code.value` | Strip `plugin(...)` wrapper: `eslint(no-unused-vars)` → `no-unused-vars`. Bare code passed through. Missing code → omit `code` entirely. | +| `url` | `code.url` | Pass through if present; omit otherwise | +| `filename` | `location.path` | Pass through | +| `labels[0].span` | `location.range` | Convert byte offsets to 1-based line + 1-based column by reading the source file | +| (literal) | `source.name` / `source.url` | Always `"oxlint"` and oxlint docs URL | + +**Byte-offset → line/column conversion:** +- Read the file referenced by `filename` as a UTF-8 `Buffer`, once per run, cached. +- Walk bytes: increment line on `\n` (byte `0x0A`), reset column to 1 after newline, increment column per byte otherwise. +- Line and column are both 1-based UTF-8 byte positions. This matches the rdjson output emitted by the existing `eslint-formatter-rdjson` (which converts eslint's UTF-16 columns to UTF-8 bytes) — reviewdog's expected encoding on this action's wire format. +- Because oxlint's `offset` is already a UTF-8 byte offset (miette writes `label.offset()` which is source byte offset), no UTF-16 conversion is involved. +- `range.start` = position at `offset`. `range.end` = position at `offset + length`. + +**Edge cases:** +- Empty `labels` array or absent `filename`: emit diagnostic with `location.path` (if available) but no `range`. Reviewdog accepts file-level diagnostics. +- Multiple labels: use first only. Matches existing formatter behavior (one location per message). +- File read failure (e.g., file deleted between lint and convert): emit file-level diagnostic without `range`, continue. +- Invalid JSON on stdin: print error to stderr, exit 1. Silent drop would mask a broken lint run as "no issues." +- Empty diagnostic array: zero output lines, exit 0. + +### `oxlint-to-rdjsonl.test.js` + +Node's built-in `node:test` runner. No devDeps. + +**Cases:** +- Severity mapping across all three values. +- Rule code extraction: `plugin(rule)`, bare, missing. +- URL pass-through and absence. +- Offset → line/column: single-line, multi-line, offset at newline boundary, offset at EOF, UTF-8 multi-byte character. +- Empty `labels` → file-level diagnostic, no `range`. +- Multiple `labels` → first wins. +- File-read failure → file-level diagnostic, no crash. +- Invalid JSON on stdin → exit 1, message on stderr. +- Empty diagnostic list → zero lines, exit 0. + +Fixtures: small inline JSON + source files under `testdata/converter/` (`simple.js`, `multiline.js`, `utf8.js`). + +Run: `node --test oxlint-to-rdjsonl.test.js`. + +### `testdata/` and `test-subproject/` + +- `testdata/*.js`: adjust content so oxlint's default ruleset fires at least one diagnostic per file (validates the pipeline without binding tests to oxlint rule internals). +- `.oxlintrc.json` at repo root to pin rules for deterministic test output. +- `test-subproject/package.json`: swap `eslint` dep for `oxlint`, regenerate lockfile. +- `test-subproject/.eslintrc.js`: delete. The subproject relies on oxlint's default rules. If the end-to-end test needs a specific rule fired, a `test-subproject/.oxlintrc.json` is added alongside (decided during implementation when writing the fixture). +- `testdata/converter/*.js`: new fixtures for converter unit tests. + +### `.github/workflows/` + +Audited during implementation. Any workflow exercising the action end-to-end will install `oxlint` instead of `eslint`. Workflow names are preserved where possible to keep README badges valid. + +### `README.md` + +Full rewrite: + +- Title: "GitHub Action: Run oxlint with reviewdog" +- Intro links oxlint docs. +- Prereq: `npm install -D oxlint`. +- Config references `.oxlintrc.json`. +- Inputs section reflects the Section 4 changes. +- Example YAML updated throughout (`oxlint_flags`, `tool_name: oxlint`). +- Screenshot URLs left as placeholders; implementation PR notes they need re-capture. +- Top of file: short "Migrating from action-eslint" callout listing renamed/removed inputs. + +## Files + +**Add:** +- `oxlint-to-rdjsonl.js` +- `oxlint-to-rdjsonl.test.js` +- `.oxlintrc.json` +- `testdata/converter/{simple,multiline,utf8}.js` + +**Modify:** +- `action.yml` +- `script.sh` +- `README.md` +- `testdata/*.js` +- `test-subproject/package.json` (+ regenerate `test-subproject/package-lock.json`) +- `.github/workflows/*.yml` (audit first) + +**Delete:** +- `eslint-formatter-rdjson/` (entire directory) +- `.eslintrc.js` +- `package.json` (repo root) +- `package-lock.json` (repo root) +- `test-subproject/.eslintrc.js` + +## Error handling summary + +| Failure | Behavior | +|---|---| +| oxlint not installed | `npm install` in consumer project (existing fallback pattern) | +| oxlint emits invalid JSON | Converter exits 1, stderr explains; action fails loudly | +| Source file unreadable | File-level diagnostic without `range`, pipeline continues | +| Reviewdog non-zero exit | Propagated as action exit code (unchanged) | + +## Out of scope + +- Backward-compat shim for `eslint_flags` / `node_options`. +- Snapshot-testing reviewdog's rendered output. +- Running oxlint's own test suite. +- Git tagging or release automation. +- Repository rename on GitHub. + +## Open questions + +None. All design decisions resolved during brainstorming. From dc3fbc110d67f1b0a26adc018dc05b1ba08ba3e6 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:23:13 -0400 Subject: [PATCH 02/28] Add implementation plan for oxlint migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Twenty bite-sized tasks covering: TDD of the JSON→rdjsonl converter, action.yml/script.sh rewrite, deletion of the bundled eslint formatter and repo-root eslint detritus, testdata/test-subproject fixture updates, workflow audit (test.yml rewrite, reviewdog.yml rename, npm-publish.yml deletion), and README rewrite with migration callout. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../plans/2026-04-22-oxlint-migration.md | 1479 +++++++++++++++++ 1 file changed, 1479 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-22-oxlint-migration.md diff --git a/docs/superpowers/plans/2026-04-22-oxlint-migration.md b/docs/superpowers/plans/2026-04-22-oxlint-migration.md new file mode 100644 index 0000000..c52a239 --- /dev/null +++ b/docs/superpowers/plans/2026-04-22-oxlint-migration.md @@ -0,0 +1,1479 @@ +# Oxlint Migration Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Repurpose this composite GitHub Action to run [oxlint](https://oxc.rs/docs/guide/usage/linter.html) through reviewdog instead of eslint. Breaking change; no backward-compat shim. + +**Architecture:** The action is a composite action. `action.yml` declares inputs and forwards them as `INPUT_*` env vars to `script.sh`, which installs reviewdog, runs `oxlint --format=json`, pipes the output through a new Node-based converter (`oxlint-to-rdjsonl.js`), then into `reviewdog -f=rdjsonl`. The converter is the only genuinely new code; everything else is renames, edits, and deletions. + +**Tech Stack:** Bash (`script.sh`), GitHub composite action YAML, Node.js (converter + tests, using `node:test` — no devDeps), oxlint (consumer-installed). + +**Spec:** `docs/superpowers/specs/2026-04-21-oxlint-migration-design.md`. + +--- + +## File Structure + +**Created:** +- `oxlint-to-rdjsonl.js` — pure-function module + CLI entrypoint. Exports `mapSeverity`, `extractRuleCode`, `positionFromOffset`, `convertDiagnostic`, `convert`, `main`. If invoked directly (`node oxlint-to-rdjsonl.js`), reads JSON from stdin, writes rdjsonl to stdout. +- `oxlint-to-rdjsonl.test.js` — uses Node's built-in `node:test` runner; imports the above module and tests each pure function plus one end-to-end test that spawns the CLI. +- `.oxlintrc.json` — repo-root oxlint config pinning rules so test-fixture output is deterministic. +- `testdata/converter/simple.js`, `testdata/converter/multiline.js`, `testdata/converter/utf8.js` — fixtures for converter unit tests (NOT linted by oxlint; they're just text files read by the converter during tests). + +**Modified:** +- `action.yml` — input renames, removals, metadata rewrite. +- `script.sh` — eslint→oxlint invocation; drop custom formatter path; pipe through converter. +- `README.md` — full rewrite for oxlint. +- `testdata/test.js`, `testdata/error.js`, `testdata/empty.js` — tweak to fire oxlint rules deterministically. +- `test-subproject/package.json` — swap eslint family for `oxlint` devDep; regenerate lockfile. +- `test-subproject/sub-testdata/*.js` — same deterministic tweaks. +- `.github/workflows/test.yml` — run `node --test` on the converter instead of the old formatter's shell test. +- `.github/workflows/reviewdog.yml` — rename `eslint_flags` → `oxlint_flags`, rename `tool_name` values, install `oxlint` before invoking the action. + +**Deleted:** +- `eslint-formatter-rdjson/` (entire directory, including `index.js`, `package.json`, tests, testdata). +- `.eslintrc.js` at repo root. +- `package.json` and `package-lock.json` at repo root. +- `test-subproject/.eslintrc.js`. +- `.github/workflows/npm-publish.yml` — publishes `eslint-formatter-rdjson` to npm; the new action has no npm package to publish. + +**Unchanged:** +- `.github/workflows/depup.yml`, `.github/workflows/release.yml` — version-bumping infrastructure operates on `action.yml`'s `REVIEWDOG_VERSION` and git tags; agnostic to what the action does. +- `.gitignore`, `LICENSE`. + +--- + +## Task 1: Scaffold converter module with severity-mapping test + +**Files:** +- Create: `oxlint-to-rdjsonl.js` +- Create: `oxlint-to-rdjsonl.test.js` + +- [ ] **Step 1.1: Write the failing test** + +Create `oxlint-to-rdjsonl.test.js` with: + +```js +const test = require('node:test'); +const assert = require('node:assert/strict'); +const { mapSeverity } = require('./oxlint-to-rdjsonl'); + +test('mapSeverity: error -> ERROR', () => { + assert.equal(mapSeverity('error'), 'ERROR'); +}); + +test('mapSeverity: warning -> WARNING', () => { + assert.equal(mapSeverity('warning'), 'WARNING'); +}); + +test('mapSeverity: advice -> INFO', () => { + assert.equal(mapSeverity('advice'), 'INFO'); +}); + +test('mapSeverity: unknown -> UNKNOWN_SEVERITY', () => { + assert.equal(mapSeverity('bogus'), 'UNKNOWN_SEVERITY'); +}); +``` + +- [ ] **Step 1.2: Run test to verify it fails** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: FAIL — `Cannot find module './oxlint-to-rdjsonl'`. + +- [ ] **Step 1.3: Write minimal implementation** + +Create `oxlint-to-rdjsonl.js`: + +```js +'use strict'; + +function mapSeverity(s) { + if (s === 'error') return 'ERROR'; + if (s === 'warning') return 'WARNING'; + if (s === 'advice') return 'INFO'; + return 'UNKNOWN_SEVERITY'; +} + +module.exports = { mapSeverity }; +``` + +- [ ] **Step 1.4: Run test to verify it passes** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: PASS — all four subtests pass. + +- [ ] **Step 1.5: Commit** + +```bash +git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js +git commit -m "feat(converter): scaffold module with severity mapping" +``` + +--- + +## Task 2: Rule code extraction + +**Files:** +- Modify: `oxlint-to-rdjsonl.test.js` (append) +- Modify: `oxlint-to-rdjsonl.js` + +- [ ] **Step 2.1: Append failing tests** + +Append to `oxlint-to-rdjsonl.test.js`: + +```js +const { extractRuleCode } = require('./oxlint-to-rdjsonl'); + +test('extractRuleCode: plugin(rule) -> rule', () => { + assert.equal(extractRuleCode('eslint(no-unused-vars)'), 'no-unused-vars'); +}); + +test('extractRuleCode: nested parens preserved in rule', () => { + assert.equal(extractRuleCode('typescript(no-empty-interface)'), 'no-empty-interface'); +}); + +test('extractRuleCode: bare code passed through', () => { + assert.equal(extractRuleCode('no-unused-vars'), 'no-unused-vars'); +}); + +test('extractRuleCode: undefined -> undefined', () => { + assert.equal(extractRuleCode(undefined), undefined); +}); + +test('extractRuleCode: empty string -> empty string', () => { + assert.equal(extractRuleCode(''), ''); +}); +``` + +- [ ] **Step 2.2: Run test to verify it fails** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: FAIL — `extractRuleCode is not a function`. + +- [ ] **Step 2.3: Implement** + +Add to `oxlint-to-rdjsonl.js`: + +```js +function extractRuleCode(code) { + if (code === undefined || code === null) return undefined; + const match = /^[^(]+\(([^)]+)\)$/.exec(code); + return match ? match[1] : code; +} +``` + +And update `module.exports`: + +```js +module.exports = { mapSeverity, extractRuleCode }; +``` + +- [ ] **Step 2.4: Run test to verify it passes** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: PASS — all subtests from Tasks 1 and 2 pass. + +- [ ] **Step 2.5: Commit** + +```bash +git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js +git commit -m "feat(converter): extract rule code from plugin(rule) format" +``` + +--- + +## Task 3: Byte-offset → line/column — single line + +**Files:** +- Modify: `oxlint-to-rdjsonl.test.js` +- Modify: `oxlint-to-rdjsonl.js` + +- [ ] **Step 3.1: Append failing tests** + +Append to `oxlint-to-rdjsonl.test.js`: + +```js +const { positionFromOffset } = require('./oxlint-to-rdjsonl'); + +test('positionFromOffset: offset 0 -> line 1, column 1', () => { + const buf = Buffer.from('abc'); + assert.deepEqual(positionFromOffset(buf, 0), { line: 1, column: 1 }); +}); + +test('positionFromOffset: middle of first line', () => { + const buf = Buffer.from('abcdef'); + assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); +}); + +test('positionFromOffset: end-of-single-line buffer', () => { + const buf = Buffer.from('abc'); + assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); +}); +``` + +- [ ] **Step 3.2: Run test to verify it fails** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: FAIL — `positionFromOffset is not a function`. + +- [ ] **Step 3.3: Implement** + +Add to `oxlint-to-rdjsonl.js`: + +```js +// Convert a UTF-8 byte offset into {line, column}, both 1-based. +// column is 1-based UTF-8 byte position within its line (what reviewdog expects). +function positionFromOffset(buffer, offset) { + let line = 1; + let column = 1; + const end = Math.min(offset, buffer.length); + for (let i = 0; i < end; i++) { + if (buffer[i] === 0x0A) { + line++; + column = 1; + } else { + column++; + } + } + return { line, column }; +} +``` + +Update `module.exports`: + +```js +module.exports = { mapSeverity, extractRuleCode, positionFromOffset }; +``` + +- [ ] **Step 3.4: Run test to verify it passes** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: PASS — all tests from Tasks 1–3. + +- [ ] **Step 3.5: Commit** + +```bash +git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js +git commit -m "feat(converter): byte-offset to line/column for single-line input" +``` + +--- + +## Task 4: Byte-offset → line/column — multi-line and boundaries + +**Files:** +- Modify: `oxlint-to-rdjsonl.test.js` + +- [ ] **Step 4.1: Append failing tests** + +Append to `oxlint-to-rdjsonl.test.js`: + +```js +test('positionFromOffset: offset on a later line', () => { + // "abc\ndef" — offset 4 is 'd' on line 2 + const buf = Buffer.from('abc\ndef'); + assert.deepEqual(positionFromOffset(buf, 4), { line: 2, column: 1 }); +}); + +test('positionFromOffset: offset at newline is end of previous line', () => { + // "abc\ndef" — offset 3 is the '\n' byte itself; column counts it as end-of-line 1 + const buf = Buffer.from('abc\ndef'); + assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); +}); + +test('positionFromOffset: across multiple newlines', () => { + const buf = Buffer.from('a\nb\nc'); + // offset 4 = 'c' on line 3, column 1 + assert.deepEqual(positionFromOffset(buf, 4), { line: 3, column: 1 }); +}); + +test('positionFromOffset: offset past end clamps to buffer length', () => { + const buf = Buffer.from('abc'); + assert.deepEqual(positionFromOffset(buf, 99), { line: 1, column: 4 }); +}); + +test('positionFromOffset: UTF-8 multi-byte char — columns are byte positions', () => { + // '🐶' is 4 UTF-8 bytes (F0 9F 90 B6). Source: "a🐶b" + const buf = Buffer.from('a🐶b'); + assert.equal(buf.length, 6); + // offset 5 is 'b' — column 6 (1-based bytes) + assert.deepEqual(positionFromOffset(buf, 5), { line: 1, column: 6 }); +}); +``` + +- [ ] **Step 4.2: Run test** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: PASS — the implementation from Task 3 already handles all of these. These tests are regression coverage; if any fail, the implementation must be fixed to make them pass before committing. + +- [ ] **Step 4.3: Commit** + +```bash +git add oxlint-to-rdjsonl.test.js +git commit -m "test(converter): cover multi-line, boundary, and UTF-8 offset cases" +``` + +--- + +## Task 5: `convertDiagnostic` for a well-formed input + +**Files:** +- Modify: `oxlint-to-rdjsonl.test.js` +- Modify: `oxlint-to-rdjsonl.js` + +- [ ] **Step 5.1: Append failing test** + +Append to `oxlint-to-rdjsonl.test.js`: + +```js +const { convertDiagnostic } = require('./oxlint-to-rdjsonl'); + +test('convertDiagnostic: full mapping of a typical diagnostic', () => { + const diagnostic = { + message: 'Unused variable', + code: 'eslint(no-unused-vars)', + severity: 'error', + url: 'https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-unused-vars.html', + filename: 'src/foo.js', + labels: [{ span: { offset: 4, length: 3 } }], + }; + // source file: "var abc = 1;" + const fileReader = (path) => { + assert.equal(path, 'src/foo.js'); + return Buffer.from('var abc = 1;'); + }; + const out = convertDiagnostic(diagnostic, fileReader); + assert.deepEqual(out, { + message: 'Unused variable', + location: { + path: 'src/foo.js', + range: { + start: { line: 1, column: 5 }, + end: { line: 1, column: 8 }, + }, + }, + severity: 'ERROR', + code: { + value: 'no-unused-vars', + url: 'https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-unused-vars.html', + }, + source: { name: 'oxlint', url: 'https://oxc.rs/docs/guide/usage/linter.html' }, + }); +}); +``` + +- [ ] **Step 5.2: Run test to verify it fails** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: FAIL — `convertDiagnostic is not a function`. + +- [ ] **Step 5.3: Implement** + +Add to `oxlint-to-rdjsonl.js`: + +```js +const OXLINT_SOURCE = { + name: 'oxlint', + url: 'https://oxc.rs/docs/guide/usage/linter.html', +}; + +function convertDiagnostic(diagnostic, fileReader) { + const out = { + message: diagnostic.message, + severity: mapSeverity(diagnostic.severity), + source: OXLINT_SOURCE, + }; + + const ruleValue = extractRuleCode(diagnostic.code); + if (ruleValue !== undefined) { + out.code = { value: ruleValue }; + if (diagnostic.url) out.code.url = diagnostic.url; + } + + const filename = diagnostic.filename; + if (filename) { + const location = { path: filename }; + const label = (diagnostic.labels || [])[0]; + if (label && label.span) { + let buffer = null; + try { + buffer = fileReader(filename); + } catch (_err) { + buffer = null; + } + if (buffer) { + const start = positionFromOffset(buffer, label.span.offset); + const end = positionFromOffset(buffer, label.span.offset + label.span.length); + location.range = { start, end }; + } + } + out.location = location; + } + + return out; +} + +module.exports = { mapSeverity, extractRuleCode, positionFromOffset, convertDiagnostic }; +``` + +- [ ] **Step 5.4: Run test to verify it passes** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: PASS — all tests from Tasks 1–5. + +- [ ] **Step 5.5: Commit** + +```bash +git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js +git commit -m "feat(converter): transform one oxlint diagnostic to rdjsonl" +``` + +--- + +## Task 6: `convertDiagnostic` edge cases — no labels, no filename, read failure, URL missing, multiple labels + +**Files:** +- Modify: `oxlint-to-rdjsonl.test.js` + +- [ ] **Step 6.1: Append failing tests** + +Append to `oxlint-to-rdjsonl.test.js`: + +```js +test('convertDiagnostic: missing labels -> file-level, no range', () => { + const out = convertDiagnostic( + { message: 'hi', code: 'eslint(x)', severity: 'warning', filename: 'a.js', labels: [] }, + () => Buffer.from('') + ); + assert.equal(out.location.path, 'a.js'); + assert.equal(out.location.range, undefined); + assert.equal(out.severity, 'WARNING'); +}); + +test('convertDiagnostic: missing filename -> no location', () => { + const out = convertDiagnostic( + { message: 'hi', severity: 'error' }, + () => { throw new Error('should not be called'); } + ); + assert.equal(out.location, undefined); +}); + +test('convertDiagnostic: fileReader throws -> file-level, no range', () => { + const out = convertDiagnostic( + { + message: 'hi', + severity: 'error', + filename: 'missing.js', + labels: [{ span: { offset: 0, length: 1 } }], + }, + () => { throw new Error('ENOENT'); } + ); + assert.deepEqual(out.location, { path: 'missing.js' }); +}); + +test('convertDiagnostic: missing url -> code without url field', () => { + const out = convertDiagnostic( + { + message: 'hi', + code: 'eslint(no-var)', + severity: 'error', + filename: 'a.js', + labels: [{ span: { offset: 0, length: 1 } }], + }, + () => Buffer.from('x') + ); + assert.deepEqual(out.code, { value: 'no-var' }); +}); + +test('convertDiagnostic: missing code -> no code field', () => { + const out = convertDiagnostic( + { message: 'hi', severity: 'error', filename: 'a.js', labels: [] }, + () => Buffer.from('') + ); + assert.equal(out.code, undefined); +}); + +test('convertDiagnostic: multiple labels -> first label used', () => { + const out = convertDiagnostic( + { + message: 'hi', + code: 'eslint(x)', + severity: 'error', + filename: 'a.js', + labels: [ + { span: { offset: 0, length: 1 } }, + { span: { offset: 5, length: 2 } }, + ], + }, + () => Buffer.from('abcdefghij') + ); + assert.deepEqual(out.location.range, { + start: { line: 1, column: 1 }, + end: { line: 1, column: 2 }, + }); +}); +``` + +- [ ] **Step 6.2: Run test** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: PASS — the implementation from Task 5 already handles these cases (thanks to the `try/catch`, `label &&` guard, etc.). If any case fails, fix the implementation before committing. + +- [ ] **Step 6.3: Commit** + +```bash +git add oxlint-to-rdjsonl.test.js +git commit -m "test(converter): edge cases for convertDiagnostic" +``` + +--- + +## Task 7: `convert` array-level function + +**Files:** +- Modify: `oxlint-to-rdjsonl.test.js` +- Modify: `oxlint-to-rdjsonl.js` + +- [ ] **Step 7.1: Append failing test** + +Append to `oxlint-to-rdjsonl.test.js`: + +```js +const { convert } = require('./oxlint-to-rdjsonl'); + +test('convert: empty array -> empty array', () => { + assert.deepEqual(convert([], () => Buffer.from('')), []); +}); + +test('convert: maps each diagnostic and preserves order', () => { + const diagnostics = [ + { message: 'a', code: 'p(r1)', severity: 'error', filename: 'f', labels: [] }, + { message: 'b', code: 'p(r2)', severity: 'warning', filename: 'f', labels: [] }, + ]; + const out = convert(diagnostics, () => Buffer.from('')); + assert.equal(out.length, 2); + assert.equal(out[0].message, 'a'); + assert.equal(out[0].severity, 'ERROR'); + assert.equal(out[1].message, 'b'); + assert.equal(out[1].severity, 'WARNING'); +}); +``` + +- [ ] **Step 7.2: Run test to verify it fails** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: FAIL — `convert is not a function`. + +- [ ] **Step 7.3: Implement** + +Add to `oxlint-to-rdjsonl.js`: + +```js +function convert(diagnostics, fileReader) { + return diagnostics.map((d) => convertDiagnostic(d, fileReader)); +} +``` + +Update `module.exports`: + +```js +module.exports = { + mapSeverity, + extractRuleCode, + positionFromOffset, + convertDiagnostic, + convert, +}; +``` + +- [ ] **Step 7.4: Run test to verify it passes** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: PASS. + +- [ ] **Step 7.5: Commit** + +```bash +git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js +git commit -m "feat(converter): convert a list of diagnostics" +``` + +--- + +## Task 8: CLI entrypoint — stdin/stdout, exit codes, invalid JSON + +**Files:** +- Modify: `oxlint-to-rdjsonl.js` +- Modify: `oxlint-to-rdjsonl.test.js` + +- [ ] **Step 8.1: Append failing test** + +Append to `oxlint-to-rdjsonl.test.js`: + +```js +const { spawnSync } = require('node:child_process'); +const path = require('node:path'); +const fs = require('node:fs'); +const os = require('node:os'); + +const CLI = path.join(__dirname, 'oxlint-to-rdjsonl.js'); + +function runCli(stdin, cwd = __dirname) { + return spawnSync(process.execPath, [CLI], { + input: stdin, + cwd, + encoding: 'utf8', + }); +} + +test('cli: empty array -> exit 0, empty stdout', () => { + const r = runCli('[]'); + assert.equal(r.status, 0, r.stderr); + assert.equal(r.stdout, ''); +}); + +test('cli: invalid JSON -> exit 1, stderr message', () => { + const r = runCli('not json'); + assert.equal(r.status, 1); + assert.match(r.stderr, /invalid|parse/i); +}); + +test('cli: one diagnostic -> one rdjsonl line', () => { + // Stage a fixture file that will be read via the diagnostic's filename. + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'oxlint-cli-')); + const fixture = path.join(tmp, 'x.js'); + fs.writeFileSync(fixture, 'var abc = 1;'); + const input = JSON.stringify([ + { + message: 'Unused', + code: 'eslint(no-unused-vars)', + severity: 'error', + url: 'https://oxc.rs/x', + filename: fixture, + labels: [{ span: { offset: 4, length: 3 } }], + }, + ]); + const r = runCli(input); + assert.equal(r.status, 0, r.stderr); + const lines = r.stdout.trim().split('\n'); + assert.equal(lines.length, 1); + const parsed = JSON.parse(lines[0]); + assert.equal(parsed.message, 'Unused'); + assert.deepEqual(parsed.location.range.start, { line: 1, column: 5 }); + assert.equal(parsed.code.value, 'no-unused-vars'); + fs.rmSync(tmp, { recursive: true, force: true }); +}); +``` + +- [ ] **Step 8.2: Run test to verify it fails** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: FAIL — the CLI entrypoint does not yet exist, so running the file as a process produces no output (the current file only exports functions). + +- [ ] **Step 8.3: Implement CLI** + +Append to `oxlint-to-rdjsonl.js`: + +```js +function readStdin() { + return new Promise((resolve, reject) => { + const chunks = []; + process.stdin.on('data', (c) => chunks.push(c)); + process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))); + process.stdin.on('error', reject); + }); +} + +function readFileSafe(filename) { + return require('node:fs').readFileSync(filename); +} + +async function main() { + const raw = await readStdin(); + const text = raw.trim(); + if (text === '') { + return 0; + } + let diagnostics; + try { + diagnostics = JSON.parse(text); + } catch (err) { + process.stderr.write(`oxlint-to-rdjsonl: failed to parse oxlint JSON on stdin: ${err.message}\n`); + return 1; + } + if (!Array.isArray(diagnostics)) { + process.stderr.write(`oxlint-to-rdjsonl: expected a JSON array on stdin, got ${typeof diagnostics}\n`); + return 1; + } + const out = convert(diagnostics, readFileSafe); + for (const d of out) { + process.stdout.write(JSON.stringify(d) + '\n'); + } + return 0; +} + +module.exports.main = main; + +if (require.main === module) { + main().then((code) => process.exit(code)).catch((err) => { + process.stderr.write(`oxlint-to-rdjsonl: ${err.stack || err.message}\n`); + process.exit(1); + }); +} +``` + +- [ ] **Step 8.4: Run test to verify it passes** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: PASS — every test including the three CLI tests. + +- [ ] **Step 8.5: Commit** + +```bash +git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js +git commit -m "feat(converter): CLI entrypoint reading stdin, writing rdjsonl" +``` + +--- + +## Task 9: Update `action.yml` + +**Files:** +- Modify: `action.yml` + +- [ ] **Step 9.1: Replace file contents** + +Overwrite `action.yml` with: + +```yaml +name: 'Run oxlint with reviewdog' +description: '🐶 Run oxlint with reviewdog on pull requests to improve code review experience.' +author: 'haya14busa (reviewdog)' +inputs: + github_token: + description: 'GITHUB_TOKEN.' + required: true + default: ${{ github.token }} + level: + description: 'Report level for reviewdog [info,warning,error]' + required: false + default: 'error' + reporter: + description: | + Reporter of reviewdog command [github-check,github-pr-review]. + Default is github-pr-review. + github-pr-review can use Markdown and add a link to rule page in reviewdog reports. + required: false + default: 'github-pr-review' + filter_mode: + description: | + Filtering mode for the reviewdog command [added,diff_context,file,nofilter]. + Default is added. + required: false + default: 'added' + fail_level: + description: | + If set to `none`, always use exit code 0 for reviewdog. Otherwise, exit code 1 for reviewdog if it finds at least 1 issue with severity greater than or equal to the given level. + Possible values: [none,any,info,warning,error] + Default is `none`. + default: 'none' + fail_on_error: + description: | + Deprecated, use `fail_level` instead. + Exit code for reviewdog when errors are found [true,false] + Default is `false`. + deprecationMessage: Deprecated, use `fail_level` instead. + required: false + default: 'false' + reviewdog_flags: + description: 'Additional reviewdog flags' + required: false + default: '' + oxlint_flags: + description: "flags and args of oxlint command. Default: '.'" + required: false + default: '.' + workdir: + description: "The directory from which to look for and run oxlint. Default '.'" + required: false + default: '.' + tool_name: + description: 'Tool name to use for reviewdog reporter' + required: false + default: 'oxlint' +runs: + using: 'composite' + steps: + - run: $GITHUB_ACTION_PATH/script.sh + shell: bash + env: + REVIEWDOG_VERSION: v0.21.0 + INPUT_GITHUB_TOKEN: ${{ inputs.github_token }} + INPUT_LEVEL: ${{ inputs.level }} + INPUT_REPORTER: ${{ inputs.reporter }} + INPUT_FILTER_MODE: ${{ inputs.filter_mode }} + INPUT_FAIL_LEVEL: ${{ inputs.fail_level }} + INPUT_FAIL_ON_ERROR: ${{ inputs.fail_on_error }} + INPUT_REVIEWDOG_FLAGS: ${{ inputs.reviewdog_flags }} + INPUT_OXLINT_FLAGS: ${{ inputs.oxlint_flags }} + INPUT_WORKDIR: ${{ inputs.workdir }} + INPUT_TOOL_NAME: ${{ inputs.tool_name }} +branding: + icon: 'alert-octagon' + color: 'blue' +``` + +- [ ] **Step 9.2: Verify YAML is well-formed** + +Run: `python3 -c "import yaml; yaml.safe_load(open('action.yml'))"` (or `node -e "require('js-yaml')"` if yaml isn't available; the goal is to catch parse errors). +Expected: no error. + +- [ ] **Step 9.3: Commit** + +```bash +git add action.yml +git commit -m "feat(action): rename inputs eslint_flags -> oxlint_flags, drop node_options" +``` + +--- + +## Task 10: Update `script.sh` + +**Files:** +- Modify: `script.sh` + +- [ ] **Step 10.1: Replace file contents** + +Overwrite `script.sh` with: + +```sh +#!/bin/sh + +cd "${GITHUB_WORKSPACE}/${INPUT_WORKDIR}" || exit 1 + +TEMP_PATH="$(mktemp -d)" +PATH="${TEMP_PATH}:$PATH" +export REVIEWDOG_GITHUB_API_TOKEN="${INPUT_GITHUB_TOKEN}" + +echo '::group::🐶 Installing reviewdog ... https://github.com/reviewdog/reviewdog' +curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s -- -b "${TEMP_PATH}" "${REVIEWDOG_VERSION}" 2>&1 +echo '::endgroup::' + +npx --no-install -c 'oxlint --version' 2>/dev/null +if [ $? -ne 0 ]; then + echo '::group:: Running `npm install` to install oxlint ...' + set -e + npm install + set +e + echo '::endgroup::' +fi + +echo "oxlint version:$(npx --no-install -c 'oxlint --version')" + +echo '::group:: Running oxlint with reviewdog 🐶 ...' +npx --no-install -c "oxlint --format=json ${INPUT_OXLINT_FLAGS:-'.'}" \ + | node "${GITHUB_ACTION_PATH}/oxlint-to-rdjsonl.js" \ + | reviewdog -f=rdjsonl \ + -name="${INPUT_TOOL_NAME}" \ + -reporter="${INPUT_REPORTER:-github-pr-review}" \ + -filter-mode="${INPUT_FILTER_MODE}" \ + -fail-level="${INPUT_FAIL_LEVEL}" \ + -fail-on-error="${INPUT_FAIL_ON_ERROR}" \ + -level="${INPUT_LEVEL}" \ + ${INPUT_REVIEWDOG_FLAGS} + +reviewdog_rc=$? +echo '::endgroup::' +exit $reviewdog_rc +``` + +- [ ] **Step 10.2: Ensure the file is executable** + +Run: `chmod +x script.sh && test -x script.sh && echo OK` +Expected: `OK`. + +- [ ] **Step 10.3: Quick shell syntax check** + +Run: `sh -n script.sh` +Expected: no output, exit 0. + +- [ ] **Step 10.4: Commit** + +```bash +git add script.sh +git commit -m "feat(action): swap eslint pipeline for oxlint + rdjsonl converter" +``` + +--- + +## Task 11: Delete `eslint-formatter-rdjson/` + +**Files:** +- Delete: `eslint-formatter-rdjson/` (recursive) + +- [ ] **Step 11.1: Verify nothing in the repo still imports it** + +Run: `grep -rn --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=eslint-formatter-rdjson eslint-formatter-rdjson .` +Expected: only references in `docs/superpowers/`, `README.md` (if still present), and potentially files that are also scheduled for deletion/update. No reference from any file that's supposed to survive unmodified. + +If the grep surfaces unexpected hits, stop and resolve them before deleting. + +- [ ] **Step 11.2: Delete the directory** + +Run: `git rm -r eslint-formatter-rdjson` +Expected: git reports deletions of every file under the directory. + +- [ ] **Step 11.3: Commit** + +```bash +git commit -m "chore: remove bundled eslint-formatter-rdjson" +``` + +--- + +## Task 12: Delete repo-root eslint/npm detritus + +**Files:** +- Delete: `.eslintrc.js` +- Delete: `package.json` +- Delete: `package-lock.json` + +- [ ] **Step 12.1: Verify nothing imports these** + +Run: `grep -rn --exclude-dir=.git --exclude-dir=node_modules "eslintrc\|package-lock\|require(.package\.json" . | grep -v docs/superpowers` +Expected: no production code referencing the repo-root `package.json` or `.eslintrc.js`. References inside `docs/superpowers/` (the spec/plan) are fine. + +- [ ] **Step 12.2: Delete the files** + +Run: `git rm .eslintrc.js package.json package-lock.json` +Expected: three deletions staged. + +- [ ] **Step 12.3: Commit** + +```bash +git commit -m "chore: remove repo-root eslint config and package manifest" +``` + +--- + +## Task 13: Add `.oxlintrc.json` + +**Files:** +- Create: `.oxlintrc.json` + +- [ ] **Step 13.1: Write the config** + +Create `.oxlintrc.json`: + +```json +{ + "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json", + "rules": { + "no-unused-vars": "error", + "no-var": "error", + "no-empty": "warn" + }, + "ignorePatterns": [ + "test-subproject/", + "node_modules/" + ] +} +``` + +- [ ] **Step 13.2: Verify it's valid JSON** + +Run: `python3 -m json.tool .oxlintrc.json > /dev/null` +Expected: exit 0, no error. + +- [ ] **Step 13.3: Commit** + +```bash +git add .oxlintrc.json +git commit -m "chore: add repo-root oxlint config for test fixtures" +``` + +--- + +## Task 14: Update `testdata/` fixtures for oxlint + +**Files:** +- Modify: `testdata/test.js` +- Modify: `testdata/error.js` +- Modify: `testdata/empty.js` + +**Rationale:** The current `testdata/error.js` uses a literal `🐶` outside a string, which eslint flagged as an unexpected character but oxlint's default JS parser treats as an identifier — different rule surface. Replace with a fixture that reliably triggers the rules pinned in `.oxlintrc.json` (`no-unused-vars`, `no-var`). + +- [ ] **Step 14.1: Rewrite `testdata/error.js`** + +Overwrite `testdata/error.js`: + +```js +// Fires: no-var (var keyword), no-unused-vars (unusedVar never read) +var unusedVar = 1; +``` + +- [ ] **Step 14.2: Rewrite `testdata/test.js`** + +Overwrite `testdata/test.js`: + +```js +// Fires: no-var, no-empty (for body) +function sample() { + for (var i = 0; i < 10; i++) { + } +} + +sample(); +``` + +- [ ] **Step 14.3: Leave `testdata/empty.js` as-is** + +Run: `cat testdata/empty.js` +Expected: `// empty` — a file with no diagnostics. This covers the "file with no issues" path. + +- [ ] **Step 14.4: Smoke test: run oxlint locally against the fixtures and confirm JSON output is non-empty** + +Run (requires oxlint installed globally or via `npx`): `npx --yes oxlint@latest --config .oxlintrc.json --format=json testdata/ > /tmp/out.json; echo exit=$?` +Expected: oxlint exits non-zero (because of rule violations) and `/tmp/out.json` contains a JSON array with at least 2 diagnostic entries. + +If oxlint isn't available in the execution environment, mark this step as "deferred to CI" — the reviewdog workflow covers the same validation. + +- [ ] **Step 14.5: Commit** + +```bash +git add testdata/ +git commit -m "test: rewrite testdata fixtures for oxlint's default rules" +``` + +--- + +## Task 15: Update `test-subproject/` + +**Files:** +- Modify: `test-subproject/package.json` +- Delete: `test-subproject/.eslintrc.js` +- Delete: `test-subproject/package-lock.json` (regenerated in next task by the lock step, or leave for the action's `npm install` fallback) +- Modify: `test-subproject/sub-testdata/*.js` (same deterministic fixture treatment) + +- [ ] **Step 15.1: Inspect current subproject fixtures** + +Run: `ls test-subproject/sub-testdata/` +Expected: list of `.js` fixture files. Read each and note what rule they currently rely on. + +- [ ] **Step 15.2: Rewrite `test-subproject/package.json`** + +Overwrite: + +```json +{ + "name": "action-eslint-subproject", + "version": "1.0.0", + "description": "A test subproject for testing reviewdog/action-eslint", + "devDependencies": { + "oxlint": "^0.15.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/reviewdog/action-eslint.git" + }, + "keywords": [], + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/reviewdog/action-eslint/issues" + }, + "homepage": "https://github.com/reviewdog/action-eslint#readme" +} +``` + +Note: the oxlint major version is provisional — bump to the current stable at the time of implementation by checking `npm view oxlint version`. Update `^0.15.0` accordingly before committing. + +- [ ] **Step 15.3: Delete the old eslint config and lockfile** + +Run: `git rm test-subproject/.eslintrc.js test-subproject/package-lock.json` +Expected: both deletions staged. + +- [ ] **Step 15.4: Rewrite each file under `test-subproject/sub-testdata/` to fire oxlint rules** + +For each `.js` file, replace the contents with something equivalent to: + +```js +// Fires: no-var, no-unused-vars +var unused = 42; +``` + +(Keep each file distinct by name — the point is just that each file produces at least one diagnostic under oxlint defaults.) + +- [ ] **Step 15.5: Regenerate the subproject lockfile** + +Run: `cd test-subproject && npm install --package-lock-only && cd ..` +Expected: `test-subproject/package-lock.json` regenerated with only `oxlint` and its (few) transitive deps. + +If `npm install --package-lock-only` is unavailable or fails locally, leave the lockfile absent; the action's `npm install` fallback in `script.sh` will create it at runtime. + +- [ ] **Step 15.6: Commit** + +```bash +git add test-subproject/ +git commit -m "test(subproject): migrate to oxlint, regenerate lockfile" +``` + +--- + +## Task 16: Replace `.github/workflows/test.yml` + +**Files:** +- Modify: `.github/workflows/test.yml` + +- [ ] **Step 16.1: Overwrite contents** + +```yaml +name: test +on: + push: + branches: + - master + pull_request: +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "24" + - name: Converter unit tests + run: node --test oxlint-to-rdjsonl.test.js +``` + +Note: `cache: "npm"` was removed — there's no repo-root `package.json` / lockfile to cache against. + +- [ ] **Step 16.2: Verify YAML** + +Run: `python3 -c "import yaml; yaml.safe_load(open('.github/workflows/test.yml'))"` +Expected: no error. + +- [ ] **Step 16.3: Commit** + +```bash +git add .github/workflows/test.yml +git commit -m "ci: run converter unit tests via node --test" +``` + +--- + +## Task 17: Update `.github/workflows/reviewdog.yml` + +**Files:** +- Modify: `.github/workflows/reviewdog.yml` + +- [ ] **Step 17.1: Overwrite contents** + +```yaml +name: reviewdog +on: [pull_request] +jobs: + oxlint: + name: runner / oxlint + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + node_version: + - "18" + - "20" + - "22" + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: ${{ matrix.node_version }} + - name: install oxlint for root fixtures + run: npm install --no-save oxlint + - name: oxlint-github-pr-check + uses: ./ + with: + tool_name: oxlint-github-pr-check + reporter: github-pr-check + level: info + oxlint_flags: "--config .oxlintrc.json testdata/" + - name: oxlint-github-check + uses: ./ + with: + tool_name: oxlint-github-check + reporter: github-check + level: warning + oxlint_flags: "--config .oxlintrc.json testdata/" + - name: oxlint-github-pr-review + uses: ./ + with: + tool_name: oxlint-github-pr-review + reporter: github-pr-review + oxlint_flags: "--config .oxlintrc.json testdata/" + - name: oxlint-subproject-github-pr-review + uses: ./ + with: + tool_name: oxlint-subproject-github-pr-review + reporter: github-pr-review + workdir: ./test-subproject + oxlint_flags: "sub-testdata/" + - name: oxlint-subproject + uses: ./ + with: + tool_name: oxlint-subproject + workdir: ./test-subproject + oxlint_flags: "sub-testdata/" + reporter: github-check + level: warning + filter_mode: file +``` + +Note: dropped the `--ignore-pattern /test-subproject/` arg since `.oxlintrc.json` already has `ignorePatterns`. For subproject steps, no `--config` flag — oxlint auto-discovers `test-subproject/.oxlintrc.json` if present, or falls back to defaults. + +- [ ] **Step 17.2: Verify YAML** + +Run: `python3 -c "import yaml; yaml.safe_load(open('.github/workflows/reviewdog.yml'))"` +Expected: no error. + +- [ ] **Step 17.3: Commit** + +```bash +git add .github/workflows/reviewdog.yml +git commit -m "ci(reviewdog): exercise action with oxlint across node matrix" +``` + +--- + +## Task 18: Delete `.github/workflows/npm-publish.yml` + +**Files:** +- Delete: `.github/workflows/npm-publish.yml` + +- [ ] **Step 18.1: Delete** + +Run: `git rm .github/workflows/npm-publish.yml` +Expected: one deletion staged. + +- [ ] **Step 18.2: Commit** + +```bash +git commit -m "ci: remove npm-publish workflow (no npm package to publish)" +``` + +--- + +## Task 19: Rewrite `README.md` + +**Files:** +- Modify: `README.md` + +- [ ] **Step 19.1: Overwrite with new content** + +Replace the entire file with: + +```markdown +# GitHub Action: Run oxlint with reviewdog + +[![depup](https://github.com/reviewdog/action-eslint/workflows/depup/badge.svg)](https://github.com/reviewdog/action-eslint/actions?query=workflow%3Adepup) +[![release](https://github.com/reviewdog/action-eslint/workflows/release/badge.svg)](https://github.com/reviewdog/action-eslint/actions?query=workflow%3Arelease) +[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/reviewdog/action-eslint?logo=github&sort=semver)](https://github.com/reviewdog/action-eslint/releases) + +This action runs [oxlint](https://oxc.rs/docs/guide/usage/linter.html) with +[reviewdog](https://github.com/reviewdog/reviewdog) on pull requests to improve +code review experience. + +## Migrating from older versions of this action (eslint) + +Earlier versions of this action ran eslint. Starting with the oxlint rewrite, +the following breaking changes apply: + +- `eslint_flags` input → `oxlint_flags`. +- `node_options` input removed (oxlint is a native binary; `NODE_OPTIONS` has no effect). +- `tool_name` default changed from `eslint` to `oxlint`. +- You must list `oxlint` (not `eslint`) in your project's `devDependencies` (or equivalent). + +## Inputs + +### `github_token` +**Required.** Default `${{ github.token }}`. + +### `level` +Optional. Report level for reviewdog (`info`, `warning`, `error`). Same as reviewdog's `-level` flag. + +### `reporter` +Optional. `github-pr-check`, `github-check`, or `github-pr-review`. Default `github-pr-review`. + +### `tool_name` +Optional. Default `oxlint`. Becomes the check/run name on GitHub and the tool label in review comments. + +### `filter_mode` +Optional. `added`, `diff_context`, `file`, or `nofilter`. Default `added`. + +### `fail_level` +Optional. `none`, `any`, `info`, `warning`, or `error`. Default `none`. + +### `fail_on_error` +Deprecated. Use `fail_level`. + +### `reviewdog_flags` +Optional. Additional flags passed to reviewdog. + +### `oxlint_flags` +Optional. Flags and args for the `oxlint` command. Default `.`. + +### `workdir` +Optional. Directory from which to run oxlint. Default `.`. + +## Example usage + +Install oxlint in your project: + +```shell +npm install --save-dev oxlint +``` + +See the [oxlint configuration docs](https://oxc.rs/docs/guide/usage/linter/config.html) +for creating a `.oxlintrc.json`. This action uses that config automatically. + +### `.github/workflows/reviewdog.yml` + +```yaml +name: reviewdog +on: [pull_request] +jobs: + oxlint: + name: runner / oxlint + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: reviewdog/action-eslint@vX + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review + oxlint_flags: "src/" +``` + +You can also set up Node and oxlint manually: + +```yaml +name: reviewdog +on: [pull_request] +jobs: + oxlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "20" + - run: npm install + - uses: reviewdog/action-eslint@vX + with: + reporter: github-check + oxlint_flags: "src/" +``` + +### Matrix example with unique tool name + +```yaml +name: reviewdog +on: [pull_request] +jobs: + oxlint: + runs-on: ubuntu-latest + strategy: + matrix: + node: [18, 20, 22] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + - uses: reviewdog/action-eslint@vX + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-check + tool_name: oxlint-node-${{ matrix.node }} + oxlint_flags: "src/" +``` +``` + +Note: replace `@vX` with the actual release tag once a release is cut. Leave `@vX` in the plan so the implementer remembers the release step is still pending. + +- [ ] **Step 19.2: Check the file renders as valid markdown** + +Run: `node -e "require('node:fs').readFileSync('README.md','utf8')" && echo OK` +Expected: `OK`. (Purely a sanity read; we're not running a markdown linter.) + +- [ ] **Step 19.3: Commit** + +```bash +git add README.md +git commit -m "docs: rewrite README for oxlint" +``` + +--- + +## Task 20: Final integration pass + +**Files:** +- None directly; this is a pre-merge verification task. + +- [ ] **Step 20.1: Re-run converter tests** + +Run: `node --test oxlint-to-rdjsonl.test.js` +Expected: all tests pass. + +- [ ] **Step 20.2: Shell syntax check on `script.sh`** + +Run: `sh -n script.sh` +Expected: no output, exit 0. + +- [ ] **Step 20.3: Final grep for stale eslint references** + +Run: `grep -rn --exclude-dir=.git --exclude-dir=docs/superpowers -i eslint .` +Expected: no matches. If anything surfaces, investigate — README screenshots URLs or the "Migrating from eslint" section are allowed; anything functional is not. + +- [ ] **Step 20.4: Confirm the file list** + +Run: `git status` and `git log --oneline master..HEAD` +Expected: clean working tree; ~19 commits corresponding to Tasks 1–19. + +- [ ] **Step 20.5: Merge/PR** + +No commit in this task — hand off for review. + +--- + +## Self-review checklist + +This section lives in the plan so the implementer can confirm the plan matches the spec before handing off. + +| Spec section | Task(s) covering it | +|---|---| +| `action.yml` renames/removals | Task 9 | +| `script.sh` new pipeline | Task 10 | +| `oxlint-to-rdjsonl.js` transform rules | Tasks 1, 2, 5 | +| Byte-offset → line/column | Tasks 3, 4 | +| Edge cases (empty labels, read failure, invalid JSON, empty list) | Tasks 6, 8 | +| `convert` batch function | Task 7 | +| CLI exit codes | Task 8 | +| `testdata/` updates | Task 14 | +| `test-subproject/` updates | Task 15 | +| `.oxlintrc.json` | Task 13 | +| Delete eslint-formatter-rdjson | Task 11 | +| Delete repo-root eslint detritus | Task 12 | +| `.github/workflows/test.yml` | Task 16 | +| `.github/workflows/reviewdog.yml` | Task 17 | +| Delete `.github/workflows/npm-publish.yml` | Task 18 | +| README rewrite + migration callout | Task 19 | +| Final verification | Task 20 | From 8936ddf932090c8302430c425ea8f7f056e9a43d Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:28:27 -0400 Subject: [PATCH 03/28] feat(converter): scaffold module with severity mapping Co-Authored-By: Claude Opus 4.7 (1M context) --- oxlint-to-rdjsonl.js | 10 ++++++++++ oxlint-to-rdjsonl.test.js | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 oxlint-to-rdjsonl.js create mode 100644 oxlint-to-rdjsonl.test.js diff --git a/oxlint-to-rdjsonl.js b/oxlint-to-rdjsonl.js new file mode 100644 index 0000000..e1932e7 --- /dev/null +++ b/oxlint-to-rdjsonl.js @@ -0,0 +1,10 @@ +'use strict'; + +function mapSeverity(s) { + if (s === 'error') return 'ERROR'; + if (s === 'warning') return 'WARNING'; + if (s === 'advice') return 'INFO'; + return 'UNKNOWN_SEVERITY'; +} + +module.exports = { mapSeverity }; diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js new file mode 100644 index 0000000..1ad1c77 --- /dev/null +++ b/oxlint-to-rdjsonl.test.js @@ -0,0 +1,19 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const { mapSeverity } = require('./oxlint-to-rdjsonl'); + +test('mapSeverity: error -> ERROR', () => { + assert.equal(mapSeverity('error'), 'ERROR'); +}); + +test('mapSeverity: warning -> WARNING', () => { + assert.equal(mapSeverity('warning'), 'WARNING'); +}); + +test('mapSeverity: advice -> INFO', () => { + assert.equal(mapSeverity('advice'), 'INFO'); +}); + +test('mapSeverity: unknown -> UNKNOWN_SEVERITY', () => { + assert.equal(mapSeverity('bogus'), 'UNKNOWN_SEVERITY'); +}); From fbb468ad66ae710b15144bd9cc1251ac6aded76a Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:29:03 -0400 Subject: [PATCH 04/28] feat(converter): extract rule code from plugin(rule) format Co-Authored-By: Claude Opus 4.7 (1M context) --- oxlint-to-rdjsonl.js | 8 +++++++- oxlint-to-rdjsonl.test.js | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/oxlint-to-rdjsonl.js b/oxlint-to-rdjsonl.js index e1932e7..3b2ddd1 100644 --- a/oxlint-to-rdjsonl.js +++ b/oxlint-to-rdjsonl.js @@ -7,4 +7,10 @@ function mapSeverity(s) { return 'UNKNOWN_SEVERITY'; } -module.exports = { mapSeverity }; +function extractRuleCode(code) { + if (code === undefined || code === null) return undefined; + const match = /^[^(]+\(([^)]+)\)$/.exec(code); + return match ? match[1] : code; +} + +module.exports = { mapSeverity, extractRuleCode }; diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js index 1ad1c77..8117970 100644 --- a/oxlint-to-rdjsonl.test.js +++ b/oxlint-to-rdjsonl.test.js @@ -17,3 +17,25 @@ test('mapSeverity: advice -> INFO', () => { test('mapSeverity: unknown -> UNKNOWN_SEVERITY', () => { assert.equal(mapSeverity('bogus'), 'UNKNOWN_SEVERITY'); }); + +const { extractRuleCode } = require('./oxlint-to-rdjsonl'); + +test('extractRuleCode: plugin(rule) -> rule', () => { + assert.equal(extractRuleCode('eslint(no-unused-vars)'), 'no-unused-vars'); +}); + +test('extractRuleCode: nested parens preserved in rule', () => { + assert.equal(extractRuleCode('typescript(no-empty-interface)'), 'no-empty-interface'); +}); + +test('extractRuleCode: bare code passed through', () => { + assert.equal(extractRuleCode('no-unused-vars'), 'no-unused-vars'); +}); + +test('extractRuleCode: undefined -> undefined', () => { + assert.equal(extractRuleCode(undefined), undefined); +}); + +test('extractRuleCode: empty string -> empty string', () => { + assert.equal(extractRuleCode(''), ''); +}); From cfe9aca56a4e5138f6aebc2511ccc9dba36950c3 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:29:42 -0400 Subject: [PATCH 05/28] feat(converter): byte-offset to line/column for single-line input Co-Authored-By: Claude Opus 4.7 (1M context) --- oxlint-to-rdjsonl.js | 19 ++++++++++++++++++- oxlint-to-rdjsonl.test.js | 17 +++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/oxlint-to-rdjsonl.js b/oxlint-to-rdjsonl.js index 3b2ddd1..b31872d 100644 --- a/oxlint-to-rdjsonl.js +++ b/oxlint-to-rdjsonl.js @@ -13,4 +13,21 @@ function extractRuleCode(code) { return match ? match[1] : code; } -module.exports = { mapSeverity, extractRuleCode }; +// Convert a UTF-8 byte offset into {line, column}, both 1-based. +// column is a 1-based UTF-8 byte position within its line (reviewdog's expected encoding). +function positionFromOffset(buffer, offset) { + let line = 1; + let column = 1; + const end = Math.min(offset, buffer.length); + for (let i = 0; i < end; i++) { + if (buffer[i] === 0x0A) { + line++; + column = 1; + } else { + column++; + } + } + return { line, column }; +} + +module.exports = { mapSeverity, extractRuleCode, positionFromOffset }; diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js index 8117970..2a10dfe 100644 --- a/oxlint-to-rdjsonl.test.js +++ b/oxlint-to-rdjsonl.test.js @@ -39,3 +39,20 @@ test('extractRuleCode: undefined -> undefined', () => { test('extractRuleCode: empty string -> empty string', () => { assert.equal(extractRuleCode(''), ''); }); + +const { positionFromOffset } = require('./oxlint-to-rdjsonl'); + +test('positionFromOffset: offset 0 -> line 1, column 1', () => { + const buf = Buffer.from('abc'); + assert.deepEqual(positionFromOffset(buf, 0), { line: 1, column: 1 }); +}); + +test('positionFromOffset: middle of first line', () => { + const buf = Buffer.from('abcdef'); + assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); +}); + +test('positionFromOffset: end-of-single-line buffer', () => { + const buf = Buffer.from('abc'); + assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); +}); From 64d0314c5f220c0fe48ae3e3a7f5bf2ac4b30aa5 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:30:05 -0400 Subject: [PATCH 06/28] test(converter): cover multi-line, boundary, and UTF-8 offset cases Co-Authored-By: Claude Opus 4.7 (1M context) --- oxlint-to-rdjsonl.test.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js index 2a10dfe..6cb135a 100644 --- a/oxlint-to-rdjsonl.test.js +++ b/oxlint-to-rdjsonl.test.js @@ -56,3 +56,29 @@ test('positionFromOffset: end-of-single-line buffer', () => { const buf = Buffer.from('abc'); assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); }); + +test('positionFromOffset: offset on a later line', () => { + const buf = Buffer.from('abc\ndef'); + assert.deepEqual(positionFromOffset(buf, 4), { line: 2, column: 1 }); +}); + +test('positionFromOffset: offset at newline is end of previous line', () => { + const buf = Buffer.from('abc\ndef'); + assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); +}); + +test('positionFromOffset: across multiple newlines', () => { + const buf = Buffer.from('a\nb\nc'); + assert.deepEqual(positionFromOffset(buf, 4), { line: 3, column: 1 }); +}); + +test('positionFromOffset: offset past end clamps to buffer length', () => { + const buf = Buffer.from('abc'); + assert.deepEqual(positionFromOffset(buf, 99), { line: 1, column: 4 }); +}); + +test('positionFromOffset: UTF-8 multi-byte char — columns are byte positions', () => { + const buf = Buffer.from('a🐶b'); + assert.equal(buf.length, 6); + assert.deepEqual(positionFromOffset(buf, 5), { line: 1, column: 6 }); +}); From 9a762bc97623b4bc2c8f8e42e4e220b768482436 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:30:45 -0400 Subject: [PATCH 07/28] feat(converter): transform one oxlint diagnostic to rdjsonl Co-Authored-By: Claude Opus 4.7 (1M context) --- oxlint-to-rdjsonl.js | 43 ++++++++++++++++++++++++++++++++++++++- oxlint-to-rdjsonl.test.js | 34 +++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/oxlint-to-rdjsonl.js b/oxlint-to-rdjsonl.js index b31872d..00e4b13 100644 --- a/oxlint-to-rdjsonl.js +++ b/oxlint-to-rdjsonl.js @@ -30,4 +30,45 @@ function positionFromOffset(buffer, offset) { return { line, column }; } -module.exports = { mapSeverity, extractRuleCode, positionFromOffset }; +const OXLINT_SOURCE = { + name: 'oxlint', + url: 'https://oxc.rs/docs/guide/usage/linter.html', +}; + +function convertDiagnostic(diagnostic, fileReader) { + const out = { + message: diagnostic.message, + severity: mapSeverity(diagnostic.severity), + source: OXLINT_SOURCE, + }; + + const ruleValue = extractRuleCode(diagnostic.code); + if (ruleValue !== undefined) { + out.code = { value: ruleValue }; + if (diagnostic.url) out.code.url = diagnostic.url; + } + + const filename = diagnostic.filename; + if (filename) { + const location = { path: filename }; + const label = (diagnostic.labels || [])[0]; + if (label && label.span) { + let buffer = null; + try { + buffer = fileReader(filename); + } catch (_err) { + buffer = null; + } + if (buffer) { + const start = positionFromOffset(buffer, label.span.offset); + const end = positionFromOffset(buffer, label.span.offset + label.span.length); + location.range = { start, end }; + } + } + out.location = location; + } + + return out; +} + +module.exports = { mapSeverity, extractRuleCode, positionFromOffset, convertDiagnostic }; diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js index 6cb135a..b388eae 100644 --- a/oxlint-to-rdjsonl.test.js +++ b/oxlint-to-rdjsonl.test.js @@ -82,3 +82,37 @@ test('positionFromOffset: UTF-8 multi-byte char — columns are byte positions', assert.equal(buf.length, 6); assert.deepEqual(positionFromOffset(buf, 5), { line: 1, column: 6 }); }); + +const { convertDiagnostic } = require('./oxlint-to-rdjsonl'); + +test('convertDiagnostic: full mapping of a typical diagnostic', () => { + const diagnostic = { + message: 'Unused variable', + code: 'eslint(no-unused-vars)', + severity: 'error', + url: 'https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-unused-vars.html', + filename: 'src/foo.js', + labels: [{ span: { offset: 4, length: 3 } }], + }; + const fileReader = (path) => { + assert.equal(path, 'src/foo.js'); + return Buffer.from('var abc = 1;'); + }; + const out = convertDiagnostic(diagnostic, fileReader); + assert.deepEqual(out, { + message: 'Unused variable', + location: { + path: 'src/foo.js', + range: { + start: { line: 1, column: 5 }, + end: { line: 1, column: 8 }, + }, + }, + severity: 'ERROR', + code: { + value: 'no-unused-vars', + url: 'https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-unused-vars.html', + }, + source: { name: 'oxlint', url: 'https://oxc.rs/docs/guide/usage/linter.html' }, + }); +}); From 4df1c64a1aa8e524cea9cdf2be09fc6fab63846a Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:31:10 -0400 Subject: [PATCH 08/28] test(converter): edge cases for convertDiagnostic Co-Authored-By: Claude Opus 4.7 (1M context) --- oxlint-to-rdjsonl.test.js | 73 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js index b388eae..ef50dc9 100644 --- a/oxlint-to-rdjsonl.test.js +++ b/oxlint-to-rdjsonl.test.js @@ -116,3 +116,76 @@ test('convertDiagnostic: full mapping of a typical diagnostic', () => { source: { name: 'oxlint', url: 'https://oxc.rs/docs/guide/usage/linter.html' }, }); }); + +test('convertDiagnostic: missing labels -> file-level, no range', () => { + const out = convertDiagnostic( + { message: 'hi', code: 'eslint(x)', severity: 'warning', filename: 'a.js', labels: [] }, + () => Buffer.from('') + ); + assert.equal(out.location.path, 'a.js'); + assert.equal(out.location.range, undefined); + assert.equal(out.severity, 'WARNING'); +}); + +test('convertDiagnostic: missing filename -> no location', () => { + const out = convertDiagnostic( + { message: 'hi', severity: 'error' }, + () => { throw new Error('should not be called'); } + ); + assert.equal(out.location, undefined); +}); + +test('convertDiagnostic: fileReader throws -> file-level, no range', () => { + const out = convertDiagnostic( + { + message: 'hi', + severity: 'error', + filename: 'missing.js', + labels: [{ span: { offset: 0, length: 1 } }], + }, + () => { throw new Error('ENOENT'); } + ); + assert.deepEqual(out.location, { path: 'missing.js' }); +}); + +test('convertDiagnostic: missing url -> code without url field', () => { + const out = convertDiagnostic( + { + message: 'hi', + code: 'eslint(no-var)', + severity: 'error', + filename: 'a.js', + labels: [{ span: { offset: 0, length: 1 } }], + }, + () => Buffer.from('x') + ); + assert.deepEqual(out.code, { value: 'no-var' }); +}); + +test('convertDiagnostic: missing code -> no code field', () => { + const out = convertDiagnostic( + { message: 'hi', severity: 'error', filename: 'a.js', labels: [] }, + () => Buffer.from('') + ); + assert.equal(out.code, undefined); +}); + +test('convertDiagnostic: multiple labels -> first label used', () => { + const out = convertDiagnostic( + { + message: 'hi', + code: 'eslint(x)', + severity: 'error', + filename: 'a.js', + labels: [ + { span: { offset: 0, length: 1 } }, + { span: { offset: 5, length: 2 } }, + ], + }, + () => Buffer.from('abcdefghij') + ); + assert.deepEqual(out.location.range, { + start: { line: 1, column: 1 }, + end: { line: 1, column: 2 }, + }); +}); From d14d68b3f7694d48e7f7b0f7f2b0cf56ac8db57d Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:31:44 -0400 Subject: [PATCH 09/28] feat(converter): convert a list of diagnostics Co-Authored-By: Claude Opus 4.7 (1M context) --- oxlint-to-rdjsonl.js | 12 +++++++++++- oxlint-to-rdjsonl.test.js | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/oxlint-to-rdjsonl.js b/oxlint-to-rdjsonl.js index 00e4b13..7adb4fc 100644 --- a/oxlint-to-rdjsonl.js +++ b/oxlint-to-rdjsonl.js @@ -71,4 +71,14 @@ function convertDiagnostic(diagnostic, fileReader) { return out; } -module.exports = { mapSeverity, extractRuleCode, positionFromOffset, convertDiagnostic }; +function convert(diagnostics, fileReader) { + return diagnostics.map((d) => convertDiagnostic(d, fileReader)); +} + +module.exports = { + mapSeverity, + extractRuleCode, + positionFromOffset, + convertDiagnostic, + convert, +}; diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js index ef50dc9..f54e0fb 100644 --- a/oxlint-to-rdjsonl.test.js +++ b/oxlint-to-rdjsonl.test.js @@ -189,3 +189,22 @@ test('convertDiagnostic: multiple labels -> first label used', () => { end: { line: 1, column: 2 }, }); }); + +const { convert } = require('./oxlint-to-rdjsonl'); + +test('convert: empty array -> empty array', () => { + assert.deepEqual(convert([], () => Buffer.from('')), []); +}); + +test('convert: maps each diagnostic and preserves order', () => { + const diagnostics = [ + { message: 'a', code: 'p(r1)', severity: 'error', filename: 'f', labels: [] }, + { message: 'b', code: 'p(r2)', severity: 'warning', filename: 'f', labels: [] }, + ]; + const out = convert(diagnostics, () => Buffer.from('')); + assert.equal(out.length, 2); + assert.equal(out[0].message, 'a'); + assert.equal(out[0].severity, 'ERROR'); + assert.equal(out[1].message, 'b'); + assert.equal(out[1].severity, 'WARNING'); +}); From b490a681a7da7d584c101f15203e39840229719b Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:32:30 -0400 Subject: [PATCH 10/28] feat(converter): CLI entrypoint reading stdin, writing rdjsonl Co-Authored-By: Claude Opus 4.7 (1M context) --- oxlint-to-rdjsonl.js | 47 +++++++++++++++++++++++++++++++++++ oxlint-to-rdjsonl.test.js | 52 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/oxlint-to-rdjsonl.js b/oxlint-to-rdjsonl.js index 7adb4fc..4adc883 100644 --- a/oxlint-to-rdjsonl.js +++ b/oxlint-to-rdjsonl.js @@ -75,10 +75,57 @@ function convert(diagnostics, fileReader) { return diagnostics.map((d) => convertDiagnostic(d, fileReader)); } +function readStdin() { + return new Promise((resolve, reject) => { + const chunks = []; + process.stdin.on('data', (c) => chunks.push(c)); + process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))); + process.stdin.on('error', reject); + }); +} + +function readFileSafe(filename) { + return require('node:fs').readFileSync(filename); +} + +async function main() { + const raw = await readStdin(); + const text = raw.trim(); + if (text === '') { + return 0; + } + let diagnostics; + try { + diagnostics = JSON.parse(text); + } catch (err) { + process.stderr.write(`oxlint-to-rdjsonl: failed to parse oxlint JSON on stdin: ${err.message}\n`); + return 1; + } + if (!Array.isArray(diagnostics)) { + process.stderr.write(`oxlint-to-rdjsonl: expected a JSON array on stdin, got ${typeof diagnostics}\n`); + return 1; + } + const out = convert(diagnostics, readFileSafe); + for (const d of out) { + process.stdout.write(JSON.stringify(d) + '\n'); + } + return 0; +} + module.exports = { mapSeverity, extractRuleCode, positionFromOffset, convertDiagnostic, convert, + main, }; + +if (require.main === module) { + main() + .then((code) => process.exit(code)) + .catch((err) => { + process.stderr.write(`oxlint-to-rdjsonl: ${err.stack || err.message}\n`); + process.exit(1); + }); +} diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js index f54e0fb..1194bc7 100644 --- a/oxlint-to-rdjsonl.test.js +++ b/oxlint-to-rdjsonl.test.js @@ -208,3 +208,55 @@ test('convert: maps each diagnostic and preserves order', () => { assert.equal(out[1].message, 'b'); assert.equal(out[1].severity, 'WARNING'); }); + +const { spawnSync } = require('node:child_process'); +const path = require('node:path'); +const fs = require('node:fs'); +const os = require('node:os'); + +const CLI = path.join(__dirname, 'oxlint-to-rdjsonl.js'); + +function runCli(stdin, cwd = __dirname) { + return spawnSync(process.execPath, [CLI], { + input: stdin, + cwd, + encoding: 'utf8', + }); +} + +test('cli: empty array -> exit 0, empty stdout', () => { + const r = runCli('[]'); + assert.equal(r.status, 0, r.stderr); + assert.equal(r.stdout, ''); +}); + +test('cli: invalid JSON -> exit 1, stderr message', () => { + const r = runCli('not json'); + assert.equal(r.status, 1); + assert.match(r.stderr, /invalid|parse/i); +}); + +test('cli: one diagnostic -> one rdjsonl line', () => { + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'oxlint-cli-')); + const fixture = path.join(tmp, 'x.js'); + fs.writeFileSync(fixture, 'var abc = 1;'); + const input = JSON.stringify([ + { + message: 'Unused', + code: 'eslint(no-unused-vars)', + severity: 'error', + url: 'https://oxc.rs/x', + filename: fixture, + labels: [{ span: { offset: 4, length: 3 } }], + }, + ]); + const r = runCli(input); + assert.equal(r.status, 0, r.stderr); + const lines = r.stdout.trim().split('\n'); + assert.equal(lines.length, 1); + const parsed = JSON.parse(lines[0]); + assert.equal(parsed.message, 'Unused'); + assert.deepEqual(parsed.location.range.start, { line: 1, column: 5 }); + assert.equal(parsed.code.value, 'no-unused-vars'); + fs.rmSync(tmp, { recursive: true, force: true }); +}); From 2605c6ce84e6567170d855d565325945ae2eb871 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:50:25 -0400 Subject: [PATCH 11/28] fix(converter): accept oxlint's real JSON shape, cache file reads Validated against oxlint 1.61.0: the output is an object wrapping the diagnostics array (`{"diagnostics": [...], "number_of_files": N, ...}`), not a bare array as the initial spec assumed. Bare arrays still parse for forward-compatibility. Cache file reads so multi-diagnostic files aren't re-read per diagnostic. Spec updated to reflect the real shape. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-04-21-oxlint-migration-design.md | 28 +++++--- oxlint-to-rdjsonl.js | 30 ++++++-- oxlint-to-rdjsonl.test.js | 69 +++++++++++++++++++ 3 files changed, 112 insertions(+), 15 deletions(-) diff --git a/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md b/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md index d6b6810..d4531e0 100644 --- a/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md +++ b/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md @@ -96,20 +96,32 @@ Pipefail is not enabled (matches current behavior). Reviewdog's exit code is the Stdin-to-stdout converter. Node built-ins only; no devDeps. -**Input:** oxlint's JSON output — a JSON array of diagnostics rendered by miette's `JSONReportHandler`: +**Input:** oxlint's JSON output — a top-level object wrapping the diagnostics array: ```json { - "message": "...", - "code": "eslint(no-unused-vars)", - "severity": "error" | "warning" | "advice", - "url": "https://oxc.rs/...", - "help": "...", - "filename": "path/to/file.js", - "labels": [{ "span": { "offset": 123, "length": 5 } }] + "diagnostics": [ + { + "message": "...", + "code": "eslint(no-unused-vars)", + "severity": "error" | "warning" | "advice", + "url": "https://oxc.rs/...", + "help": "...", + "filename": "path/to/file.js", + "labels": [{ "span": { "offset": 123, "length": 5, "line": 10, "column": 5 } }] + } + ], + "number_of_files": 1, + "number_of_rules": 93, + "threads_count": 12, + "start_time": 0.01 } ``` +Note: oxlint's span also includes pre-computed 1-based byte `line`/`column` for the span start, but not for the end. The converter derives start and end positions from `offset`/`length` via file reading (which yields the same values as oxlint's pre-computed start), keeping a single code path that also yields the end position oxlint doesn't emit. + +For robustness, the converter accepts either the object form (`{diagnostics: [...]}`) or a bare array. + **Output:** rdjsonl — one JSON object per line: ```json diff --git a/oxlint-to-rdjsonl.js b/oxlint-to-rdjsonl.js index 4adc883..5176db2 100644 --- a/oxlint-to-rdjsonl.js +++ b/oxlint-to-rdjsonl.js @@ -84,8 +84,21 @@ function readStdin() { }); } -function readFileSafe(filename) { - return require('node:fs').readFileSync(filename); +function extractDiagnostics(parsed) { + if (Array.isArray(parsed)) return parsed; + if (parsed && Array.isArray(parsed.diagnostics)) return parsed.diagnostics; + return null; +} + +function makeCachingFileReader() { + const fs = require('node:fs'); + const cache = new Map(); + return (filename) => { + if (cache.has(filename)) return cache.get(filename); + const buf = fs.readFileSync(filename); + cache.set(filename, buf); + return buf; + }; } async function main() { @@ -94,18 +107,19 @@ async function main() { if (text === '') { return 0; } - let diagnostics; + let parsed; try { - diagnostics = JSON.parse(text); + parsed = JSON.parse(text); } catch (err) { process.stderr.write(`oxlint-to-rdjsonl: failed to parse oxlint JSON on stdin: ${err.message}\n`); return 1; } - if (!Array.isArray(diagnostics)) { - process.stderr.write(`oxlint-to-rdjsonl: expected a JSON array on stdin, got ${typeof diagnostics}\n`); + const diagnostics = extractDiagnostics(parsed); + if (diagnostics === null) { + process.stderr.write(`oxlint-to-rdjsonl: expected an array or { diagnostics: [...] } on stdin\n`); return 1; } - const out = convert(diagnostics, readFileSafe); + const out = convert(diagnostics, makeCachingFileReader()); for (const d of out) { process.stdout.write(JSON.stringify(d) + '\n'); } @@ -118,6 +132,8 @@ module.exports = { positionFromOffset, convertDiagnostic, convert, + extractDiagnostics, + makeCachingFileReader, main, }; diff --git a/oxlint-to-rdjsonl.test.js b/oxlint-to-rdjsonl.test.js index 1194bc7..d5587cd 100644 --- a/oxlint-to-rdjsonl.test.js +++ b/oxlint-to-rdjsonl.test.js @@ -260,3 +260,72 @@ test('cli: one diagnostic -> one rdjsonl line', () => { assert.equal(parsed.code.value, 'no-unused-vars'); fs.rmSync(tmp, { recursive: true, force: true }); }); + +test('cli: real oxlint output shape ({ diagnostics: [...], ... }) is accepted', () => { + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'oxlint-cli-')); + const fixture = path.join(tmp, 'sample.js'); + fs.writeFileSync(fixture, 'var unusedVar = 1;\n'); + const input = JSON.stringify({ + diagnostics: [ + { + message: "Variable 'unusedVar' is declared but never used.", + code: 'eslint(no-unused-vars)', + severity: 'warning', + url: 'https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-unused-vars.html', + filename: fixture, + labels: [{ span: { offset: 4, length: 9, line: 1, column: 5 } }], + }, + ], + number_of_files: 1, + number_of_rules: 93, + threads_count: 12, + start_time: 0.01, + }); + const r = runCli(input); + assert.equal(r.status, 0, r.stderr); + const lines = r.stdout.trim().split('\n'); + assert.equal(lines.length, 1); + const parsed = JSON.parse(lines[0]); + assert.equal(parsed.severity, 'WARNING'); + assert.deepEqual(parsed.location.range, { + start: { line: 1, column: 5 }, + end: { line: 1, column: 14 }, + }); + fs.rmSync(tmp, { recursive: true, force: true }); +}); + +test('cli: garbage object (no diagnostics key) -> exit 1', () => { + const r = runCli('{"foo": 1}'); + assert.equal(r.status, 1); + assert.match(r.stderr, /diagnostics/); +}); + +const { extractDiagnostics, makeCachingFileReader } = require('./oxlint-to-rdjsonl'); + +test('extractDiagnostics: bare array passes through', () => { + assert.deepEqual(extractDiagnostics([{ a: 1 }]), [{ a: 1 }]); +}); + +test('extractDiagnostics: { diagnostics: [...] } unwraps', () => { + assert.deepEqual(extractDiagnostics({ diagnostics: [{ a: 1 }], other: 2 }), [{ a: 1 }]); +}); + +test('extractDiagnostics: null for non-matching shapes', () => { + assert.equal(extractDiagnostics({ foo: 1 }), null); + assert.equal(extractDiagnostics(null), null); + assert.equal(extractDiagnostics('string'), null); +}); + +test('makeCachingFileReader: reads each file once', () => { + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'oxlint-cache-')); + const p = path.join(tmp, 'x.js'); + fs.writeFileSync(p, 'abc'); + const reader = makeCachingFileReader(); + const first = reader(p); + // Mutate the file on disk; cached read should not reflect the change. + fs.writeFileSync(p, 'xyz'); + const second = reader(p); + assert.equal(first.toString(), 'abc'); + assert.equal(second.toString(), 'abc'); + fs.rmSync(tmp, { recursive: true, force: true }); +}); From 7f18352b6afee6b00e7364b56c5d540ba4c40058 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:53:06 -0400 Subject: [PATCH 12/28] feat(action): rename inputs eslint_flags -> oxlint_flags, drop node_options Co-Authored-By: Claude Opus 4.7 (1M context) --- action.yml | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/action.yml b/action.yml index 2473895..aeafa63 100644 --- a/action.yml +++ b/action.yml @@ -1,5 +1,5 @@ -name: 'Run eslint with reviewdog' -description: '🐶 Run eslint with reviewdog on pull requests to improve code review experience.' +name: 'Run oxlint with reviewdog' +description: '🐶 Run oxlint with reviewdog on pull requests to improve code review experience.' author: 'haya14busa (reviewdog)' inputs: github_token: @@ -41,22 +41,18 @@ inputs: description: 'Additional reviewdog flags' required: false default: '' - eslint_flags: - description: "flags and args of eslint command. Default: '.'" + oxlint_flags: + description: "flags and args of oxlint command. Default: '.'" required: false default: '.' workdir: - description: "The directory from which to look for and run eslint. Default '.'" + description: "The directory from which to look for and run oxlint. Default '.'" required: false default: '.' tool_name: description: 'Tool name to use for reviewdog reporter' required: false - default: 'eslint' - node_options: - description: 'NODE_OPTIONS for running eslint' - required: false - default: '' + default: 'oxlint' runs: using: 'composite' steps: @@ -64,8 +60,6 @@ runs: shell: bash env: REVIEWDOG_VERSION: v0.21.0 - # INPUT_ is not available in Composite run steps - # https://github.community/t/input-variable-name-is-not-available-in-composite-run-steps/127611 INPUT_GITHUB_TOKEN: ${{ inputs.github_token }} INPUT_LEVEL: ${{ inputs.level }} INPUT_REPORTER: ${{ inputs.reporter }} @@ -73,10 +67,9 @@ runs: INPUT_FAIL_LEVEL: ${{ inputs.fail_level }} INPUT_FAIL_ON_ERROR: ${{ inputs.fail_on_error }} INPUT_REVIEWDOG_FLAGS: ${{ inputs.reviewdog_flags }} - INPUT_ESLINT_FLAGS: ${{ inputs.eslint_flags }} + INPUT_OXLINT_FLAGS: ${{ inputs.oxlint_flags }} INPUT_WORKDIR: ${{ inputs.workdir }} INPUT_TOOL_NAME: ${{ inputs.tool_name }} - NODE_OPTIONS: ${{ inputs.node_options }} branding: icon: 'alert-octagon' color: 'blue' From e34d401bf7b1777a4ad2a401b429717eab882d68 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:53:57 -0400 Subject: [PATCH 13/28] feat(action): swap eslint pipeline for oxlint + rdjsonl converter Co-Authored-By: Claude Opus 4.7 (1M context) --- script.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/script.sh b/script.sh index 6ec56a5..005e404 100755 --- a/script.sh +++ b/script.sh @@ -5,26 +5,26 @@ cd "${GITHUB_WORKSPACE}/${INPUT_WORKDIR}" || exit 1 TEMP_PATH="$(mktemp -d)" PATH="${TEMP_PATH}:$PATH" export REVIEWDOG_GITHUB_API_TOKEN="${INPUT_GITHUB_TOKEN}" -ESLINT_FORMATTER="${GITHUB_ACTION_PATH}/eslint-formatter-rdjson/index.js" echo '::group::🐶 Installing reviewdog ... https://github.com/reviewdog/reviewdog' curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s -- -b "${TEMP_PATH}" "${REVIEWDOG_VERSION}" 2>&1 echo '::endgroup::' -npx --no-install -c 'eslint --version' +npx --no-install -c 'oxlint --version' 2>/dev/null if [ $? -ne 0 ]; then - echo '::group:: Running `npm install` to install eslint ...' + echo '::group:: Running `npm install` to install oxlint ...' set -e npm install set +e echo '::endgroup::' fi -echo "eslint version:$(npx --no-install -c 'eslint --version')" +echo "oxlint version:$(npx --no-install -c 'oxlint --version')" -echo '::group:: Running eslint with reviewdog 🐶 ...' -npx --no-install -c "eslint -f="${ESLINT_FORMATTER}" ${INPUT_ESLINT_FLAGS:-'.'}" \ - | reviewdog -f=rdjson \ +echo '::group:: Running oxlint with reviewdog 🐶 ...' +npx --no-install -c "oxlint --format=json ${INPUT_OXLINT_FLAGS:-'.'}" \ + | node "${GITHUB_ACTION_PATH}/oxlint-to-rdjsonl.js" \ + | reviewdog -f=rdjsonl \ -name="${INPUT_TOOL_NAME}" \ -reporter="${INPUT_REPORTER:-github-pr-review}" \ -filter-mode="${INPUT_FILTER_MODE}" \ From ceb1134c035a230c300ab961ead0d4b632af235b Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:54:18 -0400 Subject: [PATCH 14/28] chore: remove bundled eslint-formatter-rdjson Co-Authored-By: Claude Opus 4.7 (1M context) --- eslint-formatter-rdjson/index.js | 186 ----- eslint-formatter-rdjson/package.json | 29 - .../test-update-ok-file.sh | 8 - eslint-formatter-rdjson/test.sh | 9 - eslint-formatter-rdjson/testdata/.gitignore | 1 - eslint-formatter-rdjson/testdata/result.ok | 742 ------------------ 6 files changed, 975 deletions(-) delete mode 100644 eslint-formatter-rdjson/index.js delete mode 100644 eslint-formatter-rdjson/package.json delete mode 100755 eslint-formatter-rdjson/test-update-ok-file.sh delete mode 100755 eslint-formatter-rdjson/test.sh delete mode 100644 eslint-formatter-rdjson/testdata/.gitignore delete mode 100644 eslint-formatter-rdjson/testdata/result.ok diff --git a/eslint-formatter-rdjson/index.js b/eslint-formatter-rdjson/index.js deleted file mode 100644 index 97d1825..0000000 --- a/eslint-formatter-rdjson/index.js +++ /dev/null @@ -1,186 +0,0 @@ -// ESLint Formatter to Output Reviewdog Diagnostic Format (RDFormat) -// https://github.com/reviewdog/reviewdog/blob/1d8f6d6897dcfa67c33a2ccdc2ea23a8cca96c8c/proto/rdf/reviewdog.proto - -// https://github.com/eslint/eslint/blob/091e52ae1ca408f3e668f394c14d214c9ce806e6/lib/shared/types.js#L11 -// https://github.com/eslint/eslint/blob/82669fa66670a00988db5b1d10fe8f3bf30be84e/lib/shared/config-validator.js#L40 -function convertSeverity(s) { - if (s === 0) { // off - return 'INFO'; - } else if (s === 1) { - return 'WARNING'; - } else if (s === 2) { - return 'ERROR'; - } - return 'UNKNOWN_SEVERITY'; -} - -function isHighSurrogate(ch) { - return 0xD800 <= ch && ch < 0xDC00; -} - -function isLowSurrogate(ch) { - return 0xDC00 <= ch && ch < 0xE000; -} - -function utf8length(str) { - let length = 0; - for (let i = 0; i < str.length; i++) { - const ch = str.charCodeAt(i); - if (isHighSurrogate(ch)) { - i++; - length += 4; - if (i >= str.length || !isLowSurrogate(str.charCodeAt(i))) { - throw new Error("invalid surrogate character"); - } - } else if (isLowSurrogate(ch)) { - throw new Error("invalid surrogate character"); - } else if (ch < 0x80) { - length++; - } else if (ch < 0x0800) { - length += 2; - } else { - length += 3; - } - } - return length; -} - -function positionFromUTF16CodeUnitOffset(offset, text) { - const lines = text.split('\n'); - let lnum = 1; - let column = 0; - let lengthSoFar = 0; - for (const line of lines) { - if (offset <= lengthSoFar + line.length) { - const lineText = line.slice(0, offset-lengthSoFar); - // +1 because eslint offset is a bit weird and will append text right - // after the offset. - column = utf8length(lineText) + 1; - break; - } - lengthSoFar += line.length + 1; // +1 for line-break. - lnum++; - } - return {line: lnum, column: column}; -} - -// How to get UTF-8 column from UTF-16 code unit column. -// 1. Extract the line text until the column (exclusive). -// This is important when the character at the column is surrogate pair. -// 2. Count length of the extracted line text in UTF-8. -// 3. +1 to the length to get the UTF-8 column. -// -// Example: -// - sourceLines: ["haya🐶🐱busa"] -// - line: 1 -// - column: 7 -// - Expected output: {line: 1, column: 9} -// -// Ref: -// - UTF-16 length("🐶"): 2 -// - UTF-8 length("🐶"): 4 -// v------- INPUT: {line: 1, column: 7} -// haya🐶🐱busa -// UTF-16 Column (input): 12345 7 9012 -// UTF-8 Column (output): 12345 9 3456 -// ~~~~~~ <= utf8length("haya🐶") = 8 -// -// The given position points to "🐱" (line:1, column: 7) -// 1. Extract the line text until the column (exclusive): "haya🐶" -// 2. Count length of the extracted line text in UTF-8: utf8length("haya🐶") = 8 -// 3. +1 to the length to get the UTF-8 column: 9 -function positionFromLineAndUTF16CodeUnitOffsetColumn(line, column, sourceLines) { - let col = 0; - if (sourceLines.length >= line) { - // 1. Extract the line text until the column (exclusive) - const lineText = sourceLines[line-1].slice(0, column-1); - // 2&3. Count length of the extracted line text in UTF-8 and +1. - col = utf8length(lineText) + 1; - } - return {line: line, column: col}; -} - -function commonSuffixLength(str1, str2) { - let i = 0; - let seenSurrogate = false; - for (i = 0; i < str1.length && i < str2.length; ++i) { - const ch1 = str1.charCodeAt(str1.length-(i+1)); - const ch2 = str2.charCodeAt(str2.length-(i+1)); - if (ch1 !== ch2) { - if (seenSurrogate) { - if (!isHighSurrogate(ch1) || !isHighSurrogate(ch2)) { - throw new Error("invalid surrogate character"); - } - // i is now between a low surrogate and a high surrogate. - // we need to remove the low surrogate from the common suffix - // to avoid breaking surrogate pairs. - i--; - } - break; - } - seenSurrogate = isLowSurrogate(ch1); - } - return i; -} - -function buildMinimumSuggestion(fix, source) { - const l = commonSuffixLength(fix.text, source.slice(fix.range[0], fix.range[1])); - return { - range: { - start: positionFromUTF16CodeUnitOffset(fix.range[0], source), - end: positionFromUTF16CodeUnitOffset(fix.range[1] - l, source) - }, - text: fix.text.slice(0, fix.text.length - l) - }; -} - -module.exports = function (results, data) { - const rdjson = { - source: { - name: 'eslint', - url: 'https://eslint.org/' - }, - diagnostics: [] - }; - - results.forEach(result => { - const filePath = result.filePath; - const source = result.source; - const sourceLines = source ? source.split('\n') : []; - result.messages.forEach(msg => { - const diagnostic = { - message: msg.message, - location: { - path: filePath, - range: { - start: positionFromLineAndUTF16CodeUnitOffsetColumn(msg.line, msg.column, sourceLines) - } - }, - severity: convertSeverity(msg.severity), - code: { - value: msg.ruleId, - url: (data.rulesMeta[msg.ruleId] && data.rulesMeta[msg.ruleId].docs ? data.rulesMeta[msg.ruleId].docs.url : '') - }, - original_output: JSON.stringify(msg) - }; - - // the end of the range is optional - if (msg.endLine && msg.endColumn) { - diagnostic.location.range.end = positionFromLineAndUTF16CodeUnitOffsetColumn(msg.endLine, msg.endColumn, sourceLines) - } - - if (msg.fix) { - diagnostic.suggestions ??= []; - diagnostic.suggestions.push(buildMinimumSuggestion(msg.fix, source)); - } - - if (msg.suggestions) { - diagnostic.suggestions ??= []; - diagnostic.suggestions.push(...msg.suggestions.map(s => buildMinimumSuggestion(s.fix, source))); - } - - rdjson.diagnostics.push(diagnostic); - }); - }); - return JSON.stringify(rdjson); -}; diff --git a/eslint-formatter-rdjson/package.json b/eslint-formatter-rdjson/package.json deleted file mode 100644 index 8839abc..0000000 --- a/eslint-formatter-rdjson/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "eslint-formatter-rdjson", - "version": "1.1.0", - "description": "ESLint Formatter for the Reviewdog Diagnostic Format (RDFormat)", - "main": "./index.js", - "exports": "./index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/reviewdog/action-eslint.git" - }, - "keywords": [ - "eslint", - "eslint", - "formatter", - "formatter", - "rdjson", - "reviewdog", - "rdformat" - ], - "author": "haya14busa", - "license": "MIT", - "bugs": { - "url": "https://github.com/reviewdog/action-eslint/issues" - }, - "homepage": "https://github.com/reviewdog/action-eslint#readme" -} diff --git a/eslint-formatter-rdjson/test-update-ok-file.sh b/eslint-formatter-rdjson/test-update-ok-file.sh deleted file mode 100755 index 5e2b2cd..0000000 --- a/eslint-formatter-rdjson/test-update-ok-file.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# Expected to run from the root repository. -set -eux -CWD=$(pwd) -npx eslint ./testdata/*.js -f ./eslint-formatter-rdjson/index.js \ - | jq . \ - | sed -e "s!${CWD}/!!g" \ - > eslint-formatter-rdjson/testdata/result.ok diff --git a/eslint-formatter-rdjson/test.sh b/eslint-formatter-rdjson/test.sh deleted file mode 100755 index eb5df88..0000000 --- a/eslint-formatter-rdjson/test.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# Expected to run from the root repository. -set -eux -CWD=$(pwd) -npx eslint ./testdata/*.js -f ./eslint-formatter-rdjson/index.js \ - | jq . \ - | sed -e "s!${CWD}/!!g" \ - > eslint-formatter-rdjson/testdata/result.out -diff -u eslint-formatter-rdjson/testdata/result.* diff --git a/eslint-formatter-rdjson/testdata/.gitignore b/eslint-formatter-rdjson/testdata/.gitignore deleted file mode 100644 index f47cb20..0000000 --- a/eslint-formatter-rdjson/testdata/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.out diff --git a/eslint-formatter-rdjson/testdata/result.ok b/eslint-formatter-rdjson/testdata/result.ok deleted file mode 100644 index 6eaa3c6..0000000 --- a/eslint-formatter-rdjson/testdata/result.ok +++ /dev/null @@ -1,742 +0,0 @@ -{ - "source": { - "name": "eslint", - "url": "https://eslint.org/" - }, - "diagnostics": [ - { - "message": "Parsing error: Unexpected character '🐶'", - "location": { - "path": "testdata/error.js", - "range": { - "start": { - "line": 1, - "column": 1 - } - } - }, - "severity": "ERROR", - "code": { - "value": null, - "url": "" - }, - "original_output": "{\"ruleId\":null,\"fatal\":true,\"severity\":2,\"message\":\"Parsing error: Unexpected character '🐶'\",\"line\":1,\"column\":1,\"nodeType\":null}" - }, - { - "message": "'test' is defined but never used.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 2, - "column": 10 - }, - "end": { - "line": 2, - "column": 14 - } - } - }, - "severity": "ERROR", - "code": { - "value": "no-unused-vars", - "url": "https://eslint.org/docs/latest/rules/no-unused-vars" - }, - "original_output": "{\"ruleId\":\"no-unused-vars\",\"severity\":2,\"message\":\"'test' is defined but never used.\",\"line\":2,\"column\":10,\"nodeType\":\"Identifier\",\"messageId\":\"unusedVar\",\"endLine\":2,\"endColumn\":14}" - }, - { - "message": "Missing space before function parentheses.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 2, - "column": 14 - }, - "end": { - "line": 2, - "column": 15 - } - } - }, - "severity": "ERROR", - "code": { - "value": "space-before-function-paren", - "url": "https://eslint.org/docs/latest/rules/space-before-function-paren" - }, - "original_output": "{\"ruleId\":\"space-before-function-paren\",\"severity\":2,\"message\":\"Missing space before function parentheses.\",\"line\":2,\"column\":14,\"nodeType\":\"FunctionDeclaration\",\"messageId\":\"missingSpace\",\"endLine\":2,\"endColumn\":15,\"fix\":{\"range\":[22,22],\"text\":\" \"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 2, - "column": 14 - }, - "end": { - "line": 2, - "column": 14 - } - }, - "text": " " - } - ] - }, - { - "message": "The update clause in this loop moves the variable in the wrong direction.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 3, - "column": 3 - }, - "end": { - "line": 6, - "column": 4 - } - } - }, - "severity": "ERROR", - "code": { - "value": "for-direction", - "url": "https://eslint.org/docs/latest/rules/for-direction" - }, - "original_output": "{\"ruleId\":\"for-direction\",\"severity\":2,\"message\":\"The update clause in this loop moves the variable in the wrong direction.\",\"line\":3,\"column\":3,\"nodeType\":\"ForStatement\",\"messageId\":\"incorrectDirection\",\"endLine\":6,\"endColumn\":4}" - }, - { - "message": "Unexpected var, use let or const instead.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 3, - "column": 8 - }, - "end": { - "line": 3, - "column": 17 - } - } - }, - "severity": "WARNING", - "code": { - "value": "no-var", - "url": "https://eslint.org/docs/latest/rules/no-var" - }, - "original_output": "{\"ruleId\":\"no-var\",\"severity\":1,\"message\":\"Unexpected var, use let or const instead.\",\"line\":3,\"column\":8,\"nodeType\":\"VariableDeclaration\",\"messageId\":\"unexpectedVar\",\"endLine\":3,\"endColumn\":17,\"fix\":{\"range\":[34,37],\"text\":\"let\"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 3, - "column": 8 - }, - "end": { - "line": 3, - "column": 11 - } - }, - "text": "let" - } - ] - }, - { - "message": "Unexpected var, use let or const instead.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 4, - "column": 5 - }, - "end": { - "line": 4, - "column": 11 - } - } - }, - "severity": "WARNING", - "code": { - "value": "no-var", - "url": "https://eslint.org/docs/latest/rules/no-var" - }, - "original_output": "{\"ruleId\":\"no-var\",\"severity\":1,\"message\":\"Unexpected var, use let or const instead.\",\"line\":4,\"column\":5,\"nodeType\":\"VariableDeclaration\",\"messageId\":\"unexpectedVar\",\"endLine\":4,\"endColumn\":11}" - }, - { - "message": "'a' is defined but never used.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 4, - "column": 9 - }, - "end": { - "line": 4, - "column": 10 - } - } - }, - "severity": "ERROR", - "code": { - "value": "no-unused-vars", - "url": "https://eslint.org/docs/latest/rules/no-unused-vars" - }, - "original_output": "{\"ruleId\":\"no-unused-vars\",\"severity\":2,\"message\":\"'a' is defined but never used.\",\"line\":4,\"column\":9,\"nodeType\":\"Identifier\",\"messageId\":\"unusedVar\",\"endLine\":4,\"endColumn\":10}" - }, - { - "message": "Missing whitespace after semicolon.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 4, - "column": 10 - }, - "end": { - "line": 4, - "column": 11 - } - } - }, - "severity": "ERROR", - "code": { - "value": "semi-spacing", - "url": "https://eslint.org/docs/latest/rules/semi-spacing" - }, - "original_output": "{\"ruleId\":\"semi-spacing\",\"severity\":2,\"message\":\"Missing whitespace after semicolon.\",\"line\":4,\"column\":10,\"nodeType\":\"VariableDeclaration\",\"messageId\":\"missingWhitespaceAfter\",\"endLine\":4,\"endColumn\":11,\"fix\":{\"range\":[70,70],\"text\":\" \"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 4, - "column": 11 - }, - "end": { - "line": 4, - "column": 11 - } - }, - "text": " " - } - ] - }, - { - "message": "Unexpected var, use let or const instead.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 4, - "column": 11 - }, - "end": { - "line": 4, - "column": 17 - } - } - }, - "severity": "WARNING", - "code": { - "value": "no-var", - "url": "https://eslint.org/docs/latest/rules/no-var" - }, - "original_output": "{\"ruleId\":\"no-var\",\"severity\":1,\"message\":\"Unexpected var, use let or const instead.\",\"line\":4,\"column\":11,\"nodeType\":\"VariableDeclaration\",\"messageId\":\"unexpectedVar\",\"endLine\":4,\"endColumn\":17}" - }, - { - "message": "'b' is defined but never used.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 4, - "column": 15 - }, - "end": { - "line": 4, - "column": 16 - } - } - }, - "severity": "ERROR", - "code": { - "value": "no-unused-vars", - "url": "https://eslint.org/docs/latest/rules/no-unused-vars" - }, - "original_output": "{\"ruleId\":\"no-unused-vars\",\"severity\":2,\"message\":\"'b' is defined but never used.\",\"line\":4,\"column\":15,\"nodeType\":\"Identifier\",\"messageId\":\"unusedVar\",\"endLine\":4,\"endColumn\":16}" - }, - { - "message": "Extra semicolon.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 4, - "column": 16 - }, - "end": { - "line": 4, - "column": 17 - } - } - }, - "severity": "ERROR", - "code": { - "value": "semi", - "url": "https://eslint.org/docs/latest/rules/semi" - }, - "original_output": "{\"ruleId\":\"semi\",\"severity\":2,\"message\":\"Extra semicolon.\",\"line\":4,\"column\":16,\"nodeType\":\"VariableDeclaration\",\"messageId\":\"extraSemi\",\"endLine\":4,\"endColumn\":17,\"fix\":{\"range\":[74,97],\"text\":\"b//comment\\n console\"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 4, - "column": 15 - }, - "end": { - "line": 4, - "column": 17 - } - }, - "text": "b" - } - ] - }, - { - "message": "Expected space or tab after '//' in comment.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 4, - "column": 17 - }, - "end": { - "line": 4, - "column": 26 - } - } - }, - "severity": "ERROR", - "code": { - "value": "spaced-comment", - "url": "https://eslint.org/docs/latest/rules/spaced-comment" - }, - "original_output": "{\"ruleId\":\"spaced-comment\",\"severity\":2,\"message\":\"Expected space or tab after '//' in comment.\",\"line\":4,\"column\":17,\"nodeType\":\"Line\",\"messageId\":\"expectedSpaceAfter\",\"endLine\":4,\"endColumn\":26,\"fix\":{\"range\":[78,78],\"text\":\" \"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 4, - "column": 19 - }, - "end": { - "line": 4, - "column": 19 - } - }, - "text": " " - } - ] - }, - { - "message": "Extra semicolon.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 5, - "column": 19 - }, - "end": { - "line": 5, - "column": 20 - } - } - }, - "severity": "ERROR", - "code": { - "value": "semi", - "url": "https://eslint.org/docs/latest/rules/semi" - }, - "original_output": "{\"ruleId\":\"semi\",\"severity\":2,\"message\":\"Extra semicolon.\",\"line\":5,\"column\":19,\"nodeType\":\"ExpressionStatement\",\"messageId\":\"extraSemi\",\"endLine\":5,\"endColumn\":20,\"fix\":{\"range\":[103,109],\"text\":\")\\n }\"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 5, - "column": 18 - }, - "end": { - "line": 5, - "column": 20 - } - }, - "text": ")" - } - ] - }, - { - "message": "'test2' is defined but never used.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 9, - "column": 37 - }, - "end": { - "line": 9, - "column": 42 - } - } - }, - "severity": "ERROR", - "code": { - "value": "no-unused-vars", - "url": "https://eslint.org/docs/latest/rules/no-unused-vars" - }, - "original_output": "{\"ruleId\":\"no-unused-vars\",\"severity\":2,\"message\":\"'test2' is defined but never used.\",\"line\":9,\"column\":25,\"nodeType\":\"Identifier\",\"messageId\":\"unusedVar\",\"endLine\":9,\"endColumn\":30}" - }, - { - "message": "Missing space before function parentheses.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 9, - "column": 42 - }, - "end": { - "line": 9, - "column": 43 - } - } - }, - "severity": "ERROR", - "code": { - "value": "space-before-function-paren", - "url": "https://eslint.org/docs/latest/rules/space-before-function-paren" - }, - "original_output": "{\"ruleId\":\"space-before-function-paren\",\"severity\":2,\"message\":\"Missing space before function parentheses.\",\"line\":9,\"column\":30,\"nodeType\":\"FunctionDeclaration\",\"messageId\":\"missingSpace\",\"endLine\":9,\"endColumn\":31,\"fix\":{\"range\":[142,142],\"text\":\" \"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 9, - "column": 42 - }, - "end": { - "line": 9, - "column": 42 - } - }, - "text": " " - } - ] - }, - { - "message": "The update clause in this loop moves the variable in the wrong direction.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 10, - "column": 3 - }, - "end": { - "line": 13, - "column": 4 - } - } - }, - "severity": "ERROR", - "code": { - "value": "for-direction", - "url": "https://eslint.org/docs/latest/rules/for-direction" - }, - "original_output": "{\"ruleId\":\"for-direction\",\"severity\":2,\"message\":\"The update clause in this loop moves the variable in the wrong direction.\",\"line\":10,\"column\":3,\"nodeType\":\"ForStatement\",\"messageId\":\"incorrectDirection\",\"endLine\":13,\"endColumn\":4}" - }, - { - "message": "Unexpected var, use let or const instead.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 10, - "column": 8 - }, - "end": { - "line": 10, - "column": 17 - } - } - }, - "severity": "WARNING", - "code": { - "value": "no-var", - "url": "https://eslint.org/docs/latest/rules/no-var" - }, - "original_output": "{\"ruleId\":\"no-var\",\"severity\":1,\"message\":\"Unexpected var, use let or const instead.\",\"line\":10,\"column\":8,\"nodeType\":\"VariableDeclaration\",\"messageId\":\"unexpectedVar\",\"endLine\":10,\"endColumn\":17,\"fix\":{\"range\":[154,157],\"text\":\"let\"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 10, - "column": 8 - }, - "end": { - "line": 10, - "column": 11 - } - }, - "text": "let" - } - ] - }, - { - "message": "Redundant double negation.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 11, - "column": 9 - }, - "end": { - "line": 11, - "column": 12 - } - } - }, - "severity": "ERROR", - "code": { - "value": "no-extra-boolean-cast", - "url": "https://eslint.org/docs/latest/rules/no-extra-boolean-cast" - }, - "original_output": "{\"ruleId\":\"no-extra-boolean-cast\",\"severity\":2,\"message\":\"Redundant double negation.\",\"line\":11,\"column\":9,\"nodeType\":\"UnaryExpression\",\"messageId\":\"unexpectedNegation\",\"endLine\":11,\"endColumn\":12,\"fix\":{\"range\":[188,191],\"text\":\"i\"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 11, - "column": 9 - }, - "end": { - "line": 11, - "column": 11 - } - }, - "text": "" - } - ] - }, - { - "message": "Empty block statement.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 11, - "column": 14 - }, - "end": { - "line": 12, - "column": 6 - } - } - }, - "severity": "ERROR", - "code": { - "value": "no-empty", - "url": "https://eslint.org/docs/latest/rules/no-empty" - }, - "original_output": "{\"ruleId\":\"no-empty\",\"severity\":2,\"message\":\"Empty block statement.\",\"line\":11,\"column\":14,\"nodeType\":\"BlockStatement\",\"messageId\":\"unexpected\",\"endLine\":12,\"endColumn\":6,\"suggestions\":[{\"messageId\":\"suggestComment\",\"data\":{\"type\":\"block\"},\"fix\":{\"range\":[194,199],\"text\":\" /* empty */ \"},\"desc\":\"Add comment inside empty block statement.\"}]}", - "suggestions": [ - { - "range": { - "start": { - "line": 11, - "column": 15 - }, - "end": { - "line": 12, - "column": 4 - } - }, - "text": " /* empty */" - } - ] - }, - { - "message": "Unnecessary semicolon.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 14, - "column": 2 - }, - "end": { - "line": 14, - "column": 3 - } - } - }, - "severity": "ERROR", - "code": { - "value": "no-extra-semi", - "url": "https://eslint.org/docs/latest/rules/no-extra-semi" - }, - "original_output": "{\"ruleId\":\"no-extra-semi\",\"severity\":2,\"message\":\"Unnecessary semicolon.\",\"line\":14,\"column\":2,\"nodeType\":\"EmptyStatement\",\"messageId\":\"unexpected\",\"endLine\":14,\"endColumn\":3,\"fix\":{\"range\":[205,217],\"text\":\"}\\n\\nfunction\"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 14, - "column": 1 - }, - "end": { - "line": 14, - "column": 3 - } - }, - "text": "}" - } - ] - }, - { - "message": "'f' is defined but never used.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 16, - "column": 10 - }, - "end": { - "line": 16, - "column": 11 - } - } - }, - "severity": "ERROR", - "code": { - "value": "no-unused-vars", - "url": "https://eslint.org/docs/latest/rules/no-unused-vars" - }, - "original_output": "{\"ruleId\":\"no-unused-vars\",\"severity\":2,\"message\":\"'f' is defined but never used.\",\"line\":16,\"column\":10,\"nodeType\":\"Identifier\",\"messageId\":\"unusedVar\",\"endLine\":16,\"endColumn\":11}" - }, - { - "message": "Missing space before function parentheses.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 16, - "column": 11 - }, - "end": { - "line": 16, - "column": 12 - } - } - }, - "severity": "ERROR", - "code": { - "value": "space-before-function-paren", - "url": "https://eslint.org/docs/latest/rules/space-before-function-paren" - }, - "original_output": "{\"ruleId\":\"space-before-function-paren\",\"severity\":2,\"message\":\"Missing space before function parentheses.\",\"line\":16,\"column\":11,\"nodeType\":\"FunctionDeclaration\",\"messageId\":\"missingSpace\",\"endLine\":16,\"endColumn\":12,\"fix\":{\"range\":[219,219],\"text\":\" \"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 16, - "column": 11 - }, - "end": { - "line": 16, - "column": 11 - } - }, - "text": " " - } - ] - }, - { - "message": "Opening curly brace does not appear on the same line as controlling statement.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 17, - "column": 1 - }, - "end": { - "line": 17, - "column": 2 - } - } - }, - "severity": "ERROR", - "code": { - "value": "brace-style", - "url": "https://eslint.org/docs/latest/rules/brace-style" - }, - "original_output": "{\"ruleId\":\"brace-style\",\"severity\":2,\"message\":\"Opening curly brace does not appear on the same line as controlling statement.\",\"line\":17,\"column\":1,\"nodeType\":\"Punctuator\",\"messageId\":\"nextLineOpen\",\"endLine\":17,\"endColumn\":2,\"fix\":{\"range\":[221,222],\"text\":\" \"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 16, - "column": 13 - }, - "end": { - "line": 17, - "column": 1 - } - }, - "text": " " - } - ] - }, - { - "message": "Extra semicolon.", - "location": { - "path": "testdata/test.js", - "range": { - "start": { - "line": 18, - "column": 22 - }, - "end": { - "line": 18, - "column": 23 - } - } - }, - "severity": "ERROR", - "code": { - "value": "semi", - "url": "https://eslint.org/docs/latest/rules/semi" - }, - "original_output": "{\"ruleId\":\"semi\",\"severity\":2,\"message\":\"Extra semicolon.\",\"line\":18,\"column\":20,\"nodeType\":\"ExpressionStatement\",\"messageId\":\"extraSemi\",\"endLine\":18,\"endColumn\":21,\"fix\":{\"range\":[242,246],\"text\":\")\\n}\"}}", - "suggestions": [ - { - "range": { - "start": { - "line": 18, - "column": 21 - }, - "end": { - "line": 18, - "column": 23 - } - }, - "text": ")" - } - ] - } - ] -} From 44030c384df4d566f0ff65add768e54d9b8ef807 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:54:31 -0400 Subject: [PATCH 15/28] chore: remove repo-root eslint config and package manifest Co-Authored-By: Claude Opus 4.7 (1M context) --- .eslintrc.js | 20 - package-lock.json | 2374 --------------------------------------------- package.json | 31 - 3 files changed, 2425 deletions(-) delete mode 100644 .eslintrc.js delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 01da002..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - "env": { - "browser": true, - "es6": true - }, - "extends": [ - "standard", - "eslint:recommended" - ], - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "rules": { - } -}; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 74c3a7a..0000000 --- a/package-lock.json +++ /dev/null @@ -1,2374 +0,0 @@ -{ - "name": "action-eslint", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "action-eslint", - "version": "1.0.0", - "license": "MIT", - "devDependencies": { - "eslint": "^8.0.0", - "eslint-config-standard": "^17.1.0", - "eslint-formatter-rdjson": "file:eslint-formatter-rdjson", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-standard": "^5.0.0" - } - }, - "eslint-formatter-rdjson": { - "version": "1.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", - "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "peer": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/builtins/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.0", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", - "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0" - } - }, - "node_modules/eslint-formatter-rdjson": { - "resolved": "eslint-formatter-rdjson", - "link": true - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" - } - }, - "node_modules/eslint-plugin-es-x": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.1.0.tgz", - "integrity": "sha512-AhiaF31syh4CCQ+C5ccJA0VG6+kJK8+5mXKKE7Qs1xcPRg02CDPOj3mWlQxuWS/AYtg7kxrDNgW9YW3vc0Q+Mw==", - "dev": true, - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.5.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "eslint": ">=8" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-n": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.0.1.tgz", - "integrity": "sha512-CDmHegJN0OF3L5cz5tATH84RPQm9kG+Yx39wIqIwPR2C0uhBGMWfbbOtetR83PQjjidA5aXMu+LEFw1jaSwvTA==", - "dev": true, - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.1.0", - "ignore": "^5.2.4", - "is-core-module": "^2.12.1", - "minimatch": "^3.1.2", - "resolve": "^1.22.2", - "semver": "^7.5.3" - }, - "engines": { - "node": ">=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "peer": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, - "node_modules/eslint-plugin-promise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", - "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-standard": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-5.0.0.tgz", - "integrity": "sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg==", - "deprecated": "standard 16.0.0 and eslint-config-standard 16.0.0 no longer require the eslint-plugin-standard package. You can remove it from your dependencies with 'npm rm eslint-plugin-standard'. More info here: https://github.com/standard/standard/issues/1316", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peerDependencies": { - "eslint": ">=5.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/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/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/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/eslint/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/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", - "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "peer": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module/node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "peer": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 471c25a..0000000 --- a/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "action-eslint", - "version": "1.0.0", - "description": "[![Docker Image CI](https://github.com/reviewdog/action-eslint/workflows/Docker%20Image%20CI/badge.svg)](https://github.com/reviewdog/action-eslint/actions) [![Release](https://img.shields.io/github/release/reviewdog/action-eslint.svg?maxAge=43200)](https://github.com/reviewdog/action-eslint/releases)", - "main": "index.js", - "dependencies": { - }, - "devDependencies": { - "eslint": "^8.0.0", - "eslint-config-standard": "^17.1.0", - "eslint-formatter-rdjson": "file:eslint-formatter-rdjson", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-standard": "^5.0.0" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/reviewdog/action-eslint.git" - }, - "keywords": [], - "author": "", - "license": "MIT", - "bugs": { - "url": "https://github.com/reviewdog/action-eslint/issues" - }, - "homepage": "https://github.com/reviewdog/action-eslint#readme" -} From 789c2c87cbcef8e8e0e4676a8cff62c1a22b6af2 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:56:38 -0400 Subject: [PATCH 16/28] chore: add repo-root oxlint config for test fixtures Co-Authored-By: Claude Opus 4.7 (1M context) --- .oxlintrc.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .oxlintrc.json diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..23d76e7 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json", + "rules": { + "no-unused-vars": "error", + "no-var": "error", + "no-empty": "warn" + }, + "ignorePatterns": [ + "test-subproject/", + "node_modules/" + ] +} From 68ed96e28cd7a79746185a3e350381013d3dfbd2 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 07:58:43 -0400 Subject: [PATCH 17/28] test: rewrite testdata fixtures for oxlint's default rules Smoke-tested against oxlint 1.61.0: empty.js emits no diagnostics; error.js fires no-var + no-unused-vars; test.js fires no-var + no-empty (with a multi-line span). Co-Authored-By: Claude Opus 4.7 (1M context) --- testdata/empty.js | 2 +- testdata/error.js | 2 +- testdata/test.js | 19 +++---------------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/testdata/empty.js b/testdata/empty.js index 8b1a393..e13ea90 100644 --- a/testdata/empty.js +++ b/testdata/empty.js @@ -1 +1 @@ -// empty +export const clean = true; diff --git a/testdata/error.js b/testdata/error.js index c3ace9d..2b5159e 100644 --- a/testdata/error.js +++ b/testdata/error.js @@ -1 +1 @@ -🐶 // test for unexpected character +var unusedVar = 1; diff --git a/testdata/test.js b/testdata/test.js index 3d2ca59..8037a24 100644 --- a/testdata/test.js +++ b/testdata/test.js @@ -1,19 +1,6 @@ -// あいうえお -function test() { - for (var i = 0; i < 10; i--) { - var a;var b;//comment - console.log(i); +function sample() { + for (var i = 0; i < 10; i++) { } } -function /* 🐶 あいうえお */ test2() { - for (var i = 0; i < 10; i--) { - if (!!i) { - } - } -}; - -function f() -{ - console.log('🐶'); -} +sample(); From 2d5659883f246fd07823c4e2d3d322ee669b1668 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 09:01:01 -0400 Subject: [PATCH 18/28] test(subproject): migrate to oxlint, regenerate lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed a subproject-local .oxlintrc.json to shadow the repo-root config's ignorePatterns (which include test-subproject/) — otherwise oxlint considers every subproject file ignored when invoked inside the subproject. Existing sub-testdata/test.js already fires no-var, no-unused-vars, and for-direction under oxlint defaults, so the JS fixture is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- test-subproject/.eslintrc.js | 20 - test-subproject/.oxlintrc.json | 7 + test-subproject/package-lock.json | 2269 ++++------------------------- test-subproject/package.json | 12 +- 4 files changed, 294 insertions(+), 2014 deletions(-) delete mode 100644 test-subproject/.eslintrc.js create mode 100644 test-subproject/.oxlintrc.json diff --git a/test-subproject/.eslintrc.js b/test-subproject/.eslintrc.js deleted file mode 100644 index 11eb727..0000000 --- a/test-subproject/.eslintrc.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - "root": true, - "env": { - "browser": true, - "es6": true - }, - "extends": [ - "standard" - ], - "globals": { - "Atomics": "readonly", - "SharedArrayBuffer": "readonly" - }, - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "rules": { - } -}; diff --git a/test-subproject/.oxlintrc.json b/test-subproject/.oxlintrc.json new file mode 100644 index 0000000..deba903 --- /dev/null +++ b/test-subproject/.oxlintrc.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json", + "rules": { + "no-unused-vars": "warn", + "no-var": "error" + } +} diff --git a/test-subproject/package-lock.json b/test-subproject/package-lock.json index 6beffa4..0471bcc 100644 --- a/test-subproject/package-lock.json +++ b/test-subproject/package-lock.json @@ -1,7 +1,7 @@ { "name": "action-eslint-subproject", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,2075 +9,376 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "eslint": "^8.0.0", - "eslint-config-standard": "^17.0.0", - "eslint-plugin-import": "^2.18.2", - "eslint-plugin-node": "^11.0.0", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-standard": "^5.0.0" + "oxlint": "^1.61.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", - "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.61.0.tgz", + "integrity": "sha512-6eZBPgiigK5txqoVgRqxbaxiom4lM8AP8CyKPPvpzKnQ3iFRFOIDc+0AapF+qsUSwjOzr5SGk4SxQDpQhkSJMQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "*" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.61.0.tgz", + "integrity": "sha512-CkwLR69MUnyv5wjzebvbbtTSUwqLxM35CXE79bHqDIK+NtKmPEUpStTcLQRZMCo4MP0qRT6TXIQVpK0ZVScnMA==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.61.0.tgz", + "integrity": "sha512-8JbefTkbmvqkqWjmQrHke+MdpgT2UghhD/ktM4FOQSpGeCgbMToJEKdl9zwhr/YWTl92i4QI1KiTwVExpcUN8A==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=10.10.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.61.0.tgz", + "integrity": "sha512-uWpoxDT47hTnDLcdEh5jVbso8rlTTu5o0zuqa9J8E0JAKmIWn7kGFEIB03Pycn2hd2vKxybPGLhjURy/9We5FQ==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.61.0.tgz", + "integrity": "sha512-K/o4hEyW7flfMel0iBVznmMBt7VIMHGdjADocHKpK1DUF9erpWnJ+BSSWd2W0c8K3mPtpph+CuHzRU6CI3l9jQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.61.0.tgz", + "integrity": "sha512-P6040ZkcyweJ0Po9yEFqJCdvZnf3VNCGs1SIHgXDf8AAQNC6ID/heXQs9iSgo2FH7gKaKq32VWc59XZwL34C5Q==", + "cpu": [ + "arm" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.61.0.tgz", + "integrity": "sha512-bwxrGCzTZkuB+THv2TQ1aTkVEfv5oz8sl+0XZZCpoYzErJD8OhPQOTA0ENPd1zJz8QsVdSzSrS2umKtPq4/JXg==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.61.0.tgz", + "integrity": "sha512-vkhb9/wKguMkLlrm3FoJW/Xmdv31GgYAE+x8lxxQ+7HeOxXUySI0q36a3NTVIuQUdLzxCI1zzMGsk1o37FOe3w==", + "cpu": [ + "arm64" + ], "dev": true, - "bin": { - "acorn": "bin/acorn" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.61.0.tgz", + "integrity": "sha512-bl1dQh8LnVqsj6oOQAcxwbuOmNJkwc4p6o//HTBZhNTzJy21TLDwAviMqUFNUxDHkPGpmdKTSN4tWTjLryP8xg==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.61.0.tgz", + "integrity": "sha512-QoOX6KB2IiEpyOj/HKqaxi+NQHPnOgNgnr22n9N4ANJCzXkUlj1UmeAbFb4PpqdlHIzvGDM5xZ0OKtcLq9RhiQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.61.0.tgz", + "integrity": "sha512-1TGcTerjY6p152wCof3oKElccq3xHljS/Mucp04gV/4ATpP6nO7YNnp7opEg6SHkv2a57/b4b8Ndm9znJ1/qAw==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.61.0.tgz", + "integrity": "sha512-65wXEmZIrX2ADwC8i/qFL4EWLSbeuBpAm3suuX1vu4IQkKd+wLT/HU/BOl84kp91u2SxPkPDyQgu4yrqp8vwVA==", + "cpu": [ + "riscv64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.61.0.tgz", + "integrity": "sha512-TVvhgMvor7Qa6COeXxCJ7ENOM+lcAOGsQ0iUdPSCv2hxb9qSHLQ4XF1h50S6RE1gBOJ0WV3rNukg4JJJP1LWRA==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/chalk/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==", + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.61.0.tgz", + "integrity": "sha512-SjpS5uYuFoDnDdZPwZE59ndF95AsY47R5MliuneTWR1pDm2CxGJaYXbKULI71t5TVfLQUWmrHEGRL9xvuq6dnA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/chalk/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==", + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.61.0.tgz", + "integrity": "sha512-gGfAeGD4sNJGILZbc/yKcIimO9wQnPMoYp9swAaKeEtwsSQAbU+rsdQze5SBtIP6j0QDzeYd4XSSUCRCF+LIeQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=7.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/chalk/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/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.61.0.tgz", + "integrity": "sha512-OlVT0LrG/ct33EVtWRyR+B/othwmDWeRxfi13wUdPeb3lAT5TgTcFDcfLfarZtzB4W1nWF/zICMgYdkggX2WmQ==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.61.0.tgz", + "integrity": "sha512-vI//NZPJk6DToiovPtaiwD4iQ7kO1r5ReWQD0sOOyKRtP3E2f6jxin4uvwi3OvDzHA2EFfd7DcZl5dtkQh7g1w==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.61.0.tgz", + "integrity": "sha512-0ySj4/4zd2XjePs3XAQq7IigIstN4LPQZgCyigX5/ERMLjdWAJfnxcTsrtxZxuij8guJW8foXuHmhGxW0H4dDA==", + "cpu": [ + "ia32" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=0.10.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.61.0.tgz", + "integrity": "sha512-0xgSiyeqDLDZxXoe9CVJrOx3TUVsfyoOY7cNi03JbItNcC9WCZqrSNdrAbHONxhSPaVh/lzfnDcON1RqSUMhHw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/oxlint": { + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.61.0.tgz", + "integrity": "sha512-ZC0ALuhDZ6ivOFG+sy0D0pEDN49EvsId98zVlmYdkcXHsEM14m/qTNUEsUpiFiCVbpIxYtVBmmLE87nsbUHohQ==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, + "license": "MIT", "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.61.0", + "@oxlint/binding-android-arm64": "1.61.0", + "@oxlint/binding-darwin-arm64": "1.61.0", + "@oxlint/binding-darwin-x64": "1.61.0", + "@oxlint/binding-freebsd-x64": "1.61.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.61.0", + "@oxlint/binding-linux-arm-musleabihf": "1.61.0", + "@oxlint/binding-linux-arm64-gnu": "1.61.0", + "@oxlint/binding-linux-arm64-musl": "1.61.0", + "@oxlint/binding-linux-ppc64-gnu": "1.61.0", + "@oxlint/binding-linux-riscv64-gnu": "1.61.0", + "@oxlint/binding-linux-riscv64-musl": "1.61.0", + "@oxlint/binding-linux-s390x-gnu": "1.61.0", + "@oxlint/binding-linux-x64-gnu": "1.61.0", + "@oxlint/binding-linux-x64-musl": "1.61.0", + "@oxlint/binding-openharmony-arm64": "1.61.0", + "@oxlint/binding-win32-arm64-msvc": "1.61.0", + "@oxlint/binding-win32-ia32-msvc": "1.61.0", + "@oxlint/binding-win32-x64-msvc": "1.61.0" }, - "engines": { - "node": ">=6.0" + "peerDependencies": { + "oxlint-tsgolint": ">=0.18.0" }, "peerDependenciesMeta": { - "supports-color": { + "oxlint-tsgolint": { "optional": true } } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "dev": true, - "dependencies": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.0", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", - "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", - "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", - "dev": true, - "dependencies": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-module-utils": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz", - "integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==", - "dev": true, - "dependencies": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-module-utils/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-plugin-es": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz", - "integrity": "sha512-6/Jb/J/ZvSebydwbBJO1R9E5ky7YeElfK56Veh7e4QGFHCXoIXGH9HhVz+ibJLM3XJ1XjP+T7rKBLUa/Y7eIng==", - "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=4.19.1" - } - }, - "node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", - "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-plugin-es/node_modules/regexpp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", - "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz", - "integrity": "sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==", - "dev": true, - "dependencies": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.1", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.12.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "2.x - 6.x" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "dependencies": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/eslint-plugin-import/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "dependencies": { - "pify": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "dependencies": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-node": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.0.0.tgz", - "integrity": "sha512-chUs/NVID+sknFiJzxoN9lM7uKSOEta8GC8365hw1nDfwIPIjjpRSwwPvQanWv8dt/pDe9EV4anmVSwdiSndNg==", - "dev": true, - "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, - "node_modules/eslint-plugin-node/node_modules/eslint-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", - "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-plugin-promise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", - "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-standard": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-5.0.0.tgz", - "integrity": "sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg==", - "deprecated": "standard 16.0.0 and eslint-config-standard 16.0.0 no longer require the eslint-plugin-standard package. You can remove it from your dependencies with 'npm rm eslint-plugin-standard'. More info here: https://github.com/standard/standard/issues/1316", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peerDependencies": { - "eslint": ">=5.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/glob-parent/node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", - "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/resolve": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", - "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "node_modules/string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "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", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } } } diff --git a/test-subproject/package.json b/test-subproject/package.json index 4271ea4..7ea191f 100644 --- a/test-subproject/package.json +++ b/test-subproject/package.json @@ -1,17 +1,9 @@ { "name": "action-eslint-subproject", "version": "1.0.0", - "description": "A test subprojet for testing reviewdog/action-eslint", - "main": "index.js", - "dependencies": { - }, + "description": "A test subproject for testing reviewdog/action-eslint", "devDependencies": { - "eslint": "^8.0.0", - "eslint-config-standard": "^17.0.0", - "eslint-plugin-import": "^2.18.2", - "eslint-plugin-node": "^11.0.0", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-standard": "^5.0.0" + "oxlint": "^1.61.0" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" From 0853d22ee041ba7e9a2c317bf0e2545f3d7e8e16 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 09:02:24 -0400 Subject: [PATCH 19/28] ci: run converter unit tests via node --test Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/test.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b1572a9..7543d52 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,5 @@ jobs: - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" - cache: "npm" - - run: npm ci - - name: Test eslint-formatter-rdjson - run: ./eslint-formatter-rdjson/test.sh + - name: Converter unit tests + run: node --test oxlint-to-rdjsonl.test.js From b70384a689dcd0de2e7c1dc04c380e7367632479 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 09:03:01 -0400 Subject: [PATCH 20/28] ci(reviewdog): exercise action with oxlint across node matrix Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/reviewdog.yml | 36 +++++++++++++++++---------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 523752e..472711d 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -1,8 +1,8 @@ name: reviewdog on: [pull_request] jobs: - eslint: - name: runner / eslint + oxlint: + name: runner / oxlint runs-on: ubuntu-latest strategy: @@ -19,39 +19,41 @@ jobs: uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ matrix.node_version }} - - name: eslint-github-pr-check + - name: install oxlint for root fixtures + run: npm install --no-save oxlint + - name: oxlint-github-pr-check uses: ./ with: - tool_name: eslint-github-pr-check + tool_name: oxlint-github-pr-check reporter: github-pr-check level: info - eslint_flags: "testdata/ --ignore-pattern /test-subproject/" - - name: eslint-github-check + oxlint_flags: "--config .oxlintrc.json testdata/" + - name: oxlint-github-check uses: ./ with: - tool_name: eslint-github-check + tool_name: oxlint-github-check reporter: github-check level: warning - eslint_flags: "testdata/ --ignore-pattern /test-subproject/" - - name: eslint-github-pr-review + oxlint_flags: "--config .oxlintrc.json testdata/" + - name: oxlint-github-pr-review uses: ./ with: - tool_name: eslint-github-pr-review + tool_name: oxlint-github-pr-review reporter: github-pr-review - eslint_flags: "testdata/ --ignore-pattern /test-subproject/" - - name: eslint-subproject-github-pr-review + oxlint_flags: "--config .oxlintrc.json testdata/" + - name: oxlint-subproject-github-pr-review uses: ./ with: - tool_name: eslint-subproject-github-pr-review + tool_name: oxlint-subproject-github-pr-review reporter: github-pr-review workdir: ./test-subproject - eslint_flags: "sub-testdata/" - - name: eslint-subproject + oxlint_flags: "sub-testdata/" + - name: oxlint-subproject uses: ./ with: - tool_name: eslint-subproject + tool_name: oxlint-subproject workdir: ./test-subproject - eslint_flags: "sub-testdata/" + oxlint_flags: "sub-testdata/" reporter: github-check level: warning filter_mode: file From 5edd138dad98dc0c6e929a8502e099ede61bbc88 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 09:03:08 -0400 Subject: [PATCH 21/28] ci: remove npm-publish workflow (no npm package to publish) Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/npm-publish.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/npm-publish.yml diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml deleted file mode 100644 index 9a56fe0..0000000 --- a/.github/workflows/npm-publish.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: NPM Publish -on: - push: - branches: - - master -jobs: - publish: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: "24" - - run: npm install - - name: Test eslint-formatter-rdjson - run: ./eslint-formatter-rdjson/test.sh - - uses: JS-DevTools/npm-publish@0fd2f4369c5d6bcfcde6091a7c527d810b9b5c3f # v4.1.5 - with: - package: ./eslint-formatter-rdjson/package.json - token: ${{ secrets.NPM_TOKEN }} From 87e917bcf5d391a8fd6a08935ec305cf8437e759 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 09:03:57 -0400 Subject: [PATCH 22/28] docs: rewrite README for oxlint Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 118 ++++++++++++++++++++++-------------------------------- 1 file changed, 47 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index ea2f8b8..f6980b7 100644 --- a/README.md +++ b/README.md @@ -1,138 +1,114 @@ -# GitHub Action: Run eslint with reviewdog +# GitHub Action: Run oxlint with reviewdog [![depup](https://github.com/reviewdog/action-eslint/workflows/depup/badge.svg)](https://github.com/reviewdog/action-eslint/actions?query=workflow%3Adepup) [![release](https://github.com/reviewdog/action-eslint/workflows/release/badge.svg)](https://github.com/reviewdog/action-eslint/actions?query=workflow%3Arelease) [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/reviewdog/action-eslint?logo=github&sort=semver)](https://github.com/reviewdog/action-eslint/releases) -[![action-bumpr supported](https://img.shields.io/badge/bumpr-supported-ff69b4?logo=github&link=https://github.com/haya14busa/action-bumpr)](https://github.com/haya14busa/action-bumpr) -[![Used-by counter](https://img.shields.io/endpoint?url=https://haya14busa.github.io/github-used-by/data/reviewdog/action-eslint/shieldsio.json)](https://github.com/haya14busa/github-used-by/tree/main/repo/reviewdog/action-eslint) -This action runs [eslint](https://github.com/eslint/eslint) with +This action runs [oxlint](https://oxc.rs/docs/guide/usage/linter.html) with [reviewdog](https://github.com/reviewdog/reviewdog) on pull requests to improve code review experience. -[![github-pr-check sample](https://user-images.githubusercontent.com/3797062/65439130-a6043b80-de61-11e9-98b5-bd9567e184b0.png)](https://github.com/reviewdog/action-eslint/pull/1) -![eslint reviewdog rdjson demo](https://user-images.githubusercontent.com/3797062/97085944-87233a80-165b-11eb-94a8-0a47d5e24905.png) +## Migrating from older versions of this action (eslint) + +Earlier versions of this action ran eslint. Starting with the oxlint rewrite, +the following breaking changes apply: + +- `eslint_flags` input → `oxlint_flags`. +- `node_options` input removed (oxlint is a native binary; `NODE_OPTIONS` has no effect). +- `tool_name` default changed from `eslint` to `oxlint`. +- You must list `oxlint` (not `eslint`) in your project's `devDependencies` (or equivalent). ## Inputs ### `github_token` - -**Required**. Default is `${{ github.token }}`. +**Required.** Default `${{ github.token }}`. ### `level` - -Optional. Report level for reviewdog \[`info`,`warning`,`error`\]. -It's same as `-level` flag of reviewdog. +Optional. Report level for reviewdog (`info`, `warning`, `error`). Same as reviewdog's `-level` flag. ### `reporter` - -Reporter of reviewdog command \[`github-pr-check`,`github-check`,`github-pr-review`\]. -Default is `github-pr-review`. -It's same as `-reporter` flag of reviewdog. - -`github-pr-review` can use Markdown and add a link to rule page in reviewdog reports. +Optional. `github-pr-check`, `github-check`, or `github-pr-review`. Default `github-pr-review`. ### `tool_name` - -Optional. Tool name to use for reviewdog reporter. Default is `eslint`. -This becomes the check/run name on GitHub (e.g., for `github-check`/`github-pr-check`) and the tool label in review comments. -Useful when running in a matrix to distinguish checks, e.g. `eslint-${{ matrix.node_version }}`. +Optional. Default `oxlint`. Becomes the check/run name on GitHub and the tool label in review comments. ### `filter_mode` - -Optional. Filtering mode for the reviewdog command \[`added`,`diff_context`,`file`,`nofilter`\]. -Default is added. +Optional. `added`, `diff_context`, `file`, or `nofilter`. Default `added`. ### `fail_level` - -Optional. If set to `none`, always use exit code 0 for reviewdog. Otherwise, exit code 1 for reviewdog if it finds at least 1 issue with severity greater than or equal to the given level. -Possible values: [`none`, `any`, `info`, `warning`, `error`] -Default is `none`. +Optional. `none`, `any`, `info`, `warning`, or `error`. Default `none`. ### `fail_on_error` - -Deprecated, use `fail_level` instead. -Optional. Exit code for reviewdog when errors are found \[`true`,`false`\] -Default is `false`. +Deprecated. Use `fail_level`. ### `reviewdog_flags` +Optional. Additional flags passed to reviewdog. -Optional. Additional reviewdog flags - -### `eslint_flags` - -Optional. Flags and args of eslint command. Default: '.' +### `oxlint_flags` +Optional. Flags and args for the `oxlint` command. Default `.`. ### `workdir` - -Optional. The directory from which to look for and run eslint. Default '.' - -### `node_options` - -Optional. The NODE_OPTIONS environment variable to use with eslint. Default is ''. +Optional. Directory from which to run oxlint. Default `.`. ## Example usage -You also need to install [eslint](https://github.com/eslint/eslint). +Install oxlint in your project: ```shell -# Example -$ npm install eslint -D +npm install --save-dev oxlint ``` -You can create [eslint -config](https://eslint.org/docs/user-guide/configuring) -and this action uses that config too. +See the [oxlint configuration docs](https://oxc.rs/docs/guide/usage/linter/config.html) +for creating a `.oxlintrc.json`. This action uses that config automatically. -### [.github/workflows/reviewdog.yml](.github/workflows/reviewdog.yml) +### `.github/workflows/reviewdog.yml` -```yml +```yaml name: reviewdog on: [pull_request] jobs: - eslint: - name: runner / eslint + oxlint: + name: runner / oxlint runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: reviewdog/action-eslint@2fee6dd72a5419ff4113f694e2068d2a03bb35dd # v1.33.2 + - uses: actions/checkout@v4 + - uses: reviewdog/action-eslint@vX with: github_token: ${{ secrets.GITHUB_TOKEN }} - reporter: github-pr-review # Change reporter. - eslint_flags: "src/" + reporter: github-pr-review + oxlint_flags: "src/" ``` -You can also set up node and eslint manually like below. +You can also set up Node and oxlint manually: -```yml +```yaml name: reviewdog on: [pull_request] jobs: - eslint: - name: runner / eslint + oxlint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: "20" - - run: yarn install - - uses: reviewdog/action-eslint@2fee6dd72a5419ff4113f694e2068d2a03bb35dd # v1.33.2 + - run: npm install + - uses: reviewdog/action-eslint@vX with: reporter: github-check - eslint_flags: "src/" + oxlint_flags: "src/" ``` ### Matrix example with unique tool name -```yml +```yaml name: reviewdog on: [pull_request] jobs: - eslint: + oxlint: runs-on: ubuntu-latest strategy: matrix: @@ -142,10 +118,10 @@ jobs: - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} - - uses: reviewdog/action-eslint@v1 + - uses: reviewdog/action-eslint@vX with: github_token: ${{ secrets.GITHUB_TOKEN }} reporter: github-check - tool_name: eslint-node-${{ matrix.node }} - eslint_flags: "src/" + tool_name: oxlint-node-${{ matrix.node }} + oxlint_flags: "src/" ``` From c6df9ef0dd95e6e5b78c922d3ca0a598ca47ffde Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 09:29:02 -0400 Subject: [PATCH 23/28] fix(action): skip npm install when oxlint is already available Previously the action always went through `npx --no-install -c 'oxlint --version'` to detect oxlint, then fell back to `npm install` if that check failed. This broke two pnpm/monorepo cases: 1. pnpm's symlink + workspace:* resolution can make the npx check return non-zero even when oxlint is present. 2. Falling back to `npm install` fails with EUNSUPPORTEDPROTOCOL on any `workspace:*` dep. Now the script resolves oxlint by preference: - binary on PATH -> use directly - ./node_modules/.bin/oxlint -> use directly - neither -> `npm install` as before (still fails on pnpm, but the consumer can opt out by installing oxlint themselves beforehand) Invocation goes through the resolved path; `npx` is only used as a last resort after the install step. Co-Authored-By: Claude Opus 4.7 (1M context) --- script.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/script.sh b/script.sh index 005e404..148a42d 100755 --- a/script.sh +++ b/script.sh @@ -10,19 +10,28 @@ echo '::group::🐶 Installing reviewdog ... https://github.com/reviewdog/review curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s -- -b "${TEMP_PATH}" "${REVIEWDOG_VERSION}" 2>&1 echo '::endgroup::' -npx --no-install -c 'oxlint --version' 2>/dev/null -if [ $? -ne 0 ]; then +# Resolve oxlint once, preferring a pre-installed binary over touching the +# package manager. Only fall back to `npm install` when the consumer +# project has no oxlint on PATH and no ./node_modules/.bin/oxlint — this +# avoids breaking pnpm / yarn / monorepo setups where `npm install` would +# reject workspace protocols. +if command -v oxlint >/dev/null 2>&1; then + OXLINT="oxlint" +elif [ -x "./node_modules/.bin/oxlint" ]; then + OXLINT="./node_modules/.bin/oxlint" +else echo '::group:: Running `npm install` to install oxlint ...' set -e npm install set +e echo '::endgroup::' + OXLINT="npx --no-install oxlint" fi -echo "oxlint version:$(npx --no-install -c 'oxlint --version')" +echo "oxlint version:$($OXLINT --version)" echo '::group:: Running oxlint with reviewdog 🐶 ...' -npx --no-install -c "oxlint --format=json ${INPUT_OXLINT_FLAGS:-'.'}" \ +$OXLINT --format=json ${INPUT_OXLINT_FLAGS:-.} \ | node "${GITHUB_ACTION_PATH}/oxlint-to-rdjsonl.js" \ | reviewdog -f=rdjsonl \ -name="${INPUT_TOOL_NAME}" \ From fbff26322878d5a24694584db7e26e5bbe34c03d Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 09:57:28 -0400 Subject: [PATCH 24/28] chore: remove superpowers specs and plans Co-Authored-By: Claude Opus 4.7 (1M context) --- .../plans/2026-04-22-oxlint-migration.md | 1479 ----------------- .../2026-04-21-oxlint-migration-design.md | 243 --- 2 files changed, 1722 deletions(-) delete mode 100644 docs/superpowers/plans/2026-04-22-oxlint-migration.md delete mode 100644 docs/superpowers/specs/2026-04-21-oxlint-migration-design.md diff --git a/docs/superpowers/plans/2026-04-22-oxlint-migration.md b/docs/superpowers/plans/2026-04-22-oxlint-migration.md deleted file mode 100644 index c52a239..0000000 --- a/docs/superpowers/plans/2026-04-22-oxlint-migration.md +++ /dev/null @@ -1,1479 +0,0 @@ -# Oxlint Migration Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Repurpose this composite GitHub Action to run [oxlint](https://oxc.rs/docs/guide/usage/linter.html) through reviewdog instead of eslint. Breaking change; no backward-compat shim. - -**Architecture:** The action is a composite action. `action.yml` declares inputs and forwards them as `INPUT_*` env vars to `script.sh`, which installs reviewdog, runs `oxlint --format=json`, pipes the output through a new Node-based converter (`oxlint-to-rdjsonl.js`), then into `reviewdog -f=rdjsonl`. The converter is the only genuinely new code; everything else is renames, edits, and deletions. - -**Tech Stack:** Bash (`script.sh`), GitHub composite action YAML, Node.js (converter + tests, using `node:test` — no devDeps), oxlint (consumer-installed). - -**Spec:** `docs/superpowers/specs/2026-04-21-oxlint-migration-design.md`. - ---- - -## File Structure - -**Created:** -- `oxlint-to-rdjsonl.js` — pure-function module + CLI entrypoint. Exports `mapSeverity`, `extractRuleCode`, `positionFromOffset`, `convertDiagnostic`, `convert`, `main`. If invoked directly (`node oxlint-to-rdjsonl.js`), reads JSON from stdin, writes rdjsonl to stdout. -- `oxlint-to-rdjsonl.test.js` — uses Node's built-in `node:test` runner; imports the above module and tests each pure function plus one end-to-end test that spawns the CLI. -- `.oxlintrc.json` — repo-root oxlint config pinning rules so test-fixture output is deterministic. -- `testdata/converter/simple.js`, `testdata/converter/multiline.js`, `testdata/converter/utf8.js` — fixtures for converter unit tests (NOT linted by oxlint; they're just text files read by the converter during tests). - -**Modified:** -- `action.yml` — input renames, removals, metadata rewrite. -- `script.sh` — eslint→oxlint invocation; drop custom formatter path; pipe through converter. -- `README.md` — full rewrite for oxlint. -- `testdata/test.js`, `testdata/error.js`, `testdata/empty.js` — tweak to fire oxlint rules deterministically. -- `test-subproject/package.json` — swap eslint family for `oxlint` devDep; regenerate lockfile. -- `test-subproject/sub-testdata/*.js` — same deterministic tweaks. -- `.github/workflows/test.yml` — run `node --test` on the converter instead of the old formatter's shell test. -- `.github/workflows/reviewdog.yml` — rename `eslint_flags` → `oxlint_flags`, rename `tool_name` values, install `oxlint` before invoking the action. - -**Deleted:** -- `eslint-formatter-rdjson/` (entire directory, including `index.js`, `package.json`, tests, testdata). -- `.eslintrc.js` at repo root. -- `package.json` and `package-lock.json` at repo root. -- `test-subproject/.eslintrc.js`. -- `.github/workflows/npm-publish.yml` — publishes `eslint-formatter-rdjson` to npm; the new action has no npm package to publish. - -**Unchanged:** -- `.github/workflows/depup.yml`, `.github/workflows/release.yml` — version-bumping infrastructure operates on `action.yml`'s `REVIEWDOG_VERSION` and git tags; agnostic to what the action does. -- `.gitignore`, `LICENSE`. - ---- - -## Task 1: Scaffold converter module with severity-mapping test - -**Files:** -- Create: `oxlint-to-rdjsonl.js` -- Create: `oxlint-to-rdjsonl.test.js` - -- [ ] **Step 1.1: Write the failing test** - -Create `oxlint-to-rdjsonl.test.js` with: - -```js -const test = require('node:test'); -const assert = require('node:assert/strict'); -const { mapSeverity } = require('./oxlint-to-rdjsonl'); - -test('mapSeverity: error -> ERROR', () => { - assert.equal(mapSeverity('error'), 'ERROR'); -}); - -test('mapSeverity: warning -> WARNING', () => { - assert.equal(mapSeverity('warning'), 'WARNING'); -}); - -test('mapSeverity: advice -> INFO', () => { - assert.equal(mapSeverity('advice'), 'INFO'); -}); - -test('mapSeverity: unknown -> UNKNOWN_SEVERITY', () => { - assert.equal(mapSeverity('bogus'), 'UNKNOWN_SEVERITY'); -}); -``` - -- [ ] **Step 1.2: Run test to verify it fails** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: FAIL — `Cannot find module './oxlint-to-rdjsonl'`. - -- [ ] **Step 1.3: Write minimal implementation** - -Create `oxlint-to-rdjsonl.js`: - -```js -'use strict'; - -function mapSeverity(s) { - if (s === 'error') return 'ERROR'; - if (s === 'warning') return 'WARNING'; - if (s === 'advice') return 'INFO'; - return 'UNKNOWN_SEVERITY'; -} - -module.exports = { mapSeverity }; -``` - -- [ ] **Step 1.4: Run test to verify it passes** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: PASS — all four subtests pass. - -- [ ] **Step 1.5: Commit** - -```bash -git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js -git commit -m "feat(converter): scaffold module with severity mapping" -``` - ---- - -## Task 2: Rule code extraction - -**Files:** -- Modify: `oxlint-to-rdjsonl.test.js` (append) -- Modify: `oxlint-to-rdjsonl.js` - -- [ ] **Step 2.1: Append failing tests** - -Append to `oxlint-to-rdjsonl.test.js`: - -```js -const { extractRuleCode } = require('./oxlint-to-rdjsonl'); - -test('extractRuleCode: plugin(rule) -> rule', () => { - assert.equal(extractRuleCode('eslint(no-unused-vars)'), 'no-unused-vars'); -}); - -test('extractRuleCode: nested parens preserved in rule', () => { - assert.equal(extractRuleCode('typescript(no-empty-interface)'), 'no-empty-interface'); -}); - -test('extractRuleCode: bare code passed through', () => { - assert.equal(extractRuleCode('no-unused-vars'), 'no-unused-vars'); -}); - -test('extractRuleCode: undefined -> undefined', () => { - assert.equal(extractRuleCode(undefined), undefined); -}); - -test('extractRuleCode: empty string -> empty string', () => { - assert.equal(extractRuleCode(''), ''); -}); -``` - -- [ ] **Step 2.2: Run test to verify it fails** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: FAIL — `extractRuleCode is not a function`. - -- [ ] **Step 2.3: Implement** - -Add to `oxlint-to-rdjsonl.js`: - -```js -function extractRuleCode(code) { - if (code === undefined || code === null) return undefined; - const match = /^[^(]+\(([^)]+)\)$/.exec(code); - return match ? match[1] : code; -} -``` - -And update `module.exports`: - -```js -module.exports = { mapSeverity, extractRuleCode }; -``` - -- [ ] **Step 2.4: Run test to verify it passes** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: PASS — all subtests from Tasks 1 and 2 pass. - -- [ ] **Step 2.5: Commit** - -```bash -git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js -git commit -m "feat(converter): extract rule code from plugin(rule) format" -``` - ---- - -## Task 3: Byte-offset → line/column — single line - -**Files:** -- Modify: `oxlint-to-rdjsonl.test.js` -- Modify: `oxlint-to-rdjsonl.js` - -- [ ] **Step 3.1: Append failing tests** - -Append to `oxlint-to-rdjsonl.test.js`: - -```js -const { positionFromOffset } = require('./oxlint-to-rdjsonl'); - -test('positionFromOffset: offset 0 -> line 1, column 1', () => { - const buf = Buffer.from('abc'); - assert.deepEqual(positionFromOffset(buf, 0), { line: 1, column: 1 }); -}); - -test('positionFromOffset: middle of first line', () => { - const buf = Buffer.from('abcdef'); - assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); -}); - -test('positionFromOffset: end-of-single-line buffer', () => { - const buf = Buffer.from('abc'); - assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); -}); -``` - -- [ ] **Step 3.2: Run test to verify it fails** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: FAIL — `positionFromOffset is not a function`. - -- [ ] **Step 3.3: Implement** - -Add to `oxlint-to-rdjsonl.js`: - -```js -// Convert a UTF-8 byte offset into {line, column}, both 1-based. -// column is 1-based UTF-8 byte position within its line (what reviewdog expects). -function positionFromOffset(buffer, offset) { - let line = 1; - let column = 1; - const end = Math.min(offset, buffer.length); - for (let i = 0; i < end; i++) { - if (buffer[i] === 0x0A) { - line++; - column = 1; - } else { - column++; - } - } - return { line, column }; -} -``` - -Update `module.exports`: - -```js -module.exports = { mapSeverity, extractRuleCode, positionFromOffset }; -``` - -- [ ] **Step 3.4: Run test to verify it passes** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: PASS — all tests from Tasks 1–3. - -- [ ] **Step 3.5: Commit** - -```bash -git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js -git commit -m "feat(converter): byte-offset to line/column for single-line input" -``` - ---- - -## Task 4: Byte-offset → line/column — multi-line and boundaries - -**Files:** -- Modify: `oxlint-to-rdjsonl.test.js` - -- [ ] **Step 4.1: Append failing tests** - -Append to `oxlint-to-rdjsonl.test.js`: - -```js -test('positionFromOffset: offset on a later line', () => { - // "abc\ndef" — offset 4 is 'd' on line 2 - const buf = Buffer.from('abc\ndef'); - assert.deepEqual(positionFromOffset(buf, 4), { line: 2, column: 1 }); -}); - -test('positionFromOffset: offset at newline is end of previous line', () => { - // "abc\ndef" — offset 3 is the '\n' byte itself; column counts it as end-of-line 1 - const buf = Buffer.from('abc\ndef'); - assert.deepEqual(positionFromOffset(buf, 3), { line: 1, column: 4 }); -}); - -test('positionFromOffset: across multiple newlines', () => { - const buf = Buffer.from('a\nb\nc'); - // offset 4 = 'c' on line 3, column 1 - assert.deepEqual(positionFromOffset(buf, 4), { line: 3, column: 1 }); -}); - -test('positionFromOffset: offset past end clamps to buffer length', () => { - const buf = Buffer.from('abc'); - assert.deepEqual(positionFromOffset(buf, 99), { line: 1, column: 4 }); -}); - -test('positionFromOffset: UTF-8 multi-byte char — columns are byte positions', () => { - // '🐶' is 4 UTF-8 bytes (F0 9F 90 B6). Source: "a🐶b" - const buf = Buffer.from('a🐶b'); - assert.equal(buf.length, 6); - // offset 5 is 'b' — column 6 (1-based bytes) - assert.deepEqual(positionFromOffset(buf, 5), { line: 1, column: 6 }); -}); -``` - -- [ ] **Step 4.2: Run test** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: PASS — the implementation from Task 3 already handles all of these. These tests are regression coverage; if any fail, the implementation must be fixed to make them pass before committing. - -- [ ] **Step 4.3: Commit** - -```bash -git add oxlint-to-rdjsonl.test.js -git commit -m "test(converter): cover multi-line, boundary, and UTF-8 offset cases" -``` - ---- - -## Task 5: `convertDiagnostic` for a well-formed input - -**Files:** -- Modify: `oxlint-to-rdjsonl.test.js` -- Modify: `oxlint-to-rdjsonl.js` - -- [ ] **Step 5.1: Append failing test** - -Append to `oxlint-to-rdjsonl.test.js`: - -```js -const { convertDiagnostic } = require('./oxlint-to-rdjsonl'); - -test('convertDiagnostic: full mapping of a typical diagnostic', () => { - const diagnostic = { - message: 'Unused variable', - code: 'eslint(no-unused-vars)', - severity: 'error', - url: 'https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-unused-vars.html', - filename: 'src/foo.js', - labels: [{ span: { offset: 4, length: 3 } }], - }; - // source file: "var abc = 1;" - const fileReader = (path) => { - assert.equal(path, 'src/foo.js'); - return Buffer.from('var abc = 1;'); - }; - const out = convertDiagnostic(diagnostic, fileReader); - assert.deepEqual(out, { - message: 'Unused variable', - location: { - path: 'src/foo.js', - range: { - start: { line: 1, column: 5 }, - end: { line: 1, column: 8 }, - }, - }, - severity: 'ERROR', - code: { - value: 'no-unused-vars', - url: 'https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-unused-vars.html', - }, - source: { name: 'oxlint', url: 'https://oxc.rs/docs/guide/usage/linter.html' }, - }); -}); -``` - -- [ ] **Step 5.2: Run test to verify it fails** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: FAIL — `convertDiagnostic is not a function`. - -- [ ] **Step 5.3: Implement** - -Add to `oxlint-to-rdjsonl.js`: - -```js -const OXLINT_SOURCE = { - name: 'oxlint', - url: 'https://oxc.rs/docs/guide/usage/linter.html', -}; - -function convertDiagnostic(diagnostic, fileReader) { - const out = { - message: diagnostic.message, - severity: mapSeverity(diagnostic.severity), - source: OXLINT_SOURCE, - }; - - const ruleValue = extractRuleCode(diagnostic.code); - if (ruleValue !== undefined) { - out.code = { value: ruleValue }; - if (diagnostic.url) out.code.url = diagnostic.url; - } - - const filename = diagnostic.filename; - if (filename) { - const location = { path: filename }; - const label = (diagnostic.labels || [])[0]; - if (label && label.span) { - let buffer = null; - try { - buffer = fileReader(filename); - } catch (_err) { - buffer = null; - } - if (buffer) { - const start = positionFromOffset(buffer, label.span.offset); - const end = positionFromOffset(buffer, label.span.offset + label.span.length); - location.range = { start, end }; - } - } - out.location = location; - } - - return out; -} - -module.exports = { mapSeverity, extractRuleCode, positionFromOffset, convertDiagnostic }; -``` - -- [ ] **Step 5.4: Run test to verify it passes** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: PASS — all tests from Tasks 1–5. - -- [ ] **Step 5.5: Commit** - -```bash -git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js -git commit -m "feat(converter): transform one oxlint diagnostic to rdjsonl" -``` - ---- - -## Task 6: `convertDiagnostic` edge cases — no labels, no filename, read failure, URL missing, multiple labels - -**Files:** -- Modify: `oxlint-to-rdjsonl.test.js` - -- [ ] **Step 6.1: Append failing tests** - -Append to `oxlint-to-rdjsonl.test.js`: - -```js -test('convertDiagnostic: missing labels -> file-level, no range', () => { - const out = convertDiagnostic( - { message: 'hi', code: 'eslint(x)', severity: 'warning', filename: 'a.js', labels: [] }, - () => Buffer.from('') - ); - assert.equal(out.location.path, 'a.js'); - assert.equal(out.location.range, undefined); - assert.equal(out.severity, 'WARNING'); -}); - -test('convertDiagnostic: missing filename -> no location', () => { - const out = convertDiagnostic( - { message: 'hi', severity: 'error' }, - () => { throw new Error('should not be called'); } - ); - assert.equal(out.location, undefined); -}); - -test('convertDiagnostic: fileReader throws -> file-level, no range', () => { - const out = convertDiagnostic( - { - message: 'hi', - severity: 'error', - filename: 'missing.js', - labels: [{ span: { offset: 0, length: 1 } }], - }, - () => { throw new Error('ENOENT'); } - ); - assert.deepEqual(out.location, { path: 'missing.js' }); -}); - -test('convertDiagnostic: missing url -> code without url field', () => { - const out = convertDiagnostic( - { - message: 'hi', - code: 'eslint(no-var)', - severity: 'error', - filename: 'a.js', - labels: [{ span: { offset: 0, length: 1 } }], - }, - () => Buffer.from('x') - ); - assert.deepEqual(out.code, { value: 'no-var' }); -}); - -test('convertDiagnostic: missing code -> no code field', () => { - const out = convertDiagnostic( - { message: 'hi', severity: 'error', filename: 'a.js', labels: [] }, - () => Buffer.from('') - ); - assert.equal(out.code, undefined); -}); - -test('convertDiagnostic: multiple labels -> first label used', () => { - const out = convertDiagnostic( - { - message: 'hi', - code: 'eslint(x)', - severity: 'error', - filename: 'a.js', - labels: [ - { span: { offset: 0, length: 1 } }, - { span: { offset: 5, length: 2 } }, - ], - }, - () => Buffer.from('abcdefghij') - ); - assert.deepEqual(out.location.range, { - start: { line: 1, column: 1 }, - end: { line: 1, column: 2 }, - }); -}); -``` - -- [ ] **Step 6.2: Run test** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: PASS — the implementation from Task 5 already handles these cases (thanks to the `try/catch`, `label &&` guard, etc.). If any case fails, fix the implementation before committing. - -- [ ] **Step 6.3: Commit** - -```bash -git add oxlint-to-rdjsonl.test.js -git commit -m "test(converter): edge cases for convertDiagnostic" -``` - ---- - -## Task 7: `convert` array-level function - -**Files:** -- Modify: `oxlint-to-rdjsonl.test.js` -- Modify: `oxlint-to-rdjsonl.js` - -- [ ] **Step 7.1: Append failing test** - -Append to `oxlint-to-rdjsonl.test.js`: - -```js -const { convert } = require('./oxlint-to-rdjsonl'); - -test('convert: empty array -> empty array', () => { - assert.deepEqual(convert([], () => Buffer.from('')), []); -}); - -test('convert: maps each diagnostic and preserves order', () => { - const diagnostics = [ - { message: 'a', code: 'p(r1)', severity: 'error', filename: 'f', labels: [] }, - { message: 'b', code: 'p(r2)', severity: 'warning', filename: 'f', labels: [] }, - ]; - const out = convert(diagnostics, () => Buffer.from('')); - assert.equal(out.length, 2); - assert.equal(out[0].message, 'a'); - assert.equal(out[0].severity, 'ERROR'); - assert.equal(out[1].message, 'b'); - assert.equal(out[1].severity, 'WARNING'); -}); -``` - -- [ ] **Step 7.2: Run test to verify it fails** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: FAIL — `convert is not a function`. - -- [ ] **Step 7.3: Implement** - -Add to `oxlint-to-rdjsonl.js`: - -```js -function convert(diagnostics, fileReader) { - return diagnostics.map((d) => convertDiagnostic(d, fileReader)); -} -``` - -Update `module.exports`: - -```js -module.exports = { - mapSeverity, - extractRuleCode, - positionFromOffset, - convertDiagnostic, - convert, -}; -``` - -- [ ] **Step 7.4: Run test to verify it passes** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: PASS. - -- [ ] **Step 7.5: Commit** - -```bash -git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js -git commit -m "feat(converter): convert a list of diagnostics" -``` - ---- - -## Task 8: CLI entrypoint — stdin/stdout, exit codes, invalid JSON - -**Files:** -- Modify: `oxlint-to-rdjsonl.js` -- Modify: `oxlint-to-rdjsonl.test.js` - -- [ ] **Step 8.1: Append failing test** - -Append to `oxlint-to-rdjsonl.test.js`: - -```js -const { spawnSync } = require('node:child_process'); -const path = require('node:path'); -const fs = require('node:fs'); -const os = require('node:os'); - -const CLI = path.join(__dirname, 'oxlint-to-rdjsonl.js'); - -function runCli(stdin, cwd = __dirname) { - return spawnSync(process.execPath, [CLI], { - input: stdin, - cwd, - encoding: 'utf8', - }); -} - -test('cli: empty array -> exit 0, empty stdout', () => { - const r = runCli('[]'); - assert.equal(r.status, 0, r.stderr); - assert.equal(r.stdout, ''); -}); - -test('cli: invalid JSON -> exit 1, stderr message', () => { - const r = runCli('not json'); - assert.equal(r.status, 1); - assert.match(r.stderr, /invalid|parse/i); -}); - -test('cli: one diagnostic -> one rdjsonl line', () => { - // Stage a fixture file that will be read via the diagnostic's filename. - const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'oxlint-cli-')); - const fixture = path.join(tmp, 'x.js'); - fs.writeFileSync(fixture, 'var abc = 1;'); - const input = JSON.stringify([ - { - message: 'Unused', - code: 'eslint(no-unused-vars)', - severity: 'error', - url: 'https://oxc.rs/x', - filename: fixture, - labels: [{ span: { offset: 4, length: 3 } }], - }, - ]); - const r = runCli(input); - assert.equal(r.status, 0, r.stderr); - const lines = r.stdout.trim().split('\n'); - assert.equal(lines.length, 1); - const parsed = JSON.parse(lines[0]); - assert.equal(parsed.message, 'Unused'); - assert.deepEqual(parsed.location.range.start, { line: 1, column: 5 }); - assert.equal(parsed.code.value, 'no-unused-vars'); - fs.rmSync(tmp, { recursive: true, force: true }); -}); -``` - -- [ ] **Step 8.2: Run test to verify it fails** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: FAIL — the CLI entrypoint does not yet exist, so running the file as a process produces no output (the current file only exports functions). - -- [ ] **Step 8.3: Implement CLI** - -Append to `oxlint-to-rdjsonl.js`: - -```js -function readStdin() { - return new Promise((resolve, reject) => { - const chunks = []; - process.stdin.on('data', (c) => chunks.push(c)); - process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))); - process.stdin.on('error', reject); - }); -} - -function readFileSafe(filename) { - return require('node:fs').readFileSync(filename); -} - -async function main() { - const raw = await readStdin(); - const text = raw.trim(); - if (text === '') { - return 0; - } - let diagnostics; - try { - diagnostics = JSON.parse(text); - } catch (err) { - process.stderr.write(`oxlint-to-rdjsonl: failed to parse oxlint JSON on stdin: ${err.message}\n`); - return 1; - } - if (!Array.isArray(diagnostics)) { - process.stderr.write(`oxlint-to-rdjsonl: expected a JSON array on stdin, got ${typeof diagnostics}\n`); - return 1; - } - const out = convert(diagnostics, readFileSafe); - for (const d of out) { - process.stdout.write(JSON.stringify(d) + '\n'); - } - return 0; -} - -module.exports.main = main; - -if (require.main === module) { - main().then((code) => process.exit(code)).catch((err) => { - process.stderr.write(`oxlint-to-rdjsonl: ${err.stack || err.message}\n`); - process.exit(1); - }); -} -``` - -- [ ] **Step 8.4: Run test to verify it passes** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: PASS — every test including the three CLI tests. - -- [ ] **Step 8.5: Commit** - -```bash -git add oxlint-to-rdjsonl.js oxlint-to-rdjsonl.test.js -git commit -m "feat(converter): CLI entrypoint reading stdin, writing rdjsonl" -``` - ---- - -## Task 9: Update `action.yml` - -**Files:** -- Modify: `action.yml` - -- [ ] **Step 9.1: Replace file contents** - -Overwrite `action.yml` with: - -```yaml -name: 'Run oxlint with reviewdog' -description: '🐶 Run oxlint with reviewdog on pull requests to improve code review experience.' -author: 'haya14busa (reviewdog)' -inputs: - github_token: - description: 'GITHUB_TOKEN.' - required: true - default: ${{ github.token }} - level: - description: 'Report level for reviewdog [info,warning,error]' - required: false - default: 'error' - reporter: - description: | - Reporter of reviewdog command [github-check,github-pr-review]. - Default is github-pr-review. - github-pr-review can use Markdown and add a link to rule page in reviewdog reports. - required: false - default: 'github-pr-review' - filter_mode: - description: | - Filtering mode for the reviewdog command [added,diff_context,file,nofilter]. - Default is added. - required: false - default: 'added' - fail_level: - description: | - If set to `none`, always use exit code 0 for reviewdog. Otherwise, exit code 1 for reviewdog if it finds at least 1 issue with severity greater than or equal to the given level. - Possible values: [none,any,info,warning,error] - Default is `none`. - default: 'none' - fail_on_error: - description: | - Deprecated, use `fail_level` instead. - Exit code for reviewdog when errors are found [true,false] - Default is `false`. - deprecationMessage: Deprecated, use `fail_level` instead. - required: false - default: 'false' - reviewdog_flags: - description: 'Additional reviewdog flags' - required: false - default: '' - oxlint_flags: - description: "flags and args of oxlint command. Default: '.'" - required: false - default: '.' - workdir: - description: "The directory from which to look for and run oxlint. Default '.'" - required: false - default: '.' - tool_name: - description: 'Tool name to use for reviewdog reporter' - required: false - default: 'oxlint' -runs: - using: 'composite' - steps: - - run: $GITHUB_ACTION_PATH/script.sh - shell: bash - env: - REVIEWDOG_VERSION: v0.21.0 - INPUT_GITHUB_TOKEN: ${{ inputs.github_token }} - INPUT_LEVEL: ${{ inputs.level }} - INPUT_REPORTER: ${{ inputs.reporter }} - INPUT_FILTER_MODE: ${{ inputs.filter_mode }} - INPUT_FAIL_LEVEL: ${{ inputs.fail_level }} - INPUT_FAIL_ON_ERROR: ${{ inputs.fail_on_error }} - INPUT_REVIEWDOG_FLAGS: ${{ inputs.reviewdog_flags }} - INPUT_OXLINT_FLAGS: ${{ inputs.oxlint_flags }} - INPUT_WORKDIR: ${{ inputs.workdir }} - INPUT_TOOL_NAME: ${{ inputs.tool_name }} -branding: - icon: 'alert-octagon' - color: 'blue' -``` - -- [ ] **Step 9.2: Verify YAML is well-formed** - -Run: `python3 -c "import yaml; yaml.safe_load(open('action.yml'))"` (or `node -e "require('js-yaml')"` if yaml isn't available; the goal is to catch parse errors). -Expected: no error. - -- [ ] **Step 9.3: Commit** - -```bash -git add action.yml -git commit -m "feat(action): rename inputs eslint_flags -> oxlint_flags, drop node_options" -``` - ---- - -## Task 10: Update `script.sh` - -**Files:** -- Modify: `script.sh` - -- [ ] **Step 10.1: Replace file contents** - -Overwrite `script.sh` with: - -```sh -#!/bin/sh - -cd "${GITHUB_WORKSPACE}/${INPUT_WORKDIR}" || exit 1 - -TEMP_PATH="$(mktemp -d)" -PATH="${TEMP_PATH}:$PATH" -export REVIEWDOG_GITHUB_API_TOKEN="${INPUT_GITHUB_TOKEN}" - -echo '::group::🐶 Installing reviewdog ... https://github.com/reviewdog/reviewdog' -curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s -- -b "${TEMP_PATH}" "${REVIEWDOG_VERSION}" 2>&1 -echo '::endgroup::' - -npx --no-install -c 'oxlint --version' 2>/dev/null -if [ $? -ne 0 ]; then - echo '::group:: Running `npm install` to install oxlint ...' - set -e - npm install - set +e - echo '::endgroup::' -fi - -echo "oxlint version:$(npx --no-install -c 'oxlint --version')" - -echo '::group:: Running oxlint with reviewdog 🐶 ...' -npx --no-install -c "oxlint --format=json ${INPUT_OXLINT_FLAGS:-'.'}" \ - | node "${GITHUB_ACTION_PATH}/oxlint-to-rdjsonl.js" \ - | reviewdog -f=rdjsonl \ - -name="${INPUT_TOOL_NAME}" \ - -reporter="${INPUT_REPORTER:-github-pr-review}" \ - -filter-mode="${INPUT_FILTER_MODE}" \ - -fail-level="${INPUT_FAIL_LEVEL}" \ - -fail-on-error="${INPUT_FAIL_ON_ERROR}" \ - -level="${INPUT_LEVEL}" \ - ${INPUT_REVIEWDOG_FLAGS} - -reviewdog_rc=$? -echo '::endgroup::' -exit $reviewdog_rc -``` - -- [ ] **Step 10.2: Ensure the file is executable** - -Run: `chmod +x script.sh && test -x script.sh && echo OK` -Expected: `OK`. - -- [ ] **Step 10.3: Quick shell syntax check** - -Run: `sh -n script.sh` -Expected: no output, exit 0. - -- [ ] **Step 10.4: Commit** - -```bash -git add script.sh -git commit -m "feat(action): swap eslint pipeline for oxlint + rdjsonl converter" -``` - ---- - -## Task 11: Delete `eslint-formatter-rdjson/` - -**Files:** -- Delete: `eslint-formatter-rdjson/` (recursive) - -- [ ] **Step 11.1: Verify nothing in the repo still imports it** - -Run: `grep -rn --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=eslint-formatter-rdjson eslint-formatter-rdjson .` -Expected: only references in `docs/superpowers/`, `README.md` (if still present), and potentially files that are also scheduled for deletion/update. No reference from any file that's supposed to survive unmodified. - -If the grep surfaces unexpected hits, stop and resolve them before deleting. - -- [ ] **Step 11.2: Delete the directory** - -Run: `git rm -r eslint-formatter-rdjson` -Expected: git reports deletions of every file under the directory. - -- [ ] **Step 11.3: Commit** - -```bash -git commit -m "chore: remove bundled eslint-formatter-rdjson" -``` - ---- - -## Task 12: Delete repo-root eslint/npm detritus - -**Files:** -- Delete: `.eslintrc.js` -- Delete: `package.json` -- Delete: `package-lock.json` - -- [ ] **Step 12.1: Verify nothing imports these** - -Run: `grep -rn --exclude-dir=.git --exclude-dir=node_modules "eslintrc\|package-lock\|require(.package\.json" . | grep -v docs/superpowers` -Expected: no production code referencing the repo-root `package.json` or `.eslintrc.js`. References inside `docs/superpowers/` (the spec/plan) are fine. - -- [ ] **Step 12.2: Delete the files** - -Run: `git rm .eslintrc.js package.json package-lock.json` -Expected: three deletions staged. - -- [ ] **Step 12.3: Commit** - -```bash -git commit -m "chore: remove repo-root eslint config and package manifest" -``` - ---- - -## Task 13: Add `.oxlintrc.json` - -**Files:** -- Create: `.oxlintrc.json` - -- [ ] **Step 13.1: Write the config** - -Create `.oxlintrc.json`: - -```json -{ - "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json", - "rules": { - "no-unused-vars": "error", - "no-var": "error", - "no-empty": "warn" - }, - "ignorePatterns": [ - "test-subproject/", - "node_modules/" - ] -} -``` - -- [ ] **Step 13.2: Verify it's valid JSON** - -Run: `python3 -m json.tool .oxlintrc.json > /dev/null` -Expected: exit 0, no error. - -- [ ] **Step 13.3: Commit** - -```bash -git add .oxlintrc.json -git commit -m "chore: add repo-root oxlint config for test fixtures" -``` - ---- - -## Task 14: Update `testdata/` fixtures for oxlint - -**Files:** -- Modify: `testdata/test.js` -- Modify: `testdata/error.js` -- Modify: `testdata/empty.js` - -**Rationale:** The current `testdata/error.js` uses a literal `🐶` outside a string, which eslint flagged as an unexpected character but oxlint's default JS parser treats as an identifier — different rule surface. Replace with a fixture that reliably triggers the rules pinned in `.oxlintrc.json` (`no-unused-vars`, `no-var`). - -- [ ] **Step 14.1: Rewrite `testdata/error.js`** - -Overwrite `testdata/error.js`: - -```js -// Fires: no-var (var keyword), no-unused-vars (unusedVar never read) -var unusedVar = 1; -``` - -- [ ] **Step 14.2: Rewrite `testdata/test.js`** - -Overwrite `testdata/test.js`: - -```js -// Fires: no-var, no-empty (for body) -function sample() { - for (var i = 0; i < 10; i++) { - } -} - -sample(); -``` - -- [ ] **Step 14.3: Leave `testdata/empty.js` as-is** - -Run: `cat testdata/empty.js` -Expected: `// empty` — a file with no diagnostics. This covers the "file with no issues" path. - -- [ ] **Step 14.4: Smoke test: run oxlint locally against the fixtures and confirm JSON output is non-empty** - -Run (requires oxlint installed globally or via `npx`): `npx --yes oxlint@latest --config .oxlintrc.json --format=json testdata/ > /tmp/out.json; echo exit=$?` -Expected: oxlint exits non-zero (because of rule violations) and `/tmp/out.json` contains a JSON array with at least 2 diagnostic entries. - -If oxlint isn't available in the execution environment, mark this step as "deferred to CI" — the reviewdog workflow covers the same validation. - -- [ ] **Step 14.5: Commit** - -```bash -git add testdata/ -git commit -m "test: rewrite testdata fixtures for oxlint's default rules" -``` - ---- - -## Task 15: Update `test-subproject/` - -**Files:** -- Modify: `test-subproject/package.json` -- Delete: `test-subproject/.eslintrc.js` -- Delete: `test-subproject/package-lock.json` (regenerated in next task by the lock step, or leave for the action's `npm install` fallback) -- Modify: `test-subproject/sub-testdata/*.js` (same deterministic fixture treatment) - -- [ ] **Step 15.1: Inspect current subproject fixtures** - -Run: `ls test-subproject/sub-testdata/` -Expected: list of `.js` fixture files. Read each and note what rule they currently rely on. - -- [ ] **Step 15.2: Rewrite `test-subproject/package.json`** - -Overwrite: - -```json -{ - "name": "action-eslint-subproject", - "version": "1.0.0", - "description": "A test subproject for testing reviewdog/action-eslint", - "devDependencies": { - "oxlint": "^0.15.0" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/reviewdog/action-eslint.git" - }, - "keywords": [], - "author": "", - "license": "MIT", - "bugs": { - "url": "https://github.com/reviewdog/action-eslint/issues" - }, - "homepage": "https://github.com/reviewdog/action-eslint#readme" -} -``` - -Note: the oxlint major version is provisional — bump to the current stable at the time of implementation by checking `npm view oxlint version`. Update `^0.15.0` accordingly before committing. - -- [ ] **Step 15.3: Delete the old eslint config and lockfile** - -Run: `git rm test-subproject/.eslintrc.js test-subproject/package-lock.json` -Expected: both deletions staged. - -- [ ] **Step 15.4: Rewrite each file under `test-subproject/sub-testdata/` to fire oxlint rules** - -For each `.js` file, replace the contents with something equivalent to: - -```js -// Fires: no-var, no-unused-vars -var unused = 42; -``` - -(Keep each file distinct by name — the point is just that each file produces at least one diagnostic under oxlint defaults.) - -- [ ] **Step 15.5: Regenerate the subproject lockfile** - -Run: `cd test-subproject && npm install --package-lock-only && cd ..` -Expected: `test-subproject/package-lock.json` regenerated with only `oxlint` and its (few) transitive deps. - -If `npm install --package-lock-only` is unavailable or fails locally, leave the lockfile absent; the action's `npm install` fallback in `script.sh` will create it at runtime. - -- [ ] **Step 15.6: Commit** - -```bash -git add test-subproject/ -git commit -m "test(subproject): migrate to oxlint, regenerate lockfile" -``` - ---- - -## Task 16: Replace `.github/workflows/test.yml` - -**Files:** -- Modify: `.github/workflows/test.yml` - -- [ ] **Step 16.1: Overwrite contents** - -```yaml -name: test -on: - push: - branches: - - master - pull_request: -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: "24" - - name: Converter unit tests - run: node --test oxlint-to-rdjsonl.test.js -``` - -Note: `cache: "npm"` was removed — there's no repo-root `package.json` / lockfile to cache against. - -- [ ] **Step 16.2: Verify YAML** - -Run: `python3 -c "import yaml; yaml.safe_load(open('.github/workflows/test.yml'))"` -Expected: no error. - -- [ ] **Step 16.3: Commit** - -```bash -git add .github/workflows/test.yml -git commit -m "ci: run converter unit tests via node --test" -``` - ---- - -## Task 17: Update `.github/workflows/reviewdog.yml` - -**Files:** -- Modify: `.github/workflows/reviewdog.yml` - -- [ ] **Step 17.1: Overwrite contents** - -```yaml -name: reviewdog -on: [pull_request] -jobs: - oxlint: - name: runner / oxlint - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - node_version: - - "18" - - "20" - - "22" - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: setup Node.js - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: ${{ matrix.node_version }} - - name: install oxlint for root fixtures - run: npm install --no-save oxlint - - name: oxlint-github-pr-check - uses: ./ - with: - tool_name: oxlint-github-pr-check - reporter: github-pr-check - level: info - oxlint_flags: "--config .oxlintrc.json testdata/" - - name: oxlint-github-check - uses: ./ - with: - tool_name: oxlint-github-check - reporter: github-check - level: warning - oxlint_flags: "--config .oxlintrc.json testdata/" - - name: oxlint-github-pr-review - uses: ./ - with: - tool_name: oxlint-github-pr-review - reporter: github-pr-review - oxlint_flags: "--config .oxlintrc.json testdata/" - - name: oxlint-subproject-github-pr-review - uses: ./ - with: - tool_name: oxlint-subproject-github-pr-review - reporter: github-pr-review - workdir: ./test-subproject - oxlint_flags: "sub-testdata/" - - name: oxlint-subproject - uses: ./ - with: - tool_name: oxlint-subproject - workdir: ./test-subproject - oxlint_flags: "sub-testdata/" - reporter: github-check - level: warning - filter_mode: file -``` - -Note: dropped the `--ignore-pattern /test-subproject/` arg since `.oxlintrc.json` already has `ignorePatterns`. For subproject steps, no `--config` flag — oxlint auto-discovers `test-subproject/.oxlintrc.json` if present, or falls back to defaults. - -- [ ] **Step 17.2: Verify YAML** - -Run: `python3 -c "import yaml; yaml.safe_load(open('.github/workflows/reviewdog.yml'))"` -Expected: no error. - -- [ ] **Step 17.3: Commit** - -```bash -git add .github/workflows/reviewdog.yml -git commit -m "ci(reviewdog): exercise action with oxlint across node matrix" -``` - ---- - -## Task 18: Delete `.github/workflows/npm-publish.yml` - -**Files:** -- Delete: `.github/workflows/npm-publish.yml` - -- [ ] **Step 18.1: Delete** - -Run: `git rm .github/workflows/npm-publish.yml` -Expected: one deletion staged. - -- [ ] **Step 18.2: Commit** - -```bash -git commit -m "ci: remove npm-publish workflow (no npm package to publish)" -``` - ---- - -## Task 19: Rewrite `README.md` - -**Files:** -- Modify: `README.md` - -- [ ] **Step 19.1: Overwrite with new content** - -Replace the entire file with: - -```markdown -# GitHub Action: Run oxlint with reviewdog - -[![depup](https://github.com/reviewdog/action-eslint/workflows/depup/badge.svg)](https://github.com/reviewdog/action-eslint/actions?query=workflow%3Adepup) -[![release](https://github.com/reviewdog/action-eslint/workflows/release/badge.svg)](https://github.com/reviewdog/action-eslint/actions?query=workflow%3Arelease) -[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/reviewdog/action-eslint?logo=github&sort=semver)](https://github.com/reviewdog/action-eslint/releases) - -This action runs [oxlint](https://oxc.rs/docs/guide/usage/linter.html) with -[reviewdog](https://github.com/reviewdog/reviewdog) on pull requests to improve -code review experience. - -## Migrating from older versions of this action (eslint) - -Earlier versions of this action ran eslint. Starting with the oxlint rewrite, -the following breaking changes apply: - -- `eslint_flags` input → `oxlint_flags`. -- `node_options` input removed (oxlint is a native binary; `NODE_OPTIONS` has no effect). -- `tool_name` default changed from `eslint` to `oxlint`. -- You must list `oxlint` (not `eslint`) in your project's `devDependencies` (or equivalent). - -## Inputs - -### `github_token` -**Required.** Default `${{ github.token }}`. - -### `level` -Optional. Report level for reviewdog (`info`, `warning`, `error`). Same as reviewdog's `-level` flag. - -### `reporter` -Optional. `github-pr-check`, `github-check`, or `github-pr-review`. Default `github-pr-review`. - -### `tool_name` -Optional. Default `oxlint`. Becomes the check/run name on GitHub and the tool label in review comments. - -### `filter_mode` -Optional. `added`, `diff_context`, `file`, or `nofilter`. Default `added`. - -### `fail_level` -Optional. `none`, `any`, `info`, `warning`, or `error`. Default `none`. - -### `fail_on_error` -Deprecated. Use `fail_level`. - -### `reviewdog_flags` -Optional. Additional flags passed to reviewdog. - -### `oxlint_flags` -Optional. Flags and args for the `oxlint` command. Default `.`. - -### `workdir` -Optional. Directory from which to run oxlint. Default `.`. - -## Example usage - -Install oxlint in your project: - -```shell -npm install --save-dev oxlint -``` - -See the [oxlint configuration docs](https://oxc.rs/docs/guide/usage/linter/config.html) -for creating a `.oxlintrc.json`. This action uses that config automatically. - -### `.github/workflows/reviewdog.yml` - -```yaml -name: reviewdog -on: [pull_request] -jobs: - oxlint: - name: runner / oxlint - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - steps: - - uses: actions/checkout@v4 - - uses: reviewdog/action-eslint@vX - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - reporter: github-pr-review - oxlint_flags: "src/" -``` - -You can also set up Node and oxlint manually: - -```yaml -name: reviewdog -on: [pull_request] -jobs: - oxlint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npm install - - uses: reviewdog/action-eslint@vX - with: - reporter: github-check - oxlint_flags: "src/" -``` - -### Matrix example with unique tool name - -```yaml -name: reviewdog -on: [pull_request] -jobs: - oxlint: - runs-on: ubuntu-latest - strategy: - matrix: - node: [18, 20, 22] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node }} - - uses: reviewdog/action-eslint@vX - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - reporter: github-check - tool_name: oxlint-node-${{ matrix.node }} - oxlint_flags: "src/" -``` -``` - -Note: replace `@vX` with the actual release tag once a release is cut. Leave `@vX` in the plan so the implementer remembers the release step is still pending. - -- [ ] **Step 19.2: Check the file renders as valid markdown** - -Run: `node -e "require('node:fs').readFileSync('README.md','utf8')" && echo OK` -Expected: `OK`. (Purely a sanity read; we're not running a markdown linter.) - -- [ ] **Step 19.3: Commit** - -```bash -git add README.md -git commit -m "docs: rewrite README for oxlint" -``` - ---- - -## Task 20: Final integration pass - -**Files:** -- None directly; this is a pre-merge verification task. - -- [ ] **Step 20.1: Re-run converter tests** - -Run: `node --test oxlint-to-rdjsonl.test.js` -Expected: all tests pass. - -- [ ] **Step 20.2: Shell syntax check on `script.sh`** - -Run: `sh -n script.sh` -Expected: no output, exit 0. - -- [ ] **Step 20.3: Final grep for stale eslint references** - -Run: `grep -rn --exclude-dir=.git --exclude-dir=docs/superpowers -i eslint .` -Expected: no matches. If anything surfaces, investigate — README screenshots URLs or the "Migrating from eslint" section are allowed; anything functional is not. - -- [ ] **Step 20.4: Confirm the file list** - -Run: `git status` and `git log --oneline master..HEAD` -Expected: clean working tree; ~19 commits corresponding to Tasks 1–19. - -- [ ] **Step 20.5: Merge/PR** - -No commit in this task — hand off for review. - ---- - -## Self-review checklist - -This section lives in the plan so the implementer can confirm the plan matches the spec before handing off. - -| Spec section | Task(s) covering it | -|---|---| -| `action.yml` renames/removals | Task 9 | -| `script.sh` new pipeline | Task 10 | -| `oxlint-to-rdjsonl.js` transform rules | Tasks 1, 2, 5 | -| Byte-offset → line/column | Tasks 3, 4 | -| Edge cases (empty labels, read failure, invalid JSON, empty list) | Tasks 6, 8 | -| `convert` batch function | Task 7 | -| CLI exit codes | Task 8 | -| `testdata/` updates | Task 14 | -| `test-subproject/` updates | Task 15 | -| `.oxlintrc.json` | Task 13 | -| Delete eslint-formatter-rdjson | Task 11 | -| Delete repo-root eslint detritus | Task 12 | -| `.github/workflows/test.yml` | Task 16 | -| `.github/workflows/reviewdog.yml` | Task 17 | -| Delete `.github/workflows/npm-publish.yml` | Task 18 | -| README rewrite + migration callout | Task 19 | -| Final verification | Task 20 | diff --git a/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md b/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md deleted file mode 100644 index d4531e0..0000000 --- a/docs/superpowers/specs/2026-04-21-oxlint-migration-design.md +++ /dev/null @@ -1,243 +0,0 @@ -# Design: Migrate `action-eslint` to oxlint - -**Status:** approved (spec) -**Date:** 2026-04-21 - -## Summary - -In-place rewrite of this composite GitHub Action to run [oxlint](https://oxc.rs/docs/guide/usage/linter.html) with reviewdog instead of eslint. All eslint-specific code, inputs, tests, documentation, and the bundled `eslint-formatter-rdjson` are removed. This is a breaking change for existing consumers; there is no backward-compatibility shim. - -## Motivation - -Users of the action want to run oxlint — a faster Rust-based linter — through the same reviewdog integration this action provides. Rather than maintain two parallel actions, the repo is being repurposed. - -## Non-goals - -- Supporting both eslint and oxlint from the same action. -- Preserving input names for backward compatibility. -- Renaming the GitHub repository itself (that is an operational step outside this design). -- Releasing / version-tagging (handled by release tooling). - -## Architecture - -Composite action with a single bash entrypoint (`script.sh`) invoked by `action.yml`. The entrypoint: - -1. Installs reviewdog from its release script (unchanged from current behavior). -2. Verifies oxlint is available via `npx --no-install -c 'oxlint --version'`; if absent, runs `npm install` to pick up the consumer's declared `devDependencies`. -3. Pipes `oxlint --format=json ` through a small Node converter (`oxlint-to-rdjsonl.js`) into `reviewdog -f=rdjsonl`. - -The converter is the only new moving part. Everything else is renames and deletions. - -## Components - -### `action.yml` - -**Renamed inputs:** -- `eslint_flags` → `oxlint_flags` (default `.`) -- `tool_name` default: `eslint` → `oxlint` - -**Removed inputs:** -- `node_options` — oxlint is a Rust binary; `NODE_OPTIONS` has no effect. Dropping the input is cleaner than keeping a no-op. - -**Unchanged inputs:** -`github_token`, `level`, `reporter`, `filter_mode`, `fail_level`, `fail_on_error`, `reviewdog_flags`, `workdir`. - -**Env plumbing:** `INPUT_ESLINT_FLAGS` → `INPUT_OXLINT_FLAGS`. `NODE_OPTIONS` removed from `env:`. - -**Metadata:** `name` and `description` reworded for oxlint. Branding (`alert-octagon`, `blue`) unchanged. - -### `script.sh` - -Mirror of current structure, with eslint calls replaced: - -```sh -#!/bin/sh -cd "${GITHUB_WORKSPACE}/${INPUT_WORKDIR}" || exit 1 - -TEMP_PATH="$(mktemp -d)" -PATH="${TEMP_PATH}:$PATH" -export REVIEWDOG_GITHUB_API_TOKEN="${INPUT_GITHUB_TOKEN}" - -echo '::group::🐶 Installing reviewdog ...' -curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s -- -b "${TEMP_PATH}" "${REVIEWDOG_VERSION}" 2>&1 -echo '::endgroup::' - -npx --no-install -c 'oxlint --version' 2>/dev/null -if [ $? -ne 0 ]; then - echo '::group:: Running `npm install` to install oxlint ...' - set -e - npm install - set +e - echo '::endgroup::' -fi - -echo "oxlint version:$(npx --no-install -c 'oxlint --version')" - -echo '::group:: Running oxlint with reviewdog 🐶 ...' -npx --no-install -c "oxlint --format=json ${INPUT_OXLINT_FLAGS:-.}" \ - | node "${GITHUB_ACTION_PATH}/oxlint-to-rdjsonl.js" \ - | reviewdog -f=rdjsonl \ - -name="${INPUT_TOOL_NAME}" \ - -reporter="${INPUT_REPORTER:-github-pr-review}" \ - -filter-mode="${INPUT_FILTER_MODE}" \ - -fail-level="${INPUT_FAIL_LEVEL}" \ - -fail-on-error="${INPUT_FAIL_ON_ERROR}" \ - -level="${INPUT_LEVEL}" \ - ${INPUT_REVIEWDOG_FLAGS} - -reviewdog_rc=$? -echo '::endgroup::' -exit $reviewdog_rc -``` - -Pipefail is not enabled (matches current behavior). Reviewdog's exit code is the action's exit code. - -### `oxlint-to-rdjsonl.js` - -Stdin-to-stdout converter. Node built-ins only; no devDeps. - -**Input:** oxlint's JSON output — a top-level object wrapping the diagnostics array: - -```json -{ - "diagnostics": [ - { - "message": "...", - "code": "eslint(no-unused-vars)", - "severity": "error" | "warning" | "advice", - "url": "https://oxc.rs/...", - "help": "...", - "filename": "path/to/file.js", - "labels": [{ "span": { "offset": 123, "length": 5, "line": 10, "column": 5 } }] - } - ], - "number_of_files": 1, - "number_of_rules": 93, - "threads_count": 12, - "start_time": 0.01 -} -``` - -Note: oxlint's span also includes pre-computed 1-based byte `line`/`column` for the span start, but not for the end. The converter derives start and end positions from `offset`/`length` via file reading (which yields the same values as oxlint's pre-computed start), keeping a single code path that also yields the end position oxlint doesn't emit. - -For robustness, the converter accepts either the object form (`{diagnostics: [...]}`) or a bare array. - -**Output:** rdjsonl — one JSON object per line: - -```json -{"message":"...","location":{"path":"path/to/file.js","range":{"start":{"line":10,"column":5},"end":{"line":10,"column":10}}},"severity":"ERROR","code":{"value":"no-unused-vars","url":"https://oxc.rs/..."},"source":{"name":"oxlint","url":"https://oxc.rs/docs/guide/usage/linter.html"}} -``` - -**Transform rules:** - -| Input field | Output field | Notes | -|---|---|---| -| `message` | `message` | Pass through | -| `severity` | `severity` | `error` → `ERROR`, `warning` → `WARNING`, `advice` → `INFO` | -| `code` | `code.value` | Strip `plugin(...)` wrapper: `eslint(no-unused-vars)` → `no-unused-vars`. Bare code passed through. Missing code → omit `code` entirely. | -| `url` | `code.url` | Pass through if present; omit otherwise | -| `filename` | `location.path` | Pass through | -| `labels[0].span` | `location.range` | Convert byte offsets to 1-based line + 1-based column by reading the source file | -| (literal) | `source.name` / `source.url` | Always `"oxlint"` and oxlint docs URL | - -**Byte-offset → line/column conversion:** -- Read the file referenced by `filename` as a UTF-8 `Buffer`, once per run, cached. -- Walk bytes: increment line on `\n` (byte `0x0A`), reset column to 1 after newline, increment column per byte otherwise. -- Line and column are both 1-based UTF-8 byte positions. This matches the rdjson output emitted by the existing `eslint-formatter-rdjson` (which converts eslint's UTF-16 columns to UTF-8 bytes) — reviewdog's expected encoding on this action's wire format. -- Because oxlint's `offset` is already a UTF-8 byte offset (miette writes `label.offset()` which is source byte offset), no UTF-16 conversion is involved. -- `range.start` = position at `offset`. `range.end` = position at `offset + length`. - -**Edge cases:** -- Empty `labels` array or absent `filename`: emit diagnostic with `location.path` (if available) but no `range`. Reviewdog accepts file-level diagnostics. -- Multiple labels: use first only. Matches existing formatter behavior (one location per message). -- File read failure (e.g., file deleted between lint and convert): emit file-level diagnostic without `range`, continue. -- Invalid JSON on stdin: print error to stderr, exit 1. Silent drop would mask a broken lint run as "no issues." -- Empty diagnostic array: zero output lines, exit 0. - -### `oxlint-to-rdjsonl.test.js` - -Node's built-in `node:test` runner. No devDeps. - -**Cases:** -- Severity mapping across all three values. -- Rule code extraction: `plugin(rule)`, bare, missing. -- URL pass-through and absence. -- Offset → line/column: single-line, multi-line, offset at newline boundary, offset at EOF, UTF-8 multi-byte character. -- Empty `labels` → file-level diagnostic, no `range`. -- Multiple `labels` → first wins. -- File-read failure → file-level diagnostic, no crash. -- Invalid JSON on stdin → exit 1, message on stderr. -- Empty diagnostic list → zero lines, exit 0. - -Fixtures: small inline JSON + source files under `testdata/converter/` (`simple.js`, `multiline.js`, `utf8.js`). - -Run: `node --test oxlint-to-rdjsonl.test.js`. - -### `testdata/` and `test-subproject/` - -- `testdata/*.js`: adjust content so oxlint's default ruleset fires at least one diagnostic per file (validates the pipeline without binding tests to oxlint rule internals). -- `.oxlintrc.json` at repo root to pin rules for deterministic test output. -- `test-subproject/package.json`: swap `eslint` dep for `oxlint`, regenerate lockfile. -- `test-subproject/.eslintrc.js`: delete. The subproject relies on oxlint's default rules. If the end-to-end test needs a specific rule fired, a `test-subproject/.oxlintrc.json` is added alongside (decided during implementation when writing the fixture). -- `testdata/converter/*.js`: new fixtures for converter unit tests. - -### `.github/workflows/` - -Audited during implementation. Any workflow exercising the action end-to-end will install `oxlint` instead of `eslint`. Workflow names are preserved where possible to keep README badges valid. - -### `README.md` - -Full rewrite: - -- Title: "GitHub Action: Run oxlint with reviewdog" -- Intro links oxlint docs. -- Prereq: `npm install -D oxlint`. -- Config references `.oxlintrc.json`. -- Inputs section reflects the Section 4 changes. -- Example YAML updated throughout (`oxlint_flags`, `tool_name: oxlint`). -- Screenshot URLs left as placeholders; implementation PR notes they need re-capture. -- Top of file: short "Migrating from action-eslint" callout listing renamed/removed inputs. - -## Files - -**Add:** -- `oxlint-to-rdjsonl.js` -- `oxlint-to-rdjsonl.test.js` -- `.oxlintrc.json` -- `testdata/converter/{simple,multiline,utf8}.js` - -**Modify:** -- `action.yml` -- `script.sh` -- `README.md` -- `testdata/*.js` -- `test-subproject/package.json` (+ regenerate `test-subproject/package-lock.json`) -- `.github/workflows/*.yml` (audit first) - -**Delete:** -- `eslint-formatter-rdjson/` (entire directory) -- `.eslintrc.js` -- `package.json` (repo root) -- `package-lock.json` (repo root) -- `test-subproject/.eslintrc.js` - -## Error handling summary - -| Failure | Behavior | -|---|---| -| oxlint not installed | `npm install` in consumer project (existing fallback pattern) | -| oxlint emits invalid JSON | Converter exits 1, stderr explains; action fails loudly | -| Source file unreadable | File-level diagnostic without `range`, pipeline continues | -| Reviewdog non-zero exit | Propagated as action exit code (unchanged) | - -## Out of scope - -- Backward-compat shim for `eslint_flags` / `node_options`. -- Snapshot-testing reviewdog's rendered output. -- Running oxlint's own test suite. -- Git tagging or release automation. -- Repository rename on GitHub. - -## Open questions - -None. All design decisions resolved during brainstorming. From dbeb4391756f45a02d0df2607f95c7734041c87d Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 10:01:14 -0400 Subject: [PATCH 25/28] chore(action): update author to credit fork lineage Co-Authored-By: Claude Opus 4.7 (1M context) --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index aeafa63..beb5ce7 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,6 @@ name: 'Run oxlint with reviewdog' description: '🐶 Run oxlint with reviewdog on pull requests to improve code review experience.' -author: 'haya14busa (reviewdog)' +author: 'geoffharcourt (forked from haya14busa [reviewdog])' inputs: github_token: description: 'GITHUB_TOKEN.' From 9bb3b95f8dd66a0bede615d468604882ba40f9d8 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 10:02:08 -0400 Subject: [PATCH 26/28] docs: remove badges pointing to upstream workflows Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index f6980b7..5acdaae 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,5 @@ # GitHub Action: Run oxlint with reviewdog -[![depup](https://github.com/reviewdog/action-eslint/workflows/depup/badge.svg)](https://github.com/reviewdog/action-eslint/actions?query=workflow%3Adepup) -[![release](https://github.com/reviewdog/action-eslint/workflows/release/badge.svg)](https://github.com/reviewdog/action-eslint/actions?query=workflow%3Arelease) -[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/reviewdog/action-eslint?logo=github&sort=semver)](https://github.com/reviewdog/action-eslint/releases) - This action runs [oxlint](https://oxc.rs/docs/guide/usage/linter.html) with [reviewdog](https://github.com/reviewdog/reviewdog) on pull requests to improve code review experience. From 39151808fb459a9ff53a392931201c9d87d19147 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 10:03:37 -0400 Subject: [PATCH 27/28] docs: point usage examples at commonlit/action-eslint Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5acdaae..f9abf35 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ jobs: pull-requests: write steps: - uses: actions/checkout@v4 - - uses: reviewdog/action-eslint@vX + - uses: commonlit/action-eslint@vX with: github_token: ${{ secrets.GITHUB_TOKEN }} reporter: github-pr-review @@ -92,7 +92,7 @@ jobs: with: node-version: "20" - run: npm install - - uses: reviewdog/action-eslint@vX + - uses: commonlit/action-eslint@vX with: reporter: github-check oxlint_flags: "src/" @@ -114,7 +114,7 @@ jobs: - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} - - uses: reviewdog/action-eslint@vX + - uses: commonlit/action-eslint@vX with: github_token: ${{ secrets.GITHUB_TOKEN }} reporter: github-check From eb5c58750c7e68b043d8ff9d740015b44269bb26 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Wed, 22 Apr 2026 10:05:33 -0400 Subject: [PATCH 28/28] docs: restore pinned SHAs on actions/checkout and setup-node in first two examples Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f9abf35..4dbf76a 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: commonlit/action-eslint@vX with: github_token: ${{ secrets.GITHUB_TOKEN }} @@ -87,8 +87,8 @@ jobs: oxlint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: "20" - run: npm install