@vaadin/hilla-generator-plugin-signals 24.8.0-alpha2 → 24.8.0-alpha3
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/SignalProcessor.js +76 -170
- package/SignalProcessor.js.map +1 -1
- package/index.d.ts +1 -5
- package/index.js +12 -18
- package/index.js.map +1 -1
- package/package.json +10 -6
- package/utils.d.ts +4 -0
- package/utils.js +9 -0
- package/utils.js.map +1 -0
package/SignalProcessor.js
CHANGED
|
@@ -1,28 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { dirname, extname } from "node:path";
|
|
2
|
+
import { simplifyFullyQualifiedName } from "@vaadin/hilla-generator-core/Schema.js";
|
|
3
|
+
import { traverse } from "@vaadin/hilla-generator-utils/ast.js";
|
|
3
4
|
import createSourceFile from "@vaadin/hilla-generator-utils/createSourceFile.js";
|
|
4
5
|
import DependencyManager from "@vaadin/hilla-generator-utils/dependencies/DependencyManager.js";
|
|
5
6
|
import PathManager from "@vaadin/hilla-generator-utils/dependencies/PathManager.js";
|
|
6
|
-
import
|
|
7
|
+
import ast, { createTransformer } from "tsc-template";
|
|
8
|
+
import { factory, isTypeReferenceNode, isIdentifier, SyntaxKind, isTypeNode, transform, isFunctionDeclaration, isImportDeclaration, isUnionTypeNode } from "typescript";
|
|
9
|
+
import { ARRAY_TYPES, COLLECTION_SIGNALS, GENERIC_SIGNALS } from "./utils.js";
|
|
7
10
|
const HILLA_REACT_SIGNALS = "@vaadin/hilla-react-signals";
|
|
8
|
-
const
|
|
9
|
-
const METHOD_NAME = "$METHOD_NAME$";
|
|
10
|
-
const SIGNAL = "$SIGNAL$";
|
|
11
|
-
const RETURN_TYPE = "$RETURN_TYPE$";
|
|
12
|
-
const INITIAL_VALUE = "$INITIAL_VALUE$";
|
|
13
|
-
const signals = [
|
|
14
|
-
"NumberSignal",
|
|
15
|
-
"ValueSignal",
|
|
16
|
-
"ListSignal"
|
|
17
|
-
];
|
|
18
|
-
const genericSignals = ["ValueSignal", "ListSignal"];
|
|
19
|
-
const collectionSignals = ["ListSignal"];
|
|
20
|
-
const primitiveModels = Object.freeze(new Map([
|
|
21
|
-
[ts.SyntaxKind.StringKeyword, "StringModel"],
|
|
22
|
-
[ts.SyntaxKind.NumberKeyword, "NumberModel"],
|
|
23
|
-
[ts.SyntaxKind.BooleanKeyword, "BooleanModel"],
|
|
24
|
-
[ts.SyntaxKind.ArrayType, "ArrayModel"]
|
|
25
|
-
]));
|
|
11
|
+
const HILLA_LIT_FORM = "@vaadin/hilla-lit-form";
|
|
26
12
|
export default class SignalProcessor {
|
|
27
13
|
#dependencyManager;
|
|
28
14
|
#owner;
|
|
@@ -40,171 +26,91 @@ export default class SignalProcessor {
|
|
|
40
26
|
process() {
|
|
41
27
|
this.#owner.logger.debug(`Processing signals: ${this.#service}`);
|
|
42
28
|
const { imports } = this.#dependencyManager;
|
|
43
|
-
const [, connectClientId] = imports.default
|
|
29
|
+
const [, connectClientId] = Iterator.from(imports.default).find(([path]) => path.includes("connect-client"));
|
|
44
30
|
const initTypeId = imports.named.getIdentifier("@vaadin/hilla-frontend", "EndpointRequestInit");
|
|
45
31
|
let initTypeUsageCount = 0;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
transform((node) => ts.isIdentifier(node) && node.text === METHOD_NAME ? tsNode.name : node),
|
|
66
|
-
transform((node) => ts.isIdentifier(node) && node.text === SIGNAL ? signalId : node),
|
|
67
|
-
transform((node) => ts.isIdentifier(node) && node.text === RETURN_TYPE ? returnType : node),
|
|
68
|
-
transform((node) => ts.isIdentifier(node) && node.text === CONNECT_CLIENT ? connectClientId : node),
|
|
69
|
-
transform((node) => ts.isIdentifier(node) && node.text === INITIAL_VALUE ? defaultValueExpression : node)
|
|
70
|
-
]);
|
|
32
|
+
const [file] = transform(this.#sourceFile, [createTransformer((node) => {
|
|
33
|
+
if (isFunctionDeclaration(node)) {
|
|
34
|
+
if (node.name && this.#methods.has(node.name.text)) {
|
|
35
|
+
const signalId = imports.named.getIdentifier(HILLA_REACT_SIGNALS, simplifyFullyQualifiedName(this.#methods.get(node.name.text)));
|
|
36
|
+
const params = node.parameters.filter((p) => !(p.type && isTypeReferenceNode(p.type) && p.type.typeName === initTypeId));
|
|
37
|
+
const { defaultValue, defaultValueParameter } = this.#createDefaultValue(signalId.text, node.type);
|
|
38
|
+
const modifiers = node.modifiers?.filter((m) => m.kind !== SyntaxKind.AsyncKeyword);
|
|
39
|
+
const type = node.type && isTypeReferenceNode(node.type) && isIdentifier(node.type.typeName) && node.type.typeName.text === "Promise" ? node.type.typeArguments?.[0] : node.type;
|
|
40
|
+
const paramNames = params.map((p) => p.name).filter((n) => isIdentifier(n)).map((n) => n.text);
|
|
41
|
+
const result = ast`function dummy() { %{
|
|
42
|
+
return new ${signalId}(${defaultValue}${defaultValue ? "," : ""}{
|
|
43
|
+
client: ${connectClientId},
|
|
44
|
+
endpoint: '${this.#service}',
|
|
45
|
+
method: '${node.name.text}'
|
|
46
|
+
${paramNames.length ? `, params: { ${paramNames.join("\n")} }` : ""} });
|
|
47
|
+
}% });`;
|
|
48
|
+
return factory.updateFunctionDeclaration(node, modifiers, node.asteriskToken, node.name, node.typeParameters, defaultValueParameter ? [...params, defaultValueParameter] : params, type, factory.createBlock([result.node]));
|
|
49
|
+
} else if (node.parameters.some((p) => p.type && isTypeReferenceNode(p.type) && p.type.typeName === initTypeId)) {
|
|
50
|
+
initTypeUsageCount += 1;
|
|
71
51
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (ts.isFunctionDeclaration(tsNode) && tsNode.name && this.#methods.has(tsNode.name.text) && functionParams.has(tsNode.name.text)) {
|
|
76
|
-
return ts.factory.updateFunctionDeclaration(tsNode, tsNode.modifiers, tsNode.asteriskToken, tsNode.name, tsNode.typeParameters, functionParams.get(tsNode.name.text), tsNode.type, tsNode.body);
|
|
77
|
-
}
|
|
78
|
-
return tsNode;
|
|
79
|
-
}),
|
|
80
|
-
transform((tsNode) => {
|
|
81
|
-
if (ts.isFunctionDeclaration(tsNode)) {
|
|
82
|
-
if (!(tsNode.name && this.#methods.has(tsNode.name.text)) && tsNode.parameters.some((p) => p.type && ts.isTypeReferenceNode(p.type) && p.type.typeName === initTypeId)) {
|
|
83
|
-
initTypeUsageCount += 1;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return tsNode;
|
|
87
|
-
})
|
|
88
|
-
]).transformed;
|
|
52
|
+
}
|
|
53
|
+
return node;
|
|
54
|
+
})]).transformed;
|
|
89
55
|
if (initTypeUsageCount === 0) {
|
|
90
56
|
imports.named.remove("@vaadin/hilla-frontend", "EndpointRequestInit");
|
|
91
57
|
}
|
|
92
|
-
return createSourceFile([...this.#dependencyManager.imports.toCode(), ...file.statements.filter((statement) => !
|
|
93
|
-
}
|
|
94
|
-
#createDefaultValue(signalId, functionDeclaration) {
|
|
95
|
-
const defaultValue = {
|
|
96
|
-
defaultValueExpression: signalId.text.startsWith("NumberSignal") ? ts.factory.createNumericLiteral("0") : ts.factory.createIdentifier("undefined"),
|
|
97
|
-
defaultValueParam: undefined,
|
|
98
|
-
genericReturnType: undefined
|
|
99
|
-
};
|
|
100
|
-
if (!genericSignals.includes(signalId.text)) {
|
|
101
|
-
return defaultValue;
|
|
102
|
-
}
|
|
103
|
-
[defaultValue.genericReturnType] = functionDeclaration.type.typeArguments;
|
|
104
|
-
if (collectionSignals.includes(signalId.text)) {
|
|
105
|
-
return defaultValue;
|
|
106
|
-
}
|
|
107
|
-
const defaultValueType = SignalProcessor.#getDefaultValueType(defaultValue.genericReturnType);
|
|
108
|
-
if (!defaultValueType) {
|
|
109
|
-
return defaultValue;
|
|
110
|
-
}
|
|
111
|
-
defaultValue.defaultValueParam = SignalProcessor.#createDefaultValueParameter(defaultValueType);
|
|
112
|
-
const emptyValueExpression = this.#createEmptyValueExpression(defaultValueType);
|
|
113
|
-
defaultValue.defaultValueExpression = ts.factory.createBinaryExpression(ts.factory.createPropertyAccessChain(ts.factory.createIdentifier("options"), ts.factory.createToken(ts.SyntaxKind.QuestionDotToken), ts.factory.createIdentifier("defaultValue")), ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken), emptyValueExpression);
|
|
114
|
-
return defaultValue;
|
|
58
|
+
return createSourceFile([...this.#dependencyManager.imports.toCode(), ...file.statements.filter((statement) => !isImportDeclaration(statement))], file.fileName);
|
|
115
59
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
static #createDefaultValueParameter(defaultValueType) {
|
|
123
|
-
const paramType = ts.factory.createTypeLiteralNode([ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier("defaultValue"), undefined, defaultValueType)]);
|
|
124
|
-
return ts.factory.createParameterDeclaration(undefined, undefined, "options", ts.factory.createToken(ts.SyntaxKind.QuestionToken), paramType);
|
|
125
|
-
}
|
|
126
|
-
static #isDefaultValueTypeNullable(defaultValueType) {
|
|
127
|
-
return ts.isUnionTypeNode(defaultValueType) && defaultValueType.types.length && defaultValueType.types.length > 1 && defaultValueType.types.map((t) => t.kind).includes(ts.SyntaxKind.UndefinedKeyword);
|
|
128
|
-
}
|
|
129
|
-
#createEmptyValueExpression(defaultValueType) {
|
|
130
|
-
if (SignalProcessor.#isDefaultValueTypeNullable(defaultValueType)) {
|
|
131
|
-
return ts.factory.createIdentifier("undefined");
|
|
60
|
+
#createDefaultValue(signalClass, returnType) {
|
|
61
|
+
const { imports } = this.#dependencyManager;
|
|
62
|
+
if (COLLECTION_SIGNALS.includes(signalClass)) {
|
|
63
|
+
return {};
|
|
132
64
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
#determineModelImportUniqueIdentifier(returnTypeNode) {
|
|
137
|
-
let modelName = primitiveModels.get(returnTypeNode.types[0].kind);
|
|
138
|
-
let entityName;
|
|
139
|
-
if (modelName === undefined) {
|
|
140
|
-
const { entityName: e, modelName: m } = SignalProcessor.#extractModelNameFromTypeNode(returnTypeNode);
|
|
141
|
-
modelName = m;
|
|
142
|
-
entityName = e;
|
|
65
|
+
if (!GENERIC_SIGNALS.includes(signalClass)) {
|
|
66
|
+
return signalClass.startsWith("NumberSignal") ? { defaultValue: "0" } : {};
|
|
143
67
|
}
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
static #extractModelNameFromTypeNode(returnTypeNode) {
|
|
149
|
-
if (ts.isTypeReferenceNode(returnTypeNode.types[0])) {
|
|
150
|
-
const typeIdentifier = returnTypeNode.types[0].typeName;
|
|
151
|
-
if (ts.isIdentifier(typeIdentifier)) {
|
|
152
|
-
const entityName = typeIdentifier.text;
|
|
153
|
-
const modelName = `${entityName}Model`;
|
|
154
|
-
return {
|
|
155
|
-
entityName,
|
|
156
|
-
modelName
|
|
157
|
-
};
|
|
68
|
+
const type = traverse(returnType, (node) => isTypeReferenceNode(node) && isIdentifier(node.typeName) && GENERIC_SIGNALS.includes(node.typeName.text) && node.typeArguments ? node.typeArguments[0] : undefined);
|
|
69
|
+
const modelId = traverse(type, (node) => {
|
|
70
|
+
if (isUnionTypeNode(node) && node.types.length > 1 && node.types[1].kind === SyntaxKind.UndefinedKeyword) {
|
|
71
|
+
return SyntaxKind.UndefinedKeyword;
|
|
158
72
|
}
|
|
159
|
-
|
|
160
|
-
|
|
73
|
+
return this.#getModelId(node);
|
|
74
|
+
});
|
|
75
|
+
const optionsMethodTypeId = imports.named.getIdentifier(HILLA_REACT_SIGNALS, "SignalMethodOptions") ?? imports.named.add(HILLA_REACT_SIGNALS, "SignalMethodOptions");
|
|
76
|
+
return {
|
|
77
|
+
defaultValue: modelId === SyntaxKind.UndefinedKeyword ? ast`options?.defaultValue`.node : ast`options?.defaultValue ?? ${modelId}.createEmptyValue()`.node,
|
|
78
|
+
defaultValueParameter: ast`function dummy( %{ options?: ${optionsMethodTypeId}<${type}> }% ) {}`.node
|
|
79
|
+
};
|
|
161
80
|
}
|
|
162
|
-
#
|
|
81
|
+
#getModelId(node) {
|
|
163
82
|
const { imports } = this.#dependencyManager;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (modelName) {
|
|
168
|
-
if (primitiveModels.values().find((primitiveModel) => primitiveModel === modelName)) {
|
|
169
|
-
const { imports } = this.#dependencyManager;
|
|
170
|
-
const importedModel = imports.named.getIdentifier("@vaadin/hilla-lit-form", modelName);
|
|
171
|
-
if (importedModel === undefined) {
|
|
172
|
-
imports.named.add("@vaadin/hilla-lit-form", modelName, false, modelNameUniqueId);
|
|
173
|
-
}
|
|
174
|
-
} else {
|
|
175
|
-
this.#addObjectModelImport(entityName, modelName, modelNameUniqueId);
|
|
83
|
+
if (isIdentifier(node)) {
|
|
84
|
+
if (ARRAY_TYPES.includes(node.text)) {
|
|
85
|
+
return imports.named.getIdentifier(HILLA_LIT_FORM, "ArrayModel") ?? imports.named.add(HILLA_LIT_FORM, "ArrayModel");
|
|
176
86
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const { imports } = this.#dependencyManager;
|
|
181
|
-
const entityImport = imports.default.iter().map(([path]) => path).find((path) => path.startsWith("./") && path.endsWith(`/${entityName}.js`));
|
|
182
|
-
if (entityImport) {
|
|
183
|
-
const entityModelImportPath = entityImport.replace(`/${entityName}.js`, `/${modelName}.js`);
|
|
184
|
-
const importedModel = imports.default.paths().find((path) => path === entityModelImportPath);
|
|
185
|
-
if (importedModel === undefined) {
|
|
186
|
-
imports.default.add(entityModelImportPath, modelName, false, modelNameUniqueId);
|
|
87
|
+
const [path] = Iterator.from(imports.default).find(([, id]) => id === node) ?? [];
|
|
88
|
+
if (!path) {
|
|
89
|
+
throw new Error(`Model not found for ${node.text}`);
|
|
187
90
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
91
|
+
const modelName = `${node.text}Model`;
|
|
92
|
+
const modelPath = `${dirname(path)}/${modelName}${extname(path)}`;
|
|
93
|
+
return imports.default.getIdentifier(modelPath) ?? imports.default.add(modelPath, modelName);
|
|
94
|
+
} else if (isTypeNode(node)) {
|
|
95
|
+
let modelName;
|
|
96
|
+
switch (node.kind) {
|
|
97
|
+
case SyntaxKind.StringKeyword:
|
|
98
|
+
modelName = "StringModel";
|
|
99
|
+
break;
|
|
100
|
+
case SyntaxKind.NumberKeyword:
|
|
101
|
+
modelName = "NumberModel";
|
|
102
|
+
break;
|
|
103
|
+
case SyntaxKind.BooleanKeyword:
|
|
104
|
+
modelName = "BooleanModel";
|
|
105
|
+
break;
|
|
106
|
+
case SyntaxKind.ArrayType:
|
|
107
|
+
modelName = "ArrayModel";
|
|
108
|
+
break;
|
|
109
|
+
default: return undefined;
|
|
205
110
|
}
|
|
111
|
+
return imports.named.getIdentifier(HILLA_LIT_FORM, modelName) ?? imports.named.add(HILLA_LIT_FORM, modelName);
|
|
206
112
|
}
|
|
207
|
-
|
|
113
|
+
return undefined;
|
|
208
114
|
}
|
|
209
115
|
}
|
|
210
116
|
//# sourceMappingURL=./SignalProcessor.js.map
|
package/SignalProcessor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","names":["#dependencyManager","#owner","#service","#methods","#sourceFile","service: string","methods: Map<string, string>","sourceFile: SourceFile","owner: Plugin","functionParams: Map<string, ts.ParameterDeclaration[]>","#replaceSignalImport","#createDefaultValue","signalId: ts.Identifier","functionDeclaration: FunctionDeclaration","defaultValue: {\n defaultValueExpression: ts.Expression | ts.Identifier;\n defaultValueParam: ts.ParameterDeclaration | undefined;\n genericReturnType: ts.TypeNode | undefined;\n }","#getDefaultValueType","#createDefaultValueParameter","#createEmptyValueExpression","node: ts.Node","defaultValueType: ts.TypeNode","#isDefaultValueTypeNullable","defaultValueType: ts.UnionTypeNode","#determineModelImportUniqueIdentifier","returnTypeNode: ts.UnionTypeNode","#extractModelNameFromTypeNode","#getExistingEntityModelUniqueIdentifier","#addModelImport","modelName: string","entityName: string | undefined","modelName: string | undefined","modelNameUniqueId: ts.Identifier | undefined","#addObjectModelImport","entityName: string","modelNameUniqueId: ts.Identifier","method: FunctionDeclaration"],"sources":["/opt/agent/work/1af72d8adc613024/hilla/packages/ts/generator-plugin-signals/src/SignalProcessor.ts"],"sourcesContent":["import type Plugin from '@vaadin/hilla-generator-core/Plugin.js';\nimport { template, transform, traverse } from '@vaadin/hilla-generator-utils/ast.js';\nimport createFullyUniqueIdentifier from '@vaadin/hilla-generator-utils/createFullyUniqueIdentifier.js';\nimport createSourceFile from '@vaadin/hilla-generator-utils/createSourceFile.js';\nimport DependencyManager from '@vaadin/hilla-generator-utils/dependencies/DependencyManager.js';\nimport PathManager from '@vaadin/hilla-generator-utils/dependencies/PathManager.js';\nimport ts, { type FunctionDeclaration, type Identifier, type SourceFile } from 'typescript';\n\nconst HILLA_REACT_SIGNALS = '@vaadin/hilla-react-signals';\n\nconst CONNECT_CLIENT = '$CONNECT_CLIENT$';\nconst METHOD_NAME = '$METHOD_NAME$';\nconst SIGNAL = '$SIGNAL$';\nconst RETURN_TYPE = '$RETURN_TYPE$';\nconst INITIAL_VALUE = '$INITIAL_VALUE$';\n\nconst signals = ['NumberSignal', 'ValueSignal', 'ListSignal'];\nconst genericSignals = ['ValueSignal', 'ListSignal'];\nconst collectionSignals = ['ListSignal'];\n\nconst primitiveModels = Object.freeze(\n new Map<ts.SyntaxKind, string>([\n [ts.SyntaxKind.StringKeyword, 'StringModel'],\n [ts.SyntaxKind.NumberKeyword, 'NumberModel'],\n [ts.SyntaxKind.BooleanKeyword, 'BooleanModel'],\n [ts.SyntaxKind.ArrayType, 'ArrayModel'],\n ]),\n);\n\nexport default class SignalProcessor {\n readonly #dependencyManager: DependencyManager;\n readonly #owner: Plugin;\n readonly #service: string;\n readonly #methods: Map<string, string>;\n readonly #sourceFile: SourceFile;\n\n constructor(service: string, methods: Map<string, string>, sourceFile: SourceFile, owner: Plugin) {\n this.#service = service;\n this.#methods = methods;\n this.#sourceFile = sourceFile;\n this.#owner = owner;\n this.#dependencyManager = new DependencyManager(new PathManager({ extension: '.js' }));\n this.#dependencyManager.imports.fromCode(this.#sourceFile);\n }\n\n process(): SourceFile {\n this.#owner.logger.debug(`Processing signals: ${this.#service}`);\n const { imports } = this.#dependencyManager;\n\n const [, connectClientId] = imports.default.iter().find(([path]) => path.includes('connect-client'))!;\n\n const initTypeId = imports.named.getIdentifier('@vaadin/hilla-frontend', 'EndpointRequestInit');\n let initTypeUsageCount = 0;\n const functionParams: Map<string, ts.ParameterDeclaration[]> = new Map<string, ts.ParameterDeclaration[]>();\n\n const [file] = ts.transform<SourceFile>(this.#sourceFile, [\n transform((tsNode) => {\n if (ts.isFunctionDeclaration(tsNode) && tsNode.name && this.#methods.has(tsNode.name.text)) {\n const signalId = this.#replaceSignalImport(tsNode);\n const filteredParams = tsNode.parameters.filter(\n (p) => !p.type || !ts.isTypeReferenceNode(p.type) || p.type.typeName !== initTypeId,\n );\n // `filteredParams` can be altered after, need to store the param names now\n const paramNames = filteredParams.map((p) => (p.name as ts.Identifier).text).join(', ');\n const isCollectionSignal = collectionSignals.includes(signalId.text);\n\n const { defaultValueExpression, defaultValueParam, genericReturnType } = this.#createDefaultValue(\n signalId,\n tsNode,\n );\n if (defaultValueParam) {\n filteredParams.push(defaultValueParam);\n }\n\n const returnType = genericReturnType ?? signalId;\n if (filteredParams.length > 0) {\n functionParams.set(tsNode.name.text, filteredParams);\n }\n return template(\n `function ${METHOD_NAME}(): ${RETURN_TYPE} {\n return new ${SIGNAL}(${\n isCollectionSignal ? '' : `${INITIAL_VALUE}, `\n }{ client: ${CONNECT_CLIENT}, endpoint: '${this.#service}', method: '${tsNode.name.text}'${\n paramNames.length ? `, params: { ${paramNames} }` : ''\n } });\n}`,\n (statements) => statements,\n [\n transform((node) => (ts.isIdentifier(node) && node.text === METHOD_NAME ? tsNode.name : node)),\n transform((node) => (ts.isIdentifier(node) && node.text === SIGNAL ? signalId : node)),\n transform((node) => (ts.isIdentifier(node) && node.text === RETURN_TYPE ? returnType : node)),\n transform((node) => (ts.isIdentifier(node) && node.text === CONNECT_CLIENT ? connectClientId : node)),\n transform((node) =>\n ts.isIdentifier(node) && node.text === INITIAL_VALUE ? defaultValueExpression : node,\n ),\n ],\n );\n }\n return tsNode;\n }),\n transform((tsNode) => {\n if (\n ts.isFunctionDeclaration(tsNode) &&\n tsNode.name &&\n this.#methods.has(tsNode.name.text) &&\n functionParams.has(tsNode.name.text)\n ) {\n return ts.factory.updateFunctionDeclaration(\n tsNode,\n tsNode.modifiers,\n tsNode.asteriskToken,\n tsNode.name,\n tsNode.typeParameters,\n functionParams.get(tsNode.name.text)!,\n tsNode.type,\n tsNode.body,\n );\n }\n return tsNode;\n }),\n transform((tsNode) => {\n if (ts.isFunctionDeclaration(tsNode)) {\n if (\n !(tsNode.name && this.#methods.has(tsNode.name.text)) &&\n tsNode.parameters.some((p) => p.type && ts.isTypeReferenceNode(p.type) && p.type.typeName === initTypeId)\n ) {\n initTypeUsageCount += 1;\n }\n }\n return tsNode;\n }),\n ]).transformed;\n\n if (initTypeUsageCount === 0) {\n imports.named.remove('@vaadin/hilla-frontend', 'EndpointRequestInit');\n }\n\n return createSourceFile(\n [\n ...this.#dependencyManager.imports.toCode(),\n ...file.statements.filter((statement) => !ts.isImportDeclaration(statement)),\n ],\n file.fileName,\n );\n }\n\n #createDefaultValue(signalId: ts.Identifier, functionDeclaration: FunctionDeclaration) {\n const defaultValue: {\n defaultValueExpression: ts.Expression | ts.Identifier;\n defaultValueParam: ts.ParameterDeclaration | undefined;\n genericReturnType: ts.TypeNode | undefined;\n } = {\n defaultValueExpression: signalId.text.startsWith('NumberSignal')\n ? ts.factory.createNumericLiteral('0')\n : ts.factory.createIdentifier('undefined'),\n defaultValueParam: undefined,\n genericReturnType: undefined,\n };\n\n if (!genericSignals.includes(signalId.text)) {\n return defaultValue;\n }\n\n [defaultValue.genericReturnType] = (functionDeclaration.type as ts.TypeReferenceNode).typeArguments!;\n\n if (collectionSignals.includes(signalId.text)) {\n return defaultValue;\n }\n\n const defaultValueType = SignalProcessor.#getDefaultValueType(defaultValue.genericReturnType);\n if (!defaultValueType) {\n return defaultValue;\n }\n\n defaultValue.defaultValueParam = SignalProcessor.#createDefaultValueParameter(defaultValueType);\n const emptyValueExpression = this.#createEmptyValueExpression(defaultValueType);\n\n defaultValue.defaultValueExpression = ts.factory.createBinaryExpression(\n ts.factory.createPropertyAccessChain(\n ts.factory.createIdentifier('options'),\n ts.factory.createToken(ts.SyntaxKind.QuestionDotToken),\n ts.factory.createIdentifier('defaultValue'),\n ),\n ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),\n emptyValueExpression,\n );\n\n return defaultValue;\n }\n\n static #getDefaultValueType(node: ts.Node) {\n if (\n ts.isUnionTypeNode(node) &&\n node.types.length &&\n ts.isTypeReferenceNode(node.types[0]) &&\n node.types[0].typeArguments?.length === 1 &&\n ts.isUnionTypeNode(node.types[0].typeArguments[0])\n ) {\n return node.types[0].typeArguments[0];\n }\n return undefined;\n }\n\n static #createDefaultValueParameter(defaultValueType: ts.TypeNode) {\n const paramType = ts.factory.createTypeLiteralNode([\n ts.factory.createPropertySignature(\n undefined,\n ts.factory.createIdentifier('defaultValue'),\n undefined,\n defaultValueType,\n ),\n ]);\n\n return ts.factory.createParameterDeclaration(\n undefined,\n undefined,\n 'options',\n ts.factory.createToken(ts.SyntaxKind.QuestionToken),\n paramType,\n );\n }\n\n static #isDefaultValueTypeNullable(defaultValueType: ts.TypeNode) {\n return (\n ts.isUnionTypeNode(defaultValueType) &&\n defaultValueType.types.length &&\n defaultValueType.types.length > 1 &&\n defaultValueType.types.map((t) => t.kind).includes(ts.SyntaxKind.UndefinedKeyword)\n );\n }\n\n #createEmptyValueExpression(defaultValueType: ts.UnionTypeNode) {\n if (SignalProcessor.#isDefaultValueTypeNullable(defaultValueType)) {\n return ts.factory.createIdentifier('undefined');\n }\n const importedModelUniqueId = this.#determineModelImportUniqueIdentifier(defaultValueType);\n return ts.factory.createCallExpression(\n ts.factory.createPropertyAccessExpression(importedModelUniqueId, 'createEmptyValue'),\n undefined,\n [],\n );\n }\n\n #determineModelImportUniqueIdentifier(returnTypeNode: ts.UnionTypeNode) {\n let modelName = primitiveModels.get(returnTypeNode.types[0].kind);\n let entityName;\n if (modelName === undefined) {\n const { entityName: e, modelName: m } = SignalProcessor.#extractModelNameFromTypeNode(returnTypeNode);\n modelName = m;\n entityName = e;\n }\n const modelImportUniqueId =\n this.#getExistingEntityModelUniqueIdentifier(modelName) ?? createFullyUniqueIdentifier(modelName);\n\n this.#addModelImport(entityName, modelName, modelImportUniqueId);\n return modelImportUniqueId;\n }\n\n static #extractModelNameFromTypeNode(returnTypeNode: ts.UnionTypeNode) {\n if (ts.isTypeReferenceNode(returnTypeNode.types[0])) {\n const typeIdentifier = returnTypeNode.types[0].typeName;\n if (ts.isIdentifier(typeIdentifier)) {\n const entityName = typeIdentifier.text;\n const modelName = `${entityName}Model`;\n return { entityName, modelName };\n }\n }\n throw new Error('Unsupported type reference node');\n }\n\n #getExistingEntityModelUniqueIdentifier(modelName: string) {\n const { imports } = this.#dependencyManager;\n return (\n imports.named.getIdentifier('@vaadin/hilla-lit-form', modelName) ??\n imports.default.iter().find(([path]) => path.endsWith(`/${modelName}.js`))?.[1]\n );\n }\n\n #addModelImport(\n entityName: string | undefined,\n modelName: string | undefined,\n modelNameUniqueId: ts.Identifier | undefined,\n ) {\n if (modelName) {\n if (primitiveModels.values().find((primitiveModel) => primitiveModel === modelName)) {\n const { imports } = this.#dependencyManager;\n const importedModel = imports.named.getIdentifier('@vaadin/hilla-lit-form', modelName);\n if (importedModel === undefined) {\n imports.named.add('@vaadin/hilla-lit-form', modelName, false, modelNameUniqueId);\n }\n } else {\n this.#addObjectModelImport(entityName!, modelName, modelNameUniqueId!);\n }\n }\n }\n\n #addObjectModelImport(entityName: string, modelName: string, modelNameUniqueId: ts.Identifier) {\n const { imports } = this.#dependencyManager;\n const entityImport = imports.default\n .iter()\n .map(([path]) => path)\n .find((path) => path.startsWith('./') && path.endsWith(`/${entityName}.js`));\n if (entityImport) {\n const entityModelImportPath = entityImport.replace(`/${entityName}.js`, `/${modelName}.js`);\n const importedModel = imports.default.paths().find((path) => path === entityModelImportPath);\n if (importedModel === undefined) {\n imports.default.add(entityModelImportPath, modelName, false, modelNameUniqueId);\n }\n }\n }\n\n #replaceSignalImport(method: FunctionDeclaration): Identifier {\n const { imports } = this.#dependencyManager;\n\n if (method.type) {\n const type = traverse(method.type, (node) =>\n ts.isIdentifier(node) && signals.includes(node.text) ? node : undefined,\n );\n\n if (type) {\n const signalId = imports.named.getIdentifier(HILLA_REACT_SIGNALS, type.text);\n\n if (signalId) {\n return signalId;\n }\n\n const result = imports.default.iter().find(([_p, id]) => id.text === type.text);\n\n if (result) {\n const [path] = result;\n imports.default.remove(path);\n return imports.named.add(HILLA_REACT_SIGNALS, type.text, false, type);\n }\n }\n }\n\n throw new Error('Signal type not found');\n }\n}\n"],"version":3}
|
|
1
|
+
{"mappings":"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","names":["#dependencyManager","#owner","#service","#methods","#sourceFile","service: string","methods: Map<string, string>","sourceFile: SourceFile","owner: Plugin","#createDefaultValue","signalClass: string","returnType?: TypeNode","#getModelId","node: Node","modelName: string | undefined"],"sources":["/opt/agent/work/1af72d8adc613024/hilla/packages/ts/generator-plugin-signals/src/SignalProcessor.ts"],"sourcesContent":["import { dirname, extname } from 'node:path';\nimport type Plugin from '@vaadin/hilla-generator-core/Plugin.js';\nimport { simplifyFullyQualifiedName } from '@vaadin/hilla-generator-core/Schema.js';\nimport { traverse } from '@vaadin/hilla-generator-utils/ast.js';\nimport createSourceFile from '@vaadin/hilla-generator-utils/createSourceFile.js';\nimport DependencyManager from '@vaadin/hilla-generator-utils/dependencies/DependencyManager.js';\nimport PathManager from '@vaadin/hilla-generator-utils/dependencies/PathManager.js';\nimport ast, { createTransformer } from 'tsc-template';\nimport {\n factory,\n isTypeReferenceNode,\n isIdentifier,\n type ReturnStatement,\n type SourceFile,\n type TypeNode,\n type ParameterDeclaration,\n type BinaryExpression,\n type Node,\n SyntaxKind,\n isTypeNode,\n transform,\n isFunctionDeclaration,\n isImportDeclaration,\n isUnionTypeNode,\n type PropertyAccessExpression,\n} from 'typescript';\nimport { ARRAY_TYPES, COLLECTION_SIGNALS, GENERIC_SIGNALS } from './utils.js';\n\nconst HILLA_REACT_SIGNALS = '@vaadin/hilla-react-signals';\nconst HILLA_LIT_FORM = '@vaadin/hilla-lit-form';\n\nexport default class SignalProcessor {\n readonly #dependencyManager: DependencyManager;\n readonly #owner: Plugin;\n readonly #service: string;\n readonly #methods: Map<string, string>;\n readonly #sourceFile: SourceFile;\n\n constructor(service: string, methods: Map<string, string>, sourceFile: SourceFile, owner: Plugin) {\n this.#service = service;\n this.#methods = methods;\n this.#sourceFile = sourceFile;\n this.#owner = owner;\n this.#dependencyManager = new DependencyManager(new PathManager({ extension: '.js' }));\n this.#dependencyManager.imports.fromCode(this.#sourceFile);\n }\n\n process(): SourceFile {\n this.#owner.logger.debug(`Processing signals: ${this.#service}`);\n const { imports } = this.#dependencyManager;\n\n const [, connectClientId] = Iterator.from(imports.default).find(([path]) => path.includes('connect-client'))!;\n\n const initTypeId = imports.named.getIdentifier('@vaadin/hilla-frontend', 'EndpointRequestInit');\n let initTypeUsageCount = 0;\n\n const [file] = transform<SourceFile>(this.#sourceFile, [\n createTransformer((node) => {\n if (isFunctionDeclaration(node)) {\n // Check if the function is a signal method.\n if (node.name && this.#methods.has(node.name.text)) {\n // Get the signal class ID that was already imported in\n // TransferTypes plugin.\n const signalId = imports.named.getIdentifier(\n HILLA_REACT_SIGNALS,\n simplifyFullyQualifiedName(this.#methods.get(node.name.text)!),\n )!;\n\n // Remove the `init` parameter.\n const params = node.parameters.filter(\n (p) => !(p.type && isTypeReferenceNode(p.type) && p.type.typeName === initTypeId),\n );\n\n // Calculate the default value for the signal class.\n const { defaultValue, defaultValueParameter } = this.#createDefaultValue(signalId.text, node.type);\n\n // Remove the `async` modifier if present.\n const modifiers = node.modifiers?.filter((m) => m.kind !== SyntaxKind.AsyncKeyword);\n\n // Remove the `Promise` type if present.\n const type =\n node.type &&\n isTypeReferenceNode(node.type) &&\n isIdentifier(node.type.typeName) &&\n node.type.typeName.text === 'Promise'\n ? node.type.typeArguments?.[0]\n : node.type;\n\n // Get the variable parameter names to be passed to the signal\n // class.\n const paramNames = params\n .map((p) => p.name)\n .filter((n) => isIdentifier(n))\n .map((n) => n.text);\n\n // Create the signal class method body applying all the data we've\n // gathered.\n const result = ast`function dummy() { %{\n return new ${signalId}(${defaultValue}${defaultValue ? ',' : ''}{\n client: ${connectClientId},\n endpoint: '${this.#service}',\n method: '${node.name.text}'\n ${paramNames.length ? `, params: { ${paramNames.join('\\n')} }` : ''} });\n }% });`;\n\n // Update the function declaration accordingly.\n return factory.updateFunctionDeclaration(\n node,\n modifiers,\n node.asteriskToken,\n node.name,\n node.typeParameters,\n defaultValueParameter ? [...params, defaultValueParameter] : params,\n type,\n factory.createBlock([result.node as ReturnStatement]),\n );\n } else if (\n node.parameters.some((p) => p.type && isTypeReferenceNode(p.type) && p.type.typeName === initTypeId)\n ) {\n // Count the number of times the `init` parameter is used to check\n // if the type import is necessary to be removed.\n initTypeUsageCount += 1;\n }\n }\n\n return node;\n }),\n ]).transformed;\n\n // Remove the `EndpointRequestInit` import if it is not used anymore.\n if (initTypeUsageCount === 0) {\n imports.named.remove('@vaadin/hilla-frontend', 'EndpointRequestInit');\n }\n\n return createSourceFile(\n [\n ...this.#dependencyManager.imports.toCode(),\n ...file.statements.filter((statement) => !isImportDeclaration(statement)),\n ],\n file.fileName,\n );\n }\n\n #createDefaultValue(signalClass: string, returnType?: TypeNode) {\n const { imports } = this.#dependencyManager;\n\n // If the signal class is a collection signal, we have no default value to\n // generate.\n if (COLLECTION_SIGNALS.includes(signalClass)) {\n return {};\n }\n\n // If we have the NumberSignal class, we can use `0` as the default.\n if (!GENERIC_SIGNALS.includes(signalClass)) {\n return signalClass.startsWith('NumberSignal') ? { defaultValue: '0' } : {};\n }\n\n // Extract the generic argument of the signal class to get the default\n // value type.\n const type = traverse(returnType!, (node) =>\n isTypeReferenceNode(node) &&\n isIdentifier(node.typeName) &&\n GENERIC_SIGNALS.includes(node.typeName.text) &&\n node.typeArguments\n ? node.typeArguments[0]\n : undefined,\n )!;\n\n // Import the model class for the signal type (or omitting the import if\n // the type is a nullable one).\n const modelId = traverse(type, (node) => {\n // In case the generic argument of a signal class is nullable (e.g.\n // `Signal<Person | undefined>`), the default value will be `undefined`.\n if (isUnionTypeNode(node) && node.types.length > 1 && node.types[1].kind === SyntaxKind.UndefinedKeyword) {\n return SyntaxKind.UndefinedKeyword;\n }\n\n // Otherwise, we have to import the model class.\n return this.#getModelId(node);\n })!;\n\n // If we have a signal class with a generic argument (but not a collection),\n // we need to provide a possibility to set the default value.\n const optionsMethodTypeId =\n imports.named.getIdentifier(HILLA_REACT_SIGNALS, 'SignalMethodOptions') ??\n imports.named.add(HILLA_REACT_SIGNALS, 'SignalMethodOptions');\n\n return {\n defaultValue:\n modelId === SyntaxKind.UndefinedKeyword\n ? (ast`options?.defaultValue`.node as PropertyAccessExpression)\n : (ast`options?.defaultValue ?? ${modelId}.createEmptyValue()`.node as BinaryExpression),\n defaultValueParameter: ast`function dummy( %{ options?: ${optionsMethodTypeId}<${type}> }% ) {}`\n .node as ParameterDeclaration,\n };\n }\n\n #getModelId(node: Node) {\n const { imports } = this.#dependencyManager;\n\n if (isIdentifier(node)) {\n // In case the node is an array type defined as `Array<T>` or\n // `ReadonlyArray<T>`, we need to import the `ArrayModel` class.\n if (ARRAY_TYPES.includes(node.text)) {\n return (\n imports.named.getIdentifier(HILLA_LIT_FORM, 'ArrayModel') ?? imports.named.add(HILLA_LIT_FORM, 'ArrayModel')\n );\n }\n\n // Otherwise, we calculate and import the model class.\n const [path] = Iterator.from(imports.default).find(([, id]) => id === node) ?? [];\n\n if (!path) {\n throw new Error(`Model not found for ${node.text}`);\n }\n\n const modelName = `${node.text}Model`;\n const modelPath = `${dirname(path)}/${modelName}${extname(path)}`;\n\n return imports.default.getIdentifier(modelPath) ?? imports.default.add(modelPath, modelName);\n } else if (isTypeNode(node)) {\n // If the node is a primitive type, we will import the corresponding\n // model class from `@vaadin/hilla-lit-form`.\n let modelName: string | undefined;\n\n switch (node.kind) {\n case SyntaxKind.StringKeyword:\n modelName = 'StringModel';\n break;\n case SyntaxKind.NumberKeyword:\n modelName = 'NumberModel';\n break;\n case SyntaxKind.BooleanKeyword:\n modelName = 'BooleanModel';\n break;\n case SyntaxKind.ArrayType:\n modelName = 'ArrayModel';\n break;\n default:\n return undefined;\n }\n\n return imports.named.getIdentifier(HILLA_LIT_FORM, modelName) ?? imports.named.add(HILLA_LIT_FORM, modelName);\n }\n\n return undefined;\n }\n}\n"],"version":3}
|
package/index.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import Plugin from "@vaadin/hilla-generator-core/Plugin.js";
|
|
2
2
|
import type { SharedStorage } from "@vaadin/hilla-generator-core/SharedStorage.js";
|
|
3
|
-
export type PathSignalType = Readonly<{
|
|
4
|
-
path: string
|
|
5
|
-
signalType: string
|
|
6
|
-
}>;
|
|
7
3
|
export default class SignalsPlugin extends Plugin {
|
|
8
|
-
execute(sharedStorage: SharedStorage):
|
|
4
|
+
execute(sharedStorage: SharedStorage): void;
|
|
9
5
|
["constructor"]: typeof SignalsPlugin;
|
|
10
6
|
get path(): string;
|
|
11
7
|
}
|
package/index.js
CHANGED
|
@@ -1,39 +1,33 @@
|
|
|
1
1
|
import Plugin from "@vaadin/hilla-generator-core/Plugin.js";
|
|
2
2
|
import SignalProcessor from "./SignalProcessor.js";
|
|
3
|
+
import { SIGNALS } from "./utils.js";
|
|
3
4
|
if (!("Iterator" in globalThis)) {
|
|
4
5
|
const { installIntoGlobal } = await import("iterator-helpers-polyfill");
|
|
5
6
|
installIntoGlobal();
|
|
6
7
|
}
|
|
7
|
-
const SIGNAL_CLASSES =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"#/components/schemas/com.vaadin.hilla.signals.ListSignal"
|
|
11
|
-
];
|
|
12
|
-
function extractEndpointMethodsWithSignalsAsReturnType(storage) {
|
|
13
|
-
return Object.entries(storage.api.paths).filter(([_, pathObject]) => {
|
|
8
|
+
const SIGNAL_CLASSES = SIGNALS.map((signal) => `#/components/schemas/com.vaadin.hilla.runtime.transfertypes.${signal}`);
|
|
9
|
+
function mapPathToSignalType(storage) {
|
|
10
|
+
return new Map(Object.entries(storage.api.paths).filter(([_, pathObject]) => {
|
|
14
11
|
const response200 = pathObject?.post?.responses["200"];
|
|
15
12
|
return response200 && !("$ref" in response200);
|
|
16
13
|
}).flatMap(([path, pathObject]) => {
|
|
17
14
|
const response200 = pathObject?.post?.responses["200"];
|
|
18
15
|
const responseSchema = response200.content?.["application/json"]?.schema;
|
|
19
|
-
return responseSchema && "anyOf" in responseSchema ? responseSchema.anyOf?.filter((c) => "$ref" in c && c.$ref && SIGNAL_CLASSES.includes(c.$ref)).map((c) =>
|
|
20
|
-
|
|
21
|
-
signalType: "$ref" in c ? c.$ref : ""
|
|
22
|
-
})) : [];
|
|
23
|
-
}).filter((signalArray) => signalArray != null);
|
|
16
|
+
return responseSchema && "anyOf" in responseSchema ? responseSchema.anyOf?.filter((c) => "$ref" in c && !!c.$ref && SIGNAL_CLASSES.includes(c.$ref)).map((c) => [path, c.$ref]) : null;
|
|
17
|
+
}).filter((signalArray) => signalArray != null));
|
|
24
18
|
}
|
|
25
|
-
function groupByService(
|
|
26
|
-
return
|
|
27
|
-
const [_, service, method] =
|
|
19
|
+
function groupByService(signalMap) {
|
|
20
|
+
return signalMap.entries().reduce((serviceMap, [path, type]) => {
|
|
21
|
+
const [_, service, method] = path.split("/");
|
|
28
22
|
const serviceMethods = serviceMap.get(service) ?? new Map();
|
|
29
|
-
serviceMethods.set(method,
|
|
23
|
+
serviceMethods.set(method, type);
|
|
30
24
|
serviceMap.set(service, serviceMethods);
|
|
31
25
|
return serviceMap;
|
|
32
26
|
}, new Map());
|
|
33
27
|
}
|
|
34
28
|
export default class SignalsPlugin extends Plugin {
|
|
35
|
-
|
|
36
|
-
const methodsWithSignals =
|
|
29
|
+
execute(sharedStorage) {
|
|
30
|
+
const methodsWithSignals = mapPathToSignalType(sharedStorage);
|
|
37
31
|
const services = groupByService(methodsWithSignals);
|
|
38
32
|
services.forEach((methods, service) => {
|
|
39
33
|
const index = sharedStorage.sources.findIndex((source) => source.fileName === `${service}.ts`);
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAAA,OAAO,oDAAqD;AAG5D,OAAO,2CAA4C;
|
|
1
|
+
{"mappings":"AAAA,OAAO,oDAAqD;AAG5D,OAAO,2CAA4C;AACnD,SAAS,2BAA4B;AAGrC,MAAM,cAAc,aAAa;CAC/B,MAAM,EAAE,mBAAmB,GAAG,MAAM,OAAO;AAC3C,oBAAmB;AACpB;AAED,MAAM,iBAAiB,QAAQ,IAAI,CAAC,YAAY,8DAA8D,OAAO,EAAE;AAEvH,SAAS,oBAAoBA,SAA6C;AACxE,QAAO,IAAI,IACT,OAAO,QAAQ,QAAQ,IAAI,MAAM,CAC9B,OAAO,CAAC,CAAC,GAAG,WAAW,KAAK;EAC3B,MAAM,cAAc,YAAY,MAAM,UAAU;AAChD,SAAO,iBAAiB,UAAU;CACnC,EAAC,CACD,QAAQ,CAAC,CAAC,MAAM,WAAW,KAAK;EAC/B,MAAM,cAAc,YAAY,MAAM,UAAU;EAChD,MAAM,iBAAkB,YAAyC,UAAU,qBAAqB;AAEhG,SAAO,kBAAkB,WAAW,iBAChC,eAAe,OACX,OACA,CAAC,MAAsC,UAAU,OAAO,EAAE,QAAQ,eAAe,SAAS,EAAE,KAAK,CAClG,CACA,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAK,EAAU,GACtC;CACL,EAAC,CACD,OAAO,CAAC,gBAAgB,eAAe,KAAK;AAElD;AAED,SAAS,eAAeC,WAAkE;AACxF,QAAO,UAAU,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,KAAK,KAAK;EAC9D,MAAM,CAAC,GAAG,SAAS,OAAO,GAAG,KAAK,MAAM,IAAI;EAC5C,MAAM,iBAAiB,WAAW,IAAI,QAAQ,IAAI,IAAI;AACtD,iBAAe,IAAI,QAAQ,KAAK;AAChC,aAAW,IAAI,SAAS,eAAe;AACvC,SAAO;CACR,GAAE,IAAI,MAAmC;AAC3C;AAED,eAAe,MAAM,sBAAsB,OAAO;CAChD,AAAS,QAAQC,eAAoC;EACnD,MAAM,qBAAqB,oBAAoB,cAAc;EAC7D,MAAM,WAAW,eAAe,mBAAmB;AACnD,WAAS,QAAQ,CAAC,SAAS,YAAY;GACrC,MAAM,QAAQ,cAAc,QAAQ,UAAU,CAAC,WAAW,OAAO,cAAc,EAAE,QAAQ,KAAK;AAC9F,OAAI,SAAS,GAAG;AACd,kBAAc,QAAQ,SAAS,IAAI,gBACjC,SACA,SACA,cAAc,QAAQ,QACtB,MACA,SAAS;GACZ;EACF,EAAC;CACH;CAID,IAAa,OAAe;AAC1B,SAAO,OAAO,KAAK;CACpB;AACF","names":["storage: SharedStorage","signalMap: Map<string, string>","sharedStorage: SharedStorage"],"sources":["/opt/agent/work/1af72d8adc613024/hilla/packages/ts/generator-plugin-signals/src/index.ts"],"sourcesContent":["import Plugin from '@vaadin/hilla-generator-core/Plugin.js';\nimport type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js';\nimport type { OpenAPIV3 } from 'openapi-types';\nimport SignalProcessor from './SignalProcessor.js';\nimport { SIGNALS } from './utils.js';\n\n// Polyfill for iterator helpers (Stage 3 proposal)\nif (!('Iterator' in globalThis)) {\n const { installIntoGlobal } = await import('iterator-helpers-polyfill');\n installIntoGlobal();\n}\n\nconst SIGNAL_CLASSES = SIGNALS.map((signal) => `#/components/schemas/com.vaadin.hilla.runtime.transfertypes.${signal}`);\n\nfunction mapPathToSignalType(storage: SharedStorage): Map<string, string> {\n return new Map(\n Object.entries(storage.api.paths)\n .filter(([_, pathObject]) => {\n const response200 = pathObject?.post?.responses['200'];\n return response200 && !('$ref' in response200);\n })\n .flatMap(([path, pathObject]) => {\n const response200 = pathObject?.post?.responses['200'];\n const responseSchema = (response200 as OpenAPIV3.ResponseObject).content?.['application/json']?.schema;\n\n return responseSchema && 'anyOf' in responseSchema\n ? responseSchema.anyOf\n ?.filter(\n (c): c is OpenAPIV3.ReferenceObject => '$ref' in c && !!c.$ref && SIGNAL_CLASSES.includes(c.$ref),\n )\n .map((c) => [path, c.$ref] as const)\n : null;\n })\n .filter((signalArray) => signalArray != null),\n );\n}\n\nfunction groupByService(signalMap: Map<string, string>): Map<string, Map<string, string>> {\n return signalMap.entries().reduce((serviceMap, [path, type]) => {\n const [_, service, method] = path.split('/');\n const serviceMethods = serviceMap.get(service) ?? new Map<string, string>();\n serviceMethods.set(method, type);\n serviceMap.set(service, serviceMethods);\n return serviceMap;\n }, new Map<string, Map<string, string>>());\n}\n\nexport default class SignalsPlugin extends Plugin {\n override execute(sharedStorage: SharedStorage): void {\n const methodsWithSignals = mapPathToSignalType(sharedStorage);\n const services = groupByService(methodsWithSignals);\n services.forEach((methods, service) => {\n const index = sharedStorage.sources.findIndex((source) => source.fileName === `${service}.ts`);\n if (index >= 0) {\n sharedStorage.sources[index] = new SignalProcessor(\n service,\n methods,\n sharedStorage.sources[index],\n this,\n ).process();\n }\n });\n }\n\n declare ['constructor']: typeof SignalsPlugin;\n\n override get path(): string {\n return import.meta.url;\n }\n}\n"],"version":3}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/hilla-generator-plugin-signals",
|
|
3
|
-
"version": "24.8.0-
|
|
3
|
+
"version": "24.8.0-alpha3",
|
|
4
4
|
"description": "A Hilla TypeScript Generator plugin to add Shared Signals support",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -49,13 +49,17 @@
|
|
|
49
49
|
"access": "public"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@vaadin/hilla-generator-core": "24.8.0-
|
|
53
|
-
"@vaadin/hilla-generator-
|
|
54
|
-
"@vaadin/hilla-generator-plugin-client": "24.8.0-alpha2",
|
|
55
|
-
"@vaadin/hilla-generator-utils": "24.8.0-alpha2",
|
|
52
|
+
"@vaadin/hilla-generator-core": "24.8.0-alpha3",
|
|
53
|
+
"@vaadin/hilla-generator-utils": "24.8.0-alpha3",
|
|
56
54
|
"fast-deep-equal": "3.1.3",
|
|
57
55
|
"iterator-helpers-polyfill": "3.0.1",
|
|
58
56
|
"openapi-types": "12.1.3",
|
|
59
|
-
"
|
|
57
|
+
"tsc-template": "0.2.2",
|
|
58
|
+
"typescript": "5"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@vaadin/hilla-generator-plugin-backbone": "24.8.0-alpha3",
|
|
62
|
+
"@vaadin/hilla-generator-plugin-client": "24.8.0-alpha3",
|
|
63
|
+
"@vaadin/hilla-generator-plugin-transfertypes": "24.8.0-alpha3"
|
|
60
64
|
}
|
|
61
65
|
}
|
package/utils.d.ts
ADDED
package/utils.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const SIGNALS = [
|
|
2
|
+
"NumberSignal",
|
|
3
|
+
"ValueSignal",
|
|
4
|
+
"ListSignal"
|
|
5
|
+
];
|
|
6
|
+
export const COLLECTION_SIGNALS = ["ListSignal"];
|
|
7
|
+
export const GENERIC_SIGNALS = ["ValueSignal", "ListSignal"];
|
|
8
|
+
export const ARRAY_TYPES = ["Array", "ReadonlyArray"];
|
|
9
|
+
//# sourceMappingURL=./utils.js.map
|
package/utils.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"AAAA,OAAO,MAAMA,UAA6B;CAAC;CAAgB;CAAe;AAAa;AACvF,OAAO,MAAMC,qBAAwC,CAAC,YAAa;AACnE,OAAO,MAAMC,kBAAqC,CAAC,eAAe,YAAa;AAE/E,OAAO,MAAMC,cAAiC,CAAC,SAAS,eAAgB","names":["SIGNALS: readonly string[]","COLLECTION_SIGNALS: readonly string[]","GENERIC_SIGNALS: readonly string[]","ARRAY_TYPES: readonly string[]"],"sources":["/opt/agent/work/1af72d8adc613024/hilla/packages/ts/generator-plugin-signals/src/utils.ts"],"sourcesContent":["export const SIGNALS: readonly string[] = ['NumberSignal', 'ValueSignal', 'ListSignal'];\nexport const COLLECTION_SIGNALS: readonly string[] = ['ListSignal'];\nexport const GENERIC_SIGNALS: readonly string[] = ['ValueSignal', 'ListSignal'];\n\nexport const ARRAY_TYPES: readonly string[] = ['Array', 'ReadonlyArray'];\n"],"version":3}
|