@beignet/cli 0.0.47 → 0.0.49
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 +46 -0
- package/README.md +126 -42
- package/dist/analysis/contract-factories.d.ts +17 -0
- package/dist/analysis/contract-factories.d.ts.map +1 -0
- package/dist/analysis/contract-factories.js +176 -0
- package/dist/analysis/contract-factories.js.map +1 -0
- package/dist/analysis/layers.d.ts +5 -0
- package/dist/analysis/layers.d.ts.map +1 -0
- package/dist/analysis/layers.js +172 -0
- package/dist/analysis/layers.js.map +1 -0
- package/dist/analysis/port-wiring.d.ts +23 -0
- package/dist/analysis/port-wiring.d.ts.map +1 -0
- package/dist/analysis/port-wiring.js +379 -0
- package/dist/analysis/port-wiring.js.map +1 -0
- package/dist/analysis/source-index.d.ts +5 -0
- package/dist/analysis/source-index.d.ts.map +1 -1
- package/dist/analysis/source-index.js +171 -42
- package/dist/analysis/source-index.js.map +1 -1
- package/dist/analysis/workspace.d.ts +10 -4
- package/dist/analysis/workspace.d.ts.map +1 -1
- package/dist/analysis/workspace.js +66 -6
- package/dist/analysis/workspace.js.map +1 -1
- package/dist/app-map.d.ts.map +1 -1
- package/dist/app-map.js +311 -92
- package/dist/app-map.js.map +1 -1
- package/dist/check.d.ts +8 -1
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +55 -9
- package/dist/check.js.map +1 -1
- package/dist/db.d.ts +38 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +52 -0
- package/dist/db.js.map +1 -1
- package/dist/explain.js +4 -4
- package/dist/explain.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +73 -6
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +454 -170
- package/dist/inspect.js.map +1 -1
- package/dist/lib.d.ts +2 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +309 -487
- package/dist/lint.js.map +1 -1
- package/dist/make/inbox.d.ts.map +1 -1
- package/dist/make/inbox.js +12 -5
- package/dist/make/inbox.js.map +1 -1
- package/dist/make/payments.js +3 -3
- package/dist/make/payments.js.map +1 -1
- package/dist/make/tenancy.js +1 -1
- package/dist/make/tenancy.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +144 -8
- package/dist/make.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +56 -19
- package/dist/mcp.js.map +1 -1
- package/dist/preflight.d.ts +11 -3
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +139 -16
- package/dist/preflight.js.map +1 -1
- package/dist/provider-add.d.ts.map +1 -1
- package/dist/provider-add.js +149 -9
- package/dist/provider-add.js.map +1 -1
- package/dist/provider-audit.d.ts +13 -0
- package/dist/provider-audit.d.ts.map +1 -1
- package/dist/provider-audit.js +122 -8
- package/dist/provider-audit.js.map +1 -1
- package/dist/registry-edits.d.ts +7 -0
- package/dist/registry-edits.d.ts.map +1 -1
- package/dist/registry-edits.js +237 -53
- package/dist/registry-edits.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +29 -7
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.d.ts +1 -0
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +20 -6
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/db/index.d.ts +1 -0
- package/dist/templates/db/index.d.ts.map +1 -1
- package/dist/templates/db/index.js.map +1 -1
- package/dist/templates/db/migration-status.d.ts +9 -0
- package/dist/templates/db/migration-status.d.ts.map +1 -0
- package/dist/templates/db/migration-status.js +117 -0
- package/dist/templates/db/migration-status.js.map +1 -0
- package/dist/templates/db/mysql.d.ts.map +1 -1
- package/dist/templates/db/mysql.js +23 -0
- package/dist/templates/db/mysql.js.map +1 -1
- package/dist/templates/db/postgres.d.ts.map +1 -1
- package/dist/templates/db/postgres.js +21 -0
- package/dist/templates/db/postgres.js.map +1 -1
- package/dist/templates/db/sqlite.d.ts.map +1 -1
- package/dist/templates/db/sqlite.js +53 -0
- package/dist/templates/db/sqlite.js.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +5 -0
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +2 -0
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.d.ts +1 -0
- package/dist/templates/shared.d.ts.map +1 -1
- package/dist/templates/shared.js +4 -2
- package/dist/templates/shared.js.map +1 -1
- package/package.json +7 -6
- package/skills/app-structure/SKILL.md +56 -11
- package/src/analysis/contract-factories.ts +256 -0
- package/src/analysis/layers.ts +266 -0
- package/src/analysis/port-wiring.ts +506 -0
- package/src/analysis/source-index.ts +225 -57
- package/src/analysis/workspace.ts +115 -6
- package/src/app-map.ts +418 -109
- package/src/check.ts +86 -10
- package/src/db.ts +97 -0
- package/src/explain.ts +4 -4
- package/src/index.ts +108 -7
- package/src/inspect.ts +659 -216
- package/src/lib.ts +9 -1
- package/src/lint.ts +393 -643
- package/src/make/inbox.ts +12 -5
- package/src/make/payments.ts +3 -3
- package/src/make/tenancy.ts +1 -1
- package/src/make.ts +225 -8
- package/src/mcp.ts +73 -21
- package/src/preflight.ts +195 -16
- package/src/provider-add.ts +193 -9
- package/src/provider-audit.ts +210 -18
- package/src/registry-edits.ts +313 -63
- package/src/templates/agents.ts +29 -7
- package/src/templates/base.ts +21 -4
- package/src/templates/db/index.ts +1 -0
- package/src/templates/db/migration-status.ts +126 -0
- package/src/templates/db/mysql.ts +23 -0
- package/src/templates/db/postgres.ts +21 -0
- package/src/templates/db/sqlite.ts +53 -0
- package/src/templates/index.ts +5 -0
- package/src/templates/server.ts +2 -0
- package/src/templates/shared.ts +4 -2
package/dist/app-map.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import ts from "typescript";
|
|
3
|
+
import { contractBindingNames, contractFactoryBindings, isImportedContractDeclaration, } from "./analysis/contract-factories.js";
|
|
4
|
+
import { analyzePortWiring } from "./analysis/port-wiring.js";
|
|
3
5
|
import { createSourceIndex, exportedVariableDeclarations, literalText, localImportReferences, propertyAssignment, propertyName, visitCalls, } from "./analysis/source-index.js";
|
|
4
6
|
import { createAnalysisWorkspace, } from "./analysis/workspace.js";
|
|
5
7
|
import { directoryPath } from "./config.js";
|
|
@@ -287,6 +289,20 @@ export async function mapApp(options = {}) {
|
|
|
287
289
|
if (registry) {
|
|
288
290
|
addNode(registry.node);
|
|
289
291
|
registries.push(registry);
|
|
292
|
+
if (registry.outbox?.eventsIndeterminate) {
|
|
293
|
+
unresolved.push({
|
|
294
|
+
code: "outbox_events_unresolved",
|
|
295
|
+
message: `Could not resolve the events entries for outbox registry ${exportName}.`,
|
|
296
|
+
source: registry.node.source,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (registry.outbox?.jobsIndeterminate) {
|
|
300
|
+
unresolved.push({
|
|
301
|
+
code: "outbox_jobs_unresolved",
|
|
302
|
+
message: `Could not resolve the jobs entries for outbox registry ${exportName}.`,
|
|
303
|
+
source: registry.node.source,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
290
306
|
}
|
|
291
307
|
}
|
|
292
308
|
}
|
|
@@ -402,6 +418,17 @@ export async function mapApp(options = {}) {
|
|
|
402
418
|
sourceIndex,
|
|
403
419
|
addNode,
|
|
404
420
|
addEdge,
|
|
421
|
+
unresolved,
|
|
422
|
+
});
|
|
423
|
+
await addOutboxDeliveryGraph({
|
|
424
|
+
workspace,
|
|
425
|
+
sourceIndex,
|
|
426
|
+
registries,
|
|
427
|
+
nodes,
|
|
428
|
+
edges,
|
|
429
|
+
addNode,
|
|
430
|
+
addEdge,
|
|
431
|
+
unresolved,
|
|
405
432
|
});
|
|
406
433
|
await addTables({ workspace, sourceIndex, addNode });
|
|
407
434
|
await addUnresolvedLocalImports({ workspace, unresolved });
|
|
@@ -657,45 +684,51 @@ async function addPorts(args) {
|
|
|
657
684
|
if (!args.workspace.fileSet.has(portsFile))
|
|
658
685
|
return;
|
|
659
686
|
const sourceFile = await args.workspace.readSourceFile(portsFile);
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
687
|
+
const analysis = await analyzePortWiring(args.workspace);
|
|
688
|
+
if (analysis.declarationIndeterminate) {
|
|
689
|
+
args.unresolved.push({
|
|
690
|
+
code: "app_ports_declaration_unresolved",
|
|
691
|
+
message: `Could not fully resolve AppPorts in ${portsFile}.`,
|
|
692
|
+
source: { file: portsFile },
|
|
693
|
+
});
|
|
665
694
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
const feature =
|
|
695
|
+
if (analysis.indeterminate) {
|
|
696
|
+
args.unresolved.push({
|
|
697
|
+
code: "port_wiring_unresolved",
|
|
698
|
+
message: `Could not fully resolve port bindings in ${args.workspace.config.paths.portWiring}.`,
|
|
699
|
+
source: { file: args.workspace.config.paths.portWiring },
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
for (const name of analysis.declared) {
|
|
703
|
+
const property = analysis.properties.get(name);
|
|
704
|
+
const feature = property
|
|
705
|
+
? await portFeature(property.type, portsFile, args.workspace.config.paths.features, args.sourceIndex)
|
|
706
|
+
: undefined;
|
|
676
707
|
const id = portId(name);
|
|
677
708
|
args.addNode({
|
|
678
709
|
id,
|
|
679
710
|
kind: "port",
|
|
680
711
|
name,
|
|
681
712
|
...(feature ? { feature } : {}),
|
|
682
|
-
source:
|
|
683
|
-
|
|
713
|
+
source: property
|
|
714
|
+
? await args.sourceIndex.sourceLocation(portsFile, property)
|
|
715
|
+
: { file: args.workspace.config.paths.portWiring },
|
|
716
|
+
status: analysis.bound.has(name) || analysis.deferred.has(name)
|
|
684
717
|
? "registered"
|
|
685
718
|
: "missing",
|
|
686
719
|
details: {
|
|
687
|
-
binding:
|
|
720
|
+
binding: analysis.bound.has(name)
|
|
688
721
|
? "bound"
|
|
689
|
-
:
|
|
722
|
+
: analysis.deferred.has(name)
|
|
690
723
|
? "deferred"
|
|
691
724
|
: "unresolved",
|
|
692
|
-
type: property.type
|
|
725
|
+
...(property?.type ? { type: property.type.getText(sourceFile) } : {}),
|
|
693
726
|
},
|
|
694
727
|
});
|
|
695
728
|
if (feature) {
|
|
696
729
|
args.addEdge(exactEdge("owns", featureId(feature), id, portsFile));
|
|
697
730
|
}
|
|
698
|
-
if (
|
|
731
|
+
if (analysis.bound.has(name)) {
|
|
699
732
|
const bindingId = `provider:app:${name}`;
|
|
700
733
|
args.addNode({
|
|
701
734
|
id: bindingId,
|
|
@@ -709,6 +742,128 @@ async function addPorts(args) {
|
|
|
709
742
|
}
|
|
710
743
|
}
|
|
711
744
|
}
|
|
745
|
+
async function addOutboxDeliveryGraph(args) {
|
|
746
|
+
const outboxRegistries = args.registries.filter((registry) => registry.outbox !== undefined);
|
|
747
|
+
if (outboxRegistries.length === 0)
|
|
748
|
+
return;
|
|
749
|
+
const jobRegistries = outboxRegistries.filter((registry) => registry.outbox && registry.outbox.jobs.length > 0);
|
|
750
|
+
const jobsPortId = portId("jobs");
|
|
751
|
+
if (jobRegistries.length > 0 && !args.nodes.has(jobsPortId)) {
|
|
752
|
+
args.addNode({
|
|
753
|
+
id: jobsPortId,
|
|
754
|
+
kind: "port",
|
|
755
|
+
name: "jobs",
|
|
756
|
+
source: { file: args.workspace.config.paths.ports },
|
|
757
|
+
status: "missing",
|
|
758
|
+
details: {
|
|
759
|
+
binding: "unresolved",
|
|
760
|
+
requiredBy: "outbox-jobs",
|
|
761
|
+
},
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
for (const registry of jobRegistries) {
|
|
765
|
+
args.addEdge(exactEdge("depends-on", registry.node.id, jobsPortId, registry.file));
|
|
766
|
+
for (const jobId of registeredJobIds(registry.node.id, args.nodes, args.edges)) {
|
|
767
|
+
args.addEdge(exactEdge("depends-on", jobId, jobsPortId, registry.file));
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
const runtimeDirectories = new Set([
|
|
771
|
+
directoryPath(args.workspace.config.paths.routes),
|
|
772
|
+
directoryPath(args.workspace.config.paths.server),
|
|
773
|
+
directoryPath(args.workspace.config.paths.outbox),
|
|
774
|
+
directoryPath(args.workspace.config.paths.portWiring),
|
|
775
|
+
"server",
|
|
776
|
+
"infra",
|
|
777
|
+
]);
|
|
778
|
+
for (const file of args.workspace.files) {
|
|
779
|
+
if (!isTypeScriptSource(file) ||
|
|
780
|
+
isTestFile(file) ||
|
|
781
|
+
![...runtimeDirectories].some((directory) => directory === "." ||
|
|
782
|
+
file === directory ||
|
|
783
|
+
file.startsWith(`${directory}/`))) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
const sourceFile = await args.workspace.readSourceFile(file);
|
|
787
|
+
const providerLifecycle = isProviderLifecycleSource(file, sourceFile);
|
|
788
|
+
const calls = [];
|
|
789
|
+
visitCalls(sourceFile, (call) => {
|
|
790
|
+
const name = callMemberName(call);
|
|
791
|
+
if (name === "createOutboxDrainRoute" ||
|
|
792
|
+
(name === "drainOutbox" && !providerLifecycle)) {
|
|
793
|
+
calls.push(call);
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
for (const [index, call] of calls.entries()) {
|
|
797
|
+
const id = `entrypoint:${file}#outbox-drain${index === 0 ? "" : `-${index + 1}`}`;
|
|
798
|
+
args.addNode({
|
|
799
|
+
id,
|
|
800
|
+
kind: "entrypoint",
|
|
801
|
+
name: `${file} outbox drain`,
|
|
802
|
+
source: await args.sourceIndex.sourceLocation(file, call),
|
|
803
|
+
status: "registered",
|
|
804
|
+
details: { type: "outbox-drain" },
|
|
805
|
+
});
|
|
806
|
+
const options = call.arguments[0];
|
|
807
|
+
const registryExpression = options && ts.isObjectLiteralExpression(unwrapExpression(options))
|
|
808
|
+
? objectPropertyExpressionAnalysis(unwrapExpression(options), "registry").value
|
|
809
|
+
: undefined;
|
|
810
|
+
const reference = registryExpression
|
|
811
|
+
? await args.sourceIndex.resolveExpression(file, registryExpression)
|
|
812
|
+
: undefined;
|
|
813
|
+
const resolvedRegistry = reference
|
|
814
|
+
? outboxRegistries.find((registry) => registry.file === reference.file &&
|
|
815
|
+
registry.node.source.exportName === reference.exportName)
|
|
816
|
+
: outboxRegistries.length === 1
|
|
817
|
+
? outboxRegistries[0]
|
|
818
|
+
: undefined;
|
|
819
|
+
if (resolvedRegistry) {
|
|
820
|
+
args.addEdge(sourceNodeEdge("depends-on", id, resolvedRegistry.node.id, file, registryExpression ?? call));
|
|
821
|
+
if (resolvedRegistry.outbox?.jobs.length) {
|
|
822
|
+
args.addEdge(sourceNodeEdge("depends-on", id, jobsPortId, file, call));
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
else {
|
|
826
|
+
args.unresolved.push({
|
|
827
|
+
code: "outbox_drain_registry_unresolved",
|
|
828
|
+
message: `Could not resolve the outbox registry used by a drain in ${file}.`,
|
|
829
|
+
source: await args.sourceIndex.sourceLocation(file, call),
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
function isProviderLifecycleSource(file, sourceFile) {
|
|
836
|
+
if (/(^|\/)provider(s)?\.ts$/.test(file) ||
|
|
837
|
+
/(^|\/)[^/]*provider[^/]*\.ts$/.test(file) ||
|
|
838
|
+
/(^|\/)providers?\//.test(file)) {
|
|
839
|
+
return true;
|
|
840
|
+
}
|
|
841
|
+
let providerCall = false;
|
|
842
|
+
visitCalls(sourceFile, (call) => {
|
|
843
|
+
if (callMemberName(call) === "createProvider")
|
|
844
|
+
providerCall = true;
|
|
845
|
+
});
|
|
846
|
+
return providerCall;
|
|
847
|
+
}
|
|
848
|
+
function registeredJobIds(registryId, nodes, edges) {
|
|
849
|
+
const visited = new Set([registryId]);
|
|
850
|
+
let frontier = [registryId];
|
|
851
|
+
while (frontier.length > 0) {
|
|
852
|
+
const next = [];
|
|
853
|
+
for (const from of frontier) {
|
|
854
|
+
for (const edge of edges) {
|
|
855
|
+
if (edge.kind !== "registers" || edge.from !== from)
|
|
856
|
+
continue;
|
|
857
|
+
if (visited.has(edge.to))
|
|
858
|
+
continue;
|
|
859
|
+
visited.add(edge.to);
|
|
860
|
+
next.push(edge.to);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
frontier = next;
|
|
864
|
+
}
|
|
865
|
+
return [...visited].filter((id) => nodes.get(id)?.kind === "job").sort();
|
|
866
|
+
}
|
|
712
867
|
async function addOpenApiSurface(args) {
|
|
713
868
|
const file = args.workspace.config.paths.openapiRoute;
|
|
714
869
|
if (!args.workspace.fileSet.has(file))
|
|
@@ -847,14 +1002,15 @@ async function addUnresolvedLocalImports(args) {
|
|
|
847
1002
|
async function addUnresolvedContractDeclarations(args) {
|
|
848
1003
|
for (const file of appMapContractSourceFiles(args.workspace)) {
|
|
849
1004
|
const sourceFile = await args.workspace.readSourceFile(file);
|
|
1005
|
+
const factoryBindings = contractFactoryBindings(sourceFile);
|
|
1006
|
+
const bindingNames = contractBindingNames(sourceFile, factoryBindings);
|
|
850
1007
|
for (const { exportName, declaration } of exportedVariableDeclarations(sourceFile)) {
|
|
851
1008
|
if (args.contractIds.has(symbolKey(file, exportName)))
|
|
852
1009
|
continue;
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
: undefined;
|
|
856
|
-
if (!call)
|
|
1010
|
+
if (!declaration.initializer ||
|
|
1011
|
+
!isImportedContractDeclaration(declaration.initializer, factoryBindings, bindingNames)) {
|
|
857
1012
|
continue;
|
|
1013
|
+
}
|
|
858
1014
|
args.unresolved.push({
|
|
859
1015
|
code: "contract_declaration_unresolved",
|
|
860
1016
|
message: `Could not resolve the HTTP method and path for contract ${exportName}.`,
|
|
@@ -883,14 +1039,15 @@ async function registryRecord(args) {
|
|
|
883
1039
|
const initializer = args.declaration.initializer;
|
|
884
1040
|
if (!initializer)
|
|
885
1041
|
return undefined;
|
|
886
|
-
const
|
|
887
|
-
if (!
|
|
1042
|
+
const registry = registryValues(initializer, args.exportName);
|
|
1043
|
+
if (!registry)
|
|
888
1044
|
return undefined;
|
|
889
1045
|
const feature = featureForFile(args.file, directoryPath(args.workspace.config.paths.features));
|
|
890
1046
|
return {
|
|
891
1047
|
file: args.file,
|
|
892
1048
|
declaration: args.declaration,
|
|
893
|
-
values,
|
|
1049
|
+
values: registry.values,
|
|
1050
|
+
...(registry.outbox ? { outbox: registry.outbox } : {}),
|
|
894
1051
|
node: {
|
|
895
1052
|
id: registryId(args.file, args.exportName),
|
|
896
1053
|
kind: "registry",
|
|
@@ -898,13 +1055,20 @@ async function registryRecord(args) {
|
|
|
898
1055
|
...(feature ? { feature } : {}),
|
|
899
1056
|
source: await args.sourceIndex.sourceLocation(args.file, args.declaration, args.exportName),
|
|
900
1057
|
status: "registered",
|
|
1058
|
+
...(registry.outbox
|
|
1059
|
+
? {
|
|
1060
|
+
details: {
|
|
1061
|
+
registryType: "outbox",
|
|
1062
|
+
},
|
|
1063
|
+
}
|
|
1064
|
+
: {}),
|
|
901
1065
|
},
|
|
902
1066
|
};
|
|
903
1067
|
}
|
|
904
1068
|
function registryValues(initializer, exportName) {
|
|
905
1069
|
const expression = unwrapExpression(initializer);
|
|
906
1070
|
if (ts.isArrayLiteralExpression(expression) && isRegistryName(exportName)) {
|
|
907
|
-
return arrayExpressions(expression);
|
|
1071
|
+
return { values: arrayExpressions(expression) };
|
|
908
1072
|
}
|
|
909
1073
|
if (!ts.isCallExpression(expression))
|
|
910
1074
|
return undefined;
|
|
@@ -913,82 +1077,137 @@ function registryValues(initializer, exportName) {
|
|
|
913
1077
|
name === "defineNotificationRegistry" ||
|
|
914
1078
|
name === "defineAgentCapabilityRegistry") {
|
|
915
1079
|
const first = expression.arguments[0];
|
|
916
|
-
return
|
|
917
|
-
|
|
918
|
-
|
|
1080
|
+
return {
|
|
1081
|
+
values: first && ts.isArrayLiteralExpression(unwrapExpression(first))
|
|
1082
|
+
? arrayExpressions(unwrapExpression(first))
|
|
1083
|
+
: [],
|
|
1084
|
+
};
|
|
919
1085
|
}
|
|
920
|
-
if (name === "defineOutboxRegistry"
|
|
921
|
-
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1086
|
+
if (name === "defineOutboxRegistry") {
|
|
1087
|
+
const initializers = localVariableInitializers(expression.getSourceFile());
|
|
1088
|
+
const argument = expression.arguments[0];
|
|
1089
|
+
const object = argument
|
|
1090
|
+
? resolveRegistryExpression(argument, initializers)
|
|
1091
|
+
: undefined;
|
|
1092
|
+
if (!object || !ts.isObjectLiteralExpression(object)) {
|
|
1093
|
+
return {
|
|
1094
|
+
values: [],
|
|
1095
|
+
outbox: {
|
|
1096
|
+
events: [],
|
|
1097
|
+
jobs: [],
|
|
1098
|
+
eventsIndeterminate: true,
|
|
1099
|
+
jobsIndeterminate: true,
|
|
1100
|
+
},
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
const valuesFor = (property) => {
|
|
1104
|
+
const match = objectPropertyExpressionAnalysis(object, property);
|
|
1105
|
+
return {
|
|
1106
|
+
values: match.value
|
|
1107
|
+
? registryValueExpressions(match.value, initializers)
|
|
1108
|
+
: [],
|
|
1109
|
+
indeterminate: match.indeterminate,
|
|
1110
|
+
};
|
|
1111
|
+
};
|
|
1112
|
+
const events = valuesFor("events");
|
|
1113
|
+
const jobs = valuesFor("jobs");
|
|
1114
|
+
const outbox = {
|
|
1115
|
+
events: events.values,
|
|
1116
|
+
jobs: jobs.values,
|
|
1117
|
+
eventsIndeterminate: events.indeterminate,
|
|
1118
|
+
jobsIndeterminate: jobs.indeterminate,
|
|
1119
|
+
};
|
|
1120
|
+
return { values: [...outbox.events, ...outbox.jobs], outbox };
|
|
929
1121
|
}
|
|
930
1122
|
if (name === "defineUploads" &&
|
|
931
1123
|
ts.isObjectLiteralExpression(expression.arguments[0])) {
|
|
932
|
-
return
|
|
1124
|
+
return {
|
|
1125
|
+
values: expression.arguments[0].properties.flatMap((property) => ts.isPropertyAssignment(property) ? [property.initializer] : []),
|
|
1126
|
+
};
|
|
933
1127
|
}
|
|
934
1128
|
return undefined;
|
|
935
1129
|
}
|
|
936
|
-
function
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1130
|
+
function objectPropertyExpressionAnalysis(object, name) {
|
|
1131
|
+
let value;
|
|
1132
|
+
let indeterminate = false;
|
|
1133
|
+
for (const property of object.properties) {
|
|
1134
|
+
if (ts.isSpreadAssignment(property) || !property.name) {
|
|
1135
|
+
value = undefined;
|
|
1136
|
+
indeterminate = true;
|
|
1137
|
+
continue;
|
|
1138
|
+
}
|
|
1139
|
+
const propertyKey = propertyName(property.name);
|
|
1140
|
+
if (!propertyKey) {
|
|
1141
|
+
value = undefined;
|
|
1142
|
+
indeterminate = true;
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
if (propertyKey !== name)
|
|
1146
|
+
continue;
|
|
1147
|
+
if (ts.isPropertyAssignment(property)) {
|
|
1148
|
+
value = property.initializer;
|
|
1149
|
+
indeterminate = false;
|
|
1150
|
+
}
|
|
1151
|
+
else if (ts.isShorthandPropertyAssignment(property)) {
|
|
1152
|
+
value = property.name;
|
|
1153
|
+
indeterminate = false;
|
|
1154
|
+
}
|
|
1155
|
+
else {
|
|
1156
|
+
value = undefined;
|
|
1157
|
+
indeterminate = true;
|
|
1158
|
+
}
|
|
959
1159
|
}
|
|
960
|
-
return
|
|
1160
|
+
return { ...(value ? { value } : {}), indeterminate };
|
|
961
1161
|
}
|
|
962
|
-
|
|
963
|
-
const
|
|
964
|
-
const
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
if (!object?.properties.some((property) => property.name !== undefined &&
|
|
971
|
-
propertyName(property.name) === "bound")) {
|
|
972
|
-
return;
|
|
973
|
-
}
|
|
974
|
-
const bound = propertyAssignment(object, "bound")?.initializer;
|
|
975
|
-
if (bound && ts.isObjectLiteralExpression(bound)) {
|
|
976
|
-
for (const property of bound.properties) {
|
|
977
|
-
const name = property.name ? propertyName(property.name) : undefined;
|
|
978
|
-
if (name)
|
|
979
|
-
result.bound.add(name);
|
|
1162
|
+
function localVariableInitializers(sourceFile) {
|
|
1163
|
+
const initializers = new Map();
|
|
1164
|
+
for (const statement of sourceFile.statements) {
|
|
1165
|
+
if (!ts.isVariableStatement(statement))
|
|
1166
|
+
continue;
|
|
1167
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
1168
|
+
if (ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
1169
|
+
initializers.set(declaration.name.text, declaration.initializer);
|
|
980
1170
|
}
|
|
981
1171
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1172
|
+
}
|
|
1173
|
+
return initializers;
|
|
1174
|
+
}
|
|
1175
|
+
function resolveRegistryExpression(expression, initializers, visited = new Set()) {
|
|
1176
|
+
const current = unwrapExpression(expression);
|
|
1177
|
+
if (!ts.isIdentifier(current) || visited.has(current.text))
|
|
1178
|
+
return current;
|
|
1179
|
+
const initializer = initializers.get(current.text);
|
|
1180
|
+
if (!initializer)
|
|
1181
|
+
return current;
|
|
1182
|
+
const nextVisited = new Set(visited);
|
|
1183
|
+
nextVisited.add(current.text);
|
|
1184
|
+
return resolveRegistryExpression(initializer, initializers, nextVisited);
|
|
1185
|
+
}
|
|
1186
|
+
function registryValueExpressions(expression, initializers, visited = new Set()) {
|
|
1187
|
+
const current = unwrapExpression(expression);
|
|
1188
|
+
if (ts.isArrayLiteralExpression(current)) {
|
|
1189
|
+
return current.elements.flatMap((element) => ts.isSpreadElement(element)
|
|
1190
|
+
? registryValueExpressions(element.expression, initializers, new Set(visited))
|
|
1191
|
+
: ts.isExpression(element)
|
|
1192
|
+
? [element]
|
|
1193
|
+
: []);
|
|
1194
|
+
}
|
|
1195
|
+
if (ts.isIdentifier(current) && !visited.has(current.text)) {
|
|
1196
|
+
const initializer = initializers.get(current.text);
|
|
1197
|
+
if (initializer) {
|
|
1198
|
+
const nextVisited = new Set(visited);
|
|
1199
|
+
nextVisited.add(current.text);
|
|
1200
|
+
return registryValueExpressions(initializer, initializers, nextVisited);
|
|
989
1201
|
}
|
|
1202
|
+
}
|
|
1203
|
+
return [current];
|
|
1204
|
+
}
|
|
1205
|
+
function arrayExpressions(array) {
|
|
1206
|
+
return array.elements.flatMap((element) => {
|
|
1207
|
+
if (ts.isSpreadElement(element))
|
|
1208
|
+
return [element.expression];
|
|
1209
|
+
return ts.isExpression(element) ? [element] : [];
|
|
990
1210
|
});
|
|
991
|
-
return result;
|
|
992
1211
|
}
|
|
993
1212
|
function discoverFeatureNames(workspace, featuresPath) {
|
|
994
1213
|
const names = new Set();
|