create-nextly-app 0.0.2-alpha.56 → 0.0.2-alpha.58

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.
@@ -25101,6 +25101,47 @@ var import_fs_extra8 = __toESM(require_lib(), 1);
25101
25101
  var PROJECT_TYPES_WITH_FORM_BUILDER = /* @__PURE__ */ new Set([
25102
25102
  "blog"
25103
25103
  ]);
25104
+ var FONT_PACKAGE_RANGE = "^5.3.0";
25105
+ var FONT_PACKAGE_PATTERN = /@fontsource(?:-variable)?\/[a-z0-9-]+/g;
25106
+ async function collectFontDependencies(templateDirs) {
25107
+ const effective = await effectiveTemplateFiles(templateDirs);
25108
+ const found = /* @__PURE__ */ new Set();
25109
+ for (const file of effective.values()) {
25110
+ const contents = await import_fs_extra8.default.readFile(file, "utf8");
25111
+ for (const match of contents.matchAll(FONT_PACKAGE_PATTERN)) {
25112
+ found.add(match[0]);
25113
+ }
25114
+ }
25115
+ return [...found].sort();
25116
+ }
25117
+ async function effectiveTemplateFiles(templateDirs) {
25118
+ const effective = /* @__PURE__ */ new Map();
25119
+ for (const root of templateDirs) {
25120
+ if (!root || !await import_fs_extra8.default.pathExists(root)) continue;
25121
+ for (const file of await walkSourceFiles(root)) {
25122
+ effective.set(path15.relative(root, file), file);
25123
+ }
25124
+ }
25125
+ return effective;
25126
+ }
25127
+ var SEARCH_INDEX_SCRIPT = path15.join("scripts", "build-search-index.mjs");
25128
+ async function projectHasSearchIndexScript(targetDir) {
25129
+ return import_fs_extra8.default.pathExists(path15.join(targetDir, SEARCH_INDEX_SCRIPT));
25130
+ }
25131
+ async function walkSourceFiles(root) {
25132
+ const out = [];
25133
+ const entries = await import_fs_extra8.default.readdir(root, { withFileTypes: true });
25134
+ for (const entry of entries) {
25135
+ const full = path15.join(root, entry.name);
25136
+ if (entry.isDirectory()) {
25137
+ if (entry.name === "node_modules" || entry.name === ".next") continue;
25138
+ out.push(...await walkSourceFiles(full));
25139
+ } else if (/\.(?:tsx?|jsx?|mjs|cjs|css)$/.test(entry.name)) {
25140
+ out.push(full);
25141
+ }
25142
+ }
25143
+ return out;
25144
+ }
25104
25145
  function projectUsesFormBuilder(projectType) {
25105
25146
  return PROJECT_TYPES_WITH_FORM_BUILDER.has(projectType);
25106
25147
  }
@@ -25122,6 +25163,15 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
25122
25163
  ".cjs"
25123
25164
  ]);
25124
25165
  var SKIP_FILES = /* @__PURE__ */ new Set([".DS_Store", "Thumbs.db", ".gitkeep"]);
