@adbayb/stack 2.40.0-next-f8ad939 → 2.40.0-next-6049a9b

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/bin/index.js CHANGED
@@ -1,7 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { createRequire } from "node:module";
4
-
5
- const pkg = createRequire(import.meta.url)("../package.json");
3
+ import pkg from "../package.json" with { type: "json" };
6
4
 
7
5
  void import(new URL(`../${pkg.exports["."].default}`, import.meta.url));
@@ -1,6 +1,64 @@
1
1
  import { defineConfig } from "oxlint";
2
2
 
3
+ const JAVASCRIPT_EXTENSIONS = ["js", "jsx", "cjs", "mjs", "mjsx"];
4
+ const TYPESCRIPT_EXTENSIONS = ["ts", "tsx", "cts", "mts", "mtsx"];
5
+ const JAVASCRIPT_LIKE_EXTENSIONS = [...JAVASCRIPT_EXTENSIONS, ...TYPESCRIPT_EXTENSIONS];
6
+ const JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING = JAVASCRIPT_LIKE_EXTENSIONS.join(",");
7
+
8
+ const TEST_LIKE_FILES = [
9
+ `**/{test,test-d}.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
10
+ `**/*.{test,test-d}.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
11
+ ];
12
+
13
+ const RELAXED_LIKE_FILES = [
14
+ ...TEST_LIKE_FILES,
15
+ "**/.config/**",
16
+ "**/.configs/**",
17
+ "**/config/**",
18
+ "**/configs/**",
19
+ "**/examples/**",
20
+ "**/scripts/**",
21
+ "**/tools/**",
22
+ `**/config.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
23
+ `**/configs.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
24
+ `**/*.config.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
25
+ `**/*.configs.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
26
+ `**/stories.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
27
+ `**/*.stories.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
28
+ ];
29
+
3
30
  export default defineConfig({
31
+ categories: {
32
+ correctness: "error",
33
+ nursery: "error",
34
+ pedantic: "error",
35
+ perf: "error",
36
+ style: "error",
37
+ suspicious: "error",
38
+ },
39
+ options: {
40
+ denyWarnings: true,
41
+ reportUnusedDisableDirectives: "error",
42
+ respectEslintDisableDirectives: false,
43
+ typeAware: true,
44
+ typeCheck: true,
45
+ },
46
+ overrides: [
47
+ {
48
+ files: TEST_LIKE_FILES,
49
+ plugins: ["vitest"],
50
+ },
51
+ {
52
+ files: [
53
+ ...RELAXED_LIKE_FILES,
54
+ `*.config(s)?.{${JAVASCRIPT_LIKE_EXTENSIONS_AS_STRING}}`,
55
+ ],
56
+ rules: {
57
+ "import/no-anonymous-default-export": "off",
58
+ },
59
+ },
60
+ ],
61
+ // TODO: add jsPlugins for perfectionist and padding-line-between-statements + add React rules (such as set-state-in-effect) from React X https://github.com/oxc-project/oxc/issues/1022 + potentially https://github.com/es-tooling/eslint-plugin-depend/blob/main/docs/rules/ban-dependencies.md
4
62
  plugins: [
5
63
  "eslint",
6
64
  "import",
@@ -13,18 +71,38 @@ export default defineConfig({
13
71
  "react-perf",
14
72
  "typescript",
15
73
  "unicorn",
16
- "vitest",
17
74
  ],
18
- categories: {
19
- correctness: "error",
20
- perf: "error",
21
- suspicious: "error",
22
- },
23
- options: {
24
- denyWarnings: true,
25
- reportUnusedDisableDirectives: "error",
26
- respectEslintDisableDirectives: false,
27
- typeAware: true,
28
- typeCheck: true,
75
+ rules: {
76
+ "array-callback-return": ["error", { allowImplicit: true }],
77
+ "arrow-body-style": ["error", "always"],
78
+ "id-length": "off",
79
+ "import/exports-last": "off",
80
+ "import/group-exports": "off",
81
+ "import/max-dependencies": "off",
82
+ "import/no-named-export": "off",
83
+ "import/no-nodejs-modules": "off",
84
+ "import/prefer-default-export": "off",
85
+ "jsdoc/require-param-type": "off",
86
+ "jsdoc/require-property-type": "off",
87
+ "jsdoc/require-returns-type": "off",
88
+ "max-classes-per-file": "off",
89
+ "max-lines": "off",
90
+ "max-lines-per-function": "off",
91
+ "max-statements": "off",
92
+ "no-continue": "off",
93
+ "no-magic-numbers": "off",
94
+ "no-ternary": "off",
95
+ "no-undef": "off",
96
+ "no-warning-comments": "off",
97
+ "node/no-sync": "off",
98
+ "prefer-named-capture-group": "off",
99
+ "prefer-readonly-parameter-types": "off",
100
+ "react/jsx-max-depth": "off",
101
+ "sort-imports": ["error", { ignoreDeclarationSort: true }],
102
+ "strict-boolean-expressions": "off",
103
+ "typescript/consistent-return": "off",
104
+ "typescript/consistent-type-definitions": ["error", "type"],
105
+ "typescript/no-unsafe-type-assertion": "off",
106
+ "unicorn/filename-case": "off",
29
107
  },
30
108
  });
package/dist/index.js CHANGED
@@ -6,9 +6,9 @@ import { chmod, cp, mkdir, readFile, readdir, rename, rm, symlink, writeFile } f
6
6
 
7
7
  //#region src/helpers.ts
8
8
  const require = createRequire(import.meta.url);
9
- function assert(expectedCondition, createError) {
9
+ const assert = (expectedCondition, createError) => {
10
10
  if (!expectedCondition) throw createError();
11
- }
11
+ };
12
12
  /**
13
13
  * Helper to format log messages with a welcoming bot.
14
14
  *
@@ -91,7 +91,7 @@ const setPackageManager = async () => {
91
91
  *
92
92
  * @see {@link https://github.com/nodejs/corepack/issues/613}
93
93
  */
94
- return helpers.exec("pnx corepack enable");
94
+ await helpers.exec("pnx corepack enable");
95
95
  };
