piral-cli 0.14.1 → 0.14.3-beta.3296

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 (52) hide show
  1. package/lib/apps/build-pilet.d.ts +6 -2
  2. package/lib/apps/build-pilet.js +92 -38
  3. package/lib/apps/build-pilet.js.map +1 -1
  4. package/lib/apps/debug-pilet.d.ts +2 -2
  5. package/lib/apps/publish-pilet.d.ts +9 -1
  6. package/lib/apps/publish-pilet.js +64 -28
  7. package/lib/apps/publish-pilet.js.map +1 -1
  8. package/lib/build/bundler-calls.js +8 -2
  9. package/lib/build/bundler-calls.js.map +1 -1
  10. package/lib/commands.js +12 -2
  11. package/lib/commands.js.map +1 -1
  12. package/lib/common/compatibility.js +4 -0
  13. package/lib/common/compatibility.js.map +1 -1
  14. package/lib/common/index.d.ts +1 -0
  15. package/lib/common/index.js +1 -0
  16. package/lib/common/index.js.map +1 -1
  17. package/lib/common/io.js +12 -4
  18. package/lib/common/io.js.map +1 -1
  19. package/lib/common/npm.d.ts +2 -1
  20. package/lib/common/npm.js +34 -8
  21. package/lib/common/npm.js.map +1 -1
  22. package/lib/common/spec.d.ts +29 -0
  23. package/lib/common/spec.js +57 -0
  24. package/lib/common/spec.js.map +1 -0
  25. package/lib/helpers.d.ts +3 -2
  26. package/lib/helpers.js +3 -2
  27. package/lib/helpers.js.map +1 -1
  28. package/lib/injectors/pilet.d.ts +2 -2
  29. package/lib/injectors/pilet.js +32 -74
  30. package/lib/injectors/pilet.js.map +1 -1
  31. package/lib/messages.d.ts +14 -1
  32. package/lib/messages.js +23 -3
  33. package/lib/messages.js.map +1 -1
  34. package/lib/rules/pilet-uses-latest-piral.js +17 -8
  35. package/lib/rules/pilet-uses-latest-piral.js.map +1 -1
  36. package/lib/types/public.d.ts +1 -0
  37. package/package.json +2 -2
  38. package/src/apps/build-pilet.ts +144 -46
  39. package/src/apps/debug-pilet.ts +2 -2
  40. package/src/apps/publish-pilet.ts +99 -29
  41. package/src/build/bundler-calls.ts +10 -2
  42. package/src/commands.ts +14 -3
  43. package/src/common/compatibility.ts +6 -0
  44. package/src/common/index.ts +1 -0
  45. package/src/common/io.ts +16 -6
  46. package/src/common/npm.ts +44 -11
  47. package/src/common/spec.ts +58 -0
  48. package/src/helpers.ts +10 -2
  49. package/src/injectors/pilet.ts +31 -78
  50. package/src/messages.ts +22 -2
  51. package/src/rules/pilet-uses-latest-piral.ts +21 -11
  52. package/src/types/public.ts +2 -0
@@ -1,5 +1,5 @@
1
- import { relative, join, dirname, basename, resolve } from 'path';
2
- import { buildPilet } from './build-pilet';
1
+ import { relative, dirname, basename, resolve } from 'path';
2
+ import { callPiletBuild } from '../bundler';
3
3
  import { LogLevels, PiletSchemaVersion, PiletPublishSource } from '../types';
