kleinigkeiten
This commit is contained in:
+412
@@ -0,0 +1,412 @@
|
||||
import { createRequire } from "module";
|
||||
//#region src-js/bindings.js
|
||||
const ArrayIsArray = Array.isArray, require = createRequire(import.meta.url);
|
||||
new URL(".", import.meta.url).pathname;
|
||||
const { readFileSync } = require("fs");
|
||||
let nativeBinding = null;
|
||||
const loadErrors = [], isMusl = () => {
|
||||
let musl = !1;
|
||||
return process.platform === "linux" && (musl = isMuslFromFilesystem(), musl === null && (musl = isMuslFromReport()), musl === null && (musl = isMuslFromChildProcess())), musl;
|
||||
}, isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-"), isMuslFromFilesystem = () => {
|
||||
try {
|
||||
return readFileSync("/usr/bin/ldd", "utf-8").includes("musl");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}, isMuslFromReport = () => {
|
||||
let report = null;
|
||||
return process.report && typeof process.report.getReport == "function" && (process.report.excludeNetwork = !0, report = process.report.getReport()), report ? report.header && report.header.glibcVersionRuntime ? !1 : !!(ArrayIsArray(report.sharedObjects) && report.sharedObjects.some(isFileMusl)) : null;
|
||||
}, isMuslFromChildProcess = () => {
|
||||
try {
|
||||
return require("child_process").execSync("ldd --version", { encoding: "utf8" }).includes("musl");
|
||||
} catch {
|
||||
return !1;
|
||||
}
|
||||
};
|
||||
function requireNative() {
|
||||
if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) try {
|
||||
return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH);
|
||||
} catch (err) {
|
||||
loadErrors.push(err);
|
||||
}
|
||||
else if (process.platform === "android") if (process.arch === "arm64") {
|
||||
try {
|
||||
return require("./oxlint.android-arm64.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-android-arm64"), bindingPackageVersion = require("@oxlint/binding-android-arm64/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else if (process.arch === "arm") {
|
||||
try {
|
||||
return require("./oxlint.android-arm-eabi.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-android-arm-eabi"), bindingPackageVersion = require("@oxlint/binding-android-arm-eabi/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else loadErrors.push(/* @__PURE__ */ Error(`Unsupported architecture on Android ${process.arch}`));
|
||||
else if (process.platform === "win32") if (process.arch === "x64") if (process.config && process.config.variables && process.config.variables.shlib_suffix === "dll.a" || process.config && process.config.variables && process.config.variables.node_target_type === "shared_library") {
|
||||
try {
|
||||
return require("./oxlint.win32-x64-gnu.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-win32-x64-gnu"), bindingPackageVersion = require("@oxlint/binding-win32-x64-gnu/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return require("./oxlint.win32-x64-msvc.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-win32-x64-msvc"), bindingPackageVersion = require("@oxlint/binding-win32-x64-msvc/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
}
|
||||
else if (process.arch === "ia32") {
|
||||
try {
|
||||
return require("./oxlint.win32-ia32-msvc.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-win32-ia32-msvc"), bindingPackageVersion = require("@oxlint/binding-win32-ia32-msvc/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else if (process.arch === "arm64") {
|
||||
try {
|
||||
return require("./oxlint.win32-arm64-msvc.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-win32-arm64-msvc"), bindingPackageVersion = require("@oxlint/binding-win32-arm64-msvc/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else loadErrors.push(/* @__PURE__ */ Error(`Unsupported architecture on Windows: ${process.arch}`));
|
||||
else if (process.platform === "darwin") {
|
||||
try {
|
||||
return require("./oxlint.darwin-universal.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-darwin-universal"), bindingPackageVersion = require("@oxlint/binding-darwin-universal/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
if (process.arch === "x64") {
|
||||
try {
|
||||
return require("./oxlint.darwin-x64.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-darwin-x64"), bindingPackageVersion = require("@oxlint/binding-darwin-x64/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else if (process.arch === "arm64") {
|
||||
try {
|
||||
return require("./oxlint.darwin-arm64.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-darwin-arm64"), bindingPackageVersion = require("@oxlint/binding-darwin-arm64/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else loadErrors.push(/* @__PURE__ */ Error(`Unsupported architecture on macOS: ${process.arch}`));
|
||||
} else if (process.platform === "freebsd") if (process.arch === "x64") {
|
||||
try {
|
||||
return require("./oxlint.freebsd-x64.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-freebsd-x64"), bindingPackageVersion = require("@oxlint/binding-freebsd-x64/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else if (process.arch === "arm64") {
|
||||
try {
|
||||
return require("./oxlint.freebsd-arm64.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-freebsd-arm64"), bindingPackageVersion = require("@oxlint/binding-freebsd-arm64/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else loadErrors.push(/* @__PURE__ */ Error(`Unsupported architecture on FreeBSD: ${process.arch}`));
|
||||
else if (process.platform === "linux") if (process.arch === "x64") if (isMusl()) {
|
||||
try {
|
||||
return require("./oxlint.linux-x64-musl.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-x64-musl"), bindingPackageVersion = require("@oxlint/binding-linux-x64-musl/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return require("./oxlint.linux-x64-gnu.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-x64-gnu"), bindingPackageVersion = require("@oxlint/binding-linux-x64-gnu/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
}
|
||||
else if (process.arch === "arm64") if (isMusl()) {
|
||||
try {
|
||||
return require("./oxlint.linux-arm64-musl.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-arm64-musl"), bindingPackageVersion = require("@oxlint/binding-linux-arm64-musl/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return require("./oxlint.linux-arm64-gnu.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-arm64-gnu"), bindingPackageVersion = require("@oxlint/binding-linux-arm64-gnu/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
}
|
||||
else if (process.arch === "arm") if (isMusl()) {
|
||||
try {
|
||||
return require("./oxlint.linux-arm-musleabihf.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-arm-musleabihf"), bindingPackageVersion = require("@oxlint/binding-linux-arm-musleabihf/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return require("./oxlint.linux-arm-gnueabihf.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-arm-gnueabihf"), bindingPackageVersion = require("@oxlint/binding-linux-arm-gnueabihf/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
}
|
||||
else if (process.arch === "loong64") if (isMusl()) {
|
||||
try {
|
||||
return require("./oxlint.linux-loong64-musl.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-loong64-musl"), bindingPackageVersion = require("@oxlint/binding-linux-loong64-musl/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return require("./oxlint.linux-loong64-gnu.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-loong64-gnu"), bindingPackageVersion = require("@oxlint/binding-linux-loong64-gnu/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
}
|
||||
else if (process.arch === "riscv64") if (isMusl()) {
|
||||
try {
|
||||
return require("./oxlint.linux-riscv64-musl.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-riscv64-musl"), bindingPackageVersion = require("@oxlint/binding-linux-riscv64-musl/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return require("./oxlint.linux-riscv64-gnu.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-riscv64-gnu"), bindingPackageVersion = require("@oxlint/binding-linux-riscv64-gnu/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
}
|
||||
else if (process.arch === "ppc64") {
|
||||
try {
|
||||
return require("./oxlint.linux-ppc64-gnu.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-ppc64-gnu"), bindingPackageVersion = require("@oxlint/binding-linux-ppc64-gnu/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else if (process.arch === "s390x") {
|
||||
try {
|
||||
return require("./oxlint.linux-s390x-gnu.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-linux-s390x-gnu"), bindingPackageVersion = require("@oxlint/binding-linux-s390x-gnu/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else loadErrors.push(/* @__PURE__ */ Error(`Unsupported architecture on Linux: ${process.arch}`));
|
||||
else if (process.platform === "openharmony") if (process.arch === "arm64") {
|
||||
try {
|
||||
return require("./oxlint.openharmony-arm64.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-openharmony-arm64"), bindingPackageVersion = require("@oxlint/binding-openharmony-arm64/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else if (process.arch === "x64") {
|
||||
try {
|
||||
return require("./oxlint.openharmony-x64.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-openharmony-x64"), bindingPackageVersion = require("@oxlint/binding-openharmony-x64/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else if (process.arch === "arm") {
|
||||
try {
|
||||
return require("./oxlint.openharmony-arm.node");
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
try {
|
||||
let binding = require("@oxlint/binding-openharmony-arm"), bindingPackageVersion = require("@oxlint/binding-openharmony-arm/package.json").version;
|
||||
if (bindingPackageVersion !== "1.76.0" && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== "0") throw Error(`Native binding package version mismatch, expected 1.76.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`);
|
||||
return binding;
|
||||
} catch (e) {
|
||||
loadErrors.push(e);
|
||||
}
|
||||
} else loadErrors.push(/* @__PURE__ */ Error(`Unsupported architecture on OpenHarmony: ${process.arch}`));
|
||||
else loadErrors.push(/* @__PURE__ */ Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`));
|
||||
}
|
||||
nativeBinding = requireNative();
|
||||
const forceWasi = process.env.NAPI_RS_FORCE_WASI === "true" || process.env.NAPI_RS_FORCE_WASI === "error";
|
||||
if (!nativeBinding || forceWasi) {
|
||||
let wasiBinding = null, wasiBindingError = null;
|
||||
try {
|
||||
wasiBinding = require("./oxlint.wasi.cjs"), nativeBinding = wasiBinding;
|
||||
} catch (err) {
|
||||
forceWasi && (wasiBindingError = err);
|
||||
}
|
||||
if (!nativeBinding || forceWasi) try {
|
||||
wasiBinding = require("@oxlint/binding-wasm32-wasi"), nativeBinding = wasiBinding;
|
||||
} catch (err) {
|
||||
forceWasi && (wasiBindingError ? wasiBindingError.cause = err : wasiBindingError = err, loadErrors.push(err));
|
||||
}
|
||||
if (process.env.NAPI_RS_FORCE_WASI === "error" && !wasiBinding) {
|
||||
let error = /* @__PURE__ */ Error("WASI binding not found and NAPI_RS_FORCE_WASI is set to error");
|
||||
throw error.cause = wasiBindingError, error;
|
||||
}
|
||||
}
|
||||
if (!nativeBinding) {
|
||||
if (loadErrors.length > 0) {
|
||||
let error = /* @__PURE__ */ Error("Cannot find native binding. npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). Please try `npm i` again after removing both package-lock.json and node_modules directory.");
|
||||
throw error.cause = loadErrors.reduce((err, cur) => (cur.cause = err, cur)), error;
|
||||
}
|
||||
throw Error("Failed to load native binding");
|
||||
}
|
||||
const { Severity, applyFixes, getBufferOffset, lint, parseRawSync, rawTransferSupported } = nativeBinding;
|
||||
//#endregion
|
||||
export { rawTransferSupported as a, parseRawSync as i, getBufferOffset as n, lint as r, applyFixes as t };
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
import { r as lint } from "./bindings.js";
|
||||
//#region src-js/cli.ts
|
||||
let loadPlugin = null, setupRuleConfigs = null, lintFile = null, createWorkspace = null, destroyWorkspace = null, resolvedConfigLoader = null;
|
||||
/**
|
||||
* Load a plugin.
|
||||
*
|
||||
* Lazy-loads plugins code on first call, so that overhead is skipped if user doesn't use JS plugins.
|
||||
*
|
||||
* @param path - Absolute path of plugin file
|
||||
* @param pluginName - Plugin name (either alias or package name)
|
||||
* @param pluginNameIsAlias - `true` if plugin name is an alias (takes priority over name that plugin defines itself)
|
||||
* @param workspaceUri - Workspace URI (`null` in CLI mode, `string` in LSP mode)
|
||||
* @returns Plugin details or error serialized to JSON string
|
||||
*/
|
||||
function loadPluginWrapper(path, pluginName, pluginNameIsAlias, workspaceUri) {
|
||||
return loadPlugin === null ? import("./plugins.js").then((mod) => ({loadPlugin, lintFile, setupRuleConfigs} = mod, loadPlugin(path, pluginName, pluginNameIsAlias, workspaceUri))) : loadPlugin(path, pluginName, pluginNameIsAlias, workspaceUri);
|
||||
}
|
||||
/**
|
||||
* Bootstrap configuration options.
|
||||
*
|
||||
* Delegates to `setupRuleConfigs`, which was lazy-loaded by `loadPluginWrapper`.
|
||||
*
|
||||
* @param optionsJSON - Array of all rule options across all configurations, serialized as JSON
|
||||
* @returns `null` if success, or error message string
|
||||
*/
|
||||
function setupRuleConfigsWrapper(optionsJSON) {
|
||||
return setupRuleConfigs(optionsJSON);
|
||||
}
|
||||
/**
|
||||
* Lint a file.
|
||||
*
|
||||
* Delegates to `lintFile`, which was lazy-loaded by `loadPluginWrapper`.
|
||||
*
|
||||
* @param filePath - Absolute path of file being linted
|
||||
* @param bufferId - ID of buffer containing file data
|
||||
* @param buffer - Buffer containing file data, or `null` if buffer with this ID was previously sent to JS
|
||||
* @param ruleIds - IDs of rules to run on this file
|
||||
* @param optionsIds - IDs of options to use for rules on this file, in same order as `ruleIds`
|
||||
* @param settingsJSON - Settings for file, as JSON
|
||||
* @param globalsJSON - Globals for file, as JSON
|
||||
* @param workspaceUri - Workspace URI (`null` in CLI mode, `string` in LSP mode)
|
||||
* @returns Diagnostics or error serialized to JSON string
|
||||
*/
|
||||
function lintFileWrapper(filePath, bufferId, buffer, ruleIds, optionsIds, settingsJSON, globalsJSON, workspaceUri) {
|
||||
return lintFile(filePath, bufferId, buffer, ruleIds, optionsIds, settingsJSON, globalsJSON, workspaceUri);
|
||||
}
|
||||
/**
|
||||
* Create a new workspace.
|
||||
*
|
||||
* Lazy-loads workspace code on first call, so that overhead is skipped if user doesn't use JS plugins.
|
||||
*
|
||||
* @param workspace - Workspace URI
|
||||
* @returns Promise which resolves when workspace is created
|
||||
*/
|
||||
function createWorkspaceWrapper(workspace) {
|
||||
return createWorkspace === null ? import("./workspace.js").then((mod) => ({createWorkspace, destroyWorkspace} = mod, createWorkspace(workspace))) : Promise.resolve(createWorkspace(workspace));
|
||||
}
|
||||
/**
|
||||
* Destroy a workspace.
|
||||
*
|
||||
* Delegates to `destroyWorkspace`, which was lazy-loaded by `createWorkspaceWrapper`.
|
||||
*
|
||||
* @param workspace - Workspace URI
|
||||
* @returns `undefined`
|
||||
*/
|
||||
function destroyWorkspaceWrapper(workspace) {
|
||||
destroyWorkspace(workspace);
|
||||
}
|
||||
/**
|
||||
* Load JavaScript/TypeScript config files (experimental).
|
||||
*
|
||||
* Lazy-loads the js_config module on first call.
|
||||
* Uses native Node.js TypeScript support to import config files.
|
||||
*
|
||||
* @param paths - Array of absolute paths to JavaScript/TypeScript config files
|
||||
* @returns JSON-stringified result with all configs or error
|
||||
*/
|
||||
function loadJsConfigsWrapper(paths) {
|
||||
return resolvedConfigLoader === null ? import("./js_config.js").then(({ loadJsConfigs, loadVitePlusConfigs }) => (resolvedConfigLoader = process.env.VP_VERSION ? loadVitePlusConfigs : loadJsConfigs, resolvedConfigLoader(paths))) : resolvedConfigLoader(paths);
|
||||
}
|
||||
const args = process.argv.slice(2);
|
||||
process.stdout.isTTY || (process.stdin._handle?.setBlocking?.(!0), process.stdout._handle?.setBlocking?.(!0)), args.includes("--lsp") && (process.stdout.write = process.stderr.write.bind(process.stderr)), await lint(args, loadPluginWrapper, setupRuleConfigsWrapper, lintFileWrapper, createWorkspaceWrapper, destroyWorkspaceWrapper, loadJsConfigsWrapper) || (process.exitCode = 1);
|
||||
//#endregion
|
||||
export {};
|
||||
+6907
File diff suppressed because it is too large
Load Diff
+12
@@ -0,0 +1,12 @@
|
||||
//#region src-js/package/config.ts
|
||||
/**
|
||||
* Define an Oxlint configuration with type inference.
|
||||
*
|
||||
* @param config - Oxlint configuration
|
||||
* @returns Config unchanged
|
||||
*/
|
||||
function defineConfig(config) {
|
||||
return config;
|
||||
}
|
||||
//#endregion
|
||||
export { defineConfig };
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
import { t as getErrorMessage$1 } from "./utils.js";
|
||||
import { extname } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
//#region ../shared/src-js/utils.ts
|
||||
const ArrayIsArray$1 = Array.isArray, isObject$1 = (v) => typeof v == "object" && !!v && !ArrayIsArray$1(v), TS_MODULE_EXTENSIONS = /* @__PURE__ */ new Set([
|
||||
".ts",
|
||||
".mts",
|
||||
".cts"
|
||||
]);
|
||||
function normalizeModuleSpecifierPath(specifier) {
|
||||
if (!specifier.startsWith("file:")) return specifier;
|
||||
try {
|
||||
return fileURLToPath(specifier);
|
||||
} catch {
|
||||
return specifier;
|
||||
}
|
||||
}
|
||||
function isTypeScriptModuleSpecifier(specifier) {
|
||||
let ext = extname(normalizeModuleSpecifierPath(specifier)).toLowerCase();
|
||||
return TS_MODULE_EXTENSIONS.has(ext);
|
||||
}
|
||||
function isUnknownFileExtensionError(err) {
|
||||
if (err?.code === "ERR_UNKNOWN_FILE_EXTENSION") return !0;
|
||||
let message = err?.message;
|
||||
return typeof message == "string" && /unknown(?: or unsupported)? file extension/i.test(message);
|
||||
}
|
||||
function getErrorMessage(err) {
|
||||
return err instanceof Error ? err.message : String(err);
|
||||
}
|
||||
/**
|
||||
* Returns a complete replacement string suitable for `Error.message` assignment
|
||||
* (includes the original error message + appended hint), or `null` when the
|
||||
* error is unrelated to TS module loading. Callers should overwrite, not append.
|
||||
*/
|
||||
function getUnsupportedTypeScriptModuleLoadHintForError(err, specifier, nodeVersion = process.version) {
|
||||
return !isTypeScriptModuleSpecifier(specifier) || !isUnknownFileExtensionError(err) ? null : `${getErrorMessage(err)}\n\nTypeScript config files require Node.js ^20.19.0 || >=22.18.0.\nDetected Node.js ${nodeVersion}.\nPlease upgrade Node.js or use a JSON config file instead.`;
|
||||
}
|
||||
//#endregion
|
||||
//#region ../shared/src-js/js_config/index.ts
|
||||
/**
|
||||
* Import a JS/TS config file and return its `default` export as a plain object.
|
||||
*
|
||||
* - Bypasses Node.js module cache (uses `?cache=<key>`) so changed files reload (used for LSP).
|
||||
* - On `ERR_UNKNOWN_FILE_EXTENSION` for TS specifiers, wraps the error with a Node.js upgrade hint message;
|
||||
* The original error is preserved via `Error.cause`.
|
||||
*
|
||||
* @param path - Absolute path to the JS/TS config file
|
||||
* @param cacheKey - Cache-busting key.
|
||||
* Callers decide whether to use a fresh value per call or share one across a batch.
|
||||
* @throws When the file has no `default` export, the export is not a plain object,
|
||||
* or import fails (wrapped with hint message for unsupported TS module load).
|
||||
*/
|
||||
async function importJsConfig(path, cacheKey) {
|
||||
let fileUrl = pathToFileURL(path);
|
||||
fileUrl.searchParams.set("cache", cacheKey.toString());
|
||||
let module;
|
||||
try {
|
||||
module = await import(fileUrl.href);
|
||||
} catch (err) {
|
||||
let hint = getUnsupportedTypeScriptModuleLoadHintForError(err, path);
|
||||
throw hint ? Error(hint, { cause: err }) : err;
|
||||
}
|
||||
if (module.default === void 0) throw Error("Configuration file has no default export.");
|
||||
if (!isObject$1(module.default)) throw Error("Configuration file must have a default export that is an object.");
|
||||
return module.default;
|
||||
}
|
||||
//#endregion
|
||||
//#region ../shared/src-js/vite_plus_config.ts
|
||||
let vitePlusCache = null;
|
||||
/**
|
||||
* Resolve a Vite+ config via `vite-plus`'s `resolveConfig` and extract the given field.
|
||||
*
|
||||
* `vite-plus` is loaded lazily and memoized for the process.
|
||||
* Consumers declare it as an optional peer dependency; tsdown leaves the specifier external
|
||||
* so the user-installed copy is used at runtime.
|
||||
*
|
||||
* @param path - Absolute path to the Vite config file
|
||||
* @param fieldName - Field name to extract from the resolved config (e.g. `"fmt"`, `"lint"`)
|
||||
* @returns The field as an object, or `null` when the field is missing (signals "skip")
|
||||
* @throws When the field exists but is not a plain object
|
||||
*/
|
||||
async function loadViteConfigField(path, fieldName) {
|
||||
vitePlusCache ??= import("vite-plus");
|
||||
let { resolveConfig } = await vitePlusCache, config = await resolveConfig({ configFile: path }, "build");
|
||||
if (!(fieldName in config)) return null;
|
||||
let fieldValue = config[fieldName];
|
||||
if (!isObject$1(fieldValue)) throw Error(`The \`${fieldName}\` field in the default export must be an object.`);
|
||||
return fieldValue;
|
||||
}
|
||||
//#endregion
|
||||
//#region src-js/js_config.ts
|
||||
const ArrayIsArray = Array.isArray, JSONStringify = JSON.stringify, DateNow = Date.now, isObject = (v) => typeof v == "object" && !!v && !ArrayIsArray(v);
|
||||
function validateConfigExtends(root) {
|
||||
let visited = /* @__PURE__ */ new WeakSet(), inStack = /* @__PURE__ */ new WeakSet(), stackObjects = [], stackPaths = [], formatCycleError = (refPath, cycleStart, idx) => `\`extends\` contains a circular reference.
|
||||
|
||||
${refPath} points back to ${cycleStart}\nCycle: ${idx === -1 ? `${cycleStart} -> ${cycleStart}` : [...stackPaths.slice(idx), cycleStart].join(" -> ")}`, visit = (config, path) => {
|
||||
if (visited.has(config)) return;
|
||||
if (inStack.has(config)) {
|
||||
let idx = stackObjects.indexOf(config), cycleStart = idx === -1 ? "<unknown>" : stackPaths[idx];
|
||||
throw Error(formatCycleError(path, cycleStart, idx));
|
||||
}
|
||||
inStack.add(config), stackObjects.push(config), stackPaths.push(path);
|
||||
let maybeExtends = config.extends;
|
||||
if (maybeExtends !== void 0) {
|
||||
if (!ArrayIsArray(maybeExtends)) throw Error("`extends` must be an array of config objects (strings/paths are not supported).");
|
||||
for (let i = 0; i < maybeExtends.length; i++) {
|
||||
let item = maybeExtends[i];
|
||||
if (!isObject(item)) throw Error(`\`extends[${i}]\` must be a config object (strings/paths are not supported).`);
|
||||
let itemPath = `${path}.extends[${i}]`;
|
||||
if (inStack.has(item)) {
|
||||
let idx = stackObjects.indexOf(item), cycleStart = idx === -1 ? "<unknown>" : stackPaths[idx];
|
||||
throw Error(formatCycleError(itemPath, cycleStart, idx));
|
||||
}
|
||||
visit(item, itemPath);
|
||||
}
|
||||
}
|
||||
inStack.delete(config), stackObjects.pop(), stackPaths.pop(), visited.add(config);
|
||||
};
|
||||
visit(root, "<root>");
|
||||
}
|
||||
/**
|
||||
* Resolve a single config path to a `JsConfigResult`.
|
||||
* Standard mode: default export must be a plain object.
|
||||
*/
|
||||
async function resolveJsConfig(path, cacheKey) {
|
||||
let config = await importJsConfig(path, cacheKey);
|
||||
return validateConfigExtends(config), {
|
||||
path,
|
||||
config
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Resolve a single Vite+ config path to a `JsConfigResult`.
|
||||
* Extracts the `.lint` field via `vite-plus`. Returns `null` config when missing (signals "skip").
|
||||
*/
|
||||
async function resolveVitePlusConfig(path) {
|
||||
let lintConfig = await loadViteConfigField(path, "lint");
|
||||
return lintConfig === null ? {
|
||||
path,
|
||||
config: null
|
||||
} : (validateConfigExtends(lintConfig), {
|
||||
path,
|
||||
config: lintConfig
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Load config files in parallel using the given resolver, and return JSON-stringified result.
|
||||
*/
|
||||
async function loadConfigs(paths, resolver) {
|
||||
try {
|
||||
let results = await Promise.allSettled(paths.map(resolver)), successes = [], errors = [];
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let result = results[i];
|
||||
result.status === "fulfilled" ? successes.push(result.value) : errors.push({
|
||||
path: paths[i],
|
||||
error: getErrorMessage$1(result.reason)
|
||||
});
|
||||
}
|
||||
return errors.length > 0 ? JSONStringify({ Failures: errors }) : JSONStringify({ Success: successes });
|
||||
} catch (err) {
|
||||
return JSONStringify({ Error: getErrorMessage$1(err) });
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Load standard oxlint JS/TS config files in parallel.
|
||||
*/
|
||||
const loadJsConfigs = (paths) => {
|
||||
let cacheKey = DateNow();
|
||||
return loadConfigs(paths, (path) => resolveJsConfig(path, cacheKey));
|
||||
}, loadVitePlusConfigs = (paths) => loadConfigs(paths, resolveVitePlusConfig);
|
||||
//#endregion
|
||||
export { loadJsConfigs, loadVitePlusConfigs };
|
||||
+23764
File diff suppressed because one or more lines are too long
+4267
File diff suppressed because it is too large
Load Diff
+871
@@ -0,0 +1,871 @@
|
||||
import { _ as BLOCK_SIZE, b as __commonJSMin, c as allOptions, d as diagnostics, f as replacePlaceholders, g as BLOCK_ALIGN, h as ACTIVE_SIZE, i as resetStateAfterError, l as setOptions, m as getNodeByRangeIndex, o as registerPlugin, p as getLineColumnFromOffset, r as lintFileImpl, s as registeredRules, t as buffers, u as PLACEHOLDER_REGEX, v as BUFFER_SIZE, x as __toESM } from "./lint.js";
|
||||
import { a as rawTransferSupported$1, i as parseRawSync, n as getBufferOffset, t as applyFixes } from "./bindings.js";
|
||||
import assert, { AssertionError } from "node:assert";
|
||||
import { dirname, isAbsolute, join } from "node:path";
|
||||
import util from "node:util";
|
||||
//#endregion
|
||||
//#region src-js/package/parse.ts
|
||||
var import_json_stable_stringify_without_jsonify = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
||||
module.exports = function(obj, opts) {
|
||||
opts ||= {}, typeof opts == "function" && (opts = { cmp: opts });
|
||||
var space = opts.space || "";
|
||||
typeof space == "number" && (space = Array(space + 1).join(" "));
|
||||
var cycles = typeof opts.cycles == "boolean" && opts.cycles, replacer = opts.replacer || function(key, value) {
|
||||
return value;
|
||||
}, cmp = opts.cmp && (function(f) {
|
||||
return function(node) {
|
||||
return function(a, b) {
|
||||
return f({
|
||||
key: a,
|
||||
value: node[a]
|
||||
}, {
|
||||
key: b,
|
||||
value: node[b]
|
||||
});
|
||||
};
|
||||
};
|
||||
})(opts.cmp), seen = [];
|
||||
return (function stringify(parent, key, node, level) {
|
||||
var indent = space ? "\n" + Array(level + 1).join(space) : "", colonSeparator = space ? ": " : ":";
|
||||
if (node && node.toJSON && typeof node.toJSON == "function" && (node = node.toJSON()), node = replacer.call(parent, key, node), node !== void 0) {
|
||||
if (typeof node != "object" || !node) return JSON.stringify(node);
|
||||
if (isArray(node)) {
|
||||
for (var out = [], i = 0; i < node.length; i++) {
|
||||
var item = stringify(node, i, node[i], level + 1) || JSON.stringify(null);
|
||||
out.push(indent + space + item);
|
||||
}
|
||||
return "[" + out.join(",") + indent + "]";
|
||||
} else {
|
||||
if (seen.indexOf(node) !== -1) {
|
||||
if (cycles) return JSON.stringify("__cycle__");
|
||||
throw TypeError("Converting circular structure to JSON");
|
||||
} else seen.push(node);
|
||||
for (var keys = objectKeys(node).sort(cmp && cmp(node)), out = [], i = 0; i < keys.length; i++) {
|
||||
var key = keys[i], value = stringify(node, key, node[key], level + 1);
|
||||
if (value) {
|
||||
var keyValue = JSON.stringify(key) + colonSeparator + value;
|
||||
out.push(indent + space + keyValue);
|
||||
}
|
||||
}
|
||||
return seen.splice(seen.indexOf(node), 1), "{" + out.join(",") + indent + "}";
|
||||
}
|
||||
}
|
||||
})({ "": obj }, "", obj, 0);
|
||||
};
|
||||
var isArray = Array.isArray || function(x) {
|
||||
return {}.toString.call(x) === "[object Array]";
|
||||
}, objectKeys = Object.keys || function(obj) {
|
||||
var has = Object.prototype.hasOwnProperty || function() {
|
||||
return !0;
|
||||
}, keys = [];
|
||||
for (var key in obj) has.call(obj, key) && keys.push(key);
|
||||
return keys;
|
||||
};
|
||||
})))(), 1);
|
||||
const ARRAY_BUFFER_SIZE = BLOCK_SIZE + BLOCK_ALIGN, textEncoder = new TextEncoder();
|
||||
let buffer = null, blockBuffer = null, rawTransferIsSupported = null;
|
||||
/**
|
||||
* Parser source text into buffer.
|
||||
* @param path - Path of file to parse
|
||||
* @param sourceText - Source text to parse
|
||||
* @param options - Parsing options
|
||||
* @throws {Error} If raw transfer is not supported on this platform, or parsing failed
|
||||
*/
|
||||
function parse(path, sourceText, options) {
|
||||
if (!rawTransferSupported()) throw Error("`RuleTester` is not supported on 32-bit or big-endian systems, versions of NodeJS prior to v22.0.0, versions of Deno prior to v2.0.0, or other runtimes");
|
||||
buffer === null && initBuffer();
|
||||
let maxSourceByteLen = sourceText.length * 3;
|
||||
if (maxSourceByteLen > 1073741824) throw Error("Source text is too long");
|
||||
let sourceStartPos = ACTIVE_SIZE - maxSourceByteLen, sourceBuffer = new Uint8Array(buffer.buffer, buffer.byteOffset + sourceStartPos, maxSourceByteLen), { read, written: sourceByteLen } = textEncoder.encodeInto(sourceText, sourceBuffer);
|
||||
if (read !== sourceText.length) throw Error("Failed to write source text into buffer");
|
||||
if (parseRawSync(path, blockBuffer, sourceStartPos, sourceByteLen, options), buffer.int32[536870890] === 0) throw Error("Parsing failed");
|
||||
}
|
||||
/**
|
||||
* Create a `Uint8Array` which is 2 GiB in size, with its start aligned on 4 GiB.
|
||||
*
|
||||
* Store it in `buffer`, and also in `buffers` array, so it's accessible to `lintFileImpl` by passing `0`as `bufferId`.
|
||||
*
|
||||
* Achieve this by creating a 6 GiB `ArrayBuffer`, getting the offset within it that's aligned to 4 GiB,
|
||||
* chopping off that number of bytes from the start, and shortening to 2 GiB.
|
||||
*
|
||||
* It's always possible to obtain a 2 GiB slice aligned on 4 GiB within a 6 GiB buffer,
|
||||
* no matter how the 6 GiB buffer is aligned.
|
||||
*
|
||||
* `buffer` itself, and `int32` and `float64` views of `buffer`, are `BUFFER_SIZE` bytes,
|
||||
* which excludes `FixedSizeAllocatorMetadata` and `ChunkFooter`.
|
||||
* This ensures this critical data cannot be accidentally overwritten on JS side.
|
||||
* `blockBuffer` is `BLOCK_SIZE` bytes, which includes `FixedSizeAllocatorMetadata` and `ChunkFooter`.
|
||||
* `blockBuffer` is what we pass to Rust, which needs to write them.
|
||||
*
|
||||
* Note: On systems with virtual memory, this only consumes 6 GiB of *virtual* memory.
|
||||
* It does not consume physical memory until data is actually written to the `Uint8Array`.
|
||||
* Physical memory consumed corresponds to the quantity of data actually written.
|
||||
*/
|
||||
function initBuffer() {
|
||||
let arrayBuffer = new ArrayBuffer(ARRAY_BUFFER_SIZE), offset = getBufferOffset(new Uint8Array(arrayBuffer));
|
||||
buffer = new Uint8Array(arrayBuffer, offset, BUFFER_SIZE), buffer.int32 = new Int32Array(arrayBuffer, offset, BUFFER_SIZE / 4), buffer.float64 = new Float64Array(arrayBuffer, offset, BUFFER_SIZE / 8), blockBuffer = new Uint8Array(arrayBuffer, offset, BLOCK_SIZE), buffers.push(buffer);
|
||||
}
|
||||
/**
|
||||
* Returns `true` if raw transfer is supported.
|
||||
*
|
||||
* Raw transfer is only supported on 64-bit little-endian systems,
|
||||
* and NodeJS >= v22.0.0 or Deno >= v2.0.0.
|
||||
*
|
||||
* Versions of NodeJS prior to v22.0.0 do not support creating an `ArrayBuffer` larger than 4 GiB.
|
||||
* Bun (as at v1.2.4) also does not support creating an `ArrayBuffer` larger than 4 GiB.
|
||||
* Support on Deno v1 is unknown and it's EOL, so treating Deno before v2.0.0 as unsupported.
|
||||
*
|
||||
* No easy way to determining pointer width (64 bit or 32 bit) in JS,
|
||||
* so call a function on Rust side to find out.
|
||||
*
|
||||
* @returns {boolean} - `true` if raw transfer is supported on this platform
|
||||
*/
|
||||
function rawTransferSupported() {
|
||||
return rawTransferIsSupported === null && (rawTransferIsSupported = rawTransferRuntimeSupported() && rawTransferSupported$1()), rawTransferIsSupported;
|
||||
}
|
||||
function rawTransferRuntimeSupported() {
|
||||
let global;
|
||||
try {
|
||||
global = globalThis;
|
||||
} catch {
|
||||
return !1;
|
||||
}
|
||||
if (global.Bun || global.process?.versions?.bun) return !1;
|
||||
if (global.Deno) {
|
||||
let match = Deno.version?.deno?.match(/^(\d+)\./);
|
||||
return !!match && +match[1] >= 2;
|
||||
}
|
||||
if (global.process?.release?.name !== "node") return !1;
|
||||
let match = process.version?.match(/^v(\d+)\./);
|
||||
return !!match && +match[1] >= 22;
|
||||
}
|
||||
//#endregion
|
||||
//#region src-js/package/rule_tester.ts
|
||||
const ObjectKeys = Object.keys, ObjectValues = Object.values, ObjectHasOwn = Object.hasOwn, JSONStringify = JSON.stringify, ArrayFrom = Array.from, ObjectEntries = Object.entries, ObjectDefineProperty = Object.defineProperty, ArrayIsArray = Array.isArray;
|
||||
/**
|
||||
* Default `describe` function, if `describe` doesn't exist as a global.
|
||||
* @param text - Description of the test case
|
||||
* @param method - Test case logic
|
||||
* @returns Returned value of `method`
|
||||
*/
|
||||
function defaultDescribe(text, method) {
|
||||
return method.call(this);
|
||||
}
|
||||
const globalObj = globalThis;
|
||||
let describe = typeof globalObj.describe == "function" ? globalObj.describe : defaultDescribe;
|
||||
/**
|
||||
* Default `it` function, if `it` doesn't exist as a global.
|
||||
* @param text - Description of the test case
|
||||
* @param method - Test case logic
|
||||
* @throws {Error} Any error upon execution of `method`
|
||||
* @returns Returned value of `method`
|
||||
*/
|
||||
function defaultIt(text, method) {
|
||||
try {
|
||||
return method.call(this);
|
||||
} catch (err) {
|
||||
throw err instanceof AssertionError && (err.message += ` (${util.inspect(err.actual)} ${err.operator} ${util.inspect(err.expected)})`), err;
|
||||
}
|
||||
}
|
||||
let it = typeof globalObj.it == "function" ? globalObj.it : defaultIt, itOnly = it !== defaultIt && typeof it.only == "function" ? it.only.bind(it) : null;
|
||||
/**
|
||||
* Get `it` function.
|
||||
* @param only - `true` if `it.only` should be used
|
||||
* @throws {Error} If `it.only` is not available
|
||||
* @returns `it` or `it.only` function
|
||||
*/
|
||||
function getIt(only) {
|
||||
return only ? getItOnly() : it;
|
||||
}
|
||||
/**
|
||||
* Get `it.only` function.
|
||||
* @throws {Error} If `it.only` is not available
|
||||
* @returns `it.only` function
|
||||
*/
|
||||
function getItOnly() {
|
||||
if (itOnly === null) throw Error("To use `only`, use `RuleTester` with a test framework that provides `it.only()` like Mocha, or provide a custom `it.only` function by assigning it to `RuleTester.itOnly`");
|
||||
return itOnly;
|
||||
}
|
||||
const EMPTY_LANGUAGE_OPTIONS = {};
|
||||
let sharedConfig = {};
|
||||
const TEST_CASE_PROP_KEYS = /* @__PURE__ */ new Set([
|
||||
"code",
|
||||
"name",
|
||||
"only",
|
||||
"filename",
|
||||
"options",
|
||||
"settings",
|
||||
"before",
|
||||
"after",
|
||||
"output",
|
||||
"errors",
|
||||
"__proto__"
|
||||
]), DEFAULT_CWD = dirname(import.meta.dirname);
|
||||
/**
|
||||
* Utility class for testing rules.
|
||||
*/
|
||||
var RuleTester = class {
|
||||
#config;
|
||||
/**
|
||||
* Creates a new instance of RuleTester.
|
||||
* @param config? - Extra configuration for the tester (optional)
|
||||
*/
|
||||
constructor(config) {
|
||||
if (config === void 0) config = null;
|
||||
else if (config !== null && typeof config != "object") throw TypeError("`config` must be an object if provided");
|
||||
this.#config = config;
|
||||
}
|
||||
/**
|
||||
* Set the configuration to use for all future tests.
|
||||
* @param config - The configuration to use
|
||||
* @throws {TypeError} If `config` is not an object
|
||||
*/
|
||||
static setDefaultConfig(config) {
|
||||
if (typeof config != "object" || !config) throw TypeError("`config` must be an object");
|
||||
sharedConfig = config;
|
||||
}
|
||||
/**
|
||||
* Get the current configuration used for all tests.
|
||||
* @returns The current configuration
|
||||
*/
|
||||
static getDefaultConfig() {
|
||||
return sharedConfig;
|
||||
}
|
||||
/**
|
||||
* Reset the configuration to the initial configuration of the tester removing
|
||||
* any changes made until now.
|
||||
* @returns {void}
|
||||
*/
|
||||
static resetDefaultConfig() {
|
||||
sharedConfig = {};
|
||||
}
|
||||
static get describe() {
|
||||
return describe;
|
||||
}
|
||||
static set describe(value) {
|
||||
describe = value;
|
||||
}
|
||||
static get it() {
|
||||
return it;
|
||||
}
|
||||
static set it(value) {
|
||||
it = value, itOnly = typeof it.only == "function" ? it.only.bind(it) : null;
|
||||
}
|
||||
static get itOnly() {
|
||||
return getItOnly();
|
||||
}
|
||||
static set itOnly(value) {
|
||||
itOnly = value;
|
||||
}
|
||||
/**
|
||||
* Add the `only` property to a test to run it in isolation.
|
||||
* @param item - A single test to run by itself
|
||||
* @returns The test with `only` set
|
||||
*/
|
||||
static only(item) {
|
||||
return typeof item == "string" ? {
|
||||
code: item,
|
||||
only: !0
|
||||
} : {
|
||||
...item,
|
||||
only: !0
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Adds a new rule test to execute.
|
||||
* @param ruleName - Name of the rule to run
|
||||
* @param rule - Rule to test
|
||||
* @param tests - Collection of tests to run
|
||||
* @throws {TypeError|Error} If `rule` is not an object with a `create` method,
|
||||
* or if non-object `test`, or if a required scenario of the given type is missing
|
||||
*/
|
||||
run(ruleName, rule, tests) {
|
||||
let plugin = {
|
||||
meta: { name: "rule-to-test" },
|
||||
rules: { [ruleName]: rule }
|
||||
}, config = createConfigForRun(this.#config);
|
||||
describe(ruleName, () => {
|
||||
tests.valid.length > 0 && describe("valid", () => {
|
||||
let seenTestCases = /* @__PURE__ */ new Set();
|
||||
for (let test of tests.valid) typeof test == "string" && (test = { code: test }), getIt(test.only)(getTestName(test), () => {
|
||||
runValidTestCase(test, plugin, config, seenTestCases);
|
||||
});
|
||||
}), tests.invalid.length > 0 && describe("invalid", () => {
|
||||
let seenTestCases = /* @__PURE__ */ new Set();
|
||||
for (let test of tests.invalid) getIt(test.only)(getTestName(test), () => {
|
||||
runInvalidTestCase(test, plugin, config, seenTestCases);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Run valid test case.
|
||||
* @param test - Valid test case
|
||||
* @param plugin - Plugin containing rule being tested
|
||||
* @param config - Config from `RuleTester` instance
|
||||
* @param seenTestCases - Set of serialized test cases to check for duplicates
|
||||
* @throws {AssertionError} If the test case fails
|
||||
*/
|
||||
function runValidTestCase(test, plugin, config, seenTestCases) {
|
||||
try {
|
||||
runBeforeHook(test), assertValidTestCaseIsWellFormed(test, seenTestCases), assertValidTestCasePasses(test, plugin, config);
|
||||
} finally {
|
||||
runAfterHook(test);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Assert that valid test case passes.
|
||||
* @param test - Valid test case
|
||||
* @param plugin - Plugin containing rule being tested
|
||||
* @param config - Config from `RuleTester` instance
|
||||
* @throws {AssertionError} If the test case fails
|
||||
*/
|
||||
function assertValidTestCasePasses(test, plugin, config) {
|
||||
test = mergeConfigIntoTestCase(test, config), assertErrorCountIsCorrect(lint(test, plugin), 0);
|
||||
}
|
||||
/**
|
||||
* Run invalid test case.
|
||||
* @param test - Invalid test case
|
||||
* @param plugin - Plugin containing rule being tested
|
||||
* @param config - Config from `RuleTester` instance
|
||||
* @param seenTestCases - Set of serialized test cases to check for duplicates
|
||||
* @throws {AssertionError} If the test case fails
|
||||
*/
|
||||
function runInvalidTestCase(test, plugin, config, seenTestCases) {
|
||||
let ruleName = ObjectKeys(plugin.rules)[0];
|
||||
try {
|
||||
runBeforeHook(test), assertInvalidTestCaseIsWellFormed(test, seenTestCases, ruleName), assertInvalidTestCasePasses(test, plugin, config);
|
||||
} finally {
|
||||
runAfterHook(test);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Assert that invalid test case passes.
|
||||
* @param test - Invalid test case
|
||||
* @param plugin - Plugin containing rule being tested
|
||||
* @param config - Config from `RuleTester` instance
|
||||
* @throws {AssertionError} If the test case fails
|
||||
*/
|
||||
function assertInvalidTestCasePasses(test, plugin, config) {
|
||||
test = mergeConfigIntoTestCase(test, config);
|
||||
let diagnostics = lint(test, plugin), { errors } = test;
|
||||
if (typeof errors == "number") assertErrorCountIsCorrect(diagnostics, errors);
|
||||
else {
|
||||
assertErrorCountIsCorrect(diagnostics, errors.length), diagnostics.sort((diag1, diag2) => diag1.line - diag2.line || diag1.column - diag2.column);
|
||||
let messages = ObjectValues(plugin.rules)[0].meta?.messages ?? null;
|
||||
for (let errorIndex = 0; errorIndex < errors.length; errorIndex++) {
|
||||
let error = errors[errorIndex], diagnostic = diagnostics[errorIndex];
|
||||
typeof error == "string" || error instanceof RegExp ? (assertMessageMatches(diagnostic.message, error), assert(diagnostic.suggestions === null, `Error at index ${errorIndex} has suggestions. Please convert the test error into an object and specify \`suggestions\` property on it to test suggestions`)) : (assertInvalidTestCaseMessageIsCorrect(diagnostic, error, messages), assertInvalidTestCaseLocationIsCorrect(diagnostic, error, test), ObjectHasOwn(error, "suggestions") && (error.suggestions == null ? assert(diagnostic.suggestions === null, "Rule produced suggestions") : assertSuggestionsAreCorrect(diagnostic, error, messages, test)));
|
||||
}
|
||||
}
|
||||
let { code } = test, fixedCode = runFixes(diagnostics, code);
|
||||
fixedCode === null && (fixedCode = code);
|
||||
let { recursive } = test, extraPassCount = typeof recursive == "number" ? recursive : recursive === !0 ? 10 : 0;
|
||||
if (extraPassCount > 0 && fixedCode !== code) for (let pass = 0; pass < extraPassCount; pass++) {
|
||||
let newFixedCode = runFixes(lint({
|
||||
...test,
|
||||
code: fixedCode
|
||||
}, plugin), fixedCode);
|
||||
if (newFixedCode === null) break;
|
||||
fixedCode = newFixedCode;
|
||||
}
|
||||
if (ObjectHasOwn(test, "output")) {
|
||||
let expectedOutput = test.output;
|
||||
expectedOutput === null ? assert.strictEqual(fixedCode, code, "Expected no autofixes to be suggested") : (assert.strictEqual(fixedCode, expectedOutput, "Output is incorrect"), assert.notStrictEqual(code, expectedOutput, "Test property `output` matches `code`. If no autofix is expected, set output to `null`."));
|
||||
} else assert.strictEqual(fixedCode, code, "The rule fixed the code. Please add `output` property.");
|
||||
}
|
||||
/**
|
||||
* Run fixes on code and return fixed code.
|
||||
* If no fixes to apply, returns `null`.
|
||||
*
|
||||
* @param diagnostics - Array of `Diagnostic`s returned by `lint`
|
||||
* @param code - Code to run fixes on
|
||||
* @returns Fixed code, or `null` if no fixes to apply
|
||||
* @throws {Error} If error when applying fixes
|
||||
*/
|
||||
function runFixes(diagnostics, code) {
|
||||
let fixGroups = [];
|
||||
for (let diagnostic of diagnostics) diagnostic.fixes !== null && fixGroups.push(diagnostic.fixes);
|
||||
if (fixGroups.length === 0) return null;
|
||||
let fixedCode = applyFixes(code, JSONStringify(fixGroups));
|
||||
if (fixedCode === null) throw Error("Failed to apply fixes");
|
||||
return fixedCode;
|
||||
}
|
||||
/**
|
||||
* Assert that message reported by rule under test matches the expected message.
|
||||
* @param diagnostic - Diagnostic emitted by rule under test
|
||||
* @param error - Error object from test case
|
||||
* @param messages - Messages from rule under test
|
||||
* @throws {AssertionError} If `message` / `messageId` is not correct
|
||||
*/
|
||||
function assertInvalidTestCaseMessageIsCorrect(diagnostic, error, messages) {
|
||||
if (ObjectHasOwn(error, "message")) {
|
||||
assert(!ObjectHasOwn(error, "messageId"), "Error should not specify both `message` and a `messageId`"), assert(!ObjectHasOwn(error, "data"), "Error should not specify both `data` and `message`"), assertMessageMatches(diagnostic.message, error.message);
|
||||
return;
|
||||
}
|
||||
assert(ObjectHasOwn(error, "messageId"), "Test error must specify either a `messageId` or `message`"), assertMessageIdIsCorrect(diagnostic.messageId, diagnostic.message, error.messageId, error.data, messages, "");
|
||||
}
|
||||
/**
|
||||
* Assert that a `messageId` used by the rule under test is correct, and validate `data` (if provided).
|
||||
*
|
||||
* @param reportedMessageId - `messageId` from the diagnostic or suggestion
|
||||
* @param reportedMessage - Message from the diagnostic or suggestion
|
||||
* @param messageId - Expected `messageId` from the test case
|
||||
* @param data - Data from the test case (if provided)
|
||||
* @param messages - Messages from the rule under test
|
||||
* @param prefix - Prefix for assertion error messages (e.g. "" or "Suggestion at index 0: ")
|
||||
* @throws {AssertionError} If messageId is not correct
|
||||
* @throws {AssertionError} If message tenplate with placeholder data inserted does not match reported message
|
||||
*/
|
||||
function assertMessageIdIsCorrect(reportedMessageId, reportedMessage, messageId, data, messages, prefix) {
|
||||
if (assert(messages !== null, `${prefix}Cannot use 'messageId' if rule under test doesn't define 'meta.messages'`), !ObjectHasOwn(messages, messageId)) {
|
||||
let legalMessageIds = `[${ObjectKeys(messages).map((key) => `'${key}'`).join(", ")}]`;
|
||||
assert.fail(`${prefix}Invalid messageId '${messageId}'. Expected one of ${legalMessageIds}.`);
|
||||
}
|
||||
assert.strictEqual(reportedMessageId, messageId, `${prefix}messageId '${reportedMessageId}' does not match expected messageId '${messageId}'`);
|
||||
let ruleMessage = messages[messageId], unsubstitutedPlaceholders = getUnsubstitutedMessagePlaceholders(reportedMessage, ruleMessage, data);
|
||||
if (unsubstitutedPlaceholders.length !== 0 && assert.fail(`${prefix}The reported message has ` + (unsubstitutedPlaceholders.length > 1 ? `unsubstituted placeholders: ${unsubstitutedPlaceholders.map((name) => `'${name}'`).join(", ")}` : `an unsubstituted placeholder '${unsubstitutedPlaceholders[0]}'`) + `. Please provide the missing ${unsubstitutedPlaceholders.length > 1 ? "values" : "value"} via the \`data\` property.`), data !== void 0) {
|
||||
let rehydratedMessage = replacePlaceholders(ruleMessage, data);
|
||||
assert.strictEqual(reportedMessage, rehydratedMessage, `${prefix}Hydrated message "${rehydratedMessage}" does not match "${reportedMessage}"`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Assert that location reported by rule under test matches the expected location.
|
||||
* @param diagnostic - Diagnostic emitted by rule under test
|
||||
* @param error - Error object from test case
|
||||
* @param config - Config for this test case
|
||||
* @throws {AssertionError} If diagnostic's location does not match expected location
|
||||
*/
|
||||
function assertInvalidTestCaseLocationIsCorrect(diagnostic, error, test) {
|
||||
let actualLocation = {}, expectedLocation = {}, columnOffset = +(test.eslintCompat === !0);
|
||||
ObjectHasOwn(error, "line") && (actualLocation.line = diagnostic.line, expectedLocation.line = error.line), ObjectHasOwn(error, "column") && (actualLocation.column = diagnostic.column + columnOffset, expectedLocation.column = error.column);
|
||||
let canVoidEndLocation = test.eslintCompat === !0 && diagnostic.endLine === diagnostic.line && diagnostic.endColumn === diagnostic.column;
|
||||
ObjectHasOwn(error, "endLine") && (error.endLine === void 0 && canVoidEndLocation ? actualLocation.endLine = void 0 : actualLocation.endLine = diagnostic.endLine, expectedLocation.endLine = error.endLine), ObjectHasOwn(error, "endColumn") && (error.endColumn === void 0 && canVoidEndLocation ? actualLocation.endColumn = void 0 : actualLocation.endColumn = diagnostic.endColumn + columnOffset, expectedLocation.endColumn = error.endColumn), ObjectKeys(expectedLocation).length > 0 && assert.deepStrictEqual(actualLocation, expectedLocation, "Actual error location does not match expected error location.");
|
||||
}
|
||||
/**
|
||||
* Assert that suggestions reported by the rule under test match expected suggestions.
|
||||
* @param diagnostic - Diagnostic emitted by the rule under test
|
||||
* @param error - Error object from the test case
|
||||
* @param messages - Messages from the rule under test
|
||||
* @param test - Test case
|
||||
* @throws {AssertionError} If suggestions do not match
|
||||
*/
|
||||
function assertSuggestionsAreCorrect(diagnostic, error, messages, test) {
|
||||
let actualSuggestions = diagnostic.suggestions ?? [], expectedSuggestions = error.suggestions;
|
||||
assert.strictEqual(actualSuggestions.length, expectedSuggestions.length, `Error should have ${expectedSuggestions.length} suggestion${expectedSuggestions.length > 1 ? "s" : ""}. Instead found ${actualSuggestions.length} suggestion${actualSuggestions.length > 1 ? "s" : ""}.`);
|
||||
for (let i = 0; i < expectedSuggestions.length; i++) {
|
||||
let actual = actualSuggestions[i], expected = expectedSuggestions[i], prefix = `Suggestion at index ${i}`;
|
||||
assertSuggestionMessageIsCorrect(actual, expected, messages, prefix), assert(ObjectHasOwn(expected, "output"), `${prefix}: \`output\` property is required`);
|
||||
let suggestedCode = applyFixes(test.code, JSONStringify([actual.fixes]));
|
||||
assert(suggestedCode !== null, `${prefix}: Failed to apply suggestion fix`), assert.strictEqual(suggestedCode, expected.output, `${prefix}: Expected the applied suggestion fix to match the test suggestion output`), assert.notStrictEqual(expected.output, test.code, `${prefix}: The output of a suggestion should differ from the original source code`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Assert that a suggestion's message matches expectations.
|
||||
* @param actual - Actual suggestion from the diagnostic
|
||||
* @param expected - Expected suggestion from the test case
|
||||
* @param messages - Messages from the rule under test
|
||||
* @param prefix - Prefix for assertion error messages
|
||||
* @throws {AssertionError} If suggestion message does not match
|
||||
*/
|
||||
function assertSuggestionMessageIsCorrect(actual, expected, messages, prefix) {
|
||||
if (ObjectHasOwn(expected, "desc")) {
|
||||
assert(!ObjectHasOwn(expected, "messageId"), `${prefix}: Test should not specify both \`desc\` and \`messageId\``), assert(!ObjectHasOwn(expected, "data"), `${prefix}: Test should not specify both \`desc\` and \`data\``), assert.strictEqual(actual.message, expected.desc, `${prefix}: \`desc\` should be "${expected.desc}" but got "${actual.message}" instead`);
|
||||
return;
|
||||
}
|
||||
if (ObjectHasOwn(expected, "messageId")) {
|
||||
assertMessageIdIsCorrect(actual.messageId, actual.message, expected.messageId, expected.data, messages, `${prefix}: `);
|
||||
return;
|
||||
}
|
||||
ObjectHasOwn(expected, "data") && assert.fail(`${prefix}: Test must specify \`messageId\` if \`data\` is used`), assert.fail(`${prefix}: Test must specify either \`messageId\` or \`desc\``);
|
||||
}
|
||||
/**
|
||||
* Assert that the number of errors reported for test case is as expected.
|
||||
* @param diagnostics - Diagnostics reported by the rule under test
|
||||
* @param expectedErrorCount - Expected number of diagnistics
|
||||
* @throws {AssertionError} If the number of diagnostics is not as expected
|
||||
*/
|
||||
function assertErrorCountIsCorrect(diagnostics, expectedErrorCount) {
|
||||
diagnostics.length !== expectedErrorCount && assert.strictEqual(diagnostics.length, expectedErrorCount, util.format("Should have %s error%s but had %d: %s", expectedErrorCount === 0 ? "no" : expectedErrorCount, expectedErrorCount === 1 ? "" : "s", diagnostics.length, util.inspect(diagnostics)));
|
||||
}
|
||||
/**
|
||||
* Assert that message is matched by matcher.
|
||||
* Matcher can be a string or a regular expression.
|
||||
* @param message - Message
|
||||
* @param matcher - Matcher
|
||||
* @throws {AssertionError} If message does not match
|
||||
*/
|
||||
function assertMessageMatches(message, matcher) {
|
||||
typeof matcher == "string" ? assert.strictEqual(message, matcher) : assert(matcher.test(message), `Expected '${message}' to match ${matcher}`);
|
||||
}
|
||||
/**
|
||||
* Get placeholders in the reported messages but only includes the placeholders available in the raw message
|
||||
* and not in the provided data.
|
||||
* @param message - Reported message
|
||||
* @param raw - Raw message specified in the rule's `meta.messages`
|
||||
* @param data - Data from the test case's error object
|
||||
* @returns Missing placeholder names
|
||||
*/
|
||||
function getUnsubstitutedMessagePlaceholders(message, raw, data) {
|
||||
let unsubstituted = getMessagePlaceholders(message);
|
||||
if (unsubstituted.length === 0) return [];
|
||||
let known = getMessagePlaceholders(raw), provided = data === void 0 ? [] : ObjectKeys(data);
|
||||
return unsubstituted.filter((name) => known.includes(name) && !provided.includes(name));
|
||||
}
|
||||
/**
|
||||
* Extract names of `{{ name }}` placeholders from a message.
|
||||
* @param message - Message
|
||||
* @returns Array of placeholder names
|
||||
*/
|
||||
function getMessagePlaceholders(message) {
|
||||
return ArrayFrom(message.matchAll(PLACEHOLDER_REGEX), ([, name]) => name.trim());
|
||||
}
|
||||
/**
|
||||
* Create config for a test run.
|
||||
* Merges config from `RuleTester` instance on top of shared config.
|
||||
* Removes properties which are not allowed in `Config`s, as they can only be properties of `TestCase`.
|
||||
*
|
||||
* @param config - Config from `RuleTester` instance
|
||||
* @returns Merged config
|
||||
*/
|
||||
function createConfigForRun(config) {
|
||||
let merged = {};
|
||||
return addConfigPropsFrom(sharedConfig, merged), config !== null && addConfigPropsFrom(config, merged), merged;
|
||||
}
|
||||
function addConfigPropsFrom(config, merged) {
|
||||
for (let key of ObjectKeys(config)) TEST_CASE_PROP_KEYS.has(key) || (key === "languageOptions" ? merged.languageOptions = mergeLanguageOptions(config.languageOptions, merged.languageOptions) : merged[key] = config[key]);
|
||||
}
|
||||
/**
|
||||
* Create config for a test case.
|
||||
* Merges properties of test case on top of config from `RuleTester` instance.
|
||||
*
|
||||
* @param test - Test case
|
||||
* @param config - Config from `RuleTester` instance / shared config
|
||||
* @returns Merged config
|
||||
*/
|
||||
function mergeConfigIntoTestCase(test, config) {
|
||||
return {
|
||||
...config,
|
||||
...test,
|
||||
languageOptions: mergeLanguageOptions(test.languageOptions, config.languageOptions)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Merge language options from test case / config onto language options from base config.
|
||||
* @param localLanguageOptions - Language options from test case / config
|
||||
* @param baseLanguageOptions - Language options from base config
|
||||
* @returns Merged language options, or `undefined` if neither has language options
|
||||
*/
|
||||
function mergeLanguageOptions(localLanguageOptions, baseLanguageOptions) {
|
||||
return localLanguageOptions == null ? baseLanguageOptions ?? void 0 : baseLanguageOptions == null ? localLanguageOptions : {
|
||||
...baseLanguageOptions,
|
||||
...localLanguageOptions,
|
||||
parserOptions: mergeParserOptions(localLanguageOptions.parserOptions, baseLanguageOptions.parserOptions),
|
||||
globals: mergeGlobals(localLanguageOptions.globals, baseLanguageOptions.globals)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Merge parser options from test case / config onto language options from base config.
|
||||
* @param localParserOptions - Parser options from test case / config
|
||||
* @param baseParserOptions - Parser options from base config
|
||||
* @returns Merged parser options, or `undefined` if neither has parser options
|
||||
*/
|
||||
function mergeParserOptions(localParserOptions, baseParserOptions) {
|
||||
return localParserOptions == null ? baseParserOptions ?? void 0 : baseParserOptions == null ? localParserOptions : {
|
||||
...baseParserOptions,
|
||||
...localParserOptions,
|
||||
ecmaFeatures: mergeEcmaFeatures(localParserOptions.ecmaFeatures, baseParserOptions.ecmaFeatures)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Merge ecma features from test case / config onto ecma features from base config.
|
||||
* @param localEcmaFeatures - Ecma features from test case / config
|
||||
* @param baseEcmaFeatures - Ecma features from base config
|
||||
* @returns Merged ecma features, or `undefined` if neither has ecma features
|
||||
*/
|
||||
function mergeEcmaFeatures(localEcmaFeatures, baseEcmaFeatures) {
|
||||
return localEcmaFeatures == null ? baseEcmaFeatures ?? void 0 : baseEcmaFeatures == null ? localEcmaFeatures : {
|
||||
...baseEcmaFeatures,
|
||||
...localEcmaFeatures
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Merge globals from test case / config onto globals from base config.
|
||||
* @param localGlobals - Globals from test case / config
|
||||
* @param baseGlobals - Globals from base config
|
||||
* @returns Merged globals
|
||||
*/
|
||||
function mergeGlobals(localGlobals, baseGlobals) {
|
||||
return localGlobals == null ? baseGlobals ?? void 0 : baseGlobals == null ? localGlobals : {
|
||||
...baseGlobals,
|
||||
...localGlobals
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Lint a test case.
|
||||
* @param test - Test case
|
||||
* @param plugin - Plugin containing rule being tested
|
||||
* @returns Array of diagnostics
|
||||
*/
|
||||
function lint(test, plugin) {
|
||||
let parseOptions = getParseOptions(test), path, { filename, cwd } = test;
|
||||
if (filename != null && isAbsolute(filename)) cwd ??= dirname(filename), path = filename;
|
||||
else {
|
||||
if (filename == null) {
|
||||
let ext = parseOptions.lang;
|
||||
ext == null ? ext = "js" : ext === "dts" && (ext = "d.ts"), filename = `file.${ext}`;
|
||||
}
|
||||
cwd ??= DEFAULT_CWD, path = join(cwd, filename);
|
||||
}
|
||||
try {
|
||||
registerPlugin(plugin, null, !1, null);
|
||||
let optionsId = setupOptions(test, cwd);
|
||||
parse(path, test.code, parseOptions);
|
||||
let globalsJSON = getGlobalsJson(test), settingsJSON = JSONStringify(test.settings ?? {});
|
||||
lintFileImpl(path, 0, null, [0], [optionsId], settingsJSON, globalsJSON, null);
|
||||
let ruleId = `${plugin.meta.name}/${ObjectKeys(plugin.rules)[0]}`;
|
||||
return diagnostics.map((diagnostic) => {
|
||||
let line, column, endLine, endColumn;
|
||||
({line, column} = getLineColumnFromOffset(diagnostic.start)), {line: endLine, column: endColumn} = getLineColumnFromOffset(diagnostic.end);
|
||||
let node = getNodeByRangeIndex(diagnostic.start);
|
||||
return {
|
||||
ruleId,
|
||||
message: diagnostic.message,
|
||||
messageId: diagnostic.messageId,
|
||||
severity: 1,
|
||||
nodeType: node === null ? null : node.type,
|
||||
line,
|
||||
column,
|
||||
endLine,
|
||||
endColumn,
|
||||
fixes: diagnostic.fixes,
|
||||
suggestions: diagnostic.suggestions
|
||||
};
|
||||
});
|
||||
} finally {
|
||||
registeredRules.length = 0, allOptions !== null && (allOptions.length = 1), resetStateAfterError();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get parse options for a test case.
|
||||
* @param test - Test case
|
||||
* @returns Parse options
|
||||
*/
|
||||
function getParseOptions(test) {
|
||||
let parseOptions = {}, languageOptions = test.languageOptions;
|
||||
if (languageOptions ??= EMPTY_LANGUAGE_OPTIONS, languageOptions.parser != null) throw Error("Custom parsers are not supported");
|
||||
let { sourceType } = languageOptions;
|
||||
if (sourceType != null) {
|
||||
if (test.eslintCompat === !0 && sourceType === "unambiguous") throw Error("'unambiguous' source type is not supported in ESLint compatibility mode.\nDisable ESLint compatibility mode by setting `eslintCompat` to `false` in the config / test case.");
|
||||
parseOptions.sourceType = sourceType;
|
||||
} else test.eslintCompat === !0 && (parseOptions.sourceType = "module");
|
||||
let { parserOptions } = languageOptions;
|
||||
if (parserOptions != null && (parserOptions.ignoreNonFatalErrors === !0 && (parseOptions.ignoreNonFatalErrors = !0), test.filename == null)) {
|
||||
let { lang } = parserOptions;
|
||||
lang == null ? parserOptions.ecmaFeatures?.jsx === !0 && (parseOptions.lang = "jsx") : parseOptions.lang = lang;
|
||||
}
|
||||
return parseOptions;
|
||||
}
|
||||
/**
|
||||
* Get globals and envs as JSON for test case.
|
||||
*
|
||||
* Normalizes globals values to "readonly", "writable", or "off", same as Rust side does.
|
||||
* `null` is only supported in ESLint compatibility mode.
|
||||
*
|
||||
* Removes envs which are false, same as Rust side does.
|
||||
*
|
||||
* @param test - Test case
|
||||
* @returns Globals and envs as JSON string of form `{ "globals": { ... }, "envs": { ... } }`
|
||||
*/
|
||||
function getGlobalsJson(test) {
|
||||
let globals = { ...test.languageOptions?.globals }, eslintCompat = !!test.eslintCompat;
|
||||
for (let key in globals) {
|
||||
let value = globals[key];
|
||||
switch (value) {
|
||||
case "readonly":
|
||||
case "writable":
|
||||
case "off": continue;
|
||||
case "writeable":
|
||||
case "true":
|
||||
case !0:
|
||||
value = "writable";
|
||||
break;
|
||||
case "readable":
|
||||
case "false":
|
||||
case !1:
|
||||
value = "readonly";
|
||||
break;
|
||||
case null: if (eslintCompat) {
|
||||
value = "readonly";
|
||||
break;
|
||||
}
|
||||
default: throw Error(`'${value}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`);
|
||||
}
|
||||
globals[key] = value;
|
||||
}
|
||||
let originalEnvs = test.languageOptions?.env, envs = {};
|
||||
if (originalEnvs != null) for (let [key, value] of ObjectEntries(originalEnvs)) value !== !1 && ObjectDefineProperty(envs, key, {
|
||||
value: !0,
|
||||
writable: !0,
|
||||
enumerable: !0,
|
||||
configurable: !0
|
||||
});
|
||||
return JSONStringify({
|
||||
globals,
|
||||
envs
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Set up options for the test case.
|
||||
*
|
||||
* In linter, all options for all rules are sent over from Rust as a JSON string,
|
||||
* and `setOptions` is called to merge them with the default options for each rule.
|
||||
* The merged options are stored in a global variable `allOptions`.
|
||||
*
|
||||
* This function builds a JSON string in same format as Rust does, and calls `setOptions` with it.
|
||||
*
|
||||
* Returns the options ID to pass to `lintFileImpl` (either 0 for default options, or 1 for user-provided options).
|
||||
*
|
||||
* @param test - Test case
|
||||
* @param cwd - Current working directory for test case
|
||||
* @returns Options ID to pass to `lintFileImpl`
|
||||
*/
|
||||
function setupOptions(test, cwd) {
|
||||
let allOptions = [[]], allRuleIds = [0], optionsId = 0, testOptions = test.options;
|
||||
testOptions != null && (allOptions.push(testOptions), allRuleIds.push(0), optionsId = 1);
|
||||
let allOptionsJson;
|
||||
try {
|
||||
allOptionsJson = JSONStringify({
|
||||
options: allOptions,
|
||||
ruleIds: allRuleIds,
|
||||
cwd,
|
||||
workspaceUri: null
|
||||
});
|
||||
} catch (err) {
|
||||
throw Error(`Failed to serialize options: ${err}`);
|
||||
}
|
||||
return setOptions(allOptionsJson), optionsId;
|
||||
}
|
||||
const CONTROL_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/gu;
|
||||
/**
|
||||
* Get name of test case.
|
||||
* Control characters in name are replaced with `\u00xx` form.
|
||||
* @param test - Test case
|
||||
* @returns Name of test case
|
||||
*/
|
||||
function getTestName(test) {
|
||||
let name = test.name || test.code;
|
||||
return typeof name == "string" ? name.replace(CONTROL_CHAR_REGEX, (c) => `\\u${c.codePointAt(0).toString(16).padStart(4, "0")}`) : "";
|
||||
}
|
||||
/**
|
||||
* Runs before hook on the given test case.
|
||||
* @param test - Test to run the hook on
|
||||
* @throws {Error} - If the hook is not a function
|
||||
* @throws {*} - Value thrown by the hook function
|
||||
*/
|
||||
function runBeforeHook(test) {
|
||||
ObjectHasOwn(test, "before") && runHook(test, test.before, "before");
|
||||
}
|
||||
/**
|
||||
* Runs after hook on the given test case.
|
||||
* @param test - Test to run the hook on
|
||||
* @throws {Error} - If the hook is not a function
|
||||
* @throws {*} - Value thrown by the hook function
|
||||
*/
|
||||
function runAfterHook(test) {
|
||||
ObjectHasOwn(test, "after") && runHook(test, test.after, "after");
|
||||
}
|
||||
/**
|
||||
* Runs a hook on the given test case.
|
||||
* @param test - Test to run the hook on
|
||||
* @param hook - Hook function
|
||||
* @param name - Name of the hook
|
||||
* @throws {Error} - If the property is not a function
|
||||
* @throws {*} - Value thrown by the hook function
|
||||
*/
|
||||
function runHook(test, hook, name) {
|
||||
assert.strictEqual(typeof hook, "function", `Optional test case property \`${name}\` must be a function`), hook.call(test);
|
||||
}
|
||||
/**
|
||||
* Assert that a valid test case object is valid.
|
||||
* A valid test case must specify a string value for `code`.
|
||||
* Optional properties are checked for correct types.
|
||||
*
|
||||
* @param test - Valid test case object to check
|
||||
* @param seenTestCases - Set of serialized test cases to check for duplicates
|
||||
* @throws {AssertionError} If the test case is not valid
|
||||
*/
|
||||
function assertValidTestCaseIsWellFormed(test, seenTestCases) {
|
||||
assertTestCaseCommonPropertiesAreWellFormed(test), assert(!("errors" in test) || test.errors === void 0, "Valid test case must not have `errors` property"), assert(!("output" in test) || test.output === void 0, "Valid test case must not have `output` property"), assertNotDuplicateTestCase(test, seenTestCases);
|
||||
}
|
||||
/**
|
||||
* Assert that an invalid test case object is valid.
|
||||
* An invalid test case must specify a string value for `code` and must have an `errors` property.
|
||||
* Optional properties are checked for correct types.
|
||||
*
|
||||
* @param test - Invalid test case object to check
|
||||
* @param seenTestCases - Set of serialized test cases to check for duplicates
|
||||
* @param ruleName - Name of the rule being tested
|
||||
* @throws {AssertionError} If the test case is not valid
|
||||
*/
|
||||
function assertInvalidTestCaseIsWellFormed(test, seenTestCases, ruleName) {
|
||||
assertTestCaseCommonPropertiesAreWellFormed(test);
|
||||
let { errors } = test;
|
||||
typeof errors == "number" ? assert(errors > 0, "Invalid cases must have `errors` value greater than 0") : (assert(errors !== void 0, `Did not specify errors for an invalid test of rule \`${ruleName}\``), assert(ArrayIsArray(errors), `Invalid 'errors' property for invalid test of rule \`${ruleName}\`:expected a number or an array but got ${errors === null ? "null" : typeof errors}`), assert(errors.length !== 0, "Invalid cases must have at least one error")), ObjectHasOwn(test, "output") && assert(test.output === null || typeof test.output == "string", "Test property `output`, if specified, must be a string or null. If no autofix is expected, then omit the `output` property or set it to null."), assertNotDuplicateTestCase(test, seenTestCases);
|
||||
}
|
||||
/**
|
||||
* Assert that the common properties of a valid/invalid test case have the correct types.
|
||||
* @param {Object} test - Test case object to check
|
||||
* @throws {AssertionError} If the test case is not valid
|
||||
*/
|
||||
function assertTestCaseCommonPropertiesAreWellFormed(test) {
|
||||
assert(typeof test.code == "string", "Test case must specify a string value for `code`"), test.name && assert(typeof test.name == "string", "Optional test case property `name` must be a string"), ObjectHasOwn(test, "only") && assert(typeof test.only == "boolean", "Optional test case property `only` must be a boolean"), ObjectHasOwn(test, "filename") && assert(typeof test.filename == "string", "Optional test case property `filename` must be a string"), ObjectHasOwn(test, "options") && assert(ArrayIsArray(test.options), "Optional test case property `options` must be an array");
|
||||
}
|
||||
const DUPLICATION_IGNORED_PROPS = /* @__PURE__ */ new Set([
|
||||
"name",
|
||||
"errors",
|
||||
"output"
|
||||
]);
|
||||
/**
|
||||
* Assert that this test case is not a duplicate of one we have seen before.
|
||||
* @param test - Test case object
|
||||
* @param seenTestCases - Set of serialized test cases we have seen so far (managed by this function)
|
||||
* @throws {AssertionError} If the test case is a duplicate
|
||||
*/
|
||||
function assertNotDuplicateTestCase(test, seenTestCases) {
|
||||
if (!isSerializable(test)) return;
|
||||
let serializedTestCase = (0, import_json_stable_stringify_without_jsonify.default)(test, { replacer(key, value) {
|
||||
return test !== this || !DUPLICATION_IGNORED_PROPS.has(key) ? value : void 0;
|
||||
} });
|
||||
assert(!seenTestCases.has(serializedTestCase), "Detected duplicate test case"), seenTestCases.add(serializedTestCase);
|
||||
}
|
||||
/**
|
||||
* Check if a value is serializable.
|
||||
* Functions or objects like RegExp cannot be serialized by JSON.stringify().
|
||||
* Inspired by: https://stackoverflow.com/questions/30579940/reliable-way-to-check-if-objects-is-serializable-in-javascript
|
||||
* @param value - Value
|
||||
* @param seenObjects - Objects already seen in this path from the root object.
|
||||
* @returns {boolean} `true` if the value is serializable
|
||||
*/
|
||||
function isSerializable(value, seenObjects = /* @__PURE__ */ new Set()) {
|
||||
if (!isSerializablePrimitiveOrPlainObject(value)) return !1;
|
||||
if (typeof value != "object" || !value) return !0;
|
||||
if (seenObjects.has(value)) return !1;
|
||||
for (let property in value) {
|
||||
if (!ObjectHasOwn(value, property)) continue;
|
||||
let prop = value[property];
|
||||
if (!isSerializablePrimitiveOrPlainObject(prop) || !(typeof prop != "object" || !prop) && !isSerializable(prop, /* @__PURE__ */ new Set([...seenObjects, value]))) return !1;
|
||||
}
|
||||
return !0;
|
||||
}
|
||||
/**
|
||||
* Check if a value is a primitive or plain object created by the `Object` constructor.
|
||||
* @param value - Value to check
|
||||
* @returns `true` if `value` is a primitive or plain object
|
||||
*/
|
||||
function isSerializablePrimitiveOrPlainObject(value) {
|
||||
return value === null || typeof value == "string" || typeof value == "boolean" || typeof value == "number" || typeof value == "object" && (value.constructor === Object || ArrayIsArray(value));
|
||||
}
|
||||
//#endregion
|
||||
export { RuleTester };
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { a as loadPlugin, l as setOptions, n as lintFile } from "./lint.js";
|
||||
import { t as getErrorMessage } from "./utils.js";
|
||||
//#region src-js/plugins/config.ts
|
||||
/**
|
||||
* Populates Rust-resolved configuration options on the JS side.
|
||||
* Called from Rust side after all configuration options have been resolved.
|
||||
*
|
||||
* Note: the name `setupRuleConfigs` is currently incorrect, as we only populate rule options.
|
||||
* The intention is for this function to transfer all configurations in a multi-config workspace.
|
||||
* The configuration relevant to each file would then be resolved on the JS side.
|
||||
*
|
||||
* @param optionsJSON - Array of all rule options across all configurations, serialized as JSON
|
||||
* @returns `null` if success, or error message string
|
||||
*/
|
||||
function setupRuleConfigs(optionsJSON) {
|
||||
try {
|
||||
return setOptions(optionsJSON), null;
|
||||
} catch (err) {
|
||||
return getErrorMessage(err);
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
export { lintFile, loadPlugin, setupRuleConfigs };
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
//#region src-js/utils/utils.ts
|
||||
/**
|
||||
* Get error message from an error.
|
||||
*
|
||||
* `err` is expected to be an `Error` object, but can be anything.
|
||||
*
|
||||
* * If it's an `Error`, the error message and stack trace is returned.
|
||||
* * If it's another object with a string `message` property, `message` is returned.
|
||||
* * Otherwise, a generic "Unknown error" message is returned.
|
||||
*
|
||||
* This function will never throw, and always returns a non-empty string, even if:
|
||||
*
|
||||
* * `err` is `null` or `undefined`.
|
||||
* * `err` is an object with a getter for `message` property which throws.
|
||||
* * `err` has a getter for `stack` or `message` property which returns a different value each time it's accessed.
|
||||
*
|
||||
* @param err - Error
|
||||
* @returns Error message
|
||||
*/
|
||||
function getErrorMessage(err) {
|
||||
try {
|
||||
if (err instanceof Error) {
|
||||
let { stack } = err;
|
||||
if (typeof stack == "string" && stack !== "") return stack;
|
||||
}
|
||||
let { message } = err;
|
||||
if (typeof message == "string" && message !== "") return message;
|
||||
} catch {}
|
||||
return "Unknown error";
|
||||
}
|
||||
//#endregion
|
||||
export { getErrorMessage as t };
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
import { a as setCurrentWorkspace, i as destroyWorkspace, n as currentWorkspace, o as workspaces, r as currentWorkspaceUri, t as createWorkspace } from "./workspace2.js";
|
||||
export { createWorkspace, currentWorkspace, currentWorkspaceUri, destroyWorkspace, setCurrentWorkspace, workspaces };
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
//#region src-js/workspace/index.ts
|
||||
/**
|
||||
* Active workspaces.
|
||||
* Keyed by workspace URI.
|
||||
*/
|
||||
const workspaces = /* @__PURE__ */ new Map();
|
||||
/**
|
||||
* Most recent workspace that was used.
|
||||
*/
|
||||
let currentWorkspace = null, currentWorkspaceUri = null;
|
||||
/**
|
||||
* Create a new workspace.
|
||||
*/
|
||||
function createWorkspace(workspaceUri) {
|
||||
workspaces.set(workspaceUri, {
|
||||
cwd: "",
|
||||
allOptions: [],
|
||||
rules: []
|
||||
}), currentWorkspace = null, currentWorkspaceUri = null;
|
||||
}
|
||||
/**
|
||||
* Destroy a workspace.
|
||||
* Unloads all plugin data associated with this workspace.
|
||||
*/
|
||||
function destroyWorkspace(workspaceUri) {}
|
||||
/**
|
||||
* Set the current workspace.
|
||||
* @param workspace - Workspace object
|
||||
* @param workspaceUri - Workspace URI
|
||||
*/
|
||||
function setCurrentWorkspace(workspace, workspaceUri) {
|
||||
currentWorkspace = workspace, currentWorkspaceUri = workspaceUri;
|
||||
}
|
||||
//#endregion
|
||||
export { setCurrentWorkspace as a, destroyWorkspace as i, currentWorkspace as n, workspaces as o, currentWorkspaceUri as r, createWorkspace as t };
|
||||
Reference in New Issue
Block a user