corsa-oxlint 0.50.0 → 0.52.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/README.md CHANGED
@@ -24,6 +24,30 @@ The design goal is simple: performance-critical pieces live in Rust, `napi-rs`
24
24
  bridges them into Node, and end users still get to author custom plugins and
25
25
  custom rules in plain JS/TS.
26
26
 
27
+ ## Plugin-Owned Runtime Resolution
28
+
29
+ If a plugin ships its own `@typescript/native-preview` dependency, pass a
30
+ module anchor to `definePlugin()` so `corsa-oxlint` can resolve that runtime
31
+ even when package managers like pnpm do not hoist it to the consumer root.
32
+
33
+ ```ts
34
+ import { definePlugin } from "corsa-oxlint";
35
+
36
+ export default definePlugin({
37
+ meta: {
38
+ name: "example-plugin",
39
+ },
40
+ resolveFrom: import.meta.url,
41
+ rules: {
42
+ // ...
43
+ },
44
+ });
45
+ ```
46
+
47
+ Consumer overrides still win. `CORSA_EXECUTABLE`,
48
+ `parserOptions.corsa.executable`, and `settings.corsaOxlint` continue to take
49
+ priority over the plugin anchor.
50
+
27
51
  ## Configuration
28
52
 
29
53
  Oxlint does not expose arbitrary parser options at runtime, so
package/dist/context.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ContextWithParserOptions, ResolvedProjectConfig, TypeAwareParserOptions } from "./types.js";
2
2
 
3
3
  //#region src/bindings/nodejs/corsa_oxlint/ts/context.d.ts
4
- declare function defaultCorsaExecutable(rootDir: string, platform?: NodeJS.Platform): string;
4
+ declare function defaultCorsaExecutable(rootDir: string, platform?: NodeJS.Platform, resolveFrom?: string): string;
5
5
  declare function resolveProjectConfig(context: ContextWithParserOptions): ResolvedProjectConfig;
6
6
  /**
7
7
  * Resolves the type-aware parser options visible to a rule.
@@ -17,7 +17,7 @@ declare function resolveProjectConfig(context: ContextWithParserOptions): Resolv
17
17
  * parserOptions.corsa?.mode;
18
18
  * ```
19
19
  */
