@cssdoc/providers 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -3,6 +3,27 @@ import { ClassUsage, CssDocIndex, Location, Location as Location$1, PropertyAssi
3
3
  //#region src/types.d.ts
4
4
  /** Diagnostic severity. */
5
5
  type Severity = "error" | "warning";
6
+ /** A configurable per-rule severity — `off` suppresses the rule entirely. */
7
+ type RuleSeverity = "off" | "warn" | "error";
8
+ /**
9
+ * Every rule id an aspect can emit, author-side and consumer-side. A superset of `@cssdoc/lint-core`'s
10
+ * author-side `RuleName` (which omits the consumer-side `unknown-modifier`/`deprecated-modifier` and
11
+ * the opt-in `unknown-custom-property`).
12
+ */
13
+ type RuleId = "missing-summary" | "undocumented-modifier" | "deprecated-requires-canonical" | "name-not-in-css" | "unknown-modifier" | "deprecated-modifier" | "undocumented-part" | "invalid-default-value" | "invalid-property-value" | "invalid-fallback-value" | "unknown-custom-property";
14
+ /** A resolved severity for every rule. */
15
+ type RuleSeverities = Record<RuleId, RuleSeverity>;
16
+ /**
17
+ * The default rule severities. `unknown-modifier` defaults to `warn` — safe under the BEM default's
18
+ * strong `--` signal; lower it to `off` for weak-signal conventions (bare/OOCSS) where every chained
19
+ * class is a candidate. `unknown-custom-property` stays `off` (it needs an opt-in `propertyPrefix`).
20
+ */
21
+ declare const DEFAULT_RULE_SEVERITIES: RuleSeverities;
22
+ /**
23
+ * Merge per-rule overrides over {@link DEFAULT_RULE_SEVERITIES}. A `boolean` override is accepted for
24
+ * back-compat: `false` → `off`, `true` → the rule's default.
25
+ */
26
+ declare function resolveRuleSeverities(overrides?: Partial<Record<RuleId, RuleSeverity | boolean>>): RuleSeverities;
6
27
  /** One diagnostic from an aspect. */
7
28
  interface Diagnostic {
8
29
  /** The aspect that produced it (e.g. `modifier`). */
@@ -98,13 +119,13 @@ declare const func: {
98
119
  /** The aspect names covered, in a stable order (the extension point for future aspects). */
99
120
  declare const ASPECTS: readonly ["record", "modifier", "part", "custom-property", "structure", "function", "state", "condition"];
100
121
  /** Author-side hygiene diagnostics over the whole model (missing summaries, undocumented members, drift, invalid defaults). */
101
- declare function lintModel(index: CssDocIndex): Diagnostic[];
122
+ declare function lintModel(index: CssDocIndex, severities?: RuleSeverities): Diagnostic[];
102
123
  /** Consumer-side diagnostics for custom-property assignments (`--x: value` must match its `@property` syntax). */
103
- declare function checkPropertyAssignments(assignments: readonly PropertyAssignment[], index: CssDocIndex): Diagnostic[];
124
+ declare function checkPropertyAssignments(assignments: readonly PropertyAssignment[], index: CssDocIndex, severities?: RuleSeverities): Diagnostic[];
104
125
  /** Consumer-side diagnostics for class-attribute usage (unknown or deprecated modifiers). */
105
- declare function checkClassUsage(usages: readonly ClassUsage[], index: CssDocIndex): Diagnostic[];
126
+ declare function checkClassUsage(usages: readonly ClassUsage[], index: CssDocIndex, severities?: RuleSeverities): Diagnostic[];
106
127
  /** Consumer-side diagnostics for `var(--…)` references (unknown custom properties; opt-in via prefix). */
107
- declare function checkPropertyUsage(usages: readonly PropertyUsage[], index: CssDocIndex, options?: UsageOptions): Diagnostic[];
128
+ declare function checkPropertyUsage(usages: readonly PropertyUsage[], index: CssDocIndex, options?: UsageOptions, severities?: RuleSeverities): Diagnostic[];
108
129
  /** Completions for a class attribute: modifiers of `base` when given, else the component classes. */
109
130
  declare function completeClasses(base: string | undefined, index: CssDocIndex): Completion[];
110
131
  /** Completions for `var(--…)`: the declared custom properties. */
@@ -124,4 +145,4 @@ declare function definitionForCustomProperty(name: string, index: CssDocIndex):
124
145
  /** Definition of a custom function (its `@function` rule). */
125
146
  declare function definitionForFunction(name: string, index: CssDocIndex): Location$1 | undefined;
126
147
  //#endregion
127
- export { ASPECTS, Completion, CompletionKind, Diagnostic, Hover, type Location, Severity, type SourceSpan, SyntaxMatch, UsageOptions, checkClassUsage, checkPropertyAssignments, checkPropertyUsage, completeClasses, completeCustomProperties, completeFunctions, customProperty, definitionForClass, definitionForCustomProperty, definitionForFunction, func, hoverForClass, hoverForCustomProperty, hoverForFunction, lintModel, matchesSyntax, modifier, part, record };
148
+ export { ASPECTS, Completion, CompletionKind, DEFAULT_RULE_SEVERITIES, Diagnostic, Hover, type Location, RuleId, RuleSeverities, RuleSeverity, Severity, type SourceSpan, SyntaxMatch, UsageOptions, checkClassUsage, checkPropertyAssignments, checkPropertyUsage, completeClasses, completeCustomProperties, completeFunctions, customProperty, definitionForClass, definitionForCustomProperty, definitionForFunction, func, hoverForClass, hoverForCustomProperty, hoverForFunction, lintModel, matchesSyntax, modifier, part, record, resolveRuleSeverities };
package/dist/index.mjs CHANGED
@@ -119,26 +119,27 @@ const modifier = {
119
119
  for (const info of index.records) {
120
120
  const name = info.entry.name;
121
121
  for (const m of info.entry.modifiers) {
122
+ const sel = index.matcher.selectorFor(m.name);
122
123
  const span = info.memberSpans.get(memberKey("modifier", m.name)) ?? info.span;
123
124
  if (!m.description?.trim() && !m.deprecated) out.push(warn({
124
125
  aspect: "modifier",
125
126
  rule: "undocumented-modifier",
126
- message: `Modifier ".${m.name}" of "${name}" has no @modifier description.`,
127
+ message: `Modifier "${sel}" of "${name}" has no @modifier description.`,
127
128
  record: name,
128
129
  span
129
130
  }));
130
131
  if (m.deprecated && !m.deprecated.canonical && !m.deprecated.note?.trim()) out.push(warn({
131
132
  aspect: "modifier",
132
133
  rule: "deprecated-requires-canonical",
133
- message: `Deprecated modifier ".${m.name}" of "${name}" needs a canonical replacement ({@link -x}) or a note.`,
134
+ message: `Deprecated modifier "${sel}" of "${name}" needs a canonical replacement ({@link}) or a note.`,
134
135
  record: name,
135
136
  span
136
137
  }));
137
138
  }
138
- for (const authored of info.authoredModifiers) if (!info.selectorText.includes(`.${authored}`)) out.push(warn({
139
+ for (const authored of info.authoredModifiers) if (!info.selectorText.includes(index.matcher.selectorFor(authored))) out.push(warn({
139
140
  aspect: "modifier",
140
141
  rule: "name-not-in-css",
141
- message: `Documented modifier ".${authored}" of "${name}" is not defined by any selector.`,
142
+ message: `Documented modifier "${index.matcher.selectorFor(authored)}" of "${name}" is not defined by any selector.`,
142
143
  record: name,
143
144
  span: info.span
144
145
  }));
@@ -146,23 +147,24 @@ const modifier = {
146
147
  return out;
147
148
  },
148
149
  classUsage(usage, index) {
149
- if (!usage.base || !usage.token.startsWith("-")) return [];
150
+ if (!usage.base || !index.matcher.looksLikeUsage(usage.token, usage.base)) return [];
150
151
  const entry = index.componentForClass(usage.base);
151
152
  if (!entry) return [];
153
+ const sel = index.matcher.selectorFor(index.matcher.normalizeMember(usage.token));
152
154
  if (!index.isModifier(usage.base, usage.token)) return [warn({
153
155
  aspect: "modifier",
154
156
  rule: "unknown-modifier",
155
- message: `".${usage.token}" is not a documented modifier of "${entry.name}".`,
157
+ message: `"${sel}" is not a documented modifier of "${entry.name}".`,
156
158
  record: entry.name,
157
159
  span: usage.loc
158
160
  })];
159
161
  const dep = index.deprecationOf(usage.base, usage.token);
160
162
  if (dep) {
161
- const advice = dep.canonical ? `use ".${dep.canonical}"` : dep.note ?? "no replacement given";
163
+ const advice = dep.canonical ? `use "${index.matcher.selectorFor(dep.canonical)}"` : dep.note ?? "no replacement given";
162
164
  return [warn({
163
165
  aspect: "modifier",
164
166
  rule: "deprecated-modifier",
165
- message: `Modifier ".${usage.token}" of "${entry.name}" is deprecated — ${advice}.`,
167
+ message: `Modifier "${sel}" of "${entry.name}" is deprecated — ${advice}.`,
166
168
  record: entry.name,
167
169
  span: usage.loc
168
170
  })];
@@ -173,7 +175,7 @@ const modifier = {
173
175
  const entry = index.componentForClass(base);
174
176
  if (!entry) return [];
175
177
  return entry.modifiers.map((m) => ({
176
- label: `-${m.name.replace(/^-/u, "")}`,
178
+ label: m.name,
177
179
  kind: "modifier",
178
180
  detail: m.prop,
179
181
  documentation: m.description,
@@ -182,19 +184,19 @@ const modifier = {
182
184
  },
183
185
  hover(base, token, index) {
184
186
  const entry = index.componentForClass(base);
185
- const m = entry?.modifiers.find((x) => x.name === stripDot(token));
187
+ const m = entry?.modifiers.find((x) => x.name === index.matcher.normalizeMember(token));
186
188
  if (!m) return void 0;
187
- const lines = [`\`.${m.name}\` — modifier of \`${entry.className}\``];
189
+ const lines = [`\`${index.matcher.selectorFor(m.name)}\` — modifier of \`${entry.className}\``];
188
190
  if (m.description) lines.push("", m.description);
189
191
  if (m.deprecated) {
190
- const advice = m.deprecated.canonical ? `use \`.${m.deprecated.canonical}\`` : m.deprecated.note ?? "";
192
+ const advice = m.deprecated.canonical ? `use \`${index.matcher.selectorFor(m.deprecated.canonical)}\`` : m.deprecated.note ?? "";
191
193
  lines.push("", `**Deprecated** — ${advice}`);
192
194
  }
193
195
  return { contents: lines.join("\n") };
194
196
  },
195
197
  definition(base, token, index) {
196
198
  const entry = index.componentForClass(base);
197
- return entry ? index.location(entry.name, memberKey("modifier", stripDot(token))) : void 0;
199
+ return entry ? index.location(entry.name, memberKey("modifier", index.matcher.normalizeMember(token))) : void 0;
198
200
  }
199
201
  };
200
202
  const part = { model(index) {
@@ -328,7 +330,58 @@ const func = {
328
330
  }
329
331
  };
330
332
  //#endregion
333
+ //#region src/types.ts
334
+ /**
335
+ * The default rule severities. `unknown-modifier` defaults to `warn` — safe under the BEM default's
336
+ * strong `--` signal; lower it to `off` for weak-signal conventions (bare/OOCSS) where every chained
337
+ * class is a candidate. `unknown-custom-property` stays `off` (it needs an opt-in `propertyPrefix`).
338
+ */
339
+ const DEFAULT_RULE_SEVERITIES = {
340
+ "missing-summary": "warn",
341
+ "undocumented-modifier": "warn",
342
+ "deprecated-requires-canonical": "warn",
343
+ "name-not-in-css": "warn",
344
+ "unknown-modifier": "warn",
345
+ "deprecated-modifier": "warn",
346
+ "undocumented-part": "warn",
347
+ "invalid-default-value": "warn",
348
+ "invalid-property-value": "warn",
349
+ "invalid-fallback-value": "warn",
350
+ "unknown-custom-property": "off"
351
+ };
352
+ /**
353
+ * Merge per-rule overrides over {@link DEFAULT_RULE_SEVERITIES}. A `boolean` override is accepted for
354
+ * back-compat: `false` → `off`, `true` → the rule's default.
355
+ */
356
+ function resolveRuleSeverities(overrides) {
357
+ const resolved = { ...DEFAULT_RULE_SEVERITIES };
358
+ if (!overrides) return resolved;
359
+ for (const [rule, value] of Object.entries(overrides)) {
360
+ if (value === void 0) continue;
361
+ if (typeof value === "boolean") resolved[rule] = value ? DEFAULT_RULE_SEVERITIES[rule] : "off";
362
+ else resolved[rule] = value;
363
+ }
364
+ return resolved;
365
+ }
366
+ //#endregion
331
367
  //#region src/index.ts
368
+ /**
369
+ * Apply resolved rule severities to a batch of diagnostics: drop `off` rules, and stamp the configured
370
+ * severity onto the rest. This is the single place severity/enablement is decided — every host inherits
371
+ * it. Aspects emit a placeholder `warning`; this overrides it.
372
+ */
373
+ function applySeverities(diagnostics, severities) {
374
+ const out = [];
375
+ for (const d of diagnostics) {
376
+ const severity = severities[d.rule] ?? "warn";
377
+ if (severity === "off") continue;
378
+ out.push({
379
+ ...d,
380
+ severity: severity === "error" ? "error" : "warning"
381
+ });
382
+ }
383
+ return out;
384
+ }
332
385
  /** The aspect names covered, in a stable order (the extension point for future aspects). */
333
386
  const ASPECTS = [
334
387
  "record",
@@ -341,25 +394,25 @@ const ASPECTS = [
341
394
  "condition"
342
395
  ];
343
396
  /** Author-side hygiene diagnostics over the whole model (missing summaries, undocumented members, drift, invalid defaults). */
344
- function lintModel(index) {
345
- return [
397
+ function lintModel(index, severities = DEFAULT_RULE_SEVERITIES) {
398
+ return applySeverities([
346
399
  ...record.model(index),
347
400
  ...modifier.model(index),
348
401
  ...part.model(index),
349
402
  ...customProperty.model(index)
350
- ];
403
+ ], severities);
351
404
  }
352
405
  /** Consumer-side diagnostics for custom-property assignments (`--x: value` must match its `@property` syntax). */
353
- function checkPropertyAssignments(assignments, index) {
354
- return assignments.flatMap((a) => customProperty.assignment(a, index));
406
+ function checkPropertyAssignments(assignments, index, severities = DEFAULT_RULE_SEVERITIES) {
407
+ return applySeverities(assignments.flatMap((a) => customProperty.assignment(a, index)), severities);
355
408
  }
356
409
  /** Consumer-side diagnostics for class-attribute usage (unknown or deprecated modifiers). */
357
- function checkClassUsage(usages, index) {
358
- return usages.flatMap((usage) => modifier.classUsage(usage, index));
410
+ function checkClassUsage(usages, index, severities = DEFAULT_RULE_SEVERITIES) {
411
+ return applySeverities(usages.flatMap((usage) => modifier.classUsage(usage, index)), severities);
359
412
  }
360
413
  /** Consumer-side diagnostics for `var(--…)` references (unknown custom properties; opt-in via prefix). */
361
- function checkPropertyUsage(usages, index, options = {}) {
362
- return usages.flatMap((usage) => customProperty.propertyUsage(usage, index, options));
414
+ function checkPropertyUsage(usages, index, options = {}, severities = DEFAULT_RULE_SEVERITIES) {
415
+ return applySeverities(usages.flatMap((usage) => customProperty.propertyUsage(usage, index, options)), severities);
363
416
  }
364
417
  /** Completions for a class attribute: modifiers of `base` when given, else the component classes. */
365
418
  function completeClasses(base, index) {
@@ -398,4 +451,4 @@ function definitionForFunction(name, index) {
398
451
  return func.definition(name, index);
399
452
  }
400
453
  //#endregion
401
- export { ASPECTS, checkClassUsage, checkPropertyAssignments, checkPropertyUsage, completeClasses, completeCustomProperties, completeFunctions, customProperty, definitionForClass, definitionForCustomProperty, definitionForFunction, func, hoverForClass, hoverForCustomProperty, hoverForFunction, lintModel, matchesSyntax, modifier, part, record };
454
+ export { ASPECTS, DEFAULT_RULE_SEVERITIES, checkClassUsage, checkPropertyAssignments, checkPropertyUsage, completeClasses, completeCustomProperties, completeFunctions, customProperty, definitionForClass, definitionForCustomProperty, definitionForFunction, func, hoverForClass, hoverForCustomProperty, hoverForFunction, lintModel, matchesSyntax, modifier, part, record, resolveRuleSeverities };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cssdoc/providers",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Host-agnostic aspect providers over the @cssdoc/index — diagnostics, completions, hover, and definitions for modifiers, custom properties, structure, functions, states, and conditions.",
5
5
  "keywords": [
6
6
  "css",
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "css-tree": "^3.2.1",
32
- "@cssdoc/core": "0.1.0",
33
- "@cssdoc/index": "0.1.0"
32
+ "@cssdoc/core": "0.2.0",
33
+ "@cssdoc/index": "0.2.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/css-tree": "^2.3.11",