@adbayb/stack 2.38.1 → 2.39.0-next-00b7c69
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/configs/eslint/presets/sonar.js +0 -1
- package/configs/eslint/presets/unicorn.js +58 -6
- package/dist/index.js +152 -80
- package/package.json +7 -8
- package/templates/{single-project/package.json.tmpl → multi-projects/package.json} +2 -2
- package/templates/multi-projects/{pnpm-workspace.yaml.tmpl → pnpm-workspace.yaml} +6 -0
- package/templates/{multi-projects/package.json.tmpl → single-project/package.json} +2 -2
- package/templates/single-project/{pnpm-workspace.yaml.tmpl → pnpm-workspace.yaml} +6 -0
- package/templates/multi-projects/.npmrc.tmpl +0 -1
- package/templates/single-project/.npmrc.tmpl +0 -1
- /package/templates/multi-projects/.changeset/{config.json.tmpl → config.json} +0 -0
- /package/templates/multi-projects/.changeset/{welcome.md.tmpl → welcome.md} +0 -0
- /package/templates/multi-projects/.github/{PULL_REQUEST_TEMPLATE.md.tmpl → PULL_REQUEST_TEMPLATE.md} +0 -0
- /package/templates/multi-projects/{.nvmrc.tmpl → .nvmrc} +0 -0
- /package/templates/multi-projects/{CONTRIBUTING.md.tmpl → CONTRIBUTING.md} +0 -0
- /package/templates/multi-projects/{LICENSE.tmpl → LICENSE} +0 -0
- /package/templates/multi-projects/examples/default/{package.json.tmpl → package.json} +0 -0
- /package/templates/multi-projects/examples/default/src/{index.ts.tmpl → index.ts} +0 -0
- /package/templates/multi-projects/{.gitignore.tmpl → gitignore} +0 -0
- /package/templates/multi-projects/libraries/{{projectName}}/{README.md.tmpl → README.md} +0 -0
- /package/templates/multi-projects/libraries/{{projectName}}/{package.json.tmpl → package.json} +0 -0
- /package/templates/multi-projects/libraries/{{projectName}}/src/{index.test.ts.tmpl → index.test.ts} +0 -0
- /package/templates/single-project/.changeset/{config.json.tmpl → config.json} +0 -0
- /package/templates/single-project/.changeset/{welcome.md.tmpl → welcome.md} +0 -0
- /package/templates/single-project/.github/{PULL_REQUEST_TEMPLATE.md.tmpl → PULL_REQUEST_TEMPLATE.md} +0 -0
- /package/templates/single-project/{.nvmrc.tmpl → .nvmrc} +0 -0
- /package/templates/single-project/{CONTRIBUTING.md.tmpl → CONTRIBUTING.md} +0 -0
- /package/templates/single-project/{LICENSE.tmpl → LICENSE} +0 -0
- /package/templates/single-project/examples/default/{package.json.tmpl → package.json} +0 -0
- /package/templates/single-project/examples/default/src/{index.ts.tmpl → index.ts} +0 -0
- /package/templates/single-project/{.gitignore.tmpl → gitignore} +0 -0
- /package/templates/single-project/{{projectName}}/{README.md.tmpl → README.md} +0 -0
- /package/templates/single-project/{{projectName}}/{package.json.tmpl → package.json} +0 -0
- /package/templates/single-project/{{projectName}}/src/{index.test.ts.tmpl → index.test.ts} +0 -0
|
@@ -18,7 +18,6 @@ export const config = createConfig(
|
|
|
18
18
|
"sonarjs/bitwise-operators": "error",
|
|
19
19
|
"sonarjs/bool-param-default": "error",
|
|
20
20
|
"sonarjs/call-argument-line": "error",
|
|
21
|
-
"sonarjs/certificate-transparency": "error",
|
|
22
21
|
"sonarjs/class-name": "error",
|
|
23
22
|
"sonarjs/class-prototype": "error",
|
|
24
23
|
"sonarjs/code-eval": "error",
|
|
@@ -17,8 +17,10 @@ export const config = createConfig({
|
|
|
17
17
|
name: "error",
|
|
18
18
|
},
|
|
19
19
|
],
|
|
20
|
+
"unicorn/consistent-boolean-name": "error",
|
|
20
21
|
"unicorn/consistent-class-member-order": "error",
|
|
21
22
|
"unicorn/consistent-compound-words": "error",
|
|
23
|
+
"unicorn/consistent-conditional-object-spread": "error",
|
|
22
24
|
"unicorn/consistent-empty-array-spread": "error",
|
|
23
25
|
"unicorn/consistent-existence-index-check": "error",
|
|
24
26
|
"unicorn/consistent-export-decorator-position": "error",
|
|
@@ -43,62 +45,103 @@ export const config = createConfig({
|
|
|
43
45
|
},
|
|
44
46
|
],
|
|
45
47
|
"unicorn/isolated-functions": "error",
|
|
48
|
+
"unicorn/logical-assignment-operators": "error",
|
|
46
49
|
"unicorn/max-nested-calls": ["error", { max: 3 }],
|
|
50
|
+
"unicorn/name-replacements": [
|
|
51
|
+
"error",
|
|
52
|
+
{
|
|
53
|
+
replacements: {
|
|
54
|
+
application: false,
|
|
55
|
+
applications: false,
|
|
56
|
+
prop: false,
|
|
57
|
+
props: false,
|
|
58
|
+
ref: false,
|
|
59
|
+
refs: false,
|
|
60
|
+
repositories: false,
|
|
61
|
+
repository: false,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
],
|
|
47
65
|
"unicorn/new-for-builtins": "error",
|
|
48
66
|
"unicorn/no-abusive-eslint-disable": "error",
|
|
67
|
+
"unicorn/no-accidental-bitwise-operator": "error",
|
|
49
68
|
"unicorn/no-array-callback-reference": "error",
|
|
69
|
+
"unicorn/no-array-concat-in-loop": "error",
|
|
50
70
|
"unicorn/no-array-reverse": "error",
|
|
51
71
|
"unicorn/no-array-sort": "error",
|
|
72
|
+
"unicorn/no-array-sort-for-min-max": "error",
|
|
73
|
+
"unicorn/no-array-splice": "error",
|
|
52
74
|
"unicorn/no-await-expression-member": "error",
|
|
53
75
|
"unicorn/no-await-in-promise-methods": "error",
|
|
76
|
+
"unicorn/no-chained-comparison": "error",
|
|
54
77
|
"unicorn/no-console-spaces": "error",
|
|
78
|
+
"unicorn/no-constant-zero-expression": "error",
|
|
55
79
|
"unicorn/no-declarations-before-early-exit": "error",
|
|
56
80
|
"unicorn/no-document-cookie": "error",
|
|
81
|
+
"unicorn/no-double-comparison": "error",
|
|
82
|
+
"unicorn/no-duplicate-if-branches": "error",
|
|
83
|
+
"unicorn/no-duplicate-logical-operands": "error",
|
|
57
84
|
"unicorn/no-duplicate-loops": "error",
|
|
58
85
|
"unicorn/no-empty-file": "error",
|
|
59
86
|
"unicorn/no-error-property-assignment": "error",
|
|
60
87
|
"unicorn/no-for-loop": "error",
|
|
61
88
|
"unicorn/no-immediate-mutation": "error",
|
|
89
|
+
"unicorn/no-impossible-length-comparison": "error",
|
|
62
90
|
"unicorn/no-incorrect-template-string-interpolation": "error",
|
|
63
91
|
"unicorn/no-instanceof-array": "error",
|
|
92
|
+
"unicorn/no-invalid-character-comparison": "error",
|
|
64
93
|
"unicorn/no-invalid-fetch-options": "error",
|
|
65
94
|
"unicorn/no-invalid-remove-event-listener": "error",
|
|
66
95
|
"unicorn/no-lonely-if": "error",
|
|
96
|
+
"unicorn/no-loop-iterable-mutation": "error",
|
|
67
97
|
"unicorn/no-mismatched-map-key": "error",
|
|
98
|
+
"unicorn/no-misrefactored-assignment": "error",
|
|
68
99
|
"unicorn/no-negated-array-predicate": "error",
|
|
69
100
|
"unicorn/no-negated-comparison": "error",
|
|
70
101
|
"unicorn/no-negated-condition": "error",
|
|
71
102
|
"unicorn/no-nested-ternary": "error",
|
|
72
103
|
"unicorn/no-new-buffer": "error",
|
|
104
|
+
"unicorn/no-non-function-verb-prefix": "error",
|
|
73
105
|
"unicorn/no-object-as-default-parameter": "error",
|
|
74
106
|
"unicorn/no-object-methods-with-collections": "error",
|
|
75
107
|
"unicorn/no-process-exit": "error",
|
|
76
108
|
"unicorn/no-redundant-comparison": "error",
|
|
77
109
|
"unicorn/no-return-array-push": "error",
|
|
110
|
+
"unicorn/no-selector-as-dom-name": "error",
|
|
78
111
|
"unicorn/no-single-promise-in-promise-methods": "error",
|
|
79
112
|
"unicorn/no-static-only-class": "error",
|
|
80
113
|
"unicorn/no-subtraction-comparison": "error",
|
|
114
|
+
"unicorn/no-top-level-assignment-in-function": "error",
|
|
81
115
|
"unicorn/no-typeof-undefined": "error",
|
|
116
|
+
"unicorn/no-uncalled-method": "error",
|
|
82
117
|
"unicorn/no-unnecessary-array-flat-depth": "error",
|
|
83
118
|
"unicorn/no-unnecessary-array-splice-count": "error",
|
|
119
|
+
"unicorn/no-unnecessary-boolean-comparison": "error",
|
|
84
120
|
"unicorn/no-unnecessary-global-this": "error",
|
|
85
121
|
"unicorn/no-unnecessary-polyfills": "error",
|
|
86
122
|
"unicorn/no-unnecessary-slice-end": "error",
|
|
87
123
|
"unicorn/no-unnecessary-splice": "error",
|
|
88
124
|
"unicorn/no-unreadable-array-destructuring": "error",
|
|
125
|
+
"unicorn/no-unreadable-for-of-expression": "error",
|
|
89
126
|
"unicorn/no-unreadable-iife": "error",
|
|
90
127
|
"unicorn/no-unreadable-object-destructuring": "error",
|
|
91
128
|
"unicorn/no-unsafe-buffer-conversion": "error",
|
|
92
129
|
"unicorn/no-unsafe-string-replacement": "error",
|
|
93
130
|
"unicorn/no-unused-properties": "error",
|
|
94
131
|
"unicorn/no-useless-boolean-cast": "error",
|
|
132
|
+
"unicorn/no-useless-coercion": "error",
|
|
95
133
|
"unicorn/no-useless-collection-argument": "error",
|
|
134
|
+
"unicorn/no-useless-compound-assignment": "error",
|
|
96
135
|
"unicorn/no-useless-concat": "error",
|
|
136
|
+
"unicorn/no-useless-continue": "error",
|
|
137
|
+
"unicorn/no-useless-delete-check": "error",
|
|
97
138
|
"unicorn/no-useless-else": "error",
|
|
98
139
|
"unicorn/no-useless-error-capture-stack-trace": "error",
|
|
99
140
|
"unicorn/no-useless-fallback-in-spread": "error",
|
|
100
141
|
"unicorn/no-useless-iterator-to-array": "error",
|
|
101
142
|
"unicorn/no-useless-length-check": "error",
|
|
143
|
+
"unicorn/no-useless-logical-operand": "error",
|
|
144
|
+
"unicorn/no-useless-override": "error",
|
|
102
145
|
"unicorn/no-useless-promise-resolve-reject": "error",
|
|
103
146
|
"unicorn/no-useless-recursion": "error",
|
|
104
147
|
"unicorn/no-useless-spread": "error",
|
|
@@ -106,6 +149,7 @@ export const config = createConfig({
|
|
|
106
149
|
"unicorn/no-zero-fractions": "error",
|
|
107
150
|
"unicorn/number-literal-case": "error",
|
|
108
151
|
"unicorn/numeric-separators-style": "error",
|
|
152
|
+
"unicorn/operator-assignment": "error",
|
|
109
153
|
"unicorn/prefer-add-event-listener": "error",
|
|
110
154
|
"unicorn/prefer-add-event-listener-options": "error",
|
|
111
155
|
"unicorn/prefer-array-find": "error",
|
|
@@ -113,24 +157,32 @@ export const config = createConfig({
|
|
|
113
157
|
"unicorn/prefer-array-flat-map": "error",
|
|
114
158
|
"unicorn/prefer-array-from-map": "error",
|
|
115
159
|
"unicorn/prefer-array-index-of": "error",
|
|
160
|
+
"unicorn/prefer-array-iterable-methods": "error",
|
|
161
|
+
"unicorn/prefer-array-slice": "error",
|
|
116
162
|
"unicorn/prefer-array-some": "error",
|
|
117
163
|
"unicorn/prefer-at": "error",
|
|
118
164
|
"unicorn/prefer-await": "error",
|
|
119
165
|
"unicorn/prefer-bigint-literals": "error",
|
|
120
166
|
"unicorn/prefer-blob-reading-methods": "error",
|
|
167
|
+
"unicorn/prefer-boolean-return": "error",
|
|
121
168
|
"unicorn/prefer-class-fields": "error",
|
|
122
169
|
"unicorn/prefer-classlist-toggle": "error",
|
|
123
170
|
"unicorn/prefer-code-point": "error",
|
|
171
|
+
"unicorn/prefer-continue": "error",
|
|
124
172
|
"unicorn/prefer-date-now": "error",
|
|
125
173
|
"unicorn/prefer-direct-iteration": "error",
|
|
126
174
|
"unicorn/prefer-dom-node-append": "error",
|
|
127
175
|
"unicorn/prefer-dom-node-remove": "error",
|
|
128
176
|
"unicorn/prefer-dom-node-text-content": "error",
|
|
129
177
|
"unicorn/prefer-early-return": "error",
|
|
178
|
+
"unicorn/prefer-else-if": "error",
|
|
130
179
|
"unicorn/prefer-event-target": "error",
|
|
131
180
|
"unicorn/prefer-export-from": ["error", { checkUsedVariables: false }],
|
|
181
|
+
"unicorn/prefer-flat-math-min-max": "error",
|
|
132
182
|
"unicorn/prefer-global-number-constants": "error",
|
|
133
183
|
"unicorn/prefer-global-this": "error",
|
|
184
|
+
"unicorn/prefer-has-check": "error",
|
|
185
|
+
"unicorn/prefer-hoisting-branch-code": "error",
|
|
134
186
|
"unicorn/prefer-identifier-import-export-specifiers": "error",
|
|
135
187
|
"unicorn/prefer-import-meta-properties": "error",
|
|
136
188
|
"unicorn/prefer-includes": "error",
|
|
@@ -138,6 +190,8 @@ export const config = createConfig({
|
|
|
138
190
|
"unicorn/prefer-keyboard-event-key": "error",
|
|
139
191
|
"unicorn/prefer-location-assign": "error",
|
|
140
192
|
"unicorn/prefer-logical-operator-over-ternary": "error",
|
|
193
|
+
"unicorn/prefer-map-from-entries": "error",
|
|
194
|
+
"unicorn/prefer-math-constants": "error",
|
|
141
195
|
"unicorn/prefer-math-min-max": "error",
|
|
142
196
|
"unicorn/prefer-math-trunc": "error",
|
|
143
197
|
"unicorn/prefer-minimal-ternary": "error",
|
|
@@ -159,6 +213,7 @@ export const config = createConfig({
|
|
|
159
213
|
"unicorn/prefer-prototype-methods": "error",
|
|
160
214
|
"unicorn/prefer-query-selector": "error",
|
|
161
215
|
"unicorn/prefer-reflect-apply": "error",
|
|
216
|
+
"unicorn/prefer-regexp-escape": "error",
|
|
162
217
|
"unicorn/prefer-regexp-test": "error",
|
|
163
218
|
"unicorn/prefer-response-static-json": "error",
|
|
164
219
|
"unicorn/prefer-scoped-selector": "error",
|
|
@@ -169,6 +224,7 @@ export const config = createConfig({
|
|
|
169
224
|
"unicorn/prefer-single-array-predicate": "error",
|
|
170
225
|
"unicorn/prefer-single-call": "error",
|
|
171
226
|
"unicorn/prefer-single-object-destructuring": "error",
|
|
227
|
+
"unicorn/prefer-single-replace": "error",
|
|
172
228
|
"unicorn/prefer-smaller-scope": "error",
|
|
173
229
|
"unicorn/prefer-spread": "error",
|
|
174
230
|
"unicorn/prefer-string-raw": "error",
|
|
@@ -182,14 +238,10 @@ export const config = createConfig({
|
|
|
182
238
|
"unicorn/prefer-top-level-await": "error",
|
|
183
239
|
"unicorn/prefer-type-error": "error",
|
|
184
240
|
"unicorn/prefer-uint8array-base64": "error",
|
|
241
|
+
"unicorn/prefer-unary-minus": "error",
|
|
185
242
|
"unicorn/prefer-unicode-code-point-escapes": "error",
|
|
186
243
|
"unicorn/prefer-url-href": "error",
|
|
187
|
-
"unicorn/
|
|
188
|
-
"error",
|
|
189
|
-
{
|
|
190
|
-
ignore: [/^props/i, /props$/i, /^ref/i, /ref$/i],
|
|
191
|
-
},
|
|
192
|
-
],
|
|
244
|
+
"unicorn/prefer-while-loop-condition": "error",
|
|
193
245
|
"unicorn/relative-url-style": ["error", "always"],
|
|
194
246
|
"unicorn/require-array-join-separator": "error",
|
|
195
247
|
"unicorn/require-array-sort-compare": "error",
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { helpers, termost } from "termost";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import { chmod, mkdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
6
|
-
import { fdir } from "fdir";
|
|
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";
|
|
7
6
|
|
|
8
7
|
//#region src/helpers.ts
|
|
9
8
|
const require = createRequire(import.meta.url);
|
|
@@ -49,20 +48,20 @@ ${input.body}
|
|
|
49
48
|
* @param path - The relative path.
|
|
50
49
|
* @returns The resolved absolute path.
|
|
51
50
|
* @example
|
|
52
|
-
*
|
|
51
|
+
* resolveFromWorkingDirectory(".gitignore");
|
|
53
52
|
*/
|
|
54
|
-
const
|
|
55
|
-
return resolve(process.cwd(), path);
|
|
53
|
+
const resolveFromWorkingDirectory = (...path) => {
|
|
54
|
+
return resolve(process.cwd(), ...path);
|
|
56
55
|
};
|
|
57
56
|
/**
|
|
58
57
|
* Resolve a relative path to an absolute one resolved from the `stack` node module directory.
|
|
59
58
|
* @param path - The relative path.
|
|
60
59
|
* @returns The resolved absolute path.
|
|
61
60
|
* @example
|
|
62
|
-
*
|
|
61
|
+
* resolveFromPackageDirectory("./templates");
|
|
63
62
|
*/
|
|
64
|
-
const
|
|
65
|
-
return resolve(import.meta.dirname, "../", path);
|
|
63
|
+
const resolveFromPackageDirectory = (...path) => {
|
|
64
|
+
return resolve(import.meta.dirname, "../", ...path);
|
|
66
65
|
};
|
|
67
66
|
const createError = (bin, error) => {
|
|
68
67
|
const errorMessage = `\`${bin}\` command failed.\n${String(error)}`;
|
|
@@ -72,7 +71,7 @@ const createError = (bin, error) => {
|
|
|
72
71
|
}
|
|
73
72
|
return new Error(errorMessage);
|
|
74
73
|
};
|
|
75
|
-
const
|
|
74
|
+
const getPnpmVersion = async () => {
|
|
76
75
|
try {
|
|
77
76
|
return await helpers.exec("pnpm -v");
|
|
78
77
|
} catch {
|
|
@@ -112,7 +111,7 @@ const eslint = (options) => async (files = []) => {
|
|
|
112
111
|
const arguments_ = [
|
|
113
112
|
...eslintFiles,
|
|
114
113
|
"--cache",
|
|
115
|
-
`--cache-location ${
|
|
114
|
+
`--cache-location ${resolveFromWorkingDirectory("node_modules/.cache/.eslintcache")}`,
|
|
116
115
|
"--no-error-on-unmatched-pattern"
|
|
117
116
|
];
|
|
118
117
|
if (options.isFixMode) arguments_.push("--fix");
|
|
@@ -260,14 +259,14 @@ const createPackagesVersionMismatchChecker = () => {
|
|
|
260
259
|
const isDevelopment = type === "development";
|
|
261
260
|
const store = isDevelopment ? monorepoDevelopmentDependencies : monorepoDependencies;
|
|
262
261
|
const dependencies = package_[isDevelopment ? "devDependencies" : "dependencies"];
|
|
263
|
-
for (const [dependencyName,
|
|
264
|
-
if (!
|
|
262
|
+
for (const [dependencyName, dependencyVersion] of Object.entries(dependencies)) {
|
|
263
|
+
if (!dependencyVersion) continue;
|
|
265
264
|
const storedVersion = store.get(dependencyName);
|
|
266
265
|
if (!storedVersion) {
|
|
267
|
-
store.set(dependencyName,
|
|
266
|
+
store.set(dependencyName, dependencyVersion);
|
|
268
267
|
continue;
|
|
269
268
|
}
|
|
270
|
-
if (!(
|
|
269
|
+
if (!(dependencyVersion === storedVersion)) throw createPackageError(`Mismatched versions: received version \`${dependencyVersion}\` while others use \`${storedVersion}\`. To prevent issues with singleton-like code (React contexts, …), please make sure to update all packages to use the same \`${dependencyName}\` version (either \`${storedVersion}\` or \`${dependencyVersion}\`).`, {
|
|
271
270
|
consumedBy: packageName,
|
|
272
271
|
name: dependencyName
|
|
273
272
|
});
|
|
@@ -382,7 +381,7 @@ const createCleanCommand = (program) => {
|
|
|
382
381
|
async handler() {
|
|
383
382
|
const cachePath = "node_modules/.cache";
|
|
384
383
|
const files = await retrieveIgnoredFiles();
|
|
385
|
-
if (isDirectoryExistAndNotEmpty(
|
|
384
|
+
if (isDirectoryExistAndNotEmpty(resolveFromWorkingDirectory(cachePath))) files.push(cachePath);
|
|
386
385
|
return files;
|
|
387
386
|
},
|
|
388
387
|
key: "files",
|
|
@@ -428,7 +427,7 @@ const PRESERVE_FILES = ["node_modules"];
|
|
|
428
427
|
|
|
429
428
|
//#endregion
|
|
430
429
|
//#region package.json
|
|
431
|
-
var version = "2.
|
|
430
|
+
var version = "2.39.0-next-00b7c69";
|
|
432
431
|
|
|
433
432
|
//#endregion
|
|
434
433
|
//#region src/commands/create.ts
|
|
@@ -444,7 +443,7 @@ const createCreateCommand = (program) => {
|
|
|
444
443
|
});
|
|
445
444
|
} }).task({
|
|
446
445
|
async handler() {
|
|
447
|
-
await
|
|
446
|
+
await getPnpmVersion();
|
|
448
447
|
},
|
|
449
448
|
label: label$2("Check pre-requisites")
|
|
450
449
|
}).input({
|
|
@@ -467,61 +466,92 @@ const createCreateCommand = (program) => {
|
|
|
467
466
|
options: ["single-project", "multi-projects"],
|
|
468
467
|
type: "select"
|
|
469
468
|
}).task({
|
|
470
|
-
async handler({ inputDescription, inputName, inputUrl }) {
|
|
469
|
+
async handler({ inputDescription, inputName, inputTemplate, inputUrl }) {
|
|
471
470
|
if (!inputName) throw createError("stack create", "The project name is not optional. Make sure to provide a valid value (non-empty string).");
|
|
472
471
|
const { repoName, repoOwner } = (inputUrl.startsWith("git") ? /^git@.*:(?<repoOwner>.*)\/(?<repoName>.*)\.git$/ : /^https?:\/\/.*\/(?<repoOwner>.*)\/(?<repoName>.*)\.git$/).exec(inputUrl)?.groups ?? {};
|
|
473
472
|
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.");
|
|
474
473
|
const nodeVersion = await request.get("https://resolve-node.vercel.app/lts", "text");
|
|
475
|
-
const { version:
|
|
474
|
+
const { version: pnpmVersion } = await request.get("https://registry.npmjs.org/pnpm/latest", "json");
|
|
475
|
+
const projectName = slugify(inputName);
|
|
476
476
|
return {
|
|
477
477
|
licenseYear: (/* @__PURE__ */ new Date()).getFullYear().toString(),
|
|
478
478
|
nodeVersion: nodeVersion.replace("v", ""),
|
|
479
|
-
|
|
480
|
-
projectDescription:
|
|
481
|
-
projectName
|
|
479
|
+
pnpmVersion: String(pnpmVersion),
|
|
480
|
+
projectDescription: toCapitalLetter(inputDescription),
|
|
481
|
+
projectName,
|
|
482
482
|
projectUrl: inputUrl,
|
|
483
|
-
repoId: `${repoOwner}/${repoName}
|
|
483
|
+
repoId: `${repoOwner}/${repoName}`,
|
|
484
|
+
templatePath: resolveFromPackageDirectory("templates", inputTemplate),
|
|
485
|
+
workingPath: resolveFromWorkingDirectory(projectName)
|
|
484
486
|
};
|
|
485
487
|
},
|
|
486
488
|
key: "data",
|
|
487
489
|
label: label$2("Check and format input")
|
|
488
|
-
}).
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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?`);
|
|
493
495
|
},
|
|
494
|
-
|
|
495
|
-
return
|
|
496
|
+
skip({ data: { workingPath } }) {
|
|
497
|
+
return !existsSync(workingPath);
|
|
498
|
+
},
|
|
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.`);
|
|
496
503
|
}
|
|
497
504
|
}).task({
|
|
498
|
-
async handler({ data }) {
|
|
499
|
-
await
|
|
500
|
-
|
|
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
|
+
});
|
|
501
524
|
},
|
|
502
|
-
|
|
525
|
+
key: "templateEngine",
|
|
526
|
+
label({ data: { projectName }, inputTemplate }) {
|
|
527
|
+
return label$2(`Copy \`${inputTemplate}\` template to \`${projectName}\` directory`);
|
|
528
|
+
}
|
|
503
529
|
}).task({
|
|
504
|
-
handler({
|
|
505
|
-
|
|
530
|
+
async handler({ templateEngine }) {
|
|
531
|
+
await templateEngine.processContents();
|
|
532
|
+
await templateEngine.processPaths();
|
|
506
533
|
},
|
|
507
|
-
label
|
|
534
|
+
label() {
|
|
535
|
+
return label$2("Process template");
|
|
536
|
+
}
|
|
508
537
|
}).task({
|
|
509
|
-
async handler({ data: {
|
|
510
|
-
await
|
|
538
|
+
async handler({ data: { projectUrl } }) {
|
|
539
|
+
await helpers.exec("git init");
|
|
540
|
+
await helpers.exec(`git remote add origin ${projectUrl}`);
|
|
511
541
|
},
|
|
512
|
-
label: label$2("
|
|
542
|
+
label: label$2("Initialize `git`")
|
|
513
543
|
}).task({
|
|
514
544
|
async handler() {
|
|
515
545
|
await setPackageManager();
|
|
516
546
|
},
|
|
517
547
|
label: label$2("Set up the package manager")
|
|
518
548
|
}).task({
|
|
519
|
-
async handler({ data }) {
|
|
549
|
+
async handler({ data: { projectName } }) {
|
|
520
550
|
const localDevelopmentDependencies = ["quickbundle", "vitest"];
|
|
521
551
|
const globalDevelopmentDependencies = ["@adbayb/stack"];
|
|
522
552
|
try {
|
|
523
553
|
await helpers.exec(`pnpm add ${globalDevelopmentDependencies.join(" ")} --save-dev --ignore-workspace-root-check`);
|
|
524
|
-
await helpers.exec(`pnpm add ${localDevelopmentDependencies.join(" ")} --save-dev --filter ${
|
|
554
|
+
await helpers.exec(`pnpm add ${localDevelopmentDependencies.join(" ")} --save-dev --filter ${projectName}`);
|
|
525
555
|
await helpers.exec("pnpm install");
|
|
526
556
|
} catch (error) {
|
|
527
557
|
throw createError("pnpm", error);
|
|
@@ -539,53 +569,95 @@ const createCreateCommand = (program) => {
|
|
|
539
569
|
await helpers.exec("git commit -m \"chore: initial commit\"");
|
|
540
570
|
},
|
|
541
571
|
label: label$2("Commit")
|
|
542
|
-
}).task({ handler({ data }) {
|
|
572
|
+
}).task({ handler({ data: { projectName } }) {
|
|
543
573
|
botMessage({
|
|
544
|
-
description: `Run \`cd ./${
|
|
574
|
+
description: `Run \`cd ./${projectName}\` and Enjoy 🚀`,
|
|
545
575
|
title: "The project was successfully created",
|
|
546
576
|
type: "success"
|
|
547
577
|
});
|
|
548
578
|
} });
|
|
549
579
|
};
|
|
550
580
|
const label$2 = (message) => `${message} 🔨`;
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
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, {
|
|
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, {
|
|
570
590
|
force: true,
|
|
571
591
|
recursive: true
|
|
572
592
|
});
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
593
|
+
const gitignoreFile = join(workingPath, "gitignore");
|
|
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
|
|
579
622
|
});
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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;
|
|
587
649
|
});
|
|
588
650
|
};
|
|
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
|
+
};
|
|
589
661
|
|
|
590
662
|
//#endregion
|
|
591
663
|
//#region src/commands/fix/fixFormatting.ts
|
|
@@ -600,7 +672,7 @@ const fixFormatting = async (files) => {
|
|
|
600
672
|
if (prettierFiles.length === 0) return;
|
|
601
673
|
}
|
|
602
674
|
const arguments_ = [...prettierFiles];
|
|
603
|
-
if (existsSync(
|
|
675
|
+
if (existsSync(resolveFromWorkingDirectory(".gitignore"))) arguments_.push("--ignore-path .gitignore");
|
|
604
676
|
arguments_.push("--write", "--ignore-unknown", "--no-error-on-unmatched-pattern");
|
|
605
677
|
try {
|
|
606
678
|
return await helpers.exec(`prettier ${arguments_.join(" ")}`);
|
|
@@ -663,7 +735,7 @@ const createInstallCommand = (program) => {
|
|
|
663
735
|
};
|
|
664
736
|
const label = (message) => `${message} 📲`;
|
|
665
737
|
const installGitHook = async (hook, content) => {
|
|
666
|
-
const filename =
|
|
738
|
+
const filename = resolveFromWorkingDirectory(`.git/hooks/${hook}`);
|
|
667
739
|
await writeFile(filename, content);
|
|
668
740
|
return chmod(filename, "0755");
|
|
669
741
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adbayb/stack",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.39.0-next-00b7c69",
|
|
4
4
|
"description": "My opinionated JavaScript-based toolchain",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"stack",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@changesets/cli": "^2.31.0",
|
|
44
44
|
"@commitlint/cli": "^21.0.2",
|
|
45
45
|
"@commitlint/config-conventional": "^21.0.2",
|
|
46
|
-
"@eslint-react/eslint-plugin": "^5.9.
|
|
46
|
+
"@eslint-react/eslint-plugin": "^5.9.1",
|
|
47
47
|
"@eslint/compat": "^2.1.0",
|
|
48
48
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
49
49
|
"@vitest/eslint-plugin": "^1.6.20",
|
|
@@ -52,21 +52,20 @@
|
|
|
52
52
|
"eslint-import-resolver-typescript": "^4.4.5",
|
|
53
53
|
"eslint-plugin-depend": "^1.5.0",
|
|
54
54
|
"eslint-plugin-import-x": "^4.16.2",
|
|
55
|
-
"eslint-plugin-jsdoc": "^63.0.
|
|
55
|
+
"eslint-plugin-jsdoc": "^63.0.6",
|
|
56
56
|
"eslint-plugin-mdx": "^3.8.1",
|
|
57
57
|
"eslint-plugin-n": "^18.1.0",
|
|
58
|
-
"eslint-plugin-perfectionist": "^5.9.
|
|
58
|
+
"eslint-plugin-perfectionist": "^5.9.1",
|
|
59
59
|
"eslint-plugin-prettier": "^5.5.6",
|
|
60
|
-
"eslint-plugin-sonarjs": "^4.0
|
|
61
|
-
"eslint-plugin-unicorn": "^
|
|
62
|
-
"fdir": "^6.5.0",
|
|
60
|
+
"eslint-plugin-sonarjs": "^4.1.0",
|
|
61
|
+
"eslint-plugin-unicorn": "^68.0.0",
|
|
63
62
|
"globals": "^17.6.0",
|
|
64
63
|
"prettier": "^3.8.4",
|
|
65
64
|
"prettier-plugin-packagejson": "^3.0.2",
|
|
66
65
|
"termost": "^1.9.1",
|
|
67
66
|
"turbo": "^2.9.18",
|
|
68
67
|
"typescript": "^6.0.3",
|
|
69
|
-
"typescript-eslint": "^8.61.
|
|
68
|
+
"typescript-eslint": "^8.61.1"
|
|
70
69
|
},
|
|
71
70
|
"devDependencies": {
|
|
72
71
|
"@types/node": "24.13.2",
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"watch": "stack watch"
|
|
18
18
|
},
|
|
19
19
|
"prettier": "@adbayb/stack/prettier",
|
|
20
|
-
"packageManager": "pnpm@{{
|
|
20
|
+
"packageManager": "pnpm@{{pnpmVersion}}",
|
|
21
21
|
"devEngines": {
|
|
22
22
|
"packageManager": [
|
|
23
23
|
{
|
|
24
24
|
"name": "pnpm",
|
|
25
|
-
"version": "{{
|
|
25
|
+
"version": "{{pnpmVersion}}",
|
|
26
26
|
"onFail": "download"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
allowBuilds:
|
|
2
|
+
esbuild: true
|
|
3
|
+
unrs-resolver: true
|
|
4
|
+
minimumReleaseAgeExclude:
|
|
5
|
+
- "@adbayb/*"
|
|
1
6
|
packages:
|
|
2
7
|
- "applications/*"
|
|
3
8
|
- "examples/*"
|
|
@@ -11,3 +16,4 @@ publicHoistPattern:
|
|
|
11
16
|
- "*turbo*"
|
|
12
17
|
- "*typescript*"
|
|
13
18
|
- "*types*"
|
|
19
|
+
verifyDepsBeforeRun: "warn"
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"watch": "stack watch"
|
|
18
18
|
},
|
|
19
19
|
"prettier": "@adbayb/stack/prettier",
|
|
20
|
-
"packageManager": "pnpm@{{
|
|
20
|
+
"packageManager": "pnpm@{{pnpmVersion}}",
|
|
21
21
|
"devEngines": {
|
|
22
22
|
"packageManager": [
|
|
23
23
|
{
|
|
24
24
|
"name": "pnpm",
|
|
25
|
-
"version": "{{
|
|
25
|
+
"version": "{{pnpmVersion}}",
|
|
26
26
|
"onFail": "download"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
allowBuilds:
|
|
2
|
+
esbuild: true
|
|
3
|
+
unrs-resolver: true
|
|
4
|
+
minimumReleaseAgeExclude:
|
|
5
|
+
- "@adbayb/*"
|
|
1
6
|
packages:
|
|
2
7
|
- "examples/*"
|
|
3
8
|
- "tools/*"
|
|
@@ -10,3 +15,4 @@ publicHoistPattern:
|
|
|
10
15
|
- "*turbo*"
|
|
11
16
|
- "*typescript*"
|
|
12
17
|
- "*types*"
|
|
18
|
+
verifyDepsBeforeRun: "warn"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
save-exact=true
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
save-exact=true
|
|
File without changes
|
|
File without changes
|
/package/templates/multi-projects/.github/{PULL_REQUEST_TEMPLATE.md.tmpl → PULL_REQUEST_TEMPLATE.md}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/multi-projects/libraries/{{projectName}}/{package.json.tmpl → package.json}
RENAMED
|
File without changes
|
/package/templates/multi-projects/libraries/{{projectName}}/src/{index.test.ts.tmpl → index.test.ts}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/single-project/.github/{PULL_REQUEST_TEMPLATE.md.tmpl → PULL_REQUEST_TEMPLATE.md}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|