@adbayb/stack 0.0.0-next-2a0b6a2 → 0.0.0-next-1ee86fc

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.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { createRequire } from "node:module";
4
3
  import { join } from "node:path";
4
+ import { createRequire } from "node:module";
5
5
 
6
6
  const pkg = createRequire(import.meta.url)("../package.json");
7
7
 
@@ -1,28 +1,30 @@
1
1
  /* eslint-disable sort-keys-custom-order/object-keys */
2
- import { includeIgnoreFile } from "@eslint/compat";
3
- import { FlatCompat } from "@eslint/eslintrc";
4
- import vitestPlugin from "@vitest/eslint-plugin";
5
- import importPlugin from "eslint-plugin-import";
6
- import jestFormattingPlugin from "eslint-plugin-jest-formatting";
7
- import jsdocPlugin from "eslint-plugin-jsdoc";
8
- import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
9
- import reactPlugin from "eslint-plugin-react";
10
- import reactHooksPlugin from "eslint-plugin-react-hooks";
11
- import sonarjsPlugin from "eslint-plugin-sonarjs";
12
- import sortKeysCustomOrderPlugin from "eslint-plugin-sort-keys-custom-order";
13
- import globals from "globals";
14
- import { resolve } from "node:path";
15
2
  import { cwd } from "node:process";
3
+ import { join, resolve } from "node:path";
4
+ import { createRequire } from "node:module";
5
+
16
6
  import tseslint from "typescript-eslint";
7
+ import globals from "globals";
8
+ import sortKeysCustomOrderPlugin from "eslint-plugin-sort-keys-custom-order";
9
+ import sonarjsPlugin from "eslint-plugin-sonarjs";
10
+ import reactHooksPlugin from "eslint-plugin-react-hooks";
11
+ import reactPlugin from "eslint-plugin-react";
12
+ import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
13
+ import nodePlugin from "eslint-plugin-n";
14
+ import jsdocPlugin from "eslint-plugin-jsdoc";
15
+ import jestFormattingPlugin from "eslint-plugin-jest-formatting";
16
+ import importPlugin from "eslint-plugin-import-x";
17
+ import vitestPlugin from "@vitest/eslint-plugin";
18
+ import { FlatCompat } from "@eslint/eslintrc";
19
+ import { includeIgnoreFile } from "@eslint/compat";
17
20
 
18
21
  /**
19
22
  * TODO:
20
- * - Review Sonar rules: remove duplicated rules between SonarJS rules and ESLint/Import/TS rules.
21
23
  * - Review TS rules: attempt to include all rules from https://typescript-eslint.io/users/configs/#strict-type-checked and https://typescript-eslint.io/users/configs/#stylistic-type-checked ?
22
- * - Review import rules: at least, add a better behaviour for import order rules (node:* built-in imports should come first for example).
23
24
  * - Review JSDoc rules.
24
25
  */
25
26
 
27
+ const require = createRequire(import.meta.url);
26
28
  const CWD = cwd();
27
29
 
28
30
  export default tseslint.config(
@@ -54,22 +56,26 @@ export default tseslint.config(
54
56
  },
55
57
  },
56
58
  plugins: {
57
- import: importPlugin,
58
- jsdoc: jsdocPlugin,
59
- sonarjs: sonarjsPlugin,
59
+ "import-x": importPlugin,
60
+ "jsdoc": jsdocPlugin,
61
+ "n": nodePlugin,
62
+ "sonarjs": sonarjsPlugin,
60
63
  "sort-keys-custom-order": sortKeysCustomOrderPlugin,
61
64
  "@typescript-eslint": tseslint.plugin,
62
65
  },