96
96
  async function getRequest(url, responseType) {
97
97
  const response = await fetch(url);
@@ -103,31 +103,35 @@ async function getRequest(url, responseType) {
103
103
  return response.json();
104
104
  }
105
105
  const request = { get: getRequest };
106
- const oxlint = (options) => async (files = []) => {
107
- const args = [
108
- ...files,
109
- "--disable-nested-config",
110
- "--no-error-on-unmatched-pattern"
111
- ];
112
- if (options.isFixMode) args.push("--fix");
113
- try {
114
- return await helpers.exec(`oxlint ${args.join(" ")}`);
115
- } catch (error) {
116
- throw createError("oxlint", error instanceof Error ? error : new Error(String(error)));
117
- }
106
+ const oxlint = (options) => {
107
+ return async (files = []) => {
108
+ const args = [
109
+ ...files,
110
+ "--disable-nested-config",
111
+ "--no-error-on-unmatched-pattern"
112
+ ];
113
+ if (options.isFixMode) args.push("--fix");
114
+ try {
115
+ return await helpers.exec(`oxlint ${args.join(" ")}`);
116
+ } catch (error) {
117
+ throw createError("oxlint", error instanceof Error ? error : new Error(String(error)));
118
+ }
119
+ };
118
120
  };
119
- const oxfmt = (options) => async (files = []) => {
120
- const args = [
121
- ...files,
122
- "--disable-nested-config",
123
- "--no-error-on-unmatched-pattern",
124
- options.isFixMode ? "--write" : "--check"
125
- ];
126
- try {
127
- return await helpers.exec(`oxfmt ${args.join(" ")}`);
128
- } catch (error) {
129
- throw createError("oxfmt", error instanceof Error ? error : new Error(String(error)));
130
- }
121
+ const oxfmt = (options) => {
122
+ return async (files = []) => {
123
+ const args = [
124
+ ...files,
125
+ "--disable-nested-config",
126
+ "--no-error-on-unmatched-pattern",
127
+ options.isFixMode ? "--write" : "--check"
128
+ ];
129
+ try {
130
+ return await helpers.exec(`oxfmt ${args.join(" ")}`);
131
+ } catch (error) {
132
+ throw createError("oxfmt", error instanceof Error ? error : new Error(String(error)));
133
+ }
134
+ };
131
135
  };
132
136
  const turbo = async (command, options = {}) => {
133
137
  try {
@@ -199,7 +203,9 @@ const checkDependency = async () => {
199
203
  const checkDependencyVersionMismatch = createPackagesVersionMismatchChecker();
200
204
  const packages = JSON.parse(stdout).map((pkg) => {
201
205
  const packagePath = join(pkg.path, "package.json");
202
- assert(pkg.name, () => createPackageError(`\`${packagePath}\` must have a name field.`));
206
+ assert(pkg.name, () => {
207
+ return createPackageError(`\`${packagePath}\` must have a name field.`);
208
+ });
203
209
  const packageContent = require(packagePath);
204
210
  const peerDependencies = packageContent.peerDependencies ?? {};
205
211
  const devDependencies = packageContent.devDependencies ?? {};
@@ -221,7 +227,7 @@ const checkDependencyVersionRange = ({ dependencies, devDependencies, name, peer
221
227
  consumedBy: name,
222
228
  name: dependencyName
223
229
  });
224
- if (version !== "workspace:*" && !isExcluded(version) && !/^\d/.test(version)) throw createPackageError(`As a dev dependency, \`${dependencyName}\` version must be fixed (or set as "workspace:*" for local packages) to reduce accidental breaking change risks due to an implicit semver upgrade.`, {
230
+ if (version !== "workspace:*" && !isExcluded(version) && !/^\d/u.test(version)) throw createPackageError(`As a dev dependency, \`${dependencyName}\` version must be fixed (or set as "workspace:*" for local packages) to reduce accidental breaking change risks due to an implicit semver upgrade.`, {
225
231
  consumedBy: name,
226
232
  name: dependencyName
227
233
  });
@@ -276,17 +282,21 @@ const createPackagesVersionMismatchChecker = () => {
276
282
  const createPackageError = (message, context) => {
277
283
  return createError("stack check", context ? `\`${context.name}\` consumed by \`${context.consumedBy}\` doesn't conform to package guidelines.\n${message}` : message);
278
284
  };
279
- function assertVersion(version, { consumedBy, name }) {
280
- assert(version, () => createPackageError(`\`${name}\` must have a valid version specified (current version equals to \`${String(version)}\`).`, {
281
- consumedBy,
282
- name
283
- }));
284
- }
285
+ const assertVersion = (version, { consumedBy, name }) => {
286
+ assert(version, () => {
287
+ return createPackageError(`\`${name}\` must have a valid version specified (current version equals to \`${String(version)}\`).`, {
288
+ consumedBy,
289
+ name
290
+ });
291
+ });
292
+ };
285
293
  const isExcluded = (version) => {
286
- const isPreReleaseVersion = /\d+\.\d+\.\d+-(alpha|beta|experimental|next|rc).*/.exec(version);
294
+ const isPreReleaseVersion = /\d+\.\d+\.\d+-(alpha|beta|experimental|next|rc).*/u.exec(version);
287
295
  return version.startsWith("npm:") || isPreReleaseVersion;
288
296
  };
289
- const hasCaret = (version) => version.startsWith("^");
297
+ const hasCaret = (version) => {
298
+ return version.startsWith("^");
299
+ };
290
300
 
291
301
  //#endregion
292
302
  //#region src/commands/check/checkFormatting.ts
@@ -355,9 +365,13 @@ const createCheckCommand = (program) => {
355
365
  }
356
366
  });
357
367
  };
358
- const label$4 = (message) => `${message} 🧐`;
359
- const ifFilterDefinedAndNotEqualTo = (filter) => (context) => {
360
- return context.filter !== void 0 && context.filter !== filter;
368
+ const label$4 = (message) => {
369
+ return `${message} 🧐`;
370
+ };
371
+ const ifFilterDefinedAndNotEqualTo = (filter) => {
372
+ return (context) => {
373
+ return context.filter !== void 0 && context.filter !== filter;
374
+ };
361
375
  };
362
376
 
363
377
  //#endregion
@@ -399,24 +413,34 @@ const createCleanCommand = (program) => {
399
413
  }
400
414
  });
401
415
  };
402
- const label$3 = (message) => `${message} 🧹`;
416
+ const label$3 = (message) => {
417
+ return `${message} 🧹`;
418
+ };
403
419
  const cleanFiles = async (files) => {
404
- return Promise.all(files.map(async (file) => rm(file, {
405
- force: true,
406
- recursive: true
407
- })));
420
+ await Promise.all(files.map(async (file) => {
421
+ await rm(file, {
422
+ force: true,
423
+ recursive: true
424
+ });
425
+ }));
408
426
  };
409
427
  const isDirectoryExistAndNotEmpty = (path) => {
410
428
  return existsSync(path) && readdirSync(path).length > 0;
411
429
  };
412
430
  const retrieveIgnoredFiles = async () => {
413
- return (await helpers.exec("git clean -fdXn")).split(/\n|\r\n/).filter((cleanOutput) => PRESERVE_FILES.every((excludedFile) => !cleanOutput.includes(excludedFile))).map((cleanOutput) => cleanOutput.split(" ").at(-1) ?? "").filter(Boolean);
431
+ return (await helpers.exec("git clean -fdXn")).split(/\n|\r\n/u).filter((cleanOutput) => {
432
+ return PRESERVE_FILES.every((excludedFile) => {
433
+ return !cleanOutput.includes(excludedFile);
434
+ });
435
+ }).map((cleanOutput) => {
436
+ return cleanOutput.split(" ").at(-1) ?? "";
437
+ }).filter(Boolean);
414
438
  };
415
439
  const PRESERVE_FILES = ["node_modules"];
416
440
 
417
441
  //#endregion
418
442
  //#region package.json
419
- var version = "2.40.0-next-f8ad939";
443
+ var version = "2.40.0-next-6049a9b";
420
444
 
421
445
  //#endregion
422
446
  //#region src/commands/create.ts
@@ -457,7 +481,7 @@ const createCreateCommand = (program) => {
457
481
  }).task({
458
482
  async handler({ inputDescription, inputName, inputTemplate, inputUrl }) {
459
483
  if (!inputName) throw createError("stack create", "The project name is not optional. Make sure to provide a valid value (non-empty string).");
460
- const { repoName, repoOwner } = (inputUrl.startsWith("git") ? /^git@.*:(?<repoOwner>.*)\/(?<repoName>.*)\.git$/ : /^https?:\/\/.*\/(?<repoOwner>.*)\/(?<repoName>.*)\.git$/).exec(inputUrl)?.groups ?? {};
484
+ const { repoName, repoOwner } = (inputUrl.startsWith("git") ? /^git@.*:(?<repoOwner>.*)\/(?<repoName>.*)\.git$/u : /^https?:\/\/.*\/(?<repoOwner>.*)\/(?<repoName>.*)\.git$/u).exec(inputUrl)?.groups ?? {};
461
485
  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.");
462
486
  const nodeVersion = await request.get("https://resolve-node.vercel.app/lts", "text");
463
487
  const { version: pnpmVersion } = await request.get("https://registry.npmjs.org/pnpm/latest", "json");
@@ -487,7 +511,7 @@ const createCreateCommand = (program) => {
487
511
  },
488
512
  type: "confirm",
489
513
  validate({ canRemoveExistingDirectoryInput, data: { projectName } }) {
490
- if (canRemoveExistingDirectoryInput) return void 0;
514
+ if (canRemoveExistingDirectoryInput) return;
491
515
  return createError("mkdir", `Remove or rename the \`${projectName}\` existing directory to apply the template from a clean state.`);
492
516
  }
493
517
  }).task({
@@ -566,9 +590,11 @@ const createCreateCommand = (program) => {
566
590
  });
567
591
  } });
568
592
  };
569
- const label$2 = (message) => `${message} 🔨`;
593
+ const label$2 = (message) => {
594
+ return `${message} 🔨`;
595
+ };
570
596
  const slugify = (input) => {
571
- return input.toLowerCase().replaceAll(/[^a-z0-9\s-]/g, "").trim().replaceAll(/\s+/g, "-").replaceAll(/-+/g, "-");
597
+ return input.toLowerCase().replaceAll(/[^a-z0-9\s-]/gu, "").trim().replaceAll(/\s+/gu, "-").replaceAll(/-+/gu, "-");
572
598
  };
573
599
  const toCapitalLetter = (input) => {
574
600
  return input.charAt(0).toUpperCase() + input.slice(1);
@@ -587,15 +613,19 @@ const createTemplateEngine = async (workingPath, { projectName, templateModel, t
587
613
  process.chdir(workingPath);
588
614
  return {
589
615
  async processContents() {
590
- await Promise.all(templateEntries.filter(({ type }) => type === "content").map(async (entry) => {
591
- return writeFile(entry.path, setTemplateVariables(entry, templateModel));
616
+ await Promise.all(templateEntries.filter(({ type }) => {
617
+ return type === "content";
618
+ }).map(async (entry) => {
619
+ await writeFile(entry.path, setTemplateVariables(entry, templateModel));
592
620
  }));
593
621
  },
594
622
  async processPaths() {
595
623
  const sortedDirectoryEntries = templateEntries.filter(({ content, type }) => {
596
624
  if (type === "path.directory" || type === "path.file") return hasTemplateVariable(basename(content));
597
625
  return false;
598
- }).toSorted(({ path: pathA }, { path: pathB }) => pathB.length - pathA.length);
626
+ }).toSorted(({ path: pathA }, { path: pathB }) => {
627
+ return pathB.length - pathA.length;
628
+ });
599
629
  for (const entry of sortedDirectoryEntries) {
600
630
  const newPath = setTemplateVariables(entry, templateModel);
601
631
  await rename(entry.path, newPath);
@@ -623,13 +653,15 @@ const getTemplateEntries = async (path) => {
623
653
  content: await readFile(entryPath, "utf8"),
624
654
  type: "content"
625
655
  }]).map(({ content, type }) => {
626
- if (!hasTemplateVariable(content)) return void 0;
656
+ if (!hasTemplateVariable(content)) return;
627
657
  return {
628
658
  content,
629
659
  path: entryPath,
630
660
  type
631
661
  };
632
- }).filter((input) => Boolean(input));
662
+ }).filter((input) => {
663
+ return Boolean(input);
664
+ });
633
665
  }))).flat();
634
666
  };
635
667
  const setTemplateVariables = (entry, model) => {
@@ -637,7 +669,7 @@ const setTemplateVariables = (entry, model) => {
637
669
  return model[dataModelKey] ?? match;
638
670
  });
639
671
  };
