create-cwa 0.1.1 → 2.0.0-alpha.1

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/dist/index.js CHANGED
@@ -3,22 +3,51 @@ import { downloadTemplate } from 'giget';
3
3
  import fse from 'fs-extra';
4
4
  import fg from 'fast-glob';
5
5
  import { readFile, writeFile } from 'node:fs/promises';
6
- import { existsSync } from 'node:fs';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
7
  import { join, resolve } from 'node:path';
8
8
  import { tmpdir } from 'node:os';
9
9
  import { randomBytes } from 'node:crypto';
10
10
  import { spawnSync } from 'node:child_process';
11
- const MANIFEST_URL = 'https://raw.githubusercontent.com/components-web-app/components-web-app/main/cwa-manifest.json';
12
- async function fetchManifest() {
11
+ const REPO = 'components-web-app/components-web-app';
12
+ // The CLI and the template share a version: create-cwa X downloads the template at
13
+ // tag vX, so an install is reproducible. `--ref <branch|tag>` overrides it, for
14
+ // example `--ref main` for the latest unreleased template.
15
+ const CLI_VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
16
+ function parseArgs(argv) {
17
+ const args = argv.slice(2);
18
+ let ref = `v${CLI_VERSION}`;
19
+ const positional = [];
20
+ for (let i = 0; i < args.length; i++) {
21
+ const arg = args[i];
22
+ if (arg === '--ref' && args[i + 1])
23
+ ref = args[++i];
24
+ else if (arg.startsWith('--ref='))
25
+ ref = arg.slice('--ref='.length);
26
+ else
27
+ positional.push(arg);
28
+ }
29
+ return { projectName: positional[0], ref };
30
+ }
31
+ async function fetchManifest(ref) {
32
+ let res;
13
33
  try {
14
- const res = await fetch(MANIFEST_URL);
15
- if (!res.ok)
16
- throw new Error(`HTTP ${res.status}`);
17
- return (await res.json());
34
+ res = await fetch(`https://raw.githubusercontent.com/${REPO}/${ref}/cwa-manifest.json`);
18
35
  }
19
36
  catch {
20
37
  throw new Error('Could not fetch the CWA manifest. Check your internet connection and try again.');
21
38
  }
39
+ if (res.status === 404) {
40
+ throw new Error(`No CWA template found at "${ref}". Check the --ref value.`);
41
+ }
42
+ if (!res.ok) {
43
+ throw new Error(`Could not fetch the CWA manifest (HTTP ${res.status}). Try again shortly.`);
44
+ }
45
+ try {
46
+ return (await res.json());
47
+ }
48
+ catch {
49
+ throw new Error(`The CWA manifest at "${ref}" is not valid JSON.`);
50
+ }
22
51
  }
23
52
  function checkCancel(value) {
24
53
  if (isCancel(value)) {
@@ -37,8 +66,7 @@ function run(cmd, args, cwd) {
37
66
  const result = spawnSync(cmd, args, { stdio: 'inherit', cwd });
38
67
  return result.status === 0;
39
68
  }
40
- async function askQuestions(manifest, argv) {
41
- const targetArg = argv[2];
69
+ async function askQuestions(manifest, targetArg) {
42
70
  const projectName = checkCancel(await text({
43
71
  message: 'Project name?',
44
72
  placeholder: 'my-cwa-app',
@@ -79,11 +107,11 @@ async function askQuestions(manifest, argv) {
79
107
  }));
80
108
  return { projectName: projectName.trim(), ci, features: [...resolved], fixtures };
81
109
  }
82
- async function downloadRepo(manifest, tempDir) {
110
+ async function downloadRepo(manifest, ref, tempDir) {
83
111
  const s = spinner();
84
- s.start('Downloading template...');
112
+ s.start(`Downloading template (${ref})...`);
85
113
  try {
86
- await downloadTemplate(`github:${manifest.repo}#${manifest.branch}`, {
114
+ await downloadTemplate(`github:${manifest.repo}#${ref}`, {
87
115
  dir: tempDir,
88
116
  force: true,
89
117
  });
@@ -208,21 +236,22 @@ async function moveToTarget(tempDir, targetDir) {
208
236
  }
209
237
  async function main() {
210
238
  intro('create-cwa — Components Web App scaffolder');
239
+ const args = parseArgs(process.argv);
211
240
  const s = spinner();
212
241
  s.start('Fetching manifest...');
213
242
  let manifest;
214
243
  try {
215
- manifest = await fetchManifest();
244
+ manifest = await fetchManifest(args.ref);
216
245
  s.stop('Manifest loaded.');
217
246
  }
218
247
  catch (err) {
219
248
  s.stop(err.message);
220
249
  process.exit(1);
221
250
  }
222
- const answers = await askQuestions(manifest, process.argv);
251
+ const answers = await askQuestions(manifest, args.projectName);
223
252
  const targetDir = resolve(process.cwd(), answers.projectName);
224
253
  const tempDir = join(tmpdir(), `cwa-${randomBytes(6).toString('hex')}`);
225
- await downloadRepo(manifest, tempDir);
254
+ await downloadRepo(manifest, args.ref, tempDir);
226
255
  const s2 = spinner();
227
256
  s2.start('Configuring project...');
228
257
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-cwa",
3
- "version": "0.1.1",
3
+ "version": "2.0.0-alpha.1",
4
4
  "description": "Create a new CWA (Components Web App) project",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -15,26 +15,55 @@ import { downloadTemplate } from 'giget'
15
15
  import fse from 'fs-extra'
16
16
  import fg from 'fast-glob'
17
17
  import { readFile, writeFile } from 'node:fs/promises'
18
- import { existsSync } from 'node:fs'
18
+ import { existsSync, readFileSync } from 'node:fs'
19
19
  import { join, resolve } from 'node:path'
20
20
  import { tmpdir } from 'node:os'
21
21
  import { randomBytes } from 'node:crypto'
22
22
  import { spawnSync } from 'node:child_process'
23
23
  import type { Manifest, Answers } from './types.js'
24
24
 
25
- const MANIFEST_URL =
26
- 'https://raw.githubusercontent.com/components-web-app/components-web-app/main/cwa-manifest.json'
25
+ const REPO = 'components-web-app/components-web-app'
26
+
27
+ // The CLI and the template share a version: create-cwa X downloads the template at
28
+ // tag vX, so an install is reproducible. `--ref <branch|tag>` overrides it, for
29
+ // example `--ref main` for the latest unreleased template.
30
+ const CLI_VERSION: string = JSON.parse(
31
+ readFileSync(new URL('../package.json', import.meta.url), 'utf8')
32
+ ).version
33
+
34
+ function parseArgs(argv: string[]): { projectName?: string; ref: string } {
35
+ const args = argv.slice(2)
36
+ let ref = `v${CLI_VERSION}`
37
+ const positional: string[] = []
38
+ for (let i = 0; i < args.length; i++) {
39
+ const arg = args[i]
40
+ if (arg === '--ref' && args[i + 1]) ref = args[++i]
41
+ else if (arg.startsWith('--ref=')) ref = arg.slice('--ref='.length)
42
+ else positional.push(arg)
43
+ }
44
+ return { projectName: positional[0], ref }
45
+ }
27
46
 
28
- async function fetchManifest(): Promise<Manifest> {
47
+ async function fetchManifest(ref: string): Promise<Manifest> {
48
+ let res: Response
29
49
  try {
30
- const res = await fetch(MANIFEST_URL)
31
- if (!res.ok) throw new Error(`HTTP ${res.status}`)
32
- return (await res.json()) as Manifest
50
+ res = await fetch(`https://raw.githubusercontent.com/${REPO}/${ref}/cwa-manifest.json`)
33
51
  } catch {
34
52
  throw new Error(
35
53
  'Could not fetch the CWA manifest. Check your internet connection and try again.'
36
54
  )
37
55
  }
56
+ if (res.status === 404) {
57
+ throw new Error(`No CWA template found at "${ref}". Check the --ref value.`)
58
+ }
59
+ if (!res.ok) {
60
+ throw new Error(`Could not fetch the CWA manifest (HTTP ${res.status}). Try again shortly.`)
61
+ }
62
+ try {
63
+ return (await res.json()) as Manifest
64
+ } catch {
65
+ throw new Error(`The CWA manifest at "${ref}" is not valid JSON.`)
66
+ }
38
67
  }
39
68
 
40
69
  function checkCancel<T>(value: T | symbol): T {
@@ -57,9 +86,7 @@ function run(cmd: string, args: string[], cwd: string): boolean {
57
86
  return result.status === 0
58
87
  }
59
88
 
60
- async function askQuestions(manifest: Manifest, argv: string[]): Promise<Answers> {
61
- const targetArg = argv[2]
62
-
89
+ async function askQuestions(manifest: Manifest, targetArg?: string): Promise<Answers> {
63
90
  const projectName = checkCancel(
64
91
  await text({
65
92
  message: 'Project name?',
@@ -118,11 +145,11 @@ async function askQuestions(manifest: Manifest, argv: string[]): Promise<Answers
118
145
  return { projectName: projectName.trim(), ci, features: [...resolved], fixtures }
119
146
  }
120
147
 
121
- async function downloadRepo(manifest: Manifest, tempDir: string): Promise<void> {
148
+ async function downloadRepo(manifest: Manifest, ref: string, tempDir: string): Promise<void> {
122
149
  const s = spinner()
123
- s.start('Downloading template...')
150
+ s.start(`Downloading template (${ref})...`)
124
151
  try {
125
- await downloadTemplate(`github:${manifest.repo}#${manifest.branch}`, {
152
+ await downloadTemplate(`github:${manifest.repo}#${ref}`, {
126
153
  dir: tempDir,
127
154
  force: true,
128
155
  })
@@ -268,22 +295,23 @@ async function moveToTarget(tempDir: string, targetDir: string): Promise<void> {
268
295
  async function main(): Promise<void> {
269
296
  intro('create-cwa — Components Web App scaffolder')
270
297
 
298
+ const args = parseArgs(process.argv)
271
299
  const s = spinner()
272
300
  s.start('Fetching manifest...')
273
301
  let manifest: Manifest
274
302
  try {
275
- manifest = await fetchManifest()
303
+ manifest = await fetchManifest(args.ref)
276
304
  s.stop('Manifest loaded.')
277
305
  } catch (err) {
278
306
  s.stop((err as Error).message)
279
307
  process.exit(1)
280
308
  }
281
309
 
282
- const answers = await askQuestions(manifest, process.argv)
310
+ const answers = await askQuestions(manifest, args.projectName)
283
311
  const targetDir = resolve(process.cwd(), answers.projectName)
284
312
  const tempDir = join(tmpdir(), `cwa-${randomBytes(6).toString('hex')}`)
285
313
 
286
- await downloadRepo(manifest, tempDir)
314
+ await downloadRepo(manifest, args.ref, tempDir)
287
315
 
288
316
  const s2 = spinner()
289
317
  s2.start('Configuring project...')
package/src/types.ts CHANGED
@@ -26,6 +26,8 @@ export interface ManifestCi {
26
26
  export interface Manifest {
27
27
  version: string
28
28
  repo: string
29
+ // Read only by create-cwa 0.x, which downloads this branch. Newer versions download
30
+ // the tag matching their own version, or --ref.
29
31
  branch: string
30
32
  alwaysExclude: string[]
31
33
  questions: ManifestQuestion[]