@facilis.dev/analyze 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +18 -2
- package/dist/analyze.d.ts +17 -0
- package/dist/analyze.js +99 -0
- package/dist/ast/node.d.ts +29 -0
- package/dist/ast/node.js +85 -0
- package/dist/ast/walk.d.ts +8 -0
- package/dist/ast/walk.js +40 -0
- package/dist/diagnostics.d.ts +5 -0
- package/dist/diagnostics.js +12 -0
- package/dist/fs.d.ts +13 -0
- package/dist/fs.js +51 -0
- package/dist/graph-edges.d.ts +3 -0
- package/dist/graph-edges.js +148 -0
- package/dist/graph-ids.d.ts +6 -0
- package/dist/graph-ids.js +22 -0
- package/dist/graph.d.ts +15 -0
- package/dist/graph.js +158 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +15 -0
- package/dist/json.d.ts +8 -0
- package/dist/json.js +31 -0
- package/dist/module-graph.d.ts +33 -0
- package/dist/module-graph.js +86 -0
- package/dist/module-info.d.ts +27 -0
- package/dist/module-info.js +143 -0
- package/dist/node.d.ts +16 -0
- package/dist/node.js +41 -0
- package/dist/parser.d.ts +16 -0
- package/dist/parser.js +1 -0
- package/dist/passes/clients.d.ts +22 -0
- package/dist/passes/clients.js +167 -0
- package/dist/passes/config.d.ts +16 -0
- package/dist/passes/config.js +229 -0
- package/dist/passes/file-facts.d.ts +13 -0
- package/dist/passes/file-facts.js +130 -0
- package/dist/passes/i18n.d.ts +14 -0
- package/dist/passes/i18n.js +55 -0
- package/dist/passes/job-relations-diagnostics.d.ts +9 -0
- package/dist/passes/job-relations-diagnostics.js +38 -0
- package/dist/passes/job-relations.d.ts +18 -0
- package/dist/passes/job-relations.js +52 -0
- package/dist/passes/jobs.d.ts +20 -0
- package/dist/passes/jobs.js +133 -0
- package/dist/passes/jsx.d.ts +22 -0
- package/dist/passes/jsx.js +89 -0
- package/dist/passes/path-expression.d.ts +26 -0
- package/dist/passes/path-expression.js +265 -0
- package/dist/passes/route-config.d.ts +24 -0
- package/dist/passes/route-config.js +152 -0
- package/dist/passes/route-description.d.ts +13 -0
- package/dist/passes/route-description.js +23 -0
- package/dist/passes/route-elevation.d.ts +18 -0
- package/dist/passes/route-elevation.js +136 -0
- package/dist/passes/route-handler.d.ts +27 -0
- package/dist/passes/route-handler.js +87 -0
- package/dist/passes/route-location.d.ts +16 -0
- package/dist/passes/route-location.js +58 -0
- package/dist/passes/route-relation-resolve.d.ts +51 -0
- package/dist/passes/route-relation-resolve.js +172 -0
- package/dist/passes/route-relations-diagnostics.d.ts +15 -0
- package/dist/passes/route-relations-diagnostics.js +79 -0
- package/dist/passes/route-relations-follow.d.ts +16 -0
- package/dist/passes/route-relations-follow.js +116 -0
- package/dist/passes/route-relations-usage.d.ts +50 -0
- package/dist/passes/route-relations-usage.js +44 -0
- package/dist/passes/route-relations-walk.d.ts +25 -0
- package/dist/passes/route-relations-walk.js +199 -0
- package/dist/passes/route-relations.d.ts +17 -0
- package/dist/passes/route-relations.js +43 -0
- package/dist/passes/route-table.d.ts +21 -0
- package/dist/passes/route-table.js +104 -0
- package/dist/passes/route-tables.d.ts +10 -0
- package/dist/passes/route-tables.js +42 -0
- package/dist/passes/routes.d.ts +18 -0
- package/dist/passes/routes.js +152 -0
- package/dist/passes/schema-column-types.d.ts +9 -0
- package/dist/passes/schema-column-types.js +55 -0
- package/dist/passes/schema-columns.d.ts +35 -0
- package/dist/passes/schema-columns.js +197 -0
- package/dist/passes/schema-dsl.d.ts +24 -0
- package/dist/passes/schema-dsl.js +117 -0
- package/dist/passes/schema-file-links-ddl.d.ts +18 -0
- package/dist/passes/schema-file-links-ddl.js +106 -0
- package/dist/passes/schema-file-links.d.ts +19 -0
- package/dist/passes/schema-file-links.js +144 -0
- package/dist/passes/schema-foreign-keys.d.ts +21 -0
- package/dist/passes/schema-foreign-keys.js +80 -0
- package/dist/passes/schema-policies.d.ts +15 -0
- package/dist/passes/schema-policies.js +201 -0
- package/dist/passes/schema-re-exports.d.ts +5 -0
- package/dist/passes/schema-re-exports.js +77 -0
- package/dist/passes/schema-relations.d.ts +8 -0
- package/dist/passes/schema-relations.js +182 -0
- package/dist/passes/schema-scope.d.ts +7 -0
- package/dist/passes/schema-scope.js +20 -0
- package/dist/passes/schema-tables.d.ts +13 -0
- package/dist/passes/schema-tables.js +149 -0
- package/dist/passes/schema.d.ts +9 -0
- package/dist/passes/schema.js +55 -0
- package/dist/passes/screen-components.d.ts +22 -0
- package/dist/passes/screen-components.js +143 -0
- package/dist/passes/screen-preview.d.ts +29 -0
- package/dist/passes/screen-preview.js +159 -0
- package/dist/passes/screens.d.ts +12 -0
- package/dist/passes/screens.js +278 -0
- package/dist/passes/static-read.d.ts +47 -0
- package/dist/passes/static-read.js +151 -0
- package/dist/passes/views.d.ts +20 -0
- package/dist/passes/views.js +101 -0
- package/dist/passes/workflow-tables.d.ts +18 -0
- package/dist/passes/workflow-tables.js +71 -0
- package/dist/passes/workflows.d.ts +8 -0
- package/dist/passes/workflows.js +160 -0
- package/dist/path-resolver.d.ts +20 -0
- package/dist/path-resolver.js +134 -0
- package/dist/revision.d.ts +2 -0
- package/dist/revision.js +23 -0
- package/dist/source.d.ts +4 -0
- package/dist/source.js +13 -0
- package/dist/static-eval.d.ts +36 -0
- package/dist/static-eval.js +215 -0
- package/dist/types-graph.d.ts +130 -0
- package/dist/types-graph.js +4 -0
- package/dist/types-jobs.d.ts +28 -0
- package/dist/types-jobs.js +14 -0
- package/dist/types-relations.d.ts +49 -0
- package/dist/types-relations.js +11 -0
- package/dist/types-workflows.d.ts +36 -0
- package/dist/types-workflows.js +3 -0
- package/dist/types.d.ts +226 -0
- package/dist/types.js +1 -0
- package/package.json +49 -4
- package/src/analyze.ts +119 -0
- package/src/ast/node.ts +102 -0
- package/src/ast/walk.ts +37 -0
- package/src/diagnostics.ts +22 -0
- package/src/fs.ts +59 -0
- package/src/graph-edges.ts +167 -0
- package/src/graph-ids.ts +31 -0
- package/src/graph.ts +190 -0
- package/src/index.ts +24 -0
- package/src/json.ts +34 -0
- package/src/module-graph.ts +117 -0
- package/src/module-info.ts +162 -0
- package/src/node.ts +54 -0
- package/src/parser.ts +19 -0
- package/src/passes/clients.ts +233 -0
- package/src/passes/config.ts +278 -0
- package/src/passes/file-facts.ts +142 -0
- package/src/passes/i18n.ts +66 -0
- package/src/passes/job-relations-diagnostics.ts +60 -0
- package/src/passes/job-relations.ts +76 -0
- package/src/passes/jobs.ts +181 -0
- package/src/passes/jsx.ts +92 -0
- package/src/passes/path-expression.ts +297 -0
- package/src/passes/route-config.ts +188 -0
- package/src/passes/route-description.ts +33 -0
- package/src/passes/route-elevation.ts +161 -0
- package/src/passes/route-handler.ts +105 -0
- package/src/passes/route-location.ts +62 -0
- package/src/passes/route-relation-resolve.ts +228 -0
- package/src/passes/route-relations-diagnostics.ts +115 -0
- package/src/passes/route-relations-follow.ts +146 -0
- package/src/passes/route-relations-usage.ts +98 -0
- package/src/passes/route-relations-walk.ts +255 -0
- package/src/passes/route-relations.ts +62 -0
- package/src/passes/route-table.ts +123 -0
- package/src/passes/route-tables.ts +50 -0
- package/src/passes/routes.ts +188 -0
- package/src/passes/schema-column-types.ts +62 -0
- package/src/passes/schema-columns.ts +287 -0
- package/src/passes/schema-dsl.ts +136 -0
- package/src/passes/schema-file-links-ddl.ts +125 -0
- package/src/passes/schema-file-links.ts +213 -0
- package/src/passes/schema-foreign-keys.ts +121 -0
- package/src/passes/schema-policies.ts +270 -0
- package/src/passes/schema-re-exports.ts +95 -0
- package/src/passes/schema-relations.ts +239 -0
- package/src/passes/schema-scope.ts +29 -0
- package/src/passes/schema-tables.ts +216 -0
- package/src/passes/schema.ts +67 -0
- package/src/passes/screen-components.ts +162 -0
- package/src/passes/screen-preview.ts +268 -0
- package/src/passes/screens.ts +291 -0
- package/src/passes/static-read.ts +196 -0
- package/src/passes/views.ts +125 -0
- package/src/passes/workflow-tables.ts +87 -0
- package/src/passes/workflows.ts +213 -0
- package/src/path-resolver.ts +146 -0
- package/src/revision.ts +25 -0
- package/src/source.ts +15 -0
- package/src/static-eval.ts +242 -0
- package/src/types-graph.ts +161 -0
- package/src/types-jobs.ts +40 -0
- package/src/types-relations.ts +64 -0
- package/src/types-workflows.ts +42 -0
- package/src/types.ts +299 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Graph-facing fact shapes (the project graph's public model), split from types.ts so the
|
|
2
|
+
// base fact model stays under the 300-line source limit. Static screen preview/link facts live
|
|
3
|
+
// here too because they are attached to page nodes and page-link edges.
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
ColumnFact,
|
|
7
|
+
ElevationFact,
|
|
8
|
+
HttpMethod,
|
|
9
|
+
PageKind,
|
|
10
|
+
RouteInputFact,
|
|
11
|
+
ScopeFact,
|
|
12
|
+
SourceRef,
|
|
13
|
+
WrapperState,
|
|
14
|
+
} from "./types.ts";
|
|
15
|
+
|
|
16
|
+
export type GraphNodeKind = "page" | "route" | "table" | "view" | "workflow";
|
|
17
|
+
|
|
18
|
+
export interface PageNodeData {
|
|
19
|
+
readonly kind: "page";
|
|
20
|
+
readonly pagePath: string;
|
|
21
|
+
readonly pageKind: PageKind;
|
|
22
|
+
readonly callCount: number;
|
|
23
|
+
/** URL paths from the explicit route table; absent when the page is unrouted. */
|
|
24
|
+
readonly routePaths?: readonly string[];
|
|
25
|
+
/** Static component structure used by the graph's page inspector. */
|
|
26
|
+
readonly preview?: PagePreview;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface RouteNodeData {
|
|
30
|
+
readonly kind: "route";
|
|
31
|
+
readonly method: HttpMethod;
|
|
32
|
+
readonly path: string;
|
|
33
|
+
readonly permission: readonly string[];
|
|
34
|
+
readonly wrapper: WrapperState;
|
|
35
|
+
/** Presence of the handler's input schemas (body/form/query/params), from the AST. */
|
|
36
|
+
readonly input: RouteInputFact;
|
|
37
|
+
readonly dbTables: readonly string[];
|
|
38
|
+
readonly dbColumns: readonly string[];
|
|
39
|
+
/** Audited sudo/system calls, carried for the graph's elevation badge. */
|
|
40
|
+
readonly elevations?: readonly ElevationFact[];
|
|
41
|
+
/** The wrapper config's one-sentence description, or null when absent (D-129). */
|
|
42
|
+
readonly description: string | null;
|
|
43
|
+
readonly unknown: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface TableNodeData {
|
|
47
|
+
readonly kind: "table";
|
|
48
|
+
readonly table: string;
|
|
49
|
+
readonly columns: readonly ColumnFact[];
|
|
50
|
+
readonly rlsEnabled: boolean;
|
|
51
|
+
readonly scope: ScopeFact | null;
|
|
52
|
+
/**
|
|
53
|
+
* True when an installed @facilis.dev package declares the table and the project only
|
|
54
|
+
* re-exports it: its source file lives under `node_modules/`.
|
|
55
|
+
*/
|
|
56
|
+
readonly framework: boolean;
|
|
57
|
+
readonly unknown: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A declarative view declared with defineView under db/views (D-097/D-098, D-160). */
|
|
61
|
+
export interface ViewNodeData {
|
|
62
|
+
readonly kind: "view";
|
|
63
|
+
/** The view's SQL name: what a route declares in `dbTables` (D-157). */
|
|
64
|
+
readonly view: string;
|
|
65
|
+
/** Base tables named by the declaration (metadata only, D-097); [] when absent. */
|
|
66
|
+
readonly tables: readonly string[];
|
|
67
|
+
/** The view's own permission; null keeps the invoker behaviour (D-098). */
|
|
68
|
+
readonly permission: string | null;
|
|
69
|
+
/** null when a declared permission could not be read, so the mode is unknown. */
|
|
70
|
+
readonly access: "invoker" | "definer" | null;
|
|
71
|
+
readonly unknown: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** One step of a workflow definition, as the graph inspector shows it. */
|
|
75
|
+
export interface WorkflowStepNodeData {
|
|
76
|
+
readonly index: number;
|
|
77
|
+
readonly kind: "job" | "approval";
|
|
78
|
+
/** Job name or approval title key; null when the definition could not be read. */
|
|
79
|
+
readonly name: string | null;
|
|
80
|
+
readonly permission: string | null;
|
|
81
|
+
/** Forward step index declared by `onReject.step`, when present. */
|
|
82
|
+
readonly onRejectStep: number | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** A workflow definition read from `server/workflows/**` (D-135 W3). */
|
|
86
|
+
export interface WorkflowNodeData {
|
|
87
|
+
readonly kind: "workflow";
|
|
88
|
+
readonly name: string;
|
|
89
|
+
readonly steps: readonly WorkflowStepNodeData[];
|
|
90
|
+
readonly unknown: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type GraphNodeData =
|
|
94
|
+
PageNodeData | RouteNodeData | TableNodeData | ViewNodeData | WorkflowNodeData;
|
|
95
|
+
|
|
96
|
+
export interface GraphNode {
|
|
97
|
+
readonly id: string;
|
|
98
|
+
readonly kind: GraphNodeKind;
|
|
99
|
+
readonly label: string;
|
|
100
|
+
readonly sourceFile: string | null;
|
|
101
|
+
readonly data: GraphNodeData;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type GraphEdgeKind =
|
|
105
|
+
"fk" | "relation" | "route-table" | "page-route" | "page-link" | "route-view" | "view-base";
|
|
106
|
+
|
|
107
|
+
export interface GraphEdge {
|
|
108
|
+
readonly id: string;
|
|
109
|
+
readonly kind: GraphEdgeKind;
|
|
110
|
+
readonly source: string;
|
|
111
|
+
readonly target: string;
|
|
112
|
+
readonly label: string | null;
|
|
113
|
+
/** A route-table/route-view edge reached through audited sudo/system elevation. */
|
|
114
|
+
readonly access?: "elevated";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface ProjectGraph {
|
|
118
|
+
readonly nodes: readonly GraphNode[];
|
|
119
|
+
readonly edges: readonly GraphEdge[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** One node of the bounded static structure preview attached to a page. */
|
|
123
|
+
export interface PagePreviewNode {
|
|
124
|
+
readonly id: string;
|
|
125
|
+
readonly parentId: string | null;
|
|
126
|
+
/** Component name as written in the JSX (`TodosPage`, `Page`, `header`). */
|
|
127
|
+
readonly name: string;
|
|
128
|
+
readonly kind: "component" | "intrinsic" | "slot";
|
|
129
|
+
/** Project file that defines the component, when it can be resolved statically. */
|
|
130
|
+
readonly file: string | null;
|
|
131
|
+
readonly source: SourceRef;
|
|
132
|
+
/** True when the node sits under a conditional/map branch. */
|
|
133
|
+
readonly dynamic: boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Static component structure of one page, capped by the analyzer. */
|
|
137
|
+
export interface PagePreview {
|
|
138
|
+
/** URL paths resolved from the explicit route table. */
|
|
139
|
+
readonly routePaths: readonly string[];
|
|
140
|
+
readonly nodes: readonly PagePreviewNode[];
|
|
141
|
+
/** True when the maximum depth/node budget cut the structure. */
|
|
142
|
+
readonly truncated: boolean;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** An explicit client-side navigation target (`Link`, `NavLink`, `navigate()`). */
|
|
146
|
+
export interface PageLink {
|
|
147
|
+
/** Page file that renders the link. */
|
|
148
|
+
readonly from: string;
|
|
149
|
+
/** Target page file, resolved through the route table. */
|
|
150
|
+
readonly to: string;
|
|
151
|
+
/** URL path written in the source, for the edge label. */
|
|
152
|
+
readonly toPath: string;
|
|
153
|
+
readonly kind: "link" | "navlink" | "navigate";
|
|
154
|
+
readonly source: SourceRef;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Static screen facts consumed by the graph builder (not a separate analysis output). */
|
|
158
|
+
export interface ScreenFacts {
|
|
159
|
+
readonly previews: Readonly<Record<string, PagePreview>>;
|
|
160
|
+
readonly links: readonly PageLink[];
|
|
161
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Background-job fact model, split from types.ts so the base fact model stays under the
|
|
2
|
+
// 300-line source limit. A job always runs system-scoped (D-107), so D-157 applies to its
|
|
3
|
+
// `db` client without the elevation dimension routes have: no `ctx.sudo`/`ctx.system`.
|
|
4
|
+
|
|
5
|
+
import type { RouteRelationUse } from "./types-relations.ts";
|
|
6
|
+
import type { SourceRef, UnknownFact } from "./types.ts";
|
|
7
|
+
|
|
8
|
+
/** One `server/jobs/**` definition: the `defineJob({...})` default export. */
|
|
9
|
+
export interface JobFact {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly sourceFile: string;
|
|
12
|
+
readonly source: SourceRef;
|
|
13
|
+
/** Relations the definition declares; null when not statically readable (D-157). */
|
|
14
|
+
readonly dbTables: readonly string[] | null;
|
|
15
|
+
/** true allows `db.execute`; false when absent; null when unreadable (fail closed). */
|
|
16
|
+
readonly rawSql: boolean | null;
|
|
17
|
+
readonly unknown: readonly UnknownFact[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Static db usage of one job's `run(ctx)` body, following project-local calls (D-157). */
|
|
21
|
+
export interface JobRelationsFact {
|
|
22
|
+
readonly used: readonly RouteRelationUse[];
|
|
23
|
+
readonly unresolved: readonly SourceRef[];
|
|
24
|
+
/** `db.execute(...)` call sites; legal only with rawSql: true. */
|
|
25
|
+
readonly rawSql: readonly SourceRef[];
|
|
26
|
+
/** A project-external callee received the job's db client, so usage is incomplete. */
|
|
27
|
+
readonly opaque: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Usage of a job whose `run` the pass cannot inspect: explicitly empty, never guessed.
|
|
32
|
+
* `opaque` is true because "not observed" must not be reported as "never used" (the
|
|
33
|
+
* declared-but-unused warning and the AI rule both suppress on it).
|
|
34
|
+
*/
|
|
35
|
+
export const EMPTY_JOB_RELATIONS: JobRelationsFact = {
|
|
36
|
+
used: [],
|
|
37
|
+
unresolved: [],
|
|
38
|
+
rawSql: [],
|
|
39
|
+
opaque: true,
|
|
40
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Route relation-usage and view facts (D-157), split from types.ts so the base fact model
|
|
2
|
+
// stays under the 300-line source limit. A fact that cannot be determined is explicit:
|
|
3
|
+
// an empty usage is "nothing observed", never "nothing to check".
|
|
4
|
+
|
|
5
|
+
import type { ElevationKind, SourceRef, UnknownFact } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
/** A view declared with defineView under db/views/ (D-097/D-098). Not a graph node (D-157). */
|
|
8
|
+
export interface ViewFact {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
/** TypeScript binding holding the view, when declared as a const. */
|
|
11
|
+
readonly binding: string | null;
|
|
12
|
+
/** Base tables named by the declaration (metadata only, D-097); [] when absent. */
|
|
13
|
+
readonly tables: readonly string[];
|
|
14
|
+
/** The view's own permission; null keeps the invoker behaviour (D-098). */
|
|
15
|
+
readonly permission: string | null;
|
|
16
|
+
/** null when a declared permission could not be read, so the mode is unknown. */
|
|
17
|
+
readonly access: "invoker" | "definer" | null;
|
|
18
|
+
readonly source: SourceRef;
|
|
19
|
+
readonly unknown: readonly UnknownFact[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** One relation (table or view) a route reaches through a db client. */
|
|
23
|
+
export interface RouteRelationUse {
|
|
24
|
+
readonly name: string;
|
|
25
|
+
/** The use site, so a finding can jump to the expression. */
|
|
26
|
+
readonly source: SourceRef;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** What one audited elevation callback reaches through its elevated db client (D-157). */
|
|
30
|
+
export interface RouteElevationUsage {
|
|
31
|
+
readonly kind: ElevationKind;
|
|
32
|
+
/** The ctx.sudo / ctx.system call site. */
|
|
33
|
+
readonly source: SourceRef;
|
|
34
|
+
/** The elevation's own `tables` option; [] when unknown. */
|
|
35
|
+
readonly tables: readonly string[];
|
|
36
|
+
readonly used: readonly RouteRelationUse[];
|
|
37
|
+
readonly unresolved: readonly SourceRef[];
|
|
38
|
+
/** The elevation's `tables` option is missing or not statically readable. */
|
|
39
|
+
readonly tablesUnknown: boolean;
|
|
40
|
+
/** The elevated client reached a callee outside the project graph. */
|
|
41
|
+
readonly opaque: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Static db usage of one route handler, following project-local helper calls (D-157). */
|
|
45
|
+
export interface RouteRelationsFact {
|
|
46
|
+
/** Relations reached through ctx.db outside elevations, deduplicated by name. */
|
|
47
|
+
readonly used: readonly RouteRelationUse[];
|
|
48
|
+
/** Dynamic/unresolvable relation expressions, and uses the pass could not inspect. */
|
|
49
|
+
readonly unresolved: readonly SourceRef[];
|
|
50
|
+
/** `db.execute(...)` call sites; legal only with rawSql: true. */
|
|
51
|
+
readonly rawSql: readonly SourceRef[];
|
|
52
|
+
/** A project-external callee received the route's db client, so usage is incomplete. */
|
|
53
|
+
readonly opaque: boolean;
|
|
54
|
+
readonly elevations: readonly RouteElevationUsage[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Usage of a route the pass cannot scan (invalid wrapper): explicitly empty, not unknown. */
|
|
58
|
+
export const EMPTY_ROUTE_RELATIONS: RouteRelationsFact = {
|
|
59
|
+
used: [],
|
|
60
|
+
unresolved: [],
|
|
61
|
+
rawSql: [],
|
|
62
|
+
opaque: false,
|
|
63
|
+
elevations: [],
|
|
64
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Workflow fact shapes, split from types.ts so the base fact model stays under the 300-line
|
|
2
|
+
// source limit (D-135 W3). They are re-exported from types.ts, so existing imports keep working.
|
|
3
|
+
|
|
4
|
+
import type { SourceRef, UnknownFact } from "./types.ts";
|
|
5
|
+
|
|
6
|
+
/** One step of a `defineWorkflow` chain, as the static subset reads it. */
|
|
7
|
+
export interface WorkflowStepFact {
|
|
8
|
+
readonly index: number;
|
|
9
|
+
readonly kind: "job" | "approval";
|
|
10
|
+
/** Job name for a job step, approval title key for an approval step. */
|
|
11
|
+
readonly name: string | null;
|
|
12
|
+
/** Approval assignment permission, when the definition declares one. */
|
|
13
|
+
readonly permission: string | null;
|
|
14
|
+
/** Forward step index declared by `onReject.step`, when present. */
|
|
15
|
+
readonly onRejectStep: number | null;
|
|
16
|
+
readonly source: SourceRef;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** One `server/workflows/**` definition. */
|
|
20
|
+
export interface WorkflowFact {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly sourceFile: string;
|
|
23
|
+
readonly source: SourceRef;
|
|
24
|
+
readonly steps: readonly WorkflowStepFact[];
|
|
25
|
+
readonly unknown: readonly UnknownFact[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Table surface of a workflow, derived from the jobs its steps reference (never declared):
|
|
30
|
+
* the sorted union of the referenced jobs' own `dbTables` (tables and views alike).
|
|
31
|
+
*/
|
|
32
|
+
export interface WorkflowTablesFact {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly sourceFile: string;
|
|
35
|
+
readonly source: SourceRef;
|
|
36
|
+
/** Sorted unique union of the referenced jobs' declared dbTables. */
|
|
37
|
+
readonly tables: readonly string[];
|
|
38
|
+
/** Job-step names with no definition under `server/jobs/**`; [] when all resolve. */
|
|
39
|
+
readonly unknownJobs: readonly string[];
|
|
40
|
+
/** True when a referenced job's dbTables is unreadable, so the union is incomplete. */
|
|
41
|
+
readonly unknown: boolean;
|
|
42
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import type { JobFact, JobRelationsFact } from "./types-jobs.ts";
|
|
2
|
+
import type { RouteRelationsFact, ViewFact } from "./types-relations.ts";
|
|
3
|
+
import type { ProjectGraph } from "./types-graph.ts";
|
|
4
|
+
import type { WorkflowFact, WorkflowTablesFact } from "./types-workflows.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Fact model of the AST analyzer (docs/findings/ast-dsl-contract.md).
|
|
8
|
+
*
|
|
9
|
+
* Facts are parser-independent and always carry their source. A fact that cannot be
|
|
10
|
+
* determined is represented explicitly (null or an unknown entry), never as an empty value:
|
|
11
|
+
* in particular "dbTables unknown" (null) is not "no DB tables" ([]).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export interface SourceRef {
|
|
15
|
+
readonly file: string;
|
|
16
|
+
readonly line: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UnknownFact {
|
|
20
|
+
readonly code: string;
|
|
21
|
+
readonly reason: string;
|
|
22
|
+
readonly source: SourceRef;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type Severity = "error" | "warning" | "info";
|
|
26
|
+
|
|
27
|
+
export interface Diagnostic {
|
|
28
|
+
readonly code: string;
|
|
29
|
+
readonly severity: Severity;
|
|
30
|
+
readonly message: string;
|
|
31
|
+
readonly source: SourceRef | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface LocaleCatalogs {
|
|
35
|
+
readonly [locale: string]: Readonly<Record<string, string>>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ── config ──────────────────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
export interface ConfigFacts {
|
|
41
|
+
readonly parsed: boolean;
|
|
42
|
+
readonly source: SourceRef | null;
|
|
43
|
+
readonly permissions: readonly string[];
|
|
44
|
+
readonly roles: Readonly<Record<string, readonly string[]>>;
|
|
45
|
+
readonly defaultRole: string | null;
|
|
46
|
+
readonly defaultLocale: string | null;
|
|
47
|
+
readonly locales: readonly string[];
|
|
48
|
+
readonly migrationsDir: string;
|
|
49
|
+
readonly tenantColumns: readonly string[];
|
|
50
|
+
readonly ownerColumns: readonly string[];
|
|
51
|
+
readonly unknown: readonly UnknownFact[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── schema ──────────────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
export type ColumnDefaultKind = "literal" | "now" | "random" | "unknown";
|
|
57
|
+
|
|
58
|
+
export interface ColumnDefaultFact {
|
|
59
|
+
readonly kind: ColumnDefaultKind;
|
|
60
|
+
readonly value: string | null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ForeignKeyFact {
|
|
64
|
+
readonly columns: readonly string[];
|
|
65
|
+
readonly targetTable: string;
|
|
66
|
+
readonly targetColumns: readonly string[];
|
|
67
|
+
readonly onDelete: string | null;
|
|
68
|
+
readonly onUpdate: string | null;
|
|
69
|
+
readonly source: SourceRef;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ColumnFact {
|
|
73
|
+
/** Drizzle property key in the table object (the dbColumns domain). */
|
|
74
|
+
readonly property: string;
|
|
75
|
+
/** SQL column name (first literal argument of the builder, or the property key). */
|
|
76
|
+
readonly name: string;
|
|
77
|
+
readonly builder: string;
|
|
78
|
+
/** Display type derived from the builder and its arguments. */
|
|
79
|
+
readonly type: string;
|
|
80
|
+
readonly notNull: boolean;
|
|
81
|
+
readonly primaryKey: boolean;
|
|
82
|
+
readonly unique: boolean;
|
|
83
|
+
readonly default: ColumnDefaultFact | null;
|
|
84
|
+
readonly source: SourceRef;
|
|
85
|
+
readonly unknown: readonly UnknownFact[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type PolicyCommand = "SELECT" | "INSERT" | "UPDATE" | "DELETE" | "ALL";
|
|
89
|
+
|
|
90
|
+
export interface PolicyFact {
|
|
91
|
+
readonly name: string;
|
|
92
|
+
readonly command: PolicyCommand;
|
|
93
|
+
readonly restrictive: boolean;
|
|
94
|
+
readonly source: SourceRef;
|
|
95
|
+
readonly unknown: readonly UnknownFact[];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface ScopeFact {
|
|
99
|
+
readonly column: string;
|
|
100
|
+
readonly kind: "tenant" | "owner";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface TableFact {
|
|
104
|
+
readonly name: string;
|
|
105
|
+
/** TypeScript binding holding the table, when declared as a const. */
|
|
106
|
+
readonly binding: string | null;
|
|
107
|
+
readonly columns: readonly ColumnFact[];
|
|
108
|
+
readonly primaryKey: readonly string[];
|
|
109
|
+
readonly foreignKeys: readonly ForeignKeyFact[];
|
|
110
|
+
readonly policies: readonly PolicyFact[];
|
|
111
|
+
readonly rlsEnabled: boolean;
|
|
112
|
+
readonly scope: ScopeFact | null;
|
|
113
|
+
readonly source: SourceRef;
|
|
114
|
+
readonly unknown: readonly UnknownFact[];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface RelationFact {
|
|
118
|
+
readonly from: string;
|
|
119
|
+
readonly to: string;
|
|
120
|
+
readonly cardinality: "one" | "many";
|
|
121
|
+
readonly fields: readonly string[];
|
|
122
|
+
readonly references: readonly string[];
|
|
123
|
+
readonly source: SourceRef;
|
|
124
|
+
readonly unknown: readonly UnknownFact[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── routes ─────────────────────────────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
export type HttpMethod =
|
|
130
|
+
"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "TRACE" | "CONNECT" | "ALL";
|
|
131
|
+
|
|
132
|
+
export type WrapperState = "valid" | "invalid" | "unknown";
|
|
133
|
+
|
|
134
|
+
export interface RouteInputFact {
|
|
135
|
+
readonly body: boolean;
|
|
136
|
+
/** A multipart/form-data schema (D-053); mutually exclusive with `body`. */
|
|
137
|
+
readonly form: boolean;
|
|
138
|
+
readonly query: boolean;
|
|
139
|
+
readonly params: boolean;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export type ElevationKind = "sudo" | "system";
|
|
143
|
+
|
|
144
|
+
/** One audited elevation call in a route handler (D-099): `ctx.sudo` / `ctx.system`. */
|
|
145
|
+
export interface ElevationFact {
|
|
146
|
+
readonly kind: ElevationKind;
|
|
147
|
+
/** Tables passed to the elevation; [] when the array cannot be read statically. */
|
|
148
|
+
readonly tables: readonly string[];
|
|
149
|
+
/** The audit operation label, when statically readable. */
|
|
150
|
+
readonly operation: string | null;
|
|
151
|
+
readonly source: SourceRef;
|
|
152
|
+
readonly unknown: readonly UnknownFact[];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface RouteFact {
|
|
156
|
+
readonly method: HttpMethod;
|
|
157
|
+
readonly path: string;
|
|
158
|
+
readonly sourceFile: string;
|
|
159
|
+
readonly source: SourceRef;
|
|
160
|
+
readonly wrapper: WrapperState;
|
|
161
|
+
/** null = unknown; [] = explicitly public. */
|
|
162
|
+
readonly permission: readonly string[] | null;
|
|
163
|
+
/**
|
|
164
|
+
* True when the wrapper declares the route callable from another origin; false when absent;
|
|
165
|
+
* null when the declaration cannot be read statically (a cross-origin route is never assumed).
|
|
166
|
+
*/
|
|
167
|
+
readonly crossSite: boolean | null;
|
|
168
|
+
/** null = unknown; [] = explicitly no DB. */
|
|
169
|
+
readonly dbTables: readonly string[] | null;
|
|
170
|
+
/** null = unknown; [] = explicitly no columns. */
|
|
171
|
+
readonly dbColumns: readonly string[] | null;
|
|
172
|
+
/** rawSql: true allows `db.execute` (D-157); false when absent; null when unreadable. */
|
|
173
|
+
readonly rawSql: boolean | null;
|
|
174
|
+
/** Static db usage of the handler, project-local helper calls followed (D-157). */
|
|
175
|
+
readonly relations: RouteRelationsFact;
|
|
176
|
+
readonly description: string | null;
|
|
177
|
+
readonly input: RouteInputFact;
|
|
178
|
+
/** True when the handler body reads the request body (SPEC §9.3 rule 8). */
|
|
179
|
+
readonly handlerBodyRead: boolean;
|
|
180
|
+
/** True when the handler body reads the multipart form (SPEC §9.3 rule 8, D-053). */
|
|
181
|
+
readonly handlerFormRead: boolean;
|
|
182
|
+
/** Audited elevation calls in the handler, in source order. */
|
|
183
|
+
readonly elevations: readonly ElevationFact[];
|
|
184
|
+
readonly unknown: readonly UnknownFact[];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ── per-file module facts ──────────────────────────────────────────────────────────
|
|
188
|
+
|
|
189
|
+
export type ImportKind =
|
|
190
|
+
"named" | "default" | "namespace" | "side-effect" | "export-from" | "dynamic" | "require";
|
|
191
|
+
|
|
192
|
+
/** One module reference of a source file: static import, re-export, dynamic import or require. */
|
|
193
|
+
export interface ImportFact {
|
|
194
|
+
readonly specifier: string;
|
|
195
|
+
readonly kind: ImportKind;
|
|
196
|
+
/** Local binding the reference introduces; null for side-effect/re-export/dynamic forms. */
|
|
197
|
+
readonly local: string | null;
|
|
198
|
+
/** Imported name for named imports ("default" for a default import); null otherwise. */
|
|
199
|
+
readonly imported: string | null;
|
|
200
|
+
readonly source: SourceRef;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** One literal `t("key")` call; interpolated keys are skipped because they are not static. */
|
|
204
|
+
export interface TranslationCallFact {
|
|
205
|
+
readonly key: string;
|
|
206
|
+
readonly source: SourceRef;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** One call to a bare identifier (`drizzle(...)`, `t(...)`): enough for the security rules. */
|
|
210
|
+
export interface CallFact {
|
|
211
|
+
readonly name: string;
|
|
212
|
+
readonly source: SourceRef;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface FileFacts {
|
|
216
|
+
/** Project-relative path of the parsed source file. */
|
|
217
|
+
readonly path: string;
|
|
218
|
+
readonly imports: readonly ImportFact[];
|
|
219
|
+
readonly translationCalls: readonly TranslationCallFact[];
|
|
220
|
+
readonly calls: readonly CallFact[];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ── pages / client consumers ───────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
export type PageKind = "page" | "component" | "lib" | "other";
|
|
226
|
+
|
|
227
|
+
export type PathKind = "literal" | "concat" | "template" | "builder" | "dynamic" | "unknown";
|
|
228
|
+
|
|
229
|
+
export interface RouteCallFact {
|
|
230
|
+
readonly expression: string;
|
|
231
|
+
readonly kind: PathKind;
|
|
232
|
+
readonly staticPrefix: string | null;
|
|
233
|
+
readonly matchedRouteIds: readonly string[];
|
|
234
|
+
readonly source: SourceRef;
|
|
235
|
+
readonly unknown: readonly UnknownFact[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface PageFact {
|
|
239
|
+
readonly path: string;
|
|
240
|
+
readonly kind: PageKind;
|
|
241
|
+
readonly calls: readonly RouteCallFact[];
|
|
242
|
+
readonly source: SourceRef;
|
|
243
|
+
readonly unknown: readonly UnknownFact[];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ── graph ──────────────────────────────────────────────────────────────────────────
|
|
247
|
+
// The graph-facing shapes live in types-graph.ts (the 300-line split); they are re-exported
|
|
248
|
+
// here so every existing `from "./types.ts"` import keeps working.
|
|
249
|
+
|
|
250
|
+
export type {
|
|
251
|
+
GraphEdge,
|
|
252
|
+
GraphEdgeKind,
|
|
253
|
+
GraphNode,
|
|
254
|
+
GraphNodeData,
|
|
255
|
+
GraphNodeKind,
|
|
256
|
+
PageLink,
|
|
257
|
+
PageNodeData,
|
|
258
|
+
PagePreview,
|
|
259
|
+
PagePreviewNode,
|
|
260
|
+
ProjectGraph,
|
|
261
|
+
RouteNodeData,
|
|
262
|
+
ScreenFacts,
|
|
263
|
+
TableNodeData,
|
|
264
|
+
ViewNodeData,
|
|
265
|
+
WorkflowNodeData,
|
|
266
|
+
WorkflowStepNodeData,
|
|
267
|
+
} from "./types-graph.ts";
|
|
268
|
+
export type {
|
|
269
|
+
RouteElevationUsage,
|
|
270
|
+
RouteRelationUse,
|
|
271
|
+
RouteRelationsFact,
|
|
272
|
+
ViewFact,
|
|
273
|
+
} from "./types-relations.ts";
|
|
274
|
+
export type { WorkflowFact, WorkflowStepFact, WorkflowTablesFact } from "./types-workflows.ts";
|
|
275
|
+
|
|
276
|
+
// ── analysis ───────────────────────────────────────────────────────────────────────
|
|
277
|
+
|
|
278
|
+
export interface Analysis {
|
|
279
|
+
readonly revision: string;
|
|
280
|
+
readonly files: readonly string[];
|
|
281
|
+
readonly config: ConfigFacts;
|
|
282
|
+
readonly routes: readonly RouteFact[];
|
|
283
|
+
readonly tables: readonly TableFact[];
|
|
284
|
+
readonly relations: readonly RelationFact[];
|
|
285
|
+
/** Declarative views (D-157): facts, and graph nodes since D-160. */
|
|
286
|
+
readonly views: readonly ViewFact[];
|
|
287
|
+
readonly pages: readonly PageFact[];
|
|
288
|
+
readonly workflows: readonly WorkflowFact[];
|
|
289
|
+
/** Job definitions, with D-157 applied to the db client their `run` body sees. */
|
|
290
|
+
readonly jobs: readonly JobFact[];
|
|
291
|
+
readonly jobRelations: Readonly<Record<string, JobRelationsFact>>;
|
|
292
|
+
/** Each workflow's table surface, derived from the jobs its steps reference. */
|
|
293
|
+
readonly workflowTables: readonly WorkflowTablesFact[];
|
|
294
|
+
/** Module facts for every parsed source file, in path order. */
|
|
295
|
+
readonly fileFacts: readonly FileFacts[];
|
|
296
|
+
readonly locales: LocaleCatalogs;
|
|
297
|
+
readonly diagnostics: readonly Diagnostic[];
|
|
298
|
+
readonly graph: ProjectGraph;
|
|
299
|
+
}
|