@adbayb/stack 2.39.0-next-b0fcf5b → 2.39.0

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.
Files changed (30) hide show
  1. package/dist/index.js +78 -150
  2. package/package.json +2 -1
  3. package/templates/multi-projects/.npmrc.tmpl +1 -0
  4. package/templates/{single-project/package.json → multi-projects/package.json.tmpl} +11 -6
  5. package/templates/multi-projects/{pnpm-workspace.yaml → pnpm-workspace.yaml.tmpl} +0 -5
  6. package/templates/single-project/.npmrc.tmpl +1 -0
  7. package/templates/{multi-projects/package.json → single-project/package.json.tmpl} +11 -6
  8. package/templates/single-project/{pnpm-workspace.yaml → pnpm-workspace.yaml.tmpl} +0 -5
  9. /package/templates/multi-projects/.changeset/{config.json → config.json.tmpl} +0 -0
  10. /package/templates/multi-projects/.changeset/{welcome.md → welcome.md.tmpl} +0 -0
  11. /package/templates/multi-projects/.github/{PULL_REQUEST_TEMPLATE.md → PULL_REQUEST_TEMPLATE.md.tmpl} +0 -0
  12. /package/templates/multi-projects/{.nvmrc → .nvmrc.tmpl} +0 -0
  13. /package/templates/multi-projects/{CONTRIBUTING.md → CONTRIBUTING.md.tmpl} +0 -0
  14. /package/templates/multi-projects/{LICENSE → LICENSE.tmpl} +0 -0
  15. /package/templates/multi-projects/examples/default/{package.json → package.json.tmpl} +0 -0
  16. /package/templates/multi-projects/examples/default/src/{index.ts → index.ts.tmpl} +0 -0
  17. /package/templates/multi-projects/libraries/{{projectName}}/{README.md → README.md.tmpl} +0 -0
  18. /package/templates/multi-projects/libraries/{{projectName}}/{package.json → package.json.tmpl} +0 -0
  19. /package/templates/multi-projects/libraries/{{projectName}}/src/{index.test.ts → index.test.ts.tmpl} +0 -0
  20. /package/templates/single-project/.changeset/{config.json → config.json.tmpl} +0 -0
  21. /package/templates/single-project/.changeset/{welcome.md → welcome.md.tmpl} +0 -0
  22. /package/templates/single-project/.github/{PULL_REQUEST_TEMPLATE.md → PULL_REQUEST_TEMPLATE.md.tmpl} +0 -0
  23. /package/templates/single-project/{.nvmrc → .nvmrc.tmpl} +0 -0
  24. /package/templates/single-project/{CONTRIBUTING.md → CONTRIBUTING.md.tmpl} +0 -0
  25. /package/templates/single-project/{LICENSE → LICENSE.tmpl} +0 -0
  26. /package/templates/single-project/examples/default/{package.json → package.json.tmpl} +0 -0
  27. /package/templates/single-project/examples/default/src/{index.ts → index.ts.tmpl} +0 -0
  28. /package/templates/single-project/{{projectName}}/{README.md → README.md.tmpl} +0 -0
  29. /package/templates/single-project/{{projectName}}/{package.json → package.json.tmpl} +0 -0
  30. /package/templates/single-project/{{projectName}}/src/{index.test.ts → index.test.ts.tmpl} +0 -0
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { helpers, termost } from "termost";
2
2
  import { createRequire } from "node:module";
