@opencrvs/toolkit 2.0.0-rc.fdc585a → 2.0.0-rc.ff04b30
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/create-countryconfig/index.js +73 -0
- package/create-countryconfig/package.json +11 -0
- package/dist/application-config/index.js +27 -28
- package/dist/cli.js +392 -128
- package/dist/commons/api/router.d.ts +3301 -247
- package/dist/commons/conditionals/validate.d.ts +1 -0
- package/dist/commons/events/ActionInput.d.ts +108 -0
- package/dist/commons/events/Draft.d.ts +3 -0
- package/dist/commons/events/EventIndex.d.ts +0 -3
- package/dist/commons/events/EventMetadata.d.ts +0 -7
- package/dist/commons/events/WorkqueueConfig.d.ts +146 -146
- package/dist/commons/events/locations.d.ts +21 -0
- package/dist/commons/events/mocks.test.utils.d.ts +19 -0
- package/dist/commons/events/scopes.d.ts +24 -1
- package/dist/commons/events/state/index.d.ts +0 -4
- package/dist/commons/events/state/utils.d.ts +0 -2
- package/dist/commons/events/utils.d.ts +1 -1
- package/dist/conditionals/index.js +3 -1
- package/dist/events/index.js +109 -76
- package/dist/migrations/v2.0/checkout-upstream-files.d.ts +1 -1
- package/dist/migrations/v2.0/checkout-upstream-files.d.ts.map +1 -1
- package/dist/migrations/v2.0/checkout-upstream-files.js +1 -2
- package/dist/migrations/v2.0/delete-infrastructure-directory.d.ts +9 -1
- package/dist/migrations/v2.0/delete-infrastructure-directory.d.ts.map +1 -1
- package/dist/migrations/v2.0/delete-infrastructure-directory.js +66 -20
- package/dist/migrations/v2.0/fix-accept-requested-registration-function-type.d.ts +3 -0
- package/dist/migrations/v2.0/fix-accept-requested-registration-function-type.d.ts.map +1 -0
- package/dist/migrations/v2.0/fix-accept-requested-registration-function-type.js +110 -0
- package/dist/migrations/v2.0/index.d.ts +5 -3
- package/dist/migrations/v2.0/index.d.ts.map +1 -1
- package/dist/migrations/v2.0/index.js +390 -126
- package/dist/migrations/v2.0/merge-infrastructure-directory.d.ts +11 -1
- package/dist/migrations/v2.0/merge-infrastructure-directory.d.ts.map +1 -1
- package/dist/migrations/v2.0/merge-infrastructure-directory.js +17 -16
- package/dist/migrations/v2.0/migrate-scopes.d.ts.map +1 -1
- package/dist/migrations/v2.0/migrate-scopes.js +54 -30
- package/dist/migrations/v2.0/migrate-workqueue-configs.d.ts.map +1 -1
- package/dist/migrations/v2.0/migrate-workqueue-configs.js +140 -59
- package/dist/notification/index.js +41 -46
- package/dist/scopes/index.js +3 -1
- package/opencrvs-toolkit-2.0.0-rc.ff04b30.tgz +0 -0
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/opencrvs-toolkit-2.0.0-rc.fdc585a.tgz +0 -0
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
interface MergeInfrastructureOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Top-level subdirectories of `infrastructure/` to scope the merge to.
|
|
4
|
+
* When omitted or empty, the entire `infrastructure/` tree is merged
|
|
5
|
+
* (legacy behavior). Each name is relative to `infrastructure/` —
|
|
6
|
+
* e.g. `['postgres', 'metabase']` merges only
|
|
7
|
+
* `infrastructure/postgres/` and `infrastructure/metabase/`.
|
|
8
|
+
*/
|
|
9
|
+
subdirs?: string[];
|
|
10
|
+
}
|
|
11
|
+
declare function main({ subdirs }?: MergeInfrastructureOptions): Promise<void>;
|
|
2
12
|
export { main };
|
|
3
13
|
//# sourceMappingURL=merge-infrastructure-directory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-infrastructure-directory.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/merge-infrastructure-directory.ts"],"names":[],"mappings":"AAsHA,iBAAe,IAAI,
|
|
1
|
+
{"version":3,"file":"merge-infrastructure-directory.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/merge-infrastructure-directory.ts"],"names":[],"mappings":"AAsHA,UAAU,0BAA0B;IAClC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB;AAID,iBAAe,IAAI,CAAC,EAClB,OAAY,EACb,GAAE,0BAA+B,GAAG,OAAO,CAAC,IAAI,CAAC,CAoIjD;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
|
|
@@ -22,7 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
22
22
|
exports.main = main;
|
|
23
23
|
/**
|
|
24
24
|
* Codemod: Merge upstream changes into the local `infrastructure/` directory
|
|
25
|
-
* from opencrvs/opencrvs-countryconfig.
|
|
25
|
+
* (or selected subdirectories of it) from opencrvs/opencrvs-countryconfig.
|
|
26
26
|
*
|
|
27
27
|
* Usage:
|
|
28
28
|
* ts-node -r tsconfig-paths/register src/migrations/v2.0/merge-infrastructure-directory.ts
|
|
@@ -33,8 +33,10 @@ exports.main = main;
|
|
|
33
33
|
* - the upstream "theirs" branch (v2.0) → `UPSTREAM_BRANCH`
|
|
34
34
|
* - the synthetic merge-base branch (latest 1.9 release line)
|
|
35
35
|
* → `BASE_BRANCH`
|
|
36
|
-
* 2. For every file under `infrastructure/` on upstream "theirs",
|
|
37
|
-
*
|
|
36
|
+
* 2. For every file under `infrastructure/` on upstream "theirs" (or, when
|
|
37
|
+
* `subdirs` is provided, only files under
|
|
38
|
+
* `infrastructure/<subdir>/` for each requested subdir), performs a
|
|
39
|
+
* file-scoped 3-way merge:
|
|
38
40
|
* - new file on upstream → checked out and staged
|
|
39
41
|
* - existing file → 3-way merged in place via `git merge-file`,
|
|
40
42
|
* using the BASE_BRANCH version of the file
|
|
@@ -116,8 +118,14 @@ function gitShowBytes(ref, path) {
|
|
|
116
118
|
}
|
|
117
119
|
// ─── Entry point ─────────────────────────────────────────────────────────────
|
|
118
120
|
function main() {
|
|
119
|
-
return __awaiter(this,
|
|
120
|
-
|
|
121
|
+
return __awaiter(this, arguments, void 0, function* ({ subdirs = [] } = {}) {
|
|
122
|
+
// Build the pathspec list passed to `git ls-tree`. Trailing slashes make
|
|
123
|
+
// git treat them as tree paths (recurse into them).
|
|
124
|
+
const pathspecs = subdirs.length > 0
|
|
125
|
+
? subdirs.map((s) => `${INFRASTRUCTURE_DIR}/${s}/`)
|
|
126
|
+
: [`${INFRASTRUCTURE_DIR}/`];
|
|
127
|
+
const scopeLabel = pathspecs.map((p) => `'${p}'`).join(', ');
|
|
128
|
+
console.log(`Merging ${scopeLabel} from ${checkout_upstream_files_1.UPSTREAM_URL}@${checkout_upstream_files_1.UPSTREAM_BRANCH} (base: ${BASE_BRANCH})...\n`);
|
|
121
129
|
(0, checkout_upstream_files_1.assertIsGitRepo)();
|
|
122
130
|
// Best-effort cleanup of a stale temp remote from a previous aborted run.
|
|
123
131
|
(0, checkout_upstream_files_1.tryGit)(['remote', 'remove', TEMP_REMOTE]);
|
|
@@ -131,20 +139,13 @@ function main() {
|
|
|
131
139
|
const ref = `${TEMP_REMOTE}/${checkout_upstream_files_1.UPSTREAM_BRANCH}`;
|
|
132
140
|
const baseRef = `${TEMP_REMOTE}/${BASE_BRANCH}`;
|
|
133
141
|
// -z gives NUL-separated paths so filenames with spaces or newlines
|
|
134
|
-
// survive the round-trip.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
'-r',
|
|
138
|
-
'--name-only',
|
|
139
|
-
'-z',
|
|
140
|
-
ref,
|
|
141
|
-
'--',
|
|
142
|
-
`${INFRASTRUCTURE_DIR}/`
|
|
143
|
-
], { silent: true })
|
|
142
|
+
// survive the round-trip. Multiple pathspecs after `--` are unioned
|
|
143
|
+
// by git, which scopes the listing to the requested subdirectories.
|
|
144
|
+
const upstreamFiles = (0, checkout_upstream_files_1.runGit)(['ls-tree', '-r', '--name-only', '-z', ref, '--', ...pathspecs], { silent: true })
|
|
144
145
|
.split('\0')
|
|
145
146
|
.filter(Boolean);
|
|
146
147
|
if (upstreamFiles.length === 0) {
|
|
147
|
-
console.log(` No files found under
|
|
148
|
+
console.log(` No files found under ${scopeLabel} on ${ref}. Nothing to merge.`);
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
150
151
|
const tmpDir = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'opencrvs-merge-infra-'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-scopes.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/migrate-scopes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrate-scopes.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/migrate-scopes.ts"],"names":[],"mappings":"AAoXA,iBAAe,IAAI,kBAmDlB;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
|
|
@@ -25,7 +25,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
25
25
|
exports.main = main;
|
|
26
26
|
const ts_morph_1 = require("ts-morph");
|
|
27
27
|
const path_1 = __importDefault(require("path"));
|
|
28
|
-
const scopes_1 = require("../commons/scopes");
|
|
29
28
|
const scopes_deprecated_do_not_use_1 = require("../commons/scopes.deprecated.do-not-use");
|
|
30
29
|
const ROLES_FILE_RELATIVE_PATH = 'src/data-seeding/roles/roles.ts';
|
|
31
30
|
const SCOPES_PROPERTY_NAME = 'scopes';
|
|
@@ -65,60 +64,85 @@ function resolveLegacyScopeFromElement(element) {
|
|
|
65
64
|
}
|
|
66
65
|
return null;
|
|
67
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Walks each `scopes: [...]` array in the roles file, classifies elements,
|
|
69
|
+
* and rewrites the whole array using `migrateLegacyScopesArrayToV2Scopes`
|
|
70
|
+
* (which preserves v1.9 AND semantics by merging pairs of legacy scopes
|
|
71
|
+
* that targeted the same v2 type). See issue #12489.
|
|
72
|
+
*
|
|
73
|
+
* Elements are partitioned into three kinds:
|
|
74
|
+
* - drop: `SCOPES.X` references where X is not in the SCOPES map (warned
|
|
75
|
+
* and removed, matching pre-refactor behavior).
|
|
76
|
+
* - raw: non-literal expressions we cannot statically resolve (e.g.
|
|
77
|
+
* `...sharedScopes` spreads). Preserved verbatim in output so authoring
|
|
78
|
+
* intent isn't lost.
|
|
79
|
+
* - legacy: literal strings or resolvable `SCOPES.X` references.
|
|
80
|
+
* Collected and passed as a batch to the merge function.
|
|
81
|
+
*
|
|
82
|
+
* The output array text is `[...rawTexts, ...mergedScopesAsJson]`. Order of
|
|
83
|
+
* legacy entries relative to raw expressions is not preserved — scopes in a
|
|
84
|
+
* v2 array compose with OR, so position is semantically irrelevant.
|
|
85
|
+
*/
|
|
68
86
|
function migrateScopesArrays(rolesFilePath, project) {
|
|
69
87
|
const sourceFile = project.getSourceFile(rolesFilePath);
|
|
70
|
-
if (!sourceFile)
|
|
71
|
-
return { migratedCount: 0, removedCount: 0 };
|
|
88
|
+
if (!sourceFile) {
|
|
89
|
+
return { migratedCount: 0, removedCount: 0, mergedCount: 0 };
|
|
90
|
+
}
|
|
72
91
|
let migratedCount = 0;
|
|
73
92
|
let removedCount = 0;
|
|
93
|
+
let mergedCount = 0;
|
|
74
94
|
const scopesProperties = sourceFile
|
|
75
95
|
.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertyAssignment)
|
|
76
96
|
.filter((prop) => prop.getName() === SCOPES_PROPERTY_NAME);
|
|
97
|
+
const relPath = path_1.default.relative(process.cwd(), rolesFilePath);
|
|
77
98
|
for (const scopesProp of scopesProperties) {
|
|
78
99
|
const initializer = scopesProp.getInitializer();
|
|
79
100
|
if (!initializer || !ts_morph_1.Node.isArrayLiteralExpression(initializer))
|
|
80
101
|
continue;
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
continue;
|
|
102
|
+
const rawTexts = [];
|
|
103
|
+
const legacyStrings = [];
|
|
104
|
+
let anyChange = false;
|
|
105
|
+
for (const element of initializer.getElements()) {
|
|
86
106
|
const scopeKey = resolveScopeKeyFromElementAccess(element);
|
|
87
107
|
if (scopeKey && !(scopeKey in scopes_deprecated_do_not_use_1.SCOPES)) {
|
|
88
108
|
// eslint-disable-next-line no-console
|
|
89
|
-
console.warn(` [${
|
|
90
|
-
initializer.removeElement(index);
|
|
109
|
+
console.warn(` [${relPath}] Removing unknown scope reference: SCOPES.${scopeKey}`);
|
|
91
110
|
removedCount++;
|
|
111
|
+
anyChange = true;
|
|
92
112
|
continue;
|
|
93
113
|
}
|
|
94
114
|
const legacyScope = resolveLegacyScopeFromElement(element);
|
|
95
115
|
if (!legacyScope) {
|
|
96
116
|
// eslint-disable-next-line no-console
|
|
97
|
-
console.warn(` [${
|
|
117
|
+
console.warn(` [${relPath}] Preserving non-literal scope expression verbatim: ${element.getText()}`);
|
|
118
|
+
rawTexts.push(element.getText());
|
|
98
119
|
continue;
|
|
99
120
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
// eslint-disable-next-line no-console
|
|
113
|
-
console.warn(` [${path_1.default.relative(process.cwd(), rolesFilePath)}] Could not migrate scope '${legacyScope}': ${error}`);
|
|
114
|
-
}
|
|
121
|
+
legacyStrings.push(legacyScope);
|
|
122
|
+
anyChange = true;
|
|
123
|
+
}
|
|
124
|
+
if (!anyChange)
|
|
125
|
+
continue;
|
|
126
|
+
let mergedScopes;
|
|
127
|
+
try {
|
|
128
|
+
mergedScopes = (0, scopes_deprecated_do_not_use_1.migrateLegacyScopesArrayToV2Scopes)(legacyStrings);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
throw new Error(`[${relPath}] Failed to migrate scopes for role: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
115
132
|
}
|
|
133
|
+
migratedCount += legacyStrings.length;
|
|
134
|
+
mergedCount += legacyStrings.length - mergedScopes.length;
|
|
135
|
+
const outputElements = [
|
|
136
|
+
...rawTexts,
|
|
137
|
+
...mergedScopes.map((s) => JSON.stringify(s))
|
|
138
|
+
];
|
|
139
|
+
scopesProp.setInitializer(`[${outputElements.join(', ')}]`);
|
|
116
140
|
}
|
|
117
141
|
if (removedCount > 0) {
|
|
118
142
|
// eslint-disable-next-line no-console
|
|
119
|
-
console.log(` Removed ${removedCount} unknown SCOPES reference(s) from '${
|
|
143
|
+
console.log(` Removed ${removedCount} unknown SCOPES reference(s) from '${relPath}'.`);
|
|
120
144
|
}
|
|
121
|
-
return { migratedCount, removedCount };
|
|
145
|
+
return { migratedCount, removedCount, mergedCount };
|
|
122
146
|
}
|
|
123
147
|
function ensureScopesHelpersImport(rolesFilePath, project) {
|
|
124
148
|
const sourceFile = project.getSourceFile(rolesFilePath);
|
|
@@ -262,7 +286,7 @@ function main() {
|
|
|
262
286
|
return;
|
|
263
287
|
}
|
|
264
288
|
const importChanged = ensureScopesHelpersImport(rolesFilePath, project);
|
|
265
|
-
const { migratedCount, removedCount } = migrateScopesArrays(rolesFilePath, project);
|
|
289
|
+
const { migratedCount, removedCount, mergedCount } = migrateScopesArrays(rolesFilePath, project);
|
|
266
290
|
const wrappedScopesCount = wrapScopesArraysWithDefineScopes(rolesFilePath, project);
|
|
267
291
|
const wrappedRoles = wrapRolesWithDefineRoles(rolesFilePath, project);
|
|
268
292
|
const removedRoleType = removeRoleTypeDefinitionAndUnusedImports(rolesFilePath, project);
|
|
@@ -276,6 +300,6 @@ function main() {
|
|
|
276
300
|
return;
|
|
277
301
|
}
|
|
278
302
|
yield sourceFile.save();
|
|
279
|
-
console.log(`Done. Migrated ${migratedCount} legacy scope(s), removed ${removedCount} unknown SCOPES reference(s), wrapped ${wrappedScopesCount} scope array(s) with defineScopes()${wrappedRoles ? ', wrapped roles with defineRoles()' : ''}${removedRoleType ? ', and removed Role type definition' : ''}${importChanged ? '. Updated toolkit/scopes imports.' : '.'}`);
|
|
303
|
+
console.log(`Done. Migrated ${migratedCount} legacy scope(s), merged ${mergedCount} AND-paired scope(s) into single v2 objects (privilege-escalation fix, see issue #12489), removed ${removedCount} unknown SCOPES reference(s), wrapped ${wrappedScopesCount} scope array(s) with defineScopes()${wrappedRoles ? ', wrapped roles with defineRoles()' : ''}${removedRoleType ? ', and removed Role type definition' : ''}${importChanged ? '. Updated toolkit/scopes imports.' : '.'}`);
|
|
280
304
|
});
|
|
281
305
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-workqueue-configs.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/migrate-workqueue-configs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrate-workqueue-configs.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/migrate-workqueue-configs.ts"],"names":[],"mappings":"AAgVA,iBAAe,IAAI,kBAqDlB;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
|
|
@@ -39,6 +39,10 @@ exports.main = main;
|
|
|
39
39
|
* - `actions: [{...}, {...}, ...]` -> keeps first as `action`, warns about dropped extras
|
|
40
40
|
* - If `action` already exists, removes deprecated `actions` and keeps `action`
|
|
41
41
|
* - Removes unsupported `action.type` values (`DEFAULT`, `VALIDATE`, etc.)
|
|
42
|
+
* - Ensures every workqueue ends up with a valid `action`. When none is
|
|
43
|
+
* present (or the existing one is unsupported), falls back to
|
|
44
|
+
* `action: { type: ActionType.READ }` and ensures `ActionType` is imported
|
|
45
|
+
* from `@opencrvs/toolkit/events` in the file.
|
|
42
46
|
* - Saves modified files in-place
|
|
43
47
|
*/
|
|
44
48
|
const ts_morph_1 = require("ts-morph");
|
|
@@ -49,6 +53,10 @@ const ACTION_PROPERTY_NAME = 'action';
|
|
|
49
53
|
const CONDITIONALS_PROPERTY_NAME = 'conditionals';
|
|
50
54
|
const TYPE_PROPERTY_NAME = 'type';
|
|
51
55
|
const SLUG_PROPERTY_NAME = 'slug';
|
|
56
|
+
const READ_ACTION_TYPE = 'READ';
|
|
57
|
+
const ACTION_TYPE_IMPORT_NAME = 'ActionType';
|
|
58
|
+
const TOOLKIT_EVENTS_MODULE = '@opencrvs/toolkit/events';
|
|
59
|
+
const READ_ACTION_FALLBACK_INITIALIZER = `{ type: ${ACTION_TYPE_IMPORT_NAME}.${READ_ACTION_TYPE} }`;
|
|
52
60
|
const SUPPORTED_WORKQUEUE_ACTION_TYPES = new Set([
|
|
53
61
|
'READ',
|
|
54
62
|
'DELETE',
|
|
@@ -96,80 +104,146 @@ function isUnsupportedActionType(action) {
|
|
|
96
104
|
}
|
|
97
105
|
return !SUPPORTED_WORKQUEUE_ACTION_TYPES.has(typeName);
|
|
98
106
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Ensures the workqueue has a valid singular `action` property. When the
|
|
109
|
+
* existing `action` is missing or has an unsupported type, replaces it with
|
|
110
|
+
* `action: { type: ActionType.READ }`.
|
|
111
|
+
*
|
|
112
|
+
* Returns whether anything was changed and whether the READ fallback was
|
|
113
|
+
* applied (so the caller can ensure `ActionType` is imported in the file).
|
|
114
|
+
*/
|
|
115
|
+
function ensureValidAction(workqueue, relPath) {
|
|
116
|
+
const workqueueLabel = getWorkqueueLabel(workqueue);
|
|
117
|
+
const actionProperty = workqueue.getProperty(ACTION_PROPERTY_NAME);
|
|
118
|
+
if (actionProperty && ts_morph_1.Node.isPropertyAssignment(actionProperty)) {
|
|
119
|
+
const initializer = actionProperty.getInitializer();
|
|
120
|
+
if (initializer && ts_morph_1.Node.isObjectLiteralExpression(initializer)) {
|
|
121
|
+
if (!isUnsupportedActionType(initializer)) {
|
|
122
|
+
return { changed: false, usedReadFallback: false };
|
|
123
|
+
}
|
|
124
|
+
actionProperty.set({
|
|
125
|
+
name: ACTION_PROPERTY_NAME,
|
|
126
|
+
initializer: READ_ACTION_FALLBACK_INITIALIZER
|
|
127
|
+
});
|
|
128
|
+
// eslint-disable-next-line no-console
|
|
129
|
+
console.log(` [${relPath}] Replaced unsupported 'action' type with '${ACTION_TYPE_IMPORT_NAME}.${READ_ACTION_TYPE}' on workqueue '${workqueueLabel}'`);
|
|
130
|
+
return { changed: true, usedReadFallback: true };
|
|
131
|
+
}
|
|
107
132
|
}
|
|
133
|
+
workqueue.addPropertyAssignment({
|
|
134
|
+
name: ACTION_PROPERTY_NAME,
|
|
135
|
+
initializer: READ_ACTION_FALLBACK_INITIALIZER
|
|
136
|
+
});
|
|
137
|
+
// eslint-disable-next-line no-console
|
|
138
|
+
console.log(` [${relPath}] Added default 'action: ${READ_ACTION_FALLBACK_INITIALIZER}' to workqueue '${workqueueLabel}'`);
|
|
139
|
+
return { changed: true, usedReadFallback: true };
|
|
140
|
+
}
|
|
141
|
+
function migrateWorkqueueActions(workqueue, relPath) {
|
|
108
142
|
const workqueueLabel = getWorkqueueLabel(workqueue);
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
143
|
+
const actionsProperty = workqueue.getProperty(ACTIONS_PROPERTY_NAME);
|
|
144
|
+
let actionsArrayMigrated = false;
|
|
145
|
+
if (actionsProperty && ts_morph_1.Node.isPropertyAssignment(actionsProperty)) {
|
|
146
|
+
const actionsInitializer = actionsProperty.getInitializer();
|
|
147
|
+
if (actionsInitializer &&
|
|
148
|
+
ts_morph_1.Node.isArrayLiteralExpression(actionsInitializer)) {
|
|
149
|
+
const existingActionProperty = workqueue.getProperty(ACTION_PROPERTY_NAME);
|
|
150
|
+
if (existingActionProperty) {
|
|
151
|
+
if (ts_morph_1.Node.isPropertyAssignment(existingActionProperty)) {
|
|
152
|
+
const existingActionInitializer = existingActionProperty.getInitializer();
|
|
153
|
+
if (existingActionInitializer &&
|
|
154
|
+
ts_morph_1.Node.isObjectLiteralExpression(existingActionInitializer)) {
|
|
155
|
+
const conditionalsProperty = existingActionInitializer.getProperty(CONDITIONALS_PROPERTY_NAME);
|
|
156
|
+
if (conditionalsProperty) {
|
|
157
|
+
conditionalsProperty.remove();
|
|
158
|
+
// eslint-disable-next-line no-console
|
|
159
|
+
console.log(` [${relPath}] Removed deprecated 'conditionals' from 'action' on workqueue '${workqueueLabel}'`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
119
162
|
}
|
|
120
|
-
|
|
121
|
-
|
|
163
|
+
actionsProperty.remove();
|
|
164
|
+
// eslint-disable-next-line no-console
|
|
165
|
+
console.log(` [${relPath}] Removed deprecated 'actions' from workqueue '${workqueueLabel}' (existing 'action' kept)`);
|
|
166
|
+
actionsArrayMigrated = true;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
const actionCandidates = actionsInitializer
|
|
170
|
+
.getElements()
|
|
171
|
+
.filter((element) => ts_morph_1.Node.isObjectLiteralExpression(element));
|
|
172
|
+
if (actionCandidates.length === 0) {
|
|
173
|
+
actionsProperty.remove();
|
|
122
174
|
// eslint-disable-next-line no-console
|
|
123
|
-
console.log(` [${relPath}] Removed
|
|
175
|
+
console.log(` [${relPath}] Removed empty 'actions' from workqueue '${workqueueLabel}'`);
|
|
176
|
+
actionsArrayMigrated = true;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
if (actionCandidates.length > 1) {
|
|
180
|
+
const droppedCount = actionCandidates.length - 1;
|
|
181
|
+
// eslint-disable-next-line no-console
|
|
182
|
+
console.warn(` [${relPath}] Workqueue '${workqueueLabel}' has ${actionCandidates.length} actions; keeping first as 'action' and dropping ${droppedCount} extra action(s)`);
|
|
183
|
+
}
|
|
184
|
+
const conditionalsProperty = actionCandidates[0].getProperty(CONDITIONALS_PROPERTY_NAME);
|
|
185
|
+
if (conditionalsProperty) {
|
|
186
|
+
conditionalsProperty.remove();
|
|
187
|
+
// eslint-disable-next-line no-console
|
|
188
|
+
console.log(` [${relPath}] Removed deprecated 'conditionals' from migrated 'action' on workqueue '${workqueueLabel}'`);
|
|
189
|
+
}
|
|
190
|
+
if (isUnsupportedActionType(actionCandidates[0])) {
|
|
191
|
+
actionsProperty.remove();
|
|
192
|
+
// eslint-disable-next-line no-console
|
|
193
|
+
console.log(` [${relPath}] Removed deprecated 'actions' from workqueue '${workqueueLabel}' because action type is unsupported`);
|
|
194
|
+
actionsArrayMigrated = true;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
const firstActionText = actionCandidates[0].getText();
|
|
198
|
+
workqueue.addPropertyAssignment({
|
|
199
|
+
name: ACTION_PROPERTY_NAME,
|
|
200
|
+
initializer: firstActionText
|
|
201
|
+
});
|
|
202
|
+
actionsProperty.remove();
|
|
203
|
+
// eslint-disable-next-line no-console
|
|
204
|
+
console.log(` [${relPath}] Replaced 'actions' with 'action' on workqueue '${workqueueLabel}'`);
|
|
205
|
+
actionsArrayMigrated = true;
|
|
206
|
+
}
|
|
124
207
|
}
|
|
125
208
|
}
|
|
126
209
|
}
|
|
127
|
-
actionsProperty.remove();
|
|
128
|
-
// eslint-disable-next-line no-console
|
|
129
|
-
console.log(` [${relPath}] Removed deprecated 'actions' from workqueue '${workqueueLabel}' (existing 'action' kept)`);
|
|
130
|
-
return 1;
|
|
131
|
-
}
|
|
132
|
-
const actionCandidates = actionsInitializer
|
|
133
|
-
.getElements()
|
|
134
|
-
.filter((element) => ts_morph_1.Node.isObjectLiteralExpression(element));
|
|
135
|
-
if (actionCandidates.length === 0) {
|
|
136
|
-
actionsProperty.remove();
|
|
137
|
-
// eslint-disable-next-line no-console
|
|
138
|
-
console.log(` [${relPath}] Removed empty 'actions' from workqueue '${workqueueLabel}'`);
|
|
139
|
-
return 1;
|
|
140
|
-
}
|
|
141
|
-
if (actionCandidates.length > 1) {
|
|
142
|
-
const droppedCount = actionCandidates.length - 1;
|
|
143
|
-
// eslint-disable-next-line no-console
|
|
144
|
-
console.warn(` [${relPath}] Workqueue '${workqueueLabel}' has ${actionCandidates.length} actions; keeping first as 'action' and dropping ${droppedCount} extra action(s)`);
|
|
145
|
-
}
|
|
146
|
-
const conditionalsProperty = actionCandidates[0].getProperty(CONDITIONALS_PROPERTY_NAME);
|
|
147
|
-
if (conditionalsProperty) {
|
|
148
|
-
conditionalsProperty.remove();
|
|
149
|
-
// eslint-disable-next-line no-console
|
|
150
|
-
console.log(` [${relPath}] Removed deprecated 'conditionals' from migrated 'action' on workqueue '${workqueueLabel}'`);
|
|
151
210
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
211
|
+
// Always ensure the workqueue ends up with a valid `action`. This both
|
|
212
|
+
// covers workqueues that never had an `actions` array, and patches up
|
|
213
|
+
// workqueues whose existing/migrated action type is unsupported.
|
|
214
|
+
const fallback = ensureValidAction(workqueue, relPath);
|
|
215
|
+
return {
|
|
216
|
+
changed: actionsArrayMigrated || fallback.changed,
|
|
217
|
+
usedReadFallback: fallback.usedReadFallback
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Ensures `import { ActionType } from '@opencrvs/toolkit/events'` exists in
|
|
222
|
+
* the source file, merging into any existing import declaration from the
|
|
223
|
+
* same module specifier.
|
|
224
|
+
*/
|
|
225
|
+
function ensureActionTypeImport(sourceFile) {
|
|
226
|
+
const existingImport = sourceFile.getImportDeclaration((decl) => decl.getModuleSpecifierValue() === TOOLKIT_EVENTS_MODULE);
|
|
227
|
+
if (existingImport) {
|
|
228
|
+
const alreadyImported = existingImport
|
|
229
|
+
.getNamedImports()
|
|
230
|
+
.some((ni) => ni.getName() === ACTION_TYPE_IMPORT_NAME);
|
|
231
|
+
if (!alreadyImported) {
|
|
232
|
+
existingImport.addNamedImport(ACTION_TYPE_IMPORT_NAME);
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
157
235
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
initializer: firstActionText
|
|
236
|
+
sourceFile.addImportDeclaration({
|
|
237
|
+
moduleSpecifier: TOOLKIT_EVENTS_MODULE,
|
|
238
|
+
namedImports: [ACTION_TYPE_IMPORT_NAME]
|
|
162
239
|
});
|
|
163
|
-
actionsProperty.remove();
|
|
164
|
-
// eslint-disable-next-line no-console
|
|
165
|
-
console.log(` [${relPath}] Replaced 'actions' with 'action' on workqueue '${workqueueLabel}'`);
|
|
166
|
-
return 1;
|
|
167
240
|
}
|
|
168
241
|
function processFile(filePath, project) {
|
|
169
242
|
const sourceFile = project.getSourceFile(filePath);
|
|
170
243
|
if (!sourceFile)
|
|
171
244
|
return 0;
|
|
172
245
|
let migratedWorkqueues = 0;
|
|
246
|
+
let needsActionTypeImport = false;
|
|
173
247
|
const relPath = path_1.default.relative(process.cwd(), filePath);
|
|
174
248
|
const callExpressions = sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression);
|
|
175
249
|
for (const call of callExpressions) {
|
|
@@ -187,9 +261,16 @@ function processFile(filePath, project) {
|
|
|
187
261
|
for (const element of workqueuesArg.getElements()) {
|
|
188
262
|
if (!ts_morph_1.Node.isObjectLiteralExpression(element))
|
|
189
263
|
continue;
|
|
190
|
-
|
|
264
|
+
const result = migrateWorkqueueActions(element, relPath);
|
|
265
|
+
if (result.changed)
|
|
266
|
+
migratedWorkqueues++;
|
|
267
|
+
if (result.usedReadFallback)
|
|
268
|
+
needsActionTypeImport = true;
|
|
191
269
|
}
|
|
192
270
|
}
|
|
271
|
+
if (needsActionTypeImport) {
|
|
272
|
+
ensureActionTypeImport(sourceFile);
|
|
273
|
+
}
|
|
193
274
|
return migratedWorkqueues;
|
|
194
275
|
}
|
|
195
276
|
function main() {
|