@quilted/create 0.1.36 → 0.1.37

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.
@@ -34,6 +34,11 @@ async function createProject() {
34
34
  const args = getArguments();
35
35
  if (args['--help']) {
36
36
  const additionalOptions = index.stripIndent`
37
+ ${index.cyan_1(`--description`)}, ${index.cyan_1(`--no-description`)}
38
+ A short description of the package. If you don’t provide this option, the command will ask
39
+ you for a description later.
40
+ ${index.dim_1(`@see https://docs.npmjs.com/cli/v9/configuring-npm/package-json#description`)}
41
+
37
42
  ${index.cyan_1(`--react`)}, ${index.cyan_1(`--no-react`)}
38
43
  Whether this package will use React. If you don’t provide this option, the command
39
44
  will ask you about it later.
@@ -42,6 +47,11 @@ async function createProject() {
42
47
  Whether this package will be published for other projects to install. If you do not
43
48
  provide this option, the command will ask you about it later.
44
49
 
50
+ ${index.cyan_1(`--repository`)}, ${index.cyan_1(`--no-repository`)}
51
+ The URL of a git repository where your code lives. If you do not provide this option,
52
+ this command will try to guess the correct repository to use based on existing packages.
53
+ ${index.dim_1(`@see https://docs.npmjs.com/cli/v9/configuring-npm/package-json#repository`)}
54
+
45
55
  ${index.cyan_1(`--registry`)}
46
56
  The package registry to publish this package to. This option only applies if you create
47
57
  a public package. If you do not provide this option, it will use the default NPM registry.
@@ -53,22 +63,30 @@ async function createProject() {
53
63
  });
54
64
  return;
55
65
  }
56
- const inWorkspace = fs__namespace.existsSync('quilt.workspace.ts');
57
66
  const name = await getName(args);
67
+ const description = await getDescription(args);
68
+ const inWorkspace = await packageManager.getInWorkspace(args);
58
69
  const directory = await getDirectory(args, {
59
70
  name,
60
71
  inWorkspace
61
72
  });
62
73
  const isPublic = await getPublic(args);
63
- const useReact = await getReact(args);
64
- const createAsMonorepo = !inWorkspace && (await packageManager.getCreateAsMonorepo(args));
65
- const shouldInstall = await packageManager.getShouldInstall(args);
66
- const packageManager$1 = await packageManager.getPackageManager(args, {
67
- root: directory
74
+ const repository = await getRepository(args, {
75
+ inWorkspace
68
76
  });
77
+ const useReact = await getReact(args);
78
+ const createAsMonorepo = !inWorkspace && (await packageManager.getCreateAsMonorepo(args, {
79
+ type: 'package'
80
+ }));
69
81
  const setupExtras = await packageManager.getExtrasToSetup(args, {
70
82
  inWorkspace
71
83
  });
84
+ const shouldInstall = await packageManager.getShouldInstall(args, {
85
+ type: 'package'
86
+ });
87
+ const packageManager$1 = await packageManager.getPackageManager(args, {
88
+ root: directory
89
+ });
72
90
  const partOfMonorepo = inWorkspace || createAsMonorepo;
73
91
  const packageDirectory = createAsMonorepo ? path__namespace.join(directory, `packages/${packageManager.toValidPackageName(name.split('/').pop())}`) : directory;
74
92
  if (fs__namespace.existsSync(directory)) {
@@ -88,12 +106,15 @@ async function createProject() {
88
106
  const packageTemplate = packageManager.loadTemplate('package');
89
107
  const workspaceTemplate = packageManager.loadTemplate('workspace');
90
108
  let quiltProject = await packageTemplate.read('quilt.project.ts');
109
+ if (!useReact) {
110
+ quiltProject = quiltProject.replace('quiltPackage()', 'quiltPackage({react: false})');
111
+ }
91
112
 
92
113
  // If we aren’t already in a workspace, copy the workspace files over, which
93
114
  // are needed if we are making a monorepo or not.
94
115
  if (!inWorkspace) {
95
116
  await workspaceTemplate.copy(directory, file => {
96
- // When this is a single project, we use the project’s Quilt configuration as the base.
117
+ // When this is a single project, we use the project’s Quilt configuration as the base.
97
118
  if (file === 'quilt.workspace.ts') return createAsMonorepo;
98
119
 
99
120
  // We need to make some adjustments to the root package.json
@@ -103,41 +124,28 @@ async function createProject() {
103
124
  // If we are creating a monorepo, we need to add the root package.json and
104
125
  // package manager workspace configuration.
105
126
  if (createAsMonorepo) {
127
+ const packageRelativeToRoot = path__namespace.relative(rootDirectory, packageDirectory);
128
+ const packageGlobRelativeToRoot = packageManager.relativeDirectoryForDisplay(path__namespace.join(packageRelativeToRoot, '*'));
106
129
  const workspacePackageJson = JSON.parse(await workspaceTemplate.read('package.json'));
107
130
  workspacePackageJson.name = packageManager.toValidPackageName(name);
131
+ workspacePackageJson.workspaces = [packageGlobRelativeToRoot];
108
132
  if (packageManager$1.type === 'pnpm') {
109
133
  await outputRoot.write('pnpm-workspace.yaml', await packageManager.format(`
110
134
  packages:
111
- - './packages/*'
135
+ - '${packageGlobRelativeToRoot}'
112
136
  `, {
113
137
  as: 'yaml'
114
138
  }));
115
- } else {
116
- workspacePackageJson.workspaces = ['packages/*'];
117
139
  }
118
140
  await outputRoot.write('package.json', await packageManager.format(JSON.stringify(workspacePackageJson), {
119
141
  as: 'json-stringify'
120
142
  }));
121
143
  } else {
122
144
  const [projectPackageJson, projectTSConfig, workspacePackageJson] = await Promise.all([packageTemplate.read('package.json').then(content => JSON.parse(content)), packageTemplate.read('tsconfig.json').then(content => JSON.parse(content)), workspaceTemplate.read('package.json').then(content => JSON.parse(content))]);
123
- workspacePackageJson.eslintConfig = projectPackageJson.eslintConfig;
124
- workspacePackageJson.browserslist = projectPackageJson.browserslist;
125
- const newPackageJson = {};
126
-
127
- // We want to put the project’s dependencies in the package.json, respecting
128
- // the preferred ordering (dependencies, peer dependencies, dev dependencies).
129
- for (const [key, value] of Object.entries(projectPackageJson)) {
130
- if (key !== 'devDependencies') {
131
- newPackageJson[key] = value;
132
- continue;
133
- }
134
- newPackageJson.dependencies = projectPackageJson.dependencies;
135
- newPackageJson.peerDependencies = projectPackageJson.peerDependencies;
136
- newPackageJson.peerDependenciesMeta = projectPackageJson.peerDependenciesMeta;
137
- newPackageJson.devDependencies = packageManager.mergeDependencies(workspacePackageJson.devDependencies, projectPackageJson.devDependencies);
138
- }
139
- adjustPackageJson(newPackageJson, {
145
+ const mergedPackageJson = packageManager.mergeWorkspaceAndProjectPackageJsons(projectPackageJson, workspacePackageJson);
146
+ adjustPackageJson(mergedPackageJson, {
140
147
  name: packageManager.toValidPackageName(name),
148
+ description,
141
149
  react: useReact,
142
150
  isPublic,
143
151
  registry: args['--registry']
@@ -146,7 +154,7 @@ async function createProject() {
146
154
  await outputRoot.write('quilt.project.ts', await packageManager.format(quiltProject, {
147
155
  as: 'typescript'
148
156
  }));
149
- await outputRoot.write('package.json', await packageManager.format(JSON.stringify(newPackageJson), {
157
+ await outputRoot.write('package.json', await packageManager.format(JSON.stringify(mergedPackageJson), {
150
158
  as: 'json-stringify'
151
159
  }));
152
160
  await outputRoot.write('tsconfig.json', await packageManager.format(JSON.stringify(projectTSConfig), {
@@ -172,9 +180,29 @@ async function createProject() {
172
180
  if (partOfMonorepo) {
173
181
  // Write the package’s package.json (the root one was already created)
174
182
  const projectPackageJson = JSON.parse(await packageTemplate.read('package.json'));
175
- projectPackageJson.repository.directory = path__namespace.relative(rootDirectory, packageDirectory);
183
+ if (repository === false) {
184
+ delete projectPackageJson.repository;
185
+ } else {
186
+ const directory = path__namespace.relative(rootDirectory, packageDirectory);
187
+ if (typeof repository === 'string') {
188
+ projectPackageJson.repository = {
189
+ type: 'git',
190
+ url: repository,
191
+ directory
192
+ };
193
+ } else if (repository != null) {
194
+ projectPackageJson.repository = {
195
+ type: 'git',
196
+ ...repository,
197
+ directory
198
+ };
199
+ } else {
200
+ projectPackageJson.repository.directory = directory;
201
+ }
202
+ }
176
203
  adjustPackageJson(projectPackageJson, {
177
204
  name: packageManager.toValidPackageName(name),
205
+ description,
178
206
  react: useReact,
179
207
  isPublic,
180
208
  registry: args['--registry']
@@ -186,45 +214,36 @@ async function createProject() {
186
214
  await Promise.all([packageManager.addToTsConfig(packageDirectory, outputRoot), packageManager.addToPackageManagerWorkspaces(packageDirectory, outputRoot, packageManager$1.type)]);
187
215
  }
188
216
  if (shouldInstall) {
189
- process.stdout.write('\nInstalling dependencies...\n');
190
217
  // TODO: better loading, handle errors
191
218
  await packageManager$1.install();
192
- process.stdout.moveCursor(0, -1);
193
- process.stdout.clearLine(1);
194
- console.log('Installed dependencies.');
195
219
  }
196
- const packageJsonInstructions = index.stripIndent`
197
- Your new package is ready to go! However, before you go too much further,
198
- you should update the following fields in ${index.cyan_1(packageManager.relativeDirectoryForDisplay(path__namespace.relative(process.cwd(), path__namespace.join(packageDirectory, 'package.json'))))}:
199
-
200
- - ${index.bold_1(`"description"`)}, where you provide a description of what your package does
201
- - ${index.bold_1(`"repository"`)}, where you should include the ${index.bold_1(`"url"`)} of your project’s repo
202
-
203
- Before you publish your package, you will also want to update the ${index.bold_1(`"version"`)}
204
- field in the package.json file.
205
- `;
206
220
  console.log();
207
- console.log(packageJsonInstructions);
208
- const commands = [];
209
- if (!inWorkspace && directory !== process.cwd()) {
210
- commands.push(`cd ${index.cyan_1(packageManager.relativeDirectoryForDisplay(path__namespace.relative(process.cwd(), directory)))} ${index.dim_1('# Move into your new package’s directory')}`);
211
- }
212
- if (!shouldInstall) {
213
- commands.push(`${packageManager$1.commands.install()} ${index.dim_1('# Install all your dependencies')}`);
214
- }
215
- if (!inWorkspace) {
216
- // TODO: change this condition to check if git was initialized already
217
- commands.push(`git init && git add -A && git commit -m "Initial commit" ${index.dim_1('# Start your git history (optional)')}`);
218
- }
219
- if (commands.length > 0) {
220
- const whatsNext = index.stripIndent`
221
- After you update your package.json, there’s ${commands.length > 1 ? 'a few more steps' : 'one more step'} you’ll need to take
222
- in order to start building:
223
- `;
224
- console.log();
225
- console.log(whatsNext);
221
+ console.log(index.stripIndent`
222
+ Your new package, ${index.bold_1(name)}, is ready to go! You can edit the code for your package in
223
+ ${index.cyan_1(packageManager.relativeDirectoryForDisplay(path__namespace.relative(process.cwd(), path__namespace.join(packageDirectory, 'source'))))}.
224
+ `);
225
+ if (isPublic) {
226
+ const needsPackageJsonKeys = [];
227
+ if (!description) {
228
+ needsPackageJsonKeys.push('description');
229
+ }
230
+ if (repository == null) {
231
+ needsPackageJsonKeys.push('repository.url');
232
+ }
226
233
  console.log();
227
- console.log(commands.map(command => ` ${command}`).join('\n'));
234
+ if (needsPackageJsonKeys.length > 0) {
235
+ console.log(index.stripIndent`
236
+ Before you publish your package, you will need to add the ${needsPackageJsonKeys.map(key => index.bold_1(JSON.stringify(key))).join(' and ')} key${needsPackageJsonKeys.length > 1 ? 's' : ''}
237
+ to ${index.cyan_1(packageManager.relativeDirectoryForDisplay(path__namespace.relative(process.cwd(), path__namespace.join(packageDirectory, 'package.json'))))}. In that same file, make sure the contents of the
238
+ ${index.bold_1('"version"')}, ${index.bold_1('"exports"')}, and ${index.bold_1('"license"')} fields are correct for your package.
239
+ `);
240
+ } else {
241
+ console.log(index.stripIndent`
242
+ Before you publish your package, make sure the content of the
243
+ ${index.bold_1('"version"')}, ${index.bold_1('exports')}, and ${index.bold_1('license')} fields in
244
+ ${index.cyan_1(packageManager.relativeDirectoryForDisplay(path__namespace.relative(process.cwd(), path__namespace.join(packageDirectory, 'package.json'))))} are correct for your package.
245
+ `);
246
+ }
228
247
  }
229
248
  const followUp = index.stripIndent`
230
249
  Quilt can help you build, test, lint, and type-check your new package. You
@@ -245,6 +264,10 @@ function getArguments() {
245
264
  '-y': '--yes',
246
265
  '--name': String,
247
266
  '--directory': String,
267
+ '--description': String,
268
+ '--no-description': Boolean,
269
+ '--repository': String,
270
+ '--no-repository': Boolean,
248
271
  '--install': Boolean,
249
272
  '--no-install': Boolean,
250
273
  '--monorepo': Boolean,
@@ -311,6 +334,36 @@ async function getDirectory(args, {
311
334
  }
312
335
  return directory;
313
336
  }
337
+ async function getDescription(args) {
338
+ if (args['--description']) return args['--description'];
339
+ if (args['--no-description']) return false;
340
+ const description = await index.prompt({
341
+ type: 'text',
342
+ message: 'What is a short description of what this package will do?'
343
+ });
344
+ return description;
345
+ }
346
+ async function getRepository(args, {
347
+ inWorkspace = false
348
+ } = {}) {
349
+ if (args['--repository']) return args['--repository'];
350
+ if (args['--no-repository']) return false;
351
+ if (!inWorkspace) return;
352
+ const {
353
+ globby
354
+ } = await Promise.resolve().then(function () { return require('./index4.cjs'); });
355
+ const files = await globby('**/package.json', {
356
+ ignore: ['**/node_modules']
357
+ });
358
+ for (const file of files) {
359
+ try {
360
+ const json = JSON.parse(await fs__namespace.promises.readFile(file, 'utf8'));
361
+ if (json.repository) return json.repository;
362
+ } catch {
363
+ // noop
364
+ }
365
+ }
366
+ }
314
367
  async function getPublic(args) {
315
368
  let isPublic;
316
369
  if (args['--public'] || args['--yes']) {
@@ -343,6 +396,7 @@ async function getReact(args) {
343
396
  }
344
397
  function adjustPackageJson(packageJson, {
345
398
  name,
399
+ description,
346
400
  react,
347
401
  isPublic,
348
402
  registry
@@ -351,6 +405,11 @@ function adjustPackageJson(packageJson, {
351
405
  const packageParts = name.split('/');
352
406
  const scope = packageParts[0].startsWith('@') ? packageParts[0] : undefined;
353
407
  const finalRegistry = registry ?? 'https://registry.npmjs.org';
408
+ if (description) {
409
+ packageJson.description = description;
410
+ } else {
411
+ delete packageJson.description;
412
+ }
354
413
  if (scope) {
355
414
  packageJson.publishConfig[`${scope}/registry`] = finalRegistry;
356
415
  } else if (registry) {
@@ -358,6 +417,8 @@ function adjustPackageJson(packageJson, {
358
417
  }
359
418
  if (isPublic) {
360
419
  delete packageJson.private;
420
+ delete packageJson.license;
421
+ delete packageJson.repository;
361
422
  } else {
362
423
  delete packageJson.publishConfig;
363
424
  }
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ var fs = require('node:fs');
3
4
  var require$$0 = require('node:tty');
4
5
  var index = require('../index.cjs');
5
- var fs = require('node:fs');
6
6
  var node_child_process = require('node:child_process');
7
7
  var path = require('node:path');
8
8
  var node_url = require('node:url');
@@ -175,7 +175,8 @@ async function format(content, {
175
175
  as: parser
176
176
  }) {
177
177
  const [{
178
- format
178
+ format: rootFormat,
179
+ default: prettier
179
180
  }, {
180
181
  default: babel
181
182
  }, {
@@ -183,6 +184,9 @@ async function format(content, {
183
184
  }, {
184
185
  default: yaml
185
186
  }] = await Promise.all([Promise.resolve().then(function () { return require('../standalone.cjs'); }).then(function (n) { return n.standalone; }), Promise.resolve().then(function () { return require('../parser-babel.cjs'); }).then(function (n) { return n.parserBabel; }), Promise.resolve().then(function () { return require('../parser-typescript.cjs'); }).then(function (n) { return n.parserTypescript; }), Promise.resolve().then(function () { return require('../parser-yaml.cjs'); }).then(function (n) { return n.parserYaml; })]);
187
+
188
+ // CJS workaround
189
+ const format = rootFormat ?? prettier.format;
186
190
  return format(content, {
187
191
  arrowParens: 'always',
188
192
  bracketSpacing: false,
@@ -203,6 +207,42 @@ function mergeDependencies(first = {}, second = {}) {
203
207
  }
204
208
  return merged;
205
209
  }
210
+ const PACKAGE_JSON_DEPENDENCY_KEYS = new Set(['dependencies', 'devDependencies', 'peerDependencies', 'peerDependenciesMeta']);
211
+
212
+ // Merges a project and workspace package.json together, with the following nitpicky preferences:
213
+ //
214
+ // - Take all the project’s fields in the order they appear by default
215
+ // - Merge the relevant dependencies together
216
+ // - Projects don’t come with `scripts` by default, but that should go before the first dependency list
217
+ // - If there are other keys in the workspace package.json, they should go last, in the order they appeared
218
+ function mergeWorkspaceAndProjectPackageJsons(projectPackageJson, workspacePackageJson) {
219
+ const newPackageJson = {};
220
+ const seenKeys = new Set();
221
+ let hasHandledScriptsField = workspacePackageJson.scripts != null && projectPackageJson.scripts == null;
222
+ for (const [key, value] of Object.entries(projectPackageJson)) {
223
+ seenKeys.add(key);
224
+ const isDependencyKey = PACKAGE_JSON_DEPENDENCY_KEYS.has(key);
225
+ if (key === 'scripts' || isDependencyKey && !hasHandledScriptsField) {
226
+ newPackageJson.scripts = {
227
+ ...workspacePackageJson.scripts,
228
+ ...projectPackageJson.scripts
229
+ };
230
+ hasHandledScriptsField = true;
231
+ }
232
+ if (isDependencyKey) {
233
+ newPackageJson[key] = mergeDependencies(value, workspacePackageJson[key]);
234
+ } else {
235
+ newPackageJson[key] = value;
236
+ }
237
+ }
238
+ for (const [key, value] of Object.entries(workspacePackageJson)) {
239
+ if (seenKeys.has(key)) continue;
240
+ // Merged workspace + project package.json means we are not in a monorepo
241
+ if (key === 'workspaces') continue;
242
+ newPackageJson[key] = value;
243
+ }
244
+ return newPackageJson;
245
+ }
206
246
 
207
247
  var colorette = {};
208
248
 
@@ -420,7 +460,14 @@ colorette.whiteBright = whiteBright;
420
460
  colorette.yellow = yellow;
421
461
  colorette.yellowBright = yellowBright;
422
462
 
423
- async function getCreateAsMonorepo(argv) {
463
+ async function getInWorkspace(argv) {
464
+ if (argv['--in-workspace']) return true;
465
+ if (argv['--not-in-workspace']) return false;
466
+ return fs__namespace.existsSync('quilt.workspace.ts');
467
+ }
468
+ async function getCreateAsMonorepo(argv, {
469
+ type
470
+ }) {
424
471
  let createAsMonorepo;
425
472
  if (argv['--monorepo' ]) {
426
473
  createAsMonorepo = true;
@@ -429,13 +476,15 @@ async function getCreateAsMonorepo(argv) {
429
476
  } else {
430
477
  createAsMonorepo = await index.prompt({
431
478
  type: 'confirm',
432
- message: 'Do you want to create this app as a monorepo, with room for more projects?',
479
+ message: `Do you want to create this ${type} as a monorepo, with room for more projects?`,
433
480
  initial: true
434
481
  });
435
482
  }
436
483
  return createAsMonorepo;
437
484
  }
438
- async function getShouldInstall(argv) {
485
+ async function getShouldInstall(argv, {
486
+ type
487
+ }) {
439
488
  let shouldInstall;
440
489
  if (argv['--install'] || argv['--yes']) {
441
490
  shouldInstall = true;
@@ -444,7 +493,7 @@ async function getShouldInstall(argv) {
444
493
  } else {
445
494
  shouldInstall = await index.prompt({
446
495
  type: 'confirm',
447
- message: 'Do you want to install dependencies for this app after creating it?',
496
+ message: `Do you want to install dependencies for this ${type} after creating it?`,
448
497
  initial: true
449
498
  });
450
499
  }
@@ -604,12 +653,13 @@ exports.emptyDirectory = emptyDirectory;
604
653
  exports.format = format;
605
654
  exports.getCreateAsMonorepo = getCreateAsMonorepo;
606
655
  exports.getExtrasToSetup = getExtrasToSetup;
656
+ exports.getInWorkspace = getInWorkspace;
607
657
  exports.getPackageManager = getPackageManager;
608
658
  exports.getShouldInstall = getShouldInstall;
609
659
  exports.isEmpty = isEmpty;
610
660
  exports.loadTemplate = loadTemplate;
611
661
  exports.magenta_1 = magenta_1;
612
- exports.mergeDependencies = mergeDependencies;
662
+ exports.mergeWorkspaceAndProjectPackageJsons = mergeWorkspaceAndProjectPackageJsons;
613
663
  exports.relativeDirectoryForDisplay = relativeDirectoryForDisplay;
614
664
  exports.toValidPackageName = toValidPackageName;
615
665
  exports.underline_1 = underline_1;
package/build/esm/app.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
- import { c as cyan_1, b as bold_1, g as getCreateAsMonorepo, a as getShouldInstall, d as getPackageManager, e as getExtrasToSetup, f as emptyDirectory, t as toValidPackageName, h as format, m as mergeDependencies, l as loadTemplate, i as addToTsConfig, j as addToPackageManagerWorkspaces, r as relativeDirectoryForDisplay, k as dim_1, u as underline_1, n as magenta_1, o as isEmpty, p as createOutputTarget } from './shared/package-manager.mjs';
3
+ import { c as cyan_1, b as bold_1, g as getInWorkspace, a as getCreateAsMonorepo, d as getExtrasToSetup, e as getShouldInstall, f as getPackageManager, h as emptyDirectory, r as relativeDirectoryForDisplay, t as toValidPackageName, i as format, m as mergeWorkspaceAndProjectPackageJsons, l as loadTemplate, j as addToTsConfig, k as addToPackageManagerWorkspaces, n as dim_1, u as underline_1, o as magenta_1, p as isEmpty, q as createOutputTarget } from './shared/package-manager.mjs';
4
4
  import { s as stripIndent, p as printHelp, a as prompt } from './index.mjs';
5
5
  import 'node:tty';
6
6
  import 'node:child_process';
@@ -222,7 +222,7 @@ async function createApp() {
222
222
  });
223
223
  return;
224
224
  }
225
- const inWorkspace = fs.existsSync('quilt.workspace.ts');
225
+ const inWorkspace = await getInWorkspace(argv);
226
226
  const name = await getName(argv, {
227
227
  inWorkspace
228
228
  });
@@ -230,14 +230,18 @@ async function createApp() {
230
230
  name
231
231
  });
232
232
  const template = await getTemplate(argv);
233
- const createAsMonorepo = !inWorkspace && (await getCreateAsMonorepo(argv));
234
- const shouldInstall = await getShouldInstall(argv);
235
- const packageManager = await getPackageManager(argv, {
236
- root: directory
237
- });
233
+ const createAsMonorepo = !inWorkspace && (await getCreateAsMonorepo(argv, {
234
+ type: 'app'
235
+ }));
238
236
  const setupExtras = await getExtrasToSetup(argv, {
239
237
  inWorkspace
240
238
  });
239
+ const shouldInstall = await getShouldInstall(argv, {
240
+ type: 'app'
241
+ });
242
+ const packageManager = await getPackageManager(argv, {
243
+ root: directory
244
+ });
241
245
  const partOfMonorepo = inWorkspace || createAsMonorepo;
242
246
  const appDirectory = createAsMonorepo ? path.join(directory, 'app') : directory;
243
247
  if (fs.existsSync(directory)) {
@@ -271,33 +275,32 @@ async function createApp() {
271
275
  // If we are creating a monorepo, we need to add the root package.json and
272
276
  // package manager workspace configuration.
273
277
  if (createAsMonorepo) {
278
+ const appRelativeToRoot = relativeDirectoryForDisplay(path.relative(directory, appDirectory));
274
279
  const workspacePackageJson = JSON.parse(await workspaceTemplate.read('package.json'));
275
280
  workspacePackageJson.name = toValidPackageName(name);
281
+ workspacePackageJson.workspaces = [appRelativeToRoot, './packages/*'];
276
282
  if (packageManager.type === 'pnpm') {
277
283
  await outputRoot.write('pnpm-workspace.yaml', await format(`
278
284
  packages:
285
+ - '${appRelativeToRoot}'
279
286
  - './packages/*'
280
287
  `, {
281
288
  as: 'yaml'
282
289
  }));
283
- } else {
284
- workspacePackageJson.workspaces = ['packages/*'];
285
290
  }
286
291
  await outputRoot.write('package.json', await format(JSON.stringify(workspacePackageJson), {
287
292
  as: 'json-stringify'
288
293
  }));
289
294
  } else {
290
295
  const [projectPackageJson, projectTSConfig, workspacePackageJson] = await Promise.all([appTemplate.read('package.json').then(content => JSON.parse(content)), appTemplate.read('tsconfig.json').then(content => JSON.parse(content)), workspaceTemplate.read('package.json').then(content => JSON.parse(content))]);
291
- workspacePackageJson.name = toValidPackageName(name);
292
- workspacePackageJson.eslintConfig = projectPackageJson.eslintConfig;
293
- workspacePackageJson.browserslist = projectPackageJson.browserslist;
294
- workspacePackageJson.devDependencies = mergeDependencies(workspacePackageJson.devDependencies, projectPackageJson.devDependencies);
296
+ const combinedPackageJson = mergeWorkspaceAndProjectPackageJsons(projectPackageJson, workspacePackageJson);
297
+ combinedPackageJson.name = toValidPackageName(name);
295
298
  let quiltProject = await appTemplate.read('quilt.project.ts');
296
299
  quiltProject = quiltProject.replace('quiltApp', 'quiltWorkspace, quiltApp').replace('quiltApp(', 'quiltWorkspace(), quiltApp(');
297
300
  await outputRoot.write('quilt.project.ts', await format(quiltProject, {
298
301
  as: 'typescript'
299
302
  }));
300
- await outputRoot.write('package.json', await format(JSON.stringify(workspacePackageJson), {
303
+ await outputRoot.write('package.json', await format(JSON.stringify(combinedPackageJson), {
301
304
  as: 'json-stringify'
302
305
  }));
303
306
  await outputRoot.write('tsconfig.json', await format(JSON.stringify(projectTSConfig), {
@@ -330,12 +333,8 @@ async function createApp() {
330
333
  await Promise.all([addToTsConfig(appDirectory, outputRoot), addToPackageManagerWorkspaces(appDirectory, outputRoot, packageManager.type)]);
331
334
  }
332
335
  if (shouldInstall) {
333
- process.stdout.write('\nInstalling dependencies...\n');
334
336
  // TODO: better loading, handle errors
335
337
  await packageManager.install();
336
- process.stdout.moveCursor(0, -1);
337
- process.stdout.clearLine(1);
338
- console.log('Installed dependencies.');
339
338
  }
340
339
  const commands = [];
341
340
  if (!inWorkspace && directory !== process.cwd()) {
@@ -344,10 +343,6 @@ async function createApp() {
344
343
  if (!shouldInstall) {
345
344
  commands.push(`${packageManager.commands.install()} ${dim_1('# Install all your dependencies')}`);
346
345
  }
347
- if (!inWorkspace) {
348
- // TODO: change this condition to check if git was initialized already
349
- commands.push(`git init && git add -A && git commit -m "Initial commit" ${dim_1('# Start your git history (optional)')}`);
350
- }
351
346
  commands.push(`${packageManager.commands.run('develop')} ${dim_1('# Start the development server')}`);
352
347
  const whatsNext = stripIndent`
353
348
  Your new app is ready to go! There’s just ${commands.length > 1 ? 'a few more steps' : 'one more step'} you’ll need to take