@starci/eslint-canon-fe 9.16.6 → 9.16.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.16.7 - 2026-11-08
4
+
5
+ - Fixed: the test-scope Sonar way block (the app config and the plain-source config) selects the specs with positive selectors (`SPEC_FILES`, `apps/*/src/**/*.{spec,e2e-spec}.{ts,tsx}` and the package twin) instead of `ignores: ['**/*', '!**/*.spec...']`. The harness lint scope (`canonScope` of `@starci/hfs`) refuses a negated selector, so every app's `starci app check --gate lint` ended in `ESLint tool error: eslint source scope is unavailable ... unsupported canon ignores selectors` and linted nothing. The block selects the same files as before and carries the name `starci-fe/sonar-way-tests`, by which `scopeToPackages` narrows it to the specs of the package subpaths.
6
+
3
7
  ## 9.16.6 - 2026-11-08
4
8
 
5
9
  - Added (R235 `SCAN_SMELL`, the first Sonar way scan of a real app against local lint): the lint now reports what the server reported. `starci-fe/no-duplicate-import` (S3863, fixable) replaces the core `no-duplicate-imports` that spared a separate type import: a value and a type from one module are one `import { value, type Type }`, and `--fix` merges them. `starci-fe/no-nested-conditional` (S3358) now follows the server: a conditional inside a branch, a test, a call argument, a template or a cast is nested, and only an array, object, function or JSX expression starts a new reading. `starci-fe/prefer-string-raw` (S7780) also refuses a `String.raw` template that holds no backslash (fixable). `starci-fe/no-bidirectional-character` (text:S6389) refuses a raw bidirectional control character in any file. Front end: `no-useless-fragment` (S6749, fixable when the one child is an element), `no-nested-component` (S6478), `no-children-prop` (S6748; its message says a connected block passes the slot under another prop name to the pure component, FE_CONNECTED_BLOCK_RENDER_PAIR and FE_WORLD_OWNER_RENDER_BOUNDARY), `use-state-destructured` (S6754), `prefer-tag-over-role` (S6819).
@@ -12,8 +12,8 @@ export interface SonarPlugins {
12
12
  readonly sonarjs: ESLint.Plugin;
13
13
  readonly unicorn: ESLint.Plugin;
14
14
  }
15
- /** Everything but the specs, as the ignores of a block that judges the specs alone (a later negation re-includes, and the package scoping appends its own ignores after it). */
16
- export declare const EXCEPT_SPECS: readonly string[];
15
+ /** The name of the test-scope Sonar way block, which the package scoping narrows to the specs of the package subpaths. */
16
+ export declare const TEST_SCOPE_BLOCK = "starci-fe/sonar-way-tests";
17
17
  /** A disable directive is a weakening of lint, and one that suppresses nothing is dead weight. */
