@haneinfo/app-tooling 0.1.3 → 0.3.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/README.md +58 -1
- package/dist/checks.d.ts +1 -1
- package/dist/checks.d.ts.map +1 -1
- package/dist/checks.js +6 -0
- package/dist/checks.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/dictionary-schema.d.ts +5 -0
- package/dist/dictionary-schema.d.ts.map +1 -0
- package/dist/dictionary-schema.js +143 -0
- package/dist/dictionary-schema.js.map +1 -0
- package/dist/dictionary-worker.d.ts +2 -0
- package/dist/dictionary-worker.d.ts.map +1 -0
- package/dist/dictionary-worker.js +17 -0
- package/dist/dictionary-worker.js.map +1 -0
- package/dist/dictionary.d.ts +8 -0
- package/dist/dictionary.d.ts.map +1 -0
- package/dist/dictionary.js +87 -0
- package/dist/dictionary.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/scopes.d.ts +4 -0
- package/dist/scopes.d.ts.map +1 -0
- package/dist/scopes.js +352 -0
- package/dist/scopes.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,9 +1,66 @@
|
|
|
1
1
|
# @haneinfo/app-tooling
|
|
2
2
|
|
|
3
|
-
Run `haneinfo-app check` from an App repository to verify generated plugin artifacts, integration contract runtime files, enum documentation and translations,
|
|
3
|
+
Run `haneinfo-app check` from an App repository to verify generated plugin artifacts, integration contract runtime files, enum documentation and translations, domain event subscriber wiring, ScopeGuard scope coverage, and data dictionary drift. `haneinfo-app check plugins`, `integrations`, `enums`, `subscribers`, `scopes`, or `dictionary` runs one gate. Use `--root <path>` to check another App and `--json` for machine-readable results. Missing enum translations and documentation fail; orphaned translation keys are warnings.
|
|
4
4
|
|
|
5
5
|
This package owns App-level checks. The `scripts/lint-specs.mjs` file remains in each repository under the shared specs governance rule.
|
|
6
6
|
|
|
7
|
+
## Data dictionary drift
|
|
8
|
+
|
|
9
|
+
`haneinfo-app check dictionary` compares `docs/data-dictionary.md` with the consuming App's
|
|
10
|
+
`@haneinfo/metadata-schema` renderer in memory. It ignores only the generated header date,
|
|
11
|
+
UTF-8 BOM and line endings. Models, enum values, fields, descriptions, relationships and dates
|
|
12
|
+
inside the document still participate in comparison. Missing documentation and renderer failures
|
|
13
|
+
are failing diagnostics, not a successful skipped check. Drift diagnostics identify the file and
|
|
14
|
+
first differing line. `check all` includes this gate; `check enums` remains a separate contract.
|
|
15
|
+
|
|
16
|
+
The App must already have a fresh generated Prisma client. The gate compares its embedded
|
|
17
|
+
`schema.prisma` with the App source before rendering, detecting stale clients when fields,
|
|
18
|
+
attributes, enum values or `///` documentation differ. The schema fingerprint ignores formatting whitespace,
|
|
19
|
+
ordinary comments and top-level block order; it retains schema tokens, field order and `///`
|
|
20
|
+
documentation. It is a text-consistency check, not a replacement for Prisma schema validation.
|
|
21
|
+
Unknown or malformed declarations fail explicitly.
|
|
22
|
+
|
|
23
|
+
Supported schema locations are `backend/prisma/schema` (including nested `.prisma` files),
|
|
24
|
+
`backend/prisma/schema.prisma`, or the path in `backend/package.json`'s `prisma.schema`. Multiple
|
|
25
|
+
default locations need an explicit path. Executable `prisma.config.*` and non-default client
|
|
26
|
+
outputs are not evaluated or guessed; unsupported configuration/client layout fails with a
|
|
27
|
+
diagnostic. This is the Prisma 6 / default `@prisma/client` layout used by current Haneinfo Apps.
|
|
28
|
+
|
|
29
|
+
Rendering runs in an isolated Node process with the App backend as cwd, using that App's installed
|
|
30
|
+
metadata package and client. Checking several Apps in one process does not share their DMMF cache.
|
|
31
|
+
The checker requires no database connection, does not execute App bootstrap/generator scripts,
|
|
32
|
+
and never writes source, clients or documentation. After reviewing changes, run the App's
|
|
33
|
+
`prisma:generate` and `schema:docs` commands explicitly, then repeat the check.
|
|
34
|
+
|
|
35
|
+
## Scope coverage
|
|
36
|
+
|
|
37
|
+
`haneinfo-app check scopes` parses App-owned `backend/src/**/*.ts` / `*.tsx` (excluding
|
|
38
|
+
declaration, spec, and test files) with TypeScript. It reads `backend/tsconfig.json` when present
|
|
39
|
+
for local import/alias resolution. It checks each controller and HTTP method independently:
|
|
40
|
+
class and method guards combine, while required scopes follow `methodScopes ?? classScopes`.
|
|
41
|
+
An explicit empty `@Scopes()` overrides the class and fails on a ScopeGuard-protected route.
|
|
42
|
+
All Nest HTTP decorators, including Head, Options, All, Search, QueryMethod, WebDAV methods,
|
|
43
|
+
and RequestMapping, are recognized independently of decorator order and line breaks.
|
|
44
|
+
|
|
45
|
+
Named/namespace imports, import renaming, const aliases, string concatenation, imported const
|
|
46
|
+
arrays/objects, enum strings, and array spreads are supported. Constants must be treated as
|
|
47
|
+
immutable; this check does not perform whole-program mutation analysis. It never evaluates
|
|
48
|
+
App code. Dynamic scopes/guards, multiple Scopes decorators on one declaration, unknown custom
|
|
49
|
+
decorators, controller inheritance/mixins, syntax errors, and invalid tsconfig produce failing
|
|
50
|
+
diagnostics. Simple custom factories returning only unrelated `SetMetadata` are supported;
|
|
51
|
+
`RequirePermissions` from `@haneinfo/rbac` is known unrelated metadata. Use direct decorators
|
|
52
|
+
instead of opaque composed decorators. Diagnostics include file, line, column and owner name.
|
|
53
|
+
Exit codes follow the existing CLI contract: 0 passed, 1 check failed, 2 bad invocation, 3
|
|
54
|
+
unexpected error. Missing `backend/src` fails instead of returning a vacuous success.
|
|
55
|
+
|
|
56
|
+
This gate checks direct App controller/method declarations. Global guard registration,
|
|
57
|
+
programmatic metadata changes and dynamically created controllers require separate review;
|
|
58
|
+
plugin/package controllers belong to their package tests. A template with no App-owned
|
|
59
|
+
controller can pass without asserting coverage of its installed plugins. The gate checks scope
|
|
60
|
+
presence, not business permission correctness or whether a scope is grantable in the catalog.
|
|
61
|
+
`m2m-api-key@8.1.2` already denies API-key requests with missing/empty scopes (403); this check
|
|
62
|
+
does not alter runtime authorization. TypeScript ships as a production dependency for the CLI.
|
|
63
|
+
|
|
7
64
|
`haneinfo-app scaffold` initializes an unmodified template clone. It requires `--name`,
|
|
8
65
|
`--display-name`, `--db-port`, `--backend-port`, and `--frontend-port`; `--description`,
|
|
9
66
|
`--ports-registry <dev-infra/app-ports.json>`, `--root`, and `--dry-run` are optional. The dry run
|
package/dist/checks.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CheckIssue } from './integration-contracts';
|
|
2
|
-
export type CheckTarget = 'all' | 'plugins' | 'integrations' | 'enums' | 'subscribers';
|
|
2
|
+
export type CheckTarget = 'all' | 'plugins' | 'integrations' | 'enums' | 'subscribers' | 'scopes' | 'dictionary';
|
|
3
3
|
export interface CheckReport {
|
|
4
4
|
target: CheckTarget;
|
|
5
5
|
issues: CheckIssue[];
|
package/dist/checks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,UAAU,EAAsC,MAAM,yBAAyB,CAAC;AAI9F,MAAM,MAAM,WAAW,GACnB,KAAK,GACL,SAAS,GACT,cAAc,GACd,OAAO,GACP,aAAa,GACb,QAAQ,GACR,YAAY,CAAC;AAEjB,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;CACjB;AA4BD,uFAAuF;AACvF,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,WAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuBjG"}
|
package/dist/checks.js
CHANGED
|
@@ -7,8 +7,10 @@ exports.checkApp = checkApp;
|
|
|
7
7
|
const node_fs_1 = require("node:fs");
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
9
|
const plugin_cli_1 = require("@haneinfo/plugin-cli");
|
|
10
|
+
const dictionary_1 = require("./dictionary");
|
|
10
11
|
const enums_1 = require("./enums");
|
|
11
12
|
const integration_contracts_1 = require("./integration-contracts");
|
|
13
|
+
const scopes_1 = require("./scopes");
|
|
12
14
|
const subscriber_wiring_1 = require("./subscriber-wiring");
|
|
13
15
|
function pluginCliVersion() {
|
|
14
16
|
try {
|
|
@@ -56,6 +58,10 @@ async function checkApp(appRoot, target = 'all') {
|
|
|
56
58
|
}
|
|
57
59
|
if (target === 'all' || target === 'subscribers')
|
|
58
60
|
issues.push(...(0, subscriber_wiring_1.checkDomainEventSubscribers)(repositoryRoot));
|
|
61
|
+
if (target === 'all' || target === 'scopes')
|
|
62
|
+
issues.push(...(0, scopes_1.checkScopeCoverage)(repositoryRoot));
|
|
63
|
+
if (target === 'all' || target === 'dictionary')
|
|
64
|
+
issues.push(...(0, dictionary_1.checkDataDictionary)(repositoryRoot));
|
|
59
65
|
return { target, issues, warnings, passed: issues.length === 0 };
|
|
60
66
|
}
|
|
61
67
|
//# sourceMappingURL=checks.js.map
|
package/dist/checks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAAC;AAKlG,6FAA6F;AAC7F,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAAC;AAKlG,6FAA6F;AAC7F,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,CAAC,CAkDjB"}
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.runAppToolingCli = runAppToolingCli;
|
|
|
4
4
|
const node_util_1 = require("node:util");
|
|
5
5
|
const checks_1 = require("./checks");
|
|
6
6
|
const scaffold_1 = require("./scaffold");
|
|
7
|
-
const USAGE = 'Usage: haneinfo-app check [all|plugins|integrations|enums|subscribers] [--root <app-root>] [--json]\n haneinfo-app scaffold --name <kebab-case> --display-name <text> --db-port <port> --backend-port <port> --frontend-port <port> [--description <text>] [--ports-registry <file>] [--root <template-root>] [--dry-run]';
|
|
7
|
+
const USAGE = 'Usage: haneinfo-app check [all|plugins|integrations|enums|subscribers|scopes|dictionary] [--root <app-root>] [--json]\n haneinfo-app scaffold --name <kebab-case> --display-name <text> --db-port <port> --backend-port <port> --frontend-port <port> [--description <text>] [--ports-registry <file>] [--root <template-root>] [--dry-run]';
|
|
8
8
|
/** Exit codes: 0 passed, 1 verification failed, 2 invalid invocation, 3 unexpected error. */
|
|
9
9
|
async function runAppToolingCli(argv, cwd, output) {
|
|
10
10
|
if (argv[0] === 'scaffold')
|
|
@@ -29,7 +29,7 @@ async function runAppToolingCli(argv, cwd, output) {
|
|
|
29
29
|
const [command, requested = 'all', ...extra] = parsed.positionals;
|
|
30
30
|
if (command !== 'check' ||
|
|
31
31
|
extra.length > 0 ||
|
|
32
|
-
!['all', 'plugins', 'integrations', 'enums', 'subscribers'].includes(requested)) {
|
|
32
|
+
!['all', 'plugins', 'integrations', 'enums', 'subscribers', 'scopes', 'dictionary'].includes(requested)) {
|
|
33
33
|
output.stderr(USAGE);
|
|
34
34
|
return 2;
|
|
35
35
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AAUA,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Block order can change when Prisma flattens a schema folder; field/doc order cannot. */
|
|
2
|
+
export declare function schemaFingerprint(sources: string[]): string;
|
|
3
|
+
/** Verify the same default Prisma client that @haneinfo/common selects from the App cwd. */
|
|
4
|
+
export declare function verifyDictionarySchema(backendRoot: string): void;
|
|
5
|
+
//# sourceMappingURL=dictionary-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary-schema.d.ts","sourceRoot":"","sources":["../src/dictionary-schema.ts"],"names":[],"mappings":"AAmDA,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CA6B3D;AAcD,4FAA4F;AAC5F,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CA+ChE"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.schemaFingerprint = schemaFingerprint;
|
|
7
|
+
exports.verifyDictionarySchema = verifyDictionarySchema;
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_module_1 = require("node:module");
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
/** Compare schema text without depending on Prisma's formatter or losing /// metadata. */
|
|
12
|
+
function tokens(source) {
|
|
13
|
+
const result = [];
|
|
14
|
+
let offset = 0;
|
|
15
|
+
while (offset < source.length) {
|
|
16
|
+
const remaining = source.slice(offset);
|
|
17
|
+
const whitespace = /^\s+/u.exec(remaining);
|
|
18
|
+
if (whitespace) {
|
|
19
|
+
offset += whitespace[0].length;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (remaining.startsWith('//')) {
|
|
23
|
+
const end = remaining.indexOf('\n');
|
|
24
|
+
const line = end < 0 ? remaining : remaining.slice(0, end);
|
|
25
|
+
if (line.startsWith('///'))
|
|
26
|
+
result.push({ kind: 'doc', text: line.slice(3).replace(/\r$/u, '').replace(/^ ?/u, '') });
|
|
27
|
+
offset += line.length;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (remaining.startsWith('/*')) {
|
|
31
|
+
const end = remaining.indexOf('*/', 2);
|
|
32
|
+
if (end < 0 || remaining.slice(2, end).includes('/*'))
|
|
33
|
+
throw new Error('unsupported unterminated/nested schema comment');
|
|
34
|
+
offset += end + 2;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (remaining.startsWith('"')) {
|
|
38
|
+
const value = /^"(?:\\.|[^"\\])*"/u.exec(remaining);
|
|
39
|
+
if (!value)
|
|
40
|
+
throw new Error('unterminated schema string');
|
|
41
|
+
result.push({ kind: 'string', text: value[0] });
|
|
42
|
+
offset += value[0].length;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const word = /^[A-Za-z_][A-Za-z0-9_]*/u.exec(remaining);
|
|
46
|
+
if (word) {
|
|
47
|
+
result.push({ kind: 'word', text: word[0] });
|
|
48
|
+
offset += word[0].length;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
result.push({ kind: 'symbol', text: remaining[0] });
|
|
52
|
+
offset++;
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
/** Block order can change when Prisma flattens a schema folder; field/doc order cannot. */
|
|
57
|
+
function schemaFingerprint(sources) {
|
|
58
|
+
const blocks = new Map();
|
|
59
|
+
for (const source of sources) {
|
|
60
|
+
const input = tokens(source);
|
|
61
|
+
let offset = 0;
|
|
62
|
+
while (offset < input.length) {
|
|
63
|
+
const block = [];
|
|
64
|
+
while (input[offset]?.kind === 'doc')
|
|
65
|
+
block.push(input[offset++]);
|
|
66
|
+
const kind = input[offset++];
|
|
67
|
+
const name = input[offset++];
|
|
68
|
+
const open = input[offset++];
|
|
69
|
+
if (kind?.kind !== 'word' || name?.kind !== 'word' || open?.text !== '{')
|
|
70
|
+
throw new Error('unsupported schema declaration; expected a named block');
|
|
71
|
+
block.push(kind, name, open);
|
|
72
|
+
let depth = 1;
|
|
73
|
+
while (depth > 0 && offset < input.length) {
|
|
74
|
+
const token = input[offset++];
|
|
75
|
+
block.push(token);
|
|
76
|
+
if (token.kind === 'symbol' && token.text === '{')
|
|
77
|
+
depth++;
|
|
78
|
+
if (token.kind === 'symbol' && token.text === '}')
|
|
79
|
+
depth--;
|
|
80
|
+
}
|
|
81
|
+
if (depth !== 0)
|
|
82
|
+
throw new Error(`unterminated ${kind.text} ${name.text} schema block`);
|
|
83
|
+
const key = `${kind.text}:${name.text}`;
|
|
84
|
+
if (blocks.has(key))
|
|
85
|
+
throw new Error(`duplicate ${kind.text} ${name.text} schema block`);
|
|
86
|
+
blocks.set(key, block);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (blocks.size === 0)
|
|
90
|
+
throw new Error('schema contains no named blocks');
|
|
91
|
+
return JSON.stringify([...blocks.entries()].sort(([a], [b]) => a.localeCompare(b)));
|
|
92
|
+
}
|
|
93
|
+
function schemaFiles(file) {
|
|
94
|
+
if (!(0, node_fs_1.statSync)(file).isDirectory())
|
|
95
|
+
return [file];
|
|
96
|
+
return (0, node_fs_1.readdirSync)(file, { withFileTypes: true })
|
|
97
|
+
.flatMap((entry) => {
|
|
98
|
+
const child = node_path_1.default.join(file, entry.name);
|
|
99
|
+
if (entry.isDirectory())
|
|
100
|
+
return ['migrations', 'node_modules'].includes(entry.name) ? [] : schemaFiles(child);
|
|
101
|
+
return entry.name.endsWith('.prisma') ? [child] : [];
|
|
102
|
+
})
|
|
103
|
+
.sort();
|
|
104
|
+
}
|
|
105
|
+
/** Verify the same default Prisma client that @haneinfo/common selects from the App cwd. */
|
|
106
|
+
function verifyDictionarySchema(backendRoot) {
|
|
107
|
+
const manifest = node_path_1.default.join(backendRoot, 'package.json');
|
|
108
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)(manifest, 'utf8'));
|
|
109
|
+
const configured = pkg.prisma?.schema;
|
|
110
|
+
if (configured !== undefined && (typeof configured !== 'string' || !configured.trim()))
|
|
111
|
+
throw new Error('package.json prisma.schema must be a non-empty path');
|
|
112
|
+
const configs = [
|
|
113
|
+
'prisma.config.ts',
|
|
114
|
+
'prisma.config.js',
|
|
115
|
+
'prisma.config.mjs',
|
|
116
|
+
'prisma.config.cjs',
|
|
117
|
+
'prisma.config.mts',
|
|
118
|
+
'prisma.config.cts',
|
|
119
|
+
];
|
|
120
|
+
if (configs.some((name) => (0, node_fs_1.existsSync)(node_path_1.default.join(backendRoot, name))))
|
|
121
|
+
throw new Error('prisma.config.* cannot be evaluated safely by this checker; this schema configuration is unsupported');
|
|
122
|
+
const defaults = [
|
|
123
|
+
node_path_1.default.join(backendRoot, 'prisma', 'schema'),
|
|
124
|
+
node_path_1.default.join(backendRoot, 'prisma', 'schema.prisma'),
|
|
125
|
+
].filter(node_fs_1.existsSync);
|
|
126
|
+
if (!configured && defaults.length > 1)
|
|
127
|
+
throw new Error('multiple schema locations exist; declare the schema used by prisma:generate in package.json prisma.schema');
|
|
128
|
+
const schema = typeof configured === 'string' ? node_path_1.default.resolve(backendRoot, configured) : defaults[0];
|
|
129
|
+
if (!schema || !(0, node_fs_1.existsSync)(schema))
|
|
130
|
+
throw new Error('active Prisma schema is missing; expected prisma/schema or prisma/schema.prisma');
|
|
131
|
+
const source = schemaFingerprint(schemaFiles(schema).map((file) => (0, node_fs_1.readFileSync)(file, 'utf8')));
|
|
132
|
+
const appRequire = (0, node_module_1.createRequire)(manifest);
|
|
133
|
+
const clientRequire = (0, node_module_1.createRequire)(appRequire.resolve('@prisma/client/package.json'));
|
|
134
|
+
const generated = clientRequire.resolve('.prisma/client/schema.prisma');
|
|
135
|
+
const embedded = schemaFingerprint([(0, node_fs_1.readFileSync)(generated, 'utf8')]);
|
|
136
|
+
if (source !== embedded) {
|
|
137
|
+
const active = new Map(JSON.parse(source));
|
|
138
|
+
const client = new Map(JSON.parse(embedded));
|
|
139
|
+
const changed = [...new Set([...active.keys(), ...client.keys()])].filter((key) => JSON.stringify(active.get(key)) !== JSON.stringify(client.get(key)));
|
|
140
|
+
throw new Error(`generated Prisma client differs from the active schema in ${changed.join(', ')} (including /// documentation); run the App prisma:generate command before checking or generating docs`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=dictionary-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary-schema.js","sourceRoot":"","sources":["../src/dictionary-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary-worker.d.ts","sourceRoot":"","sources":["../src/dictionary-worker.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_module_1 = require("node:module");
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
// Import in the consuming App's cwd so @haneinfo/common selects that App's Prisma DMMF.
|
|
9
|
+
const appRequire = (0, node_module_1.createRequire)(node_path_1.default.join(process.cwd(), 'package.json'));
|
|
10
|
+
const api = appRequire('@haneinfo/metadata-schema');
|
|
11
|
+
if (typeof api.renderDataDictionary !== 'function')
|
|
12
|
+
throw new Error('App metadata-schema package does not export renderDataDictionary');
|
|
13
|
+
const markdown = api.renderDataDictionary(new api.MetaService().buildMeta());
|
|
14
|
+
if (typeof markdown !== 'string')
|
|
15
|
+
throw new Error('renderDataDictionary must return Markdown text');
|
|
16
|
+
process.stdout.write(JSON.stringify({ markdown }));
|
|
17
|
+
//# sourceMappingURL=dictionary-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary-worker.js","sourceRoot":"","sources":["../src/dictionary-worker.ts"],"names":[],"mappings":";;;;;AAAA,6CAA4C;AAC5C,0DAA6B;AAE7B,wFAAwF;AACxF,MAAM,UAAU,GAAG,IAAA,2BAAa,EAAC,mBAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;AAC3E,MAAM,GAAG,GAAG,UAAU,CAAC,2BAA2B,CAGjD,CAAC;AACF,IAAI,OAAO,GAAG,CAAC,oBAAoB,KAAK,UAAU;IAChD,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;AACtF,MAAM,QAAQ,GAAG,GAAG,CAAC,oBAAoB,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;AAC7E,IAAI,OAAO,QAAQ,KAAK,QAAQ;IAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;AACpG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CheckIssue } from './integration-contracts';
|
|
2
|
+
declare function renderFromApp(backendRoot: string): string;
|
|
3
|
+
/** Ignore the renderer's volatile header date, BOM and platform line endings only. */
|
|
4
|
+
export declare function normalizeDataDictionary(markdown: string): string;
|
|
5
|
+
/** Compare in memory. This gate never generates a client or writes the dictionary. */
|
|
6
|
+
export declare function checkDataDictionary(appRoot: string, renderer?: typeof renderFromApp): CheckIssue[];
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=dictionary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary.d.ts","sourceRoot":"","sources":["../src/dictionary.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,iBAAS,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAalD;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQhE;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,uBAAgB,GAAG,UAAU,EAAE,CAoD3F"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.normalizeDataDictionary = normalizeDataDictionary;
|
|
7
|
+
exports.checkDataDictionary = checkDataDictionary;
|
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const dictionary_schema_1 = require("./dictionary-schema");
|
|
12
|
+
function renderFromApp(backendRoot) {
|
|
13
|
+
const result = (0, node_child_process_1.spawnSync)(process.execPath, [node_path_1.default.join(__dirname, 'dictionary-worker.js')], {
|
|
14
|
+
cwd: backendRoot,
|
|
15
|
+
encoding: 'utf8',
|
|
16
|
+
timeout: 30_000,
|
|
17
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
18
|
+
});
|
|
19
|
+
if (result.error || result.status !== 0)
|
|
20
|
+
throw new Error(result.error?.message ?? (result.stderr.trim() || 'dictionary worker failed'));
|
|
21
|
+
const rendered = JSON.parse(result.stdout);
|
|
22
|
+
if (typeof rendered.markdown !== 'string')
|
|
23
|
+
throw new Error('dictionary worker returned invalid Markdown');
|
|
24
|
+
return rendered.markdown;
|
|
25
|
+
}
|
|
26
|
+
/** Ignore the renderer's volatile header date, BOM and platform line endings only. */
|
|
27
|
+
function normalizeDataDictionary(markdown) {
|
|
28
|
+
return markdown
|
|
29
|
+
.replace(/^\uFEFF/u, '')
|
|
30
|
+
.replace(/\r\n?/gu, '\n')
|
|
31
|
+
.replace(/^(# Data Dictionary\n\n)> Auto-generated from Prisma schema on \d{4}-\d{2}-\d{2}\.\n/u, '$1> Auto-generated from Prisma schema on <date>.\n');
|
|
32
|
+
}
|
|
33
|
+
/** Compare in memory. This gate never generates a client or writes the dictionary. */
|
|
34
|
+
function checkDataDictionary(appRoot, renderer = renderFromApp) {
|
|
35
|
+
const file = node_path_1.default.join(appRoot, 'docs', 'data-dictionary.md');
|
|
36
|
+
if (!(0, node_fs_1.existsSync)(file))
|
|
37
|
+
return [
|
|
38
|
+
{
|
|
39
|
+
code: 'dictionary-missing',
|
|
40
|
+
path: file,
|
|
41
|
+
message: 'data dictionary is missing; run the App prisma:generate and schema:docs commands',
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
const backendRoot = node_path_1.default.join(appRoot, 'backend');
|
|
45
|
+
try {
|
|
46
|
+
(0, dictionary_schema_1.verifyDictionarySchema)(backendRoot);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return [
|
|
50
|
+
{
|
|
51
|
+
code: 'dictionary-schema-unverified',
|
|
52
|
+
path: node_path_1.default.join(backendRoot, 'prisma'),
|
|
53
|
+
message: error instanceof Error ? error.message : String(error),
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
let expected;
|
|
58
|
+
try {
|
|
59
|
+
const rendered = normalizeDataDictionary(renderer(backendRoot));
|
|
60
|
+
if (!rendered.startsWith('# Data Dictionary\n\n'))
|
|
61
|
+
throw new Error('metadata renderer returned an unrecognized data dictionary header');
|
|
62
|
+
expected = rendered;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
code: 'dictionary-render-failed',
|
|
68
|
+
path: file,
|
|
69
|
+
message: error instanceof Error ? error.message : String(error),
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
const actual = normalizeDataDictionary((0, node_fs_1.readFileSync)(file, 'utf8'));
|
|
74
|
+
if (expected === actual)
|
|
75
|
+
return [];
|
|
76
|
+
const expectedLines = expected.split('\n');
|
|
77
|
+
const actualLines = actual.split('\n');
|
|
78
|
+
const line = Array.from({ length: Math.max(expectedLines.length, actualLines.length) }, (_, i) => i).find((i) => expectedLines[i] !== actualLines[i]) ?? 0;
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
code: 'dictionary-drift',
|
|
82
|
+
path: `${file}:${line + 1}:1`,
|
|
83
|
+
message: `dictionary differs from the App metadata renderer; run schema:docs after reviewing schema changes. Expected ${JSON.stringify((expectedLines[line] ?? '<end>').slice(0, 180))}, found ${JSON.stringify((actualLines[line] ?? '<end>').slice(0, 180))}`,
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=dictionary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dictionary.js","sourceRoot":"","sources":["../src/dictionary.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export * from './checks';
|
|
2
2
|
export * from './cli';
|
|
3
|
+
export * from './dictionary';
|
|
3
4
|
export * from './enums';
|
|
4
5
|
export * from './integration-contracts';
|
|
5
6
|
export * from './scaffold';
|
|
7
|
+
export * from './scopes';
|
|
6
8
|
export * from './subscriber-wiring';
|
|
7
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -16,8 +16,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./checks"), exports);
|
|
18
18
|
__exportStar(require("./cli"), exports);
|
|
19
|
+
__exportStar(require("./dictionary"), exports);
|
|
19
20
|
__exportStar(require("./enums"), exports);
|
|
20
21
|
__exportStar(require("./integration-contracts"), exports);
|
|
21
22
|
__exportStar(require("./scaffold"), exports);
|
|
23
|
+
__exportStar(require("./scopes"), exports);
|
|
22
24
|
__exportStar(require("./subscriber-wiring"), exports);
|
|
23
25
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,wCAAsB;AACtB,0CAAwB;AACxB,0DAAwC;AACxC,6CAA2B;AAC3B,sDAAoC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,wCAAsB;AACtB,+CAA6B;AAC7B,0CAAwB;AACxB,0DAAwC;AACxC,6CAA2B;AAC3B,2CAAyB;AACzB,sDAAoC"}
|
package/dist/scopes.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAyO1D,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CA+JhE"}
|
package/dist/scopes.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.checkScopeCoverage = checkScopeCoverage;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
10
|
+
const NEST = '@nestjs/common';
|
|
11
|
+
const M2M = '@haneinfo/m2m-api-key';
|
|
12
|
+
const HTTP = new Set([
|
|
13
|
+
'Get',
|
|
14
|
+
'Post',
|
|
15
|
+
'Put',
|
|
16
|
+
'Patch',
|
|
17
|
+
'Delete',
|
|
18
|
+
'Head',
|
|
19
|
+
'Options',
|
|
20
|
+
'All',
|
|
21
|
+
'Search',
|
|
22
|
+
'QueryMethod',
|
|
23
|
+
'Propfind',
|
|
24
|
+
'Proppatch',
|
|
25
|
+
'Mkcol',
|
|
26
|
+
'Copy',
|
|
27
|
+
'Move',
|
|
28
|
+
'Lock',
|
|
29
|
+
'Unlock',
|
|
30
|
+
'RequestMapping',
|
|
31
|
+
]);
|
|
32
|
+
const METADATA_KEYS = new Set(['scopes', '__guards__', 'path', 'method']);
|
|
33
|
+
function sourceFiles(directory) {
|
|
34
|
+
return (0, node_fs_1.readdirSync)(directory, { withFileTypes: true })
|
|
35
|
+
.flatMap((entry) => {
|
|
36
|
+
const file = node_path_1.default.join(directory, entry.name);
|
|
37
|
+
if (entry.isDirectory())
|
|
38
|
+
return sourceFiles(file);
|
|
39
|
+
return /\.tsx?$/u.test(entry.name) && !/\.(?:d|spec|test)\.tsx?$/u.test(entry.name)
|
|
40
|
+
? [file]
|
|
41
|
+
: [];
|
|
42
|
+
})
|
|
43
|
+
.sort();
|
|
44
|
+
}
|
|
45
|
+
function unwrap(expression) {
|
|
46
|
+
while (typescript_1.default.isParenthesizedExpression(expression) ||
|
|
47
|
+
typescript_1.default.isAsExpression(expression) ||
|
|
48
|
+
typescript_1.default.isTypeAssertionExpression(expression) ||
|
|
49
|
+
typescript_1.default.isSatisfiesExpression(expression) ||
|
|
50
|
+
typescript_1.default.isNonNullExpression(expression))
|
|
51
|
+
expression = expression.expression;
|
|
52
|
+
return expression;
|
|
53
|
+
}
|
|
54
|
+
class StaticAnalysis {
|
|
55
|
+
constructor(checker) {
|
|
56
|
+
this.checker = checker;
|
|
57
|
+
}
|
|
58
|
+
symbol(expression) {
|
|
59
|
+
return this.checker.getSymbolAtLocation(typescript_1.default.isPropertyAccessExpression(expression) ? expression.name : expression);
|
|
60
|
+
}
|
|
61
|
+
declaration(expression) {
|
|
62
|
+
let symbol = this.symbol(expression);
|
|
63
|
+
if (symbol && symbol.flags & typescript_1.default.SymbolFlags.Alias)
|
|
64
|
+
symbol = this.checker.getAliasedSymbol(symbol);
|
|
65
|
+
return symbol?.valueDeclaration ?? symbol?.declarations?.[0];
|
|
66
|
+
}
|
|
67
|
+
reference(input, seen = new Set()) {
|
|
68
|
+
const expression = unwrap(input);
|
|
69
|
+
if (seen.has(expression))
|
|
70
|
+
return undefined;
|
|
71
|
+
seen.add(expression);
|
|
72
|
+
if (typescript_1.default.isPropertyAccessExpression(expression)) {
|
|
73
|
+
const namespace = this.symbol(expression.expression)?.declarations?.[0];
|
|
74
|
+
if (namespace && typescript_1.default.isNamespaceImport(namespace)) {
|
|
75
|
+
const module = namespace.parent.parent.moduleSpecifier;
|
|
76
|
+
if (typescript_1.default.isStringLiteral(module))
|
|
77
|
+
return { module: module.text, name: expression.name.text };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const imported = this.symbol(expression)?.declarations?.[0];
|
|
81
|
+
if (imported && typescript_1.default.isImportSpecifier(imported)) {
|
|
82
|
+
const module = imported.parent.parent.parent.moduleSpecifier;
|
|
83
|
+
if (typescript_1.default.isStringLiteral(module) &&
|
|
84
|
+
!module.text.startsWith('.') &&
|
|
85
|
+
!module.text.startsWith('/')) {
|
|
86
|
+
return { module: module.text, name: (imported.propertyName ?? imported.name).text };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const declaration = this.declaration(expression);
|
|
90
|
+
if (declaration &&
|
|
91
|
+
typescript_1.default.isVariableDeclaration(declaration) &&
|
|
92
|
+
declaration.initializer &&
|
|
93
|
+
declaration.parent.flags & typescript_1.default.NodeFlags.Const) {
|
|
94
|
+
return this.reference(declaration.initializer, seen);
|
|
95
|
+
}
|
|
96
|
+
// Local barrels resolve to the original package declaration via the TypeScript checker.
|
|
97
|
+
if (declaration) {
|
|
98
|
+
const file = declaration.getSourceFile().fileName.replaceAll('\\', '/');
|
|
99
|
+
for (const module of [NEST, M2M]) {
|
|
100
|
+
if (file.includes(`/node_modules/${module}/`)) {
|
|
101
|
+
return {
|
|
102
|
+
module,
|
|
103
|
+
name: this.checker.getSymbolAtLocation(declaration.name ?? declaration)?.name ?? '',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
value(input, seen = new Set()) {
|
|
111
|
+
const expression = unwrap(input);
|
|
112
|
+
if (seen.has(expression))
|
|
113
|
+
throw new Error('cyclic constant');
|
|
114
|
+
const next = new Set(seen).add(expression);
|
|
115
|
+
if (typescript_1.default.isStringLiteralLike(expression))
|
|
116
|
+
return expression.text;
|
|
117
|
+
if (typescript_1.default.isArrayLiteralExpression(expression))
|
|
118
|
+
return this.arguments(expression.elements, next);
|
|
119
|
+
if (typescript_1.default.isBinaryExpression(expression) &&
|
|
120
|
+
expression.operatorToken.kind === typescript_1.default.SyntaxKind.PlusToken) {
|
|
121
|
+
const left = this.value(expression.left, next);
|
|
122
|
+
const right = this.value(expression.right, next);
|
|
123
|
+
if (typeof left === 'string' && typeof right === 'string')
|
|
124
|
+
return left + right;
|
|
125
|
+
}
|
|
126
|
+
const declaration = this.declaration(expression);
|
|
127
|
+
if (declaration &&
|
|
128
|
+
typescript_1.default.isVariableDeclaration(declaration) &&
|
|
129
|
+
declaration.initializer &&
|
|
130
|
+
declaration.parent.flags & typescript_1.default.NodeFlags.Const)
|
|
131
|
+
return this.value(declaration.initializer, next);
|
|
132
|
+
if (declaration &&
|
|
133
|
+
(typescript_1.default.isPropertyAssignment(declaration) || typescript_1.default.isEnumMember(declaration)) &&
|
|
134
|
+
declaration.initializer)
|
|
135
|
+
return this.value(declaration.initializer, next);
|
|
136
|
+
throw new Error(`cannot statically resolve ${expression.getText()}`);
|
|
137
|
+
}
|
|
138
|
+
arguments(elements, seen = new Set()) {
|
|
139
|
+
return elements.flatMap((element) => {
|
|
140
|
+
if (!typescript_1.default.isSpreadElement(element))
|
|
141
|
+
return [this.value(element, seen)];
|
|
142
|
+
const value = this.value(element.expression, seen);
|
|
143
|
+
if (!Array.isArray(value))
|
|
144
|
+
throw new Error('spread constant is not an array');
|
|
145
|
+
return value;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
guards(elements, seen = new Set()) {
|
|
149
|
+
let guarded = false;
|
|
150
|
+
for (const input of elements) {
|
|
151
|
+
const expression = unwrap(typescript_1.default.isSpreadElement(input) ? input.expression : input);
|
|
152
|
+
if (seen.has(expression))
|
|
153
|
+
throw new Error('cyclic guard constant');
|
|
154
|
+
const next = new Set(seen).add(expression);
|
|
155
|
+
if (typescript_1.default.isArrayLiteralExpression(expression)) {
|
|
156
|
+
guarded = this.guards(expression.elements, next) || guarded;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const ref = typescript_1.default.isSpreadElement(input) ? undefined : this.reference(expression);
|
|
160
|
+
if (ref) {
|
|
161
|
+
guarded = (ref.module === M2M && ref.name === 'ScopeGuard') || guarded;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const declaration = this.declaration(expression);
|
|
165
|
+
if (declaration &&
|
|
166
|
+
typescript_1.default.isVariableDeclaration(declaration) &&
|
|
167
|
+
declaration.initializer &&
|
|
168
|
+
declaration.parent.flags & typescript_1.default.NodeFlags.Const) {
|
|
169
|
+
guarded =
|
|
170
|
+
this.guards([
|
|
171
|
+
typescript_1.default.isSpreadElement(input)
|
|
172
|
+
? typescript_1.default.factory.createSpreadElement(declaration.initializer)
|
|
173
|
+
: declaration.initializer,
|
|
174
|
+
], next) || guarded;
|
|
175
|
+
}
|
|
176
|
+
else if (declaration && typescript_1.default.isClassDeclaration(declaration)) {
|
|
177
|
+
const bases = declaration.heritageClauses
|
|
178
|
+
?.filter((clause) => clause.token === typescript_1.default.SyntaxKind.ExtendsKeyword)
|
|
179
|
+
.flatMap((clause) => clause.types.map((base) => base.expression)) ?? [];
|
|
180
|
+
guarded = this.guards(bases, next) || guarded;
|
|
181
|
+
}
|
|
182
|
+
else
|
|
183
|
+
throw new Error(`cannot resolve guard ${expression.getText()}`);
|
|
184
|
+
}
|
|
185
|
+
return guarded;
|
|
186
|
+
}
|
|
187
|
+
/** Only simple, unrelated metadata factories are safe to ignore among local decorators. */
|
|
188
|
+
unrelatedMetadata(expression) {
|
|
189
|
+
const declaration = this.declaration(expression);
|
|
190
|
+
const initializer = declaration && typescript_1.default.isVariableDeclaration(declaration) ? declaration.initializer : undefined;
|
|
191
|
+
const factory = initializer && typescript_1.default.isArrowFunction(initializer) ? initializer : declaration;
|
|
192
|
+
if (!factory ||
|
|
193
|
+
!(typescript_1.default.isArrowFunction(factory) || typescript_1.default.isFunctionDeclaration(factory)) ||
|
|
194
|
+
!factory.body)
|
|
195
|
+
return false;
|
|
196
|
+
let body = factory.body;
|
|
197
|
+
if (typescript_1.default.isBlock(body)) {
|
|
198
|
+
if (body.statements.length !== 1 ||
|
|
199
|
+
!typescript_1.default.isReturnStatement(body.statements[0]) ||
|
|
200
|
+
!body.statements[0].expression)
|
|
201
|
+
return false;
|
|
202
|
+
body = body.statements[0].expression;
|
|
203
|
+
}
|
|
204
|
+
if (!typescript_1.default.isCallExpression(body))
|
|
205
|
+
return false;
|
|
206
|
+
const ref = this.reference(body.expression);
|
|
207
|
+
if (ref?.module !== NEST || ref.name !== 'SetMetadata' || !body.arguments[0])
|
|
208
|
+
return false;
|
|
209
|
+
try {
|
|
210
|
+
const key = this.value(body.arguments[0]);
|
|
211
|
+
return typeof key === 'string' && !METADATA_KEYS.has(key);
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/** Check direct controller/method metadata in App source; never execute App code. */
|
|
219
|
+
function checkScopeCoverage(appRoot) {
|
|
220
|
+
const sourceRoot = node_path_1.default.join(appRoot, 'backend', 'src');
|
|
221
|
+
if (!(0, node_fs_1.existsSync)(sourceRoot))
|
|
222
|
+
return [
|
|
223
|
+
{
|
|
224
|
+
code: 'scope-source-missing',
|
|
225
|
+
path: sourceRoot,
|
|
226
|
+
message: 'backend/src is missing; scope coverage was not checked',
|
|
227
|
+
},
|
|
228
|
+
];
|
|
229
|
+
const files = sourceFiles(sourceRoot);
|
|
230
|
+
// TypeScript's config diagnostics expect normalized separators, including invalid JSON on Windows.
|
|
231
|
+
const configPath = node_path_1.default.join(appRoot, 'backend', 'tsconfig.json').replaceAll('\\', '/');
|
|
232
|
+
let options = {
|
|
233
|
+
experimentalDecorators: true,
|
|
234
|
+
target: typescript_1.default.ScriptTarget.ES2021,
|
|
235
|
+
moduleResolution: typescript_1.default.ModuleResolutionKind.Node10,
|
|
236
|
+
};
|
|
237
|
+
if ((0, node_fs_1.existsSync)(configPath)) {
|
|
238
|
+
const config = typescript_1.default.readConfigFile(configPath, typescript_1.default.sys.readFile);
|
|
239
|
+
const parsed = typescript_1.default.parseJsonConfigFileContent(config.config ?? {}, typescript_1.default.sys, node_path_1.default.dirname(configPath));
|
|
240
|
+
const errors = [config.error, ...parsed.errors].filter((error) => !!error && error.code !== 18003);
|
|
241
|
+
if (errors.length)
|
|
242
|
+
return errors.map((error) => ({
|
|
243
|
+
code: 'scope-config-invalid',
|
|
244
|
+
path: configPath,
|
|
245
|
+
message: typescript_1.default.flattenDiagnosticMessageText(error.messageText, '\n'),
|
|
246
|
+
}));
|
|
247
|
+
options = parsed.options;
|
|
248
|
+
}
|
|
249
|
+
const program = typescript_1.default.createProgram(files, { ...options, noEmit: true });
|
|
250
|
+
const analysis = new StaticAnalysis(program.getTypeChecker());
|
|
251
|
+
const issues = [];
|
|
252
|
+
const report = (node, owner, code, message) => {
|
|
253
|
+
const source = node.getSourceFile();
|
|
254
|
+
const position = source.getLineAndCharacterOfPosition(node.getStart());
|
|
255
|
+
issues.push({
|
|
256
|
+
code,
|
|
257
|
+
path: `${node_path_1.default.relative(appRoot, source.fileName).replaceAll('\\', '/')}:${position.line + 1}:${position.character + 1}`,
|
|
258
|
+
message: `${owner}: ${message}`,
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
const decorators = (node) => typescript_1.default.canHaveDecorators(node) ? (typescript_1.default.getDecorators(node) ?? []) : [];
|
|
262
|
+
const metadata = (node, owner) => {
|
|
263
|
+
const result = { guarded: false, route: false };
|
|
264
|
+
let scopeCount = 0;
|
|
265
|
+
for (const decorator of decorators(node)) {
|
|
266
|
+
const call = unwrap(decorator.expression);
|
|
267
|
+
const ref = analysis.reference(typescript_1.default.isCallExpression(call) ? call.expression : call);
|
|
268
|
+
try {
|
|
269
|
+
if (!typescript_1.default.isCallExpression(call))
|
|
270
|
+
throw new Error('decorator is not a direct factory call');
|
|
271
|
+
if (ref?.module === NEST) {
|
|
272
|
+
if (HTTP.has(ref.name))
|
|
273
|
+
result.route = true;
|
|
274
|
+
else if (ref.name === 'UseGuards')
|
|
275
|
+
result.guarded = analysis.guards(call.arguments) || result.guarded;
|
|
276
|
+
else if (ref.name === 'SetMetadata') {
|
|
277
|
+
const key = call.arguments[0] && analysis.value(call.arguments[0]);
|
|
278
|
+
if (typeof key !== 'string' || METADATA_KEYS.has(key))
|
|
279
|
+
throw new Error('use direct Controller/HTTP/UseGuards/Scopes decorators for routing and scope metadata');
|
|
280
|
+
}
|
|
281
|
+
else if (ref.name === 'applyDecorators')
|
|
282
|
+
throw new Error('composed decorators are not supported; use direct decorators');
|
|
283
|
+
}
|
|
284
|
+
else if (ref?.module === M2M && ref.name === 'Scopes') {
|
|
285
|
+
scopeCount++;
|
|
286
|
+
if (scopeCount > 1)
|
|
287
|
+
throw new Error('multiple @Scopes decorators on one declaration are ambiguous; use one');
|
|
288
|
+
const scopes = analysis.arguments(call.arguments);
|
|
289
|
+
if (scopes.some((scope) => typeof scope !== 'string' || !scope.trim()))
|
|
290
|
+
throw new Error('scope values must be non-empty static strings');
|
|
291
|
+
result.scopes = scopes;
|
|
292
|
+
}
|
|
293
|
+
else if (!(ref?.module === '@haneinfo/rbac' && ref.name === 'RequirePermissions') &&
|
|
294
|
+
!analysis.unrelatedMetadata(call.expression))
|
|
295
|
+
throw new Error(`unsupported decorator ${call.expression.getText()}; its routing/guard/scope metadata cannot be verified`);
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
report(decorator, owner, 'scope-analysis-unsupported', error instanceof Error ? error.message : String(error));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return result;
|
|
302
|
+
};
|
|
303
|
+
for (const file of files) {
|
|
304
|
+
const source = program.getSourceFile(file);
|
|
305
|
+
if (!source)
|
|
306
|
+
continue;
|
|
307
|
+
for (const error of program.getSyntacticDiagnostics(source)) {
|
|
308
|
+
const position = source.getLineAndCharacterOfPosition(error.start ?? 0);
|
|
309
|
+
issues.push({
|
|
310
|
+
code: 'scope-source-invalid',
|
|
311
|
+
path: `${node_path_1.default.relative(appRoot, file).replaceAll('\\', '/')}:${position.line + 1}:${position.character + 1}`,
|
|
312
|
+
message: typescript_1.default.flattenDiagnosticMessageText(error.messageText, '\n'),
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
const visit = (node) => {
|
|
316
|
+
if (typescript_1.default.isClassDeclaration(node) || typescript_1.default.isClassExpression(node)) {
|
|
317
|
+
const members = node.members.filter(typescript_1.default.isMethodDeclaration);
|
|
318
|
+
const refs = [...decorators(node), ...members.flatMap(decorators)].map((decorator) => {
|
|
319
|
+
const call = unwrap(decorator.expression);
|
|
320
|
+
return analysis.reference(typescript_1.default.isCallExpression(call) ? call.expression : call);
|
|
321
|
+
});
|
|
322
|
+
const candidate = refs.some((ref) => (ref?.module === NEST &&
|
|
323
|
+
(ref.name === 'Controller' || HTTP.has(ref.name) || ref.name === 'UseGuards')) ||
|
|
324
|
+
ref?.module === M2M) ||
|
|
325
|
+
(file.endsWith('.controller.ts') && refs.length > 0) ||
|
|
326
|
+
decorators(node).some((decorator) => {
|
|
327
|
+
const call = unwrap(decorator.expression);
|
|
328
|
+
return !analysis.reference(typescript_1.default.isCallExpression(call) ? call.expression : call);
|
|
329
|
+
});
|
|
330
|
+
if (candidate) {
|
|
331
|
+
const owner = node.name?.text ?? '<anonymous controller>';
|
|
332
|
+
if (node.heritageClauses?.some((clause) => clause.token === typescript_1.default.SyntaxKind.ExtendsKeyword))
|
|
333
|
+
report(node, owner, 'scope-analysis-unsupported', 'controller inheritance/mixins require explicit review; inherited routes and metadata are not analyzed');
|
|
334
|
+
const classMetadata = metadata(node, owner);
|
|
335
|
+
for (const method of members) {
|
|
336
|
+
const methodOwner = `${owner}.${method.name.getText()}`;
|
|
337
|
+
const methodMetadata = metadata(method, methodOwner);
|
|
338
|
+
if (!methodMetadata.route || !(classMetadata.guarded || methodMetadata.guarded))
|
|
339
|
+
continue;
|
|
340
|
+
const scopes = methodMetadata.scopes ?? classMetadata.scopes;
|
|
341
|
+
if (!scopes?.length)
|
|
342
|
+
report(method.name, methodOwner, 'scope-coverage-missing', `${methodMetadata.scopes ? 'empty method @Scopes() overrides class scopes' : 'no non-empty methodScopes ?? classScopes'}; ScopeGuard denies API-key requests with 403`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
typescript_1.default.forEachChild(node, visit);
|
|
347
|
+
};
|
|
348
|
+
visit(source);
|
|
349
|
+
}
|
|
350
|
+
return issues;
|
|
351
|
+
}
|
|
352
|
+
//# sourceMappingURL=scopes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopes.js","sourceRoot":"","sources":["../src/scopes.ts"],"names":[],"mappings":";;;;;AA6OA,gDA+JC;AA5YD,qCAAkD;AAClD,0DAA6B;AAC7B,4DAA4B;AAG5B,MAAM,IAAI,GAAG,gBAAgB,CAAC;AAC9B,MAAM,GAAG,GAAG,uBAAuB,CAAC;AACpC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC;IACnB,KAAK;IACL,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,MAAM;IACN,SAAS;IACT,KAAK;IACL,QAAQ;IACR,aAAa;IACb,UAAU;IACV,WAAW;IACX,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,QAAQ;IACR,gBAAgB;CACjB,CAAC,CAAC;AACH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAI1E,SAAS,WAAW,CAAC,SAAiB;IACpC,OAAO,IAAA,qBAAW,EAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACnD,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACjB,MAAM,IAAI,GAAG,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,KAAK,CAAC,WAAW,EAAE;YAAE,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAClD,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACjF,CAAC,CAAC,CAAC,IAAI,CAAC;YACR,CAAC,CAAC,EAAE,CAAC;IACT,CAAC,CAAC;SACD,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,MAAM,CAAC,UAAyB;IACvC,OACE,oBAAE,CAAC,yBAAyB,CAAC,UAAU,CAAC;QACxC,oBAAE,CAAC,cAAc,CAAC,UAAU,CAAC;QAC7B,oBAAE,CAAC,yBAAyB,CAAC,UAAU,CAAC;QACxC,oBAAE,CAAC,qBAAqB,CAAC,UAAU,CAAC;QACpC,oBAAE,CAAC,mBAAmB,CAAC,UAAU,CAAC;QAElC,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;IACrC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,cAAc;IAClB,YAA6B,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAG,CAAC;IAEhD,MAAM,CAAC,UAAyB;QACtC,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,CACrC,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CACzE,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,UAAyB;QACnC,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,GAAG,oBAAE,CAAC,WAAW,CAAC,KAAK;YAC/C,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACjD,OAAO,MAAM,EAAE,gBAAgB,IAAI,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,SAAS,CAAC,KAAoB,EAAE,OAAO,IAAI,GAAG,EAAW;QACvD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3C,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrB,IAAI,oBAAE,CAAC,0BAA0B,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;YACxE,IAAI,SAAS,IAAI,oBAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;gBACvD,IAAI,oBAAE,CAAC,eAAe,CAAC,MAAM,CAAC;oBAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7F,CAAC;QACH,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5D,IAAI,QAAQ,IAAI,oBAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;YAC7D,IACE,oBAAE,CAAC,eAAe,CAAC,MAAM,CAAC;gBAC1B,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAC5B,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAC5B,CAAC;gBACD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACtF,CAAC;QACH,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACjD,IACE,WAAW;YACX,oBAAE,CAAC,qBAAqB,CAAC,WAAW,CAAC;YACrC,WAAW,CAAC,WAAW;YACvB,WAAW,CAAC,MAAM,CAAC,KAAK,GAAG,oBAAE,CAAC,SAAS,CAAC,KAAK,EAC7C,CAAC;YACD,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACvD,CAAC;QACD,wFAAwF;QACxF,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,IAAI,GAAG,WAAW,CAAC,aAAa,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YACxE,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;gBACjC,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC9C,OAAO;wBACL,MAAM;wBACN,IAAI,EACF,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAC7B,WAAmC,CAAC,IAAI,IAAI,WAAW,CACzD,EAAE,IAAI,IAAI,EAAE;qBAChB,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,KAAoB,EAAE,OAAO,IAAI,GAAG,EAAW;QACnD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,oBAAE,CAAC,mBAAmB,CAAC,UAAU,CAAC;YAAE,OAAO,UAAU,CAAC,IAAI,CAAC;QAC/D,IAAI,oBAAE,CAAC,wBAAwB,CAAC,UAAU,CAAC;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9F,IACE,oBAAE,CAAC,kBAAkB,CAAC,UAAU,CAAC;YACjC,UAAU,CAAC,aAAa,CAAC,IAAI,KAAK,oBAAE,CAAC,UAAU,CAAC,SAAS,EACzD,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACjD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,OAAO,IAAI,GAAG,KAAK,CAAC;QACjF,CAAC;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACjD,IACE,WAAW;YACX,oBAAE,CAAC,qBAAqB,CAAC,WAAW,CAAC;YACrC,WAAW,CAAC,WAAW;YACvB,WAAW,CAAC,MAAM,CAAC,KAAK,GAAG,oBAAE,CAAC,SAAS,CAAC,KAAK;YAE7C,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACnD,IACE,WAAW;YACX,CAAC,oBAAE,CAAC,oBAAoB,CAAC,WAAW,CAAC,IAAI,oBAAE,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YACtE,WAAW,CAAC,WAAW;YAEvB,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,6BAA6B,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,SAAS,CAAC,QAAkC,EAAE,OAAO,IAAI,GAAG,EAAW;QACrE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAClC,IAAI,CAAC,oBAAE,CAAC,eAAe,CAAC,OAAO,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YACrE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACnD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YAC9E,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,QAAkC,EAAE,OAAO,IAAI,GAAG,EAAW;QAClE,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,oBAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAChF,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACnE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC3C,IAAI,oBAAE,CAAC,wBAAwB,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC5C,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC;gBAC5D,SAAS;YACX,CAAC;YACD,MAAM,GAAG,GAAG,oBAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;YAC/E,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC,IAAI,OAAO,CAAC;gBACvE,SAAS;YACX,CAAC;YACD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YACjD,IACE,WAAW;gBACX,oBAAE,CAAC,qBAAqB,CAAC,WAAW,CAAC;gBACrC,WAAW,CAAC,WAAW;gBACvB,WAAW,CAAC,MAAM,CAAC,KAAK,GAAG,oBAAE,CAAC,SAAS,CAAC,KAAK,EAC7C,CAAC;gBACD,OAAO;oBACL,IAAI,CAAC,MAAM,CACT;wBACE,oBAAE,CAAC,eAAe,CAAC,KAAK,CAAC;4BACvB,CAAC,CAAC,oBAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,WAAW,CAAC,WAAW,CAAC;4BACzD,CAAC,CAAC,WAAW,CAAC,WAAW;qBAC5B,EACD,IAAI,CACL,IAAI,OAAO,CAAC;YACjB,CAAC;iBAAM,IAAI,WAAW,IAAI,oBAAE,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC7D,MAAM,KAAK,GACT,WAAW,CAAC,eAAe;oBACzB,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,oBAAE,CAAC,UAAU,CAAC,cAAc,CAAC;qBAClE,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC5E,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC;YAChD,CAAC;;gBAAM,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,2FAA2F;IAC3F,iBAAiB,CAAC,UAAyB;QACzC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QACjD,MAAM,WAAW,GACf,WAAW,IAAI,oBAAE,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7F,MAAM,OAAO,GAAG,WAAW,IAAI,oBAAE,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC;QAC3F,IACE,CAAC,OAAO;YACR,CAAC,CAAC,oBAAE,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,oBAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;YACnE,CAAC,OAAO,CAAC,IAAI;YAEb,OAAO,KAAK,CAAC;QACf,IAAI,IAAI,GAAY,OAAO,CAAC,IAAI,CAAC;QACjC,IAAI,oBAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,IACE,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;gBAC5B,CAAC,oBAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBACzC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU;gBAE9B,OAAO,KAAK,CAAC;YACf,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QACvC,CAAC;QACD,IAAI,CAAC,oBAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,GAAG,EAAE,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3F,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1C,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF;AAED,qFAAqF;AACrF,SAAgB,kBAAkB,CAAC,OAAe;IAChD,MAAM,UAAU,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACxD,IAAI,CAAC,IAAA,oBAAU,EAAC,UAAU,CAAC;QACzB,OAAO;YACL;gBACE,IAAI,EAAE,sBAAsB;gBAC5B,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,wDAAwD;aAClE;SACF,CAAC;IACJ,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACtC,mGAAmG;IACnG,MAAM,UAAU,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACxF,IAAI,OAAO,GAAuB;QAChC,sBAAsB,EAAE,IAAI;QAC5B,MAAM,EAAE,oBAAE,CAAC,YAAY,CAAC,MAAM;QAC9B,gBAAgB,EAAE,oBAAE,CAAC,oBAAoB,CAAC,MAAM;KACjD,CAAC;IACF,IAAI,IAAA,oBAAU,EAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,oBAAE,CAAC,cAAc,CAAC,UAAU,EAAE,oBAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,oBAAE,CAAC,0BAA0B,CAC1C,MAAM,CAAC,MAAM,IAAI,EAAE,EACnB,oBAAE,CAAC,GAAG,EACN,mBAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CACzB,CAAC;QACF,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CACpD,CAAC,KAAK,EAA0B,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CACnE,CAAC;QACF,IAAI,MAAM,CAAC,MAAM;YACf,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBAC5B,IAAI,EAAE,sBAAsB;gBAC5B,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,oBAAE,CAAC,4BAA4B,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC;aAClE,CAAC,CAAC,CAAC;QACN,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC3B,CAAC;IACD,MAAM,OAAO,GAAG,oBAAE,CAAC,aAAa,CAAC,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,CAAC,IAAa,EAAE,KAAa,EAAE,IAAY,EAAE,OAAe,EAAE,EAAE;QAC7E,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACvE,MAAM,CAAC,IAAI,CAAC;YACV,IAAI;YACJ,IAAI,EAAE,GAAG,mBAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,QAAQ,CAAC,SAAS,GAAG,CAAC,EAAE;YACvH,OAAO,EAAE,GAAG,KAAK,KAAK,OAAO,EAAE;SAChC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,CAAC,IAAa,EAAE,EAAE,CACnC,oBAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,QAAQ,GAAG,CAAC,IAAa,EAAE,KAAa,EAAY,EAAE;QAC1D,MAAM,MAAM,GAAa,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAC1D,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,oBAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACnF,IAAI,CAAC;gBACH,IAAI,CAAC,oBAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;gBAC1F,IAAI,GAAG,EAAE,MAAM,KAAK,IAAI,EAAE,CAAC;oBACzB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;wBAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;yBACvC,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW;wBAC/B,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC;yBAChE,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;wBACpC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;wBACnE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC;4BACnD,MAAM,IAAI,KAAK,CACb,uFAAuF,CACxF,CAAC;oBACN,CAAC;yBAAM,IAAI,GAAG,CAAC,IAAI,KAAK,iBAAiB;wBACvC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;gBACpF,CAAC;qBAAM,IAAI,GAAG,EAAE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACxD,UAAU,EAAE,CAAC;oBACb,IAAI,UAAU,GAAG,CAAC;wBAChB,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAC;oBACJ,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAClD,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;wBACpE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;oBACnE,MAAM,CAAC,MAAM,GAAG,MAAkB,CAAC;gBACrC,CAAC;qBAAM,IACL,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,gBAAgB,IAAI,GAAG,CAAC,IAAI,KAAK,oBAAoB,CAAC;oBACxE,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;oBAE5C,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,uDAAuD,CAC1G,CAAC;YACN,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CACJ,SAAS,EACT,KAAK,EACL,4BAA4B,EAC5B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,6BAA6B,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;YACxE,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,sBAAsB;gBAC5B,IAAI,EAAE,GAAG,mBAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,QAAQ,CAAC,SAAS,GAAG,CAAC,EAAE;gBAC5G,OAAO,EAAE,oBAAE,CAAC,4BAA4B,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC;aAClE,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,IAAa,EAAE,EAAE;YAC9B,IAAI,oBAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,oBAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,oBAAE,CAAC,mBAAmB,CAAC,CAAC;gBAC5D,MAAM,IAAI,GAAG,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;oBACnF,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;oBAC1C,OAAO,QAAQ,CAAC,SAAS,CAAC,oBAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAChF,CAAC,CAAC,CAAC;gBACH,MAAM,SAAS,GACb,IAAI,CAAC,IAAI,CACP,CAAC,GAAG,EAAE,EAAE,CACN,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI;oBACnB,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;oBAChF,GAAG,EAAE,MAAM,KAAK,GAAG,CACtB;oBACD,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;oBACpD,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;wBAClC,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;wBAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,oBAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;oBACjF,CAAC,CAAC,CAAC;gBACL,IAAI,SAAS,EAAE,CAAC;oBACd,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,wBAAwB,CAAC;oBAC1D,IAAI,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,oBAAE,CAAC,UAAU,CAAC,cAAc,CAAC;wBACvF,MAAM,CACJ,IAAI,EACJ,KAAK,EACL,4BAA4B,EAC5B,uGAAuG,CACxG,CAAC;oBACJ,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;oBAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;wBAC7B,MAAM,WAAW,GAAG,GAAG,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;wBACxD,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;wBACrD,IAAI,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,CAAC,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC;4BAC7E,SAAS;wBACX,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,IAAI,aAAa,CAAC,MAAM,CAAC;wBAC7D,IAAI,CAAC,MAAM,EAAE,MAAM;4BACjB,MAAM,CACJ,MAAM,CAAC,IAAI,EACX,WAAW,EACX,wBAAwB,EACxB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,+CAA+C,CAAC,CAAC,CAAC,0CAA0C,+CAA+C,CACvK,CAAC;oBACN,CAAC;gBACH,CAAC;YACH,CAAC;YACD,oBAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC,CAAC;QACF,KAAK,CAAC,MAAM,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haneinfo/app-tooling",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"description": "Shared Haneinfo App checks and scaffold tooling",
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"typescript": "^5.9.3",
|
|
17
18
|
"@haneinfo/plugin-cli": "2.1.1"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@types/node": "^24.13.0",
|
|
21
|
-
"typescript": "^5.9.3",
|
|
22
22
|
"vitest": "^4.1.11"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|