@livon/client 0.27.0-rc.1
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/dist/client.cjs +354 -0
- package/dist/client.d.ts +100 -0
- package/dist/client.js +314 -0
- package/dist/generate.cjs +676 -0
- package/dist/generate.d.ts +37 -0
- package/dist/generate.js +625 -0
- package/dist/index.cjs +42 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +2 -0
- package/package.json +50 -0
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
|
|
3
|
+
return "u" < typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
|
|
4
|
+
}();
|
|
5
|
+
var __webpack_require__ = {};
|
|
6
|
+
(()=>{
|
|
7
|
+
__webpack_require__.n = (module)=>{
|
|
8
|
+
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
9
|
+
__webpack_require__.d(getter, {
|
|
10
|
+
a: getter
|
|
11
|
+
});
|
|
12
|
+
return getter;
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
17
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: definition[key]
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
})();
|
|
23
|
+
(()=>{
|
|
24
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
25
|
+
})();
|
|
26
|
+
(()=>{
|
|
27
|
+
__webpack_require__.r = (exports1)=>{
|
|
28
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
29
|
+
value: 'Module'
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
32
|
+
value: true
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __webpack_exports__ = {};
|
|
37
|
+
__webpack_require__.r(__webpack_exports__);
|
|
38
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
39
|
+
getClientGeneratorFingerprint: ()=>getClientGeneratorFingerprint,
|
|
40
|
+
generateClientFiles: ()=>generateClientFiles
|
|
41
|
+
});
|
|
42
|
+
const external_node_fs_namespaceObject = require("node:fs");
|
|
43
|
+
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
|
|
44
|
+
const external_node_crypto_namespaceObject = require("node:crypto");
|
|
45
|
+
const external_node_path_namespaceObject = require("node:path");
|
|
46
|
+
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
47
|
+
const external_node_url_namespaceObject = require("node:url");
|
|
48
|
+
const AST_PLACEHOLDER = '${{LIVON_AST}}';
|
|
49
|
+
const CLIENT_IMPORTS_PLACEHOLDER = '${{LIVON_CLIENT_IMPORTS}}';
|
|
50
|
+
const CLIENT_TYPE_DEFS_PLACEHOLDER = '${{LIVON_CLIENT_TYPE_DEFS}}';
|
|
51
|
+
const CLIENT_EVENT_MAP_PLACEHOLDER = '${{LIVON_CLIENT_EVENT_MAP}}';
|
|
52
|
+
const CLIENT_FIELD_OPS_PLACEHOLDER = '${{LIVON_CLIENT_FIELD_OPS}}';
|
|
53
|
+
const CLIENT_OP_DEFS_PLACEHOLDER = '${{LIVON_CLIENT_OP_DEFS}}';
|
|
54
|
+
const CLIENT_OP_LINES_PLACEHOLDER = '${{LIVON_CLIENT_OP_LINES}}';
|
|
55
|
+
const CLIENT_SUB_NAMES_PLACEHOLDER = '${{LIVON_CLIENT_SUB_NAMES}}';
|
|
56
|
+
const CLIENT_EXPORT_NAME_PLACEHOLDER = '${{LIVON_CLIENT_EXPORT_NAME}}';
|
|
57
|
+
const moduleUrl = __rslib_import_meta_url__;
|
|
58
|
+
const templatesDir = external_node_path_default().resolve(external_node_path_default().dirname((0, external_node_url_namespaceObject.fileURLToPath)(moduleUrl)), '../templates');
|
|
59
|
+
const sourceFilePath = (0, external_node_url_namespaceObject.fileURLToPath)(moduleUrl);
|
|
60
|
+
const serializeAst = (ast)=>JSON.stringify(ast, null, 2);
|
|
61
|
+
const hashText = (value)=>(0, external_node_crypto_namespaceObject.createHash)('sha256').update(value).digest('hex');
|
|
62
|
+
const isValidIdentifier = (value)=>/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
|
63
|
+
const renderPropertyName = (value)=>isValidIdentifier(value) ? value : JSON.stringify(value);
|
|
64
|
+
const pascalCaseName = (value)=>{
|
|
65
|
+
const normalized = value.replace(/[^a-zA-Z0-9]+(.)/g, (_, group)=>String(group).toUpperCase());
|
|
66
|
+
return 0 === normalized.length ? 'Type' : normalized.charAt(0).toUpperCase() + normalized.slice(1);
|
|
67
|
+
};
|
|
68
|
+
const sanitizeTypeName = (value)=>{
|
|
69
|
+
const pascal = pascalCaseName(value);
|
|
70
|
+
const cleaned = pascal.replace(/[^A-Za-z0-9_$]/g, '');
|
|
71
|
+
if (0 === cleaned.length) return 'Type';
|
|
72
|
+
return isValidIdentifier(cleaned) ? cleaned : `Type${cleaned}`;
|
|
73
|
+
};
|
|
74
|
+
const resolveUniqueName = (base, used, index = 0)=>{
|
|
75
|
+
const suffix = index > 0 ? String(index) : '';
|
|
76
|
+
const candidate = `${base}${suffix}`;
|
|
77
|
+
if (!used.has(candidate)) {
|
|
78
|
+
used.add(candidate);
|
|
79
|
+
return candidate;
|
|
80
|
+
}
|
|
81
|
+
return resolveUniqueName(base, used, index + 1);
|
|
82
|
+
};
|
|
83
|
+
const isTypeDefinitionNode = (node)=>'api' !== node.type && 'api-composed' !== node.type && 'operation' !== node.type && 'field' !== node.type && "subscription" !== node.type;
|
|
84
|
+
const isString = (value)=>'string' == typeof value;
|
|
85
|
+
const isRecord = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
|
|
86
|
+
const extractDocText = (doc)=>{
|
|
87
|
+
if (!doc) return;
|
|
88
|
+
if ('string' == typeof doc) return doc;
|
|
89
|
+
if (!isRecord(doc)) return;
|
|
90
|
+
const value = 'string' == typeof doc.description && doc.description || 'string' == typeof doc.summary && doc.summary || 'string' == typeof doc.text && doc.text || 'string' == typeof doc.title && doc.title;
|
|
91
|
+
return value || void 0;
|
|
92
|
+
};
|
|
93
|
+
const renderJSDoc = (lines, indent = '')=>{
|
|
94
|
+
if (0 === lines.length) return [];
|
|
95
|
+
return [
|
|
96
|
+
`${indent}/**`,
|
|
97
|
+
...lines.map((line)=>`${indent} * ${line}`),
|
|
98
|
+
`${indent} */`
|
|
99
|
+
];
|
|
100
|
+
};
|
|
101
|
+
const walkAst = (node, visit)=>{
|
|
102
|
+
visit(node);
|
|
103
|
+
node.children?.forEach((child)=>walkAst(child, visit));
|
|
104
|
+
};
|
|
105
|
+
const collectNamedNodes = (root)=>{
|
|
106
|
+
const nodes = new Map();
|
|
107
|
+
const usedNames = new Set();
|
|
108
|
+
walkAst(root, (node)=>{
|
|
109
|
+
if (!node.name || !isTypeDefinitionNode(node)) return;
|
|
110
|
+
if (nodes.has(node.name)) return;
|
|
111
|
+
const baseName = sanitizeTypeName(node.name);
|
|
112
|
+
const typeName = resolveUniqueName(baseName, usedNames);
|
|
113
|
+
nodes.set(node.name, {
|
|
114
|
+
name: node.name,
|
|
115
|
+
typeName,
|
|
116
|
+
node
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
return nodes;
|
|
120
|
+
};
|
|
121
|
+
const collectOperations = (root)=>{
|
|
122
|
+
const operations = [];
|
|
123
|
+
walkAst(root, (node)=>{
|
|
124
|
+
if ('operation' !== node.type || !node.name) return;
|
|
125
|
+
const input = node.children?.[0];
|
|
126
|
+
const output = node.children?.[1];
|
|
127
|
+
const constraints = node.constraints;
|
|
128
|
+
const requestType = node.request ?? ('string' == typeof constraints?.request ? constraints.request : void 0);
|
|
129
|
+
const responseType = node.response ?? ('string' == typeof constraints?.response ? constraints.response : void 0);
|
|
130
|
+
operations.push({
|
|
131
|
+
name: node.name,
|
|
132
|
+
input,
|
|
133
|
+
output,
|
|
134
|
+
doc: node.doc,
|
|
135
|
+
publishTopics: readPublishTopics(node),
|
|
136
|
+
requestType,
|
|
137
|
+
responseType,
|
|
138
|
+
constraints: node.constraints
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
return operations;
|
|
142
|
+
};
|
|
143
|
+
const collectFieldOperations = (root)=>{
|
|
144
|
+
const operations = [];
|
|
145
|
+
walkAst(root, (node)=>{
|
|
146
|
+
if ('field' !== node.type) return;
|
|
147
|
+
const constraints = node.constraints;
|
|
148
|
+
const owner = 'string' == typeof constraints?.owner ? constraints.owner : void 0;
|
|
149
|
+
const field = 'string' == typeof constraints?.field ? constraints.field : void 0;
|
|
150
|
+
if (!owner || !field) return;
|
|
151
|
+
const children = node.children ?? [];
|
|
152
|
+
const input = 3 === children.length ? children[1] : void 0;
|
|
153
|
+
const output = 3 === children.length ? children[2] : children[1];
|
|
154
|
+
const requestType = node.request ?? ('string' == typeof constraints?.request ? constraints.request : void 0);
|
|
155
|
+
const responseType = node.response ?? ('string' == typeof constraints?.response ? constraints.response : void 0);
|
|
156
|
+
const dependsOnType = node.dependsOn ?? ('string' == typeof constraints?.dependsOn ? constraints.dependsOn : void 0);
|
|
157
|
+
operations.push({
|
|
158
|
+
owner,
|
|
159
|
+
field,
|
|
160
|
+
input,
|
|
161
|
+
output,
|
|
162
|
+
doc: node.doc,
|
|
163
|
+
requestType,
|
|
164
|
+
responseType,
|
|
165
|
+
dependsOnType,
|
|
166
|
+
constraints: node.constraints
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
return operations;
|
|
170
|
+
};
|
|
171
|
+
const readPublishTopics = (node)=>{
|
|
172
|
+
const constraints = node.constraints;
|
|
173
|
+
if (!constraints || 'object' != typeof constraints || Array.isArray(constraints)) return [];
|
|
174
|
+
const raw = constraints.publish;
|
|
175
|
+
if (!Array.isArray(raw)) return [];
|
|
176
|
+
return raw.filter(isString);
|
|
177
|
+
};
|
|
178
|
+
const collectPublishEvents = (root, namedNodes)=>{
|
|
179
|
+
const events = [];
|
|
180
|
+
walkAst(root, (node)=>{
|
|
181
|
+
if ('operation' !== node.type) return;
|
|
182
|
+
const topics = readPublishTopics(node);
|
|
183
|
+
if (0 === topics.length) return;
|
|
184
|
+
const output = node.children?.[1];
|
|
185
|
+
const payloadType = renderType(output, namedNodes);
|
|
186
|
+
topics.forEach((topic)=>{
|
|
187
|
+
events.push({
|
|
188
|
+
topic,
|
|
189
|
+
payloadType
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
return events;
|
|
194
|
+
};
|
|
195
|
+
const resolveTypeName = (typeName, namedNodes)=>{
|
|
196
|
+
if (!typeName) return;
|
|
197
|
+
const named = namedNodes.get(typeName);
|
|
198
|
+
return named?.typeName;
|
|
199
|
+
};
|
|
200
|
+
const collectSubscriptionEvents = (root, namedNodes)=>{
|
|
201
|
+
const events = [];
|
|
202
|
+
walkAst(root, (node)=>{
|
|
203
|
+
if ("subscription" !== node.type || !node.name) return;
|
|
204
|
+
const constraints = node.constraints;
|
|
205
|
+
const responseType = node.response ?? ('string' == typeof constraints?.response ? constraints.response : void 0);
|
|
206
|
+
const resolvedType = resolveTypeName(responseType, namedNodes);
|
|
207
|
+
const payload = node.children?.[0];
|
|
208
|
+
const payloadType = resolvedType ?? renderType(payload, namedNodes, node.name);
|
|
209
|
+
events.push({
|
|
210
|
+
topic: node.name,
|
|
211
|
+
payloadType
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
return events;
|
|
215
|
+
};
|
|
216
|
+
const groupFieldOperations = (fieldOperations)=>{
|
|
217
|
+
const grouped = fieldOperations.reduce((acc, op)=>{
|
|
218
|
+
const existing = acc.get(op.owner) ?? [];
|
|
219
|
+
acc.set(op.owner, existing.concat(op));
|
|
220
|
+
return acc;
|
|
221
|
+
}, new Map());
|
|
222
|
+
return Array.from(grouped.entries()).map(([owner, operations])=>({
|
|
223
|
+
owner,
|
|
224
|
+
operations
|
|
225
|
+
}));
|
|
226
|
+
};
|
|
227
|
+
const renderLiteral = (value)=>{
|
|
228
|
+
if ('string' == typeof value || 'number' == typeof value || 'boolean' == typeof value) return JSON.stringify(value);
|
|
229
|
+
return 'unknown';
|
|
230
|
+
};
|
|
231
|
+
const resolveDocText = (doc)=>{
|
|
232
|
+
const text = extractDocText(doc);
|
|
233
|
+
if (!text) return [];
|
|
234
|
+
return text.split(/\r?\n/).map((line)=>line.trim()).filter((line)=>line.length > 0);
|
|
235
|
+
};
|
|
236
|
+
const renderConstraints = (constraints)=>{
|
|
237
|
+
if (!constraints || 'object' != typeof constraints) return [];
|
|
238
|
+
const entries = Object.entries(constraints).filter(([_, value])=>void 0 !== value);
|
|
239
|
+
if (0 === entries.length) return [];
|
|
240
|
+
const parts = entries.map(([key, value])=>{
|
|
241
|
+
if (Array.isArray(value)) return `${key}=[${value.map((item)=>JSON.stringify(item)).join(', ')}]`;
|
|
242
|
+
return `${key}=${JSON.stringify(value)}`;
|
|
243
|
+
});
|
|
244
|
+
return [
|
|
245
|
+
`Constraints: ${parts.join(', ')}.`
|
|
246
|
+
];
|
|
247
|
+
};
|
|
248
|
+
const buildExample = (node, namedNodes, depth = 0, visited = new Set())=>{
|
|
249
|
+
if (!node) return 'undefined';
|
|
250
|
+
if (depth > 2) return '...';
|
|
251
|
+
if (node.name && namedNodes.has(node.name) && isTypeDefinitionNode(node)) {
|
|
252
|
+
const named = namedNodes.get(node.name).node;
|
|
253
|
+
if (named !== node) {
|
|
254
|
+
if (visited.has(node.name)) return '...';
|
|
255
|
+
visited.add(node.name);
|
|
256
|
+
return buildExample(named, namedNodes, depth + 1, visited);
|
|
257
|
+
}
|
|
258
|
+
if (visited.has(node.name)) return '...';
|
|
259
|
+
visited.add(node.name);
|
|
260
|
+
}
|
|
261
|
+
switch(node.type){
|
|
262
|
+
case 'string':
|
|
263
|
+
return '"string"';
|
|
264
|
+
case 'number':
|
|
265
|
+
return '0';
|
|
266
|
+
case 'boolean':
|
|
267
|
+
return 'false';
|
|
268
|
+
case 'date':
|
|
269
|
+
return 'new Date()';
|
|
270
|
+
case 'binary':
|
|
271
|
+
return 'new Uint8Array()';
|
|
272
|
+
case 'literal':
|
|
273
|
+
return renderLiteral(node.constraints?.value);
|
|
274
|
+
case 'enum':
|
|
275
|
+
{
|
|
276
|
+
const values = Array.isArray(node.constraints?.values) ? node.constraints?.values ?? [] : [];
|
|
277
|
+
return values.length > 0 ? renderLiteral(values[0]) : '"value"';
|
|
278
|
+
}
|
|
279
|
+
case 'array':
|
|
280
|
+
{
|
|
281
|
+
const child = node.children?.[0];
|
|
282
|
+
return `[${buildExample(child, namedNodes, depth + 1, visited)}]`;
|
|
283
|
+
}
|
|
284
|
+
case 'tuple':
|
|
285
|
+
{
|
|
286
|
+
const items = (node.children ?? []).map((child)=>buildExample(child, namedNodes, depth + 1, visited));
|
|
287
|
+
return `[${items.join(', ')}]`;
|
|
288
|
+
}
|
|
289
|
+
case 'union':
|
|
290
|
+
{
|
|
291
|
+
const first = node.children?.[0];
|
|
292
|
+
return buildExample(first, namedNodes, depth + 1, visited);
|
|
293
|
+
}
|
|
294
|
+
case 'object':
|
|
295
|
+
{
|
|
296
|
+
const fields = (node.children ?? []).filter((child)=>'field' === child.type && child.name);
|
|
297
|
+
const body = fields.slice(0, 3).map((field)=>{
|
|
298
|
+
const value = buildExample(field.children?.[0], namedNodes, depth + 1, visited);
|
|
299
|
+
return `${renderPropertyName(field.name ?? 'field')}: ${value}`;
|
|
300
|
+
});
|
|
301
|
+
const tail = fields.length > 3 ? ', ...' : '';
|
|
302
|
+
return `{ ${body.join(', ')}${tail} }`;
|
|
303
|
+
}
|
|
304
|
+
default:
|
|
305
|
+
return '...';
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
const renderTypeDoc = (node, namedNodes)=>{
|
|
309
|
+
const lines = [];
|
|
310
|
+
lines.push(...resolveDocText(node.doc));
|
|
311
|
+
lines.push(`Type: ${node.type}${node.name ? ` (${node.name})` : ''}.`);
|
|
312
|
+
lines.push(...renderConstraints(node.constraints));
|
|
313
|
+
if ('object' === node.type) {
|
|
314
|
+
const fields = (node.children ?? []).filter((child)=>'field' === child.type && child.name);
|
|
315
|
+
if (fields.length > 0) lines.push(`Fields: ${fields.map((field)=>field.name).join(', ')}.`);
|
|
316
|
+
}
|
|
317
|
+
lines.push(`@example ${buildExample(node, namedNodes)}`);
|
|
318
|
+
return lines;
|
|
319
|
+
};
|
|
320
|
+
const renderFieldDoc = (fieldName, fieldNode, fieldType, namedNodes)=>{
|
|
321
|
+
const doc = fieldNode.doc ?? fieldNode.children?.[0]?.doc;
|
|
322
|
+
const lines = [];
|
|
323
|
+
lines.push(...resolveDocText(doc));
|
|
324
|
+
lines.push(`Field: ${fieldName}.`);
|
|
325
|
+
lines.push(`Type: ${fieldType}.`);
|
|
326
|
+
lines.push(...renderConstraints(fieldNode.constraints));
|
|
327
|
+
lines.push(`@link ${fieldType}`);
|
|
328
|
+
lines.push(`@example ${buildExample(fieldNode.children?.[0], namedNodes)}`);
|
|
329
|
+
return lines;
|
|
330
|
+
};
|
|
331
|
+
const renderOperationDoc = (operation, inputType, outputType, namedNodes)=>{
|
|
332
|
+
const lines = [];
|
|
333
|
+
lines.push(...resolveDocText(operation.doc));
|
|
334
|
+
lines.push(`Operation: ${operation.name}.`);
|
|
335
|
+
lines.push(...renderConstraints(operation.constraints));
|
|
336
|
+
if (operation.input) {
|
|
337
|
+
const requestType = operation.requestType ?? inputType;
|
|
338
|
+
lines.push(`@param input ${requestType}`);
|
|
339
|
+
lines.push(`@link ${requestType}`);
|
|
340
|
+
} else lines.push("@param input void");
|
|
341
|
+
const responseType = operation.responseType ?? outputType;
|
|
342
|
+
lines.push(`@returns ${responseType}`);
|
|
343
|
+
lines.push(`@resolve ${responseType}`);
|
|
344
|
+
lines.push(`@link ${responseType}`);
|
|
345
|
+
if (operation.publishTopics.length > 0) lines.push(`Publishes events: ${operation.publishTopics.join(', ')}.`);
|
|
346
|
+
const inputExample = operation.input ? buildExample(operation.input, namedNodes) : '';
|
|
347
|
+
const call = operation.input ? `(${inputExample})` : '()';
|
|
348
|
+
lines.push(`@example await client.${renderPropertyName(operation.name)}${call}`);
|
|
349
|
+
if (operation.input) {
|
|
350
|
+
const requestType = operation.requestType ?? inputType;
|
|
351
|
+
const signatureInput = `${inputExample}: ${requestType}`;
|
|
352
|
+
lines.push(`@example ${operation.name}(${signatureInput}): ${responseType}`);
|
|
353
|
+
} else lines.push(`@example ${operation.name}(): ${responseType}`);
|
|
354
|
+
return lines;
|
|
355
|
+
};
|
|
356
|
+
const renderFieldOperationDoc = (owner, field, inputType, outputType, hasInput, operation, namedNodes)=>{
|
|
357
|
+
const lines = [];
|
|
358
|
+
lines.push(...resolveDocText(operation.doc));
|
|
359
|
+
lines.push(`Field operation: ${owner}.${field}.`);
|
|
360
|
+
lines.push(...renderConstraints(operation.constraints));
|
|
361
|
+
const dependsOn = operation.dependsOnType ?? owner;
|
|
362
|
+
lines.push(`Depends on: ${dependsOn}.`);
|
|
363
|
+
lines.push(`@link ${dependsOn}`);
|
|
364
|
+
if (hasInput) {
|
|
365
|
+
const requestType = operation.requestType ?? inputType;
|
|
366
|
+
lines.push(`@param input ${requestType}`);
|
|
367
|
+
lines.push(`@link ${requestType}`);
|
|
368
|
+
} else lines.push("@param input void");
|
|
369
|
+
const responseType = operation.responseType ?? outputType;
|
|
370
|
+
lines.push(`@returns ${responseType}`);
|
|
371
|
+
lines.push(`@resolve ${responseType}`);
|
|
372
|
+
lines.push(`@link ${responseType}`);
|
|
373
|
+
const inputExample = hasInput ? buildExample(operation.input, namedNodes) : '';
|
|
374
|
+
const call = hasInput ? `(${inputExample})` : '()';
|
|
375
|
+
lines.push(`@example await ${field}${call}`);
|
|
376
|
+
if (hasInput) {
|
|
377
|
+
const requestType = operation.requestType ?? inputType;
|
|
378
|
+
lines.push(`@example ${field}(${inputExample}: ${requestType}): ${responseType}`);
|
|
379
|
+
} else lines.push(`@example ${field}(): ${responseType}`);
|
|
380
|
+
return lines;
|
|
381
|
+
};
|
|
382
|
+
const renderType = (node, namedNodes, ignoreName)=>{
|
|
383
|
+
if (!node) return 'unknown';
|
|
384
|
+
if (node.name && node.name !== ignoreName && namedNodes.has(node.name) && isTypeDefinitionNode(node)) return namedNodes.get(node.name).typeName;
|
|
385
|
+
switch(node.type){
|
|
386
|
+
case 'string':
|
|
387
|
+
return 'string';
|
|
388
|
+
case 'number':
|
|
389
|
+
return 'number';
|
|
390
|
+
case 'boolean':
|
|
391
|
+
return 'boolean';
|
|
392
|
+
case 'date':
|
|
393
|
+
return 'Date';
|
|
394
|
+
case 'binary':
|
|
395
|
+
return 'Uint8Array';
|
|
396
|
+
case 'literal':
|
|
397
|
+
return renderLiteral(node.constraints?.value);
|
|
398
|
+
case 'enum':
|
|
399
|
+
{
|
|
400
|
+
const values = Array.isArray(node.constraints?.values) ? node.constraints?.values ?? [] : [];
|
|
401
|
+
const literalValues = values.map((value)=>renderLiteral(value)).filter((value)=>'unknown' !== value);
|
|
402
|
+
return literalValues.length > 0 ? literalValues.join(' | ') : 'string';
|
|
403
|
+
}
|
|
404
|
+
case 'array':
|
|
405
|
+
{
|
|
406
|
+
const child = node.children?.[0];
|
|
407
|
+
return `Array<${renderType(child, namedNodes)}>`;
|
|
408
|
+
}
|
|
409
|
+
case 'tuple':
|
|
410
|
+
{
|
|
411
|
+
const items = (node.children ?? []).map((child)=>renderType(child, namedNodes));
|
|
412
|
+
return `[${items.join(', ')}]`;
|
|
413
|
+
}
|
|
414
|
+
case 'union':
|
|
415
|
+
{
|
|
416
|
+
const options = (node.children ?? []).map((child)=>renderType(child, namedNodes));
|
|
417
|
+
return options.length > 0 ? options.join(' | ') : 'unknown';
|
|
418
|
+
}
|
|
419
|
+
case 'object':
|
|
420
|
+
return node.name && namedNodes.has(node.name) ? namedNodes.get(node.name).typeName : 'Record<string, unknown>';
|
|
421
|
+
default:
|
|
422
|
+
return 'unknown';
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
const renderOperationTypeName = (operation, used)=>resolveUniqueName(`${pascalCaseName(operation.name)}Operation`, used);
|
|
426
|
+
const renderFieldOperationTypeName = (ownerType, field, used)=>resolveUniqueName(`${ownerType}${pascalCaseName(field)}Field`, used);
|
|
427
|
+
const renderTypeDefinitions = (namedNodes, fieldOperations, usedNames)=>{
|
|
428
|
+
const lines = [];
|
|
429
|
+
const fieldTypeNames = new Map();
|
|
430
|
+
const groups = groupFieldOperations(fieldOperations);
|
|
431
|
+
const groupsByOwner = groups.reduce((acc, group)=>{
|
|
432
|
+
acc.set(group.owner, group.operations);
|
|
433
|
+
return acc;
|
|
434
|
+
}, new Map());
|
|
435
|
+
const namedEntries = Array.from(namedNodes.values()).sort((a, b)=>a.typeName.localeCompare(b.typeName));
|
|
436
|
+
namedEntries.forEach((entry)=>{
|
|
437
|
+
const node = entry.node;
|
|
438
|
+
lines.push(...renderJSDoc(renderTypeDoc(node, namedNodes)));
|
|
439
|
+
if ('object' === node.type) {
|
|
440
|
+
lines.push(`export interface ${entry.typeName} {`);
|
|
441
|
+
const fields = (node.children ?? []).filter((child)=>'field' === child.type && child.name);
|
|
442
|
+
fields.forEach((fieldNode)=>{
|
|
443
|
+
const fieldName = fieldNode.name ?? 'field';
|
|
444
|
+
const childType = renderType(fieldNode.children?.[0], namedNodes);
|
|
445
|
+
lines.push(...renderJSDoc(renderFieldDoc(fieldName, fieldNode, childType, namedNodes), ' '));
|
|
446
|
+
lines.push(` ${renderPropertyName(fieldName)}: ${childType};`);
|
|
447
|
+
});
|
|
448
|
+
const operations = groupsByOwner.get(entry.name) ?? [];
|
|
449
|
+
operations.forEach((operation)=>{
|
|
450
|
+
const fieldMap = fieldTypeNames.get(entry.name) ?? new Map();
|
|
451
|
+
const fieldTypeName = renderFieldOperationTypeName(entry.typeName, operation.field, usedNames);
|
|
452
|
+
fieldMap.set(operation.field, fieldTypeName);
|
|
453
|
+
fieldTypeNames.set(entry.name, fieldMap);
|
|
454
|
+
const inputType = renderType(operation.input, namedNodes);
|
|
455
|
+
const outputType = renderType(operation.output, namedNodes);
|
|
456
|
+
const hasInput = Boolean(operation.input);
|
|
457
|
+
lines.push(...renderJSDoc(renderFieldOperationDoc(entry.typeName, operation.field, inputType, outputType, hasInput, operation, namedNodes), ' '));
|
|
458
|
+
lines.push(` ${renderPropertyName(operation.field)}?: ${fieldTypeName};`);
|
|
459
|
+
});
|
|
460
|
+
lines.push('}');
|
|
461
|
+
lines.push('');
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const typeBody = renderType(node, namedNodes, entry.name);
|
|
465
|
+
lines.push(`export type ${entry.typeName} = ${typeBody};`);
|
|
466
|
+
lines.push('');
|
|
467
|
+
});
|
|
468
|
+
return {
|
|
469
|
+
definitions: lines,
|
|
470
|
+
fieldTypeNames
|
|
471
|
+
};
|
|
472
|
+
};
|
|
473
|
+
const renderFieldOperationDefinitions = (fieldOperations, namedNodes, usedNames, fieldTypeNames)=>{
|
|
474
|
+
const lines = [];
|
|
475
|
+
const operations = fieldOperations.map((operation)=>{
|
|
476
|
+
const owner = namedNodes.get(operation.owner)?.typeName ?? sanitizeTypeName(operation.owner);
|
|
477
|
+
const fieldTypeName = fieldTypeNames.get(operation.owner)?.get(operation.field) ?? renderFieldOperationTypeName(owner, operation.field, usedNames);
|
|
478
|
+
const inputType = renderType(operation.input, namedNodes);
|
|
479
|
+
const outputType = renderType(operation.output, namedNodes);
|
|
480
|
+
return {
|
|
481
|
+
owner,
|
|
482
|
+
field: operation.field,
|
|
483
|
+
fieldTypeName,
|
|
484
|
+
inputType,
|
|
485
|
+
outputType,
|
|
486
|
+
hasInput: Boolean(operation.input),
|
|
487
|
+
doc: operation.doc,
|
|
488
|
+
inputNode: operation.input,
|
|
489
|
+
requestType: operation.requestType,
|
|
490
|
+
responseType: operation.responseType,
|
|
491
|
+
dependsOnType: operation.dependsOnType
|
|
492
|
+
};
|
|
493
|
+
}).sort((a, b)=>a.fieldTypeName.localeCompare(b.fieldTypeName));
|
|
494
|
+
operations.forEach((operation)=>{
|
|
495
|
+
lines.push(...renderJSDoc(renderFieldOperationDoc(operation.owner, operation.field, operation.inputType, operation.outputType, operation.hasInput, {
|
|
496
|
+
owner: operation.owner,
|
|
497
|
+
field: operation.field,
|
|
498
|
+
input: operation.inputNode,
|
|
499
|
+
doc: operation.doc,
|
|
500
|
+
requestType: operation.requestType,
|
|
501
|
+
responseType: operation.responseType,
|
|
502
|
+
dependsOnType: operation.dependsOnType
|
|
503
|
+
}, namedNodes)));
|
|
504
|
+
lines.push(`export interface ${operation.fieldTypeName} {`);
|
|
505
|
+
if (operation.hasInput) lines.push(` (input: ${operation.inputType}): Promise<${operation.outputType}>;`);
|
|
506
|
+
else lines.push(` (): Promise<${operation.outputType}>;`);
|
|
507
|
+
lines.push('}');
|
|
508
|
+
lines.push('');
|
|
509
|
+
});
|
|
510
|
+
return lines;
|
|
511
|
+
};
|
|
512
|
+
const renderOperationDefinitions = (operations, namedNodes, usedNames)=>{
|
|
513
|
+
const lines = [];
|
|
514
|
+
const clientLines = [];
|
|
515
|
+
const sorted = operations.map((operation)=>({
|
|
516
|
+
operation,
|
|
517
|
+
typeName: renderOperationTypeName(operation, usedNames)
|
|
518
|
+
})).sort((a, b)=>a.typeName.localeCompare(b.typeName));
|
|
519
|
+
sorted.forEach((entry)=>{
|
|
520
|
+
const inputType = renderType(entry.operation.input, namedNodes);
|
|
521
|
+
const outputType = renderType(entry.operation.output, namedNodes);
|
|
522
|
+
lines.push(...renderJSDoc(renderOperationDoc(entry.operation, inputType, outputType, namedNodes)));
|
|
523
|
+
lines.push(`export interface ${entry.typeName} {`);
|
|
524
|
+
if (entry.operation.input) lines.push(` (input: ${inputType}): Promise<${outputType}>;`);
|
|
525
|
+
else lines.push(` (): Promise<${outputType}>;`);
|
|
526
|
+
lines.push('}');
|
|
527
|
+
lines.push('');
|
|
528
|
+
clientLines.push(...renderJSDoc(renderOperationDoc(entry.operation, inputType, outputType, namedNodes), ' '));
|
|
529
|
+
clientLines.push(` ${renderPropertyName(entry.operation.name)}: ${entry.typeName};`);
|
|
530
|
+
});
|
|
531
|
+
return {
|
|
532
|
+
lines,
|
|
533
|
+
clientLines
|
|
534
|
+
};
|
|
535
|
+
};
|
|
536
|
+
const renderEventMapDefinitions = (events)=>{
|
|
537
|
+
if (0 === events.length) return [
|
|
538
|
+
'export type LivonEventMap = Record<string, never>;',
|
|
539
|
+
''
|
|
540
|
+
];
|
|
541
|
+
const entries = events.reduce((acc, event)=>{
|
|
542
|
+
if (!acc.has(event.topic)) acc.set(event.topic, event.payloadType);
|
|
543
|
+
return acc;
|
|
544
|
+
}, new Map());
|
|
545
|
+
const lines = [
|
|
546
|
+
'export type LivonEventMap = {'
|
|
547
|
+
];
|
|
548
|
+
Array.from(entries.entries()).forEach(([topic, payloadType])=>{
|
|
549
|
+
lines.push(` ${JSON.stringify(topic)}: ${payloadType};`);
|
|
550
|
+
});
|
|
551
|
+
lines.push('};');
|
|
552
|
+
lines.push('');
|
|
553
|
+
return lines;
|
|
554
|
+
};
|
|
555
|
+
const defaultAstTemplate = ()=>`export const ast = ${AST_PLACEHOLDER} as const;\n\nexport default ast;\n`;
|
|
556
|
+
const defaultClientTemplate = ()=>[
|
|
557
|
+
CLIENT_IMPORTS_PLACEHOLDER,
|
|
558
|
+
CLIENT_TYPE_DEFS_PLACEHOLDER,
|
|
559
|
+
CLIENT_EVENT_MAP_PLACEHOLDER,
|
|
560
|
+
CLIENT_FIELD_OPS_PLACEHOLDER,
|
|
561
|
+
CLIENT_OP_DEFS_PLACEHOLDER,
|
|
562
|
+
CLIENT_OP_LINES_PLACEHOLDER,
|
|
563
|
+
CLIENT_SUB_NAMES_PLACEHOLDER,
|
|
564
|
+
CLIENT_EXPORT_NAME_PLACEHOLDER
|
|
565
|
+
].join('\n');
|
|
566
|
+
const readTemplate = (filename, fallback)=>{
|
|
567
|
+
const templatePath = external_node_path_default().join(templatesDir, filename);
|
|
568
|
+
try {
|
|
569
|
+
return external_node_fs_default().readFileSync(templatePath, 'utf8');
|
|
570
|
+
} catch {
|
|
571
|
+
return fallback();
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
const applyTemplate = (template, placeholder, value, label)=>{
|
|
575
|
+
if (!template.includes(placeholder)) throw new Error(`Template ${label} is missing placeholder ${placeholder}`);
|
|
576
|
+
return template.split(placeholder).join(value);
|
|
577
|
+
};
|
|
578
|
+
const applyTemplateMap = (template, placeholders, label)=>placeholders.reduce((next, entry)=>applyTemplate(next, entry.key, entry.value, label), template);
|
|
579
|
+
const getClientGeneratorFingerprint = ()=>{
|
|
580
|
+
const source = external_node_fs_default().readFileSync(sourceFilePath, 'utf8');
|
|
581
|
+
const astTemplate = readTemplate('ast.template.ts', defaultAstTemplate);
|
|
582
|
+
const clientTemplate = readTemplate('client.template.ts', defaultClientTemplate);
|
|
583
|
+
const parts = [
|
|
584
|
+
hashText(source),
|
|
585
|
+
hashText(astTemplate),
|
|
586
|
+
hashText(clientTemplate)
|
|
587
|
+
];
|
|
588
|
+
return hashText(parts.join(':'));
|
|
589
|
+
};
|
|
590
|
+
const generateClientFiles = ({ ast, exportName = 'api', astModuleName = 'ast', clientModuleName = 'api' })=>{
|
|
591
|
+
const namedNodes = collectNamedNodes(ast);
|
|
592
|
+
const operations = collectOperations(ast);
|
|
593
|
+
const fieldOperations = collectFieldOperations(ast);
|
|
594
|
+
const usedNames = new Set(Array.from(namedNodes.values()).map((node)=>node.typeName));
|
|
595
|
+
const publishEvents = collectPublishEvents(ast, namedNodes);
|
|
596
|
+
const subscriptionEvents = collectSubscriptionEvents(ast, namedNodes);
|
|
597
|
+
const { definitions: typeDefinitions, fieldTypeNames } = renderTypeDefinitions(namedNodes, fieldOperations, usedNames);
|
|
598
|
+
const fieldOperationDefinitions = renderFieldOperationDefinitions(fieldOperations, namedNodes, usedNames, fieldTypeNames);
|
|
599
|
+
const { lines: operationDefinitions, clientLines } = renderOperationDefinitions(operations, namedNodes, usedNames);
|
|
600
|
+
const eventsByTopic = new Map();
|
|
601
|
+
subscriptionEvents.forEach((event)=>eventsByTopic.set(event.topic, event));
|
|
602
|
+
publishEvents.forEach((event)=>{
|
|
603
|
+
if (!eventsByTopic.has(event.topic)) eventsByTopic.set(event.topic, event);
|
|
604
|
+
});
|
|
605
|
+
const events = Array.from(eventsByTopic.values());
|
|
606
|
+
const eventMapDefinitions = renderEventMapDefinitions(events);
|
|
607
|
+
const eventTopics = events.map((event)=>event.topic);
|
|
608
|
+
const subscriptionNamesArray = Array.from(new Set(eventTopics)).map((topic)=>JSON.stringify(topic));
|
|
609
|
+
const clientImports = [
|
|
610
|
+
"import { createClient as createRuntimeClient } from '@livon/client';",
|
|
611
|
+
"import type { ClientHandlerContext, ClientModule } from '@livon/client';",
|
|
612
|
+
`import { ast } from './${astModuleName}.js';`
|
|
613
|
+
].join('\n');
|
|
614
|
+
const clientTypeDefs = typeDefinitions.join('\n');
|
|
615
|
+
const clientEventMap = eventMapDefinitions.join('\n');
|
|
616
|
+
const clientFieldOps = fieldOperationDefinitions.join('\n');
|
|
617
|
+
const clientOpDefs = operationDefinitions.join('\n');
|
|
618
|
+
const clientOpLines = clientLines.join('\n');
|
|
619
|
+
const clientSubscriptionNames = subscriptionNamesArray.join(', ');
|
|
620
|
+
const astTemplate = readTemplate('ast.template.ts', defaultAstTemplate);
|
|
621
|
+
const clientTemplate = readTemplate('client.template.ts', defaultClientTemplate);
|
|
622
|
+
const astSource = applyTemplate(astTemplate, AST_PLACEHOLDER, serializeAst(ast), 'ast');
|
|
623
|
+
const clientSource = applyTemplateMap(clientTemplate, [
|
|
624
|
+
{
|
|
625
|
+
key: CLIENT_IMPORTS_PLACEHOLDER,
|
|
626
|
+
value: clientImports
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
key: CLIENT_TYPE_DEFS_PLACEHOLDER,
|
|
630
|
+
value: clientTypeDefs
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
key: CLIENT_EVENT_MAP_PLACEHOLDER,
|
|
634
|
+
value: clientEventMap
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
key: CLIENT_FIELD_OPS_PLACEHOLDER,
|
|
638
|
+
value: clientFieldOps
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
key: CLIENT_OP_DEFS_PLACEHOLDER,
|
|
642
|
+
value: clientOpDefs
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
key: CLIENT_OP_LINES_PLACEHOLDER,
|
|
646
|
+
value: clientOpLines
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
key: CLIENT_SUB_NAMES_PLACEHOLDER,
|
|
650
|
+
value: clientSubscriptionNames
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
key: CLIENT_EXPORT_NAME_PLACEHOLDER,
|
|
654
|
+
value: exportName
|
|
655
|
+
}
|
|
656
|
+
], 'client');
|
|
657
|
+
const astFile = `${astModuleName}.ts`;
|
|
658
|
+
const clientFile = `${clientModuleName}.ts`;
|
|
659
|
+
return {
|
|
660
|
+
astFile,
|
|
661
|
+
clientFile,
|
|
662
|
+
files: {
|
|
663
|
+
[astFile]: astSource,
|
|
664
|
+
[clientFile]: clientSource
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
};
|
|
668
|
+
exports.generateClientFiles = __webpack_exports__.generateClientFiles;
|
|
669
|
+
exports.getClientGeneratorFingerprint = __webpack_exports__.getClientGeneratorFingerprint;
|
|
670
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
671
|
+
"generateClientFiles",
|
|
672
|
+
"getClientGeneratorFingerprint"
|
|
673
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
674
|
+
Object.defineProperty(exports, '__esModule', {
|
|
675
|
+
value: true
|
|
676
|
+
});
|