@opencrvs/toolkit 2.0.0-rc.fc7f7fc → 2.0.0-rc.fef9d21

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.
Files changed (70) hide show
  1. package/dist/cli.js +1383 -142
  2. package/dist/commons/api/router.d.ts +42 -63
  3. package/dist/migrations/v2.0/add-birth-certificate-issuance-flag.d.ts.map +1 -1
  4. package/dist/migrations/v2.0/add-birth-certificate-issuance-flag.js +3 -4
  5. package/dist/migrations/v2.0/add-resend-invite-notification.d.ts +3 -0
  6. package/dist/migrations/v2.0/add-resend-invite-notification.d.ts.map +1 -0
  7. package/dist/migrations/v2.0/add-resend-invite-notification.js +373 -0
  8. package/dist/migrations/v2.0/checkout-upstream-files.d.ts +19 -0
  9. package/dist/migrations/v2.0/checkout-upstream-files.d.ts.map +1 -1
  10. package/dist/migrations/v2.0/checkout-upstream-files.js +17 -13
  11. package/dist/migrations/v2.0/convert-config-files-to-ts.d.ts.map +1 -1
  12. package/dist/migrations/v2.0/convert-config-files-to-ts.js +4 -5
  13. package/dist/migrations/v2.0/convert-paragraph-to-heading.d.ts.map +1 -1
  14. package/dist/migrations/v2.0/convert-paragraph-to-heading.js +4 -5
  15. package/dist/migrations/v2.0/create-events-index.d.ts.map +1 -1
  16. package/dist/migrations/v2.0/create-events-index.js +1 -2
  17. package/dist/migrations/v2.0/delete-infrastructure-directory.d.ts +3 -0
  18. package/dist/migrations/v2.0/delete-infrastructure-directory.d.ts.map +1 -0
  19. package/dist/migrations/v2.0/delete-infrastructure-directory.js +77 -0
  20. package/dist/migrations/v2.0/index.d.ts +8 -4
  21. package/dist/migrations/v2.0/index.d.ts.map +1 -1
  22. package/dist/migrations/v2.0/index.js +1351 -139
  23. package/dist/migrations/v2.0/make-built-in-validate-actions-custom.d.ts.map +1 -1
  24. package/dist/migrations/v2.0/make-built-in-validate-actions-custom.js +5 -6
  25. package/dist/migrations/v2.0/merge-infrastructure-directory.d.ts +3 -0
  26. package/dist/migrations/v2.0/merge-infrastructure-directory.d.ts.map +1 -0
  27. package/dist/migrations/v2.0/merge-infrastructure-directory.js +221 -0
  28. package/dist/migrations/v2.0/migrate-application-config-url.d.ts +3 -0
  29. package/dist/migrations/v2.0/migrate-application-config-url.d.ts.map +1 -0
  30. package/dist/migrations/v2.0/migrate-application-config-url.js +342 -0
  31. package/dist/migrations/v2.0/migrate-scopes.d.ts.map +1 -1
  32. package/dist/migrations/v2.0/migrate-scopes.js +6 -7
  33. package/dist/migrations/v2.0/migrate-validated-workqueue-status-to-flag.d.ts.map +1 -1
  34. package/dist/migrations/v2.0/migrate-validated-workqueue-status-to-flag.js +3 -4
  35. package/dist/migrations/v2.0/migrate-workqueue-configs.d.ts.map +1 -1
  36. package/dist/migrations/v2.0/migrate-workqueue-configs.js +3 -4
  37. package/dist/migrations/v2.0/remove-delete-actions.d.ts.map +1 -1
  38. package/dist/migrations/v2.0/remove-delete-actions.js +3 -4
  39. package/dist/migrations/v2.0/remove-demo-scope.d.ts.map +1 -1
  40. package/dist/migrations/v2.0/remove-demo-scope.js +2 -3
  41. package/dist/migrations/v2.0/remove-deprecated-imports.d.ts.map +1 -1
  42. package/dist/migrations/v2.0/remove-deprecated-imports.js +3 -4
  43. package/dist/migrations/v2.0/remove-fhir-url-helpers.d.ts +3 -0
  44. package/dist/migrations/v2.0/remove-fhir-url-helpers.d.ts.map +1 -0
  45. package/dist/migrations/v2.0/remove-fhir-url-helpers.js +163 -0
  46. package/dist/migrations/v2.0/remove-hearth-migrations.d.ts.map +1 -1
  47. package/dist/migrations/v2.0/remove-hearth-migrations.js +1 -2
  48. package/dist/migrations/v2.0/remove-old-statistics-service.d.ts +3 -0
  49. package/dist/migrations/v2.0/remove-old-statistics-service.d.ts.map +1 -0
  50. package/dist/migrations/v2.0/remove-old-statistics-service.js +356 -0
  51. package/dist/migrations/v2.0/remove-pending-certification-flag.d.ts.map +1 -1
  52. package/dist/migrations/v2.0/remove-pending-certification-flag.js +3 -4
  53. package/dist/migrations/v2.0/remove-review-from-register-action.d.ts.map +1 -1
  54. package/dist/migrations/v2.0/remove-review-from-register-action.js +3 -4
  55. package/dist/migrations/v2.0/remove-unused-environment-variables.d.ts +3 -0
  56. package/dist/migrations/v2.0/remove-unused-environment-variables.d.ts.map +1 -0
  57. package/dist/migrations/v2.0/remove-unused-environment-variables.js +186 -0
  58. package/dist/migrations/v2.0/rename-api-paths.d.ts.map +1 -1
  59. package/dist/migrations/v2.0/rename-api-paths.js +3 -4
  60. package/dist/migrations/v2.0/rename-location-parent-id.d.ts.map +1 -1
  61. package/dist/migrations/v2.0/rename-location-parent-id.js +3 -4
  62. package/dist/migrations/v2.0/simplify-analytics-precalculations.d.ts.map +1 -1
  63. package/dist/migrations/v2.0/simplify-analytics-precalculations.js +1 -2
  64. package/dist/migrations/v2.0/update-package-json.d.ts +3 -0
  65. package/dist/migrations/v2.0/update-package-json.d.ts.map +1 -0
  66. package/dist/migrations/v2.0/update-package-json.js +105 -0
  67. package/opencrvs-toolkit-2.0.0-rc.fef9d21.tgz +0 -0
  68. package/package.json +1 -1
  69. package/tsconfig.tsbuildinfo +1 -1
  70. package/opencrvs-toolkit-2.0.0-rc.fc7f7fc.tgz +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"make-built-in-validate-actions-custom.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/make-built-in-validate-actions-custom.ts"],"names":[],"mappings":"AA6WA,iBAAe,IAAI,kBAiDlB;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