18
18
  export declare const linterOptions: Readonly<{
19
19
  noInlineConfig: true;
@@ -21,6 +21,8 @@ export declare const linterOptions: Readonly<{
21
21
  }>;
22
22
  /** The product source of a front end: every app's `src/` and every workspace package's `src/` (slots fe.* and repo.packages). */
23
23
  export declare const SOURCE_FILES: readonly string[];
24
+ /** The specs of that source, the positive `files` of the block that judges the specs alone (no negated selector: the lint scope of the harness proves a scope from plain globs only). */
25
+ export declare const SPEC_FILES: readonly string[];
24
26
  /** Build output, installed packages, generated wire types and the harness's report directory are never linted. */
25
27
  export declare const IGNORED: readonly string[];
26
28
  /**
@@ -91,6 +93,7 @@ export declare const buildPlainSourceConfig: ({ root, plugin, hooks, reactHooks,
91
93
  }) => Linter.Config[];
92
94
  /** The front-end files of a root workspace package: its workbench (drawn with Grammar) and its public face, and every `.tsx` file of the package source wherever it sits (a `src/client/` renderer is drawn too: FE-PACKAGES-2); the React-free workbench contract stays back end. */
93
95
  export declare const PACKAGE_SOURCE_FILES: readonly string[];
96
+ export declare const PACKAGE_SPEC_FILES: readonly string[];
94
97
  /** What a package folder never lints: installed packages, build output, generated wire types. */
95
98
  export declare const PACKAGE_IGNORED: readonly string[];
96
99
  /**
@@ -15,12 +15,14 @@ import { OUTSIDE_THE_SCAN_FILES } from "#runtime/scripts/lib/sonar-syntax-rules.
15
15
  import { sonarWayRules, sonarWayTestRules } from "#runtime/scripts/lib/sonar-way.mjs";
16
16
  import { eslintPlugin } from "./eslint-boundary.js";
17
17
  import { isHfsView } from "./hfs.js";
18
- /** Everything but the specs, as the ignores of a block that judges the specs alone (a later negation re-includes, and the package scoping appends its own ignores after it). */
19
- export const EXCEPT_SPECS = Object.freeze(["**/*", ...OUTSIDE_THE_SCAN_FILES.map((spec) => `!${spec}`)]);
18
+ /** The name of the test-scope Sonar way block, which the package scoping narrows to the specs of the package subpaths. */
19
+ export const TEST_SCOPE_BLOCK = "starci-fe/sonar-way-tests";
20
20
  /** A disable directive is a weakening of lint, and one that suppresses nothing is dead weight. */
21
21
  export const linterOptions = Object.freeze({ noInlineConfig: true, reportUnusedDisableDirectives: "error" });
22
22
  /** The product source of a front end: every app's `src/` and every workspace package's `src/` (slots fe.* and repo.packages). */
23
23
  export const SOURCE_FILES = Object.freeze(["apps/*/src/**/*.{ts,tsx}", "packages/*/src/**/*.{ts,tsx}"]);
24
+ /** The specs of that source, the positive `files` of the block that judges the specs alone (no negated selector: the lint scope of the harness proves a scope from plain globs only). */
25
+ export const SPEC_FILES = Object.freeze(["apps/*/src/**/*.{spec,e2e-spec}.{ts,tsx}", "packages/*/src/**/*.{spec,e2e-spec}.{ts,tsx}"]);
24
26
  /** Build output, installed packages, generated wire types and the harness's report directory are never linted. */
25
27
  export const IGNORED = Object.freeze(["**/node_modules/**", "**/.next/**", "**/dist/**", "**/coverage/**", "**/__generated__/**", ".starci/**"]);
26
28
  /**
@@ -92,7 +94,7 @@ export const buildFeConfig = ({ hfs, plugin, source, reactHooks, tsPlugin, sonar
92
94
  // Sonar way: what the scan raises is refused while the code is written; a spec is outside the scan, so outside this block.
93
95
  { files: [...SOURCE_FILES], ignores: [...OUTSIDE_THE_SCAN_FILES], plugins: { sonarjs: sonar.sonarjs, unicorn: sonar.unicorn }, rules: sonarWayRules(sonar.sonarjs, "fe").rules },
94
96
  // Sonar way, test scope: the scan reads the specs with the rules of the tests (sonar.tests), so the specs of the source are judged by those and by no other.
95
- { files: [...SOURCE_FILES], ignores: [...EXCEPT_SPECS], plugins: { sonarjs: sonar.sonarjs }, rules: sonarWayTestRules(sonar.sonarjs) },
97
+ { name: TEST_SCOPE_BLOCK, files: [...SPEC_FILES], plugins: { sonarjs: sonar.sonarjs }, rules: sonarWayTestRules(sonar.sonarjs) },
96
98
  ];
97
99
  };
98
100
  /**
@@ -115,6 +117,7 @@ export const SLOT_FREE_RULES = Object.freeze([
115
117
  ]);
116
118
  /** The source of a plain front-end tree: its `src/`. */
117
119
  export const PLAIN_SOURCE_FILES = Object.freeze(["src/**/*.{ts,tsx}"]);
120
+ const PLAIN_SPEC_FILES = Object.freeze(["src/**/*.{spec,e2e-spec}.{ts,tsx}"]);
118
121
  /**
119
122
  * The flat config of a TypeScript front-end tree that is no HFS app: the same fences as an app (typed linting, no inline directive, every rule at
120
123
  * `error`) over the rules that need no slot view. It takes the root of the tree and nothing else.
@@ -151,11 +154,12 @@ export const buildPlainSourceConfig = ({ root, plugin, hooks, reactHooks, tsPlug
151
154
  rules: { ...canonRules, ...hooks, ...BORROWED },
152
155
  },
153
156
  { files: [...PLAIN_SOURCE_FILES], ignores: [...OUTSIDE_THE_SCAN_FILES], plugins: { sonarjs: sonar.sonarjs, unicorn: sonar.unicorn }, rules: sonarWayRules(sonar.sonarjs, "fe").rules },
154
- { files: [...PLAIN_SOURCE_FILES], ignores: [...EXCEPT_SPECS], plugins: { sonarjs: sonar.sonarjs }, rules: sonarWayTestRules(sonar.sonarjs) },
157
+ { name: TEST_SCOPE_BLOCK, files: [...PLAIN_SPEC_FILES], plugins: { sonarjs: sonar.sonarjs }, rules: sonarWayTestRules(sonar.sonarjs) },
155
158
  ];
156
159
  };
157
160
  /** The front-end files of a root workspace package: its workbench (drawn with Grammar) and its public face, and every `.tsx` file of the package source wherever it sits (a `src/client/` renderer is drawn too: FE-PACKAGES-2); the React-free workbench contract stays back end. */
158
161
  export const PACKAGE_SOURCE_FILES = Object.freeze(["packages/*/src/workbench/**/*.{ts,tsx}", "packages/*/src/public/**/*.{ts,tsx}", "packages/*/src/**/*.tsx"]);
162
+ export const PACKAGE_SPEC_FILES = Object.freeze(["packages/*/src/workbench/**/*.{spec,e2e-spec}.{ts,tsx}", "packages/*/src/public/**/*.{spec,e2e-spec}.{ts,tsx}", "packages/*/src/**/*.{spec,e2e-spec}.tsx"]);
159
163
  const PACKAGE_CONTRACT = Object.freeze(["packages/*/src/workbench/contract/**"]);
160
164
  /** What a package folder never lints: installed packages, build output, generated wire types. */
161
165
  export const PACKAGE_IGNORED = Object.freeze(["**/node_modules/**", "**/.next/**", "**/dist/**", "**/coverage/**", "**/__generated__/**"]);
@@ -170,5 +174,5 @@ export const PACKAGE_IGNORED = Object.freeze(["**/node_modules/**", "**/.next/**
170
174
  export const scopeToPackages = (config) => config.map((block) => {
171
175
  if (block.files === undefined)
172
176
  return { ...block, ignores: [...PACKAGE_IGNORED] };
173
- return { ...block, files: [...PACKAGE_SOURCE_FILES], ignores: [...(block.ignores ?? []), ...PACKAGE_CONTRACT] };
177
+ return { ...block, files: [...(block.name === TEST_SCOPE_BLOCK ? PACKAGE_SPEC_FILES : PACKAGE_SOURCE_FILES)], ignores: [...(block.ignores ?? []), ...PACKAGE_CONTRACT] };
174
178
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starci/eslint-canon-fe",
3
- "version": "9.16.6",
3
+ "version": "9.16.7",
4
4
  "description": "Universal front-end lint laws for TypeScript and Next.js, independent of the selected Grammar family.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -86,6 +86,6 @@
86
86
  "eslint-plugin-react-hooks": "^7.1.1",
87
87
  "typescript": "^6.0.3"
88
88
  },
89
- "gitHead": "5cd9650d8f2b83f57ecfc348ccd8ea359ff4cd4a",
90
- "starciSource": "a54264f79c8f56449a186491298356721ff16ba525bb051e3212e252bc6b9948"
89
+ "gitHead": "1ac3e3ed36e167ca7dbed5cad593ca8033106f44",
90
+ "starciSource": "7fed82137872a789ce9a69b64d07ddaca1758b3f96b2b0a8ef36935de076f28a"
91
91
  }