uilint-eslint 0.2.67 → 0.2.68

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
@@ -27,7 +27,6 @@ export default [
27
27
  {
28
28
  plugins: { uilint: uilint.plugin },
29
29
  rules: {
30
- "uilint/no-arbitrary-tailwind": "error",
31
30
  "uilint/consistent-spacing": [
32
31
  "warn",
33
32
  { scale: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16] },
@@ -48,7 +47,6 @@ export default [
48
47
 
49
48
  | Rule | Description |
50
49
  | ------------------------------ | ------------------------------------------------------- |
51
- | `no-arbitrary-tailwind` | Forbid arbitrary Tailwind values like `w-[123px]` |
52
50
  | `consistent-spacing` | Enforce spacing scale (no magic numbers in gap/padding) |
53
51
  | `no-direct-store-import` | Forbid direct Zustand store imports (use hooks) |
54
52
  | `no-mixed-component-libraries` | Forbid mixing shadcn and MUI components in same file |
@@ -63,10 +61,6 @@ The `semantic` rule reads `.uilint/styleguide.md` and uses Ollama to analyze you
63
61
 
64
62
  ## Configuration
65
63
 
66
- ### `no-arbitrary-tailwind`
67
-
68
- No options. Reports any use of Tailwind arbitrary values like `w-[100px]`, `bg-[#fff]`, etc.
69
-
70
64
  ### `consistent-spacing`
71
65
 
72
66
  ```javascript
package/dist/index.d.ts CHANGED
@@ -72,7 +72,7 @@ interface RuleMigration {
72
72
  * making it easy to maintain and extend as new rules are added.
73
73
  */
74
74
  interface RuleMeta {
75
- /** Rule identifier (e.g., "no-arbitrary-tailwind") - must match filename */
75
+ /** Rule identifier (e.g., "consistent-dark-mode") - must match filename */
76
76
  id: string;
77
77
  /** Semantic version of the rule (e.g., "1.0.0") */
78
78
  version: string;
@@ -672,9 +672,6 @@ declare function analyzeJSXElementCoverage(jsxNode: TSESTree.JSXElement, filePat
672
672
  * All available rules
673
673
  */
674
674
  declare const rules: {
675
- "no-arbitrary-tailwind": _typescript_eslint_utils_ts_eslint.RuleModule<"noArbitraryValue", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
676
- name: string;
677
- };
678
675
  "consistent-dark-mode": _typescript_eslint_utils_ts_eslint.RuleModule<"inconsistentDarkMode" | "missingDarkMode", [({
679
676
  warnOnMissingDarkMode?: boolean;
680
677
  } | undefined)?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
@@ -818,9 +815,6 @@ declare const plugin: {
818
815
  version: string;
819
816
  };
820
817
  rules: {
821
- "no-arbitrary-tailwind": _typescript_eslint_utils_ts_eslint.RuleModule<"noArbitraryValue", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
822
- name: string;
823
- };
824
818
  "consistent-dark-mode": _typescript_eslint_utils_ts_eslint.RuleModule<"inconsistentDarkMode" | "missingDarkMode", [({
825
819
  warnOnMissingDarkMode?: boolean;
826
820
  } | undefined)?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
package/dist/index.js CHANGED
@@ -3,132 +3,12 @@ import { ESLintUtils } from "@typescript-eslint/utils";
3
3
  var createRule = ESLintUtils.RuleCreator(
4
4
  (name) => `https://github.com/peter-suggate/uilint/blob/main/packages/uilint-eslint/docs/rules/${name}.md`
5
5
  );
6
- function defineRuleMeta(meta18) {
7
- return meta18;
8
- }
9
-
10
- // src/rules/no-arbitrary-tailwind.ts
11
- var meta = defineRuleMeta({
12
- id: "no-arbitrary-tailwind",
13
- version: "1.0.0",
14
- name: "No Arbitrary Tailwind",
15
- description: "Forbid arbitrary values like w-[123px], bg-[#fff]",
16
- defaultSeverity: "error",
17
- category: "static",
18
- icon: "\u{1F3A8}",
19
- hint: "Enforces design system tokens",
20
- defaultEnabled: true,
21
- docs: `
22
- ## What it does
23
-
24
- Prevents the use of arbitrary Tailwind CSS values (bracket notation) in your codebase.
25
- Arbitrary values like \`w-[123px]\`, \`bg-[#ff5500]\`, or \`text-[14px]\` bypass Tailwind's
26
- design system and can lead to inconsistent UI.
27
-
28
- ## Why it's useful
29
-
30
- - **Consistency**: Forces use of your design system's spacing, colors, and typography scales
31
- - **Maintainability**: Changes to design tokens automatically propagate everywhere
32
- - **Performance**: Arbitrary values generate extra CSS that can't be deduplicated
33
-
34
- ## Examples
35
-
36
- ### \u274C Incorrect
37
-
38
- \`\`\`tsx
39
- <div className="w-[123px] h-[456px]"> // Arbitrary dimensions
40
- <div className="bg-[#ff5500]"> // Arbitrary color
41
- <div className="text-[14px]"> // Arbitrary font size
42
- <div className="p-[7px]"> // Arbitrary padding
43
- \`\`\`
44
-
45
- ### \u2705 Correct
46
-
47
- \`\`\`tsx
48
- <div className="w-32 h-96"> // Use spacing scale
49
- <div className="bg-orange-500"> // Use color palette
50
- <div className="text-sm"> // Use typography scale
51
- <div className="p-2"> // Use spacing scale
52
- \`\`\`
53
-
54
- ## Notes
55
-
56
- - Data attributes like \`data-[state=open]\` are allowed as they don't affect styling
57
- - If you need a truly custom value, consider extending your Tailwind config instead
58
- `
59
- });
60
- var ARBITRARY_VALUE_REGEX = /\b[\w-]+-\[[^\]]+\]/g;
61
- var no_arbitrary_tailwind_default = createRule({
62
- name: "no-arbitrary-tailwind",
63
- meta: {
64
- type: "problem",
65
- docs: {
66
- description: "Forbid arbitrary Tailwind values like w-[123px]"
67
- },
68
- messages: {
69
- noArbitraryValue: "Avoid arbitrary Tailwind value '{{value}}'. Use the spacing/color scale instead."
70
- },
71
- schema: []
72
- },
73
- defaultOptions: [],
74
- create(context) {
75
- return {
76
- // Check className attributes in JSX
77
- JSXAttribute(node) {
78
- if (node.name.type === "JSXIdentifier" && (node.name.name === "className" || node.name.name === "class")) {
79
- const value = node.value;
80
- if (value?.type === "Literal" && typeof value.value === "string") {
81
- checkClassString(context, value, value.value);
82
- }
83
- if (value?.type === "JSXExpressionContainer") {
84
- const expr = value.expression;
85
- if (expr.type === "Literal" && typeof expr.value === "string") {
86
- checkClassString(context, expr, expr.value);
87
- }
88
- if (expr.type === "TemplateLiteral") {
89
- for (const quasi of expr.quasis) {
90
- checkClassString(context, quasi, quasi.value.raw);
91
- }
92
- }
93
- }
94
- }
95
- },
96
- // Check cn(), clsx(), classnames() calls
97
- CallExpression(node) {
98
- if (node.callee.type !== "Identifier") return;
99
- const name = node.callee.name;
100
- if (name === "cn" || name === "clsx" || name === "classnames") {
101
- for (const arg of node.arguments) {
102
- if (arg.type === "Literal" && typeof arg.value === "string") {
103
- checkClassString(context, arg, arg.value);
104
- }
105
- if (arg.type === "TemplateLiteral") {
106
- for (const quasi of arg.quasis) {
107
- checkClassString(context, quasi, quasi.value.raw);
108
- }
109
- }
110
- }
111
- }
112
- }
113
- };
114
- }
115
- });
116
- function checkClassString(context, node, classString) {
117
- const matches = classString.matchAll(ARBITRARY_VALUE_REGEX);
118
- for (const match of matches) {
119
- if (match[0].startsWith("data-")) {
120
- continue;
121
- }
122
- context.report({
123
- node,
124
- messageId: "noArbitraryValue",
125
- data: { value: match[0] }
126
- });
127
- }
6
+ function defineRuleMeta(meta17) {
7
+ return meta17;
128
8
  }
129
9
 
130
10
  // src/rules/consistent-dark-mode.ts
131
- var meta2 = defineRuleMeta({
11
+ var meta = defineRuleMeta({
132
12
  id: "consistent-dark-mode",
133
13
  version: "1.0.0",
134
14
  name: "Consistent Dark Mode",
@@ -352,7 +232,7 @@ var consistent_dark_mode_default = createRule({
352
232
  let fileHasColorClasses = false;
353
233
  let fileHasDarkMode = false;
354
234
  const reportedNodes = /* @__PURE__ */ new Set();
355
- function checkClassString2(node, classString) {
235
+ function checkClassString(node, classString) {
356
236
  const classes = classString.split(/\s+/).filter(Boolean);
357
237
  if (classes.length === 0) return;
358
238
  const prefixUsage = /* @__PURE__ */ new Map();
@@ -401,11 +281,11 @@ var consistent_dark_mode_default = createRule({
401
281
  }
402
282
  }
403
283
  function processStringValue(node, value) {
404
- checkClassString2(node, value);
284
+ checkClassString(node, value);
405
285
  }
406
286
  function processTemplateLiteral(node) {
407
287
  for (const quasi of node.quasis) {
408
- checkClassString2(quasi, quasi.value.raw);
288
+ checkClassString(quasi, quasi.value.raw);
409
289
  }
410
290
  }
411
291
  return {
@@ -466,7 +346,7 @@ var consistent_dark_mode_default = createRule({
466
346
  });
467
347
 
468
348
  // src/rules/no-direct-store-import.ts
469
- var meta3 = defineRuleMeta({
349
+ var meta2 = defineRuleMeta({
470
350
  id: "no-direct-store-import",
471
351
  version: "1.0.0",
472
352
  name: "No Direct Store Import",
@@ -608,7 +488,7 @@ var no_direct_store_import_default = createRule({
608
488
  });
609
489
 
610
490
  // src/rules/prefer-zustand-state-management.ts
611
- var meta4 = defineRuleMeta({
491
+ var meta3 = defineRuleMeta({
612
492
  id: "prefer-zustand-state-management",
613
493
  version: "1.0.0",
614
494
  name: "Prefer Zustand State Management",
@@ -1391,7 +1271,7 @@ function clearCache() {
1391
1271
  }
1392
1272
 
1393
1273
  // src/rules/no-mixed-component-libraries/index.ts
1394
- var meta5 = defineRuleMeta({
1274
+ var meta4 = defineRuleMeta({
1395
1275
  id: "no-mixed-component-libraries",
1396
1276
  version: "1.0.0",
1397
1277
  name: "No Mixed Component Libraries",
@@ -1778,7 +1658,7 @@ function getStyleguide(startDir, explicitPath) {
1778
1658
  // src/rules/semantic/index.ts
1779
1659
  import { UILINT_DEFAULT_OLLAMA_MODEL } from "uilint-core";
1780
1660
  import { buildSourceScanPrompt } from "uilint-core";
1781
- var meta6 = defineRuleMeta({
1661
+ var meta5 = defineRuleMeta({
1782
1662
  id: "semantic",
1783
1663
  version: "1.0.0",
1784
1664
  name: "Semantic Analysis",
@@ -2123,7 +2003,7 @@ function runSemanticAnalysisSync(sourceCode, styleguide, model, filePath) {
2123
2003
  // src/rules/semantic-vision.ts
2124
2004
  import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync5 } from "fs";
2125
2005
  import { dirname as dirname5, join as join5, relative as relative2 } from "path";
2126
- var meta7 = defineRuleMeta({
2006
+ var meta6 = defineRuleMeta({
2127
2007
  id: "semantic-vision",
2128
2008
  version: "1.0.0",
2129
2009
  name: "Vision Analysis",
@@ -2347,7 +2227,7 @@ var semantic_vision_default = createRule({
2347
2227
  });
2348
2228
 
2349
2229
  // src/rules/enforce-absolute-imports.ts
2350
- var meta8 = defineRuleMeta({
2230
+ var meta7 = defineRuleMeta({
2351
2231
  id: "enforce-absolute-imports",
2352
2232
  version: "1.0.0",
2353
2233
  name: "Enforce Absolute Imports",
@@ -2523,7 +2403,7 @@ var enforce_absolute_imports_default = createRule({
2523
2403
  });
2524
2404
 
2525
2405
  // src/rules/no-any-in-props.ts
2526
- var meta9 = defineRuleMeta({
2406
+ var meta8 = defineRuleMeta({
2527
2407
  id: "no-any-in-props",
2528
2408
  version: "1.0.0",
2529
2409
  name: "No Any in Props",
@@ -2873,7 +2753,7 @@ var no_any_in_props_default = createRule({
2873
2753
  });
2874
2754
 
2875
2755
  // src/rules/zustand-use-selectors.ts
2876
- var meta10 = defineRuleMeta({
2756
+ var meta9 = defineRuleMeta({
2877
2757
  id: "zustand-use-selectors",
2878
2758
  version: "1.0.0",
2879
2759
  name: "Zustand Use Selectors",
@@ -3102,7 +2982,7 @@ var zustand_use_selectors_default = createRule({
3102
2982
  });
3103
2983
 
3104
2984
  // src/rules/no-prop-drilling-depth.ts
3105
- var meta11 = defineRuleMeta({
2985
+ var meta10 = defineRuleMeta({
3106
2986
  id: "no-prop-drilling-depth",
3107
2987
  version: "1.0.0",
3108
2988
  name: "No Prop Drilling Depth",
@@ -3458,7 +3338,7 @@ var no_prop_drilling_depth_default = createRule({
3458
3338
  });
3459
3339
 
3460
3340
  // src/rules/no-secrets-in-code.ts
3461
- var meta12 = defineRuleMeta({
3341
+ var meta11 = defineRuleMeta({
3462
3342
  id: "no-secrets-in-code",
3463
3343
  version: "1.0.0",
3464
3344
  name: "No Secrets in Code",
@@ -3813,7 +3693,7 @@ var no_secrets_in_code_default = createRule({
3813
3693
  });
3814
3694
 
3815
3695
  // src/rules/require-input-validation.ts
3816
- var meta13 = defineRuleMeta({
3696
+ var meta12 = defineRuleMeta({
3817
3697
  id: "require-input-validation",
3818
3698
  version: "1.0.0",
3819
3699
  name: "Require Input Validation",
@@ -4155,7 +4035,7 @@ function log(message) {
4155
4035
  } catch {
4156
4036
  }
4157
4037
  }
4158
- var meta14 = defineRuleMeta({
4038
+ var meta13 = defineRuleMeta({
4159
4039
  id: "no-semantic-duplicates",
4160
4040
  version: "1.0.0",
4161
4041
  name: "No Semantic Duplicates",
@@ -4316,8 +4196,8 @@ function loadIndex(projectRoot, indexPath) {
4316
4196
  log(`Loaded metadata.json: ${Object.keys(entries).length} entries`);
4317
4197
  const metadataStore = /* @__PURE__ */ new Map();
4318
4198
  const fileToChunks = /* @__PURE__ */ new Map();
4319
- for (const [id, meta18] of Object.entries(entries)) {
4320
- const m = meta18;
4199
+ for (const [id, meta17] of Object.entries(entries)) {
4200
+ const m = meta17;
4321
4201
  metadataStore.set(id, {
4322
4202
  filePath: m.filePath,
4323
4203
  startLine: m.startLine,
@@ -4407,9 +4287,9 @@ function findSimilarChunks(index, chunkId, threshold) {
4407
4287
  const sortedAll = allScores.sort((a, b) => b.score - a.score).slice(0, 10);
4408
4288
  log(` Top 10 similarity scores (threshold=${threshold}):`);
4409
4289
  for (const { id, score } of sortedAll) {
4410
- const meta18 = index.metadataStore.get(id);
4290
+ const meta17 = index.metadataStore.get(id);
4411
4291
  const meetsThreshold = score >= threshold ? "\u2713" : "\u2717";
4412
- log(` ${meetsThreshold} ${(score * 100).toFixed(1)}% - ${id} (${meta18?.name || "anonymous"} in ${meta18?.filePath})`);
4292
+ log(` ${meetsThreshold} ${(score * 100).toFixed(1)}% - ${id} (${meta17?.name || "anonymous"} in ${meta17?.filePath})`);
4413
4293
  }
4414
4294
  log(` Found ${results.length} chunks above threshold`);
4415
4295
  return results.sort((a, b) => b.score - a.score);
@@ -4498,20 +4378,20 @@ var no_semantic_duplicates_default = createRule({
4498
4378
  log(` Chunk ${chunkId} already reported, skipping`);
4499
4379
  continue;
4500
4380
  }
4501
- const meta18 = index.metadataStore.get(chunkId);
4502
- if (!meta18) {
4381
+ const meta17 = index.metadataStore.get(chunkId);
4382
+ if (!meta17) {
4503
4383
  log(` No metadata for chunk ${chunkId}`);
4504
4384
  continue;
4505
4385
  }
4506
- log(` Checking chunk ${chunkId}: lines ${meta18.startLine}-${meta18.endLine} (node at line ${nodeLine})`);
4507
- if (nodeLine >= meta18.startLine && nodeLine <= meta18.endLine) {
4386
+ log(` Checking chunk ${chunkId}: lines ${meta17.startLine}-${meta17.endLine} (node at line ${nodeLine})`);
4387
+ if (nodeLine >= meta17.startLine && nodeLine <= meta17.endLine) {
4508
4388
  log(` Node is within chunk range, searching for similar chunks...`);
4509
4389
  const similar = findSimilarChunks(index, chunkId, threshold);
4510
4390
  if (similar.length > 0) {
4511
4391
  const best = similar[0];
4512
4392
  const bestMeta = index.metadataStore.get(best.id);
4513
4393
  if (bestMeta) {
4514
- const chunkLines = meta18.endLine - meta18.startLine + 1;
4394
+ const chunkLines = meta17.endLine - meta17.startLine + 1;
4515
4395
  if (chunkLines < minLines) {
4516
4396
  log(` Skipping: chunk has ${chunkLines} lines, below minLines=${minLines}`);
4517
4397
  continue;
@@ -4519,17 +4399,17 @@ var no_semantic_duplicates_default = createRule({
4519
4399
  reportedChunks.add(chunkId);
4520
4400
  const relPath = relative3(projectRoot, bestMeta.filePath);
4521
4401
  const similarity = Math.round(best.score * 100);
4522
- log(` REPORTING: ${meta18.kind} '${name || meta18.name}' is ${similarity}% similar to '${bestMeta.name}' at ${relPath}:${bestMeta.startLine}`);
4402
+ log(` REPORTING: ${meta17.kind} '${name || meta17.name}' is ${similarity}% similar to '${bestMeta.name}' at ${relPath}:${bestMeta.startLine}`);
4523
4403
  context.report({
4524
4404
  node,
4525
4405
  loc: {
4526
- start: { line: meta18.startLine, column: meta18.startColumn },
4527
- end: { line: meta18.endLine, column: meta18.endColumn }
4406
+ start: { line: meta17.startLine, column: meta17.startColumn },
4407
+ end: { line: meta17.endLine, column: meta17.endColumn }
4528
4408
  },
4529
4409
  messageId: "semanticDuplicate",
4530
4410
  data: {
4531
- kind: meta18.kind,
4532
- name: name || meta18.name || "(anonymous)",
4411
+ kind: meta17.kind,
4412
+ name: name || meta17.name || "(anonymous)",
4533
4413
  similarity: String(similarity),
4534
4414
  otherName: bestMeta.name || "(anonymous)",
4535
4415
  otherLocation: `${relPath}:${bestMeta.startLine}`
@@ -4540,7 +4420,7 @@ var no_semantic_duplicates_default = createRule({
4540
4420
  log(` No similar chunks found above threshold`);
4541
4421
  }
4542
4422
  } else {
4543
- log(` Node line ${nodeLine} not in chunk range ${meta18.startLine}-${meta18.endLine}`);
4423
+ log(` Node line ${nodeLine} not in chunk range ${meta17.startLine}-${meta17.endLine}`);
4544
4424
  }
4545
4425
  }
4546
4426
  }
@@ -5786,7 +5666,7 @@ function simpleGlobMatch(pattern, path) {
5786
5666
  const regex = new RegExp(`^${regexStr}$`);
5787
5667
  return regex.test(normalizedPath);
5788
5668
  }
5789
- var meta15 = defineRuleMeta({
5669
+ var meta14 = defineRuleMeta({
5790
5670
  id: "require-test-coverage",
5791
5671
  version: "1.0.0",
5792
5672
  name: "Require Test Coverage",
@@ -6499,7 +6379,7 @@ function checkForJSX(ast, visited = /* @__PURE__ */ new WeakSet()) {
6499
6379
  }
6500
6380
 
6501
6381
  // src/rules/prefer-tailwind.ts
6502
- var meta16 = defineRuleMeta({
6382
+ var meta15 = defineRuleMeta({
6503
6383
  id: "prefer-tailwind",
6504
6384
  version: "1.0.0",
6505
6385
  name: "Prefer Tailwind",
@@ -6926,21 +6806,20 @@ var ruleRegistry = [
6926
6806
  meta4,
6927
6807
  meta5,
6928
6808
  meta6,
6929
- meta7,
6930
6809
  // New UI rules
6810
+ meta7,
6931
6811
  meta8,
6932
6812
  meta9,
6933
6813
  meta10,
6934
- meta11,
6935
6814
  // New security rules
6815
+ meta11,
6936
6816
  meta12,
6937
- meta13,
6938
6817
  // Semantic duplicate detection
6939
- meta14,
6818
+ meta13,
6940
6819
  // Test coverage enforcement
6941
- meta15,
6820
+ meta14,
6942
6821
  // Style preferences
6943
- meta16
6822
+ meta15
6944
6823
  ];
6945
6824
  function getRuleMetadata(id) {
6946
6825
  return ruleRegistry.find((rule) => rule.id === id);
@@ -6959,7 +6838,6 @@ function getAllRuleIds() {
6959
6838
  // src/index.ts
6960
6839
  import { ResolverFactory as ResolverFactory3 } from "oxc-resolver";
6961
6840
  var rules = {
6962
- "no-arbitrary-tailwind": no_arbitrary_tailwind_default,
6963
6841
  "consistent-dark-mode": consistent_dark_mode_default,
6964
6842
  "no-direct-store-import": no_direct_store_import_default,
6965
6843
  "prefer-zustand-state-management": prefer_zustand_state_management_default,
@@ -6977,12 +6855,12 @@ var rules = {
6977
6855
  "prefer-tailwind": prefer_tailwind_default
6978
6856
  };
6979
6857
  var version = "0.1.0";
6980
- var meta17 = {
6858
+ var meta16 = {
6981
6859
  name: "uilint",
6982
6860
  version
6983
6861
  };
6984
6862
  var plugin = {
6985
- meta: meta17,
6863
+ meta: meta16,
6986
6864
  rules
6987
6865
  };
6988
6866
  var jsxLanguageOptions = {
@@ -7000,7 +6878,6 @@ var recommendedConfig = {
7000
6878
  },
7001
6879
  languageOptions: jsxLanguageOptions,
7002
6880
  rules: {
7003
- "uilint/no-arbitrary-tailwind": "error",
7004
6881
  "uilint/consistent-dark-mode": ["error", ...[
7005
6882
  {
7006
6883
  "warnOnMissingDarkMode": true
@@ -7129,7 +7006,6 @@ var strictConfig = {
7129
7006
  },
7130
7007
  languageOptions: jsxLanguageOptions,
7131
7008
  rules: {
7132
- "uilint/no-arbitrary-tailwind": "error",
7133
7009
  "uilint/consistent-dark-mode": ["error", ...[
7134
7010
  {
7135
7011
  "warnOnMissingDarkMode": true
@@ -7274,7 +7150,7 @@ var configs = {
7274
7150
  strict: strictConfig
7275
7151
  };
7276
7152
  var uilintEslint = {
7277
- meta: meta17,
7153
+ meta: meta16,
7278
7154
  plugin,
7279
7155
  rules,
7280
7156
  configs
@@ -7312,7 +7188,7 @@ export {
7312
7188
  isEventHandlerAttribute,
7313
7189
  loadCache,
7314
7190
  loadStyleguide,
7315
- meta17 as meta,
7191
+ meta16 as meta,
7316
7192
  plugin,
7317
7193
  ruleRegistry,
7318
7194
  rules,