@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.
Files changed (46) hide show
  1. package/eslint/index.cjs.default.js +1 -0
  2. package/eslint/index.cjs.js +1050 -0
  3. package/eslint/index.cjs.mjs +2 -0
  4. package/eslint/index.d.ts +1 -0
  5. package/eslint/index.esm.js +1046 -0
  6. package/eslint/package.json +25 -0
  7. package/eslint/rollup.alias-internal.config.d.ts +11 -0
  8. package/eslint/src/index.d.ts +1 -0
  9. package/eslint/src/lib/index.d.ts +2 -0
  10. package/eslint/src/lib/plugin.d.ts +22 -0
  11. package/eslint/src/lib/valid-dbx-route-model-tags.rule.d.ts +59 -0
  12. package/firebase-api-manifest/main.js +318 -228
  13. package/firebase-api-manifest/package.json +3 -3
  14. package/generate-firestore-indexes/main.js +37 -24
  15. package/generate-firestore-indexes/package.json +2 -2
  16. package/generate-mcp-manifest/main.js +57 -39
  17. package/generate-mcp-manifest/package.json +3 -3
  18. package/generate-route-manifest/main.js +1137 -0
  19. package/generate-route-manifest/package.json +10 -0
  20. package/index.cjs.js +4847 -1953
  21. package/index.esm.js +4827 -1954
  22. package/lint-cache/package.json +2 -2
  23. package/manifest-extract/index.cjs.js +175 -240
  24. package/manifest-extract/index.esm.js +174 -239
  25. package/manifest-extract/package.json +9 -4
  26. package/package.json +16 -6
  27. package/src/lib/index.d.ts +2 -0
  28. package/src/lib/manifest/types.d.ts +53 -0
  29. package/src/lib/mcp-scan/manifest/package-root.d.ts +17 -0
  30. package/src/lib/mcp-scan/manifest/tokens-schema.d.ts +5 -4
  31. package/src/lib/mcp-scan/scan/extract-models/assemble.d.ts +17 -0
  32. package/src/lib/route/component-resolve.d.ts +48 -0
  33. package/src/lib/route/index.d.ts +18 -0
  34. package/src/lib/route/route-build-tree.d.ts +31 -0
  35. package/src/lib/route/route-extract.d.ts +46 -0
  36. package/src/lib/route/route-load-tree.d.ts +17 -0
  37. package/src/lib/route/route-manifest.d.ts +132 -0
  38. package/src/lib/route/route-model-tag.d.ts +89 -0
  39. package/src/lib/route/route-models-extract.d.ts +22 -0
  40. package/src/lib/route/route-resolve-sources.d.ts +39 -0
  41. package/src/lib/route/route-types.d.ts +136 -0
  42. package/src/lib/route/url-match.d.ts +116 -0
  43. package/src/lib/scan-helpers/firestore-model-extract-utils.d.ts +43 -0
  44. package/test/index.cjs.js +1 -1
  45. package/test/index.esm.js +1 -1
  46. 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.replace(/^\/+|\/+$/g, '');
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.replace(/^\/+|\/+$/g, '');
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.15.0",
3
+ "version": "13.17.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.15.0",
6
- "@dereekb/dbx-cli": "13.15.0",
7
- "@dereekb/firebase": "13.15.0",
8
- "@dereekb/firebase-server/test": "13.15.0",
9
- "@dereekb/model": "13.15.0",
10
- "@dereekb/nestjs": "13.15.0",
11
- "@dereekb/rxjs": "13.15.0",
12
- "@dereekb/util": "13.15.0",
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",