25166
+ var IGNORE_FILE_IN_TEMPLATE = "gitignore";
25167
+ var IGNORE_FILE_IN_PROJECT = ".gitignore";
25168
+ async function restoreIgnoreFile(targetDir) {
25169
+ const shipped = path15.join(targetDir, IGNORE_FILE_IN_TEMPLATE);
25170
+ if (!await import_fs_extra8.default.pathExists(shipped)) return;
25171
+ await import_fs_extra8.default.move(shipped, path15.join(targetDir, IGNORE_FILE_IN_PROJECT), {
25172
+ overwrite: true
25173
+ });
25174
+ }
25125
25175
  function resolveTemplatePath(localTemplatePath) {
25126
25176
  const __dirname = path15.dirname(fileURLToPath(import.meta.url));
25127
25177
  const fromDist = path15.resolve(__dirname, "../templates");
@@ -25245,7 +25295,7 @@ async function resolveRuntimeVersions() {
25245
25295
  resolvedRuntimeVersions = Object.fromEntries(entries);
25246
25296
  return resolvedRuntimeVersions;
25247
25297
  }
25248
- async function generatePackageJson(projectName, database, useYalc = false, projectType = "blank") {
25298
+ async function generatePackageJson(projectName, database, useYalc = false, projectType = "blank", templateDirs = [], targetDir) {
25249
25299
  if (projectType === "plugin") {
25250
25300
  return generatePluginPackageJson(projectName, useYalc);
25251
25301
  }
@@ -25257,6 +25307,9 @@ async function generatePackageJson(projectName, database, useYalc = false, proje
25257
25307
  };
25258
25308
  dependencies["@tanstack/react-query"] = "^5.62.0";
25259
25309
  dependencies["lucide-react"] = "^0.544.0";
25310
+ for (const font of await collectFontDependencies(templateDirs)) {
25311
+ dependencies[font] = FONT_PACKAGE_RANGE;
25312
+ }
25260
25313
  if (!useYalc) {
25261
25314
  const versions = await resolveNextlyVersions(
25262
25315
  templateNextlyChannel(projectType)
@@ -25279,12 +25332,10 @@ async function generatePackageJson(projectName, database, useYalc = false, proje
25279
25332
  "@tailwindcss/postcss": PINNED_VERSIONS["@tailwindcss/postcss"],
25280
25333
  tailwindcss: PINNED_VERSIONS.tailwindcss,
25281
25334
  eslint: PINNED_VERSIONS.eslint,
25282
- "eslint-config-next": runtimeVersions["eslint-config-next"],
25283
- // Pagefind powers /search in the blog template. Zero-config
25284
- // static index generated at `next build` time. Templates that
25285
- // don't ship a /search page simply won't invoke it.
25286
- pagefind: "^1.1.0"
25335
+ "eslint-config-next": runtimeVersions["eslint-config-next"]
25287
25336
  };
25337
+ const shipsSearchIndex = targetDir ? await projectHasSearchIndexScript(targetDir) : false;
25338
+ if (shipsSearchIndex) devDependencies.pagefind = "^1.1.0";
25288
25339
  const pkg = {
25289
25340
  name: projectName,
25290
25341
  version: "0.1.0",
@@ -25296,11 +25347,25 @@ async function generatePackageJson(projectName, database, useYalc = false, proje
25296
25347
  // prompts, and child supervision. `nextly dev` is gone; the only
25297
25348
  // supported dev command is the standard `next dev`.
25298
25349
  dev: "next dev --turbopack",
25299
- // Build: migrate DB + compile Next.js + (if present) generate
25300
- // the Pagefind search index. Templates without the search
25301
- // script silently skip the last step.
25302
- build: "nextly migrate && next build && (test -f scripts/build-search-index.mjs && node scripts/build-search-index.mjs || true)",
25303
- "search:index": "node scripts/build-search-index.mjs",
25350
+ // Build: migrate the database, compile Next.js, and generate the Pagefind
25351
+ // search index for the templates that ship its builder.
25352
+ //
25353
+ // Whether that last step appears is decided HERE, from the files the
25354
+ // scaffold actually received, rather than by a shell conditional in the
25355
+ // script. Two reasons, and both were live:
25356
+ //
25357
+ // `npm run` uses cmd.exe on Windows, which has no `test` and no `true` —
25358
+ // so the `(test -f … || true)` form this replaces failed for every Windows
25359
+ // user, after `next build` had already succeeded. `&&` is all that remains,
25360
+ // and cmd.exe understands it.
25361
+ //
25362
+ // And `|| true` turned a failed index build into a successful one. The
25363
+ // search page then ships pointing at an index that was never written,
25364
+ // which fails in the browser rather than in CI.
25365
+ build: shipsSearchIndex ? "nextly migrate && next build && node scripts/build-search-index.mjs" : "nextly migrate && next build",
25366
+ // Offered only where the file exists. A script that always fails is worse
25367
+ // than an absent one: it reads as a supported command.
25368
+ ...shipsSearchIndex ? { "search:index": "node scripts/build-search-index.mjs" } : {},
25304
25369
  start: "next start",
25305
25370
  lint: "next lint",
25306
25371
  nextly: "nextly",
@@ -25310,8 +25375,11 @@ async function generatePackageJson(projectName, database, useYalc = false, proje
25310
25375
  "db:setup": "nextly db:sync",
25311
25376
  "db:migrate": "nextly migrate",
25312
25377
  "db:migrate:status": "nextly migrate:status",
25378
+ // No `db:migrate:reset`: `nextly migrate:reset` is not a command the CLI
25379
+ // registers, so the script it generated failed for every scaffolded
25380
+ // project. `migrate:fresh` is the one that drops all tables and re-runs
25381
+ // the migrations, and it is already exposed above.
25313
25382
  "db:migrate:fresh": "nextly migrate:fresh",
25314
- "db:migrate:reset": "nextly migrate:reset",
25315
25383
  "types:generate": "nextly generate:types"
25316
25384
  },
25317
25385
  dependencies,
@@ -25413,13 +25481,46 @@ function generatePnpmWorkspaceYaml() {
25413
25481
  # compiled binding (sqlite apps crash at boot) and sharp/esbuild degrade.
25414
25482
  #
25415
25483
  # pnpm 11+ reads \`allowBuilds\`; pnpm 10.6+ reads \`onlyBuiltDependencies\`.
25416
- # npm, yarn, and pnpm 9 ignore this file (they run build scripts by default).
25484
+ # npm and yarn ignore this file; pnpm 9 needs neither key, because it runs
25485
+ # build scripts by default.
25486
+ #
25487
+ # It does still READ the file, which is what the empty \`packages\` list is
25488
+ # for: through pnpm 9.3 the presence of this file declares a workspace, and
25489
+ # a missing \`packages\` key fails the install outright. This app has no
25490
+ # workspace members.
25491
+ packages: []
25417
25492
  allowBuilds:
25418
25493
  ${allowBuilds}
25419
25494
  onlyBuiltDependencies:
25420
25495
  ${onlyBuilt}
25421
25496
  `;
25422
25497
  }
25498
+ function generateNpmrc(packageManager) {
25499
+ if (packageManager !== "pnpm") return null;
25500
+ return `# This project is a single package, not a monorepo. pnpm 9 treats the
25501
+ # pnpm-workspace.yaml shipped for its build allowlist as declaring a
25502
+ # workspace root, which makes \`pnpm add <pkg>\` demand a -w flag. There is no
25503
+ # other package here for that check to protect.
25504
+ ${NPMRC_WORKSPACE_ROOT_KEY}=true
25505
+ `;
25506
+ }
25507
+ var NPMRC_WORKSPACE_ROOT_KEY = "ignore-workspace-root-check";
25508
+ async function writeScaffoldNpmrc(targetDir, packageManager) {
25509
+ const addition = generateNpmrc(packageManager);
25510
+ if (!addition) return;
25511
+ const npmrcPath = path15.join(targetDir, ".npmrc");
25512
+ const link = await import_fs_extra8.default.lstat(npmrcPath).catch(() => null);
25513
+ if (link?.isSymbolicLink()) return;
25514
+ if (link && link.nlink > 1) return;
25515
+ const existing = link ? await import_fs_extra8.default.readFile(npmrcPath, "utf-8") : "";
25516
+ const alreadyDeclared = new RegExp(
25517
+ `^\\s*${NPMRC_WORKSPACE_ROOT_KEY}\\s*=`,
25518
+ "m"
25519
+ ).test(existing);
25520
+ if (alreadyDeclared) return;
25521
+ const separator = existing === "" || existing.endsWith("\n") ? "" : "\n";
25522
+ await import_fs_extra8.default.writeFile(npmrcPath, existing + separator + addition, "utf-8");
25523
+ }
25423
25524
  async function copyTemplate(options) {
25424
25525
  const {
25425
25526
  projectName,
@@ -25430,6 +25531,7 @@ async function copyTemplate(options) {
25430
25531
  useYalc = false,
25431
25532
  approach,
25432
25533
  templateSource,
25534
+ packageManager,
25433
25535
  allowExistingTarget = false
25434
25536
  } = options;
25435
25537
  if (!allowExistingTarget && targetDir !== process.cwd() && await import_fs_extra8.default.pathExists(targetDir)) {
@@ -25448,7 +25550,13 @@ async function copyTemplate(options) {
25448
25550
  typeDir = path15.join(templatesRoot, projectType);
25449
25551
  }
25450
25552
  if (projectType === "plugin") {
25451
- await copyPluginTemplate({ projectName, typeDir, targetDir, useYalc });
25553
+ await copyPluginTemplate({
25554
+ projectName,
25555
+ typeDir,
25556
+ targetDir,
25557
+ useYalc,
25558
+ packageManager
25559
+ });
25452
25560
  return;
25453
25561
  }
25454
25562
  if (!await import_fs_extra8.default.pathExists(baseDir)) {
@@ -25507,6 +25615,13 @@ async function copyTemplate(options) {
25507
25615
  overwrite: false
25508
25616
  });
25509
25617
  }
25618
+ const templateScriptsDir = path15.join(typeDir, "scripts");
25619
+ if (await import_fs_extra8.default.pathExists(templateScriptsDir)) {
25620
+ await import_fs_extra8.default.copy(templateScriptsDir, path15.join(targetDir, "scripts"), {
25621
+ overwrite: false,
25622
+ filter: (src) => !SKIP_FILES.has(path15.basename(src))
25623
+ });
25624
+ }
25510
25625
  const frontendPagePath = path15.join(
25511
25626
  targetDir,
25512
25627
  "src",
@@ -25522,7 +25637,9 @@ async function copyTemplate(options) {
25522
25637
  projectName,
25523
25638
  database,
25524
25639
  useYalc,
25525
- projectType
25640
+ projectType,
25641
+ [baseDir, typeDir],
25642
+ targetDir
25526
25643
  );
25527
25644
  await import_fs_extra8.default.writeFile(
25528
25645
  path15.join(targetDir, "package.json"),
@@ -25534,6 +25651,8 @@ async function copyTemplate(options) {
25534
25651
  generatePnpmWorkspaceYaml(),
25535
25652
  "utf-8"
25536
25653
  );
25654
+ await restoreIgnoreFile(targetDir);
25655
+ await writeScaffoldNpmrc(targetDir, packageManager);
25537
25656
  if (database.type === "sqlite") {
25538
25657
  await import_fs_extra8.default.ensureDir(path15.join(targetDir, "data"));
25539
25658
  }
@@ -25549,7 +25668,7 @@ async function copyTemplate(options) {
25549
25668
  await replacePlaceholders(targetDir, placeholders);
25550
25669
  }
25551
25670
  async function copyPluginTemplate(opts) {
25552
- const { projectName, typeDir, targetDir, useYalc } = opts;
25671
+ const { projectName, typeDir, targetDir, useYalc, packageManager } = opts;
25553
25672
  if (!await import_fs_extra8.default.pathExists(typeDir)) {
25554
25673
  throw new Error(
25555
25674
  `Plugin template not found at ${typeDir}. The package may be corrupted or the download failed.`
@@ -25578,6 +25697,8 @@ async function copyPluginTemplate(opts) {
25578
25697
  generatePnpmWorkspaceYaml(),
25579
25698
  "utf-8"
25580
25699
  );
25700
+ await restoreIgnoreFile(targetDir);
25701
+ await writeScaffoldNpmrc(targetDir, packageManager);
25581
25702
  const nextlyRange = await resolvePluginNextlyRange(useYalc);
25582
25703
  await replacePlaceholders(
25583
25704
  targetDir,
@@ -29158,6 +29279,7 @@ async function createNextly(options = {}) {
29158
29279
  } else {
29159
29280
  s3.start("Scaffolding project...");
29160
29281
  }
29282
+ const scaffoldPackageManager = await detectPackageManager2(targetDir);
29161
29283
  await copyTemplate({
29162
29284
  projectName,
29163
29285
  projectType,
@@ -29167,6 +29289,7 @@ async function createNextly(options = {}) {
29167
29289
  useYalc,
29168
29290
  approach,
29169
29291
  templateSource,
29292
+ packageManager: scaffoldPackageManager,
29170
29293
  // Suppress copyTemplate's "directory already exists" guard when the
29171
29294
  // installer has already negotiated the conflict with the user
29172
29295
  // (either by emptying the dir or accepting an overlay). Without
@@ -29353,5 +29476,5 @@ async function createNextly(options = {}) {
29353
29476
  */
29354
29477
 
29355
29478
  export { __commonJS, __require, __toESM, capture, createNextly, init, resolveProjectArg, shutdown, validateProjectName };
29356
- //# sourceMappingURL=chunk-6434MGWG.mjs.map
29357
- //# sourceMappingURL=chunk-6434MGWG.mjs.map
29479
+ //# sourceMappingURL=chunk-E6IFBI6N.mjs.map
29480
+ //# sourceMappingURL=chunk-E6IFBI6N.mjs.map