4
4
  import {
5
5
  postFile,
@@ -15,6 +15,10 @@ import {
15
15
  checkExists,
16
16
  findTarball,
17
17
  downloadFile,
18
+ matchAnyPilet,
19
+ retrievePiletData,
20
+ removeDirectory,
21
+ logInfo,
18
22
  } from '../common';
19
23
 
20
24
  export interface PublishPiletOptions {
@@ -23,7 +27,7 @@ export interface PublishPiletOptions {
23
27
  * used with `--fresh`, otherwise expects source to be a path leading
24
28
  * to a `*.tgz` file.
25
29
  */
26
- source?: string;
30
+ source?: string | Array<string>;
27
31
 
28
32
  /**
29
33
  * Sets the URL of the feed service to deploy to.
@@ -67,6 +71,16 @@ export interface PublishPiletOptions {
67
71
  * Places additional fields that should be posted to the feed service.
68
72
  */
69
73
  fields?: Record<string, string>;
74
+
75
+ /**
76
+ * Sets the bundler to use for building, if any specific.
77
+ */
78
+ bundlerName?: string;
79
+
80
+ /**
81
+ * Additional arguments for a specific bundler.
82
+ */
83
+ _?: Record<string, any>;
70
84
  }
71
85
 
72
86
  export const publishPiletDefaults: PublishPiletOptions = {
@@ -83,41 +97,94 @@ export const publishPiletDefaults: PublishPiletOptions = {
83
97
 
84
98
  async function getFiles(
85
99
  baseDir: string,
86
- source: string,
100
+ sources: Array<string>,
87
101
  from: PiletPublishSource,
88
102
  fresh: boolean,
89
103
  schemaVersion: PiletSchemaVersion,
104
+ logLevel: LogLevels,
105
+ bundlerName: string,
106
+ _?: Record<string, any>,
90
107
  ca?: Buffer,
91
108
  ): Promise<Array<string>> {
92
109
  if (fresh) {
93
110
  log('generalDebug_0003', 'Detected "--fresh". Trying to resolve the package.json.');
94
- const details = require(join(baseDir, 'package.json'));
95
- progress('Triggering pilet build ...');
96
- await buildPilet(baseDir, {
97
- target: details.main,
98
- fresh,
99
- schemaVersion,
100
- });
101
- log('generalDebug_0003', 'Successfully built.');
102
- progress('Triggering pilet pack ...');
103
- const file = await createPiletPackage(baseDir, '.', '.');
104
- log('generalDebug_0003', 'Successfully packed.');
105
- return [file];
111
+ const allEntries = await matchAnyPilet(baseDir, sources);
112
+
113
+ if (allEntries.length === 0) {
114
+ fail('entryFileMissing_0077');
115
+ }
116
+
117
+ return await Promise.all(
118
+ allEntries.map(async (entryModule) => {
119
+ const targetDir = dirname(entryModule);
120
+ const { root, piletPackage, importmap, peerDependencies, peerModules, appPackage } = await retrievePiletData(
121
+ targetDir,
122
+ );
123
+ const dest = resolve(root, piletPackage.main);
124
+ const outDir = dirname(dest);
125
+ const outFile = basename(dest);
126
+ const externals = [...Object.keys(peerDependencies), ...peerModules];
127
+ progress('Triggering pilet build ...');
128
+
129
+ if (fresh) {
130
+ progress('Removing output directory ...');
131
+ await removeDirectory(outDir);
132
+ }
133
+
134
+ logInfo('Bundle pilet ...');
135
+
136
+ await callPiletBuild(
137
+ {
138
+ root,
139
+ piral: appPackage.name,
140
+ optimizeModules: false,
141
+ sourceMaps: true,
142
+ contentHash: true,
143
+ minify: true,
144
+ externals,
145
+ targetDir,
146
+ importmap,
147
+ outFile,
148
+ outDir,
149
+ entryModule: `./${relative(root, entryModule)}`,
150
+ logLevel,
151
+ version: schemaVersion,
152
+ ignored: [],
153
+ _,
154
+ },
155
+ bundlerName,
156
+ );
157
+
158
+ log('generalDebug_0003', `Pilet "${piletPackage.name}" built successfully!`);
159
+ progress('Triggering pilet pack ...');
160
+
161
+ const file = await createPiletPackage(root, '.', '.');
162
+ log('generalDebug_0003', `Pilet "${piletPackage.name}" packed successfully!`);
163
+
164
+ return file;
165
+ }),
166
+ );
106
167
  } else {
107
168
  log('generalDebug_0003', `Did not find fresh flag. Trying to match from "${from}".`);
108
169
 
109
170
  switch (from) {
110
- case 'local':
111
- log('generalDebug_0003', `Matching files using "${source}".`);
112
- return await matchFiles(baseDir, source);
113
- case 'remote':
114
- log('generalDebug_0003', `Download file from "${source}".`);
115
- return await downloadFile(source, ca);
116
- case 'npm':
117
- log('generalDebug_0003', `View npm package "${source}".`);
118
- const url = await findTarball(source);
119
- log('generalDebug_0003', `Download file from "${url}".`);
120
- return await downloadFile(url, ca);
171
+ case 'local': {
172
+ log('generalDebug_0003', `Matching files using "${sources.join('", "')}".`);
173
+ const allFiles = await Promise.all(sources.map((s) => matchFiles(baseDir, s)));
174
+ return allFiles.reduce((result, files) => [...result, ...files], []);
175
+ }
176
+ case 'remote': {
177
+ log('generalDebug_0003', `Download file from "${sources.join('", "')}".`);
178
+ const allFiles = await Promise.all(sources.map((s) => downloadFile(s, ca)));
179
+ return allFiles.reduce((result, files) => [...result, ...files], []);
180
+ }
181
+ case 'npm': {
182
+ log('generalDebug_0003', `View npm package "${sources.join('", "')}".`);
183
+ const allUrls = await Promise.all(sources.map((s) => findTarball(s)));
184
+ log('generalDebug_0003', `Download file from "${allUrls.join('", "')}".`);
185
+ const allFiles = await Promise.all(allUrls.map((url) => downloadFile(url, ca)));
186
+ return allFiles.reduce((result, files) => [...result, ...files], []);
187
+ }
121
188
  }
122
189
  }
123
190
  }
@@ -133,6 +200,8 @@ export async function publishPilet(baseDir = process.cwd(), options: PublishPile
133
200
  schemaVersion = publishPiletDefaults.schemaVersion,
134
201
  cert = config.cert ?? publishPiletDefaults.cert,
135
202
  fields = publishPiletDefaults.fields,
203
+ _ = {},
204
+ bundlerName,
136
205
  } = options;
137
206
  const fullBase = resolve(process.cwd(), baseDir);
138
207
  setLogLevel(logLevel);
@@ -153,12 +222,13 @@ export async function publishPilet(baseDir = process.cwd(), options: PublishPile
153
222
  }
154
223
 
155
224
  log('generalDebug_0003', 'Getting the tgz files ...');
156
- const files = await getFiles(fullBase, source, from, fresh, schemaVersion, ca);
225
+ const sources = Array.isArray(source) ? source : [source];
226
+ const files = await getFiles(fullBase, sources, from, fresh, schemaVersion, logLevel, bundlerName, _, ca);
157
227
  const successfulUploads: Array<string> = [];
158
228
  log('generalDebug_0003', 'Received available tgz files.');
159
229
 
160
230
  if (files.length === 0) {
161
- fail('missingPiletTarball_0061', source);
231
+ fail('missingPiletTarball_0061', sources);
162
232
  }
163
233
 
164
234
  log('generalInfo_0000', `Using feed service "${url}".`);
@@ -54,7 +54,7 @@ function createBundler(cwd: string, ps: ChildProcess, args: any) {
54
54
  export function callDynamic<T extends BaseBundleParameters>(name: string, path: string, args: T) {
55
55
  const cwd = args.root;
56
56
  return new Promise<Bundler>((resolve, reject) => {
57
- const ps = fork(getPath(name), [], { cwd });
57
+ const ps = fork(getPath(name), [], { cwd, stdio: 'pipe' });
58
58
  const bundler = createBundler(cwd, ps, args);
59
59
  const setup = {
60
60
  type: 'init',
@@ -67,6 +67,10 @@ export function callDynamic<T extends BaseBundleParameters>(name: string, path:
67
67
  });
68
68
  };
69
69
 
70
+ ps.stderr.pipe(process.stderr);
71
+ ps.stdout.pipe(process.stdout);
72
+ ps.stdin.pipe(process.stdin);
73
+
70
74
  ps.on('message', (msg: any) => {
71
75
  switch (msg.type) {
72
76
  case 'pending':
@@ -92,7 +96,7 @@ export function callDynamic<T extends BaseBundleParameters>(name: string, path:
92
96
  export function callStatic<T extends BaseBundleParameters>(name: string, path: string, args: T) {
93
97
  const cwd = args.root;
94
98
  return new Promise<Bundler>((resolve, reject) => {
95
- const ps = fork(getPath(name), [], { cwd });
99
+ const ps = fork(getPath(name), [], { cwd, stdio: 'pipe' });
96
100
  const bundler = createBundler(cwd, ps, args);
97
101
  const setup = {
98
102
  type: 'init',
@@ -105,6 +109,10 @@ export function callStatic<T extends BaseBundleParameters>(name: string, path: s
105
109
  });
106
110
  };
107
111
 
112
+ ps.stderr.pipe(process.stderr);
113
+ ps.stdout.pipe(process.stdout);
114
+ ps.stdin.pipe(process.stdin);
115
+
108
116
  ps.on('message', (msg: any) => {
109
117
  switch (msg.type) {
110
118
  case 'done':
package/src/commands.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { piletBuildTypeKeys } from '.';
1
2
  import * as apps from './apps';
2
3
  import {
3
4
  availableBundlers,
@@ -13,7 +14,7 @@ import {
13
14
  schemaKeys,
14
15
  fromKeys,
15
16
  bundlerKeys,
16
- buildTypeKeys,
17
+ piralBuildTypeKeys,
17
18
  } from './helpers';
18
19
  import {
19
20
  ToolCommand,
@@ -23,6 +24,7 @@ import {
23
24
  PiralBuildType,
24
25
  PiletPublishSource,
25
26
  PiletSchemaVersion,
27
+ PiletBuildType,
26
28
  } from './types';
27
29
 
28
30
  function specializeCommand(commands: Array<ToolCommand<any>>, command: ToolCommand<any>, suffix: string) {
@@ -143,7 +145,7 @@ const allCommands: Array<ToolCommand<any>> = [
143
145
  .boolean('optimize-modules')
144
146
  .describe('optimize-modules', 'Also includes the node modules for target transpilation.')
145
147
  .default('optimize-modules', apps.buildPiralDefaults.optimizeModules)
146
- .choices('type', buildTypeKeys)
148
+ .choices('type', piralBuildTypeKeys)
147
149
  .describe('type', 'Selects the target type of the build. "all" builds all target types.')
148
150
  .default('type', apps.buildPiralDefaults.type)
149
151
  .choices('bundler', availableBundlers)
@@ -186,7 +188,7 @@ const allCommands: Array<ToolCommand<any>> = [
186
188
  .number('log-level')
187
189
  .describe('log-level', 'Sets the log level to use (1-5).')
188
190
  .default('log-level', apps.publishPiralDefaults.logLevel)
189
- .choices('type', buildTypeKeys)
191
+ .choices('type', piralBuildTypeKeys)
190
192
  .describe('type', 'Selects the target type to publish. "all" publishes all target types.')
191
193
  .default('type', apps.publishPiralDefaults.type)
192
194
  .choices('provider', availableReleaseProviders)
@@ -482,6 +484,9 @@ const allCommands: Array<ToolCommand<any>> = [
482
484
  .choices('bundler', availableBundlers)
483
485
  .describe('bundler', 'Sets the bundler to use.')
484
486
  .default('bundler', availableBundlers[0])
487
+ .choices('type', piletBuildTypeKeys)
488
+ .describe('type', 'Selects the target type of the build.')
489
+ .default('type', apps.buildPiletDefaults.type)
485
490
  .string('app')
486
491
  .describe('app', 'Sets the name of the Piral instance.')
487
492
  .string('base')
@@ -498,6 +503,7 @@ const allCommands: Array<ToolCommand<any>> = [
498
503
  declaration: args.declaration as boolean,
499
504
  sourceMaps: args['source-maps'] as boolean,
500
505
  optimizeModules: args['optimize-modules'] as boolean,
506
+ type: args.type as PiletBuildType,
501
507
  fresh: args.fresh as boolean,
502
508
  logLevel: args['log-level'] as LogLevels,
503
509
  schemaVersion: args.schema as PiletSchemaVersion,
@@ -567,6 +573,9 @@ const allCommands: Array<ToolCommand<any>> = [
567
573
  .choices('schema', schemaKeys)
568
574
  .describe('schema', 'Sets the schema to be used when making a fresh build of the pilet.')
569
575
  .default('schema', apps.publishPiletDefaults.schemaVersion)
576
+ .choices('bundler', availableBundlers)
577
+ .describe('bundler', 'Sets the bundler to use.')
578
+ .default('bundler', availableBundlers[0])
570
579
  .choices('from', fromKeys)
571
580
  .describe('from', 'Sets the type of the source to use for publishing.')
572
581
  .default('from', apps.publishPiletDefaults.from)
@@ -584,10 +593,12 @@ const allCommands: Array<ToolCommand<any>> = [
584
593
  url: args.url as string,
585
594
  logLevel: args['log-level'] as LogLevels,
586
595
  cert: args['ca-cert'] as string,
596
+ bundlerName: args.bundler as string,
587
597
  fresh: args.fresh as boolean,
588
598
  from: args.from as PiletPublishSource,
589
599
  schemaVersion: args.schema as PiletSchemaVersion,
590
600
  fields: args.fields as Record<string, string>,
601
+ _: args,
591
602
  });
592
603
  },
593
604
  },
@@ -4,6 +4,12 @@ import { log } from './log';
4
4
 
5
5
  export function checkAppShellCompatibility(piralVersion: string) {
6
6
  log('generalDebug_0003', `Checking compatibility ...`);
7
+
8
+ if (!piralVersion) {
9
+ log('appShellMaybeIncompatible_0102', cliVersion);
10
+ return false;
11
+ }
12
+
7
13
  const compatible = findCompatVersion(piralVersion);
8
14
  log('generalDebug_0003', `Used versions: "${compatible}" and "${compatVersion}".`);
9
15
 
@@ -25,4 +25,5 @@ export * from './port';
25
25
  export * from './rules';
26
26
  export * from './scaffold';
27
27
  export * from './scripts';
28
+ export * from './spec';
28
29
  export * from './template';
package/src/common/io.ts CHANGED
@@ -254,7 +254,7 @@ export async function matchAnyPilet(baseDir: string, patterns: Array<string>) {
254
254
  log('generalDebug_0003', `Found a "source" field with value "${source}".`);
255
255
  const target = resolve(targetDir, source);
256
256
  const exists = await checkExists(target);
257
-
257
+
258
258
  if (exists) {
259
259
  log('generalDebug_0003', `Taking existing target as "${target}".`);
260
260
  matched(name, target);
@@ -264,7 +264,7 @@ export async function matchAnyPilet(baseDir: string, patterns: Array<string>) {
264
264
  } else {
265
265
  log('generalDebug_0003', `No "source" field found. Trying combinations in "src".`);
266
266
  const files = await matchPattern(targetDir, `src/index.{${exts}}`);
267
-
267
+
268
268
  if (files.length > 0) {
269
269
  log('generalDebug_0003', `Found a result; taking "${files[0]}".`);
270
270
  matched(name, files[0]);
@@ -420,10 +420,20 @@ export async function copy(source: string, target: string, forceOverwrite = Forc
420
420
 
421
421
  try {
422
422
  const flag = forceOverwrite === ForceOverwrite.yes ? 0 : constants.COPYFILE_EXCL;
423
- await new Promise<void>((resolve, reject) => {
424
- copyFile(source, target, flag, (err) => (err ? reject(err) : resolve()));
425
- });
426
- return true;
423
+ const isDir = await checkIsDirectory(source);
424
+
425
+ if (isDir) {
426
+ const files = await getFileNames(source);
427
+ const results = await Promise.all(
428
+ files.map((file) => copy(resolve(source, file), resolve(target, file), forceOverwrite)),
429
+ );
430
+ return results.every(Boolean);
431
+ } else {
432
+ await new Promise<void>((resolve, reject) => {
433
+ copyFile(source, target, flag, (err) => (err ? reject(err) : resolve()));
434
+ });
435
+ return true;
436
+ }
427
437
  } catch (e) {
428
438
  if (forceOverwrite === ForceOverwrite.prompt) {
429
439
  const shouldOverwrite = await promptOverwrite(target);
package/src/common/npm.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { resolve, relative } from 'path';
1
+ import { resolve, relative, dirname } from 'path';
2
2
  import { createReadStream, existsSync, access, constants } from 'fs';
3
3
  import { log, fail } from './log';
4
4
  import { config } from './config';
@@ -107,23 +107,56 @@ export async function determineNpmClient(root: string, selected?: NpmClientType)
107
107
 
108
108
  export async function isMonorepoPackageRef(refName: string, root: string): Promise<boolean> {
109
109
  const c = require(`./clients/npm`);
110
- const details = await c.listPackage(refName, root);
111
- return details?.dependencies?.[refName]?.extraneous ?? false;
112
- }
110
+ const newRoot = await detectMonorepoRoot(root);
113
111
 
114
- export type MonorepoKind = 'none' | 'lerna' | 'yarn';
112
+ if (newRoot) {
113
+ const details = await c.listPackage(refName, newRoot);
114
+ return details?.dependencies?.[refName]?.extraneous ?? false;
115
+ }
115
116
 
116
- export async function detectMonorepo(root: string): Promise<MonorepoKind> {
117
+ return false;
118
+ }
119
+
120
+ export async function detectMonorepoRoot(root: string): Promise<string> {
117
121
  const file = await getLernaConfigPath(root);
118
122
 
119
123
  if (file !== undefined) {
120
- return 'lerna';
124
+ return dirname(file);
121
125
  }
122
126
 
123
- const packageJson = await readJson(root, 'package.json');
127
+ let previous = root;
128
+
129
+ do {
130
+ const packageJson = await readJson(root, 'package.json');
131
+
132
+ if (Array.isArray(packageJson?.workspaces)) {
133
+ return root;
134
+ }
135
+
136
+ previous = root;
137
+ root = dirname(root);
138
+ } while (root !== previous);
139
+
140
+ return undefined;
141
+ }
142
+
143
+ export type MonorepoKind = 'none' | 'lerna' | 'yarn';
144
+
145
+ export async function detectMonorepo(root: string): Promise<MonorepoKind> {
146
+ const newRoot = await detectMonorepoRoot(root);
124
147
 
125
- if (Array.isArray(packageJson?.workspaces)) {
126
- return 'yarn';
148
+ if (newRoot) {
149
+ const file = await getLernaConfigPath(newRoot);
150
+
151
+ if (file !== undefined) {
152
+ return 'lerna';
153
+ }
154
+
155
+ const packageJson = await readJson(newRoot, 'package.json');
156
+
157
+ if (Array.isArray(packageJson?.workspaces)) {
158
+ return 'yarn';
159
+ }
127
160
  }
128
161
 
129
162
  return 'none';
@@ -159,7 +192,7 @@ export function createPackage(target = '.'): Promise<string> {
159
192
  return c.createPackage(target);
160
193
  }
161
194
 
162
- export function findTarball(packageRef: string) {
195
+ export function findTarball(packageRef: string): Promise<string> {
163
196
  const c = require(`./clients/npm`);
164
197
  return c.findTarball(packageRef);
165
198
  }
@@ -0,0 +1,58 @@
1
+ import { existsSync, readFileSync, statSync } from 'fs';
2
+ import { computeHash, computeIntegrity } from './hash';
3
+
4
+ const checkV1 = /^\/\/\s*@pilet\s+v:1\s*\(([A-Za-z0-9\_\:\-]+)\)/;
5
+ const checkV2 = /^\/\/\s*@pilet\s+v:2\s*(?:\(([A-Za-z0-9\_\:\-]+),\s*(.*)\))?/;
6
+
7
+ function getDependencies(deps: string, basePath: string) {
8
+ try {
9
+ const depMap = JSON.parse(deps);
10
+
11
+ if (depMap && typeof depMap === 'object') {
12
+ return Object.keys(depMap).reduce((obj, depName) => {
13
+ const depUrl = depMap[depName];
14
+
15
+ if (typeof depUrl === 'string') {
16
+ const url = new URL(depUrl, basePath);
17
+ obj[depName] = url.href;
18
+ }
19
+
20
+ return obj;
21
+ }, {});
22
+ }
23
+ } catch {}
24
+
25
+ return {};
26
+ }
27
+
28
+ export function getPiletSpecMeta(target: string, basePath: string) {
29
+ if (existsSync(target) && statSync(target).isFile()) {
30
+ const content = readFileSync(target, 'utf8');
31
+
32
+ if (checkV1.test(content)) {
33
+ // uses single argument; requireRef (required)
34
+ const [, requireRef] = checkV1.exec(content);
35
+ return {
36
+ spec: 'v1',
37
+ requireRef,
38
+ integrity: computeIntegrity(content),
39
+ };
40
+ } else if (checkV2.test(content)) {
41
+ // uses two arguments; requireRef and dependencies as JSON (required)
42
+ const [, requireRef, plainDependencies] = checkV2.exec(content);
43
+ return {
44
+ spec: 'v2',
45
+ requireRef,
46
+ dependencies: getDependencies(plainDependencies, basePath),
47
+ };
48
+ } else {
49
+ return {
50
+ spec: 'v0',
51
+ hash: computeHash(content),
52
+ noCache: true,
53
+ };
54
+ }
55
+ }
56
+
57
+ return {};
58
+ }
package/src/helpers.ts CHANGED
@@ -1,9 +1,17 @@
1
1
  import { ForceOverwrite, SourceLanguage } from './common/enums';
2
- import { Framework, NpmClientType, PiletSchemaVersion, PiletPublishSource, PiralBuildType } from './types';
2
+ import {
3
+ Framework,
4
+ NpmClientType,
5
+ PiletSchemaVersion,
6
+ PiletPublishSource,
7
+ PiralBuildType,
8
+ PiletBuildType,
9
+ } from './types';
3
10
 
4
11
  export const schemaKeys: Array<PiletSchemaVersion> = ['v0', 'v1', 'v2', 'none'];
5
12
  export const fromKeys: Array<PiletPublishSource> = ['local', 'remote', 'npm'];
6
- export const buildTypeKeys: Array<PiralBuildType> = ['all', 'release', 'emulator', 'emulator-sources'];
13
+ export const piralBuildTypeKeys: Array<PiralBuildType> = ['all', 'release', 'emulator', 'emulator-sources'];
14
+ export const piletBuildTypeKeys: Array<PiletBuildType> = ['default', 'standalone'];
7
15
  export const clientTypeKeys: Array<NpmClientType> = ['npm', 'pnpm', 'yarn'];
8
16
  export const bundlerKeys: Array<string> = ['none', 'parcel', 'webpack', 'webpack5', 'esbuild'];
9
17
  export const availableBundlers: Array<string> = [];
@@ -3,8 +3,8 @@ import { join } from 'path';
3
3
  import { EventEmitter } from 'events';
4
4
  import { readFileSync, existsSync, statSync } from 'fs';
5
5
  import { KrasInjector, KrasResponse, KrasRequest, KrasInjectorConfig, KrasConfiguration, KrasResult } from 'kras';
6
- import { computeHash, computeIntegrity } from '../common/hash';
7
6
  import { log } from '../common/log';
7
+ import { getPiletSpecMeta } from '../common/spec';
8
8
  import { axios, mime } from '../external';
9
9
  import { Bundler } from '../types';
10
10
 
@@ -26,62 +26,6 @@ interface PiletMetadata {
26
26
  [key: string]: unknown;
27
27
  }
28
28
 
29
- const checkV1 = /^\/\/\s*@pilet\s+v:1\s*\(([A-Za-z0-9\_\:\-]+)\)/;
30
- const checkV2 = /^\/\/\s*@pilet\s+v:2\s*(?:\(([A-Za-z0-9\_\:\-]+),\s*(.*)\))?/;
31
-
32
- function getDependencies(deps: string, basePath: string) {
33
- try {
34
- const depMap = JSON.parse(deps);
35
-
36
- if (depMap && typeof depMap === 'object') {
37
- return Object.keys(depMap).reduce((obj, depName) => {
38
- const depUrl = depMap[depName];
39
-
40
- if (typeof depUrl === 'string') {
41
- const url = new URL(depUrl, basePath);
42
- obj[depName] = url.href;
43
- }
44
-
45
- return obj;
46
- }, {});
47
- }
48
- } catch {}
49
-
50
- return {};
51
- }
52
-
53
- function getPiletSpecMeta(target: string, basePath: string) {
54
- if (existsSync(target) && statSync(target).isFile()) {
55
- const content = readFileSync(target, 'utf8');
56
-
57
- if (checkV1.test(content)) {
58
- // uses single argument; requireRef (required)
59
- const [, requireRef] = checkV1.exec(content);
60
- return {
61
- spec: 'v1',
62
- requireRef,
63
- integrity: computeIntegrity(content),
64
- };
65
- } else if (checkV2.test(content)) {
66
- // uses two arguments; requireRef and dependencies as JSON (required)
67
- const [, requireRef, plainDependencies] = checkV2.exec(content);
68
- return {
69
- spec: 'v2',
70
- requireRef,
71
- dependencies: getDependencies(plainDependencies, basePath),
72
- };
73
- } else {
74
- return {
75
- spec: 'v0',
76
- hash: computeHash(content),
77
- noCache: true,
78
- };
79
- }
80
- }
81
-
82
- return {};
83
- }
84
-
85
29
  function fillPiletMeta(pilet: Pilet, basePath: string) {
86
30
  const { root, bundler } = pilet;
87
31
  const def = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
@@ -100,6 +44,24 @@ function fillPiletMeta(pilet: Pilet, basePath: string) {
100
44
  return JSON.stringify(meta);
101
45
  }
102
46
 
47
+ async function loadFeed(feed: string) {
48
+ try {
49
+ const response = await axios.default.get<{ items?: Array<PiletMetadata> } | Array<PiletMetadata> | PiletMetadata>(
50
+ feed,
51
+ );
52
+
53
+ if (Array.isArray(response.data)) {
54
+ return response.data;
55
+ } else if (Array.isArray(response.data?.items)) {
56
+ return response.data.items;
57
+ } else {
58
+ return [response.data];
59
+ }
60
+ } catch (e) {
61
+ log('generalWarning_0001', `Couldn't load feed at ${feed}.`);
62
+ }
63
+ }
64
+
103
65
  export default class PiletInjector implements KrasInjector {
104
66
  public config: PiletInjectorConfig;
105
67
  private piletApi: string;
@@ -165,35 +127,26 @@ export default class PiletInjector implements KrasInjector {
165
127
  return JSON.stringify(mergedPilets);
166
128
  }
167
129
 
168
- async loadRemoteFeed(feed?: string): Promise<Array<PiletMetadata>> {
130
+ async loadRemoteFeed(feed?: string | Array<string>): Promise<Array<Array<PiletMetadata>>> {
169
131
  if (feed) {
170
- try {
171
- const response = await axios.default.get<{ items?: Array<PiletMetadata> } | Array<PiletMetadata> | PiletMetadata>(feed);
172
-
173
- if (Array.isArray(response.data)) {
174
- return response.data;
175
- } else if (Array.isArray(response.data?.items)) {
176
- return response.data.items;
177
- } else {
178
- return [response.data];
179
- }
180
- } catch (e) {
181
- log('generalWarning_0001', `Couldn't load feed at ${feed}.`);
182
- }
132
+ const feeds = Array.isArray(feed) ? feed : [feed];
133
+ return await Promise.all(feeds.map(loadFeed));
183
134
  }
184
-
185
135
  }
186
136
 
187
- mergePilets(localPilets: Array<PiletMetadata>, remotePilets: Array<PiletMetadata>) {
188
- if (!remotePilets) {
137
+ mergePilets(localPilets: Array<PiletMetadata>, remoteFeeds: Array<Array<PiletMetadata>>) {
138
+ if (!remoteFeeds) {
189
139
  return localPilets;
190
140
  }
191
141
 
192
142
  const names = localPilets.map((pilet) => pilet.name);
193
- const merged = [
194
- ...localPilets,
195
- ...remotePilets.filter((pilet) => pilet.name !== undefined && !names.includes(pilet.name)),
196
- ];
143
+ const merged = [...localPilets];
144
+
145
+ for (const remotePilets of remoteFeeds) {
146
+ const newPilets = remotePilets.filter((pilet) => pilet.name !== undefined && !names.includes(pilet.name));
147
+ names.push(...newPilets.map((p) => p.name));
148
+ merged.push(...newPilets);
149
+ }
197
150
 
198
151
  return merged;
199
152
  }