1
+ {"version":3,"file":"make-built-in-validate-actions-custom.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/make-built-in-validate-actions-custom.ts"],"names":[],"mappings":"AA2WA,iBAAe,IAAI,kBAiDlB;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
@@ -45,7 +45,6 @@ exports.main = main;
45
45
  */
46
46
  const ts_morph_1 = require("ts-morph");
47
47
  const path_1 = __importDefault(require("path"));
48
- const _1 = require(".");
49
48
  const TOOLKIT_EVENTS_MODULE = '@opencrvs/toolkit/events';
50
49
  const REQUIRED_SYMBOLS = [
51
50
  'ConditionalType',
@@ -263,7 +262,7 @@ function processFile(filePath, project) {
263
262
  // Resolve the root event type for use in the auditHistoryLabel id
264
263
  const eventType = resolveEventType(configArg);
265
264
  if (!eventType) {
266
- console.warn(` [${path_1.default.relative((0, _1.getCwd)(), configArg.getSourceFile().getFilePath())}] Could not resolve root 'type' from defineConfig — skipping auditHistoryLabel id generation`);
265
+ console.warn(` [${path_1.default.relative(process.cwd(), configArg.getSourceFile().getFilePath())}] Could not resolve root 'type' from defineConfig — skipping auditHistoryLabel id generation`);
267
266
  }
268
267
  // Iterate over every element in the `actions` array
269
268
  let fileNeedsImports = false;
@@ -276,7 +275,7 @@ function processFile(filePath, project) {
276
275
  transformedCount++;
277
276
  fileNeedsImports = true;
278
277
  configHadValidateAction = true;
279
- console.log(` [${path_1.default.relative((0, _1.getCwd)(), filePath)}] Transformed VALIDATE action to CUSTOM with customActionType: '${VALIDATE_DECLARATION_VALUE}'`);
278
+ console.log(` [${path_1.default.relative(process.cwd(), filePath)}] Transformed VALIDATE action to CUSTOM with customActionType: '${VALIDATE_DECLARATION_VALUE}'`);
280
279
  }
281
280
  }
282
281
  // Add top-level flags array to the config object if a VALIDATE action was found
@@ -296,7 +295,7 @@ function processFile(filePath, project) {
296
295
  }
297
296
  ]`
298
297
  });
299
- console.log(` [${path_1.default.relative((0, _1.getCwd)(), filePath)}] Added top-level 'flags' array to defineConfig`);
298
+ console.log(` [${path_1.default.relative(process.cwd(), filePath)}] Added top-level 'flags' array to defineConfig`);
300
299
  }
301
300
  if (fileNeedsImports) {
302
301
  ensureImports(sourceFile);
@@ -306,7 +305,7 @@ function processFile(filePath, project) {
306
305
  }
307
306
  function main() {
308
307
  return __awaiter(this, void 0, void 0, function* () {
309
- const srcDir = path_1.default.join((0, _1.getCwd)(), 'src');
308
+ const srcDir = path_1.default.join(process.cwd(), 'src');
310
309
  console.log(`Scanning for defineConfig calls in: ${srcDir}\n`);
311
310
  const project = new ts_morph_1.Project({
312
311
  tsConfigFilePath: path_1.default.resolve(srcDir, '../tsconfig.json'),
@@ -337,7 +336,7 @@ function main() {
337
336
  for (const filePath of modifiedFiles) {
338
337
  const sourceFile = project.getSourceFileOrThrow(filePath);
339
338
  yield sourceFile.save();
340
- console.log(` Saved: ${path_1.default.relative((0, _1.getCwd)(), filePath)}`);
339
+ console.log(` Saved: ${path_1.default.relative(process.cwd(), filePath)}`);
341
340
  }
342
341
  console.log(`\nDone. Transformed ${totalTransformed} VALIDATE action(s) to CUSTOM with customActionType: '${VALIDATE_DECLARATION_VALUE}'.`);
343
342
  });
@@ -0,0 +1,3 @@
1
+ declare function main(): Promise<void>;
2
+ export { main };
3
+ //# sourceMappingURL=merge-infrastructure-directory.d.ts.map
@@ -0,0 +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,IAAI,OAAO,CAAC,IAAI,CAAC,CAkInC;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ /*
3
+ * This Source Code Form is subject to the terms of the Mozilla Public
4
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
5
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
+ *
7
+ * OpenCRVS is also distributed under the terms of the Civil Registration
8
+ * & Healthcare Disclaimer located at http://opencrvs.org/license.
9
+ *
10
+ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
11
+ */
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.main = main;
23
+ /**
24
+ * Codemod: Merge upstream changes into the local `infrastructure/` directory
25
+ * from opencrvs/opencrvs-countryconfig.
26
+ *
27
+ * Usage:
28
+ * ts-node -r tsconfig-paths/register src/migrations/v2.0/merge-infrastructure-directory.ts
29
+ *
30
+ * What it does:
31
+ * 1. Registers a temporary git remote that points at the canonical
32
+ * opencrvs-countryconfig repository and fetches both:
33
+ * - the upstream "theirs" branch (v2.0) → `UPSTREAM_BRANCH`
34
+ * - the synthetic merge-base branch (latest 1.9 release line)
35
+ * → `BASE_BRANCH`
36
+ * 2. For every file under `infrastructure/` on upstream "theirs", performs
37
+ * a file-scoped 3-way merge:
38
+ * - new file on upstream → checked out and staged
39
+ * - existing file → 3-way merged in place via `git merge-file`,
40
+ * using the BASE_BRANCH version of the file
41
+ * as the ancestor (or an empty file if the
42
+ * base doesn't have it)
43
+ * Files local to the country config that don't exist on upstream are
44
+ * left untouched.
45
+ * 3. Cleanly merged files are staged. Files with conflicts are left in the
46
+ * working tree with standard <<<<<<< / ======= / >>>>>>> markers and
47
+ * MUST be resolved manually by the developer.
48
+ * 4. Removes the temporary remote in all cases (success, failure, or
49
+ * unexpected error) via a `finally` block.
50
+ *
51
+ * Why a content-based synthetic merge-base instead of `git merge-base`:
52
+ * - Country config repos rarely share git history with
53
+ * opencrvs-countryconfig (squashed forks, template-cloned repos, etc.),
54
+ * so `git merge-base HEAD upstream/develop` typically returns nothing.
55
+ * - With no merge-base, a 3-way merge degenerates to a 2-way diff against
56
+ * an empty file — every line that differs becomes a conflict.
57
+ * - `release-v1.9` is the latest 1.9.x release line on upstream and is a
58
+ * near-perfect representation of "what `infrastructure/` looked like
59
+ * before v2.0", regardless of whether the fork's git history reaches it.
60
+ * - For files the country config never modified relative to that baseline,
61
+ * `git merge-file` resolves cleanly to upstream's v2.0 version. Conflicts
62
+ * are produced only where local edits genuinely overlap with v1.9 → v2.0
63
+ * upstream edits — which is what the developer needs to review anyway.
64
+ *
65
+ * Why per-file merge instead of a real `git merge`:
66
+ * - Limits the blast radius to `infrastructure/` only — no other paths
67
+ * are touched.
68
+ * - Doesn't put the repository into an in-progress merge state
69
+ * (no MERGE_HEAD), so subsequent codemods/commands behave normally.
70
+ * - Works regardless of whether the local repo shares history with
71
+ * opencrvs-countryconfig.
72
+ *
73
+ * Caveats:
74
+ * - Local edits to merged files may be overwritten where they overlap
75
+ * with upstream changes. Run on a clean working tree.
76
+ * - Requires git to be installed and network access to github.com.
77
+ * - Requires the country config working directory to be a git repo.
78
+ * - Binary files in `infrastructure/` are not merged textually; if both
79
+ * sides changed a binary file, the result will be invalid and a warning
80
+ * is printed.
81
+ * - Forks that are on a much older 1.9.x and never merged later 1.9 patches
82
+ * may see a few extra conflicts on files where 1.9.x → release-v1.9
83
+ * patches and v1.9 → v2.0 changes textually overlap.
84
+ */
85
+ const child_process_1 = require("child_process");
86
+ const fs_1 = require("fs");
87
+ const os_1 = require("os");
88
+ const path_1 = require("path");
89
+ const checkout_upstream_files_1 = require("./checkout-upstream-files");
90
+ // Distinct from the remote used by `checkout-upstream-files` so that a stale
91
+ // remote left behind by an aborted run of one codemod doesn't trip up the
92
+ // other.
93
+ const TEMP_REMOTE = 'opencrvs-upgrade-v19-v20-codemod-merge-infra';
94
+ const INFRASTRUCTURE_DIR = 'infrastructure';
95
+ // Synthetic merge-base: the tip of upstream's latest 1.9.x release line.
96
+ // We use this branch's content as the "common ancestor" for every file,
97
+ // since most country forks don't share git history with upstream.
98
+ const BASE_BRANCH = 'release-v1.9';
99
+ /**
100
+ * Reads `git show <ref>:<path>` as a Uint8Array (binary-safe).
101
+ * Returns `null` if the path doesn't exist at that ref.
102
+ */
103
+ function gitShowBytes(ref, path) {
104
+ try {
105
+ const buf = (0, child_process_1.execFileSync)('git', ['show', `${ref}:${path}`], {
106
+ cwd: process.cwd(),
107
+ stdio: ['ignore', 'pipe', 'pipe']
108
+ });
109
+ // Return a plain Uint8Array view to satisfy strict typings of `fs`
110
+ // (which want `ArrayBufferView`, not Node's `Buffer` subtype).
111
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
112
+ }
113
+ catch (_a) {
114
+ return null;
115
+ }
116
+ }
117
+ // ─── Entry point ─────────────────────────────────────────────────────────────
118
+ function main() {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ console.log(`Merging '${INFRASTRUCTURE_DIR}/' from ${checkout_upstream_files_1.UPSTREAM_URL}@${checkout_upstream_files_1.UPSTREAM_BRANCH} (base: ${BASE_BRANCH})...\n`);
121
+ (0, checkout_upstream_files_1.assertIsGitRepo)();
122
+ // Best-effort cleanup of a stale temp remote from a previous aborted run.
123
+ (0, checkout_upstream_files_1.tryGit)(['remote', 'remove', TEMP_REMOTE]);
124
+ try {
125
+ console.log(` Adding temporary remote '${TEMP_REMOTE}' → ${checkout_upstream_files_1.UPSTREAM_URL}`);
126
+ (0, checkout_upstream_files_1.runGit)(['remote', 'add', TEMP_REMOTE, checkout_upstream_files_1.UPSTREAM_URL], { silent: true });
127
+ // Fetch both branches at depth=1 — we only need their tip contents,
128
+ // not their history (the merge is content-based, not history-based).
129
+ console.log(` Fetching ${TEMP_REMOTE}/{${checkout_upstream_files_1.UPSTREAM_BRANCH},${BASE_BRANCH}} (depth 1)...`);
130
+ (0, checkout_upstream_files_1.runGit)(['fetch', '--depth=1', TEMP_REMOTE, checkout_upstream_files_1.UPSTREAM_BRANCH, BASE_BRANCH]);
131
+ const ref = `${TEMP_REMOTE}/${checkout_upstream_files_1.UPSTREAM_BRANCH}`;
132
+ const baseRef = `${TEMP_REMOTE}/${BASE_BRANCH}`;
133
+ // -z gives NUL-separated paths so filenames with spaces or newlines
134
+ // survive the round-trip.
135
+ const upstreamFiles = (0, checkout_upstream_files_1.runGit)([
136
+ 'ls-tree',
137
+ '-r',
138
+ '--name-only',
139
+ '-z',
140
+ ref,
141
+ '--',
142
+ `${INFRASTRUCTURE_DIR}/`
143
+ ], { silent: true })
144
+ .split('\0')
145
+ .filter(Boolean);
146
+ if (upstreamFiles.length === 0) {
147
+ console.log(` No files found under '${INFRASTRUCTURE_DIR}/' on ${ref}. Nothing to merge.`);
148
+ return;
149
+ }
150
+ const tmpDir = (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'opencrvs-merge-infra-'));
151
+ const baseTmp = (0, path_1.join)(tmpDir, 'base');
152
+ const theirsTmp = (0, path_1.join)(tmpDir, 'theirs');
153
+ let added = 0;
154
+ let merged = 0;
155
+ const conflictedFiles = [];
156
+ for (const file of upstreamFiles) {
157
+ const fullPath = (0, path_1.join)(process.cwd(), file);
158
+ if (!(0, fs_1.existsSync)(fullPath)) {
159
+ // New upstream file — `git checkout` handles binary correctly and
160
+ // stages the result, matching the UX of `checkout-upstream-files`.
161
+ if ((0, checkout_upstream_files_1.tryGit)(['checkout', ref, '--', file])) {
162
+ console.log(` + ${file} (new from upstream)`);
163
+ added++;
164
+ }
165
+ else {
166
+ console.warn(` [warn] failed to add new file ${file}`);
167
+ }
168
+ continue;
169
+ }
170
+ const theirContents = gitShowBytes(ref, file);
171
+ if (theirContents === null) {
172
+ // Shouldn't happen — `ls-tree` just told us the file is there.
173
+ console.warn(` [warn] could not read ${file} from ${ref} — skipping.`);
174
+ continue;
175
+ }
176
+ (0, fs_1.writeFileSync)(theirsTmp, theirContents);
177
+ // Pull the base version from upstream's latest 1.9 release line. If
178
+ // the file didn't exist there yet (added in v2.0), fall back to an
179
+ // empty base — `git merge-file` will then treat any local content as
180
+ // a local addition.
181
+ const baseContents = gitShowBytes(baseRef, file);
182
+ (0, fs_1.writeFileSync)(baseTmp, baseContents !== null && baseContents !== void 0 ? baseContents : new Uint8Array(0));
183
+ // `git merge-file` does an in-place 3-way merge. Exit codes:
184
+ // 0 → clean merge
185
+ // 1..N → that many conflicts; markers written into the file
186
+ // <0/127 → error (e.g. binary file rejected)
187
+ try {
188
+ (0, child_process_1.execFileSync)('git', ['merge-file', fullPath, baseTmp, theirsTmp], {
189
+ cwd: process.cwd(),
190
+ stdio: ['ignore', 'pipe', 'pipe']
191
+ });
192
+ (0, checkout_upstream_files_1.runGit)(['add', '--', file], { silent: true });
193
+ merged++;
194
+ }
195
+ catch (err) {
196
+ const status = err.status;
197
+ if (typeof status === 'number' && status > 0) {
198
+ conflictedFiles.push(file);
199
+ console.warn(` ! ${file} (${status} conflict${status > 1 ? 's' : ''})`);
200
+ }
201
+ else {
202
+ conflictedFiles.push(file);
203
+ console.warn(` [warn] merge failed for ${file} (likely binary or unreadable) — left untouched.`);
204
+ }
205
+ }
206
+ }
207
+ console.log(`\n Done. ${added} added, ${merged} merged cleanly, ${conflictedFiles.length} with conflicts.`);
208
+ if (conflictedFiles.length > 0) {
209
+ console.warn(`\n NOTE: ${conflictedFiles.length} file(s) under '${INFRASTRUCTURE_DIR}/' have merge conflicts that you must resolve manually.\n` +
210
+ ` Look for the standard conflict markers (<<<<<<<, =======, >>>>>>>) in:\n` +
211
+ conflictedFiles.map((f) => ` - ${f}`).join('\n') +
212
+ `\n After resolving, stage the fixes with: git add ${INFRASTRUCTURE_DIR}/`);
213
+ }
214
+ }
215
+ finally {
216
+ if ((0, checkout_upstream_files_1.tryGit)(['remote', 'remove', TEMP_REMOTE])) {
217
+ console.log(` Removed temporary remote '${TEMP_REMOTE}'.`);
218
+ }
219
+ }
220
+ });
221
+ }
@@ -0,0 +1,3 @@
1
+ declare function main(): Promise<void>;
2
+ export { main };
3
+ //# sourceMappingURL=migrate-application-config-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate-application-config-url.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/migrate-application-config-url.ts"],"names":[],"mappings":"AAwUA,iBAAe,IAAI,kBAqElB;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
@@ -0,0 +1,342 @@
1
+ "use strict";
2
+ /*
3
+ * This Source Code Form is subject to the terms of the Mozilla Public
4
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
5
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
+ *
7
+ * OpenCRVS is also distributed under the terms of the Civil Registration
8
+ * & Healthcare Disclaimer located at http://opencrvs.org/license.
9
+ *
10
+ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
11
+ */
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.main = main;
26
+ /**
27
+ * Codemod: Replace usages of the legacy `APPLICATION_CONFIG_URL` env-derived
28
+ * constant with direct usage of the v2.0 `applicationConfig` object.
29
+ *
30
+ * Background:
31
+ * In v1.9 country configs read application configuration over HTTP from
32
+ * the config service via `APPLICATION_CONFIG_URL`. In v2.0 the config is
33
+ * defined statically in `src/api/application/application-config.ts` (as
34
+ * `applicationConfig`) and consumed by import.
35
+ *
36
+ * What it does (per source file under `src/`):
37
+ * 1. If the file imports `APPLICATION_CONFIG_URL` (from any module), the
38
+ * named import is removed; if that leaves the import declaration empty,
39
+ * the whole declaration is removed.
40
+ * 2. An import of `applicationConfig` from
41
+ * `@countryconfig/api/application/application-config` is added
42
+ * (idempotent — re-uses an existing import declaration if one exists).
43
+ * 3. Block-bodied functions whose body references *both*
44
+ * `APPLICATION_CONFIG_URL` *and* a `fetch(...)` call are recognised
45
+ * as "config-fetcher" functions. Their entire body is replaced with
46
+ * `return applicationConfig` — eliminating the URL construction,
47
+ * `fetch`, JSON parsing, and unwrapping of `.config`. Callers
48
+ * (`await getApplicationConfig()` etc.) keep working because async
49
+ * functions still wrap the return value in a `Promise`.
50
+ * 4. Any remaining bare identifier references to `APPLICATION_CONFIG_URL`
51
+ * are renamed to `applicationConfig`. Property names (e.g.
52
+ * `obj.APPLICATION_CONFIG_URL` or `{ APPLICATION_CONFIG_URL: x }`)
53
+ * are left alone.
54
+ *
55
+ * Caveats:
56
+ * - Wholesale body replacement of config-fetcher functions destroys any
57
+ * custom logic the country had inlined there (error handling, derived
58
+ * fields, etc.). Each rewrite is logged so the developer can review
59
+ * the diff and re-apply customisations on top of `applicationConfig`.
60
+ * - The shape of v2.0 `applicationConfig` is not identical to the v1.9
61
+ * `IApplicationConfigResponse.config` — callers that destructured
62
+ * v1.9-only fields will produce TypeScript errors and need manual
63
+ * review.
64
+ * - Files that have a local declaration named `applicationConfig` are
65
+ * skipped to avoid a name collision; a warning is logged so the
66
+ * developer can resolve it manually.
67
+ * - Files that reference `APPLICATION_CONFIG_URL` *without* importing it
68
+ * (e.g. as a local variable) are skipped — we only rewrite imported
69
+ * usages.
70
+ * - Concise-body arrow functions (`() => fetch(...)`) are not
71
+ * body-rewritten — only their identifier is renamed in step 4. If a
72
+ * country happens to inline the fetch in concise form, the result
73
+ * will need manual cleanup.
74
+ */
75
+ const path_1 = __importDefault(require("path"));
76
+ const ts_morph_1 = require("ts-morph");
77
+ const TARGET_IDENTIFIER = 'APPLICATION_CONFIG_URL';
78
+ const REPLACEMENT_IDENTIFIER = 'applicationConfig';
79
+ const REPLACEMENT_MODULE = '@countryconfig/api/application/application-config';
80
+ /**
81
+ * Function-like syntax kinds whose `body` we know how to replace via
82
+ * `setBodyText` (i.e. block-bodied callables).
83
+ */
84
+ const FUNCTION_LIKE_KINDS = [
85
+ ts_morph_1.SyntaxKind.FunctionDeclaration,
86
+ ts_morph_1.SyntaxKind.FunctionExpression,
87
+ ts_morph_1.SyntaxKind.ArrowFunction,
88
+ ts_morph_1.SyntaxKind.MethodDeclaration
89
+ ];
90
+ /**
91
+ * Returns the name of the function-like node for logging purposes.
92
+ * Falls back to `<anonymous>` when nothing useful can be derived.
93
+ */
94
+ function describeFunction(node) {
95
+ var _a, _b, _c;
96
+ if (ts_morph_1.Node.isFunctionDeclaration(node) || ts_morph_1.Node.isMethodDeclaration(node)) {
97
+ return (_a = node.getName()) !== null && _a !== void 0 ? _a : '<anonymous>';
98
+ }
99
+ // FunctionExpression / ArrowFunction: try to pick up the assignment target.
100
+ const parent = node.getParent();
101
+ if (parent && ts_morph_1.Node.isVariableDeclaration(parent)) {
102
+ return parent.getName();
103
+ }
104
+ if (parent && ts_morph_1.Node.isPropertyAssignment(parent)) {
105
+ return parent.getName();
106
+ }
107
+ if (ts_morph_1.Node.isFunctionExpression(node) &&
108
+ node.getNameNode() !== undefined) {
109
+ return (_c = (_b = node.getNameNode()) === null || _b === void 0 ? void 0 : _b.getText()) !== null && _c !== void 0 ? _c : '<anonymous>';
110
+ }
111
+ return '<anonymous>';
112
+ }
113
+ /**
114
+ * True when the node has a block body that we can safely replace via
115
+ * `setBodyText` (excludes concise-body arrow functions like `() => 1`).
116
+ */
117
+ function hasBlockBody(node) {
118
+ if (ts_morph_1.Node.isFunctionDeclaration(node) ||
119
+ ts_morph_1.Node.isFunctionExpression(node) ||
120
+ ts_morph_1.Node.isMethodDeclaration(node)) {
121
+ return node.getBody() !== undefined;
122
+ }
123
+ if (ts_morph_1.Node.isArrowFunction(node)) {
124
+ return node.getBody().getKind() === ts_morph_1.SyntaxKind.Block;
125
+ }
126
+ return false;
127
+ }
128
+ /**
129
+ * True when the node's body references `APPLICATION_CONFIG_URL` AND
130
+ * contains at least one `fetch(...)` call — the "config-fetcher" signature.
131
+ */
132
+ function isConfigFetcher(node) {
133
+ let referencesTarget = false;
134
+ let callsFetch = false;
135
+ for (const id of node.getDescendantsOfKind(ts_morph_1.SyntaxKind.Identifier)) {
136
+ const text = id.getText();
137
+ if (!referencesTarget && text === TARGET_IDENTIFIER)
138
+ referencesTarget = true;
139
+ if (!callsFetch && text === 'fetch') {
140
+ // Only count `fetch(` calls, not bare references like
141
+ // `const f = fetch` (rare, but pedantic).
142
+ const parent = id.getParent();
143
+ if (ts_morph_1.Node.isCallExpression(parent) &&
144
+ parent.getExpression() === id) {
145
+ callsFetch = true;
146
+ }
147
+ }
148
+ if (referencesTarget && callsFetch)
149
+ return true;
150
+ }
151
+ return false;
152
+ }
153
+ function processFile(sourceFile) {
154
+ const importsWithTarget = sourceFile
155
+ .getImportDeclarations()
156
+ .filter((decl) => decl.getNamedImports().some((ni) => ni.getName() === TARGET_IDENTIFIER));
157
+ if (importsWithTarget.length === 0) {
158
+ return { changed: false, rewrittenFunctions: [], renamedReferences: 0 };
159
+ }
160
+ // Bail out if a same-named local would collide with the new identifier.
161
+ // Imported `applicationConfig` doesn't count as a local declaration.
162
+ const collidingLocals = sourceFile
163
+ .getDescendantsOfKind(ts_morph_1.SyntaxKind.Identifier)
164
+ .filter((id) => id.getText() === REPLACEMENT_IDENTIFIER)
165
+ .filter((id) => {
166
+ const parent = id.getParent();
167
+ const kind = parent.getKind();
168
+ return (kind === ts_morph_1.SyntaxKind.VariableDeclaration ||
169
+ kind === ts_morph_1.SyntaxKind.FunctionDeclaration ||
170
+ kind === ts_morph_1.SyntaxKind.ClassDeclaration ||
171
+ kind === ts_morph_1.SyntaxKind.Parameter);
172
+ });
173
+ if (collidingLocals.length > 0) {
174
+ return {
175
+ changed: false,
176
+ rewrittenFunctions: [],
177
+ renamedReferences: 0,
178
+ skippedReason: `local declaration named '${REPLACEMENT_IDENTIFIER}' would collide`
179
+ };
180
+ }
181
+ // ─── 1. Rewrite "config-fetcher" function bodies ───────────────────────
182
+ // We only replace block-bodied functions that reference both
183
+ // APPLICATION_CONFIG_URL and `fetch(...)`. The bodies are replaced with
184
+ // `return applicationConfig`, which works for both sync and async
185
+ // functions (the latter automatically wraps the value in a Promise).
186
+ const candidateFunctions = FUNCTION_LIKE_KINDS.flatMap((kind) => sourceFile.getDescendantsOfKind(kind));
187
+ // Outermost-first: when functions are nested, rewriting the outer one
188
+ // also discards the inner one, so we shouldn't try to rewrite the inner
189
+ // afterwards. Sorting by start position handles this; we additionally
190
+ // filter out any candidate whose ancestor we already rewrote.
191
+ candidateFunctions.sort((a, b) => a.getStart() - b.getStart());
192
+ const rewrittenFunctions = [];
193
+ const rewrittenSet = new Set();
194
+ for (const fn of candidateFunctions) {
195
+ if (!hasBlockBody(fn))
196
+ continue;
197
+ if (!isConfigFetcher(fn))
198
+ continue;
199
+ // Skip if any ancestor was already rewritten (its descendants are now
200
+ // detached from the source file).
201
+ let inRewrittenAncestor = false;
202
+ let cursor = fn.getParent();
203
+ while (cursor) {
204
+ if (rewrittenSet.has(cursor)) {
205
+ inRewrittenAncestor = true;
206
+ break;
207
+ }
208
+ cursor = cursor.getParent();
209
+ }
210
+ if (inRewrittenAncestor)
211
+ continue;
212
+ const start = fn.getStart();
213
+ const line = sourceFile.getLineAndColumnAtPos(start).line;
214
+ const name = describeFunction(fn);
215
+ if (ts_morph_1.Node.isFunctionDeclaration(fn) ||
216
+ ts_morph_1.Node.isFunctionExpression(fn) ||
217
+ ts_morph_1.Node.isMethodDeclaration(fn) ||
218
+ ts_morph_1.Node.isArrowFunction(fn)) {
219
+ fn.setBodyText(`return ${REPLACEMENT_IDENTIFIER}`);
220
+ }
221
+ rewrittenFunctions.push({ name, line });
222
+ rewrittenSet.add(fn);
223
+ }
224
+ // ─── 2. Remove the `APPLICATION_CONFIG_URL` import ─────────────────────
225
+ for (const decl of importsWithTarget) {
226
+ const targetNamed = decl
227
+ .getNamedImports()
228
+ .find((ni) => ni.getName() === TARGET_IDENTIFIER);
229
+ targetNamed === null || targetNamed === void 0 ? void 0 : targetNamed.remove();
230
+ const isNowEmpty = decl.getNamedImports().length === 0 &&
231
+ !decl.getDefaultImport() &&
232
+ !decl.getNamespaceImport();
233
+ if (isNowEmpty)
234
+ decl.remove();
235
+ }
236
+ // ─── 3. Add the new `applicationConfig` import ─────────────────────────
237
+ const existing = sourceFile.getImportDeclaration((decl) => decl.getModuleSpecifierValue() === REPLACEMENT_MODULE);
238
+ if (existing) {
239
+ const alreadyImported = existing
240
+ .getNamedImports()
241
+ .some((ni) => ni.getName() === REPLACEMENT_IDENTIFIER);
242
+ if (!alreadyImported)
243
+ existing.addNamedImport(REPLACEMENT_IDENTIFIER);
244
+ }
245
+ else {
246
+ sourceFile.addImportDeclaration({
247
+ moduleSpecifier: REPLACEMENT_MODULE,
248
+ namedImports: [REPLACEMENT_IDENTIFIER]
249
+ });
250
+ }
251
+ // ─── 4. Rename remaining identifier references ─────────────────────────
252
+ // Anything still named APPLICATION_CONFIG_URL after the function-body
253
+ // rewrites and import cleanup is a stray reference; rename it. Iterate
254
+ // from highest position to lowest so `replaceWithText` doesn't shift
255
+ // offsets for nodes we haven't visited yet.
256
+ const renameTargets = sourceFile
257
+ .getDescendantsOfKind(ts_morph_1.SyntaxKind.Identifier)
258
+ .filter((id) => id.getText() === TARGET_IDENTIFIER)
259
+ .filter((id) => !id.getFirstAncestorByKind(ts_morph_1.SyntaxKind.ImportDeclaration))
260
+ .filter((id) => {
261
+ const parent = id.getParent();
262
+ const parentKind = parent.getKind();
263
+ if (parentKind === ts_morph_1.SyntaxKind.PropertyAccessExpression) {
264
+ const pae = parent.asKind(ts_morph_1.SyntaxKind.PropertyAccessExpression);
265
+ // Right-hand side of `x.APPLICATION_CONFIG_URL` — leave alone.
266
+ if (pae.getNameNode() === id)
267
+ return false;
268
+ }
269
+ if (parentKind === ts_morph_1.SyntaxKind.PropertyAssignment) {
270
+ const pa = parent.asKind(ts_morph_1.SyntaxKind.PropertyAssignment);
271
+ // `{ APPLICATION_CONFIG_URL: ... }` — leave the key alone.
272
+ if (pa.getNameNode() === id)
273
+ return false;
274
+ }
275
+ if (parentKind === ts_morph_1.SyntaxKind.ShorthandPropertyAssignment) {
276
+ // `{ APPLICATION_CONFIG_URL }` shorthand — both binding name AND
277
+ // referenced symbol. Leave alone here; if the user wants to rename
278
+ // the referenced value they should expand it manually first.
279
+ return false;
280
+ }
281
+ return true;
282
+ })
283
+ .sort((a, b) => b.getPos() - a.getPos());
284
+ for (const id of renameTargets) {
285
+ id.replaceWithText(REPLACEMENT_IDENTIFIER);
286
+ }
287
+ return {
288
+ changed: true,
289
+ rewrittenFunctions,
290
+ renamedReferences: renameTargets.length
291
+ };
292
+ }
293
+ function main() {
294
+ return __awaiter(this, void 0, void 0, function* () {
295
+ const project = new ts_morph_1.Project({
296
+ tsConfigFilePath: path_1.default.resolve(process.cwd(), 'tsconfig.json'),
297
+ skipAddingFilesFromTsConfig: false
298
+ });
299
+ const sourceFiles = project.getSourceFiles().filter((sf) => {
300
+ const fp = sf.getFilePath();
301
+ return fp.includes('/src/') && !fp.includes('/node_modules/');
302
+ });
303
+ console.log(`Migrating '${TARGET_IDENTIFIER}' → '${REPLACEMENT_IDENTIFIER}' across ${sourceFiles.length} source file(s)...\n`);
304
+ let changedFiles = 0;
305
+ let totalRewrittenFunctions = 0;
306
+ let totalRenamedReferences = 0;
307
+ const skipped = [];
308
+ for (const sourceFile of sourceFiles) {
309
+ const filePath = sourceFile.getFilePath();
310
+ const rel = path_1.default.relative(process.cwd(), filePath);
311
+ const result = processFile(sourceFile);
312
+ if (result.skippedReason) {
313
+ skipped.push(`${rel} (${result.skippedReason})`);
314
+ continue;
315
+ }
316
+ if (!result.changed)
317
+ continue;
318
+ yield sourceFile.save();
319
+ changedFiles++;
320
+ totalRewrittenFunctions += result.rewrittenFunctions.length;
321
+ totalRenamedReferences += result.renamedReferences;
322
+ for (const fn of result.rewrittenFunctions) {
323
+ console.log(` [${rel}:${fn.line}] Rewrote '${fn.name}' body → 'return ${REPLACEMENT_IDENTIFIER}' (config fetch eliminated)`);
324
+ }
325
+ if (result.renamedReferences > 0) {
326
+ console.log(` [${rel}] Renamed ${result.renamedReferences} stray reference(s) ${TARGET_IDENTIFIER} → ${REPLACEMENT_IDENTIFIER}`);
327
+ }
328
+ }
329
+ if (skipped.length > 0) {
330
+ console.warn(`\n ${skipped.length} file(s) skipped:\n` +
331
+ skipped.map((s) => ` - ${s}`).join('\n'));
332
+ }
333
+ if (changedFiles === 0) {
334
+ console.log(`\nNo files reference '${TARGET_IDENTIFIER}'. Nothing to do.`);
335
+ return;
336
+ }
337
+ console.log(`\nDone. Updated ${changedFiles} file(s): ${totalRewrittenFunctions} fetch function(s) rewritten, ${totalRenamedReferences} bare reference(s) renamed.`);
338
+ if (totalRewrittenFunctions > 0) {
339
+ console.log(`NOTE: rewriting fetch functions discards any custom logic that lived inside them. Review the diff and re-apply any country-specific adjustments on top of '${REPLACEMENT_IDENTIFIER}'.`);
340
+ }
341
+ });
342
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-scopes.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/migrate-scopes.ts"],"names":[],"mappings":"AA2VA,iBAAe,IAAI,kBAmDlB;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}
1
+ {"version":3,"file":"migrate-scopes.d.ts","sourceRoot":"","sources":["../../../src/migrations/v2.0/migrate-scopes.ts"],"names":[],"mappings":"AAyVA,iBAAe,IAAI,kBAmDlB;AAED,OAAO,EAAE,IAAI,EAAE,CAAA"}