@apifuse/provider-sdk 2.2.0-beta.56 → 2.2.0-beta.57
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 +4 -0
- package/dist/cli/migrate-operation-declaration.d.ts +7 -0
- package/dist/cli/migrate-operation-declaration.js +52 -12
- package/package.json +1 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-index.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-one.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-two.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-mixed-index.ts.txt +14 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-registry.ts.txt +3 -0
- package/src/cli/migrate-operation-declaration.ts +75 -10
package/CHANGELOG.md
CHANGED
|
@@ -45,6 +45,7 @@ export type OperationDeclarationRepositoryResult = {
|
|
|
45
45
|
readonly providerRoot: string;
|
|
46
46
|
readonly changedFiles: readonly string[];
|
|
47
47
|
readonly operationCount: number;
|
|
48
|
+
readonly notes: readonly OperationDeclarationNote[];
|
|
48
49
|
readonly sidecar?: string;
|
|
49
50
|
readonly localeTodoCount: number;
|
|
50
51
|
} | {
|
|
@@ -53,9 +54,15 @@ export type OperationDeclarationRepositoryResult = {
|
|
|
53
54
|
readonly refusals: readonly OperationDeclarationRefusal[];
|
|
54
55
|
/** Operations that were independently migratable before repository-atomic refusal. */
|
|
55
56
|
readonly operationCount: number;
|
|
57
|
+
readonly notes: readonly OperationDeclarationNote[];
|
|
56
58
|
readonly changedFiles: readonly string[];
|
|
57
59
|
readonly localeTodoCount: number;
|
|
58
60
|
};
|
|
61
|
+
export type OperationDeclarationNote = {
|
|
62
|
+
readonly code: "runtime_composed_registry";
|
|
63
|
+
readonly path: string;
|
|
64
|
+
readonly initializer: string;
|
|
65
|
+
};
|
|
59
66
|
/** Run the file transform repository-wide, committing writes only if every file is provable. */
|
|
60
67
|
export declare function migrateOperationDeclarationRepository(providerRootInput: string, options?: {
|
|
61
68
|
readonly check?: boolean;
|
|
@@ -68,7 +68,8 @@ function migrateOperationDeclarationInternal(sourceText, fileName, options, cont
|
|
|
68
68
|
}
|
|
69
69
|
const constObjects = collectModuleConstObjects(source);
|
|
70
70
|
const constArrays = collectModuleConstArrays(source);
|
|
71
|
-
const discovery = discoverOperationSites(source, fileName, constObjects, options.operationIds, context.operationSites, context.excludedBindings);
|
|
71
|
+
const discovery = discoverOperationSites(source, fileName, constObjects, options.operationIds, context.operationSites, context.excludedBindings, context.runtimeComposedInitializers);
|
|
72
|
+
context.recordDiscoveredSites?.(discovery.discoveredCount);
|
|
72
73
|
if (discovery.refusals.length > 0) {
|
|
73
74
|
return { status: "refused", refusals: discovery.refusals };
|
|
74
75
|
}
|
|
@@ -599,14 +600,15 @@ function replaceExampleLocaleMember(member, newName, localeKey, source) {
|
|
|
599
600
|
text: `${newName}: ${JSON.stringify(localeKey)}`,
|
|
600
601
|
};
|
|
601
602
|
}
|
|
602
|
-
function discoverOperationSites(source, fileName, constObjects, operationIds, operationSites, excludedBindings) {
|
|
603
|
+
function discoverOperationSites(source, fileName, constObjects, operationIds, operationSites, excludedBindings, runtimeComposedInitializers) {
|
|
603
604
|
const sitesByStart = new Map();
|
|
605
|
+
const discoveredStarts = new Set();
|
|
604
606
|
const localIds = new Map(operationIds ?? []);
|
|
605
607
|
const localExcludedBindings = new Set(excludedBindings ?? []);
|
|
606
608
|
const refusals = [];
|
|
607
609
|
const operationFactories = collectSimpleOperationFactories(source);
|
|
608
610
|
const factoryCallIds = new Map();
|
|
609
|
-
for (const map of collectOperationsMaps(source, constObjects, fileName, refusals)) {
|
|
611
|
+
for (const map of collectOperationsMaps(source, constObjects, fileName, refusals, runtimeComposedInitializers)) {
|
|
610
612
|
for (const property of map.properties) {
|
|
611
613
|
if (ts.isSpreadAssignment(property))
|
|
612
614
|
continue;
|
|
@@ -680,12 +682,15 @@ function discoverOperationSites(source, fileName, constObjects, operationIds, op
|
|
|
680
682
|
if (ts.isCallExpression(node) && isOperationHelperCall(node)) {
|
|
681
683
|
const argument = operationArgument(node);
|
|
682
684
|
const bindingName = enclosingBindingName(node);
|
|
685
|
+
const unwrappedArgument = unwrapExpression(argument);
|
|
686
|
+
if (unwrappedArgument !== undefined && ts.isObjectLiteralExpression(unwrappedArgument)) {
|
|
687
|
+
discoveredStarts.add(unwrappedArgument.getStart(source));
|
|
688
|
+
}
|
|
683
689
|
if (bindingName !== undefined && localExcludedBindings.has(bindingName))
|
|
684
690
|
return;
|
|
685
691
|
const operationKey = (bindingName === undefined ? undefined : localIds.get(bindingName)) ??
|
|
686
692
|
bindingName ??
|
|
687
693
|
"<anonymous>";
|
|
688
|
-
const unwrappedArgument = unwrapExpression(argument);
|
|
689
694
|
if (unwrappedArgument === undefined || !ts.isObjectLiteralExpression(unwrappedArgument)) {
|
|
690
695
|
refusals.push(refusal(fileName, operationKey, "non_literal", "Operation helper argument must be an object literal."));
|
|
691
696
|
}
|
|
@@ -711,8 +716,11 @@ function discoverOperationSites(source, fileName, constObjects, operationIds, op
|
|
|
711
716
|
ts.forEachChild(node, visit);
|
|
712
717
|
};
|
|
713
718
|
visit(source);
|
|
719
|
+
for (const start of sitesByStart.keys())
|
|
720
|
+
discoveredStarts.add(start);
|
|
714
721
|
return {
|
|
715
722
|
sites: [...sitesByStart.values()].sort((left, right) => left.object.getStart(source) - right.object.getStart(source)),
|
|
723
|
+
discoveredCount: discoveredStarts.size,
|
|
716
724
|
refusals,
|
|
717
725
|
};
|
|
718
726
|
}
|
|
@@ -741,7 +749,7 @@ function collectSimpleOperationFactories(source) {
|
|
|
741
749
|
}
|
|
742
750
|
return factories;
|
|
743
751
|
}
|
|
744
|
-
function collectOperationsMaps(source, constObjects, fileName, refusals) {
|
|
752
|
+
function collectOperationsMaps(source, constObjects, fileName, refusals, runtimeComposedInitializers) {
|
|
745
753
|
const maps = new Map();
|
|
746
754
|
const inspect = (expression, label) => {
|
|
747
755
|
const unwrapped = unwrapExpression(expression);
|
|
@@ -758,6 +766,8 @@ function collectOperationsMaps(source, constObjects, fileName, refusals) {
|
|
|
758
766
|
return;
|
|
759
767
|
}
|
|
760
768
|
if (ts.isCallExpression(unwrapped)) {
|
|
769
|
+
if (runtimeComposedInitializers?.has(expression.getStart(source)) === true)
|
|
770
|
+
return;
|
|
761
771
|
refusals.push(refusal(fileName, label, "factory_composed_operations", "The operations map is produced by a factory call and cannot be statically enumerated."));
|
|
762
772
|
}
|
|
763
773
|
};
|
|
@@ -1274,6 +1284,7 @@ export function migrateOperationDeclarationRepository(providerRootInput, options
|
|
|
1274
1284
|
const todos = [];
|
|
1275
1285
|
const refusals = [...repositoryIndex.refusals];
|
|
1276
1286
|
let operationCount = 0;
|
|
1287
|
+
let repositoryDiscoveredCount = 0;
|
|
1277
1288
|
for (const sourcePath of sourceFiles) {
|
|
1278
1289
|
const relativePath = slash(relative(providerRoot, sourcePath));
|
|
1279
1290
|
const result = migrateOperationDeclarationInternal(readFileSync(sourcePath, "utf8"), relativePath, {
|
|
@@ -1283,6 +1294,10 @@ export function migrateOperationDeclarationRepository(providerRootInput, options
|
|
|
1283
1294
|
operationSites: repositoryIndex.operationSites.get(sourcePath),
|
|
1284
1295
|
excludedBindings: repositoryIndex.excludedBindings.get(sourcePath),
|
|
1285
1296
|
staticObjectResolver: repositoryIndex.staticObjectResolverFor(sourcePath),
|
|
1297
|
+
runtimeComposedInitializers: repositoryIndex.runtimeComposedInitializers.get(sourcePath),
|
|
1298
|
+
recordDiscoveredSites: (count) => {
|
|
1299
|
+
repositoryDiscoveredCount += count;
|
|
1300
|
+
},
|
|
1286
1301
|
});
|
|
1287
1302
|
if (result.status === "refused") {
|
|
1288
1303
|
refusals.push(...result.refusals);
|
|
@@ -1295,7 +1310,18 @@ export function migrateOperationDeclarationRepository(providerRootInput, options
|
|
|
1295
1310
|
todos.push(...result.localeTodos);
|
|
1296
1311
|
}
|
|
1297
1312
|
}
|
|
1298
|
-
|
|
1313
|
+
const notes = repositoryDiscoveredCount === 0
|
|
1314
|
+
? []
|
|
1315
|
+
: repositoryIndex.declarations.flatMap((declaration) => declaration.runtimeInitializer === undefined
|
|
1316
|
+
? []
|
|
1317
|
+
: [
|
|
1318
|
+
{
|
|
1319
|
+
code: "runtime_composed_registry",
|
|
1320
|
+
path: slash(relative(providerRoot, declaration.path)),
|
|
1321
|
+
initializer: declaration.runtimeInitializer,
|
|
1322
|
+
},
|
|
1323
|
+
]);
|
|
1324
|
+
if (repositoryIndex.declarations.length > 0 && repositoryDiscoveredCount === 0) {
|
|
1299
1325
|
for (const declaration of repositoryIndex.declarations) {
|
|
1300
1326
|
refusals.push(refusal(slash(relative(providerRoot, declaration.path)), "<operations>", "no_operations_discovered", `Provider construct ${declaration.construct} declares operations via unresolved initializer ${JSON.stringify(declaration.initializer.getText(declaration.initializer.getSourceFile()))}, but repository-wide discovery found zero operation sites.`));
|
|
1301
1327
|
}
|
|
@@ -1309,6 +1335,7 @@ export function migrateOperationDeclarationRepository(providerRootInput, options
|
|
|
1309
1335
|
providerRoot,
|
|
1310
1336
|
refusals,
|
|
1311
1337
|
operationCount,
|
|
1338
|
+
notes,
|
|
1312
1339
|
changedFiles,
|
|
1313
1340
|
localeTodoCount: todos.length,
|
|
1314
1341
|
};
|
|
@@ -1322,6 +1349,7 @@ export function migrateOperationDeclarationRepository(providerRootInput, options
|
|
|
1322
1349
|
providerRoot,
|
|
1323
1350
|
changedFiles: [],
|
|
1324
1351
|
operationCount,
|
|
1352
|
+
notes,
|
|
1325
1353
|
localeTodoCount: 0,
|
|
1326
1354
|
};
|
|
1327
1355
|
}
|
|
@@ -1338,6 +1366,7 @@ export function migrateOperationDeclarationRepository(providerRootInput, options
|
|
|
1338
1366
|
providerRoot,
|
|
1339
1367
|
changedFiles,
|
|
1340
1368
|
operationCount,
|
|
1369
|
+
notes,
|
|
1341
1370
|
sidecar,
|
|
1342
1371
|
localeTodoCount: todos.length,
|
|
1343
1372
|
};
|
|
@@ -1489,12 +1518,12 @@ function buildRepositoryOperationIndex(sourceFiles, providerRoot) {
|
|
|
1489
1518
|
const operationIds = buildOperationIdIndex(sourceFiles);
|
|
1490
1519
|
const operationSites = new Map();
|
|
1491
1520
|
const excludedBindings = new Map();
|
|
1521
|
+
const runtimeComposedInitializers = new Map();
|
|
1492
1522
|
const refusals = [];
|
|
1493
1523
|
const declarations = [];
|
|
1494
1524
|
const indexedProviderProperties = new Set();
|
|
1495
1525
|
const factoryIds = new Map();
|
|
1496
1526
|
const bindingCandidates = new Map();
|
|
1497
|
-
let discoveredCount = 0;
|
|
1498
1527
|
const relativePath = (path) => slash(relative(providerRoot, path));
|
|
1499
1528
|
const resolutionRefusal = (path, operationKey, detail) => {
|
|
1500
1529
|
refusals.push(refusal(relativePath(path), operationKey, "non_literal", detail));
|
|
@@ -1749,7 +1778,6 @@ function buildRepositoryOperationIndex(sourceFiles, providerRoot) {
|
|
|
1749
1778
|
}
|
|
1750
1779
|
sites.set(start, operationId);
|
|
1751
1780
|
operationSites.set(path, sites);
|
|
1752
|
-
discoveredCount += 1;
|
|
1753
1781
|
};
|
|
1754
1782
|
const classifyEntry = (entry) => {
|
|
1755
1783
|
const resolved = resolveLocatedExpression(entry.value, new Set());
|
|
@@ -1793,7 +1821,6 @@ function buildRepositoryOperationIndex(sourceFiles, providerRoot) {
|
|
|
1793
1821
|
};
|
|
1794
1822
|
factory.ids.add(entry.operationId);
|
|
1795
1823
|
factoryIds.set(key, factory);
|
|
1796
|
-
discoveredCount += 1;
|
|
1797
1824
|
return;
|
|
1798
1825
|
}
|
|
1799
1826
|
resolutionRefusal(resolved.value.path, entry.operationId, `Operation initializer ${JSON.stringify(expression.getText(resolved.value.source))} is not a raw object, operation helper, or simple same-file factory call.`);
|
|
@@ -1803,10 +1830,23 @@ function buildRepositoryOperationIndex(sourceFiles, providerRoot) {
|
|
|
1803
1830
|
if (indexedProviderProperties.has(key))
|
|
1804
1831
|
return;
|
|
1805
1832
|
indexedProviderProperties.add(key);
|
|
1806
|
-
|
|
1833
|
+
const resolvedInitializer = resolveLocatedExpression({ path, source, expression: node.initializer }, new Set());
|
|
1834
|
+
let runtimeInitializer;
|
|
1835
|
+
if (resolvedInitializer.status === "resolved") {
|
|
1836
|
+
const resolvedExpression = unwrapExpression(resolvedInitializer.value.expression);
|
|
1837
|
+
if (resolvedExpression !== undefined && ts.isCallExpression(resolvedExpression)) {
|
|
1838
|
+
runtimeInitializer = resolvedExpression.getText(resolvedInitializer.value.source);
|
|
1839
|
+
const initializers = runtimeComposedInitializers.get(path) ?? new Set();
|
|
1840
|
+
initializers.add(node.initializer.getStart(source));
|
|
1841
|
+
runtimeComposedInitializers.set(path, initializers);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
declarations.push({ path, construct, initializer: node.initializer, runtimeInitializer });
|
|
1807
1845
|
const flattened = flattenRegistry({ path, source, expression: node.initializer }, new Set());
|
|
1808
1846
|
if ("detail" in flattened) {
|
|
1809
|
-
|
|
1847
|
+
if (runtimeInitializer === undefined) {
|
|
1848
|
+
resolutionRefusal(path, "<operations>", flattened.detail);
|
|
1849
|
+
}
|
|
1810
1850
|
}
|
|
1811
1851
|
else {
|
|
1812
1852
|
for (const entry of flattened.entries.values())
|
|
@@ -1919,9 +1959,9 @@ function buildRepositoryOperationIndex(sourceFiles, providerRoot) {
|
|
|
1919
1959
|
operationIds,
|
|
1920
1960
|
operationSites,
|
|
1921
1961
|
excludedBindings,
|
|
1962
|
+
runtimeComposedInitializers,
|
|
1922
1963
|
refusals,
|
|
1923
1964
|
declarations,
|
|
1924
|
-
discoveredCount,
|
|
1925
1965
|
staticObjectResolverFor: (currentPath) => (expression, source) => resolveStaticObject(expression, sources.has(source.fileName) ? source.fileName : currentPath),
|
|
1926
1966
|
};
|
|
1927
1967
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { makeRegistry } from "./operations/registry";
|
|
2
|
+
|
|
3
|
+
const literalOperation = defineOperation<ProviderContext>()({
|
|
4
|
+
annotations: { readOnly: true },
|
|
5
|
+
input: LiteralInputSchema,
|
|
6
|
+
output: LiteralOutputSchema,
|
|
7
|
+
handler: literalHandler,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const literalProvider = buildProvider({
|
|
11
|
+
operations: { literal: literalOperation },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export default buildProvider({ operations: makeRegistry({ publicOnly: true }) });
|
|
@@ -141,6 +141,8 @@ type RepositoryMigrationContext = {
|
|
|
141
141
|
readonly operationSites?: ReadonlyMap<number, string>;
|
|
142
142
|
readonly excludedBindings?: ReadonlySet<string>;
|
|
143
143
|
readonly staticObjectResolver?: StaticObjectResolver;
|
|
144
|
+
readonly runtimeComposedInitializers?: ReadonlySet<number>;
|
|
145
|
+
readonly recordDiscoveredSites?: (count: number) => void;
|
|
144
146
|
};
|
|
145
147
|
|
|
146
148
|
type OperationSite = {
|
|
@@ -194,7 +196,9 @@ function migrateOperationDeclarationInternal(
|
|
|
194
196
|
options.operationIds,
|
|
195
197
|
context.operationSites,
|
|
196
198
|
context.excludedBindings,
|
|
199
|
+
context.runtimeComposedInitializers,
|
|
197
200
|
);
|
|
201
|
+
context.recordDiscoveredSites?.(discovery.discoveredCount);
|
|
198
202
|
if (discovery.refusals.length > 0) {
|
|
199
203
|
return { status: "refused", refusals: discovery.refusals };
|
|
200
204
|
}
|
|
@@ -1047,18 +1051,27 @@ function discoverOperationSites(
|
|
|
1047
1051
|
operationIds: ReadonlyMap<string, string> | undefined,
|
|
1048
1052
|
operationSites: ReadonlyMap<number, string> | undefined,
|
|
1049
1053
|
excludedBindings: ReadonlySet<string> | undefined,
|
|
1054
|
+
runtimeComposedInitializers: ReadonlySet<number> | undefined,
|
|
1050
1055
|
): {
|
|
1051
1056
|
readonly sites: OperationSite[];
|
|
1057
|
+
readonly discoveredCount: number;
|
|
1052
1058
|
readonly refusals: OperationDeclarationRefusal[];
|
|
1053
1059
|
} {
|
|
1054
1060
|
const sitesByStart = new Map<number, OperationSite>();
|
|
1061
|
+
const discoveredStarts = new Set<number>();
|
|
1055
1062
|
const localIds = new Map(operationIds ?? []);
|
|
1056
1063
|
const localExcludedBindings = new Set(excludedBindings ?? []);
|
|
1057
1064
|
const refusals: OperationDeclarationRefusal[] = [];
|
|
1058
1065
|
const operationFactories = collectSimpleOperationFactories(source);
|
|
1059
1066
|
const factoryCallIds = new Map<string, Set<string>>();
|
|
1060
1067
|
|
|
1061
|
-
for (const map of collectOperationsMaps(
|
|
1068
|
+
for (const map of collectOperationsMaps(
|
|
1069
|
+
source,
|
|
1070
|
+
constObjects,
|
|
1071
|
+
fileName,
|
|
1072
|
+
refusals,
|
|
1073
|
+
runtimeComposedInitializers,
|
|
1074
|
+
)) {
|
|
1062
1075
|
for (const property of map.properties) {
|
|
1063
1076
|
if (ts.isSpreadAssignment(property)) continue;
|
|
1064
1077
|
const key = staticPropertyName(property.name);
|
|
@@ -1145,12 +1158,15 @@ function discoverOperationSites(
|
|
|
1145
1158
|
if (ts.isCallExpression(node) && isOperationHelperCall(node)) {
|
|
1146
1159
|
const argument = operationArgument(node);
|
|
1147
1160
|
const bindingName = enclosingBindingName(node);
|
|
1161
|
+
const unwrappedArgument = unwrapExpression(argument);
|
|
1162
|
+
if (unwrappedArgument !== undefined && ts.isObjectLiteralExpression(unwrappedArgument)) {
|
|
1163
|
+
discoveredStarts.add(unwrappedArgument.getStart(source));
|
|
1164
|
+
}
|
|
1148
1165
|
if (bindingName !== undefined && localExcludedBindings.has(bindingName)) return;
|
|
1149
1166
|
const operationKey =
|
|
1150
1167
|
(bindingName === undefined ? undefined : localIds.get(bindingName)) ??
|
|
1151
1168
|
bindingName ??
|
|
1152
1169
|
"<anonymous>";
|
|
1153
|
-
const unwrappedArgument = unwrapExpression(argument);
|
|
1154
1170
|
if (unwrappedArgument === undefined || !ts.isObjectLiteralExpression(unwrappedArgument)) {
|
|
1155
1171
|
refusals.push(
|
|
1156
1172
|
refusal(
|
|
@@ -1181,10 +1197,12 @@ function discoverOperationSites(
|
|
|
1181
1197
|
ts.forEachChild(node, visit);
|
|
1182
1198
|
};
|
|
1183
1199
|
visit(source);
|
|
1200
|
+
for (const start of sitesByStart.keys()) discoveredStarts.add(start);
|
|
1184
1201
|
return {
|
|
1185
1202
|
sites: [...sitesByStart.values()].sort(
|
|
1186
1203
|
(left, right) => left.object.getStart(source) - right.object.getStart(source),
|
|
1187
1204
|
),
|
|
1205
|
+
discoveredCount: discoveredStarts.size,
|
|
1188
1206
|
refusals,
|
|
1189
1207
|
};
|
|
1190
1208
|
}
|
|
@@ -1223,6 +1241,7 @@ function collectOperationsMaps(
|
|
|
1223
1241
|
constObjects: ReadonlyMap<string, TS.ObjectLiteralExpression>,
|
|
1224
1242
|
fileName: string,
|
|
1225
1243
|
refusals: OperationDeclarationRefusal[],
|
|
1244
|
+
runtimeComposedInitializers?: ReadonlySet<number>,
|
|
1226
1245
|
): TS.ObjectLiteralExpression[] {
|
|
1227
1246
|
const maps = new Map<number, TS.ObjectLiteralExpression>();
|
|
1228
1247
|
const inspect = (expression: TS.Expression, label: string): void => {
|
|
@@ -1238,6 +1257,7 @@ function collectOperationsMaps(
|
|
|
1238
1257
|
return;
|
|
1239
1258
|
}
|
|
1240
1259
|
if (ts.isCallExpression(unwrapped)) {
|
|
1260
|
+
if (runtimeComposedInitializers?.has(expression.getStart(source)) === true) return;
|
|
1241
1261
|
refusals.push(
|
|
1242
1262
|
refusal(
|
|
1243
1263
|
fileName,
|
|
@@ -1893,6 +1913,7 @@ export type OperationDeclarationRepositoryResult =
|
|
|
1893
1913
|
readonly providerRoot: string;
|
|
1894
1914
|
readonly changedFiles: readonly string[];
|
|
1895
1915
|
readonly operationCount: number;
|
|
1916
|
+
readonly notes: readonly OperationDeclarationNote[];
|
|
1896
1917
|
readonly sidecar?: string;
|
|
1897
1918
|
readonly localeTodoCount: number;
|
|
1898
1919
|
}
|
|
@@ -1902,10 +1923,17 @@ export type OperationDeclarationRepositoryResult =
|
|
|
1902
1923
|
readonly refusals: readonly OperationDeclarationRefusal[];
|
|
1903
1924
|
/** Operations that were independently migratable before repository-atomic refusal. */
|
|
1904
1925
|
readonly operationCount: number;
|
|
1926
|
+
readonly notes: readonly OperationDeclarationNote[];
|
|
1905
1927
|
readonly changedFiles: readonly string[];
|
|
1906
1928
|
readonly localeTodoCount: number;
|
|
1907
1929
|
};
|
|
1908
1930
|
|
|
1931
|
+
export type OperationDeclarationNote = {
|
|
1932
|
+
readonly code: "runtime_composed_registry";
|
|
1933
|
+
readonly path: string;
|
|
1934
|
+
readonly initializer: string;
|
|
1935
|
+
};
|
|
1936
|
+
|
|
1909
1937
|
/** Run the file transform repository-wide, committing writes only if every file is provable. */
|
|
1910
1938
|
export function migrateOperationDeclarationRepository(
|
|
1911
1939
|
providerRootInput: string,
|
|
@@ -1920,6 +1948,7 @@ export function migrateOperationDeclarationRepository(
|
|
|
1920
1948
|
const todos: LocaleTodo[] = [];
|
|
1921
1949
|
const refusals: OperationDeclarationRefusal[] = [...repositoryIndex.refusals];
|
|
1922
1950
|
let operationCount = 0;
|
|
1951
|
+
let repositoryDiscoveredCount = 0;
|
|
1923
1952
|
|
|
1924
1953
|
for (const sourcePath of sourceFiles) {
|
|
1925
1954
|
const relativePath = slash(relative(providerRoot, sourcePath));
|
|
@@ -1934,6 +1963,10 @@ export function migrateOperationDeclarationRepository(
|
|
|
1934
1963
|
operationSites: repositoryIndex.operationSites.get(sourcePath),
|
|
1935
1964
|
excludedBindings: repositoryIndex.excludedBindings.get(sourcePath),
|
|
1936
1965
|
staticObjectResolver: repositoryIndex.staticObjectResolverFor(sourcePath),
|
|
1966
|
+
runtimeComposedInitializers: repositoryIndex.runtimeComposedInitializers.get(sourcePath),
|
|
1967
|
+
recordDiscoveredSites: (count) => {
|
|
1968
|
+
repositoryDiscoveredCount += count;
|
|
1969
|
+
},
|
|
1937
1970
|
},
|
|
1938
1971
|
);
|
|
1939
1972
|
if (result.status === "refused") {
|
|
@@ -1947,7 +1980,21 @@ export function migrateOperationDeclarationRepository(
|
|
|
1947
1980
|
todos.push(...result.localeTodos);
|
|
1948
1981
|
}
|
|
1949
1982
|
}
|
|
1950
|
-
|
|
1983
|
+
const notes: OperationDeclarationNote[] =
|
|
1984
|
+
repositoryDiscoveredCount === 0
|
|
1985
|
+
? []
|
|
1986
|
+
: repositoryIndex.declarations.flatMap((declaration) =>
|
|
1987
|
+
declaration.runtimeInitializer === undefined
|
|
1988
|
+
? []
|
|
1989
|
+
: [
|
|
1990
|
+
{
|
|
1991
|
+
code: "runtime_composed_registry" as const,
|
|
1992
|
+
path: slash(relative(providerRoot, declaration.path)),
|
|
1993
|
+
initializer: declaration.runtimeInitializer,
|
|
1994
|
+
},
|
|
1995
|
+
],
|
|
1996
|
+
);
|
|
1997
|
+
if (repositoryIndex.declarations.length > 0 && repositoryDiscoveredCount === 0) {
|
|
1951
1998
|
for (const declaration of repositoryIndex.declarations) {
|
|
1952
1999
|
refusals.push(
|
|
1953
2000
|
refusal(
|
|
@@ -1970,6 +2017,7 @@ export function migrateOperationDeclarationRepository(
|
|
|
1970
2017
|
providerRoot,
|
|
1971
2018
|
refusals,
|
|
1972
2019
|
operationCount,
|
|
2020
|
+
notes,
|
|
1973
2021
|
changedFiles,
|
|
1974
2022
|
localeTodoCount: todos.length,
|
|
1975
2023
|
};
|
|
@@ -1984,6 +2032,7 @@ export function migrateOperationDeclarationRepository(
|
|
|
1984
2032
|
providerRoot,
|
|
1985
2033
|
changedFiles: [],
|
|
1986
2034
|
operationCount,
|
|
2035
|
+
notes,
|
|
1987
2036
|
localeTodoCount: 0,
|
|
1988
2037
|
};
|
|
1989
2038
|
}
|
|
@@ -2000,6 +2049,7 @@ export function migrateOperationDeclarationRepository(
|
|
|
2000
2049
|
providerRoot,
|
|
2001
2050
|
changedFiles,
|
|
2002
2051
|
operationCount,
|
|
2052
|
+
notes,
|
|
2003
2053
|
sidecar,
|
|
2004
2054
|
localeTodoCount: todos.length,
|
|
2005
2055
|
};
|
|
@@ -2180,15 +2230,16 @@ type ProviderOperationsDeclaration = {
|
|
|
2180
2230
|
readonly path: string;
|
|
2181
2231
|
readonly construct: string;
|
|
2182
2232
|
readonly initializer: TS.Expression;
|
|
2233
|
+
readonly runtimeInitializer?: string;
|
|
2183
2234
|
};
|
|
2184
2235
|
|
|
2185
2236
|
type RepositoryOperationIndex = {
|
|
2186
2237
|
readonly operationIds: Map<string, Map<string, string>>;
|
|
2187
2238
|
readonly operationSites: Map<string, Map<number, string>>;
|
|
2188
2239
|
readonly excludedBindings: Map<string, Set<string>>;
|
|
2240
|
+
readonly runtimeComposedInitializers: Map<string, Set<number>>;
|
|
2189
2241
|
readonly refusals: OperationDeclarationRefusal[];
|
|
2190
2242
|
readonly declarations: ProviderOperationsDeclaration[];
|
|
2191
|
-
readonly discoveredCount: number;
|
|
2192
2243
|
readonly staticObjectResolverFor: (path: string) => StaticObjectResolver;
|
|
2193
2244
|
};
|
|
2194
2245
|
|
|
@@ -2205,12 +2256,12 @@ function buildRepositoryOperationIndex(
|
|
|
2205
2256
|
const operationIds = buildOperationIdIndex(sourceFiles);
|
|
2206
2257
|
const operationSites = new Map<string, Map<number, string>>();
|
|
2207
2258
|
const excludedBindings = new Map<string, Set<string>>();
|
|
2259
|
+
const runtimeComposedInitializers = new Map<string, Set<number>>();
|
|
2208
2260
|
const refusals: OperationDeclarationRefusal[] = [];
|
|
2209
2261
|
const declarations: ProviderOperationsDeclaration[] = [];
|
|
2210
2262
|
const indexedProviderProperties = new Set<string>();
|
|
2211
2263
|
const factoryIds = new Map<string, { path: string; name: string; ids: Set<string> }>();
|
|
2212
2264
|
const bindingCandidates = new Map<string, { path: string; name: string; ids: Set<string> }>();
|
|
2213
|
-
let discoveredCount = 0;
|
|
2214
2265
|
|
|
2215
2266
|
const relativePath = (path: string): string => slash(relative(providerRoot, path));
|
|
2216
2267
|
const resolutionRefusal = (path: string, operationKey: string, detail: string): void => {
|
|
@@ -2489,7 +2540,6 @@ function buildRepositoryOperationIndex(
|
|
|
2489
2540
|
}
|
|
2490
2541
|
sites.set(start, operationId);
|
|
2491
2542
|
operationSites.set(path, sites);
|
|
2492
|
-
discoveredCount += 1;
|
|
2493
2543
|
};
|
|
2494
2544
|
|
|
2495
2545
|
const classifyEntry = (entry: RegistryEntry): void => {
|
|
@@ -2543,7 +2593,6 @@ function buildRepositoryOperationIndex(
|
|
|
2543
2593
|
};
|
|
2544
2594
|
factory.ids.add(entry.operationId);
|
|
2545
2595
|
factoryIds.set(key, factory);
|
|
2546
|
-
discoveredCount += 1;
|
|
2547
2596
|
return;
|
|
2548
2597
|
}
|
|
2549
2598
|
resolutionRefusal(
|
|
@@ -2562,10 +2611,26 @@ function buildRepositoryOperationIndex(
|
|
|
2562
2611
|
const key = `${path}\0${node.getStart(source)}`;
|
|
2563
2612
|
if (indexedProviderProperties.has(key)) return;
|
|
2564
2613
|
indexedProviderProperties.add(key);
|
|
2565
|
-
|
|
2614
|
+
const resolvedInitializer = resolveLocatedExpression(
|
|
2615
|
+
{ path, source, expression: node.initializer },
|
|
2616
|
+
new Set(),
|
|
2617
|
+
);
|
|
2618
|
+
let runtimeInitializer: string | undefined;
|
|
2619
|
+
if (resolvedInitializer.status === "resolved") {
|
|
2620
|
+
const resolvedExpression = unwrapExpression(resolvedInitializer.value.expression);
|
|
2621
|
+
if (resolvedExpression !== undefined && ts.isCallExpression(resolvedExpression)) {
|
|
2622
|
+
runtimeInitializer = resolvedExpression.getText(resolvedInitializer.value.source);
|
|
2623
|
+
const initializers = runtimeComposedInitializers.get(path) ?? new Set<number>();
|
|
2624
|
+
initializers.add(node.initializer.getStart(source));
|
|
2625
|
+
runtimeComposedInitializers.set(path, initializers);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
declarations.push({ path, construct, initializer: node.initializer, runtimeInitializer });
|
|
2566
2629
|
const flattened = flattenRegistry({ path, source, expression: node.initializer }, new Set());
|
|
2567
2630
|
if ("detail" in flattened) {
|
|
2568
|
-
|
|
2631
|
+
if (runtimeInitializer === undefined) {
|
|
2632
|
+
resolutionRefusal(path, "<operations>", flattened.detail);
|
|
2633
|
+
}
|
|
2569
2634
|
} else {
|
|
2570
2635
|
for (const entry of flattened.entries.values()) classifyEntry(entry);
|
|
2571
2636
|
}
|
|
@@ -2691,9 +2756,9 @@ function buildRepositoryOperationIndex(
|
|
|
2691
2756
|
operationIds,
|
|
2692
2757
|
operationSites,
|
|
2693
2758
|
excludedBindings,
|
|
2759
|
+
runtimeComposedInitializers,
|
|
2694
2760
|
refusals,
|
|
2695
2761
|
declarations,
|
|
2696
|
-
discoveredCount,
|
|
2697
2762
|
staticObjectResolverFor: (currentPath) => (expression, source) =>
|
|
2698
2763
|
resolveStaticObject(expression, sources.has(source.fileName) ? source.fileName : currentPath),
|
|
2699
2764
|
};
|