@rnzeus/eslint-plugin 0.1.3 → 0.1.4
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 +87 -7
- package/dist/configs/imports.cjs +595 -0
- package/dist/configs/imports.cjs.map +1 -0
- package/dist/configs/styles.cjs +161 -0
- package/dist/configs/styles.cjs.map +1 -1
- package/dist/plugin.cjs +161 -0
- package/dist/plugin.cjs.map +1 -1
- package/package.json +3 -2
package/dist/configs/styles.cjs
CHANGED
|
@@ -413,9 +413,170 @@ var rule2 = {
|
|
|
413
413
|
};
|
|
414
414
|
var styles_naming_default = rule2;
|
|
415
415
|
|
|
416
|
+
// src/rules/slice-imports.ts
|
|
417
|
+
var import_node_path3 = __toESM(require("path"));
|
|
418
|
+
var DEFAULTS3 = {
|
|
419
|
+
layers: ["shared", "entities", "features", "widgets", "pages", "app"],
|
|
420
|
+
srcRoot: "src"
|
|
421
|
+
};
|
|
422
|
+
function normalizePath(filepath) {
|
|
423
|
+
return filepath.split(import_node_path3.default.sep).join("/");
|
|
424
|
+
}
|
|
425
|
+
function getFileContext(filename, srcRoot, layers) {
|
|
426
|
+
const normalized = normalizePath(filename);
|
|
427
|
+
const parts = normalized.split("/");
|
|
428
|
+
const srcIndex = parts.lastIndexOf(srcRoot);
|
|
429
|
+
if (srcIndex === -1) return null;
|
|
430
|
+
const layer = parts[srcIndex + 1];
|
|
431
|
+
if (!layer || !layers.includes(layer)) return null;
|
|
432
|
+
if (layer === "shared") {
|
|
433
|
+
return { layer, slice: null };
|
|
434
|
+
}
|
|
435
|
+
const slice = parts[srcIndex + 2];
|
|
436
|
+
if (!slice) return null;
|
|
437
|
+
return { layer, slice };
|
|
438
|
+
}
|
|
439
|
+
function parseAliasImport(importPath, layers) {
|
|
440
|
+
if (!importPath.startsWith("@")) return null;
|
|
441
|
+
const normalized = importPath.replace(/^@/, "");
|
|
442
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
443
|
+
const layer = parts[0];
|
|
444
|
+
if (!layer || !layers.includes(layer)) return null;
|
|
445
|
+
if (layer === "shared") {
|
|
446
|
+
return {
|
|
447
|
+
layer,
|
|
448
|
+
slice: null,
|
|
449
|
+
rest: parts.slice(1)
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
const slice = parts[1];
|
|
453
|
+
if (!slice) {
|
|
454
|
+
return {
|
|
455
|
+
layer,
|
|
456
|
+
slice: null,
|
|
457
|
+
rest: []
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
layer,
|
|
462
|
+
slice,
|
|
463
|
+
rest: parts.slice(2)
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function getLayerIndex(layer, layers) {
|
|
467
|
+
return layers.indexOf(layer);
|
|
468
|
+
}
|
|
469
|
+
function isRelativeImport(importPath) {
|
|
470
|
+
return importPath.startsWith("./") || importPath.startsWith("../");
|
|
471
|
+
}
|
|
472
|
+
function isCrossSliceXImport(imported, currentSlice) {
|
|
473
|
+
return imported.rest[0] === "@x" && imported.rest[1] === currentSlice;
|
|
474
|
+
}
|
|
475
|
+
var rule3 = {
|
|
476
|
+
meta: {
|
|
477
|
+
type: "problem",
|
|
478
|
+
docs: {
|
|
479
|
+
description: "Enforces FSD import boundaries: layer order, same-slice relative imports only, and cross-slice access only through @x/<currentSlice>."
|
|
480
|
+
},
|
|
481
|
+
schema: [
|
|
482
|
+
{
|
|
483
|
+
type: "object",
|
|
484
|
+
properties: {
|
|
485
|
+
layers: {
|
|
486
|
+
type: "array",
|
|
487
|
+
items: { type: "string" }
|
|
488
|
+
},
|
|
489
|
+
srcRoot: { type: "string" }
|
|
490
|
+
},
|
|
491
|
+
additionalProperties: false
|
|
492
|
+
}
|
|
493
|
+
],
|
|
494
|
+
messages: {
|
|
495
|
+
forbiddenHigherLayer: 'Layer "{{currentLayer}}" cannot import from higher layer "{{importedLayer}}".',
|
|
496
|
+
sameSliceMustBeRelative: 'Same-slice imports must be relative. Replace "{{importPath}}" with a relative path.',
|
|
497
|
+
crossSliceMustUseX: 'Cross-slice imports inside layer "{{layer}}" are allowed only through "@{{layer}}/{{targetSlice}}/@x/{{currentSlice}}".'
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
create(context) {
|
|
501
|
+
const opt = context.options?.[0] ?? {};
|
|
502
|
+
const layers = opt.layers ?? DEFAULTS3.layers;
|
|
503
|
+
const srcRoot = opt.srcRoot ?? DEFAULTS3.srcRoot;
|
|
504
|
+
const filename = context.getFilename();
|
|
505
|
+
const fileCtx = getFileContext(filename, srcRoot, layers);
|
|
506
|
+
if (!fileCtx) return {};
|
|
507
|
+
return {
|
|
508
|
+
ImportDeclaration(node) {
|
|
509
|
+
const importPath = node.source?.value;
|
|
510
|
+
if (typeof importPath !== "string") return;
|
|
511
|
+
if (isRelativeImport(importPath)) return;
|
|
512
|
+
const imported = parseAliasImport(importPath, layers);
|
|
513
|
+
if (!imported) return;
|
|
514
|
+
const currentLayer = fileCtx.layer;
|
|
515
|
+
const currentSlice = fileCtx.slice;
|
|
516
|
+
const importedLayer = imported.layer;
|
|
517
|
+
const importedSlice = imported.slice;
|
|
518
|
+
const currentLayerIndex = getLayerIndex(currentLayer, layers);
|
|
519
|
+
const importedLayerIndex = getLayerIndex(importedLayer, layers);
|
|
520
|
+
if (currentLayerIndex === -1 || importedLayerIndex === -1) return;
|
|
521
|
+
if (importedLayerIndex > currentLayerIndex) {
|
|
522
|
+
context.report({
|
|
523
|
+
node: node.source,
|
|
524
|
+
messageId: "forbiddenHigherLayer",
|
|
525
|
+
data: {
|
|
526
|
+
currentLayer,
|
|
527
|
+
importedLayer
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
if (currentLayer === "shared") {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
if (!currentSlice) return;
|
|
536
|
+
if (importedLayer !== currentLayer) return;
|
|
537
|
+
if (!importedSlice) {
|
|
538
|
+
context.report({
|
|
539
|
+
node: node.source,
|
|
540
|
+
messageId: "crossSliceMustUseX",
|
|
541
|
+
data: {
|
|
542
|
+
layer: currentLayer,
|
|
543
|
+
targetSlice: "<targetSlice>",
|
|
544
|
+
currentSlice
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
if (importedSlice === currentSlice) {
|
|
550
|
+
context.report({
|
|
551
|
+
node: node.source,
|
|
552
|
+
messageId: "sameSliceMustBeRelative",
|
|
553
|
+
data: {
|
|
554
|
+
importPath
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (!isCrossSliceXImport(imported, currentSlice)) {
|
|
560
|
+
context.report({
|
|
561
|
+
node: node.source,
|
|
562
|
+
messageId: "crossSliceMustUseX",
|
|
563
|
+
data: {
|
|
564
|
+
layer: currentLayer,
|
|
565
|
+
targetSlice: importedSlice,
|
|
566
|
+
currentSlice
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
var slice_imports_default = rule3;
|
|
575
|
+
|
|
416
576
|
// src/plugin.ts
|
|
417
577
|
var plugin = {
|
|
418
578
|
rules: {
|
|
579
|
+
"slice-imports": slice_imports_default,
|
|
419
580
|
"styles-usage": styles_usage_default,
|
|
420
581
|
"styles-naming": styles_naming_default
|
|
421
582
|
}
|
|
@@ -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 * 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"]}
|
|
1
|
+
{"version":3,"sources":["../../src/rules/styles-usage.ts","../../src/rules/styles-naming.ts","../../src/rules/slice-imports.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 type { Rule } from \"eslint\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n /**\n * Allowed FSD layers in dependency order:\n * shared -> entities -> features -> widgets -> pages -> app\n */\n layers?: string[];\n\n /**\n * Source root marker in absolute filename.\n * Used to detect current layer/slice from file path.\n * Default: \"src\"\n */\n srcRoot?: string;\n },\n];\n\nconst DEFAULTS = {\n layers: [\"shared\", \"entities\", \"features\", \"widgets\", \"pages\", \"app\"],\n srcRoot: \"src\",\n} as const;\n\ntype FileContext = {\n layer: string;\n slice: string | null;\n};\n\ntype ImportContext = {\n layer: string;\n slice: string | null;\n rest: string[];\n};\n\nfunction normalizePath(filepath: string): string {\n return filepath.split(path.sep).join(\"/\");\n}\n\nfunction getFileContext(\n filename: string,\n srcRoot: string,\n layers: readonly string[],\n): FileContext | null {\n const normalized = normalizePath(filename);\n const parts = normalized.split(\"/\");\n\n const srcIndex = parts.lastIndexOf(srcRoot);\n if (srcIndex === -1) return null;\n\n const layer = parts[srcIndex + 1];\n if (!layer || !layers.includes(layer)) return null;\n\n // shared is not slice-oriented for this rule\n if (layer === \"shared\") {\n return { layer, slice: null };\n }\n\n const slice = parts[srcIndex + 2];\n if (!slice) return null;\n\n return { layer, slice };\n}\n\nfunction parseAliasImport(\n importPath: string,\n layers: readonly string[],\n): ImportContext | null {\n if (!importPath.startsWith(\"@\")) return null;\n\n const normalized = importPath.replace(/^@/, \"\");\n const parts = normalized.split(\"/\").filter(Boolean);\n\n const layer = parts[0];\n if (!layer || !layers.includes(layer)) return null;\n\n if (layer === \"shared\") {\n return {\n layer,\n slice: null,\n rest: parts.slice(1),\n };\n }\n\n const slice = parts[1];\n if (!slice) {\n return {\n layer,\n slice: null,\n rest: [],\n };\n }\n\n return {\n layer,\n slice,\n rest: parts.slice(2),\n };\n}\n\nfunction getLayerIndex(layer: string, layers: readonly string[]): number {\n return layers.indexOf(layer);\n}\n\nfunction isRelativeImport(importPath: string): boolean {\n return importPath.startsWith(\"./\") || importPath.startsWith(\"../\");\n}\n\nfunction isCrossSliceXImport(\n imported: ImportContext,\n currentSlice: string,\n): boolean {\n // expected:\n // @entities/product/@x/cart\n // @entities/product/@x/cart/...\n return imported.rest[0] === \"@x\" && imported.rest[1] === currentSlice;\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Enforces FSD import boundaries: layer order, same-slice relative imports only, and cross-slice access only through @x/<currentSlice>.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n layers: {\n type: \"array\",\n items: { type: \"string\" },\n },\n srcRoot: { type: \"string\" },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n forbiddenHigherLayer:\n 'Layer \"{{currentLayer}}\" cannot import from higher layer \"{{importedLayer}}\".',\n sameSliceMustBeRelative:\n 'Same-slice imports must be relative. Replace \"{{importPath}}\" with a relative path.',\n crossSliceMustUseX:\n 'Cross-slice imports inside layer \"{{layer}}\" are allowed only through \"@{{layer}}/{{targetSlice}}/@x/{{currentSlice}}\".',\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n const layers = opt.layers ?? DEFAULTS.layers;\n const srcRoot = opt.srcRoot ?? DEFAULTS.srcRoot;\n\n const filename = context.getFilename();\n const fileCtx = getFileContext(filename, srcRoot, layers);\n\n if (!fileCtx) return {};\n\n return {\n ImportDeclaration(node: any) {\n const importPath = node.source?.value;\n if (typeof importPath !== \"string\") return;\n\n // rule only validates alias imports for now\n if (isRelativeImport(importPath)) return;\n\n const imported = parseAliasImport(importPath, layers);\n if (!imported) return;\n\n const currentLayer = fileCtx.layer;\n const currentSlice = fileCtx.slice;\n\n const importedLayer = imported.layer;\n const importedSlice = imported.slice;\n\n const currentLayerIndex = getLayerIndex(currentLayer, layers);\n const importedLayerIndex = getLayerIndex(importedLayer, layers);\n\n if (currentLayerIndex === -1 || importedLayerIndex === -1) return;\n\n // 1) Layer order\n // lower layers must not import higher layers\n if (importedLayerIndex > currentLayerIndex) {\n context.report({\n node: node.source,\n messageId: \"forbiddenHigherLayer\",\n data: {\n currentLayer,\n importedLayer,\n },\n });\n return;\n }\n\n // shared is not slice-oriented here\n if (currentLayer === \"shared\") {\n return;\n }\n\n // if current file has no slice, do nothing further\n if (!currentSlice) return;\n\n // 2) Same-layer restrictions\n if (importedLayer !== currentLayer) return;\n\n // no valid slice in target -> still forbidden as direct same-layer import\n if (!importedSlice) {\n context.report({\n node: node.source,\n messageId: \"crossSliceMustUseX\",\n data: {\n layer: currentLayer,\n targetSlice: \"<targetSlice>\",\n currentSlice,\n },\n });\n return;\n }\n\n // 2a) Same slice via alias -> forbidden, must be relative\n if (importedSlice === currentSlice) {\n context.report({\n node: node.source,\n messageId: \"sameSliceMustBeRelative\",\n data: {\n importPath,\n },\n });\n return;\n }\n\n // 2b) Other slice in same layer -> only through @x/<currentSlice>\n if (!isCrossSliceXImport(imported, currentSlice)) {\n context.report({\n node: node.source,\n messageId: \"crossSliceMustUseX\",\n data: {\n layer: currentLayer,\n targetSlice: importedSlice,\n currentSlice,\n },\n });\n }\n },\n };\n },\n};\n\nexport default rule;\n","import stylesUsageRule from \"./rules/styles-usage\";\nimport stylesNamingRule from \"./rules/styles-naming\";\nimport sliceImportsRule from \"./rules/slice-imports\";\n\nconst plugin = {\n rules: {\n \"slice-imports\": sliceImportsRule,\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","import_node_path","DEFAULTS","path","rule"]}
|
package/dist/plugin.cjs
CHANGED
|
@@ -425,9 +425,170 @@ var rule2 = {
|
|
|
425
425
|
};
|
|
426
426
|
var styles_naming_default = rule2;
|
|
427
427
|
|
|
428
|
+
// src/rules/slice-imports.ts
|
|
429
|
+
var import_node_path3 = __toESM(require("path"));
|
|
430
|
+
var DEFAULTS3 = {
|
|
431
|
+
layers: ["shared", "entities", "features", "widgets", "pages", "app"],
|
|
432
|
+
srcRoot: "src"
|
|
433
|
+
};
|
|
434
|
+
function normalizePath(filepath) {
|
|
435
|
+
return filepath.split(import_node_path3.default.sep).join("/");
|
|
436
|
+
}
|
|
437
|
+
function getFileContext(filename, srcRoot, layers) {
|
|
438
|
+
const normalized = normalizePath(filename);
|
|
439
|
+
const parts = normalized.split("/");
|
|
440
|
+
const srcIndex = parts.lastIndexOf(srcRoot);
|
|
441
|
+
if (srcIndex === -1) return null;
|
|
442
|
+
const layer = parts[srcIndex + 1];
|
|
443
|
+
if (!layer || !layers.includes(layer)) return null;
|
|
444
|
+
if (layer === "shared") {
|
|
445
|
+
return { layer, slice: null };
|
|
446
|
+
}
|
|
447
|
+
const slice = parts[srcIndex + 2];
|
|
448
|
+
if (!slice) return null;
|
|
449
|
+
return { layer, slice };
|
|
450
|
+
}
|
|
451
|
+
function parseAliasImport(importPath, layers) {
|
|
452
|
+
if (!importPath.startsWith("@")) return null;
|
|
453
|
+
const normalized = importPath.replace(/^@/, "");
|
|
454
|
+
const parts = normalized.split("/").filter(Boolean);
|
|
455
|
+
const layer = parts[0];
|
|
456
|
+
if (!layer || !layers.includes(layer)) return null;
|
|
457
|
+
if (layer === "shared") {
|
|
458
|
+
return {
|
|
459
|
+
layer,
|
|
460
|
+
slice: null,
|
|
461
|
+
rest: parts.slice(1)
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
const slice = parts[1];
|
|
465
|
+
if (!slice) {
|
|
466
|
+
return {
|
|
467
|
+
layer,
|
|
468
|
+
slice: null,
|
|
469
|
+
rest: []
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
layer,
|
|
474
|
+
slice,
|
|
475
|
+
rest: parts.slice(2)
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
function getLayerIndex(layer, layers) {
|
|
479
|
+
return layers.indexOf(layer);
|
|
480
|
+
}
|
|
481
|
+
function isRelativeImport(importPath) {
|
|
482
|
+
return importPath.startsWith("./") || importPath.startsWith("../");
|
|
483
|
+
}
|
|
484
|
+
function isCrossSliceXImport(imported, currentSlice) {
|
|
485
|
+
return imported.rest[0] === "@x" && imported.rest[1] === currentSlice;
|
|
486
|
+
}
|
|
487
|
+
var rule3 = {
|
|
488
|
+
meta: {
|
|
489
|
+
type: "problem",
|
|
490
|
+
docs: {
|
|
491
|
+
description: "Enforces FSD import boundaries: layer order, same-slice relative imports only, and cross-slice access only through @x/<currentSlice>."
|
|
492
|
+
},
|
|
493
|
+
schema: [
|
|
494
|
+
{
|
|
495
|
+
type: "object",
|
|
496
|
+
properties: {
|
|
497
|
+
layers: {
|
|
498
|
+
type: "array",
|
|
499
|
+
items: { type: "string" }
|
|
500
|
+
},
|
|
501
|
+
srcRoot: { type: "string" }
|
|
502
|
+
},
|
|
503
|
+
additionalProperties: false
|
|
504
|
+
}
|
|
505
|
+
],
|
|
506
|
+
messages: {
|
|
507
|
+
forbiddenHigherLayer: 'Layer "{{currentLayer}}" cannot import from higher layer "{{importedLayer}}".',
|
|
508
|
+
sameSliceMustBeRelative: 'Same-slice imports must be relative. Replace "{{importPath}}" with a relative path.',
|
|
509
|
+
crossSliceMustUseX: 'Cross-slice imports inside layer "{{layer}}" are allowed only through "@{{layer}}/{{targetSlice}}/@x/{{currentSlice}}".'
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
create(context) {
|
|
513
|
+
const opt = context.options?.[0] ?? {};
|
|
514
|
+
const layers = opt.layers ?? DEFAULTS3.layers;
|
|
515
|
+
const srcRoot = opt.srcRoot ?? DEFAULTS3.srcRoot;
|
|
516
|
+
const filename = context.getFilename();
|
|
517
|
+
const fileCtx = getFileContext(filename, srcRoot, layers);
|
|
518
|
+
if (!fileCtx) return {};
|
|
519
|
+
return {
|
|
520
|
+
ImportDeclaration(node) {
|
|
521
|
+
const importPath = node.source?.value;
|
|
522
|
+
if (typeof importPath !== "string") return;
|
|
523
|
+
if (isRelativeImport(importPath)) return;
|
|
524
|
+
const imported = parseAliasImport(importPath, layers);
|
|
525
|
+
if (!imported) return;
|
|
526
|
+
const currentLayer = fileCtx.layer;
|
|
527
|
+
const currentSlice = fileCtx.slice;
|
|
528
|
+
const importedLayer = imported.layer;
|
|
529
|
+
const importedSlice = imported.slice;
|
|
530
|
+
const currentLayerIndex = getLayerIndex(currentLayer, layers);
|
|
531
|
+
const importedLayerIndex = getLayerIndex(importedLayer, layers);
|
|
532
|
+
if (currentLayerIndex === -1 || importedLayerIndex === -1) return;
|
|
533
|
+
if (importedLayerIndex > currentLayerIndex) {
|
|
534
|
+
context.report({
|
|
535
|
+
node: node.source,
|
|
536
|
+
messageId: "forbiddenHigherLayer",
|
|
537
|
+
data: {
|
|
538
|
+
currentLayer,
|
|
539
|
+
importedLayer
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
if (currentLayer === "shared") {
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
if (!currentSlice) return;
|
|
548
|
+
if (importedLayer !== currentLayer) return;
|
|
549
|
+
if (!importedSlice) {
|
|
550
|
+
context.report({
|
|
551
|
+
node: node.source,
|
|
552
|
+
messageId: "crossSliceMustUseX",
|
|
553
|
+
data: {
|
|
554
|
+
layer: currentLayer,
|
|
555
|
+
targetSlice: "<targetSlice>",
|
|
556
|
+
currentSlice
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (importedSlice === currentSlice) {
|
|
562
|
+
context.report({
|
|
563
|
+
node: node.source,
|
|
564
|
+
messageId: "sameSliceMustBeRelative",
|
|
565
|
+
data: {
|
|
566
|
+
importPath
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (!isCrossSliceXImport(imported, currentSlice)) {
|
|
572
|
+
context.report({
|
|
573
|
+
node: node.source,
|
|
574
|
+
messageId: "crossSliceMustUseX",
|
|
575
|
+
data: {
|
|
576
|
+
layer: currentLayer,
|
|
577
|
+
targetSlice: importedSlice,
|
|
578
|
+
currentSlice
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
var slice_imports_default = rule3;
|
|
587
|
+
|
|
428
588
|
// src/plugin.ts
|
|
429
589
|
var plugin = {
|
|
430
590
|
rules: {
|
|
591
|
+
"slice-imports": slice_imports_default,
|
|
431
592
|
"styles-usage": styles_usage_default,
|
|
432
593
|
"styles-naming": styles_naming_default
|
|
433
594
|
}
|
package/dist/plugin.cjs.map
CHANGED
|
@@ -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 * 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/rules/styles-usage.ts","../src/rules/styles-naming.ts","../src/rules/slice-imports.ts"],"sourcesContent":["import stylesUsageRule from \"./rules/styles-usage\";\nimport stylesNamingRule from \"./rules/styles-naming\";\nimport sliceImportsRule from \"./rules/slice-imports\";\n\nconst plugin = {\n rules: {\n \"slice-imports\": sliceImportsRule,\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","import type { Rule } from \"eslint\";\nimport path from \"node:path\";\n\ntype Options = [\n {\n /**\n * Allowed FSD layers in dependency order:\n * shared -> entities -> features -> widgets -> pages -> app\n */\n layers?: string[];\n\n /**\n * Source root marker in absolute filename.\n * Used to detect current layer/slice from file path.\n * Default: \"src\"\n */\n srcRoot?: string;\n },\n];\n\nconst DEFAULTS = {\n layers: [\"shared\", \"entities\", \"features\", \"widgets\", \"pages\", \"app\"],\n srcRoot: \"src\",\n} as const;\n\ntype FileContext = {\n layer: string;\n slice: string | null;\n};\n\ntype ImportContext = {\n layer: string;\n slice: string | null;\n rest: string[];\n};\n\nfunction normalizePath(filepath: string): string {\n return filepath.split(path.sep).join(\"/\");\n}\n\nfunction getFileContext(\n filename: string,\n srcRoot: string,\n layers: readonly string[],\n): FileContext | null {\n const normalized = normalizePath(filename);\n const parts = normalized.split(\"/\");\n\n const srcIndex = parts.lastIndexOf(srcRoot);\n if (srcIndex === -1) return null;\n\n const layer = parts[srcIndex + 1];\n if (!layer || !layers.includes(layer)) return null;\n\n // shared is not slice-oriented for this rule\n if (layer === \"shared\") {\n return { layer, slice: null };\n }\n\n const slice = parts[srcIndex + 2];\n if (!slice) return null;\n\n return { layer, slice };\n}\n\nfunction parseAliasImport(\n importPath: string,\n layers: readonly string[],\n): ImportContext | null {\n if (!importPath.startsWith(\"@\")) return null;\n\n const normalized = importPath.replace(/^@/, \"\");\n const parts = normalized.split(\"/\").filter(Boolean);\n\n const layer = parts[0];\n if (!layer || !layers.includes(layer)) return null;\n\n if (layer === \"shared\") {\n return {\n layer,\n slice: null,\n rest: parts.slice(1),\n };\n }\n\n const slice = parts[1];\n if (!slice) {\n return {\n layer,\n slice: null,\n rest: [],\n };\n }\n\n return {\n layer,\n slice,\n rest: parts.slice(2),\n };\n}\n\nfunction getLayerIndex(layer: string, layers: readonly string[]): number {\n return layers.indexOf(layer);\n}\n\nfunction isRelativeImport(importPath: string): boolean {\n return importPath.startsWith(\"./\") || importPath.startsWith(\"../\");\n}\n\nfunction isCrossSliceXImport(\n imported: ImportContext,\n currentSlice: string,\n): boolean {\n // expected:\n // @entities/product/@x/cart\n // @entities/product/@x/cart/...\n return imported.rest[0] === \"@x\" && imported.rest[1] === currentSlice;\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Enforces FSD import boundaries: layer order, same-slice relative imports only, and cross-slice access only through @x/<currentSlice>.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n layers: {\n type: \"array\",\n items: { type: \"string\" },\n },\n srcRoot: { type: \"string\" },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n forbiddenHigherLayer:\n 'Layer \"{{currentLayer}}\" cannot import from higher layer \"{{importedLayer}}\".',\n sameSliceMustBeRelative:\n 'Same-slice imports must be relative. Replace \"{{importPath}}\" with a relative path.',\n crossSliceMustUseX:\n 'Cross-slice imports inside layer \"{{layer}}\" are allowed only through \"@{{layer}}/{{targetSlice}}/@x/{{currentSlice}}\".',\n },\n },\n\n create(context) {\n const opt = (context.options?.[0] ?? {}) as Options[0];\n const layers = opt.layers ?? DEFAULTS.layers;\n const srcRoot = opt.srcRoot ?? DEFAULTS.srcRoot;\n\n const filename = context.getFilename();\n const fileCtx = getFileContext(filename, srcRoot, layers);\n\n if (!fileCtx) return {};\n\n return {\n ImportDeclaration(node: any) {\n const importPath = node.source?.value;\n if (typeof importPath !== \"string\") return;\n\n // rule only validates alias imports for now\n if (isRelativeImport(importPath)) return;\n\n const imported = parseAliasImport(importPath, layers);\n if (!imported) return;\n\n const currentLayer = fileCtx.layer;\n const currentSlice = fileCtx.slice;\n\n const importedLayer = imported.layer;\n const importedSlice = imported.slice;\n\n const currentLayerIndex = getLayerIndex(currentLayer, layers);\n const importedLayerIndex = getLayerIndex(importedLayer, layers);\n\n if (currentLayerIndex === -1 || importedLayerIndex === -1) return;\n\n // 1) Layer order\n // lower layers must not import higher layers\n if (importedLayerIndex > currentLayerIndex) {\n context.report({\n node: node.source,\n messageId: \"forbiddenHigherLayer\",\n data: {\n currentLayer,\n importedLayer,\n },\n });\n return;\n }\n\n // shared is not slice-oriented here\n if (currentLayer === \"shared\") {\n return;\n }\n\n // if current file has no slice, do nothing further\n if (!currentSlice) return;\n\n // 2) Same-layer restrictions\n if (importedLayer !== currentLayer) return;\n\n // no valid slice in target -> still forbidden as direct same-layer import\n if (!importedSlice) {\n context.report({\n node: node.source,\n messageId: \"crossSliceMustUseX\",\n data: {\n layer: currentLayer,\n targetSlice: \"<targetSlice>\",\n currentSlice,\n },\n });\n return;\n }\n\n // 2a) Same slice via alias -> forbidden, must be relative\n if (importedSlice === currentSlice) {\n context.report({\n node: node.source,\n messageId: \"sameSliceMustBeRelative\",\n data: {\n importPath,\n },\n });\n return;\n }\n\n // 2b) Other slice in same layer -> only through @x/<currentSlice>\n if (!isCrossSliceXImport(imported, currentSlice)) {\n context.report({\n node: node.source,\n messageId: \"crossSliceMustUseX\",\n data: {\n layer: currentLayer,\n targetSlice: importedSlice,\n currentSlice,\n },\n });\n }\n },\n };\n },\n};\n\nexport default rule;\n"],"mappings":"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","names":["path","fs","import_node_path","DEFAULTS","path","rule","import_node_path","DEFAULTS","path","rule"]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rnzeus/eslint-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"main": "dist/plugin.cjs",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./dist/plugin.cjs",
|
|
8
|
-
"./configs/styles": "./dist/configs/styles.cjs"
|
|
8
|
+
"./configs/styles": "./dist/configs/styles.cjs",
|
|
9
|
+
"./configs/imports": "./dist/configs/imports.cjs"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"dist"
|