@saasicat/cli 1.0.0-rc.1 → 1.0.0-rc.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.
- package/bin/saasicat.js +64 -14
- package/dist/.build-stamp +1 -1
- package/dist/index.cjs +91 -8
- package/dist/index.d.cts +57 -7
- package/dist/index.d.ts +57 -7
- package/dist/index.js +82 -4
- package/package.json +6 -5
package/bin/saasicat.js
CHANGED
|
@@ -43,10 +43,12 @@ import {
|
|
|
43
43
|
applyTokens,
|
|
44
44
|
constraintsFor,
|
|
45
45
|
checkSchema,
|
|
46
|
-
|
|
46
|
+
extractFragmentBlocks,
|
|
47
47
|
findFkPointers,
|
|
48
48
|
hasConstraints,
|
|
49
49
|
assertValidProjectKey,
|
|
50
|
+
judgeModuleResolution,
|
|
51
|
+
readEffectiveModuleResolution,
|
|
50
52
|
buildImportMap,
|
|
51
53
|
migrationCreatedBy,
|
|
52
54
|
rewriteImports,
|
|
@@ -133,14 +135,15 @@ async function selectFragmentFiles(dir, filter) {
|
|
|
133
135
|
|
|
134
136
|
async function loadFragments(dir, filter) {
|
|
135
137
|
const selected = await selectFragmentFiles(dir, filter);
|
|
136
|
-
const blocks = new Map();
|
|
138
|
+
const blocks = { enums: new Map(), models: new Map() };
|
|
137
139
|
for (const file of selected) {
|
|
138
140
|
const content = await readFile(join(dir, file), 'utf8');
|
|
139
|
-
const fileBlocks =
|
|
140
|
-
for (const [name, body] of fileBlocks) {
|
|
141
|
-
if (!blocks.has(name))
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
const fileBlocks = extractFragmentBlocks(content);
|
|
142
|
+
for (const [name, body] of fileBlocks.enums) {
|
|
143
|
+
if (!blocks.enums.has(name)) blocks.enums.set(name, body);
|
|
144
|
+
}
|
|
145
|
+
for (const [name, body] of fileBlocks.models) {
|
|
146
|
+
if (!blocks.models.has(name)) blocks.models.set(name, body);
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
149
|
return { files: selected, blocks };
|
|
@@ -172,7 +175,7 @@ async function cmdSchemaApply(args) {
|
|
|
172
175
|
}
|
|
173
176
|
|
|
174
177
|
const { files, blocks } = await loadFragments(fragmentsDir, filter);
|
|
175
|
-
if (blocks.size === 0) {
|
|
178
|
+
if (blocks.models.size === 0) {
|
|
176
179
|
console.error('✗ No models found in the selected fragments.');
|
|
177
180
|
process.exit(1);
|
|
178
181
|
}
|
|
@@ -186,13 +189,16 @@ async function cmdSchemaApply(args) {
|
|
|
186
189
|
// one where the manual step is most likely to have been forgotten.
|
|
187
190
|
const fk = resolveFkPointers(result.schema, args);
|
|
188
191
|
|
|
189
|
-
if (result.added.length === 0 && fk.enabled.length === 0) {
|
|
192
|
+
if (result.added.length === 0 && result.addedEnums.length === 0 && fk.enabled.length === 0) {
|
|
190
193
|
console.log(`→ Nothing to do. Models already present: ${result.skipped.join(', ')}`);
|
|
191
194
|
reportFkPointers(fk, args);
|
|
192
195
|
return;
|
|
193
196
|
}
|
|
194
197
|
|
|
195
198
|
if (args['dry-run']) {
|
|
199
|
+
if (result.addedEnums.length) {
|
|
200
|
+
console.log(`(--dry-run) Would append enums: ${result.addedEnums.join(', ')}`);
|
|
201
|
+
}
|
|
196
202
|
if (result.added.length) {
|
|
197
203
|
console.log(`(--dry-run) Would append: ${result.added.join(', ')}`);
|
|
198
204
|
}
|
|
@@ -210,12 +216,18 @@ async function cmdSchemaApply(args) {
|
|
|
210
216
|
for (const { line } of fk.enabled) {
|
|
211
217
|
console.log(` ${line + 1}: ${fk.schema.split('\n')[line]?.trim() ?? ''}`);
|
|
212
218
|
}
|
|
213
|
-
|
|
214
|
-
if (
|
|
219
|
+
const appended = result.added.length > 0 || result.addedEnums.length > 0;
|
|
220
|
+
if (fk.enabled.length > 0 && appended) console.log('');
|
|
221
|
+
if (appended) console.log(result.schema.slice(schema.length));
|
|
215
222
|
return;
|
|
216
223
|
}
|
|
217
224
|
|
|
218
225
|
await writeFile(schemaPath, fk.schema, 'utf8');
|
|
226
|
+
if (result.addedEnums.length) {
|
|
227
|
+
console.log(
|
|
228
|
+
`✓ Appended ${result.addedEnums.length} enum(s): ${result.addedEnums.join(', ')}`,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
219
231
|
console.log(`✓ Appended ${result.added.length} model(s): ${result.added.join(', ')}`);
|
|
220
232
|
if (result.skipped.length) {
|
|
221
233
|
console.log(`→ Skipped (already present): ${result.skipped.join(', ')}`);
|
|
@@ -711,6 +723,23 @@ async function cmdInit(args, argv) {
|
|
|
711
723
|
}
|
|
712
724
|
|
|
713
725
|
const root = resolve(args.dir ?? '.');
|
|
726
|
+
|
|
727
|
+
// Before anything is written: the files below import subpath exports,
|
|
728
|
+
// and under `moduleResolution: node` none of them resolves. Found by
|
|
729
|
+
// running the quickstart against an app that predates `nodenext`.
|
|
730
|
+
if (existsSync(join(root, 'tsconfig.json'))) {
|
|
731
|
+
const ts = loadTypeScript(root);
|
|
732
|
+
if (ts === null) {
|
|
733
|
+
console.log('! tsconfig.json not checked: no TypeScript resolvable from this project.');
|
|
734
|
+
} else {
|
|
735
|
+
const verdict = judgeModuleResolution(readEffectiveModuleResolution(root, ts));
|
|
736
|
+
if (!verdict.ok) {
|
|
737
|
+
console.error(`✗ ${verdict.reason}`);
|
|
738
|
+
process.exit(1);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
714
743
|
const plan = planInit({
|
|
715
744
|
projectKey: args['project-key'],
|
|
716
745
|
appName: args['app-name'],
|
|
@@ -772,12 +801,33 @@ async function cmdInit(args, argv) {
|
|
|
772
801
|
console.log(' — the generated app does NOT compile until you do. An empty');
|
|
773
802
|
console.log(' array means "deliberately auth-free" to the platform, and');
|
|
774
803
|
console.log(' would publish GET /admin/discovery to anyone who asks.');
|
|
804
|
+
console.log(' 2. Name the modules in `imports: [YourPrismaModule, YourAuthModule]`');
|
|
805
|
+
console.log(' — the one exporting PrismaService and the one your guard needs.');
|
|
806
|
+
console.log(' The platform module resolves its providers from that list;');
|
|
807
|
+
console.log(' without it the first boot stops at "Nest can\'t resolve');
|
|
808
|
+
console.log(' dependencies of … (PrismaService)".');
|
|
775
809
|
if (plan.quotaProviders.length > 0) {
|
|
776
|
-
console.log('
|
|
777
|
-
console.log('
|
|
810
|
+
console.log(' 3. Check each quota provider counts the right thing');
|
|
811
|
+
console.log(' 4. saasicat schema migrate --name=add_saasicat');
|
|
778
812
|
} else {
|
|
779
|
-
console.log('
|
|
813
|
+
console.log(' 3. saasicat schema migrate --name=add_saasicat');
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* The TypeScript that will compile the project: the consumer's own, resolved
|
|
819
|
+
* from the project root, so the tsconfig is read the way the build reads it.
|
|
820
|
+
* Falls back to the one this CLI was installed with, then to null.
|
|
821
|
+
*/
|
|
822
|
+
function loadTypeScript(root) {
|
|
823
|
+
for (const from of [join(root, 'package.json'), import.meta.url]) {
|
|
824
|
+
try {
|
|
825
|
+
return createRequire(from)('typescript');
|
|
826
|
+
} catch {
|
|
827
|
+
// Not resolvable from here — try the next origin.
|
|
828
|
+
}
|
|
780
829
|
}
|
|
830
|
+
return null;
|
|
781
831
|
}
|
|
782
832
|
|
|
783
833
|
/** Adds the platform to `src/app.module.ts`, or says exactly what to paste. */
|
package/dist/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
50ce8728dd7552e453dc2c893c0d307dfd0f579444dbe981751740c140d74380
|
package/dist/index.cjs
CHANGED
|
@@ -85,6 +85,9 @@ __export(index_exports, {
|
|
|
85
85
|
enableFkPointers: () => enableFkPointers,
|
|
86
86
|
extractBlockNames: () => extractBlockNames,
|
|
87
87
|
extractBlocks: () => extractBlocks,
|
|
88
|
+
extractEnumBlocks: () => extractEnumBlocks,
|
|
89
|
+
extractEnumNames: () => extractEnumNames,
|
|
90
|
+
extractFragmentBlocks: () => extractFragmentBlocks,
|
|
88
91
|
extractModelBlocks: () => extractModelBlocks,
|
|
89
92
|
extractModelNames: () => extractModelNames,
|
|
90
93
|
findFkPointers: () => findFkPointers,
|
|
@@ -93,6 +96,7 @@ __export(index_exports, {
|
|
|
93
96
|
hasConstraints: () => hasConstraints,
|
|
94
97
|
isNoLongerPublic: () => isNoLongerPublic,
|
|
95
98
|
isOneToOne: () => isOneToOne,
|
|
99
|
+
judgeModuleResolution: () => judgeModuleResolution,
|
|
96
100
|
kebabCase: () => kebabCase,
|
|
97
101
|
migrationCreatedBy: () => migrationCreatedBy,
|
|
98
102
|
minimumQuotasPerPlan: () => minimumQuotasPerPlan,
|
|
@@ -108,6 +112,7 @@ __export(index_exports, {
|
|
|
108
112
|
planInit: () => planInit,
|
|
109
113
|
projectKeyPattern: () => projectKeyPattern,
|
|
110
114
|
quotaKeyPattern: () => quotaKeyPattern,
|
|
115
|
+
readEffectiveModuleResolution: () => readEffectiveModuleResolution,
|
|
111
116
|
relationNameOf: () => relationNameOf,
|
|
112
117
|
reportConstraints: () => reportConstraints,
|
|
113
118
|
rewriteImports: () => rewriteImports,
|
|
@@ -1248,13 +1253,43 @@ function extractModelBlocks(fragment) {
|
|
|
1248
1253
|
return extractBlocks(fragment, "model");
|
|
1249
1254
|
}
|
|
1250
1255
|
__name(extractModelBlocks, "extractModelBlocks");
|
|
1256
|
+
function extractEnumBlocks(fragment) {
|
|
1257
|
+
return extractBlocks(fragment, "enum");
|
|
1258
|
+
}
|
|
1259
|
+
__name(extractEnumBlocks, "extractEnumBlocks");
|
|
1260
|
+
function extractEnumNames(schema2) {
|
|
1261
|
+
return extractBlockNames(schema2, "enum");
|
|
1262
|
+
}
|
|
1263
|
+
__name(extractEnumNames, "extractEnumNames");
|
|
1264
|
+
function extractFragmentBlocks(fragment) {
|
|
1265
|
+
return {
|
|
1266
|
+
enums: extractEnumBlocks(fragment),
|
|
1267
|
+
models: extractModelBlocks(fragment)
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
__name(extractFragmentBlocks, "extractFragmentBlocks");
|
|
1251
1271
|
function applyFragmentBlocks(schema2, fragmentBlocks, options = {}) {
|
|
1252
|
-
const
|
|
1272
|
+
const blocks = fragmentBlocks instanceof Map ? {
|
|
1273
|
+
enums: /* @__PURE__ */ new Map(),
|
|
1274
|
+
models: fragmentBlocks
|
|
1275
|
+
} : fragmentBlocks;
|
|
1276
|
+
const existingModels = new Set(extractModelNames(schema2));
|
|
1277
|
+
const existingEnums = new Set(extractEnumNames(schema2));
|
|
1253
1278
|
const added = [];
|
|
1254
1279
|
const skipped = [];
|
|
1280
|
+
const addedEnums = [];
|
|
1281
|
+
const skippedEnums = [];
|
|
1255
1282
|
const additions = [];
|
|
1256
|
-
for (const [name, block] of
|
|
1257
|
-
if (
|
|
1283
|
+
for (const [name, block] of blocks.enums) {
|
|
1284
|
+
if (existingEnums.has(name)) {
|
|
1285
|
+
skippedEnums.push(name);
|
|
1286
|
+
} else {
|
|
1287
|
+
addedEnums.push(name);
|
|
1288
|
+
additions.push(block);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
for (const [name, block] of blocks.models) {
|
|
1292
|
+
if (existingModels.has(name)) {
|
|
1258
1293
|
skipped.push(name);
|
|
1259
1294
|
} else {
|
|
1260
1295
|
added.push(name);
|
|
@@ -1265,6 +1300,8 @@ function applyFragmentBlocks(schema2, fragmentBlocks, options = {}) {
|
|
|
1265
1300
|
return {
|
|
1266
1301
|
added,
|
|
1267
1302
|
skipped,
|
|
1303
|
+
addedEnums,
|
|
1304
|
+
skippedEnums,
|
|
1268
1305
|
schema: schema2
|
|
1269
1306
|
};
|
|
1270
1307
|
}
|
|
@@ -1281,6 +1318,8 @@ function applyFragmentBlocks(schema2, fragmentBlocks, options = {}) {
|
|
|
1281
1318
|
return {
|
|
1282
1319
|
added,
|
|
1283
1320
|
skipped,
|
|
1321
|
+
addedEnums,
|
|
1322
|
+
skippedEnums,
|
|
1284
1323
|
schema: trimmedSchema + header + additions.join("\n\n") + "\n"
|
|
1285
1324
|
};
|
|
1286
1325
|
}
|
|
@@ -1835,6 +1874,38 @@ function patchOptionsFor(plan) {
|
|
|
1835
1874
|
}
|
|
1836
1875
|
__name(patchOptionsFor, "patchOptionsFor");
|
|
1837
1876
|
|
|
1877
|
+
// src/init/module-resolution.ts
|
|
1878
|
+
var import_node_path = require("path");
|
|
1879
|
+
var RESOLVES_SUBPATHS = /* @__PURE__ */ new Set([
|
|
1880
|
+
"node16",
|
|
1881
|
+
"nodenext",
|
|
1882
|
+
"bundler"
|
|
1883
|
+
]);
|
|
1884
|
+
function judgeModuleResolution(value) {
|
|
1885
|
+
if (value === null || RESOLVES_SUBPATHS.has(value)) {
|
|
1886
|
+
return {
|
|
1887
|
+
ok: true,
|
|
1888
|
+
value
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
return {
|
|
1892
|
+
ok: false,
|
|
1893
|
+
value,
|
|
1894
|
+
reason: `tsconfig.json resolves modules with "moduleResolution": "${value}"` + (value === "node10" ? ' (what TypeScript calls the "node" setting)' : "") + '. The files init writes import subpath exports (`@saasicat/nest/platform`, `/billing`, `/discovery`), which TypeScript resolves only under "node16", "nodenext" or "bundler". Set one of those first \u2014 `nest new` has used "nodenext" since NestJS 10.'
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
__name(judgeModuleResolution, "judgeModuleResolution");
|
|
1898
|
+
function readEffectiveModuleResolution(root, ts) {
|
|
1899
|
+
const configPath = (0, import_node_path.join)(root, "tsconfig.json");
|
|
1900
|
+
const read = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
1901
|
+
if (read.error || read.config === void 0) return null;
|
|
1902
|
+
const parsed = ts.parseJsonConfigFileContent(read.config, ts.sys, root);
|
|
1903
|
+
const kind = parsed.options.moduleResolution;
|
|
1904
|
+
if (kind === void 0) return null;
|
|
1905
|
+
return ts.ModuleResolutionKind[kind].toLowerCase();
|
|
1906
|
+
}
|
|
1907
|
+
__name(readEffectiveModuleResolution, "readEffectiveModuleResolution");
|
|
1908
|
+
|
|
1838
1909
|
// src/codemods/v1-imports.ts
|
|
1839
1910
|
var PUBLIC_PREFIXES = [
|
|
1840
1911
|
"ui/",
|
|
@@ -2118,7 +2189,7 @@ ${block}`;
|
|
|
2118
2189
|
return {
|
|
2119
2190
|
source,
|
|
2120
2191
|
status: "declined",
|
|
2121
|
-
reason: "no `@Module({
|
|
2192
|
+
reason: "this file has no `@Module({ ... })` with an `imports:` key on a line of its own \u2014 the shape `nest new` writes \u2014 so there is nowhere to add the platform without guessing at the structure",
|
|
2122
2193
|
manualBlock
|
|
2123
2194
|
};
|
|
2124
2195
|
}
|
|
@@ -2206,6 +2277,13 @@ function renderForRootBlock(options) {
|
|
|
2206
2277
|
" // your whole capability inventory \u2014 and the manifest routes to",
|
|
2207
2278
|
" // anyone who asks. Import your guard and put it in.",
|
|
2208
2279
|
" controller: { guards: [YourAuthGuard] },",
|
|
2280
|
+
" // The modules whose providers the platform injects: the one",
|
|
2281
|
+
" // exporting PrismaService, and the one your guard depends on.",
|
|
2282
|
+
" // `prismaPersistence({ client: PrismaService })` is resolved",
|
|
2283
|
+
" // inside the platform module, which sees only what is listed",
|
|
2284
|
+
" // here or declared @Global. Same rule as the guard: this does",
|
|
2285
|
+
" // not compile until you name them.",
|
|
2286
|
+
" imports: [YourPrismaModule, YourAuthModule],",
|
|
2209
2287
|
options.persistenceImport ? " persistence," : " // persistence: prismaPersistence({ client: PrismaService }),",
|
|
2210
2288
|
" catalog: { featureUiRegistry: " + options.registry.constName + " },",
|
|
2211
2289
|
" adminResources: true,",
|
|
@@ -2852,7 +2930,7 @@ DoctorCommands = _ts_decorate12([
|
|
|
2852
2930
|
|
|
2853
2931
|
// src/discovery.command.ts
|
|
2854
2932
|
var import_node_fs = require("fs");
|
|
2855
|
-
var
|
|
2933
|
+
var import_node_path2 = require("path");
|
|
2856
2934
|
var import_common13 = require("@nestjs/common");
|
|
2857
2935
|
var import_nest_commander5 = require("nest-commander");
|
|
2858
2936
|
var import_nest6 = require("@saasicat/nest");
|
|
@@ -2890,8 +2968,8 @@ var DiscoveryScanCommand = class extends import_nest_commander5.CommandRunner {
|
|
|
2890
2968
|
try {
|
|
2891
2969
|
const snapshot = this.scanner.rebuildSnapshot();
|
|
2892
2970
|
if (flags.out) {
|
|
2893
|
-
const outPath = (0,
|
|
2894
|
-
(0, import_node_fs.mkdirSync)((0,
|
|
2971
|
+
const outPath = (0, import_node_path2.resolve)(flags.out);
|
|
2972
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path2.dirname)(outPath), {
|
|
2895
2973
|
recursive: true
|
|
2896
2974
|
});
|
|
2897
2975
|
(0, import_node_fs.writeFileSync)(outPath, JSON.stringify(snapshot, null, 2) + "\n", "utf-8");
|
|
@@ -2900,7 +2978,7 @@ var DiscoveryScanCommand = class extends import_nest_commander5.CommandRunner {
|
|
|
2900
2978
|
process.stdout.write(`Discovery-Scan (${snapshot.app.key} v${snapshot.app.version}): ${snapshot.capabilities.length} Capabilities \xB7 ${snapshot.features.length} Features \xB7 ${snapshot.quotas.length} Quotas \xB7 hash ${snapshot.hash.slice(0, 19)}\u2026
|
|
2901
2979
|
`);
|
|
2902
2980
|
if (target) {
|
|
2903
|
-
process.stdout.write(`Snapshot persisted: ${(0,
|
|
2981
|
+
process.stdout.write(`Snapshot persisted: ${(0, import_node_path2.resolve)(target)}
|
|
2904
2982
|
`);
|
|
2905
2983
|
} else {
|
|
2906
2984
|
process.stderr.write("WARNING: the snapshot was not persisted \u2014 neither snapshotPath (DiscoveryModule.forRoot) configured nor --out given. The seed gate will find no snapshot this way.\n");
|
|
@@ -3329,6 +3407,9 @@ UserCommands = _ts_decorate14([
|
|
|
3329
3407
|
enableFkPointers,
|
|
3330
3408
|
extractBlockNames,
|
|
3331
3409
|
extractBlocks,
|
|
3410
|
+
extractEnumBlocks,
|
|
3411
|
+
extractEnumNames,
|
|
3412
|
+
extractFragmentBlocks,
|
|
3332
3413
|
extractModelBlocks,
|
|
3333
3414
|
extractModelNames,
|
|
3334
3415
|
findFkPointers,
|
|
@@ -3337,6 +3418,7 @@ UserCommands = _ts_decorate14([
|
|
|
3337
3418
|
hasConstraints,
|
|
3338
3419
|
isNoLongerPublic,
|
|
3339
3420
|
isOneToOne,
|
|
3421
|
+
judgeModuleResolution,
|
|
3340
3422
|
kebabCase,
|
|
3341
3423
|
migrationCreatedBy,
|
|
3342
3424
|
minimumQuotasPerPlan,
|
|
@@ -3352,6 +3434,7 @@ UserCommands = _ts_decorate14([
|
|
|
3352
3434
|
planInit,
|
|
3353
3435
|
projectKeyPattern,
|
|
3354
3436
|
quotaKeyPattern,
|
|
3437
|
+
readEffectiveModuleResolution,
|
|
3355
3438
|
relationNameOf,
|
|
3356
3439
|
reportConstraints,
|
|
3357
3440
|
rewriteImports,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MfaService, AdminAuditService, AdminManifestService, DiscoverySnapshot, ProviderSpec, DiscoveryScanner } from '@saasicat/nest';
|
|
2
2
|
import { UserPort, PlatformUserDto, AuditQueryPort, AuditEntry, AdminManifest, ManifestAccessPort, PlanCatalog, UserManagementPort } from '@saasicat/core';
|
|
3
3
|
import { Type, DynamicModule } from '@nestjs/common';
|
|
4
|
+
import * as TypeScript from 'typescript';
|
|
4
5
|
import { CommandRunner } from 'nest-commander';
|
|
5
6
|
|
|
6
7
|
declare const CLI_CONTEXT_CONFIG_TOKEN: unique symbol;
|
|
@@ -381,19 +382,41 @@ declare function extractModelNames(schema: string): string[];
|
|
|
381
382
|
* `name -> complete block text incl. opening/closing braces`.
|
|
382
383
|
*/
|
|
383
384
|
declare function extractModelBlocks(fragment: string): Map<string, string>;
|
|
385
|
+
/** Returns all `enum X { ... }` blocks from a fragment, keyed by name. */
|
|
386
|
+
declare function extractEnumBlocks(fragment: string): Map<string, string>;
|
|
387
|
+
/** Names of all top-level `enum X { ... }` blocks in the schema. */
|
|
388
|
+
declare function extractEnumNames(schema: string): string[];
|
|
389
|
+
/**
|
|
390
|
+
* What a fragment contributes: its enums and its models. Both travel
|
|
391
|
+
* together, because a model's `BillingCycle` field is a validation error in
|
|
392
|
+
* a schema that has the model and not the enum — which is what `apply` used
|
|
393
|
+
* to produce for every consumer whose schema did not already carry the enums
|
|
394
|
+
* by hand, and what the example app masked by carrying them.
|
|
395
|
+
*/
|
|
396
|
+
interface FragmentBlocks {
|
|
397
|
+
enums: Map<string, string>;
|
|
398
|
+
models: Map<string, string>;
|
|
399
|
+
}
|
|
400
|
+
declare function extractFragmentBlocks(fragment: string): FragmentBlocks;
|
|
384
401
|
interface ApplyResult {
|
|
385
|
-
/**
|
|
402
|
+
/** Models that were added. */
|
|
386
403
|
added: string[];
|
|
387
|
-
/**
|
|
404
|
+
/** Models that were already present (no write). */
|
|
388
405
|
skipped: string[];
|
|
389
|
-
/**
|
|
406
|
+
/** Enums that were added, before the models that use them. */
|
|
407
|
+
addedEnums: string[];
|
|
408
|
+
/** Enums that were already present (no write). */
|
|
409
|
+
skippedEnums: string[];
|
|
410
|
+
/** Resulting schema text. When nothing was added, identical to the input. */
|
|
390
411
|
schema: string;
|
|
391
412
|
}
|
|
392
413
|
/**
|
|
393
|
-
* Appends missing models from `fragmentBlocks` to the end of
|
|
394
|
-
*
|
|
414
|
+
* Appends missing enums and models from `fragmentBlocks` to the end of
|
|
415
|
+
* `schema`. Existing blocks (same name) stay unchanged and are listed as
|
|
416
|
+
* skipped. A plain map of models is accepted for the callers that only ever
|
|
417
|
+
* had models; the enums are then `[]`, which is what they were before.
|
|
395
418
|
*/
|
|
396
|
-
declare function applyFragmentBlocks(schema: string, fragmentBlocks: Map<string, string>, options?: {
|
|
419
|
+
declare function applyFragmentBlocks(schema: string, fragmentBlocks: FragmentBlocks | Map<string, string>, options?: {
|
|
397
420
|
fragmentLabel?: string;
|
|
398
421
|
}): ApplyResult;
|
|
399
422
|
|
|
@@ -804,6 +827,33 @@ interface PatchOptionsFromPlan {
|
|
|
804
827
|
};
|
|
805
828
|
}
|
|
806
829
|
|
|
830
|
+
interface ModuleResolutionVerdict {
|
|
831
|
+
readonly ok: boolean;
|
|
832
|
+
/** The effective setting, lower-cased as TypeScript names it, or null when unset. */
|
|
833
|
+
readonly value: string | null;
|
|
834
|
+
readonly reason?: string;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Judges an effective `moduleResolution`, as `readEffectiveModuleResolution`
|
|
838
|
+
* reports it.
|
|
839
|
+
*
|
|
840
|
+
* Unset is `ok`: TypeScript then derives it from `module`, and a `module`
|
|
841
|
+
* that implies the old resolution is a setup this cannot see from here —
|
|
842
|
+
* the next build says so, with TypeScript's own message.
|
|
843
|
+
*/
|
|
844
|
+
declare function judgeModuleResolution(value: string | null): ModuleResolutionVerdict;
|
|
845
|
+
/**
|
|
846
|
+
* The `moduleResolution` a project's `tsconfig.json` resolves to, after
|
|
847
|
+
* `extends`, lower-cased as TypeScript names the kind (`node10`, `node16`,
|
|
848
|
+
* `nodenext`, `bundler`, `classic`) — or null when there is no config, the
|
|
849
|
+
* config cannot be parsed, or the option is not set anywhere in the chain.
|
|
850
|
+
*
|
|
851
|
+
* `ts` is whichever TypeScript will compile the project: the consumer's own
|
|
852
|
+
* when it can be resolved from the project root, so the reading matches the
|
|
853
|
+
* build that follows.
|
|
854
|
+
*/
|
|
855
|
+
declare function readEffectiveModuleResolution(root: string, ts: typeof TypeScript): string | null;
|
|
856
|
+
|
|
807
857
|
/** The pattern `plan-catalog.schema.json` puts on `projectKey`. */
|
|
808
858
|
declare function projectKeyPattern(): RegExp;
|
|
809
859
|
/** The pattern it puts on the keys inside a plan's `quotas` object. */
|
|
@@ -1174,4 +1224,4 @@ declare class UserCommands extends CommandRunner {
|
|
|
1174
1224
|
parsePassword(val: string): string;
|
|
1175
1225
|
}
|
|
1176
1226
|
|
|
1177
|
-
export { AUDIT_QUERY_PORT_TOKEN, AdminCommands, AdminManifestDoctorCheck, AdminMfaSetupCommand, AdminWhoamiCommand, type ApplyResult, AuditCommands, AuditTailCommand, AuditTailFlow, type AuditTailOptions, type BlockAttributeKind, type BlockAttributes, CLI_CONTEXT_CONFIG_TOKEN, CONSTRAINTS_MARKER, type CheckSeverity, type CliContextConfig, CliContextModule, type CliContextModuleOptions, CliContextService, CliError, type CliIdentity, type ConstraintsOutcome, type ConstraintsReport, DEFAULT_MANIFEST_CHECKS, DOCTOR_CHECKS_TOKEN, DiscoveryCommands, DiscoveryScanCommand, DiscoverySnapshotDoctorCheck, type DoctorCheck, type DoctorCheckResult, DoctorCommands, DoctorFlow, type DoctorReport, type EnableFkResult, type FieldMismatch, type FieldMismatchReason, type FieldSignature, type FkModelNames, type FkPointer, type InitOptions, type InitPlan, LIMIT_FILTER_IMPORTS, LIMIT_FILTER_PROVIDER, MANIFEST_ACCESS_PORT_TOKEN, MANIFEST_CHECKS_TOKEN, type ManifestCheck, ManifestCheckCommand, type ManifestCheckReport, type ManifestCheckResult, ManifestCliFlow, ManifestCommands, type ManifestDiff, ManifestDumpCommand, ManifestHashCommand, type ManifestRewriteOptions, ManifestValidateCommand, MfaSetupFlow, type MfaSetupOptions, type MfaSetupResult, type MissingBlockAttribute, type MissingEnumValue, type MissingField, type MoveTable, PLATFORM_DOCTOR_CHECK_PROVIDERS, type ParsedSchema, type PatchAppModuleOptions, type PatchOptionsFromPlan, type PatchResult, PlanCatalogDoctorCheck, type PlannedFile, type QuotaProviderFile, type QuotaSpec, type RenameResult, type RenameTable, type RewriteResult, type SchemaCheckReport, UI_VUE_SPECIFIER, USER_MANAGEMENT_PORT_TOKEN, USER_PORT_TOKEN, UserCommands, UserPortDoctorCheck, WhoAmIFlow, type WhoAmIResult, appendConstraints, applyFragmentBlocks, applyTokens, assertModelsExist, assertValidProjectKey, assertValidQuotaKey, blankStringLiterals, blockBodyLines, breaksContract, buildImportMap, checkSchema, constraintsFor, enableFkPointers, extractBlockNames, extractBlocks, extractModelBlocks, extractModelNames, findFkPointers, foreignKeyOf, hasBackRelation, hasConstraints, isNoLongerPublic, isOneToOne, kebabCase, migrationCreatedBy, minimumQuotasPerPlan, namedImports, parseBlockAttributes, parseEnumValues, parseFields, parseQuota, parseSchema, pascalCase, patchAppModule, patchOptionsFor, planInit, projectKeyPattern, quotaKeyPattern, relationNameOf, reportConstraints, rewriteImports, rewriteManifest, rewriteNames, rewriteSubpath, stripLineComment, structuralOnly, tablesAddressedBy };
|
|
1227
|
+
export { AUDIT_QUERY_PORT_TOKEN, AdminCommands, AdminManifestDoctorCheck, AdminMfaSetupCommand, AdminWhoamiCommand, type ApplyResult, AuditCommands, AuditTailCommand, AuditTailFlow, type AuditTailOptions, type BlockAttributeKind, type BlockAttributes, CLI_CONTEXT_CONFIG_TOKEN, CONSTRAINTS_MARKER, type CheckSeverity, type CliContextConfig, CliContextModule, type CliContextModuleOptions, CliContextService, CliError, type CliIdentity, type ConstraintsOutcome, type ConstraintsReport, DEFAULT_MANIFEST_CHECKS, DOCTOR_CHECKS_TOKEN, DiscoveryCommands, DiscoveryScanCommand, DiscoverySnapshotDoctorCheck, type DoctorCheck, type DoctorCheckResult, DoctorCommands, DoctorFlow, type DoctorReport, type EnableFkResult, type FieldMismatch, type FieldMismatchReason, type FieldSignature, type FkModelNames, type FkPointer, type FragmentBlocks, type InitOptions, type InitPlan, LIMIT_FILTER_IMPORTS, LIMIT_FILTER_PROVIDER, MANIFEST_ACCESS_PORT_TOKEN, MANIFEST_CHECKS_TOKEN, type ManifestCheck, ManifestCheckCommand, type ManifestCheckReport, type ManifestCheckResult, ManifestCliFlow, ManifestCommands, type ManifestDiff, ManifestDumpCommand, ManifestHashCommand, type ManifestRewriteOptions, ManifestValidateCommand, MfaSetupFlow, type MfaSetupOptions, type MfaSetupResult, type MissingBlockAttribute, type MissingEnumValue, type MissingField, type ModuleResolutionVerdict, type MoveTable, PLATFORM_DOCTOR_CHECK_PROVIDERS, type ParsedSchema, type PatchAppModuleOptions, type PatchOptionsFromPlan, type PatchResult, PlanCatalogDoctorCheck, type PlannedFile, type QuotaProviderFile, type QuotaSpec, type RenameResult, type RenameTable, type RewriteResult, type SchemaCheckReport, UI_VUE_SPECIFIER, USER_MANAGEMENT_PORT_TOKEN, USER_PORT_TOKEN, UserCommands, UserPortDoctorCheck, WhoAmIFlow, type WhoAmIResult, appendConstraints, applyFragmentBlocks, applyTokens, assertModelsExist, assertValidProjectKey, assertValidQuotaKey, blankStringLiterals, blockBodyLines, breaksContract, buildImportMap, checkSchema, constraintsFor, enableFkPointers, extractBlockNames, extractBlocks, extractEnumBlocks, extractEnumNames, extractFragmentBlocks, extractModelBlocks, extractModelNames, findFkPointers, foreignKeyOf, hasBackRelation, hasConstraints, isNoLongerPublic, isOneToOne, judgeModuleResolution, kebabCase, migrationCreatedBy, minimumQuotasPerPlan, namedImports, parseBlockAttributes, parseEnumValues, parseFields, parseQuota, parseSchema, pascalCase, patchAppModule, patchOptionsFor, planInit, projectKeyPattern, quotaKeyPattern, readEffectiveModuleResolution, relationNameOf, reportConstraints, rewriteImports, rewriteManifest, rewriteNames, rewriteSubpath, stripLineComment, structuralOnly, tablesAddressedBy };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MfaService, AdminAuditService, AdminManifestService, DiscoverySnapshot, ProviderSpec, DiscoveryScanner } from '@saasicat/nest';
|
|
2
2
|
import { UserPort, PlatformUserDto, AuditQueryPort, AuditEntry, AdminManifest, ManifestAccessPort, PlanCatalog, UserManagementPort } from '@saasicat/core';
|
|
3
3
|
import { Type, DynamicModule } from '@nestjs/common';
|
|
4
|
+
import * as TypeScript from 'typescript';
|
|
4
5
|
import { CommandRunner } from 'nest-commander';
|
|
5
6
|
|
|
6
7
|
declare const CLI_CONTEXT_CONFIG_TOKEN: unique symbol;
|
|
@@ -381,19 +382,41 @@ declare function extractModelNames(schema: string): string[];
|
|
|
381
382
|
* `name -> complete block text incl. opening/closing braces`.
|
|
382
383
|
*/
|
|
383
384
|
declare function extractModelBlocks(fragment: string): Map<string, string>;
|
|
385
|
+
/** Returns all `enum X { ... }` blocks from a fragment, keyed by name. */
|
|
386
|
+
declare function extractEnumBlocks(fragment: string): Map<string, string>;
|
|
387
|
+
/** Names of all top-level `enum X { ... }` blocks in the schema. */
|
|
388
|
+
declare function extractEnumNames(schema: string): string[];
|
|
389
|
+
/**
|
|
390
|
+
* What a fragment contributes: its enums and its models. Both travel
|
|
391
|
+
* together, because a model's `BillingCycle` field is a validation error in
|
|
392
|
+
* a schema that has the model and not the enum — which is what `apply` used
|
|
393
|
+
* to produce for every consumer whose schema did not already carry the enums
|
|
394
|
+
* by hand, and what the example app masked by carrying them.
|
|
395
|
+
*/
|
|
396
|
+
interface FragmentBlocks {
|
|
397
|
+
enums: Map<string, string>;
|
|
398
|
+
models: Map<string, string>;
|
|
399
|
+
}
|
|
400
|
+
declare function extractFragmentBlocks(fragment: string): FragmentBlocks;
|
|
384
401
|
interface ApplyResult {
|
|
385
|
-
/**
|
|
402
|
+
/** Models that were added. */
|
|
386
403
|
added: string[];
|
|
387
|
-
/**
|
|
404
|
+
/** Models that were already present (no write). */
|
|
388
405
|
skipped: string[];
|
|
389
|
-
/**
|
|
406
|
+
/** Enums that were added, before the models that use them. */
|
|
407
|
+
addedEnums: string[];
|
|
408
|
+
/** Enums that were already present (no write). */
|
|
409
|
+
skippedEnums: string[];
|
|
410
|
+
/** Resulting schema text. When nothing was added, identical to the input. */
|
|
390
411
|
schema: string;
|
|
391
412
|
}
|
|
392
413
|
/**
|
|
393
|
-
* Appends missing models from `fragmentBlocks` to the end of
|
|
394
|
-
*
|
|
414
|
+
* Appends missing enums and models from `fragmentBlocks` to the end of
|
|
415
|
+
* `schema`. Existing blocks (same name) stay unchanged and are listed as
|
|
416
|
+
* skipped. A plain map of models is accepted for the callers that only ever
|
|
417
|
+
* had models; the enums are then `[]`, which is what they were before.
|
|
395
418
|
*/
|
|
396
|
-
declare function applyFragmentBlocks(schema: string, fragmentBlocks: Map<string, string>, options?: {
|
|
419
|
+
declare function applyFragmentBlocks(schema: string, fragmentBlocks: FragmentBlocks | Map<string, string>, options?: {
|
|
397
420
|
fragmentLabel?: string;
|
|
398
421
|
}): ApplyResult;
|
|
399
422
|
|
|
@@ -804,6 +827,33 @@ interface PatchOptionsFromPlan {
|
|
|
804
827
|
};
|
|
805
828
|
}
|
|
806
829
|
|
|
830
|
+
interface ModuleResolutionVerdict {
|
|
831
|
+
readonly ok: boolean;
|
|
832
|
+
/** The effective setting, lower-cased as TypeScript names it, or null when unset. */
|
|
833
|
+
readonly value: string | null;
|
|
834
|
+
readonly reason?: string;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Judges an effective `moduleResolution`, as `readEffectiveModuleResolution`
|
|
838
|
+
* reports it.
|
|
839
|
+
*
|
|
840
|
+
* Unset is `ok`: TypeScript then derives it from `module`, and a `module`
|
|
841
|
+
* that implies the old resolution is a setup this cannot see from here —
|
|
842
|
+
* the next build says so, with TypeScript's own message.
|
|
843
|
+
*/
|
|
844
|
+
declare function judgeModuleResolution(value: string | null): ModuleResolutionVerdict;
|
|
845
|
+
/**
|
|
846
|
+
* The `moduleResolution` a project's `tsconfig.json` resolves to, after
|
|
847
|
+
* `extends`, lower-cased as TypeScript names the kind (`node10`, `node16`,
|
|
848
|
+
* `nodenext`, `bundler`, `classic`) — or null when there is no config, the
|
|
849
|
+
* config cannot be parsed, or the option is not set anywhere in the chain.
|
|
850
|
+
*
|
|
851
|
+
* `ts` is whichever TypeScript will compile the project: the consumer's own
|
|
852
|
+
* when it can be resolved from the project root, so the reading matches the
|
|
853
|
+
* build that follows.
|
|
854
|
+
*/
|
|
855
|
+
declare function readEffectiveModuleResolution(root: string, ts: typeof TypeScript): string | null;
|
|
856
|
+
|
|
807
857
|
/** The pattern `plan-catalog.schema.json` puts on `projectKey`. */
|
|
808
858
|
declare function projectKeyPattern(): RegExp;
|
|
809
859
|
/** The pattern it puts on the keys inside a plan's `quotas` object. */
|
|
@@ -1174,4 +1224,4 @@ declare class UserCommands extends CommandRunner {
|
|
|
1174
1224
|
parsePassword(val: string): string;
|
|
1175
1225
|
}
|
|
1176
1226
|
|
|
1177
|
-
export { AUDIT_QUERY_PORT_TOKEN, AdminCommands, AdminManifestDoctorCheck, AdminMfaSetupCommand, AdminWhoamiCommand, type ApplyResult, AuditCommands, AuditTailCommand, AuditTailFlow, type AuditTailOptions, type BlockAttributeKind, type BlockAttributes, CLI_CONTEXT_CONFIG_TOKEN, CONSTRAINTS_MARKER, type CheckSeverity, type CliContextConfig, CliContextModule, type CliContextModuleOptions, CliContextService, CliError, type CliIdentity, type ConstraintsOutcome, type ConstraintsReport, DEFAULT_MANIFEST_CHECKS, DOCTOR_CHECKS_TOKEN, DiscoveryCommands, DiscoveryScanCommand, DiscoverySnapshotDoctorCheck, type DoctorCheck, type DoctorCheckResult, DoctorCommands, DoctorFlow, type DoctorReport, type EnableFkResult, type FieldMismatch, type FieldMismatchReason, type FieldSignature, type FkModelNames, type FkPointer, type InitOptions, type InitPlan, LIMIT_FILTER_IMPORTS, LIMIT_FILTER_PROVIDER, MANIFEST_ACCESS_PORT_TOKEN, MANIFEST_CHECKS_TOKEN, type ManifestCheck, ManifestCheckCommand, type ManifestCheckReport, type ManifestCheckResult, ManifestCliFlow, ManifestCommands, type ManifestDiff, ManifestDumpCommand, ManifestHashCommand, type ManifestRewriteOptions, ManifestValidateCommand, MfaSetupFlow, type MfaSetupOptions, type MfaSetupResult, type MissingBlockAttribute, type MissingEnumValue, type MissingField, type MoveTable, PLATFORM_DOCTOR_CHECK_PROVIDERS, type ParsedSchema, type PatchAppModuleOptions, type PatchOptionsFromPlan, type PatchResult, PlanCatalogDoctorCheck, type PlannedFile, type QuotaProviderFile, type QuotaSpec, type RenameResult, type RenameTable, type RewriteResult, type SchemaCheckReport, UI_VUE_SPECIFIER, USER_MANAGEMENT_PORT_TOKEN, USER_PORT_TOKEN, UserCommands, UserPortDoctorCheck, WhoAmIFlow, type WhoAmIResult, appendConstraints, applyFragmentBlocks, applyTokens, assertModelsExist, assertValidProjectKey, assertValidQuotaKey, blankStringLiterals, blockBodyLines, breaksContract, buildImportMap, checkSchema, constraintsFor, enableFkPointers, extractBlockNames, extractBlocks, extractModelBlocks, extractModelNames, findFkPointers, foreignKeyOf, hasBackRelation, hasConstraints, isNoLongerPublic, isOneToOne, kebabCase, migrationCreatedBy, minimumQuotasPerPlan, namedImports, parseBlockAttributes, parseEnumValues, parseFields, parseQuota, parseSchema, pascalCase, patchAppModule, patchOptionsFor, planInit, projectKeyPattern, quotaKeyPattern, relationNameOf, reportConstraints, rewriteImports, rewriteManifest, rewriteNames, rewriteSubpath, stripLineComment, structuralOnly, tablesAddressedBy };
|
|
1227
|
+
export { AUDIT_QUERY_PORT_TOKEN, AdminCommands, AdminManifestDoctorCheck, AdminMfaSetupCommand, AdminWhoamiCommand, type ApplyResult, AuditCommands, AuditTailCommand, AuditTailFlow, type AuditTailOptions, type BlockAttributeKind, type BlockAttributes, CLI_CONTEXT_CONFIG_TOKEN, CONSTRAINTS_MARKER, type CheckSeverity, type CliContextConfig, CliContextModule, type CliContextModuleOptions, CliContextService, CliError, type CliIdentity, type ConstraintsOutcome, type ConstraintsReport, DEFAULT_MANIFEST_CHECKS, DOCTOR_CHECKS_TOKEN, DiscoveryCommands, DiscoveryScanCommand, DiscoverySnapshotDoctorCheck, type DoctorCheck, type DoctorCheckResult, DoctorCommands, DoctorFlow, type DoctorReport, type EnableFkResult, type FieldMismatch, type FieldMismatchReason, type FieldSignature, type FkModelNames, type FkPointer, type FragmentBlocks, type InitOptions, type InitPlan, LIMIT_FILTER_IMPORTS, LIMIT_FILTER_PROVIDER, MANIFEST_ACCESS_PORT_TOKEN, MANIFEST_CHECKS_TOKEN, type ManifestCheck, ManifestCheckCommand, type ManifestCheckReport, type ManifestCheckResult, ManifestCliFlow, ManifestCommands, type ManifestDiff, ManifestDumpCommand, ManifestHashCommand, type ManifestRewriteOptions, ManifestValidateCommand, MfaSetupFlow, type MfaSetupOptions, type MfaSetupResult, type MissingBlockAttribute, type MissingEnumValue, type MissingField, type ModuleResolutionVerdict, type MoveTable, PLATFORM_DOCTOR_CHECK_PROVIDERS, type ParsedSchema, type PatchAppModuleOptions, type PatchOptionsFromPlan, type PatchResult, PlanCatalogDoctorCheck, type PlannedFile, type QuotaProviderFile, type QuotaSpec, type RenameResult, type RenameTable, type RewriteResult, type SchemaCheckReport, UI_VUE_SPECIFIER, USER_MANAGEMENT_PORT_TOKEN, USER_PORT_TOKEN, UserCommands, UserPortDoctorCheck, WhoAmIFlow, type WhoAmIResult, appendConstraints, applyFragmentBlocks, applyTokens, assertModelsExist, assertValidProjectKey, assertValidQuotaKey, blankStringLiterals, blockBodyLines, breaksContract, buildImportMap, checkSchema, constraintsFor, enableFkPointers, extractBlockNames, extractBlocks, extractEnumBlocks, extractEnumNames, extractFragmentBlocks, extractModelBlocks, extractModelNames, findFkPointers, foreignKeyOf, hasBackRelation, hasConstraints, isNoLongerPublic, isOneToOne, judgeModuleResolution, kebabCase, migrationCreatedBy, minimumQuotasPerPlan, namedImports, parseBlockAttributes, parseEnumValues, parseFields, parseQuota, parseSchema, pascalCase, patchAppModule, patchOptionsFor, planInit, projectKeyPattern, quotaKeyPattern, readEffectiveModuleResolution, relationNameOf, reportConstraints, rewriteImports, rewriteManifest, rewriteNames, rewriteSubpath, stripLineComment, structuralOnly, tablesAddressedBy };
|
package/dist/index.js
CHANGED
|
@@ -1129,13 +1129,43 @@ function extractModelBlocks(fragment) {
|
|
|
1129
1129
|
return extractBlocks(fragment, "model");
|
|
1130
1130
|
}
|
|
1131
1131
|
__name(extractModelBlocks, "extractModelBlocks");
|
|
1132
|
+
function extractEnumBlocks(fragment) {
|
|
1133
|
+
return extractBlocks(fragment, "enum");
|
|
1134
|
+
}
|
|
1135
|
+
__name(extractEnumBlocks, "extractEnumBlocks");
|
|
1136
|
+
function extractEnumNames(schema2) {
|
|
1137
|
+
return extractBlockNames(schema2, "enum");
|
|
1138
|
+
}
|
|
1139
|
+
__name(extractEnumNames, "extractEnumNames");
|
|
1140
|
+
function extractFragmentBlocks(fragment) {
|
|
1141
|
+
return {
|
|
1142
|
+
enums: extractEnumBlocks(fragment),
|
|
1143
|
+
models: extractModelBlocks(fragment)
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
__name(extractFragmentBlocks, "extractFragmentBlocks");
|
|
1132
1147
|
function applyFragmentBlocks(schema2, fragmentBlocks, options = {}) {
|
|
1133
|
-
const
|
|
1148
|
+
const blocks = fragmentBlocks instanceof Map ? {
|
|
1149
|
+
enums: /* @__PURE__ */ new Map(),
|
|
1150
|
+
models: fragmentBlocks
|
|
1151
|
+
} : fragmentBlocks;
|
|
1152
|
+
const existingModels = new Set(extractModelNames(schema2));
|
|
1153
|
+
const existingEnums = new Set(extractEnumNames(schema2));
|
|
1134
1154
|
const added = [];
|
|
1135
1155
|
const skipped = [];
|
|
1156
|
+
const addedEnums = [];
|
|
1157
|
+
const skippedEnums = [];
|
|
1136
1158
|
const additions = [];
|
|
1137
|
-
for (const [name, block] of
|
|
1138
|
-
if (
|
|
1159
|
+
for (const [name, block] of blocks.enums) {
|
|
1160
|
+
if (existingEnums.has(name)) {
|
|
1161
|
+
skippedEnums.push(name);
|
|
1162
|
+
} else {
|
|
1163
|
+
addedEnums.push(name);
|
|
1164
|
+
additions.push(block);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
for (const [name, block] of blocks.models) {
|
|
1168
|
+
if (existingModels.has(name)) {
|
|
1139
1169
|
skipped.push(name);
|
|
1140
1170
|
} else {
|
|
1141
1171
|
added.push(name);
|
|
@@ -1146,6 +1176,8 @@ function applyFragmentBlocks(schema2, fragmentBlocks, options = {}) {
|
|
|
1146
1176
|
return {
|
|
1147
1177
|
added,
|
|
1148
1178
|
skipped,
|
|
1179
|
+
addedEnums,
|
|
1180
|
+
skippedEnums,
|
|
1149
1181
|
schema: schema2
|
|
1150
1182
|
};
|
|
1151
1183
|
}
|
|
@@ -1162,6 +1194,8 @@ function applyFragmentBlocks(schema2, fragmentBlocks, options = {}) {
|
|
|
1162
1194
|
return {
|
|
1163
1195
|
added,
|
|
1164
1196
|
skipped,
|
|
1197
|
+
addedEnums,
|
|
1198
|
+
skippedEnums,
|
|
1165
1199
|
schema: trimmedSchema + header + additions.join("\n\n") + "\n"
|
|
1166
1200
|
};
|
|
1167
1201
|
}
|
|
@@ -1716,6 +1750,38 @@ function patchOptionsFor(plan) {
|
|
|
1716
1750
|
}
|
|
1717
1751
|
__name(patchOptionsFor, "patchOptionsFor");
|
|
1718
1752
|
|
|
1753
|
+
// src/init/module-resolution.ts
|
|
1754
|
+
import { join } from "path";
|
|
1755
|
+
var RESOLVES_SUBPATHS = /* @__PURE__ */ new Set([
|
|
1756
|
+
"node16",
|
|
1757
|
+
"nodenext",
|
|
1758
|
+
"bundler"
|
|
1759
|
+
]);
|
|
1760
|
+
function judgeModuleResolution(value) {
|
|
1761
|
+
if (value === null || RESOLVES_SUBPATHS.has(value)) {
|
|
1762
|
+
return {
|
|
1763
|
+
ok: true,
|
|
1764
|
+
value
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
return {
|
|
1768
|
+
ok: false,
|
|
1769
|
+
value,
|
|
1770
|
+
reason: `tsconfig.json resolves modules with "moduleResolution": "${value}"` + (value === "node10" ? ' (what TypeScript calls the "node" setting)' : "") + '. The files init writes import subpath exports (`@saasicat/nest/platform`, `/billing`, `/discovery`), which TypeScript resolves only under "node16", "nodenext" or "bundler". Set one of those first \u2014 `nest new` has used "nodenext" since NestJS 10.'
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
__name(judgeModuleResolution, "judgeModuleResolution");
|
|
1774
|
+
function readEffectiveModuleResolution(root, ts) {
|
|
1775
|
+
const configPath = join(root, "tsconfig.json");
|
|
1776
|
+
const read = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
1777
|
+
if (read.error || read.config === void 0) return null;
|
|
1778
|
+
const parsed = ts.parseJsonConfigFileContent(read.config, ts.sys, root);
|
|
1779
|
+
const kind = parsed.options.moduleResolution;
|
|
1780
|
+
if (kind === void 0) return null;
|
|
1781
|
+
return ts.ModuleResolutionKind[kind].toLowerCase();
|
|
1782
|
+
}
|
|
1783
|
+
__name(readEffectiveModuleResolution, "readEffectiveModuleResolution");
|
|
1784
|
+
|
|
1719
1785
|
// src/codemods/v1-imports.ts
|
|
1720
1786
|
var PUBLIC_PREFIXES = [
|
|
1721
1787
|
"ui/",
|
|
@@ -1999,7 +2065,7 @@ ${block}`;
|
|
|
1999
2065
|
return {
|
|
2000
2066
|
source,
|
|
2001
2067
|
status: "declined",
|
|
2002
|
-
reason: "no `@Module({
|
|
2068
|
+
reason: "this file has no `@Module({ ... })` with an `imports:` key on a line of its own \u2014 the shape `nest new` writes \u2014 so there is nowhere to add the platform without guessing at the structure",
|
|
2003
2069
|
manualBlock
|
|
2004
2070
|
};
|
|
2005
2071
|
}
|
|
@@ -2087,6 +2153,13 @@ function renderForRootBlock(options) {
|
|
|
2087
2153
|
" // your whole capability inventory \u2014 and the manifest routes to",
|
|
2088
2154
|
" // anyone who asks. Import your guard and put it in.",
|
|
2089
2155
|
" controller: { guards: [YourAuthGuard] },",
|
|
2156
|
+
" // The modules whose providers the platform injects: the one",
|
|
2157
|
+
" // exporting PrismaService, and the one your guard depends on.",
|
|
2158
|
+
" // `prismaPersistence({ client: PrismaService })` is resolved",
|
|
2159
|
+
" // inside the platform module, which sees only what is listed",
|
|
2160
|
+
" // here or declared @Global. Same rule as the guard: this does",
|
|
2161
|
+
" // not compile until you name them.",
|
|
2162
|
+
" imports: [YourPrismaModule, YourAuthModule],",
|
|
2090
2163
|
options.persistenceImport ? " persistence," : " // persistence: prismaPersistence({ client: PrismaService }),",
|
|
2091
2164
|
" catalog: { featureUiRegistry: " + options.registry.constName + " },",
|
|
2092
2165
|
" adminResources: true,",
|
|
@@ -3209,6 +3282,9 @@ export {
|
|
|
3209
3282
|
enableFkPointers,
|
|
3210
3283
|
extractBlockNames,
|
|
3211
3284
|
extractBlocks,
|
|
3285
|
+
extractEnumBlocks,
|
|
3286
|
+
extractEnumNames,
|
|
3287
|
+
extractFragmentBlocks,
|
|
3212
3288
|
extractModelBlocks,
|
|
3213
3289
|
extractModelNames,
|
|
3214
3290
|
findFkPointers,
|
|
@@ -3217,6 +3293,7 @@ export {
|
|
|
3217
3293
|
hasConstraints,
|
|
3218
3294
|
isNoLongerPublic,
|
|
3219
3295
|
isOneToOne,
|
|
3296
|
+
judgeModuleResolution,
|
|
3220
3297
|
kebabCase,
|
|
3221
3298
|
migrationCreatedBy,
|
|
3222
3299
|
minimumQuotasPerPlan,
|
|
@@ -3232,6 +3309,7 @@ export {
|
|
|
3232
3309
|
planInit,
|
|
3233
3310
|
projectKeyPattern,
|
|
3234
3311
|
quotaKeyPattern,
|
|
3312
|
+
readEffectiveModuleResolution,
|
|
3235
3313
|
relationNameOf,
|
|
3236
3314
|
reportConstraints,
|
|
3237
3315
|
rewriteImports,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saasicat/cli",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.3",
|
|
4
4
|
"description": "CLI helpers for SaaS platform consumers. Provides CliContextService (identity, MFA, production confirm, audit tag).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"types": "./dist/index.d.cts",
|
|
17
17
|
"default": "./dist/index.cjs"
|
|
18
18
|
}
|
|
19
|
-
}
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
23
|
"dist",
|
|
@@ -29,9 +30,9 @@
|
|
|
29
30
|
},
|
|
30
31
|
"dependencies": {
|
|
31
32
|
"qrcode-terminal": "^0.12.0",
|
|
32
|
-
"@saasicat/nest": "^1.0.0-rc.
|
|
33
|
-
"@saasicat/spec": "^1.0.0-rc.
|
|
34
|
-
"@saasicat/core": "^1.0.0-rc.
|
|
33
|
+
"@saasicat/nest": "^1.0.0-rc.3",
|
|
34
|
+
"@saasicat/spec": "^1.0.0-rc.3",
|
|
35
|
+
"@saasicat/core": "^1.0.0-rc.3"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
38
|
"@nestjs/common": "^11.0.0",
|