20
- declare function resolveTypeAwareParserOptions(context: ContextWithParserOptions, defaults?: TypeAwareParserOptionDefaults): TypeAwareParserOptions;
20
+ declare function resolveTypeAwareParserOptions(context: ContextWithParserOptions, defaults?: TypeAwareParserOptionDefaults, resolveFrom?: string): TypeAwareParserOptions;
21
21
  type TypeAwareParserOptionDefaults = {
22
22
  readonly corsa?: boolean;
23
23
  readonly projectService?: boolean;
package/dist/context.js CHANGED
@@ -14,12 +14,12 @@ const DEFAULT_TS_CONFIG = { compilerOptions: {
14
14
  target: "es2022",
15
15
  strict: true
16
16
  } };
17
- function defaultCorsaExecutable(rootDir, platform = process.platform) {
18
- const nativePreview = resolveNativePreviewExecutable(rootDir);
17
+ function defaultCorsaExecutable(rootDir, platform = process.platform, resolveFrom) {
18
+ const nativePreview = resolveNativePreviewExecutableFrom(resolve(rootDir, "package.json")) ?? (resolveFrom ? resolveNativePreviewExecutableFrom(resolveFrom) : void 0);
19
19
  if (nativePreview) return nativePreview;
20
20
  const fallback = resolve(rootDir, platform === "win32" ? ".cache/corsa.exe" : ".cache/corsa");
21
21
  if (existsSync(fallback)) return fallback;
22
- throw new Error(["corsa-oxlint could not locate a Corsa runtime executable.", "Install `@typescript/native-preview`, set `CORSA_EXECUTABLE`, or configure `parserOptions.corsa.executable`."].join(" "));
22
+ throw new Error(["corsa-oxlint could not locate a Corsa runtime executable.", "Install `@typescript/native-preview`, set `CORSA_EXECUTABLE`, configure `parserOptions.corsa.executable`, or pass `resolveFrom` to `definePlugin`."].join(" "));
23
23
  }
24
24
  function resolveProjectConfig(context) {
25
25
  const filename = resolve(context.filename);
@@ -49,9 +49,9 @@ function resolveProjectConfig(context) {
49
49
  * parserOptions.corsa?.mode;
50
50
  * ```
51
51
  */
52
- function resolveTypeAwareParserOptions(context, defaults = {}) {
52
+ function resolveTypeAwareParserOptions(context, defaults = {}, resolveFrom) {
53
53
  const parserOptions = mergeTypeAwareParserOptions(resolveSettingsParserOptions(context.settings?.corsaOxlint), mergeTypeAwareParserOptions(context.parserOptions, context.languageOptions?.parserOptions));
54
- return applyTypeAwareParserOptionDefaults(parserOptions, defaults, resolve(parserOptions.tsconfigRootDir ?? context.cwd));
54
+ return applyTypeAwareParserOptionDefaults(parserOptions, defaults, resolve(parserOptions.tsconfigRootDir ?? context.cwd), resolveFrom);
55
55
  }
56
56
  function resolveRuntimeOptions(rootDir, parserOptions) {
57
57
  const runtime = parserOptions.corsa;
@@ -104,8 +104,8 @@ function globMatch(value, pattern) {
104
104
  function asArray(value) {
105
105
  return value ? Array.isArray(value) ? value : [value] : [];
106
106
  }
107
- function resolveNativePreviewExecutable(rootDir) {
108
- const requireFromRoot = createRequire(resolve(rootDir, "package.json"));
107
+ function resolveNativePreviewExecutableFrom(anchor) {
108
+ const requireFromRoot = createRequire(anchor);
109
109
  const packageJsonPath = resolveOptional(requireFromRoot, "@typescript/native-preview/package.json");
110
110
  if (packageJsonPath) {
111
111
  const binPath = nativePreviewBinPath(packageJsonPath);
@@ -135,13 +135,13 @@ function resolveSettingsParserOptions(settings) {
135
135
  const { parserOptions, ...inline } = settings;
136
136
  return mergeTypeAwareParserOptions(inline, parserOptions);
137
137
  }
138
- function applyTypeAwareParserOptionDefaults(parserOptions, defaults, rootDir) {
138
+ function applyTypeAwareParserOptionDefaults(parserOptions, defaults, rootDir, resolveFrom) {
139
139
  let resolved = parserOptions;
140
140
  if (defaults.projectService === true && parserOptions.projectService === void 0 && parserOptions.project === void 0) resolved = {
141
141
  ...resolved,
142
142
  projectService: true
143
143
  };
144
- if (defaults.corsa === true && resolved.corsa?.executable === void 0) resolved = mergeTypeAwareParserOptions(resolved, { corsa: { executable: process.env.CORSA_EXECUTABLE ?? defaultCorsaExecutable(rootDir) } });
144
+ if (defaults.corsa === true && resolved.corsa?.executable === void 0) resolved = mergeTypeAwareParserOptions(resolved, { corsa: { executable: process.env.CORSA_EXECUTABLE ?? defaultCorsaExecutable(rootDir, void 0, resolveFrom) } });
145
145
  return resolved;
146
146
  }
147
147
  function mergeTypeAwareParserOptions(base, override) {
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../ts/context.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\n\nimport type {\n ContextWithParserOptions,\n CorsaOxlintSettings,\n ProjectServiceOptions,\n ResolvedProjectConfig,\n ResolvedRuntimeOptions,\n TypeAwareParserOptions,\n} from \"./types\";\n\nconst DEFAULT_CACHE_LIFETIME_MS = 250;\nconst DEFAULT_PROJECT_PATTERNS = [\"*.ts\", \"*.tsx\", \"*.js\", \"*.jsx\"];\nconst DEFAULT_TS_CONFIG = {\n compilerOptions: {\n module: \"esnext\",\n target: \"es2022\",\n strict: true,\n },\n};\n\nexport function defaultCorsaExecutable(rootDir: string, platform = process.platform): string {\n const nativePreview = resolveNativePreviewExecutable(rootDir);\n if (nativePreview) {\n return nativePreview;\n }\n const fallback = resolve(rootDir, platform === \"win32\" ? \".cache/corsa.exe\" : \".cache/corsa\");\n if (existsSync(fallback)) {\n return fallback;\n }\n throw new Error(\n [\n \"corsa-oxlint could not locate a Corsa runtime executable.\",\n \"Install `@typescript/native-preview`, set `CORSA_EXECUTABLE`, or configure `parserOptions.corsa.executable`.\",\n ].join(\" \"),\n );\n}\n\nexport function resolveProjectConfig(context: ContextWithParserOptions): ResolvedProjectConfig {\n const filename = resolve(context.filename);\n const parserOptions = resolveTypeAwareParserOptions(context);\n const rootDir = resolve(parserOptions.tsconfigRootDir ?? context.cwd);\n const runtime = resolveRuntimeOptions(rootDir, parserOptions);\n const configPath =\n resolveExplicitProject(rootDir, parserOptions) ??\n discoverTsconfig(filename, rootDir) ??\n resolveDefaultProject(rootDir, filename, parserOptions.projectService);\n if (!configPath) {\n throw new Error(`corsa oxlint could not resolve a tsconfig for ${filename}`);\n }\n return { filename, rootDir, configPath, runtime };\n}\n\n/**\n * Resolves the type-aware parser options visible to a rule.\n *\n * Oxlint exposes a fixed `context.languageOptions.parserOptions` object at\n * runtime, so `corsa oxlint` stores its richer configuration under\n * `settings.corsaOxlint` and rehydrates the rule-facing parser options\n * shape from there.\n *\n * @example\n * ```ts\n * const parserOptions = resolveTypeAwareParserOptions(context);\n * parserOptions.corsa?.mode;\n * ```\n */\nexport function resolveTypeAwareParserOptions(\n context: ContextWithParserOptions,\n defaults: TypeAwareParserOptionDefaults = {},\n): TypeAwareParserOptions {\n const parserOptions = mergeTypeAwareParserOptions(\n resolveSettingsParserOptions(context.settings?.corsaOxlint),\n mergeTypeAwareParserOptions(context.parserOptions, context.languageOptions?.parserOptions),\n );\n const rootDir = resolve(parserOptions.tsconfigRootDir ?? context.cwd);\n return applyTypeAwareParserOptionDefaults(parserOptions, defaults, rootDir);\n}\n\ntype TypeAwareParserOptionDefaults = {\n readonly corsa?: boolean;\n readonly projectService?: boolean;\n};\n\nfunction resolveRuntimeOptions(\n rootDir: string,\n parserOptions: TypeAwareParserOptions,\n): ResolvedRuntimeOptions {\n const runtime = parserOptions.corsa;\n return {\n executable: resolve(\n runtime?.executable ?? process.env.CORSA_EXECUTABLE ?? defaultCorsaExecutable(rootDir),\n ),\n cwd: resolve(runtime?.cwd ?? rootDir),\n mode: runtime?.mode ?? \"msgpack\",\n cacheLifetimeMs: runtime?.cacheLifetimeMs ?? DEFAULT_CACHE_LIFETIME_MS,\n };\n}\n\nfunction resolveExplicitProject(\n rootDir: string,\n parserOptions: TypeAwareParserOptions,\n): string | undefined {\n const projects = asArray(parserOptions.project).map((project) => {\n return resolve(rootDir, project);\n });\n return projects.find(existsSync);\n}\n\nfunction discoverTsconfig(filename: string, rootDir: string): string | undefined {\n let current = dirname(filename);\n const boundary = resolve(rootDir);\n while (current.startsWith(boundary)) {\n const candidate = resolve(current, \"tsconfig.json\");\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n return undefined;\n}\n\nfunction resolveDefaultProject(\n rootDir: string,\n filename: string,\n projectService: boolean | ProjectServiceOptions | undefined,\n): string | undefined {\n if (!projectService) {\n return undefined;\n }\n if (projectService !== true && projectService.defaultProject) {\n return resolve(rootDir, projectService.defaultProject);\n }\n if (!matchesDefaultProject(filename, projectService as true | ProjectServiceOptions)) {\n return undefined;\n }\n const id = Buffer.from(filename).toString(\"hex\").slice(0, 24);\n const cacheDir = resolve(rootDir, \".cache/corsa_oxlint/default\");\n const configPath = resolve(cacheDir, `${id}.tsconfig.json`);\n if (!existsSync(configPath)) {\n mkdirSync(cacheDir, { recursive: true });\n writeFileSync(\n configPath,\n JSON.stringify(\n {\n ...DEFAULT_TS_CONFIG,\n files: [filename],\n },\n null,\n 2,\n ),\n );\n }\n return configPath;\n}\n\nfunction matchesDefaultProject(\n filename: string,\n projectService: true | ProjectServiceOptions,\n): boolean {\n const patterns =\n (projectService === true ? undefined : projectService.allowDefaultProject) ??\n DEFAULT_PROJECT_PATTERNS;\n return patterns.some((pattern: string) => globMatch(filename, pattern));\n}\n\nfunction globMatch(value: string, pattern: string): boolean {\n const escaped = pattern.replaceAll(\".\", \"\\\\.\").replaceAll(\"*\", \".*\");\n return new RegExp(`${escaped}$`).test(value);\n}\n\nfunction asArray(value: string | string[] | undefined): string[] {\n return value ? (Array.isArray(value) ? value : [value]) : [];\n}\n\nfunction resolveNativePreviewExecutable(rootDir: string): string | undefined {\n const requireFromRoot = createRequire(resolve(rootDir, \"package.json\"));\n const packageJsonPath = resolveOptional(\n requireFromRoot,\n \"@typescript/native-preview/package.json\",\n );\n if (packageJsonPath) {\n const binPath = nativePreviewBinPath(packageJsonPath);\n if (binPath && existsSync(binPath)) {\n return binPath;\n }\n }\n const packageEntry = resolveOptional(requireFromRoot, \"@typescript/native-preview\");\n return packageEntry && existsSync(packageEntry) ? packageEntry : undefined;\n}\n\nfunction resolveOptional(requireFromRoot: NodeJS.Require, specifier: string): string | undefined {\n try {\n return requireFromRoot.resolve(specifier);\n } catch {\n return undefined;\n }\n}\n\nfunction nativePreviewBinPath(packageJsonPath: string): string | undefined {\n try {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as {\n readonly bin?: string | Record<string, string>;\n };\n const bin =\n typeof packageJson.bin === \"string\"\n ? packageJson.bin\n : (packageJson.bin?.tsgo ?? Object.values(packageJson.bin ?? {})[0]);\n return bin ? resolve(dirname(packageJsonPath), bin) : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveSettingsParserOptions(\n settings: CorsaOxlintSettings | undefined,\n): TypeAwareParserOptions {\n if (!settings) {\n return {};\n }\n const { parserOptions, ...inline } = settings;\n return mergeTypeAwareParserOptions(inline, parserOptions);\n}\n\nfunction applyTypeAwareParserOptionDefaults(\n parserOptions: TypeAwareParserOptions,\n defaults: TypeAwareParserOptionDefaults,\n rootDir: string,\n): TypeAwareParserOptions {\n let resolved = parserOptions;\n if (\n defaults.projectService === true &&\n parserOptions.projectService === undefined &&\n parserOptions.project === undefined\n ) {\n resolved = {\n ...resolved,\n projectService: true,\n };\n }\n if (defaults.corsa === true && resolved.corsa?.executable === undefined) {\n resolved = mergeTypeAwareParserOptions(resolved, {\n corsa: {\n executable: process.env.CORSA_EXECUTABLE ?? defaultCorsaExecutable(rootDir),\n },\n });\n }\n return resolved;\n}\n\nexport function mergeTypeAwareParserOptions(\n base: TypeAwareParserOptions | undefined,\n override: TypeAwareParserOptions | undefined,\n): TypeAwareParserOptions {\n if (!base) {\n return normalizeTypeAwareParserOptions(override ?? {});\n }\n if (!override) {\n return normalizeTypeAwareParserOptions(base);\n }\n const runtime = {\n ...base.corsa,\n ...override.corsa,\n };\n return {\n ...base,\n ...override,\n project: override.project ?? base.project,\n projectService: mergeProjectService(base.projectService, override.projectService),\n tsconfigRootDir: override.tsconfigRootDir ?? base.tsconfigRootDir,\n ...(Object.keys(runtime).length > 0 ? { corsa: runtime } : {}),\n };\n}\n\nfunction normalizeTypeAwareParserOptions(options: TypeAwareParserOptions): TypeAwareParserOptions {\n const runtime = options.corsa;\n if (!runtime) {\n return options;\n }\n return {\n ...options,\n corsa: runtime,\n };\n}\n\nfunction mergeProjectService(\n base: boolean | ProjectServiceOptions | undefined,\n override: boolean | ProjectServiceOptions | undefined,\n): boolean | ProjectServiceOptions | undefined {\n if (override === undefined) {\n return base;\n }\n if (typeof override === \"boolean\") {\n return override;\n }\n if (base === undefined || typeof base === \"boolean\") {\n return override;\n }\n return {\n ...base,\n ...override,\n allowDefaultProject: override.allowDefaultProject ?? base.allowDefaultProject,\n defaultProject: override.defaultProject ?? base.defaultProject,\n };\n}\n"],"mappings":";;;;AAaA,MAAM,4BAA4B;AAClC,MAAM,2BAA2B;CAAC;CAAQ;CAAS;CAAQ;AAAO;AAClE,MAAM,oBAAoB,EACxB,iBAAiB;CACf,QAAQ;CACR,QAAQ;CACR,QAAQ;AACV,EACF;AAEA,SAAgB,uBAAuB,SAAiB,WAAW,QAAQ,UAAkB;CAC3F,MAAM,gBAAgB,+BAA+B,OAAO;CAC5D,IAAI,eACF,OAAO;CAET,MAAM,WAAW,QAAQ,SAAS,aAAa,UAAU,qBAAqB,cAAc;CAC5F,IAAI,WAAW,QAAQ,GACrB,OAAO;CAET,MAAM,IAAI,MACR,CACE,6DACA,8GACF,EAAE,KAAK,GAAG,CACZ;AACF;AAEA,SAAgB,qBAAqB,SAA0D;CAC7F,MAAM,WAAW,QAAQ,QAAQ,QAAQ;CACzC,MAAM,gBAAgB,8BAA8B,OAAO;CAC3D,MAAM,UAAU,QAAQ,cAAc,mBAAmB,QAAQ,GAAG;CACpE,MAAM,UAAU,sBAAsB,SAAS,aAAa;CAC5D,MAAM,aACJ,uBAAuB,SAAS,aAAa,KAC7C,iBAAiB,UAAU,OAAO,KAClC,sBAAsB,SAAS,UAAU,cAAc,cAAc;CACvE,IAAI,CAAC,YACH,MAAM,IAAI,MAAM,iDAAiD,UAAU;CAE7E,OAAO;EAAE;EAAU;EAAS;EAAY;CAAQ;AAClD;;;;;;;;;;;;;;;AAgBA,SAAgB,8BACd,SACA,WAA0C,CAAC,GACnB;CACxB,MAAM,gBAAgB,4BACpB,6BAA6B,QAAQ,UAAU,WAAW,GAC1D,4BAA4B,QAAQ,eAAe,QAAQ,iBAAiB,aAAa,CAC3F;CAEA,OAAO,mCAAmC,eAAe,UADzC,QAAQ,cAAc,mBAAmB,QAAQ,GACQ,CAAC;AAC5E;AAOA,SAAS,sBACP,SACA,eACwB;CACxB,MAAM,UAAU,cAAc;CAC9B,OAAO;EACL,YAAY,QACV,SAAS,cAAc,QAAQ,IAAI,oBAAoB,uBAAuB,OAAO,CACvF;EACA,KAAK,QAAQ,SAAS,OAAO,OAAO;EACpC,MAAM,SAAS,QAAQ;EACvB,iBAAiB,SAAS,mBAAmB;CAC/C;AACF;AAEA,SAAS,uBACP,SACA,eACoB;CAIpB,OAHiB,QAAQ,cAAc,OAAO,EAAE,KAAK,YAAY;EAC/D,OAAO,QAAQ,SAAS,OAAO;CACjC,CACc,EAAE,KAAK,UAAU;AACjC;AAEA,SAAS,iBAAiB,UAAkB,SAAqC;CAC/E,IAAI,UAAU,QAAQ,QAAQ;CAC9B,MAAM,WAAW,QAAQ,OAAO;CAChC,OAAO,QAAQ,WAAW,QAAQ,GAAG;EACnC,MAAM,YAAY,QAAQ,SAAS,eAAe;EAClD,IAAI,WAAW,SAAS,GACtB,OAAO;EAET,MAAM,SAAS,QAAQ,OAAO;EAC9B,IAAI,WAAW,SACb;EAEF,UAAU;CACZ;AAEF;AAEA,SAAS,sBACP,SACA,UACA,gBACoB;CACpB,IAAI,CAAC,gBACH;CAEF,IAAI,mBAAmB,QAAQ,eAAe,gBAC5C,OAAO,QAAQ,SAAS,eAAe,cAAc;CAEvD,IAAI,CAAC,sBAAsB,UAAU,cAA8C,GACjF;CAEF,MAAM,KAAK,OAAO,KAAK,QAAQ,EAAE,SAAS,KAAK,EAAE,MAAM,GAAG,EAAE;CAC5D,MAAM,WAAW,QAAQ,SAAS,6BAA6B;CAC/D,MAAM,aAAa,QAAQ,UAAU,GAAG,GAAG,eAAe;CAC1D,IAAI,CAAC,WAAW,UAAU,GAAG;EAC3B,UAAU,UAAU,EAAE,WAAW,KAAK,CAAC;EACvC,cACE,YACA,KAAK,UACH;GACE,GAAG;GACH,OAAO,CAAC,QAAQ;EAClB,GACA,MACA,CACF,CACF;CACF;CACA,OAAO;AACT;AAEA,SAAS,sBACP,UACA,gBACS;CAIT,SAFG,mBAAmB,OAAO,KAAA,IAAY,eAAe,wBACtD,0BACc,MAAM,YAAoB,UAAU,UAAU,OAAO,CAAC;AACxE;AAEA,SAAS,UAAU,OAAe,SAA0B;CAC1D,MAAM,UAAU,QAAQ,WAAW,KAAK,KAAK,EAAE,WAAW,KAAK,IAAI;CACnE,OAAO,IAAI,OAAO,GAAG,QAAQ,EAAE,EAAE,KAAK,KAAK;AAC7C;AAEA,SAAS,QAAQ,OAAgD;CAC/D,OAAO,QAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,IAAK,CAAC;AAC7D;AAEA,SAAS,+BAA+B,SAAqC;CAC3E,MAAM,kBAAkB,cAAc,QAAQ,SAAS,cAAc,CAAC;CACtE,MAAM,kBAAkB,gBACtB,iBACA,yCACF;CACA,IAAI,iBAAiB;EACnB,MAAM,UAAU,qBAAqB,eAAe;EACpD,IAAI,WAAW,WAAW,OAAO,GAC/B,OAAO;CAEX;CACA,MAAM,eAAe,gBAAgB,iBAAiB,4BAA4B;CAClF,OAAO,gBAAgB,WAAW,YAAY,IAAI,eAAe,KAAA;AACnE;AAEA,SAAS,gBAAgB,iBAAiC,WAAuC;CAC/F,IAAI;EACF,OAAO,gBAAgB,QAAQ,SAAS;CAC1C,QAAQ;EACN;CACF;AACF;AAEA,SAAS,qBAAqB,iBAA6C;CACzE,IAAI;EACF,MAAM,cAAc,KAAK,MAAM,aAAa,iBAAiB,MAAM,CAAC;EAGpE,MAAM,MACJ,OAAO,YAAY,QAAQ,WACvB,YAAY,MACX,YAAY,KAAK,QAAQ,OAAO,OAAO,YAAY,OAAO,CAAC,CAAC,EAAE;EACrE,OAAO,MAAM,QAAQ,QAAQ,eAAe,GAAG,GAAG,IAAI,KAAA;CACxD,QAAQ;EACN;CACF;AACF;AAEA,SAAS,6BACP,UACwB;CACxB,IAAI,CAAC,UACH,OAAO,CAAC;CAEV,MAAM,EAAE,eAAe,GAAG,WAAW;CACrC,OAAO,4BAA4B,QAAQ,aAAa;AAC1D;AAEA,SAAS,mCACP,eACA,UACA,SACwB;CACxB,IAAI,WAAW;CACf,IACE,SAAS,mBAAmB,QAC5B,cAAc,mBAAmB,KAAA,KACjC,cAAc,YAAY,KAAA,GAE1B,WAAW;EACT,GAAG;EACH,gBAAgB;CAClB;CAEF,IAAI,SAAS,UAAU,QAAQ,SAAS,OAAO,eAAe,KAAA,GAC5D,WAAW,4BAA4B,UAAU,EAC/C,OAAO,EACL,YAAY,QAAQ,IAAI,oBAAoB,uBAAuB,OAAO,EAC5E,EACF,CAAC;CAEH,OAAO;AACT;AAEA,SAAgB,4BACd,MACA,UACwB;CACxB,IAAI,CAAC,MACH,OAAO,gCAAgC,YAAY,CAAC,CAAC;CAEvD,IAAI,CAAC,UACH,OAAO,gCAAgC,IAAI;CAE7C,MAAM,UAAU;EACd,GAAG,KAAK;EACR,GAAG,SAAS;CACd;CACA,OAAO;EACL,GAAG;EACH,GAAG;EACH,SAAS,SAAS,WAAW,KAAK;EAClC,gBAAgB,oBAAoB,KAAK,gBAAgB,SAAS,cAAc;EAChF,iBAAiB,SAAS,mBAAmB,KAAK;EAClD,GAAI,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,EAAE,OAAO,QAAQ,IAAI,CAAC;CAC9D;AACF;AAEA,SAAS,gCAAgC,SAAyD;CAChG,MAAM,UAAU,QAAQ;CACxB,IAAI,CAAC,SACH,OAAO;CAET,OAAO;EACL,GAAG;EACH,OAAO;CACT;AACF;AAEA,SAAS,oBACP,MACA,UAC6C;CAC7C,IAAI,aAAa,KAAA,GACf,OAAO;CAET,IAAI,OAAO,aAAa,WACtB,OAAO;CAET,IAAI,SAAS,KAAA,KAAa,OAAO,SAAS,WACxC,OAAO;CAET,OAAO;EACL,GAAG;EACH,GAAG;EACH,qBAAqB,SAAS,uBAAuB,KAAK;EAC1D,gBAAgB,SAAS,kBAAkB,KAAK;CAClD;AACF"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../ts/context.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\n\nimport type {\n ContextWithParserOptions,\n CorsaOxlintSettings,\n ProjectServiceOptions,\n ResolvedProjectConfig,\n ResolvedRuntimeOptions,\n TypeAwareParserOptions,\n} from \"./types\";\n\nconst DEFAULT_CACHE_LIFETIME_MS = 250;\nconst DEFAULT_PROJECT_PATTERNS = [\"*.ts\", \"*.tsx\", \"*.js\", \"*.jsx\"];\nconst DEFAULT_TS_CONFIG = {\n compilerOptions: {\n module: \"esnext\",\n target: \"es2022\",\n strict: true,\n },\n};\n\nexport function defaultCorsaExecutable(\n rootDir: string,\n platform = process.platform,\n resolveFrom?: string,\n): string {\n const nativePreview =\n resolveNativePreviewExecutableFrom(resolve(rootDir, \"package.json\")) ??\n (resolveFrom ? resolveNativePreviewExecutableFrom(resolveFrom) : undefined);\n if (nativePreview) {\n return nativePreview;\n }\n const fallback = resolve(rootDir, platform === \"win32\" ? \".cache/corsa.exe\" : \".cache/corsa\");\n if (existsSync(fallback)) {\n return fallback;\n }\n throw new Error(\n [\n \"corsa-oxlint could not locate a Corsa runtime executable.\",\n \"Install `@typescript/native-preview`, set `CORSA_EXECUTABLE`, configure `parserOptions.corsa.executable`, or pass `resolveFrom` to `definePlugin`.\",\n ].join(\" \"),\n );\n}\n\nexport function resolveProjectConfig(context: ContextWithParserOptions): ResolvedProjectConfig {\n const filename = resolve(context.filename);\n const parserOptions = resolveTypeAwareParserOptions(context);\n const rootDir = resolve(parserOptions.tsconfigRootDir ?? context.cwd);\n const runtime = resolveRuntimeOptions(rootDir, parserOptions);\n const configPath =\n resolveExplicitProject(rootDir, parserOptions) ??\n discoverTsconfig(filename, rootDir) ??\n resolveDefaultProject(rootDir, filename, parserOptions.projectService);\n if (!configPath) {\n throw new Error(`corsa oxlint could not resolve a tsconfig for ${filename}`);\n }\n return { filename, rootDir, configPath, runtime };\n}\n\n/**\n * Resolves the type-aware parser options visible to a rule.\n *\n * Oxlint exposes a fixed `context.languageOptions.parserOptions` object at\n * runtime, so `corsa oxlint` stores its richer configuration under\n * `settings.corsaOxlint` and rehydrates the rule-facing parser options\n * shape from there.\n *\n * @example\n * ```ts\n * const parserOptions = resolveTypeAwareParserOptions(context);\n * parserOptions.corsa?.mode;\n * ```\n */\nexport function resolveTypeAwareParserOptions(\n context: ContextWithParserOptions,\n defaults: TypeAwareParserOptionDefaults = {},\n resolveFrom?: string,\n): TypeAwareParserOptions {\n const parserOptions = mergeTypeAwareParserOptions(\n resolveSettingsParserOptions(context.settings?.corsaOxlint),\n mergeTypeAwareParserOptions(context.parserOptions, context.languageOptions?.parserOptions),\n );\n const rootDir = resolve(parserOptions.tsconfigRootDir ?? context.cwd);\n return applyTypeAwareParserOptionDefaults(parserOptions, defaults, rootDir, resolveFrom);\n}\n\ntype TypeAwareParserOptionDefaults = {\n readonly corsa?: boolean;\n readonly projectService?: boolean;\n};\n\nfunction resolveRuntimeOptions(\n rootDir: string,\n parserOptions: TypeAwareParserOptions,\n): ResolvedRuntimeOptions {\n const runtime = parserOptions.corsa;\n return {\n executable: resolve(\n runtime?.executable ?? process.env.CORSA_EXECUTABLE ?? defaultCorsaExecutable(rootDir),\n ),\n cwd: resolve(runtime?.cwd ?? rootDir),\n mode: runtime?.mode ?? \"msgpack\",\n cacheLifetimeMs: runtime?.cacheLifetimeMs ?? DEFAULT_CACHE_LIFETIME_MS,\n };\n}\n\nfunction resolveExplicitProject(\n rootDir: string,\n parserOptions: TypeAwareParserOptions,\n): string | undefined {\n const projects = asArray(parserOptions.project).map((project) => {\n return resolve(rootDir, project);\n });\n return projects.find(existsSync);\n}\n\nfunction discoverTsconfig(filename: string, rootDir: string): string | undefined {\n let current = dirname(filename);\n const boundary = resolve(rootDir);\n while (current.startsWith(boundary)) {\n const candidate = resolve(current, \"tsconfig.json\");\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n return undefined;\n}\n\nfunction resolveDefaultProject(\n rootDir: string,\n filename: string,\n projectService: boolean | ProjectServiceOptions | undefined,\n): string | undefined {\n if (!projectService) {\n return undefined;\n }\n if (projectService !== true && projectService.defaultProject) {\n return resolve(rootDir, projectService.defaultProject);\n }\n if (!matchesDefaultProject(filename, projectService as true | ProjectServiceOptions)) {\n return undefined;\n }\n const id = Buffer.from(filename).toString(\"hex\").slice(0, 24);\n const cacheDir = resolve(rootDir, \".cache/corsa_oxlint/default\");\n const configPath = resolve(cacheDir, `${id}.tsconfig.json`);\n if (!existsSync(configPath)) {\n mkdirSync(cacheDir, { recursive: true });\n writeFileSync(\n configPath,\n JSON.stringify(\n {\n ...DEFAULT_TS_CONFIG,\n files: [filename],\n },\n null,\n 2,\n ),\n );\n }\n return configPath;\n}\n\nfunction matchesDefaultProject(\n filename: string,\n projectService: true | ProjectServiceOptions,\n): boolean {\n const patterns =\n (projectService === true ? undefined : projectService.allowDefaultProject) ??\n DEFAULT_PROJECT_PATTERNS;\n return patterns.some((pattern: string) => globMatch(filename, pattern));\n}\n\nfunction globMatch(value: string, pattern: string): boolean {\n const escaped = pattern.replaceAll(\".\", \"\\\\.\").replaceAll(\"*\", \".*\");\n return new RegExp(`${escaped}$`).test(value);\n}\n\nfunction asArray(value: string | string[] | undefined): string[] {\n return value ? (Array.isArray(value) ? value : [value]) : [];\n}\n\nfunction resolveNativePreviewExecutableFrom(anchor: string): string | undefined {\n const requireFromRoot = createRequire(anchor);\n const packageJsonPath = resolveOptional(\n requireFromRoot,\n \"@typescript/native-preview/package.json\",\n );\n if (packageJsonPath) {\n const binPath = nativePreviewBinPath(packageJsonPath);\n if (binPath && existsSync(binPath)) {\n return binPath;\n }\n }\n const packageEntry = resolveOptional(requireFromRoot, \"@typescript/native-preview\");\n return packageEntry && existsSync(packageEntry) ? packageEntry : undefined;\n}\n\nfunction resolveOptional(requireFromRoot: NodeJS.Require, specifier: string): string | undefined {\n try {\n return requireFromRoot.resolve(specifier);\n } catch {\n return undefined;\n }\n}\n\nfunction nativePreviewBinPath(packageJsonPath: string): string | undefined {\n try {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as {\n readonly bin?: string | Record<string, string>;\n };\n const bin =\n typeof packageJson.bin === \"string\"\n ? packageJson.bin\n : (packageJson.bin?.tsgo ?? Object.values(packageJson.bin ?? {})[0]);\n return bin ? resolve(dirname(packageJsonPath), bin) : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveSettingsParserOptions(\n settings: CorsaOxlintSettings | undefined,\n): TypeAwareParserOptions {\n if (!settings) {\n return {};\n }\n const { parserOptions, ...inline } = settings;\n return mergeTypeAwareParserOptions(inline, parserOptions);\n}\n\nfunction applyTypeAwareParserOptionDefaults(\n parserOptions: TypeAwareParserOptions,\n defaults: TypeAwareParserOptionDefaults,\n rootDir: string,\n resolveFrom?: string,\n): TypeAwareParserOptions {\n let resolved = parserOptions;\n if (\n defaults.projectService === true &&\n parserOptions.projectService === undefined &&\n parserOptions.project === undefined\n ) {\n resolved = {\n ...resolved,\n projectService: true,\n };\n }\n if (defaults.corsa === true && resolved.corsa?.executable === undefined) {\n resolved = mergeTypeAwareParserOptions(resolved, {\n corsa: {\n executable:\n process.env.CORSA_EXECUTABLE ?? defaultCorsaExecutable(rootDir, undefined, resolveFrom),\n },\n });\n }\n return resolved;\n}\n\nexport function mergeTypeAwareParserOptions(\n base: TypeAwareParserOptions | undefined,\n override: TypeAwareParserOptions | undefined,\n): TypeAwareParserOptions {\n if (!base) {\n return normalizeTypeAwareParserOptions(override ?? {});\n }\n if (!override) {\n return normalizeTypeAwareParserOptions(base);\n }\n const runtime = {\n ...base.corsa,\n ...override.corsa,\n };\n return {\n ...base,\n ...override,\n project: override.project ?? base.project,\n projectService: mergeProjectService(base.projectService, override.projectService),\n tsconfigRootDir: override.tsconfigRootDir ?? base.tsconfigRootDir,\n ...(Object.keys(runtime).length > 0 ? { corsa: runtime } : {}),\n };\n}\n\nfunction normalizeTypeAwareParserOptions(options: TypeAwareParserOptions): TypeAwareParserOptions {\n const runtime = options.corsa;\n if (!runtime) {\n return options;\n }\n return {\n ...options,\n corsa: runtime,\n };\n}\n\nfunction mergeProjectService(\n base: boolean | ProjectServiceOptions | undefined,\n override: boolean | ProjectServiceOptions | undefined,\n): boolean | ProjectServiceOptions | undefined {\n if (override === undefined) {\n return base;\n }\n if (typeof override === \"boolean\") {\n return override;\n }\n if (base === undefined || typeof base === \"boolean\") {\n return override;\n }\n return {\n ...base,\n ...override,\n allowDefaultProject: override.allowDefaultProject ?? base.allowDefaultProject,\n defaultProject: override.defaultProject ?? base.defaultProject,\n };\n}\n"],"mappings":"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"}
package/dist/plugin.d.ts CHANGED
@@ -5,6 +5,11 @@ import { Diagnostic, Plugin as Plugin$1, Rule as Rule$1, RuleMeta } from "@oxlin
5
5
 
6
6
  //#region src/bindings/nodejs/corsa_oxlint/ts/plugin.d.ts
7
7
  type Plugin = Omit<Plugin$1, "rules"> & {
8
+ /**
9
+ * Optional module URL or absolute path used to resolve the plugin's own
10
+ * runtime dependencies when they are not visible from the consumer root.
11
+ */
12
+ readonly resolveFrom?: string;
8
13
  readonly rules: Record<string, Rule>;
9
14
  } & Record<string, unknown>;
10
15
  type Rule = Rule$1 & Record<string, unknown>;
@@ -67,7 +72,7 @@ declare function definePlugin(plugin: Plugin): Plugin;
67
72
  */
68
73
  declare function defineRule<MessageId extends string = string, const Options extends readonly unknown[] = readonly unknown[]>(rule: RuleDefinition<MessageId, Options>): Rule;
69
74
  declare function compatPlugin(plugin: Plugin): Plugin;
70
- declare function decorateRule(rule: Rule): Rule;
75
+ declare function decorateRule(rule: Rule, resolveFrom?: string): Rule;
71
76
  //#endregion
72
77
  export { Plugin, Rule, RuleContext, RuleDefinition, RuleDiagnostic, RuleDocs, RuleMetaWithMessages, Visitor, VisitorWithHooks, compatPlugin, decorateRule, definePlugin, defineRule };
73
78
  //# sourceMappingURL=plugin.d.ts.map
package/dist/plugin.js CHANGED
@@ -6,10 +6,15 @@ const defineOxlintPlugin = oxlintPluginApi.definePlugin;
6
6
  const defineOxlintRule = oxlintPluginApi.defineRule;
7
7
  const baseCompatPlugin = Reflect.get(oxlintPluginApi, ["es", "lintCompatPlugin"].join(""));
8
8
  function definePlugin(plugin) {
9
- return defineOxlintPlugin({
9
+ const defined = defineOxlintPlugin({
10
10
  ...plugin,
11
- rules: wrapRules(plugin.rules ?? {})
11
+ rules: wrapRules(plugin.rules ?? {}, plugin.resolveFrom)
12
12
  });
13
+ if (plugin.resolveFrom === void 0) return defined;
14
+ return {
15
+ ...defined,
16
+ resolveFrom: plugin.resolveFrom
17
+ };
13
18
  }
14
19
  function defineRule(rule) {
15
20
  return defineOxlintRule(decorateRule(rule));
@@ -17,30 +22,30 @@ function defineRule(rule) {
17
22
  function compatPlugin(plugin) {
18
23
  return baseCompatPlugin(definePlugin(plugin));
19
24
  }
20
- function decorateRule(rule) {
25
+ function decorateRule(rule, resolveFrom) {
21
26
  if (rule.create) return {
22
27
  ...rule,
23
28
  create(context) {
24
- return rule.create(decorateContext(context, rule));
29
+ return rule.create(decorateContext(context, rule, resolveFrom));
25
30
  }
26
31
  };
27
32
  if ("createOnce" in rule && typeof rule.createOnce === "function") return {
28
33
  ...rule,
29
34
  createOnce(context) {
30
- return rule.createOnce(decorateContext(context, rule));
35
+ return rule.createOnce(decorateContext(context, rule, resolveFrom));
31
36
  }
32
37
  };
33
38
  return rule;
34
39
  }
35
- function wrapRules(rules) {
36
- return Object.fromEntries(Object.entries(rules).map(([name, rule]) => [name, decorateRule(rule)]));
40
+ function wrapRules(rules, resolveFrom) {
41
+ return Object.fromEntries(Object.entries(rules).map(([name, rule]) => [name, decorateRule(rule, resolveFrom)]));
37
42
  }
38
- function decorateContext(context, rule) {
43
+ function decorateContext(context, rule, resolveFrom) {
39
44
  const typeAware = requiresTypeChecking(rule);
40
45
  const parserOptions = Object.freeze(resolveTypeAwareParserOptions(context, {
41
46
  corsa: typeAware,
42
47
  projectService: typeAware
43
- }));
48
+ }, resolveFrom));
44
49
  const baseLanguageOptions = context.languageOptions;
45
50
  const languageOptions = Object.freeze({
46
51
  ...baseLanguageOptions,
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","names":[],"sources":["../ts/plugin.ts"],"sourcesContent":["import * as oxlintPluginApi from \"@oxlint/plugins\";\nimport type {\n Context as OxlintContext,\n Diagnostic,\n Plugin as OxlintPlugin,\n Rule as OxlintRule,\n RuleMeta as OxlintRuleMeta,\n} from \"@oxlint/plugins\";\n\nimport { AST_NODE_TYPES } from \"./compat\";\nimport { resolveTypeAwareParserOptions } from \"./context\";\nimport type { ESTree as PublicESTree } from \"./index\";\nimport { getParserServices } from \"./parser_services\";\nimport type { ContextWithParserOptions, ParserServices } from \"./types\";\n\nexport type Plugin = Omit<OxlintPlugin, \"rules\"> & {\n readonly rules: Record<string, Rule>;\n} & Record<string, unknown>;\nexport type Rule = OxlintRule & Record<string, unknown>;\nexport type RuleDiagnostic<MessageId extends string = string> = Diagnostic & {\n readonly messageId?: MessageId | null | undefined;\n};\nexport type RuleContext<\n MessageId extends string = string,\n Options extends readonly unknown[] = readonly unknown[],\n> = Omit<ContextWithParserOptions, \"options\" | \"report\"> & {\n readonly options: Readonly<Options>;\n report(this: void, diagnostic: RuleDiagnostic<MessageId>): void;\n};\nexport type RuleDocs = {\n readonly description?: string;\n readonly recommended?: unknown;\n readonly url?: string;\n /**\n * Enables corsa-oxlint's type-aware parser service defaults for this rule.\n *\n * @default false\n */\n readonly requiresTypeChecking?: boolean;\n};\nexport type RuleMetaWithMessages<MessageId extends string = string> = Omit<\n OxlintRuleMeta,\n \"docs\" | \"messages\"\n> & {\n readonly docs?: RuleDocs;\n readonly messages?: Record<MessageId, string>;\n};\ntype CorsaAstNodeType = keyof typeof AST_NODE_TYPES;\ntype BivariantVisitorHandler<Handler extends (...args: any[]) => any> = {\n bivarianceHack(...args: Parameters<Handler>): ReturnType<Handler>;\n}[\"bivarianceHack\"];\ntype VisitorNode<Kind extends CorsaAstNodeType> = PublicESTree[Kind];\n\nexport type Visitor = {\n [Kind in CorsaAstNodeType]?: BivariantVisitorHandler<(node: VisitorNode<Kind>) => void>;\n} & {\n [Kind in CorsaAstNodeType as `${Kind}:exit`]?: BivariantVisitorHandler<\n (node: VisitorNode<Kind>) => void\n >;\n} & Record<string, BivariantVisitorHandler<(node: PublicESTree.Node) => void> | undefined>;\n\nexport type VisitorWithHooks = Visitor & {\n readonly before?: () => boolean | void;\n readonly after?: () => void;\n};\nexport type RuleDefinition<\n MessageId extends string = string,\n Options extends readonly unknown[] = readonly unknown[],\n> = Record<string, unknown> & {\n readonly defaultOptions?: Options;\n readonly meta?: RuleMetaWithMessages<MessageId>;\n} & (\n | {\n readonly create: (context: RuleContext<MessageId, Options>) => Visitor;\n readonly createOnce?: never;\n }\n | {\n readonly create?: (context: RuleContext<MessageId, Options>) => Visitor;\n readonly createOnce: (context: RuleContext<MessageId, Options>) => VisitorWithHooks;\n }\n );\n\nconst defineOxlintPlugin = oxlintPluginApi.definePlugin;\nconst defineOxlintRule = oxlintPluginApi.defineRule;\nconst baseCompatPlugin = Reflect.get(\n oxlintPluginApi as object,\n [\"es\", \"lintCompatPlugin\"].join(\"\"),\n) as typeof oxlintPluginApi.definePlugin;\n\nexport function definePlugin(plugin: Plugin): Plugin {\n return defineOxlintPlugin({\n ...plugin,\n rules: wrapRules(plugin.rules ?? {}),\n } as OxlintPlugin) as Plugin;\n}\n\n/**\n * Defines a single Oxlint rule with type-aware parser services.\n *\n * @example\n * ```ts\n * export default defineRule({\n * meta: { schema: [], messages: { demo: \"demo\" } },\n * create(context) {\n * const services = context.parserServices;\n * return {};\n * },\n * });\n * ```\n */\nexport function defineRule<\n MessageId extends string = string,\n const Options extends readonly unknown[] = readonly unknown[],\n>(rule: RuleDefinition<MessageId, Options>): Rule;\nexport function defineRule(rule: RuleDefinition): Rule {\n return defineOxlintRule(decorateRule(rule as unknown as Rule) as OxlintRule) as Rule;\n}\n\nexport function compatPlugin(plugin: Plugin): Plugin {\n return baseCompatPlugin(definePlugin(plugin)) as Plugin;\n}\n\nexport function decorateRule(rule: Rule): Rule {\n if (rule.create) {\n return {\n ...rule,\n create(context) {\n return rule.create!(decorateContext(context, rule));\n },\n } as Rule;\n }\n if (\"createOnce\" in rule && typeof (rule as any).createOnce === \"function\") {\n return {\n ...rule,\n createOnce(context) {\n return (rule as any).createOnce(decorateContext(context, rule));\n },\n } as Rule;\n }\n return rule;\n}\n\nfunction wrapRules(rules: Record<string, Rule>): Record<string, Rule> {\n return Object.fromEntries(\n Object.entries(rules).map(([name, rule]) => [name, decorateRule(rule)]),\n );\n}\n\nfunction decorateContext(context: ContextWithParserOptions, rule: Rule): ContextWithParserOptions {\n const typeAware = requiresTypeChecking(rule);\n const parserOptions = Object.freeze(\n resolveTypeAwareParserOptions(context, {\n corsa: typeAware,\n projectService: typeAware,\n }),\n );\n const baseLanguageOptions = context.languageOptions;\n const languageOptions = Object.freeze({\n ...baseLanguageOptions,\n parserOptions,\n });\n return Object.create(context as OxlintContext, {\n languageOptions: {\n configurable: true,\n enumerable: true,\n get() {\n return languageOptions;\n },\n },\n parserOptions: {\n configurable: true,\n enumerable: false,\n get() {\n return parserOptions;\n },\n },\n parserServices: {\n configurable: true,\n enumerable: false,\n get(): ParserServices {\n return getParserServices(context);\n },\n },\n }) as ContextWithParserOptions;\n}\n\nfunction requiresTypeChecking(rule: Rule): boolean {\n return (\n (rule.meta as { readonly docs?: { readonly requiresTypeChecking?: unknown } } | undefined)?.docs\n ?.requiresTypeChecking === true\n );\n}\n"],"mappings":";;;;AAkFA,MAAM,qBAAqB,gBAAgB;AAC3C,MAAM,mBAAmB,gBAAgB;AACzC,MAAM,mBAAmB,QAAQ,IAC/B,iBACA,CAAC,MAAM,kBAAkB,EAAE,KAAK,EAAE,CACpC;AAEA,SAAgB,aAAa,QAAwB;CACnD,OAAO,mBAAmB;EACxB,GAAG;EACH,OAAO,UAAU,OAAO,SAAS,CAAC,CAAC;CACrC,CAAiB;AACnB;AAoBA,SAAgB,WAAW,MAA4B;CACrD,OAAO,iBAAiB,aAAa,IAAuB,CAAe;AAC7E;AAEA,SAAgB,aAAa,QAAwB;CACnD,OAAO,iBAAiB,aAAa,MAAM,CAAC;AAC9C;AAEA,SAAgB,aAAa,MAAkB;CAC7C,IAAI,KAAK,QACP,OAAO;EACL,GAAG;EACH,OAAO,SAAS;GACd,OAAO,KAAK,OAAQ,gBAAgB,SAAS,IAAI,CAAC;EACpD;CACF;CAEF,IAAI,gBAAgB,QAAQ,OAAQ,KAAa,eAAe,YAC9D,OAAO;EACL,GAAG;EACH,WAAW,SAAS;GAClB,OAAQ,KAAa,WAAW,gBAAgB,SAAS,IAAI,CAAC;EAChE;CACF;CAEF,OAAO;AACT;AAEA,SAAS,UAAU,OAAmD;CACpE,OAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,EAAE,KAAK,CAAC,MAAM,UAAU,CAAC,MAAM,aAAa,IAAI,CAAC,CAAC,CACxE;AACF;AAEA,SAAS,gBAAgB,SAAmC,MAAsC;CAChG,MAAM,YAAY,qBAAqB,IAAI;CAC3C,MAAM,gBAAgB,OAAO,OAC3B,8BAA8B,SAAS;EACrC,OAAO;EACP,gBAAgB;CAClB,CAAC,CACH;CACA,MAAM,sBAAsB,QAAQ;CACpC,MAAM,kBAAkB,OAAO,OAAO;EACpC,GAAG;EACH;CACF,CAAC;CACD,OAAO,OAAO,OAAO,SAA0B;EAC7C,iBAAiB;GACf,cAAc;GACd,YAAY;GACZ,MAAM;IACJ,OAAO;GACT;EACF;EACA,eAAe;GACb,cAAc;GACd,YAAY;GACZ,MAAM;IACJ,OAAO;GACT;EACF;EACA,gBAAgB;GACd,cAAc;GACd,YAAY;GACZ,MAAsB;IACpB,OAAO,kBAAkB,OAAO;GAClC;EACF;CACF,CAAC;AACH;AAEA,SAAS,qBAAqB,MAAqB;CACjD,OACG,KAAK,MAAsF,MACxF,yBAAyB;AAEjC"}
1
+ {"version":3,"file":"plugin.js","names":[],"sources":["../ts/plugin.ts"],"sourcesContent":["import * as oxlintPluginApi from \"@oxlint/plugins\";\nimport type {\n Context as OxlintContext,\n Diagnostic,\n Plugin as OxlintPlugin,\n Rule as OxlintRule,\n RuleMeta as OxlintRuleMeta,\n} from \"@oxlint/plugins\";\n\nimport { AST_NODE_TYPES } from \"./compat\";\nimport { resolveTypeAwareParserOptions } from \"./context\";\nimport type { ESTree as PublicESTree } from \"./index\";\nimport { getParserServices } from \"./parser_services\";\nimport type { ContextWithParserOptions, ParserServices } from \"./types\";\n\nexport type Plugin = Omit<OxlintPlugin, \"rules\"> & {\n /**\n * Optional module URL or absolute path used to resolve the plugin's own\n * runtime dependencies when they are not visible from the consumer root.\n */\n readonly resolveFrom?: string;\n readonly rules: Record<string, Rule>;\n} & Record<string, unknown>;\nexport type Rule = OxlintRule & Record<string, unknown>;\nexport type RuleDiagnostic<MessageId extends string = string> = Diagnostic & {\n readonly messageId?: MessageId | null | undefined;\n};\nexport type RuleContext<\n MessageId extends string = string,\n Options extends readonly unknown[] = readonly unknown[],\n> = Omit<ContextWithParserOptions, \"options\" | \"report\"> & {\n readonly options: Readonly<Options>;\n report(this: void, diagnostic: RuleDiagnostic<MessageId>): void;\n};\nexport type RuleDocs = {\n readonly description?: string;\n readonly recommended?: unknown;\n readonly url?: string;\n /**\n * Enables corsa-oxlint's type-aware parser service defaults for this rule.\n *\n * @default false\n */\n readonly requiresTypeChecking?: boolean;\n};\nexport type RuleMetaWithMessages<MessageId extends string = string> = Omit<\n OxlintRuleMeta,\n \"docs\" | \"messages\"\n> & {\n readonly docs?: RuleDocs;\n readonly messages?: Record<MessageId, string>;\n};\ntype CorsaAstNodeType = keyof typeof AST_NODE_TYPES;\ntype BivariantVisitorHandler<Handler extends (...args: any[]) => any> = {\n bivarianceHack(...args: Parameters<Handler>): ReturnType<Handler>;\n}[\"bivarianceHack\"];\ntype VisitorNode<Kind extends CorsaAstNodeType> = PublicESTree[Kind];\n\nexport type Visitor = {\n [Kind in CorsaAstNodeType]?: BivariantVisitorHandler<(node: VisitorNode<Kind>) => void>;\n} & {\n [Kind in CorsaAstNodeType as `${Kind}:exit`]?: BivariantVisitorHandler<\n (node: VisitorNode<Kind>) => void\n >;\n} & Record<string, BivariantVisitorHandler<(node: PublicESTree.Node) => void> | undefined>;\n\nexport type VisitorWithHooks = Visitor & {\n readonly before?: () => boolean | void;\n readonly after?: () => void;\n};\nexport type RuleDefinition<\n MessageId extends string = string,\n Options extends readonly unknown[] = readonly unknown[],\n> = Record<string, unknown> & {\n readonly defaultOptions?: Options;\n readonly meta?: RuleMetaWithMessages<MessageId>;\n} & (\n | {\n readonly create: (context: RuleContext<MessageId, Options>) => Visitor;\n readonly createOnce?: never;\n }\n | {\n readonly create?: (context: RuleContext<MessageId, Options>) => Visitor;\n readonly createOnce: (context: RuleContext<MessageId, Options>) => VisitorWithHooks;\n }\n );\n\nconst defineOxlintPlugin = oxlintPluginApi.definePlugin;\nconst defineOxlintRule = oxlintPluginApi.defineRule;\nconst baseCompatPlugin = Reflect.get(\n oxlintPluginApi as object,\n [\"es\", \"lintCompatPlugin\"].join(\"\"),\n) as typeof oxlintPluginApi.definePlugin;\n\nexport function definePlugin(plugin: Plugin): Plugin {\n const defined = defineOxlintPlugin({\n ...plugin,\n rules: wrapRules(plugin.rules ?? {}, plugin.resolveFrom),\n } as OxlintPlugin) as Plugin;\n if (plugin.resolveFrom === undefined) {\n return defined;\n }\n return {\n ...defined,\n resolveFrom: plugin.resolveFrom,\n };\n}\n\n/**\n * Defines a single Oxlint rule with type-aware parser services.\n *\n * @example\n * ```ts\n * export default defineRule({\n * meta: { schema: [], messages: { demo: \"demo\" } },\n * create(context) {\n * const services = context.parserServices;\n * return {};\n * },\n * });\n * ```\n */\nexport function defineRule<\n MessageId extends string = string,\n const Options extends readonly unknown[] = readonly unknown[],\n>(rule: RuleDefinition<MessageId, Options>): Rule;\nexport function defineRule(rule: RuleDefinition): Rule {\n return defineOxlintRule(decorateRule(rule as unknown as Rule) as OxlintRule) as Rule;\n}\n\nexport function compatPlugin(plugin: Plugin): Plugin {\n return baseCompatPlugin(definePlugin(plugin)) as Plugin;\n}\n\nexport function decorateRule(rule: Rule, resolveFrom?: string): Rule {\n if (rule.create) {\n return {\n ...rule,\n create(context) {\n return rule.create!(decorateContext(context, rule, resolveFrom));\n },\n } as Rule;\n }\n if (\"createOnce\" in rule && typeof (rule as any).createOnce === \"function\") {\n return {\n ...rule,\n createOnce(context) {\n return (rule as any).createOnce(decorateContext(context, rule, resolveFrom));\n },\n } as Rule;\n }\n return rule;\n}\n\nfunction wrapRules(rules: Record<string, Rule>, resolveFrom?: string): Record<string, Rule> {\n return Object.fromEntries(\n Object.entries(rules).map(([name, rule]) => [name, decorateRule(rule, resolveFrom)]),\n );\n}\n\nfunction decorateContext(\n context: ContextWithParserOptions,\n rule: Rule,\n resolveFrom?: string,\n): ContextWithParserOptions {\n const typeAware = requiresTypeChecking(rule);\n const parserOptions = Object.freeze(\n resolveTypeAwareParserOptions(\n context,\n {\n corsa: typeAware,\n projectService: typeAware,\n },\n resolveFrom,\n ),\n );\n const baseLanguageOptions = context.languageOptions;\n const languageOptions = Object.freeze({\n ...baseLanguageOptions,\n parserOptions,\n });\n return Object.create(context as OxlintContext, {\n languageOptions: {\n configurable: true,\n enumerable: true,\n get() {\n return languageOptions;\n },\n },\n parserOptions: {\n configurable: true,\n enumerable: false,\n get() {\n return parserOptions;\n },\n },\n parserServices: {\n configurable: true,\n enumerable: false,\n get(): ParserServices {\n return getParserServices(context);\n },\n },\n }) as ContextWithParserOptions;\n}\n\nfunction requiresTypeChecking(rule: Rule): boolean {\n return (\n (rule.meta as { readonly docs?: { readonly requiresTypeChecking?: unknown } } | undefined)?.docs\n ?.requiresTypeChecking === true\n );\n}\n"],"mappings":";;;;AAuFA,MAAM,qBAAqB,gBAAgB;AAC3C,MAAM,mBAAmB,gBAAgB;AACzC,MAAM,mBAAmB,QAAQ,IAC/B,iBACA,CAAC,MAAM,kBAAkB,EAAE,KAAK,EAAE,CACpC;AAEA,SAAgB,aAAa,QAAwB;CACnD,MAAM,UAAU,mBAAmB;EACjC,GAAG;EACH,OAAO,UAAU,OAAO,SAAS,CAAC,GAAG,OAAO,WAAW;CACzD,CAAiB;CACjB,IAAI,OAAO,gBAAgB,KAAA,GACzB,OAAO;CAET,OAAO;EACL,GAAG;EACH,aAAa,OAAO;CACtB;AACF;AAoBA,SAAgB,WAAW,MAA4B;CACrD,OAAO,iBAAiB,aAAa,IAAuB,CAAe;AAC7E;AAEA,SAAgB,aAAa,QAAwB;CACnD,OAAO,iBAAiB,aAAa,MAAM,CAAC;AAC9C;AAEA,SAAgB,aAAa,MAAY,aAA4B;CACnE,IAAI,KAAK,QACP,OAAO;EACL,GAAG;EACH,OAAO,SAAS;GACd,OAAO,KAAK,OAAQ,gBAAgB,SAAS,MAAM,WAAW,CAAC;EACjE;CACF;CAEF,IAAI,gBAAgB,QAAQ,OAAQ,KAAa,eAAe,YAC9D,OAAO;EACL,GAAG;EACH,WAAW,SAAS;GAClB,OAAQ,KAAa,WAAW,gBAAgB,SAAS,MAAM,WAAW,CAAC;EAC7E;CACF;CAEF,OAAO;AACT;AAEA,SAAS,UAAU,OAA6B,aAA4C;CAC1F,OAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,EAAE,KAAK,CAAC,MAAM,UAAU,CAAC,MAAM,aAAa,MAAM,WAAW,CAAC,CAAC,CACrF;AACF;AAEA,SAAS,gBACP,SACA,MACA,aAC0B;CAC1B,MAAM,YAAY,qBAAqB,IAAI;CAC3C,MAAM,gBAAgB,OAAO,OAC3B,8BACE,SACA;EACE,OAAO;EACP,gBAAgB;CAClB,GACA,WACF,CACF;CACA,MAAM,sBAAsB,QAAQ;CACpC,MAAM,kBAAkB,OAAO,OAAO;EACpC,GAAG;EACH;CACF,CAAC;CACD,OAAO,OAAO,OAAO,SAA0B;EAC7C,iBAAiB;GACf,cAAc;GACd,YAAY;GACZ,MAAM;IACJ,OAAO;GACT;EACF;EACA,eAAe;GACb,cAAc;GACd,YAAY;GACZ,MAAM;IACJ,OAAO;GACT;EACF;EACA,gBAAgB;GACd,cAAc;GACd,YAAY;GACZ,MAAsB;IACpB,OAAO,kBAAkB,OAAO;GAClC;EACF;CACF,CAAC;AACH;AAEA,SAAS,qBAAqB,MAAqB;CACjD,OACG,KAAK,MAAsF,MACxF,yBAAyB;AAEjC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "corsa-oxlint",
3
- "version": "0.50.0",
3
+ "version": "0.52.0",
4
4
  "description": "Type-aware Oxlint helpers powered by Corsa",
5
5
  "homepage": "https://github.com/ubugeeei-prod/corsa-bind/tree/main/src/bindings/nodejs/corsa_oxlint",
6
6
  "bugs": {
@@ -101,7 +101,7 @@
101
101
  "./package.json": "./package.json"
102
102
  },
103
103
  "dependencies": {
104
- "@corsa-bind/napi": "0.50.0"
104
+ "@corsa-bind/napi": "0.52.0"
105
105
  },
106
106
  "devDependencies": {
107
107
  "@oxlint/plugins": "1.69.0",