Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b9ad774
feat: introduce `tsdown`, support js & ts
9romise Aug 21, 2025
928fe26
fix: dont bundle typescript
9romise Aug 21, 2025
1b24273
chore: update
9romise Aug 22, 2025
0f786d8
chore: update
9romise Aug 22, 2025
aedcd8d
refactor: rewrite `processor` in ts
9romise Aug 22, 2025
bd930b7
chore: specific tsdown target
9romise Aug 22, 2025
79d440d
fix: dont touch docs
9romise Aug 22, 2025
18d7488
ci: try fix
9romise Aug 22, 2025
861c1d6
fix: correct docs dev & build
9romise Aug 22, 2025
3d7f91c
chore: update
9romise Aug 22, 2025
f1c5923
chore: update
9romise Aug 25, 2025
eb2d18d
build: remove specific node version
9romise Oct 30, 2025
27f3479
chore: use `import` instead of `require` in esm files
9romise Oct 30, 2025
8c11d97
Merge branch 'master' into rewrite-ts
9romise Nov 20, 2025
17974eb
chore: update `tsdown`
9romise Nov 20, 2025
5e71d49
ci: add build in workflow
9romise Nov 20, 2025
6c4041b
fix: don't fix extension
9romise Nov 20, 2025
8d33d93
chore: update
9romise Nov 20, 2025
f081f42
Merge branch 'master' into pr/2916
9romise Nov 20, 2025
7108c0a
chore: use pkg.pr.new/rolldown temporarily
9romise Nov 20, 2025
1d7a583
ci: run build on node lts
9romise Nov 20, 2025
e9f7c7e
ci: cleanup
9romise Nov 20, 2025
3b54278
ci: add `needs`
9romise Nov 20, 2025
4438e9f
chore: update
9romise Nov 20, 2025
7633074
Merge remote-tracking branch 'upstream/master' into rewrite-ts
9romise Nov 22, 2025
75b42d3
chore: update typegen
9romise Nov 22, 2025
34f9c2b
cherry-pick: #2967
9romise Nov 22, 2025
4f2f525
chore: update `plugin.js`
9romise Nov 22, 2025
7cfa8d0
refactor: rewrite `index` in `.ts`
9romise Nov 22, 2025
e3dbe93
cherry-pick: #2968
9romise Nov 22, 2025
b92bc9c
chore: fix lint
9romise Nov 22, 2025
46ac044
Merge branch 'master' into rewrite-ts
9romise Nov 27, 2025
9c58e1f
chore: use latest `tsdown`, don't override `rolldown`
9romise Nov 27, 2025
e4a6bdb
Merge branch 'master' into rewrite-ts
9romise Dec 5, 2025
7559e8d
build: upgrade tsdown
9romise Dec 5, 2025
7e482cb
fix: includes `removed-rules`
9romise Dec 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,35 @@ jobs:
- name: Lint
run: npm run lint

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v6
with:
node-version: lts/*

- name: Install Packages
run: npm install
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build job uses npm install without the --legacy-peer-deps flag, while the lint job uses npm install --legacy-peer-deps. This inconsistency could lead to different dependency resolution and potential build failures. The build job should use the same installation command as other jobs for consistency.

Suggested change
run: npm install
run: npm install --legacy-peer-deps

Copilot uses AI. Check for mistakes.

- name: Build
run: npm run build

- name: Cache dist
uses: actions/upload-artifact@v5
with:
retention-days: 3
name: dist
path: dist

test:
name: Test
strategy:
matrix:
node: [18, 20, 21, 'lts/*']
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Checkout
uses: actions/checkout@v5
Expand All @@ -41,12 +64,18 @@ jobs:
node-version: ${{ matrix.node }}
- name: Install Packages
run: npm install
- name: Restore dist cache
uses: actions/download-artifact@v6
with:
name: dist
Comment on lines +67 to +70
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The download-artifact action is missing the path parameter to specify where the artifact should be extracted. By default, artifacts are downloaded to the current working directory, but it's unclear if that matches the expected dist location. The path parameter should be explicitly set to dist to ensure the artifact is extracted to the correct location.

Copilot uses AI. Check for mistakes.
- name: Test
run: npm test

test-with-eslint-v8:
name: Test with ESLint v8
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Checkout
uses: actions/checkout@v5
Expand All @@ -58,12 +87,18 @@ jobs:
run: npm install
- name: Install ESLint v8
run: npm install --save-dev eslint@8 --force
- name: Restore dist cache
uses: actions/download-artifact@v6
with:
name: dist
Comment on lines +90 to +93
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The download-artifact action is missing the path parameter to specify where the artifact should be extracted. By default, artifacts are downloaded to the current working directory, but it's unclear if that matches the expected dist location. The path parameter should be explicitly set to dist to ensure the artifact is extracted to the correct location.

Copilot uses AI. Check for mistakes.
- name: Test
run: npm test

test-without-eslint-stylistic:
name: Test without ESLint Stylistic
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Checkout
uses: actions/checkout@v5
Expand All @@ -73,6 +108,10 @@ jobs:
run: npm install
- name: Uninstall @stylistic/eslint-plugin
run: npm uninstall @stylistic/eslint-plugin
- name: Restore dist cache
uses: actions/download-artifact@v6
with:
name: dist
Comment on lines +111 to +114
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The download-artifact action is missing the path parameter to specify where the artifact should be extracted. By default, artifacts are downloaded to the current working directory, but it's unclear if that matches the expected dist location. The path parameter should be explicitly set to dist to ensure the artifact is extracted to the correct location.

Copilot uses AI. Check for mistakes.
- name: Test
run: npm test

Expand All @@ -82,6 +121,8 @@ jobs:
matrix:
stylistic: [2, 3, 4]
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Checkout
uses: actions/checkout@v5
Expand All @@ -91,12 +132,18 @@ jobs:
run: npm install
- name: Install @stylistic/eslint-plugin v${{ matrix.stylistic }}
run: npm install -D @stylistic/eslint-plugin@${{ matrix.stylistic }} --force
- name: Restore dist cache
uses: actions/download-artifact@v6
with:
name: dist
Comment on lines +135 to +138
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The download-artifact action is missing the path parameter to specify where the artifact should be extracted. By default, artifacts are downloaded to the current working directory, but it's unclear if that matches the expected dist location. The path parameter should be explicitly set to dist to ensure the artifact is extracted to the correct location.

Copilot uses AI. Check for mistakes.
- name: Test
run: npm test

test-with-typescript-eslint-v7:
name: Test with typescript-eslint v7
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Checkout
uses: actions/checkout@v5
Expand All @@ -106,5 +153,9 @@ jobs:
run: npm install
- name: Install @typescript-eslint/parser v7
run: npm install -D @typescript-eslint/parser@7 --force
- name: Restore dist cache
uses: actions/download-artifact@v6
with:
name: dist
Comment on lines +156 to +159
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The download-artifact action is missing the path parameter to specify where the artifact should be extracted. By default, artifacts are downloaded to the current working directory, but it's unclear if that matches the expected dist location. The path parameter should be explicitly set to dist to ensure the artifact is extracted to the correct location.

Copilot uses AI. Check for mistakes.
- name: Test
run: npm test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ yarn-error.log
/docs/.vitepress/cache
typings/eslint/lib/rules
eslint-typegen.d.ts
dist
2 changes: 1 addition & 1 deletion docs/.vitepress/theme/components/eslint-code-block.vue
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export default {
this.height = `${Math.max(120, 20 * (1 + lines))}px`
// Load linter.
const [plugin, { Linter }, vueEslintParser, globals] = await Promise.all([
import('../../../..'),
import('../../../../lib/index'),
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import path '../../../../lib/index' attempts to import from the source directory, but with the package.json change, the built output is now in the dist directory. This import should be updated to '../../../../dist/index' or '../../../../lib/index.js' (if the intent is to use the transpiled output), or ensure that Vite/VitePress is configured to handle TypeScript imports from lib/ directory.

Suggested change
import('../../../../lib/index'),
import('../../../../dist/index'),

Copilot uses AI. Check for mistakes.
import('eslint'),
import('vue-eslint-parser'),
import('globals')
Expand Down
6 changes: 0 additions & 6 deletions lib/index.js

This file was deleted.

4 changes: 4 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import configs from './configs/index.js'
import plugin from './plugin.js'

export default Object.assign(plugin, { configs })
3 changes: 0 additions & 3 deletions lib/meta.js

This file was deleted.

3 changes: 3 additions & 0 deletions lib/meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import pkg from '../package.json' with { type: 'json' }

export default { name: pkg.name, version: pkg.version }
6 changes: 3 additions & 3 deletions lib/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
'use strict'

const plugin = {
meta: require('./meta'),
meta: require('./meta.ts').default,
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using require('./meta.ts').default to import a TypeScript file from a CommonJS module is problematic. After tsdown transpiles the code, the file should be ./meta.js in the dist directory, not ./meta.ts. This will cause a runtime error because the .ts file won't exist in the built output. The require path should reference the transpiled .js file.

Copilot uses AI. Check for mistakes.
rules: {
'array-bracket-newline': require('./rules/array-bracket-newline'),
'array-bracket-spacing': require('./rules/array-bracket-spacing'),
Expand Down Expand Up @@ -258,8 +258,8 @@ const plugin = {
'valid-v-text': require('./rules/valid-v-text')
},
processors: {
'.vue': require('./processor'),
vue: require('./processor')
'.vue': require('./processor.ts').default,
vue: require('./processor.ts').default
Comment on lines +261 to +262
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using require('./processor.ts').default to import a TypeScript file from a CommonJS module is problematic. After tsdown transpiles the code, the file should be ./processor.js in the dist directory, not ./processor.ts. This will cause a runtime error because the .ts file won't exist in the built output. The require path should reference the transpiled .js file.

Suggested change
'.vue': require('./processor.ts').default,
vue: require('./processor.ts').default
'.vue': require('./processor.js').default,
vue: require('./processor.js').default

Copilot uses AI. Check for mistakes.
}
}

Expand Down
75 changes: 30 additions & 45 deletions lib/processor.js → lib/processor.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,34 @@
/**
* @author Toru Nagashima <https://github.com/mysticatea>
*/
'use strict'
import type { Linter } from 'eslint'
import meta from './meta.ts'

