@beignet/cli 0.0.7 → 0.0.8
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/CHANGELOG.md +10 -0
- package/README.md +40 -3
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +404 -44
- package/dist/inspect.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +267 -96
- package/dist/make.js.map +1 -1
- package/dist/registry-edits.d.ts +77 -0
- package/dist/registry-edits.d.ts.map +1 -0
- package/dist/registry-edits.js +255 -0
- package/dist/registry-edits.js.map +1 -0
- package/package.json +2 -2
- package/src/inspect.ts +648 -58
- package/src/make.ts +433 -121
- package/src/registry-edits.ts +352 -0
package/dist/make.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"make.d.ts","sourceRoot":"","sources":["../src/make.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,KAAK,aAAa,EAMnB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"make.d.ts","sourceRoot":"","sources":["../src/make.ts"],"names":[],"mappings":"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"}
|
package/dist/make.js
CHANGED
|
@@ -2,6 +2,7 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { directoryPath, loadBeignetConfig, normalizePath, resolveConfig, } from "./config.js";
|
|
5
|
+
import { appendToArrayExpression, appendToNamedArray, appendToOutboxRegistryArray, arrayInitializerInfo, identifiersFromArrayExpression, insertAfterImports, matchingDelimiterIndex, } from "./registry-edits.js";
|
|
5
6
|
export { makeFeatureAddonChoices } from "./choices.js";
|
|
6
7
|
export async function makeResource(options) {
|
|
7
8
|
return makeResourceSlice(options, "resource");
|
|
@@ -50,6 +51,18 @@ async function makeResourceSlice(options, mode) {
|
|
|
50
51
|
mode,
|
|
51
52
|
generationOptions,
|
|
52
53
|
});
|
|
54
|
+
// Generated event-publishing use cases depend on ctx.ports.eventBus, so
|
|
55
|
+
// --events also wires the port, a deferred key, the in-memory dev provider,
|
|
56
|
+
// and the provider dependency. Plan the wiring before writing any files so
|
|
57
|
+
// an anchor miss aborts the generator without leaving partial output.
|
|
58
|
+
const eventBusWirings = generationOptions.events
|
|
59
|
+
? [eventBusPortWiring("make resource --events")]
|
|
60
|
+
: [];
|
|
61
|
+
const plannedEventBusUpdates = eventBusWirings.length > 0
|
|
62
|
+
? (await wirePortProviders(targetDir, config, eventBusWirings, {
|
|
63
|
+
dryRun: true,
|
|
64
|
+
})).updatedFiles
|
|
65
|
+
: [];
|
|
53
66
|
const createdFiles = plannedFiles
|
|
54
67
|
.filter((file) => file.result === "created")
|
|
55
68
|
.map((file) => file.path);
|
|
@@ -60,7 +73,7 @@ async function makeResourceSlice(options, mode) {
|
|
|
60
73
|
.filter((file) => file.result === "skipped")
|
|
61
74
|
.map((file) => file.path);
|
|
62
75
|
if (options.dryRun) {
|
|
63
|
-
updatedFiles.push(...plannedWiringUpdates);
|
|
76
|
+
updatedFiles.push(...plannedWiringUpdates, ...plannedEventBusUpdates);
|
|
64
77
|
}
|
|
65
78
|
else {
|
|
66
79
|
for (const file of plannedFiles) {
|
|
@@ -72,6 +85,11 @@ async function makeResourceSlice(options, mode) {
|
|
|
72
85
|
mode,
|
|
73
86
|
generationOptions,
|
|
74
87
|
})));
|
|
88
|
+
if (eventBusWirings.length > 0) {
|
|
89
|
+
updatedFiles.push(...(await wirePortProviders(targetDir, config, eventBusWirings, {
|
|
90
|
+
dryRun: false,
|
|
91
|
+
})).updatedFiles);
|
|
92
|
+
}
|
|
75
93
|
}
|
|
76
94
|
return {
|
|
77
95
|
schemaVersion: 1,
|
|
@@ -80,7 +98,7 @@ async function makeResourceSlice(options, mode) {
|
|
|
80
98
|
dryRun: Boolean(options.dryRun),
|
|
81
99
|
files: generatedFiles.map((file) => file.path),
|
|
82
100
|
createdFiles,
|
|
83
|
-
updatedFiles,
|
|
101
|
+
updatedFiles: uniqueStrings(updatedFiles),
|
|
84
102
|
skippedFiles,
|
|
85
103
|
};
|
|
86
104
|
}
|
|
@@ -416,7 +434,15 @@ export async function makeEvent(options) {
|
|
|
416
434
|
? resolveConfig(options.config)
|
|
417
435
|
: await loadBeignetConfig(targetDir);
|
|
418
436
|
await assertFeatureArtifactApp(targetDir, config, "event");
|
|
419
|
-
|
|
437
|
+
// Events are published through ctx.ports.eventBus, so the generator wires
|
|
438
|
+
// the port and an in-memory dev provider when the app has no bus yet. Plan
|
|
439
|
+
// the wiring before writing any files so an anchor miss aborts the
|
|
440
|
+
// generator without leaving partial output.
|
|
441
|
+
const eventBusWirings = [eventBusPortWiring("make event")];
|
|
442
|
+
await wirePortProviders(targetDir, config, eventBusWirings, {
|
|
443
|
+
dryRun: true,
|
|
444
|
+
});
|
|
445
|
+
const result = await makeFeatureArtifact({
|
|
420
446
|
targetDir,
|
|
421
447
|
config,
|
|
422
448
|
force: Boolean(options.force),
|
|
@@ -428,6 +454,13 @@ export async function makeEvent(options) {
|
|
|
428
454
|
"@beignet/core": beignetDependencyVersion,
|
|
429
455
|
},
|
|
430
456
|
});
|
|
457
|
+
await applyOutboxRegistryUpdate(result, targetDir, names, "events", config, {
|
|
458
|
+
dryRun: Boolean(options.dryRun),
|
|
459
|
+
});
|
|
460
|
+
await applyPortProviderWiring(result, targetDir, config, eventBusWirings, {
|
|
461
|
+
dryRun: Boolean(options.dryRun),
|
|
462
|
+
});
|
|
463
|
+
return result;
|
|
431
464
|
}
|
|
432
465
|
export async function makeJob(options) {
|
|
433
466
|
const targetDir = path.resolve(options.cwd ?? process.cwd());
|
|
@@ -436,7 +469,7 @@ export async function makeJob(options) {
|
|
|
436
469
|
? resolveConfig(options.config)
|
|
437
470
|
: await loadBeignetConfig(targetDir);
|
|
438
471
|
await assertFeatureArtifactApp(targetDir, config, "job");
|
|
439
|
-
|
|
472
|
+
const result = await makeFeatureArtifact({
|
|
440
473
|
targetDir,
|
|
441
474
|
config,
|
|
442
475
|
force: Boolean(options.force),
|
|
@@ -451,6 +484,10 @@ export async function makeJob(options) {
|
|
|
451
484
|
"@beignet/core": beignetDependencyVersion,
|
|
452
485
|
},
|
|
453
486
|
});
|
|
487
|
+
await applyOutboxRegistryUpdate(result, targetDir, names, "jobs", config, {
|
|
488
|
+
dryRun: Boolean(options.dryRun),
|
|
489
|
+
});
|
|
490
|
+
return result;
|
|
454
491
|
}
|
|
455
492
|
export async function makeTask(options) {
|
|
456
493
|
const targetDir = path.resolve(options.cwd ?? process.cwd());
|
|
@@ -535,7 +572,18 @@ export async function makeNotification(options) {
|
|
|
535
572
|
? resolveConfig(options.config)
|
|
536
573
|
: await loadBeignetConfig(targetDir);
|
|
537
574
|
await assertFeatureArtifactApp(targetDir, config, "notification");
|
|
538
|
-
|
|
575
|
+
// The generated mail channel sends through ctx.ports.mailer and sending
|
|
576
|
+
// notifications uses ctx.ports.notifications, so the generator wires both
|
|
577
|
+
// ports with dev-default providers. Each port is wired independently and
|
|
578
|
+
// skipped when the app already has it, for example when the resend
|
|
579
|
+
// integration contributed the mailer. Plan the wiring before writing any
|
|
580
|
+
// files so an anchor miss aborts the generator without leaving partial
|
|
581
|
+
// output.
|
|
582
|
+
const notificationWirings = notificationPortWirings("make notification");
|
|
583
|
+
await wirePortProviders(targetDir, config, notificationWirings, {
|
|
584
|
+
dryRun: true,
|
|
585
|
+
});
|
|
586
|
+
const result = await makeFeatureArtifact({
|
|
539
587
|
targetDir,
|
|
540
588
|
config,
|
|
541
589
|
force: Boolean(options.force),
|
|
@@ -550,6 +598,8 @@ export async function makeNotification(options) {
|
|
|
550
598
|
"@beignet/core": beignetDependencyVersion,
|
|
551
599
|
},
|
|
552
600
|
});
|
|
601
|
+
await applyPortProviderWiring(result, targetDir, config, notificationWirings, { dryRun: Boolean(options.dryRun) });
|
|
602
|
+
return result;
|
|
553
603
|
}
|
|
554
604
|
export async function makeListener(options) {
|
|
555
605
|
const targetDir = path.resolve(options.cwd ?? process.cwd());
|
|
@@ -712,6 +762,150 @@ async function applyCronSecretWiring(targetDir, plan, options) {
|
|
|
712
762
|
skippedFiles: plan.skippedFiles,
|
|
713
763
|
};
|
|
714
764
|
}
|
|
765
|
+
function eventBusPortWiring(command) {
|
|
766
|
+
return {
|
|
767
|
+
command,
|
|
768
|
+
portKey: "eventBus",
|
|
769
|
+
portType: "EventBusPort",
|
|
770
|
+
portTypeModule: "@beignet/core/ports",
|
|
771
|
+
providerFactory: "createInMemoryEventBusProvider",
|
|
772
|
+
providerModule: "@beignet/provider-event-bus-memory",
|
|
773
|
+
dependency: "@beignet/provider-event-bus-memory",
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function notificationPortWirings(command) {
|
|
777
|
+
return [
|
|
778
|
+
{
|
|
779
|
+
command,
|
|
780
|
+
portKey: "mailer",
|
|
781
|
+
portType: "MailerPort",
|
|
782
|
+
portTypeModule: "@beignet/core/mail",
|
|
783
|
+
providerFactory: "createMemoryMailerProvider",
|
|
784
|
+
providerModule: "@beignet/core/mail",
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
command,
|
|
788
|
+
portKey: "notifications",
|
|
789
|
+
portType: "NotificationPort",
|
|
790
|
+
portTypeModule: "@beignet/core/notifications",
|
|
791
|
+
providerFactory: "createInlineNotificationsProvider",
|
|
792
|
+
providerModule: "@beignet/core/notifications",
|
|
793
|
+
},
|
|
794
|
+
];
|
|
795
|
+
}
|
|
796
|
+
function providersFilePath(config) {
|
|
797
|
+
return `${directoryPath(path.dirname(config.paths.server))}/providers.ts`;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Wire provider-backed app ports a generator depends on.
|
|
801
|
+
*
|
|
802
|
+
* Each wiring is independent and skipped silently when its port key already
|
|
803
|
+
* appears in the ports file, so apps that wired their own adapter (or scaffolds
|
|
804
|
+
* whose integrations already contribute the port) are left untouched. All
|
|
805
|
+
* anchors are computed before any file is written; an anchor miss aborts with a
|
|
806
|
+
* copy-pasteable manual instruction so the generator never leaves partial
|
|
807
|
+
* wiring behind. Callers validate anchors with `dryRun: true` before writing
|
|
808
|
+
* artifact files.
|
|
809
|
+
*/
|
|
810
|
+
async function wirePortProviders(targetDir, config, wirings, options) {
|
|
811
|
+
const portsFile = config.paths.ports;
|
|
812
|
+
const infrastructureFile = config.paths.infrastructurePorts;
|
|
813
|
+
const providersFile = providersFilePath(config);
|
|
814
|
+
const manualFor = (wiring) => `Wire the ${wiring.portKey} port manually: add ${wiring.portKey}: ${wiring.portType}; to AppPorts in ${portsFile}, defer "${wiring.portKey}" in ${infrastructureFile}, and register ${wiring.providerFactory}() from ${wiring.providerModule} in ${providersFile}.`;
|
|
815
|
+
const portsOriginal = await readOptionalFile(path.join(targetDir, portsFile));
|
|
816
|
+
if (portsOriginal === undefined) {
|
|
817
|
+
if (wirings.length === 0)
|
|
818
|
+
return { updatedFiles: [] };
|
|
819
|
+
throw new Error(`Could not find the generated ports file ${portsFile}. ${manualFor(wirings[0])}`);
|
|
820
|
+
}
|
|
821
|
+
// A port key that already appears in the ports file means the app wired its
|
|
822
|
+
// own adapter or an integration already contributes the port.
|
|
823
|
+
const active = wirings.filter((wiring) => !new RegExp(`\\b${wiring.portKey}\\b`).test(portsOriginal));
|
|
824
|
+
if (active.length === 0)
|
|
825
|
+
return { updatedFiles: [] };
|
|
826
|
+
let portsNext = portsOriginal;
|
|
827
|
+
for (const wiring of active) {
|
|
828
|
+
portsNext = addNamedTypeImport(portsNext, wiring.portType, wiring.portTypeModule);
|
|
829
|
+
portsNext = insertTypeProperty(portsNext, "AppPorts", `${wiring.portKey}: ${wiring.portType};`, `Could not find AppPorts in ${portsFile}. ${manualFor(wiring)} Or restore the generated ports file before running beignet ${wiring.command}.`);
|
|
830
|
+
}
|
|
831
|
+
const infrastructureOriginal = await readOptionalFile(path.join(targetDir, infrastructureFile));
|
|
832
|
+
if (infrastructureOriginal === undefined) {
|
|
833
|
+
throw new Error(`Could not find the generated infrastructure ports file ${infrastructureFile}. ${manualFor(active[0])}`);
|
|
834
|
+
}
|
|
835
|
+
let infrastructureNext = infrastructureOriginal;
|
|
836
|
+
for (const wiring of active) {
|
|
837
|
+
const appended = appendDeferredPortKey(infrastructureNext, wiring.portKey);
|
|
838
|
+
if (appended === infrastructureNext &&
|
|
839
|
+
!new RegExp(`["']${wiring.portKey}["']`).test(infrastructureNext)) {
|
|
840
|
+
throw new Error(`Could not find the deferred port list in ${infrastructureFile}. ${manualFor(wiring)} Or restore the generated infrastructure ports file before running beignet ${wiring.command}.`);
|
|
841
|
+
}
|
|
842
|
+
infrastructureNext = appended;
|
|
843
|
+
}
|
|
844
|
+
const providersOriginal = await readOptionalFile(path.join(targetDir, providersFile));
|
|
845
|
+
if (providersOriginal === undefined) {
|
|
846
|
+
throw new Error(`Could not find the generated providers file ${providersFile}. ${manualFor(active[0])}`);
|
|
847
|
+
}
|
|
848
|
+
let providersNext = providersOriginal;
|
|
849
|
+
for (const wiring of active) {
|
|
850
|
+
if (new RegExp(`\\b${wiring.providerFactory}\\b`).test(providersNext)) {
|
|
851
|
+
continue;
|
|
852
|
+
}
|
|
853
|
+
const appended = appendToNamedArray(providersNext, "providers", `${wiring.providerFactory}()`, `import { ${wiring.providerFactory} } from "${wiring.providerModule}";`);
|
|
854
|
+
if (appended.kind === "missing") {
|
|
855
|
+
throw new Error(`Could not find the exported providers array in ${providersFile}. ${manualFor(wiring)} Or restore the generated providers file before running beignet ${wiring.command}.`);
|
|
856
|
+
}
|
|
857
|
+
if (appended.kind === "updated")
|
|
858
|
+
providersNext = appended.source;
|
|
859
|
+
}
|
|
860
|
+
const dependencies = active.filter((wiring) => wiring.dependency !== undefined);
|
|
861
|
+
let packageJsonNext;
|
|
862
|
+
if (dependencies.length > 0) {
|
|
863
|
+
const packageJsonOriginal = await readFile(path.join(targetDir, "package.json"), "utf8");
|
|
864
|
+
const packageJson = JSON.parse(packageJsonOriginal);
|
|
865
|
+
packageJson.dependencies = packageJson.dependencies ?? {};
|
|
866
|
+
for (const wiring of dependencies) {
|
|
867
|
+
packageJson.dependencies[wiring.dependency] ??=
|
|
868
|
+
beignetDependencyVersion(packageJson);
|
|
869
|
+
}
|
|
870
|
+
const next = `${JSON.stringify(packageJson, null, "\t")}\n`;
|
|
871
|
+
if (next !== packageJsonOriginal)
|
|
872
|
+
packageJsonNext = next;
|
|
873
|
+
}
|
|
874
|
+
const plannedFiles = [];
|
|
875
|
+
if (portsNext !== portsOriginal) {
|
|
876
|
+
plannedFiles.push({ path: portsFile, content: portsNext });
|
|
877
|
+
}
|
|
878
|
+
if (infrastructureNext !== infrastructureOriginal) {
|
|
879
|
+
plannedFiles.push({
|
|
880
|
+
path: infrastructureFile,
|
|
881
|
+
content: infrastructureNext,
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
if (providersNext !== providersOriginal) {
|
|
885
|
+
plannedFiles.push({ path: providersFile, content: providersNext });
|
|
886
|
+
}
|
|
887
|
+
if (packageJsonNext !== undefined) {
|
|
888
|
+
plannedFiles.push({ path: "package.json", content: packageJsonNext });
|
|
889
|
+
}
|
|
890
|
+
if (!options.dryRun) {
|
|
891
|
+
for (const file of plannedFiles) {
|
|
892
|
+
await writeFile(path.join(targetDir, file.path), file.content);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return { updatedFiles: plannedFiles.map((file) => file.path) };
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Record port provider wiring updates on a make result.
|
|
899
|
+
*/
|
|
900
|
+
async function applyPortProviderWiring(result, targetDir, config, wirings, options) {
|
|
901
|
+
const wired = await wirePortProviders(targetDir, config, wirings, options);
|
|
902
|
+
for (const file of wired.updatedFiles) {
|
|
903
|
+
if (!result.updatedFiles.includes(file))
|
|
904
|
+
result.updatedFiles.push(file);
|
|
905
|
+
if (!result.files.includes(file))
|
|
906
|
+
result.files.push(file);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
715
909
|
export async function makeUpload(options) {
|
|
716
910
|
const targetDir = path.resolve(options.cwd ?? process.cwd());
|
|
717
911
|
const names = uploadNames(options.name);
|
|
@@ -1635,49 +1829,6 @@ function trimmedSlice(source, start, end) {
|
|
|
1635
1829
|
end: trimmedEnd,
|
|
1636
1830
|
};
|
|
1637
1831
|
}
|
|
1638
|
-
function identifiersFromArrayExpression(expression) {
|
|
1639
|
-
const withoutBrackets = expression.replace(/^\[/, "").replace(/\]$/, "");
|
|
1640
|
-
return new Set(Array.from(withoutBrackets.matchAll(/\b[A-Za-z_$][\w$]*\b/g), ([name]) => name));
|
|
1641
|
-
}
|
|
1642
|
-
function appendToArrayExpression(expression, names) {
|
|
1643
|
-
const closingBracket = /\]\s*$/.exec(expression);
|
|
1644
|
-
if (!closingBracket)
|
|
1645
|
-
return expression;
|
|
1646
|
-
const beforeClosingBracket = expression.slice(0, closingBracket.index);
|
|
1647
|
-
const closingBracketText = expression.slice(closingBracket.index);
|
|
1648
|
-
const inner = beforeClosingBracket.replace(/^\[/, "");
|
|
1649
|
-
if (!inner.trim())
|
|
1650
|
-
return `[${names.join(", ")}]`;
|
|
1651
|
-
if (!expression.includes("\n")) {
|
|
1652
|
-
const separator = /,\s*$/.test(inner) ? " " : ", ";
|
|
1653
|
-
return `${beforeClosingBracket}${separator}${names.join(", ")}${closingBracketText}`;
|
|
1654
|
-
}
|
|
1655
|
-
const itemIndent = inner
|
|
1656
|
-
.split("\n")
|
|
1657
|
-
.find((line) => line.trim())
|
|
1658
|
-
?.match(/^[\t ]*/)?.[0] ?? "\t";
|
|
1659
|
-
const closingIndent = inner.match(/\n([\t ]*)$/)?.[1] ?? "";
|
|
1660
|
-
const trimmedBeforeClosingBracket = beforeClosingBracket.replace(/\s*$/, "");
|
|
1661
|
-
const appendedNames = names.join(`,\n${itemIndent}`);
|
|
1662
|
-
if (/,\s*$/.test(inner)) {
|
|
1663
|
-
return `${trimmedBeforeClosingBracket}\n${itemIndent}${appendedNames},\n${closingIndent}${closingBracketText}`;
|
|
1664
|
-
}
|
|
1665
|
-
return `${trimmedBeforeClosingBracket},\n${itemIndent}${appendedNames}${closingBracketText}`;
|
|
1666
|
-
}
|
|
1667
|
-
function insertAfterImports(source, line) {
|
|
1668
|
-
const lines = source.split("\n");
|
|
1669
|
-
let lastImportIndex = -1;
|
|
1670
|
-
for (let index = 0; index < lines.length; index++) {
|
|
1671
|
-
if (lines[index].startsWith("import ")) {
|
|
1672
|
-
lastImportIndex = index;
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
if (lastImportIndex === -1) {
|
|
1676
|
-
return `${line}\n${source}`;
|
|
1677
|
-
}
|
|
1678
|
-
lines.splice(lastImportIndex + 1, 0, line);
|
|
1679
|
-
return lines.join("\n");
|
|
1680
|
-
}
|
|
1681
1832
|
function replaceRequired(source, searchValue, replaceValue, message) {
|
|
1682
1833
|
const next = source.replace(searchValue, replaceValue);
|
|
1683
1834
|
if (next === source)
|
|
@@ -1855,6 +2006,35 @@ function appendDeferredPortKey(source, portKey) {
|
|
|
1855
2006
|
const nextTuple = appendToArrayExpression(tuple, [`"${portKey}"`]);
|
|
1856
2007
|
return `${source.slice(0, arrayStart)}${nextTuple}${source.slice(arrayEnd + 1)}`;
|
|
1857
2008
|
}
|
|
2009
|
+
/**
|
|
2010
|
+
* Add a name to an `import type { ... } from "<module>";` statement, creating
|
|
2011
|
+
* the import when the module is not imported yet. Names are inserted in sorted
|
|
2012
|
+
* position and single-line versus multiline formatting is preserved.
|
|
2013
|
+
*/
|
|
2014
|
+
function addNamedTypeImport(source, name, moduleName) {
|
|
2015
|
+
const escapedModule = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2016
|
+
const importPattern = new RegExp(`import type \\{([^}]*)\\} from "${escapedModule}";`);
|
|
2017
|
+
const match = importPattern.exec(source);
|
|
2018
|
+
if (!match) {
|
|
2019
|
+
return insertAfterImports(source, `import type { ${name} } from "${moduleName}";`);
|
|
2020
|
+
}
|
|
2021
|
+
const names = match[1]
|
|
2022
|
+
.split(",")
|
|
2023
|
+
.map((entry) => entry.trim())
|
|
2024
|
+
.filter(Boolean);
|
|
2025
|
+
if (names.includes(name))
|
|
2026
|
+
return source;
|
|
2027
|
+
const insertIndex = names.findIndex((existing) => existing.localeCompare(name) > 0);
|
|
2028
|
+
if (insertIndex === -1)
|
|
2029
|
+
names.push(name);
|
|
2030
|
+
else
|
|
2031
|
+
names.splice(insertIndex, 0, name);
|
|
2032
|
+
const indent = match[1].match(/\n([\t ]+)/)?.[1] ?? "\t";
|
|
2033
|
+
const replacement = match[1].includes("\n")
|
|
2034
|
+
? `import type {\n${indent}${names.join(`,\n${indent}`)},\n} from "${moduleName}";`
|
|
2035
|
+
: `import type { ${names.join(", ")} } from "${moduleName}";`;
|
|
2036
|
+
return `${source.slice(0, match.index)}${replacement}${source.slice(match.index + match[0].length)}`;
|
|
2037
|
+
}
|
|
1858
2038
|
function topLevelBoundObjectRange(source, openBrace, closeBrace) {
|
|
1859
2039
|
const body = source.slice(openBrace + 1, closeBrace);
|
|
1860
2040
|
if (!hasTopLevelObjectProperty(body, "bound"))
|
|
@@ -2022,40 +2202,6 @@ function detectPropertyIndent(body) {
|
|
|
2022
2202
|
function matchingBraceIndex(source, openBrace) {
|
|
2023
2203
|
return matchingDelimiterIndex(source, openBrace, "{", "}");
|
|
2024
2204
|
}
|
|
2025
|
-
function matchingDelimiterIndex(source, openIndex, open, close) {
|
|
2026
|
-
let depth = 0;
|
|
2027
|
-
let inString;
|
|
2028
|
-
let escaped = false;
|
|
2029
|
-
for (let index = openIndex; index < source.length; index++) {
|
|
2030
|
-
const char = source[index];
|
|
2031
|
-
if (inString) {
|
|
2032
|
-
if (escaped) {
|
|
2033
|
-
escaped = false;
|
|
2034
|
-
}
|
|
2035
|
-
else if (char === "\\") {
|
|
2036
|
-
escaped = true;
|
|
2037
|
-
}
|
|
2038
|
-
else if (char === inString) {
|
|
2039
|
-
inString = undefined;
|
|
2040
|
-
}
|
|
2041
|
-
continue;
|
|
2042
|
-
}
|
|
2043
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
2044
|
-
inString = char;
|
|
2045
|
-
continue;
|
|
2046
|
-
}
|
|
2047
|
-
if (char === open) {
|
|
2048
|
-
depth++;
|
|
2049
|
-
continue;
|
|
2050
|
-
}
|
|
2051
|
-
if (char === close) {
|
|
2052
|
-
depth--;
|
|
2053
|
-
if (depth === 0)
|
|
2054
|
-
return index;
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
return -1;
|
|
2058
|
-
}
|
|
2059
2205
|
function replaceTransactionPortsRequired(source, entry, message) {
|
|
2060
2206
|
return insertTypeProperty(source, "AppTransactionPorts", entry.trim(), message);
|
|
2061
2207
|
}
|
|
@@ -3135,21 +3281,46 @@ export async function stopScheduleContext(): Promise<void> {
|
|
|
3135
3281
|
await writeFile(destination, next);
|
|
3136
3282
|
return "updated";
|
|
3137
3283
|
}
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3284
|
+
/**
|
|
3285
|
+
* Append a feature event or job registry to `server/outbox.ts`.
|
|
3286
|
+
*
|
|
3287
|
+
* The outbox registry is opt-in, so this never creates the file; it returns
|
|
3288
|
+
* `undefined` when the app has no outbox module. It also bails to "skipped"
|
|
3289
|
+
* instead of writing when the `defineOutboxRegistry({...})` anchor is missing
|
|
3290
|
+
* or the matching array is not editable.
|
|
3291
|
+
*/
|
|
3292
|
+
async function updateOutboxRegistry(targetDir, names, kind, config, options) {
|
|
3293
|
+
const destination = path.join(targetDir, config.paths.outbox);
|
|
3294
|
+
const existing = await readOptionalFile(destination);
|
|
3295
|
+
if (existing === undefined)
|
|
3147
3296
|
return undefined;
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3297
|
+
const featureIndexPath = path.join(featureArtifactDir(names, kind, config), "index.ts");
|
|
3298
|
+
const registryName = `${names.featureSingularCamel}${kind === "events" ? "Events" : "Jobs"}`;
|
|
3299
|
+
const importLine = `import { ${registryName} } from "${aliasModule(featureIndexPath)}";`;
|
|
3300
|
+
const appended = appendToOutboxRegistryArray(existing, kind, `...${registryName}`, importLine);
|
|
3301
|
+
if (appended.kind === "missing" || appended.kind === "unchanged") {
|
|
3302
|
+
return "skipped";
|
|
3303
|
+
}
|
|
3304
|
+
if (!options.dryRun)
|
|
3305
|
+
await writeFile(destination, appended.source);
|
|
3306
|
+
return "updated";
|
|
3307
|
+
}
|
|
3308
|
+
/**
|
|
3309
|
+
* Record an outbox registry update on a make result using the same
|
|
3310
|
+
* bookkeeping as the task and schedule registries. No-op when the app has no
|
|
3311
|
+
* outbox module.
|
|
3312
|
+
*/
|
|
3313
|
+
async function applyOutboxRegistryUpdate(result, targetDir, names, kind, config, options) {
|
|
3314
|
+
const registryResult = await updateOutboxRegistry(targetDir, names, kind, config, options);
|
|
3315
|
+
if (registryResult === undefined)
|
|
3316
|
+
return;
|
|
3317
|
+
if (registryResult === "updated")
|
|
3318
|
+
result.updatedFiles.push(config.paths.outbox);
|
|
3319
|
+
if (registryResult === "skipped")
|
|
3320
|
+
result.skippedFiles.push(config.paths.outbox);
|
|
3321
|
+
if (!result.files.includes(config.paths.outbox)) {
|
|
3322
|
+
result.files.push(config.paths.outbox);
|
|
3323
|
+
}
|
|
3153
3324
|
}
|
|
3154
3325
|
function defineUploadsInitializerInfo(source, constName) {
|
|
3155
3326
|
const match = new RegExp(`\\bconst\\s+${constName}\\s*=\\s*defineUploads\\s*\\(`).exec(source);
|