640
- const TEMPLATE_VARIABLE_MATCHER = /* @__PURE__ */ new RegExp(/{{(.*?)}}/g, "gi");
672
+ const TEMPLATE_VARIABLE_MATCHER = /\{\{(.*?)\}\}/giu;
641
673
  const hasTemplateVariable = (input) => {
642
674
  /**
643
675
  * TemplateVariableMatcher.test() is not used since the `RegExp` is stateful when the global is
@@ -685,7 +717,9 @@ const createFixCommand = (program) => {
685
717
  label: label$1("Fix code issues")
686
718
  });
687
719
  };
688
- const label$1 = (message) => `${message} 🚑`;
720
+ const label$1 = (message) => {
721
+ return `${message} 🚑`;
722
+ };
689
723
 
690
724
  //#endregion
691
725
  //#region src/commands/install.ts
@@ -705,7 +739,9 @@ const createInstallCommand = (program) => {
705
739
  label: label("Install `git.commit-msg` hook")
706
740
  });
707
741
  };
708
- const label = (message) => `${message} 📲`;
742
+ const label = (message) => {
743
+ return `${message} 📲`;
744
+ };
709
745
  const installGitHook = async (hook, content) => {
710
746
  const filename = resolveFromWorkingDirectory(`.git/hooks/${hook}`);
711
747
  await writeFile(filename, content);
@@ -760,8 +796,10 @@ const createReleaseCommand = (program) => {
760
796
  skip: ifNotEqualTo("publish")
761
797
  });
762
798
  };
763
- const ifNotEqualTo = (validOption) => (context) => {
764
- return !context[validOption];
799
+ const ifNotEqualTo = (validOption) => {
800
+ return (context) => {
801
+ return !context[validOption];
802
+ };
765
803
  };
766
804
 
767
805
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adbayb/stack",
3
- "version": "2.40.0-next-f8ad939",
3
+ "version": "2.40.0-next-6049a9b",
4
4
  "description": "My opinionated JavaScript-based toolchain",
5
5
  "keywords": [
6
6
  "development",