oxlint-plugin-vize 0.441.0 → 0.442.0
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/dist/cli.mjs +425 -45
- package/dist/index.mjs +1 -94
- package/dist/{workaround-r91ttnV_.mjs → workaround-CiQUFJw0.mjs} +94 -1
- package/package.json +11 -11
package/dist/cli.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { n as prepareWorkaroundSource, p as isStandaloneHtmlFile, u as hasVueLikeExtension } from "./workaround-
|
|
1
|
+
import { m as loadBinding, n as prepareWorkaroundSource, p as isStandaloneHtmlFile, u as hasVueLikeExtension } from "./workaround-CiQUFJw0.mjs";
|
|
2
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs from "node:fs";
|
|
5
|
-
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
6
6
|
import os from "node:os";
|
|
7
|
-
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
8
8
|
//#region src/cli/args.ts
|
|
9
9
|
const OPTION_NAMES_WITH_VALUES = new Set([
|
|
10
10
|
"-A",
|
|
@@ -216,7 +216,7 @@ function verifyOxlintCliEntrypoint(executable, entrypoint) {
|
|
|
216
216
|
]
|
|
217
217
|
});
|
|
218
218
|
const output = `${handshake.stdout ?? ""}${handshake.stderr ?? ""}`.trim();
|
|
219
|
-
if (handshake.error == null && handshake.status === 0 && VERSION_HANDSHAKE_PATTERN.test(output)) return;
|
|
219
|
+
if (handshake.error == null && handshake.status === 0 && VERSION_HANDSHAKE_PATTERN.test(output)) return output.match(VERSION_HANDSHAKE_PATTERN)?.[0] ?? "";
|
|
220
220
|
const detail = handshake.error == null ? `exit ${String(handshake.status)}${output === "" ? " with no output" : `: ${output.split("\n", 1)[0]}`}` : handshake.error.message;
|
|
221
221
|
throw new Error(`The oxlint entrypoint at ${entrypoint} did not answer the \`--version\` handshake (${detail}). It appears to be a non-lint wrapper shim, so its runs cannot be trusted as lint results. Install the real \`oxlint\` package where \`oxlint-vize\` can resolve it.`);
|
|
222
222
|
}
|
|
@@ -801,10 +801,12 @@ function joinProjectJson(source, bridge, totals) {
|
|
|
801
801
|
//#endregion
|
|
802
802
|
//#region src/cli/project-output.ts
|
|
803
803
|
function unavailableProjectTransport(original, error) {
|
|
804
|
+
const suffix = `\nScript-safe Vue transport unavailable: ${error instanceof Error ? error.message : String(error)}\n`;
|
|
804
805
|
return {
|
|
805
806
|
...original,
|
|
807
|
+
rawStderr: Buffer.concat([original.rawStderr ?? Buffer.from(original.stderr), Buffer.from(suffix)]),
|
|
806
808
|
status: Math.max(original.status ?? 1, 1),
|
|
807
|
-
stderr: original.stderr +
|
|
809
|
+
stderr: original.stderr + suffix
|
|
808
810
|
};
|
|
809
811
|
}
|
|
810
812
|
function projectOutputFormat(args) {
|
|
@@ -859,6 +861,9 @@ function mergeProjectOutput(original, bridge, args) {
|
|
|
859
861
|
});
|
|
860
862
|
}
|
|
861
863
|
return {
|
|
864
|
+
rawStdout: format === "json" ? void 0 : Buffer.concat([original.rawStdout ?? Buffer.from(original.stdout), bridge.rawStdout ?? Buffer.from(bridge.stdout)]),
|
|
865
|
+
rawStderr: Buffer.concat([original.rawStderr ?? Buffer.from(original.stderr), bridge.rawStderr ?? Buffer.from(bridge.stderr)]),
|
|
866
|
+
phases: [original.observation, bridge.observation].filter((packet) => packet != null),
|
|
862
867
|
stdout,
|
|
863
868
|
stderr: original.stderr + bridge.stderr,
|
|
864
869
|
status: Math.max(original.status ?? 1, bridge.status ?? 1)
|
|
@@ -900,10 +905,12 @@ async function prepareScopedSelection(cwd, originalArgs, vueFiles, run, candidat
|
|
|
900
905
|
const original = await run(originalArgs);
|
|
901
906
|
if (vueFiles.some(isStandaloneHtmlFile)) return { result: unavailableProjectTransport(original, /* @__PURE__ */ new Error("Scoped Vue transport cannot combine standalone HTML and Vue targets.")) };
|
|
902
907
|
if (!vueFiles.some((file) => selected.includes(file))) return { result: original };
|
|
908
|
+
const suffix = "Script-safe Vue transport requires one regular JSON or TS/MTS object config; the original engine report is retained, but Vize transport is unqualified.\n";
|
|
903
909
|
return { result: {
|
|
904
910
|
...original,
|
|
905
911
|
status: Math.max(original.status ?? 1, 1),
|
|
906
|
-
stderr: original.stderr +
|
|
912
|
+
stderr: original.stderr + suffix,
|
|
913
|
+
rawStderr: Buffer.concat([original.rawStderr ?? Buffer.from(original.stderr), Buffer.from(suffix)])
|
|
907
914
|
} };
|
|
908
915
|
}
|
|
909
916
|
const options = withoutLintTargets(originalArgs);
|
|
@@ -1006,6 +1013,387 @@ function equalFiles(expected, actual) {
|
|
|
1006
1013
|
return expected.length === actual.length && expected.every((file, index) => file === actual[index]);
|
|
1007
1014
|
}
|
|
1008
1015
|
//#endregion
|
|
1016
|
+
//#region src/cli/html-custody.ts
|
|
1017
|
+
const read = (file) => {
|
|
1018
|
+
try {
|
|
1019
|
+
const stat = fs.lstatSync(file);
|
|
1020
|
+
if (!stat.isFile() || stat.isSymbolicLink()) throw new Error(`HTML custody requires a regular original: ${file}`);
|
|
1021
|
+
return fs.readFileSync(file);
|
|
1022
|
+
} catch (error) {
|
|
1023
|
+
if (error.code === "ENOENT") return null;
|
|
1024
|
+
throw error;
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
const digest$1 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
1028
|
+
const same = (left, right) => left == null ? right == null : right != null && left.equals(right);
|
|
1029
|
+
/** Snapshots prove identity, and do not perform native ignore selection. */
|
|
1030
|
+
function captureHtmlCustody(options, candidates) {
|
|
1031
|
+
const sources = new Map([[options.rootJson, Buffer.from(options.rootBytes)]]);
|
|
1032
|
+
const originals = /* @__PURE__ */ new Map();
|
|
1033
|
+
const directories = /* @__PURE__ */ new Set();
|
|
1034
|
+
for (const candidate of [options.cwd, ...candidates]) {
|
|
1035
|
+
const stat = fs.lstatSync(candidate);
|
|
1036
|
+
if (isStandaloneHtmlFile(candidate) && stat.isFile() && !stat.isSymbolicLink()) originals.set(candidate, fs.readFileSync(candidate));
|
|
1037
|
+
let directory = stat.isDirectory() ? candidate : path.dirname(candidate);
|
|
1038
|
+
for (;;) {
|
|
1039
|
+
directories.add(directory);
|
|
1040
|
+
const parent = path.dirname(directory);
|
|
1041
|
+
if (parent === directory) break;
|
|
1042
|
+
directory = parent;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
for (const directory of directories) {
|
|
1046
|
+
for (const name of [".gitignore", options.customIgnoreFilename]) {
|
|
1047
|
+
const file = path.join(directory, name);
|
|
1048
|
+
sources.set(file, read(file));
|
|
1049
|
+
}
|
|
1050
|
+
if (fs.existsSync(path.join(directory, ".git"))) {
|
|
1051
|
+
const file = path.join(directory, ".git/info/exclude");
|
|
1052
|
+
sources.set(file, read(file));
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
return {
|
|
1056
|
+
sources,
|
|
1057
|
+
originals
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
/** Keep full source/provider/ignore bytes bound before and after the one operation. */
|
|
1061
|
+
function assertHtmlCustody(context, completed) {
|
|
1062
|
+
if (!context.custody || !context.provider || !context.options) throw new Error("original HTML custody is unavailable");
|
|
1063
|
+
const { custody, provider, options } = context;
|
|
1064
|
+
if (digest$1(fs.readFileSync(provider.entrypoint)) !== provider.sha256 || !Buffer.from(provider.packageBytes).equals(fs.readFileSync(provider.package))) throw new Error("actual host provider changed during HTML execution");
|
|
1065
|
+
for (const [file, expected] of [...custody.sources, ...custody.originals]) if (!same(expected, read(file))) throw new Error(`original HTML input changed during real host execution: ${file}`);
|
|
1066
|
+
if (!completed) return;
|
|
1067
|
+
if (completed.hostProfile !== options.hostProfile || completed.cwd !== options.cwd || completed.literalTarget !== options.literalTarget || completed.rootJson !== options.rootJson || completed.format !== options.format || completed.engineConfigValidation !== "not-performed" || Object.keys(options.presentation).some((key) => completed.presentation[key] !== options.presentation[key])) throw new Error("complete HTML result lost original execution/presentation identity");
|
|
1068
|
+
for (const original of completed.originals) {
|
|
1069
|
+
const prior = custody.originals.get(original.path);
|
|
1070
|
+
if (!prior || !prior.equals(Buffer.from(original.bytes))) throw new Error(`native HTML original lacks pre-host custody: ${original.path}`);
|
|
1071
|
+
}
|
|
1072
|
+
for (const source of completed.sources) if (!custody.sources.has(source.path) || !same(custody.sources.get(source.path) ?? null, source.bytes == null ? null : Buffer.from(source.bytes))) throw new Error(`native HTML authority lacks pre-host custody: ${source.path}`);
|
|
1073
|
+
if (completed.executedFileCount !== completed.originals.length || completed.files.length !== completed.originals.length || !Number.isFinite(completed.elapsedSeconds) || completed.elapsedSeconds < 0) throw new Error("complete HTML execution counts are invalid");
|
|
1074
|
+
}
|
|
1075
|
+
//#endregion
|
|
1076
|
+
//#region src/cli/presentation-context.ts
|
|
1077
|
+
/** Actual piped-child inputs used by both pinned hosts' presentation selection. */
|
|
1078
|
+
const presentationInputs = [
|
|
1079
|
+
"CI",
|
|
1080
|
+
"FORCE_COLOR",
|
|
1081
|
+
"NO_COLOR",
|
|
1082
|
+
"GITHUB_ACTIONS",
|
|
1083
|
+
"AI_AGENT",
|
|
1084
|
+
"CURSOR_AGENT",
|
|
1085
|
+
"CLAUDECODE",
|
|
1086
|
+
"CLAUDE_CODE",
|
|
1087
|
+
"REPL_ID",
|
|
1088
|
+
"GEMINI_CLI",
|
|
1089
|
+
"CODEX_SANDBOX",
|
|
1090
|
+
"CODEX_THREAD_ID",
|
|
1091
|
+
"COPILOT_CLI",
|
|
1092
|
+
"OPENCODE",
|
|
1093
|
+
"JUNIE_DATA",
|
|
1094
|
+
"JUNIE_SHIM_PATH",
|
|
1095
|
+
"PATH",
|
|
1096
|
+
"EDITOR",
|
|
1097
|
+
"TERM_PROGRAM"
|
|
1098
|
+
];
|
|
1099
|
+
function presentationContext() {
|
|
1100
|
+
return Object.fromEntries(presentationInputs.map((key) => [key, process.env[key] ?? null]));
|
|
1101
|
+
}
|
|
1102
|
+
/** Pinned c42d639/2ae2939 agent_detection and default_output_format contracts. */
|
|
1103
|
+
function implicitDefault(context) {
|
|
1104
|
+
const agentKeys = presentationInputs.filter((key) => ![
|
|
1105
|
+
"CI",
|
|
1106
|
+
"FORCE_COLOR",
|
|
1107
|
+
"NO_COLOR",
|
|
1108
|
+
"GITHUB_ACTIONS",
|
|
1109
|
+
"PATH",
|
|
1110
|
+
"EDITOR",
|
|
1111
|
+
"TERM_PROGRAM"
|
|
1112
|
+
].includes(key));
|
|
1113
|
+
return context.GITHUB_ACTIONS !== "true" && !agentKeys.some((key) => Boolean(context[key])) && !/[.]pi[/\\]agent/u.test(context.PATH ?? "") && !(context.EDITOR ?? "").includes("devin") && !(context.TERM_PROGRAM ?? "").includes("kiro");
|
|
1114
|
+
}
|
|
1115
|
+
//#endregion
|
|
1116
|
+
//#region src/cli/html-operation.ts
|
|
1117
|
+
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
1118
|
+
/** Capture original root/provider/piped-child context without executing a provider query. */
|
|
1119
|
+
function prepareHtmlContext(cwd, args, entrypoint, version, candidates) {
|
|
1120
|
+
const context = { environment: presentationContext() };
|
|
1121
|
+
try {
|
|
1122
|
+
if (!["1.78.0", "1.86.0"].includes(version)) throw new Error("original HTML requires a qualified Oxlint 1.78.0 or 1.86.0 host");
|
|
1123
|
+
const targets = getLintTargets(args);
|
|
1124
|
+
if (targets.length !== 1) throw new Error("original HTML requires one literal original target");
|
|
1125
|
+
const config = readScopedConfig(cwd, args);
|
|
1126
|
+
if (!config || config.module || path.dirname(config.file) !== cwd) throw new Error("original HTML requires one regular JSON root in the original cwd");
|
|
1127
|
+
const plugin = fileURLToPath(new URL("./index.mjs", import.meta.url));
|
|
1128
|
+
const pluginRoot = import.meta.url.endsWith(".ts") ? fileURLToPath(new URL("../../dist/index.mjs", import.meta.url)) : plugin;
|
|
1129
|
+
const owned = fs.realpathSync(pluginRoot);
|
|
1130
|
+
if (!Array.isArray(config.value.jsPlugins) || !config.value.jsPlugins.some((specifier) => ownsPlugin(specifier, config.file, owned))) throw new Error("original HTML requires this wrapper's genuine Vize plugin in the original root");
|
|
1131
|
+
const actual = fs.realpathSync(entrypoint);
|
|
1132
|
+
const packageFile = path.join(path.dirname(actual), "../package.json");
|
|
1133
|
+
const packageBytes = fs.readFileSync(packageFile);
|
|
1134
|
+
const metadata = JSON.parse(packageBytes.toString("utf8"));
|
|
1135
|
+
if (metadata.name !== "oxlint" || metadata.version !== version) throw new Error("original HTML provider package does not match the real version handshake");
|
|
1136
|
+
context.provider = {
|
|
1137
|
+
requestedEntrypoint: entrypoint,
|
|
1138
|
+
entrypoint: actual,
|
|
1139
|
+
sha256: digest(fs.readFileSync(actual)),
|
|
1140
|
+
package: packageFile,
|
|
1141
|
+
packageBytes: Array.from(packageBytes),
|
|
1142
|
+
version
|
|
1143
|
+
};
|
|
1144
|
+
let format = "default";
|
|
1145
|
+
let explicitFormat = false;
|
|
1146
|
+
let noIgnore = false;
|
|
1147
|
+
const patterns = [];
|
|
1148
|
+
let customIgnoreFilename = ".eslintignore";
|
|
1149
|
+
const options = withoutLintTargets(args);
|
|
1150
|
+
for (let index = 0; index < options.length; index++) {
|
|
1151
|
+
const arg = options[index];
|
|
1152
|
+
if (arg === "--") break;
|
|
1153
|
+
if ([
|
|
1154
|
+
"-c",
|
|
1155
|
+
"--config",
|
|
1156
|
+
"--threads"
|
|
1157
|
+
].includes(arg)) {
|
|
1158
|
+
index++;
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
if (arg.startsWith("--config=") || arg.startsWith("--threads=")) continue;
|
|
1162
|
+
if (arg === "-f" || arg === "--format") {
|
|
1163
|
+
explicitFormat = true;
|
|
1164
|
+
format = options[++index];
|
|
1165
|
+
continue;
|
|
1166
|
+
}
|
|
1167
|
+
if (arg.startsWith("--format=")) {
|
|
1168
|
+
explicitFormat = true;
|
|
1169
|
+
format = arg.slice(9);
|
|
1170
|
+
continue;
|
|
1171
|
+
}
|
|
1172
|
+
if (arg === "--ignore-pattern") {
|
|
1173
|
+
patterns.push(options[++index]);
|
|
1174
|
+
continue;
|
|
1175
|
+
}
|
|
1176
|
+
if (arg.startsWith("--ignore-pattern=")) {
|
|
1177
|
+
patterns.push(arg.slice(17));
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
if (arg === "--ignore-path") {
|
|
1181
|
+
customIgnoreFilename = options[++index];
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
if (arg.startsWith("--ignore-path=")) {
|
|
1185
|
+
customIgnoreFilename = arg.slice(14);
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
if (arg === "--no-ignore") {
|
|
1189
|
+
noIgnore = true;
|
|
1190
|
+
continue;
|
|
1191
|
+
}
|
|
1192
|
+
if (arg === "--deny-warnings" || arg === "--no-error-on-unmatched-pattern" || arg === "--disable-nested-config" || arg === "--type-aware" || arg === "--type-check" || arg === "--import-plugin" || arg === "--vue-plugin") continue;
|
|
1193
|
+
if (arg === "--tsconfig") {
|
|
1194
|
+
index++;
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
if (arg.startsWith("--tsconfig=")) continue;
|
|
1198
|
+
throw new Error(`original HTML cannot preserve this option's presentation/write/severity contract: ${arg}`);
|
|
1199
|
+
}
|
|
1200
|
+
if (path.basename(customIgnoreFilename) !== customIgnoreFilename || [".", ".."].includes(customIgnoreFilename)) throw new Error("original HTML requires one custom-ignore filename");
|
|
1201
|
+
if (![
|
|
1202
|
+
"default",
|
|
1203
|
+
"json",
|
|
1204
|
+
"unix",
|
|
1205
|
+
"stylish"
|
|
1206
|
+
].includes(format)) throw new Error("original HTML requires an explicit default, json, unix or stylish report");
|
|
1207
|
+
if (!explicitFormat && !implicitDefault(context.environment)) throw new Error("original HTML requires an explicit supported format when the host selects agent/GitHub output");
|
|
1208
|
+
const forceColor = context.environment.CI != null || context.environment.FORCE_COLOR != null && context.environment.FORCE_COLOR !== "0";
|
|
1209
|
+
context.options = {
|
|
1210
|
+
cwd,
|
|
1211
|
+
literalTarget: targets[0],
|
|
1212
|
+
rootJson: config.file,
|
|
1213
|
+
rootBytes: Array.from(fs.readFileSync(config.file)),
|
|
1214
|
+
hostProfile: version,
|
|
1215
|
+
noIgnore,
|
|
1216
|
+
cliIgnorePatterns: patterns,
|
|
1217
|
+
customIgnoreFilename,
|
|
1218
|
+
format,
|
|
1219
|
+
presentation: {
|
|
1220
|
+
cwd,
|
|
1221
|
+
graphicalTheme: forceColor ? "color" : "plain",
|
|
1222
|
+
links: false,
|
|
1223
|
+
width: 400,
|
|
1224
|
+
stylishNoColor: context.environment.NO_COLOR != null,
|
|
1225
|
+
stylishRelative: true
|
|
1226
|
+
}
|
|
1227
|
+
};
|
|
1228
|
+
context.custody = captureHtmlCustody(context.options, candidates);
|
|
1229
|
+
} catch (error) {
|
|
1230
|
+
context.failure = error instanceof Error ? error.message : String(error);
|
|
1231
|
+
}
|
|
1232
|
+
return context;
|
|
1233
|
+
}
|
|
1234
|
+
/** One genuine native operation after normal stock/Vue setup, never a carrier. */
|
|
1235
|
+
function executeHtml(context) {
|
|
1236
|
+
if (context.failure || !context.options) throw new Error(context.failure ?? "original HTML context is unavailable");
|
|
1237
|
+
const binding = loadBinding();
|
|
1238
|
+
if (typeof binding.lintOxlintHtml !== "function") throw new Error("installed native binding does not expose original HTML execution");
|
|
1239
|
+
assertHtmlCustody(context);
|
|
1240
|
+
if (!Buffer.from(context.options.rootBytes).equals(fs.readFileSync(context.options.rootJson))) throw new Error("original root bytes changed during real host setup");
|
|
1241
|
+
const outcome = binding.lintOxlintHtml(context.options);
|
|
1242
|
+
context.outcome = outcome;
|
|
1243
|
+
if (Boolean(outcome.completed) === Boolean(outcome.refused)) throw new Error("original HTML operation did not return an exclusive complete/refused result");
|
|
1244
|
+
if (outcome.refused) throw new Error(`${outcome.refused.kind}: ${outcome.refused.details}`);
|
|
1245
|
+
assertHtmlCustody(context, outcome.completed);
|
|
1246
|
+
return outcome;
|
|
1247
|
+
}
|
|
1248
|
+
function ownsPlugin(specifier, configFile, owned) {
|
|
1249
|
+
if (typeof specifier !== "string") return false;
|
|
1250
|
+
try {
|
|
1251
|
+
if (specifier.startsWith("file:")) return fs.realpathSync(fileURLToPath(specifier)) === owned;
|
|
1252
|
+
if (path.isAbsolute(specifier) || specifier.startsWith("./") || specifier.startsWith("../")) return fs.realpathSync(path.resolve(path.dirname(configFile), specifier)) === owned;
|
|
1253
|
+
if (specifier.split("/").length !== (specifier.startsWith("@") ? 2 : 1)) return false;
|
|
1254
|
+
const ownedMetadata = fs.realpathSync(path.join(path.dirname(owned), "../package.json"));
|
|
1255
|
+
let directory = path.dirname(configFile);
|
|
1256
|
+
for (;;) {
|
|
1257
|
+
const candidate = path.join(directory, "node_modules", specifier, "package.json");
|
|
1258
|
+
if (fs.existsSync(candidate)) return fs.realpathSync(candidate) === ownedMetadata && fs.realpathSync(path.join(path.dirname(candidate), "dist/index.mjs")) === owned;
|
|
1259
|
+
const parent = path.dirname(directory);
|
|
1260
|
+
if (parent === directory) return false;
|
|
1261
|
+
directory = parent;
|
|
1262
|
+
}
|
|
1263
|
+
} catch {
|
|
1264
|
+
return false;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
//#endregion
|
|
1268
|
+
//#region src/cli/html-project-output.ts
|
|
1269
|
+
const noFiles = "No files found to lint. Please check your paths and ignore patterns.\n";
|
|
1270
|
+
const stylishFooter = new RegExp(String.raw`\n(?:\u001B\[(?:31|33)m)?✖ [1-9][0-9]* problems? \([0-9]+ errors?, [0-9]+ warnings?\)(?:\u001B\[0m)?\n$`, "u");
|
|
1271
|
+
function completeJson(text) {
|
|
1272
|
+
const report = JSON.parse(text);
|
|
1273
|
+
if (typeof report !== "object" || report == null || Array.isArray(report)) throw new Error("HTML join requires an actual complete host JSON object");
|
|
1274
|
+
const result = report;
|
|
1275
|
+
if (!Array.isArray(result.diagnostics) || ![
|
|
1276
|
+
"number_of_files",
|
|
1277
|
+
"number_of_rules",
|
|
1278
|
+
"threads_count",
|
|
1279
|
+
"start_time"
|
|
1280
|
+
].every((key) => typeof result[key] === "number" && Number.isFinite(result[key]) && result[key] >= 0)) throw new Error("HTML join requires genuine host file/rule/thread/time authority");
|
|
1281
|
+
return result;
|
|
1282
|
+
}
|
|
1283
|
+
/** Genuine child packets establish host setup; no additional provider query. */
|
|
1284
|
+
function qualifyHtmlHost(context, original) {
|
|
1285
|
+
if (context.failure || !context.options || !context.provider) throw new Error(context.failure ?? "original HTML host context is unavailable");
|
|
1286
|
+
const phases = original.phases ?? (original.observation ? [original.observation] : []);
|
|
1287
|
+
if (phases.length === 0) throw new Error("original HTML requires complete actual host observations");
|
|
1288
|
+
for (const phase of phases) {
|
|
1289
|
+
if (phase.signal || phase.error || ![0, 1].includes(phase.status ?? -1) || phase.cwd !== context.options.cwd || phase.args[0] !== context.provider.entrypoint && phase.args[0] !== context.provider.requestedEntrypoint) throw new Error("actual host phase failed before qualified HTML execution");
|
|
1290
|
+
if (Buffer.from(phase.stderrBytes).length !== 0 || Object.keys(context.environment).some((key) => phase.environment[key] !== context.environment[key])) throw new Error("actual host phase lost its original presentation/setup context");
|
|
1291
|
+
const rawOutput = Buffer.from(phase.stdoutBytes);
|
|
1292
|
+
const output = rawOutput.toString("utf8");
|
|
1293
|
+
if (!rawOutput.equals(Buffer.from(output))) throw new Error("actual host output is not lossless UTF8");
|
|
1294
|
+
if (output.startsWith(noFiles)) continue;
|
|
1295
|
+
const report = output;
|
|
1296
|
+
if (context.options.format === "json") completeJson(report);
|
|
1297
|
+
else if (context.options.format === "default" && !/Finished in [0-9]+(?:\.[0-9]+)?(?:ms|s) on [0-9]+ files? with [0-9]+ rules? using [0-9]+ threads?\.\n$/u.test(report)) throw new Error("actual default host report is incomplete");
|
|
1298
|
+
else if (context.options.format === "unix" && !(phase.status === 0 && report === "") && !/\n[1-9][0-9]* problems?\n$/u.test(report)) throw new Error("actual Unix host report is incomplete");
|
|
1299
|
+
else if (context.options.format === "stylish" && !(phase.status === 0 && report === "") && !stylishFooter.test(report)) throw new Error("actual Stylish host report is incomplete");
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
/** Recognize the pinned closed normal walker-empty packet, never a substring. */
|
|
1303
|
+
function eligibleEmptyHost(original, native, args) {
|
|
1304
|
+
if (native.rootDecision !== "Eligible" || original.stderr !== "" || original.observation?.signal || original.observation?.error || original.status !== (args.includes("--no-error-on-unmatched-pattern") ? 0 : 1) || !original.stdout.startsWith(noFiles)) return void 0;
|
|
1305
|
+
const rest = original.stdout.slice(69);
|
|
1306
|
+
if (native.format === "unix" || native.format === "stylish") return rest === "" ? rest : void 0;
|
|
1307
|
+
if (native.format === "default") return /^Finished in [0-9]+(?:\.[0-9]+)?(?:ms|s) on 0 files with [0-9]+ rules? using [0-9]+ threads?\.\n$/u.test(rest) ? rest : void 0;
|
|
1308
|
+
try {
|
|
1309
|
+
const report = completeJson(rest);
|
|
1310
|
+
if (report.diagnostics.length !== 0 || report.number_of_files !== 0 || Object.keys(report).length !== 5) return void 0;
|
|
1311
|
+
return joinProjectJson(rest, "{\"diagnostics\":[]}", {}) === rest ? rest : void 0;
|
|
1312
|
+
} catch {
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
function mergeHtmlOutput(original, native, args) {
|
|
1317
|
+
if (native.executedFileCount === 0) return original;
|
|
1318
|
+
if (original.observation?.signal || original.observation?.error || original.status == null) throw new Error("original host failed before a qualified HTML join");
|
|
1319
|
+
const empty = eligibleEmptyHost(original, native, args);
|
|
1320
|
+
if (original.stdout.startsWith(noFiles) && empty == null) throw new Error("original NoFilesFound packet is not the qualified normal walker-empty branch");
|
|
1321
|
+
let stdout = empty ?? original.stdout;
|
|
1322
|
+
if (native.format === "json") {
|
|
1323
|
+
const report = completeJson(stdout);
|
|
1324
|
+
const rows = JSON.parse(native.jsonDiagnostics);
|
|
1325
|
+
if (!Array.isArray(rows)) throw new Error("native HTML did not render complete diagnostic fragments");
|
|
1326
|
+
stdout = joinProjectJson(stdout, `{"diagnostics":${native.jsonDiagnostics}}`, {
|
|
1327
|
+
number_of_files: Number(report.number_of_files) + native.executedFileCount,
|
|
1328
|
+
start_time: Number(report.start_time) + native.elapsedSeconds
|
|
1329
|
+
});
|
|
1330
|
+
} else stdout += native.output;
|
|
1331
|
+
const nativeFailure = native.errors > 0 || (args.includes("--deny-warnings") || native.projection.denyWarnings) && native.warnings > 0;
|
|
1332
|
+
return {
|
|
1333
|
+
...original,
|
|
1334
|
+
stdout,
|
|
1335
|
+
rawStdout: void 0,
|
|
1336
|
+
status: Math.max(empty == null ? original.status : 0, nativeFailure ? 1 : 0)
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
function unavailableHtml(original, error) {
|
|
1340
|
+
const suffix = `\nOriginal HTML unavailable: ${error instanceof Error ? error.message : String(error)}\n`;
|
|
1341
|
+
return {
|
|
1342
|
+
...original,
|
|
1343
|
+
rawStderr: Buffer.concat([original.rawStderr ?? Buffer.from(original.stderr), Buffer.from(suffix)]),
|
|
1344
|
+
status: Math.max(original.status ?? 1, 1),
|
|
1345
|
+
stderr: original.stderr + suffix
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
//#endregion
|
|
1349
|
+
//#region src/cli/process.ts
|
|
1350
|
+
/** Retain the actual child packet, including buffered bytes on stream/spawn failure. */
|
|
1351
|
+
function runOxlint(executable, args, cwd) {
|
|
1352
|
+
return new Promise((resolve) => {
|
|
1353
|
+
const child = spawn(executable, args, {
|
|
1354
|
+
cwd,
|
|
1355
|
+
stdio: [
|
|
1356
|
+
"ignore",
|
|
1357
|
+
"pipe",
|
|
1358
|
+
"pipe"
|
|
1359
|
+
]
|
|
1360
|
+
});
|
|
1361
|
+
const stdout = [], stderr = [];
|
|
1362
|
+
let error = null;
|
|
1363
|
+
const failure = (reason) => {
|
|
1364
|
+
error ??= reason.message;
|
|
1365
|
+
};
|
|
1366
|
+
child.stdout.on("data", (chunk) => stdout.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk));
|
|
1367
|
+
child.stderr.on("data", (chunk) => stderr.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk));
|
|
1368
|
+
child.stdout.on("error", failure);
|
|
1369
|
+
child.stderr.on("error", failure);
|
|
1370
|
+
child.on("error", failure);
|
|
1371
|
+
child.on("close", (status, signal) => {
|
|
1372
|
+
const stdoutBytes = Buffer.concat(stdout), stderrBytes = Buffer.concat(stderr);
|
|
1373
|
+
const failureBytes = error ? Buffer.from(`\nOxlint child failure: ${error}\n`) : Buffer.alloc(0);
|
|
1374
|
+
const reportedStderr = Buffer.concat([stderrBytes, failureBytes]);
|
|
1375
|
+
resolve({
|
|
1376
|
+
status,
|
|
1377
|
+
stdout: stdoutBytes.toString("utf8"),
|
|
1378
|
+
rawStdout: stdoutBytes,
|
|
1379
|
+
rawStderr: reportedStderr,
|
|
1380
|
+
stderr: reportedStderr.toString("utf8"),
|
|
1381
|
+
observation: {
|
|
1382
|
+
executable,
|
|
1383
|
+
args: [...args],
|
|
1384
|
+
cwd,
|
|
1385
|
+
status,
|
|
1386
|
+
signal,
|
|
1387
|
+
error,
|
|
1388
|
+
stdoutBytes,
|
|
1389
|
+
stderrBytes,
|
|
1390
|
+
environment: presentationContext()
|
|
1391
|
+
}
|
|
1392
|
+
});
|
|
1393
|
+
});
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
//#endregion
|
|
1009
1397
|
//#region src/cli.ts
|
|
1010
1398
|
async function main() {
|
|
1011
1399
|
const cwd = process.cwd();
|
|
@@ -1014,11 +1402,20 @@ async function main() {
|
|
|
1014
1402
|
const candidates = /* @__PURE__ */ new Set();
|
|
1015
1403
|
const lintFiles = collectVueLikeFilesFromTargets(cwd, targets, (file) => candidates.add(file));
|
|
1016
1404
|
const oxlintEntrypoint = resolveOxlintCliEntrypoint(cwd);
|
|
1017
|
-
verifyOxlintCliEntrypoint(process.execPath, oxlintEntrypoint);
|
|
1018
|
-
const
|
|
1405
|
+
const version = verifyOxlintCliEntrypoint(process.execPath, oxlintEntrypoint);
|
|
1406
|
+
const html = lintFiles.some(isStandaloneHtmlFile) ? prepareHtmlContext(cwd, forwardedArgs, oxlintEntrypoint, version, candidates) : void 0;
|
|
1407
|
+
const vueFiles = html ? lintFiles.filter((file) => !isStandaloneHtmlFile(file)) : lintFiles;
|
|
1408
|
+
let scoped;
|
|
1409
|
+
try {
|
|
1410
|
+
scoped = await prepareScopedSelection(cwd, forwardedArgs, vueFiles, (args) => runOxlint(process.execPath, [oxlintEntrypoint, ...args], cwd), candidates);
|
|
1411
|
+
} catch (error) {
|
|
1412
|
+
if (!html) throw error;
|
|
1413
|
+
html.failure = error instanceof Error ? error.message : String(error);
|
|
1414
|
+
scoped = { result: await runOxlint(process.execPath, [oxlintEntrypoint, ...forwardedArgs], cwd) };
|
|
1415
|
+
}
|
|
1019
1416
|
const sourceResult = scoped && "result" in scoped ? scoped.result : void 0;
|
|
1020
1417
|
const transport = scoped && "prepared" in scoped ? scoped : void 0;
|
|
1021
|
-
const prepared = sourceResult ? prepareScriptlessWorkaroundFiles(cwd, []) : transport?.prepared ?? prepareScriptlessWorkaroundFiles(cwd,
|
|
1418
|
+
const prepared = sourceResult ? prepareScriptlessWorkaroundFiles(cwd, []) : transport?.prepared ?? prepareScriptlessWorkaroundFiles(cwd, vueFiles);
|
|
1022
1419
|
const args = [oxlintEntrypoint, ...transport?.args ?? [...forwardedArgs, ...prepared.appendedArgs]];
|
|
1023
1420
|
try {
|
|
1024
1421
|
let result;
|
|
@@ -1030,20 +1427,34 @@ async function main() {
|
|
|
1030
1427
|
merged = {
|
|
1031
1428
|
...result,
|
|
1032
1429
|
stdout: mappedStdout,
|
|
1033
|
-
stderr: mappedStderr
|
|
1430
|
+
stderr: mappedStderr,
|
|
1431
|
+
rawStdout: mappedStdout === result.stdout ? result.rawStdout : void 0,
|
|
1432
|
+
rawStderr: mappedStderr === result.stderr ? result.rawStderr : void 0
|
|
1034
1433
|
};
|
|
1035
1434
|
if (transport?.originalResult) merged = mergeProjectOutput(transport.originalResult, merged, forwardedArgs);
|
|
1435
|
+
if (html) try {
|
|
1436
|
+
qualifyHtmlHost(html, merged);
|
|
1437
|
+
const outcome = executeHtml(html);
|
|
1438
|
+
if (!outcome.completed) throw new Error("original HTML operation is incomplete");
|
|
1439
|
+
merged = mergeHtmlOutput(merged, outcome.completed, forwardedArgs);
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
merged = unavailableHtml(merged, error);
|
|
1442
|
+
}
|
|
1036
1443
|
} catch (error) {
|
|
1037
1444
|
if (transport?.originalResult) {
|
|
1038
1445
|
process.exitCode = Math.max(transport.originalResult.status ?? 1, result?.status ?? 1, 1);
|
|
1039
|
-
await writeStream(process.stdout, transport.originalResult.stdout);
|
|
1040
|
-
await writeStream(process.stderr,
|
|
1446
|
+
await writeStream(process.stdout, transport.originalResult.rawStdout ?? transport.originalResult.stdout);
|
|
1447
|
+
await writeStream(process.stderr, Buffer.concat([
|
|
1448
|
+
transport.originalResult.rawStderr ?? Buffer.from(transport.originalResult.stderr),
|
|
1449
|
+
result?.rawStderr ?? Buffer.from(result?.stderr ?? ""),
|
|
1450
|
+
result?.rawStdout ?? Buffer.from(result?.stdout ?? "")
|
|
1451
|
+
]));
|
|
1041
1452
|
}
|
|
1042
1453
|
throw error;
|
|
1043
1454
|
}
|
|
1044
1455
|
const { stdout, stderr } = merged;
|
|
1045
|
-
if (stdout) await writeStream(process.stdout, stdout);
|
|
1046
|
-
if (stderr) await writeStream(process.stderr, stderr);
|
|
1456
|
+
if (stdout) await writeStream(process.stdout, merged.rawStdout ?? stdout);
|
|
1457
|
+
if (stderr) await writeStream(process.stderr, merged.rawStderr ?? stderr);
|
|
1047
1458
|
if (merged.status === 0 && stdout === "" && stderr === "" && expectsLintReport(forwardedArgs)) {
|
|
1048
1459
|
await writeStream(process.stderr, `The oxlint run at ${oxlintEntrypoint} exited 0 but produced no report, although the requested format always emits one. Refusing to treat the silent run as a clean lint result.
|
|
1049
1460
|
`);
|
|
@@ -1060,37 +1471,6 @@ main().catch((error) => {
|
|
|
1060
1471
|
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
1061
1472
|
process.exitCode = Math.max(Number(process.exitCode) || 1, 1);
|
|
1062
1473
|
});
|
|
1063
|
-
function runOxlint(executable, args, cwd) {
|
|
1064
|
-
return new Promise((resolve, reject) => {
|
|
1065
|
-
const child = spawn(executable, args, {
|
|
1066
|
-
cwd,
|
|
1067
|
-
stdio: [
|
|
1068
|
-
"ignore",
|
|
1069
|
-
"pipe",
|
|
1070
|
-
"pipe"
|
|
1071
|
-
]
|
|
1072
|
-
});
|
|
1073
|
-
const stdoutChunks = [];
|
|
1074
|
-
const stderrChunks = [];
|
|
1075
|
-
child.stdout.on("data", (chunk) => {
|
|
1076
|
-
stdoutChunks.push(asBuffer(chunk));
|
|
1077
|
-
});
|
|
1078
|
-
child.stderr.on("data", (chunk) => {
|
|
1079
|
-
stderrChunks.push(asBuffer(chunk));
|
|
1080
|
-
});
|
|
1081
|
-
child.on("error", reject);
|
|
1082
|
-
child.on("close", (status) => {
|
|
1083
|
-
resolve({
|
|
1084
|
-
status,
|
|
1085
|
-
stderr: Buffer.concat(stderrChunks).toString("utf8"),
|
|
1086
|
-
stdout: Buffer.concat(stdoutChunks).toString("utf8")
|
|
1087
|
-
});
|
|
1088
|
-
});
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
1091
|
-
function asBuffer(chunk) {
|
|
1092
|
-
return typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
1093
|
-
}
|
|
1094
1474
|
function writeStream(stream, text) {
|
|
1095
1475
|
return new Promise((resolve, reject) => {
|
|
1096
1476
|
stream.write(text, (error) => {
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { a as validateWorkaroundAuthority, c as formatBlockLabel, d as isPatinaFile, f as isScriptLikeFile, i as resolveWorkaroundSource, l as getDiagnosticBlock, o as compareLineColumn, r as readOriginalWorkaroundSource, s as extractSfcBlocks, t as isLocationBridgeProgram } from "./workaround-
|
|
2
|
-
import { createRequire } from "node:module";
|
|
1
|
+
import { a as validateWorkaroundAuthority, c as formatBlockLabel, d as isPatinaFile, f as isScriptLikeFile, i as resolveWorkaroundSource, l as getDiagnosticBlock, m as loadBinding, o as compareLineColumn, r as readOriginalWorkaroundSource, s as extractSfcBlocks, t as isLocationBridgeProgram } from "./workaround-CiQUFJw0.mjs";
|
|
3
2
|
import { definePlugin, defineRule } from "@oxlint/plugins";
|
|
4
|
-
import { spawnSync } from "node:child_process";
|
|
5
|
-
import path from "node:path";
|
|
6
3
|
import fs from "node:fs";
|
|
7
4
|
//#region src/plugin-option-guards.ts
|
|
8
5
|
function optionField(value) {
|
|
@@ -81,96 +78,6 @@ function isHyphenationStyle(value) {
|
|
|
81
78
|
return value === "always" || value === "never";
|
|
82
79
|
}
|
|
83
80
|
//#endregion
|
|
84
|
-
//#region src/native.ts
|
|
85
|
-
const require = createRequire(import.meta.url);
|
|
86
|
-
const FALLBACK_BINDING_PACKAGE = "@vizejs/native";
|
|
87
|
-
let bindingCache = null;
|
|
88
|
-
function isMusl() {
|
|
89
|
-
const report = process.report?.getReport();
|
|
90
|
-
if (typeof report === "object" && report !== null && "header" in report) return !report.header.glibcVersionRuntime;
|
|
91
|
-
const result = spawnSync("ldd", ["--version"], {
|
|
92
|
-
encoding: "utf8",
|
|
93
|
-
stdio: [
|
|
94
|
-
"ignore",
|
|
95
|
-
"pipe",
|
|
96
|
-
"pipe"
|
|
97
|
-
]
|
|
98
|
-
});
|
|
99
|
-
if (result.error) return true;
|
|
100
|
-
return `${result.stdout ?? ""}\n${result.stderr ?? ""}`.includes("musl");
|
|
101
|
-
}
|
|
102
|
-
function getBindingPackageName() {
|
|
103
|
-
const { arch, platform } = process;
|
|
104
|
-
switch (platform) {
|
|
105
|
-
case "darwin": switch (arch) {
|
|
106
|
-
case "arm64": return "@vizejs/native-darwin-arm64";
|
|
107
|
-
case "x64": return "@vizejs/native-darwin-x64";
|
|
108
|
-
default: throw new Error(`Unsupported architecture on macOS: ${arch}`);
|
|
109
|
-
}
|
|
110
|
-
case "linux": switch (arch) {
|
|
111
|
-
case "arm64": return isMusl() ? "@vizejs/native-linux-arm64-musl" : "@vizejs/native-linux-arm64-gnu";
|
|
112
|
-
case "x64": return isMusl() ? "@vizejs/native-linux-x64-musl" : "@vizejs/native-linux-x64-gnu";
|
|
113
|
-
default: throw new Error(`Unsupported architecture on Linux: ${arch}`);
|
|
114
|
-
}
|
|
115
|
-
case "win32": switch (arch) {
|
|
116
|
-
case "arm64": return "@vizejs/native-win32-arm64-msvc";
|
|
117
|
-
case "x64": return "@vizejs/native-win32-x64-msvc";
|
|
118
|
-
default: throw new Error(`Unsupported architecture on Windows: ${arch}`);
|
|
119
|
-
}
|
|
120
|
-
default: throw new Error(`Unsupported OS: ${platform}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
function isPatinaBinding(binding) {
|
|
124
|
-
return typeof binding.lintPatinaSfc === "function" && typeof binding.getPatinaRules === "function";
|
|
125
|
-
}
|
|
126
|
-
function loadBinding() {
|
|
127
|
-
if (bindingCache) return bindingCache;
|
|
128
|
-
const attemptedPackages = getAttemptedPackages();
|
|
129
|
-
let lastError = null;
|
|
130
|
-
for (const packageName of attemptedPackages) try {
|
|
131
|
-
const binding = require(packageName);
|
|
132
|
-
if (!isPatinaBinding(binding)) throw new Error(`${packageName} does not expose the Patina Oxlint bridge.`);
|
|
133
|
-
bindingCache = binding;
|
|
134
|
-
return bindingCache;
|
|
135
|
-
} catch (error) {
|
|
136
|
-
lastError = error;
|
|
137
|
-
}
|
|
138
|
-
const message = lastError instanceof Error && lastError.message ? ` ${lastError.message}` : "";
|
|
139
|
-
throw new Error(`Failed to load the Vize native binding. Tried ${attemptedPackages.join(", ")}.${message}`);
|
|
140
|
-
}
|
|
141
|
-
function getAttemptedPackages() {
|
|
142
|
-
const platformBindingPackage = getBindingPackageName();
|
|
143
|
-
return shouldPreferWorkspaceBinding(resolveFallbackBindingPath()) ? [FALLBACK_BINDING_PACKAGE, platformBindingPackage] : [platformBindingPackage, FALLBACK_BINDING_PACKAGE];
|
|
144
|
-
}
|
|
145
|
-
function resolveFallbackBindingPath() {
|
|
146
|
-
try {
|
|
147
|
-
return require.resolve(FALLBACK_BINDING_PACKAGE);
|
|
148
|
-
} catch {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
function shouldPreferWorkspaceBinding(resolvedPath) {
|
|
153
|
-
const override = process.env.VIZE_PREFER_WORKSPACE_BINDING;
|
|
154
|
-
if (override === "1" || override === "true") return true;
|
|
155
|
-
if (override === "0" || override === "false") return false;
|
|
156
|
-
if (resolvedPath == null) return false;
|
|
157
|
-
return resolvedPath.includes(`${path.sep}npm${path.sep}native${path.sep}`);
|
|
158
|
-
}
|
|
159
|
-
if (import.meta.vitest) {
|
|
160
|
-
const { describe, expect, it } = import.meta.vitest;
|
|
161
|
-
describe("shouldPreferWorkspaceBinding", () => {
|
|
162
|
-
it("detects the local workspace native package", () => {
|
|
163
|
-
expect(shouldPreferWorkspaceBinding(`${path.sep}Users${path.sep}example${path.sep}repo${path.sep}npm${path.sep}native${path.sep}index.js`)).toBe(true);
|
|
164
|
-
});
|
|
165
|
-
it("ignores published platform packages", () => {
|
|
166
|
-
expect(shouldPreferWorkspaceBinding(`${path.sep}repo${path.sep}node_modules${path.sep}.pnpm${path.sep}@vizejs+native-darwin-arm64${path.sep}node_modules${path.sep}@vizejs${path.sep}native-darwin-arm64${path.sep}index.js`)).toBe(false);
|
|
167
|
-
});
|
|
168
|
-
it("returns false when the fallback package cannot be resolved", () => {
|
|
169
|
-
expect(shouldPreferWorkspaceBinding(null)).toBe(false);
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
//#endregion
|
|
174
81
|
//#region src/rule-selection.ts
|
|
175
82
|
const selectionCache = /* @__PURE__ */ new WeakMap();
|
|
176
83
|
/** A selection is a batching hint, never a second reporting/severity gate. */
|
|
@@ -1,6 +1,99 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import path from "node:path";
|
|
1
4
|
import fs from "node:fs";
|
|
2
5
|
import { createHash } from "node:crypto";
|
|
3
6
|
import { isUtf8 } from "node:buffer";
|
|
7
|
+
//#region src/native.ts
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const FALLBACK_BINDING_PACKAGE = "@vizejs/native";
|
|
10
|
+
let bindingCache = null;
|
|
11
|
+
function isMusl() {
|
|
12
|
+
const report = process.report?.getReport();
|
|
13
|
+
if (typeof report === "object" && report !== null && "header" in report) return !report.header.glibcVersionRuntime;
|
|
14
|
+
const result = spawnSync("ldd", ["--version"], {
|
|
15
|
+
encoding: "utf8",
|
|
16
|
+
stdio: [
|
|
17
|
+
"ignore",
|
|
18
|
+
"pipe",
|
|
19
|
+
"pipe"
|
|
20
|
+
]
|
|
21
|
+
});
|
|
22
|
+
if (result.error) return true;
|
|
23
|
+
return `${result.stdout ?? ""}\n${result.stderr ?? ""}`.includes("musl");
|
|
24
|
+
}
|
|
25
|
+
function getBindingPackageName() {
|
|
26
|
+
const { arch, platform } = process;
|
|
27
|
+
switch (platform) {
|
|
28
|
+
case "darwin": switch (arch) {
|
|
29
|
+
case "arm64": return "@vizejs/native-darwin-arm64";
|
|
30
|
+
case "x64": return "@vizejs/native-darwin-x64";
|
|
31
|
+
default: throw new Error(`Unsupported architecture on macOS: ${arch}`);
|
|
32
|
+
}
|
|
33
|
+
case "linux": switch (arch) {
|
|
34
|
+
case "arm64": return isMusl() ? "@vizejs/native-linux-arm64-musl" : "@vizejs/native-linux-arm64-gnu";
|
|
35
|
+
case "x64": return isMusl() ? "@vizejs/native-linux-x64-musl" : "@vizejs/native-linux-x64-gnu";
|
|
36
|
+
default: throw new Error(`Unsupported architecture on Linux: ${arch}`);
|
|
37
|
+
}
|
|
38
|
+
case "win32": switch (arch) {
|
|
39
|
+
case "arm64": return "@vizejs/native-win32-arm64-msvc";
|
|
40
|
+
case "x64": return "@vizejs/native-win32-x64-msvc";
|
|
41
|
+
default: throw new Error(`Unsupported architecture on Windows: ${arch}`);
|
|
42
|
+
}
|
|
43
|
+
default: throw new Error(`Unsupported OS: ${platform}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function isPatinaBinding(binding) {
|
|
47
|
+
return typeof binding.lintPatinaSfc === "function" && typeof binding.getPatinaRules === "function";
|
|
48
|
+
}
|
|
49
|
+
function loadBinding() {
|
|
50
|
+
if (bindingCache) return bindingCache;
|
|
51
|
+
const attemptedPackages = getAttemptedPackages();
|
|
52
|
+
let lastError = null;
|
|
53
|
+
for (const packageName of attemptedPackages) try {
|
|
54
|
+
const binding = require(packageName);
|
|
55
|
+
if (!isPatinaBinding(binding)) throw new Error(`${packageName} does not expose the Patina Oxlint bridge.`);
|
|
56
|
+
bindingCache = binding;
|
|
57
|
+
return bindingCache;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
lastError = error;
|
|
60
|
+
}
|
|
61
|
+
const message = lastError instanceof Error && lastError.message ? ` ${lastError.message}` : "";
|
|
62
|
+
throw new Error(`Failed to load the Vize native binding. Tried ${attemptedPackages.join(", ")}.${message}`);
|
|
63
|
+
}
|
|
64
|
+
function getAttemptedPackages() {
|
|
65
|
+
const platformBindingPackage = getBindingPackageName();
|
|
66
|
+
return shouldPreferWorkspaceBinding(resolveFallbackBindingPath()) ? [FALLBACK_BINDING_PACKAGE, platformBindingPackage] : [platformBindingPackage, FALLBACK_BINDING_PACKAGE];
|
|
67
|
+
}
|
|
68
|
+
function resolveFallbackBindingPath() {
|
|
69
|
+
try {
|
|
70
|
+
return require.resolve(FALLBACK_BINDING_PACKAGE);
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function shouldPreferWorkspaceBinding(resolvedPath) {
|
|
76
|
+
const override = process.env.VIZE_PREFER_WORKSPACE_BINDING;
|
|
77
|
+
if (override === "1" || override === "true") return true;
|
|
78
|
+
if (override === "0" || override === "false") return false;
|
|
79
|
+
if (resolvedPath == null) return false;
|
|
80
|
+
return resolvedPath.includes(`${path.sep}npm${path.sep}native${path.sep}`);
|
|
81
|
+
}
|
|
82
|
+
if (import.meta.vitest) {
|
|
83
|
+
const { describe, expect, it } = import.meta.vitest;
|
|
84
|
+
describe("shouldPreferWorkspaceBinding", () => {
|
|
85
|
+
it("detects the local workspace native package", () => {
|
|
86
|
+
expect(shouldPreferWorkspaceBinding(`${path.sep}Users${path.sep}example${path.sep}repo${path.sep}npm${path.sep}native${path.sep}index.js`)).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
it("ignores published platform packages", () => {
|
|
89
|
+
expect(shouldPreferWorkspaceBinding(`${path.sep}repo${path.sep}node_modules${path.sep}.pnpm${path.sep}@vizejs+native-darwin-arm64${path.sep}node_modules${path.sep}@vizejs${path.sep}native-darwin-arm64${path.sep}index.js`)).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
it("returns false when the fallback package cannot be resolved", () => {
|
|
92
|
+
expect(shouldPreferWorkspaceBinding(null)).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
4
97
|
//#region src/file-kinds.ts
|
|
5
98
|
function isVueLikeFile(filename) {
|
|
6
99
|
return hasVueLikeExtension(filename);
|
|
@@ -291,4 +384,4 @@ if (import.meta.vitest) {
|
|
|
291
384
|
});
|
|
292
385
|
}
|
|
293
386
|
//#endregion
|
|
294
|
-
export { validateWorkaroundAuthority as a, formatBlockLabel as c, isPatinaFile as d, isScriptLikeFile as f, resolveWorkaroundSource as i, getDiagnosticBlock as l, prepareWorkaroundSource as n, compareLineColumn as o, isStandaloneHtmlFile as p, readOriginalWorkaroundSource as r, extractSfcBlocks as s, isLocationBridgeProgram as t, hasVueLikeExtension as u };
|
|
387
|
+
export { validateWorkaroundAuthority as a, formatBlockLabel as c, isPatinaFile as d, isScriptLikeFile as f, resolveWorkaroundSource as i, getDiagnosticBlock as l, loadBinding as m, prepareWorkaroundSource as n, compareLineColumn as o, isStandaloneHtmlFile as p, readOriginalWorkaroundSource as r, extractSfcBlocks as s, isLocationBridgeProgram as t, hasVueLikeExtension 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.
|
|
15
|
+
"@vizejs/native": "0.442.0",
|
|
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.
|
|
53
|
-
"@vizejs/native-darwin-x64": "0.
|
|
54
|
-
"@vizejs/native-linux-arm64-gnu": "0.
|
|
55
|
-
"@vizejs/native-linux-arm64-musl": "0.
|
|
56
|
-
"@vizejs/native-linux-x64-gnu": "0.
|
|
57
|
-
"@vizejs/native-linux-x64-musl": "0.
|
|
58
|
-
"@vizejs/native-win32-arm64-msvc": "0.
|
|
59
|
-
"@vizejs/native-win32-x64-msvc": "0.
|
|
52
|
+
"@vizejs/native-darwin-arm64": "0.442.0",
|
|
53
|
+
"@vizejs/native-darwin-x64": "0.442.0",
|
|
54
|
+
"@vizejs/native-linux-arm64-gnu": "0.442.0",
|
|
55
|
+
"@vizejs/native-linux-arm64-musl": "0.442.0",
|
|
56
|
+
"@vizejs/native-linux-x64-gnu": "0.442.0",
|
|
57
|
+
"@vizejs/native-linux-x64-musl": "0.442.0",
|
|
58
|
+
"@vizejs/native-win32-arm64-msvc": "0.442.0",
|
|
59
|
+
"@vizejs/native-win32-x64-msvc": "0.442.0"
|
|
60
60
|
},
|
|
61
61
|
"publishConfig": {
|
|
62
62
|
"access": "public"
|
|
@@ -68,12 +68,12 @@
|
|
|
68
68
|
},
|
|
69
69
|
"type": "module",
|
|
70
70
|
"types": "./dist/index.d.mts",
|
|
71
|
-
"version": "0.
|
|
71
|
+
"version": "0.442.0",
|
|
72
72
|
"scripts": {
|
|
73
73
|
"build": "vp pack",
|
|
74
74
|
"check": "vp check src vite.config.ts",
|
|
75
75
|
"check:fix": "vp check --fix src vite.config.ts",
|
|
76
76
|
"fmt": "vp fmt --write src vite.config.ts",
|
|
77
|
-
"test": "vp pack && vp test run src/file-state.test.ts src/batched-rules.test.ts src/script-safe-source.test.ts src/active-rule-collection.test.ts && node src/test.ts && node src/script-location.test.ts && node src/casing-options.test.ts && node src/template-style-fixes.test.mjs"
|
|
77
|
+
"test": "vp pack && vp test run src/file-state.test.ts src/batched-rules.test.ts src/script-safe-source.test.ts src/active-rule-collection.test.ts && node src/test.ts && node src/script-location.test.ts && node src/casing-options.test.ts && node src/template-style-fixes.test.mjs && node src/html-binding.test.mjs"
|
|
78
78
|
}
|
|
79
79
|
}
|