@dereekb/dbx-cli 13.15.0 → 13.17.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/eslint/index.cjs.default.js +1 -0
- package/eslint/index.cjs.js +1050 -0
- package/eslint/index.cjs.mjs +2 -0
- package/eslint/index.d.ts +1 -0
- package/eslint/index.esm.js +1046 -0
- package/eslint/package.json +25 -0
- package/eslint/rollup.alias-internal.config.d.ts +11 -0
- package/eslint/src/index.d.ts +1 -0
- package/eslint/src/lib/index.d.ts +2 -0
- package/eslint/src/lib/plugin.d.ts +22 -0
- package/eslint/src/lib/valid-dbx-route-model-tags.rule.d.ts +59 -0
- package/firebase-api-manifest/main.js +318 -228
- package/firebase-api-manifest/package.json +3 -3
- package/generate-firestore-indexes/main.js +37 -24
- package/generate-firestore-indexes/package.json +2 -2
- package/generate-mcp-manifest/main.js +57 -39
- package/generate-mcp-manifest/package.json +3 -3
- package/generate-route-manifest/main.js +1137 -0
- package/generate-route-manifest/package.json +10 -0
- package/index.cjs.js +4847 -1953
- package/index.esm.js +4827 -1954
- package/lint-cache/package.json +2 -2
- package/manifest-extract/index.cjs.js +175 -240
- package/manifest-extract/index.esm.js +174 -239
- package/manifest-extract/package.json +9 -4
- package/package.json +16 -6
- package/src/lib/index.d.ts +2 -0
- package/src/lib/manifest/types.d.ts +53 -0
- package/src/lib/mcp-scan/manifest/package-root.d.ts +17 -0
- package/src/lib/mcp-scan/manifest/tokens-schema.d.ts +5 -4
- package/src/lib/mcp-scan/scan/extract-models/assemble.d.ts +17 -0
- package/src/lib/route/component-resolve.d.ts +48 -0
- package/src/lib/route/index.d.ts +18 -0
- package/src/lib/route/route-build-tree.d.ts +31 -0
- package/src/lib/route/route-extract.d.ts +46 -0
- package/src/lib/route/route-load-tree.d.ts +17 -0
- package/src/lib/route/route-manifest.d.ts +132 -0
- package/src/lib/route/route-model-tag.d.ts +89 -0
- package/src/lib/route/route-models-extract.d.ts +22 -0
- package/src/lib/route/route-resolve-sources.d.ts +39 -0
- package/src/lib/route/route-types.d.ts +136 -0
- package/src/lib/route/url-match.d.ts +116 -0
- package/src/lib/scan-helpers/firestore-model-extract-utils.d.ts +43 -0
- package/test/index.cjs.js +1 -1
- package/test/index.esm.js +1 -1
- package/test/package.json +9 -9
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the UIRouter route-extraction core.
|
|
3
|
+
*
|
|
4
|
+
* Originally lived in `@dereekb/dbx-components-mcp` behind the `dbx_route_*`
|
|
5
|
+
* tools; lifted here so both the dev MCP server and the build-time
|
|
6
|
+
* `dbx-cli-generate-route-manifest` binary share one extractor.
|
|
7
|
+
*
|
|
8
|
+
* The core is validator-style: it reads TypeScript source and extracts the
|
|
9
|
+
* UIRouter state tree by syntactic analysis. No DI graph evaluation; we record
|
|
10
|
+
* class-name references as strings.
|
|
11
|
+
*
|
|
12
|
+
* Routes are described as a flat list of {@link RouteNode}s during extraction
|
|
13
|
+
* and turned into a parent-linked {@link RouteTree} by `route-build-tree.ts`.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* One file's raw contents passed into the route extractor. Callers reading
|
|
17
|
+
* paths or globs off disk resolve them to this shape before calling into the
|
|
18
|
+
* core.
|
|
19
|
+
*/
|
|
20
|
+
export interface RouteSource {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly text: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Stable issue codes so consumers can suppress or interpret individual
|
|
26
|
+
* findings without string-matching the message text.
|
|
27
|
+
*/
|
|
28
|
+
export type RouteIssueCode = 'DUPLICATE_STATE_NAME' | 'CYCLE_DETECTED' | 'ORPHAN_STATE' | 'UNRESOLVED_COMPONENT' | 'DYNAMIC_STATE_NAME' | 'NO_STATES_FOUND';
|
|
29
|
+
/**
|
|
30
|
+
* Severity of a route issue. Errors fail the tool call (`isError: true`);
|
|
31
|
+
* warnings are surfaced but the tree still renders.
|
|
32
|
+
*/
|
|
33
|
+
export type RouteIssueSeverity = 'error' | 'warning' | 'info';
|
|
34
|
+
export interface RouteIssue {
|
|
35
|
+
readonly code: RouteIssueCode;
|
|
36
|
+
readonly severity: RouteIssueSeverity;
|
|
37
|
+
readonly message: string;
|
|
38
|
+
readonly file: string | undefined;
|
|
39
|
+
readonly line: number | undefined;
|
|
40
|
+
readonly stateName: string | undefined;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A single JSDoc tag captured from a state declaration's `export const`
|
|
44
|
+
* documentation. `name` is the tag name without the leading `@`
|
|
45
|
+
* (e.g. `dbxRouteModel`); `text` is the trimmed remainder of the tag line.
|
|
46
|
+
*/
|
|
47
|
+
export interface RouteNodeJsDocTag {
|
|
48
|
+
readonly name: string;
|
|
49
|
+
readonly text: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A single state declaration extracted from a `Ng2StateDeclaration` object
|
|
53
|
+
* literal. Field names mirror UIRouter's state-config shape; `name` is always
|
|
54
|
+
* populated, every other field is optional.
|
|
55
|
+
*
|
|
56
|
+
* `name` may carry a trailing `.**` (UIRouter future-state marker). We keep it
|
|
57
|
+
* verbatim for fidelity but strip the marker when computing parent linkage.
|
|
58
|
+
*/
|
|
59
|
+
export interface RouteNode {
|
|
60
|
+
readonly name: string;
|
|
61
|
+
readonly url: string | undefined;
|
|
62
|
+
readonly component: string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Explicit `parent` field if set; otherwise undefined (parent is derived from the dot-prefix of `name`).
|
|
65
|
+
*/
|
|
66
|
+
readonly explicitParent: string | undefined;
|
|
67
|
+
readonly redirectTo: string | undefined;
|
|
68
|
+
readonly abstract: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* `name` ends with `.**` — UIRouter lazy/future-state marker.
|
|
71
|
+
*/
|
|
72
|
+
readonly futureState: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Names of declared params (object keys only).
|
|
75
|
+
*/
|
|
76
|
+
readonly paramKeys: readonly string[];
|
|
77
|
+
/**
|
|
78
|
+
* Names of declared resolves (object keys, or array element identifiers).
|
|
79
|
+
*/
|
|
80
|
+
readonly resolveKeys: readonly string[];
|
|
81
|
+
/**
|
|
82
|
+
* Source file the state was defined in.
|
|
83
|
+
*/
|
|
84
|
+
readonly file: string;
|
|
85
|
+
readonly line: number;
|
|
86
|
+
/**
|
|
87
|
+
* Identifier of the `export const` (or `const`) the state object literal is
|
|
88
|
+
* assigned to, when the state was declared as `const FOO: Ng2StateDeclaration = { ... }`.
|
|
89
|
+
* `undefined` for inline literals inside a `STATES` array or
|
|
90
|
+
* `provideStates({ states: [...] })` call.
|
|
91
|
+
*/
|
|
92
|
+
readonly declaredAs: string | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* `@dbxRouteModel*` JSDoc tags captured from the declaring `export const`'s
|
|
95
|
+
* documentation, when the state was declared as a typed const. Used by the
|
|
96
|
+
* route-manifest builder to augment / override the component-level model
|
|
97
|
+
* annotations. `undefined` for inline literals or consts without route-model
|
|
98
|
+
* tags.
|
|
99
|
+
*/
|
|
100
|
+
readonly jsDocTags: readonly RouteNodeJsDocTag[] | undefined;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A node in the resolved {@link RouteTree}. Children are linked by a parent
|
|
104
|
+
* pass; the original {@link RouteNode} is preserved on `data`.
|
|
105
|
+
*/
|
|
106
|
+
export interface RouteTreeNode {
|
|
107
|
+
readonly data: RouteNode;
|
|
108
|
+
/**
|
|
109
|
+
* Composed URL from root → this node, or `undefined` if any segment is missing.
|
|
110
|
+
*/
|
|
111
|
+
readonly fullUrl: string | undefined;
|
|
112
|
+
readonly parent: RouteTreeNode | undefined;
|
|
113
|
+
readonly children: readonly RouteTreeNode[];
|
|
114
|
+
}
|
|
115
|
+
export interface RouteTree {
|
|
116
|
+
/**
|
|
117
|
+
* Top-level nodes (no resolvable parent in the source set).
|
|
118
|
+
*/
|
|
119
|
+
readonly roots: readonly RouteTreeNode[];
|
|
120
|
+
/**
|
|
121
|
+
* Every node, indexed by state name.
|
|
122
|
+
*/
|
|
123
|
+
readonly byName: ReadonlyMap<string, RouteTreeNode>;
|
|
124
|
+
/**
|
|
125
|
+
* Issues surfaced during extraction or tree building.
|
|
126
|
+
*/
|
|
127
|
+
readonly issues: readonly RouteIssue[];
|
|
128
|
+
/**
|
|
129
|
+
* Files actually parsed (after import-walking).
|
|
130
|
+
*/
|
|
131
|
+
readonly filesChecked: number;
|
|
132
|
+
/**
|
|
133
|
+
* Total nodes in the tree.
|
|
134
|
+
*/
|
|
135
|
+
readonly nodeCount: number;
|
|
136
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure URL ↔ route matcher, shared by the dev-server `dbx_route_resolve_url`
|
|
3
|
+
* tool and (mirrored, not imported) by the firebase-server/mcp `url-models`
|
|
4
|
+
* runtime tool.
|
|
5
|
+
*
|
|
6
|
+
* No ts-morph, no node:fs — operates on a flat list of candidates each carrying
|
|
7
|
+
* a composed `fullUrl` and an opaque `value`. Matching mirrors UIRouter's
|
|
8
|
+
* literal-then-param preference: a literal segment-for-segment match wins over a
|
|
9
|
+
* parameterised one, and ties at either tier collapse to an `ambiguous` result.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* One candidate fed to {@link matchUrlAgainstEntries}: a composed URL pattern
|
|
13
|
+
* plus the opaque payload to return when it matches.
|
|
14
|
+
*/
|
|
15
|
+
export interface UrlMatchEntry<T> {
|
|
16
|
+
readonly fullUrl: string | undefined;
|
|
17
|
+
readonly value: T;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A single resolved match. `via` distinguishes a literal path match from a
|
|
21
|
+
* parameterised one; `params` carries the captured `:param` / `{param}` values
|
|
22
|
+
* (empty for literal matches).
|
|
23
|
+
*/
|
|
24
|
+
export interface UrlMatchMatch<T> {
|
|
25
|
+
readonly kind: 'match';
|
|
26
|
+
readonly via: 'literal' | 'param';
|
|
27
|
+
readonly value: T;
|
|
28
|
+
readonly matchedFullUrl: string;
|
|
29
|
+
readonly params: Readonly<Record<string, string>>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* More than one candidate matched at the same tier; the caller must
|
|
33
|
+
* disambiguate (or report the tie).
|
|
34
|
+
*/
|
|
35
|
+
export interface UrlMatchAmbiguous<T> {
|
|
36
|
+
readonly kind: 'ambiguous';
|
|
37
|
+
readonly values: readonly T[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* No candidate matched. `candidates` holds the closest scored near-misses
|
|
41
|
+
* (top 5) for a "did you mean" style hint.
|
|
42
|
+
*/
|
|
43
|
+
export interface UrlMatchNone<T> {
|
|
44
|
+
readonly kind: 'none';
|
|
45
|
+
readonly candidates: readonly T[];
|
|
46
|
+
}
|
|
47
|
+
export type UrlMatchResult<T> = UrlMatchMatch<T> | UrlMatchAmbiguous<T> | UrlMatchNone<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Input to {@link matchUrlAgainstEntries}.
|
|
50
|
+
*/
|
|
51
|
+
export interface MatchUrlAgainstEntriesInput<T> {
|
|
52
|
+
readonly entries: readonly UrlMatchEntry<T>[];
|
|
53
|
+
readonly pathname: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Collapses an empty pathname to `/` and strips a single trailing slash so
|
|
57
|
+
* `/a/b/` and `/a/b` compare equal.
|
|
58
|
+
*
|
|
59
|
+
* @param pathname - The raw pathname to normalize.
|
|
60
|
+
* @returns The normalized pathname.
|
|
61
|
+
*/
|
|
62
|
+
export declare function normalizePathname(pathname: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Splits a path into its non-empty segments (the leading slash is dropped).
|
|
65
|
+
*
|
|
66
|
+
* @param path - The path or URL pattern to split.
|
|
67
|
+
* @returns The ordered segment list, empty for `/`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function splitSegments(path: string): readonly string[];
|
|
70
|
+
/**
|
|
71
|
+
* Whether a composed URL contains at least one `:param` or `{param}` segment.
|
|
72
|
+
*
|
|
73
|
+
* @param path - The composed URL pattern.
|
|
74
|
+
* @returns `true` when the pattern declares a parameter.
|
|
75
|
+
*/
|
|
76
|
+
export declare function hasParamSegment(path: string): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Attempts a segment-for-segment match of a route pattern against concrete
|
|
79
|
+
* input segments. `:name` and `{name}` / `{name:type}` segments capture the
|
|
80
|
+
* input value (URL-decoded); literal segments must match exactly.
|
|
81
|
+
*
|
|
82
|
+
* @param route - The route pattern's segments.
|
|
83
|
+
* @param input - The concrete URL's segments.
|
|
84
|
+
* @returns The captured params when every segment matches, else `undefined`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function tryMatchSegments(route: readonly string[], input: readonly string[]): Readonly<Record<string, string>> | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Extracts param-name segments from a composed UIRouter URL. Recognises:
|
|
89
|
+
* - `:name` (Express-style)
|
|
90
|
+
* - `{name}` (UIRouter type-less)
|
|
91
|
+
* - `{name:type}` and `{name:regex}` (UIRouter typed / regex)
|
|
92
|
+
* Order is preserved; duplicates are de-duplicated by first occurrence.
|
|
93
|
+
*
|
|
94
|
+
* @param fullUrl - Composed URL (e.g. `/{orgId}/users/:userId`) or undefined.
|
|
95
|
+
* @returns The param key list in declaration order, or an empty array.
|
|
96
|
+
*/
|
|
97
|
+
export declare function extractUrlParamKeys(fullUrl: string | undefined): readonly string[];
|
|
98
|
+
/**
|
|
99
|
+
* Matches a pathname against a flat candidate list, preferring a literal
|
|
100
|
+
* (exact composed-URL) match over a parameterised one. A tie at either tier
|
|
101
|
+
* collapses to `ambiguous`; otherwise the closest near-misses are scored and
|
|
102
|
+
* returned in a `none` result.
|
|
103
|
+
*
|
|
104
|
+
* @param input - The candidate entries and the pathname to resolve.
|
|
105
|
+
* @returns A discriminated match / ambiguous / none result.
|
|
106
|
+
*/
|
|
107
|
+
export declare function matchUrlAgainstEntries<T>(input: MatchUrlAgainstEntriesInput<T>): UrlMatchResult<T>;
|
|
108
|
+
/**
|
|
109
|
+
* Scores every candidate by shared leading segments (literal segment = 2,
|
|
110
|
+
* param segment = 1, mismatch stops scoring) and returns the top 5 values.
|
|
111
|
+
*
|
|
112
|
+
* @param entries - The candidate entries to score.
|
|
113
|
+
* @param pathname - The pathname being resolved.
|
|
114
|
+
* @returns Up to five closest candidate values, best first.
|
|
115
|
+
*/
|
|
116
|
+
export declare function scoreCandidates<T>(entries: readonly UrlMatchEntry<T>[], pathname: string): readonly T[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure ts-morph helpers shared by the two Firestore-model extractors that
|
|
3
|
+
* mirror `scripts/extract-firebase-models.mjs`: the rich `mcp-scan` walker in
|
|
4
|
+
* this package (`mcp-scan/scan/extract-models/*`) and the lightweight
|
|
5
|
+
* per-file walker in the `@dereekb/dbx-cli/manifest-extract` sub-lib. Both
|
|
6
|
+
* reimplemented the identical `firestoreModelIdentity(...)` argument parsing
|
|
7
|
+
* and `extends` passthrough-wrapper peeling; centralizing them here keeps the
|
|
8
|
+
* two extractors in lock-step without duplicating the logic.
|
|
9
|
+
*/
|
|
10
|
+
import { Node, type ExpressionWithTypeArguments } from 'ts-morph';
|
|
11
|
+
/**
|
|
12
|
+
* The model-type, collection-prefix, and parent-identity const parsed out of a
|
|
13
|
+
* `firestoreModelIdentity(...)` call by {@link parseFirestoreModelIdentityArgs}.
|
|
14
|
+
*/
|
|
15
|
+
export interface ParsedModelIdentityArgs {
|
|
16
|
+
readonly modelType: string;
|
|
17
|
+
readonly collectionPrefix: string | undefined;
|
|
18
|
+
readonly parentIdentityConst: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parses the arguments of a `firestoreModelIdentity(...)` call into its
|
|
22
|
+
* model-type / prefix / parent-identity parts, handling the 1/2/3-arg shapes:.
|
|
23
|
+
*
|
|
24
|
+
* • `firestoreModelIdentity('user')` → `modelType: 'user'`
|
|
25
|
+
* • `firestoreModelIdentity('storageFile', 'sf')` → `modelType: 'storageFile'`, `prefix: 'sf'`
|
|
26
|
+
* • `firestoreModelIdentity(notificationBoxIdentity, 'notification')` → `parent: 'notificationBoxIdentity'`, `modelType: 'notification'`
|
|
27
|
+
* • `firestoreModelIdentity(guestbookIdentity, 'guestbookEntry', 'gbe')` → all three
|
|
28
|
+
*
|
|
29
|
+
* @param args - The call's argument nodes (e.g. `call.getArguments()`).
|
|
30
|
+
* @returns The parsed parts, or `undefined` when the shape is unrecognisable.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseFirestoreModelIdentityArgs(args: readonly Node[]): ParsedModelIdentityArgs | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Resolves an `extends` clause to the concrete ancestor interface name,
|
|
35
|
+
* peeling any leading {@link PASSTHROUGH_TYPE_WRAPPERS}. Returns the leftmost
|
|
36
|
+
* identifier of the unwrapped expression so the inheritance walker can chain
|
|
37
|
+
* through utility-wrapped declarations like
|
|
38
|
+
* `extends Partial<MaybeMap<Omit<Base, '…'>>>`.
|
|
39
|
+
*
|
|
40
|
+
* @param expr - The `ExpressionWithTypeArguments` produced by `getExtends()`
|
|
41
|
+
* @returns The resolved interface name, or the original leftmost identifier when no inner reference is reachable.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveExtendsName(expr: ExpressionWithTypeArguments): string;
|
package/test/index.cjs.js
CHANGED
|
@@ -335,7 +335,7 @@ function _ts_generator(thisArg, body) {
|
|
|
335
335
|
case 2:
|
|
336
336
|
address = server.address();
|
|
337
337
|
port = (typeof address === "undefined" ? "undefined" : _type_of(address)) === 'object' && address ? address.port : 0;
|
|
338
|
-
trimmedPrefix = prefix.
|
|
338
|
+
trimmedPrefix = prefix.replaceAll(/^\/+|\/+$/g, '');
|
|
339
339
|
apiBaseUrl = trimmedPrefix.length > 0 ? "http://".concat(host, ":").concat(port, "/").concat(trimmedPrefix) : "http://".concat(host, ":").concat(port);
|
|
340
340
|
return [
|
|
341
341
|
2,
|
package/test/index.esm.js
CHANGED
|
@@ -333,7 +333,7 @@ function _ts_generator(thisArg, body) {
|
|
|
333
333
|
case 2:
|
|
334
334
|
address = server.address();
|
|
335
335
|
port = (typeof address === "undefined" ? "undefined" : _type_of(address)) === 'object' && address ? address.port : 0;
|
|
336
|
-
trimmedPrefix = prefix.
|
|
336
|
+
trimmedPrefix = prefix.replaceAll(/^\/+|\/+$/g, '');
|
|
337
337
|
apiBaseUrl = trimmedPrefix.length > 0 ? "http://".concat(host, ":").concat(port, "/").concat(trimmedPrefix) : "http://".concat(host, ":").concat(port);
|
|
338
338
|
return [
|
|
339
339
|
2,
|
package/test/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli/test",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.17.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/date": "13.
|
|
6
|
-
"@dereekb/dbx-cli": "13.
|
|
7
|
-
"@dereekb/firebase": "13.
|
|
8
|
-
"@dereekb/firebase-server/test": "13.
|
|
9
|
-
"@dereekb/model": "13.
|
|
10
|
-
"@dereekb/nestjs": "13.
|
|
11
|
-
"@dereekb/rxjs": "13.
|
|
12
|
-
"@dereekb/util": "13.
|
|
5
|
+
"@dereekb/date": "13.17.0",
|
|
6
|
+
"@dereekb/dbx-cli": "13.17.0",
|
|
7
|
+
"@dereekb/firebase": "13.17.0",
|
|
8
|
+
"@dereekb/firebase-server/test": "13.17.0",
|
|
9
|
+
"@dereekb/model": "13.17.0",
|
|
10
|
+
"@dereekb/nestjs": "13.17.0",
|
|
11
|
+
"@dereekb/rxjs": "13.17.0",
|
|
12
|
+
"@dereekb/util": "13.17.0",
|
|
13
13
|
"@nestjs/common": "^11.1.19",
|
|
14
14
|
"arktype": "^2.2.0",
|
|
15
15
|
"vitest": "4.1.5",
|