@starci/eslint-grammar-core 0.15.34 → 0.16.2
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 +14 -0
- package/README.md +1 -1
- package/dist/index.js +4 -0
- package/dist/lib/why.js +15 -0
- package/dist/mascot.d.ts +28 -0
- package/dist/mascot.js +166 -0
- package/dist/surface-depth.d.ts +7 -0
- package/dist/surface-depth.js +92 -0
- package/docs/mascot.md +60 -0
- package/docs/surface-depth.md +40 -0
- package/package.json +2 -2
- package/runtime/bundle.json +74 -0
- package/runtime/engine/by-code-unit.mjs +6 -6
- package/runtime/engine/model-config.mjs +98 -76
- package/runtime/engine/orca-config.mjs +22 -17
- package/runtime/engine/release-config.mjs +22 -18
- package/runtime/engine/removed-vocabulary.mjs +21 -20
- package/runtime/engine/resources-config.mjs +42 -35
- package/runtime/engine/runtime-root.mjs +11 -13
- package/runtime/engine/secrets.mjs +170 -102
- package/runtime/engine/sonar-config.mjs +16 -13
- package/runtime/knowledge/hfs/canon-pins.yaml +10 -10
- package/runtime/knowledge/hfs/rules.yaml +95 -6
- package/runtime/knowledge/hfs/slots.yaml +2 -2
- package/runtime/knowledge/patterns/fe/ui.yaml +13 -1
- package/runtime/scripts/hfs/allows.mjs +37 -38
- package/runtime/scripts/hfs/architecture/config.mjs +302 -268
- package/runtime/scripts/hfs/architecture/side-boundary.mjs +2 -5
- package/runtime/scripts/hfs/architecture/type-context.mjs +255 -250
- package/runtime/scripts/hfs/architecture/typescript.mjs +358 -318
- package/runtime/scripts/hfs/declaration-shape.mjs +140 -103
- package/runtime/scripts/hfs/declaration-slots.mjs +64 -61
- package/runtime/scripts/hfs/edition-slots.mjs +43 -40
- package/runtime/scripts/hfs/param-names.mjs +6 -11
- package/runtime/scripts/hfs/rule-catalog.mjs +353 -257
- package/runtime/scripts/hfs/rule-params-shape.mjs +60 -47
- package/runtime/scripts/hfs/slot-app-view.mjs +69 -74
- package/runtime/scripts/hfs/slot-classify.mjs +42 -38
- package/runtime/scripts/hfs/slot-errors.mjs +8 -7
- package/runtime/scripts/hfs/slot-imports.mjs +70 -63
- package/runtime/scripts/hfs/slot-manifest-shape.mjs +74 -52
- package/runtime/scripts/hfs/slot-match.mjs +122 -111
- package/runtime/scripts/hfs/slot-path.mjs +0 -2
- package/runtime/scripts/hfs/slot-required.mjs +65 -59
- package/runtime/scripts/hfs/slot-semantic-problems.mjs +138 -112
- package/runtime/scripts/hfs/slot-side-problems.mjs +23 -19
- package/runtime/scripts/hfs/slots.mjs +175 -152
- package/runtime/scripts/hfs/typescript-programs.mjs +66 -69
- package/runtime/scripts/hfs/view.mjs +38 -40
- package/runtime/scripts/lib/glob.mjs +23 -14
- package/runtime/scripts/lib/grammar-lint.mjs +33 -37
- package/runtime/scripts/lib/i18n.mjs +32 -35
- package/runtime/scripts/lib/json-clone.mjs +45 -36
- package/runtime/scripts/lib/json.mjs +26 -14
- package/runtime/scripts/lib/list.mjs +9 -14
- package/runtime/scripts/lib/path-key.mjs +53 -38
- package/runtime/scripts/lib/read-text.mjs +30 -17
- package/runtime/scripts/lib/regex.mjs +1 -2
- package/runtime/scripts/lib/source-phrases.mjs +13 -13
- package/runtime/scripts/lib/ts-analysis.mjs +28 -26
- package/runtime/scripts/lib/ts-ast.mjs +36 -42
- package/runtime/scripts/lib/walk.mjs +33 -27
- package/runtime/scripts/lib/yaml-cached.mjs +4 -4
|
@@ -51,7 +51,7 @@ versioning:
|
|
|
51
51
|
# 3.10.0 is a minor (2026-10-29): it ADDS the lite be.platform.database.entities slot, the entity registry (slot fields role and importedBy), so the
|
|
52
52
|
# tier matrix and the public-entry rules admit exactly its <c>Entities imports and its deep importers (persistence.md BE-PERSISTENCE-3).
|
|
53
53
|
# 3.11.0 (ruling:lite-official-postgres-image, 2026-10-29) is, like 3.9.0, a change for lite only: it ADDS the managed app.db.image slot
|
|
54
|
-
# (db/Dockerfile, written by `starci app sync --
|
|
54
|
+
# (db/Dockerfile, written by `starci app sync --execute`), narrows ruleParams.db.extensions to the extensions that image carries, and gives
|
|
55
55
|
# @nestjs/schedule and cron one owner, platform/jobs (R335).
|
|
56
56
|
# 3.13.0 (rulings lite-pgmq-bus-bullmq-jobs and lite-db-image-in-stacks, 2026-10-29) is a change for lite only: ruleParams.db.extensions
|
|
57
57
|
# admits pgmq, the event bus, ruleParams.db.queueOutbox is retired with the pg_cron half of R258, the lite event-bus functions replace
|
|
@@ -940,7 +940,7 @@ slots:
|
|
|
940
940
|
|
|
941
941
|
# ----- app root: the database of a lite app (ruling:lite-self-hosted-postgres-passport-minio): a self-hosted PostgreSQL in the app's
|
|
942
942
|
# stack (the `db` service, built from the managed .starcistacks/images/db/Dockerfile: the official postgres image plus pgvector and pgmq, ruling:lite-db-image-in-stacks), migrated by
|
|
943
|
-
# `starci app db migrate --url-env <NAME>`. A full app keeps its TypeORM migrations under be/ and has no such folder.
|
|
943
|
+
# `starci app db migrate --db-url-env <NAME>`. A full app keeps its TypeORM migrations under be/ and has no such folder.
|
|
944
944
|
- id: app.db
|
|
945
945
|
profiles: [app]
|
|
946
946
|
editions: [lite]
|
|
@@ -24,7 +24,7 @@ rules:
|
|
|
24
24
|
- id: FE-UI
|
|
25
25
|
title: Compose the selected Grammar
|
|
26
26
|
kind: mandatory
|
|
27
|
-
hfsRules: [R93, R244, R313, R314, R315, R316, R317, R318, R319, R320]
|
|
27
|
+
hfsRules: [R93, R244, R313, R314, R315, R316, R317, R318, R319, R320, R338, R339, R340]
|
|
28
28
|
requirement: |-
|
|
29
29
|
Components compose the selected Grammar through its published entry and props; application CSS carries
|
|
30
30
|
layout only (css.yaml). A missing visual capability is added to that Grammar before the app consumes it.
|
|
@@ -59,6 +59,15 @@ rules:
|
|
|
59
59
|
(owner:agent-avatar-initials-bot-badge). Apps neither declare nor import an avatar-generation
|
|
60
60
|
library and draw no avatar visuals; the family owns the renderer API (the StarCi recipe is
|
|
61
61
|
groupIdentity in its playbook).
|
|
62
|
+
- id: case-4
|
|
63
|
+
date: "2026-10-30"
|
|
64
|
+
source: owner
|
|
65
|
+
when: A screen shows generated character art (a mascot)
|
|
66
|
+
write: |-
|
|
67
|
+
Render it with the selected Grammar's Mascot at a step of its size scale (sm, md, lg, or hero for a split
|
|
68
|
+
screen), passing the asset slot it was requested under (assetSlot, and assetSha256 once delivered); a scene
|
|
69
|
+
or illustration is framed by MediaFrame. Generated art under /images/ never renders through a bare Image or
|
|
70
|
+
img (R338, R339).
|
|
62
71
|
verification:
|
|
63
72
|
automated:
|
|
64
73
|
- FE_VENDOR_BOUNDARY
|
|
@@ -81,5 +90,8 @@ rules:
|
|
|
81
90
|
- FE_SINGLE_COMMIT_PER_RENDER
|
|
82
91
|
- FE_NO_COMMIT_IN_COLLECTION_ITEM
|
|
83
92
|
- FE_CONTROL_HEIGHT
|
|
93
|
+
- FE_GENERATED_ART_OUTSIDE_FRAME
|
|
94
|
+
- FE_MASCOT_ASSET_SLOT_MISSING
|
|
95
|
+
- FE_RAISED_SURFACE_IN_SURFACE
|
|
84
96
|
manual: []
|
|
85
97
|
relatedExamples: [full-app-shell, lite-app-shell]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { braceVariants, globExpression } from '../lib/glob.mjs';
|
|
3
3
|
import { declaredLogicOf } from './manifest-shape.mjs';
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* What a slot's `requires`, `allows` and `forbids` entries (knowledge/hfs/slots.yaml) say about a file, read through the
|
|
7
6
|
* resolver of scripts/hfs/slots.mjs. The machine checks that judge "this folder holds only what its slot allows"
|
|
@@ -14,65 +13,65 @@ import { declaredLogicOf } from './manifest-shape.mjs';
|
|
|
14
13
|
*/
|
|
15
14
|
const VAR = /<([A-Za-z][A-Za-z0-9-]*)>/g;
|
|
16
15
|
const SPEC = /\.spec\.ts$/;
|
|
17
|
-
|
|
18
16
|
/**
|
|
19
17
|
* Whether `relative` is the unit spec `<stem>.spec.ts` of a measured file beside it that the slot names: a file the slot declares in
|
|
20
18
|
* `logic`, or a `requires`/`allows` file of a logic role (ruleParams.be.logicRoles), in a slot whose coverage is required and whose tests
|
|
21
19
|
* are unit-beside. The slot admits that spec without listing it, as unit-test-colocated (R47) accepts it.
|
|
22
20
|
*/
|
|
23
21
|
function isMeasuredSpec(resolver, classified, slot, relative, named) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
if (!SPEC.test(relative) || slot.coverage !== 'required' || slot.tests !== 'unit-beside')
|
|
23
|
+
return false;
|
|
24
|
+
const subject = relative.replace(SPEC, '.ts');
|
|
25
|
+
if (declaredLogicOf(slot).includes(subject))
|
|
26
|
+
return true;
|
|
27
|
+
const role = /\.([a-z0-9-]+)\.ts$/.exec(subject)?.[1];
|
|
28
|
+
// An app resolver keeps no rule parameters of its own: a path on a side reads that side's.
|
|
29
|
+
const params = classified.side ? resolver.sides?.[classified.side]?.ruleParams() : resolver.ruleParams?.();
|
|
30
|
+
return (params?.logicRoles ?? []).includes(role) && named.some((matcher) => matcher.expression.test(subject));
|
|
31
31
|
}
|
|
32
|
-
|
|
33
32
|
function matchersOf(entries, bindings) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
return (entries ?? []).flatMap((entry) => {
|
|
34
|
+
const directory = entry.endsWith('/');
|
|
35
|
+
const body = directory ? entry.slice(0, -1) : entry;
|
|
36
|
+
const filled = body.replace(VAR, (_whole, name) => bindings[name] ?? '*');
|
|
37
|
+
return braceVariants(filled).map((variant) => ({ entry, directory, expression: globExpression(directory ? `${variant}/**` : variant) }));
|
|
38
|
+
});
|
|
40
39
|
}
|
|
41
|
-
|
|
42
40
|
/** The path of `file` below the instance root of the slot that owns it. */
|
|
43
41
|
export function relativeToRoot(file, root) {
|
|
44
|
-
|
|
42
|
+
return root && file.startsWith(`${root}/`) ? file.slice(root.length + 1) : path.posix.basename(file);
|
|
45
43
|
}
|
|
46
|
-
|
|
47
44
|
/**
|
|
48
45
|
* Whether the slot that owns `file` names it in `requires` or `allows` (and does not forbid it); null when no enabled slot
|
|
49
46
|
* owns it. Unlike allowsFile it judges a slot that lists only `requires` too, so a folder closed by its slot (an app's
|
|
50
47
|
* src/) is read from the slot and never from a check's own list.
|
|
51
48
|
*/
|
|
52
49
|
export function slotAdmitsFile(resolver, file) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
const classified = resolver.classifyPath(file);
|
|
51
|
+
if (classified.status === 'no-slot' || classified.status === 'ambiguous' || !classified.slot)
|
|
52
|
+
return null;
|
|
53
|
+
const slot = resolver.slot(classified.slot);
|
|
54
|
+
const relative = relativeToRoot(classified.path, classified.root);
|
|
55
|
+
const named = matchersOf([...(slot.requires ?? []), ...(slot.allows ?? [])], classified.bindings);
|
|
56
|
+
const hit = named.some(matcher => matcher.expression.test(relative)) || isMeasuredSpec(resolver, classified, slot, relative, named);
|
|
57
|
+
const forbidden = matchersOf(slot.forbids, classified.bindings).some(matcher => matcher.expression.test(relative) || matcher.expression.test(`${relative}/`));
|
|
58
|
+
return hit && !forbidden;
|
|
61
59
|
}
|
|
62
|
-
|
|
63
60
|
/**
|
|
64
61
|
* {slot, root, relative, allowed, entry?, forbiddenBy?} for a repository-relative file, or null when no enabled slot owns
|
|
65
62
|
* it or the slot names no `allows`. `allowed` is true when the relative path matches a `requires` or `allows` entry.
|
|
66
63
|
*/
|
|
67
64
|
export function allowsFile(resolver, file) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
const classified = resolver.classifyPath(file);
|
|
66
|
+
if (classified.status === 'no-slot' || classified.status === 'ambiguous' || !classified.slot)
|
|
67
|
+
return null;
|
|
68
|
+
const slot = resolver.slot(classified.slot);
|
|
69
|
+
if (!slot?.allows?.length)
|
|
70
|
+
return null;
|
|
71
|
+
const relative = relativeToRoot(classified.path, classified.root);
|
|
72
|
+
const named = matchersOf([...(slot.requires ?? []), ...slot.allows], classified.bindings);
|
|
73
|
+
const hit = named.find(matcher => matcher.expression.test(relative));
|
|
74
|
+
const spec = !hit && isMeasuredSpec(resolver, classified, slot, relative, named);
|
|
75
|
+
const forbidden = matchersOf(slot.forbids, classified.bindings).find(matcher => matcher.expression.test(relative) || matcher.expression.test(`${relative}/`));
|
|
76
|
+
return { slot: slot.id, root: classified.root, relative, allowed: (Boolean(hit) || spec) && !forbidden, entry: hit?.entry, forbiddenBy: forbidden?.entry, allows: slot.allows };
|
|
78
77
|
}
|