@dereekb/dbx-cli 13.11.14 → 13.11.15
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/firebase-api-manifest/main.js +345 -255
- package/firebase-api-manifest/package.json +1 -1
- package/index.cjs.js +1102 -933
- package/index.esm.js +1100 -931
- package/lint-cache/main.js +655 -0
- package/lint-cache/package.json +12 -0
- package/manifest-extract/index.cjs.js +152 -125
- package/manifest-extract/index.esm.js +152 -125
- package/manifest-extract/package.json +1 -1
- package/manifest-extract/src/lib/extract-crud.d.ts +2 -2
- package/manifest-extract/src/lib/extract-models.d.ts +2 -2
- package/package.json +12 -7
- package/src/lib/action/iterate.d.ts +3 -4
- package/src/lib/api/call.passthrough.command.d.ts +1 -1
- package/src/lib/api/expand-keys.d.ts +9 -7
- package/src/lib/api/get-args.helper.d.ts +6 -0
- package/src/lib/api/get-many.command.d.ts +1 -1
- package/src/lib/api/get.command.d.ts +1 -1
- package/src/lib/auth/oidc.flow.d.ts +3 -0
- package/src/lib/manifest/build-manifest-commands.d.ts +4 -2
- package/src/lib/manifest/build-model-decode-command.d.ts +5 -2
- package/src/lib/manifest/model-info-utils.d.ts +13 -9
- package/src/lib/middleware/auth.middleware.d.ts +3 -2
- package/test/package.json +9 -9
|
@@ -36,15 +36,21 @@ function collectGroupsFromConfig(initializer, importIdentToModule, sink) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
function readGroupFromProperty(property, importIdentToModule) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
let result;
|
|
40
|
+
if (Node.isPropertyAssignment(property)) {
|
|
41
|
+
const valueExpr = property.getInitializer();
|
|
42
|
+
if (valueExpr && Node.isArrayLiteralExpression(valueExpr)) {
|
|
43
|
+
const first = valueExpr.getElements()[0];
|
|
44
|
+
if (first && Node.isIdentifier(first)) {
|
|
45
|
+
const className = first.getText();
|
|
46
|
+
const importedFromModule = importIdentToModule.get(className);
|
|
47
|
+
if (importedFromModule) {
|
|
48
|
+
result = { groupKey: property.getName(), className, importedFromModule };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
48
54
|
}
|
|
49
55
|
function isFunctionsConfigVariable(variable) {
|
|
50
56
|
const name = variable.getName();
|
|
@@ -67,63 +73,80 @@ import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
|
67
73
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
68
74
|
var _pathsCache;
|
|
69
75
|
function loadTsconfigPaths(workspaceRoot) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
let result;
|
|
77
|
+
if (_pathsCache) {
|
|
78
|
+
result = _pathsCache;
|
|
79
|
+
} else {
|
|
80
|
+
const tsconfigPath = join(workspaceRoot, "tsconfig.base.json");
|
|
81
|
+
const raw = readFileSync2(tsconfigPath, "utf8");
|
|
82
|
+
const cleaned = stripJsonComments(raw);
|
|
83
|
+
const tsconfig = JSON.parse(cleaned);
|
|
84
|
+
const paths = tsconfig.compilerOptions?.paths ?? {};
|
|
85
|
+
const map = /* @__PURE__ */ new Map();
|
|
86
|
+
for (const [key, value] of Object.entries(paths)) {
|
|
87
|
+
if (Array.isArray(value) && value[0]) {
|
|
88
|
+
map.set(key, resolve(workspaceRoot, value[0]));
|
|
89
|
+
}
|
|
80
90
|
}
|
|
91
|
+
_pathsCache = map;
|
|
92
|
+
result = map;
|
|
81
93
|
}
|
|
82
|
-
|
|
83
|
-
return map;
|
|
94
|
+
return result;
|
|
84
95
|
}
|
|
85
96
|
function resolveModuleToPackage(input) {
|
|
86
97
|
const { workspaceRoot, importingFile, moduleSpecifier } = input;
|
|
98
|
+
let result;
|
|
87
99
|
if (moduleSpecifier.startsWith(".")) {
|
|
88
100
|
const importingDir = dirname(importingFile);
|
|
89
101
|
const candidatePath = resolve(importingDir, moduleSpecifier);
|
|
90
|
-
|
|
102
|
+
result = locatePackageForPath(workspaceRoot, candidatePath);
|
|
103
|
+
} else {
|
|
104
|
+
const paths = loadTsconfigPaths(workspaceRoot);
|
|
105
|
+
const indexFile = paths.get(moduleSpecifier);
|
|
106
|
+
if (indexFile) {
|
|
107
|
+
result = locatePackageForPath(workspaceRoot, indexFile);
|
|
108
|
+
} else {
|
|
109
|
+
result = locatePackageInNodeModules({ workspaceRoot, importingFile, moduleSpecifier });
|
|
110
|
+
}
|
|
91
111
|
}
|
|
92
|
-
|
|
93
|
-
const indexFile = paths.get(moduleSpecifier);
|
|
94
|
-
if (indexFile) return locatePackageForPath(workspaceRoot, indexFile);
|
|
95
|
-
return locatePackageInNodeModules({ workspaceRoot, importingFile, moduleSpecifier });
|
|
112
|
+
return result;
|
|
96
113
|
}
|
|
97
114
|
function locatePackageInNodeModules(input) {
|
|
98
115
|
const { importingFile, moduleSpecifier } = input;
|
|
99
116
|
let current = dirname(importingFile);
|
|
100
|
-
|
|
117
|
+
let result;
|
|
118
|
+
while (!result && current && current !== dirname(current)) {
|
|
101
119
|
const candidateRoot = join(current, "node_modules", moduleSpecifier);
|
|
102
120
|
const pkgJson = join(candidateRoot, "package.json");
|
|
103
121
|
if (existsSync(pkgJson)) {
|
|
104
122
|
try {
|
|
105
123
|
const pkg = JSON.parse(readFileSync2(pkgJson, "utf8"));
|
|
106
|
-
if (pkg.name)
|
|
124
|
+
if (pkg.name) {
|
|
125
|
+
result = { packageName: pkg.name, packageRoot: candidateRoot };
|
|
126
|
+
}
|
|
107
127
|
} catch {
|
|
108
128
|
}
|
|
109
129
|
}
|
|
110
|
-
current = dirname(current);
|
|
130
|
+
if (!result) current = dirname(current);
|
|
111
131
|
}
|
|
112
|
-
return
|
|
132
|
+
return result;
|
|
113
133
|
}
|
|
114
134
|
function locatePackageForPath(workspaceRoot, startPath) {
|
|
115
135
|
let current = startPath;
|
|
116
|
-
|
|
136
|
+
let result;
|
|
137
|
+
while (!result && current && current !== workspaceRoot && current !== dirname(current)) {
|
|
117
138
|
if (existsSync(join(current, "package.json"))) {
|
|
118
139
|
try {
|
|
119
140
|
const pkg = JSON.parse(readFileSync2(join(current, "package.json"), "utf8"));
|
|
120
|
-
if (pkg.name)
|
|
141
|
+
if (pkg.name) {
|
|
142
|
+
result = { packageName: pkg.name, packageRoot: current };
|
|
143
|
+
}
|
|
121
144
|
} catch {
|
|
122
145
|
}
|
|
123
146
|
}
|
|
124
|
-
current = dirname(current);
|
|
147
|
+
if (!result) current = dirname(current);
|
|
125
148
|
}
|
|
126
|
-
return
|
|
149
|
+
return result;
|
|
127
150
|
}
|
|
128
151
|
function relPath(workspaceRoot, absolutePath) {
|
|
129
152
|
return relative(workspaceRoot, absolutePath).split("\\").join("/");
|
|
@@ -149,17 +172,18 @@ function extractCrudEntries(source) {
|
|
|
149
172
|
const functionsClassName = findFunctionsClassName(sourceFile);
|
|
150
173
|
const typeDocsCache = /* @__PURE__ */ new Map();
|
|
151
174
|
const resolveTypeDocs = (typeName) => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
175
|
+
let result;
|
|
176
|
+
if (typeName) {
|
|
177
|
+
if (typeDocsCache.has(typeName)) {
|
|
178
|
+
result = typeDocsCache.get(typeName);
|
|
179
|
+
} else {
|
|
180
|
+
result = readTypeDocs(sourceFile, typeName);
|
|
181
|
+
if (result) {
|
|
182
|
+
typeDocsCache.set(typeName, result);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
161
185
|
}
|
|
162
|
-
return
|
|
186
|
+
return result;
|
|
163
187
|
};
|
|
164
188
|
if (crudConfigType) {
|
|
165
189
|
const literal = crudConfigType.getTypeNode();
|
|
@@ -229,54 +253,64 @@ function extractCrudEntries(source) {
|
|
|
229
253
|
return { groupName, modelKeys, entries, functionsClassName };
|
|
230
254
|
}
|
|
231
255
|
function findTypeAliasByEnding(sourceFile, ending) {
|
|
256
|
+
let result;
|
|
232
257
|
for (const alias of sourceFile.getTypeAliases()) {
|
|
233
258
|
if (alias.getName().endsWith(ending) && alias.getTypeNode()) {
|
|
234
|
-
|
|
259
|
+
result = alias;
|
|
260
|
+
break;
|
|
235
261
|
}
|
|
236
262
|
}
|
|
237
|
-
return
|
|
263
|
+
return result;
|
|
238
264
|
}
|
|
239
265
|
function findFunctionsClassName(sourceFile) {
|
|
266
|
+
let result;
|
|
240
267
|
for (const cls of sourceFile.getClasses()) {
|
|
241
268
|
if (!cls.isAbstract()) {
|
|
242
269
|
continue;
|
|
243
270
|
}
|
|
244
271
|
const name = cls.getName();
|
|
245
272
|
if (name?.endsWith("Functions")) {
|
|
246
|
-
|
|
273
|
+
result = name;
|
|
274
|
+
break;
|
|
247
275
|
}
|
|
248
276
|
}
|
|
249
|
-
return
|
|
277
|
+
return result;
|
|
250
278
|
}
|
|
251
279
|
function inferGroupName(sourceFile) {
|
|
280
|
+
let result;
|
|
252
281
|
for (const alias of sourceFile.getTypeAliases()) {
|
|
253
282
|
const name = alias.getName();
|
|
254
283
|
if (name.endsWith("ModelCrudFunctionsConfig")) {
|
|
255
284
|
const stem = name.slice(0, -"ModelCrudFunctionsConfig".length);
|
|
256
285
|
if (stem.length > 0) {
|
|
257
|
-
|
|
286
|
+
result = stem;
|
|
287
|
+
break;
|
|
258
288
|
}
|
|
259
289
|
}
|
|
260
290
|
}
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
291
|
+
if (result === void 0) {
|
|
292
|
+
for (const alias of sourceFile.getTypeAliases()) {
|
|
293
|
+
const name = alias.getName();
|
|
294
|
+
if (name.endsWith("FunctionTypeMap")) {
|
|
295
|
+
const stem = name.slice(0, -"FunctionTypeMap".length);
|
|
296
|
+
if (stem.length > 0) {
|
|
297
|
+
result = stem;
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
267
300
|
}
|
|
268
301
|
}
|
|
269
302
|
}
|
|
270
|
-
return
|
|
303
|
+
return result;
|
|
271
304
|
}
|
|
272
305
|
function isNullLiteralType(node) {
|
|
306
|
+
let result = false;
|
|
273
307
|
if (Node2.isLiteralTypeNode(node)) {
|
|
274
308
|
const literal = node.getLiteral();
|
|
275
309
|
if (Node2.isNullLiteral(literal)) {
|
|
276
|
-
|
|
310
|
+
result = true;
|
|
277
311
|
}
|
|
278
312
|
}
|
|
279
|
-
return
|
|
313
|
+
return result;
|
|
280
314
|
}
|
|
281
315
|
function collectVerbEntries(input) {
|
|
282
316
|
const { modelName, verb, valueNode, entries, fallbackDescription, resolveTypeDocs } = input;
|
|
@@ -324,32 +358,33 @@ function collectVerbEntries(input) {
|
|
|
324
358
|
});
|
|
325
359
|
}
|
|
326
360
|
function readTupleParamsResult(node) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
361
|
+
let pair;
|
|
362
|
+
if (Node2.isTupleTypeNode(node)) {
|
|
363
|
+
const elements = node.getElements();
|
|
364
|
+
if (elements.length > 0) {
|
|
365
|
+
const params = elements[0] ? typeNodeName(elements[0]) : void 0;
|
|
366
|
+
const result = elements[1] ? typeNodeName(elements[1]) : void 0;
|
|
367
|
+
pair = { params, result };
|
|
368
|
+
}
|
|
333
369
|
}
|
|
334
|
-
|
|
335
|
-
const result = elements[1] ? typeNodeName(elements[1]) : void 0;
|
|
336
|
-
return { params, result };
|
|
370
|
+
return pair;
|
|
337
371
|
}
|
|
338
372
|
function readBareParams(node) {
|
|
339
373
|
const params = typeNodeName(node);
|
|
340
|
-
|
|
341
|
-
return void 0;
|
|
342
|
-
}
|
|
343
|
-
return { params, result: void 0 };
|
|
374
|
+
return params ? { params, result: void 0 } : void 0;
|
|
344
375
|
}
|
|
345
376
|
function typeNodeName(node) {
|
|
377
|
+
let result;
|
|
346
378
|
if (Node2.isTypeReference(node)) {
|
|
347
|
-
|
|
379
|
+
result = node.getTypeName().getText();
|
|
380
|
+
} else {
|
|
381
|
+
const text = node.getText().trim();
|
|
382
|
+
result = text.length > 0 ? text : void 0;
|
|
348
383
|
}
|
|
349
|
-
|
|
350
|
-
return text.length > 0 ? text : void 0;
|
|
384
|
+
return result;
|
|
351
385
|
}
|
|
352
386
|
function readTypeDocs(sourceFile, typeName) {
|
|
387
|
+
let result;
|
|
353
388
|
const interfaceDecl = sourceFile.getInterface(typeName);
|
|
354
389
|
if (interfaceDecl) {
|
|
355
390
|
const typeDescription = readJsDocSummary(interfaceDecl);
|
|
@@ -362,26 +397,31 @@ function readTypeDocs(sourceFile, typeName) {
|
|
|
362
397
|
const field = description ? { name: fieldName, typeText, description } : { name: fieldName, typeText };
|
|
363
398
|
fields.push(field);
|
|
364
399
|
}
|
|
365
|
-
if (
|
|
366
|
-
|
|
400
|
+
if (typeDescription || fields.length > 0) {
|
|
401
|
+
result = { typeDescription, fields: fields.length > 0 ? fields : void 0 };
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
const typeAlias = sourceFile.getTypeAlias(typeName);
|
|
405
|
+
if (typeAlias) {
|
|
406
|
+
const typeDescription = readJsDocSummary(typeAlias);
|
|
407
|
+
if (typeDescription) {
|
|
408
|
+
result = { typeDescription };
|
|
409
|
+
}
|
|
367
410
|
}
|
|
368
|
-
return { typeDescription, fields: fields.length > 0 ? fields : void 0 };
|
|
369
|
-
}
|
|
370
|
-
const typeAlias = sourceFile.getTypeAlias(typeName);
|
|
371
|
-
if (typeAlias) {
|
|
372
|
-
const typeDescription = readJsDocSummary(typeAlias);
|
|
373
|
-
return typeDescription ? { typeDescription } : void 0;
|
|
374
411
|
}
|
|
375
|
-
return
|
|
412
|
+
return result;
|
|
376
413
|
}
|
|
377
414
|
function readJsDocSummary(node) {
|
|
415
|
+
let result;
|
|
378
416
|
const docs = node.getJsDocs();
|
|
379
|
-
if (docs.length
|
|
380
|
-
|
|
417
|
+
if (docs.length > 0) {
|
|
418
|
+
const last = docs[docs.length - 1];
|
|
419
|
+
const description = last.getDescription().trim();
|
|
420
|
+
if (description.length > 0) {
|
|
421
|
+
result = description;
|
|
422
|
+
}
|
|
381
423
|
}
|
|
382
|
-
|
|
383
|
-
const description = last.getDescription().trim();
|
|
384
|
-
return description.length > 0 ? description : void 0;
|
|
424
|
+
return result;
|
|
385
425
|
}
|
|
386
426
|
|
|
387
427
|
// packages/dbx-cli/manifest-extract/src/lib/extract-models.ts
|
|
@@ -552,20 +592,25 @@ function readGenericInterfaceName(call) {
|
|
|
552
592
|
function readConverterFields(call) {
|
|
553
593
|
const fnName = call.getExpression().getText();
|
|
554
594
|
const args = call.getArguments();
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
595
|
+
let result;
|
|
596
|
+
if (args.length > 0) {
|
|
597
|
+
const config = args[0];
|
|
598
|
+
if (Node3.isObjectLiteralExpression(config)) {
|
|
599
|
+
let fieldsLiteral;
|
|
600
|
+
if (fnName === SNAPSHOT_FN) {
|
|
601
|
+
fieldsLiteral = readObjectProperty(config, FIELDS_LITERAL_KEY);
|
|
602
|
+
} else {
|
|
603
|
+
const objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
|
|
604
|
+
if (objectField && Node3.isObjectLiteralExpression(objectField)) {
|
|
605
|
+
fieldsLiteral = readObjectProperty(objectField, FIELDS_LITERAL_KEY);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
if (fieldsLiteral) {
|
|
609
|
+
result = readFieldEntries(fieldsLiteral);
|
|
610
|
+
}
|
|
565
611
|
}
|
|
566
612
|
}
|
|
567
|
-
|
|
568
|
-
return readFieldEntries(fieldsLiteral);
|
|
613
|
+
return result;
|
|
569
614
|
}
|
|
570
615
|
function readFieldEntries(fields) {
|
|
571
616
|
const out = [];
|
|
@@ -589,33 +634,38 @@ function readFieldEntries(fields) {
|
|
|
589
634
|
return out;
|
|
590
635
|
}
|
|
591
636
|
function readNestedFromExpression(expr) {
|
|
592
|
-
if (!Node3.isCallExpression(expr)) return void 0;
|
|
593
|
-
const fnName = expr.getExpression().getText();
|
|
594
|
-
if (fnName !== SUB_OBJECT_FN && fnName !== OBJECT_ARRAY_FN) return void 0;
|
|
595
|
-
const args = expr.getArguments();
|
|
596
|
-
if (args.length === 0) return void 0;
|
|
597
|
-
const config = args[0];
|
|
598
|
-
if (!Node3.isObjectLiteralExpression(config)) return void 0;
|
|
599
|
-
const objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
|
|
600
|
-
if (!objectField) return void 0;
|
|
601
|
-
const isArray = fnName === OBJECT_ARRAY_FN;
|
|
602
637
|
let result;
|
|
603
|
-
if (Node3.
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
638
|
+
if (Node3.isCallExpression(expr)) {
|
|
639
|
+
const fnName = expr.getExpression().getText();
|
|
640
|
+
if (fnName === SUB_OBJECT_FN || fnName === OBJECT_ARRAY_FN) {
|
|
641
|
+
const args = expr.getArguments();
|
|
642
|
+
if (args.length > 0) {
|
|
643
|
+
const config = args[0];
|
|
644
|
+
if (Node3.isObjectLiteralExpression(config)) {
|
|
645
|
+
const objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
|
|
646
|
+
if (objectField) {
|
|
647
|
+
const isArray = fnName === OBJECT_ARRAY_FN;
|
|
648
|
+
if (Node3.isIdentifier(objectField)) {
|
|
649
|
+
result = { ref: objectField.getText(), isArray };
|
|
650
|
+
} else if (Node3.isObjectLiteralExpression(objectField)) {
|
|
651
|
+
const fieldsLiteral = readObjectProperty(objectField, FIELDS_LITERAL_KEY);
|
|
652
|
+
if (fieldsLiteral) {
|
|
653
|
+
const inlineFields = readFieldEntries(fieldsLiteral);
|
|
654
|
+
result = {
|
|
655
|
+
inline: {
|
|
656
|
+
converterConst: void 0,
|
|
657
|
+
factory: fnName,
|
|
658
|
+
interfaceName: readGenericInterfaceName(expr),
|
|
659
|
+
fields: inlineFields,
|
|
660
|
+
line: expr.getStartLineNumber()
|
|
661
|
+
},
|
|
662
|
+
isArray
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
619
669
|
}
|
|
620
670
|
}
|
|
621
671
|
return result;
|
|
@@ -749,16 +799,17 @@ function identifierName(node) {
|
|
|
749
799
|
// packages/dbx-cli/firebase-api-manifest/src/generate-api-manifest/find-api-files.ts
|
|
750
800
|
function findApiFiles(packageRoot) {
|
|
751
801
|
const libRoot = join2(packageRoot, "src", "lib");
|
|
752
|
-
if (!safeIsDirectory(libRoot)) return [];
|
|
753
802
|
const out = [];
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
const
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
803
|
+
if (safeIsDirectory(libRoot)) {
|
|
804
|
+
const seenClassNames = /* @__PURE__ */ new Set();
|
|
805
|
+
for (const file of walkApiFiles(libRoot)) {
|
|
806
|
+
const text = readFileSync3(file, "utf8");
|
|
807
|
+
const extraction = extractCrudEntries({ name: file, text });
|
|
808
|
+
if (!extraction.functionsClassName) continue;
|
|
809
|
+
if (seenClassNames.has(extraction.functionsClassName)) continue;
|
|
810
|
+
seenClassNames.add(extraction.functionsClassName);
|
|
811
|
+
out.push({ filePath: file, className: extraction.functionsClassName, extraction });
|
|
812
|
+
}
|
|
762
813
|
}
|
|
763
814
|
return out;
|
|
764
815
|
}
|
|
@@ -775,15 +826,17 @@ function* walkApiFiles(dir) {
|
|
|
775
826
|
}
|
|
776
827
|
}
|
|
777
828
|
function isApiFile(name) {
|
|
778
|
-
|
|
779
|
-
return name.endsWith(".api.ts") || name.endsWith(".api.d.ts");
|
|
829
|
+
const isSpec = name.endsWith(".spec.ts") || name.endsWith(".test.ts");
|
|
830
|
+
return !isSpec && (name.endsWith(".api.ts") || name.endsWith(".api.d.ts"));
|
|
780
831
|
}
|
|
781
832
|
function safeIsDirectory(p) {
|
|
833
|
+
let result;
|
|
782
834
|
try {
|
|
783
|
-
|
|
835
|
+
result = statSync(p).isDirectory();
|
|
784
836
|
} catch {
|
|
785
|
-
|
|
837
|
+
result = false;
|
|
786
838
|
}
|
|
839
|
+
return result;
|
|
787
840
|
}
|
|
788
841
|
|
|
789
842
|
// packages/dbx-cli/firebase-api-manifest/src/generate-api-manifest/find-model-files.ts
|
|
@@ -791,24 +844,20 @@ import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as
|
|
|
791
844
|
import { join as join3 } from "node:path";
|
|
792
845
|
function findModelFiles(packageRoot) {
|
|
793
846
|
const libRoot = join3(packageRoot, "src", "lib");
|
|
794
|
-
if (!safeIsDirectory2(libRoot)) return [];
|
|
795
847
|
const out = [];
|
|
796
|
-
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
848
|
+
if (safeIsDirectory2(libRoot)) {
|
|
849
|
+
for (const filePath of walkSourceFiles(libRoot)) {
|
|
850
|
+
const text = readFileSync4(filePath, "utf8");
|
|
851
|
+
if (!textHasModelMarker(text)) continue;
|
|
852
|
+
const extraction = extractModelsFromSource({ name: filePath, text });
|
|
853
|
+
if (extraction.identities.length === 0 && extraction.modelGroups.length === 0 && extraction.converters.length === 0) continue;
|
|
854
|
+
out.push({ filePath, extraction });
|
|
855
|
+
}
|
|
802
856
|
}
|
|
803
857
|
return out;
|
|
804
858
|
}
|
|
805
859
|
function textHasModelMarker(text) {
|
|
806
|
-
|
|
807
|
-
if (text.includes("@dbxModelGroup")) return true;
|
|
808
|
-
if (text.includes("snapshotConverterFunctions")) return true;
|
|
809
|
-
if (text.includes("firestoreSubObject")) return true;
|
|
810
|
-
if (text.includes("firestoreObjectArray")) return true;
|
|
811
|
-
return false;
|
|
860
|
+
return text.includes("firestoreModelIdentity(") || text.includes("@dbxModelGroup") || text.includes("snapshotConverterFunctions") || text.includes("firestoreSubObject") || text.includes("firestoreObjectArray");
|
|
812
861
|
}
|
|
813
862
|
function* walkSourceFiles(dir) {
|
|
814
863
|
for (const entry of readdirSync2(dir).sort()) {
|
|
@@ -823,20 +872,16 @@ function* walkSourceFiles(dir) {
|
|
|
823
872
|
}
|
|
824
873
|
}
|
|
825
874
|
function isCandidateSourceFile(name) {
|
|
826
|
-
|
|
827
|
-
if (name.endsWith(".api.ts")) return false;
|
|
828
|
-
if (name.endsWith(".spec.ts")) return false;
|
|
829
|
-
if (name.endsWith(".test.ts")) return false;
|
|
830
|
-
if (name.endsWith(".id.ts")) return false;
|
|
831
|
-
if (name.endsWith(".d.ts")) return false;
|
|
832
|
-
return true;
|
|
875
|
+
return name.endsWith(".ts") && !name.endsWith(".api.ts") && !name.endsWith(".spec.ts") && !name.endsWith(".test.ts") && !name.endsWith(".id.ts") && !name.endsWith(".d.ts");
|
|
833
876
|
}
|
|
834
877
|
function safeIsDirectory2(p) {
|
|
878
|
+
let result;
|
|
835
879
|
try {
|
|
836
|
-
|
|
880
|
+
result = statSync2(p).isDirectory();
|
|
837
881
|
} catch {
|
|
838
|
-
|
|
882
|
+
result = false;
|
|
839
883
|
}
|
|
884
|
+
return result;
|
|
840
885
|
}
|
|
841
886
|
|
|
842
887
|
// packages/dbx-cli/firebase-api-manifest/src/generate-api-manifest/assemble-models.ts
|
|
@@ -895,34 +940,39 @@ function appendEntriesFromSource(source, registries, accumulator) {
|
|
|
895
940
|
}
|
|
896
941
|
function buildEntryForIdentity(input) {
|
|
897
942
|
const { identity, source, registries, enumNames } = input;
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
943
|
+
let result;
|
|
944
|
+
if (identity.collectionPrefix !== void 0) {
|
|
945
|
+
const modelName = capitalize(identity.modelType);
|
|
946
|
+
const iface = registries.interfaceRegistry.get(modelName);
|
|
947
|
+
if (iface?.hasDbxModelTag) {
|
|
948
|
+
const converter = findConverterForInterface(source.extraction, modelName) ?? findConverterFromRegistry(registries.converterRegistry, modelName);
|
|
949
|
+
if (converter) {
|
|
950
|
+
const fields = buildFields({
|
|
951
|
+
converter,
|
|
952
|
+
iface,
|
|
953
|
+
interfaceRegistry: registries.interfaceRegistry,
|
|
954
|
+
converterRegistry: registries.converterRegistry,
|
|
955
|
+
enumNames,
|
|
956
|
+
depth: 0,
|
|
957
|
+
visitedConverters: /* @__PURE__ */ new Set()
|
|
958
|
+
});
|
|
959
|
+
const modelGroup = registries.groupByModelName.get(modelName);
|
|
960
|
+
result = {
|
|
961
|
+
modelType: identity.modelType,
|
|
962
|
+
modelName,
|
|
963
|
+
...modelGroup ? { modelGroup } : {},
|
|
964
|
+
identityConst: identity.identityConst,
|
|
965
|
+
collectionPrefix: identity.collectionPrefix,
|
|
966
|
+
...identity.parentIdentityConst ? { parentIdentityConst: identity.parentIdentityConst } : {},
|
|
967
|
+
...iface.description ? { description: iface.description } : {},
|
|
968
|
+
sourcePackage: source.sourcePackage,
|
|
969
|
+
sourceFile: source.sourceFile,
|
|
970
|
+
fields
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
return result;
|
|
926
976
|
}
|
|
927
977
|
function findConverterForInterface(extraction, interfaceName) {
|
|
928
978
|
return extraction.converters.find((c) => c.interfaceName === interfaceName);
|
|
@@ -975,28 +1025,36 @@ function buildField(input) {
|
|
|
975
1025
|
}
|
|
976
1026
|
function resolveNestedFields(input) {
|
|
977
1027
|
const { field } = input;
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1028
|
+
let result;
|
|
1029
|
+
if (input.depth < MAX_NESTED_DEPTH) {
|
|
1030
|
+
let nestedConverter;
|
|
1031
|
+
let aborted = false;
|
|
1032
|
+
if (field.nestedConverterInline) {
|
|
1033
|
+
nestedConverter = field.nestedConverterInline;
|
|
1034
|
+
} else if (field.nestedConverterRef) {
|
|
1035
|
+
if (input.visitedConverters.has(field.nestedConverterRef)) {
|
|
1036
|
+
aborted = true;
|
|
1037
|
+
} else {
|
|
1038
|
+
nestedConverter = input.converterRegistry.get(field.nestedConverterRef);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
if (!aborted && nestedConverter) {
|
|
1042
|
+
const nextVisited = new Set(input.visitedConverters);
|
|
1043
|
+
if (nestedConverter.converterConst) nextVisited.add(nestedConverter.converterConst);
|
|
1044
|
+
const nestedIface = nestedConverter.interfaceName ? input.interfaceRegistry.get(nestedConverter.interfaceName) : void 0;
|
|
1045
|
+
const fields = buildFields({
|
|
1046
|
+
converter: nestedConverter,
|
|
1047
|
+
iface: nestedIface,
|
|
1048
|
+
interfaceRegistry: input.interfaceRegistry,
|
|
1049
|
+
converterRegistry: input.converterRegistry,
|
|
1050
|
+
enumNames: input.enumNames,
|
|
1051
|
+
depth: input.depth + 1,
|
|
1052
|
+
visitedConverters: nextVisited
|
|
1053
|
+
});
|
|
1054
|
+
result = { fields, isArray: field.nestedIsArray ?? false };
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return result;
|
|
1000
1058
|
}
|
|
1001
1059
|
function collectAncestors(iface, registry) {
|
|
1002
1060
|
const out = [];
|
|
@@ -1053,14 +1111,12 @@ function capitalize(s) {
|
|
|
1053
1111
|
import { existsSync as existsSync2, readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync3 } from "node:fs";
|
|
1054
1112
|
import { dirname as dirname2, isAbsolute as isAbsolute2, join as join4, resolve as resolve2 } from "node:path";
|
|
1055
1113
|
function deriveValidatorName(paramsTypeName) {
|
|
1056
|
-
|
|
1057
|
-
return paramsTypeName.charAt(0).toLowerCase() + paramsTypeName.slice(1) + "Type";
|
|
1114
|
+
return paramsTypeName ? paramsTypeName.charAt(0).toLowerCase() + paramsTypeName.slice(1) + "Type" : "";
|
|
1058
1115
|
}
|
|
1059
1116
|
function isExportedFromPackage(input) {
|
|
1060
1117
|
const { packageRoot, identifier } = input;
|
|
1061
1118
|
const indexPath = locateBarrelEntry(packageRoot);
|
|
1062
|
-
|
|
1063
|
-
return findIdentifierInBarrelChain(indexPath, identifier, /* @__PURE__ */ new Set());
|
|
1119
|
+
return indexPath ? findIdentifierInBarrelChain(indexPath, identifier, /* @__PURE__ */ new Set()) : false;
|
|
1064
1120
|
}
|
|
1065
1121
|
function locateBarrelEntry(packageRoot) {
|
|
1066
1122
|
const candidates = [join4(packageRoot, "src", "index.ts"), join4(packageRoot, "src", "index.d.ts"), join4(packageRoot, "index.d.ts"), join4(packageRoot, "index.ts")];
|
|
@@ -1068,25 +1124,37 @@ function locateBarrelEntry(packageRoot) {
|
|
|
1068
1124
|
}
|
|
1069
1125
|
var EXPORT_DECL_PATTERNS = [/export\s+(?:declare\s+)?const\s+IDENT\b/, /export\s+(?:declare\s+)?function\s+IDENT\b/, /export\s*\{[^}]*\bIDENT\b[^}]*\}/];
|
|
1070
1126
|
function findIdentifierInBarrelChain(filePath, identifier, visited) {
|
|
1071
|
-
|
|
1072
|
-
visited.
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1127
|
+
let result = false;
|
|
1128
|
+
if (!visited.has(filePath)) {
|
|
1129
|
+
visited.add(filePath);
|
|
1130
|
+
let text;
|
|
1131
|
+
try {
|
|
1132
|
+
text = readFileSync5(filePath, "utf8");
|
|
1133
|
+
} catch {
|
|
1134
|
+
text = void 0;
|
|
1135
|
+
}
|
|
1136
|
+
if (text !== void 0) {
|
|
1137
|
+
for (const pattern of EXPORT_DECL_PATTERNS) {
|
|
1138
|
+
const re = new RegExp(pattern.source.replace("IDENT", escapeRegExp(identifier)));
|
|
1139
|
+
if (re.test(text)) {
|
|
1140
|
+
result = true;
|
|
1141
|
+
break;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
if (!result) {
|
|
1145
|
+
const dir = dirname2(filePath);
|
|
1146
|
+
for (const reExportTarget of collectReExportTargets(text)) {
|
|
1147
|
+
const resolved = resolveReExport(dir, reExportTarget);
|
|
1148
|
+
if (!resolved) continue;
|
|
1149
|
+
if (findIdentifierInBarrelChain(resolved, identifier, visited)) {
|
|
1150
|
+
result = true;
|
|
1151
|
+
break;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1088
1156
|
}
|
|
1089
|
-
return
|
|
1157
|
+
return result;
|
|
1090
1158
|
}
|
|
1091
1159
|
function collectReExportTargets(text) {
|
|
1092
1160
|
const out = [];
|
|
@@ -1098,15 +1166,16 @@ function collectReExportTargets(text) {
|
|
|
1098
1166
|
return out;
|
|
1099
1167
|
}
|
|
1100
1168
|
function resolveReExport(fromDir, target) {
|
|
1101
|
-
if (!target.startsWith(".")) return void 0;
|
|
1102
|
-
const candidate = isAbsolute2(target) ? target : resolve2(fromDir, target);
|
|
1103
1169
|
let result;
|
|
1104
|
-
|
|
1105
|
-
const
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1170
|
+
if (target.startsWith(".")) {
|
|
1171
|
+
const candidate = isAbsolute2(target) ? target : resolve2(fromDir, target);
|
|
1172
|
+
for (const ext of [".ts", ".mts", ".d.ts", "/index.ts", "/index.mts", "/index.d.ts"]) {
|
|
1173
|
+
const probe = hasTsModuleExtension(candidate) ? candidate : candidate + ext;
|
|
1174
|
+
const resolved = resolveExistingTsPath(probe);
|
|
1175
|
+
if (resolved) {
|
|
1176
|
+
result = resolved;
|
|
1177
|
+
break;
|
|
1178
|
+
}
|
|
1110
1179
|
}
|
|
1111
1180
|
}
|
|
1112
1181
|
return result;
|
|
@@ -1115,14 +1184,24 @@ function hasTsModuleExtension(value) {
|
|
|
1115
1184
|
return value.endsWith(".ts") || value.endsWith(".mts");
|
|
1116
1185
|
}
|
|
1117
1186
|
function resolveExistingTsPath(probe) {
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1187
|
+
let result;
|
|
1188
|
+
if (existsSync2(probe)) {
|
|
1189
|
+
const stat = statSync3(probe);
|
|
1190
|
+
if (stat.isFile()) {
|
|
1191
|
+
result = probe;
|
|
1192
|
+
} else if (stat.isDirectory()) {
|
|
1193
|
+
const sourceIndex = join4(probe, "index.ts");
|
|
1194
|
+
if (existsSync2(sourceIndex)) {
|
|
1195
|
+
result = sourceIndex;
|
|
1196
|
+
} else {
|
|
1197
|
+
const declarationIndex = join4(probe, "index.d.ts");
|
|
1198
|
+
if (existsSync2(declarationIndex)) {
|
|
1199
|
+
result = declarationIndex;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
return result;
|
|
1126
1205
|
}
|
|
1127
1206
|
function escapeRegExp(value) {
|
|
1128
1207
|
return value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
@@ -1216,9 +1295,14 @@ function renderModelEntry(entry, emitConverters) {
|
|
|
1216
1295
|
return ` { ${fields.filter((v) => Boolean(v)).join(", ")} }`;
|
|
1217
1296
|
}
|
|
1218
1297
|
function renderModelFields(fields, emitConverters) {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1298
|
+
let result;
|
|
1299
|
+
if (fields.length === 0) {
|
|
1300
|
+
result = "[]";
|
|
1301
|
+
} else {
|
|
1302
|
+
const items = fields.map((field) => renderModelField(field, emitConverters));
|
|
1303
|
+
result = `[${items.join(", ")}]`;
|
|
1304
|
+
}
|
|
1305
|
+
return result;
|
|
1222
1306
|
}
|
|
1223
1307
|
function renderModelField(field, emitConverters) {
|
|
1224
1308
|
const nestedIsArrayLiteral = field.nestedIsArray ? "true" : "false";
|
|
@@ -1336,9 +1420,15 @@ async function main() {
|
|
|
1336
1420
|
}
|
|
1337
1421
|
}
|
|
1338
1422
|
function compareEntries(a, b) {
|
|
1339
|
-
|
|
1340
|
-
if (a.entry.
|
|
1341
|
-
|
|
1423
|
+
let result;
|
|
1424
|
+
if (a.entry.model !== b.entry.model) {
|
|
1425
|
+
result = a.entry.model.localeCompare(b.entry.model);
|
|
1426
|
+
} else if (a.entry.verb === b.entry.verb) {
|
|
1427
|
+
result = (a.entry.specifier ?? "").localeCompare(b.entry.specifier ?? "");
|
|
1428
|
+
} else {
|
|
1429
|
+
result = a.entry.verb.localeCompare(b.entry.verb);
|
|
1430
|
+
}
|
|
1431
|
+
return result;
|
|
1342
1432
|
}
|
|
1343
1433
|
function ensureOutputDir(outputDir) {
|
|
1344
1434
|
if (!existsSync3(outputDir)) mkdirSync(outputDir, { recursive: true });
|