oxlint-plugin-vize 0.441.0 → 0.443.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 CHANGED
@@ -1,10 +1,10 @@
1
- import { n as prepareWorkaroundSource, p as isStandaloneHtmlFile, u as hasVueLikeExtension } from "./workaround-r91ttnV_.mjs";
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 + `\nScript-safe Vue transport unavailable: ${error instanceof Error ? error.message : String(error)}\n`
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 + "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"
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,391 @@ 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 (![
1123
+ "1.78.0",
1124
+ "1.81.0",
1125
+ "1.86.0"
1126
+ ].includes(version)) throw new Error("original HTML requires a qualified Oxlint 1.78.0, 1.81.0 or 1.86.0 host");
1127
+ const targets = getLintTargets(args);
1128
+ if (targets.length !== 1) throw new Error("original HTML requires one literal original target");
1129
+ const config = readScopedConfig(cwd, args);
1130
+ if (!config || config.module || path.dirname(config.file) !== cwd) throw new Error("original HTML requires one regular JSON root in the original cwd");
1131
+ const plugin = fileURLToPath(new URL("./index.mjs", import.meta.url));
1132
+ const pluginRoot = import.meta.url.endsWith(".ts") ? fileURLToPath(new URL("../../dist/index.mjs", import.meta.url)) : plugin;
1133
+ const owned = fs.realpathSync(pluginRoot);
1134
+ 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");
1135
+ const actual = fs.realpathSync(entrypoint);
1136
+ const packageFile = path.join(path.dirname(actual), "../package.json");
1137
+ const packageBytes = fs.readFileSync(packageFile);
1138
+ const metadata = JSON.parse(packageBytes.toString("utf8"));
1139
+ if (metadata.name !== "oxlint" || metadata.version !== version) throw new Error("original HTML provider package does not match the real version handshake");
1140
+ context.provider = {
1141
+ requestedEntrypoint: entrypoint,
1142
+ entrypoint: actual,
1143
+ sha256: digest(fs.readFileSync(actual)),
1144
+ package: packageFile,
1145
+ packageBytes: Array.from(packageBytes),
1146
+ version
1147
+ };
1148
+ let format = "default";
1149
+ let explicitFormat = false;
1150
+ let noIgnore = false;
1151
+ const patterns = [];
1152
+ let customIgnoreFilename = ".eslintignore";
1153
+ const options = withoutLintTargets(args);
1154
+ for (let index = 0; index < options.length; index++) {
1155
+ const arg = options[index];
1156
+ if (arg === "--") break;
1157
+ if ([
1158
+ "-c",
1159
+ "--config",
1160
+ "--threads"
1161
+ ].includes(arg)) {
1162
+ index++;
1163
+ continue;
1164
+ }
1165
+ if (arg.startsWith("--config=") || arg.startsWith("--threads=")) continue;
1166
+ if (arg === "-f" || arg === "--format") {
1167
+ explicitFormat = true;
1168
+ format = options[++index];
1169
+ continue;
1170
+ }
1171
+ if (arg.startsWith("--format=")) {
1172
+ explicitFormat = true;
1173
+ format = arg.slice(9);
1174
+ continue;
1175
+ }
1176
+ if (arg === "--ignore-pattern") {
1177
+ patterns.push(options[++index]);
1178
+ continue;
1179
+ }
1180
+ if (arg.startsWith("--ignore-pattern=")) {
1181
+ patterns.push(arg.slice(17));
1182
+ continue;
1183
+ }
1184
+ if (arg === "--ignore-path") {
1185
+ customIgnoreFilename = options[++index];
1186
+ continue;
1187
+ }
1188
+ if (arg.startsWith("--ignore-path=")) {
1189
+ customIgnoreFilename = arg.slice(14);
1190
+ continue;
1191
+ }
1192
+ if (arg === "--no-ignore") {
1193
+ noIgnore = true;
1194
+ continue;
1195
+ }
1196
+ 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;
1197
+ if (arg === "--tsconfig") {
1198
+ index++;
1199
+ continue;
1200
+ }
1201
+ if (arg.startsWith("--tsconfig=")) continue;
1202
+ throw new Error(`original HTML cannot preserve this option's presentation/write/severity contract: ${arg}`);
1203
+ }
1204
+ if (path.basename(customIgnoreFilename) !== customIgnoreFilename || [".", ".."].includes(customIgnoreFilename)) throw new Error("original HTML requires one custom-ignore filename");
1205
+ if (![
1206
+ "default",
1207
+ "json",
1208
+ "unix",
1209
+ "stylish"
1210
+ ].includes(format)) throw new Error("original HTML requires an explicit default, json, unix or stylish report");
1211
+ if (!explicitFormat && !implicitDefault(context.environment)) throw new Error("original HTML requires an explicit supported format when the host selects agent/GitHub output");
1212
+ const forceColor = context.environment.CI != null || context.environment.FORCE_COLOR != null && context.environment.FORCE_COLOR !== "0";
1213
+ context.options = {
1214
+ cwd,
1215
+ literalTarget: targets[0],
1216
+ rootJson: config.file,
1217
+ rootBytes: Array.from(fs.readFileSync(config.file)),
1218
+ hostProfile: version,
1219
+ noIgnore,
1220
+ cliIgnorePatterns: patterns,
1221
+ customIgnoreFilename,
1222
+ format,
1223
+ presentation: {
1224
+ cwd,
1225
+ graphicalTheme: forceColor ? "color" : "plain",
1226
+ links: false,
1227
+ width: 400,
1228
+ stylishNoColor: context.environment.NO_COLOR != null,
1229
+ stylishRelative: true
1230
+ }
1231
+ };
1232
+ context.custody = captureHtmlCustody(context.options, candidates);
1233
+ } catch (error) {
1234
+ context.failure = error instanceof Error ? error.message : String(error);
1235
+ }
1236
+ return context;
1237
+ }
1238
+ /** One genuine native operation after normal stock/Vue setup, never a carrier. */
1239
+ function executeHtml(context) {
1240
+ if (context.failure || !context.options) throw new Error(context.failure ?? "original HTML context is unavailable");
1241
+ const binding = loadBinding();
1242
+ if (typeof binding.lintOxlintHtml !== "function") throw new Error("installed native binding does not expose original HTML execution");
1243
+ assertHtmlCustody(context);
1244
+ if (!Buffer.from(context.options.rootBytes).equals(fs.readFileSync(context.options.rootJson))) throw new Error("original root bytes changed during real host setup");
1245
+ const outcome = binding.lintOxlintHtml(context.options);
1246
+ context.outcome = outcome;
1247
+ if (Boolean(outcome.completed) === Boolean(outcome.refused)) throw new Error("original HTML operation did not return an exclusive complete/refused result");
1248
+ if (outcome.refused) throw new Error(`${outcome.refused.kind}: ${outcome.refused.details}`);
1249
+ assertHtmlCustody(context, outcome.completed);
1250
+ return outcome;
1251
+ }
1252
+ function ownsPlugin(specifier, configFile, owned) {
1253
+ if (typeof specifier !== "string") return false;
1254
+ try {
1255
+ if (specifier.startsWith("file:")) return fs.realpathSync(fileURLToPath(specifier)) === owned;
1256
+ if (path.isAbsolute(specifier) || specifier.startsWith("./") || specifier.startsWith("../")) return fs.realpathSync(path.resolve(path.dirname(configFile), specifier)) === owned;
1257
+ if (specifier.split("/").length !== (specifier.startsWith("@") ? 2 : 1)) return false;
1258
+ const ownedMetadata = fs.realpathSync(path.join(path.dirname(owned), "../package.json"));
1259
+ let directory = path.dirname(configFile);
1260
+ for (;;) {
1261
+ const candidate = path.join(directory, "node_modules", specifier, "package.json");
1262
+ if (fs.existsSync(candidate)) return fs.realpathSync(candidate) === ownedMetadata && fs.realpathSync(path.join(path.dirname(candidate), "dist/index.mjs")) === owned;
1263
+ const parent = path.dirname(directory);
1264
+ if (parent === directory) return false;
1265
+ directory = parent;
1266
+ }
1267
+ } catch {
1268
+ return false;
1269
+ }
1270
+ }
1271
+ //#endregion
1272
+ //#region src/cli/html-project-output.ts
1273
+ const noFiles = "No files found to lint. Please check your paths and ignore patterns.\n";
1274
+ 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");
1275
+ function completeJson(text) {
1276
+ const report = JSON.parse(text);
1277
+ if (typeof report !== "object" || report == null || Array.isArray(report)) throw new Error("HTML join requires an actual complete host JSON object");
1278
+ const result = report;
1279
+ if (!Array.isArray(result.diagnostics) || ![
1280
+ "number_of_files",
1281
+ "number_of_rules",
1282
+ "threads_count",
1283
+ "start_time"
1284
+ ].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");
1285
+ return result;
1286
+ }
1287
+ /** Genuine child packets establish host setup; no additional provider query. */
1288
+ function qualifyHtmlHost(context, original) {
1289
+ if (context.failure || !context.options || !context.provider) throw new Error(context.failure ?? "original HTML host context is unavailable");
1290
+ const phases = original.phases ?? (original.observation ? [original.observation] : []);
1291
+ if (phases.length === 0) throw new Error("original HTML requires complete actual host observations");
1292
+ for (const phase of phases) {
1293
+ 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");
1294
+ 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");
1295
+ const rawOutput = Buffer.from(phase.stdoutBytes);
1296
+ const output = rawOutput.toString("utf8");
1297
+ if (!rawOutput.equals(Buffer.from(output))) throw new Error("actual host output is not lossless UTF8");
1298
+ if (output.startsWith(noFiles)) continue;
1299
+ const report = output;
1300
+ if (context.options.format === "json") completeJson(report);
1301
+ 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");
1302
+ 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");
1303
+ else if (context.options.format === "stylish" && !(phase.status === 0 && report === "") && !stylishFooter.test(report)) throw new Error("actual Stylish host report is incomplete");
1304
+ }
1305
+ }
1306
+ /** Recognize the pinned closed normal walker-empty packet, never a substring. */
1307
+ function eligibleEmptyHost(original, native, args) {
1308
+ 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;
1309
+ const rest = original.stdout.slice(69);
1310
+ if (native.format === "unix" || native.format === "stylish") return rest === "" ? rest : void 0;
1311
+ 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;
1312
+ try {
1313
+ const report = completeJson(rest);
1314
+ if (report.diagnostics.length !== 0 || report.number_of_files !== 0 || Object.keys(report).length !== 5) return void 0;
1315
+ return joinProjectJson(rest, "{\"diagnostics\":[]}", {}) === rest ? rest : void 0;
1316
+ } catch {
1317
+ return;
1318
+ }
1319
+ }
1320
+ function mergeHtmlOutput(original, native, args) {
1321
+ if (native.executedFileCount === 0) return original;
1322
+ if (original.observation?.signal || original.observation?.error || original.status == null) throw new Error("original host failed before a qualified HTML join");
1323
+ const empty = eligibleEmptyHost(original, native, args);
1324
+ if (original.stdout.startsWith(noFiles) && empty == null) throw new Error("original NoFilesFound packet is not the qualified normal walker-empty branch");
1325
+ let stdout = empty ?? original.stdout;
1326
+ if (native.format === "json") {
1327
+ const report = completeJson(stdout);
1328
+ const rows = JSON.parse(native.jsonDiagnostics);
1329
+ if (!Array.isArray(rows)) throw new Error("native HTML did not render complete diagnostic fragments");
1330
+ stdout = joinProjectJson(stdout, `{"diagnostics":${native.jsonDiagnostics}}`, {
1331
+ number_of_files: Number(report.number_of_files) + native.executedFileCount,
1332
+ start_time: Number(report.start_time) + native.elapsedSeconds
1333
+ });
1334
+ } else stdout += native.output;
1335
+ const nativeFailure = native.errors > 0 || (args.includes("--deny-warnings") || native.projection.denyWarnings) && native.warnings > 0;
1336
+ return {
1337
+ ...original,
1338
+ stdout,
1339
+ rawStdout: void 0,
1340
+ status: Math.max(empty == null ? original.status : 0, nativeFailure ? 1 : 0)
1341
+ };
1342
+ }
1343
+ function unavailableHtml(original, error) {
1344
+ const suffix = `\nOriginal HTML unavailable: ${error instanceof Error ? error.message : String(error)}\n`;
1345
+ return {
1346
+ ...original,
1347
+ rawStderr: Buffer.concat([original.rawStderr ?? Buffer.from(original.stderr), Buffer.from(suffix)]),
1348
+ status: Math.max(original.status ?? 1, 1),
1349
+ stderr: original.stderr + suffix
1350
+ };
1351
+ }
1352
+ //#endregion
1353
+ //#region src/cli/process.ts
1354
+ /** Retain the actual child packet, including buffered bytes on stream/spawn failure. */
1355
+ function runOxlint(executable, args, cwd) {
1356
+ return new Promise((resolve) => {
1357
+ const child = spawn(executable, args, {
1358
+ cwd,
1359
+ stdio: [
1360
+ "ignore",
1361
+ "pipe",
1362
+ "pipe"
1363
+ ]
1364
+ });
1365
+ const stdout = [], stderr = [];
1366
+ let error = null;
1367
+ const failure = (reason) => {
1368
+ error ??= reason.message;
1369
+ };
1370
+ child.stdout.on("data", (chunk) => stdout.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk));
1371
+ child.stderr.on("data", (chunk) => stderr.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk));
1372
+ child.stdout.on("error", failure);
1373
+ child.stderr.on("error", failure);
1374
+ child.on("error", failure);
1375
+ child.on("close", (status, signal) => {
1376
+ const stdoutBytes = Buffer.concat(stdout), stderrBytes = Buffer.concat(stderr);
1377
+ const failureBytes = error ? Buffer.from(`\nOxlint child failure: ${error}\n`) : Buffer.alloc(0);
1378
+ const reportedStderr = Buffer.concat([stderrBytes, failureBytes]);
1379
+ resolve({
1380
+ status,
1381
+ stdout: stdoutBytes.toString("utf8"),
1382
+ rawStdout: stdoutBytes,
1383
+ rawStderr: reportedStderr,
1384
+ stderr: reportedStderr.toString("utf8"),
1385
+ observation: {
1386
+ executable,
1387
+ args: [...args],
1388
+ cwd,
1389
+ status,
1390
+ signal,
1391
+ error,
1392
+ stdoutBytes,
1393
+ stderrBytes,
1394
+ environment: presentationContext()
1395
+ }
1396
+ });
1397
+ });
1398
+ });
1399
+ }
1400
+ //#endregion
1009
1401
  //#region src/cli.ts
