create-tina-app 0.0.0-dde3eb3-20251028070343 → 0.0.0-e1d5853-20251216014949

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- require('../dist')
3
+ import('../dist/index.js');
package/dist/index.js CHANGED
@@ -1,127 +1,30 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __export = (target, all) => {
11
- for (var name2 in all)
12
- __defProp(target, name2, { get: all[name2], enumerable: true });
13
- };
14
- var __copyProps = (to, from, except, desc) => {
15
- if (from && typeof from === "object" || typeof from === "function") {
16
- for (let key of __getOwnPropNames(from))
17
- if (!__hasOwnProp.call(to, key) && key !== except)
18
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
- }
20
- return to;
21
- };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
- // If the importer is in node compatibility mode or this is not an ESM
24
- // file that has been converted to a CommonJS file using a Babel-
25
- // compatible transform (i.e. "__esModule" has not been set), then set
26
- // "default" to the CommonJS "module.exports" for node compatibility.
27
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
- mod
29
- ));
30
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
-
32
- // package.json
33
- var require_package = __commonJS({
34
- "package.json"(exports2, module2) {
35
- module2.exports = {
36
- name: "create-tina-app",
37
- version: "1.5.2",
38
- main: "dist/index.js",
39
- files: [
40
- "dist",
41
- "examples",
42
- "bin/*"
43
- ],
44
- bin: "bin/create-tina-app",
45
- typings: "dist/index.d.ts",
46
- license: "Apache-2.0",
47
- buildConfig: {
48
- entryPoints: [
49
- {
50
- name: "src/index.ts",
51
- target: "node"
52
- }
53
- ]
54
- },
55
- engines: {
56
- node: ">=18.18.0"
57
- },
58
- scripts: {
59
- types: "pnpm tsc",
60
- build: "tinacms-scripts build",
61
- "test-run-bin": "pnpm create-tina-app"
62
- },
63
- publishConfig: {
64
- registry: "https://registry.npmjs.org"
65
- },
66
- repository: {
67
- url: "https://github.com/tinacms/tinacms.git",
68
- directory: "packages/create-tina-app"
69
- },
70
- devDependencies: {
71
- "@tinacms/scripts": "workspace:*",
72
- "@types/cross-spawn": "catalog:",
73
- "@types/fs-extra": "^11.0.4",
74
- "@types/node": "^22.13.1",
75
- "@types/prompts": "catalog:",
76
- "@types/tar": "catalog:",
77
- typescript: "^5.7.3"
78
- },
79
- dependencies: {
80
- "@tinacms/metrics": "workspace:*",
81
- chalk: "4.1.2",
82
- commander: "^12.1.0",
83
- "cross-spawn": "catalog:",
84
- "fs-extra": "catalog:",
85
- ora: "catalog:",
86
- prompts: "catalog:",
87
- tar: "catalog:",
88
- "validate-npm-package-name": "catalog:"
89
- }
90
- };
91
- }
92
- });
93
-
94
1
  // src/index.ts
95
- var index_exports = {};
96
- __export(index_exports, {
97
- run: () => run
98
- });
99
- module.exports = __toCommonJS(index_exports);
100
- var import_metrics = require("@tinacms/metrics");
101
- var import_prompts = __toESM(require("prompts"));
102
- var import_node_path = __toESM(require("node:path"));
2
+ import { Telemetry } from "@tinacms/metrics";
3
+ import prompts from "prompts";
4
+ import path4 from "node:path";
5
+ import { createRequire } from "node:module";
103
6
 
104
7
  // src/util/fileUtil.ts
105
- var import_fs_extra = __toESM(require("fs-extra"));
106
- var import_path = __toESM(require("path"));
8
+ import fs from "fs-extra";
9
+ import path from "path";
107
10
 
108
11
  // src/util/textstyles.ts
109
- var import_chalk = __toESM(require("chalk"));
12
+ import chalk from "chalk";
110
13
  var TextStyles = {
111
- tinaOrange: import_chalk.default.hex("#EC4816"),
112
- link: (url) => `\x1B]8;;${url}\x07${import_chalk.default.cyan.underline(url)}\x1B]8;;\x07`,
113
- cmd: import_chalk.default.bgBlackBright.bold.white,
114
- info: import_chalk.default.blue,
115
- success: import_chalk.default.green,
116
- warn: import_chalk.default.yellow,
117
- err: import_chalk.default.red,
118
- bold: import_chalk.default.bold
14
+ tinaOrange: chalk.hex("#EC4816"),
15
+ link: (url) => `\x1B]8;;${url}\x07${chalk.cyan.underline(url)}\x1B]8;;\x07`,
16
+ cmd: chalk.bgBlackBright.bold.white,
17
+ info: chalk.blue,
18
+ success: chalk.green,
19
+ warn: chalk.yellow,
20
+ err: chalk.red,
21
+ bold: chalk.bold
119
22
  };
120
23
 
121
24
  // src/util/fileUtil.ts