/**
* @typedef {import('eslint').Linter.LintMessage} LintMessage
*/
/**
* @typedef {object} GroupState
* @property {Set<string>} GroupState.disableAllKeys
* @property {Map<string, string[]>} GroupState.disableRuleKeys
*/
type LintMessage = Linter.LintMessage

interface GroupState {
disableAllKeys: Set<string>
disableRuleKeys: Map<string, string[]>
}

module.exports = {
/** @param {string} code */
preprocess(code) {
export default {
preprocess(code: string): string[] {
return [code]
},

/**
* @param {LintMessage[][]} messages
* @returns {LintMessage[]}
*/
postprocess(messages) {
postprocess(messages: LintMessage[][]): LintMessage[] {
const state = {
/** @type {GroupState} */
block: {
disableAllKeys: new Set(),
disableRuleKeys: new Map()
},
/** @type {GroupState} */
disableAllKeys: new Set<string>(),
disableRuleKeys: new Map<string, string[]>()
} satisfies GroupState,
line: {
disableAllKeys: new Set(),
disableRuleKeys: new Map()
}
disableAllKeys: new Set<string>(),
disableRuleKeys: new Map<string, string[]>()
} satisfies GroupState
}
/** @type {string[]} */
const usedDisableDirectiveKeys = []
/** @type {Map<string,LintMessage>} */
const unusedDisableDirectiveReports = new Map()
const usedDisableDirectiveKeys: string[] = []
const unusedDisableDirectiveReports = new Map<string, LintMessage>()

// Filter messages which are in disabled area.
const filteredMessages = messages[0].filter((message) => {
Expand Down Expand Up @@ -136,15 +126,14 @@ module.exports = {

supportsAutofix: true,

meta: require('./meta')
meta
}

/**
* @param {Map<string, string[]>} disableRuleKeys
* @param {string} rule
* @param {string} key
*/
function addDisableRule(disableRuleKeys, rule, key) {
function addDisableRule(
disableRuleKeys: GroupState['disableRuleKeys'],
rule: string,
key: string
): void {
let keys = disableRuleKeys.get(rule)
if (keys) {
keys.push(key)
Expand All @@ -154,11 +143,7 @@ function addDisableRule(disableRuleKeys, rule, key) {
}
}

/**
* @param {LintMessage} message
* @returns {string} message key
*/
function messageToKey(message) {
function messageToKey(message: LintMessage): string {
return `line:${message.line},column${
// -1 because +1 by ESLint's `report-translator`.
message.column - 1
Expand All @@ -167,11 +152,11 @@ function messageToKey(message) {

/**
* Compares the locations of two objects in a source file
* @param {Position} itemA The first object
* @param {Position} itemB The second object
* @returns {number} A value less than 1 if itemA appears before itemB in the source file, greater than 1 if
* @param itemA The first object
* @param itemB The second object
* @returns A value less than 1 if itemA appears before itemB in the source file, greater than 1 if
* itemA appears after itemB in the source file, or 0 if itemA and itemB have the same location.
*/
function compareLocations(itemA, itemB) {
function compareLocations(itemA: Position, itemB: Position): number {
return itemA.line - itemB.line || itemA.column - itemB.column
}
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"name": "eslint-plugin-vue",
"version": "10.6.2",
"description": "Official ESLint plugin for Vue.js",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"new": "node tools/new-rule.js",
"start": "npm run test:base -- --watch",
Expand All @@ -22,15 +22,16 @@
"update": "node ./tools/update.js",
"update-resources": "node ./tools/update-resources.js",
"typegen": "node ./tools/generate-typegen.mjs",
"build": "npm run typegen && tsdown",
"docs:watch": "vitepress dev docs",
"predocs:build": "npm run update",
"docs:build": "vitepress build docs",
"generate:version": "env-cmd -e version npm run update && npm run lint:fix",
"changeset:version": "changeset version && npm run generate:version && git add --all",
"changeset:publish": "npm run typegen && changeset publish"
"changeset:publish": "npm run build && changeset publish"
},
"files": [
"lib"
"dist"
],
"homepage": "https://eslint.vuejs.org",
"keywords": [
Expand Down Expand Up @@ -117,6 +118,7 @@
"markdownlint-cli": "^0.42.0",
"pathe": "^1.1.2",
"prettier": "^3.7.0",
"tsdown": "^0.17.0",
"typescript": "^5.7.2",
"vite-plugin-eslint4b": "^0.5.1",
"vitepress": "^1.4.1",
Expand Down
2 changes: 1 addition & 1 deletion tools/generate-typegen.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fs from 'node:fs/promises'
import { pluginsToRulesDTS } from 'eslint-typegen/core'
import plugin from '../lib/index.js'
import plugin from '../lib/index.ts'
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importing a TypeScript file (../lib/index.ts) from an ESM module (.mjs) will fail at runtime because Node.js doesn't natively support TypeScript imports without a loader. Since the build script runs typegen before tsdown, this script executes before the TypeScript files are transpiled. Consider using a TypeScript loader, running this script with tsx/ts-node, or restructuring the build process so typegen runs after the build.

Suggested change
import plugin from '../lib/index.ts'
import plugin from '../lib/index.js'

Copilot uses AI. Check for mistakes.

const dts = await pluginsToRulesDTS(
{
Expand Down
6 changes: 3 additions & 3 deletions tools/update-lib-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ const content = `/*
'use strict'

const plugin = {
meta: require('./meta'),
meta: require('./meta.ts').default,
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using require('./meta.ts').default to import a TypeScript file from a CommonJS module is problematic. After tsdown transpiles the code, the file should be ./meta.js in the dist directory, not ./meta.ts. This will cause a runtime error because the .ts file won't exist in the built output. The require path should reference the transpiled .js file.

Copilot uses AI. Check for mistakes.
rules: {
${rules
.map((rule) => `'${rule.name}': require('./rules/${rule.name}')`)
.join(',\n')}
},
processors: {
'.vue': require('./processor'),
'vue': require('./processor')
'.vue': require('./processor.ts').default,
'vue': require('./processor.ts').default
Comment on lines +34 to +35
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using require('./processor.ts').default to import a TypeScript file from a CommonJS module is problematic. After tsdown transpiles the code, the file should be ./processor.js in the dist directory, not ./processor.ts. This will cause a runtime error because the .ts file won't exist in the built output. The require path should reference the transpiled .js file.

Suggested change
'.vue': require('./processor.ts').default,
'vue': require('./processor.ts').default
'.vue': require('./processor.js').default,
'vue': require('./processor.js').default

Copilot uses AI. Check for mistakes.
}
}

Expand Down
11 changes: 7 additions & 4 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"target": "ES2019",
"module": "node16",
"moduleResolution": "Node16",
"target": "esnext",
"module": "preserve",
"moduleResolution": "bundler",
"lib": ["es2020"],
"types": [
"vitest/globals"
Expand All @@ -20,11 +20,14 @@
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"baseUrl": ".",
"paths": {
"*": ["typings/*"]
},
"skipLibCheck": true
"skipLibCheck": true,
"allowImportingTsExtensions": true
},
"include": [
"lib/**/*",
Expand Down
11 changes: 11 additions & 0 deletions tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineConfig } from 'tsdown'

export default defineConfig({
entry: ['lib/index.ts'],
format: ['cjs'],
copy: ['lib/index.d.ts', 'lib/eslint-typegen.d.ts', 'lib/removed-rules.js'],
dts: false,
external: ['typescript'],
unbundle: true,
fixedExtension: false
})
Loading