@timothyrusso/eslint-plugin-arch 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/dist/configs/recommended.d.ts +33 -0
- package/dist/configs/recommended.d.ts.map +1 -0
- package/dist/configs/recommended.js +103 -0
- package/dist/configs/recommended.js.map +1 -0
- package/dist/createRule.d.ts +6 -0
- package/dist/createRule.d.ts.map +1 -0
- package/dist/createRule.js +4 -0
- package/dist/createRule.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/kitConfig.d.ts +26 -0
- package/dist/kitConfig.d.ts.map +1 -0
- package/dist/kitConfig.js +2 -0
- package/dist/kitConfig.js.map +1 -0
- package/dist/paths.d.ts +13 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +47 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugin.d.ts +10 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +13 -0
- package/dist/plugin.js.map +1 -0
- package/dist/rules/index.d.ts +43 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +24 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/noDashes.d.ts +8 -0
- package/dist/rules/noDashes.d.ts.map +1 -0
- package/dist/rules/noDashes.js +59 -0
- package/dist/rules/noDashes.js.map +1 -0
- package/dist/rules/noEffectInViews.d.ts +9 -0
- package/dist/rules/noEffectInViews.d.ts.map +1 -0
- package/dist/rules/noEffectInViews.js +43 -0
- package/dist/rules/noEffectInViews.js.map +1 -0
- package/dist/rules/noEffectRunInFacades.d.ts +9 -0
- package/dist/rules/noEffectRunInFacades.d.ts.map +1 -0
- package/dist/rules/noEffectRunInFacades.js +50 -0
- package/dist/rules/noEffectRunInFacades.js.map +1 -0
- package/dist/rules/noInlineComments.d.ts +8 -0
- package/dist/rules/noInlineComments.d.ts.map +1 -0
- package/dist/rules/noInlineComments.js +128 -0
- package/dist/rules/noInlineComments.js.map +1 -0
- package/dist/rules/noJsxCommentText.d.ts +9 -0
- package/dist/rules/noJsxCommentText.d.ts.map +1 -0
- package/dist/rules/noJsxCommentText.js +31 -0
- package/dist/rules/noJsxCommentText.js.map +1 -0
- package/dist/rules/noLiteralGutter.d.ts +17 -0
- package/dist/rules/noLiteralGutter.d.ts.map +1 -0
- package/dist/rules/noLiteralGutter.js +155 -0
- package/dist/rules/noLiteralGutter.js.map +1 -0
- package/dist/rules/noRelativeImports.d.ts +13 -0
- package/dist/rules/noRelativeImports.d.ts.map +1 -0
- package/dist/rules/noRelativeImports.js +51 -0
- package/dist/rules/noRelativeImports.js.map +1 -0
- package/dist/rules/preferViewmodel.d.ts +12 -0
- package/dist/rules/preferViewmodel.d.ts.map +1 -0
- package/dist/rules/preferViewmodel.js +93 -0
- package/dist/rules/preferViewmodel.js.map +1 -0
- package/dist/rules/stableRowHandlers.d.ts +10 -0
- package/dist/rules/stableRowHandlers.d.ts.map +1 -0
- package/dist/rules/stableRowHandlers.js +162 -0
- package/dist/rules/stableRowHandlers.js.map +1 -0
- package/dist/rules/viewmodelReturnShape.d.ts +5 -0
- package/dist/rules/viewmodelReturnShape.d.ts.map +1 -0
- package/dist/rules/viewmodelReturnShape.js +150 -0
- package/dist/rules/viewmodelReturnShape.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createRule } from '../createRule.js';
|
|
2
|
+
/**
|
|
3
|
+
* NOTE: built from code points, so this file passes its own rule and a repo-wide text replace
|
|
4
|
+
* cannot rewrite the characters the rule depends on.
|
|
5
|
+
*/
|
|
6
|
+
const EM = String.fromCodePoint(0x2014);
|
|
7
|
+
const EN = String.fromCodePoint(0x2013);
|
|
8
|
+
/**
|
|
9
|
+
* No em dash anywhere in a file, and no en dash in prose: string literals, template text, JSX
|
|
10
|
+
* text and comments. A numeric range takes a plain hyphen (`8-12`).
|
|
11
|
+
*/
|
|
12
|
+
export const noDashes = createRule({
|
|
13
|
+
name: 'no-dashes',
|
|
14
|
+
meta: {
|
|
15
|
+
type: 'problem',
|
|
16
|
+
docs: {
|
|
17
|
+
description: 'Forbids the em dash (U+2014) anywhere and the en dash (U+2013) in strings, JSX text and comments.',
|
|
18
|
+
},
|
|
19
|
+
schema: [],
|
|
20
|
+
messages: {
|
|
21
|
+
emDash: 'No em dash. Use a colon, a comma, parentheses or a middle dot.',
|
|
22
|
+
enDash: 'No en dash in prose. Use a hyphen, also for a numeric range such as 8-12.',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultOptions: [],
|
|
26
|
+
create(context) {
|
|
27
|
+
const sourceCode = context.sourceCode;
|
|
28
|
+
const text = sourceCode.getText();
|
|
29
|
+
if (!text.includes(EM) && !text.includes(EN))
|
|
30
|
+
return {};
|
|
31
|
+
function reportEach(start, end, ch, messageId) {
|
|
32
|
+
let at = text.indexOf(ch, start);
|
|
33
|
+
while (at !== -1 && at < end) {
|
|
34
|
+
context.report({
|
|
35
|
+
loc: { start: sourceCode.getLocFromIndex(at), end: sourceCode.getLocFromIndex(at + 1) },
|
|
36
|
+
messageId,
|
|
37
|
+
});
|
|
38
|
+
at = text.indexOf(ch, at + 1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function checkProse(node) {
|
|
42
|
+
reportEach(node.range[0], node.range[1], EN, 'enDash');
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
Program() {
|
|
46
|
+
reportEach(0, text.length, EM, 'emDash');
|
|
47
|
+
for (const comment of sourceCode.getAllComments())
|
|
48
|
+
checkProse(comment);
|
|
49
|
+
},
|
|
50
|
+
Literal(node) {
|
|
51
|
+
if (typeof node.value === 'string')
|
|
52
|
+
checkProse(node);
|
|
53
|
+
},
|
|
54
|
+
TemplateElement: checkProse,
|
|
55
|
+
JSXText: checkProse,
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=noDashes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noDashes.js","sourceRoot":"","sources":["../../src/rules/noDashes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;GAGG;AACH,MAAM,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;AACxC,MAAM,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAC;IACjC,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,mGAAmG;SACjH;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,MAAM,EAAE,gEAAgE;YACxE,MAAM,EAAE,2EAA2E;SACpF;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACtC,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAAE,OAAO,EAAE,CAAC;QAExD,SAAS,UAAU,CAAC,KAAa,EAAE,GAAW,EAAE,EAAU,EAAE,SAA8B;YACxF,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YACjC,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,EAAE,CAAC;gBAC7B,OAAO,CAAC,MAAM,CAAC;oBACb,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE;oBACvF,SAAS;iBACV,CAAC,CAAC;gBACH,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,SAAS,UAAU,CAAC,IAAsC;YACxD,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;QACzD,CAAC;QAED,OAAO;YACL,OAAO;gBACL,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;gBACzC,KAAK,MAAM,OAAO,IAAI,UAAU,CAAC,cAAc,EAAE;oBAAE,UAAU,CAAC,OAAO,CAAC,CAAC;YACzE,CAAC;YACD,OAAO,CAAC,IAAI;gBACV,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;oBAAE,UAAU,CAAC,IAAI,CAAC,CAAC;YACvD,CAAC;YACD,eAAe,EAAE,UAAU;YAC3B,OAAO,EAAE,UAAU;SACpB,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `.tsx` never imports Effect. Views read a ViewModel; facades hand Effects to
|
|
3
|
+
* `useEffectQuery` and `useEffectMutation`. The dependency-cruiser rule catches the same import
|
|
4
|
+
* across the graph; this one puts the message on the line.
|
|
5
|
+
*/
|
|
6
|
+
export declare const noEffectInViews: import("@typescript-eslint/utils/ts-eslint").RuleModule<"effectImport", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=noEffectInViews.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noEffectInViews.d.ts","sourceRoot":"","sources":["../../src/rules/noEffectInViews.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,eAAO,MAAM,eAAe;;CAgC1B,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
import { createRule } from '../createRule.js';
|
|
3
|
+
/** `effect`, a subpath of it, or an `@effect/*` package. */
|
|
4
|
+
const EFFECT_MODULE = /^(?:effect|@effect\/[^/]+)(?:\/|$)/;
|
|
5
|
+
/**
|
|
6
|
+
* A `.tsx` never imports Effect. Views read a ViewModel; facades hand Effects to
|
|
7
|
+
* `useEffectQuery` and `useEffectMutation`. The dependency-cruiser rule catches the same import
|
|
8
|
+
* across the graph; this one puts the message on the line.
|
|
9
|
+
*/
|
|
10
|
+
export const noEffectInViews = createRule({
|
|
11
|
+
name: 'no-effect-in-views',
|
|
12
|
+
meta: {
|
|
13
|
+
type: 'problem',
|
|
14
|
+
docs: { description: 'Forbids importing `effect` or `@effect/*` in a `.tsx` file.' },
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
effectImport: 'A view does not import {{source}}. Run the Effect in a use case and read the result through the ViewModel and a facade.',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
if (!context.filename.endsWith('.tsx'))
|
|
23
|
+
return {};
|
|
24
|
+
function check(source) {
|
|
25
|
+
if (source?.type !== AST_NODE_TYPES.Literal || typeof source.value !== 'string')
|
|
26
|
+
return;
|
|
27
|
+
if (EFFECT_MODULE.test(source.value)) {
|
|
28
|
+
context.report({ node: source, messageId: 'effectImport', data: { source: source.value } });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
ImportDeclaration: node => check(node.source),
|
|
33
|
+
ExportNamedDeclaration: node => check(node.source),
|
|
34
|
+
ExportAllDeclaration: node => check(node.source),
|
|
35
|
+
ImportExpression: node => check(node.source),
|
|
36
|
+
CallExpression(node) {
|
|
37
|
+
if (node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === 'require')
|
|
38
|
+
check(node.arguments[0]);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=noEffectInViews.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noEffectInViews.js","sourceRoot":"","sources":["../../src/rules/noEffectInViews.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAiB,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,4DAA4D;AAC5D,MAAM,aAAa,GAAG,oCAAoC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;IACxC,IAAI,EAAE,oBAAoB;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,WAAW,EAAE,6DAA6D,EAAE;QACpF,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,YAAY,EACV,yHAAyH;SAC5H;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAElD,SAAS,KAAK,CAAC,MAAwC;YACrD,IAAI,MAAM,EAAE,IAAI,KAAK,cAAc,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ;gBAAE,OAAO;YACxF,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC9F,CAAC;QACH,CAAC;QAED,OAAO;YACL,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAC7C,sBAAsB,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAClD,oBAAoB,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAChD,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAC5C,cAAc,CAAC,IAAI;gBACjB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;oBAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YACjH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A facade runs an Effect only through `useEffectQuery` or `useEffectMutation`: no `Effect.run*`,
|
|
3
|
+
* no `runtime.runPromise`, no `ManagedRuntime`. The dependency-cruiser rule
|
|
4
|
+
* `facades-run-through-boundary` sees modules, not the names imported from them; this sees names.
|
|
5
|
+
*/
|
|
6
|
+
export declare const noEffectRunInFacades: import("@typescript-eslint/utils/ts-eslint").RuleModule<"run" | "runtime", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=noEffectRunInFacades.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noEffectRunInFacades.d.ts","sourceRoot":"","sources":["../../src/rules/noEffectRunInFacades.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;CAyC/B,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
import { createRule } from '../createRule.js';
|
|
3
|
+
const RUN_METHOD = /^run(?:Promise|Sync|Fork|Callback)(?:Exit)?$/;
|
|
4
|
+
/**
|
|
5
|
+
* A facade runs an Effect only through `useEffectQuery` or `useEffectMutation`: no `Effect.run*`,
|
|
6
|
+
* no `runtime.runPromise`, no `ManagedRuntime`. The dependency-cruiser rule
|
|
7
|
+
* `facades-run-through-boundary` sees modules, not the names imported from them; this sees names.
|
|
8
|
+
*/
|
|
9
|
+
export const noEffectRunInFacades = createRule({
|
|
10
|
+
name: 'no-effect-run-in-facades',
|
|
11
|
+
meta: {
|
|
12
|
+
type: 'problem',
|
|
13
|
+
docs: { description: 'Forbids `*.run*` calls and `ManagedRuntime` in files under `facades/`.' },
|
|
14
|
+
schema: [],
|
|
15
|
+
messages: {
|
|
16
|
+
run: 'A facade does not call {{name}}. Hand the Effect to useEffectQuery or useEffectMutation.',
|
|
17
|
+
runtime: 'A facade does not touch ManagedRuntime. The app runtime is built once, in core/runtime.',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
if (!context.filename.split('\\').join('/').includes('/facades/'))
|
|
23
|
+
return {};
|
|
24
|
+
return {
|
|
25
|
+
CallExpression(node) {
|
|
26
|
+
const callee = node.callee;
|
|
27
|
+
if (callee.type !== AST_NODE_TYPES.MemberExpression || callee.property.type !== AST_NODE_TYPES.Identifier) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (RUN_METHOD.test(callee.property.name)) {
|
|
31
|
+
context.report({ node: callee, messageId: 'run', data: { name: callee.property.name } });
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
ImportDeclaration(node) {
|
|
35
|
+
if (/^effect\/ManagedRuntime$/.test(node.source.value)) {
|
|
36
|
+
context.report({ node: node.source, messageId: 'runtime' });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
for (const spec of node.specifiers) {
|
|
40
|
+
if (spec.type === AST_NODE_TYPES.ImportSpecifier &&
|
|
41
|
+
spec.imported.type === AST_NODE_TYPES.Identifier &&
|
|
42
|
+
spec.imported.name === 'ManagedRuntime') {
|
|
43
|
+
context.report({ node: spec, messageId: 'runtime' });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=noEffectRunInFacades.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noEffectRunInFacades.js","sourceRoot":"","sources":["../../src/rules/noEffectRunInFacades.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,UAAU,GAAG,8CAA8C,CAAC;AAElE;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC;IAC7C,IAAI,EAAE,0BAA0B;IAChC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,WAAW,EAAE,wEAAwE,EAAE;QAC/F,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,GAAG,EAAE,0FAA0F;YAC/F,OAAO,EAAE,yFAAyF;SACnG;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,OAAO,EAAE,CAAC;QAC7E,OAAO;YACL,cAAc,CAAC,IAAI;gBACjB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC3B,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,gBAAgB,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU,EAAE,CAAC;oBAC1G,OAAO;gBACT,CAAC;gBACD,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC1C,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC3F,CAAC;YACH,CAAC;YACD,iBAAiB,CAAC,IAAI;gBACpB,IAAI,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;oBACvD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;oBAC5D,OAAO;gBACT,CAAC;gBACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACnC,IACE,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,eAAe;wBAC5C,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,cAAc,CAAC,UAAU;wBAChD,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,gBAAgB,EACvC,CAAC;wBACD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;oBACvD,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Only `// NOTE:` and `// HACK:` codetags, tool directives and TSDoc blocks leading a declaration
|
|
3
|
+
* or member are allowed.
|
|
4
|
+
*/
|
|
5
|
+
export declare const noInlineComments: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noComment" | "misplacedDoc", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=noInlineComments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noInlineComments.d.ts","sourceRoot":"","sources":["../../src/rules/noInlineComments.ts"],"names":[],"mappings":"AAiDA;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;CAgF3B,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { createRule } from '../createRule.js';
|
|
2
|
+
const DIRECTIVE = /^\s*(?:biome-ignore\b|eslint-disable|eslint-enable\b|@ts-check\b|@ts-expect-error\b|@ts-ignore\b|@ts-nocheck\b|\/\s*<reference\b)/;
|
|
3
|
+
const CODETAG = /^\s*(?:NOTE|HACK):/;
|
|
4
|
+
const CODETAG_SHAPED = /^\s*[A-Z][A-Z0-9_]+:/;
|
|
5
|
+
const TOP_LEVEL_DECLARATIONS = new Set([
|
|
6
|
+
'VariableDeclaration',
|
|
7
|
+
'FunctionDeclaration',
|
|
8
|
+
'ClassDeclaration',
|
|
9
|
+
'TSTypeAliasDeclaration',
|
|
10
|
+
'TSInterfaceDeclaration',
|
|
11
|
+
'TSEnumDeclaration',
|
|
12
|
+
'TSDeclareFunction',
|
|
13
|
+
'TSModuleDeclaration',
|
|
14
|
+
]);
|
|
15
|
+
const MEMBERS = new Set([
|
|
16
|
+
'PropertyDefinition',
|
|
17
|
+
'MethodDefinition',
|
|
18
|
+
'TSAbstractPropertyDefinition',
|
|
19
|
+
'TSAbstractMethodDefinition',
|
|
20
|
+
'TSPropertySignature',
|
|
21
|
+
'TSMethodSignature',
|
|
22
|
+
'TSIndexSignature',
|
|
23
|
+
'TSCallSignatureDeclaration',
|
|
24
|
+
'TSConstructSignatureDeclaration',
|
|
25
|
+
'TSEnumMember',
|
|
26
|
+
]);
|
|
27
|
+
const EXPORTS = new Set(['ExportNamedDeclaration', 'ExportDefaultDeclaration']);
|
|
28
|
+
/** Program-level statements a TSDoc block may lead whatever they export: `export default {}`, `export {}`. */
|
|
29
|
+
const EXPORT_STATEMENTS = new Set([...EXPORTS, 'ExportAllDeclaration']);
|
|
30
|
+
function isTopLevelDeclaration(node) {
|
|
31
|
+
if (!TOP_LEVEL_DECLARATIONS.has(node.type))
|
|
32
|
+
return false;
|
|
33
|
+
const parent = node.parent;
|
|
34
|
+
if (!parent)
|
|
35
|
+
return false;
|
|
36
|
+
if (parent.type === 'Program')
|
|
37
|
+
return true;
|
|
38
|
+
return EXPORTS.has(parent.type) && parent.parent?.type === 'Program';
|
|
39
|
+
}
|
|
40
|
+
function isDocTarget(node) {
|
|
41
|
+
return MEMBERS.has(node.type) || isTopLevelDeclaration(node);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Only `// NOTE:` and `// HACK:` codetags, tool directives and TSDoc blocks leading a declaration
|
|
45
|
+
* or member are allowed.
|
|
46
|
+
*/
|
|
47
|
+
export const noInlineComments = createRule({
|
|
48
|
+
name: 'no-inline-comments',
|
|
49
|
+
meta: {
|
|
50
|
+
type: 'problem',
|
|
51
|
+
docs: {
|
|
52
|
+
description: 'Inline comments are banned. Only `// NOTE:` / `// HACK:` codetags, tool directives, and TSDoc blocks leading a declaration are allowed.',
|
|
53
|
+
},
|
|
54
|
+
schema: [],
|
|
55
|
+
messages: {
|
|
56
|
+
noComment: 'Inline comments are not allowed. Delete it, or record the why as `// NOTE: ...` or `// HACK: ... because ...`.',
|
|
57
|
+
misplacedDoc: 'A `/** */` block is only allowed as the leading comment of a declaration, class member or interface member.',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
defaultOptions: [],
|
|
61
|
+
create(context) {
|
|
62
|
+
const sourceCode = context.sourceCode;
|
|
63
|
+
const docBlocks = new Set();
|
|
64
|
+
function isShebang(comment) {
|
|
65
|
+
return comment.range[0] === 0 && sourceCode.text.startsWith('#!');
|
|
66
|
+
}
|
|
67
|
+
function allowLeadingDocs(node) {
|
|
68
|
+
for (const comment of sourceCode.getCommentsBefore(node)) {
|
|
69
|
+
if (comment.type === 'Block' && comment.value.startsWith('*'))
|
|
70
|
+
docBlocks.add(comment);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
Program(node) {
|
|
75
|
+
// NOTE: a file overview, the TSDoc block above the first import, documents the module.
|
|
76
|
+
const first = node.body[0];
|
|
77
|
+
if (first?.type === 'ImportDeclaration')
|
|
78
|
+
allowLeadingDocs(first);
|
|
79
|
+
for (const statement of node.body) {
|
|
80
|
+
if (EXPORT_STATEMENTS.has(statement.type))
|
|
81
|
+
allowLeadingDocs(statement);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
'*'(node) {
|
|
85
|
+
if (!isDocTarget(node))
|
|
86
|
+
return;
|
|
87
|
+
allowLeadingDocs(node);
|
|
88
|
+
// NOTE: on `export const x` the block leads the `export` keyword, not the declaration node.
|
|
89
|
+
if (node.parent && EXPORTS.has(node.parent.type))
|
|
90
|
+
allowLeadingDocs(node.parent);
|
|
91
|
+
// NOTE: a decorator sits between the TSDoc and the declaration it documents (and before
|
|
92
|
+
// `export`), so the block is a leading comment of the decorator, not of the declaration.
|
|
93
|
+
const decorators = 'decorators' in node && Array.isArray(node.decorators) ? node.decorators : [];
|
|
94
|
+
const first = decorators[0];
|
|
95
|
+
if (first)
|
|
96
|
+
allowLeadingDocs(first);
|
|
97
|
+
},
|
|
98
|
+
'Program:exit'() {
|
|
99
|
+
let codetagLine = null;
|
|
100
|
+
for (const comment of sourceCode.getAllComments()) {
|
|
101
|
+
if (DIRECTIVE.test(comment.value) || isShebang(comment))
|
|
102
|
+
continue;
|
|
103
|
+
if (comment.type === 'Line') {
|
|
104
|
+
// NOTE: a wrapped codetag, the `//` lines directly under it at the same indentation, is
|
|
105
|
+
// one comment.
|
|
106
|
+
const continuesCodetag = codetagLine !== null &&
|
|
107
|
+
comment.loc.start.line === codetagLine.loc.start.line + 1 &&
|
|
108
|
+
comment.loc.start.column === codetagLine.loc.start.column &&
|
|
109
|
+
!CODETAG_SHAPED.test(comment.value);
|
|
110
|
+
if (CODETAG.test(comment.value) || continuesCodetag) {
|
|
111
|
+
codetagLine = comment;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
context.report({ loc: comment.loc, messageId: 'noComment' });
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!comment.value.startsWith('*')) {
|
|
118
|
+
context.report({ loc: comment.loc, messageId: 'noComment' });
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (!docBlocks.has(comment))
|
|
122
|
+
context.report({ loc: comment.loc, messageId: 'misplacedDoc' });
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
//# sourceMappingURL=noInlineComments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noInlineComments.js","sourceRoot":"","sources":["../../src/rules/noInlineComments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inside JSX, `//` is not a comment: it is text, which type-checks clean and then crashes React
|
|
3
|
+
* Native with "Text strings must be rendered within a <Text> component". A comment inside a JSX
|
|
4
|
+
* expression container is a real comment and passes.
|
|
5
|
+
*/
|
|
6
|
+
export declare const noJsxCommentText: import("@typescript-eslint/utils/ts-eslint").RuleModule<"commentText", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=noJsxCommentText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noJsxCommentText.d.ts","sourceRoot":"","sources":["../../src/rules/noJsxCommentText.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;CAwB3B,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createRule } from '../createRule.js';
|
|
2
|
+
/**
|
|
3
|
+
* Inside JSX, `//` is not a comment: it is text, which type-checks clean and then crashes React
|
|
4
|
+
* Native with "Text strings must be rendered within a <Text> component". A comment inside a JSX
|
|
5
|
+
* expression container is a real comment and passes.
|
|
6
|
+
*/
|
|
7
|
+
export const noJsxCommentText = createRule({
|
|
8
|
+
name: 'no-jsx-comment-text',
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'problem',
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Forbids comment-shaped JSX text (`// ...` or `/* ... */` written as a JSX child).',
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
messages: {
|
|
16
|
+
commentText: 'This comment sits in a JSX text position and renders as literal text. Wrap it in {/* ... */} or lift it above the element.',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultOptions: [],
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
JSXText(node) {
|
|
23
|
+
const content = node.value.trim();
|
|
24
|
+
if (content.startsWith('//') || content.startsWith('/*')) {
|
|
25
|
+
context.report({ node, messageId: 'commentText' });
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=noJsxCommentText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noJsxCommentText.js","sourceRoot":"","sources":["../../src/rules/noJsxCommentText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;IACzC,IAAI,EAAE,qBAAqB;IAC3B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,mFAAmF;SACjG;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,WAAW,EACT,4HAA4H;SAC/H;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,OAAO,CAAC,IAAI;gBACV,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;gBAClC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type Options = [
|
|
2
|
+
{
|
|
3
|
+
gutterToken: string;
|
|
4
|
+
spacingImport: string;
|
|
5
|
+
allowlistFile?: string;
|
|
6
|
+
nonGutterTokens?: string[];
|
|
7
|
+
}
|
|
8
|
+
];
|
|
9
|
+
/**
|
|
10
|
+
* One horizontal edge, owned in one place: a horizontal padding or margin is never a literal number
|
|
11
|
+
* (0 is a reset, not a measurement) and never the spacing step that stood in for the gutter.
|
|
12
|
+
*/
|
|
13
|
+
export declare const noLiteralGutter: import("@typescript-eslint/utils/ts-eslint").RuleModule<"literal" | "token", Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=noLiteralGutter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noLiteralGutter.d.ts","sourceRoot":"","sources":["../../src/rules/noLiteralGutter.ts"],"names":[],"mappings":"AAMA,KAAK,OAAO,GAAG;IACb;QACE,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;KAC5B;CACF,CAAC;AAyDF;;;GAGG;AACH,eAAO,MAAM,eAAe;;CAuF1B,CAAC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
4
|
+
import { createRule } from '../createRule.js';
|
|
5
|
+
import { matchesAny, relativePath } from '../paths.js';
|
|
6
|
+
/** Horizontal style properties, and the layout-primitive props that spell the same thing. */
|
|
7
|
+
const STYLE_PROPS = new Set([
|
|
8
|
+
'paddingHorizontal',
|
|
9
|
+
'paddingLeft',
|
|
10
|
+
'paddingRight',
|
|
11
|
+
'paddingStart',
|
|
12
|
+
'paddingEnd',
|
|
13
|
+
'marginHorizontal',
|
|
14
|
+
'marginLeft',
|
|
15
|
+
'marginRight',
|
|
16
|
+
'marginStart',
|
|
17
|
+
'marginEnd',
|
|
18
|
+
]);
|
|
19
|
+
const SHORTHAND_PROPS = new Set(['px', 'mx', 'pl', 'pr', 'ml', 'mr']);
|
|
20
|
+
/** The spacing step that kept standing in for the gutter. */
|
|
21
|
+
const DEFAULT_NON_GUTTER_TOKENS = ['xl'];
|
|
22
|
+
const allowlists = new Map();
|
|
23
|
+
/**
|
|
24
|
+
* Reads an allowlist file once per process: one path or glob per line, relative to the ESLint
|
|
25
|
+
* working directory, with `#` starting a comment.
|
|
26
|
+
*/
|
|
27
|
+
function readAllowlist(cwd, file) {
|
|
28
|
+
const path = resolve(cwd, file);
|
|
29
|
+
const cached = allowlists.get(path);
|
|
30
|
+
if (cached)
|
|
31
|
+
return cached;
|
|
32
|
+
const entries = existsSync(path)
|
|
33
|
+
? readFileSync(path, 'utf8')
|
|
34
|
+
.split('\n')
|
|
35
|
+
.map(line => line.replace(/#.*/, '').trim())
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
: [];
|
|
38
|
+
allowlists.set(path, entries);
|
|
39
|
+
return entries;
|
|
40
|
+
}
|
|
41
|
+
function propName(key) {
|
|
42
|
+
if (key.type === AST_NODE_TYPES.Identifier)
|
|
43
|
+
return key.name;
|
|
44
|
+
if (key.type === AST_NODE_TYPES.Literal && typeof key.value === 'string')
|
|
45
|
+
return key.value;
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
function isNonZeroNumber(node) {
|
|
49
|
+
if (node.type === AST_NODE_TYPES.UnaryExpression && node.operator === '-')
|
|
50
|
+
return isNonZeroNumber(node.argument);
|
|
51
|
+
return node.type === AST_NODE_TYPES.Literal && typeof node.value === 'number' && node.value !== 0;
|
|
52
|
+
}
|
|
53
|
+
function rootIdentifier(node) {
|
|
54
|
+
if (node.type === AST_NODE_TYPES.Identifier)
|
|
55
|
+
return node.name;
|
|
56
|
+
if (node.type === AST_NODE_TYPES.MemberExpression)
|
|
57
|
+
return rootIdentifier(node.object);
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* One horizontal edge, owned in one place: a horizontal padding or margin is never a literal number
|
|
62
|
+
* (0 is a reset, not a measurement) and never the spacing step that stood in for the gutter.
|
|
63
|
+
*/
|
|
64
|
+
export const noLiteralGutter = createRule({
|
|
65
|
+
name: 'no-literal-gutter',
|
|
66
|
+
meta: {
|
|
67
|
+
type: 'problem',
|
|
68
|
+
docs: {
|
|
69
|
+
description: 'Forbids literal numbers and the non-gutter spacing token in horizontal padding and margin style properties.',
|
|
70
|
+
},
|
|
71
|
+
schema: [
|
|
72
|
+
{
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {
|
|
75
|
+
gutterToken: { type: 'string', minLength: 1 },
|
|
76
|
+
spacingImport: { type: 'string', minLength: 1 },
|
|
77
|
+
allowlistFile: { type: 'string', minLength: 1 },
|
|
78
|
+
nonGutterTokens: { type: 'array', items: { type: 'string', minLength: 1 } },
|
|
79
|
+
},
|
|
80
|
+
required: ['gutterToken', 'spacingImport'],
|
|
81
|
+
additionalProperties: false,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
messages: {
|
|
85
|
+
literal: '{{prop}} is a literal. Use {{gutter}} for a screen edge or a spacing step from {{spacing}} inside a component.',
|
|
86
|
+
token: '{{prop}} uses {{value}}, which is not the gutter. Use {{gutter}} for a screen edge or a smaller step.',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
defaultOptions: [{ gutterToken: 'screenGutter', spacingImport: '@/theme/tokens' }],
|
|
90
|
+
create(context, [options]) {
|
|
91
|
+
if (options.allowlistFile) {
|
|
92
|
+
const allow = readAllowlist(context.cwd, options.allowlistFile);
|
|
93
|
+
if (allow.length > 0 && matchesAny(relativePath(context.cwd, context.filename), allow))
|
|
94
|
+
return {};
|
|
95
|
+
}
|
|
96
|
+
const nonGutter = new Set(options.nonGutterTokens ?? DEFAULT_NON_GUTTER_TOKENS);
|
|
97
|
+
const spacingLocals = new Set();
|
|
98
|
+
const data = (prop, value = '') => ({
|
|
99
|
+
prop,
|
|
100
|
+
value,
|
|
101
|
+
gutter: options.gutterToken,
|
|
102
|
+
spacing: options.spacingImport,
|
|
103
|
+
});
|
|
104
|
+
function isNonGutterToken(node) {
|
|
105
|
+
if (node.type !== AST_NODE_TYPES.MemberExpression || node.computed)
|
|
106
|
+
return false;
|
|
107
|
+
if (node.property.type !== AST_NODE_TYPES.Identifier || !nonGutter.has(node.property.name))
|
|
108
|
+
return false;
|
|
109
|
+
const root = rootIdentifier(node.object);
|
|
110
|
+
return root !== undefined && spacingLocals.has(root);
|
|
111
|
+
}
|
|
112
|
+
function checkValue(prop, value) {
|
|
113
|
+
if (isNonZeroNumber(value)) {
|
|
114
|
+
context.report({ node: value, messageId: 'literal', data: data(prop) });
|
|
115
|
+
}
|
|
116
|
+
else if (isNonGutterToken(value)) {
|
|
117
|
+
context.report({ node: value, messageId: 'token', data: data(prop, context.sourceCode.getText(value)) });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
ImportDeclaration(node) {
|
|
122
|
+
if (node.source.value !== options.spacingImport)
|
|
123
|
+
return;
|
|
124
|
+
for (const spec of node.specifiers)
|
|
125
|
+
spacingLocals.add(spec.local.name);
|
|
126
|
+
},
|
|
127
|
+
Property(node) {
|
|
128
|
+
const name = propName(node.key);
|
|
129
|
+
if (name === undefined || !STYLE_PROPS.has(name))
|
|
130
|
+
return;
|
|
131
|
+
checkValue(name, node.value);
|
|
132
|
+
},
|
|
133
|
+
JSXAttribute(node) {
|
|
134
|
+
if (node.name.type !== AST_NODE_TYPES.JSXIdentifier)
|
|
135
|
+
return;
|
|
136
|
+
const name = node.name.name;
|
|
137
|
+
if (!STYLE_PROPS.has(name) && !SHORTHAND_PROPS.has(name))
|
|
138
|
+
return;
|
|
139
|
+
const value = node.value;
|
|
140
|
+
if (!value)
|
|
141
|
+
return;
|
|
142
|
+
const inner = value.type === AST_NODE_TYPES.JSXExpressionContainer &&
|
|
143
|
+
value.expression.type !== AST_NODE_TYPES.JSXEmptyExpression
|
|
144
|
+
? value.expression
|
|
145
|
+
: value;
|
|
146
|
+
if (inner.type === AST_NODE_TYPES.Literal && typeof inner.value === 'string' && nonGutter.has(inner.value)) {
|
|
147
|
+
context.report({ node: inner, messageId: 'token', data: data(name, `'${inner.value}'`) });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
checkValue(name, inner);
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
//# sourceMappingURL=noLiteralGutter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noLiteralGutter.js","sourceRoot":"","sources":["../../src/rules/noLiteralGutter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type Options = [{
|
|
2
|
+
allow?: string[];
|
|
3
|
+
}];
|
|
4
|
+
/**
|
|
5
|
+
* Imports go through the path alias (`@/features/...`), never `./` or `../`, so a file can move
|
|
6
|
+
* without rewriting its imports. `allow` lists folders or files, as globs relative to the ESLint
|
|
7
|
+
* working directory, where relative imports are fine.
|
|
8
|
+
*/
|
|
9
|
+
export declare const noRelativeImports: import("@typescript-eslint/utils/ts-eslint").RuleModule<"relative", Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=noRelativeImports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noRelativeImports.d.ts","sourceRoot":"","sources":["../../src/rules/noRelativeImports.ts"],"names":[],"mappings":"AAIA,KAAK,OAAO,GAAG,CAAC;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AAItC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;CAuC5B,CAAC"}
|