cloesce 0.0.3

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.
@@ -0,0 +1,13 @@
1
+ /** Use as @GET (no parentheses) */
2
+ export function GET(_value, _ctx) { }
3
+ /** Use as @POST (no parentheses) */
4
+ export function POST(_value, _ctx) { }
5
+ export function PUT(_value, _ctx) { }
6
+ export function PATCH(_value, _ctx) { }
7
+ export function DELETE(_value, _ctx) { }
8
+ /** Class decorator (no-op) */
9
+ export function D1(value, _ctx) {
10
+ return value;
11
+ }
12
+ /** Field decorator (no-op) */
13
+ export function PrimaryKey(_v, _ctx) { }
@@ -0,0 +1,111 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { WranglerEnv } from './cloesce.js'; // adjust import path
36
+ let MyEnvironment = (() => {
37
+ let _classDecorators = [WranglerEnv({
38
+ name: "my-worker",
39
+ compatibility_date: "2024-01-01"
40
+ })];
41
+ let _classDescriptor;
42
+ let _classExtraInitializers = [];
43
+ let _classThis;
44
+ var MyEnvironment = class {
45
+ static { _classThis = this; }
46
+ static {
47
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
48
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
49
+ MyEnvironment = _classThis = _classDescriptor.value;
50
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
51
+ __runInitializers(_classThis, _classExtraInitializers);
52
+ }
53
+ };
54
+ return MyEnvironment = _classThis;
55
+ })();
56
+ let Dog = (() => {
57
+ let _classDecorators = [D1];
58
+ let _classDescriptor;
59
+ let _classExtraInitializers = [];
60
+ let _classThis;
61
+ let _staticExtraInitializers = [];
62
+ let _instanceExtraInitializers = [];
63
+ let _static_woof_decorators;
64
+ let _id_decorators;
65
+ let _id_initializers = [];
66
+ let _id_extraInitializers = [];
67
+ let _get_name_decorators;
68
+ let _get_breed_decorators;
69
+ var Dog = class {
70
+ static { _classThis = this; }
71
+ static {
72
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
73
+ _id_decorators = [PrimaryKey];
74
+ _get_name_decorators = [GET];
75
+ _get_breed_decorators = [GET];
76
+ _static_woof_decorators = [POST];
77
+ __esDecorate(this, null, _static_woof_decorators, { kind: "method", name: "woof", static: true, private: false, access: { has: obj => "woof" in obj, get: obj => obj.woof }, metadata: _metadata }, null, _staticExtraInitializers);
78
+ __esDecorate(this, null, _get_name_decorators, { kind: "method", name: "get_name", static: false, private: false, access: { has: obj => "get_name" in obj, get: obj => obj.get_name }, metadata: _metadata }, null, _instanceExtraInitializers);
79
+ __esDecorate(this, null, _get_breed_decorators, { kind: "method", name: "get_breed", static: false, private: false, access: { has: obj => "get_breed" in obj, get: obj => obj.get_breed }, metadata: _metadata }, null, _instanceExtraInitializers);
80
+ __esDecorate(null, null, _id_decorators, { kind: "field", name: "id", static: false, private: false, access: { has: obj => "id" in obj, get: obj => obj.id, set: (obj, value) => { obj.id = value; } }, metadata: _metadata }, _id_initializers, _id_extraInitializers);
81
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
82
+ Dog = _classThis = _classDescriptor.value;
83
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
84
+ __runInitializers(_classThis, _staticExtraInitializers);
85
+ __runInitializers(_classThis, _classExtraInitializers);
86
+ }
87
+ id = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _id_initializers, void 0));
88
+ name = __runInitializers(this, _id_extraInitializers);
89
+ breed;
90
+ preferred_treat;
91
+ async get_name(db, req) {
92
+ const who = new URL(req.url).searchParams.get("name");
93
+ return new Response(JSON.stringify({ hello: who }), {
94
+ headers: { "content-type": "application/json" },
95
+ });
96
+ }
97
+ async get_breed(db, req) {
98
+ const breed = new URL(req.url).searchParams.get("breed");
99
+ return new Response(JSON.stringify({ hello: breed }), {
100
+ headers: { "content-type": "application/json" },
101
+ });
102
+ }
103
+ static async woof(db, req, phrase) {
104
+ return new Response(JSON.stringify({ phrase }), {
105
+ status: 201,
106
+ headers: { "content-type": "application/json" },
107
+ });
108
+ }
109
+ };
110
+ return Dog = _classThis;
111
+ })();
@@ -0,0 +1,14 @@
1
+ import { Project } from "ts-morph";
2
+ import { CloesceAst, Either } from "./common.js";
3
+ export declare class CidlExtractor {
4
+ projectName: string;
5
+ version: string;
6
+ constructor(projectName: string, version: string);
7
+ extract(project: Project): Either<string, CloesceAst>;
8
+ private static model;
9
+ private static readonly primTypeMap;
10
+ private static cidlType;
11
+ private static includeTree;
12
+ private static method;
13
+ }
14
+ //# sourceMappingURL=extract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EASR,MAAM,UAAU,CAAC;AAElB,OAAO,EAEL,UAAU,EAGV,MAAM,EAUP,MAAM,aAAa,CAAC;AAqBrB,qBAAa,aAAa;IAEf,WAAW,EAAE,MAAM;IACnB,OAAO,EAAE,MAAM;gBADf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM;IAGxB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC;IA8CrD,OAAO,CAAC,MAAM,CAAC,KAAK;IA+KpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAQjC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ;IAgGvB,OAAO,CAAC,MAAM,CAAC,WAAW;IA8D1B,OAAO,CAAC,MAAM,CAAC,MAAM;CAqDtB"}
@@ -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
+ }
@@ -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