oxlint-plugin-vize 0.429.1 → 0.429.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -10
- package/dist/cli.mjs +1 -2
- package/dist/index.mjs +36 -27
- package/dist/{workaround-DRe3y2CB.mjs → workaround-CcnA_oWy.mjs} +8 -4
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ This package lets Oxlint execute Patina through Vize's native binding while stil
|
|
|
6
6
|
|
|
7
7
|
> [!IMPORTANT]
|
|
8
8
|
> `oxlint-plugin-vize` is a terminal-first Vue SFC linting package.
|
|
9
|
-
> Until upstream Vue support in Oxlint matures,
|
|
9
|
+
> Until upstream Vue support in Oxlint matures, use `oxlint-vize` for original SFC locations in terminal and JSON output. Direct `oxlint` still has JS plugin location limits.
|
|
10
10
|
|
|
11
11
|
## Main Features
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ This package lets Oxlint execute Patina through Vize's native binding while stil
|
|
|
15
15
|
- Ships preset rule maps for JS/TS Oxlint configs: `configs.recommended`, `configs.happyPath`, `configs.essential`, `configs.ecosystem`, `configs.opinionated`, `configs.nuxt`, `configs.all`, and type-aware opt-in variants.
|
|
16
16
|
- Ships `createVizeLintConfig()`, `flatConfigs`, and `defineVizeLintConfig()` for the Vite+ `lint` block in `vite.config.ts`, which is the only Oxlint configuration `vp lint` and `vp check` read.
|
|
17
17
|
- Supports runtime settings through `settings.vize`, including `locale`, `preset`, and `helpLevel`.
|
|
18
|
-
- Provides the `oxlint-vize` CLI wrapper, which runs Oxlint with a
|
|
18
|
+
- Provides the `oxlint-vize` CLI wrapper, which runs Oxlint with a temporary location bridge for Vue and HTML files and reports their original paths and Patina locations.
|
|
19
19
|
- Resolves Vize native bindings through platform-specific optional dependencies, so published installs do not need a separate `@vizejs/native` package.
|
|
20
20
|
- Caches file contents and native rule results for the lifetime of the Oxlint process, reducing duplicate work when several Vize rules are enabled for the same file.
|
|
21
21
|
|
|
@@ -229,20 +229,18 @@ For day-to-day terminal runs, the recommended command today is:
|
|
|
229
229
|
vp exec oxlint-vize -c .oxlintrc.json -f stylish src
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
-
`oxlint-vize`
|
|
233
|
-
`stylish` is currently the most usable compromise for mixed Oxlint + Vize output because the Patina summary can inline the original SFC location even though Oxlint still anchors JS plugin diagnostics to the extracted script program.
|
|
232
|
+
`oxlint-vize` appends a temporary `<script setup>` location bridge for Vue and HTML files, including files with existing scripts. This lets Patina report the original SFC line and column through Oxlint's JS plugin pipeline. The wrapper rewrites temporary paths back to the original files; `-f json` retains those original positions for machine-readable diagnostics.
|
|
234
233
|
|
|
235
234
|
## Limitations
|
|
236
235
|
|
|
237
|
-
- Raw `oxlint` still misses files without `<script>` or `<script setup>`.
|
|
238
|
-
-
|
|
239
|
-
- Formatter parity is not there yet. `stylish` is recommended for human-readable terminal output, while `json` and other machine-readable outputs are best treated as debugging aids for original template/style positions.
|
|
236
|
+
- Raw `oxlint` still misses files without `<script>` or `<script setup>`. It also anchors template diagnostics to an extracted script instead of the original template location. Use `oxlint-vize` when linting Vue and HTML files.
|
|
237
|
+
- The wrapper's temporary files are not copied back when Oxlint fix flags are used; it warns when `--fix` or `--fix-suggestions` is passed.
|
|
240
238
|
- Oxlint core rules that need JavaScript bindings extracted from Vue templates, such as template-aware unused-variable checks, still depend on upstream work in [Oxc's Better Vue Support](https://github.com/oxc-project/oxc/issues/15761).
|
|
241
|
-
-
|
|
239
|
+
- Direct `oxlint` original-SFC ranges depend on the JS plugin reporting work tracked in [oxc-project/oxc#20465](https://github.com/oxc-project/oxc/issues/20465).
|
|
242
240
|
- Type-aware Vize rules are experimental and excluded from the default exported configs. Opt into them explicitly with `configs.recommendedWithTypeAware`, `configs.opinionatedWithTypeAware`, or `createVizeRuleConfig({ includeTypeAware: true, preset: ... })`, and use `settings.vize.typeAware: true` when you want the shared full-file pass to run them eagerly.
|
|
243
241
|
|
|
244
242
|
## Current expectations
|
|
245
243
|
|
|
246
244
|
- This release is meant for terminal-first workflows.
|
|
247
|
-
-
|
|
248
|
-
- Once Oxlint
|
|
245
|
+
- The `oxlint-vize` wrapper reports original Patina positions in `stylish` and `json`; direct `oxlint` remains limited by its extracted-script JS plugin input.
|
|
246
|
+
- Once Oxlint preserves original Vue positions for JS plugins, the temporary location bridge can be removed.
|
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as hasVueLikeExtension,
|
|
1
|
+
import { i as hasVueLikeExtension, s as isStandaloneHtmlFile, t as appendScriptlessWorkaround } from "./workaround-CcnA_oWy.mjs";
|
|
2
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs from "node:fs";
|
|
@@ -200,7 +200,6 @@ function prepareScriptlessWorkaroundFiles(cwd, filenames) {
|
|
|
200
200
|
for (const filename of filenames) {
|
|
201
201
|
const source = fs.readFileSync(filename, "utf8");
|
|
202
202
|
const isStandaloneHtml = isStandaloneHtmlFile(filename);
|
|
203
|
-
if (!isStandaloneHtml && hasScriptLikeBlock(source)) continue;
|
|
204
203
|
const relativeFilename = path.relative(cwd, filename);
|
|
205
204
|
if (tempDir == null) {
|
|
206
205
|
const created = createWorkaroundTempDir(nodeModulesDir, tempRoot);
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
|
-
import { a as isPatinaFile, c as compareLineColumn, d as getDiagnosticBlock, l as extractSfcBlocks, o as isScriptLikeFile, r as resolveWorkaroundSource, u as formatBlockLabel } from "./workaround-
|
|
1
|
+
import { a as isPatinaFile, c as compareLineColumn, d as getDiagnosticBlock, l as extractSfcBlocks, n as isLocationBridgeProgram, o as isScriptLikeFile, r as resolveWorkaroundSource, u as formatBlockLabel } from "./workaround-CcnA_oWy.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { definePlugin, defineRule } from "@oxlint/plugins";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import fs from "node:fs";
|
|
7
|
+
//#region src/plugin-option-guards.ts
|
|
8
|
+
function optionField(value) {
|
|
9
|
+
return value === void 0 || value === "always" || value === "never" || value === "any";
|
|
10
|
+
}
|
|
11
|
+
function optionalBooleanField(value) {
|
|
12
|
+
return value === void 0 || typeof value === "boolean";
|
|
13
|
+
}
|
|
14
|
+
function isString(value) {
|
|
15
|
+
return typeof value === "string";
|
|
16
|
+
}
|
|
17
|
+
function isRecord$1(value) {
|
|
18
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
function hasOnlyKeys(value, keys) {
|
|
21
|
+
return Object.keys(value).every((key) => keys.includes(key));
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
7
24
|
//#region src/native.ts
|
|
8
25
|
const require = createRequire(import.meta.url);
|
|
9
26
|
const FALLBACK_BINDING_PACKAGE = "@vizejs/native";
|
|
@@ -553,29 +570,36 @@ function createSummaryLine(message) {
|
|
|
553
570
|
}
|
|
554
571
|
//#endregion
|
|
555
572
|
//#region src/plugin.ts
|
|
556
|
-
function createOxlintDiagnostic(diagnostic, state, scriptMap, helpLevel) {
|
|
573
|
+
function createOxlintDiagnostic(diagnostic, state, scriptMap, helpLevel, program) {
|
|
557
574
|
const loc = state.usesOriginalLocations ? createOriginalSfcLoc(diagnostic) : mapToScriptLoc(diagnostic, scriptMap);
|
|
558
575
|
const block = loc === null ? getDiagnosticBlock(diagnostic, getSfcBlocks(state)) : null;
|
|
576
|
+
const message = formatPatinaMessage(diagnostic, {
|
|
577
|
+
hasMappedLocation: loc !== null,
|
|
578
|
+
blockLabel: formatBlockLabel(block),
|
|
579
|
+
helpLevel
|
|
580
|
+
});
|
|
581
|
+
if (loc == null && state.extractedScript.length === 0) return {
|
|
582
|
+
node: program,
|
|
583
|
+
message
|
|
584
|
+
};
|
|
585
|
+
const fallbackColumn = state.extractedScript.length === 0 ? 0 : 1;
|
|
559
586
|
return {
|
|
560
587
|
loc: loc ?? {
|
|
561
588
|
start: {
|
|
562
589
|
line: 1,
|
|
563
|
-
column:
|
|
590
|
+
column: fallbackColumn
|
|
564
591
|
},
|
|
565
592
|
end: {
|
|
566
593
|
line: 1,
|
|
567
|
-
column:
|
|
594
|
+
column: fallbackColumn
|
|
568
595
|
}
|
|
569
596
|
},
|
|
570
|
-
message
|
|
571
|
-
hasMappedLocation: loc !== null,
|
|
572
|
-
blockLabel: formatBlockLabel(block),
|
|
573
|
-
helpLevel
|
|
574
|
-
})
|
|
597
|
+
message
|
|
575
598
|
};
|
|
576
599
|
}
|
|
577
600
|
function shouldReportForCurrentProgram(diagnostic, state, scriptMap) {
|
|
578
|
-
if (state.usesOriginalLocations
|
|
601
|
+
if (state.usesOriginalLocations) return isScriptLikeFile(state.filename) || isLocationBridgeProgram(state.extractedScript);
|
|
602
|
+
if (scriptMap == null) return true;
|
|
579
603
|
const block = getDiagnosticBlock(diagnostic, getSfcBlocks(state));
|
|
580
604
|
return !isScriptBlock(block) || block === scriptMap.block;
|
|
581
605
|
}
|
|
@@ -602,7 +626,7 @@ function createPatinaRule(ruleMeta) {
|
|
|
602
626
|
schema: ruleOptionsSchema(ruleMeta.name)
|
|
603
627
|
},
|
|
604
628
|
createOnce(context) {
|
|
605
|
-
return { Program() {
|
|
629
|
+
return { Program(program) {
|
|
606
630
|
if (!isPatinaFile(context.filename)) return;
|
|
607
631
|
const settings = getVizeSettings(context);
|
|
608
632
|
const activePreset = getActivePreset(settings);
|
|
@@ -615,7 +639,7 @@ function createPatinaRule(ruleMeta) {
|
|
|
615
639
|
if (diagnostics.length === 0) return;
|
|
616
640
|
for (const diagnostic of diagnostics) {
|
|
617
641
|
if (!markDiagnosticAsReported(state, diagnostic)) continue;
|
|
618
|
-
context.report(createOxlintDiagnostic(diagnostic, state, scriptMap, helpLevel));
|
|
642
|
+
context.report(createOxlintDiagnostic(diagnostic, state, scriptMap, helpLevel, program));
|
|
619
643
|
}
|
|
620
644
|
} };
|
|
621
645
|
}
|
|
@@ -740,21 +764,6 @@ function isHtmlSelfClosingOption(value) {
|
|
|
740
764
|
function isHyphenationStyle(value) {
|
|
741
765
|
return value === "always" || value === "never";
|
|
742
766
|
}
|
|
743
|
-
function optionField(value) {
|
|
744
|
-
return value === void 0 || value === "always" || value === "never" || value === "any";
|
|
745
|
-
}
|
|
746
|
-
function optionalBooleanField(value) {
|
|
747
|
-
return value === void 0 || typeof value === "boolean";
|
|
748
|
-
}
|
|
749
|
-
function isString(value) {
|
|
750
|
-
return typeof value === "string";
|
|
751
|
-
}
|
|
752
|
-
function isRecord$1(value) {
|
|
753
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
754
|
-
}
|
|
755
|
-
function hasOnlyKeys(value, keys) {
|
|
756
|
-
return Object.keys(value).every((key) => keys.includes(key));
|
|
757
|
-
}
|
|
758
767
|
var plugin_default = definePlugin({
|
|
759
768
|
meta: { name: "vize" },
|
|
760
769
|
rules: Object.fromEntries(getPatinaRules().map((ruleMeta) => [ruleMeta.name, createPatinaRule(ruleMeta)]))
|
|
@@ -141,12 +141,16 @@ function isStandaloneHtmlFile(filename) {
|
|
|
141
141
|
const SCRIPTLESS_WORKAROUND_MARKER = "oxlint-plugin-vize-scriptless";
|
|
142
142
|
const SCRIPTLESS_WORKAROUND_OPEN_TAG_PREFIX = `<script setup lang="ts" data-${SCRIPTLESS_WORKAROUND_MARKER}="`;
|
|
143
143
|
const SCRIPTLESS_WORKAROUND_FILENAME_ATTR = `data-${SCRIPTLESS_WORKAROUND_MARKER}="`;
|
|
144
|
+
const LOCATION_BRIDGE_MARKER = "/*vize-location-bridge*/";
|
|
144
145
|
function hasScriptLikeBlock(source) {
|
|
145
146
|
return extractSfcBlocks(source).some((block) => block.kind === "script" || block.kind === "script-setup");
|
|
146
147
|
}
|
|
147
148
|
function appendScriptlessWorkaround(source, filename) {
|
|
148
149
|
return `${createWorkaroundScript(source, filename)}${source}`;
|
|
149
150
|
}
|
|
151
|
+
function isLocationBridgeProgram(extractedScript) {
|
|
152
|
+
return extractedScript.trimEnd().endsWith(LOCATION_BRIDGE_MARKER);
|
|
153
|
+
}
|
|
150
154
|
function resolveWorkaroundSource(source, fallbackFilename) {
|
|
151
155
|
const workaroundBlock = getPrependedWorkaroundBlock(source);
|
|
152
156
|
if (workaroundBlock == null) return {
|
|
@@ -167,7 +171,7 @@ function getPrependedWorkaroundBlock(source) {
|
|
|
167
171
|
if (!source.startsWith(SCRIPTLESS_WORKAROUND_OPEN_TAG_PREFIX)) return null;
|
|
168
172
|
const [firstBlock] = extractSfcBlocks(source);
|
|
169
173
|
if (!firstBlock || firstBlock.kind !== "script-setup") return null;
|
|
170
|
-
if (!isWhitespaceOnly(firstBlock.content)) return null;
|
|
174
|
+
if (!firstBlock.content.endsWith(LOCATION_BRIDGE_MARKER) || !isWhitespaceOnly(firstBlock.content.slice(0, -24))) return null;
|
|
171
175
|
const contentStart = offsetFromLineColumn(source, firstBlock.contentStart);
|
|
172
176
|
const contentEnd = offsetFromLineColumn(source, firstBlock.contentEnd);
|
|
173
177
|
const encodedFilename = encodedFilenameFromWorkaroundOpenTag(source.slice(0, contentStart));
|
|
@@ -175,7 +179,7 @@ function getPrependedWorkaroundBlock(source) {
|
|
|
175
179
|
const closeTagEnd = contentEnd + 9;
|
|
176
180
|
const strippedSourceStart = sourceStartAfterSyntheticBlock(source, closeTagEnd);
|
|
177
181
|
if (strippedSourceStart == null) return null;
|
|
178
|
-
if (firstBlock.content !== createWhitespaceMirror(source.slice(strippedSourceStart))) return null;
|
|
182
|
+
if (firstBlock.content !== createWhitespaceMirror(source.slice(strippedSourceStart)) + LOCATION_BRIDGE_MARKER) return null;
|
|
179
183
|
return {
|
|
180
184
|
closeTagEnd,
|
|
181
185
|
encodedFilename
|
|
@@ -194,7 +198,7 @@ function encodedFilenameFromWorkaroundOpenTag(openTag) {
|
|
|
194
198
|
return openTag.slice(encodedFilenameStart, encodedFilenameEnd);
|
|
195
199
|
}
|
|
196
200
|
function createWorkaroundScript(source, filename) {
|
|
197
|
-
return `${SCRIPTLESS_WORKAROUND_OPEN_TAG_PREFIX}${encodeWorkaroundFilename(filename)}">${createWhitespaceMirror(source)}<\/script>\n`;
|
|
201
|
+
return `${SCRIPTLESS_WORKAROUND_OPEN_TAG_PREFIX}${encodeWorkaroundFilename(filename)}">${createWhitespaceMirror(source)}${LOCATION_BRIDGE_MARKER}<\/script>\n`;
|
|
198
202
|
}
|
|
199
203
|
function createWhitespaceMirror(source) {
|
|
200
204
|
return source.replaceAll(/[^\r\n]/gu, " ");
|
|
@@ -251,4 +255,4 @@ if (import.meta.vitest) {
|
|
|
251
255
|
});
|
|
252
256
|
}
|
|
253
257
|
//#endregion
|
|
254
|
-
export { isPatinaFile as a, compareLineColumn as c, getDiagnosticBlock as d, hasVueLikeExtension as i, extractSfcBlocks as l,
|
|
258
|
+
export { isPatinaFile as a, compareLineColumn as c, getDiagnosticBlock as d, hasVueLikeExtension as i, extractSfcBlocks as l, isLocationBridgeProgram as n, isScriptLikeFile as o, resolveWorkaroundSource as r, isStandaloneHtmlFile as s, appendScriptlessWorkaround as t, formatBlockLabel as u };
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"@tsdown/css": "0.22.14",
|
|
14
14
|
"@types/node": "25.9.2",
|
|
15
|
-
"@vizejs/native": "0.429.
|
|
15
|
+
"@vizejs/native": "0.429.2",
|
|
16
16
|
"tsdown": "0.22.14",
|
|
17
17
|
"typescript": "6.0.3",
|
|
18
18
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.1.24",
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
},
|
|
50
50
|
"name": "oxlint-plugin-vize",
|
|
51
51
|
"optionalDependencies": {
|
|
52
|
-
"@vizejs/native-darwin-arm64": "0.429.
|
|
53
|
-
"@vizejs/native-darwin-x64": "0.429.
|
|
54
|
-
"@vizejs/native-linux-arm64-gnu": "0.429.
|
|
55
|
-
"@vizejs/native-linux-arm64-musl": "0.429.
|
|
56
|
-
"@vizejs/native-linux-x64-gnu": "0.429.
|
|
57
|
-
"@vizejs/native-linux-x64-musl": "0.429.
|
|
58
|
-
"@vizejs/native-win32-arm64-msvc": "0.429.
|
|
59
|
-
"@vizejs/native-win32-x64-msvc": "0.429.
|
|
52
|
+
"@vizejs/native-darwin-arm64": "0.429.2",
|
|
53
|
+
"@vizejs/native-darwin-x64": "0.429.2",
|
|
54
|
+
"@vizejs/native-linux-arm64-gnu": "0.429.2",
|
|
55
|
+
"@vizejs/native-linux-arm64-musl": "0.429.2",
|
|
56
|
+
"@vizejs/native-linux-x64-gnu": "0.429.2",
|
|
57
|
+
"@vizejs/native-linux-x64-musl": "0.429.2",
|
|
58
|
+
"@vizejs/native-win32-arm64-msvc": "0.429.2",
|
|
59
|
+
"@vizejs/native-win32-x64-msvc": "0.429.2"
|
|
60
60
|
},
|
|
61
61
|
"publishConfig": {
|
|
62
62
|
"access": "public"
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
},
|
|
69
69
|
"type": "module",
|
|
70
70
|
"types": "./dist/index.d.mts",
|
|
71
|
-
"version": "0.429.
|
|
71
|
+
"version": "0.429.2",
|
|
72
72
|
"scripts": {
|
|
73
73
|
"build": "vp pack",
|
|
74
74
|
"check": "vp check src vite.config.ts",
|