@starci/hfs 4.0.10 → 4.1.0
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 +1 -1
- package/emit/operations.mjs +1 -1
- package/emit/type-schema.mjs +2 -1
- package/lint/run.mjs +3 -2
- package/package.json +1 -1
- package/report/order.mjs +2 -0
- package/runtime/config.example.yaml +187 -0
- package/runtime/engine/by-code-unit.mjs +12 -0
- package/runtime/engine/config.mjs +221 -239
- package/runtime/engine/invalid-config.mjs +5 -5
- package/runtime/engine/model-config.mjs +90 -0
- package/runtime/engine/orca-config.mjs +3 -1
- package/runtime/engine/removed-vocabulary.mjs +28 -0
- package/runtime/engine/resources-config.mjs +52 -0
- package/runtime/engine/runtime-root.mjs +17 -0
- package/runtime/engine/secrets.mjs +35 -31
- package/runtime/engine/sonar-config.mjs +21 -0
- package/runtime/engine/temp-root.mjs +32 -0
- package/runtime/knowledge/hfs/canon-pins.yaml +14 -14
- package/runtime/knowledge/hfs/peer-integrations.yaml +2 -3
- package/runtime/knowledge/hfs/rules.yaml +98 -65
- package/runtime/knowledge/hfs/slots.yaml +11 -14
- package/runtime/knowledge/patterns/be/api.yaml +7 -24
- package/runtime/knowledge/patterns/be/cli.yaml +3 -12
- package/runtime/knowledge/patterns/be/realtime.yaml +1 -14
- package/runtime/knowledge/patterns/be/webhooks.yaml +0 -19
- package/runtime/modules/kernel/failure-codes.yaml +1 -41
- package/runtime/modules/kernel/removed-vocabulary.yaml +168 -0
- package/runtime/modules/models/registry.yaml +25 -359
- package/runtime/modules/models/runtimes.yaml +92 -256
- package/runtime/modules/models/tiers.yaml +65 -0
- package/runtime/scripts/api/fs/claim-file.mjs +30 -0
- package/runtime/scripts/api/fs/ensure-temp-root.mjs +27 -0
- package/runtime/scripts/api/fs/forbidden-root.mjs +2 -1
- package/runtime/scripts/api/fs/make-temp-dir.mjs +11 -0
- package/runtime/scripts/api/fs/safe-remove.mjs +52 -35
- package/runtime/scripts/api/git/lib.mjs +34 -1
- package/runtime/scripts/api/process/resolve-real-tool.mjs +14 -8
- package/runtime/scripts/api/process/run-program.mjs +2 -1
- package/runtime/scripts/api/sops/lib.mjs +198 -120
- package/runtime/scripts/hfs/allows.mjs +3 -3
- package/runtime/scripts/hfs/architecture/ast-walks.mjs +63 -50
- package/runtime/scripts/hfs/architecture/automatic-gates.mjs +96 -0
- package/runtime/scripts/hfs/architecture/backend.mjs +261 -175
- package/runtime/scripts/hfs/architecture/background-unowned.mjs +69 -34
- package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +55 -54
- package/runtime/scripts/hfs/architecture/clones.mjs +179 -106
- package/runtime/scripts/hfs/architecture/config-unread.mjs +5 -22
- package/runtime/scripts/hfs/architecture/config.mjs +95 -80
- package/runtime/scripts/hfs/architecture/connection-map.mjs +233 -141
- package/runtime/scripts/hfs/architecture/constructor-deps.mjs +15 -9
- package/runtime/scripts/hfs/architecture/context-coupling.mjs +76 -52
- package/runtime/scripts/hfs/architecture/context-map.mjs +215 -141
- package/runtime/scripts/hfs/architecture/context-owner.mjs +39 -30
- package/runtime/scripts/hfs/architecture/context-platform-tables.mjs +31 -17
- package/runtime/scripts/hfs/architecture/context-transaction.mjs +38 -25
- package/runtime/scripts/hfs/architecture/contract-fixture-guard.mjs +86 -40
- package/runtime/scripts/hfs/architecture/contracts-readonly.mjs +342 -0
- package/runtime/scripts/hfs/architecture/contracts.mjs +263 -455
- package/runtime/scripts/hfs/architecture/cross-app-duplicate.mjs +43 -34
- package/runtime/scripts/hfs/architecture/dead-exports.mjs +201 -154
- package/runtime/scripts/hfs/architecture/default-deny.mjs +118 -93
- package/runtime/scripts/hfs/architecture/doc-language.mjs +2 -1
- package/runtime/scripts/hfs/architecture/entrypoint.mjs +45 -30
- package/runtime/scripts/hfs/architecture/error-codes.mjs +19 -12
- package/runtime/scripts/hfs/architecture/error-masked.mjs +39 -26
- package/runtime/scripts/hfs/architecture/fe-slot-allows.mjs +2 -1
- package/runtime/scripts/hfs/architecture/feature-shape.mjs +26 -20
- package/runtime/scripts/hfs/architecture/framework-pinned.mjs +1 -1
- package/runtime/scripts/hfs/architecture/frontend-grammar.mjs +190 -0
- package/runtime/scripts/hfs/architecture/frontend-routing.mjs +186 -0
- package/runtime/scripts/hfs/architecture/frontend-world-render.mjs +311 -0
- package/runtime/scripts/hfs/architecture/frontend-world.mjs +328 -0
- package/runtime/scripts/hfs/architecture/frontend.mjs +109 -829
- package/runtime/scripts/hfs/architecture/hfs-graph.mjs +14 -2
- package/runtime/scripts/hfs/architecture/hfs.mjs +120 -288
- package/runtime/scripts/hfs/architecture/hooks-are-hooks.mjs +46 -26
- package/runtime/scripts/hfs/architecture/i18n-keys.mjs +114 -76
- package/runtime/scripts/hfs/architecture/index.mjs +158 -102
- package/runtime/scripts/hfs/architecture/injection-token-exported.mjs +33 -28
- package/runtime/scripts/hfs/architecture/machine-ast.mjs +180 -144
- package/runtime/scripts/hfs/architecture/managed-scripts.mjs +8 -2
- package/runtime/scripts/hfs/architecture/module-per-transport.mjs +150 -101
- package/runtime/scripts/hfs/architecture/next-data-contract.mjs +51 -43
- package/runtime/scripts/hfs/architecture/next-data-key.mjs +338 -0
- package/runtime/scripts/hfs/architecture/next-data.mjs +179 -427
- package/runtime/scripts/hfs/architecture/owners.mjs +27 -13
- package/runtime/scripts/hfs/architecture/package-shape.mjs +51 -23
- package/runtime/scripts/hfs/architecture/presentation.mjs +165 -0
- package/runtime/scripts/hfs/architecture/reachability.mjs +127 -61
- package/runtime/scripts/hfs/architecture/register-once.mjs +112 -63
- package/runtime/scripts/hfs/architecture/registration.mjs +187 -110
- package/runtime/scripts/hfs/architecture/required-files.mjs +100 -68
- package/runtime/scripts/hfs/architecture/route-files-thin.mjs +83 -58
- package/runtime/scripts/hfs/architecture/schema-owner.mjs +182 -108
- package/runtime/scripts/hfs/architecture/source-names-shape.mjs +318 -0
- package/runtime/scripts/hfs/architecture/source-names.mjs +83 -248
- package/runtime/scripts/hfs/architecture/sql-owner.mjs +175 -118
- package/runtime/scripts/hfs/architecture/sql-returning.mjs +39 -28
- package/runtime/scripts/hfs/architecture/sql-tokens.mjs +302 -172
- package/runtime/scripts/hfs/architecture/supabase-ast.mjs +1 -1
- package/runtime/scripts/hfs/architecture/supabase-be.mjs +55 -45
- package/runtime/scripts/hfs/architecture/supabase-results.mjs +182 -0
- package/runtime/scripts/hfs/architecture/supabase-tables.mjs +20 -12
- package/runtime/scripts/hfs/architecture/supabase.mjs +191 -263
- package/runtime/scripts/hfs/architecture/symbols.mjs +175 -99
- package/runtime/scripts/hfs/architecture/test-world-files.mjs +82 -41
- package/runtime/scripts/hfs/architecture/tiers.mjs +120 -69
- package/runtime/scripts/hfs/architecture/transport-owner.mjs +84 -57
- package/runtime/scripts/hfs/architecture/type-context.mjs +282 -0
- package/runtime/scripts/hfs/architecture/typescript.mjs +116 -276
- package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +84 -62
- package/runtime/scripts/hfs/architecture.mjs +3 -4
- package/runtime/scripts/hfs/check.mjs +61 -70
- package/runtime/scripts/hfs/coverage-scope.mjs +84 -38
- package/runtime/scripts/hfs/declaration-shape.mjs +77 -36
- package/runtime/scripts/hfs/declaration-slots.mjs +1 -1
- package/runtime/scripts/hfs/edition-slots.mjs +5 -3
- package/runtime/scripts/hfs/linear-text.mjs +30 -0
- package/runtime/scripts/hfs/manifest-shape.mjs +164 -63
- package/runtime/scripts/hfs/path-findings.mjs +58 -38
- package/runtime/scripts/hfs/pin-findings.mjs +31 -0
- package/runtime/scripts/hfs/repo-identity.mjs +5 -2
- package/runtime/scripts/hfs/rule-catalog.mjs +194 -0
- package/runtime/scripts/hfs/rule-params-shape.mjs +33 -27
- package/runtime/scripts/hfs/rules/cli.mjs +5 -1
- package/runtime/scripts/hfs/rules/contract-compat.mjs +40 -22
- package/runtime/scripts/hfs/rules/contract.mjs +35 -27
- package/runtime/scripts/hfs/rules/database-config.mjs +57 -32
- package/runtime/scripts/hfs/rules/database-migrations.mjs +52 -31
- package/runtime/scripts/hfs/rules/database-plpgsql.mjs +106 -91
- package/runtime/scripts/hfs/rules/database-sql.mjs +254 -173
- package/runtime/scripts/hfs/rules/database.mjs +36 -23
- package/runtime/scripts/hfs/rules/deps.mjs +64 -32
- package/runtime/scripts/hfs/rules/docker.mjs +113 -65
- package/runtime/scripts/hfs/rules/edition.mjs +118 -111
- package/runtime/scripts/hfs/rules/event-bus.mjs +91 -45
- package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +17 -16
- package/runtime/scripts/hfs/rules/fe-no-tests.mjs +36 -16
- package/runtime/scripts/hfs/rules/frontend-tree.mjs +4 -3
- package/runtime/scripts/hfs/rules/integration-specs.mjs +75 -41
- package/runtime/scripts/hfs/rules/kinds.mjs +59 -25
- package/runtime/scripts/hfs/rules/lint-suppression.mjs +9 -3
- package/runtime/scripts/hfs/rules/monorepo.mjs +82 -45
- package/runtime/scripts/hfs/rules/peer-integrations.mjs +24 -3
- package/runtime/scripts/hfs/rules/pipeline.mjs +58 -9
- package/runtime/scripts/hfs/rules/proof-commands.mjs +14 -8
- package/runtime/scripts/hfs/rules/repo-local-checks.mjs +11 -6
- package/runtime/scripts/hfs/rules/saga.mjs +128 -61
- package/runtime/scripts/hfs/rules/secrets.mjs +4 -3
- package/runtime/scripts/hfs/rules/services.mjs +34 -16
- package/runtime/scripts/hfs/rules/stacks.mjs +21 -14
- package/runtime/scripts/hfs/rules/supabase-secrets.mjs +32 -23
- package/runtime/scripts/hfs/rules/test-topology.mjs +25 -11
- package/runtime/scripts/hfs/secret.mjs +59 -48
- package/runtime/scripts/hfs/slot-app-view.mjs +102 -0
- package/runtime/scripts/hfs/slot-classify.mjs +65 -0
- package/runtime/scripts/hfs/slot-errors.mjs +11 -0
- package/runtime/scripts/hfs/slot-imports.mjs +76 -0
- package/runtime/scripts/hfs/slot-manifest-shape.mjs +73 -0
- package/runtime/scripts/hfs/slot-match.mjs +153 -0
- package/runtime/scripts/hfs/slot-path.mjs +8 -0
- package/runtime/scripts/hfs/slot-required.mjs +76 -0
- package/runtime/scripts/hfs/slot-semantic-problems.mjs +148 -0
- package/runtime/scripts/hfs/slot-side-problems.mjs +28 -0
- package/runtime/scripts/hfs/slots.mjs +72 -693
- package/runtime/scripts/hfs/sql/pg-parse.mjs +5 -2
- package/runtime/scripts/hfs/trailing-slashes.mjs +8 -0
- package/runtime/scripts/hfs/tree.mjs +19 -14
- package/runtime/scripts/hfs/typescript-programs.mjs +6 -4
- package/runtime/scripts/hfs/view.mjs +1 -1
- package/runtime/scripts/lib/dockerfile.mjs +56 -33
- package/runtime/scripts/lib/event-contract.mjs +17 -13
- package/runtime/scripts/lib/git.mjs +2 -2
- package/runtime/scripts/lib/graphql-contract.mjs +158 -322
- package/runtime/scripts/lib/graphql-sdl.mjs +262 -0
- package/runtime/scripts/lib/i18n.mjs +3 -2
- package/runtime/scripts/lib/in-order.mjs +71 -0
- package/runtime/scripts/lib/language.mjs +3 -3
- package/runtime/scripts/lib/list.mjs +8 -1
- package/runtime/scripts/lib/path-key.mjs +38 -5
- package/runtime/scripts/lib/pid-alive.mjs +7 -0
- package/runtime/scripts/lib/regex.mjs +1 -1
- package/runtime/scripts/lib/same-text.mjs +1 -1
- package/runtime/scripts/lib/secret-patterns.mjs +6 -2
- package/runtime/scripts/lib/sleep-sync.mjs +2 -2
- package/runtime/scripts/lib/sops-envelope.mjs +95 -48
- package/runtime/scripts/lib/stack-services.mjs +1 -2
- package/runtime/scripts/lib/ts-ast.mjs +9 -0
- package/runtime/scripts/lib/walk.mjs +6 -1
- package/scaffold/add-cli-lite.mjs +2 -1
- package/scaffold/add-table.mjs +2 -2
- package/scaffold/add.mjs +3 -2
- package/scaffold/app.mjs +4 -2
- package/scaffold/edition-gate.mjs +25 -25
- package/scaffold/lite-exports.mjs +2 -1
- package/scaffold/service.mjs +5 -4
- package/sync/hygiene.mjs +15 -9
- package/sync/index.mjs +7 -3
- package/templates/app/ci-workflows/github/workflows/ci.yml +4 -4
- package/templates/app/ci-workflows/github/workflows/e2e.yml +3 -3
- package/templates/app/ci-workflows/github/workflows/images.yml +3 -3
- package/templates/app/ci-workflows/sonar-steps.yml +2 -2
- package/templates/app/ci-workflows-lite/github/workflows/ci.yml +6 -6
- package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +3 -3
- package/templates/app/ci-workflows-lite/github/workflows/images.yml +3 -3
- package/templates/app/starciwork.gitignore +1 -1
- package/templates/be/image/api/Dockerfile +1 -1
- package/templates/be/image/cli/Dockerfile +1 -1
- package/templates/be/image/worker/Dockerfile +1 -1
- package/templates/be/patterns/cli/group.cli.spec.ts.tpl +1 -1
- package/templates/be/patterns/cli/group.cli.ts.tpl +2 -2
- package/templates/be/patterns/event-bus/platform/event-runner.service.spec.ts.tpl +13 -0
- package/templates/be/patterns/event-bus/platform/event-runner.service.ts.tpl +7 -2
- package/templates/be/patterns/event-bus/platform/event.policy.ts.tpl +4 -1
- package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.ts.tpl +2 -1
- package/templates/be/patterns/outbox/platform/outbox-relay.policy.ts.tpl +24 -9
- package/templates/be/patterns/queues/platform/queue-relay.service.ts.tpl +3 -2
- package/templates/be/patterns/queues/platform/queue-worker.service.ts.tpl +8 -5
- package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.spec.ts +1 -1
- package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.ts +2 -2
- package/templates/be/skeleton/src/features/cli/seed/seed.cli.spec.ts +1 -1
- package/templates/be/skeleton/src/features/cli/seed/seed.cli.ts +2 -2
- package/templates/be/skeleton/src/modules/platform/database/migrate-connections.client.ts +3 -2
- package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.ts +5 -4
- package/templates/be/skeleton/src/modules/platform/primitives/index.ts +1 -0
- package/templates/be/skeleton/src/modules/platform/primitives/sequence.policy.spec.ts +47 -0
- package/templates/be/skeleton/src/modules/platform/primitives/sequence.policy.ts +16 -0
- package/templates/be/skeleton-lite/apps/api/Dockerfile +1 -0
- package/templates/be/skeleton-lite/src/modules/platform/primitives/index.ts +2 -0
- package/templates/fe/image/next/Dockerfile +2 -1
- package/templates/fe/skeleton/apps/app/src/app/[locale]/page.tsx +2 -2
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/page.tsx +2 -2
- package/templates/fe/skeleton/packages/__project__-i18n/src/index.ts +1 -2
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/layout.tsx +1 -2
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/page.tsx +2 -2
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/index.tsx +7 -1
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-out.ts +1 -1
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/validation/validation.mapper.ts +10 -2
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/request.ts +10 -3
- package/upgrade/index.mjs +9 -2
- package/runtime/engine/admission.mjs +0 -308
- package/runtime/engine/canonical-json.mjs +0 -10
- package/runtime/engine/db/blob.mjs +0 -315
- package/runtime/engine/db/ledger-paths.mjs +0 -83
- package/runtime/engine/db/ledger.mjs +0 -1118
- package/runtime/engine/db/machine-connection.mjs +0 -135
- package/runtime/engine/db/machine-schema.mjs +0 -84
- package/runtime/engine/db/machine.mjs +0 -1367
- package/runtime/engine/db/migrations/machine/0001-init.sql +0 -924
- package/runtime/engine/db/migrations/runtime/0001-init.sql +0 -1108
- package/runtime/engine/db/provider-reservations.mjs +0 -101
- package/runtime/engine/digest.mjs +0 -16
- package/runtime/engine/refuse.mjs +0 -11
- package/runtime/modules/ops/_labels.yaml +0 -53
- package/runtime/scripts/api/node/lib.mjs +0 -14
- package/runtime/scripts/api/node/spawn-node.mjs +0 -6
- package/runtime/scripts/api/process/lib.mjs +0 -111
- package/runtime/scripts/api/process/owned-process.mjs +0 -78
- package/runtime/scripts/api/process/stop-owned-process.mjs +0 -9
- package/runtime/scripts/connectors/lib.mjs +0 -488
- package/runtime/scripts/lib/clip.mjs +0 -19
- package/runtime/scripts/lib/display-names.mjs +0 -259
- package/runtime/scripts/lib/example-refs.mjs +0 -158
- package/runtime/scripts/lib/json-schema.mjs +0 -52
- package/runtime/scripts/lib/process-identity.mjs +0 -6
- package/runtime/scripts/lib/read-yaml.mjs +0 -18
- package/runtime/scripts/lib/redact.mjs +0 -161
- package/runtime/scripts/lib/sleep.mjs +0 -7
- package/runtime/scripts/lib/source-phrases.mjs +0 -34
- package/runtime/scripts/lib/sqlite.mjs +0 -21
|
@@ -1,171 +1,207 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { canonical } from './config.mjs';
|
|
3
|
-
import { sourceLocation } from '../../lib/ts-ast.mjs';
|
|
3
|
+
import { hasAnyFlag, sourceLocation } from '../../lib/ts-ast.mjs';
|
|
4
|
+
|
|
5
|
+
const HELPER_DEPTH = 4;
|
|
6
|
+
|
|
7
|
+
const checkerOf = (env, sourceFile) => env.context.checkerFor(sourceFile.fileName);
|
|
8
|
+
|
|
9
|
+
function aliased(env, checker, symbol) {
|
|
10
|
+
const { ts } = env;
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
let current = symbol;
|
|
13
|
+
while (current && hasAnyFlag(current.flags, ts.SymbolFlags.Alias) && !seen.has(current)) {
|
|
14
|
+
seen.add(current);
|
|
15
|
+
let target;
|
|
16
|
+
try { target = checker.getAliasedSymbol(current); } catch { break; }
|
|
17
|
+
if (!target || target === current || !(target.declarations?.length)) break;
|
|
18
|
+
current = target;
|
|
19
|
+
}
|
|
20
|
+
return current;
|
|
21
|
+
}
|
|
4
22
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export function machineKit({ config, context, graph }) {
|
|
12
|
-
const ts = context.ts;
|
|
13
|
-
const resolver = graph.resolver;
|
|
14
|
-
|
|
15
|
-
const checkerOf = sourceFile => context.checkerFor(sourceFile.fileName);
|
|
16
|
-
|
|
17
|
-
const aliased = (checker, symbol) => {
|
|
18
|
-
const seen = new Set();
|
|
19
|
-
let current = symbol;
|
|
20
|
-
while (current && (current.flags & ts.SymbolFlags.Alias) && !seen.has(current)) {
|
|
21
|
-
seen.add(current);
|
|
22
|
-
let target;
|
|
23
|
-
try { target = checker.getAliasedSymbol(current); } catch { break; }
|
|
24
|
-
if (!target || target === current || !(target.declarations?.length)) break;
|
|
25
|
-
current = target;
|
|
26
|
-
}
|
|
27
|
-
return current;
|
|
28
|
-
};
|
|
23
|
+
function symbolAt(env, checker, node) {
|
|
24
|
+
const { ts } = env;
|
|
25
|
+
if (!node) return null;
|
|
26
|
+
if (ts.isShorthandPropertyAssignment(node.parent ?? {}) && node.parent.name === node) return checker.getShorthandAssignmentValueSymbol(node.parent) ?? null;
|
|
27
|
+
return checker.getSymbolAtLocation(node) ?? null;
|
|
28
|
+
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
/** {name, module} when `target` is bound directly by an import specifier, default import or namespace import, else null. */
|
|
31
|
+
function ownImportBinding(env, checker, target) {
|
|
32
|
+
const { ts } = env;
|
|
33
|
+
const declaration = symbolAt(env, checker, target)?.declarations?.[0];
|
|
34
|
+
if (!declaration) return null;
|
|
35
|
+
if (ts.isImportSpecifier(declaration)) return { name: (declaration.propertyName ?? declaration.name).text, module: declaration.parent.parent.parent.moduleSpecifier.text };
|
|
36
|
+
if (ts.isImportClause(declaration)) return { name: 'default', module: declaration.parent.moduleSpecifier.text };
|
|
37
|
+
if (ts.isNamespaceImport(declaration)) return { name: '*', module: declaration.parent.parent.moduleSpecifier.text };
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
};
|
|
47
|
-
if (ts.isIdentifier(node)) return own(node);
|
|
48
|
-
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
|
|
49
|
-
const namespace = own(node.expression);
|
|
50
|
-
return namespace?.name === '*' ? { name: node.name.text, module: namespace.module } : null;
|
|
51
|
-
}
|
|
52
|
-
return null;
|
|
53
|
-
};
|
|
41
|
+
/** {name, module} when `node` (identifier, or namespace.member) is bound by an import from a module specifier, else null. */
|
|
42
|
+
function importBinding(env, checker, node) {
|
|
43
|
+
const { ts } = env;
|
|
44
|
+
if (ts.isIdentifier(node)) return ownImportBinding(env, checker, node);
|
|
45
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
|
|
46
|
+
const namespace = ownImportBinding(env, checker, node.expression);
|
|
47
|
+
return namespace?.name === '*' ? { name: node.name.text, module: namespace.module } : null;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
function isImportOf(env, checker, node, name, moduleName) {
|
|
53
|
+
const binding = importBinding(env, checker, node);
|
|
54
|
+
return Boolean(binding) && binding.name === name && binding.module === moduleName;
|
|
55
|
+
}
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
/** The declarations `node` resolves to through aliases. */
|
|
58
|
+
const declarationsOf = (env, checker, node) => aliased(env, checker, symbolAt(env, checker, node))?.declarations ?? [];
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
/** The repository-relative graph path of the file declaring `declaration`, or null when it is outside the program. */
|
|
61
|
+
const graphPath = (env, declaration) => env.graph.abs(canonical(declaration.getSourceFile().fileName));
|
|
65
62
|
|
|
66
|
-
|
|
63
|
+
const graphFile = (env, rel) => env.graph.files.get(rel) ?? null;
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
/** The capability (owner) root, slot and tier of a declaration, or null. */
|
|
66
|
+
function ownerOfDeclaration(env, declaration) {
|
|
67
|
+
const rel = graphPath(env, declaration);
|
|
68
|
+
const file = rel ? graphFile(env, rel) : null;
|
|
69
|
+
return file?.owner ? { rel, root: file.owner.root, slot: file.owner.slot, tier: file.tier, name: path.posix.basename(file.owner.root) } : null;
|
|
70
|
+
}
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
72
|
+
/** The string a node evaluates to: a literal, or a const whose type is a string literal. */
|
|
73
|
+
function stringValue(env, checker, node) {
|
|
74
|
+
const { ts } = env;
|
|
75
|
+
if (!node) return null;
|
|
76
|
+
if (ts.isStringLiteralLike(node)) return node.text;
|
|
77
|
+
let type;
|
|
78
|
+
try { type = checker.getTypeAtLocation(node); } catch { return null; }
|
|
79
|
+
if (type?.isStringLiteral?.()) return type.value;
|
|
80
|
+
const declaration = declarationsOf(env, checker, ts.isPropertyAccessExpression(node) ? node.name : node)[0];
|
|
81
|
+
if (declaration && ts.isVariableDeclaration(declaration) && declaration.initializer) return stringValue(env, checker, declaration.initializer);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
86
84
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
};
|
|
92
|
-
step(node);
|
|
85
|
+
function walk(env, node, visit) {
|
|
86
|
+
const step = child => {
|
|
87
|
+
if (visit(child) === false) return;
|
|
88
|
+
env.ts.forEachChild(child, step);
|
|
93
89
|
};
|
|
90
|
+
step(node);
|
|
91
|
+
}
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
const decorators = (env, node) => (env.ts.canHaveDecorators?.(node) ? env.ts.getDecorators(node) ?? [] : []);
|
|
94
|
+
const isExported = (env, node) => hasAnyFlag(env.ts.getCombinedModifierFlags?.(node), env.ts.ModifierFlags.Export);
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
function propertyNameText(env, name) {
|
|
97
|
+
if (!name) return null;
|
|
98
|
+
if (env.ts.isIdentifier(name) || env.ts.isStringLiteralLike(name)) return name.text;
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
/** The object literal properties of `literal` by static name. */
|
|
103
|
+
const propertyOf = (env, literal, key) => literal.properties
|
|
104
|
+
.find(property => (env.ts.isPropertyAssignment(property) || env.ts.isShorthandPropertyAssignment(property)) && propertyNameText(env, property.name) === key);
|
|
106
105
|
|
|
107
|
-
|
|
106
|
+
const valueOfProperty = (env, property) => (env.ts.isPropertyAssignment(property) ? property.initializer : property.name);
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
const at = (env, rel, sourceFile, node, extra = {}) => ({ path: rel, ...sourceLocation(sourceFile, node), ...extra });
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
110
|
+
/** The app root file of an app (apps/<name>/src/app.module.ts), or null when the program does not hold it. */
|
|
111
|
+
const appRoot = (env, name) => graphFile(env, `apps/${name}/src/app.module.ts`);
|
|
112
|
+
|
|
113
|
+
/** The body a call or a spread identifier resolves to when it is a function or a const declared in a file of the program (not a package), else null. */
|
|
114
|
+
function helperBodyOf(env, checker, node) {
|
|
115
|
+
const { ts } = env;
|
|
116
|
+
const target = ts.isCallExpression(node) ? node.expression : node;
|
|
117
|
+
for (const declaration of declarationsOf(env, checker, ts.isPropertyAccessExpression(target) ? target.name : target)) {
|
|
118
|
+
if (!graphPath(env, declaration)) continue;
|
|
119
|
+
if (ts.isFunctionDeclaration(declaration) && declaration.body) return { declaration, body: declaration.body };
|
|
120
|
+
if (ts.isVariableDeclaration(declaration) && declaration.initializer) return { declaration, body: declaration.initializer };
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
|
|
125
|
+
/** The provider entry of an object literal that provides `name` imported from `moduleName`, or null. */
|
|
126
|
+
function providerEntry(env, search, checker, literal, anchor) {
|
|
127
|
+
const provide = propertyOf(env, literal, 'provide');
|
|
128
|
+
if (!provide || !isImportOf(env, checker, valueOfProperty(env, provide), search.name, search.moduleName)) return null;
|
|
129
|
+
const use = propertyOf(env, literal, 'useClass');
|
|
130
|
+
return { node: anchor ?? literal, useClass: use ? valueOfProperty(env, use) : null, checker };
|
|
131
|
+
}
|
|
119
132
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
/** The expression that may reference a helper: the argument of a spread, or the call itself. */
|
|
134
|
+
function helperReferenceOf(ts, node) {
|
|
135
|
+
if (ts.isSpreadElement(node)) return node.expression;
|
|
136
|
+
return ts.isCallExpression(node) ? node : null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function followHelper(env, search, checker, node, anchor, depth) {
|
|
140
|
+
const reference = helperReferenceOf(env.ts, node);
|
|
141
|
+
if (!reference || depth >= HELPER_DEPTH) return;
|
|
142
|
+
const helper = helperBodyOf(env, checker, reference);
|
|
143
|
+
if (!helper || search.seen.has(helper.declaration)) return;
|
|
144
|
+
search.seen.add(helper.declaration);
|
|
145
|
+
scanProviders(env, search, helper.body, anchor ?? node, depth + 1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function scanProviders(env, search, root, anchor, depth) {
|
|
149
|
+
const checker = checkerOf(env, root.getSourceFile());
|
|
150
|
+
walk(env, root, node => {
|
|
151
|
+
if (!env.ts.isObjectLiteralExpression(node)) {
|
|
152
|
+
followHelper(env, search, checker, node, anchor, depth);
|
|
153
|
+
return;
|
|
127
154
|
}
|
|
128
|
-
|
|
129
|
-
|
|
155
|
+
const entry = providerEntry(env, search, checker, node, anchor);
|
|
156
|
+
if (entry) search.found.push(entry);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
130
159
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
walk(root, node => {
|
|
143
|
-
if (ts.isObjectLiteralExpression(node)) {
|
|
144
|
-
const provide = propertyOf(node, 'provide');
|
|
145
|
-
if (provide && isImportOf(checker, valueOfProperty(provide), name, moduleName)) {
|
|
146
|
-
const use = propertyOf(node, 'useClass');
|
|
147
|
-
found.push({ node: anchor ?? node, useClass: use ? valueOfProperty(use) : null, checker });
|
|
148
|
-
}
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
const reference = ts.isSpreadElement(node) ? node.expression : (ts.isCallExpression(node) ? node : null);
|
|
152
|
-
if (reference && depth < HELPER_DEPTH) {
|
|
153
|
-
const helper = helperBodyOf(checker, reference);
|
|
154
|
-
if (helper && !seen.has(helper.declaration)) {
|
|
155
|
-
seen.add(helper.declaration);
|
|
156
|
-
scan(helper.body, anchor ?? node, depth + 1);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return true;
|
|
160
|
-
});
|
|
161
|
-
};
|
|
162
|
-
scan(file.sourceFile, null, 0);
|
|
163
|
-
return found.sort((a, b) => a.node.getStart() - b.node.getStart());
|
|
164
|
-
};
|
|
160
|
+
/**
|
|
161
|
+
* The `{ provide: <token>, ... }` provider literals of `file` whose token is `name` imported from `moduleName`, in source order.
|
|
162
|
+
* A call or a spread of a function or a const declared in another file of the program is followed (to a depth of four), so a
|
|
163
|
+
* helper that builds the `APP_GUARD` or `APP_FILTER` entries outside the app root file is read too: the entry's `node` is then the
|
|
164
|
+
* call or spread inside the app root (where the entry is provided), its `useClass` and `checker` those of the helper's file.
|
|
165
|
+
*/
|
|
166
|
+
function providersOf(env, file, name, moduleName) {
|
|
167
|
+
const search = { name, moduleName, found: [], seen: new Set() };
|
|
168
|
+
scanProviders(env, search, file.sourceFile, null, 0);
|
|
169
|
+
return search.found.sort((a, b) => a.node.getStart() - b.node.getStart());
|
|
170
|
+
}
|
|
165
171
|
|
|
166
|
-
|
|
167
|
-
|
|
172
|
+
/**
|
|
173
|
+
* The small TypeScript reading kit the R33/R38/R39/R41/R45/R84/R86 machine checks share (connection-map, sql-owner,
|
|
174
|
+
* register-once, error-masked, default-deny-app-guard, entrypoint-only-in-apps, error-home). Everything is decided by
|
|
175
|
+
* the checker and by where a declaration lives (the HFS graph), never by a variable name: a framework symbol is
|
|
176
|
+
* recognised by the package it is imported from, a capability class by the file that declares it.
|
|
177
|
+
*/
|
|
178
|
+
export function machineKit({ context, graph }) {
|
|
179
|
+
const env = { ts: context.ts, context, graph };
|
|
180
|
+
const bound = operation => (...args) => operation(env, ...args);
|
|
181
|
+
return {
|
|
182
|
+
ts: env.ts,
|
|
183
|
+
resolver: graph.resolver,
|
|
184
|
+
providersOf: bound(providersOf),
|
|
185
|
+
checkerOf: bound(checkerOf),
|
|
186
|
+
aliased: bound(aliased),
|
|
187
|
+
symbolAt: bound(symbolAt),
|
|
188
|
+
importBinding: bound(importBinding),
|
|
189
|
+
isImportOf: bound(isImportOf),
|
|
190
|
+
declarationsOf: bound(declarationsOf),
|
|
191
|
+
graphPath: bound(graphPath),
|
|
192
|
+
graphFile: bound(graphFile),
|
|
193
|
+
ownerOfDeclaration: bound(ownerOfDeclaration),
|
|
194
|
+
stringValue: bound(stringValue),
|
|
195
|
+
walk: bound(walk),
|
|
196
|
+
decorators: bound(decorators),
|
|
197
|
+
isExported: bound(isExported),
|
|
198
|
+
propertyNameText: bound(propertyNameText),
|
|
199
|
+
propertyOf: bound(propertyOf),
|
|
200
|
+
valueOfProperty: bound(valueOfProperty),
|
|
201
|
+
at: bound(at),
|
|
202
|
+
appRoot: bound(appRoot),
|
|
203
|
+
};
|
|
168
204
|
}
|
|
169
205
|
|
|
170
|
-
export const upperSnake = name => name.
|
|
206
|
+
export const upperSnake = name => name.replaceAll('-', '_').toUpperCase();
|
|
171
207
|
export const pascal = name => name.split('-').filter(Boolean).map(part => part[0].toUpperCase() + part.slice(1)).join('');
|
|
@@ -10,6 +10,10 @@ const TEMPLATE_ROOTS = [
|
|
|
10
10
|
path.resolve(import.meta.dirname, '..', '..', '..', '..', 'templates'),
|
|
11
11
|
];
|
|
12
12
|
const managedScriptCache = new Map();
|
|
13
|
+
const SCRIPT_ENTRY_START = String.raw`^\s*"`;
|
|
14
|
+
const SCRIPT_ENTRY_NAME = String.raw`([^"\n]+)`;
|
|
15
|
+
const SCRIPT_ENTRY_END = String.raw`":\s*"`;
|
|
16
|
+
const SCRIPT_ENTRY = new RegExp([SCRIPT_ENTRY_START, SCRIPT_ENTRY_NAME, SCRIPT_ENTRY_END].join(''), 'gmu');
|
|
13
17
|
|
|
14
18
|
/** The script names of a profile/edition template after its partials are expanded. */
|
|
15
19
|
export function managedScriptNames(profile, edition = 'full') {
|
|
@@ -18,10 +22,12 @@ export function managedScriptNames(profile, edition = 'full') {
|
|
|
18
22
|
const slot = loadSlotManifest().slots.find((entry) => entry.id === `${profile}.package-manifest`);
|
|
19
23
|
const group = slot && managedGroupOf(slot, edition);
|
|
20
24
|
const templates = group && TEMPLATE_ROOTS.find((dir) => fs.existsSync(path.join(dir, profile, group, 'package.json')));
|
|
21
|
-
if (!templates) throw Error(`The managed package-scripts template of profile ${profile} cannot be found next to the runtime.`);
|
|
25
|
+
if (!templates) throw new Error(`The managed package-scripts template of profile ${profile} cannot be found next to the runtime.`);
|
|
22
26
|
const text = fs.readFileSync(path.join(templates, profile, group, 'package.json'), 'utf8')
|
|
23
27
|
.replace(/^\{\{> ([\w./-]+)\}\}\r?\n/gmu, (_, partial) => fs.readFileSync(path.join(templates, partial), 'utf8'));
|
|
24
|
-
|
|
28
|
+
// The key is bounded by quotes, never the colon, so `[^"]` cannot backtrack; the strict script-name class filters after.
|
|
29
|
+
const names = [...text.matchAll(SCRIPT_ENTRY)].map((match) => match[1]);
|
|
30
|
+
managedScriptCache.set(key, new Set(names.filter((name) => /^[A-Za-z0-9:_.-]+$/.test(name))));
|
|
25
31
|
}
|
|
26
32
|
return managedScriptCache.get(key);
|
|
27
33
|
}
|