@craft-ts/dev-tools 0.7.0-beta.13 → 0.7.0-beta.15
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 +64 -10
- package/package.json +8 -2
- package/src/bin/agent-selector.d.ts +22 -0
- package/src/bin/agent-selector.js +100 -0
- package/src/bin/agent-selector.js.map +1 -0
- package/src/bin/craft-graph.js +74 -8
- package/src/bin/craft-graph.js.map +1 -1
- package/src/bin/craft.d.ts +23 -0
- package/src/bin/craft.js +245 -28
- package/src/bin/craft.js.map +1 -1
- package/src/eslint-rules/anchor-has-href.cjs +37 -3
- package/src/eslint-rules/craft-computed-name-match.cjs +26 -5
- package/src/eslint-rules/craft-name-match-utils.cjs +18 -9
- package/src/eslint-rules/hyperscript-walk.cjs +3 -3
- package/src/eslint-rules/index.cjs +46 -1
- package/src/eslint-rules/no-auth-token-in-local-storage.cjs +17 -0
- package/src/eslint-rules/no-craft-computed-side-effects.cjs +12 -5
- package/src/eslint-rules/no-craft-service-component-same-file.cjs +138 -0
- package/src/eslint-rules/no-effect-import-in-frontend.cjs +52 -0
- package/src/eslint-rules/no-effect-in-params.cjs +31 -1
- package/src/eslint-rules/no-explicit-effect-type.cjs +137 -0
- package/src/eslint-rules/no-free-has.cjs +47 -0
- package/src/eslint-rules/no-heading-level-skip.cjs +6 -6
- package/src/eslint-rules/no-raw-class.cjs +76 -0
- package/src/eslint-rules/no-raw-css-value.cjs +163 -0
- package/src/eslint-rules/no-raw-user-url.cjs +114 -0
- package/src/eslint-rules/no-trust-forwarded-headers.cjs +43 -0
- package/src/eslint-rules/no-unsafe-html.cjs +93 -0
- package/src/eslint-rules/no-unsafe-transfer-state.cjs +54 -0
- package/src/eslint-rules/prefer-craft-template-blocks.cjs +8 -8
- package/src/eslint-rules/prefer-direct-yieldable-callback.cjs +57 -14
- package/src/eslint-rules/prefer-inline-effect-insertion.cjs +263 -0
- package/src/eslint-rules/prefer-inline-route-providers.cjs +138 -0
- package/src/eslint-rules/recommended-config.cjs +6 -0
- package/src/eslint-rules/require-reactive-template-bindings.cjs +8 -8
- package/src/eslint-rules/require-route-security-policy.cjs +87 -0
- package/src/eslint-rules/require-server-function-timeout.cjs +39 -0
- package/src/eslint-rules/security-config.cjs +14 -0
- package/src/eslint-rules/security-rule-utils.cjs +21 -0
- package/src/eslint-rules/style-file-boundary.cjs +75 -0
- package/src/eslint-rules/sync-effect-body.cjs +343 -0
- package/src/index.d.ts +4 -0
- package/src/index.js +4 -0
- package/src/index.js.map +1 -1
- package/src/scripts/architecture-graph.js +8 -2
- package/src/scripts/architecture-graph.js.map +1 -1
- package/src/scripts/create/create-project.d.ts +71 -1
- package/src/scripts/create/create-project.js +1937 -176
- package/src/scripts/create/create-project.js.map +1 -1
- package/src/scripts/data-flow-graph.d.ts +1 -1
- package/src/scripts/effect-dependency-graph.d.ts +1 -1
- package/src/scripts/security-check.d.ts +30 -0
- package/src/scripts/security-check.js +223 -0
- package/src/scripts/security-check.js.map +1 -0
- package/src/scripts/style-architecture.d.ts +56 -0
- package/src/scripts/style-architecture.js +142 -0
- package/src/scripts/style-architecture.js.map +1 -0
- package/src/scripts/style-graph.d.ts +99 -0
- package/src/scripts/style-graph.js +179 -0
- package/src/scripts/style-graph.js.map +1 -0
- package/src/scripts/style-report.d.ts +55 -0
- package/src/scripts/style-report.js +67 -0
- package/src/scripts/style-report.js.map +1 -0
- package/src/scripts/template/migrate-template.js +1 -1
- package/src/scripts/template/migrate-template.js.map +1 -1
- package/src/scripts/angular-brand-codemod.ts +0 -3985
- package/src/scripts/architecture/migrate-architecture.ts +0 -653
- package/src/scripts/architecture-graph.ts +0 -3136
- package/src/scripts/components/migrate-components.ts +0 -227
- package/src/scripts/components/migration-diagnostic.ts +0 -8
- package/src/scripts/create/create-project.ts +0 -849
- package/src/scripts/data-flow-graph.ts +0 -240
- package/src/scripts/dependency-graph.ts +0 -5908
- package/src/scripts/effect-dependency-graph.ts +0 -630
- package/src/scripts/migrate.ts +0 -162
- package/src/scripts/migration-workspace.ts +0 -93
- package/src/scripts/primitives/migrate-named-primitives.ts +0 -627
- package/src/scripts/primitives/migrate-primitive-generators.ts +0 -410
- package/src/scripts/primitives/migrate-primitives.ts +0 -655
- package/src/scripts/primitives/migrate-yieldable-reactive-reads.ts +0 -499
- package/src/scripts/primitives/migration-diagnostic.ts +0 -15
- package/src/scripts/routes/migrate-routes.ts +0 -895
- package/src/scripts/routes/migration-diagnostic.ts +0 -25
- package/src/scripts/routes/route-command.ts +0 -1807
- package/src/scripts/routes/verify-routes.ts +0 -1511
- package/src/scripts/services/config.ts +0 -60
- package/src/scripts/services/migrate-services.ts +0 -1348
- package/src/scripts/services/migration-diagnostic.ts +0 -28
- package/src/scripts/template/migrate-template.ts +0 -418
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Node,
|
|
3
|
-
SyntaxKind,
|
|
4
|
-
type CallExpression,
|
|
5
|
-
type SourceFile,
|
|
6
|
-
type VariableDeclaration,
|
|
7
|
-
} from 'ts-morph';
|
|
8
|
-
import type {
|
|
9
|
-
DependencyGraphEdge,
|
|
10
|
-
DependencyGraphNode,
|
|
11
|
-
DependencyGraphProof,
|
|
12
|
-
} from './dependency-graph';
|
|
13
|
-
|
|
14
|
-
export interface DataClassificationNodeDetails {
|
|
15
|
-
readonly classification: string;
|
|
16
|
-
readonly source: 'schema-annotation';
|
|
17
|
-
readonly schemaName: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ExternalOutputNodeDetails {
|
|
21
|
-
readonly boundary: 'server-function-response';
|
|
22
|
-
readonly serverFunctionId?: string;
|
|
23
|
-
readonly schemaName?: string;
|
|
24
|
-
readonly classifications: readonly string[];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface DataFlowRelationDetails {
|
|
28
|
-
readonly classification: string;
|
|
29
|
-
readonly resolution: 'static' | 'unknown';
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
declare module './dependency-graph' {
|
|
33
|
-
interface DependencyGraphNodeRegistry {
|
|
34
|
-
'data-classification': DataClassificationNodeDetails;
|
|
35
|
-
'external-output': ExternalOutputNodeDetails;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
interface DependencyGraphEdgeRegistry {
|
|
39
|
-
'exposes-data': DataFlowRelationDetails;
|
|
40
|
-
'flows-data': DataFlowRelationDetails;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
type SchemaInfo = {
|
|
45
|
-
readonly declaration: VariableDeclaration;
|
|
46
|
-
readonly filePath: string;
|
|
47
|
-
readonly name: string;
|
|
48
|
-
readonly classifications: Set<string>;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const classificationId = (filePath: string, name: string, value: string) =>
|
|
52
|
-
`data-classification:${filePath}#${name}:${value}`;
|
|
53
|
-
|
|
54
|
-
const outputId = (filePath: string, line: number) =>
|
|
55
|
-
`external-output:${filePath}:${line}`;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Extracts schema annotations and server-function response boundaries. The
|
|
59
|
-
* propagation is intentionally conservative: only statically named schema
|
|
60
|
-
* variables are followed, and no transform is assumed to remove sensitivity.
|
|
61
|
-
*/
|
|
62
|
-
export function collectDataFlowGraph(
|
|
63
|
-
sourceFiles: readonly SourceFile[],
|
|
64
|
-
): { nodes: DependencyGraphNode[]; edges: DependencyGraphEdge[] } {
|
|
65
|
-
const nodes = new Map<string, DependencyGraphNode>();
|
|
66
|
-
const edges = new Map<string, DependencyGraphEdge>();
|
|
67
|
-
const schemas = new Map<string, SchemaInfo>();
|
|
68
|
-
const schemaByName = new Map<string, SchemaInfo[]>();
|
|
69
|
-
|
|
70
|
-
const addNode = (node: DependencyGraphNode) => {
|
|
71
|
-
if (!nodes.has(node.id)) nodes.set(node.id, node);
|
|
72
|
-
};
|
|
73
|
-
const addEdge = (edge: DependencyGraphEdge) => {
|
|
74
|
-
const key = `${edge.from}:${edge.kind}:${edge.to}`;
|
|
75
|
-
if (!edges.has(key)) edges.set(key, edge);
|
|
76
|
-
};
|
|
77
|
-
const proof = (node: Node, pattern: string): DependencyGraphProof => ({
|
|
78
|
-
filePath: node.getSourceFile().getFilePath(),
|
|
79
|
-
line: node.getStartLineNumber(),
|
|
80
|
-
pattern,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
for (const sourceFile of sourceFiles) {
|
|
84
|
-
for (const declaration of sourceFile.getVariableDeclarations()) {
|
|
85
|
-
const initializer = declaration.getInitializer();
|
|
86
|
-
if (!initializer || !containsSchema(initializer)) continue;
|
|
87
|
-
const name = declaration.getName();
|
|
88
|
-
const info: SchemaInfo = {
|
|
89
|
-
declaration,
|
|
90
|
-
filePath: sourceFile.getFilePath(),
|
|
91
|
-
name,
|
|
92
|
-
classifications: new Set(findSchemaAnnotations(initializer)),
|
|
93
|
-
};
|
|
94
|
-
schemas.set(`${sourceFile.getFilePath()}#${name}`, info);
|
|
95
|
-
schemaByName.set(name, [...(schemaByName.get(name) ?? []), info]);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const classifications = new Map<string, { schema: SchemaInfo; value: string; node: Node }>();
|
|
100
|
-
for (const info of schemas.values()) {
|
|
101
|
-
for (const value of info.classifications) {
|
|
102
|
-
const annotation = findSchemaAnnotation(info.declaration.getInitializer(), value);
|
|
103
|
-
if (!annotation) continue;
|
|
104
|
-
classifications.set(`${info.filePath}#${info.name}:${value}`, {
|
|
105
|
-
schema: info,
|
|
106
|
-
value,
|
|
107
|
-
node: annotation,
|
|
108
|
-
});
|
|
109
|
-
addNode({
|
|
110
|
-
id: classificationId(info.filePath, info.name, value),
|
|
111
|
-
kind: 'data-classification',
|
|
112
|
-
label: `${info.name} [${value}]`,
|
|
113
|
-
filePath: info.filePath,
|
|
114
|
-
line: info.declaration.getStartLineNumber(),
|
|
115
|
-
details: {
|
|
116
|
-
classification: value,
|
|
117
|
-
source: 'schema-annotation',
|
|
118
|
-
schemaName: info.name,
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const classificationsFor = (info: SchemaInfo, seen = new Set<string>()): Set<string> => {
|
|
125
|
-
const key = `${info.filePath}#${info.name}`;
|
|
126
|
-
if (seen.has(key)) return new Set();
|
|
127
|
-
const nextSeen = new Set([...seen, key]);
|
|
128
|
-
const result = new Set(info.classifications);
|
|
129
|
-
const initializer = info.declaration.getInitializer();
|
|
130
|
-
if (!initializer) return result;
|
|
131
|
-
for (const identifier of initializer.getDescendantsOfKind(SyntaxKind.Identifier)) {
|
|
132
|
-
for (const target of schemaByName.get(identifier.getText()) ?? []) {
|
|
133
|
-
for (const value of classificationsFor(target, nextSeen)) result.add(value);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return result;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
for (const sourceFile of sourceFiles) {
|
|
140
|
-
if (!sourceFile.getBaseName().endsWith('.fn-serveur.ts')) continue;
|
|
141
|
-
const serverFunction = sourceFile
|
|
142
|
-
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
143
|
-
.find((call) => call.getExpression().getText() === 'serverFunction');
|
|
144
|
-
if (!serverFunction) continue;
|
|
145
|
-
const id = serverFunction
|
|
146
|
-
.getArguments()[0]
|
|
147
|
-
?.asKind(SyntaxKind.StringLiteral)
|
|
148
|
-
?.getLiteralValue();
|
|
149
|
-
const options = serverFunction
|
|
150
|
-
.getArguments()[2]
|
|
151
|
-
?.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
152
|
-
const output = options
|
|
153
|
-
?.getProperty('output')
|
|
154
|
-
?.asKind(SyntaxKind.PropertyAssignment)
|
|
155
|
-
?.getInitializer();
|
|
156
|
-
if (!output) continue;
|
|
157
|
-
const schemaName = output.asKind(SyntaxKind.Identifier)?.getText();
|
|
158
|
-
const schema = schemaName
|
|
159
|
-
? [...(schemaByName.get(schemaName) ?? [])][0]
|
|
160
|
-
: undefined;
|
|
161
|
-
const values = schema ? [...classificationsFor(schema)] : [];
|
|
162
|
-
const outputNode: DependencyGraphNode = {
|
|
163
|
-
id: outputId(sourceFile.getFilePath(), serverFunction.getStartLineNumber()),
|
|
164
|
-
kind: 'external-output',
|
|
165
|
-
label: `${id ?? 'server-function'} response`,
|
|
166
|
-
filePath: sourceFile.getFilePath(),
|
|
167
|
-
line: serverFunction.getStartLineNumber(),
|
|
168
|
-
details: {
|
|
169
|
-
boundary: 'server-function-response',
|
|
170
|
-
...(id === undefined ? {} : { serverFunctionId: id }),
|
|
171
|
-
...(schemaName === undefined ? {} : { schemaName }),
|
|
172
|
-
classifications: values,
|
|
173
|
-
},
|
|
174
|
-
};
|
|
175
|
-
addNode(outputNode);
|
|
176
|
-
|
|
177
|
-
for (const value of values) {
|
|
178
|
-
const source = [...classifications.values()].find(
|
|
179
|
-
(candidate) => candidate.value === value &&
|
|
180
|
-
classificationsFor(candidate.schema).has(value),
|
|
181
|
-
);
|
|
182
|
-
if (!source) continue;
|
|
183
|
-
addEdge({
|
|
184
|
-
from: classificationId(source.schema.filePath, source.schema.name, value),
|
|
185
|
-
to: outputNode.id,
|
|
186
|
-
kind: 'exposes-data',
|
|
187
|
-
evidence: 'ast',
|
|
188
|
-
details: { classification: value, resolution: 'static' },
|
|
189
|
-
proof: proof(output, `server function output: ${schemaName ?? 'unknown schema'}`),
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return { nodes: [...nodes.values()], edges: [...edges.values()] };
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function containsSchema(node: Node): boolean {
|
|
198
|
-
return [
|
|
199
|
-
...(Node.isCallExpression(node) ? [node] : []),
|
|
200
|
-
...node.getDescendantsOfKind(SyntaxKind.CallExpression),
|
|
201
|
-
].some((call) => call.getExpression().getText().startsWith('Schema.'));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function findSchemaAnnotations(node: Node): string[] {
|
|
205
|
-
const values = new Set<string>();
|
|
206
|
-
for (const call of [
|
|
207
|
-
...(Node.isCallExpression(node) ? [node] : []),
|
|
208
|
-
...node.getDescendantsOfKind(SyntaxKind.CallExpression),
|
|
209
|
-
]) {
|
|
210
|
-
const value = readSensitivity(call);
|
|
211
|
-
if (value) values.add(value);
|
|
212
|
-
}
|
|
213
|
-
return [...values];
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function findSchemaAnnotation(node: Node | undefined, value: string): Node | undefined {
|
|
217
|
-
if (!node) return undefined;
|
|
218
|
-
return [
|
|
219
|
-
...(Node.isCallExpression(node) ? [node] : []),
|
|
220
|
-
...node.getDescendantsOfKind(SyntaxKind.CallExpression),
|
|
221
|
-
].find((call) => readSensitivity(call) === value);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function readSensitivity(call: CallExpression): string | undefined {
|
|
225
|
-
// Effect expose l'annotation en méthode (`Schema.String.annotate({ … })`) ;
|
|
226
|
-
// `annotations` reste accepté pour les variantes qui l'orthographient ainsi.
|
|
227
|
-
const callee = call.getExpression().getText();
|
|
228
|
-
if (!callee.endsWith('annotate') && !callee.endsWith('annotations')) {
|
|
229
|
-
return undefined;
|
|
230
|
-
}
|
|
231
|
-
const object = call
|
|
232
|
-
.getArguments()[0]
|
|
233
|
-
?.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
234
|
-
return object
|
|
235
|
-
?.getProperty('sensitivity')
|
|
236
|
-
?.asKind(SyntaxKind.PropertyAssignment)
|
|
237
|
-
?.getInitializer()
|
|
238
|
-
?.asKind(SyntaxKind.StringLiteral)
|
|
239
|
-
?.getLiteralValue();
|
|
240
|
-
}
|