@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Timothy Russo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @timothyrusso/eslint-plugin-arch
|
|
2
|
+
|
|
3
|
+
ESLint rules for the kit's architecture: the ViewModel contract, comments, dashes, layout tokens,
|
|
4
|
+
stable row handlers and Effect placement. Flat config only, ESLint 9.15 or later.
|
|
5
|
+
|
|
6
|
+
## Use
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm install -D @timothyrusso/eslint-plugin-arch @timothyrusso/config-presets eslint typescript
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`eslint.config.js` at the app root:
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import arch from '@timothyrusso/eslint-plugin-arch';
|
|
16
|
+
import { loadKitConfig } from '@timothyrusso/config-presets';
|
|
17
|
+
|
|
18
|
+
export default [
|
|
19
|
+
{ ignores: ['node_modules/**', 'dist/**', '.expo/**'] },
|
|
20
|
+
...arch.configs.recommended(loadKitConfig()),
|
|
21
|
+
];
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`configs.recommended(kitConfig)` reads `appRoot`, `featuresRoot` and the `lint` section of
|
|
25
|
+
`kit.config.json` (a raw parsed file works too: every field takes the schema default). It
|
|
26
|
+
registers the plugin as `arch`, parses every JS and TS file with `@typescript-eslint/parser`, and
|
|
27
|
+
turns rules on as follows:
|
|
28
|
+
|
|
29
|
+
| Rule | On when |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| `arch/viewmodel-return-shape` | always |
|
|
32
|
+
| `arch/prefer-viewmodel` | always, `allow` = `lint.allowedHooksInViews` (default empty) |
|
|
33
|
+
| `arch/no-inline-comments` | always |
|
|
34
|
+
| `arch/no-jsx-comment-text` | always |
|
|
35
|
+
| `arch/stable-row-handlers` | always |
|
|
36
|
+
| `arch/no-effect-in-views` | always |
|
|
37
|
+
| `arch/no-effect-run-in-facades` | always |
|
|
38
|
+
| `arch/no-relative-imports` | always, allowed only in root-level `*.config.{js,cjs,mjs,ts}` files (`DEFAULT_RELATIVE_IMPORT_ALLOW`) |
|
|
39
|
+
| `no-restricted-syntax` (`enum`, `as Error`) | always |
|
|
40
|
+
| `arch/no-dashes` | `lint.dashes` is not `allow` |
|
|
41
|
+
| `arch/no-literal-gutter` | `lint.layoutTokens` is set; only in `appRoot` and `<featuresRoot>/core/design-system` |
|
|
42
|
+
| `no-restricted-imports` (`ActivityIndicator`) | `lint.singleSpinner`; off inside the design system |
|
|
43
|
+
|
|
44
|
+
Override any of them in a later config block, for example a wider allowlist for relative imports
|
|
45
|
+
(an override replaces the default list, so spread it back in):
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
import arch, { DEFAULT_RELATIVE_IMPORT_ALLOW } from '@timothyrusso/eslint-plugin-arch';
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
files: ['**/*.ts'],
|
|
52
|
+
rules: { 'arch/no-relative-imports': ['error', { allow: [...DEFAULT_RELATIVE_IMPORT_ALLOW, 'scripts'] }] },
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The package also exports `rules` (for `RuleTester`), `RESTRICTED_SYNTAX`, `SOURCE_FILES`,
|
|
57
|
+
`DEFAULT_RELATIVE_IMPORT_ALLOW` and the
|
|
58
|
+
`LintKitConfig` type.
|
|
59
|
+
|
|
60
|
+
Checks that need more than one file (i18n parity, unused catalog keys, hooks, watch bounds) are
|
|
61
|
+
node scripts in `@timothyrusso/config-presets`, because ESLint sees one file at a time.
|
|
62
|
+
|
|
63
|
+
## Rules
|
|
64
|
+
|
|
65
|
+
### viewmodel-return-shape
|
|
66
|
+
|
|
67
|
+
A hook in a `*.logic.ts` file returns an object literal whose keys are a non-empty subset of
|
|
68
|
+
`{ state, derived, effects }`, or returns nothing. Spreads and computed keys are rejected because
|
|
69
|
+
they cannot be checked. Returns inside nested functions belong to those functions.
|
|
70
|
+
|
|
71
|
+
### prefer-viewmodel
|
|
72
|
+
|
|
73
|
+
A `.tsx` that imports its sibling `.logic` module (same basename) calls only that ViewModel hook,
|
|
74
|
+
at most once. Any other hook call, including `React.useState` and another view's ViewModel, is
|
|
75
|
+
reported unless its name is in `allow`. A `.tsx` without a `.logic` import is presentational and
|
|
76
|
+
exempt, and so are test files.
|
|
77
|
+
|
|
78
|
+
### no-inline-comments
|
|
79
|
+
|
|
80
|
+
Only `// NOTE:` and `// HACK:` codetags (a codetag may wrap onto the `//` lines directly under
|
|
81
|
+
it), tool directives (`eslint-disable`, `biome-ignore`, `@ts-expect-error`, triple-slash
|
|
82
|
+
references), a shebang, and TSDoc `/** */` blocks. A TSDoc block must lead a top-level
|
|
83
|
+
declaration, a class or interface member, an `export` statement, or the first import (a file
|
|
84
|
+
overview).
|
|
85
|
+
|
|
86
|
+
### no-dashes
|
|
87
|
+
|
|
88
|
+
No em dash (U+2014) anywhere in the file. No en dash (U+2013) in string literals, template text,
|
|
89
|
+
JSX text or comments. A numeric range takes a hyphen (`8-12`).
|
|
90
|
+
|
|
91
|
+
### no-literal-gutter
|
|
92
|
+
|
|
93
|
+
A horizontal padding or margin (`paddingHorizontal`, `paddingLeft`, `paddingRight`,
|
|
94
|
+
`paddingStart`, `paddingEnd` and the `margin` equivalents, as a style key or a JSX prop, plus the
|
|
95
|
+
`px`, `mx`, `pl`, `pr`, `ml`, `mr` layout props) is never a literal number other than 0, and never
|
|
96
|
+
the non-gutter token of the spacing scale (`spacing.xl` by default). Use the gutter token for a
|
|
97
|
+
screen edge and a smaller step inside a component. Arithmetic on a token passes.
|
|
98
|
+
|
|
99
|
+
Options: `gutterToken` and `spacingImport` (from `lint.layoutTokens`: the spacing object is
|
|
100
|
+
whatever the file imports from `spacingImport`), `allowlistFile` (one path or glob per line,
|
|
101
|
+
relative to the ESLint working directory, `#` starts a comment; a missing file allows nothing),
|
|
102
|
+
and `nonGutterTokens` (default `['xl']`).
|
|
103
|
+
|
|
104
|
+
### no-jsx-comment-text
|
|
105
|
+
|
|
106
|
+
JSX text that starts with `//` or `/*`. Inside JSX those characters are text, which type-checks
|
|
107
|
+
and then fails at runtime in React Native. A comment inside `{}` passes.
|
|
108
|
+
|
|
109
|
+
### stable-row-handlers
|
|
110
|
+
|
|
111
|
+
In a file that renders a `FlashList` or `FlatList`, a function passed as a prop to a row component
|
|
112
|
+
(the outermost element `renderItem` returns) or to a `memo` component is a `useCallback` result
|
|
113
|
+
or a module-level function. An inline arrow, a function expression, a `.bind()` call or a function
|
|
114
|
+
declared inside the component is reported. Props and ViewModel members (`effects.select`) pass,
|
|
115
|
+
since their stability is decided elsewhere.
|
|
116
|
+
|
|
117
|
+
### no-effect-in-views
|
|
118
|
+
|
|
119
|
+
A `.tsx` never imports `effect`, a subpath of it or an `@effect/*` package, including type-only
|
|
120
|
+
imports, re-exports, `import()` and `require()`. The `effect-only-in-inner-layers` rule of
|
|
121
|
+
`@timothyrusso/arch-rules` catches the same import across the graph; this one puts the message on
|
|
122
|
+
the line.
|
|
123
|
+
|
|
124
|
+
### no-effect-run-in-facades
|
|
125
|
+
|
|
126
|
+
In a file under `facades/`: no `.runPromise`, `.runSync`, `.runFork`, `.runCallback` (or their
|
|
127
|
+
`Exit` variants) on anything, and no `ManagedRuntime` import. The dependency-cruiser rule
|
|
128
|
+
`facades-run-through-boundary` sees modules, not the names imported from them; this rule sees
|
|
129
|
+
names. Facades hand Effects to `useEffectQuery` and `useEffectMutation`.
|
|
130
|
+
|
|
131
|
+
### no-relative-imports
|
|
132
|
+
|
|
133
|
+
`./` and `../` in imports, re-exports, `import()`, `require()` and `import('...')` types, unless
|
|
134
|
+
the file is in one of the `allow` globs (relative to the ESLint working directory; `*` stays in
|
|
135
|
+
one folder, `**` spans folders, `{a,b}` matches either, a folder covers everything under it). The
|
|
136
|
+
recommended config allows root-level `*.config.{js,cjs,mjs,ts}` files, which import their
|
|
137
|
+
neighbours (`./kit.config.json`) by nature.
|
|
138
|
+
|
|
139
|
+
## Develop
|
|
140
|
+
|
|
141
|
+
Tests are Jest with `@typescript-eslint/rule-tester`, one file per rule in
|
|
142
|
+
`src/__tests__/rules/`. `src/__tests__/recommended.test.ts` lints the Expo-shaped fixture app in
|
|
143
|
+
`src/__tests__/fixtures/app` through ESLint's `ESLint` class with `configs.recommended` and its
|
|
144
|
+
`kit.config.json`: the clean files report nothing, and every file with `broken` in its path
|
|
145
|
+
reports exactly its deliberate violations. The fixture app is excluded from Biome, the kit's own
|
|
146
|
+
ESLint run, `tsc` and dependency-cruiser.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Linter } from 'eslint';
|
|
2
|
+
import type { LintKitConfig } from '../kitConfig.js';
|
|
3
|
+
/** The namespace the recommended config registers the plugin under: rules read `arch/<rule>`. */
|
|
4
|
+
export declare const PLUGIN_NAMESPACE = "arch";
|
|
5
|
+
/** Every file the recommended config lints. */
|
|
6
|
+
export declare const SOURCE_FILES = "**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}";
|
|
7
|
+
/**
|
|
8
|
+
* Where `no-relative-imports` allows relative imports by default: root-level config files, such as
|
|
9
|
+
* `eslint.config.js` importing `./kit.config.json` or `metro.config.js`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_RELATIVE_IMPORT_ALLOW: readonly ["*.config.{js,cjs,mjs,ts}"];
|
|
12
|
+
/** `no-restricted-syntax` entries: no TypeScript `enum`, no `as Error`. */
|
|
13
|
+
export declare const RESTRICTED_SYNTAX: readonly [{
|
|
14
|
+
readonly selector: "TSEnumDeclaration";
|
|
15
|
+
readonly message: "Use a union of string literals or an `as const` object, not `enum`.";
|
|
16
|
+
}, {
|
|
17
|
+
readonly selector: "TSAsExpression > TSTypeReference.typeAnnotation > Identifier[name='Error']";
|
|
18
|
+
readonly message: "Do not cast to Error: narrow with `instanceof` or convert with a helper.";
|
|
19
|
+
}];
|
|
20
|
+
/**
|
|
21
|
+
* The kit's flat config for an app, driven by its `kit.config.json`. Spread it into
|
|
22
|
+
* `eslint.config.js`; override a rule in a later block.
|
|
23
|
+
*
|
|
24
|
+
* - Always: the ViewModel rules (`prefer-viewmodel` allows `lint.allowedHooksInViews`),
|
|
25
|
+
* `no-inline-comments`, `no-jsx-comment-text`, `stable-row-handlers`, `no-effect-in-views`,
|
|
26
|
+
* `no-effect-run-in-facades`, `no-relative-imports` (allowed in root-level config files) and `no-restricted-syntax` for `enum` and
|
|
27
|
+
* `as Error`.
|
|
28
|
+
* - `lint.dashes` is not `allow`: `no-dashes`.
|
|
29
|
+
* - `lint.layoutTokens`: `no-literal-gutter` in `appRoot` and `<featuresRoot>/core/design-system`.
|
|
30
|
+
* - `lint.singleSpinner`: `no-restricted-imports` for `ActivityIndicator`, outside the design system.
|
|
31
|
+
*/
|
|
32
|
+
export declare function recommended(kitConfig?: LintKitConfig): Linter.Config[];
|
|
33
|
+
//# sourceMappingURL=recommended.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recommended.d.ts","sourceRoot":"","sources":["../../src/configs/recommended.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIrD,iGAAiG;AACjG,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAIvC,+CAA+C;AAC/C,eAAO,MAAM,YAAY,yCAAuB,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,6BAA6B,uCAAwC,CAAC;AAEnF,2EAA2E;AAC3E,eAAO,MAAM,iBAAiB;;;;;;EASpB,CAAC;AAOX;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,SAAS,GAAE,aAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,CAkE1E"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as tsParser from '@typescript-eslint/parser';
|
|
2
|
+
import { plugin } from '../plugin.js';
|
|
3
|
+
/** The namespace the recommended config registers the plugin under: rules read `arch/<rule>`. */
|
|
4
|
+
export const PLUGIN_NAMESPACE = 'arch';
|
|
5
|
+
const EXTENSIONS = '{js,jsx,mjs,cjs,ts,tsx,mts,cts}';
|
|
6
|
+
/** Every file the recommended config lints. */
|
|
7
|
+
export const SOURCE_FILES = `**/*.${EXTENSIONS}`;
|
|
8
|
+
/**
|
|
9
|
+
* Where `no-relative-imports` allows relative imports by default: root-level config files, such as
|
|
10
|
+
* `eslint.config.js` importing `./kit.config.json` or `metro.config.js`.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_RELATIVE_IMPORT_ALLOW = ['*.config.{js,cjs,mjs,ts}'];
|
|
13
|
+
/** `no-restricted-syntax` entries: no TypeScript `enum`, no `as Error`. */
|
|
14
|
+
export const RESTRICTED_SYNTAX = [
|
|
15
|
+
{
|
|
16
|
+
selector: 'TSEnumDeclaration',
|
|
17
|
+
message: 'Use a union of string literals or an `as const` object, not `enum`.',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
selector: "TSAsExpression > TSTypeReference.typeAnnotation > Identifier[name='Error']",
|
|
21
|
+
message: 'Do not cast to Error: narrow with `instanceof` or convert with a helper.',
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
/** The folder of the design system, which owns the spinner and the spacing scale. */
|
|
25
|
+
function designSystemRoot(featuresRoot) {
|
|
26
|
+
return `${featuresRoot}/core/design-system`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The kit's flat config for an app, driven by its `kit.config.json`. Spread it into
|
|
30
|
+
* `eslint.config.js`; override a rule in a later block.
|
|
31
|
+
*
|
|
32
|
+
* - Always: the ViewModel rules (`prefer-viewmodel` allows `lint.allowedHooksInViews`),
|
|
33
|
+
* `no-inline-comments`, `no-jsx-comment-text`, `stable-row-handlers`, `no-effect-in-views`,
|
|
34
|
+
* `no-effect-run-in-facades`, `no-relative-imports` (allowed in root-level config files) and `no-restricted-syntax` for `enum` and
|
|
35
|
+
* `as Error`.
|
|
36
|
+
* - `lint.dashes` is not `allow`: `no-dashes`.
|
|
37
|
+
* - `lint.layoutTokens`: `no-literal-gutter` in `appRoot` and `<featuresRoot>/core/design-system`.
|
|
38
|
+
* - `lint.singleSpinner`: `no-restricted-imports` for `ActivityIndicator`, outside the design system.
|
|
39
|
+
*/
|
|
40
|
+
export function recommended(kitConfig = {}) {
|
|
41
|
+
const appRoot = kitConfig.appRoot ?? 'app';
|
|
42
|
+
const featuresRoot = kitConfig.featuresRoot ?? 'features';
|
|
43
|
+
const lint = kitConfig.lint ?? {};
|
|
44
|
+
const designSystem = designSystemRoot(featuresRoot);
|
|
45
|
+
const prefix = (rule) => `${PLUGIN_NAMESPACE}/${rule}`;
|
|
46
|
+
const rules = {
|
|
47
|
+
[prefix('viewmodel-return-shape')]: 'error',
|
|
48
|
+
[prefix('prefer-viewmodel')]: ['error', { allow: [...(lint.allowedHooksInViews ?? [])] }],
|
|
49
|
+
[prefix('no-inline-comments')]: 'error',
|
|
50
|
+
[prefix('no-jsx-comment-text')]: 'error',
|
|
51
|
+
[prefix('stable-row-handlers')]: 'error',
|
|
52
|
+
[prefix('no-effect-in-views')]: 'error',
|
|
53
|
+
[prefix('no-effect-run-in-facades')]: 'error',
|
|
54
|
+
[prefix('no-relative-imports')]: ['error', { allow: [...DEFAULT_RELATIVE_IMPORT_ALLOW] }],
|
|
55
|
+
'no-restricted-syntax': ['error', ...RESTRICTED_SYNTAX],
|
|
56
|
+
};
|
|
57
|
+
if (lint.dashes !== 'allow')
|
|
58
|
+
rules[prefix('no-dashes')] = 'error';
|
|
59
|
+
if (lint.singleSpinner) {
|
|
60
|
+
rules['no-restricted-imports'] = [
|
|
61
|
+
'error',
|
|
62
|
+
{
|
|
63
|
+
paths: [
|
|
64
|
+
{
|
|
65
|
+
name: 'react-native',
|
|
66
|
+
importNames: ['ActivityIndicator'],
|
|
67
|
+
message: `Use the design system spinner from ${designSystem}.`,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
const configs = [
|
|
74
|
+
{
|
|
75
|
+
name: `${PLUGIN_NAMESPACE}/recommended`,
|
|
76
|
+
files: [SOURCE_FILES],
|
|
77
|
+
plugins: { [PLUGIN_NAMESPACE]: plugin },
|
|
78
|
+
languageOptions: {
|
|
79
|
+
parser: tsParser,
|
|
80
|
+
sourceType: 'module',
|
|
81
|
+
parserOptions: { ecmaFeatures: { jsx: true } },
|
|
82
|
+
},
|
|
83
|
+
rules,
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
if (lint.singleSpinner) {
|
|
87
|
+
configs.push({
|
|
88
|
+
name: `${PLUGIN_NAMESPACE}/recommended/design-system-spinner`,
|
|
89
|
+
files: [`${designSystem}/**/*.${EXTENSIONS}`],
|
|
90
|
+
rules: { 'no-restricted-imports': 'off' },
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (lint.layoutTokens) {
|
|
94
|
+
const { gutterToken, spacingImport, allowlistFile } = lint.layoutTokens;
|
|
95
|
+
configs.push({
|
|
96
|
+
name: `${PLUGIN_NAMESPACE}/recommended/layout`,
|
|
97
|
+
files: [`${appRoot}/**/*.{ts,tsx}`, `${designSystem}/**/*.{ts,tsx}`],
|
|
98
|
+
rules: { [prefix('no-literal-gutter')]: ['error', { gutterToken, spacingImport, allowlistFile }] },
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return configs;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=recommended.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recommended.js","sourceRoot":"","sources":["../../src/configs/recommended.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
/** Every rule links to its section of the package README. */
|
|
3
|
+
export declare const createRule: <Options extends readonly unknown[], MessageIds extends string>({ meta, name, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<Options, MessageIds, unknown>>) => ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
|
|
4
|
+
name: string;
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=createRule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createRule.d.ts","sourceRoot":"","sources":["../src/createRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,6DAA6D;AAC7D,eAAO,MAAM,UAAU;;CAEtB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
/** Every rule links to its section of the package README. */
|
|
3
|
+
export const createRule = ESLintUtils.RuleCreator(name => `https://github.com/timothyrusso/agentic-kit/tree/main/packages/eslint-plugin-arch#${name}`);
|
|
4
|
+
//# sourceMappingURL=createRule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createRule.js","sourceRoot":"","sources":["../src/createRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CAC/C,IAAI,CAAC,EAAE,CAAC,qFAAqF,IAAI,EAAE,CACpG,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @timothyrusso/eslint-plugin-arch. ESLint rules for the agentic-kit architecture: ViewModel contract, comments, dashes, layout, stable row handlers, Effect in views.
|
|
3
|
+
*/
|
|
4
|
+
import { recommended } from './configs/recommended.js';
|
|
5
|
+
export { DEFAULT_RELATIVE_IMPORT_ALLOW, PLUGIN_NAMESPACE, RESTRICTED_SYNTAX, recommended, SOURCE_FILES, } from './configs/recommended.js';
|
|
6
|
+
export type { LintKitConfig } from './kitConfig.js';
|
|
7
|
+
export { rules } from './rules/index.js';
|
|
8
|
+
/** `configs.recommended(kitConfig)` builds the flat config for an app. */
|
|
9
|
+
export declare const configs: {
|
|
10
|
+
recommended: typeof recommended;
|
|
11
|
+
};
|
|
12
|
+
/** The plugin, with `configs`. The recommended config registers this same object. */
|
|
13
|
+
declare const eslintPluginArch: import("@eslint/core", { with: { "resolution-mode": "require" } }).Plugin & {
|
|
14
|
+
configs: {
|
|
15
|
+
recommended: typeof recommended;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export default eslintPluginArch;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,0EAA0E;AAC1E,eAAO,MAAM,OAAO;;CAAkB,CAAC;AAEvC,qFAAqF;AACrF,QAAA,MAAM,gBAAgB;;;;CAAqC,CAAC;AAE5D,eAAe,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @timothyrusso/eslint-plugin-arch. ESLint rules for the agentic-kit architecture: ViewModel contract, comments, dashes, layout, stable row handlers, Effect in views.
|
|
3
|
+
*/
|
|
4
|
+
import { recommended } from './configs/recommended.js';
|
|
5
|
+
import { plugin } from './plugin.js';
|
|
6
|
+
export { DEFAULT_RELATIVE_IMPORT_ALLOW, PLUGIN_NAMESPACE, RESTRICTED_SYNTAX, recommended, SOURCE_FILES, } from './configs/recommended.js';
|
|
7
|
+
export { rules } from './rules/index.js';
|
|
8
|
+
/** `configs.recommended(kitConfig)` builds the flat config for an app. */
|
|
9
|
+
export const configs = { recommended };
|
|
10
|
+
/** The plugin, with `configs`. The recommended config registers this same object. */
|
|
11
|
+
const eslintPluginArch = Object.assign(plugin, { configs });
|
|
12
|
+
export default eslintPluginArch;
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,YAAY,GACb,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,0EAA0E;AAC1E,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,WAAW,EAAE,CAAC;AAEvC,qFAAqF;AACrF,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;AAE5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fields of `kit.config.json` the recommended config reads. A `KitConfig` from
|
|
3
|
+
* `@timothyrusso/config-presets` satisfies it, and so does the raw parsed file: every field is
|
|
4
|
+
* optional and takes the schema default.
|
|
5
|
+
*/
|
|
6
|
+
export interface LintKitConfig {
|
|
7
|
+
/** expo-router app folder. Defaults to `app`. */
|
|
8
|
+
readonly appRoot?: string;
|
|
9
|
+
/** Folder that holds the feature modules. Defaults to `features`. */
|
|
10
|
+
readonly featuresRoot?: string;
|
|
11
|
+
readonly lint?: {
|
|
12
|
+
/** Hooks a view may call besides its own ViewModel hook. */
|
|
13
|
+
readonly allowedHooksInViews?: readonly string[];
|
|
14
|
+
/** `forbid` (the default) turns on `no-dashes`. */
|
|
15
|
+
readonly dashes?: 'forbid' | 'allow';
|
|
16
|
+
/** Turns on `no-literal-gutter` for the app folder and the design system. */
|
|
17
|
+
readonly layoutTokens?: {
|
|
18
|
+
readonly gutterToken: string;
|
|
19
|
+
readonly spacingImport: string;
|
|
20
|
+
readonly allowlistFile: string;
|
|
21
|
+
};
|
|
22
|
+
/** Forbids `ActivityIndicator` in favour of the design system spinner. */
|
|
23
|
+
readonly singleSpinner?: boolean;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=kitConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kitConfig.d.ts","sourceRoot":"","sources":["../src/kitConfig.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,4DAA4D;QAC5D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACjD,mDAAmD;QACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;QACrC,6EAA6E;QAC7E,QAAQ,CAAC,YAAY,CAAC,EAAE;YACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;YAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;YAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;SAChC,CAAC;QACF,0EAA0E;QAC1E,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;KAClC,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kitConfig.js","sourceRoot":"","sources":["../src/kitConfig.ts"],"names":[],"mappings":""}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** A file path relative to `cwd`, with forward slashes, for matching against config folders. */
|
|
2
|
+
export declare function relativePath(cwd: string, filename: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Turns a small glob into a regular expression that matches a relative path and everything under
|
|
5
|
+
* it: `**` spans folders, `*` stays inside one segment, `{a,b}` is either. `packages/*` matches
|
|
6
|
+
* `packages/a/src/b.ts`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
9
|
+
/** Whether `path` sits in one of the folders or files the globs name. */
|
|
10
|
+
export declare function matchesAny(path: string, globs: readonly string[]): boolean;
|
|
11
|
+
/** Whether a file is a test, which the ViewModel rules skip. */
|
|
12
|
+
export declare function isTestFile(filename: string): boolean;
|
|
13
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAEA,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGlE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqBjD;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAE1E;AAED,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEpD"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { isAbsolute, relative, sep } from 'node:path';
|
|
2
|
+
/** A file path relative to `cwd`, with forward slashes, for matching against config folders. */
|
|
3
|
+
export function relativePath(cwd, filename) {
|
|
4
|
+
const rel = isAbsolute(filename) ? relative(cwd, filename) : filename;
|
|
5
|
+
return rel.split(sep).join('/');
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Turns a small glob into a regular expression that matches a relative path and everything under
|
|
9
|
+
* it: `**` spans folders, `*` stays inside one segment, `{a,b}` is either. `packages/*` matches
|
|
10
|
+
* `packages/a/src/b.ts`.
|
|
11
|
+
*/
|
|
12
|
+
export function globToRegExp(glob) {
|
|
13
|
+
const trimmed = glob.replace(/^\.\//, '').replace(/\/+$/, '');
|
|
14
|
+
let source = '';
|
|
15
|
+
for (let i = 0; i < trimmed.length; i += 1) {
|
|
16
|
+
const ch = trimmed.charAt(i);
|
|
17
|
+
if (ch === '*' && trimmed.charAt(i + 1) === '*') {
|
|
18
|
+
source += '.*';
|
|
19
|
+
i += 1;
|
|
20
|
+
}
|
|
21
|
+
else if (ch === '*') {
|
|
22
|
+
source += '[^/]*';
|
|
23
|
+
}
|
|
24
|
+
else if (ch === '{') {
|
|
25
|
+
source += '(?:';
|
|
26
|
+
}
|
|
27
|
+
else if (ch === '}') {
|
|
28
|
+
source += ')';
|
|
29
|
+
}
|
|
30
|
+
else if (ch === ',') {
|
|
31
|
+
source += '|';
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
source += ch.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return new RegExp(`^${source}(?:/|$)`);
|
|
38
|
+
}
|
|
39
|
+
/** Whether `path` sits in one of the folders or files the globs name. */
|
|
40
|
+
export function matchesAny(path, globs) {
|
|
41
|
+
return globs.some(glob => globToRegExp(glob).test(path));
|
|
42
|
+
}
|
|
43
|
+
/** Whether a file is a test, which the ViewModel rules skip. */
|
|
44
|
+
export function isTestFile(filename) {
|
|
45
|
+
return filename.includes('.test.') || filename.includes('.spec.');
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEtD,gGAAgG;AAChG,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,QAAgB;IACxD,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACtE,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9D,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,EAAE,KAAK,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YAChD,MAAM,IAAI,IAAI,CAAC;YACf,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,MAAM,IAAI,OAAO,CAAC;QACpB,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC;QAClB,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,CAAC;QAChB,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,EAAE,CAAC,OAAO,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,IAAI,MAAM,SAAS,CAAC,CAAC;AACzC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAwB;IAC/D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACpE,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ESLint } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* The plugin object, without `configs`: the recommended config registers this same instance.
|
|
4
|
+
*
|
|
5
|
+
* NOTE: the rules are typed with `@typescript-eslint/utils`, whose `RuleContext` declares members
|
|
6
|
+
* ESLint's own `Rule` type leaves out, so the two types do not unify. They are the same objects at
|
|
7
|
+
* runtime; the cast is the one place the plugin crosses from one type to the other.
|
|
8
|
+
*/
|
|
9
|
+
export declare const plugin: ESLint.Plugin;
|
|
10
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGrC;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAG3B,CAAC"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { rules } from './rules/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The plugin object, without `configs`: the recommended config registers this same instance.
|
|
4
|
+
*
|
|
5
|
+
* NOTE: the rules are typed with `@typescript-eslint/utils`, whose `RuleContext` declares members
|
|
6
|
+
* ESLint's own `Rule` type leaves out, so the two types do not unify. They are the same objects at
|
|
7
|
+
* runtime; the cast is the one place the plugin crosses from one type to the other.
|
|
8
|
+
*/
|
|
9
|
+
export const plugin = {
|
|
10
|
+
meta: { name: '@timothyrusso/eslint-plugin-arch' },
|
|
11
|
+
rules: rules,
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAkB;IACnC,IAAI,EAAE,EAAE,IAAI,EAAE,kCAAkC,EAAE;IAClD,KAAK,EAAE,KAAuD;CAC/D,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Every rule the plugin ships, by rule id. */
|
|
2
|
+
export declare const rules: {
|
|
3
|
+
'no-dashes': import("@typescript-eslint/utils/ts-eslint").RuleModule<"emDash" | "enDash", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
4
|
+
name: string;
|
|
5
|
+
};
|
|
6
|
+
'no-effect-in-views': import("@typescript-eslint/utils/ts-eslint").RuleModule<"effectImport", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
'no-effect-run-in-facades': import("@typescript-eslint/utils/ts-eslint").RuleModule<"run" | "runtime", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
'no-inline-comments': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noComment" | "misplacedDoc", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
13
|
+
name: string;
|
|
14
|
+
};
|
|
15
|
+
'no-jsx-comment-text': import("@typescript-eslint/utils/ts-eslint").RuleModule<"commentText", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
16
|
+
name: string;
|
|
17
|
+
};
|
|
18
|
+
'no-literal-gutter': import("@typescript-eslint/utils/ts-eslint").RuleModule<"literal" | "token", [{
|
|
19
|
+
gutterToken: string;
|
|
20
|
+
spacingImport: string;
|
|
21
|
+
allowlistFile?: string;
|
|
22
|
+
nonGutterTokens?: string[];
|
|
23
|
+
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
24
|
+
name: string;
|
|
25
|
+
};
|
|
26
|
+
'no-relative-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"relative", [{
|
|
27
|
+
allow?: string[];
|
|
28
|
+
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
29
|
+
name: string;
|
|
30
|
+
};
|
|
31
|
+
'prefer-viewmodel': import("@typescript-eslint/utils/ts-eslint").RuleModule<"foreignHook" | "calledTwice", [{
|
|
32
|
+
allow?: string[];
|
|
33
|
+
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
34
|
+
name: string;
|
|
35
|
+
};
|
|
36
|
+
'stable-row-handlers': import("@typescript-eslint/utils/ts-eslint").RuleModule<"inline" | "unstable", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
37
|
+
name: string;
|
|
38
|
+
};
|
|
39
|
+
'viewmodel-return-shape': import("@typescript-eslint/utils/ts-eslint").RuleModule<"notObject" | "wrongShape", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
40
|
+
name: string;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAWA,+CAA+C;AAC/C,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWjB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { noDashes } from './noDashes.js';
|
|
2
|
+
import { noEffectInViews } from './noEffectInViews.js';
|
|
3
|
+
import { noEffectRunInFacades } from './noEffectRunInFacades.js';
|
|
4
|
+
import { noInlineComments } from './noInlineComments.js';
|
|
5
|
+
import { noJsxCommentText } from './noJsxCommentText.js';
|
|
6
|
+
import { noLiteralGutter } from './noLiteralGutter.js';
|
|
7
|
+
import { noRelativeImports } from './noRelativeImports.js';
|
|
8
|
+
import { preferViewmodel } from './preferViewmodel.js';
|
|
9
|
+
import { stableRowHandlers } from './stableRowHandlers.js';
|
|
10
|
+
import { viewmodelReturnShape } from './viewmodelReturnShape.js';
|
|
11
|
+
/** Every rule the plugin ships, by rule id. */
|
|
12
|
+
export const rules = {
|
|
13
|
+
'no-dashes': noDashes,
|
|
14
|
+
'no-effect-in-views': noEffectInViews,
|
|
15
|
+
'no-effect-run-in-facades': noEffectRunInFacades,
|
|
16
|
+
'no-inline-comments': noInlineComments,
|
|
17
|
+
'no-jsx-comment-text': noJsxCommentText,
|
|
18
|
+
'no-literal-gutter': noLiteralGutter,
|
|
19
|
+
'no-relative-imports': noRelativeImports,
|
|
20
|
+
'prefer-viewmodel': preferViewmodel,
|
|
21
|
+
'stable-row-handlers': stableRowHandlers,
|
|
22
|
+
'viewmodel-return-shape': viewmodelReturnShape,
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,+CAA+C;AAC/C,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,WAAW,EAAE,QAAQ;IACrB,oBAAoB,EAAE,eAAe;IACrC,0BAA0B,EAAE,oBAAoB;IAChD,oBAAoB,EAAE,gBAAgB;IACtC,qBAAqB,EAAE,gBAAgB;IACvC,mBAAmB,EAAE,eAAe;IACpC,qBAAqB,EAAE,iBAAiB;IACxC,kBAAkB,EAAE,eAAe;IACnC,qBAAqB,EAAE,iBAAiB;IACxC,wBAAwB,EAAE,oBAAoB;CAC/C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No em dash anywhere in a file, and no en dash in prose: string literals, template text, JSX
|
|
3
|
+
* text and comments. A numeric range takes a plain hyphen (`8-12`).
|
|
4
|
+
*/
|
|
5
|
+
export declare const noDashes: import("@typescript-eslint/utils/ts-eslint").RuleModule<"emDash" | "enDash", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=noDashes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noDashes.d.ts","sourceRoot":"","sources":["../../src/rules/noDashes.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,eAAO,MAAM,QAAQ;;CA8CnB,CAAC"}
|