63
66
  settings: {
64
- "import/resolver": {
67
+ "import-x/resolver": {
65
68
  node: true,
66
69
  typescript: true,
67
70
  },
71
+ "node": {
72
+ version: require(join(CWD, "package.json")).engines.node,
73
+ },
68
74
  },
69
75
  rules: {
70
76
  //#region eslint
71
77
  "constructor-super": "error",
72
- eqeqeq: "error",
78
+ "eqeqeq": "error",
73
79
  "for-direction": "error",
74
80
  "getter-return": "error",
75
81
  "no-alert": "error",
@@ -193,53 +199,56 @@ export default tseslint.config(
193
199
  "valid-typeof": "error",
194
200
  //#endregion
195
201
  //#region import
196
- "import/consistent-type-specifier-style": ["error", "prefer-top-level"],
197
- "import/export": "error",
198
- "import/first": "error",
199
- "import/newline-after-import": "error",
200
- "import/no-absolute-path": "error",
201
- "import/no-amd": "error",
202
- "import/no-commonjs": "error",
203
- "import/no-cycle": "error",
204
- "import/no-default-export": "error",
205
- "import/no-deprecated": "error",
206
- "import/no-duplicates": "error",
207
- "import/no-empty-named-blocks": "error",
208
- "import/no-extraneous-dependencies": "error",
209
- "import/no-import-module-exports": "error",
210
- "import/no-mutable-exports": "error",
211
- "import/no-named-as-default": "error",
212
- "import/no-namespace": "error",
213
- "import/no-relative-packages": "error",
214
- "import/no-self-import": "error",
215
- "import/no-unassigned-import": "error",
216
- "import/no-unused-modules": "error",
217
- "import/no-useless-path-segments": [
202
+ "import-x/consistent-type-specifier-style": ["error", "prefer-top-level"],
203
+ "import-x/export": "error",
204
+ "import-x/first": "error",
205
+ "import-x/newline-after-import": "error",
206
+ "import-x/no-absolute-path": "error",
207
+ "import-x/no-amd": "error",
208
+ "import-x/no-anonymous-default-export": "error",
209
+ "import-x/no-commonjs": "error",
210
+ "import-x/no-cycle": "error",
211
+ "import-x/no-default-export": "error",
212
+ "import-x/no-deprecated": "error",
213
+ "import-x/no-duplicates": "error",
214
+ "import-x/no-empty-named-blocks": "error",
215
+ "import-x/no-extraneous-dependencies": "error",
216
+ "import-x/no-import-module-exports": "error",
217
+ "import-x/no-mutable-exports": "error",
218
+ "import-x/no-named-default": "error",
219
+ "import-x/no-namespace": "error",
220
+ "import-x/no-relative-packages": "error",
221
+ "import-x/no-self-import": "error",
222
+ "import-x/no-unassigned-import": "error",
223
+ "import-x/no-unused-modules": "error",
224
+ "import-x/no-useless-path-segments": [
218
225
  "error",
219
226
  {
220
227
  commonjs: true,
221
228
  noUselessIndex: true,
222
229
  },
223
230
  ],
224
- "import/no-webpack-loader-syntax": "error",
225
- "import/order": [
231
+ "import-x/no-webpack-loader-syntax": "error",
232
+ "import-x/order": [
226
233
  "error",
227
234
  {
228
- alphabetize: {
235
+ "alphabetize": {
229
236
  caseInsensitive: false,
230
- order: "asc",
237
+ order: "desc",
231
238
  orderImportKind: "desc",
232
239
  },
233
- groups: [
234
- ["builtin", "external"],
240
+ "groups": [
241
+ "builtin",
242
+ "external",
235
243
  "internal",
244
+ ["parent", "sibling", "index"],
245
+ "object",
236
246
  "unknown",
237
- "parent",
238
- ["sibling", "index"],
239
247
  ],
240
248
  "newlines-between": "always",
241
249
  },
242
250
  ],
251
+ "import-x/unambiguous": "error",
243
252
  //#endregion
244
253
  //#region jsdoc
245
254
  "jsdoc/check-access": "error",
@@ -307,6 +316,37 @@ export default tseslint.config(
307
316
  "jsdoc/tag-lines": "error",
308
317
  "jsdoc/valid-types": "error",
309
318
  //#endregion
319
+ //#region n
320
+ "n/callback-return": "error",
321
+ "n/exports-style": ["error", "module.exports"],
322
+ "n/hashbang": "error",
323
+ "n/no-exports-assign": "error",
324
+ "n/no-path-concat": "error",
325
+ "n/no-process-env": [
326
+ "error",
327
+ {
328
+ allowedVariables: ["NODE_ENV"],
329
+ },
330
+ ],
331
+ "n/no-unpublished-bin": "error",
332
+ "n/no-unsupported-features/es-builtins": "error",
333
+ "n/no-unsupported-features/es-syntax": "error",
334
+ "n/no-unsupported-features/node-builtins": [
335
+ "error",
336
+ { allowExperimental: true },
337
+ ],
338
+ "n/prefer-global/buffer": ["error", "never"],
339
+ "n/prefer-global/console": ["error", "always"],
340
+ "n/prefer-global/process": ["error", "never"],
341
+ "n/prefer-global/text-decoder": ["error", "always"],
342
+ "n/prefer-global/text-encoder": ["error", "always"],
343
+ "n/prefer-global/url": ["error", "always"],
344
+ "n/prefer-global/url-search-params": ["error", "always"],
345
+ "n/prefer-node-protocol": "error",
346
+ "n/prefer-promises/dns": "error",
347
+ "n/prefer-promises/fs": "error",
348
+ "n/process-exit-as-throw": "error",
349
+ //#endregion
310
350
  //#region sonarjs
311
351
  "sonarjs/alt-text": "error",
312
352
  "sonarjs/anchor-has-content": "error",
@@ -548,7 +588,7 @@ export default tseslint.config(
548
588
  "@typescript-eslint/ban-ts-comment": [
549
589
  "error",
550
590
  {
551
- minimumDescriptionLength: 3,
591
+ "minimumDescriptionLength": 3,
552
592
  "ts-check": false,
553
593
  "ts-expect-error": "allow-with-description",
554
594
  "ts-ignore": "allow-with-description",
@@ -684,7 +724,7 @@ export default tseslint.config(
684
724
  {
685
725
  files: ["**/*.{jsx,tsx}"],
686
726
  plugins: {
687
- react: reactPlugin,
727
+ "react": reactPlugin,
688
728
  "react-hooks": reactHooksPlugin,
689
729
  },
690
730
  settings: {
@@ -758,7 +798,7 @@ export default tseslint.config(
758
798
  ],
759
799
  plugins: {
760
800
  "jest-formatting": jestFormattingPlugin,
761
- vitest: vitestPlugin,
801
+ "vitest": vitestPlugin,
762
802
  },
763
803
  rules: {
764
804
  "jest-formatting/padding-around-all": "error",
@@ -828,7 +868,8 @@ export default tseslint.config(
828
868
  "**/*.test.{js,ts,jsx,tsx,cjs,cts,mjs,mts}",
829
869
  ],
830
870
  rules: {
831
- "import/no-default-export": "off",
871
+ "import-x/no-anonymous-default-export": "off",
872
+ "import-x/no-default-export": "off",
832
873
  "sonarjs/sonar-no-magic-numbers": "off",
833
874
  },
834
875
  },
@@ -13,7 +13,7 @@ export default {
13
13
  plugins: [],
14
14
  printWidth: 80,
15
15
  proseWrap: "preserve",
16
- quoteProps: "as-needed",
16
+ quoteProps: "consistent",
17
17
  requirePragma: false,
18
18
  semi: true,
19
19
  singleAttributePerLine: true,
@@ -7,8 +7,8 @@
7
7
  "allowUnreachableCode": false,
8
8
  "allowUnusedLabels": false,
9
9
  "checkJs": false,
10
- "composite": true,
11
10
  "exactOptionalPropertyTypes": true,
11
+ "incremental": true,
12
12
  "lib": ["ESNext"],
13
13
  "module": "Preserve",
14
14
  "noEmit": true,
package/dist/index.mjs CHANGED
@@ -1,10 +1,14 @@
1
1
  import { helpers, termost } from 'termost';
2
- import { existsSync, readdirSync, cpSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
3
- import { createRequire } from 'node:module';
4
- import { resolve, join } from 'node:path';
5
2
  import process from 'node:process';
3
+ import { resolve, join } from 'node:path';
4
+ import { createRequire } from 'node:module';
5
+ import { existsSync, cpSync, readFileSync, renameSync, writeFileSync, readdirSync } from 'node:fs';
6
+ import { writeFile, chmod, mkdir, symlink } from 'node:fs/promises';
6
7
  import { fdir } from 'fdir';
7
- import { mkdir, symlink, writeFile, chmod } from 'node:fs/promises';
8
+
9
+ var version = "0.0.0-next-1ee86fc";
10
+
11
+ const VERSION = version;
8
12
 
9
13
  const require = createRequire(import.meta.url);
10
14
  /**
@@ -210,126 +214,126 @@ const PRETTIER_IGNORE_FILES = [
210
214
  "pnpm-lock.yaml"
211
215
  ];
212
216
 
213
- const createBuildCommand = (program)=>{
217
+ const createWatchCommand = (program)=>{
214
218
  program.command({
215
- name: "build",
216
- description: "Build the project in production mode"
219
+ name: "watch",
220
+ description: "Build and start the project in development mode"
217
221
  }).task({
218
222
  async handler () {
219
- await turbo("build");
223
+ await turbo("watch");
220
224
  }
221
225
  });
222
226
  };
223
227
 
224
- const onlyValues = [
225
- "commit",
226
- "lint",
227
- "type"
228
- ];
229
- const createCheckCommand = (program)=>{
228
+ const createTestCommand = (program)=>{
230
229
  program.command({
231
- name: "check",
232
- description: "Check code health (static analysis)"
233
- }).option({
234
- key: "only",
235
- name: "only",
236
- description: `Run only one specified task (accepted value: ${onlyValues.join(", ")})`,
237
- defaultValue: undefined
230
+ name: "test",
231
+ description: "Test the code execution"
238
232
  }).task({
239
- label: label$4("Preparing the project"),
240
233
  async handler () {
241
- await turbo("build", {
242
- hasLiveOutput: false
243
- });
244
- },
245
- skip ({ only }) {
246
- return only === "commit"; // No need to build if only commitlint is run
234
+ await turbo("test");
235
+ }
236
+ });
237
+ };
238
+
239
+ const createStartCommand = (program)=>{
240
+ program.command({
241
+ name: "start",
242
+ description: "Start the project in production mode"
243
+ }).task({
244
+ async handler () {
245
+ await turbo("start");
247
246
  }
247
+ });
248
+ };
249
+
250
+ const createReleaseCommand = (program)=>{
251
+ program.command({
252
+ name: "release",
253
+ description: "Log, version, and publish package(s)"
254
+ }).option({
255
+ key: "log",
256
+ name: "log",
257
+ description: "Add a new changelog entry"
258
+ }).option({
259
+ key: "tag",
260
+ name: "tag",
261
+ description: "Bump the package(s) version"
262
+ }).option({
263
+ key: "publish",
264
+ name: "publish",
265
+ description: "Publish package(s) to the registry"
248
266
  }).task({
249
- label: label$4("Checking linters"),
250
- async handler (_, argv) {
251
- const filenames = argv.operands;
252
- await checkLints(filenames);
267
+ async handler () {
268
+ helpers.message("New changelog entry\n");
269
+ await changeset("changeset");
253
270
  },
254
- skip: ifOnlyDefinedAndNotEqualTo("lint")
271
+ skip: ifNotEqualTo("log")
255
272
  }).task({
256
- label: label$4("Checking types"),
257
273
  async handler () {
258
- await checkTypes();
274
+ helpers.message("Bumping the package(s) version\n");
275
+ await changeset("changeset version && pnpm install --no-frozen-lockfile");
259
276
  },
260
- skip (context, argv) {
261
- return ifOnlyDefinedAndNotEqualTo("type")(context) || !hasDependency("typescript") || // For now, skip type-checking if some files are passed down
262
- // @see: https://github.com/microsoft/TypeScript/issues/27379
263
- argv.operands.length > 0;
264
- }
277
+ skip: ifNotEqualTo("tag")
265
278
  }).task({
266
- label: label$4("Checking commit"),
267
279
  async handler () {
268
- await checkCommit();
280
+ helpers.message("Publishing package(s) to the registry\n");
281
+ await changeset("stack build && pnpm changeset publish");
269
282
  },
270
- skip ({ only }) {
271
- return only !== "commit";
272
- }
283
+ skip: ifNotEqualTo("publish")
273
284
  });
274
285
  };
275
- const label$4 = (message)=>`${message} 🧐`;
276
- const ifOnlyDefinedAndNotEqualTo = (only)=>(context)=>{
277
- return context.only !== undefined && context.only !== only;
286
+ const ifNotEqualTo = (validOption)=>(context)=>{
287
+ return !context[validOption];
278
288
  };
279
289
 
280
- const createCleanCommand = (program)=>{
290
+ const createInstallCommand = (program)=>{
281
291
  program.command({
282
- name: "clean",
283
- description: "Clean the project"
292
+ name: "install",
293
+ description: "Setup initial requirements"
284
294
  }).task({
285
- key: "files",
286
- label: label$3("Retrieving removable assets"),
295
+ label: label$4("Installing `git.pre-commit` hook"),
287
296
  async handler () {
288
- const cachePath = "node_modules/.cache";
289
- const files = await retrieveIgnoredFiles();
290
- if (isDirectoryExistAndNotEmpty(resolveFromProjectDirectory(cachePath))) {
291
- files.push(cachePath);
292
- }
293
- return files;
297
+ await installGitHook("pre-commit", `${getStackCommand("fix $(git status --porcelain | awk 'BEGIN{ ORS=\" \" } { print $2 }')", false)} && git add -A`);
294
298
  }
295
299
  }).task({
296
- label ({ files }) {
297
- return files.length > 0 ? label$3("Cleaning assets") : "Already clean ✨";
298
- },
299
- async handler ({ files }) {
300
- if (files.length === 0) return;
301
- await cleanFiles(files);
300
+ label: label$4("Installing `git.commit-msg` hook"),
301
+ async handler () {
302
+ await installGitHook("commit-msg", `${getStackCommand("check --only commit", false)}`);
302
303
  }
304
+ });
305
+ };
306
+ const label$4 = (message)=>`${message} 📲`;
307
+ const installGitHook = async (hook, content)=>{
308
+ const filename = resolveFromProjectDirectory(`.git/hooks/${hook}`);
309
+ await writeFile(filename, content);
310
+ return chmod(filename, "0755");
311
+ };
312
+
313
+ const createFixCommand = (program)=>{
314
+ program.command({
315
+ name: "fix",
316
+ description: "Fix auto-fixable issues"
303
317
  }).task({
304
- handler ({ files }) {
305
- helpers.message(`Removed assets: ${files.join(", ")}\n`, {
306
- type: "information"
318
+ label: label$3("Preparing the project"),
319
+ async handler () {
320
+ await turbo("build", {
321
+ hasLiveOutput: false
307
322
  });
308
- },
309
- skip ({ files }) {
310
- return files.length === 0;
323
+ }
324
+ }).task({
325
+ label: label$3("Fixing lints"),
326
+ async handler (_, argv) {
327
+ await fixLints(argv.operands);
328
+ }
329
+ }).task({
330
+ label: label$3("Fixing formatting"),
331
+ async handler (_, argv) {
332
+ await fixFormatting(argv.operands);
311
333
  }
312
334
  });
313
335
  };
314
- const label$3 = (message)=>`${message} 🧹`;
315
- const cleanFiles = async (files)=>{
316
- return helpers.exec(`rm -rf ${files.join(" ")}`);
317
- };
318
- const isDirectoryExistAndNotEmpty = (path)=>{
319
- return existsSync(path) && readdirSync(path).length > 0;
320
- };
321
- const retrieveIgnoredFiles = async ()=>{
322
- const rawFiles = await helpers.exec(`git clean -fdXn | grep -v '${PRESERVE_FILES.join("\\|")}' | cut -c 14-`);
323
- return rawFiles.split(/\n/).filter(Boolean);
324
- };
325
- const PRESERVE_FILES = [
326
- "node_modules",
327
- ".turbo"
328
- ];
329
-
330
- var version = "0.0.0-next-2a0b6a2";
331
-
332
- const VERSION = version;
336
+ const label$3 = (message)=>`${message} 🚑`;
333
337
 
334
338
  const createCreateCommand = (program)=>{
335
339
  program.command({
@@ -507,123 +511,119 @@ const label$2 = (message)=>`${message} 🔨`;
507
511
  });
508
512
  };
509
513
 
510
- const createFixCommand = (program)=>{
514
+ const createCleanCommand = (program)=>{
511
515
  program.command({
512
- name: "fix",
513
- description: "Fix auto-fixable issues"
516
+ name: "clean",
517
+ description: "Clean the project"
514
518
  }).task({
515
- label: label$1("Preparing the project"),
519
+ key: "files",
520
+ label: label$1("Retrieving removable assets"),
516
521
  async handler () {
517
- await turbo("build", {
518
- hasLiveOutput: false
519
- });
522
+ const cachePath = "node_modules/.cache";
523
+ const files = await retrieveIgnoredFiles();
524
+ if (isDirectoryExistAndNotEmpty(resolveFromProjectDirectory(cachePath))) {
525
+ files.push(cachePath);
526
+ }
527
+ return files;
520
528
  }
521
529
  }).task({
522
- label: label$1("Fixing lints"),
523
- async handler (_, argv) {
524
- await fixLints(argv.operands);
530
+ label ({ files }) {
531
+ return files.length > 0 ? label$1("Cleaning assets") : "Already clean ✨";
532
+ },
533
+ async handler ({ files }) {
534
+ if (files.length === 0) return;
535
+ await cleanFiles(files);
525
536
  }
526
537
  }).task({
527
- label: label$1("Fixing formatting"),
528
- async handler (_, argv) {
529
- await fixFormatting(argv.operands);
538
+ handler ({ files }) {
539
+ helpers.message(`Removed assets: ${files.join(", ")}\n`, {
540
+ type: "information"
541
+ });
542
+ },
543
+ skip ({ files }) {
544
+ return files.length === 0;
530
545
  }
531
546
  });
532
547
  };
533
- const label$1 = (message)=>`${message} 🚑`;
534
-
535
- const createInstallCommand = (program)=>{
536
- program.command({
537
- name: "install",
538
- description: "Setup initial requirements"
539
- }).task({
540
- label: label("Installing `git.pre-commit` hook"),
541
- async handler () {
542
- await installGitHook("pre-commit", `${getStackCommand("fix $(git status --porcelain | awk 'BEGIN{ ORS=\" \" } { print $2 }')", false)} && git add -A`);
543
- }
544
- }).task({
545
- label: label("Installing `git.commit-msg` hook"),
546
- async handler () {
547
- await installGitHook("commit-msg", `${getStackCommand("check --only commit", false)}`);
548
- }
549
- });
548
+ const label$1 = (message)=>`${message} 🧹`;
549
+ const cleanFiles = async (files)=>{
550
+ return helpers.exec(`rm -rf ${files.join(" ")}`);
550
551
  };
551
- const label = (message)=>`${message} 📲`;
552
- const installGitHook = async (hook, content)=>{
553
- const filename = resolveFromProjectDirectory(`.git/hooks/${hook}`);
554
- await writeFile(filename, content);
555
- return chmod(filename, "0755");
552
+ const isDirectoryExistAndNotEmpty = (path)=>{
553
+ return existsSync(path) && readdirSync(path).length > 0;
554
+ };
555
+ const retrieveIgnoredFiles = async ()=>{
556
+ const rawFiles = await helpers.exec(`git clean -fdXn | grep -v '${PRESERVE_FILES.join("\\|")}' | cut -c 14-`);
557
+ return rawFiles.split(/\n/).filter(Boolean);
556
558
  };
559
+ const PRESERVE_FILES = [
560
+ "node_modules",
561
+ ".turbo"
562
+ ];
557
563
 
558
- const createReleaseCommand = (program)=>{
564
+ const onlyValues = [
565
+ "commit",
566
+ "lint",
567
+ "type"
568
+ ];
569
+ const createCheckCommand = (program)=>{
559
570
  program.command({
560
- name: "release",
561
- description: "Log, version, and publish package(s)"
562
- }).option({
563
- key: "log",
564
- name: "log",
565
- description: "Add a new changelog entry"
566
- }).option({
567
- key: "tag",
568
- name: "tag",
569
- description: "Bump the package(s) version"
571
+ name: "check",
572
+ description: "Check code health (static analysis)"
570
573
  }).option({
571
- key: "publish",
572
- name: "publish",
573
- description: "Publish package(s) to the registry"
574
+ key: "only",
575
+ name: "only",
576
+ description: `Run only one specified task (accepted value: ${onlyValues.join(", ")})`,
577
+ defaultValue: undefined
574
578
  }).task({
579
+ label: label("Preparing the project"),
575
580
  async handler () {
576
- helpers.message("New changelog entry\n");
577
- await changeset("changeset");
581
+ await turbo("build", {
582
+ hasLiveOutput: false
583
+ });
578
584
  },
579
- skip: ifNotEqualTo("log")
585
+ skip ({ only }) {
586
+ return only === "commit"; // No need to build if only commitlint is run
587
+ }
580
588
  }).task({
581
- async handler () {
582
- helpers.message("Bumping the package(s) version\n");
583
- await changeset("changeset version && pnpm install --no-frozen-lockfile");
589
+ label: label("Checking linters"),
590
+ async handler (_, argv) {
591
+ const filenames = argv.operands;
592
+ await checkLints(filenames);
584
593
  },
585
- skip: ifNotEqualTo("tag")
594
+ skip: ifOnlyDefinedAndNotEqualTo("lint")
586
595
  }).task({
596
+ label: label("Checking types"),
587
597
  async handler () {
588
- helpers.message("Publishing package(s) to the registry\n");
589
- await changeset("stack build && pnpm changeset publish");
598
+ await checkTypes();
590
599
  },
591
- skip: ifNotEqualTo("publish")
592
- });
593
- };
594
- const ifNotEqualTo = (validOption)=>(context)=>{
595
- return !context[validOption];
596
- };
597
-
598
- const createStartCommand = (program)=>{
599
- program.command({
600
- name: "start",
601
- description: "Start the project in production mode"
602
- }).task({
603
- async handler () {
604
- await turbo("start");
600
+ skip (context, argv) {
601
+ return ifOnlyDefinedAndNotEqualTo("type")(context) || !hasDependency("typescript") || // For now, skip type-checking if some files are passed down
602
+ // @see: https://github.com/microsoft/TypeScript/issues/27379
603
+ argv.operands.length > 0;
605
604
  }
606
- });
607
- };
608
-
609
- const createTestCommand = (program)=>{
610
- program.command({
611
- name: "test",
612
- description: "Test the code execution"
613
605
  }).task({
606
+ label: label("Checking commit"),
614
607
  async handler () {
615
- await turbo("test");
608
+ await checkCommit();
609
+ },
610
+ skip ({ only }) {
611
+ return only !== "commit";
616
612
  }
617
613
  });
618
614
  };
615
+ const label = (message)=>`${message} 🧐`;
616
+ const ifOnlyDefinedAndNotEqualTo = (only)=>(context)=>{
617
+ return context.only !== undefined && context.only !== only;
618
+ };
619
619
 
620
- const createWatchCommand = (program)=>{
620
+ const createBuildCommand = (program)=>{
621
621
  program.command({
622
- name: "watch",
623
- description: "Build and start the project in development mode"
622
+ name: "build",
623
+ description: "Build the project in production mode"
624
624
  }).task({
625
625
  async handler () {
626
- await turbo("watch");
626
+ await turbo("build");
627
627
  }
628
628
  });
629
629
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adbayb/stack",
3
- "version": "0.0.0-next-2a0b6a2",
3
+ "version": "0.0.0-next-1ee86fc",
4
4
  "description": "My opinionated JavaScript-based toolchain",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -55,24 +55,25 @@
55
55
  "@eslint/compat": "^1.2.1",
56
56
  "@eslint/eslintrc": "^3.1.0",
57
57
  "@vitest/eslint-plugin": "^1.1.7",
58
- "eslint": "^9.13.0",
59
- "eslint-plugin-react": "^7.37.2",
60
- "globals": "^15.11.0",
61
- "typescript-eslint": "^8.11.0",
62
58
  "eslint-config-prettier": "^9.1.0",
63
59
  "eslint-import-resolver-typescript": "^3.6.3",
64
- "eslint-plugin-import": "^2.31.0",
60
+ "eslint-plugin-import-x": "^4.3.1",
65
61
  "eslint-plugin-jest-formatting": "^3.1.0",
66
62
  "eslint-plugin-jsdoc": "^50.4.3",
67
63
  "eslint-plugin-mdx": "^3.1.5",
64
+ "eslint-plugin-n": "^17.11.1",
68
65
  "eslint-plugin-prettier": "^5.2.1",
69
66
  "eslint-plugin-react-hooks": "^5.0.0",
67
+ "eslint-plugin-react": "^7.37.2",
70
68
  "eslint-plugin-sonarjs": "^2.0.4",
71
69
  "eslint-plugin-sort-keys-custom-order": "^2.2.0",
70
+ "eslint": "^9.13.0",
72
71
  "fdir": "^6.4.2",
72
+ "globals": "^15.11.0",
73
73
  "prettier": "^3.3.3",
74
74
  "termost": "^0.17.0",
75
75
  "turbo": "^2.2.3",
76
+ "typescript-eslint": "^8.11.0",
76
77
  "typescript": "^5.6.3"
77
78
  },
78
79
  "scripts": {
@@ -38,9 +38,10 @@ jobs:
38
38
  - name: Install dependencies
39
39
  run: pnpm install --frozen-lockfile
40
40
  - name: Publish pre-release version(s)
41
+ if: "!contains(github.event.head_commit.message, 'chore: release package(s)')"
41
42
  run: |
42
- pnpm --recursive exec pnpm version "$(pnpm show ./ version)-next-${GITHUB_SHA::7}"
43
- pnpm --recursive exec pnpm publish --tag next --no-git-checks
43
+ pnpm --filter=\!@examples/\* --recursive exec pnpm version "$(pnpm show ./ version)-next-${GITHUB_SHA::7}"
44
+ pnpm --filter=\!@examples/\* --recursive exec pnpm publish --tag next --no-git-checks
44
45
  - name: Prepare or Publish stable version(s)
45
46
  uses: changesets/action@v1
46
47
  with:
@@ -38,9 +38,10 @@ jobs:
38
38
  - name: Install dependencies
39
39
  run: pnpm install --frozen-lockfile
40
40
  - name: Publish pre-release version(s)
41
+ if: "!contains(github.event.head_commit.message, 'chore: release package(s)')"
41
42
  run: |
42
- pnpm --recursive exec pnpm version "$(pnpm show ./ version)-next-${GITHUB_SHA::7}"
43
- pnpm --recursive exec pnpm publish --tag next --no-git-checks
43
+ pnpm --filter=\!@examples/\* --recursive exec pnpm version "$(pnpm show ./ version)-next-${GITHUB_SHA::7}"
44
+ pnpm --filter=\!@examples/\* --recursive exec pnpm publish --tag next --no-git-checks
44
45
  - name: Prepare or Publish stable version(s)
45
46
  uses: changesets/action@v1
46
47
  with: