openmrs 5.3.3-pre.1421 → 5.3.3-pre.1424

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.
@@ -1 +1 @@
1
- openmrs:build: cache hit, replaying output 84205ded3bab6162
1
+ openmrs:build: cache hit, replaying output 124f62a216601cdd
package/dist/cli.js CHANGED
@@ -195,10 +195,10 @@ yargs_1.default.command('assemble', 'Assembles an import map incl. all required
195
195
  coerce: (arg) => (0, utils_1.trimEnd)(arg, '/'),
196
196
  })
197
197
  .option('config', {
198
- default: 'spa-build-config.json',
198
+ default: ['spa-build-config.json'],
199
199
  description: 'Path to a SPA build config JSON.',
200
- type: 'string',
201
- coerce: (arg) => (0, path_1.resolve)(process.cwd(), arg),
200
+ type: 'array',
201
+ coerce: (arg) => arg.map((p) => (0, path_1.resolve)(process.cwd(), p)),
202
202
  })
203
203
  .option('hash-importmap', {
204
204
  default: false,
@@ -5,26 +5,60 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runAssemble = void 0;
7
7
  const promises_1 = require("fs/promises");
8
+ const fs_1 = require("fs");
8
9
  const path_1 = require("path");
10
+ const stream_1 = require("stream");
9
11
  const inquirer_1 = require("inquirer");
10
12
  const rimraf_1 = __importDefault(require("rimraf"));
11
13
  const axios_1 = __importDefault(require("axios"));
12
14
  const npm_registry_fetch_1 = __importDefault(require("npm-registry-fetch"));
13
15
  const pacote_1 = __importDefault(require("pacote"));
14
16
  const utils_1 = require("../utils");
15
- const fs_1 = require("fs");
16
17
  const npmConfig_1 = require("../utils/npmConfig");
17
- async function readConfig(mode, config, fetchOptions) {
18
+ async function readConfig(mode, configs, fetchOptions) {
18
19
  switch (mode) {
19
- case 'config':
20
- if (!(0, fs_1.existsSync)(config)) {
21
- throw new Error(`Could not find the config file "${config}".`);
20
+ // curly-braces are here to add a lexical scope which allows us to safely
21
+ // declare variables
22
+ case 'config': {
23
+ if (configs.length === 0) {
24
+ configs = [(0, path_1.resolve)(process.cwd(), 'spa-build-config.json')];
22
25
  }
23
- (0, utils_1.logInfo)(`Reading configuration ...`);
24
- return {
25
- baseDir: (0, path_1.dirname)(config),
26
- ...JSON.parse(await (0, promises_1.readFile)(config, 'utf8')),
26
+ const results = {
27
+ configs: [],
28
+ errors: [],
27
29
  };
30
+ for (const config of configs) {
31
+ if (!(0, fs_1.existsSync)(config)) {
32
+ results.errors.push(new Error(`Could not find the config file "${config}".`));
33
+ continue;
34
+ }
35
+ (0, utils_1.logInfo)(`Reading configuration ${config} ...`);
36
+ results.configs.push({
37
+ ...JSON.parse(await (0, promises_1.readFile)(config, 'utf8')),
38
+ });
39
+ }
40
+ if (results.errors.length > 0) {
41
+ throw new Error(results.errors.reduce((str, e, idx) => {
42
+ if (idx > 0) {
43
+ str += '\n\n';
44
+ }
45
+ return str + e.message;
46
+ }, ''));
47
+ }
48
+ return results.configs.reduce((config, newConfig) => {
49
+ if (newConfig.frontendModules) {
50
+ config.frontendModules = { ...config.frontendModules, ...newConfig.frontendModules };
51
+ }
52
+ // excludes are processed for each config in turn; this ensure that modules removed in one config can
53
+ // be added back by providing another config override
54
+ if (Array.isArray(newConfig.frontendModuleExcludes)) {
55
+ newConfig.frontendModuleExcludes.forEach((exclude) => {
56
+ typeof exclude === 'string' && config.frontendModules[exclude] && delete config.frontendModules[exclude];
57
+ });
58
+ }
59
+ return config;
60
+ });
61
+ }
28
62
  case 'survey': {
29
63
  (0, utils_1.logInfo)(`Loading available frontend modules ...`);
30
64
  const packages = await npm_registry_fetch_1.default
@@ -56,7 +90,6 @@ async function readConfig(mode, config, fetchOptions) {
56
90
  }
57
91
  const answers = await (0, inquirer_1.prompt)(questions);
58
92
  return {
59
- baseDir: process.cwd(),
60
93
  publicUrl: '.',
61
94
  frontendModules: Object.keys(answers)
62
95
  .filter((m) => answers[m])
@@ -68,7 +101,6 @@ async function readConfig(mode, config, fetchOptions) {
68
101
  }
69
102
  }
70
103
  return {
71
- baseDir: process.cwd(),
72
104
  frontendModules: {},
73
105
  publicUrl: '.',
74
106
  };
@@ -79,17 +111,11 @@ async function downloadPackage(cacheDir, esmName, esmVersion, baseDir, fetchOpti
79
111
  }
80
112
  if (esmVersion.startsWith('file:')) {
81
113
  const source = (0, path_1.resolve)(baseDir, esmVersion.substring(5));
82
- const file = (0, path_1.basename)(source);
83
- const target = (0, path_1.resolve)(cacheDir, file);
84
- await (0, promises_1.copyFile)(source, target);
85
- return file;
114
+ return (0, promises_1.readFile)(source);
86
115
  }
87
116
  else if (/^https?:\/\//.test(esmVersion)) {
88
117
  const response = await axios_1.default.get(esmVersion);
89
- const content = response.data;
90
- const file = esmName.replace('@', '').replace(/\//g, '-') + '.tgz';
91
- await (0, promises_1.writeFile)((0, path_1.resolve)(cacheDir, file), content);
92
- return file;
118
+ return response.data;
93
119
  }
94
120
  else {
95
121
  const packageName = `${esmName}@${esmVersion}`;
@@ -97,19 +123,16 @@ async function downloadPackage(cacheDir, esmName, esmVersion, baseDir, fetchOpti
97
123
  if (!Boolean(tarManifest) || !Boolean(tarManifest._resolved) || !Boolean(tarManifest._integrity)) {
98
124
  throw new Error(`Failed to load manifest for ${packageName} from registry ${fetchOptions.registry}`);
99
125
  }
100
- const tarball = await pacote_1.default.tarball(tarManifest._resolved, {
126
+ return pacote_1.default.tarball(tarManifest._resolved, {
101
127
  ...fetchOptions,
102
128
  integrity: tarManifest._integrity,
103
129
  });
104
- const filename = `${tarManifest.name}-${tarManifest.version}.tgz`.replace(/^@/, '').replace(/\//, '-');
105
- await (0, promises_1.writeFile)((0, path_1.resolve)(cacheDir, filename), tarball);
106
- return filename;
107
130
  }
108
131
  }
109
- async function extractFiles(sourceFile, targetDir) {
132
+ async function extractFiles(buffer, targetDir) {
110
133
  await (0, promises_1.mkdir)(targetDir, { recursive: true });
111
134
  const packageRoot = 'package';
112
- const rs = (0, fs_1.createReadStream)(sourceFile);
135
+ const rs = stream_1.Readable.from(buffer);
113
136
  const files = await (0, utils_1.untar)(rs);
114
137
  const packageJson = JSON.parse(files[`${packageRoot}/package.json`].toString('utf8'));
115
138
  const version = packageJson.version ?? '0.0.0';
@@ -125,7 +148,6 @@ async function extractFiles(sourceFile, targetDir) {
125
148
  await (0, promises_1.mkdir)((0, path_1.dirname)(targetFile), { recursive: true });
126
149
  await (0, promises_1.writeFile)(targetFile, content);
127
150
  }));
128
- await (0, promises_1.unlink)(sourceFile);
129
151
  return [fileName, version];
130
152
  }
131
153
  async function runAssemble(args) {
@@ -138,7 +160,7 @@ async function runAssemble(args) {
138
160
  frontendModules: {},
139
161
  };
140
162
  const routes = {};
141
- (0, utils_1.logInfo)(`Assembling the importmap ...`);
163
+ (0, utils_1.logInfo)(`Assembling dependencies and building import map and routes registry...`);
142
164
  const { frontendModules = {}, publicUrl = '.' } = config;
143
165
  const cacheDir = (0, path_1.resolve)(process.cwd(), '.cache');
144
166
  if (args.fresh && (0, fs_1.existsSync)(args.target)) {
@@ -147,13 +169,13 @@ async function runAssemble(args) {
147
169
  await (0, promises_1.mkdir)(args.target, { recursive: true });
148
170
  await Promise.all(Object.keys(frontendModules).map(async (esmName) => {
149
171
  const esmVersion = frontendModules[esmName];
150
- const tgzFileName = await downloadPackage(cacheDir, esmName, esmVersion, config.baseDir, npmConf);
151
- const dirName = tgzFileName.replace('.tgz', '');
152
- const [fileName, version] = await extractFiles((0, path_1.resolve)(cacheDir, tgzFileName), (0, path_1.resolve)(args.target, dirName));
172
+ const tgzBuffer = await downloadPackage(cacheDir, esmName, esmVersion, process.cwd(), npmConf);
173
+ const dirName = `${esmName}-${esmVersion}`.replace(/^@/, '').replace(/\//, '-');
174
+ const [fileName, version] = await extractFiles(tgzBuffer, (0, path_1.resolve)(args.target, dirName));
153
175
  const appRoutes = (0, path_1.resolve)(args.target, dirName, 'routes.json');
154
176
  if ((0, fs_1.existsSync)(appRoutes)) {
155
177
  try {
156
- routes[esmName] = JSON.parse((0, fs_1.readFileSync)(appRoutes).toString());
178
+ routes[esmName] = JSON.parse((await (0, promises_1.readFile)(appRoutes)).toString());
157
179
  routes[esmName]['version'] = version;
158
180
  }
159
181
  catch (e) {
@@ -174,7 +196,8 @@ async function runAssemble(args) {
174
196
  await (0, promises_1.writeFile)((0, path_1.resolve)(args.target, `routes.registry${args.hashImportmap ? '.' + (0, utils_1.contentHash)(routes) : ''}.json`), JSON.stringify(routes), 'utf-8');
175
197
  }
176
198
  if (args.manifest) {
177
- await (0, promises_1.writeFile)((0, path_1.resolve)(args.target, 'spa-module-versions.json'), JSON.stringify(versionManifest), 'utf8');
199
+ await (0, promises_1.writeFile)((0, path_1.resolve)(args.target, 'spa-assemble-config.json'), JSON.stringify(versionManifest), 'utf8');
178
200
  }
201
+ (0, utils_1.logInfo)(`Finished assembling frontend distribution`);
179
202
  }
180
203
  exports.runAssemble = runAssemble;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmrs",
3
- "version": "5.3.3-pre.1421",
3
+ "version": "5.3.3-pre.1424",
4
4
  "license": "MPL-2.0",
5
5
  "main": "dist/index.js",
6
6
  "bin": "./dist/cli.js",
@@ -30,8 +30,8 @@
30
30
  "homepage": "https://github.com/openmrs/openmrs-esm-core#readme",
31
31
  "dependencies": {
32
32
  "@carbon/icons-react": "11.26.0",
33
- "@openmrs/esm-app-shell": "5.3.3-pre.1421",
34
- "@openmrs/webpack-config": "5.3.3-pre.1421",
33
+ "@openmrs/esm-app-shell": "5.3.3-pre.1424",
34
+ "@openmrs/webpack-config": "5.3.3-pre.1424",
35
35
  "@pnpm/npm-conf": "^2.1.0",
36
36
  "@swc/core": "^1.3.58",
37
37
  "autoprefixer": "^10.4.2",
package/src/cli.ts CHANGED
@@ -258,10 +258,10 @@ yargs.command(
258
258
  coerce: (arg) => trimEnd(arg, '/'),
259
259
  })
260
260
  .option('config', {
261
- default: 'spa-build-config.json',
261
+ default: ['spa-build-config.json'],
262
262
  description: 'Path to a SPA build config JSON.',
263
- type: 'string',
264
- coerce: (arg) => resolve(process.cwd(), arg),
263
+ type: 'array',
264
+ coerce: (arg: Array<string>) => arg.map((p) => resolve(process.cwd(), p)),
265
265
  })
266
266
  .option('hash-importmap', {
267
267
  default: false,
@@ -1,12 +1,13 @@
1
- import { copyFile, mkdir, readFile, unlink, writeFile } from 'fs/promises';
1
+ import { mkdir, readFile, writeFile } from 'fs/promises';
2
+ import { existsSync } from 'fs';
2
3
  import { resolve, dirname, basename } from 'path';
4
+ import { Readable } from 'stream';
3
5
  import { prompt, type Question } from 'inquirer';
4
6
  import rimraf from 'rimraf';
5
7
  import axios from 'axios';
6
8
  import npmRegistryFetch from 'npm-registry-fetch';
7
9
  import pacote from 'pacote';
8
10
  import { contentHash, logInfo, logWarn, untar } from '../utils';
9
- import { createReadStream, existsSync, readFileSync } from 'fs';
10
11
  import { getNpmRegistryConfiguration } from '../utils/npmConfig';
11
12
 
12
13
  /* eslint-disable no-console */
@@ -14,7 +15,7 @@ import { getNpmRegistryConfiguration } from '../utils/npmConfig';
14
15
  export interface AssembleArgs {
15
16
  target: string;
16
17
  mode: string;
17
- config: string;
18
+ config: Array<string>;
18
19
  registry?: string;
19
20
  hashImportmap: boolean;
20
21
  fresh: boolean;
@@ -32,29 +33,72 @@ interface NpmSearchResult {
32
33
  }
33
34
 
34
35
  interface AssembleConfig {
35
- baseDir: string;
36
36
  publicUrl: string;
37
37
  frontendModules: Record<string, string>;
38
+ frontendModuleExcludes?: Array<string>;
38
39
  }
39
40
 
40
41
  async function readConfig(
41
42
  mode: string,
42
- config: string,
43
+ configs: Array<string>,
43
44
  fetchOptions: npmRegistryFetch.Options,
44
45
  ): Promise<AssembleConfig> {
45
46
  switch (mode) {
46
- case 'config':
47
- if (!existsSync(config)) {
48
- throw new Error(`Could not find the config file "${config}".`);
47
+ // curly-braces are here to add a lexical scope which allows us to safely
48
+ // declare variables
49
+ case 'config': {
50
+ if (configs.length === 0) {
51
+ configs = [resolve(process.cwd(), 'spa-build-config.json')];
49
52
  }
50
53
 
51
- logInfo(`Reading configuration ...`);
52
-
53
- return {
54
- baseDir: dirname(config),
55
- ...JSON.parse(await readFile(config, 'utf8')),
54
+ const results: {
55
+ configs: Array<AssembleConfig>;
56
+ errors: Array<Error>;
57
+ } = {
58
+ configs: [],
59
+ errors: [],
56
60
  };
57
61
 
62
+ for (const config of configs) {
63
+ if (!existsSync(config)) {
64
+ results.errors.push(new Error(`Could not find the config file "${config}".`));
65
+ continue;
66
+ }
67
+
68
+ logInfo(`Reading configuration ${config} ...`);
69
+
70
+ results.configs.push({
71
+ ...JSON.parse(await readFile(config, 'utf8')),
72
+ });
73
+ }
74
+
75
+ if (results.errors.length > 0) {
76
+ throw new Error(
77
+ results.errors.reduce((str, e, idx) => {
78
+ if (idx > 0) {
79
+ str += '\n\n';
80
+ }
81
+
82
+ return str + e.message;
83
+ }, ''),
84
+ );
85
+ }
86
+
87
+ return results.configs.reduce((config, newConfig) => {
88
+ if (newConfig.frontendModules) {
89
+ config.frontendModules = { ...config.frontendModules, ...newConfig.frontendModules };
90
+ }
91
+
92
+ // excludes are processed for each config in turn; this ensure that modules removed in one config can
93
+ // be added back by providing another config override
94
+ if (Array.isArray(newConfig.frontendModuleExcludes)) {
95
+ newConfig.frontendModuleExcludes.forEach((exclude) => {
96
+ typeof exclude === 'string' && config.frontendModules[exclude] && delete config.frontendModules[exclude];
97
+ });
98
+ }
99
+ return config;
100
+ });
101
+ }
58
102
  case 'survey': {
59
103
  logInfo(`Loading available frontend modules ...`);
60
104
 
@@ -95,7 +139,6 @@ async function readConfig(
95
139
  const answers = await prompt(questions);
96
140
 
97
141
  return {
98
- baseDir: process.cwd(),
99
142
  publicUrl: '.',
100
143
  frontendModules: Object.keys(answers)
101
144
  .filter((m) => answers[m])
@@ -108,7 +151,6 @@ async function readConfig(
108
151
  }
109
152
 
110
153
  return {
111
- baseDir: process.cwd(),
112
154
  frontendModules: {},
113
155
  publicUrl: '.',
114
156
  };
@@ -120,23 +162,17 @@ async function downloadPackage(
120
162
  esmVersion: string,
121
163
  baseDir: string,
122
164
  fetchOptions: npmRegistryFetch.Options,
123
- ) {
165
+ ): Promise<Buffer> {
124
166
  if (!existsSync(cacheDir)) {
125
167
  await mkdir(cacheDir, { recursive: true });
126
168
  }
127
169
 
128
170
  if (esmVersion.startsWith('file:')) {
129
171
  const source = resolve(baseDir, esmVersion.substring(5));
130
- const file = basename(source);
131
- const target = resolve(cacheDir, file);
132
- await copyFile(source, target);
133
- return file;
172
+ return readFile(source);
134
173
  } else if (/^https?:\/\//.test(esmVersion)) {
135
174
  const response = await axios.get<Buffer>(esmVersion);
136
- const content = response.data;
137
- const file = esmName.replace('@', '').replace(/\//g, '-') + '.tgz';
138
- await writeFile(resolve(cacheDir, file), content);
139
- return file;
175
+ return response.data;
140
176
  } else {
141
177
  const packageName = `${esmName}@${esmVersion}`;
142
178
  const tarManifest = await pacote.manifest(packageName, fetchOptions);
@@ -145,23 +181,17 @@ async function downloadPackage(
145
181
  throw new Error(`Failed to load manifest for ${packageName} from registry ${fetchOptions.registry}`);
146
182
  }
147
183
 
148
- const tarball = await pacote.tarball(tarManifest._resolved, {
184
+ return pacote.tarball(tarManifest._resolved, {
149
185
  ...fetchOptions,
150
186
  integrity: tarManifest._integrity,
151
187
  });
152
-
153
- const filename = `${tarManifest.name}-${tarManifest.version}.tgz`.replace(/^@/, '').replace(/\//, '-');
154
-
155
- await writeFile(resolve(cacheDir, filename), tarball);
156
-
157
- return filename;
158
188
  }
159
189
  }
160
190
 
161
- async function extractFiles(sourceFile: string, targetDir: string) {
191
+ async function extractFiles(buffer: Buffer, targetDir: string) {
162
192
  await mkdir(targetDir, { recursive: true });
163
193
  const packageRoot = 'package';
164
- const rs = createReadStream(sourceFile);
194
+ const rs = Readable.from(buffer);
165
195
  const files = await untar(rs);
166
196
  const packageJson = JSON.parse(files[`${packageRoot}/package.json`].toString('utf8'));
167
197
  const version = packageJson.version ?? '0.0.0';
@@ -181,7 +211,6 @@ async function extractFiles(sourceFile: string, targetDir: string) {
181
211
  }),
182
212
  );
183
213
 
184
- await unlink(sourceFile);
185
214
  return [fileName, version];
186
215
  }
187
216
 
@@ -199,7 +228,7 @@ export async function runAssemble(args: AssembleArgs) {
199
228
 
200
229
  const routes = {};
201
230
 
202
- logInfo(`Assembling the importmap ...`);
231
+ logInfo(`Assembling dependencies and building import map and routes registry...`);
203
232
 
204
233
  const { frontendModules = {}, publicUrl = '.' } = config;
205
234
  const cacheDir = resolve(process.cwd(), '.cache');
@@ -213,15 +242,15 @@ export async function runAssemble(args: AssembleArgs) {
213
242
  await Promise.all(
214
243
  Object.keys(frontendModules).map(async (esmName) => {
215
244
  const esmVersion = frontendModules[esmName];
216
- const tgzFileName = await downloadPackage(cacheDir, esmName, esmVersion, config.baseDir, npmConf);
245
+ const tgzBuffer = await downloadPackage(cacheDir, esmName, esmVersion, process.cwd(), npmConf);
217
246
 
218
- const dirName = tgzFileName.replace('.tgz', '');
219
- const [fileName, version] = await extractFiles(resolve(cacheDir, tgzFileName), resolve(args.target, dirName));
247
+ const dirName = `${esmName}-${esmVersion}`.replace(/^@/, '').replace(/\//, '-');
248
+ const [fileName, version] = await extractFiles(tgzBuffer, resolve(args.target, dirName));
220
249
 
221
250
  const appRoutes = resolve(args.target, dirName, 'routes.json');
222
251
  if (existsSync(appRoutes)) {
223
252
  try {
224
- routes[esmName] = JSON.parse(readFileSync(appRoutes).toString());
253
+ routes[esmName] = JSON.parse((await readFile(appRoutes)).toString());
225
254
  routes[esmName]['version'] = version;
226
255
  } catch (e) {
227
256
  logWarn(`Error while processing routes for ${esmName} using ${appRoutes}: ${e}`);
@@ -256,6 +285,8 @@ export async function runAssemble(args: AssembleArgs) {
256
285
  }
257
286
 
258
287
  if (args.manifest) {
259
- await writeFile(resolve(args.target, 'spa-module-versions.json'), JSON.stringify(versionManifest), 'utf8');
288
+ await writeFile(resolve(args.target, 'spa-assemble-config.json'), JSON.stringify(versionManifest), 'utf8');
260
289
  }
290
+
291
+ logInfo(`Finished assembling frontend distribution`);
261
292
  }