eslint-plugin-kerfjs 5.0.0-beta.87 → 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.
@@ -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 a helper 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.
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.87' },
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,
@@ -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
- !registry.sources.has(helper) &&
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({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-kerfjs",
3
- "version": "5.0.0-beta.87",
3
+ "version": "5.0.0-beta.89",
4
4
  "description": "ESLint rules that enforce kerf's hard rules — catches AI-shaped bugs at edit time.",
5
5
  "type": "module",
6
6
  "license": "MIT",