@webda/content-mapper 0.0.0-stage → 4.0.0-beta.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/LICENSE +166 -0
- package/lib/coercions.d.ts +22 -0
- package/lib/coercions.d.ts.map +1 -0
- package/lib/coercions.js +10 -0
- package/lib/coercions.js.map +1 -0
- package/lib/context.d.ts +56 -0
- package/lib/context.d.ts.map +1 -0
- package/lib/context.js +111 -0
- package/lib/context.js.map +1 -0
- package/lib/defaults.d.ts +31 -0
- package/lib/defaults.d.ts.map +1 -0
- package/lib/defaults.js +33 -0
- package/lib/defaults.js.map +1 -0
- package/lib/generators/accessors.d.ts +15 -0
- package/lib/generators/accessors.d.ts.map +1 -0
- package/lib/generators/accessors.js +567 -0
- package/lib/generators/accessors.js.map +1 -0
- package/lib/generators/behaviors.d.ts +21 -0
- package/lib/generators/behaviors.d.ts.map +1 -0
- package/lib/generators/behaviors.js +292 -0
- package/lib/generators/behaviors.js.map +1 -0
- package/lib/generators/imports.d.ts +86 -0
- package/lib/generators/imports.d.ts.map +1 -0
- package/lib/generators/imports.js +205 -0
- package/lib/generators/imports.js.map +1 -0
- package/lib/generators/loadparameters.d.ts +7 -0
- package/lib/generators/loadparameters.d.ts.map +1 -0
- package/lib/generators/loadparameters.js +175 -0
- package/lib/generators/loadparameters.js.map +1 -0
- package/lib/generators/qlvalidator.d.ts +53 -0
- package/lib/generators/qlvalidator.d.ts.map +1 -0
- package/lib/generators/qlvalidator.js +238 -0
- package/lib/generators/qlvalidator.js.map +1 -0
- package/lib/index.d.ts +53 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +36 -0
- package/lib/index.js.map +1 -0
- package/lib/module-discovery.d.ts +211 -0
- package/lib/module-discovery.d.ts.map +1 -0
- package/lib/module-discovery.js +662 -0
- package/lib/module-discovery.js.map +1 -0
- package/lib/module.d.ts +213 -0
- package/lib/module.d.ts.map +1 -0
- package/lib/module.js +1243 -0
- package/lib/module.js.map +1 -0
- package/lib/plan.d.ts +101 -0
- package/lib/plan.d.ts.map +1 -0
- package/lib/plan.js +61 -0
- package/lib/plan.js.map +1 -0
- package/lib/property-order.d.ts +37 -0
- package/lib/property-order.d.ts.map +1 -0
- package/lib/property-order.js +141 -0
- package/lib/property-order.js.map +1 -0
- package/lib/schema/action.d.ts +46 -0
- package/lib/schema/action.d.ts.map +1 -0
- package/lib/schema/action.js +190 -0
- package/lib/schema/action.js.map +1 -0
- package/lib/schema/annotations.d.ts +63 -0
- package/lib/schema/annotations.d.ts.map +1 -0
- package/lib/schema/annotations.js +116 -0
- package/lib/schema/annotations.js.map +1 -0
- package/lib/schema/converter.d.ts +363 -0
- package/lib/schema/converter.d.ts.map +1 -0
- package/lib/schema/converter.js +1377 -0
- package/lib/schema/converter.js.map +1 -0
- package/lib/schema/jsdoc.d.ts +34 -0
- package/lib/schema/jsdoc.d.ts.map +1 -0
- package/lib/schema/jsdoc.js +206 -0
- package/lib/schema/jsdoc.js.map +1 -0
- package/lib/schema/model.d.ts +27 -0
- package/lib/schema/model.d.ts.map +1 -0
- package/lib/schema/model.js +86 -0
- package/lib/schema/model.js.map +1 -0
- package/lib/schema/project.d.ts +34 -0
- package/lib/schema/project.d.ts.map +1 -0
- package/lib/schema/project.js +305 -0
- package/lib/schema/project.js.map +1 -0
- package/lib/schema/service.d.ts +62 -0
- package/lib/schema/service.d.ts.map +1 -0
- package/lib/schema/service.js +130 -0
- package/lib/schema/service.js.map +1 -0
- package/lib/schema/types.d.ts +61 -0
- package/lib/schema/types.d.ts.map +1 -0
- package/lib/schema/types.js +36 -0
- package/lib/schema/types.js.map +1 -0
- package/lib/schema/worker-cli.d.ts +3 -0
- package/lib/schema/worker-cli.d.ts.map +1 -0
- package/lib/schema/worker-cli.js +7 -0
- package/lib/schema/worker-cli.js.map +1 -0
- package/lib/schema/worker.d.ts +81 -0
- package/lib/schema/worker.d.ts.map +1 -0
- package/lib/schema/worker.js +186 -0
- package/lib/schema/worker.js.map +1 -0
- package/lib/server.d.ts +2 -0
- package/lib/server.d.ts.map +1 -0
- package/lib/server.js +133 -0
- package/lib/server.js.map +1 -0
- package/lib/session.d.ts +84 -0
- package/lib/session.d.ts.map +1 -0
- package/lib/session.js +141 -0
- package/lib/session.js.map +1 -0
- package/lib/spans.d.ts +46 -0
- package/lib/spans.d.ts.map +1 -0
- package/lib/spans.js +64 -0
- package/lib/spans.js.map +1 -0
- package/lib/twopass.d.ts +45 -0
- package/lib/twopass.d.ts.map +1 -0
- package/lib/twopass.js +87 -0
- package/lib/twopass.js.map +1 -0
- package/lib/vite.d.ts +20 -0
- package/lib/vite.d.ts.map +1 -0
- package/lib/vite.js +41 -0
- package/lib/vite.js.map +1 -0
- package/package.json +89 -3
- package/README.md +0 -3
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import * as is from "typescript/unstable/ast/is";
|
|
2
|
+
import { classesOf, isStatic, memberName } from "../context.js";
|
|
3
|
+
import { ValueImports } from "./imports.js";
|
|
4
|
+
/**
|
|
5
|
+
* Storage slot backing a Behaviour's `parent` reference.
|
|
6
|
+
*
|
|
7
|
+
* Must match `BEHAVIOR_PARENT_KEY` in `@webda/ts-plugin`: the per-Behaviour
|
|
8
|
+
* `parent` getter reads it and `toJSON` filters it out, so a mismatch silently
|
|
9
|
+
* serialises the parent back into stored data.
|
|
10
|
+
*/
|
|
11
|
+
export const BEHAVIOR_PARENT_KEY = "__parent__";
|
|
12
|
+
/**
|
|
13
|
+
* Whether a class carries the `@WebdaBehavior` JSDoc tag.
|
|
14
|
+
*
|
|
15
|
+
* Discovery is by tag rather than decorator, matching the compiler, so the
|
|
16
|
+
* marker leaves no runtime trace.
|
|
17
|
+
* @param ctx - analysis context
|
|
18
|
+
* @param sf - file declaring the class
|
|
19
|
+
* @param cls - the class declaration
|
|
20
|
+
* @returns true when the class is a Behaviour
|
|
21
|
+
*/
|
|
22
|
+
function hasBehaviorTag(ctx, sf, cls) {
|
|
23
|
+
return /@WebdaBehavior\b/.test(ctx.triviaOf(sf, cls));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve a property's type to a Behaviour class name.
|
|
27
|
+
*
|
|
28
|
+
* Returns undefined for primitives and for classes without the tag.
|
|
29
|
+
* @param ctx - analysis context
|
|
30
|
+
* @param sf - file holding the property
|
|
31
|
+
* @param typeNode - the property's type node
|
|
32
|
+
* @returns the Behaviour class name, when usable at runtime
|
|
33
|
+
*/
|
|
34
|
+
function resolveBehaviorClass(ctx, sf, typeNode) {
|
|
35
|
+
const type = ctx.checker.getTypeFromTypeNode(typeNode);
|
|
36
|
+
if (!type)
|
|
37
|
+
return undefined;
|
|
38
|
+
const symbol = type.getSymbol?.() ?? type.symbol;
|
|
39
|
+
const name = symbol?.name;
|
|
40
|
+
if (!name || !/^[A-Za-z_$][\w$]*$/.test(name))
|
|
41
|
+
return undefined;
|
|
42
|
+
const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
43
|
+
const node = declaration?.resolve(ctx.project);
|
|
44
|
+
if (!node || !is.isClassDeclaration(node))
|
|
45
|
+
return undefined;
|
|
46
|
+
const owner = node.getSourceFile?.() ?? node._sourceFile;
|
|
47
|
+
if (!owner || !/@WebdaBehavior\b/.test(ctx.triviaOf(owner, node)))
|
|
48
|
+
return undefined;
|
|
49
|
+
// The symbol name can differ from what the file imports — `@webda/core`
|
|
50
|
+
// exposes the alias `Binaries` while the class is `BinariesImpl`. Whether it
|
|
51
|
+
// can be made a runtime value here is the caller's decision, through
|
|
52
|
+
// `ValueImports`, which promotes or adds the import or refuses.
|
|
53
|
+
void sf;
|
|
54
|
+
return name;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether a name reaches this file only through a type-only import.
|
|
58
|
+
* @param sf - the file that will contain the generated reference
|
|
59
|
+
* @param name - identifier to be used as a value
|
|
60
|
+
* @returns true when the name is imported for types only
|
|
61
|
+
*/
|
|
62
|
+
function isTypeOnlyImport(sf, name) {
|
|
63
|
+
for (const statement of sf.statements) {
|
|
64
|
+
if (!is.isImportDeclaration(statement))
|
|
65
|
+
continue;
|
|
66
|
+
const clause = statement.importClause;
|
|
67
|
+
const elements = clause?.namedBindings?.elements;
|
|
68
|
+
if (!elements)
|
|
69
|
+
continue;
|
|
70
|
+
for (const element of elements) {
|
|
71
|
+
if (element.name?.text === name && (clause.isTypeOnly || element.isTypeOnly))
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Whether the class already declares the `[WEBDA_STORAGE]` slot.
|
|
79
|
+
*
|
|
80
|
+
* The name is computed, so `memberName` returns undefined for it and a
|
|
81
|
+
* name-based lookup silently misses it — injecting a second declaration then
|
|
82
|
+
* produces TS2300/TS2687/TS2416 against the inherited one.
|
|
83
|
+
* @param ctx - analysis context
|
|
84
|
+
* @param sf - file declaring the class
|
|
85
|
+
* @param cls - the class declaration
|
|
86
|
+
* @returns true when a storage slot is already declared
|
|
87
|
+
*/
|
|
88
|
+
function hasStorageSlot(ctx, sf, cls) {
|
|
89
|
+
for (const member of cls.members ?? []) {
|
|
90
|
+
const name = member.name;
|
|
91
|
+
if (name && /\bWEBDA_STORAGE\b/.test(ctx.textOf(sf, name)))
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
// The slot may be inherited with a narrower shape — `@webda/core`'s binary
|
|
95
|
+
// service declares `protected [WEBDA_STORAGE]: { service: ... }`. Redeclaring
|
|
96
|
+
// it as a loose record is TS2416, and skipping the redeclaration keeps the
|
|
97
|
+
// base type intact. Unique-symbol keys surface as `__@WEBDA_STORAGE@<id>`.
|
|
98
|
+
const symbol = cls.name ? ctx.checker.getSymbolAtLocation(cls.name) : undefined;
|
|
99
|
+
const declared = symbol ? ctx.checker.getDeclaredTypeOfSymbol(symbol) : undefined;
|
|
100
|
+
for (const property of declared?.getProperties?.() ?? []) {
|
|
101
|
+
if (/WEBDA_STORAGE/.test(property.name ?? ""))
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Names of members the class already declares.
|
|
108
|
+
* @param cls - the class declaration
|
|
109
|
+
* @returns declared member names
|
|
110
|
+
*/
|
|
111
|
+
function declaredMembers(cls) {
|
|
112
|
+
const names = new Set();
|
|
113
|
+
for (const member of cls.members ?? []) {
|
|
114
|
+
const name = memberName(member);
|
|
115
|
+
if (name)
|
|
116
|
+
names.add(name);
|
|
117
|
+
}
|
|
118
|
+
return names;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The `toJSON` injected into Behaviour classes.
|
|
122
|
+
*
|
|
123
|
+
* Copies own properties, then merges the storage slot while dropping the parent
|
|
124
|
+
* back-reference — serialising it would create a cycle.
|
|
125
|
+
* @param i - indentation of class members
|
|
126
|
+
* @returns generated source
|
|
127
|
+
*/
|
|
128
|
+
function renderToJSON(i) {
|
|
129
|
+
return [
|
|
130
|
+
`${i}toJSON() {`,
|
|
131
|
+
`${i} const result: Record<string, any> = {};`,
|
|
132
|
+
`${i} for (const key of Object.keys(this)) {`,
|
|
133
|
+
`${i} result[key] = (this as any)[key];`,
|
|
134
|
+
`${i} }`,
|
|
135
|
+
`${i} const storage: Record<string, any> | undefined = (this as any)[WEBDA_STORAGE];`,
|
|
136
|
+
`${i} if (storage) {`,
|
|
137
|
+
`${i} for (const key of Object.keys(storage)) {`,
|
|
138
|
+
`${i} if (key !== ${JSON.stringify(BEHAVIOR_PARENT_KEY)}) {`,
|
|
139
|
+
`${i} result[key] = storage[key];`,
|
|
140
|
+
`${i} }`,
|
|
141
|
+
`${i} }`,
|
|
142
|
+
`${i} }`,
|
|
143
|
+
`${i} return result;`,
|
|
144
|
+
`${i}}`
|
|
145
|
+
].join("\n");
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* One hydration block, for a single Behaviour-typed property.
|
|
149
|
+
*
|
|
150
|
+
* Takes the current value or the raw stored value, coerces it into a Behaviour
|
|
151
|
+
* instance, and links it back to its owner.
|
|
152
|
+
* @param property - property name
|
|
153
|
+
* @param behaviorClass - Behaviour class to instantiate
|
|
154
|
+
* @param i - indentation of the method body
|
|
155
|
+
* @param arrayLike - fill an Array-derived behaviour item by item
|
|
156
|
+
* @returns generated source
|
|
157
|
+
*/
|
|
158
|
+
function renderHydrationBlock(property, behaviorClass, i, arrayLike = false) {
|
|
159
|
+
const key = JSON.stringify(property);
|
|
160
|
+
// An Array-derived behaviour (`BinariesImpl`) is filled item by item, as
|
|
161
|
+
// the TypeScript 6 transformer does. `Object.assign` onto an array copies
|
|
162
|
+
// indices but is not what ships, and the oracle holds it to what ships.
|
|
163
|
+
const fill = arrayLike
|
|
164
|
+
? [
|
|
165
|
+
`${i} if (Array.isArray(v)) {`,
|
|
166
|
+
`${i} for (const item of v) {`,
|
|
167
|
+
`${i} inst.push(item);`,
|
|
168
|
+
`${i} }`,
|
|
169
|
+
`${i} }`
|
|
170
|
+
]
|
|
171
|
+
: [`${i} if (v !== undefined && v !== null) {`, `${i} Object.assign(inst, v);`, `${i} }`];
|
|
172
|
+
return [
|
|
173
|
+
`${i}{`,
|
|
174
|
+
`${i} let v: any = this.${property};`,
|
|
175
|
+
`${i} if (rawData !== undefined && rawData !== null && rawData[${key}] !== undefined) {`,
|
|
176
|
+
`${i} v = rawData[${key}];`,
|
|
177
|
+
`${i} }`,
|
|
178
|
+
`${i} if (!(v instanceof ${behaviorClass})) {`,
|
|
179
|
+
`${i} const inst = new ${behaviorClass}();`,
|
|
180
|
+
...fill,
|
|
181
|
+
`${i} v = inst;`,
|
|
182
|
+
`${i} }`,
|
|
183
|
+
`${i} (v as any)[WEBDA_STORAGE] = (v as any)[WEBDA_STORAGE] || {};`,
|
|
184
|
+
`${i} (v as any)[WEBDA_STORAGE][${JSON.stringify(BEHAVIOR_PARENT_KEY)}] = { instance: this, attribute: ${key} };`,
|
|
185
|
+
`${i} this.${property} = v;`,
|
|
186
|
+
`${i}}`
|
|
187
|
+
].join("\n");
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Create the behaviour generator.
|
|
191
|
+
* @param options - generator options
|
|
192
|
+
* @returns a generator
|
|
193
|
+
*/
|
|
194
|
+
export function behaviorsGenerator(options = {}) {
|
|
195
|
+
const storageModule = options.storageModule ?? "@webda/models";
|
|
196
|
+
return {
|
|
197
|
+
name: "behaviors",
|
|
198
|
+
analyze(ctx) {
|
|
199
|
+
const out = [];
|
|
200
|
+
for (const sf of ctx.sourceFiles) {
|
|
201
|
+
const edits = [];
|
|
202
|
+
const imports = new ValueImports(ctx, sf, "behaviors");
|
|
203
|
+
let needsStorage = false;
|
|
204
|
+
for (const cls of classesOf(sf)) {
|
|
205
|
+
const existing = declaredMembers(cls);
|
|
206
|
+
// Members start immediately after the class's `{`; the closing brace
|
|
207
|
+
// is the last character of the declaration.
|
|
208
|
+
const openPos = cls.members?.pos ?? undefined;
|
|
209
|
+
const closePos = cls.end - 1;
|
|
210
|
+
if (openPos === undefined)
|
|
211
|
+
continue;
|
|
212
|
+
const memberIndent = `${ctx.textOf(sf, cls).match(/\n([ \t]+)\S/)?.[1] ?? " "}`;
|
|
213
|
+
if (hasBehaviorTag(ctx, sf, cls)) {
|
|
214
|
+
needsStorage = true;
|
|
215
|
+
if (!hasStorageSlot(ctx, sf, cls)) {
|
|
216
|
+
edits.push({
|
|
217
|
+
start: openPos,
|
|
218
|
+
end: openPos,
|
|
219
|
+
text: `\n${memberIndent}[WEBDA_STORAGE]: Record<string, any> = {};`,
|
|
220
|
+
source: "behaviors"
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (!existing.has("parent")) {
|
|
224
|
+
edits.push({
|
|
225
|
+
start: closePos,
|
|
226
|
+
end: closePos,
|
|
227
|
+
text: `${memberIndent}get parent() { return this[WEBDA_STORAGE][${JSON.stringify(BEHAVIOR_PARENT_KEY)}]; }\n`,
|
|
228
|
+
source: "behaviors"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
// An author-written toJSON wins; replacing it would drop their shape.
|
|
232
|
+
if (!existing.has("toJSON")) {
|
|
233
|
+
edits.push({
|
|
234
|
+
start: closePos,
|
|
235
|
+
end: closePos,
|
|
236
|
+
text: `${renderToJSON(memberIndent)}\n`,
|
|
237
|
+
source: "behaviors"
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// Behaviour-typed properties anywhere gain hydration.
|
|
242
|
+
if (existing.has("__hydrateBehaviors"))
|
|
243
|
+
continue;
|
|
244
|
+
const blocks = [];
|
|
245
|
+
for (const member of cls.members ?? []) {
|
|
246
|
+
if (!is.isPropertyDeclaration(member) || isStatic(member))
|
|
247
|
+
continue;
|
|
248
|
+
const name = memberName(member);
|
|
249
|
+
if (!name || !member.type)
|
|
250
|
+
continue;
|
|
251
|
+
const typeNode = member.type;
|
|
252
|
+
const behaviorClass = resolveBehaviorClass(ctx, sf, typeNode);
|
|
253
|
+
if (!behaviorClass)
|
|
254
|
+
continue;
|
|
255
|
+
// `new BinariesImpl()` needs a binding. `Binaries<...>` names the
|
|
256
|
+
// alias, so its module is where the class is looked for.
|
|
257
|
+
const via = [...new Set(ctx.textOf(sf, typeNode).match(/[A-Za-z_$][\w$]*/g) ?? [])];
|
|
258
|
+
if (!imports.ensure(behaviorClass, typeNode, via))
|
|
259
|
+
continue;
|
|
260
|
+
const arrayLike = ctx.checker.isArrayLikeType(ctx.checker.getTypeFromTypeNode(typeNode));
|
|
261
|
+
blocks.push(renderHydrationBlock(name, behaviorClass, `${memberIndent} `, arrayLike));
|
|
262
|
+
}
|
|
263
|
+
if (!blocks.length)
|
|
264
|
+
continue;
|
|
265
|
+
needsStorage = true;
|
|
266
|
+
edits.push({
|
|
267
|
+
start: closePos,
|
|
268
|
+
end: closePos,
|
|
269
|
+
text: `${memberIndent}protected __hydrateBehaviors(rawData?: any): void {\n` +
|
|
270
|
+
`${blocks.join("\n")}\n` +
|
|
271
|
+
`${memberIndent}}\n`,
|
|
272
|
+
source: "behaviors"
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
if (edits.length) {
|
|
276
|
+
edits.push(...imports.collect());
|
|
277
|
+
if (needsStorage && !/\bWEBDA_STORAGE\b/.test(sf.text)) {
|
|
278
|
+
edits.push({
|
|
279
|
+
start: 0,
|
|
280
|
+
end: 0,
|
|
281
|
+
text: `import { WEBDA_STORAGE } from ${JSON.stringify(storageModule)};\n`,
|
|
282
|
+
source: "behaviors"
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
out.push({ fileName: sf.fileName, edits });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return out;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=behaviors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behaviors.js","sourceRoot":"","sources":["../../src/generators/behaviors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { SourceFile } from "typescript/unstable/ast";
|
|
2
|
+
import type { AnalysisContext, Edit } from "../plan.ts";
|
|
3
|
+
/** Collects the import edits one file needs. */
|
|
4
|
+
export declare class ValueImports {
|
|
5
|
+
private readonly ctx;
|
|
6
|
+
private readonly sf;
|
|
7
|
+
private readonly source;
|
|
8
|
+
private readonly edits;
|
|
9
|
+
/**
|
|
10
|
+
* @param ctx - analysis context
|
|
11
|
+
* @param sf - the file the generated code goes into
|
|
12
|
+
* @param source - generator name, recorded on the edits
|
|
13
|
+
*/
|
|
14
|
+
constructor(ctx: AnalysisContext, sf: SourceFile, source: string);
|
|
15
|
+
/**
|
|
16
|
+
* Ensure `name` is a runtime value in this file.
|
|
17
|
+
* @param name - identifier the generated code will use as a value
|
|
18
|
+
* @param location - node the reference will appear at, for scope lookup
|
|
19
|
+
* @param via - names the file already imports whose module may export
|
|
20
|
+
* `name`, nearest first — e.g. `BelongTo` for `ModelLink`
|
|
21
|
+
* @returns true when the name is, or will be, available as a value
|
|
22
|
+
*/
|
|
23
|
+
ensure(name: string, location: unknown, via?: string[]): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Ensure `name` can be used in a type position in this file.
|
|
26
|
+
*
|
|
27
|
+
* The type-level twin of {@link ensure}: a setter's parameter type is
|
|
28
|
+
* printed from the relation's own `set` signature, so it can name types the
|
|
29
|
+
* file never imports — `PrimaryKeyType<User>`. An `import type` is erased at
|
|
30
|
+
* emit, so adding one cannot change runtime behaviour.
|
|
31
|
+
* @param name - identifier the generated code will use as a type
|
|
32
|
+
* @param location - node the reference will appear at, for scope lookup
|
|
33
|
+
* @param via - names the file already imports whose module may export `name`
|
|
34
|
+
* @returns true when the name is, or will be, available as a type
|
|
35
|
+
*/
|
|
36
|
+
ensureType(name: string, location: unknown, via?: string[]): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The edits accumulated so far.
|
|
39
|
+
* @returns promotions and additions, in a stable order
|
|
40
|
+
*/
|
|
41
|
+
collect(): Edit[];
|
|
42
|
+
/**
|
|
43
|
+
* Snapshot the pending edits, so a property rejected by a later check does
|
|
44
|
+
* not leave an import behind for code that was never generated.
|
|
45
|
+
* @returns a function restoring the snapshot
|
|
46
|
+
*/
|
|
47
|
+
checkpoint(): () => void;
|
|
48
|
+
/**
|
|
49
|
+
* Find the import binding a name, if any.
|
|
50
|
+
* @param name - the local name
|
|
51
|
+
* @returns the declaration, the element, and whether it is type-only
|
|
52
|
+
*/
|
|
53
|
+
private importOf;
|
|
54
|
+
/**
|
|
55
|
+
* Turn a type-only import of a name into a value import.
|
|
56
|
+
*
|
|
57
|
+
* `import { type X }` loses its inline `type`. `import type { X, Y }` loses
|
|
58
|
+
* the declaration-level one, which makes Y a value import too — harmless
|
|
59
|
+
* without `verbatimModuleSyntax`, since an unused or type-only value import
|
|
60
|
+
* is still elided.
|
|
61
|
+
* @param binding - the import to promote
|
|
62
|
+
*/
|
|
63
|
+
private promote;
|
|
64
|
+
/**
|
|
65
|
+
* Record a deletion keyed by position, so repeated promotions collapse.
|
|
66
|
+
* @param start - offset of the text to remove
|
|
67
|
+
* @param length - characters to remove
|
|
68
|
+
*/
|
|
69
|
+
private addRemoval;
|
|
70
|
+
/**
|
|
71
|
+
* Whether the module an import declaration names exports `name` as a value.
|
|
72
|
+
* @param declaration - an import declaration in this file
|
|
73
|
+
* @param name - the export to look for
|
|
74
|
+
* @returns true when the module exports a value by that name
|
|
75
|
+
*/
|
|
76
|
+
private moduleExportsValue;
|
|
77
|
+
/**
|
|
78
|
+
* Whether the module an import declaration names exports `name` with a meaning.
|
|
79
|
+
* @param declaration - an import declaration in this file
|
|
80
|
+
* @param name - the export to look for
|
|
81
|
+
* @param meaning - `Value` or `Type`
|
|
82
|
+
* @returns true when the module exports `name` with that meaning
|
|
83
|
+
*/
|
|
84
|
+
private moduleExports;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=imports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/generators/imports.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,OAAO,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAExD,gDAAgD;AAChD,qBAAa,YAAY;IASrB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IAEjD;;;;OAIG;IACH,YACmB,GAAG,EAAE,eAAe,EACpB,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,MAAM,EAC7B;IAEJ;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,OAAO,CAmBnE;IAED;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,OAAO,CAYvE;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,EAAE,CAEhB;IAED;;;;OAIG;IACH,UAAU,IAAI,MAAM,IAAI,CAMvB;IAED;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAiBhB;;;;;;;;OAQG;IACH,OAAO,CAAC,OAAO;IAcf;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAIlB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;CAQtB"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make a name usable as a runtime value in a file, or report that it cannot be.
|
|
3
|
+
*
|
|
4
|
+
* Generated code constructs things — `new ModelLink(User)`,
|
|
5
|
+
* `new ModelRelated(Ident, this, "_user")`, `new BinariesImpl()` — so every
|
|
6
|
+
* name it mentions has to survive emit as a value. Authors routinely import
|
|
7
|
+
* those names as types only, or not at all (`BelongTo<User>` names the alias,
|
|
8
|
+
* not the `ModelLink` it resolves to). The TypeScript 6 transformers papered
|
|
9
|
+
* over this by synthesising imports from the declaring file's path, which for
|
|
10
|
+
* workspace packages — symlinks — produced monorepo-relative specifiers like
|
|
11
|
+
* `"../../../models/lib/relations.js"` that break once installed from npm.
|
|
12
|
+
*
|
|
13
|
+
* Only two moves are allowed, and anything else is refused:
|
|
14
|
+
*
|
|
15
|
+
* 1. **Promote** an existing `import type` of the name to a value import. The
|
|
16
|
+
* author already chose the module; only the erasure changes.
|
|
17
|
+
* 2. **Add** `import { Name }` from a module the file already imports another
|
|
18
|
+
* name from, when the checker confirms that module exports `Name` as a
|
|
19
|
+
* value. The specifier is the one the author wrote, never a computed path.
|
|
20
|
+
*
|
|
21
|
+
* Each import is emitted as its own statement and each promotion as a fixed
|
|
22
|
+
* range, so two generators that need the same name produce identical edits,
|
|
23
|
+
* which `mergePlan` collapses — rather than duplicate bindings, which are
|
|
24
|
+
* TS2300.
|
|
25
|
+
*/
|
|
26
|
+
import { SymbolFlags } from "typescript/unstable/sync";
|
|
27
|
+
import * as is from "typescript/unstable/ast/is";
|
|
28
|
+
/** Collects the import edits one file needs. */
|
|
29
|
+
export class ValueImports {
|
|
30
|
+
ctx;
|
|
31
|
+
sf;
|
|
32
|
+
source;
|
|
33
|
+
edits = new Map();
|
|
34
|
+
/**
|
|
35
|
+
* @param ctx - analysis context
|
|
36
|
+
* @param sf - the file the generated code goes into
|
|
37
|
+
* @param source - generator name, recorded on the edits
|
|
38
|
+
*/
|
|
39
|
+
constructor(ctx, sf, source) {
|
|
40
|
+
this.ctx = ctx;
|
|
41
|
+
this.sf = sf;
|
|
42
|
+
this.source = source;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Ensure `name` is a runtime value in this file.
|
|
46
|
+
* @param name - identifier the generated code will use as a value
|
|
47
|
+
* @param location - node the reference will appear at, for scope lookup
|
|
48
|
+
* @param via - names the file already imports whose module may export
|
|
49
|
+
* `name`, nearest first — e.g. `BelongTo` for `ModelLink`
|
|
50
|
+
* @returns true when the name is, or will be, available as a value
|
|
51
|
+
*/
|
|
52
|
+
ensure(name, location, via = []) {
|
|
53
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(name))
|
|
54
|
+
return false;
|
|
55
|
+
const importing = this.importOf(name);
|
|
56
|
+
if (importing) {
|
|
57
|
+
if (importing.typeOnly)
|
|
58
|
+
this.promote(importing);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
// Declared in this file, or global.
|
|
62
|
+
if (this.ctx.checker.resolveName(name, SymbolFlags.Value, location))
|
|
63
|
+
return true;
|
|
64
|
+
for (const hint of via) {
|
|
65
|
+
const hinted = this.importOf(hint);
|
|
66
|
+
if (!hinted || !this.moduleExportsValue(hinted.declaration, name))
|
|
67
|
+
continue;
|
|
68
|
+
const text = `import { ${name} } from ${this.ctx.textOf(this.sf, hinted.declaration.moduleSpecifier)};\n`;
|
|
69
|
+
this.edits.set(`add:${name}`, { start: 0, end: 0, text, source: this.source });
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Ensure `name` can be used in a type position in this file.
|
|
76
|
+
*
|
|
77
|
+
* The type-level twin of {@link ensure}: a setter's parameter type is
|
|
78
|
+
* printed from the relation's own `set` signature, so it can name types the
|
|
79
|
+
* file never imports — `PrimaryKeyType<User>`. An `import type` is erased at
|
|
80
|
+
* emit, so adding one cannot change runtime behaviour.
|
|
81
|
+
* @param name - identifier the generated code will use as a type
|
|
82
|
+
* @param location - node the reference will appear at, for scope lookup
|
|
83
|
+
* @param via - names the file already imports whose module may export `name`
|
|
84
|
+
* @returns true when the name is, or will be, available as a type
|
|
85
|
+
*/
|
|
86
|
+
ensureType(name, location, via = []) {
|
|
87
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(name))
|
|
88
|
+
return false;
|
|
89
|
+
if (this.importOf(name))
|
|
90
|
+
return true;
|
|
91
|
+
if (this.ctx.checker.resolveName(name, SymbolFlags.Type, location))
|
|
92
|
+
return true;
|
|
93
|
+
for (const hint of via) {
|
|
94
|
+
const hinted = this.importOf(hint);
|
|
95
|
+
if (!hinted || !this.moduleExports(hinted.declaration, name, SymbolFlags.Type))
|
|
96
|
+
continue;
|
|
97
|
+
const text = `import type { ${name} } from ${this.ctx.textOf(this.sf, hinted.declaration.moduleSpecifier)};\n`;
|
|
98
|
+
this.edits.set(`type:${name}`, { start: 0, end: 0, text, source: this.source });
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The edits accumulated so far.
|
|
105
|
+
* @returns promotions and additions, in a stable order
|
|
106
|
+
*/
|
|
107
|
+
collect() {
|
|
108
|
+
return [...this.edits.values()];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Snapshot the pending edits, so a property rejected by a later check does
|
|
112
|
+
* not leave an import behind for code that was never generated.
|
|
113
|
+
* @returns a function restoring the snapshot
|
|
114
|
+
*/
|
|
115
|
+
checkpoint() {
|
|
116
|
+
const saved = new Map(this.edits);
|
|
117
|
+
return () => {
|
|
118
|
+
this.edits.clear();
|
|
119
|
+
for (const [key, edit] of saved)
|
|
120
|
+
this.edits.set(key, edit);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Find the import binding a name, if any.
|
|
125
|
+
* @param name - the local name
|
|
126
|
+
* @returns the declaration, the element, and whether it is type-only
|
|
127
|
+
*/
|
|
128
|
+
importOf(name) {
|
|
129
|
+
for (const statement of this.sf.statements) {
|
|
130
|
+
if (!is.isImportDeclaration(statement))
|
|
131
|
+
continue;
|
|
132
|
+
const declaration = statement;
|
|
133
|
+
const clause = declaration.importClause;
|
|
134
|
+
if (!clause)
|
|
135
|
+
continue;
|
|
136
|
+
if (clause.name?.text === name) {
|
|
137
|
+
return { declaration, clause, element: undefined, typeOnly: !!clause.isTypeOnly };
|
|
138
|
+
}
|
|
139
|
+
for (const element of clause.namedBindings?.elements ?? []) {
|
|
140
|
+
if (element.name?.text !== name)
|
|
141
|
+
continue;
|
|
142
|
+
return { declaration, clause, element, typeOnly: !!(clause.isTypeOnly || element.isTypeOnly) };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Turn a type-only import of a name into a value import.
|
|
149
|
+
*
|
|
150
|
+
* `import { type X }` loses its inline `type`. `import type { X, Y }` loses
|
|
151
|
+
* the declaration-level one, which makes Y a value import too — harmless
|
|
152
|
+
* without `verbatimModuleSyntax`, since an unused or type-only value import
|
|
153
|
+
* is still elided.
|
|
154
|
+
* @param binding - the import to promote
|
|
155
|
+
*/
|
|
156
|
+
promote(binding) {
|
|
157
|
+
if (binding.element?.isTypeOnly) {
|
|
158
|
+
const start = binding.element.getStart();
|
|
159
|
+
const match = /^type\s+/.exec(this.sf.text.slice(start, binding.element.end));
|
|
160
|
+
if (match)
|
|
161
|
+
this.addRemoval(start, match[0].length);
|
|
162
|
+
}
|
|
163
|
+
if (binding.clause.isTypeOnly) {
|
|
164
|
+
const start = binding.declaration.getStart();
|
|
165
|
+
const match = /^import(\s+)type\s+/.exec(this.sf.text.slice(start, binding.declaration.end));
|
|
166
|
+
if (match)
|
|
167
|
+
this.addRemoval(start + "import".length + match[1].length, match[0].length - "import".length - match[1].length);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Record a deletion keyed by position, so repeated promotions collapse.
|
|
172
|
+
* @param start - offset of the text to remove
|
|
173
|
+
* @param length - characters to remove
|
|
174
|
+
*/
|
|
175
|
+
addRemoval(start, length) {
|
|
176
|
+
this.edits.set(`promote:${start}`, { start, end: start + length, text: "", source: this.source });
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Whether the module an import declaration names exports `name` as a value.
|
|
180
|
+
* @param declaration - an import declaration in this file
|
|
181
|
+
* @param name - the export to look for
|
|
182
|
+
* @returns true when the module exports a value by that name
|
|
183
|
+
*/
|
|
184
|
+
moduleExportsValue(declaration, name) {
|
|
185
|
+
return this.moduleExports(declaration, name, SymbolFlags.Value);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Whether the module an import declaration names exports `name` with a meaning.
|
|
189
|
+
* @param declaration - an import declaration in this file
|
|
190
|
+
* @param name - the export to look for
|
|
191
|
+
* @param meaning - `Value` or `Type`
|
|
192
|
+
* @returns true when the module exports `name` with that meaning
|
|
193
|
+
*/
|
|
194
|
+
moduleExports(declaration, name, meaning) {
|
|
195
|
+
const moduleSymbol = this.ctx.checker.getSymbolAtLocation(declaration.moduleSpecifier);
|
|
196
|
+
if (!moduleSymbol)
|
|
197
|
+
return false;
|
|
198
|
+
const exported = this.ctx.checker.getExportsOfModule(moduleSymbol).find(symbol => symbol.name === name);
|
|
199
|
+
if (!exported)
|
|
200
|
+
return false;
|
|
201
|
+
const target = exported.flags & SymbolFlags.Alias ? this.ctx.checker.getAliasedSymbol(exported) : exported;
|
|
202
|
+
return (target.flags & meaning) !== 0;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/generators/imports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadparameters.d.ts","sourceRoot":"","sources":["../../src/generators/loadparameters.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAoC,SAAS,EAAE,MAAM,YAAY,CAAC;AA6G9E;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,SAAS,CAyCnD"}
|