eslint-plugin-kerfjs 5.0.0-beta.88 → 5.0.0-beta.89
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/docs/rules/ui-wiring.md +9 -1
- package/index.js +1 -1
- package/lib/rules/ui-wiring.js +20 -2
- package/package.json +1 -1
package/docs/rules/ui-wiring.md
CHANGED
|
@@ -8,7 +8,15 @@ Declare application entry modules in the application UI profile to check root wi
|
|
|
8
8
|
{ "schemaVersion": 1, "scope": "workspace", "wiring": { "entries": ["src/main.tsx"] } }
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Entry paths are relative to the workspace root. The rule follows relative imports, re-exports, and literal dynamic imports from each entry. An application-scoped obligation is checked at the entry if any reachable module renders its component; a recognized helper call in any reachable module satisfies it. Reachable leaf modules need no duplicate wiring. A module outside every declared entry keeps the per-file check. A composition entry can set `wiring.scope` to `"module"` for
|
|
11
|
+
Entry paths are relative to the workspace root. The rule follows relative imports, re-exports, and literal dynamic imports from each entry. An application-scoped obligation is checked at the entry if any reachable module renders its component; a recognized helper call or required registration import in any reachable module satisfies it. Reachable leaf modules need no duplicate wiring. A module outside every declared entry keeps the per-file check. A composition entry can set `wiring.scope` to `"module"` for wiring that must be installed beside its rendering code; omitted scope means `"application"`. Computed import paths and unresolved modules stay outside the static graph, so put them in a declared entry or check them separately. `KUI-L402` still checks the helper's call site.
|
|
12
|
+
|
|
13
|
+
For a page-lifetime root helper, declare the actual app entry in the workspace `.kerf-ui-profile.json`. For example, if `src/client/app.tsx` imports `init.ts`, `init.ts` calls `wireShellSearch(root)`, and that imported helper calls `wireTokenSearchFields(root)`, use:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{ "schemaVersion": 1, "scope": "workspace", "wiring": { "entries": ["src/client/app.tsx"] } }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The entry graph then covers a `TokenSearchField` in an imported view without duplicate wiring in that view. Include every independently mounted application entry. The path must resolve through relative imports from each entry to both the view and the helper; merely naming the helper in the profile does not count as invoking it.
|
|
12
20
|
|
|
13
21
|
Consumer composition catalogs can name an application helper's defining file in `wiring.sources`:
|
|
14
22
|
|
package/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import uiPublicBoundaries from './lib/rules/ui-public-boundaries.js';
|
|
|
14
14
|
import uiWiring from './lib/rules/ui-wiring.js';
|
|
15
15
|
|
|
16
16
|
const plugin = {
|
|
17
|
-
meta: { name: 'eslint-plugin-kerfjs', version: '5.0.0-beta.
|
|
17
|
+
meta: { name: 'eslint-plugin-kerfjs', version: '5.0.0-beta.89' },
|
|
18
18
|
rules: {
|
|
19
19
|
'no-inline-jsx-event-handlers': noInlineJsxEventHandlers,
|
|
20
20
|
'no-raw-with-dynamic-arg': noRawWithDynamicArg,
|
package/lib/rules/ui-wiring.js
CHANGED
|
@@ -21,6 +21,16 @@ const script = /\.(?:[cm]?[jt]sx?)$/;
|
|
|
21
21
|
const imports =
|
|
22
22
|
/(?:^|[;\n])\s*(?:import|export)\s+(?:[^;'"`]*?\s+from\s*)?['"]([^'"]+)['"]/g;
|
|
23
23
|
const dynamicImports = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
24
|
+
const staticImports =
|
|
25
|
+
/(?:^|[;\n])\s*import\s+(?:[^;'"`]*?\s+from\s*)?['"]([^'"]+)['"]/g;
|
|
26
|
+
|
|
27
|
+
function moduleImportSources(source) {
|
|
28
|
+
const withoutComments = source.replace(
|
|
29
|
+
/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g,
|
|
30
|
+
(comment) => comment.replace(/[^\n]/g, ' '),
|
|
31
|
+
);
|
|
32
|
+
return [...withoutComments.matchAll(staticImports)].map((match) => match[1]);
|
|
33
|
+
}
|
|
24
34
|
|
|
25
35
|
function entryModules(entryFile, currentFile, currentText) {
|
|
26
36
|
const modules = new Map();
|
|
@@ -223,11 +233,15 @@ export default {
|
|
|
223
233
|
);
|
|
224
234
|
const ownEntry = entries.find(({ file }) => file === filename);
|
|
225
235
|
const reachableCalls = new Set(calls.keys());
|
|
236
|
+
const reachableImports = new Set(registry.sources);
|
|
226
237
|
if (ownEntry)
|
|
227
238
|
for (const [file, source] of ownEntry.modules)
|
|
228
|
-
if (file !== filename)
|
|
239
|
+
if (file !== filename) {
|
|
240
|
+
for (const imported of moduleImportSources(source))
|
|
241
|
+
reachableImports.add(imported);
|
|
229
242
|
for (const helper of moduleCalls(source, file, contract))
|
|
230
243
|
reachableCalls.add(helper);
|
|
244
|
+
}
|
|
231
245
|
const required = new Map(used);
|
|
232
246
|
if (ownEntry)
|
|
233
247
|
for (const [file, source] of ownEntry.modules)
|
|
@@ -242,7 +256,11 @@ export default {
|
|
|
242
256
|
for (const helper of entry.wiring.helpers) {
|
|
243
257
|
if (helper.startsWith('@')) {
|
|
244
258
|
if (
|
|
245
|
-
!
|
|
259
|
+
!(
|
|
260
|
+
entry.wiring.scope === 'module'
|
|
261
|
+
? registry.sources
|
|
262
|
+
: reachableImports
|
|
263
|
+
).has(helper) &&
|
|
246
264
|
!isExcepted(contract, MISSING_CODE, filename)
|
|
247
265
|
)
|
|
248
266
|
context.report({
|