cloesce 0.0.3-fix.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/LICENSE +201 -0
- package/README.md +23 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +352 -0
- package/dist/cli.wasm +0 -0
- package/dist/cloesce.d.ts +108 -0
- package/dist/cloesce.d.ts.map +1 -0
- package/dist/cloesce.js +453 -0
- package/dist/common.d.ts +96 -0
- package/dist/common.d.ts.map +1 -0
- package/dist/common.js +96 -0
- package/dist/decorators.d.ts +13 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +13 -0
- package/dist/dog.cloesce.js +111 -0
- package/dist/extract.d.ts +14 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +517 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +60 -0
package/dist/extract.js
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import { SyntaxKind, } from "ts-morph";
|
|
2
|
+
import { HttpVerb, left, right, ExtractorError, ExtractorErrorCode, } from "./common.js";
|
|
3
|
+
import { TypeFormatFlags } from "typescript";
|
|
4
|
+
var AttributeDecoratorKind;
|
|
5
|
+
(function (AttributeDecoratorKind) {
|
|
6
|
+
AttributeDecoratorKind["PrimaryKey"] = "PrimaryKey";
|
|
7
|
+
AttributeDecoratorKind["ForeignKey"] = "ForeignKey";
|
|
8
|
+
AttributeDecoratorKind["OneToOne"] = "OneToOne";
|
|
9
|
+
AttributeDecoratorKind["OneToMany"] = "OneToMany";
|
|
10
|
+
AttributeDecoratorKind["ManyToMany"] = "ManyToMany";
|
|
11
|
+
AttributeDecoratorKind["DataSource"] = "DataSource";
|
|
12
|
+
})(AttributeDecoratorKind || (AttributeDecoratorKind = {}));
|
|
13
|
+
var ClassDecoratorKind;
|
|
14
|
+
(function (ClassDecoratorKind) {
|
|
15
|
+
ClassDecoratorKind["D1"] = "D1";
|
|
16
|
+
ClassDecoratorKind["WranglerEnv"] = "WranglerEnv";
|
|
17
|
+
ClassDecoratorKind["PlainOldObject"] = "PlainOldObject";
|
|
18
|
+
})(ClassDecoratorKind || (ClassDecoratorKind = {}));
|
|
19
|
+
var ParameterDecoratorKind;
|
|
20
|
+
(function (ParameterDecoratorKind) {
|
|
21
|
+
ParameterDecoratorKind["Inject"] = "Inject";
|
|
22
|
+
})(ParameterDecoratorKind || (ParameterDecoratorKind = {}));
|
|
23
|
+
export class CidlExtractor {
|
|
24
|
+
projectName;
|
|
25
|
+
version;
|
|
26
|
+
constructor(projectName, version) {
|
|
27
|
+
this.projectName = projectName;
|
|
28
|
+
this.version = version;
|
|
29
|
+
}
|
|
30
|
+
extract(project) {
|
|
31
|
+
const models = {};
|
|
32
|
+
const poos = {};
|
|
33
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
34
|
+
for (const classDecl of sourceFile.getClasses()) {
|
|
35
|
+
if (hasDecorator(classDecl, ClassDecoratorKind.D1)) {
|
|
36
|
+
const result = CidlExtractor.model(classDecl, sourceFile);
|
|
37
|
+
// Error: propogate from models
|
|
38
|
+
if (!result.ok) {
|
|
39
|
+
result.value.addContext((old) => `${classDecl.getName()}.${old}`);
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
models[result.value.name] = result.value;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (hasDecorator(classDecl, ClassDecoratorKind.PlainOldObject)) {
|
|
46
|
+
const result = CidlExtractor.poo(classDecl, sourceFile);
|
|
47
|
+
// Error: propogate from models
|
|
48
|
+
if (!result.ok) {
|
|
49
|
+
result.value.addContext((old) => `${classDecl.getName()}.${old}`);
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
poos[result.value.name] = result.value;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const wranglerEnvs = project
|
|
58
|
+
.getSourceFiles()
|
|
59
|
+
.flatMap((sourceFile) => {
|
|
60
|
+
return sourceFile
|
|
61
|
+
.getClasses()
|
|
62
|
+
.filter((classDecl) => hasDecorator(classDecl, ClassDecoratorKind.WranglerEnv))
|
|
63
|
+
.map((classDecl) => {
|
|
64
|
+
return {
|
|
65
|
+
name: classDecl.getName(),
|
|
66
|
+
source_path: sourceFile.getFilePath().toString(),
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
// Error: A wrangler environment is required
|
|
71
|
+
if (wranglerEnvs.length < 1) {
|
|
72
|
+
return err(ExtractorErrorCode.MissingWranglerEnv);
|
|
73
|
+
}
|
|
74
|
+
// Error: Only one wrangler environment can exist
|
|
75
|
+
if (wranglerEnvs.length > 1) {
|
|
76
|
+
return err(ExtractorErrorCode.TooManyWranglerEnvs, (e) => (e.context = wranglerEnvs.map((w) => w.name).toString()));
|
|
77
|
+
}
|
|
78
|
+
return right({
|
|
79
|
+
version: this.version,
|
|
80
|
+
project_name: this.projectName,
|
|
81
|
+
language: "TypeScript",
|
|
82
|
+
wrangler_env: wranglerEnvs[0],
|
|
83
|
+
models,
|
|
84
|
+
poos,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
static model(classDecl, sourceFile) {
|
|
88
|
+
const name = classDecl.getName();
|
|
89
|
+
const attributes = [];
|
|
90
|
+
const navigationProperties = [];
|
|
91
|
+
const dataSources = {};
|
|
92
|
+
const methods = {};
|
|
93
|
+
let primary_key = undefined;
|
|
94
|
+
for (const prop of classDecl.getProperties()) {
|
|
95
|
+
const decorators = prop.getDecorators();
|
|
96
|
+
const typeRes = CidlExtractor.cidlType(prop.getType());
|
|
97
|
+
// Error: invalid property type
|
|
98
|
+
if (!typeRes.ok) {
|
|
99
|
+
typeRes.value.context = prop.getName();
|
|
100
|
+
typeRes.value.snippet = prop.getText();
|
|
101
|
+
return typeRes;
|
|
102
|
+
}
|
|
103
|
+
// No decorators means this is a standard attribute
|
|
104
|
+
if (decorators.length === 0) {
|
|
105
|
+
const cidl_type = typeRes.value;
|
|
106
|
+
attributes.push({
|
|
107
|
+
foreign_key_reference: null,
|
|
108
|
+
value: {
|
|
109
|
+
name: prop.getName(),
|
|
110
|
+
cidl_type,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// TODO: Limiting to one decorator. Can't get too fancy on us.
|
|
116
|
+
const decorator = decorators[0];
|
|
117
|
+
const name = getDecoratorName(decorator);
|
|
118
|
+
// Process decorators
|
|
119
|
+
const cidl_type = typeRes.value;
|
|
120
|
+
switch (name) {
|
|
121
|
+
case AttributeDecoratorKind.PrimaryKey: {
|
|
122
|
+
primary_key = {
|
|
123
|
+
name: prop.getName(),
|
|
124
|
+
cidl_type,
|
|
125
|
+
};
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case AttributeDecoratorKind.ForeignKey: {
|
|
129
|
+
attributes.push({
|
|
130
|
+
foreign_key_reference: getDecoratorArgument(decorator, 0) ?? null,
|
|
131
|
+
value: {
|
|
132
|
+
name: prop.getName(),
|
|
133
|
+
cidl_type,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case AttributeDecoratorKind.OneToOne: {
|
|
139
|
+
const reference = getDecoratorArgument(decorator, 0);
|
|
140
|
+
// Error: One to one navigation properties requre a reference
|
|
141
|
+
if (!reference) {
|
|
142
|
+
return err(ExtractorErrorCode.MissingNavigationPropertyReference, (e) => {
|
|
143
|
+
e.snippet = prop.getText();
|
|
144
|
+
e.context = prop.getName();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
let model_name = getObjectName(cidl_type);
|
|
148
|
+
// Error: navigation properties require a model reference
|
|
149
|
+
if (!model_name) {
|
|
150
|
+
return err(ExtractorErrorCode.MissingNavigationPropertyReference, (e) => {
|
|
151
|
+
e.snippet = prop.getText();
|
|
152
|
+
e.context = prop.getName();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
navigationProperties.push({
|
|
156
|
+
var_name: prop.getName(),
|
|
157
|
+
model_name,
|
|
158
|
+
kind: { OneToOne: { reference } },
|
|
159
|
+
});
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
case AttributeDecoratorKind.OneToMany: {
|
|
163
|
+
const reference = getDecoratorArgument(decorator, 0);
|
|
164
|
+
// Error: One to one navigation properties requre a reference
|
|
165
|
+
if (!reference) {
|
|
166
|
+
return err(ExtractorErrorCode.MissingNavigationPropertyReference, (e) => {
|
|
167
|
+
e.snippet = prop.getText();
|
|
168
|
+
e.context = prop.getName();
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
let model_name = getObjectName(cidl_type);
|
|
172
|
+
// Error: navigation properties require a model reference
|
|
173
|
+
if (!model_name) {
|
|
174
|
+
return err(ExtractorErrorCode.MissingNavigationPropertyReference, (e) => {
|
|
175
|
+
e.snippet = prop.getText();
|
|
176
|
+
e.context = prop.getName();
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
navigationProperties.push({
|
|
180
|
+
var_name: prop.getName(),
|
|
181
|
+
model_name,
|
|
182
|
+
kind: { OneToMany: { reference } },
|
|
183
|
+
});
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case AttributeDecoratorKind.ManyToMany: {
|
|
187
|
+
const unique_id = getDecoratorArgument(decorator, 0);
|
|
188
|
+
// Error: many to many attribtues require a unique id
|
|
189
|
+
if (!unique_id)
|
|
190
|
+
return err(ExtractorErrorCode.MissingManyToManyUniqueId, (e) => {
|
|
191
|
+
e.snippet = prop.getText();
|
|
192
|
+
e.context = prop.getName();
|
|
193
|
+
});
|
|
194
|
+
// Error: navigation properties require a model reference
|
|
195
|
+
let model_name = getObjectName(cidl_type);
|
|
196
|
+
if (!model_name) {
|
|
197
|
+
return err(ExtractorErrorCode.MissingNavigationPropertyReference, (e) => {
|
|
198
|
+
e.snippet = prop.getText();
|
|
199
|
+
e.context = prop.getName();
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
navigationProperties.push({
|
|
203
|
+
var_name: prop.getName(),
|
|
204
|
+
model_name,
|
|
205
|
+
kind: { ManyToMany: { unique_id } },
|
|
206
|
+
});
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case AttributeDecoratorKind.DataSource: {
|
|
210
|
+
const initializer = prop.getInitializer();
|
|
211
|
+
const treeRes = CidlExtractor.includeTree(initializer, classDecl, sourceFile);
|
|
212
|
+
if (!treeRes.ok) {
|
|
213
|
+
treeRes.value.addContext((old) => `${prop.getName()} ${old}`);
|
|
214
|
+
treeRes.value.snippet = prop.getText();
|
|
215
|
+
return treeRes;
|
|
216
|
+
}
|
|
217
|
+
dataSources[prop.getName()] = {
|
|
218
|
+
name: prop.getName(),
|
|
219
|
+
tree: treeRes.value,
|
|
220
|
+
};
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (primary_key == undefined) {
|
|
226
|
+
return err(ExtractorErrorCode.MissingPrimaryKey, (e) => {
|
|
227
|
+
e.snippet = classDecl.getText();
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// Process methods
|
|
231
|
+
for (const m of classDecl.getMethods()) {
|
|
232
|
+
const result = CidlExtractor.method(m);
|
|
233
|
+
if (!result.ok) {
|
|
234
|
+
result.value.addContext((old) => `${m.getName()} ${old}`);
|
|
235
|
+
return left(result.value);
|
|
236
|
+
}
|
|
237
|
+
methods[result.value.name] = result.value;
|
|
238
|
+
}
|
|
239
|
+
return right({
|
|
240
|
+
name,
|
|
241
|
+
attributes,
|
|
242
|
+
primary_key,
|
|
243
|
+
navigation_properties: navigationProperties,
|
|
244
|
+
methods,
|
|
245
|
+
data_sources: dataSources,
|
|
246
|
+
source_path: sourceFile.getFilePath().toString(),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
static poo(classDecl, sourceFile) {
|
|
250
|
+
const name = classDecl.getName();
|
|
251
|
+
const attributes = [];
|
|
252
|
+
for (const prop of classDecl.getProperties()) {
|
|
253
|
+
const typeRes = CidlExtractor.cidlType(prop.getType());
|
|
254
|
+
// Error: invalid property type
|
|
255
|
+
if (!typeRes.ok) {
|
|
256
|
+
typeRes.value.context = prop.getName();
|
|
257
|
+
typeRes.value.snippet = prop.getText();
|
|
258
|
+
return typeRes;
|
|
259
|
+
}
|
|
260
|
+
const cidl_type = typeRes.value;
|
|
261
|
+
attributes.push({
|
|
262
|
+
name: prop.getName(),
|
|
263
|
+
cidl_type,
|
|
264
|
+
});
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
return right({
|
|
268
|
+
name,
|
|
269
|
+
attributes,
|
|
270
|
+
source_path: sourceFile.getFilePath().toString(),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
static primTypeMap = {
|
|
274
|
+
number: "Integer",
|
|
275
|
+
Number: "Integer",
|
|
276
|
+
string: "Text",
|
|
277
|
+
String: "Text",
|
|
278
|
+
boolean: "Integer",
|
|
279
|
+
Boolean: "Integer",
|
|
280
|
+
Date: "Text",
|
|
281
|
+
};
|
|
282
|
+
static cidlType(type, inject = false) {
|
|
283
|
+
// Void
|
|
284
|
+
if (type.isVoid()) {
|
|
285
|
+
return right("Void");
|
|
286
|
+
}
|
|
287
|
+
// Null
|
|
288
|
+
if (type.isNull()) {
|
|
289
|
+
return right({ Nullable: "Void" });
|
|
290
|
+
}
|
|
291
|
+
// Nullable via union
|
|
292
|
+
const [unwrappedType, nullable] = unwrapNullable(type);
|
|
293
|
+
const tyText = unwrappedType
|
|
294
|
+
.getText(undefined, TypeFormatFlags.UseAliasDefinedOutsideCurrentScope)
|
|
295
|
+
.split("|")[0]
|
|
296
|
+
.trim();
|
|
297
|
+
// Primitives
|
|
298
|
+
const prim = this.primTypeMap[tyText];
|
|
299
|
+
if (prim) {
|
|
300
|
+
return right(wrapNullable(prim, nullable));
|
|
301
|
+
}
|
|
302
|
+
const generics = [
|
|
303
|
+
...unwrappedType.getAliasTypeArguments(),
|
|
304
|
+
...unwrappedType.getTypeArguments(),
|
|
305
|
+
];
|
|
306
|
+
// Error: can't handle multiple generics
|
|
307
|
+
if (generics.length > 1) {
|
|
308
|
+
return err(ExtractorErrorCode.MultipleGenericType);
|
|
309
|
+
}
|
|
310
|
+
// No generics -> inject or object
|
|
311
|
+
if (generics.length === 0) {
|
|
312
|
+
const base = inject ? { Inject: tyText } : { Object: tyText };
|
|
313
|
+
return right(wrapNullable(base, nullable));
|
|
314
|
+
}
|
|
315
|
+
// Single generic
|
|
316
|
+
const genericTy = generics[0];
|
|
317
|
+
const symbolName = unwrappedType.getSymbol()?.getName();
|
|
318
|
+
const aliasName = unwrappedType.getAliasSymbol()?.getName();
|
|
319
|
+
if (symbolName === "Promise" || aliasName === "IncludeTree") {
|
|
320
|
+
return wrapGeneric(genericTy, nullable, (inner) => inner);
|
|
321
|
+
}
|
|
322
|
+
if (unwrappedType.isArray()) {
|
|
323
|
+
return wrapGeneric(genericTy, nullable, (inner) => ({ Array: inner }));
|
|
324
|
+
}
|
|
325
|
+
if (aliasName === "HttpResult") {
|
|
326
|
+
return wrapGeneric(genericTy, nullable, (inner) => ({
|
|
327
|
+
HttpResult: inner,
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
// Error: unknown type
|
|
331
|
+
return err(ExtractorErrorCode.UnknownType);
|
|
332
|
+
function wrapNullable(inner, isNullable) {
|
|
333
|
+
if (isNullable) {
|
|
334
|
+
return { Nullable: inner };
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
return inner;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function wrapGeneric(t, isNullable, wrapper) {
|
|
341
|
+
const res = CidlExtractor.cidlType(t, inject);
|
|
342
|
+
// Error: propogated from `cidlType`
|
|
343
|
+
if (!res.ok) {
|
|
344
|
+
return res;
|
|
345
|
+
}
|
|
346
|
+
return right(wrapNullable(wrapper(res.value), isNullable));
|
|
347
|
+
}
|
|
348
|
+
function unwrapNullable(ty) {
|
|
349
|
+
if (ty.isUnion()) {
|
|
350
|
+
const nonNull = ty.getUnionTypes().filter((t) => !t.isNull());
|
|
351
|
+
if (nonNull.length === 1) {
|
|
352
|
+
return [nonNull[0], true];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return [ty, false];
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
static includeTree(expr, currentClass, sf) {
|
|
359
|
+
// Include trees must be of the expected form
|
|
360
|
+
if (!expr ||
|
|
361
|
+
!expr.isKind ||
|
|
362
|
+
!expr.isKind(SyntaxKind.ObjectLiteralExpression)) {
|
|
363
|
+
return err(ExtractorErrorCode.InvalidIncludeTree);
|
|
364
|
+
}
|
|
365
|
+
const result = {};
|
|
366
|
+
for (const prop of expr.getProperties()) {
|
|
367
|
+
if (!prop.isKind(SyntaxKind.PropertyAssignment))
|
|
368
|
+
continue;
|
|
369
|
+
// Error: navigation property not found
|
|
370
|
+
const navProp = findPropertyByName(currentClass, prop.getName());
|
|
371
|
+
if (!navProp) {
|
|
372
|
+
return err(ExtractorErrorCode.UnknownNavigationPropertyReference, (e) => {
|
|
373
|
+
e.snippet = expr.getText();
|
|
374
|
+
e.context = prop.getName();
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
const typeRes = CidlExtractor.cidlType(navProp.getType());
|
|
378
|
+
// Error: invalid referenced nav prop type
|
|
379
|
+
if (!typeRes.ok) {
|
|
380
|
+
typeRes.value.snippet = navProp.getText();
|
|
381
|
+
typeRes.value.context = prop.getName();
|
|
382
|
+
return typeRes;
|
|
383
|
+
}
|
|
384
|
+
// Error: invalid referenced nav prop type
|
|
385
|
+
const cidl_type = typeRes.value;
|
|
386
|
+
if (typeof cidl_type === "string") {
|
|
387
|
+
return err(ExtractorErrorCode.InvalidNavigationPropertyReference, (e) => {
|
|
388
|
+
((e.snippet = navProp.getText()), (e.context = prop.getName()));
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
// Recurse for nested includes
|
|
392
|
+
const initializer = prop.getInitializer?.();
|
|
393
|
+
let nestedTree = {};
|
|
394
|
+
if (initializer?.isKind?.(SyntaxKind.ObjectLiteralExpression)) {
|
|
395
|
+
const targetModel = getObjectName(cidl_type);
|
|
396
|
+
const targetClass = currentClass
|
|
397
|
+
.getSourceFile()
|
|
398
|
+
.getProject()
|
|
399
|
+
.getSourceFiles()
|
|
400
|
+
.flatMap((f) => f.getClasses())
|
|
401
|
+
.find((c) => c.getName() === targetModel);
|
|
402
|
+
if (targetClass) {
|
|
403
|
+
const treeRes = CidlExtractor.includeTree(initializer, targetClass, sf);
|
|
404
|
+
// Error: Propogated from `includeTree`
|
|
405
|
+
if (!treeRes.ok) {
|
|
406
|
+
treeRes.value.snippet = expr.getText();
|
|
407
|
+
return treeRes;
|
|
408
|
+
}
|
|
409
|
+
nestedTree = treeRes.value;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
result[navProp.getName()] = nestedTree;
|
|
413
|
+
}
|
|
414
|
+
return right(result);
|
|
415
|
+
}
|
|
416
|
+
static method(method) {
|
|
417
|
+
const decorators = method.getDecorators();
|
|
418
|
+
const decoratorNames = decorators.map((d) => getDecoratorName(d));
|
|
419
|
+
const httpVerb = decoratorNames.find((name) => Object.values(HttpVerb).includes(name));
|
|
420
|
+
const parameters = [];
|
|
421
|
+
for (const param of method.getParameters()) {
|
|
422
|
+
// Handle injected param
|
|
423
|
+
if (param.getDecorator(ParameterDecoratorKind.Inject)) {
|
|
424
|
+
const typeRes = CidlExtractor.cidlType(param.getType(), true);
|
|
425
|
+
// Error: invalid type
|
|
426
|
+
if (!typeRes.ok) {
|
|
427
|
+
typeRes.value.snippet = method.getText();
|
|
428
|
+
typeRes.value.context = param.getName();
|
|
429
|
+
return typeRes;
|
|
430
|
+
}
|
|
431
|
+
parameters.push({
|
|
432
|
+
name: param.getName(),
|
|
433
|
+
cidl_type: typeRes.value,
|
|
434
|
+
});
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
// Handle all other params
|
|
438
|
+
const typeRes = CidlExtractor.cidlType(param.getType());
|
|
439
|
+
// Error: invalid type
|
|
440
|
+
if (!typeRes.ok) {
|
|
441
|
+
typeRes.value.snippet = method.getText();
|
|
442
|
+
typeRes.value.context = param.getName();
|
|
443
|
+
return typeRes;
|
|
444
|
+
}
|
|
445
|
+
parameters.push({
|
|
446
|
+
name: param.getName(),
|
|
447
|
+
cidl_type: typeRes.value,
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
const typeRes = CidlExtractor.cidlType(method.getReturnType());
|
|
451
|
+
// Error: invalid type
|
|
452
|
+
if (!typeRes.ok) {
|
|
453
|
+
typeRes.value.snippet = method.getText();
|
|
454
|
+
return typeRes;
|
|
455
|
+
}
|
|
456
|
+
return right({
|
|
457
|
+
name: method.getName(),
|
|
458
|
+
is_static: method.isStatic(),
|
|
459
|
+
http_verb: httpVerb,
|
|
460
|
+
return_type: typeRes.value,
|
|
461
|
+
parameters,
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
function err(code, fn) {
|
|
466
|
+
let e = new ExtractorError(code);
|
|
467
|
+
if (fn) {
|
|
468
|
+
fn(e);
|
|
469
|
+
}
|
|
470
|
+
return left(e);
|
|
471
|
+
}
|
|
472
|
+
function getDecoratorName(decorator) {
|
|
473
|
+
const name = decorator.getName() ?? decorator.getExpression().getText();
|
|
474
|
+
return String(name).replace(/\(.*\)$/, "");
|
|
475
|
+
}
|
|
476
|
+
function getDecoratorArgument(decorator, index) {
|
|
477
|
+
const args = decorator.getArguments();
|
|
478
|
+
if (!args[index])
|
|
479
|
+
return undefined;
|
|
480
|
+
const arg = args[index];
|
|
481
|
+
// Identifier
|
|
482
|
+
if (arg.getKind?.() === SyntaxKind.Identifier) {
|
|
483
|
+
return arg.getText();
|
|
484
|
+
}
|
|
485
|
+
// String literal
|
|
486
|
+
const text = arg.getText?.();
|
|
487
|
+
if (!text)
|
|
488
|
+
return undefined;
|
|
489
|
+
const match = text.match(/^['"](.*)['"]$/);
|
|
490
|
+
return match ? match[1] : text;
|
|
491
|
+
}
|
|
492
|
+
function getObjectName(t) {
|
|
493
|
+
if (typeof t === "string")
|
|
494
|
+
return undefined;
|
|
495
|
+
if ("Object" in t) {
|
|
496
|
+
return t.Object;
|
|
497
|
+
}
|
|
498
|
+
else if ("Array" in t) {
|
|
499
|
+
return getObjectName(t.Array);
|
|
500
|
+
}
|
|
501
|
+
else if ("HttpResult" in t) {
|
|
502
|
+
if (t == null)
|
|
503
|
+
return undefined;
|
|
504
|
+
return getObjectName(t.HttpResult);
|
|
505
|
+
}
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
508
|
+
function findPropertyByName(cls, name) {
|
|
509
|
+
const exactMatch = cls.getProperties().find((p) => p.getName() === name);
|
|
510
|
+
return exactMatch;
|
|
511
|
+
}
|
|
512
|
+
function hasDecorator(node, name) {
|
|
513
|
+
return node.getDecorators().some((d) => {
|
|
514
|
+
const decoratorName = getDecoratorName(d);
|
|
515
|
+
return decoratorName === name || decoratorName.endsWith("." + name);
|
|
516
|
+
});
|
|
517
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { cloesce, modelsFromSql } from "./cloesce.js";
|
|
2
|
+
export { HttpResult } from "./common.js";
|
|
3
|
+
export declare const D1: ClassDecorator;
|
|
4
|
+
export declare const WranglerEnv: ClassDecorator;
|
|
5
|
+
export declare const PrimaryKey: PropertyDecorator;
|
|
6
|
+
export declare const GET: MethodDecorator;
|
|
7
|
+
export declare const POST: MethodDecorator;
|
|
8
|
+
export declare const PUT: MethodDecorator;
|
|
9
|
+
export declare const PATCH: MethodDecorator;
|
|
10
|
+
export declare const DELETE: MethodDecorator;
|
|
11
|
+
export declare const DataSource: PropertyDecorator;
|
|
12
|
+
export declare const OneToMany: (_: string) => PropertyDecorator;
|
|
13
|
+
export declare const OneToOne: (_: string) => PropertyDecorator;
|
|
14
|
+
export declare const ManyToMany: (_: string) => PropertyDecorator;
|
|
15
|
+
export declare const ForeignKey: <T>(_: T) => PropertyDecorator;
|
|
16
|
+
export declare const Inject: ParameterDecorator;
|
|
17
|
+
type Primitive = string | number | boolean | bigint | symbol | null | undefined;
|
|
18
|
+
export type IncludeTree<T> = T extends Primitive ? never : {
|
|
19
|
+
[K in keyof T]?: T[K] extends (infer U)[] ? IncludeTree<NonNullable<U>> : IncludeTree<NonNullable<T[K]>>;
|
|
20
|
+
};
|
|
21
|
+
export declare function instantiateModelArray<T extends object>(data: any, ctor: {
|
|
22
|
+
new (): T;
|
|
23
|
+
}): T[];
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,eAAO,MAAM,EAAE,EAAE,cAAyB,CAAC;AAC3C,eAAO,MAAM,WAAW,EAAE,cAAyB,CAAC;AACpD,eAAO,MAAM,UAAU,EAAE,iBAA4B,CAAC;AACtD,eAAO,MAAM,GAAG,EAAE,eAA0B,CAAC;AAC7C,eAAO,MAAM,IAAI,EAAE,eAA0B,CAAC;AAC9C,eAAO,MAAM,GAAG,EAAE,eAA0B,CAAC;AAC7C,eAAO,MAAM,KAAK,EAAE,eAA0B,CAAC;AAC/C,eAAO,MAAM,MAAM,EAAE,eAA0B,CAAC;AAChD,eAAO,MAAM,UAAU,EAAE,iBAA4B,CAAC;AACtD,eAAO,MAAM,SAAS,MAChB,MAAM,KAAG,iBACL,CAAC;AACX,eAAO,MAAM,QAAQ,MACf,MAAM,KAAG,iBACL,CAAC;AACX,eAAO,MAAM,UAAU,MACjB,MAAM,KAAG,iBACL,CAAC;AACX,eAAO,MAAM,UAAU,GACpB,CAAC,KAAK,CAAC,KAAG,iBACH,CAAC;AACX,eAAO,MAAM,MAAM,EAAE,kBAA6B,CAAC;AAGnD,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAChF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAC5C,KAAK,GACL;KACG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GACrC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAC3B,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACnC,CAAC;AAGN,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACpD,IAAI,EAAE,GAAG,EACT,IAAI,EAAE;IAAE,QAAQ,CAAC,CAAA;CAAE,GAClB,CAAC,EAAE,CAKL"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { cloesce, modelsFromSql } from "./cloesce.js";
|
|
2
|
+
// Compiler hints
|
|
3
|
+
export const D1 = () => { };
|
|
4
|
+
export const PlainOldObject = () => { };
|
|
5
|
+
export const WranglerEnv = () => { };
|
|
6
|
+
export const PrimaryKey = () => { };
|
|
7
|
+
export const GET = () => { };
|
|
8
|
+
export const POST = () => { };
|
|
9
|
+
export const PUT = () => { };
|
|
10
|
+
export const PATCH = () => { };
|
|
11
|
+
export const DELETE = () => { };
|
|
12
|
+
export const DataSource = () => { };
|
|
13
|
+
export const OneToMany = (_) => () => { };
|
|
14
|
+
export const OneToOne = (_) => () => { };
|
|
15
|
+
export const ManyToMany = (_) => () => { };
|
|
16
|
+
export const ForeignKey = (_) => () => { };
|
|
17
|
+
export const Inject = () => { };
|
|
18
|
+
// Helpers
|
|
19
|
+
export function instantiateObjectArray(data, ctor) {
|
|
20
|
+
if (Array.isArray(data)) {
|
|
21
|
+
return data.map((x) => instantiateObjectArray(x, ctor)).flat();
|
|
22
|
+
}
|
|
23
|
+
return [Object.assign(new ctor(), data)];
|
|
24
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;CAAG;AAExB,MAAM,MAAM,OAAO,GAAG,CACpB,EAAE,EAAE,IAAI,EACR,GAAG,EAAE,OAAO,EACZ,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,OAAO,CAAC,QAAQ,CAAC,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cloesce",
|
|
3
|
+
"version": "0.0.3-fix.1",
|
|
4
|
+
"description": "A tool to extract and compile TypeScript code into something wrangler can consume and deploy for D1 Databases and Cloudflare Workers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./cli": "./dist/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"cloesce": "./dist/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/**",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.17"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc -p tsconfig.json",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"test": "vitest --run",
|
|
32
|
+
"format": "prettier --check .",
|
|
33
|
+
"format:fix": "prettier --write .",
|
|
34
|
+
"prepublishOnly": "npm run typecheck && npm run build && npm run test"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"cmd-ts": "^0.14.1",
|
|
38
|
+
"ts-morph": "^22.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@cloudflare/workers-types": "^4.20250906.0",
|
|
42
|
+
"prettier": "^3.6.2",
|
|
43
|
+
"ts-node": "^10.9.2",
|
|
44
|
+
"typescript": "^5.6.0",
|
|
45
|
+
"vitest": "^3.2.4",
|
|
46
|
+
"wrangler": "^4.34.0"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/bens-schreiber/cloesce.git"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://github.com/bens-schreiber/cloesce",
|
|
53
|
+
"keywords": [
|
|
54
|
+
"cloudflare",
|
|
55
|
+
"workers",
|
|
56
|
+
"d1",
|
|
57
|
+
"orm",
|
|
58
|
+
"cli"
|
|
59
|
+
]
|
|
60
|
+
}
|