1010
1402
  async function main() {
1011
1403
  const cwd = process.cwd();
@@ -1014,11 +1406,20 @@ async function main() {
1014
1406
  const candidates = /* @__PURE__ */ new Set();
1015
1407
  const lintFiles = collectVueLikeFilesFromTargets(cwd, targets, (file) => candidates.add(file));
1016
1408
  const oxlintEntrypoint = resolveOxlintCliEntrypoint(cwd);
1017
- verifyOxlintCliEntrypoint(process.execPath, oxlintEntrypoint);
1018
- const scoped = await prepareScopedSelection(cwd, forwardedArgs, lintFiles, (args) => runOxlint(process.execPath, [oxlintEntrypoint, ...args], cwd), candidates);
1409
+ const version = verifyOxlintCliEntrypoint(process.execPath, oxlintEntrypoint);
1410
+ const html = lintFiles.some(isStandaloneHtmlFile) ? prepareHtmlContext(cwd, forwardedArgs, oxlintEntrypoint, version, candidates) : void 0;
1411
+ const vueFiles = html ? lintFiles.filter((file) => !isStandaloneHtmlFile(file)) : lintFiles;
1412
+ let scoped;
1413
+ try {
1414
+ scoped = await prepareScopedSelection(cwd, forwardedArgs, vueFiles, (args) => runOxlint(process.execPath, [oxlintEntrypoint, ...args], cwd), candidates);
1415
+ } catch (error) {
1416
+ if (!html) throw error;
1417
+ html.failure = error instanceof Error ? error.message : String(error);
1418
+ scoped = { result: await runOxlint(process.execPath, [oxlintEntrypoint, ...forwardedArgs], cwd) };
1419
+ }
1019
1420
  const sourceResult = scoped && "result" in scoped ? scoped.result : void 0;
1020
1421
  const transport = scoped && "prepared" in scoped ? scoped : void 0;
1021
- const prepared = sourceResult ? prepareScriptlessWorkaroundFiles(cwd, []) : transport?.prepared ?? prepareScriptlessWorkaroundFiles(cwd, lintFiles);
1422
+ const prepared = sourceResult ? prepareScriptlessWorkaroundFiles(cwd, []) : transport?.prepared ?? prepareScriptlessWorkaroundFiles(cwd, vueFiles);
1022
1423
  const args = [oxlintEntrypoint, ...transport?.args ?? [...forwardedArgs, ...prepared.appendedArgs]];
1023
1424
  try {
1024
1425
  let result;
@@ -1030,20 +1431,34 @@ async function main() {
1030
1431
  merged = {
1031
1432
  ...result,
1032
1433
  stdout: mappedStdout,
1033
- stderr: mappedStderr
1434
+ stderr: mappedStderr,
1435
+ rawStdout: mappedStdout === result.stdout ? result.rawStdout : void 0,
1436
+ rawStderr: mappedStderr === result.stderr ? result.rawStderr : void 0
1034
1437
  };
1035
1438
  if (transport?.originalResult) merged = mergeProjectOutput(transport.originalResult, merged, forwardedArgs);
1439
+ if (html) try {
1440
+ qualifyHtmlHost(html, merged);
1441
+ const outcome = executeHtml(html);
1442
+ if (!outcome.completed) throw new Error("original HTML operation is incomplete");
1443
+ merged = mergeHtmlOutput(merged, outcome.completed, forwardedArgs);
1444
+ } catch (error) {
1445
+ merged = unavailableHtml(merged, error);
1446
+ }
1036
1447
  } catch (error) {
1037
1448
  if (transport?.originalResult) {
1038
1449
  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, transport.originalResult.stderr + (result?.stderr ?? "") + (result?.stdout ?? ""));
1450
+ await writeStream(process.stdout, transport.originalResult.rawStdout ?? transport.originalResult.stdout);
1451
+ await writeStream(process.stderr, Buffer.concat([
1452
+ transport.originalResult.rawStderr ?? Buffer.from(transport.originalResult.stderr),
1453
+ result?.rawStderr ?? Buffer.from(result?.stderr ?? ""),
1454
+ result?.rawStdout ?? Buffer.from(result?.stdout ?? "")
1455
+ ]));
1041
1456
  }
1042
1457
  throw error;
1043
1458
  }
1044
1459
  const { stdout, stderr } = merged;
1045
- if (stdout) await writeStream(process.stdout, stdout);
1046
- if (stderr) await writeStream(process.stderr, stderr);
1460
+ if (stdout) await writeStream(process.stdout, merged.rawStdout ?? stdout);
1461
+ if (stderr) await writeStream(process.stderr, merged.rawStderr ?? stderr);
1047
1462
  if (merged.status === 0 && stdout === "" && stderr === "" && expectsLintReport(forwardedArgs)) {
1048
1463
  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
1464
  `);
@@ -1060,37 +1475,6 @@ main().catch((error) => {
1060
1475
  process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
1061
1476
  process.exitCode = Math.max(Number(process.exitCode) || 1, 1);
1062
1477
  });
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
1478
  function writeStream(stream, text) {
1095
1479
  return new Promise((resolve, reject) => {
1096
1480
  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-r91ttnV_.mjs";
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.441.0",
15
+ "@vizejs/native": "0.443.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.441.0",
53
- "@vizejs/native-darwin-x64": "0.441.0",
54
- "@vizejs/native-linux-arm64-gnu": "0.441.0",
55
- "@vizejs/native-linux-arm64-musl": "0.441.0",
56
- "@vizejs/native-linux-x64-gnu": "0.441.0",
57
- "@vizejs/native-linux-x64-musl": "0.441.0",
58
- "@vizejs/native-win32-arm64-msvc": "0.441.0",
59
- "@vizejs/native-win32-x64-msvc": "0.441.0"
52
+ "@vizejs/native-darwin-arm64": "0.443.0",
53
+ "@vizejs/native-darwin-x64": "0.443.0",
54
+ "@vizejs/native-linux-arm64-gnu": "0.443.0",
55
+ "@vizejs/native-linux-arm64-musl": "0.443.0",
56
+ "@vizejs/native-linux-x64-gnu": "0.443.0",
57
+ "@vizejs/native-linux-x64-musl": "0.443.0",
58
+ "@vizejs/native-win32-arm64-msvc": "0.443.0",
59
+ "@vizejs/native-win32-x64-msvc": "0.443.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.441.0",
71
+ "version": "0.443.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
  }