3
- import { basename, join, resolve } from "node:path";
4
- import { existsSync, readdirSync } from "node:fs";
5
- import { chmod, cp, mkdir, readFile, readdir, rename, rm, symlink, writeFile } from "node:fs/promises";
3
+ import { join, resolve } from "node:path";
4
+ import { cpSync, existsSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
5
+ import { chmod, mkdir, rm, symlink, writeFile } from "node:fs/promises";
6
+ import { fdir } from "fdir";
6
7
 
7
8
  //#region src/helpers.ts
8
9
  const require = createRequire(import.meta.url);
@@ -48,20 +49,20 @@ ${input.body}
48
49
  * @param path - The relative path.
49
50
  * @returns The resolved absolute path.
50
51
  * @example
51
- * resolveFromWorkingDirectory(".gitignore");
52
+ * resolveFromProjectDirectory(".gitignore");
52
53
  */
53
- const resolveFromWorkingDirectory = (...path) => {
54
- return resolve(process.cwd(), ...path);
54
+ const resolveFromProjectDirectory = (path) => {
55
+ return resolve(process.cwd(), path);
55
56
  };
56
57
  /**
57
58
  * Resolve a relative path to an absolute one resolved from the `stack` node module directory.
58
59
  * @param path - The relative path.
59
60
  * @returns The resolved absolute path.
60
61
  * @example
61
- * resolveFromPackageDirectory("./templates");
62
+ * resolveFromStackDirectory("./templates");
62
63
  */
63
- const resolveFromPackageDirectory = (...path) => {
64
- return resolve(import.meta.dirname, "../", ...path);
64
+ const resolveFromStackDirectory = (path) => {
65
+ return resolve(import.meta.dirname, "../", path);
65
66
  };
66
67
  const createError = (bin, error) => {
67
68
  const errorMessage = `\`${bin}\` command failed.\n${String(error)}`;
@@ -71,7 +72,7 @@ const createError = (bin, error) => {
71
72
  }
72
73
  return new Error(errorMessage);
73
74
  };
74
- const getPnpmVersion = async () => {
75
+ const getNpmVersion = async () => {
75
76
  try {
76
77
  return await helpers.exec("pnpm -v");
77
78
  } catch {
@@ -89,7 +90,7 @@ const setPackageManager = async () => {
89
90
  * Corepack is downloaded remotely to get always up-to-date npm registry fingerprints since they're hardcoded.
90
91
  * @see {@link https://github.com/nodejs/corepack/issues/613}
91
92
  */
92
- return helpers.exec("pnx corepack enable");
93
+ return helpers.exec("npx corepack enable");
93
94
  };
94
95
  const request = { async get(url, responseType) {
95
96
  const response = await fetch(url);
@@ -111,7 +112,7 @@ const eslint = (options) => async (files = []) => {
111
112
  const arguments_ = [
112
113
  ...eslintFiles,
113
114
  "--cache",
114
- `--cache-location ${resolveFromWorkingDirectory("node_modules/.cache/.eslintcache")}`,
115
+ `--cache-location ${resolveFromProjectDirectory("node_modules/.cache/.eslintcache")}`,
115
116
  "--no-error-on-unmatched-pattern"
116
117
  ];
117
118
  if (options.isFixMode) arguments_.push("--fix");
@@ -381,7 +382,7 @@ const createCleanCommand = (program) => {
381
382
  async handler() {
382
383
  const cachePath = "node_modules/.cache";
383
384
  const files = await retrieveIgnoredFiles();
384
- if (isDirectoryExistAndNotEmpty(resolveFromWorkingDirectory(cachePath))) files.push(cachePath);
385
+ if (isDirectoryExistAndNotEmpty(resolveFromProjectDirectory(cachePath))) files.push(cachePath);
385
386
  return files;
386
387
  },
387
388
  key: "files",
@@ -427,7 +428,7 @@ const PRESERVE_FILES = ["node_modules"];
427
428
 
428
429
  //#endregion
429
430
  //#region package.json
430
- var version = "2.39.0-next-b0fcf5b";
431
+ var version = "2.39.0";
431
432
 
432
433
  //#endregion
433
434
  //#region src/commands/create.ts
@@ -438,12 +439,12 @@ const createCreateCommand = (program) => {
438
439
  }).task({ handler() {
439
440
  botMessage({
440
441
  description: "I can guarantee you a project creation in under 1 minute 🚀",
441
- title: `I'm Stack v${version} 👋`,
442
+ title: `I'm Stack v${version}, your bot assistant`,
442
443
  type: "information"
443
444
  });
444
445
  } }).task({
445
446
  async handler() {
446
- await getPnpmVersion();
447
+ await getNpmVersion();
447
448
  },
448
449
  label: label$2("Check pre-requisites")
449
450
  }).input({
@@ -466,92 +467,61 @@ const createCreateCommand = (program) => {
466
467
  options: ["single-project", "multi-projects"],
467
468
  type: "select"
468
469
  }).task({
469
- async handler({ inputDescription, inputName, inputTemplate, inputUrl }) {
470
+ async handler({ inputDescription, inputName, inputUrl }) {
470
471
  if (!inputName) throw createError("stack create", "The project name is not optional. Make sure to provide a valid value (non-empty string).");
471
472
  const { repoName, repoOwner } = (inputUrl.startsWith("git") ? /^git@.*:(?<repoOwner>.*)\/(?<repoName>.*)\.git$/ : /^https?:\/\/.*\/(?<repoOwner>.*)\/(?<repoName>.*)\.git$/).exec(inputUrl)?.groups ?? {};
472
473
  if (!repoOwner || !repoName) throw createError("git", "The owner and repository name can not be extracted. Please make sure to follow either `/^git@.*:(?<repoOwner>.*)/(?<repoName>.*).git$/` or `/^https?://.*/(?<repoOwner>.*)/(?<repoName>.*).git$/` pattern.");
473
474
  const nodeVersion = await request.get("https://resolve-node.vercel.app/lts", "text");
474
- const { version: pnpmVersion } = await request.get("https://registry.npmjs.org/pnpm/latest", "json");
475
- const projectName = slugify(inputName);
475
+ const { version: npmVersion } = await request.get("https://registry.npmjs.org/pnpm/latest", "json");
476
476
  return {
477
477
  licenseYear: (/* @__PURE__ */ new Date()).getFullYear().toString(),
478
478
  nodeVersion: nodeVersion.replace("v", ""),
479
- pnpmVersion: String(pnpmVersion),
480
- projectDescription: toCapitalLetter(inputDescription),
481
- projectName,
479
+ npmVersion: String(npmVersion),
480
+ projectDescription: inputDescription.charAt(0).toUpperCase() + inputDescription.slice(1),
481
+ projectName: inputName.toLowerCase(),
482
482
  projectUrl: inputUrl,
483
- repoId: `${repoOwner}/${repoName}`,
484
- templatePath: resolveFromPackageDirectory("templates", inputTemplate),
485
- workingPath: resolveFromWorkingDirectory(projectName)
483
+ repoId: `${repoOwner}/${repoName}`
486
484
  };
487
485
  },
488
486
  key: "data",
489
487
  label: label$2("Check and format input")
490
- }).input({
491
- defaultValue: true,
492
- key: "canRemoveExistingDirectoryInput",
493
- label({ data: { projectName } }) {
494
- return label$2(`\`${projectName}\` directory already exists, do you want to remove it?`);
495
- },
496
- skip({ data: { workingPath } }) {
497
- return !existsSync(workingPath);
488
+ }).task({
489
+ async handler({ data }) {
490
+ const projectPath = resolve(process.cwd(), data.projectName);
491
+ await mkdir(projectPath);
492
+ process.chdir(projectPath);
498
493
  },
499
- type: "confirm",
500
- validate({ canRemoveExistingDirectoryInput, data: { projectName } }) {
501
- if (canRemoveExistingDirectoryInput) return;
502
- return createError("mkdir", `Remove or rename the \`${projectName}\` existing directory to apply the template from a clean state.`);
494
+ label({ data }) {
495
+ return label$2(`Create \`${data.projectName}\` folder`);
503
496
  }
504
497
  }).task({
505
- async handler({ canRemoveExistingDirectoryInput, data: { licenseYear, nodeVersion, pnpmVersion, projectDescription, projectName, projectUrl, repoId, templatePath, workingPath }, inputTemplate }) {
506
- if (canRemoveExistingDirectoryInput) await rm(workingPath, {
507
- force: true,
508
- recursive: true
509
- });
510
- return createTemplateEngine(workingPath, {
511
- projectName,
512
- templateModel: {
513
- licenseYear,
514
- nodeVersion,
515
- pnpmVersion,
516
- projectDescription,
517
- projectName,
518
- projectUrl,
519
- repoId
520
- },
521
- templateName: inputTemplate,
522
- templatePath
523
- });
498
+ async handler({ data }) {
499
+ await helpers.exec("git init");
500
+ await helpers.exec(`git remote add origin ${data.projectUrl}`);
524
501
  },
525
- key: "templateEngine",
526
- label({ data: { projectName }, inputTemplate }) {
527
- return label$2(`Copy \`${inputTemplate}\` template to \`${projectName}\` directory`);
528
- }
502
+ label: label$2("Initialize `git`")
529
503
  }).task({
530
- async handler({ templateEngine }) {
531
- await templateEngine.processContents();
532
- await templateEngine.processPaths();
504
+ handler({ data, inputTemplate }) {
505
+ applyTemplate(inputTemplate, data);
533
506
  },
534
- label() {
535
- return label$2("Process template");
536
- }
507
+ label: label$2("Apply template")
537
508
  }).task({
538
- async handler({ data: { projectUrl } }) {
539
- await helpers.exec("git init");
540
- await helpers.exec(`git remote add origin ${projectUrl}`);
509
+ async handler({ data: { projectName }, inputTemplate }) {
510
+ await symlink(join(inputTemplate === "single-project" ? projectName : join("libraries", projectName), "README.md"), "./README.md");
541
511
  },
542
- label: label$2("Initialize `git`")
512
+ label: label$2("Create a symlink to `README.md` file")
543
513
  }).task({
544
514
  async handler() {
545
515
  await setPackageManager();
546
516
  },
547
517
  label: label$2("Set up the package manager")
548
518
  }).task({
549
- async handler({ data: { projectName } }) {
519
+ async handler({ data }) {
550
520
  const localDevelopmentDependencies = ["quickbundle", "vitest"];
551
521
  const globalDevelopmentDependencies = ["@adbayb/stack"];
552
522
  try {
553
523
  await helpers.exec(`pnpm add ${globalDevelopmentDependencies.join(" ")} --save-dev --ignore-workspace-root-check`);
554
- await helpers.exec(`pnpm add ${localDevelopmentDependencies.join(" ")} --save-dev --filter ${projectName}`);
524
+ await helpers.exec(`pnpm add ${localDevelopmentDependencies.join(" ")} --save-dev --filter ${data.projectName}`);
555
525
  await helpers.exec("pnpm install");
556
526
  } catch (error) {
557
527
  throw createError("pnpm", error);
@@ -569,95 +539,53 @@ const createCreateCommand = (program) => {
569
539
  await helpers.exec("git commit -m \"chore: initial commit\"");
570
540
  },
571
541
  label: label$2("Commit")
572
- }).task({ handler({ data: { projectName } }) {
542
+ }).task({ handler({ data }) {
573
543
  botMessage({
574
- description: `Run \`cd ./${projectName}\` and Enjoy 🚀`,
544
+ description: `Run \`cd ./${data.projectName}\` and Enjoy 🚀`,
575
545
  title: "The project was successfully created",
576
546
  type: "success"
577
547
  });
578
548
  } });
579
549
  };
580
550
  const label$2 = (message) => `${message} 🔨`;
581
- const slugify = (input) => {
582
- return input.toLowerCase().replaceAll(/[^a-z0-9\s-]/g, "").trim().replaceAll(/\s+/g, "-").replaceAll(/-+/g, "-");
583
- };
584
- const toCapitalLetter = (input) => {
585
- return input.charAt(0).toUpperCase() + input.slice(1);
586
- };
587
- const createTemplateEngine = async (workingPath, { projectName, templateModel, templateName, templatePath }) => {
588
- if (!existsSync(workingPath)) await mkdir(workingPath);
589
- await cp(templatePath, workingPath, {
551
+ /**
552
+ * A simple template engine to evaluate dynamic expressions and apply side effets (such as hydrating a content with values from an input object) on impacted template files.
553
+ * @param template - The selected template.
554
+ * @param dataModel - Data model mapping the template expression key with its corresponding value.
555
+ * @example
556
+ * applyTemplate(
557
+ * { toReplace: "value" },
558
+ * );
559
+ */
560
+ const applyTemplate = (template, dataModel) => {
561
+ const templateExtension = ".tmpl";
562
+ const templateRootPath = resolveFromStackDirectory(join("./templates", template));
563
+ const projectRootPath = resolveFromProjectDirectory("./");
564
+ const templateExpressionRegExp = /{{(.*?)}}/g;
565
+ const evaluate = (content) => {
566
+ return content.replaceAll(templateExpressionRegExp, (_, key) => dataModel[key] || "");
567
+ };
568
+ /** Copy the template before mutations. */
569
+ cpSync(templateRootPath, projectRootPath, {
590
570
  force: true,
591
571
  recursive: true
592
572
  });
593
- const gitignoreFile = join(workingPath, ".gitignore.tmpl");
594
- if (existsSync(gitignoreFile)) await rename(gitignoreFile, join(workingPath, ".gitignore"));
595
- const eslintConfigFile = join(workingPath, "eslint.config.js.tmpl");
596
- if (existsSync(eslintConfigFile)) await rename(eslintConfigFile, join(workingPath, "eslint.config.js"));
597
- const templateEntries = await getTemplateEntries(workingPath);
598
- process.chdir(workingPath);
599
- return {
600
- async processContents() {
601
- await Promise.all(templateEntries.filter(({ type }) => type === "content").map(async (entry) => {
602
- return writeFile(entry.path, setTemplateVariables(entry, templateModel));
603
- }));
604
- },
605
- async processPaths() {
606
- const sortedDirectoryEntries = templateEntries.filter(({ content, type }) => {
607
- if (type === "path.directory" || type === "path.file") return hasTemplateVariable(basename(content));
608
- return false;
609
- }).toSorted(({ path: pathA }, { path: pathB }) => pathB.length - pathA.length);
610
- for (const entry of sortedDirectoryEntries) {
611
- const newPath = setTemplateVariables(entry, templateModel);
612
- await rename(entry.path, newPath);
613
- }
614
- await symlink(join(templateName === "single-project" ? projectName : join("libraries", projectName), "README.md"), "./README.md");
615
- }
616
- };
617
- };
618
- const getTemplateEntries = async (path) => {
619
- const entries = await readdir(path, {
620
- recursive: true,
621
- withFileTypes: true
573
+ /** Template file mutations. */
574
+ new fdir().withBasePath().glob(`**/*${templateExtension}`).crawl(projectRootPath).sync().forEach((templateFilePath) => {
575
+ const projectFilePath = templateFilePath.slice(0, templateFilePath.lastIndexOf(templateExtension));
576
+ const content = evaluate(readFileSync(templateFilePath, "utf8"));
577
+ renameSync(templateFilePath, projectFilePath);
578
+ writeFileSync(projectFilePath, content, "utf8");
622
579
  });
623
- return (await Promise.all(entries.map(async (entry) => {
624
- const isDirectory = entry.isDirectory();
625
- if (!isDirectory && !entry.isFile()) return [];
626
- const entryPath = resolve(entry.parentPath, entry.name);
627
- return (isDirectory ? [{
628
- content: entryPath,
629
- type: "path.directory"
630
- }] : [{
631
- content: entryPath,
632
- type: "path.file"
633
- }, {
634
- content: await readFile(entryPath, "utf8"),
635
- type: "content"
636
- }]).map(({ content, type }) => {
637
- if (!hasTemplateVariable(content)) return void 0;
638
- return {
639
- content,
640
- path: entryPath,
641
- type
642
- };
643
- }).filter((input) => Boolean(input));
644
- }))).flat();
645
- };
646
- const setTemplateVariables = (entry, model) => {
647
- return entry.content.replaceAll(TEMPLATE_VARIABLE_MATCHER, (match, dataModelKey) => {
648
- return model[dataModelKey] ?? match;
580
+ /** Template folder mutations. */
581
+ new fdir().withBasePath().onlyDirs().filter((path) => {
582
+ return templateExpressionRegExp.test(path);
583
+ }).crawl(projectRootPath).sync().toSorted((a, b) => b.length - a.length).forEach((templateFolderPath) => {
584
+ renameSync(templateFolderPath, templateFolderPath.replaceAll(templateExpressionRegExp, (_, dataModelKey) => {
585
+ return dataModel[dataModelKey];
586
+ }));
649
587
  });
650
588
  };
651
- const TEMPLATE_VARIABLE_MATCHER = /* @__PURE__ */ new RegExp(/{{(.*?)}}/g, "gi");
652
- const hasTemplateVariable = (input) => {
653
- /**
654
- * TemplateVariableMatcher.test() is not used since the `RegExp` is stateful when the global is used leading to some unstable results
655
- * (relying on latest `lastIndex` set (lastIndex specifies the index at which to start the next match)).
656
- * String.search is stateless.
657
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test MDN documentation}.
658
- */
659
- return input.search(TEMPLATE_VARIABLE_MATCHER) >= 0;
660
- };
661
589
 
662
590
  //#endregion
663
591
  //#region src/commands/fix/fixFormatting.ts
@@ -672,7 +600,7 @@ const fixFormatting = async (files) => {
672
600
  if (prettierFiles.length === 0) return;
673
601
  }
674
602
  const arguments_ = [...prettierFiles];
675
- if (existsSync(resolveFromWorkingDirectory(".gitignore"))) arguments_.push("--ignore-path .gitignore");
603
+ if (existsSync(resolveFromProjectDirectory(".gitignore"))) arguments_.push("--ignore-path .gitignore");
676
604
  arguments_.push("--write", "--ignore-unknown", "--no-error-on-unmatched-pattern");
677
605
  try {
678
606
  return await helpers.exec(`prettier ${arguments_.join(" ")}`);
@@ -735,7 +663,7 @@ const createInstallCommand = (program) => {
735
663
  };
736
664
  const label = (message) => `${message} 📲`;
737
665
  const installGitHook = async (hook, content) => {
738
- const filename = resolveFromWorkingDirectory(`.git/hooks/${hook}`);
666
+ const filename = resolveFromProjectDirectory(`.git/hooks/${hook}`);
739
667
  await writeFile(filename, content);
740
668
  return chmod(filename, "0755");
741
669
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adbayb/stack",
3
- "version": "2.39.0-next-b0fcf5b",
3
+ "version": "2.39.0",
4
4
  "description": "My opinionated JavaScript-based toolchain",
5
5
  "keywords": [
6
6
  "stack",
@@ -59,6 +59,7 @@
59
59
  "eslint-plugin-prettier": "^5.5.6",
60
60
  "eslint-plugin-sonarjs": "^4.1.0",
61
61
  "eslint-plugin-unicorn": "^68.0.0",
62
+ "fdir": "^6.5.0",
62
63
  "globals": "^17.6.0",
63
64
  "prettier": "^3.8.4",
64
65
  "prettier-plugin-packagejson": "^3.0.2",
@@ -0,0 +1 @@
1
+ save-exact=true
@@ -17,13 +17,18 @@
17
17
  "watch": "stack watch"
18
18
  },
19
19
  "prettier": "@adbayb/stack/prettier",
20
- "packageManager": "pnpm@{{pnpmVersion}}",
20
+ "packageManager": "pnpm@{{npmVersion}}",
21
21
  "devEngines": {
22
- "packageManager": {
23
- "name": "pnpm",
24
- "version": "{{pnpmVersion}}",
25
- "onFail": "download"
26
- },
22
+ "packageManager": [
23
+ {
24
+ "name": "pnpm",
25
+ "version": "{{npmVersion}}",
26
+ "onFail": "download"
27
+ },
28
+ {
29
+ "name": "npm"
30
+ }
31
+ ],
27
32
  "runtime": {
28
33
  "name": "node",
29
34
  "version": ">=24.0.0",
@@ -1,6 +1,3 @@
1
- allowBuilds:
2
- esbuild: true
3
- unrs-resolver: true
4
1
  minimumReleaseAgeExclude:
5
2
  - "@adbayb/*"
6
3
  packages:
@@ -16,5 +13,3 @@ publicHoistPattern:
16
13
  - "*turbo*"
17
14
  - "*typescript*"
18
15
  - "*types*"
19
- saveExact: true
20
- verifyDepsBeforeRun: "warn"
@@ -0,0 +1 @@
1
+ save-exact=true
@@ -17,13 +17,18 @@
17
17
  "watch": "stack watch"
18
18
  },
19
19
  "prettier": "@adbayb/stack/prettier",
20
- "packageManager": "pnpm@{{pnpmVersion}}",
20
+ "packageManager": "pnpm@{{npmVersion}}",
21
21
  "devEngines": {
22
- "packageManager": {
23
- "name": "pnpm",
24
- "version": "{{pnpmVersion}}",
25
- "onFail": "download"
26
- },
22
+ "packageManager": [
23
+ {
24
+ "name": "pnpm",
25
+ "version": "{{npmVersion}}",
26
+ "onFail": "download"
27
+ },
28
+ {
29
+ "name": "npm"
30
+ }
31
+ ],
27
32
  "runtime": {
28
33
  "name": "node",
29
34
  "version": ">=24.0.0",
@@ -1,6 +1,3 @@
1
- allowBuilds:
2
- esbuild: true
3
- unrs-resolver: true
4
1
  minimumReleaseAgeExclude:
5
2
  - "@adbayb/*"
6
3
  packages:
@@ -15,5 +12,3 @@ publicHoistPattern:
15
12
  - "*turbo*"
16
13
  - "*typescript*"
17
14
  - "*types*"
18
- saveExact: true
19
- verifyDepsBeforeRun: "warn"