122
25
  async function isWriteable(directory) {
123
26
  try {
124
- await import_fs_extra.default.promises.access(directory, (import_fs_extra.default.constants || import_fs_extra.default).W_OK);
27
+ await fs.promises.access(directory, (fs.constants || fs).W_OK);
125
28
  return true;
126
29
  } catch (err) {
127
30
  return false;
@@ -148,12 +51,12 @@ function folderContainsInstallConflicts(root) {
148
51
  "yarn-debug.log",
149
52
  "yarn-error.log"
150
53
  ];
151
- const conflicts = import_fs_extra.default.readdirSync(root).filter((file) => !validFiles.includes(file)).filter((file) => !/\.iml$/.test(file));
54
+ const conflicts = fs.readdirSync(root).filter((file) => !validFiles.includes(file)).filter((file) => !/\.iml$/.test(file));
152
55
  return conflicts;
153
56
  }
154
57
  async function setupProjectDirectory(dir) {
155
- const appName = import_path.default.basename(dir);
156
- await import_fs_extra.default.mkdirp(dir);
58
+ const appName = path.basename(dir);
59
+ await fs.mkdirp(dir);
157
60
  process.chdir(dir);
158
61
  const conflicts = folderContainsInstallConflicts(dir);
159
62
  if (conflicts.length > 0) {
@@ -162,7 +65,7 @@ async function setupProjectDirectory(dir) {
162
65
  ];
163
66
  for (const file of conflicts) {
164
67
  try {
165
- const stats = import_fs_extra.default.lstatSync(import_path.default.join(dir, file));
68
+ const stats = fs.lstatSync(path.join(dir, file));
166
69
  if (stats.isDirectory()) {
167
70
  errorMessageLines.push(` - ${TextStyles.info(file)}/`);
168
71
  } else {
@@ -177,36 +80,36 @@ async function setupProjectDirectory(dir) {
177
80
  return appName;
178
81
  }
179
82
  function updateProjectPackageName(dir, name2) {
180
- const packageJsonPath = import_path.default.join(dir, "package.json");
181
- const packageJson = JSON.parse(import_fs_extra.default.readFileSync(packageJsonPath, "utf8"));
83
+ const packageJsonPath = path.join(dir, "package.json");
84
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
182
85
  packageJson.name = name2;
183
- import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
86
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
184
87
  }
185
88
  function updateProjectPackageVersion(dir, version2) {
186
- const packageJsonPath = import_path.default.join(dir, "package.json");
187
- const packageJson = JSON.parse(import_fs_extra.default.readFileSync(packageJsonPath, "utf8"));
89
+ const packageJsonPath = path.join(dir, "package.json");
90
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
188
91
  packageJson.version = version2;
189
- import_fs_extra.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
92
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
190
93
  }
191
94
  async function updateThemeSettings(dir, selectedTheme) {
192
- const settingsDir = import_path.default.join(dir, "content", "settings");
193
- const configPath = import_path.default.join(settingsDir, "config.json");
194
- await import_fs_extra.default.mkdirp(settingsDir);
95
+ const settingsDir = path.join(dir, "content", "settings");
96
+ const configPath = path.join(settingsDir, "config.json");
97
+ await fs.mkdirp(settingsDir);
195
98
  let config = {};
196
99
  try {
197
- const existingConfig = await import_fs_extra.default.readFile(configPath, "utf8");
100
+ const existingConfig = await fs.readFile(configPath, "utf8");
198
101
  config = JSON.parse(existingConfig);
199
102
  } catch (error) {
200
103
  }
201
104
  config.selectedTheme = selectedTheme;
202
- await import_fs_extra.default.writeFile(configPath, JSON.stringify(config, null, 2));
105
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2));
203
106
  }
204
107
 
205
108
  // src/util/install.ts
206
- var import_cross_spawn = __toESM(require("cross-spawn"));
109
+ import spawn from "cross-spawn";
207
110
  function install(packageManager, verboseOutput) {
208
111
  return new Promise((resolve, reject) => {
209
- const child = (0, import_cross_spawn.default)(packageManager, ["install"], {
112
+ const child = spawn(packageManager, ["install"], {
210
113
  stdio: verboseOutput ? "inherit" : "ignore",
211
114
  env: { ...process.env, ADBLOCK: "1", DISABLE_OPENCOLLECTIVE: "1" }
212
115
  });
@@ -221,12 +124,12 @@ function install(packageManager, verboseOutput) {
221
124
  }
222
125
 
223
126
  // src/util/git.ts
224
- var import_child_process = require("child_process");
225
- var import_path2 = __toESM(require("path"));
226
- var import_fs_extra2 = __toESM(require("fs-extra"));
127
+ import { execSync } from "child_process";
128
+ import path2 from "path";
129
+ import fs2 from "fs-extra";
227
130
  function isInGitRepository() {
228
131
  try {
229
- (0, import_child_process.execSync)("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
132
+ execSync("git rev-parse --is-inside-work-tree", { stdio: "ignore" });
230
133
  return true;
231
134
  } catch (_) {
232
135
  }
@@ -234,7 +137,7 @@ function isInGitRepository() {
234
137
  }
235
138
  function isInMercurialRepository() {
236
139
  try {
237
- (0, import_child_process.execSync)("hg --cwd . root", { stdio: "ignore" });
140
+ execSync("hg --cwd . root", { stdio: "ignore" });
238
141
  return true;
239
142
  } catch (_) {
240
143
  }
@@ -242,27 +145,27 @@ function isInMercurialRepository() {
242
145
  }
243
146
  function makeFirstCommit(root) {
244
147
  try {
245
- (0, import_child_process.execSync)("git checkout -b main", { stdio: "ignore" });
246
- (0, import_child_process.execSync)("git add -A", { stdio: "ignore" });
247
- (0, import_child_process.execSync)('git commit -m "Initial commit from Create Tina App"', {
148
+ execSync("git checkout -b main", { stdio: "ignore" });
149
+ execSync("git add -A", { stdio: "ignore" });
150
+ execSync('git commit -m "Initial commit from Create Tina App"', {
248
151
  stdio: "ignore"
249
152
  });
250
153
  } catch (err) {
251
- import_fs_extra2.default.removeSync(import_path2.default.join(root, ".git"));
154
+ fs2.removeSync(path2.join(root, ".git"));
252
155
  throw err;
253
156
  }
254
157
  }
255
158
  function initializeGit(spinner) {
256
- (0, import_child_process.execSync)("git --version", { stdio: "ignore" });
159
+ execSync("git --version", { stdio: "ignore" });
257
160
  if (isInGitRepository() || isInMercurialRepository()) {
258
161
  spinner.warn("Already in a Git repository, skipping.");
259
162
  return false;
260
163
  }
261
- if (!import_fs_extra2.default.existsSync(".gitignore")) {
164
+ if (!fs2.existsSync(".gitignore")) {
262
165
  spinner.warn(
263
166
  "There is no .gitignore file in this repository, creating one..."
264
167
  );
265
- import_fs_extra2.default.writeFileSync(
168
+ fs2.writeFileSync(
266
169
  ".gitignore",
267
170
  `node_modules
268
171
  .yarn/*
@@ -272,14 +175,14 @@ function initializeGit(spinner) {
272
175
  `
273
176
  );
274
177
  }
275
- (0, import_child_process.execSync)("git init", { stdio: "ignore" });
178
+ execSync("git init", { stdio: "ignore" });
276
179
  return true;
277
180
  }
278
181
 
279
182
  // src/util/examples.ts
280
- var import_node_stream = require("node:stream");
281
- var import_promises = require("node:stream/promises");
282
- var import_tar = require("tar");
183
+ import { Readable } from "node:stream";
184
+ import { pipeline } from "node:stream/promises";
185
+ import { x } from "tar";
283
186
  async function getRepoInfo(url, examplePath) {
284
187
  const [, username, name2, t, _branch, ...file] = url.pathname.split("/");
285
188
  const filePath = examplePath ? examplePath.replace(/^\//, "") : file.join("/");
@@ -314,14 +217,14 @@ async function downloadTarStream(url) {
314
217
  if (!res.body) {
315
218
  throw new Error(`Failed to download: ${url}`);
316
219
  }
317
- return import_node_stream.Readable.fromWeb(res.body);
220
+ return Readable.fromWeb(res.body);
318
221
  }
319
222
  async function downloadAndExtractRepo(root, { username, name: name2, branch, filePath }) {
320
- await (0, import_promises.pipeline)(
223
+ await pipeline(
321
224
  await downloadTarStream(
322
225
  `https://codeload.github.com/${username}/${name2}/tar.gz/${branch}`
323
226
  ),
324
- (0, import_tar.x)({
227
+ x({
325
228
  cwd: root,
326
229
  strip: filePath ? filePath.split("/").length + 1 : 1,
327
230
  filter: (p) => p.startsWith(
@@ -332,14 +235,28 @@ async function downloadAndExtractRepo(root, { username, name: name2, branch, fil
332
235
  }
333
236
 
334
237
  // src/templates.ts
335
- var import_fs_extra3 = require("fs-extra");
336
- var import_path3 = __toESM(require("path"));
238
+ import { copy } from "fs-extra";
239
+ import path3 from "path";
337
240
  var TEMPLATES = [
338
241
  {
339
242
  title: "\u2B50 NextJS starter",
340
243
  description: "Kickstart your project with Next.js \u2013 our top recommendation for a seamless, performant, and versatile web experience.",
341
244
  value: "tina-nextjs-starter",
342
245
  isInternal: false,
246
+ features: [
247
+ {
248
+ name: "Visual Editing",
249
+ description: "\u2705"
250
+ },
251
+ {
252
+ name: "ISR",
253
+ description: "\u2705"
254
+ },
255
+ {
256
+ name: "SSG",
257
+ description: "\u2705"
258
+ }
259
+ ],
343
260
  gitURL: "https://github.com/tinacms/tina-nextjs-starter",
344
261
  devUrl: "http://localhost:3000"
345
262
  },
@@ -348,6 +265,20 @@ var TEMPLATES = [
348
265
  description: "Get your documentation site up and running with TinaCMS and Next.js in minutes.",
349
266
  value: "tina-docs",
350
267
  isInternal: false,
268
+ features: [
269
+ {
270
+ name: "Visual Editing",
271
+ description: "\u2705"
272
+ },
273
+ {
274
+ name: "ISR",
275
+ description: "\u2705"
276
+ },
277
+ {
278
+ name: "SSG",
279
+ description: "\u2705"
280
+ }
281
+ ],
351
282
  gitURL: "https://github.com/tinacms/tina-docs",
352
283
  devUrl: "http://localhost:3000"
353
284
  },
@@ -356,6 +287,20 @@ var TEMPLATES = [
356
287
  description: "Get started with Astro - a modern static site generator designed for fast, lightweight, and flexible web projects.",
357
288
  value: "tina-astro-starter",
358
289
  isInternal: false,
290
+ features: [
291
+ {
292
+ name: "Visual Editing",
293
+ description: "\u274C"
294
+ },
295
+ {
296
+ name: "ISR",
297
+ description: "\u274C"
298
+ },
299
+ {
300
+ name: "SSG",
301
+ description: "\u2705"
302
+ }
303
+ ],
359
304
  gitURL: "https://github.com/tinacms/tina-astro-starter",
360
305
  devUrl: "http://localhost:4321"
361
306
  },
@@ -364,6 +309,20 @@ var TEMPLATES = [
364
309
  description: "With Hugo, you wield the power of lightning-fast site generation, crafting web experiences at the speed of thought.",
365
310
  value: "tina-hugo-starter",
366
311
  isInternal: false,
312
+ features: [
313
+ {
314
+ name: "Visual Editing",
315
+ description: "\u274C"
316
+ },
317
+ {
318
+ name: "ISR",
319
+ description: "\u274C"
320
+ },
321
+ {
322
+ name: "SSG",
323
+ description: "\u2705"
324
+ }
325
+ ],
367
326
  gitURL: "https://github.com/tinacms/tina-hugo-starter",
368
327
  devUrl: "http://localhost:1313"
369
328
  },
@@ -372,6 +331,20 @@ var TEMPLATES = [
372
331
  description: "Dive into Remix to orchestrate seamless, interactive user journeys like a maestro of the web.",
373
332
  value: "tina-remix-starter",
374
333
  isInternal: false,
334
+ features: [
335
+ {
336
+ name: "Visual Editing",
337
+ description: "\u274C"
338
+ },
339
+ {
340
+ name: "ISR",
341
+ description: "\u274C"
342
+ },
343
+ {
344
+ name: "SSG",
345
+ description: "\u26A0\uFE0F Requires adapter"
346
+ }
347
+ ],
375
348
  gitURL: "https://github.com/tinacms/tina-remix-starter",
376
349
  devUrl: "http://localhost:3000"
377
350
  },
@@ -380,14 +353,42 @@ var TEMPLATES = [
380
353
  description: "Docusaurus empowers you to build and evolve documentation like crafting a living, breathing knowledge repository.",
381
354
  value: "tinasaurus",
382
355
  isInternal: false,
356
+ features: [
357
+ {
358
+ name: "Visual Editing",
359
+ description: "\u274C"
360
+ },
361
+ {
362
+ name: "ISR",
363
+ description: "\u274C"
364
+ },
365
+ {
366
+ name: "SSR",
367
+ description: "\u2705"
368
+ }
369
+ ],
383
370
  gitURL: "https://github.com/tinacms/tinasaurus",
384
371
  devUrl: "http://localhost:3000"
385
372
  },
386
373
  {
387
374
  title: "Bare bones starter",
388
- description: "Stripped down to essentials, this starter is the canvas for pure, unadulterated code creativity.",
375
+ description: "Stripped down to essentials, this starter is the canvas for pure, unadulterated code creativity. Built with Next.js.",
389
376
  value: "basic",
390
377
  isInternal: false,
378
+ features: [
379
+ {
380
+ name: "Visual Editing",
381
+ description: "\u2705"
382
+ },
383
+ {
384
+ name: "ISR",
385
+ description: "\u2705"
386
+ },
387
+ {
388
+ name: "SSG",
389
+ description: "\u2705"
390
+ }
391
+ ],
391
392
  gitURL: "https://github.com/tinacms/tina-barebones-starter",
392
393
  devUrl: "http://localhost:3000"
393
394
  }
@@ -404,8 +405,8 @@ async function downloadTemplate(template, root, spinner) {
404
405
  )}`;
405
406
  await downloadAndExtractRepo(root, repoInfo);
406
407
  } else {
407
- const templateFile = import_path3.default.join(__dirname, "..", "examples", template.value);
408
- await (0, import_fs_extra3.copy)(`${templateFile}/`, "./");
408
+ const templateFile = path3.join(__dirname, "..", "examples", template.value);
409
+ await copy(`${templateFile}/`, "./");
409
410
  }
410
411
  }
411
412
 
@@ -429,11 +430,11 @@ function preRunChecks(spinner) {
429
430
  }
430
431
 
431
432
  // src/util/checkPkgManagers.ts
432
- var import_child_process2 = require("child_process");
433
+ import { exec } from "child_process";
433
434
  async function checkPackageExists(name2) {
434
435
  try {
435
436
  await new Promise((resolve, reject) => {
436
- (0, import_child_process2.exec)(`${name2} -v`, (error, stdout, stderr) => {
437
+ exec(`${name2} -v`, (error, stdout, stderr) => {
437
438
  if (error) {
438
439
  reject(stderr);
439
440
  }
@@ -447,11 +448,14 @@ async function checkPackageExists(name2) {
447
448
  }
448
449
 
449
450
  // src/index.ts
450
- var import_node_process = require("node:process");
451
+ import { exit } from "node:process";
451
452
 
452
453
  // src/util/options.ts
453
- var import_commander = require("commander");
454
- var import_package = __toESM(require_package());
454
+ import { Command } from "commander";
455
+
456
+ // package.json
457
+ var name = "create-tina-app";
458
+ var version = "2.0.0";
455
459
 
456
460
  // src/util/packageManagers.ts
457
461
  var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
@@ -459,8 +463,8 @@ var PKG_MANAGERS = ["npm", "yarn", "pnpm", "bun"];
459
463
  // src/util/options.ts
460
464
  function extractOptions(args) {
461
465
  let projectName = "";
462
- const program = new import_commander.Command(import_package.name);
463
- program.version(import_package.version).option(
466
+ const program = new Command(name);
467
+ program.version(version).option(
464
468
  "-t, --template <template>",
465
469
  `Choose which template to start from. Valid templates are: ${TEMPLATES.map(
466
470
  (x2) => x2.value
@@ -485,11 +489,111 @@ function extractOptions(args) {
485
489
  return opts;
486
490
  }
487
491
 
488
- // src/index.ts
489
- var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
492
+ // src/util/isNpm.js
493
+ import { builtinModules as builtins } from "node:module";
494
+ function validate(name2) {
495
+ if (name2 === null) {
496
+ return {
497
+ message: "name cannot be null",
498
+ isError: true
499
+ };
500
+ }
501
+ if (name2 === void 0) {
502
+ return {
503
+ message: "name cannot be undefined",
504
+ isError: true
505
+ };
506
+ }
507
+ if (typeof name2 !== "string") {
508
+ return {
509
+ message: "name must be a string",
510
+ isError: true
511
+ };
512
+ }
513
+ if (!name2.length) {
514
+ return {
515
+ message: "name length must be greater than zero",
516
+ isError: true
517
+ };
518
+ }
519
+ if (name2.startsWith(".")) {
520
+ return {
521
+ message: "name cannot start with a period",
522
+ isError: true
523
+ };
524
+ }
525
+ if (name2.match(/^_/)) {
526
+ return {
527
+ message: "name cannot start with an underscore",
528
+ isError: true
529
+ };
530
+ }
531
+ if (name2.trim() !== name2) {
532
+ return {
533
+ message: "name cannot contain leading or trailing spaces",
534
+ isError: true
535
+ };
536
+ }
537
+ const exclusionList = ["node_modules", "favicon.ico"];
538
+ exclusionList.forEach(function(excludedName) {
539
+ if (name2.toLowerCase() === excludedName) {
540
+ return {
541
+ message: excludedName + " is not a valid package name",
542
+ isError: true
543
+ };
544
+ }
545
+ });
546
+ if (builtins.includes(name2.toLowerCase())) {
547
+ return {
548
+ message: name2 + " is a core module name",
549
+ isError: true
550
+ };
551
+ }
552
+ if (name2.length > 214) {
553
+ return {
554
+ message: "name can no longer contain more than 214 characters",
555
+ isError: true
556
+ };
557
+ }
558
+ if (name2.toLowerCase() !== name2) {
559
+ return {
560
+ message: "name can no longer contain capital letters",
561
+ isError: true
562
+ };
563
+ }
564
+ if (/[~'!()*]/.test(name2.split("/").slice(-1)[0])) {
565
+ return {
566
+ message: `name can no longer contain special characters ("~'!()*")`,
567
+ isError: true
568
+ };
569
+ }
570
+ if (encodeURIComponent(name2) !== name2) {
571
+ const scopedPackagePattern = new RegExp("^(?:@([^/]+?)[/])?([^/]+?)$");
572
+ const nameMatch = name2.match(scopedPackagePattern);
573
+ if (nameMatch) {
574
+ const user = nameMatch[1];
575
+ const pkg = nameMatch[2];
576
+ if (pkg.startsWith(".")) {
577
+ return {
578
+ message: "name cannot start with a period",
579
+ isError: true
580
+ };
581
+ }
582
+ if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
583
+ return { message: null, isError: false };
584
+ }
585
+ }
586
+ return {
587
+ message: "name can only contain URL-friendly characters",
588
+ isError: true
589
+ };
590
+ }
591
+ return { message: null, isError: false };
592
+ }
490
593
 
491
594
  // src/util/asciiArt.ts
492
595
  var llama = " :--=: \n :-===- \n -=====- \n -=======. \n .=========-. \n :===========--:\n -=============.\n .==========-:. \n :=========-. \n -=========- \n .==========- \n -==========- \n :===========- \n -=============. \n :==============: \n :===============- \n .:-================- \n ..::---==================== \n ....::::::::::-------============================. \n .---=================================================: \n .-=====================================================- \n:=======================================================. \n .-====================================================. \n .-=================================================. \n :=============================================- \n -============================================. \n .============-:. -==========- \n :=========-: .. -==========. \n -========: :-=- -=========- \n .========. .-==== :=========: \n -=======: :=====. -========: \n -======- -====- -=======: \n -=====: -====: :======. \n .=====. -====. .-====- \n :==== -===- -====: \n -==- :===- :====. ";
596
+ var errorArt = " ++++++++++++++\u2260 \n +++++++++\u2248 \u03C0+++++++++\u2260 \n ++++ ++++ \n +++ +++\u2248 \n +++ +++ \n \u03C0++ +++ \n ++ ++ \n +- +\u03C0 \n ++\xD7 +++++++++ \u2260+++++++++ \u221A+++++++++ ++ \n + ++ \u2248+++ ++ ++ ++++ +\u221E \n ++ ++ ++ ++ ++ ++ + \n ++ ++ ++ ++ ++ ++ ++ \n ++ ++-+++++++- ++ ++ +++++++- + \n \u221A+ ++\xF7+++++ ++ ++++++++ ++ \n ++ ++ \u221E++ ++ ++ ++ \n ++ ++ +++ ++ ++ ++ \n ++ ++ +++ \u2260+++++++++ ++ \u2260+ \n ++ ++ ++ +\u2260\u221E\u221A\u221A\u2260\xD7+\u03C0 ++ \u2260+ \n ++ \u2260+ \n ++ \u2260+ \n ++ +++ \u2260+ \n ++ ++++ \u2260+ \n ++ ++++++++ \u2260+ \n ++ ++++++++++ =+ \n ++ ++++++ =+ \n ++ \u2248++++++ =+ \n ++ +++++++ \u2260+ \n ++ +++++++ \u2260+ \n ++ +++++++ =+ \n ++ ++++++++ =+ \n ++ \u221E++++++++++++ \u2260+ \n ++ \u221E++++++++++++++++++++++++++++++- =+ \n ++ +++++++++++++++++++++++++++++++++ \u2260+ \n ++ +++++++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++++++++++++++++++++++++ \u2260+ \n ++ +++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++++++++++++++++++++++ \u2260+ \n ++ ++++++++\u2260\u2260++++++=\u221A ++++++++ \u2260+ \n ++ ++++++ + +++++++ \u2260+ \n ++ +++++ \u221E+++ \xF7++++++ \u2260+ \n ++ ++++ +++ +++++\u221A \u2260+ \n ++ +++= +++\u221A ++++ \u2260+ \n ++ ++\u221E =++ +++ \u2260+ \n ++ ++\u2248 +++ ++\xF7 =+ \n ++ +++ +++\u2260 +++ =+ \n ++ \u2260+ \n ++ + \n \u2248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n ++ +\u2260 \n ++ +++++++++ ++++++++ +++++++ ++++++ ++++++++ +\u2260 \n ++ ++ ++ ++ + ++ ++ ++ ++ ++ +\u2260 \n ++ ++ ++ ++ + ++ ++ ++ ++ ++ +\u2260 \n ++ ++++++++ ++++++++ ++++++++ ++ ++ ++++++++ +\u2260 \n ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\u2260 \n ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\u2260 \n ++ +++++++++ ++ ++ ++ ++ +++++++ ++ ++ +\u2260 \n ++ +\u2260 \n ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n \n ";
493
597
  var tinaCms = "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\n \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\n \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D";
494
598
 
495
599
  // src/themes.ts
@@ -527,6 +631,21 @@ var THEMES = [
527
631
  ];
528
632
 
529
633
  // src/index.ts
634
+ function formatTemplateChoice(template) {
635
+ let description = template.description || "";
636
+ if (template.features && template.features.length > 0) {
637
+ const featuresText = template.features.map((feature) => ` \u2022 ${feature.name}: ${feature.description}`).join("\n");
638
+ description = `${description}
639
+
640
+ Features:
641
+ ${featuresText}`;
642
+ }
643
+ return {
644
+ title: template.title,
645
+ value: template.value,
646
+ description
647
+ };
648
+ }
530
649
  async function run() {
531
650
  const ora = (await import("ora")).default;
532
651
  let packageManagerInstallationHadError = false;
@@ -536,12 +655,13 @@ async function run() {
536
655
  } else {
537
656
  console.log(TextStyles.tinaOrange(`\u{1F999} TinaCMS`));
538
657
  }
539
- const version2 = require_package().version;
658
+ const require2 = createRequire(import.meta.url);
659
+ const version2 = require2("../package.json").version;
540
660
  console.log(`Create Tina App v${version2}`);
541
661
  const spinner = ora();
542
662
  preRunChecks(spinner);
543
663
  const opts = extractOptions(process.argv);
544
- const telemetry = new import_metrics.Telemetry({ disabled: opts?.noTelemetry });
664
+ const telemetry = new Telemetry({ disabled: opts?.noTelemetry });
545
665
  let template = null;
546
666
  if (opts.template) {
547
667
  template = TEMPLATES.find((_template) => _template.value === opts.template);
@@ -551,7 +671,7 @@ async function run() {
551
671
  (x2) => x2.value
552
672
  )}`
553
673
  );
554
- (0, import_node_process.exit)(1);
674
+ exit(1);
555
675
  }
556
676
  }
557
677
  let pkgManager = opts.pkgManager;
@@ -560,7 +680,7 @@ async function run() {
560
680
  spinner.fail(
561
681
  `The provided package manager '${opts.pkgManager}' is not supported. Please provide one of the following: ${PKG_MANAGERS}`
562
682
  );
563
- (0, import_node_process.exit)(1);
683
+ exit(1);
564
684
  }
565
685
  }
566
686
  if (!pkgManager) {
@@ -574,9 +694,9 @@ async function run() {
574
694
  spinner.fail(
575
695
  `You have no supported package managers installed. Please install one of the following: ${PKG_MANAGERS}`
576
696
  );
577
- (0, import_node_process.exit)(1);
697
+ exit(1);
578
698
  }
579
- const res = await (0, import_prompts.default)({
699
+ const res = await prompts({
580
700
  message: "Which package manager would you like to use?",
581
701
  name: "packageManager",
582
702
  type: "select",
@@ -584,46 +704,46 @@ async function run() {
584
704
  return { title: manager, value: manager };
585
705
  })
586
706
  });
587
- if (!Object.hasOwn(res, "packageManager")) (0, import_node_process.exit)(1);
707
+ if (!Object.hasOwn(res, "packageManager")) exit(1);
588
708
  pkgManager = res.packageManager;
589
709
  }
590
710
  let projectName = opts.projectName;
591
711
  if (!projectName) {
592
- const res = await (0, import_prompts.default)({
712
+ const res = await prompts({
593
713
  name: "name",
594
714
  type: "text",
595
715
  message: "What is your project named?",
596
716
  initial: "my-tina-app",
597
717
  validate: (name2) => {
598
- const { validForNewPackages, errors } = (0, import_validate_npm_package_name.default)(
599
- import_node_path.default.basename(import_node_path.default.resolve(name2))
718
+ const { message, isError } = validate(
719
+ path4.basename(path4.resolve(name2))
600
720
  );
601
- if (validForNewPackages) return true;
602
- return `Invalid project name: ${errors[0]}`;
721
+ if (isError) return `Invalid project name: ${message}`;
722
+ return true;
603
723
  }
604
724
  });
605
- if (!Object.hasOwn(res, "name")) (0, import_node_process.exit)(1);
725
+ if (!Object.hasOwn(res, "name")) exit(1);
606
726
  projectName = res.name;
607
727
  }
608
728
  if (!template) {
609
- const res = await (0, import_prompts.default)({
729
+ const res = await prompts({
610
730
  name: "template",
611
731
  type: "select",
612
732
  message: "What starter code would you like to use?",
613
- choices: TEMPLATES
733
+ choices: TEMPLATES.map(formatTemplateChoice)
614
734
  });
615
- if (!Object.hasOwn(res, "template")) (0, import_node_process.exit)(1);
735
+ if (!Object.hasOwn(res, "template")) exit(1);
616
736
  template = TEMPLATES.find((_template) => _template.value === res.template);
617
737
  }
618
738
  let themeChoice;
619
739
  if (template.value === "tina-docs") {
620
- const res = await (0, import_prompts.default)({
740
+ const res = await prompts({
621
741
  name: "theme",
622
742
  type: "select",
623
743
  message: "What theme would you like to use?",
624
744
  choices: THEMES
625
745
  });
626
- if (!Object.hasOwn(res, "theme")) (0, import_node_process.exit)(1);
746
+ if (!Object.hasOwn(res, "theme")) exit(1);
627
747
  themeChoice = res.theme;
628
748
  }
629
749
  await telemetry.submitRecord({
@@ -633,8 +753,8 @@ async function run() {
633
753
  pkgManager
634
754
  }
635
755
  });
636
- const rootDir = import_node_path.default.join(process.cwd(), projectName);
637
- if (!await isWriteable(import_node_path.default.dirname(rootDir))) {
756
+ const rootDir = path4.join(process.cwd(), projectName);
757
+ if (!await isWriteable(path4.dirname(rootDir))) {
638
758
  spinner.fail(
639
759
  "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."
640
760
  );
@@ -645,7 +765,7 @@ async function run() {
645
765
  appName = await setupProjectDirectory(rootDir);
646
766
  } catch (err) {
647
767
  spinner.fail(err.message);
648
- (0, import_node_process.exit)(1);
768
+ exit(1);
649
769
  }
650
770
  try {
651
771
  await downloadTemplate(template, rootDir, spinner);
@@ -661,7 +781,7 @@ async function run() {
661
781
  spinner.succeed();
662
782
  } catch (err) {
663
783
  spinner.fail(`Failed to download template: ${err.message}`);
664
- (0, import_node_process.exit)(1);
784
+ exit(1);
665
785
  }
666
786
  spinner.start("Installing packages.");
667
787
  try {
@@ -684,7 +804,9 @@ async function run() {
684
804
  `);
685
805
  if (template.value === "tina-hugo-starter") {
686
806
  spinner.warn(
687
- `Hugo is required for this starter. Install it via ${TextStyles.link("https://gohugo.io/installation/")}
807
+ `Hugo is required for this starter. Install it via ${TextStyles.link(
808
+ "https://gohugo.io/installation/"
809
+ )}
688
810
  `
689
811
  );
690
812
  }
@@ -693,28 +815,40 @@ async function run() {
693
815
 
694
816
  ${padCommand(`cd ${appName}`)}# move into your project directory${packageManagerInstallationHadError ? `
695
817
  ${padCommand(`${pkgManager} install`)}# install dependencies` : ""}
696
- ${padCommand(`${pkgManager} run dev`)}# start the dev server ${TextStyles.link(template.devUrl)}
818
+ ${padCommand(
819
+ `${pkgManager} run dev`
820
+ )}# start the dev server ${TextStyles.link(template.devUrl)}
697
821
  ${padCommand(`${pkgManager} run build`)}# build the app for production
698
822
  `);
699
823
  console.log("Next steps:");
700
824
  console.log(
701
- ` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link("https://tina.io/docs/using-tina-editor")}`
825
+ ` \u2022 \u{1F4DD} Edit some content: ${TextStyles.link(
826
+ "https://tina.io/docs/using-tina-editor"
827
+ )}`
702
828
  );
703
829
  console.log(
704
- ` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link("https://tina.io/docs/schema/")}`
830
+ ` \u2022 \u{1F4D6} Learn the basics: ${TextStyles.link(
831
+ "https://tina.io/docs/schema/"
832
+ )}`
705
833
  );
706
834
  console.log(
707
- ` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link("https://tina.io/docs/advanced/extending-tina/")}`
835
+ ` \u2022 \u{1F58C}\uFE0F Extend Tina with custom field components: ${TextStyles.link(
836
+ "https://tina.io/docs/advanced/extending-tina/"
837
+ )}`
708
838
  );
709
839
  console.log(
710
- ` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link("https://tina.io/docs/tinacloud/")}`
840
+ ` \u2022 \u{1F680} Deploy to Production: ${TextStyles.link(
841
+ "https://tina.io/docs/tinacloud/"
842
+ )}`
711
843
  );
712
844
  }
713
845
  run().catch((error) => {
714
- console.error("Error running create-tina-app:", error);
846
+ if (process.stdout.columns >= 60) {
847
+ console.log(TextStyles.tinaOrange(`${errorArt}`));
848
+ }
849
+ console.error("Error running create-tina-app: \n", error);
715
850
  process.exit(1);
716
851
  });
717
- // Annotate the CommonJS export names for ESM import in node:
718
- 0 && (module.exports = {
852
+ export {
719
853
  run
720
- });
854
+ };
@@ -1,7 +1,12 @@
1
1
  import { Ora } from 'ora';
2
+ type Feature = {
3
+ name: string;
4
+ description: string;
5
+ };
2
6
  export type BaseExample = {
3
7
  title: string;
4
8
  description?: string;
9
+ features?: Feature[];
5
10
  value: string;
6
11
  devUrl: string;
7
12
  };
@@ -15,3 +20,4 @@ export type ExternalTemplate = BaseExample & {
15
20
  export type Template = InternalTemplate | ExternalTemplate;
16
21
  export declare const TEMPLATES: Template[];
17
22
  export declare function downloadTemplate(template: Template, root: string, spinner: Ora): Promise<void>;
23
+ export {};
@@ -1,2 +1,3 @@
1
1
  export declare const llama: string;
2
+ export declare const errorArt: string;
2
3
  export declare const tinaCms: string;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @typedef {Object} ValidationResult
3
+ * @property {string | null} message
4
+ * @property {boolean} isError
5
+ */
6
+ /**
7
+ * Validates whether the provided name is valid on NPM.
8
+ *
9
+ * @param {string} name
10
+ * @returns {ValidationResult}
11
+ */
12
+ export default function validate(name: string): ValidationResult;
13
+ export type ValidationResult = {
14
+ message: string | null;
15
+ isError: boolean;
16
+ };
@@ -1,11 +1,10 @@
1
- import chalk from 'chalk';
2
1
  export declare const TextStyles: {
3
- tinaOrange: chalk.Chalk;
2
+ tinaOrange: import("chalk").ChalkInstance;
4
3
  link: (url: string) => string;
5
- cmd: chalk.Chalk;
6
- info: chalk.Chalk;
7
- success: chalk.Chalk;
8
- warn: chalk.Chalk;
9
- err: chalk.Chalk;
10
- bold: chalk.Chalk;
4
+ cmd: import("chalk").ChalkInstance;
5
+ info: import("chalk").ChalkInstance;
6
+ success: import("chalk").ChalkInstance;
7
+ warn: import("chalk").ChalkInstance;
8
+ err: import("chalk").ChalkInstance;
9
+ bold: import("chalk").ChalkInstance;
11
10
  };
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "create-tina-app",
3
- "version": "0.0.0-dde3eb3-20251028070343",
3
+ "version": "0.0.0-e1d5853-20251216014949",
4
+ "type": "module",
4
5
  "main": "dist/index.js",
5
6
  "files": [
6
7
  "dist",
@@ -35,18 +36,17 @@
35
36
  "@types/prompts": "^2.4.9",
36
37
  "@types/tar": "6.1.13",
37
38
  "typescript": "^5.7.3",
38
- "@tinacms/scripts": "0.0.0-dde3eb3-20251028070343"
39
+ "@tinacms/scripts": "1.4.2"
39
40
  },
40
41
  "dependencies": {
41
- "chalk": "4.1.2",
42
+ "chalk": "^5.4.1",
42
43
  "commander": "^12.1.0",
43
44
  "cross-spawn": "^7.0.6",
44
45
  "fs-extra": "^11.3.0",
45
46
  "ora": "^8.2.0",
46
47
  "prompts": "^2.4.2",
47
48
  "tar": "7.4.0",
48
- "validate-npm-package-name": "^5.0.1",
49
- "@tinacms/metrics": "1.1.0"
49
+ "@tinacms/metrics": "2.0.1"
50
50
  },
51
51
  "scripts": {
52
52
  "types": "pnpm tsc",