@isentinel/eslint-config 6.0.0-beta.10 → 6.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -14179,6 +14179,7 @@ const oxlintRuleMapping = {
14179
14179
  "dot-notation": "js-plugin",
14180
14180
  "id-length": "js-plugin",
14181
14181
  "no-dupe-args": "js-plugin",
14182
+ "no-loop-func": "js-plugin",
14182
14183
  "no-octal": "js-plugin",
14183
14184
  "no-octal-escape": "js-plugin",
14184
14185
  "no-restricted-syntax": "js-plugin",
package/dist/oxlint.mjs CHANGED
@@ -7,8 +7,8 @@ import path from "node:path";
7
7
  import process from "node:process";
8
8
  import "prettier";
9
9
  import { minVersion } from "semver";
10
- import globals from "globals";
11
10
  import { pathToFileURL } from "node:url";
11
+ import globals from "globals";
12
12
  //#region src/rules/oxlint-mapping.ts
13
13
  /**
14
14
  * Notable rule families that intentionally stay in ESLint in hybrid mode,
@@ -148,6 +148,7 @@ const oxlintRuleMapping = {
148
148
  "dot-notation": "js-plugin",
149
149
  "id-length": "js-plugin",
150
150
  "no-dupe-args": "js-plugin",
151
+ "no-loop-func": "js-plugin",
151
152
  "no-octal": "js-plugin",
152
153
  "no-octal-escape": "js-plugin",
153
154
  "no-restricted-syntax": "js-plugin",
@@ -1409,6 +1410,24 @@ const NATIVE_PLUGINS = /* @__PURE__ */ new Set([
1409
1410
  "vue"
1410
1411
  ]);
1411
1412
  /**
1413
+ * Anchor for resolving a plugin from the consumer project, used when a plugin
1414
+ * is a peer dependency the consumer installs rather than one we depend on.
1415
+ */
1416
+ const consumerAnchor = pathToFileURL(`${process.cwd()}/`).href;
1417
+ const specifierCache = /* @__PURE__ */ new Map();
1418
+ /**
1419
+ * Resolve a jsPlugin specifier, throwing when the package is not installed.
1420
+ *
1421
+ * @param specifier - The plugin package specifier.
1422
+ * @returns The absolute `file://` specifier.
1423
+ * @throws {Error} When the package cannot be resolved.
1424
+ */
1425
+ function resolveJsPluginSpecifier(specifier) {
1426
+ const resolved = tryResolveJsPlugin(specifier);
1427
+ if (resolved === void 0) throw new Error(`[@isentinel/eslint-config] Cannot resolve oxlint jsPlugin "${specifier}". Install it in your project, or disable the rules that require it.`);
1428
+ return resolved;
1429
+ }
1430
+ /**
1412
1431
  * Split a canonical (ESLint-named) rule map into oxlint-native rules and
1413
1432
  * jsPlugin rules, translating rule names via the oxlint rule mapping.
1414
1433
  *
@@ -1445,7 +1464,7 @@ function splitOxlintRules(rules, keepUnmappedOff = false) {
1445
1464
  nativePlugins.add(prefix);
1446
1465
  } else {
1447
1466
  const specifier = oxlintJsPlugins[prefix];
1448
- if (specifier !== void 0 && isPackageExists(specifier)) {
1467
+ if (specifier !== void 0 && canResolveJsPlugin(specifier)) {
1449
1468
  jsPluginRules[translated] = value;
1450
1469
  jsPluginPrefixes.add(prefix);
1451
1470
  }
@@ -1470,7 +1489,7 @@ function splitOxlintRules(rules, keepUnmappedOff = false) {
1470
1489
  if (specifier === void 0) throw new Error(`[@isentinel/eslint-config] Unknown oxlint jsPlugin prefix: ${prefix}`);
1471
1490
  jsPlugins.push({
1472
1491
  name: prefix,
1473
- specifier
1492
+ specifier: resolveJsPluginSpecifier(specifier)
1474
1493
  });
1475
1494
  }
1476
1495
  return {
@@ -1510,6 +1529,49 @@ function createOxlintConfigs({ name, excludeFiles, files, globals, keepUnmappedO
1510
1529
  });
1511
1530
  return fragments;
1512
1531
  }
1532
+ /**
1533
+ * Resolve a specifier against an optional anchor, swallowing resolution errors.
1534
+ *
1535
+ * @param specifier - The plugin package specifier.
1536
+ * @param anchor - The URL to resolve against, or the current module by default.
1537
+ * @returns The resolved URL, or `undefined` when it does not resolve.
1538
+ */
1539
+ function resolveFrom(specifier, anchor) {
1540
+ try {
1541
+ return import.meta.resolve(specifier, anchor);
1542
+ } catch {
1543
+ return;
1544
+ }
1545
+ }
1546
+ /**
1547
+ * Resolve a jsPlugin package specifier to an absolute `file://` URL.
1548
+ *
1549
+ * Oxlint resolves bare `jsPlugins` specifiers relative to the consumer's config
1550
+ * file, which fails under pnpm's isolated node_modules: our plugin dependencies
1551
+ * only exist inside our own virtual store scope, never at the consumer's root.
1552
+ * Resolving here (from our package first, then the consumer) and emitting an
1553
+ * absolute specifier makes loading independent of the consumer's layout.
1554
+ *
1555
+ * @param specifier - The plugin package specifier.
1556
+ * @returns The resolved specifier, or `undefined` when it resolves nowhere.
1557
+ */
1558
+ function tryResolveJsPlugin(specifier) {
1559
+ const cached = specifierCache.get(specifier);
1560
+ if (cached !== void 0 || specifierCache.has(specifier)) return cached;
1561
+ const resolved = resolveFrom(specifier) ?? resolveFrom(specifier, consumerAnchor);
1562
+ specifierCache.set(specifier, resolved);
1563
+ return resolved;
1564
+ }
1565
+ /**
1566
+ * Whether a jsPlugin package can be resolved from either our package or the
1567
+ * consumer project.
1568
+ *
1569
+ * @param specifier - The plugin package specifier.
1570
+ * @returns Whether the plugin is resolvable.
1571
+ */
1572
+ function canResolveJsPlugin(specifier) {
1573
+ return tryResolveJsPlugin(specifier) !== void 0;
1574
+ }
1513
1575
  function mappedTarget(rule) {
1514
1576
  return oxlintRuleMapping[rule] === "js-plugin" ? "js-plugin" : "native";
1515
1577
  }
@@ -1522,7 +1584,7 @@ function oxlintComments({ prettierOptions = {}, stylistic = true } = {}) {
1522
1584
  files: [GLOB_SRC],
1523
1585
  jsPlugins: [{
1524
1586
  name: "oxlint-comments",
1525
- specifier: "oxlint-plugin-oxlint-comments"
1587
+ specifier: resolveJsPluginSpecifier("oxlint-plugin-oxlint-comments")
1526
1588
  }],
1527
1589
  rules: {
1528
1590
  "oxlint-comments/disable-enable-pair": ["error", { allowWholeFile: true }],
@@ -1609,7 +1671,7 @@ function oxlintDisables({ root }) {
1609
1671
  files: [GLOB_DTS],
1610
1672
  jsPlugins: [{
1611
1673
  name: "oxlint-comments",
1612
- specifier: "oxlint-plugin-oxlint-comments"
1674
+ specifier: resolveJsPluginSpecifier("oxlint-plugin-oxlint-comments")
1613
1675
  }],
1614
1676
  rules: { "oxlint-comments/no-unlimited-disable": "off" }
1615
1677
  },
@@ -2361,11 +2423,11 @@ function oxlintOxfmt(options) {
2361
2423
  }
2362
2424
  if (!jsPlugins.some((plugin) => typeof plugin !== "string" && plugin.name === "style")) jsPlugins.push({
2363
2425
  name: "style",
2364
- specifier: "@stylistic/eslint-plugin"
2426
+ specifier: resolveJsPluginSpecifier("@stylistic/eslint-plugin")
2365
2427
  });
2366
2428
  const oxfmtPlugin = {
2367
2429
  name: "oxfmt",
2368
- specifier: "eslint-plugin-oxfmt"
2430
+ specifier: resolveJsPluginSpecifier("eslint-plugin-oxfmt")
2369
2431
  };
2370
2432
  const jsFiles = oxfmtFiles?.flat() ?? ["**/*.{,c,m}js", "**/*.{,c,m}jsx"];
2371
2433
  const tsFiles = oxfmtFiles?.flat() ?? [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isentinel/eslint-config",
3
- "version": "6.0.0-beta.10",
3
+ "version": "6.0.0-beta.11",
4
4
  "description": "iSentinel's ESLint config",
5
5
  "keywords": [
6
6
  "eslint-config",
@@ -133,7 +133,7 @@
133
133
  "typescript": "6.0.3",
134
134
  "unplugin-unused": "0.5.7",
135
135
  "vitest": "4.1.10",
136
- "@isentinel/eslint-config": "6.0.0-beta.10"
136
+ "@isentinel/eslint-config": "6.0.0-beta.11"
137
137
  },
138
138
  "peerDependencies": {
139
139
  "@vitest/eslint-plugin": "^1.6.4",