@brighterly/lib-fe-codestyle 0.5.2 → 1.0.1
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/README.md +234 -178
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +181 -0
- package/dist/config/define-config.d.ts +11 -0
- package/dist/config/define-config.js +33 -0
- package/dist/config/load-config.d.ts +15 -0
- package/dist/config/load-config.js +52 -0
- package/dist/config/schema.d.ts +58 -0
- package/dist/config/schema.js +139 -0
- package/dist/{invariants → engine}/ast.d.ts +1 -6
- package/dist/{invariants → engine}/ast.js +18 -1
- package/dist/engine/docs.d.ts +14 -0
- package/dist/engine/docs.js +72 -0
- package/dist/engine/meta.d.ts +32 -0
- package/dist/engine/meta.js +47 -0
- package/dist/engine/migrate.d.ts +22 -0
- package/dist/engine/migrate.js +175 -0
- package/dist/engine/overrides.d.ts +36 -0
- package/dist/engine/overrides.js +92 -0
- package/dist/engine/registry.d.ts +35 -0
- package/dist/engine/registry.js +100 -0
- package/dist/engine/report.d.ts +23 -0
- package/dist/engine/report.js +87 -0
- package/dist/engine/run.d.ts +57 -0
- package/dist/engine/run.js +353 -0
- package/dist/engine/self-test.d.ts +33 -0
- package/dist/engine/self-test.js +141 -0
- package/dist/engine/types.d.ts +232 -0
- package/dist/{invariants → engine}/types.js +2 -1
- package/dist/{invariants → engine}/util.d.ts +31 -39
- package/dist/{invariants → engine}/util.js +59 -86
- package/dist/index.d.ts +16 -0
- package/dist/index.js +14 -0
- package/dist/rules/convention.d.ts +20 -0
- package/dist/{invariants/rules → rules}/convention.js +89 -15
- package/dist/rules/index.d.ts +28 -0
- package/dist/{invariants/rules → rules}/index.js +40 -32
- package/dist/{invariants/rules → rules}/regression.d.ts +1 -1
- package/dist/{invariants/rules → rules}/regression.js +26 -6
- package/dist/{invariants/rules → rules}/shared.d.ts +1 -1
- package/dist/validate/index.d.ts +1 -1
- package/dist/validate/index.js +1 -1
- package/package.json +8 -13
- package/dist/invariants/index.d.ts +0 -7
- package/dist/invariants/index.js +0 -5
- package/dist/invariants/rules/convention.d.ts +0 -18
- package/dist/invariants/rules/fixtures.d.ts +0 -17
- package/dist/invariants/rules/fixtures.js +0 -89
- package/dist/invariants/rules/index.d.ts +0 -55
- package/dist/invariants/rules/linter.d.ts +0 -10
- package/dist/invariants/rules/linter.js +0 -9
- package/dist/invariants/run.d.ts +0 -53
- package/dist/invariants/run.js +0 -746
- package/dist/invariants/self-test.d.ts +0 -46
- package/dist/invariants/self-test.js +0 -84
- package/dist/invariants/types.d.ts +0 -222
- /package/dist/{invariants/rules → rules}/shared.js +0 -0
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fixtures for the common rule pack — shipped, not test-only.
|
|
3
|
-
*
|
|
4
|
-
* Fixtures travel with their rules. A consuming app runs `--self-test` over the rules it
|
|
5
|
-
* actually loads, so if the pack shipped rules without fixtures every consumer would report
|
|
6
|
-
* "no self-test fixture" for rules it did not write and cannot fix.
|
|
7
|
-
*
|
|
8
|
-
* `bad` must produce at least one finding, `good` none.
|
|
9
|
-
*/
|
|
10
|
-
export const commonFixtures = {
|
|
11
|
-
'core/R1': {
|
|
12
|
-
file: 'app/a.ts',
|
|
13
|
-
bad: 'const t = localStorage.getItem("k")',
|
|
14
|
-
good: 'const t = safeLocalStorage.getItem("k")',
|
|
15
|
-
},
|
|
16
|
-
'core/R2': {
|
|
17
|
-
file: 'app/components/A.vue',
|
|
18
|
-
bad: '<template><div /></template>\n<style scoped lang="scss">.a { color: red; }</style>',
|
|
19
|
-
good: '<template><div /></template>\n<style scoped lang="scss" src="@scss/components/A.scss" />',
|
|
20
|
-
},
|
|
21
|
-
'core/R3': {
|
|
22
|
-
file: 'app/a.ts',
|
|
23
|
-
bad: 'const v = JSON.parse(raw)',
|
|
24
|
-
good: 'let v = null\ntry { v = JSON.parse(raw) } catch { v = null }',
|
|
25
|
-
},
|
|
26
|
-
'core/R4': {
|
|
27
|
-
file: 'app/assets/scss/fonts.scss',
|
|
28
|
-
bad: '@font-face { font-family: Rubik, sans-serif; src: url(a.woff2); }',
|
|
29
|
-
good: '@font-face { font-family: Rubik; src: url(a.woff2); }',
|
|
30
|
-
},
|
|
31
|
-
'core/C1': {
|
|
32
|
-
file: 'app/a.ts',
|
|
33
|
-
bad: 'window.addEventListener("resize", onResize)',
|
|
34
|
-
good: 'useEventListener(window, "resize", onResize)',
|
|
35
|
-
},
|
|
36
|
-
'core/C3': [
|
|
37
|
-
{
|
|
38
|
-
file: 'app/assets/scss/components/Card.scss',
|
|
39
|
-
bad: '.card { color: #1f2937; }',
|
|
40
|
-
good: '.card { color: $slate-800; }',
|
|
41
|
-
},
|
|
42
|
-
// In a .vue file only the <style> block is a stylesheet: an SVG fill in the
|
|
43
|
-
// template has no place to put a $token, so it must stay quiet.
|
|
44
|
-
{
|
|
45
|
-
file: 'app/components/UI/Icons/IconLeaf.vue',
|
|
46
|
-
bad: '<template><svg><path fill="currentColor" /></svg></template>\n<style scoped lang="scss">\n.icon { color: #e2e8f0; }\n</style>',
|
|
47
|
-
good: '<template><svg><path fill="#E2E8F0" /></svg></template>\n<style scoped lang="scss">\n.icon { color: $slate-200; }\n</style>',
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
'core/C4': [
|
|
51
|
-
{
|
|
52
|
-
file: 'app/a.ts',
|
|
53
|
-
bad: "const d = dayjs().format('YYYY-MM-DD')",
|
|
54
|
-
good: 'const d = dayjs().format(DateFormat.DefaultDate)',
|
|
55
|
-
},
|
|
56
|
-
// The day-extraction misuse fires; a bare toISOString() (an API timestamp) and the
|
|
57
|
-
// epoch duration trick do not.
|
|
58
|
-
{
|
|
59
|
-
file: 'app/b.ts',
|
|
60
|
-
bad: "const day = new Date().toISOString().split('T')[0]",
|
|
61
|
-
good: 'const generatedAt = dayjs().toISOString()\nconst duration = new Date(s * 1000).toISOString().slice(14, 19)',
|
|
62
|
-
},
|
|
63
|
-
// Every letter run must be a real dayjs token — an answer label that happens to fit
|
|
64
|
-
// the char class ('ADHD / ADD' carries a DD) is not a format string.
|
|
65
|
-
{
|
|
66
|
-
file: 'app/c.ts',
|
|
67
|
-
good: "const option = { code: 'ADHD_ADD', label: 'ADHD / ADD' }",
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
'core/C6': {
|
|
71
|
-
file: 'app/assets/scss/components/Card.scss',
|
|
72
|
-
bad: '.card { font-size: 14px; }',
|
|
73
|
-
good: '.card { @include font(14px, 20px); color: $slate-800; }',
|
|
74
|
-
},
|
|
75
|
-
'core/C7': {
|
|
76
|
-
// Two script tags in OPPOSITE orders, so the bad fixture violates whichever
|
|
77
|
-
// direction the consuming app declares in settings.scriptAttrOrder. The good
|
|
78
|
-
// fixture carries no lang attribute, so it is clean under either canonical.
|
|
79
|
-
file: 'app/components/A.vue',
|
|
80
|
-
bad: '<script lang="ts" setup>\n</script>\n<script setup lang="ts">\n</script>',
|
|
81
|
-
good: '<template><div /></template>\n<script setup>\nconst a = 1\n</script>',
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* `core/C2` and `core/C5` are `once` rules over the whole file list — a single-file fixture
|
|
86
|
-
* cannot express them, so they are exempt from the fixture requirement and covered by
|
|
87
|
-
* their own tests instead.
|
|
88
|
-
*/
|
|
89
|
-
export const commonSelfTestSkip = ['core/C2', 'core/C5'];
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One rule list, assembled from the family files — the same shape each consuming app uses
|
|
3
|
-
* for its own rules.
|
|
4
|
-
*
|
|
5
|
-
* The family letter says where a rule came from and who owns changing it:
|
|
6
|
-
* R — regression: it broke production at least once → a code decision
|
|
7
|
-
* B — business: a data contract → NOT shipped here; every app's
|
|
8
|
-
* contract is its own domain
|
|
9
|
-
* C — convention: a preference we chose → team consensus
|
|
10
|
-
* L — linter: a built-in ESLint rule → eslint.config.mjs
|
|
11
|
-
*
|
|
12
|
-
* Shared rule ids carry the `core/` prefix (`core/R1`); app-local ids stay bare (`R1`).
|
|
13
|
-
* The prefix marks provenance and keeps the two number lines independent — and `run()`
|
|
14
|
-
* still fails fast on a duplicate rather than letting an allowlist silently suppress
|
|
15
|
-
* the wrong rule.
|
|
16
|
-
*/
|
|
17
|
-
import type { Rule } from '../types.js';
|
|
18
|
-
export { linterOwnedRules } from './linter.js';
|
|
19
|
-
export { commonFixtures, commonSelfTestSkip } from './fixtures.js';
|
|
20
|
-
export { eachLine, setting } from './shared.js';
|
|
21
|
-
export type { LineFn } from './shared.js';
|
|
22
|
-
/** Every shared rule, in report order. Hover `sharedRuleIds` members for what each checks. */
|
|
23
|
-
export declare const commonRules: Rule[];
|
|
24
|
-
/**
|
|
25
|
-
* The hoverable catalog: every rule this pack ships, id → id. Use these constants for
|
|
26
|
-
* `allowlists` / `levels` keys and `--rule=` values when you want the contract in the
|
|
27
|
-
* IDE — hover any member for what the rule checks, at which level, and what to do
|
|
28
|
-
* instead. A test pins this map to `commonRules`, so it cannot drift.
|
|
29
|
-
*/
|
|
30
|
-
export declare const sharedRuleIds: {
|
|
31
|
-
/** `warn` (target `error`, interim 2026-09-25) — bare `localStorage`/`sessionStorage` access. The accessor itself throws SecurityError on Safari ITP, Firefox strict mode and in-app webviews; `if (localStorage)` guards throw too. Fix: the app's safe storage wrapper (`settings.safeStorageModule`). */
|
|
32
|
-
readonly 'core/R1': "core/R1";
|
|
33
|
-
/** `error` — SCSS rules written inline in a Vue `<style>` block. Inline styles drift from the design tokens invisibly. Fix: a dedicated `.scss` file referenced via `<style scoped lang="scss" src="…" />`. */
|
|
34
|
-
readonly 'core/R2': "core/R2";
|
|
35
|
-
/** `warn` (target `error`, interim 2026-09-25) — `JSON.parse` with no enclosing `try`/`catch`. A corrupt stored value crashes that code path permanently for the visitor. Fix: the app's guarded parse helper (`settings.safeJsonParse`) or try/catch. */
|
|
36
|
-
readonly 'core/R3': "core/R3";
|
|
37
|
-
/** `error` — `@font-face` declaring a font *stack*. Inside `@font-face`, `font-family` names the face being defined; a comma-separated stack is invalid and the browser drops the face silently. Fix: single family name inside, the stack on the selectors that use it. */
|
|
38
|
-
readonly 'core/R4': "core/R4";
|
|
39
|
-
/** `warn` — hand-rolled browser API with a VueUse equivalent (`new IntersectionObserver`, `addEventListener`, `setInterval`, …). VueUse owns the lifecycle/SSR/error paths. Fix: the composable named in the message, imported from `@vueuse/core`. */
|
|
40
|
-
readonly 'core/C1': "core/C1";
|
|
41
|
-
/** `warn` — a component whose filename duplicates a UI-kit component (`settings.uiKitRoot`). A same-name second component splits the design system in two. Fix: import or extend the UI-kit one. */
|
|
42
|
-
readonly 'core/C2': "core/C2";
|
|
43
|
-
/** `warn` — a literal colour (`#hex`, numeric `rgba()`) in SCSS/Vue instead of a palette token. Hardcoded colours survive theme and palette changes silently. Fix: a token from `settings.scssTokensFile`. */
|
|
44
|
-
readonly 'core/C3': "core/C3";
|
|
45
|
-
/** `warn` — a hand-rolled date format string (`'YYYY-MM-DD'`) or a `toISOString()` whose date part is extracted (`.split('T')[0]`, `.slice(0, 10)`). The date's shape becomes an accident instead of a contract. Fix: the shared enum (`settings.dateFormatModule`). */
|
|
46
|
-
readonly 'core/C4': "core/C4";
|
|
47
|
-
/** `warn` — a type file outside `types/<entity>/{enums,interfaces,types}.ts` (root under `settings.typesRoot`). Root-level or mixed-kind type files accrete unrelated entities. `.d.ts` ambient files are exempt. */
|
|
48
|
-
readonly 'core/C5': "core/C5";
|
|
49
|
-
/** `warn` — a raw `font-family`/`font-size`/`font-weight` declaration. Hand-written fonts drift off the UI-kit type scale silently. Fix: the app's typography source (`settings.typographySource`). */
|
|
50
|
-
readonly 'core/C6': "core/C6";
|
|
51
|
-
/** `warn` — `<script>` attribute order differing from the app canonical (`settings.scriptAttrOrder`, default `setup-first`). The two spellings are compiler-equivalent, so the split only ever grows. */
|
|
52
|
-
readonly 'core/C7': "core/C7";
|
|
53
|
-
};
|
|
54
|
-
/** Union of every id the shared pack ships — for typing app config keys. */
|
|
55
|
-
export type SharedRuleId = keyof typeof sharedRuleIds;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Linter rules — invariants a built-in ESLint rule already covers better than we could.
|
|
3
|
-
*
|
|
4
|
-
* Declared here, configured in each app\'s `eslint.config.mjs`, so the generated inventory
|
|
5
|
-
* is complete and nobody re-implements one by accident. Empty today: a declaration here
|
|
6
|
-
* asserts the rule IS configured, and claiming coverage the linter does not provide is the
|
|
7
|
-
* exact failure this directory exists to prevent.
|
|
8
|
-
*/
|
|
9
|
-
import type { LinterOwnedRule } from '../types.js';
|
|
10
|
-
export declare const linterOwnedRules: LinterOwnedRule[];
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Linter rules — invariants a built-in ESLint rule already covers better than we could.
|
|
3
|
-
*
|
|
4
|
-
* Declared here, configured in each app\'s `eslint.config.mjs`, so the generated inventory
|
|
5
|
-
* is complete and nobody re-implements one by accident. Empty today: a declaration here
|
|
6
|
-
* asserts the rule IS configured, and claiming coverage the linter does not provide is the
|
|
7
|
-
* exact failure this directory exists to prevent.
|
|
8
|
-
*/
|
|
9
|
-
export const linterOwnedRules = [];
|
package/dist/invariants/run.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The invariants runner — `run(options)`.
|
|
3
|
-
*
|
|
4
|
-
* This is land-app's `invariants/cli.mts` with four hardcoded constants lifted into
|
|
5
|
-
* arguments (scan roots, rule sources, the spec dir/project, the README path) and the rule
|
|
6
|
-
* list, config and fixtures injected. Nothing else was redesigned: the argv surface, the
|
|
7
|
-
* self-test gate, the caches, the suppression grammar, severity resolution, the reporter
|
|
8
|
-
* and the exit codes are the originals.
|
|
9
|
-
*
|
|
10
|
-
* Exit codes:
|
|
11
|
-
* 0 — no error-level violations
|
|
12
|
-
* 1 — at least one error-level violation
|
|
13
|
-
* 2 — the validator itself failed
|
|
14
|
-
*/
|
|
15
|
-
import type { Allowlists, Levels, LinterOwnedRule, RetiredRules, Rule, Unmaintained } from './types.js';
|
|
16
|
-
import type { Fixture } from './self-test.js';
|
|
17
|
-
export interface RunOptions {
|
|
18
|
-
/** Repo root. Passed, never derived — import.meta.url here resolves into node_modules. */
|
|
19
|
-
root: string;
|
|
20
|
-
rules: Rule[];
|
|
21
|
-
linterOwnedRules: LinterOwnedRule[];
|
|
22
|
-
config: {
|
|
23
|
-
allowlists: Allowlists;
|
|
24
|
-
levels: Levels;
|
|
25
|
-
retired: RetiredRules;
|
|
26
|
-
unmaintained: Unmaintained;
|
|
27
|
-
/** App-specific paths shared rules read from RuleContext.settings. */
|
|
28
|
-
settings?: Readonly<Record<string, string>>;
|
|
29
|
-
};
|
|
30
|
-
/** Directories walked for the candidate file set. */
|
|
31
|
-
scanRoots: string[];
|
|
32
|
-
/** Path prefixes whose change triggers the self-test in --staged mode. */
|
|
33
|
-
ruleSources: string[];
|
|
34
|
-
/** Vitest project name for the module-resolving half. */
|
|
35
|
-
vitestProject: string;
|
|
36
|
-
/** Directory holding the vector-2 specs. */
|
|
37
|
-
specDir: string;
|
|
38
|
-
/** README whose generated inventory must not drift. */
|
|
39
|
-
readmePath: string;
|
|
40
|
-
/** Config file a dangling allowlist/levels key is reported against. */
|
|
41
|
-
configFile?: string;
|
|
42
|
-
/** Fixtures for --self-test, keyed by rule id. Omit to skip the self-test entirely. */
|
|
43
|
-
fixtures?: Record<string, Fixture>;
|
|
44
|
-
/** Repo-specific self-test assertions; each returns failure messages. */
|
|
45
|
-
extraChecks?: (() => string[] | Promise<string[]>)[];
|
|
46
|
-
/** Rule ids exempt from the fixture requirement — registry rules a fixture cannot express. */
|
|
47
|
-
selfTestSkip?: string[];
|
|
48
|
-
/** Defaults to process.argv.slice(2). Injectable so tests need no argv games. */
|
|
49
|
-
argv?: string[];
|
|
50
|
-
/** Defaults to process.exit. Injectable so tests can assert the code. */
|
|
51
|
-
exit?: (code: number) => never;
|
|
52
|
-
}
|
|
53
|
-
export declare const run: (options: RunOptions) => Promise<void>;
|