create-tina-app 1.3.0 → 1.3.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.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export declare const PKG_MANAGERS: string[];
2
- export declare const run: () => Promise<void>;
2
+ export declare function run(): Promise<void>;
package/dist/index.js CHANGED
@@ -17,6 +17,10 @@ var __copyProps = (to, from, except, desc) => {
17
17
  return to;
18
18
  };
19
19
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
24
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
21
25
  mod
22
26
  ));
@@ -36,12 +40,49 @@ var import_node_path = __toESM(require("path"));
36
40
 
37
41
  // package.json
38
42
  var name = "create-tina-app";
39
- var version = "1.3.0";
43
+ var version = "1.3.1";
40
44
 
41
45
  // src/util/fileUtil.ts
42
46
  var import_fs_extra = __toESM(require("fs-extra"));
43
47
  var import_path = __toESM(require("path"));
48
+
49
+ // src/util/logger.ts
44
50
  var import_chalk = __toESM(require("chalk"));
51
+ var TextStyles = {
52
+ link: import_chalk.default.bold.cyan,
53
+ cmd: import_chalk.default.inverse,
54
+ info: import_chalk.default.blue,
55
+ success: import_chalk.default.green,
56
+ warn: import_chalk.default.yellow,
57
+ err: import_chalk.default.red,
58
+ bold: import_chalk.default.bold
59
+ };
60
+ var Logger = class {
61
+ log(message) {
62
+ console.info(message);
63
+ }
64
+ debug(message) {
65
+ console.debug(TextStyles.info(`[DEBUG] ${message}`));
66
+ }
67
+ info(message) {
68
+ console.info(TextStyles.info(`[INFO] ${message}`));
69
+ }
70
+ success(message) {
71
+ console.log(TextStyles.success(`[SUCCESS] ${message}`));
72
+ }
73
+ cmd(message) {
74
+ console.log(TextStyles.cmd(message));
75
+ }
76
+ warn(message) {
77
+ console.warn(TextStyles.warn(`[WARNING] ${message}`));
78
+ }
79
+ err(message) {
80
+ console.error(TextStyles.err(`[ERROR] ${message}`));
81
+ }
82
+ };
83
+ var log = new Logger();
84
+
85
+ // src/util/fileUtil.ts
45
86
  async function isWriteable(directory) {
46
87
  try {
47
88
  await import_fs_extra.default.promises.access(directory, (import_fs_extra.default.constants || import_fs_extra.default).W_OK);
@@ -50,10 +91,7 @@ async function isWriteable(directory) {
50
91
  return false;
51
92
  }
52
93
  }
53
- function makeDir(root) {
54
- return import_fs_extra.default.mkdirp(root);
55
- }
56
- function isFolderEmpty(root, name2) {
94
+ function folderContainsInstallConflicts(root) {
57
95
  const validFiles = [
58
96
  ".DS_Store",
59
97
  ".git",
@@ -75,35 +113,49 @@ function isFolderEmpty(root, name2) {
75
113
  "yarn-error.log"
76
114
  ];
77
115
  const conflicts = import_fs_extra.default.readdirSync(root).filter((file) => !validFiles.includes(file)).filter((file) => !/\.iml$/.test(file));
116
+ return conflicts;
117
+ }
118
+ async function setupProjectDirectory(dir) {
119
+ const appName = import_path.default.basename(dir);
120
+ await import_fs_extra.default.mkdirp(dir);
121
+ process.chdir(dir);
122
+ const conflicts = folderContainsInstallConflicts(dir);
78
123
  if (conflicts.length > 0) {
79
- console.log(
80
- `The directory ${import_chalk.default.green(name2)} contains files that could conflict:`
124
+ log.err(
125
+ `The directory '${TextStyles.bold(
126
+ appName
127
+ )}' contains files that could conflict. Below is a list of conflicts, please remove them and try again.`
81
128
  );
82
- console.log();
83
129
  for (const file of conflicts) {
84
130
  try {
85
- const stats = import_fs_extra.default.lstatSync(import_path.default.join(root, file));
131
+ const stats = import_fs_extra.default.lstatSync(import_path.default.join(dir, file));
86
132
  if (stats.isDirectory()) {
87
- console.log(` ${import_chalk.default.blue(file)}/`);
133
+ log.log(`- ${TextStyles.info(file)}/`);
88
134
  } else {
89
- console.log(` ${file}`);
135
+ log.log(`- ${file}`);
90
136
  }
91
137
  } catch {
92
- console.log(` ${file}`);
138
+ log.log(`- ${file}`);
93
139
  }
94
140
  }
95
- console.log();
96
- console.log(
97
- "Either try using a new directory name, or remove the files listed above."
98
- );
99
- console.log();
100
- return false;
141
+ process.exit(1);
101
142
  }
102
- return true;
143
+ return appName;
144
+ }
145
+ function updateProjectPackageName(dir, name2) {
146
+ const packageJsonPath = import_path.default.join(dir, "package.json");
147
+ const packageJson = JSON.parse(import_fs_extra.default.readFileSync(packageJsonPath, "utf8"));
148
+ packageJson.name = name2;
149
+ import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
150
+ }
151
+ function updateProjectPackageVersion(dir, version2) {
152
+ const packageJsonPath = import_path.default.join(dir, "package.json");
153
+ const packageJson = JSON.parse(import_fs_extra.default.readFileSync(packageJsonPath, "utf8"));
154
+ packageJson.version = version2;
155
+ import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
103
156
  }
104
157
 
105
158
  // src/util/install.ts
106
- var import_chalk2 = __toESM(require("chalk"));
107
159
  var import_cross_spawn = __toESM(require("cross-spawn"));
108
160
  function install(root, dependencies, { packageManager, isOnline, devDependencies }) {
109
161
  const npmFlags = [];
@@ -116,11 +168,9 @@ function install(root, dependencies, { packageManager, isOnline, devDependencies
116
168
  switch (packageManager) {
117
169
  case "yarn":
118
170
  args = ["add", "--exact"];
119
- if (!isOnline)
120
- args.push("--offline");
171
+ if (!isOnline) args.push("--offline");
121
172
  args.push("--cwd", root);
122
- if (devDependencies)
123
- args.push("--dev");
173
+ if (devDependencies) args.push("--dev");
124
174
  args.push(...dependencies);
125
175
  break;
126
176
  case "npm":
@@ -130,23 +180,19 @@ function install(root, dependencies, { packageManager, isOnline, devDependencies
130
180
  break;
131
181
  case "pnpm":
132
182
  args = ["add"];
133
- if (!isOnline)
134
- args.push("--offline");
183
+ if (!isOnline) args.push("--offline");
135
184
  args.push("--save-exact");
136
- if (devDependencies)
137
- args.push("-D");
185
+ if (devDependencies) args.push("-D");
138
186
  args.push(...dependencies);
139
187
  break;
140
188
  }
141
189
  } else {
142
190
  args = ["install"];
143
191
  if (!isOnline) {
144
- console.log(import_chalk2.default.yellow("You appear to be offline."));
192
+ log.warn("You appear to be offline.");
145
193
  if (packageManager === "yarn") {
146
- console.log(import_chalk2.default.yellow("Falling back to the local Yarn cache."));
194
+ log.warn("Falling back to the local Yarn cache.");
147
195
  args.push("--offline");
148
- } else {
149
- console.log();
150
196
  }
151
197
  }
152
198
  }
@@ -175,14 +221,10 @@ function install(root, dependencies, { packageManager, isOnline, devDependencies
175
221
  });
176
222
  }
177
223
 
178
- // src/index.ts
179
- var import_chalk5 = __toESM(require("chalk"));
180
-
181
224
  // src/util/git.ts
182
225
  var import_child_process = require("child_process");
183
226
  var import_path2 = __toESM(require("path"));
184
227
  var import_fs_extra2 = __toESM(require("fs-extra"));
185
- var import_chalk3 = __toESM(require("chalk"));
186
228
  function isInGitRepository() {
187
229
  try {
188
230
  (0, import_child_process.execSync)("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
@@ -199,46 +241,38 @@ function isInMercurialRepository() {
199
241
  }
200
242
  return false;
201
243
  }
202
- function tryGitInit(root) {
203
- let didInit = false;
244
+ function makeFirstCommit(root) {
204
245
  try {
205
- (0, import_child_process.execSync)("git --version", { stdio: "ignore" });
206
- if (isInGitRepository() || isInMercurialRepository()) {
207
- return false;
208
- }
209
- if (!import_fs_extra2.default.existsSync(".gitignore")) {
210
- console.warn(
211
- import_chalk3.default.yellow(
212
- "There is no .gitignore file in this repository, creating one..."
213
- )
214
- );
215
- import_fs_extra2.default.writeFileSync(
216
- ".gitignore",
217
- `node_modules
218
- .yarn/*
219
- .DS_Store
220
- .cache
221
- .next/
222
- `
223
- );
224
- }
225
- (0, import_child_process.execSync)("git init", { stdio: "ignore" });
226
- didInit = true;
227
246
  (0, import_child_process.execSync)("git checkout -b main", { stdio: "ignore" });
228
247
  (0, import_child_process.execSync)("git add -A", { stdio: "ignore" });
229
248
  (0, import_child_process.execSync)('git commit -m "Initial commit from Create Tina App"', {
230
249
  stdio: "ignore"
231
250
  });
232
- return true;
233
- } catch (e) {
234
- if (didInit) {
235
- try {
236
- import_fs_extra2.default.removeSync(import_path2.default.join(root, ".git"));
237
- } catch (_) {
238
- }
239
- }
251
+ } catch (err) {
252
+ import_fs_extra2.default.removeSync(import_path2.default.join(root, ".git"));
253
+ throw err;
254
+ }
255
+ }
256
+ function initializeGit() {
257
+ (0, import_child_process.execSync)("git --version", { stdio: "ignore" });
258
+ if (isInGitRepository() || isInMercurialRepository()) {
259
+ log.warn("Already in a Git repository, skipping.");
240
260
  return false;
241
261
  }
262
+ if (!import_fs_extra2.default.existsSync(".gitignore")) {
263
+ log.warn("There is no .gitignore file in this repository, creating one...");
264
+ import_fs_extra2.default.writeFileSync(
265
+ ".gitignore",
266
+ `node_modules
267
+ .yarn/*
268
+ .DS_Store
269
+ .cache
270
+ .next/
271
+ `
272
+ );
273
+ }
274
+ (0, import_child_process.execSync)("git init", { stdio: "ignore" });
275
+ return true;
242
276
  }
243
277
 
244
278
  // src/util/examples.ts
@@ -248,7 +282,14 @@ var import_tar = require("tar");
248
282
  async function getRepoInfo(url, examplePath) {
249
283
  const [, username, name2, t, _branch, ...file] = url.pathname.split("/");
250
284
  const filePath = examplePath ? examplePath.replace(/^\//, "") : file.join("/");
251
- if (t === void 0 || t === "" && _branch === void 0) {
285
+ if (
286
+ // Support repos whose entire purpose is to be a Next.js example, e.g.
287
+ // https://github.com/:username/:my-cool-nextjs-example-repo-name.
288
+ t === void 0 || // Support GitHub URL that ends with a trailing slash, e.g.
289
+ // https://github.com/:username/:my-cool-nextjs-example-repo-name/
290
+ // In this case "t" will be an empty string while the next part "_branch" will be undefined
291
+ t === "" && _branch === void 0
292
+ ) {
252
293
  try {
253
294
  const infoResponse = await fetch(
254
295
  `https://api.github.com/repos/${username}/${name2}`
@@ -290,7 +331,6 @@ async function downloadAndExtractRepo(root, { username, name: name2, branch, fil
290
331
  }
291
332
 
292
333
  // src/templates.ts
293
- var import_chalk4 = __toESM(require("chalk"));
294
334
  var import_fs_extra3 = require("fs-extra");
295
335
  var import_path3 = __toESM(require("path"));
296
336
  var TEMPLATES = [
@@ -301,6 +341,13 @@ var TEMPLATES = [
301
341
  isInternal: false,
302
342
  gitURL: "https://github.com/tinacms/tina-cloud-starter"
303
343
  },
344
+ {
345
+ title: "Astro Starter",
346
+ description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
347
+ value: "tina-astro-starter",
348
+ isInternal: false,
349
+ gitURL: "https://github.com/tinacms/tina-astro-starter"
350
+ },
304
351
  {
305
352
  title: "Hugo Starter",
306
353
  description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
@@ -315,13 +362,6 @@ var TEMPLATES = [
315
362
  isInternal: false,
316
363
  gitURL: "https://github.com/tinacms/tina-remix-starter"
317
364
  },
318
- {
319
- title: "Documentation Starter",
320
- description: "Transform documentation with Smooth Doc: Features MDX support, light/dark mode, and seamless Vercel deployment for a dynamic, interactive experience.",
321
- value: "demo-docs",
322
- isInternal: false,
323
- gitURL: "https://github.com/tinacms/demo-docs"
324
- },
325
365
  {
326
366
  title: "Docusaurus Starter",
327
367
  description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
@@ -337,69 +377,84 @@ var TEMPLATES = [
337
377
  gitURL: "https://github.com/tinacms/tina-barebones-starter"
338
378
  }
339
379
  ];
340
- var downloadTemplate = async (template, root) => {
380
+ async function downloadTemplate(template, root) {
341
381
  if (template.isInternal === false) {
342
382
  const repoURL = new URL(template.gitURL);
343
383
  const repoInfo = await getRepoInfo(repoURL);
344
- const repoInfo2 = repoInfo;
345
- console.log(
346
- `Downloading files from repo ${import_chalk4.default.cyan(
384
+ if (!repoInfo) {
385
+ throw new Error("Repository information not found.");
386
+ }
387
+ log.info(
388
+ `Downloading files from repo ${TextStyles.link(
347
389
  `${repoInfo == null ? void 0 : repoInfo.username}/${repoInfo == null ? void 0 : repoInfo.name}`
348
- )}. This might take a moment.`
390
+ )}.`
349
391
  );
350
- if (!repoInfo2) {
351
- throw new Error("downloadExample Failed. Repo info not found");
352
- }
353
- await downloadAndExtractRepo(root, repoInfo2);
392
+ await downloadAndExtractRepo(root, repoInfo);
354
393
  } else {
355
394
  const templateFile = import_path3.default.join(__dirname, "..", "examples", template.value);
356
395
  await (0, import_fs_extra3.copy)(`${templateFile}/`, "./");
357
396
  }
358
- };
397
+ }
359
398
 
360
399
  // src/util/preRunChecks.ts
361
- var preRunChecks = () => {
362
- if (process.version.startsWith("v15")) {
363
- console.warn(
364
- "WARNING: Version 15 of Node.js is not supported in create-tina-app, please update to the latest LTS version. See https://nodejs.org/en/download/ for more details"
400
+ var SUPPORTED_NODE_VERSION_BOUNDS = { oldest: 18, latest: 22 };
401
+ var SUPPORTED_NODE_VERSION_RANGE = [
402
+ ...Array(SUPPORTED_NODE_VERSION_BOUNDS.latest).keys()
403
+ ].map((i) => i + SUPPORTED_NODE_VERSION_BOUNDS.oldest);
404
+ var isSupported = SUPPORTED_NODE_VERSION_RANGE.some(
405
+ (version2) => process.version.startsWith(`v${version2}`)
406
+ );
407
+ function preRunChecks() {
408
+ checkSupportedNodeVersion();
409
+ }
410
+ function checkSupportedNodeVersion() {
411
+ if (!isSupported) {
412
+ log.warn(
413
+ `Node ${process.version} is not supported by create-tina-app. Please update to be within v${SUPPORTED_NODE_VERSION_BOUNDS.oldest}-v${SUPPORTED_NODE_VERSION_BOUNDS.latest}. See https://nodejs.org/en/download/ for more details.`
365
414
  );
366
415
  }
367
- };
416
+ }
368
417
 
369
418
  // src/util/checkPkgManagers.ts
370
419
  var import_child_process2 = require("child_process");
371
- function checkPackageExists(name2) {
372
- return new Promise((resolve, reject) => {
373
- (0, import_child_process2.exec)(`${name2} -v`, (error, stdout, stderr) => {
374
- if (error) {
375
- reject(stderr);
376
- }
377
- resolve(stdout);
420
+ async function checkPackageExists(name2) {
421
+ try {
422
+ await new Promise((resolve, reject) => {
423
+ (0, import_child_process2.exec)(`${name2} -v`, (error, stdout, stderr) => {
424
+ if (error) {
425
+ reject(stderr);
426
+ }
427
+ resolve(stdout);
428
+ });
378
429
  });
379
- });
430
+ return true;
431
+ } catch (_) {
432
+ return false;
433
+ }
380
434
  }
381
435
 
382
436
  // src/index.ts
437
+ var import_node_process = require("process");
438
+ var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
383
439
  var PKG_MANAGERS = ["npm", "yarn", "pnpm"];
384
- var successText = import_chalk5.default.bold.green;
385
- var linkText = import_chalk5.default.bold.cyan;
386
- var cmdText = import_chalk5.default.inverse;
387
- var logText = import_chalk5.default.italic.gray;
388
- var projectName = "";
389
- var program = new import_commander.Command(name);
390
- program.version(version).option(
391
- "-t, --template <template>",
392
- `Choose which template to start from. Valid templates are: ${TEMPLATES.map(
393
- (x2) => x2.value
394
- )}`
395
- ).option(
396
- "-p, --pkg-manager <pkg-manager>",
397
- `Choose which package manager to use. Valid package managers are: ${PKG_MANAGERS}`
398
- ).option("-d, --dir <dir>", "Choose which directory to run this script from").option("--noTelemetry", "Disable anonymous telemetry that is collected").arguments("[project-directory]").usage(`${import_chalk5.default.green("<project-directory>")} [options]`).action((name2) => {
399
- projectName = name2;
400
- });
401
- var run = async () => {
440
+ async function run() {
402
441
  preRunChecks();
442
+ let projectName = "";
443
+ const program = new import_commander.Command(name);
444
+ program.version(version).option(
445
+ "-t, --template <template>",
446
+ `Choose which template to start from. Valid templates are: ${TEMPLATES.map(
447
+ (x2) => x2.value
448
+ )}`
449
+ ).option(
450
+ "-p, --pkg-manager <pkg-manager>",
451
+ `Choose which package manager to use. Valid package managers are: ${PKG_MANAGERS}`
452
+ ).option(
453
+ "-d, --dir <dir>",
454
+ "Choose which directory to run this script from."
455
+ ).option("--noTelemetry", "Disable anonymous telemetry that is collected.").arguments("[project-directory]").usage(`${TextStyles.success("<project-directory>")} [options]`).action((name2) => {
456
+ projectName = name2;
457
+ });
403
458
  program.parse(process.argv);
404
459
  const opts = program.opts();
405
460
  if (opts.dir) {
@@ -410,37 +465,37 @@ var run = async () => {
410
465
  if (template) {
411
466
  template = TEMPLATES.find((_template) => _template.value === template);
412
467
  if (!template) {
413
- console.error(
414
- `The provided template is invalid. Please provide one of the following: ${TEMPLATES.map(
468
+ log.err(
469
+ `The provided template '${opts.template}' is invalid. Please provide one of the following: ${TEMPLATES.map(
415
470
  (x2) => x2.value
416
471
  )}`
417
472
  );
418
- throw new Error("Invalid template.");
473
+ (0, import_node_process.exit)(1);
419
474
  }
420
475
  }
421
476
  let pkgManager = opts.pkgManager;
422
477
  if (pkgManager) {
423
478
  if (!PKG_MANAGERS.find((_pkgManager) => _pkgManager === pkgManager)) {
424
- console.error(
425
- `The provided package manager is not supported. Please provide one of the following: ${PKG_MANAGERS}`
479
+ log.err(
480
+ `The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
426
481
  );
427
- throw new Error("Invalid package manager.");
482
+ (0, import_node_process.exit)(1);
428
483
  }
429
484
  }
430
485
  if (!pkgManager) {
431
486
  const installedPkgManagers = [];
432
487
  for (const pkg_manager of PKG_MANAGERS) {
433
- try {
434
- await checkPackageExists(pkg_manager);
488
+ if (await checkPackageExists(pkg_manager)) {
435
489
  installedPkgManagers.push(pkg_manager);
436
- } catch {
437
490
  }
438
491
  }
439
492
  if (installedPkgManagers.length === 0) {
440
- console.error(`You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`);
441
- throw new Error("No supported package managers installed.");
493
+ log.err(
494
+ `You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
495
+ );
496
+ (0, import_node_process.exit)(1);
442
497
  }
443
- const pkgManagerRes = await (0, import_prompts.default)({
498
+ const res = await (0, import_prompts.default)({
444
499
  message: "Which package manager would you like to use?",
445
500
  name: "packageManager",
446
501
  type: "select",
@@ -448,26 +503,35 @@ var run = async () => {
448
503
  return { title: manager, value: manager };
449
504
  })
450
505
  });
451
- pkgManager = pkgManagerRes.packageManager;
506
+ if (!Object.hasOwn(res, "packageManager")) (0, import_node_process.exit)(1);
507
+ pkgManager = res.packageManager;
452
508
  }
453
509
  if (!projectName) {
454
510
  const res = await (0, import_prompts.default)({
455
511
  name: "name",
456
512
  type: "text",
457
513
  message: "What is your project named?",
458
- initial: "my-tina-app"
514
+ initial: "my-tina-app",
515
+ validate: (name2) => {
516
+ const { validForNewPackages, errors } = (0, import_validate_npm_package_name.default)(
517
+ import_node_path.default.basename(import_node_path.default.resolve(name2))
518
+ );
519
+ if (validForNewPackages) return true;
520
+ return `Invalid project name: ${errors[0]}`;
521
+ }
459
522
  });
523
+ if (!Object.hasOwn(res, "name")) (0, import_node_process.exit)(1);
460
524
  projectName = res.name;
461
525
  }
462
- const dirName = projectName;
463
526
  if (!template) {
464
- const templateRes = await (0, import_prompts.default)({
527
+ const res = await (0, import_prompts.default)({
465
528
  name: "template",
466
529
  type: "select",
467
530
  message: "What starter code would you like to use?",
468
531
  choices: TEMPLATES
469
532
  });
470
- template = TEMPLATES.find((_template) => _template.value === templateRes.template);
533
+ if (!Object.hasOwn(res, "template")) (0, import_node_process.exit)(1);
534
+ template = TEMPLATES.find((_template) => _template.value === res.template);
471
535
  }
472
536
  await telemetry.submitRecord({
473
537
  event: {
@@ -476,54 +540,51 @@ var run = async () => {
476
540
  pkgManager
477
541
  }
478
542
  });
479
- const root = import_node_path.default.join(process.cwd(), dirName);
480
- if (!await isWriteable(import_node_path.default.dirname(root))) {
481
- console.error(
482
- "The application path is not writable, please check folder permissions and try again."
483
- );
484
- console.error(
485
- "It is likely you do not have write permissions for this folder."
543
+ const rootDir = import_node_path.default.join(process.cwd(), projectName);
544
+ if (!await isWriteable(import_node_path.default.dirname(rootDir))) {
545
+ log.err(
546
+ "The application path is not writable, please check folder permissions and try again. It is likely you do not have write permissions for this folder."
486
547
  );
487
548
  process.exit(1);
488
549
  }
489
- const appName = import_node_path.default.basename(root);
490
- await makeDir(root);
491
- process.chdir(root);
492
- if (!isFolderEmpty(root, appName)) {
493
- process.exit(1);
550
+ const appName = await setupProjectDirectory(rootDir);
551
+ try {
552
+ await downloadTemplate(template, rootDir);
553
+ updateProjectPackageName(rootDir, projectName);
554
+ updateProjectPackageVersion(rootDir, "0.0.1");
555
+ } catch (err) {
556
+ log.err(`Failed to download template: ${err.message}`);
557
+ (0, import_node_process.exit)(1);
494
558
  }
495
- await downloadTemplate(template, root);
496
- console.log(
497
- logText("Installing packages. This might take a couple of minutes.\n")
498
- );
499
- await install(root, null, { packageManager: pkgManager, isOnline: true });
500
- if (tryGitInit(root)) {
501
- console.log(logText("Initializing git repository.\n"));
559
+ log.info("Installing packages.");
560
+ await install(rootDir, null, { packageManager: pkgManager, isOnline: true });
561
+ log.info("Initializing git repository.");
562
+ try {
563
+ if (initializeGit()) {
564
+ makeFirstCommit(rootDir);
565
+ log.info("Initialized git repository.");
566
+ }
567
+ } catch (err) {
568
+ log.err("Failed to initialize Git repository, skipping.");
502
569
  }
503
- console.log(`${successText("Starter successfully created!")}`);
504
- console.log(import_chalk5.default.bold("\nTo launch your app, run:\n"));
505
- console.log(` ${cmdText(`cd ${appName}`)}`);
506
- console.log(
507
- ` ${cmdText(`${pkgManager} ${pkgManager === "npm" ? "run " : ""}dev`)}`
508
- );
509
- console.log("\nNext steps:\n");
510
- console.log(
511
- `\u2022 \u{1F4DD} Edit some content on ${linkText(
512
- "http://localhost:3000"
513
- )} (See ${linkText("https://tina.io/docs/using-tina-editor")})`
514
- );
515
- console.log(
516
- `\u2022 \u{1F4D6} Learn the basics: ${linkText("https://tina.io/docs/schema/")}`
517
- );
518
- console.log(
519
- `\u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${linkText(
520
- "https://tina.io/docs/advanced/extending-tina/"
521
- )}`
522
- );
523
- console.log(
524
- `\u2022 \u{1F680} Deploy to Production: ${linkText("https://tina.io/docs/tina-cloud/")}`
525
- );
526
- };
570
+ log.success("Starter successfully created!");
571
+ log.log(TextStyles.bold("\nTo launch your app, run:\n"));
572
+ log.cmd(`cd ${appName}
573
+ ${pkgManager} run dev`);
574
+ log.log(`
575
+ Next steps:
576
+ \u2022 \u{1F4DD} Edit some content on ${TextStyles.link(
577
+ "http://localhost:3000"
578
+ )} (See ${TextStyles.link("https://tina.io/docs/using-tina-editor")})
579
+ \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}
580
+ \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link(
581
+ "https://tina.io/docs/advanced/extending-tina/"
582
+ )}
583
+ \u2022 \u{1F680} Deploy to Production: ${TextStyles.link(
584
+ "https://tina.io/docs/tina-cloud/"
585
+ )}
586
+ `);
587
+ }
527
588
  run();
528
589
  // Annotate the CommonJS export names for ESM import in node:
529
590
  0 && (module.exports = {
@@ -12,5 +12,5 @@ export type ExternalTemplate = BaseExample & {
12
12
  };
13
13
  export type Template = InternalTemplate | ExternalTemplate;
14
14
  export declare const TEMPLATES: Template[];
15
- export declare const downloadTemplate: (template: Template, root: string) => Promise<void>;
15
+ export declare function downloadTemplate(template: Template, root: string): Promise<void>;
16
16
  export {};
@@ -1,2 +1,2 @@
1
1
  import { PKG_MANAGERS } from '..';
2
- export declare function checkPackageExists(name: (typeof PKG_MANAGERS)[number]): Promise<unknown>;
2
+ export declare function checkPackageExists(name: (typeof PKG_MANAGERS)[number]): Promise<boolean>;
@@ -1,6 +1,5 @@
1
- /**
2
-
3
- */
4
1
  export declare function isWriteable(directory: string): Promise<boolean>;
5
- export declare function makeDir(root: string): Promise<void>;
6
- export declare function isFolderEmpty(root: string, name: string): boolean;
2
+ export declare function folderContainsInstallConflicts(root: string): string[];
3
+ export declare function setupProjectDirectory(dir: string): Promise<string>;
4
+ export declare function updateProjectPackageName(dir: string, name: string): void;
5
+ export declare function updateProjectPackageVersion(dir: string, version: string): void;
@@ -1,4 +1,2 @@
1
- /**
2
-
3
- */
4
- export declare function tryGitInit(root: string): boolean;
1
+ export declare function makeFirstCommit(root: string): void;
2
+ export declare function initializeGit(): boolean;
@@ -0,0 +1,20 @@
1
+ import chalk from 'chalk';
2
+ export declare const TextStyles: {
3
+ link: chalk.Chalk;
4
+ cmd: chalk.Chalk;
5
+ info: chalk.Chalk;
6
+ success: chalk.Chalk;
7
+ warn: chalk.Chalk;
8
+ err: chalk.Chalk;
9
+ bold: chalk.Chalk;
10
+ };
11
+ export declare class Logger {
12
+ log(message: string): void;
13
+ debug(message: string): void;
14
+ info(message: string): void;
15
+ success(message: string): void;
16
+ cmd(message: string): void;
17
+ warn(message: string): void;
18
+ err(message: string): void;
19
+ }
20
+ export declare const log: Logger;
@@ -1,4 +1 @@
1
- /**
2
-
3
- */
4
- export declare const preRunChecks: () => void;
1
+ export declare function preRunChecks(): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-tina-app",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist",
@@ -31,21 +31,21 @@
31
31
  "devDependencies": {
32
32
  "@types/cross-spawn": "^6.0.6",
33
33
  "@types/fs-extra": "^11.0.4",
34
- "@types/node": "^20.14.12",
34
+ "@types/node": "^22.9.0",
35
35
  "@types/prompts": "^2.4.9",
36
36
  "@types/tar": "6.1.13",
37
- "typescript": "^5.5.4",
38
- "@tinacms/scripts": "1.2.1"
37
+ "typescript": "^5.6.3",
38
+ "@tinacms/scripts": "1.3.1"
39
39
  },
40
40
  "dependencies": {
41
41
  "chalk": "4.1.2",
42
42
  "commander": "^12.1.0",
43
- "cross-spawn": "^7.0.3",
43
+ "cross-spawn": "^7.0.5",
44
44
  "fs-extra": "^11.2.0",
45
- "got": "^14.4.2",
46
45
  "prompts": "^2.4.2",
47
46
  "tar": "7.4.0",
48
- "@tinacms/metrics": "1.0.5"
47
+ "validate-npm-package-name": "^5.0.1",
48
+ "@tinacms/metrics": "1.0.8"
49
49
  },
50
50
  "scripts": {
51
51
  "types": "pnpm tsc",