@rnzeus/eslint-plugin 0.1.1 → 0.1.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/README.md CHANGED
@@ -20,9 +20,10 @@ Ensures that all styles declared in `*.styles.ts(x)` files are actually used in
20
20
  **What it checks:**
21
21
  - detects unused style keys
22
22
  - forbids passing the whole `styles` object (`styles={styles}`)
23
- - supports arrays: `style={[styles.foo, styles.bar]}`
23
+ - supports arrays: `style={[styles.foo, condition && styles.bar]}`
24
24
  - supports conditional styles
25
25
  - supports dynamic styles **only with explicit directive comments**
26
+ - supports additional “style-like” props (configurable): e.g. `contentContainerStyle`
26
27
 
27
28
  **File convention (required):**
28
29
  ```
@@ -91,6 +92,64 @@ module.exports = [
91
92
 
92
93
  ---
93
94
 
95
+ ## Configure `styles-usage` style props
96
+
97
+ By default, `rnzeus/styles-usage` tracks style usage from these JSX props:
98
+
99
+ - `style`
100
+ - `contentContainerStyle`
101
+
102
+ You can extend or override this list via rule options.
103
+
104
+ ### Merge (default)
105
+
106
+ `type: "merge"` is the default behavior:
107
+ - takes plugin defaults
108
+ - adds your `styleProps`
109
+ - de-duplicates
110
+
111
+ Example (add FlatList prop):
112
+
113
+ ```js
114
+ module.exports = [
115
+ ...styles,
116
+ {
117
+ rules: {
118
+ "rnzeus/styles-usage": [
119
+ "error",
120
+ {
121
+ styleProps: ["columnWrapperStyle"],
122
+ type: "merge", // optional (default)
123
+ },
124
+ ],
125
+ },
126
+ },
127
+ ];
128
+ ```
129
+
130
+ ### Override
131
+
132
+ `type: "override"` ignores plugin defaults and uses **only** your `styleProps`.
133
+
134
+ ```js
135
+ module.exports = [
136
+ ...styles,
137
+ {
138
+ rules: {
139
+ "rnzeus/styles-usage": [
140
+ "error",
141
+ {
142
+ styleProps: ["style"],
143
+ type: "override",
144
+ },
145
+ ],
146
+ },
147
+ },
148
+ ];
149
+ ```
150
+
151
+ ---
152
+
94
153
  ## Dynamic styles (important)
95
154
 
96
155
  Dynamic access like this is **not allowed by default**:
@@ -126,10 +185,11 @@ This makes dynamic styles:
126
185
  | Check | Status |
127
186
  |-----|------|
128
187
  Unused styles | ✅ |
129
- Whole styles object | ❌ |
188
+ Whole styles object (`styles={styles}`) | ❌ |
130
189
  Array styles | ✅ |
131
190
  Conditional styles | ✅ |
132
191
  Dynamic styles | ⚠️ (directive required) |
192
+ Extra style props | ✅ (configurable) |
133
193
 
134
194
  ---
135
195
 
@@ -29,7 +29,8 @@ var DEFAULTS = {
29
29
  stylesSuffix: ".styles",
30
30
  stylesExtensions: ["ts", "tsx"],
31
31
  directiveTag: "rnzeus-styles-used",
32
- stylesObjectName: "styles"
32
+ stylesObjectName: "styles",
33
+ styleProps: ["style", "contentContainerStyle"]
33
34
  };
34
35
  var stylesKeysCache = /* @__PURE__ */ new Map();
35
36
  var MAX_CACHE = 200;
@@ -40,7 +41,7 @@ function cacheSet(file, value) {
40
41
  }
41
42
  stylesKeysCache.set(file, value);
42
43
  }
43
- function fileProbablyUsesStyles(sourceCode, stylesSuffix) {
44
+ function fileProbablyUsesStyles(sourceCode, stylesSuffix, stylesObjectName) {
44
45
  const ast = sourceCode.ast;
45
46
  const body = ast?.body ?? [];
46
47
  for (const n of body) {
@@ -48,7 +49,8 @@ function fileProbablyUsesStyles(sourceCode, stylesSuffix) {
48
49
  const v = n.source?.value;
49
50
  if (typeof v === "string" && v.includes(stylesSuffix)) return true;
50
51
  }
51
- return sourceCode.getText().includes("styles.");
52
+ const text = sourceCode.getText();
53
+ return text.includes(`${stylesObjectName}.`);
52
54
  }
53
55
  function extractStyleKeysFromText(text) {
54
56
  const keys = /* @__PURE__ */ new Set();
@@ -141,6 +143,24 @@ function findBestReportNode(sourceCode) {
141
143
  }
142
144
  return ast;
143
145
  }
146
+ function uniqueStrings(items) {
147
+ const out = [];
148
+ const seen = /* @__PURE__ */ new Set();
149
+ for (const s of items) {
150
+ if (!s || typeof s !== "string") continue;
151
+ if (seen.has(s)) continue;
152
+ seen.add(s);
153
+ out.push(s);
154
+ }
155
+ return out;
156
+ }
157
+ function buildStyleProps(defaults, incoming, mode) {
158
+ if (!incoming || incoming.length === 0) return new Set(defaults);
159
+ if (mode === "override") {
160
+ return new Set(uniqueStrings(incoming));
161
+ }
162
+ return new Set(uniqueStrings([...defaults, ...incoming]));
163
+ }
144
164
  var rule = {
145
165
  meta: {
146
166
  type: "problem",
@@ -154,7 +174,9 @@ var rule = {
154
174
  stylesSuffix: { type: "string" },
155
175
  stylesExtensions: { type: "array", items: { type: "string" } },
156
176
  directiveTag: { type: "string" },
157
- stylesObjectName: { type: "string" }
177
+ stylesObjectName: { type: "string" },
178
+ styleProps: { type: "array", items: { type: "string" } },
179
+ type: { type: "string", enum: ["merge", "override"] }
158
180
  },
159
181
  additionalProperties: false
160
182
  }
@@ -171,9 +193,16 @@ var rule = {
171
193
  const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;
172
194
  const directiveTag = opt.directiveTag ?? DEFAULTS.directiveTag;
173
195
  const stylesObjectName = opt.stylesObjectName ?? DEFAULTS.stylesObjectName;
174
- const filename = context.getFilename();
175
- const sourceCode = context.getSourceCode();
176
- if (!fileProbablyUsesStyles(sourceCode, stylesSuffix)) return {};
196
+ const mode = opt.type ?? "merge";
197
+ const STYLE_PROPS = buildStyleProps(
198
+ DEFAULTS.styleProps,
199
+ opt.styleProps,
200
+ mode
201
+ );
202
+ const filename = context.filename;
203
+ const sourceCode = context.sourceCode;
204
+ if (!fileProbablyUsesStyles(sourceCode, stylesSuffix, stylesObjectName))
205
+ return {};
177
206
  const ext = import_node_path.default.extname(filename);
178
207
  if (ext !== ".ts" && ext !== ".tsx") return {};
179
208
  const stylesPath = resolveSiblingStylesFile(
@@ -236,7 +265,7 @@ var rule = {
236
265
  }
237
266
  }
238
267
  function onJSXAttribute(node) {
239
- if (node.name?.name === "style") {
268
+ if (node.name?.type === "JSXIdentifier" && STYLE_PROPS.has(node.name.name)) {
240
269
  const expr = node.value?.expression;
241
270
  if (expr) visitExpression(expr);
242
271
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/rules/styles-usage.ts","../../src/rules/styles-naming.ts","../../src/plugin.ts","../../src/configs/styles.ts"],"sourcesContent":["import type { Rule, SourceCode } from \"eslint\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n stylesSuffix?: string;\n stylesExtensions?: string[];\n directiveTag?: string;\n stylesObjectName?: string;\n }\n];\n\nconst DEFAULTS = {\n stylesSuffix: \".styles\",\n stylesExtensions: [\"ts\", \"tsx\"],\n directiveTag: \"rnzeus-styles-used\",\n stylesObjectName: \"styles\",\n} as const;\n\n/**\n * Cache: stylesPath -> { mtimeMs, keys }\n */\nconst stylesKeysCache = new Map<\n string,\n { mtimeMs: number; keys: Set<string> }\n>();\n\nconst MAX_CACHE = 200;\n\nfunction cacheSet(file: string, value: { mtimeMs: number; keys: Set<string> }) {\n if (stylesKeysCache.size >= MAX_CACHE) {\n const firstKey = stylesKeysCache.keys().next().value;\n if (firstKey) stylesKeysCache.delete(firstKey);\n }\n stylesKeysCache.set(file, value);\n}\n\nfunction fileProbablyUsesStyles(\n sourceCode: SourceCode,\n stylesSuffix: string\n): boolean {\n const ast: any = sourceCode.ast;\n const body: any[] = ast?.body ?? [];\n\n for (const n of body) {\n if (n.type !== \"ImportDeclaration\") continue;\n const v = n.source?.value;\n if (typeof v === \"string\" && v.includes(stylesSuffix)) return true;\n }\n\n // cheap fallback\n return sourceCode.getText().includes(\"styles.\");\n}\n\nfunction extractStyleKeysFromText(text: string): Set<string> {\n const keys = new Set<string>();\n\n const idx = text.indexOf(\"StyleSheet.create\");\n if (idx === -1) return keys;\n\n const braceStart = text.indexOf(\"{\", idx);\n if (braceStart === -1) return keys;\n\n let depth = 0;\n let readingKey = false;\n let currentKey = \"\";\n\n for (let i = braceStart; i < text.length; i++) {\n const ch = text[i];\n\n if (ch === \"{\") {\n depth++;\n continue;\n }\n\n if (ch === \"}\") {\n depth--;\n if (depth === 0) break;\n continue;\n }\n\n if (depth !== 1) continue;\n\n if (!readingKey && /[A-Za-z_$]/.test(ch)) {\n readingKey = true;\n currentKey = ch;\n continue;\n }\n\n if (readingKey) {\n if (/[\\w$]/.test(ch)) {\n currentKey += ch;\n continue;\n }\n\n if (ch === \":\") {\n keys.add(currentKey);\n readingKey = false;\n currentKey = \"\";\n continue;\n }\n\n readingKey = false;\n currentKey = \"\";\n }\n }\n\n return keys;\n}\n\nfunction resolveSiblingStylesFile(\n filename: string,\n stylesSuffix: string,\n stylesExtensions: readonly string[]\n): string | null {\n const dir = path.dirname(filename);\n const ext = path.extname(filename);\n const base = path.basename(filename, ext);\n\n for (const e of stylesExtensions) {\n const candidate = path.join(dir, `${base}${stylesSuffix}.${e}`);\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return null;\n}\n\nfunction parseDirectiveKeys(\n sourceCode: SourceCode,\n directiveTag: string\n): Set<string> {\n const used = new Set<string>();\n const tag = directiveTag.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const re = new RegExp(`${tag}\\\\s*:\\\\s*([^\\\\n\\\\r*]+)`, \"i\");\n\n for (const c of sourceCode.getAllComments()) {\n const match = c.value.match(re);\n if (!match) continue;\n\n match[1]\n .split(\"|\")\n .map((s) => s.trim())\n .filter(Boolean)\n .forEach((k) => used.add(k));\n }\n\n return used;\n}\n\nfunction isIdentifier(node: any, name: string): boolean {\n return node?.type === \"Identifier\" && node.name === name;\n}\n\nfunction isStylesMemberExpression(\n node: any,\n stylesObjectName: string\n): { key: string; computed: boolean } | null {\n if (node?.type !== \"MemberExpression\") return null;\n if (!isIdentifier(node.object, stylesObjectName)) return null;\n\n if (node.computed) {\n if (\n node.property?.type === \"Literal\" &&\n typeof node.property.value === \"string\"\n ) {\n return { key: node.property.value, computed: true };\n }\n return { key: \"\", computed: true };\n }\n\n if (node.property?.type === \"Identifier\") {\n return { key: node.property.name, computed: false };\n }\n\n return null;\n}\n\nfunction findBestReportNode(sourceCode: SourceCode): any {\n const ast: any = sourceCode.ast;\n const body: any[] = ast?.body ?? [];\n\n for (const n of body) {\n if (n.type !== \"ImportDeclaration\") continue;\n const v = n.source?.value;\n if (typeof v === \"string\" && v.includes(\".styles\")) return n;\n }\n\n return ast;\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Ensures styles declared in sibling <File>.styles.ts(x) are used in <File>.ts(x).\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n stylesSuffix: { type: \"string\" },\n stylesExtensions: { type: \"array\", items: { type: \"string\" } },\n directiveTag: { type: \"string\" },\n stylesObjectName: { type: \"string\" },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unusedStyles: \"Unused styles in {{stylesFile}}: {{keys}}\",\n noWholeStylesObject:\n \"Do not pass the whole styles object. Use style={styles.foo}.\",\n dynamicNeedsDirective:\n \"Dynamic styles access ({{stylesName}}[...]) requires directive: {{tag}}\",\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n\n const stylesSuffix = opt.stylesSuffix ?? DEFAULTS.stylesSuffix;\n const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;\n const directiveTag = opt.directiveTag ?? DEFAULTS.directiveTag;\n const stylesObjectName = opt.stylesObjectName ?? DEFAULTS.stylesObjectName;\n\n const filename = context.getFilename();\n const sourceCode = context.getSourceCode();\n\n if (!fileProbablyUsesStyles(sourceCode, stylesSuffix)) return {};\n\n const ext = path.extname(filename);\n if (ext !== \".ts\" && ext !== \".tsx\") return {};\n\n const stylesPath = resolveSiblingStylesFile(\n filename,\n stylesSuffix,\n stylesExtensions\n );\n if (!stylesPath) return {};\n\n let declaredKeys: Set<string> = new Set();\n\n try {\n const stat = fs.statSync(stylesPath);\n const cached = stylesKeysCache.get(stylesPath);\n\n if (!cached || cached.mtimeMs !== stat.mtimeMs) {\n const text = fs.readFileSync(stylesPath, \"utf8\");\n const keys = extractStyleKeysFromText(text);\n cacheSet(stylesPath, { mtimeMs: stat.mtimeMs, keys });\n declaredKeys = keys;\n } else {\n declaredKeys = cached.keys;\n }\n } catch {\n declaredKeys = new Set();\n }\n\n const usedKeys = new Set<string>();\n const directiveKeys = parseDirectiveKeys(sourceCode, directiveTag);\n directiveKeys.forEach((k) => usedKeys.add(k));\n\n let sawDynamic = false;\n let firstDynamicNode: any | null = null;\n\n function recordFromNode(node: any) {\n const info = isStylesMemberExpression(node, stylesObjectName);\n if (!info) return;\n\n if (info.key) {\n usedKeys.add(info.key);\n } else {\n sawDynamic = true;\n if (!firstDynamicNode) firstDynamicNode = node;\n }\n }\n\n function checkNoWholeStylesObject(node: any) {\n if (node.name?.type !== \"JSXIdentifier\") return;\n if (node.name.name !== \"styles\") return;\n\n const expr = node.value?.expression;\n if (isIdentifier(expr, stylesObjectName)) {\n context.report({ node, messageId: \"noWholeStylesObject\" });\n }\n }\n\n function visitExpression(expr: any) {\n if (!expr) return;\n\n recordFromNode(expr);\n\n if (expr.type === \"ArrayExpression\") {\n expr.elements?.forEach(visitExpression);\n } else if (expr.type === \"ObjectExpression\") {\n expr.properties?.forEach((p: any) => visitExpression(p.value));\n } else if (expr.type === \"ConditionalExpression\") {\n visitExpression(expr.consequent);\n visitExpression(expr.alternate);\n } else if (expr.type === \"LogicalExpression\") {\n visitExpression(expr.left);\n visitExpression(expr.right);\n }\n }\n\n function onJSXAttribute(node: any) {\n if (node.name?.name === \"style\") {\n const expr = node.value?.expression;\n if (expr) visitExpression(expr);\n }\n checkNoWholeStylesObject(node);\n }\n\n function finish() {\n if (sawDynamic && directiveKeys.size === 0 && firstDynamicNode) {\n context.report({\n node: firstDynamicNode,\n messageId: \"dynamicNeedsDirective\",\n data: { tag: directiveTag, stylesName: stylesObjectName },\n });\n }\n\n const unused = [...declaredKeys].filter((k) => !usedKeys.has(k));\n if (unused.length) {\n context.report({\n node: findBestReportNode(sourceCode),\n messageId: \"unusedStyles\",\n data: {\n stylesFile: path.basename(stylesPath as string),\n keys: unused.sort().join(\", \"),\n },\n });\n }\n }\n\n return {\n JSXAttribute: onJSXAttribute,\n \"Program:exit\": finish,\n };\n },\n};\n\nexport default rule;\n","import type { Rule } from \"eslint\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n /**\n * Suffix for styles files.\n * Default: \".styles\"\n */\n stylesSuffix?: string;\n\n /**\n * Allowed extensions.\n * Default: [\"ts\", \"tsx\"]\n */\n stylesExtensions?: string[];\n }\n];\n\nconst DEFAULTS = {\n stylesSuffix: \".styles\",\n stylesExtensions: [\"ts\", \"tsx\"],\n} as const;\n\nconst SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;\n\nfunction extractTopLevelStyleKeys(\n text: string\n): { key: string; index: number }[] {\n const result: { key: string; index: number }[] = [];\n\n const idx = text.indexOf(\"StyleSheet.create\");\n if (idx === -1) return result;\n\n const braceStart = text.indexOf(\"{\", idx);\n if (braceStart === -1) return result;\n\n let depth = 0;\n let readingKey = false;\n let currentKey = \"\";\n let keyStartIndex = -1;\n\n for (let i = braceStart; i < text.length; i++) {\n const ch = text[i];\n\n if (ch === \"{\") {\n depth++;\n continue;\n }\n\n if (ch === \"}\") {\n depth--;\n if (depth === 0) break;\n continue;\n }\n\n if (depth !== 1) continue;\n\n if (!readingKey && /[A-Za-z_$]/.test(ch)) {\n readingKey = true;\n currentKey = ch;\n keyStartIndex = i;\n continue;\n }\n\n if (readingKey) {\n if (/[\\w$]/.test(ch)) {\n currentKey += ch;\n continue;\n }\n\n if (ch === \":\") {\n result.push({ key: currentKey, index: keyStartIndex });\n readingKey = false;\n currentKey = \"\";\n keyStartIndex = -1;\n continue;\n }\n\n readingKey = false;\n currentKey = \"\";\n keyStartIndex = -1;\n }\n }\n\n return result;\n}\n\nfunction isStylesFile(\n filename: string,\n stylesSuffix: string,\n stylesExtensions: readonly string[]\n): boolean {\n const ext = path.extname(filename);\n if (!stylesExtensions.includes(ext.replace(\".\", \"\"))) return false;\n return path.basename(filename).includes(stylesSuffix);\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Enforce snake_case naming for style keys in *.styles.ts(x) files.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n stylesSuffix: { type: \"string\" },\n stylesExtensions: { type: \"array\", items: { type: \"string\" } },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n invalidName:\n 'Style name \"{{name}}\" must be snake_case (e.g. \"{{suggestion}}\").',\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n\n const stylesSuffix = opt.stylesSuffix ?? DEFAULTS.stylesSuffix;\n const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;\n\n const filename = context.getFilename();\n if (!isStylesFile(filename, stylesSuffix, stylesExtensions)) {\n return {};\n }\n\n const sourceCode = context.getSourceCode();\n const text = sourceCode.getText();\n\n const keys = extractTopLevelStyleKeys(text);\n\n function toSnakeCase(input: string): string {\n return input\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[-\\s]+/g, \"_\")\n .toLowerCase();\n }\n\n for (const { key, index } of keys) {\n if (!SNAKE_CASE_RE.test(key)) {\n const loc = sourceCode.getLocFromIndex(index);\n\n context.report({\n loc: {\n start: loc,\n end: { line: loc.line, column: loc.column + key.length },\n },\n messageId: \"invalidName\",\n data: {\n name: key,\n suggestion: toSnakeCase(key),\n },\n });\n }\n }\n\n return {};\n },\n};\n\nexport default rule;\n","import stylesUsageRule from \"./rules/styles-usage\";\nimport stylesNamingRule from \"./rules/styles-naming\";\n\nconst plugin = {\n rules: {\n \"styles-usage\": stylesUsageRule,\n \"styles-naming\": stylesNamingRule,\n },\n};\n\nexport default plugin;\n","import plugin from \"../plugin\";\n\nexport = [\n {\n plugins: { rnzeus: plugin },\n rules: {\n \"rnzeus/styles-usage\": \"error\",\n \"rnzeus/styles-naming\": \"error\",\n },\n },\n];\n"],"mappings":"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","names":["path","fs","import_node_path","DEFAULTS","path","rule"]}
1
+ {"version":3,"sources":["../../src/rules/styles-usage.ts","../../src/rules/styles-naming.ts","../../src/plugin.ts","../../src/configs/styles.ts"],"sourcesContent":["import type { Rule, SourceCode } from \"eslint\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n stylesSuffix?: string;\n stylesExtensions?: string[];\n directiveTag?: string;\n stylesObjectName?: string;\n\n /**\n * JSX props that should be treated as “style-like props”.\n * Example: [\"style\", \"contentContainerStyle\", \"columnWrapperStyle\"]\n */\n styleProps?: string[];\n\n /**\n * How to apply styleProps relative to defaults.\n * - \"merge\" (default): DEFAULTS.styleProps + styleProps (unique)\n * - \"override\": only styleProps\n */\n type?: \"merge\" | \"override\";\n }\n];\n\nconst DEFAULTS = {\n stylesSuffix: \".styles\",\n stylesExtensions: [\"ts\", \"tsx\"],\n directiveTag: \"rnzeus-styles-used\",\n stylesObjectName: \"styles\",\n\n styleProps: [\"style\", \"contentContainerStyle\"],\n} as const;\n\nconst stylesKeysCache = new Map<\n string,\n { mtimeMs: number; keys: Set<string> }\n>();\nconst MAX_CACHE = 200;\n\nfunction cacheSet(file: string, value: { mtimeMs: number; keys: Set<string> }) {\n if (stylesKeysCache.size >= MAX_CACHE) {\n const firstKey = stylesKeysCache.keys().next().value;\n if (firstKey) stylesKeysCache.delete(firstKey);\n }\n stylesKeysCache.set(file, value);\n}\n\nfunction fileProbablyUsesStyles(\n sourceCode: SourceCode,\n stylesSuffix: string,\n stylesObjectName: string\n): boolean {\n const ast: any = sourceCode.ast;\n const body: any[] = ast?.body ?? [];\n\n for (const n of body) {\n if (n.type !== \"ImportDeclaration\") continue;\n const v = n.source?.value;\n if (typeof v === \"string\" && v.includes(stylesSuffix)) return true;\n }\n\n const text = sourceCode.getText();\n return text.includes(`${stylesObjectName}.`);\n}\n\nfunction extractStyleKeysFromText(text: string): Set<string> {\n const keys = new Set<string>();\n\n const idx = text.indexOf(\"StyleSheet.create\");\n if (idx === -1) return keys;\n\n const braceStart = text.indexOf(\"{\", idx);\n if (braceStart === -1) return keys;\n\n let depth = 0;\n let readingKey = false;\n let currentKey = \"\";\n\n for (let i = braceStart; i < text.length; i++) {\n const ch = text[i];\n\n if (ch === \"{\") {\n depth++;\n continue;\n }\n\n if (ch === \"}\") {\n depth--;\n if (depth === 0) break;\n continue;\n }\n\n if (depth !== 1) continue;\n\n if (!readingKey && /[A-Za-z_$]/.test(ch)) {\n readingKey = true;\n currentKey = ch;\n continue;\n }\n\n if (readingKey) {\n if (/[\\w$]/.test(ch)) {\n currentKey += ch;\n continue;\n }\n\n if (ch === \":\") {\n keys.add(currentKey);\n readingKey = false;\n currentKey = \"\";\n continue;\n }\n\n readingKey = false;\n currentKey = \"\";\n }\n }\n\n return keys;\n}\n\nfunction resolveSiblingStylesFile(\n filename: string,\n stylesSuffix: string,\n stylesExtensions: readonly string[]\n): string | null {\n const dir = path.dirname(filename);\n const ext = path.extname(filename);\n const base = path.basename(filename, ext);\n\n for (const e of stylesExtensions) {\n const candidate = path.join(dir, `${base}${stylesSuffix}.${e}`);\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return null;\n}\n\nfunction parseDirectiveKeys(\n sourceCode: SourceCode,\n directiveTag: string\n): Set<string> {\n const used = new Set<string>();\n const tag = directiveTag.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const re = new RegExp(`${tag}\\\\s*:\\\\s*([^\\\\n\\\\r*]+)`, \"i\");\n\n for (const c of sourceCode.getAllComments()) {\n const match = c.value.match(re);\n if (!match) continue;\n\n match[1]\n .split(\"|\")\n .map((s) => s.trim())\n .filter(Boolean)\n .forEach((k) => used.add(k));\n }\n\n return used;\n}\n\nfunction isIdentifier(node: any, name: string): boolean {\n return node?.type === \"Identifier\" && node.name === name;\n}\n\nfunction isStylesMemberExpression(\n node: any,\n stylesObjectName: string\n): { key: string; computed: boolean } | null {\n if (node?.type !== \"MemberExpression\") return null;\n if (!isIdentifier(node.object, stylesObjectName)) return null;\n\n if (node.computed) {\n if (\n node.property?.type === \"Literal\" &&\n typeof node.property.value === \"string\"\n ) {\n return { key: node.property.value, computed: true };\n }\n return { key: \"\", computed: true };\n }\n\n if (node.property?.type === \"Identifier\") {\n return { key: node.property.name, computed: false };\n }\n\n return null;\n}\n\nfunction findBestReportNode(sourceCode: SourceCode): any {\n const ast: any = sourceCode.ast;\n const body: any[] = ast?.body ?? [];\n\n for (const n of body) {\n if (n.type !== \"ImportDeclaration\") continue;\n const v = n.source?.value;\n if (typeof v === \"string\" && v.includes(\".styles\")) return n;\n }\n\n return ast;\n}\n\nfunction uniqueStrings(items: readonly string[]): string[] {\n const out: string[] = [];\n const seen = new Set<string>();\n for (const s of items) {\n if (!s || typeof s !== \"string\") continue;\n if (seen.has(s)) continue;\n seen.add(s);\n out.push(s);\n }\n return out;\n}\n\nfunction buildStyleProps(\n defaults: readonly string[],\n incoming: string[] | undefined,\n mode: \"merge\" | \"override\"\n): Set<string> {\n if (!incoming || incoming.length === 0) return new Set(defaults);\n\n if (mode === \"override\") {\n return new Set(uniqueStrings(incoming));\n }\n\n // merge (default): defaults + incoming (unique)\n return new Set(uniqueStrings([...defaults, ...incoming]));\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Ensures styles declared in sibling <File>.styles.ts(x) are used in <File>.ts(x).\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n stylesSuffix: { type: \"string\" },\n stylesExtensions: { type: \"array\", items: { type: \"string\" } },\n directiveTag: { type: \"string\" },\n stylesObjectName: { type: \"string\" },\n\n styleProps: { type: \"array\", items: { type: \"string\" } },\n type: { type: \"string\", enum: [\"merge\", \"override\"] },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unusedStyles: \"Unused styles in {{stylesFile}}: {{keys}}\",\n noWholeStylesObject:\n \"Do not pass the whole styles object. Use style={styles.foo}.\",\n dynamicNeedsDirective:\n \"Dynamic styles access ({{stylesName}}[...]) requires directive: {{tag}}\",\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n\n const stylesSuffix = opt.stylesSuffix ?? DEFAULTS.stylesSuffix;\n const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;\n const directiveTag = opt.directiveTag ?? DEFAULTS.directiveTag;\n const stylesObjectName = opt.stylesObjectName ?? DEFAULTS.stylesObjectName;\n\n const mode: \"merge\" | \"override\" = opt.type ?? \"merge\";\n const STYLE_PROPS = buildStyleProps(\n DEFAULTS.styleProps,\n opt.styleProps,\n mode\n );\n\n const filename = context.filename;\n const sourceCode = context.sourceCode;\n\n if (!fileProbablyUsesStyles(sourceCode, stylesSuffix, stylesObjectName))\n return {};\n\n const ext = path.extname(filename);\n if (ext !== \".ts\" && ext !== \".tsx\") return {};\n\n const stylesPath = resolveSiblingStylesFile(\n filename,\n stylesSuffix,\n stylesExtensions\n );\n if (!stylesPath) return {};\n\n let declaredKeys: Set<string> = new Set();\n\n try {\n const stat = fs.statSync(stylesPath);\n const cached = stylesKeysCache.get(stylesPath);\n\n if (!cached || cached.mtimeMs !== stat.mtimeMs) {\n const text = fs.readFileSync(stylesPath, \"utf8\");\n const keys = extractStyleKeysFromText(text);\n cacheSet(stylesPath, { mtimeMs: stat.mtimeMs, keys });\n declaredKeys = keys;\n } else {\n declaredKeys = cached.keys;\n }\n } catch {\n declaredKeys = new Set();\n }\n\n const usedKeys = new Set<string>();\n const directiveKeys = parseDirectiveKeys(sourceCode, directiveTag);\n directiveKeys.forEach((k) => usedKeys.add(k));\n\n let sawDynamic = false;\n let firstDynamicNode: any | null = null;\n\n function recordFromNode(node: any) {\n const info = isStylesMemberExpression(node, stylesObjectName);\n if (!info) return;\n\n if (info.key) {\n usedKeys.add(info.key);\n } else {\n sawDynamic = true;\n if (!firstDynamicNode) firstDynamicNode = node;\n }\n }\n\n function checkNoWholeStylesObject(node: any) {\n // <Child styles={styles} /> — запрещаем\n if (node.name?.type !== \"JSXIdentifier\") return;\n if (node.name.name !== \"styles\") return;\n\n const expr = node.value?.expression;\n if (isIdentifier(expr, stylesObjectName)) {\n context.report({ node, messageId: \"noWholeStylesObject\" });\n }\n }\n\n function visitExpression(expr: any) {\n if (!expr) return;\n\n recordFromNode(expr);\n\n if (expr.type === \"ArrayExpression\") {\n expr.elements?.forEach(visitExpression);\n } else if (expr.type === \"ObjectExpression\") {\n expr.properties?.forEach((p: any) => visitExpression(p.value));\n } else if (expr.type === \"ConditionalExpression\") {\n visitExpression(expr.consequent);\n visitExpression(expr.alternate);\n } else if (expr.type === \"LogicalExpression\") {\n visitExpression(expr.left);\n visitExpression(expr.right);\n }\n }\n\n function onJSXAttribute(node: any) {\n if (\n node.name?.type === \"JSXIdentifier\" &&\n STYLE_PROPS.has(node.name.name)\n ) {\n const expr = node.value?.expression;\n if (expr) visitExpression(expr);\n }\n\n checkNoWholeStylesObject(node);\n }\n\n function finish() {\n if (sawDynamic && directiveKeys.size === 0 && firstDynamicNode) {\n context.report({\n node: firstDynamicNode,\n messageId: \"dynamicNeedsDirective\",\n data: { tag: directiveTag, stylesName: stylesObjectName },\n });\n }\n\n const unused = [...declaredKeys].filter((k) => !usedKeys.has(k));\n if (unused.length) {\n context.report({\n node: findBestReportNode(sourceCode),\n messageId: \"unusedStyles\",\n data: {\n stylesFile: path.basename(stylesPath as string),\n keys: unused.sort().join(\", \"),\n },\n });\n }\n }\n\n return {\n JSXAttribute: onJSXAttribute,\n \"Program:exit\": finish,\n };\n },\n};\n\nexport default rule;\n","import type { Rule } from \"eslint\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n /**\n * Suffix for styles files.\n * Default: \".styles\"\n */\n stylesSuffix?: string;\n\n /**\n * Allowed extensions.\n * Default: [\"ts\", \"tsx\"]\n */\n stylesExtensions?: string[];\n }\n];\n\nconst DEFAULTS = {\n stylesSuffix: \".styles\",\n stylesExtensions: [\"ts\", \"tsx\"],\n} as const;\n\nconst SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;\n\nfunction extractTopLevelStyleKeys(\n text: string\n): { key: string; index: number }[] {\n const result: { key: string; index: number }[] = [];\n\n const idx = text.indexOf(\"StyleSheet.create\");\n if (idx === -1) return result;\n\n const braceStart = text.indexOf(\"{\", idx);\n if (braceStart === -1) return result;\n\n let depth = 0;\n let readingKey = false;\n let currentKey = \"\";\n let keyStartIndex = -1;\n\n for (let i = braceStart; i < text.length; i++) {\n const ch = text[i];\n\n if (ch === \"{\") {\n depth++;\n continue;\n }\n\n if (ch === \"}\") {\n depth--;\n if (depth === 0) break;\n continue;\n }\n\n if (depth !== 1) continue;\n\n if (!readingKey && /[A-Za-z_$]/.test(ch)) {\n readingKey = true;\n currentKey = ch;\n keyStartIndex = i;\n continue;\n }\n\n if (readingKey) {\n if (/[\\w$]/.test(ch)) {\n currentKey += ch;\n continue;\n }\n\n if (ch === \":\") {\n result.push({ key: currentKey, index: keyStartIndex });\n readingKey = false;\n currentKey = \"\";\n keyStartIndex = -1;\n continue;\n }\n\n readingKey = false;\n currentKey = \"\";\n keyStartIndex = -1;\n }\n }\n\n return result;\n}\n\nfunction isStylesFile(\n filename: string,\n stylesSuffix: string,\n stylesExtensions: readonly string[]\n): boolean {\n const ext = path.extname(filename);\n if (!stylesExtensions.includes(ext.replace(\".\", \"\"))) return false;\n return path.basename(filename).includes(stylesSuffix);\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Enforce snake_case naming for style keys in *.styles.ts(x) files.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n stylesSuffix: { type: \"string\" },\n stylesExtensions: { type: \"array\", items: { type: \"string\" } },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n invalidName:\n 'Style name \"{{name}}\" must be snake_case (e.g. \"{{suggestion}}\").',\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n\n const stylesSuffix = opt.stylesSuffix ?? DEFAULTS.stylesSuffix;\n const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;\n\n const filename = context.getFilename();\n if (!isStylesFile(filename, stylesSuffix, stylesExtensions)) {\n return {};\n }\n\n const sourceCode = context.getSourceCode();\n const text = sourceCode.getText();\n\n const keys = extractTopLevelStyleKeys(text);\n\n function toSnakeCase(input: string): string {\n return input\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[-\\s]+/g, \"_\")\n .toLowerCase();\n }\n\n for (const { key, index } of keys) {\n if (!SNAKE_CASE_RE.test(key)) {\n const loc = sourceCode.getLocFromIndex(index);\n\n context.report({\n loc: {\n start: loc,\n end: { line: loc.line, column: loc.column + key.length },\n },\n messageId: \"invalidName\",\n data: {\n name: key,\n suggestion: toSnakeCase(key),\n },\n });\n }\n }\n\n return {};\n },\n};\n\nexport default rule;\n","import stylesUsageRule from \"./rules/styles-usage\";\nimport stylesNamingRule from \"./rules/styles-naming\";\n\nconst plugin = {\n rules: {\n \"styles-usage\": stylesUsageRule,\n \"styles-naming\": stylesNamingRule,\n },\n};\n\nexport default plugin;\n","import plugin from \"../plugin\";\n\nexport = [\n {\n plugins: { rnzeus: plugin },\n rules: {\n \"rnzeus/styles-usage\": \"error\",\n \"rnzeus/styles-naming\": \"error\",\n },\n },\n];\n"],"mappings":"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","names":["path","fs","import_node_path","DEFAULTS","path","rule"]}
package/dist/plugin.cjs CHANGED
@@ -41,7 +41,8 @@ var DEFAULTS = {
41
41
  stylesSuffix: ".styles",
42
42
  stylesExtensions: ["ts", "tsx"],
43
43
  directiveTag: "rnzeus-styles-used",
44
- stylesObjectName: "styles"
44
+ stylesObjectName: "styles",
45
+ styleProps: ["style", "contentContainerStyle"]
45
46
  };
46
47
  var stylesKeysCache = /* @__PURE__ */ new Map();
47
48
  var MAX_CACHE = 200;
@@ -52,7 +53,7 @@ function cacheSet(file, value) {
52
53
  }
53
54
  stylesKeysCache.set(file, value);
54
55
  }
55
- function fileProbablyUsesStyles(sourceCode, stylesSuffix) {
56
+ function fileProbablyUsesStyles(sourceCode, stylesSuffix, stylesObjectName) {
56
57
  const ast = sourceCode.ast;
57
58
  const body = ast?.body ?? [];
58
59
  for (const n of body) {
@@ -60,7 +61,8 @@ function fileProbablyUsesStyles(sourceCode, stylesSuffix) {
60
61
  const v = n.source?.value;
61
62
  if (typeof v === "string" && v.includes(stylesSuffix)) return true;
62
63
  }
63
- return sourceCode.getText().includes("styles.");
64
+ const text = sourceCode.getText();
65
+ return text.includes(`${stylesObjectName}.`);
64
66
  }
65
67
  function extractStyleKeysFromText(text) {
66
68
  const keys = /* @__PURE__ */ new Set();
@@ -153,6 +155,24 @@ function findBestReportNode(sourceCode) {
153
155
  }
154
156
  return ast;
155
157
  }
158
+ function uniqueStrings(items) {
159
+ const out = [];
160
+ const seen = /* @__PURE__ */ new Set();
161
+ for (const s of items) {
162
+ if (!s || typeof s !== "string") continue;
163
+ if (seen.has(s)) continue;
164
+ seen.add(s);
165
+ out.push(s);
166
+ }
167
+ return out;
168
+ }
169
+ function buildStyleProps(defaults, incoming, mode) {
170
+ if (!incoming || incoming.length === 0) return new Set(defaults);
171
+ if (mode === "override") {
172
+ return new Set(uniqueStrings(incoming));
173
+ }
174
+ return new Set(uniqueStrings([...defaults, ...incoming]));
175
+ }
156
176
  var rule = {
157
177
  meta: {
158
178
  type: "problem",
@@ -166,7 +186,9 @@ var rule = {
166
186
  stylesSuffix: { type: "string" },
167
187
  stylesExtensions: { type: "array", items: { type: "string" } },
168
188
  directiveTag: { type: "string" },
169
- stylesObjectName: { type: "string" }
189
+ stylesObjectName: { type: "string" },
190
+ styleProps: { type: "array", items: { type: "string" } },
191
+ type: { type: "string", enum: ["merge", "override"] }
170
192
  },
171
193
  additionalProperties: false
172
194
  }
@@ -183,9 +205,16 @@ var rule = {
183
205
  const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;
184
206
  const directiveTag = opt.directiveTag ?? DEFAULTS.directiveTag;
185
207
  const stylesObjectName = opt.stylesObjectName ?? DEFAULTS.stylesObjectName;
186
- const filename = context.getFilename();
187
- const sourceCode = context.getSourceCode();
188
- if (!fileProbablyUsesStyles(sourceCode, stylesSuffix)) return {};
208
+ const mode = opt.type ?? "merge";
209
+ const STYLE_PROPS = buildStyleProps(
210
+ DEFAULTS.styleProps,
211
+ opt.styleProps,
212
+ mode
213
+ );
214
+ const filename = context.filename;
215
+ const sourceCode = context.sourceCode;
216
+ if (!fileProbablyUsesStyles(sourceCode, stylesSuffix, stylesObjectName))
217
+ return {};
189
218
  const ext = import_node_path.default.extname(filename);
190
219
  if (ext !== ".ts" && ext !== ".tsx") return {};
191
220
  const stylesPath = resolveSiblingStylesFile(
@@ -248,7 +277,7 @@ var rule = {
248
277
  }
249
278
  }
250
279
  function onJSXAttribute(node) {
251
- if (node.name?.name === "style") {
280
+ if (node.name?.type === "JSXIdentifier" && STYLE_PROPS.has(node.name.name)) {
252
281
  const expr = node.value?.expression;
253
282
  if (expr) visitExpression(expr);
254
283
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts","../src/rules/styles-usage.ts","../src/rules/styles-naming.ts"],"sourcesContent":["import stylesUsageRule from \"./rules/styles-usage\";\nimport stylesNamingRule from \"./rules/styles-naming\";\n\nconst plugin = {\n rules: {\n \"styles-usage\": stylesUsageRule,\n \"styles-naming\": stylesNamingRule,\n },\n};\n\nexport default plugin;\n","import type { Rule, SourceCode } from \"eslint\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n stylesSuffix?: string;\n stylesExtensions?: string[];\n directiveTag?: string;\n stylesObjectName?: string;\n }\n];\n\nconst DEFAULTS = {\n stylesSuffix: \".styles\",\n stylesExtensions: [\"ts\", \"tsx\"],\n directiveTag: \"rnzeus-styles-used\",\n stylesObjectName: \"styles\",\n} as const;\n\n/**\n * Cache: stylesPath -> { mtimeMs, keys }\n */\nconst stylesKeysCache = new Map<\n string,\n { mtimeMs: number; keys: Set<string> }\n>();\n\nconst MAX_CACHE = 200;\n\nfunction cacheSet(file: string, value: { mtimeMs: number; keys: Set<string> }) {\n if (stylesKeysCache.size >= MAX_CACHE) {\n const firstKey = stylesKeysCache.keys().next().value;\n if (firstKey) stylesKeysCache.delete(firstKey);\n }\n stylesKeysCache.set(file, value);\n}\n\nfunction fileProbablyUsesStyles(\n sourceCode: SourceCode,\n stylesSuffix: string\n): boolean {\n const ast: any = sourceCode.ast;\n const body: any[] = ast?.body ?? [];\n\n for (const n of body) {\n if (n.type !== \"ImportDeclaration\") continue;\n const v = n.source?.value;\n if (typeof v === \"string\" && v.includes(stylesSuffix)) return true;\n }\n\n // cheap fallback\n return sourceCode.getText().includes(\"styles.\");\n}\n\nfunction extractStyleKeysFromText(text: string): Set<string> {\n const keys = new Set<string>();\n\n const idx = text.indexOf(\"StyleSheet.create\");\n if (idx === -1) return keys;\n\n const braceStart = text.indexOf(\"{\", idx);\n if (braceStart === -1) return keys;\n\n let depth = 0;\n let readingKey = false;\n let currentKey = \"\";\n\n for (let i = braceStart; i < text.length; i++) {\n const ch = text[i];\n\n if (ch === \"{\") {\n depth++;\n continue;\n }\n\n if (ch === \"}\") {\n depth--;\n if (depth === 0) break;\n continue;\n }\n\n if (depth !== 1) continue;\n\n if (!readingKey && /[A-Za-z_$]/.test(ch)) {\n readingKey = true;\n currentKey = ch;\n continue;\n }\n\n if (readingKey) {\n if (/[\\w$]/.test(ch)) {\n currentKey += ch;\n continue;\n }\n\n if (ch === \":\") {\n keys.add(currentKey);\n readingKey = false;\n currentKey = \"\";\n continue;\n }\n\n readingKey = false;\n currentKey = \"\";\n }\n }\n\n return keys;\n}\n\nfunction resolveSiblingStylesFile(\n filename: string,\n stylesSuffix: string,\n stylesExtensions: readonly string[]\n): string | null {\n const dir = path.dirname(filename);\n const ext = path.extname(filename);\n const base = path.basename(filename, ext);\n\n for (const e of stylesExtensions) {\n const candidate = path.join(dir, `${base}${stylesSuffix}.${e}`);\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return null;\n}\n\nfunction parseDirectiveKeys(\n sourceCode: SourceCode,\n directiveTag: string\n): Set<string> {\n const used = new Set<string>();\n const tag = directiveTag.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const re = new RegExp(`${tag}\\\\s*:\\\\s*([^\\\\n\\\\r*]+)`, \"i\");\n\n for (const c of sourceCode.getAllComments()) {\n const match = c.value.match(re);\n if (!match) continue;\n\n match[1]\n .split(\"|\")\n .map((s) => s.trim())\n .filter(Boolean)\n .forEach((k) => used.add(k));\n }\n\n return used;\n}\n\nfunction isIdentifier(node: any, name: string): boolean {\n return node?.type === \"Identifier\" && node.name === name;\n}\n\nfunction isStylesMemberExpression(\n node: any,\n stylesObjectName: string\n): { key: string; computed: boolean } | null {\n if (node?.type !== \"MemberExpression\") return null;\n if (!isIdentifier(node.object, stylesObjectName)) return null;\n\n if (node.computed) {\n if (\n node.property?.type === \"Literal\" &&\n typeof node.property.value === \"string\"\n ) {\n return { key: node.property.value, computed: true };\n }\n return { key: \"\", computed: true };\n }\n\n if (node.property?.type === \"Identifier\") {\n return { key: node.property.name, computed: false };\n }\n\n return null;\n}\n\nfunction findBestReportNode(sourceCode: SourceCode): any {\n const ast: any = sourceCode.ast;\n const body: any[] = ast?.body ?? [];\n\n for (const n of body) {\n if (n.type !== \"ImportDeclaration\") continue;\n const v = n.source?.value;\n if (typeof v === \"string\" && v.includes(\".styles\")) return n;\n }\n\n return ast;\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Ensures styles declared in sibling <File>.styles.ts(x) are used in <File>.ts(x).\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n stylesSuffix: { type: \"string\" },\n stylesExtensions: { type: \"array\", items: { type: \"string\" } },\n directiveTag: { type: \"string\" },\n stylesObjectName: { type: \"string\" },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unusedStyles: \"Unused styles in {{stylesFile}}: {{keys}}\",\n noWholeStylesObject:\n \"Do not pass the whole styles object. Use style={styles.foo}.\",\n dynamicNeedsDirective:\n \"Dynamic styles access ({{stylesName}}[...]) requires directive: {{tag}}\",\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n\n const stylesSuffix = opt.stylesSuffix ?? DEFAULTS.stylesSuffix;\n const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;\n const directiveTag = opt.directiveTag ?? DEFAULTS.directiveTag;\n const stylesObjectName = opt.stylesObjectName ?? DEFAULTS.stylesObjectName;\n\n const filename = context.getFilename();\n const sourceCode = context.getSourceCode();\n\n if (!fileProbablyUsesStyles(sourceCode, stylesSuffix)) return {};\n\n const ext = path.extname(filename);\n if (ext !== \".ts\" && ext !== \".tsx\") return {};\n\n const stylesPath = resolveSiblingStylesFile(\n filename,\n stylesSuffix,\n stylesExtensions\n );\n if (!stylesPath) return {};\n\n let declaredKeys: Set<string> = new Set();\n\n try {\n const stat = fs.statSync(stylesPath);\n const cached = stylesKeysCache.get(stylesPath);\n\n if (!cached || cached.mtimeMs !== stat.mtimeMs) {\n const text = fs.readFileSync(stylesPath, \"utf8\");\n const keys = extractStyleKeysFromText(text);\n cacheSet(stylesPath, { mtimeMs: stat.mtimeMs, keys });\n declaredKeys = keys;\n } else {\n declaredKeys = cached.keys;\n }\n } catch {\n declaredKeys = new Set();\n }\n\n const usedKeys = new Set<string>();\n const directiveKeys = parseDirectiveKeys(sourceCode, directiveTag);\n directiveKeys.forEach((k) => usedKeys.add(k));\n\n let sawDynamic = false;\n let firstDynamicNode: any | null = null;\n\n function recordFromNode(node: any) {\n const info = isStylesMemberExpression(node, stylesObjectName);\n if (!info) return;\n\n if (info.key) {\n usedKeys.add(info.key);\n } else {\n sawDynamic = true;\n if (!firstDynamicNode) firstDynamicNode = node;\n }\n }\n\n function checkNoWholeStylesObject(node: any) {\n if (node.name?.type !== \"JSXIdentifier\") return;\n if (node.name.name !== \"styles\") return;\n\n const expr = node.value?.expression;\n if (isIdentifier(expr, stylesObjectName)) {\n context.report({ node, messageId: \"noWholeStylesObject\" });\n }\n }\n\n function visitExpression(expr: any) {\n if (!expr) return;\n\n recordFromNode(expr);\n\n if (expr.type === \"ArrayExpression\") {\n expr.elements?.forEach(visitExpression);\n } else if (expr.type === \"ObjectExpression\") {\n expr.properties?.forEach((p: any) => visitExpression(p.value));\n } else if (expr.type === \"ConditionalExpression\") {\n visitExpression(expr.consequent);\n visitExpression(expr.alternate);\n } else if (expr.type === \"LogicalExpression\") {\n visitExpression(expr.left);\n visitExpression(expr.right);\n }\n }\n\n function onJSXAttribute(node: any) {\n if (node.name?.name === \"style\") {\n const expr = node.value?.expression;\n if (expr) visitExpression(expr);\n }\n checkNoWholeStylesObject(node);\n }\n\n function finish() {\n if (sawDynamic && directiveKeys.size === 0 && firstDynamicNode) {\n context.report({\n node: firstDynamicNode,\n messageId: \"dynamicNeedsDirective\",\n data: { tag: directiveTag, stylesName: stylesObjectName },\n });\n }\n\n const unused = [...declaredKeys].filter((k) => !usedKeys.has(k));\n if (unused.length) {\n context.report({\n node: findBestReportNode(sourceCode),\n messageId: \"unusedStyles\",\n data: {\n stylesFile: path.basename(stylesPath as string),\n keys: unused.sort().join(\", \"),\n },\n });\n }\n }\n\n return {\n JSXAttribute: onJSXAttribute,\n \"Program:exit\": finish,\n };\n },\n};\n\nexport default rule;\n","import type { Rule } from \"eslint\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n /**\n * Suffix for styles files.\n * Default: \".styles\"\n */\n stylesSuffix?: string;\n\n /**\n * Allowed extensions.\n * Default: [\"ts\", \"tsx\"]\n */\n stylesExtensions?: string[];\n }\n];\n\nconst DEFAULTS = {\n stylesSuffix: \".styles\",\n stylesExtensions: [\"ts\", \"tsx\"],\n} as const;\n\nconst SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;\n\nfunction extractTopLevelStyleKeys(\n text: string\n): { key: string; index: number }[] {\n const result: { key: string; index: number }[] = [];\n\n const idx = text.indexOf(\"StyleSheet.create\");\n if (idx === -1) return result;\n\n const braceStart = text.indexOf(\"{\", idx);\n if (braceStart === -1) return result;\n\n let depth = 0;\n let readingKey = false;\n let currentKey = \"\";\n let keyStartIndex = -1;\n\n for (let i = braceStart; i < text.length; i++) {\n const ch = text[i];\n\n if (ch === \"{\") {\n depth++;\n continue;\n }\n\n if (ch === \"}\") {\n depth--;\n if (depth === 0) break;\n continue;\n }\n\n if (depth !== 1) continue;\n\n if (!readingKey && /[A-Za-z_$]/.test(ch)) {\n readingKey = true;\n currentKey = ch;\n keyStartIndex = i;\n continue;\n }\n\n if (readingKey) {\n if (/[\\w$]/.test(ch)) {\n currentKey += ch;\n continue;\n }\n\n if (ch === \":\") {\n result.push({ key: currentKey, index: keyStartIndex });\n readingKey = false;\n currentKey = \"\";\n keyStartIndex = -1;\n continue;\n }\n\n readingKey = false;\n currentKey = \"\";\n keyStartIndex = -1;\n }\n }\n\n return result;\n}\n\nfunction isStylesFile(\n filename: string,\n stylesSuffix: string,\n stylesExtensions: readonly string[]\n): boolean {\n const ext = path.extname(filename);\n if (!stylesExtensions.includes(ext.replace(\".\", \"\"))) return false;\n return path.basename(filename).includes(stylesSuffix);\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Enforce snake_case naming for style keys in *.styles.ts(x) files.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n stylesSuffix: { type: \"string\" },\n stylesExtensions: { type: \"array\", items: { type: \"string\" } },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n invalidName:\n 'Style name \"{{name}}\" must be snake_case (e.g. \"{{suggestion}}\").',\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n\n const stylesSuffix = opt.stylesSuffix ?? DEFAULTS.stylesSuffix;\n const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;\n\n const filename = context.getFilename();\n if (!isStylesFile(filename, stylesSuffix, stylesExtensions)) {\n return {};\n }\n\n const sourceCode = context.getSourceCode();\n const text = sourceCode.getText();\n\n const keys = extractTopLevelStyleKeys(text);\n\n function toSnakeCase(input: string): string {\n return input\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[-\\s]+/g, \"_\")\n .toLowerCase();\n }\n\n for (const { key, index } of keys) {\n if (!SNAKE_CASE_RE.test(key)) {\n const loc = sourceCode.getLocFromIndex(index);\n\n context.report({\n loc: {\n start: loc,\n end: { line: loc.line, column: loc.column + key.length },\n },\n messageId: \"invalidName\",\n data: {\n name: key,\n suggestion: toSnakeCase(key),\n },\n });\n }\n }\n\n return {};\n },\n};\n\nexport default rule;\n"],"mappings":"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","names":["path","fs","import_node_path","DEFAULTS","path","rule"]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/rules/styles-usage.ts","../src/rules/styles-naming.ts"],"sourcesContent":["import stylesUsageRule from \"./rules/styles-usage\";\nimport stylesNamingRule from \"./rules/styles-naming\";\n\nconst plugin = {\n rules: {\n \"styles-usage\": stylesUsageRule,\n \"styles-naming\": stylesNamingRule,\n },\n};\n\nexport default plugin;\n","import type { Rule, SourceCode } from \"eslint\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n stylesSuffix?: string;\n stylesExtensions?: string[];\n directiveTag?: string;\n stylesObjectName?: string;\n\n /**\n * JSX props that should be treated as “style-like props”.\n * Example: [\"style\", \"contentContainerStyle\", \"columnWrapperStyle\"]\n */\n styleProps?: string[];\n\n /**\n * How to apply styleProps relative to defaults.\n * - \"merge\" (default): DEFAULTS.styleProps + styleProps (unique)\n * - \"override\": only styleProps\n */\n type?: \"merge\" | \"override\";\n }\n];\n\nconst DEFAULTS = {\n stylesSuffix: \".styles\",\n stylesExtensions: [\"ts\", \"tsx\"],\n directiveTag: \"rnzeus-styles-used\",\n stylesObjectName: \"styles\",\n\n styleProps: [\"style\", \"contentContainerStyle\"],\n} as const;\n\nconst stylesKeysCache = new Map<\n string,\n { mtimeMs: number; keys: Set<string> }\n>();\nconst MAX_CACHE = 200;\n\nfunction cacheSet(file: string, value: { mtimeMs: number; keys: Set<string> }) {\n if (stylesKeysCache.size >= MAX_CACHE) {\n const firstKey = stylesKeysCache.keys().next().value;\n if (firstKey) stylesKeysCache.delete(firstKey);\n }\n stylesKeysCache.set(file, value);\n}\n\nfunction fileProbablyUsesStyles(\n sourceCode: SourceCode,\n stylesSuffix: string,\n stylesObjectName: string\n): boolean {\n const ast: any = sourceCode.ast;\n const body: any[] = ast?.body ?? [];\n\n for (const n of body) {\n if (n.type !== \"ImportDeclaration\") continue;\n const v = n.source?.value;\n if (typeof v === \"string\" && v.includes(stylesSuffix)) return true;\n }\n\n const text = sourceCode.getText();\n return text.includes(`${stylesObjectName}.`);\n}\n\nfunction extractStyleKeysFromText(text: string): Set<string> {\n const keys = new Set<string>();\n\n const idx = text.indexOf(\"StyleSheet.create\");\n if (idx === -1) return keys;\n\n const braceStart = text.indexOf(\"{\", idx);\n if (braceStart === -1) return keys;\n\n let depth = 0;\n let readingKey = false;\n let currentKey = \"\";\n\n for (let i = braceStart; i < text.length; i++) {\n const ch = text[i];\n\n if (ch === \"{\") {\n depth++;\n continue;\n }\n\n if (ch === \"}\") {\n depth--;\n if (depth === 0) break;\n continue;\n }\n\n if (depth !== 1) continue;\n\n if (!readingKey && /[A-Za-z_$]/.test(ch)) {\n readingKey = true;\n currentKey = ch;\n continue;\n }\n\n if (readingKey) {\n if (/[\\w$]/.test(ch)) {\n currentKey += ch;\n continue;\n }\n\n if (ch === \":\") {\n keys.add(currentKey);\n readingKey = false;\n currentKey = \"\";\n continue;\n }\n\n readingKey = false;\n currentKey = \"\";\n }\n }\n\n return keys;\n}\n\nfunction resolveSiblingStylesFile(\n filename: string,\n stylesSuffix: string,\n stylesExtensions: readonly string[]\n): string | null {\n const dir = path.dirname(filename);\n const ext = path.extname(filename);\n const base = path.basename(filename, ext);\n\n for (const e of stylesExtensions) {\n const candidate = path.join(dir, `${base}${stylesSuffix}.${e}`);\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return null;\n}\n\nfunction parseDirectiveKeys(\n sourceCode: SourceCode,\n directiveTag: string\n): Set<string> {\n const used = new Set<string>();\n const tag = directiveTag.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const re = new RegExp(`${tag}\\\\s*:\\\\s*([^\\\\n\\\\r*]+)`, \"i\");\n\n for (const c of sourceCode.getAllComments()) {\n const match = c.value.match(re);\n if (!match) continue;\n\n match[1]\n .split(\"|\")\n .map((s) => s.trim())\n .filter(Boolean)\n .forEach((k) => used.add(k));\n }\n\n return used;\n}\n\nfunction isIdentifier(node: any, name: string): boolean {\n return node?.type === \"Identifier\" && node.name === name;\n}\n\nfunction isStylesMemberExpression(\n node: any,\n stylesObjectName: string\n): { key: string; computed: boolean } | null {\n if (node?.type !== \"MemberExpression\") return null;\n if (!isIdentifier(node.object, stylesObjectName)) return null;\n\n if (node.computed) {\n if (\n node.property?.type === \"Literal\" &&\n typeof node.property.value === \"string\"\n ) {\n return { key: node.property.value, computed: true };\n }\n return { key: \"\", computed: true };\n }\n\n if (node.property?.type === \"Identifier\") {\n return { key: node.property.name, computed: false };\n }\n\n return null;\n}\n\nfunction findBestReportNode(sourceCode: SourceCode): any {\n const ast: any = sourceCode.ast;\n const body: any[] = ast?.body ?? [];\n\n for (const n of body) {\n if (n.type !== \"ImportDeclaration\") continue;\n const v = n.source?.value;\n if (typeof v === \"string\" && v.includes(\".styles\")) return n;\n }\n\n return ast;\n}\n\nfunction uniqueStrings(items: readonly string[]): string[] {\n const out: string[] = [];\n const seen = new Set<string>();\n for (const s of items) {\n if (!s || typeof s !== \"string\") continue;\n if (seen.has(s)) continue;\n seen.add(s);\n out.push(s);\n }\n return out;\n}\n\nfunction buildStyleProps(\n defaults: readonly string[],\n incoming: string[] | undefined,\n mode: \"merge\" | \"override\"\n): Set<string> {\n if (!incoming || incoming.length === 0) return new Set(defaults);\n\n if (mode === \"override\") {\n return new Set(uniqueStrings(incoming));\n }\n\n // merge (default): defaults + incoming (unique)\n return new Set(uniqueStrings([...defaults, ...incoming]));\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Ensures styles declared in sibling <File>.styles.ts(x) are used in <File>.ts(x).\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n stylesSuffix: { type: \"string\" },\n stylesExtensions: { type: \"array\", items: { type: \"string\" } },\n directiveTag: { type: \"string\" },\n stylesObjectName: { type: \"string\" },\n\n styleProps: { type: \"array\", items: { type: \"string\" } },\n type: { type: \"string\", enum: [\"merge\", \"override\"] },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unusedStyles: \"Unused styles in {{stylesFile}}: {{keys}}\",\n noWholeStylesObject:\n \"Do not pass the whole styles object. Use style={styles.foo}.\",\n dynamicNeedsDirective:\n \"Dynamic styles access ({{stylesName}}[...]) requires directive: {{tag}}\",\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n\n const stylesSuffix = opt.stylesSuffix ?? DEFAULTS.stylesSuffix;\n const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;\n const directiveTag = opt.directiveTag ?? DEFAULTS.directiveTag;\n const stylesObjectName = opt.stylesObjectName ?? DEFAULTS.stylesObjectName;\n\n const mode: \"merge\" | \"override\" = opt.type ?? \"merge\";\n const STYLE_PROPS = buildStyleProps(\n DEFAULTS.styleProps,\n opt.styleProps,\n mode\n );\n\n const filename = context.filename;\n const sourceCode = context.sourceCode;\n\n if (!fileProbablyUsesStyles(sourceCode, stylesSuffix, stylesObjectName))\n return {};\n\n const ext = path.extname(filename);\n if (ext !== \".ts\" && ext !== \".tsx\") return {};\n\n const stylesPath = resolveSiblingStylesFile(\n filename,\n stylesSuffix,\n stylesExtensions\n );\n if (!stylesPath) return {};\n\n let declaredKeys: Set<string> = new Set();\n\n try {\n const stat = fs.statSync(stylesPath);\n const cached = stylesKeysCache.get(stylesPath);\n\n if (!cached || cached.mtimeMs !== stat.mtimeMs) {\n const text = fs.readFileSync(stylesPath, \"utf8\");\n const keys = extractStyleKeysFromText(text);\n cacheSet(stylesPath, { mtimeMs: stat.mtimeMs, keys });\n declaredKeys = keys;\n } else {\n declaredKeys = cached.keys;\n }\n } catch {\n declaredKeys = new Set();\n }\n\n const usedKeys = new Set<string>();\n const directiveKeys = parseDirectiveKeys(sourceCode, directiveTag);\n directiveKeys.forEach((k) => usedKeys.add(k));\n\n let sawDynamic = false;\n let firstDynamicNode: any | null = null;\n\n function recordFromNode(node: any) {\n const info = isStylesMemberExpression(node, stylesObjectName);\n if (!info) return;\n\n if (info.key) {\n usedKeys.add(info.key);\n } else {\n sawDynamic = true;\n if (!firstDynamicNode) firstDynamicNode = node;\n }\n }\n\n function checkNoWholeStylesObject(node: any) {\n // <Child styles={styles} /> — запрещаем\n if (node.name?.type !== \"JSXIdentifier\") return;\n if (node.name.name !== \"styles\") return;\n\n const expr = node.value?.expression;\n if (isIdentifier(expr, stylesObjectName)) {\n context.report({ node, messageId: \"noWholeStylesObject\" });\n }\n }\n\n function visitExpression(expr: any) {\n if (!expr) return;\n\n recordFromNode(expr);\n\n if (expr.type === \"ArrayExpression\") {\n expr.elements?.forEach(visitExpression);\n } else if (expr.type === \"ObjectExpression\") {\n expr.properties?.forEach((p: any) => visitExpression(p.value));\n } else if (expr.type === \"ConditionalExpression\") {\n visitExpression(expr.consequent);\n visitExpression(expr.alternate);\n } else if (expr.type === \"LogicalExpression\") {\n visitExpression(expr.left);\n visitExpression(expr.right);\n }\n }\n\n function onJSXAttribute(node: any) {\n if (\n node.name?.type === \"JSXIdentifier\" &&\n STYLE_PROPS.has(node.name.name)\n ) {\n const expr = node.value?.expression;\n if (expr) visitExpression(expr);\n }\n\n checkNoWholeStylesObject(node);\n }\n\n function finish() {\n if (sawDynamic && directiveKeys.size === 0 && firstDynamicNode) {\n context.report({\n node: firstDynamicNode,\n messageId: \"dynamicNeedsDirective\",\n data: { tag: directiveTag, stylesName: stylesObjectName },\n });\n }\n\n const unused = [...declaredKeys].filter((k) => !usedKeys.has(k));\n if (unused.length) {\n context.report({\n node: findBestReportNode(sourceCode),\n messageId: \"unusedStyles\",\n data: {\n stylesFile: path.basename(stylesPath as string),\n keys: unused.sort().join(\", \"),\n },\n });\n }\n }\n\n return {\n JSXAttribute: onJSXAttribute,\n \"Program:exit\": finish,\n };\n },\n};\n\nexport default rule;\n","import type { Rule } from \"eslint\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n /**\n * Suffix for styles files.\n * Default: \".styles\"\n */\n stylesSuffix?: string;\n\n /**\n * Allowed extensions.\n * Default: [\"ts\", \"tsx\"]\n */\n stylesExtensions?: string[];\n }\n];\n\nconst DEFAULTS = {\n stylesSuffix: \".styles\",\n stylesExtensions: [\"ts\", \"tsx\"],\n} as const;\n\nconst SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;\n\nfunction extractTopLevelStyleKeys(\n text: string\n): { key: string; index: number }[] {\n const result: { key: string; index: number }[] = [];\n\n const idx = text.indexOf(\"StyleSheet.create\");\n if (idx === -1) return result;\n\n const braceStart = text.indexOf(\"{\", idx);\n if (braceStart === -1) return result;\n\n let depth = 0;\n let readingKey = false;\n let currentKey = \"\";\n let keyStartIndex = -1;\n\n for (let i = braceStart; i < text.length; i++) {\n const ch = text[i];\n\n if (ch === \"{\") {\n depth++;\n continue;\n }\n\n if (ch === \"}\") {\n depth--;\n if (depth === 0) break;\n continue;\n }\n\n if (depth !== 1) continue;\n\n if (!readingKey && /[A-Za-z_$]/.test(ch)) {\n readingKey = true;\n currentKey = ch;\n keyStartIndex = i;\n continue;\n }\n\n if (readingKey) {\n if (/[\\w$]/.test(ch)) {\n currentKey += ch;\n continue;\n }\n\n if (ch === \":\") {\n result.push({ key: currentKey, index: keyStartIndex });\n readingKey = false;\n currentKey = \"\";\n keyStartIndex = -1;\n continue;\n }\n\n readingKey = false;\n currentKey = \"\";\n keyStartIndex = -1;\n }\n }\n\n return result;\n}\n\nfunction isStylesFile(\n filename: string,\n stylesSuffix: string,\n stylesExtensions: readonly string[]\n): boolean {\n const ext = path.extname(filename);\n if (!stylesExtensions.includes(ext.replace(\".\", \"\"))) return false;\n return path.basename(filename).includes(stylesSuffix);\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Enforce snake_case naming for style keys in *.styles.ts(x) files.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n stylesSuffix: { type: \"string\" },\n stylesExtensions: { type: \"array\", items: { type: \"string\" } },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n invalidName:\n 'Style name \"{{name}}\" must be snake_case (e.g. \"{{suggestion}}\").',\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n\n const stylesSuffix = opt.stylesSuffix ?? DEFAULTS.stylesSuffix;\n const stylesExtensions = opt.stylesExtensions ?? DEFAULTS.stylesExtensions;\n\n const filename = context.getFilename();\n if (!isStylesFile(filename, stylesSuffix, stylesExtensions)) {\n return {};\n }\n\n const sourceCode = context.getSourceCode();\n const text = sourceCode.getText();\n\n const keys = extractTopLevelStyleKeys(text);\n\n function toSnakeCase(input: string): string {\n return input\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[-\\s]+/g, \"_\")\n .toLowerCase();\n }\n\n for (const { key, index } of keys) {\n if (!SNAKE_CASE_RE.test(key)) {\n const loc = sourceCode.getLocFromIndex(index);\n\n context.report({\n loc: {\n start: loc,\n end: { line: loc.line, column: loc.column + key.length },\n },\n messageId: \"invalidName\",\n data: {\n name: key,\n suggestion: toSnakeCase(key),\n },\n });\n }\n }\n\n return {};\n },\n};\n\nexport default rule;\n"],"mappings":"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","names":["path","fs","import_node_path","DEFAULTS","path","rule"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rnzeus/eslint-plugin",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "commonjs",
5
5
  "main": "dist/plugin.cjs",
6
6
  "exports": {