@ykdz/template 0.0.3 → 0.0.4
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 +1 -1
- package/dist/src/cli.d.ts +0 -1
- package/dist/src/cli.js +14 -2
- package/dist/src/declarations.d.ts +2 -3
- package/dist/src/declarations.js +46 -36
- package/dist/src/dependency-catalog.d.ts +9 -1
- package/dist/src/dependency-catalog.js +69 -0
- package/dist/src/devcontainer.d.ts +49 -9
- package/dist/src/devcontainer.js +192 -14
- package/dist/src/editor-customization.d.ts +0 -1
- package/dist/src/editor-customization.js +54 -47
- package/dist/src/generation-context.d.ts +0 -1
- package/dist/src/generation-context.js +4 -1
- package/dist/src/module-graph.d.ts +8 -5
- package/dist/src/module-graph.js +10 -0
- package/dist/src/next-step-instructions.d.ts +0 -1
- package/dist/src/next-step-instructions.js +35 -0
- package/dist/src/package-addition.d.ts +1 -1
- package/dist/src/package-addition.js +170 -15
- package/dist/src/preset-projection.d.ts +1 -1
- package/dist/src/project-github.d.ts +3 -2
- package/dist/src/project-github.js +24 -6
- package/dist/src/renderer.d.ts +16 -2
- package/dist/src/renderer.js +95 -12
- package/dist/src/runtime-paths.d.ts +0 -1
- package/dist/src/template-boundary-check.d.ts +34 -0
- package/dist/src/template-boundary-check.js +448 -0
- package/dist/src/toolchain-resolution.d.ts +0 -1
- package/dist/templates/hono-api/projection.d.ts +2 -3
- package/dist/templates/hono-api/projection.js +230 -69
- package/dist/templates/projection-plans.d.ts +0 -1
- package/dist/templates/registry.d.ts +0 -1
- package/dist/templates/registry.js +2 -2
- package/dist/templates/rust-bin/projection.d.ts +2 -3
- package/dist/templates/rust-bin/projection.js +161 -53
- package/dist/templates/ts-lib/projection.d.ts +2 -3
- package/dist/templates/ts-lib/projection.js +215 -64
- package/dist/templates/vue-app/projection.d.ts +2 -3
- package/dist/templates/vue-app/projection.js +246 -83
- package/dist/templates/vue-hono-app/projection.d.ts +0 -1
- package/dist/templates/vue-hono-app/projection.js +191 -87
- package/package.json +10 -5
- package/pnpm-workspace.yaml +1 -0
- package/templates/hono-api/.github/dependabot.yml +13 -0
- package/templates/rust-bin/.github/dependabot.yml +18 -1
- package/templates/rust-bin/rust-toolchain.toml +3 -0
- package/templates/rust-bin/rustfmt.toml +2 -0
- package/templates/shared/devcontainer/browser-test.Dockerfile +2 -0
- package/templates/shared/devcontainer/node-pnpm.Dockerfile +6 -0
- package/templates/shared/devcontainer/rust.Dockerfile +16 -0
- package/templates/shared/editor-customization/capabilities.json +56 -0
- package/templates/ts-lib/.github/dependabot.yml +13 -0
- package/templates/ts-lib/src/index.ts +5 -1
- package/templates/vue-app/.github/dependabot.yml +13 -0
- package/templates/vue-app/.github/workflows/check.yml +1 -1
- package/templates/vue-hono-app/.github/dependabot.yml +13 -0
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/declarations.d.ts.map +0 -1
- package/dist/src/dependency-catalog.d.ts.map +0 -1
- package/dist/src/devcontainer.d.ts.map +0 -1
- package/dist/src/editor-customization.d.ts.map +0 -1
- package/dist/src/generation-context.d.ts.map +0 -1
- package/dist/src/module-graph.d.ts.map +0 -1
- package/dist/src/next-step-instructions.d.ts.map +0 -1
- package/dist/src/package-addition.d.ts.map +0 -1
- package/dist/src/preset-projection.d.ts.map +0 -1
- package/dist/src/project-github.d.ts.map +0 -1
- package/dist/src/renderer.d.ts.map +0 -1
- package/dist/src/runtime-paths.d.ts.map +0 -1
- package/dist/src/toolchain-resolution.d.ts.map +0 -1
- package/dist/templates/hono-api/projection.d.ts.map +0 -1
- package/dist/templates/projection-plans.d.ts.map +0 -1
- package/dist/templates/registry.d.ts.map +0 -1
- package/dist/templates/rust-bin/projection.d.ts.map +0 -1
- package/dist/templates/ts-lib/projection.d.ts.map +0 -1
- package/dist/templates/vue-app/projection.d.ts.map +0 -1
- package/dist/templates/vue-hono-app/projection.d.ts.map +0 -1
- package/templates/hono-api/projection.ts +0 -453
- package/templates/projection-plans.ts +0 -135
- package/templates/registry.ts +0 -59
- package/templates/rust-bin/projection.ts +0 -346
- package/templates/ts-lib/projection.ts +0 -454
- package/templates/vue-app/projection.ts +0 -687
- package/templates/vue-hono-app/projection.ts +0 -669
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
const inlineOperationKinds = new Set([
|
|
4
|
+
"writeText",
|
|
5
|
+
"writeJson",
|
|
6
|
+
"mergeJson",
|
|
7
|
+
]);
|
|
8
|
+
export const templateBoundaryDebtAllowlist = [];
|
|
9
|
+
function operationTarget(operation) {
|
|
10
|
+
if ("to" in operation) {
|
|
11
|
+
return operation.to;
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
function isInlineProtectedOperation(operation) {
|
|
16
|
+
const generatedPath = operationTarget(operation);
|
|
17
|
+
return (generatedPath !== undefined &&
|
|
18
|
+
inlineOperationKinds.has(operation.kind) &&
|
|
19
|
+
isProtectedGeneratedPath(generatedPath));
|
|
20
|
+
}
|
|
21
|
+
export function isProtectedGeneratedPath(generatedPath) {
|
|
22
|
+
const normalizedPath = generatedPath.split("\\").join("/");
|
|
23
|
+
const fileName = normalizedPath.split("/").at(-1);
|
|
24
|
+
return (normalizedPath === ".devcontainer/Dockerfile" ||
|
|
25
|
+
normalizedPath === ".devcontainer/devcontainer.json" ||
|
|
26
|
+
normalizedPath === ".github/dependabot.yml" ||
|
|
27
|
+
normalizedPath.startsWith(".github/workflows/") ||
|
|
28
|
+
normalizedPath.startsWith(".vscode/") ||
|
|
29
|
+
fileName === "oxfmt.config.ts" ||
|
|
30
|
+
fileName === "oxlint.config.ts" ||
|
|
31
|
+
fileName === "playwright.config.ts" ||
|
|
32
|
+
fileName === "rustfmt.toml" ||
|
|
33
|
+
fileName === "rust-toolchain.toml" ||
|
|
34
|
+
fileName === "turbo.json" ||
|
|
35
|
+
fileName === "tsconfig.config.json" ||
|
|
36
|
+
fileName === "vite.config.ts" ||
|
|
37
|
+
fileName === "vitest.config.ts");
|
|
38
|
+
}
|
|
39
|
+
function propertyStringValue(objectLiteral, name) {
|
|
40
|
+
const initializer = propertyInitializer(objectLiteral, name);
|
|
41
|
+
if (!initializer) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
if (ts.isStringLiteralLike(initializer)) {
|
|
45
|
+
return initializer.text;
|
|
46
|
+
}
|
|
47
|
+
if (ts.isNoSubstitutionTemplateLiteral(initializer) ||
|
|
48
|
+
ts.isTemplateExpression(initializer)) {
|
|
49
|
+
return initializer.getText();
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
function propertyInitializer(objectLiteral, name) {
|
|
54
|
+
const property = objectLiteral.properties.find((candidate) => {
|
|
55
|
+
return (ts.isPropertyAssignment(candidate) &&
|
|
56
|
+
ts.isIdentifier(candidate.name) &&
|
|
57
|
+
candidate.name.text === name);
|
|
58
|
+
});
|
|
59
|
+
if (!property || !ts.isPropertyAssignment(property)) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return property.initializer;
|
|
63
|
+
}
|
|
64
|
+
function propertyPathMatches(objectLiteral, name, expectedPath) {
|
|
65
|
+
const initializer = propertyInitializer(objectLiteral, name);
|
|
66
|
+
if (!initializer) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
if (ts.isStringLiteralLike(initializer)) {
|
|
70
|
+
return initializer.text === expectedPath;
|
|
71
|
+
}
|
|
72
|
+
if (ts.isNoSubstitutionTemplateLiteral(initializer)) {
|
|
73
|
+
return initializer.text === expectedPath;
|
|
74
|
+
}
|
|
75
|
+
if (ts.isTemplateExpression(initializer)) {
|
|
76
|
+
const literalParts = [
|
|
77
|
+
initializer.head.text,
|
|
78
|
+
...initializer.templateSpans.map((span) => span.literal.text),
|
|
79
|
+
].filter((part) => part.length > 0);
|
|
80
|
+
let searchStart = 0;
|
|
81
|
+
return literalParts.every((part, index) => {
|
|
82
|
+
const foundAt = expectedPath.indexOf(part, searchStart);
|
|
83
|
+
if (foundAt === -1) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const isFirst = index === 0;
|
|
87
|
+
const isLast = index === literalParts.length - 1;
|
|
88
|
+
if (isFirst && initializer.head.text.length > 0 && foundAt !== 0) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (isLast && !expectedPath.endsWith(part)) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
searchStart = foundAt + part.length;
|
|
95
|
+
return true;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
function owningFunctionName(node) {
|
|
101
|
+
let current = node;
|
|
102
|
+
while (current) {
|
|
103
|
+
if ((ts.isFunctionDeclaration(current) ||
|
|
104
|
+
ts.isFunctionExpression(current) ||
|
|
105
|
+
ts.isArrowFunction(current) ||
|
|
106
|
+
ts.isMethodDeclaration(current)) &&
|
|
107
|
+
current.name) {
|
|
108
|
+
return current.name.getText();
|
|
109
|
+
}
|
|
110
|
+
if (ts.isPropertyAssignment(current) &&
|
|
111
|
+
(ts.isFunctionExpression(current.initializer) ||
|
|
112
|
+
ts.isArrowFunction(current.initializer))) {
|
|
113
|
+
return current.name.getText();
|
|
114
|
+
}
|
|
115
|
+
current = current.parent;
|
|
116
|
+
}
|
|
117
|
+
return "<module>";
|
|
118
|
+
}
|
|
119
|
+
function propertyNameText(name) {
|
|
120
|
+
if (ts.isIdentifier(name) || ts.isStringLiteralLike(name)) {
|
|
121
|
+
return name.text;
|
|
122
|
+
}
|
|
123
|
+
if (ts.isNumericLiteral(name)) {
|
|
124
|
+
return name.text;
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
function expressionLiteralJsonValue(expression) {
|
|
129
|
+
if (ts.isParenthesizedExpression(expression)) {
|
|
130
|
+
return expressionLiteralJsonValue(expression.expression);
|
|
131
|
+
}
|
|
132
|
+
if (ts.isAsExpression(expression) ||
|
|
133
|
+
ts.isSatisfiesExpression(expression) ||
|
|
134
|
+
ts.isTypeAssertionExpression(expression)) {
|
|
135
|
+
return expressionLiteralJsonValue(expression.expression);
|
|
136
|
+
}
|
|
137
|
+
if (ts.isStringLiteralLike(expression)) {
|
|
138
|
+
return { known: true, value: expression.text };
|
|
139
|
+
}
|
|
140
|
+
if (ts.isNoSubstitutionTemplateLiteral(expression)) {
|
|
141
|
+
return { known: true, value: expression.text };
|
|
142
|
+
}
|
|
143
|
+
if (ts.isNumericLiteral(expression)) {
|
|
144
|
+
return { known: true, value: Number(expression.text) };
|
|
145
|
+
}
|
|
146
|
+
if (expression.kind === ts.SyntaxKind.TrueKeyword) {
|
|
147
|
+
return { known: true, value: true };
|
|
148
|
+
}
|
|
149
|
+
if (expression.kind === ts.SyntaxKind.FalseKeyword) {
|
|
150
|
+
return { known: true, value: false };
|
|
151
|
+
}
|
|
152
|
+
if (expression.kind === ts.SyntaxKind.NullKeyword) {
|
|
153
|
+
return { known: true, value: null };
|
|
154
|
+
}
|
|
155
|
+
if (ts.isPrefixUnaryExpression(expression)) {
|
|
156
|
+
const operand = expressionLiteralJsonValue(expression.operand);
|
|
157
|
+
if (!operand.known || typeof operand.value !== "number") {
|
|
158
|
+
return { known: false };
|
|
159
|
+
}
|
|
160
|
+
if (expression.operator === ts.SyntaxKind.MinusToken) {
|
|
161
|
+
return { known: true, value: -operand.value };
|
|
162
|
+
}
|
|
163
|
+
if (expression.operator === ts.SyntaxKind.PlusToken) {
|
|
164
|
+
return { known: true, value: operand.value };
|
|
165
|
+
}
|
|
166
|
+
return { known: false };
|
|
167
|
+
}
|
|
168
|
+
if (ts.isArrayLiteralExpression(expression)) {
|
|
169
|
+
const values = [];
|
|
170
|
+
for (const element of expression.elements) {
|
|
171
|
+
if (ts.isSpreadElement(element)) {
|
|
172
|
+
return { known: false };
|
|
173
|
+
}
|
|
174
|
+
const value = expressionLiteralJsonValue(element);
|
|
175
|
+
if (!value.known) {
|
|
176
|
+
return { known: false };
|
|
177
|
+
}
|
|
178
|
+
values.push(value.value);
|
|
179
|
+
}
|
|
180
|
+
return { known: true, value: values };
|
|
181
|
+
}
|
|
182
|
+
if (ts.isObjectLiteralExpression(expression)) {
|
|
183
|
+
const value = {};
|
|
184
|
+
for (const property of expression.properties) {
|
|
185
|
+
if (!ts.isPropertyAssignment(property)) {
|
|
186
|
+
return { known: false };
|
|
187
|
+
}
|
|
188
|
+
const name = propertyNameText(property.name);
|
|
189
|
+
if (name === undefined) {
|
|
190
|
+
return { known: false };
|
|
191
|
+
}
|
|
192
|
+
const initializer = expressionLiteralJsonValue(property.initializer);
|
|
193
|
+
if (!initializer.known) {
|
|
194
|
+
return { known: false };
|
|
195
|
+
}
|
|
196
|
+
value[name] = initializer.value;
|
|
197
|
+
}
|
|
198
|
+
return { known: true, value };
|
|
199
|
+
}
|
|
200
|
+
return { known: false };
|
|
201
|
+
}
|
|
202
|
+
function jsonValuesEqual(left, right) {
|
|
203
|
+
if (Object.is(left, right)) {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
207
|
+
return (Array.isArray(left) &&
|
|
208
|
+
Array.isArray(right) &&
|
|
209
|
+
left.length === right.length &&
|
|
210
|
+
left.every((entry, index) => jsonValuesEqual(entry, right[index])));
|
|
211
|
+
}
|
|
212
|
+
if (typeof left !== "object" ||
|
|
213
|
+
left === null ||
|
|
214
|
+
typeof right !== "object" ||
|
|
215
|
+
right === null) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
const leftEntries = Object.entries(left);
|
|
219
|
+
const rightRecord = right;
|
|
220
|
+
const rightKeys = new Set(Object.keys(rightRecord));
|
|
221
|
+
return (leftEntries.length === rightKeys.size &&
|
|
222
|
+
leftEntries.every(([key, value]) => {
|
|
223
|
+
rightKeys.delete(key);
|
|
224
|
+
return jsonValuesEqual(value, rightRecord[key]);
|
|
225
|
+
}) &&
|
|
226
|
+
rightKeys.size === 0);
|
|
227
|
+
}
|
|
228
|
+
function expressionMatchesJsonValue(expression, expectedValue) {
|
|
229
|
+
const literalValue = expressionLiteralJsonValue(expression);
|
|
230
|
+
return (literalValue.known && jsonValuesEqual(literalValue.value, expectedValue));
|
|
231
|
+
}
|
|
232
|
+
function isExactOperationAstMatch(node, operation) {
|
|
233
|
+
if (operation.kind === "writeText") {
|
|
234
|
+
return propertyStringValue(node, "text") === operation.text;
|
|
235
|
+
}
|
|
236
|
+
const value = propertyInitializer(node, "value");
|
|
237
|
+
return (value !== undefined && expressionMatchesJsonValue(value, operation.value));
|
|
238
|
+
}
|
|
239
|
+
function findAstMatchesForOperation(sourceFile, operation) {
|
|
240
|
+
const exactMatches = [];
|
|
241
|
+
const candidateMatches = [];
|
|
242
|
+
function visit(node) {
|
|
243
|
+
if (!ts.isObjectLiteralExpression(node)) {
|
|
244
|
+
ts.forEachChild(node, visit);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (propertyStringValue(node, "kind") === operation.kind &&
|
|
248
|
+
propertyPathMatches(node, "to", operation.to)) {
|
|
249
|
+
const match = {
|
|
250
|
+
node,
|
|
251
|
+
owningFunction: owningFunctionName(node),
|
|
252
|
+
};
|
|
253
|
+
candidateMatches.push(match);
|
|
254
|
+
if (isExactOperationAstMatch(node, operation)) {
|
|
255
|
+
exactMatches.push(match);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
ts.forEachChild(node, visit);
|
|
259
|
+
}
|
|
260
|
+
visit(sourceFile);
|
|
261
|
+
if (exactMatches.length > 0) {
|
|
262
|
+
return exactMatches;
|
|
263
|
+
}
|
|
264
|
+
return candidateMatches;
|
|
265
|
+
}
|
|
266
|
+
function findOwningFunctionsForOperation(sourceFile, operation) {
|
|
267
|
+
const owners = new Set(findAstMatchesForOperation(sourceFile, operation).map((match) => match.owningFunction));
|
|
268
|
+
if (owners.size > 0) {
|
|
269
|
+
return [...owners];
|
|
270
|
+
}
|
|
271
|
+
return ["<unknown>"];
|
|
272
|
+
}
|
|
273
|
+
function isPropertyAccess(expression, objectName, propertyName) {
|
|
274
|
+
return (ts.isPropertyAccessExpression(expression) &&
|
|
275
|
+
ts.isIdentifier(expression.expression) &&
|
|
276
|
+
expression.expression.text === objectName &&
|
|
277
|
+
expression.name.text === propertyName);
|
|
278
|
+
}
|
|
279
|
+
function isEditorExtensionsProjectionValue(expression) {
|
|
280
|
+
if (!ts.isObjectLiteralExpression(expression)) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
const [property] = expression.properties;
|
|
284
|
+
return (expression.properties.length === 1 &&
|
|
285
|
+
property !== undefined &&
|
|
286
|
+
ts.isPropertyAssignment(property) &&
|
|
287
|
+
ts.isIdentifier(property.name) &&
|
|
288
|
+
property.name.text === "recommendations" &&
|
|
289
|
+
isPropertyAccess(property.initializer, "editorCustomization", "extensions"));
|
|
290
|
+
}
|
|
291
|
+
function isStructuredEditorCustomizationOperation(sourceFile, operation) {
|
|
292
|
+
if (operation.kind !== "writeJson") {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
if (operation.to !== ".vscode/extensions.json" &&
|
|
296
|
+
operation.to !== ".vscode/settings.json") {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
const matches = findAstMatchesForOperation(sourceFile, operation);
|
|
300
|
+
if (matches.length === 0) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
return matches.every((match) => {
|
|
304
|
+
const value = propertyInitializer(match.node, "value");
|
|
305
|
+
return (value !== undefined &&
|
|
306
|
+
(operation.to === ".vscode/settings.json"
|
|
307
|
+
? isPropertyAccess(value, "editorCustomization", "settings")
|
|
308
|
+
: isEditorExtensionsProjectionValue(value)));
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
function isStringArray(value) {
|
|
312
|
+
return (Array.isArray(value) && value.every((entry) => typeof entry === "string"));
|
|
313
|
+
}
|
|
314
|
+
function isRecord(value) {
|
|
315
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
316
|
+
}
|
|
317
|
+
function hasExactKeys(value, expectedKeys) {
|
|
318
|
+
const keys = Object.keys(value);
|
|
319
|
+
const expectedKeySet = new Set(expectedKeys);
|
|
320
|
+
return (keys.length === expectedKeySet.size &&
|
|
321
|
+
keys.every((key) => expectedKeySet.has(key)));
|
|
322
|
+
}
|
|
323
|
+
function isStructuralTurboValue(value) {
|
|
324
|
+
if (!isRecord(value) ||
|
|
325
|
+
!hasExactKeys(value, ["tasks"]) ||
|
|
326
|
+
!isRecord(value.tasks)) {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
return Object.values(value.tasks).every((task) => {
|
|
330
|
+
if (!isRecord(task)) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
return Object.entries(task).every(([key, entryValue]) => {
|
|
334
|
+
if (key === "dependsOn" || key === "outputs") {
|
|
335
|
+
return isStringArray(entryValue);
|
|
336
|
+
}
|
|
337
|
+
if (key === "cache" || key === "persistent") {
|
|
338
|
+
return typeof entryValue === "boolean";
|
|
339
|
+
}
|
|
340
|
+
return false;
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
const rootTsconfigConfigCompilerOptions = {
|
|
345
|
+
module: "NodeNext",
|
|
346
|
+
moduleResolution: "NodeNext",
|
|
347
|
+
noEmitOnError: true,
|
|
348
|
+
skipLibCheck: false,
|
|
349
|
+
strict: true,
|
|
350
|
+
target: "ES2022",
|
|
351
|
+
};
|
|
352
|
+
const rootTsconfigConfigIncludes = new Set([
|
|
353
|
+
"oxlint.config.ts",
|
|
354
|
+
"oxfmt.config.ts",
|
|
355
|
+
"playwright.config.ts",
|
|
356
|
+
"vite.config.ts",
|
|
357
|
+
"vitest.config.ts",
|
|
358
|
+
]);
|
|
359
|
+
function isStructuralTsconfigConfigValue(value) {
|
|
360
|
+
if (!isRecord(value) ||
|
|
361
|
+
!hasExactKeys(value, ["compilerOptions", "include"]) ||
|
|
362
|
+
!isRecord(value.compilerOptions) ||
|
|
363
|
+
!isStringArray(value.include)) {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
return (jsonValuesEqual(value.compilerOptions, rootTsconfigConfigCompilerOptions) &&
|
|
367
|
+
value.include.every((entry) => rootTsconfigConfigIncludes.has(entry)));
|
|
368
|
+
}
|
|
369
|
+
function isDevelopmentContainerPlanValue(expression) {
|
|
370
|
+
return isPropertyAccess(expression, "developmentContainer", "devcontainer");
|
|
371
|
+
}
|
|
372
|
+
function isAllowedStructuralMachineDeclaration(sourceFile, operation) {
|
|
373
|
+
if (operation.kind !== "writeJson") {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
if (operation.to === "turbo.json") {
|
|
377
|
+
return isStructuralTurboValue(operation.value);
|
|
378
|
+
}
|
|
379
|
+
if (operation.to === "tsconfig.config.json") {
|
|
380
|
+
return isStructuralTsconfigConfigValue(operation.value);
|
|
381
|
+
}
|
|
382
|
+
if (operation.to !== ".devcontainer/devcontainer.json") {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
const matches = findAstMatchesForOperation(sourceFile, operation);
|
|
386
|
+
return (matches.length > 0 &&
|
|
387
|
+
matches.every((match) => {
|
|
388
|
+
const value = propertyInitializer(match.node, "value");
|
|
389
|
+
return value !== undefined && isDevelopmentContainerPlanValue(value);
|
|
390
|
+
}));
|
|
391
|
+
}
|
|
392
|
+
function allowlistKey(preset, generatedPath, owningFunction) {
|
|
393
|
+
return `${preset}\0${owningFunction}\0${generatedPath}`;
|
|
394
|
+
}
|
|
395
|
+
export async function checkTemplateSourceBoundary({ projections, allowlist = [], }) {
|
|
396
|
+
const allowed = new Map(allowlist.map((entry) => [
|
|
397
|
+
allowlistKey(entry.preset, entry.generatedPath, entry.owningFunction),
|
|
398
|
+
entry.reason,
|
|
399
|
+
]));
|
|
400
|
+
const checkedPresets = new Set(projections.map((projection) => projection.name));
|
|
401
|
+
const usedAllowlistKeys = new Set();
|
|
402
|
+
const violations = [];
|
|
403
|
+
const allowlistedDebt = [];
|
|
404
|
+
for (const projection of projections) {
|
|
405
|
+
const sourceText = await readFile(projection.sourceFilePath, "utf8");
|
|
406
|
+
const sourceFile = ts.createSourceFile(projection.sourceFilePath, sourceText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
407
|
+
for (const operation of projection.plan.operations) {
|
|
408
|
+
if (!isInlineProtectedOperation(operation)) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (isStructuredEditorCustomizationOperation(sourceFile, operation)) {
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (isAllowedStructuralMachineDeclaration(sourceFile, operation)) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
const owningFunctions = findOwningFunctionsForOperation(sourceFile, operation);
|
|
418
|
+
for (const owningFunction of owningFunctions) {
|
|
419
|
+
const diagnostic = {
|
|
420
|
+
preset: projection.name,
|
|
421
|
+
generatedPath: operation.to,
|
|
422
|
+
owningFunction,
|
|
423
|
+
operationKind: operation.kind,
|
|
424
|
+
sourceFilePath: projection.sourceFilePath,
|
|
425
|
+
};
|
|
426
|
+
const allowlistReason = allowed.get(allowlistKey(projection.name, operation.to, owningFunction));
|
|
427
|
+
if (allowlistReason) {
|
|
428
|
+
usedAllowlistKeys.add(allowlistKey(projection.name, operation.to, owningFunction));
|
|
429
|
+
allowlistedDebt.push({ ...diagnostic, allowlistReason });
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
violations.push(diagnostic);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
const unusedAllowlistEntries = allowlist.filter((entry) => {
|
|
437
|
+
if (!checkedPresets.has(entry.preset)) {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
return !usedAllowlistKeys.has(allowlistKey(entry.preset, entry.generatedPath, entry.owningFunction));
|
|
441
|
+
});
|
|
442
|
+
return {
|
|
443
|
+
ok: violations.length === 0 && unusedAllowlistEntries.length === 0,
|
|
444
|
+
violations,
|
|
445
|
+
allowlistedDebt,
|
|
446
|
+
unusedAllowlistEntries,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
@@ -32,4 +32,3 @@ export type OnlineToolchainResolutionContractResult = {
|
|
|
32
32
|
export declare function resolveToolchainVersions(options?: ResolveToolchainVersionsOptions): Promise<ResolvedToolchainVersions>;
|
|
33
33
|
export declare function checkOnlineToolchainResolutionContract(options?: OnlineToolchainResolutionContractOptions): Promise<OnlineToolchainResolutionContractResult>;
|
|
34
34
|
export {};
|
|
35
|
-
//# sourceMappingURL=toolchain-resolution.d.ts.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { BuiltInPreset, ProjectBlueprint } from "../../src/declarations.js";
|
|
2
|
-
import type { PresetProjection } from "../../src/preset-projection.js";
|
|
2
|
+
import type { PresetBlueprintOptions, PresetProjection } from "../../src/preset-projection.js";
|
|
3
3
|
export declare const honoApiPresetMetadata: BuiltInPreset;
|
|
4
|
-
export declare function honoApiBlueprint(): ProjectBlueprint;
|
|
4
|
+
export declare function honoApiBlueprint(options?: PresetBlueprintOptions): ProjectBlueprint;
|
|
5
5
|
export declare function projectHonoApiPackageScripts(): Record<string, string>;
|
|
6
6
|
export declare const honoApiPresetProjection: PresetProjection;
|
|
7
|
-
//# sourceMappingURL=projection.d.ts.map
|