@alint-js/core 0.7.1 → 0.7.3

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.d.mts CHANGED
@@ -203,6 +203,15 @@ interface RunOptions {
203
203
  * Defaults to `true`. Pass `false` for runs that target partial subsets of a project.
204
204
  */
205
205
  projectTargets?: boolean;
206
+ /**
207
+ * Only run rules whose configured id (`plugin/rule`) or own name (`rule`) matches one of these
208
+ * glob patterns. Everything else stays unplanned, so a filtered run neither calls its model nor
209
+ * reports its diagnostics.
210
+ *
211
+ * A filter that matches no enabled rule fails the run, because a silent empty run is
212
+ * indistinguishable from a clean one. Pass the patterns you typed on the command line.
213
+ */
214
+ ruleFilter?: readonly string[];
206
215
  runner?: RunnerOptions;
207
216
  setupConfig?: SetupConfig;
208
217
  /**
package/dist/index.mjs CHANGED
@@ -271,7 +271,7 @@ function mergeStopGateConfig(resolved, item) {
271
271
  }
272
272
  //#endregion
273
273
  //#region package.json
274
- var version = "0.7.1";
274
+ var version = "0.7.3";
275
275
  //#endregion
276
276
  //#region src/core/cache/types.ts
277
277
  const CACHE_MAGIC = "ALINT_CACHE";
@@ -1165,6 +1165,19 @@ function resolveRuleLanguages(languages) {
1165
1165
  };
1166
1166
  }
1167
1167
  //#endregion
1168
+ //#region src/core/rule-filter.ts
1169
+ const minimatchOptions = { dot: true };
1170
+ /**
1171
+ * Whether one enabled rule survives a `--rule` filter.
1172
+ *
1173
+ * A pattern matches the configured rule id (`plugin/rule`) or the rule's own name
1174
+ * (`rule`), so `--rule docs/review-copy` narrows a run to a single rule while
1175
+ * `--rule 'docs/*'` keeps a plugin's rules. Patterns are matched with glob syntax.
1176
+ */
1177
+ function matchesRuleFilter(rule, patterns) {
1178
+ return patterns.some((pattern) => minimatch(rule.id, pattern, minimatchOptions) || minimatch(rule.localId, pattern, minimatchOptions));
1179
+ }
1180
+ //#endregion
1168
1181
  //#region src/core/preparation.ts
1169
1182
  /**
1170
1183
  * The `ctx.src.extract` a run hands to rules, for parsing files it was never asked to lint, which
@@ -1197,10 +1210,17 @@ function createSourceExtractor(cwd, config, getSrc) {
1197
1210
  function prepareRun(options = {}) {
1198
1211
  const cwd$2 = options.cwd ?? cwd();
1199
1212
  const config = options.config ?? [];
1213
+ const ruleFilter = options.ruleFilter ?? [];
1200
1214
  const files = [];
1201
1215
  const directories = [];
1216
+ const knownRuleIds = /* @__PURE__ */ new Set();
1202
1217
  const missingLanguages = /* @__PURE__ */ new Map();
1203
1218
  const unregisteredLanguages = /* @__PURE__ */ new Map();
1219
+ const prepareRulesFor = (effectiveConfig) => {
1220
+ const enabledRules = buildRuleRegistry(effectiveConfig).enabledRules;
1221
+ for (const enabledRule of enabledRules) knownRuleIds.add(enabledRule.id);
1222
+ return prepareRules(enabledRules, ruleFilter);
1223
+ };
1204
1224
  for (const filePath of options.files ?? []) {
1205
1225
  const path = resolve(cwd$2, filePath);
1206
1226
  const resolvedConfig = resolveConfigForFile(path, config, { cwd: cwd$2 });
@@ -1208,7 +1228,7 @@ function prepareRun(options = {}) {
1208
1228
  const effectiveConfig = resolvedConfig.config;
1209
1229
  const languageRegistry = createLanguageRegistry(effectiveConfig);
1210
1230
  const language = resolveLanguageForPath(path, languageRegistry, { language: effectiveConfig.language });
1211
- const rules = prepareRules(effectiveConfig);
1231
+ const rules = prepareRulesFor(effectiveConfig);
1212
1232
  recordMissingLanguages(missingLanguages, rules, languageRegistry, path);
1213
1233
  if (effectiveConfig.language === void 0 && language.name === "plaintext" && rules.some(({ enabledRule }) => !isTargetLanguageAccepted(resolveRuleLanguages(enabledRule.rule.languages), "file", "plaintext"))) recordUnregistered(unregisteredLanguages, path, unregisteredLanguageSeverity(effectiveConfig.linterOptions));
1214
1234
  files.push({
@@ -1237,7 +1257,7 @@ function prepareRun(options = {}) {
1237
1257
  agent: effectiveConfig.agent,
1238
1258
  configHash: stableHash({ settings: effectiveConfig.settings }),
1239
1259
  directoryIndex: directories.length,
1240
- rules: prepareRules(effectiveConfig),
1260
+ rules: prepareRulesFor(effectiveConfig),
1241
1261
  settings: effectiveConfig.settings,
1242
1262
  target: {
1243
1263
  kind: "directory",
@@ -1245,11 +1265,13 @@ function prepareRun(options = {}) {
1245
1265
  }
1246
1266
  });
1247
1267
  }
1268
+ const project = options.projectTargets === false ? void 0 : prepareProject(cwd$2, config, prepareRulesFor);
1269
+ if (ruleFilter.length > 0 && !hasPreparedRule(files, directories, project)) throw new Error(formatUnmatchedRuleFilter(ruleFilter, knownRuleIds));
1248
1270
  return {
1249
1271
  directories,
1250
1272
  files,
1251
1273
  missingLanguages,
1252
- project: options.projectTargets === false ? void 0 : prepareProject(cwd$2, config),
1274
+ project,
1253
1275
  unregisteredLanguages
1254
1276
  };
1255
1277
  }
@@ -1258,7 +1280,15 @@ function createLanguageRegistry(config) {
1258
1280
  for (const plugin of Object.values(config.plugins)) for (const language of Object.values(plugin.languages ?? {})) registerLanguage(registry, language);
1259
1281
  return registry;
1260
1282
  }
1261
- function prepareProject(root, config) {
1283
+ function formatUnmatchedRuleFilter(ruleFilter, knownRuleIds) {
1284
+ const patterns = ruleFilter.map((pattern) => `"${pattern}"`).join(", ");
1285
+ const knownIds = [...knownRuleIds].sort();
1286
+ return `No enabled rule matched --rule ${patterns}. ${knownIds.length === 0 ? "This run enabled no rule at all. Run `alint config inspect <file>` to see which rules apply to a file." : `Enabled rules: ${knownIds.slice(0, 20).join(", ")}${knownIds.length > 20 ? ", ..." : ""}.`}`;
1287
+ }
1288
+ function hasPreparedRule(files, directories, project) {
1289
+ return files.some((input) => input.rules.length > 0) || directories.some((input) => input.rules.length > 0) || (project?.rules.length ?? 0) > 0;
1290
+ }
1291
+ function prepareProject(root, config, prepareRulesFor) {
1262
1292
  const resolvedConfig = resolveConfigForProject(root, config, { cwd: root });
1263
1293
  if (resolvedConfig.ignored) return void 0;
1264
1294
  const effectiveConfig = resolvedConfig.config;
@@ -1266,15 +1296,19 @@ function prepareProject(root, config) {
1266
1296
  agent: effectiveConfig.agent,
1267
1297
  configHash: stableHash({ settings: effectiveConfig.settings }),
1268
1298
  root,
1269
- rules: prepareRules(effectiveConfig),
1299
+ rules: prepareRulesFor(effectiveConfig),
1270
1300
  settings: effectiveConfig.settings
1271
1301
  };
1272
1302
  }
1273
- function prepareRules(config) {
1274
- return buildRuleRegistry(config).enabledRules.map((enabledRule, ruleIndex) => ({
1303
+ /**
1304
+ * Keeps the registry position of every surviving rule: `ruleIndex` is an enabled-registry
1305
+ * position that jobs and progress refs share, so filtering must not renumber the rules that stay.
1306
+ */
1307
+ function prepareRules(enabledRules, ruleFilter) {
1308
+ return enabledRules.map((enabledRule, ruleIndex) => ({
1275
1309
  enabledRule,
1276
1310
  ruleIndex
1277
- }));
1311
+ })).filter((rule) => ruleFilter.length === 0 || matchesRuleFilter(rule.enabledRule, ruleFilter));
1278
1312
  }
1279
1313
  function recordMissingLanguages(into, rules, registry, path) {
1280
1314
  for (const { enabledRule } of rules) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alint-js/core",
3
3
  "type": "module",
4
- "version": "0.7.1",
4
+ "version": "0.7.3",
5
5
  "description": "Public rule and plugin SDK and run engine for alint",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -56,7 +56,7 @@
56
56
  "pathe": "^2.0.3",
57
57
  "proper-lockfile": "4.1.2",
58
58
  "valibot": "^1.4.2",
59
- "@alint-js/utils": "0.7.1"
59
+ "@alint-js/utils": "0.7.3"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/proper-lockfile": "4.1.4",