From 87b1161541505ebc74ad5b9905df91787e264c0d Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Thu, 19 Aug 2021 17:04:15 +0900 Subject: [PATCH 1/2] Support for ESLint v8 --- .github/workflows/NodeCI.yml | 42 +++++++- package.json | 2 +- tests/utils/source-code-fixer.ts | 162 +++++++++++++++++++++++++++++++ tests/utils/utils.ts | 5 +- 4 files changed, 202 insertions(+), 9 deletions(-) create mode 100644 tests/utils/source-code-fixer.ts diff --git a/.github/workflows/NodeCI.yml b/.github/workflows/NodeCI.yml index 4b3896a07..2a970bc50 100644 --- a/.github/workflows/NodeCI.yml +++ b/.github/workflows/NodeCI.yml @@ -18,18 +18,50 @@ jobs: run: npm install - name: Lint run: npm run lint - test: - runs-on: ubuntu-latest + test-for-eslint7: + name: "Test for ESLint ${{ matrix.eslint }} on ${{ matrix.node }} OS: ${{matrix.os}}" + runs-on: ${{ matrix.os }} strategy: matrix: - node-version: [10.x, 12.x, 13.x, 14.x, 15.x] + os: [ubuntu-latest] + node: [10, 12, 14, 16] + eslint: [7] steps: - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js ${{ matrix.node }} uses: actions/setup-node@v2 with: - node-version: ${{ matrix.node-version }} + node-version: ${{ matrix.node }} + - name: Install ESLint ${{ matrix.eslint }} + run: |+ + npm i -D eslint@${{ matrix.eslint }} + npx rimraf node_modules + if: matrix.eslint != 7 - name: Install Packages run: npm install --legacy-peer-deps - name: Test run: npm test + test-for-eslint8: + name: "Test for ESLint ${{ matrix.eslint }} on ${{ matrix.node }} OS: ${{matrix.os}}" + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + eslint: [^8.0.0-0] + node: [14, 16] + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Node.js ${{ matrix.node }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + - name: Install ESLint ${{ matrix.eslint }} + run: |+ + npm i -D eslint@${{ matrix.eslint }} + npx rimraf node_modules + if: matrix.eslint != 7 + - name: Install Packages + run: npm install --legacy-peer-deps + - name: Test + run: yarn test diff --git a/package.json b/package.json index 68145c013..c74e5d946 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "svelte-eslint-parser": "^0.4.3" }, "peerDependencies": { - "eslint": "^7.0.0", + "eslint": "^7.0.0 || ^8.0.0-0", "svelte": "^3.37.0" }, "peerDependenciesMeta": { diff --git a/tests/utils/source-code-fixer.ts b/tests/utils/source-code-fixer.ts new file mode 100644 index 000000000..41f36ba40 --- /dev/null +++ b/tests/utils/source-code-fixer.ts @@ -0,0 +1,162 @@ +/** + * Copy from https://github.com/eslint/eslint/blob/master/lib/linter/source-code-fixer.js + * @see https://github.com/eslint/eslint/issues/14936 + */ +/** + * @fileoverview An object that caches and applies source code fixes. + * @author Nicholas C. Zakas + */ + +import type { Linter } from "eslint" + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +// const debug = require("debug")("eslint:source-code-fixer"); +type Message = { + fix?: Linter.LintMessage["fix"] +} + +type HasFixMessage = Message & { + fix: NonNullable +} + +function hasFixMessage(m: Message): m is HasFixMessage { + return Boolean(m.fix) +} +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +const BOM = "\uFEFF" + +/** + * Compares items in a messages array by range. + * @param {Message} a The first message. + * @param {Message} b The second message. + * @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal. + * @private + */ +function compareMessagesByFixRange(a: HasFixMessage, b: HasFixMessage) { + return a.fix.range[0] - b.fix.range[0] || a.fix.range[1] - b.fix.range[1] +} + +/** + * Compares items in a messages array by line and column. + * @param {Message} a The first message. + * @param {Message} b The second message. + * @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal. + * @private + */ +function compareMessagesByLocation(a: any, b: any) { + return a.line - b.line || a.column - b.column +} + +// ------------------------------------------------------------------------------ +// Public Interface +// ------------------------------------------------------------------------------ + +/** + * Applies the fixes specified by the messages to the given text. Tries to be + * smart about the fixes and won't apply fixes over the same area in the text. + * @param {string} sourceText The text to apply the changes to. + * @param {Message[]} messages The array of messages reported by ESLint. + * @param {boolean|Function} [shouldFix=true] Determines whether each message should be fixed + * @returns {Object} An object containing the fixed text and any unfixed messages. + */ +export function applyFixes( + sourceText: string, + messages: M[], + shouldFix: boolean | ((m: M) => boolean) = true, +): { + fixed: boolean + messages: M[] + output: string +} { + // debug("Applying fixes"); + + if (shouldFix === false) { + // debug("shouldFix parameter was false, not attempting fixes"); + return { + fixed: false, + messages, + output: sourceText, + } + } + + // clone the array + const remainingMessages = [] + const fixes: (HasFixMessage & M)[] = [] + const bom = sourceText.startsWith(BOM) ? BOM : "" + const text = bom ? sourceText.slice(1) : sourceText + let lastPos = Number.NEGATIVE_INFINITY + let output = bom + + /** + * Try to use the 'fix' from a problem. + * @param {Message} problem The message object to apply fixes from + * @returns {boolean} Whether fix was successfully applied + */ + function attemptFix(problem: HasFixMessage) { + const fix = problem.fix + const start = fix.range[0] + const end = fix.range[1] + + // Remain it as a problem if it's overlapped or it's a negative range + if (lastPos >= start || start > end) { + remainingMessages.push(problem) + return false + } + + // Remove BOM. + if ((start < 0 && end >= 0) || (start === 0 && fix.text.startsWith(BOM))) { + output = "" + } + + // Make output to this fix. + output += text.slice(Math.max(0, lastPos), Math.max(0, start)) + output += fix.text + lastPos = end + return true + } + + messages.forEach((problem) => { + if (hasFixMessage(problem)) { + fixes.push(problem) + } else { + remainingMessages.push(problem) + } + }) + + if (fixes.length) { + // debug("Found fixes to apply"); + let fixesWereApplied = false + + for (const problem of fixes.sort(compareMessagesByFixRange)) { + if (typeof shouldFix !== "function" || shouldFix(problem)) { + attemptFix(problem) + + // The only time attemptFix will fail is if a previous fix was + // applied which conflicts with it. So we can mark this as true. + fixesWereApplied = true + } else { + remainingMessages.push(problem) + } + } + output += text.slice(Math.max(0, lastPos)) + + return { + fixed: fixesWereApplied, + messages: remainingMessages.sort(compareMessagesByLocation), + output, + } + } + + // debug("No fixes to apply"); + return { + fixed: false, + messages, + output: bom + text, + } +} diff --git a/tests/utils/utils.ts b/tests/utils/utils.ts index 4c65f0239..7ecc91534 100644 --- a/tests/utils/utils.ts +++ b/tests/utils/utils.ts @@ -2,11 +2,10 @@ import fs from "fs" import path from "path" import type { RuleTester } from "eslint" import { Linter } from "eslint" -// @ts-expect-error for test -import { SourceCodeFixer } from "eslint/lib/linter" import * as svelteESLintParser from "svelte-eslint-parser" // eslint-disable-next-line @typescript-eslint/no-require-imports -- tests import plugin = require("../../src/index") +import { applyFixes } from "./source-code-fixer" /** * Prevents leading spaces in a multiline template literal from appearing in the resulting string @@ -208,7 +207,7 @@ function writeFixtures( } if (force || !exists(outputFile)) { - const output = SourceCodeFixer.applyFixes(config.code, result).output + const output = applyFixes(config.code, result).output if (plugin.rules[ruleName].meta.fixable != null) { fs.writeFileSync(outputFile, output, "utf8") From 08ac4b603cfe7626ec7c147bf900e84d85de6bed Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Thu, 19 Aug 2021 17:06:22 +0900 Subject: [PATCH 2/2] fix ci --- .github/workflows/NodeCI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/NodeCI.yml b/.github/workflows/NodeCI.yml index 2a970bc50..e44b5d557 100644 --- a/.github/workflows/NodeCI.yml +++ b/.github/workflows/NodeCI.yml @@ -34,7 +34,7 @@ jobs: node-version: ${{ matrix.node }} - name: Install ESLint ${{ matrix.eslint }} run: |+ - npm i -D eslint@${{ matrix.eslint }} + npm i -D eslint@${{ matrix.eslint }} --legacy-peer-deps npx rimraf node_modules if: matrix.eslint != 7 - name: Install Packages @@ -58,7 +58,7 @@ jobs: node-version: ${{ matrix.node }} - name: Install ESLint ${{ matrix.eslint }} run: |+ - npm i -D eslint@${{ matrix.eslint }} + npm i -D eslint@${{ matrix.eslint }} --legacy-peer-deps npx rimraf node_modules if: matrix.eslint != 7 - name: Install Packages