@stack-dev/cli 0.1.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.
- package/.turbo/daemon/6fa76abe2aa470d0-turbo.log.2025-08-02 +5 -0
- package/.turbo/daemon/6fa76abe2aa470d0-turbo.log.2025-12-29 +1 -0
- package/.turbo/daemon/6fa76abe2aa470d0-turbo.log.2025-12-30 +0 -0
- package/.turbo/turbo-build.log +21 -0
- package/.turbo/turbo-check-types.log +5 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2097 -0
- package/dist/index.mjs +2073 -0
- package/eslint.config.mjs +3 -0
- package/package.json +35 -0
- package/prettier.config.mjs +3 -0
- package/src/file-generator/file-generator-imp.ts +20 -0
- package/src/file-generator/file-generator.ts +5 -0
- package/src/file-generator/index.ts +3 -0
- package/src/file-generator/package-json-generator.ts +23 -0
- package/src/index.ts +185 -0
- package/src/link-packages.ts +65 -0
- package/src/package-json/dependency.ts +28 -0
- package/src/package-json/index.ts +3 -0
- package/src/package-json/package-json.ts +269 -0
- package/src/packages/create-config-package.ts +29 -0
- package/src/packages/index.ts +4 -0
- package/src/packages/library-package/create-library-package.ts +85 -0
- package/src/packages/library-package/files/add-file-generator.ts +8 -0
- package/src/packages/library-package/files/add-spec-file-generator.ts +17 -0
- package/src/packages/library-package/files/eslint-config-file-generator.ts +11 -0
- package/src/packages/library-package/files/index-file-generator.ts +9 -0
- package/src/packages/library-package/files/prettier-config-file-generator.ts +11 -0
- package/src/packages/library-package/files/tsconfig-file-generator.ts +15 -0
- package/src/packages/library-package/files/tsup-config-file-generator.ts +23 -0
- package/src/packages/library-package/files/vitest-config-file-generator.ts +19 -0
- package/src/packages/library-package/index.ts +1 -0
- package/src/packages/react-package/create-react-package.ts +25 -0
- package/src/packages/react-package/create-tailwind-react-package.ts +30 -0
- package/src/packages/react-package/create-unstyled-react-package.ts +3 -0
- package/src/packages/react-package/css-react-package/create-css-react-package.ts +103 -0
- package/src/packages/react-package/css-react-package/files/button-css-module-file-generator.ts +16 -0
- package/src/packages/react-package/css-react-package/files/button-file-generator.ts +14 -0
- package/src/packages/react-package/css-react-package/files/button-spec-file-generator.ts +33 -0
- package/src/packages/react-package/css-react-package/files/eslint-config-file-generator.ts +18 -0
- package/src/packages/react-package/css-react-package/files/index-file-generator.ts +9 -0
- package/src/packages/react-package/css-react-package/files/prettier-config-file-generator.ts +11 -0
- package/src/packages/react-package/css-react-package/files/tsconfig-file-generator.ts +15 -0
- package/src/packages/react-package/css-react-package/files/tsup-config-file-generator.ts +24 -0
- package/src/packages/react-package/css-react-package/files/vitest-config-file-generator.ts +23 -0
- package/src/packages/react-package/index.ts +1 -0
- package/src/packages/react-package/styled-components-react-package/create-styled-components-react-package.ts +112 -0
- package/src/packages/react-package/styled-components-react-package/files/button-file-generator.ts +30 -0
- package/src/packages/react-package/styled-components-react-package/files/button-spec-file-generator.ts +33 -0
- package/src/packages/react-package/styled-components-react-package/files/eslint-config-file-generator.ts +18 -0
- package/src/packages/react-package/styled-components-react-package/files/index-file-generator.ts +9 -0
- package/src/packages/react-package/styled-components-react-package/files/prettier-config-file-generator.ts +11 -0
- package/src/packages/react-package/styled-components-react-package/files/tsconfig-file-generator.ts +15 -0
- package/src/packages/react-package/styled-components-react-package/files/tsup-config-file-generator.ts +21 -0
- package/src/packages/react-package/styled-components-react-package/files/vitest-config-file-generator.ts +23 -0
- package/src/packages/vite-react-app/create-vite-react-app.ts +79 -0
- package/src/packages/vite-react-app/files/app-file-generator.ts +28 -0
- package/src/packages/vite-react-app/files/eslint-config-file-generator.ts +11 -0
- package/src/packages/vite-react-app/files/index-html-file-generator.ts +20 -0
- package/src/packages/vite-react-app/files/main-file-generator.ts +14 -0
- package/src/packages/vite-react-app/files/prettier-config-file-generator.ts +11 -0
- package/src/packages/vite-react-app/files/tsconfig-file-generator.ts +15 -0
- package/src/packages/vite-react-app/files/vite-config-file-generator.ts +17 -0
- package/src/packages/vite-react-app/files/vitest-config-file-generator.ts +19 -0
- package/src/tsconfig/compiler-options.ts +83 -0
- package/src/tsconfig/index.ts +4 -0
- package/src/tsconfig/reference.ts +21 -0
- package/src/tsconfig/tsconfig.ts +137 -0
- package/src/unlink-packages.ts +47 -0
- package/src/utils/package-generator.ts +41 -0
- package/src/utils/package-type.ts +44 -0
- package/src/utils/package.ts +126 -0
- package/src/utils/style-type.ts +41 -0
- package/src/utils/utils.ts +28 -0
- package/src/utils/workspace.ts +78 -0
- package/src/workspace/create-workspace.ts +39 -0
- package/src/workspace/index.ts +1 -0
- package/src/workspace/root-package.ts +195 -0
- package/src/workspace/typescript-config.ts +84 -0
- package/tsconfig.json +14 -0
- package/tsup.config.ts +16 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2097 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
|
|
25
|
+
// src/utils/utils.ts
|
|
26
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
27
|
+
var import_node_path = __toESM(require("path"));
|
|
28
|
+
|
|
29
|
+
// src/package-json/package-json.ts
|
|
30
|
+
var import_core = require("@stack-dev/core");
|
|
31
|
+
var import_json5 = __toESM(require("json5"));
|
|
32
|
+
var import_lodash = require("lodash");
|
|
33
|
+
|
|
34
|
+
// src/package-json/dependency.ts
|
|
35
|
+
var Dependency = class _Dependency {
|
|
36
|
+
_name;
|
|
37
|
+
_version;
|
|
38
|
+
constructor(name, version) {
|
|
39
|
+
this._name = name;
|
|
40
|
+
this._version = version;
|
|
41
|
+
}
|
|
42
|
+
get name() {
|
|
43
|
+
return this._name;
|
|
44
|
+
}
|
|
45
|
+
get version() {
|
|
46
|
+
return this._version;
|
|
47
|
+
}
|
|
48
|
+
equals(other) {
|
|
49
|
+
if (other instanceof _Dependency) {
|
|
50
|
+
return this._name === other._name && this._version === other._version;
|
|
51
|
+
} else {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/package-json/package-json.ts
|
|
58
|
+
var PackageJSON = class _PackageJSON {
|
|
59
|
+
_name;
|
|
60
|
+
_dependencies;
|
|
61
|
+
_devDependencies;
|
|
62
|
+
_peerDependencies;
|
|
63
|
+
_additionalData;
|
|
64
|
+
constructor(args) {
|
|
65
|
+
this._name = args.name;
|
|
66
|
+
this._dependencies = args.dependencies ?? [];
|
|
67
|
+
this._devDependencies = args.devDependencies ?? [];
|
|
68
|
+
this._peerDependencies = args.peerDependencies ?? [];
|
|
69
|
+
this._additionalData = args.additionalData ?? {};
|
|
70
|
+
}
|
|
71
|
+
get name() {
|
|
72
|
+
return this._name;
|
|
73
|
+
}
|
|
74
|
+
get dependencies() {
|
|
75
|
+
return this._dependencies;
|
|
76
|
+
}
|
|
77
|
+
get devDependencies() {
|
|
78
|
+
return this._devDependencies;
|
|
79
|
+
}
|
|
80
|
+
get peerDependencies() {
|
|
81
|
+
return this._peerDependencies;
|
|
82
|
+
}
|
|
83
|
+
addDependency(dependency) {
|
|
84
|
+
return new _PackageJSON({
|
|
85
|
+
name: this.name,
|
|
86
|
+
dependencies: [...this.dependencies, dependency],
|
|
87
|
+
devDependencies: this.devDependencies,
|
|
88
|
+
additionalData: this._additionalData
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
addDevDependency(dependency) {
|
|
92
|
+
return new _PackageJSON({
|
|
93
|
+
name: this.name,
|
|
94
|
+
dependencies: this.dependencies,
|
|
95
|
+
devDependencies: [...this.devDependencies, dependency],
|
|
96
|
+
additionalData: this._additionalData
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
addPeerDependency(dependency) {
|
|
100
|
+
return new _PackageJSON({
|
|
101
|
+
name: this.name,
|
|
102
|
+
dependencies: this.dependencies,
|
|
103
|
+
devDependencies: this.devDependencies,
|
|
104
|
+
peerDependencies: [...this.peerDependencies, dependency],
|
|
105
|
+
additionalData: this._additionalData
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
removeDependency(name) {
|
|
109
|
+
return new _PackageJSON({
|
|
110
|
+
name: this.name,
|
|
111
|
+
dependencies: this.dependencies.filter((d) => d.name !== name),
|
|
112
|
+
devDependencies: this.devDependencies,
|
|
113
|
+
additionalData: this._additionalData
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
removeDevDependency(name) {
|
|
117
|
+
return new _PackageJSON({
|
|
118
|
+
name: this.name,
|
|
119
|
+
dependencies: this.dependencies,
|
|
120
|
+
devDependencies: this.devDependencies.filter((d) => d.name !== name),
|
|
121
|
+
additionalData: this._additionalData
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
removePeerDependency(name) {
|
|
125
|
+
return new _PackageJSON({
|
|
126
|
+
name: this.name,
|
|
127
|
+
dependencies: this.dependencies,
|
|
128
|
+
devDependencies: this.devDependencies,
|
|
129
|
+
peerDependencies: this.peerDependencies.filter((d) => d.name !== name),
|
|
130
|
+
additionalData: this._additionalData
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
static parse(s) {
|
|
134
|
+
const json = import_json5.default.parse(s);
|
|
135
|
+
const name = json.name;
|
|
136
|
+
const dependencies = _PackageJSON.parseDependencies(json);
|
|
137
|
+
const devDependencies = _PackageJSON.parseDevDependencies(json);
|
|
138
|
+
const peerDependencies = _PackageJSON.parsePeerDependencies(json);
|
|
139
|
+
const additionalData = { ...json };
|
|
140
|
+
delete additionalData["name"];
|
|
141
|
+
delete additionalData["dependencies"];
|
|
142
|
+
delete additionalData["devDependencies"];
|
|
143
|
+
delete additionalData["peerDependencies"];
|
|
144
|
+
return new _PackageJSON({
|
|
145
|
+
name,
|
|
146
|
+
dependencies,
|
|
147
|
+
devDependencies,
|
|
148
|
+
peerDependencies,
|
|
149
|
+
additionalData
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
static parseDependencies(json) {
|
|
153
|
+
if ("dependencies" in json && typeof json.dependencies === "object") {
|
|
154
|
+
return Object.entries(json.dependencies).map(
|
|
155
|
+
([name, version]) => new Dependency(name, version)
|
|
156
|
+
);
|
|
157
|
+
} else {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
static parseDevDependencies(json) {
|
|
162
|
+
if ("devDependencies" in json && typeof json.devDependencies === "object") {
|
|
163
|
+
return Object.entries(json.devDependencies).map(
|
|
164
|
+
([name, version]) => new Dependency(name, version)
|
|
165
|
+
);
|
|
166
|
+
} else {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
static parsePeerDependencies(json) {
|
|
171
|
+
if ("peerDependencies" in json && typeof json.peerDependencies === "object") {
|
|
172
|
+
return Object.entries(json.peerDependencies).map(
|
|
173
|
+
([name, version]) => new Dependency(name, version)
|
|
174
|
+
);
|
|
175
|
+
} else {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
format(namespace) {
|
|
180
|
+
const json = {
|
|
181
|
+
name: this._name,
|
|
182
|
+
dependencies: makeDependencyObject(this._dependencies, namespace),
|
|
183
|
+
devDependencies: makeDependencyObject(this._devDependencies, namespace),
|
|
184
|
+
peerDependencies: makeDependencyObject(this._peerDependencies, namespace),
|
|
185
|
+
...this._additionalData
|
|
186
|
+
};
|
|
187
|
+
const ordered = (0, import_core.sortKeys)(json, comparePackageJSONKeys);
|
|
188
|
+
return JSON.stringify(ordered, null, 2);
|
|
189
|
+
}
|
|
190
|
+
equals(other) {
|
|
191
|
+
if (other instanceof _PackageJSON) {
|
|
192
|
+
const sameDependencies = (0, import_core.haveSameItems)(
|
|
193
|
+
this._dependencies,
|
|
194
|
+
other._dependencies,
|
|
195
|
+
(d1, d2) => d1.equals(d2)
|
|
196
|
+
);
|
|
197
|
+
const sameDevDependencies = (0, import_core.haveSameItems)(
|
|
198
|
+
this._devDependencies,
|
|
199
|
+
other._devDependencies,
|
|
200
|
+
(d1, d2) => d1.equals(d2)
|
|
201
|
+
);
|
|
202
|
+
const samePeerDependencies = (0, import_core.haveSameItems)(
|
|
203
|
+
this._peerDependencies,
|
|
204
|
+
other._peerDependencies,
|
|
205
|
+
(d1, d2) => d1.equals(d2)
|
|
206
|
+
);
|
|
207
|
+
return this._name === other._name && sameDependencies && sameDevDependencies && samePeerDependencies && (0, import_lodash.isEqual)(this._additionalData, other._additionalData);
|
|
208
|
+
} else {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
function makeDependencyObject(dependencies, namespace) {
|
|
214
|
+
if (dependencies.length === 0) {
|
|
215
|
+
return void 0;
|
|
216
|
+
}
|
|
217
|
+
const result = {};
|
|
218
|
+
dependencies.toSorted((a, b) => comparePackageNames(a.name, b.name, namespace)).forEach((d) => result[d.name] = d.version);
|
|
219
|
+
return result;
|
|
220
|
+
}
|
|
221
|
+
function comparePackageNames(a, b, namespace) {
|
|
222
|
+
if (a.startsWith(namespace) && b.startsWith(namespace)) {
|
|
223
|
+
return a.localeCompare(b);
|
|
224
|
+
} else if (a.startsWith(namespace)) {
|
|
225
|
+
return -1;
|
|
226
|
+
} else if (b.startsWith(namespace)) {
|
|
227
|
+
return 1;
|
|
228
|
+
} else {
|
|
229
|
+
return a.localeCompare(b);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function comparePackageJSONKeys(a, b) {
|
|
233
|
+
return getKeyIndex(a) - getKeyIndex(b);
|
|
234
|
+
}
|
|
235
|
+
function getKeyIndex(s) {
|
|
236
|
+
switch (s.toLowerCase()) {
|
|
237
|
+
case "name":
|
|
238
|
+
return 0;
|
|
239
|
+
case "version":
|
|
240
|
+
return 1;
|
|
241
|
+
case "private":
|
|
242
|
+
return 2;
|
|
243
|
+
case "bin":
|
|
244
|
+
return 3;
|
|
245
|
+
case "main":
|
|
246
|
+
return 4;
|
|
247
|
+
case "module":
|
|
248
|
+
return 5;
|
|
249
|
+
case "types":
|
|
250
|
+
return 6;
|
|
251
|
+
case "exports":
|
|
252
|
+
return 7;
|
|
253
|
+
case "scripts":
|
|
254
|
+
return 8;
|
|
255
|
+
case "dependencies":
|
|
256
|
+
return 9;
|
|
257
|
+
case "devDependencies":
|
|
258
|
+
return 10;
|
|
259
|
+
case "peerdependencies":
|
|
260
|
+
return 11;
|
|
261
|
+
default:
|
|
262
|
+
return Number.MAX_VALUE;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/utils/utils.ts
|
|
267
|
+
async function getDirectoryPackageJson(directory) {
|
|
268
|
+
const packageJsonPath = getPackageJSONPath(directory);
|
|
269
|
+
const packageJsonText = await import_promises.default.readFile(packageJsonPath, {
|
|
270
|
+
encoding: "utf-8"
|
|
271
|
+
});
|
|
272
|
+
return PackageJSON.parse(packageJsonText);
|
|
273
|
+
}
|
|
274
|
+
function getPackageJSONPath(directory) {
|
|
275
|
+
return import_node_path.default.join(directory, "package.json");
|
|
276
|
+
}
|
|
277
|
+
async function fileExists(filepath) {
|
|
278
|
+
try {
|
|
279
|
+
await import_promises.default.access(filepath, import_promises.default.constants.F_OK);
|
|
280
|
+
return true;
|
|
281
|
+
} catch {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/utils/workspace.ts
|
|
287
|
+
var import_promises2 = __toESM(require("fs/promises"));
|
|
288
|
+
var import_path = __toESM(require("path"));
|
|
289
|
+
var import_yaml = __toESM(require("yaml"));
|
|
290
|
+
async function getDirectoryWorkspaceFile(directory) {
|
|
291
|
+
const raw = await getRawDirectoryWorkspaceFile(directory);
|
|
292
|
+
if ("packages" in raw && raw.packages instanceof Array) {
|
|
293
|
+
return {
|
|
294
|
+
packages: raw.packages.filter((p) => typeof p === "string")
|
|
295
|
+
};
|
|
296
|
+
} else {
|
|
297
|
+
return { packages: [] };
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async function getRawDirectoryWorkspaceFile(directory) {
|
|
301
|
+
const case1 = import_path.default.join(directory, "pnpm-workspace.yaml");
|
|
302
|
+
const case2 = import_path.default.join(directory, "pnpm-workspace.yml");
|
|
303
|
+
if (await fileExists(case1)) {
|
|
304
|
+
return import_yaml.default.parse(await import_promises2.default.readFile(case1, { encoding: "utf-8" }));
|
|
305
|
+
} else if (await fileExists(case2)) {
|
|
306
|
+
return import_yaml.default.parse(await import_promises2.default.readFile(case2, { encoding: "utf-8" }));
|
|
307
|
+
} else {
|
|
308
|
+
throw new Error(`Directory "${directory}" is not a workspace.`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async function isWorkspaceRoot(directory) {
|
|
312
|
+
return await fileExists(import_path.default.join(directory, "pnpm-workspace.yaml")) || await fileExists(import_path.default.join(directory, "pnpm-workspace.yml"));
|
|
313
|
+
}
|
|
314
|
+
async function getWorkspaceRoot(directory = process.cwd()) {
|
|
315
|
+
const parent = import_path.default.dirname(directory);
|
|
316
|
+
if (parent === directory) {
|
|
317
|
+
throw new Error("Not a workspace.");
|
|
318
|
+
}
|
|
319
|
+
if (await isWorkspaceRoot(directory)) {
|
|
320
|
+
return directory;
|
|
321
|
+
}
|
|
322
|
+
return getWorkspaceRoot(parent);
|
|
323
|
+
}
|
|
324
|
+
async function getNamespace(directory = process.cwd()) {
|
|
325
|
+
const root = await getWorkspaceRoot(directory);
|
|
326
|
+
const packageJson = await getDirectoryPackageJson(root);
|
|
327
|
+
const result = packageJson.name;
|
|
328
|
+
if (!result) {
|
|
329
|
+
throw new Error("Missing name.");
|
|
330
|
+
}
|
|
331
|
+
return `@${result}`;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/packages/library-package/create-library-package.ts
|
|
335
|
+
var import_node_path3 = __toESM(require("path"));
|
|
336
|
+
|
|
337
|
+
// src/file-generator/package-json-generator.ts
|
|
338
|
+
var PackageJsonGenerator = class {
|
|
339
|
+
_packageJson;
|
|
340
|
+
_namespace;
|
|
341
|
+
constructor(packageJson, namespace = "") {
|
|
342
|
+
this._packageJson = packageJson;
|
|
343
|
+
this._namespace = namespace;
|
|
344
|
+
}
|
|
345
|
+
get filepath() {
|
|
346
|
+
return "package.json";
|
|
347
|
+
}
|
|
348
|
+
async generate() {
|
|
349
|
+
return this._packageJson.format(this._namespace);
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// src/utils/package-generator.ts
|
|
354
|
+
var import_promises3 = __toESM(require("fs/promises"));
|
|
355
|
+
var import_node_path2 = __toESM(require("path"));
|
|
356
|
+
var PackageGenerator = class {
|
|
357
|
+
_root;
|
|
358
|
+
_packageJson;
|
|
359
|
+
_fileGenerators;
|
|
360
|
+
constructor(root, packageJson, fileGenerators = []) {
|
|
361
|
+
this._root = root;
|
|
362
|
+
this._packageJson = packageJson;
|
|
363
|
+
this._fileGenerators = fileGenerators;
|
|
364
|
+
}
|
|
365
|
+
async generate() {
|
|
366
|
+
const all = [this._packageJson, ...this._fileGenerators];
|
|
367
|
+
await import_promises3.default.mkdir(this._root, { recursive: true });
|
|
368
|
+
await Promise.all(all.map((gen) => this.write(gen)));
|
|
369
|
+
}
|
|
370
|
+
async write(fileGenerator) {
|
|
371
|
+
const contents = await fileGenerator.generate();
|
|
372
|
+
const filepath = import_node_path2.default.join(this._root, fileGenerator.filepath);
|
|
373
|
+
const directory = import_node_path2.default.dirname(filepath);
|
|
374
|
+
await import_promises3.default.mkdir(directory, { recursive: true });
|
|
375
|
+
await import_promises3.default.writeFile(filepath, contents);
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// src/file-generator/file-generator-imp.ts
|
|
380
|
+
var FileGeneratorImp = class {
|
|
381
|
+
_filepath;
|
|
382
|
+
_contents;
|
|
383
|
+
constructor(filepath, contents) {
|
|
384
|
+
this._filepath = filepath;
|
|
385
|
+
this._contents = contents;
|
|
386
|
+
}
|
|
387
|
+
get filepath() {
|
|
388
|
+
return this._filepath;
|
|
389
|
+
}
|
|
390
|
+
async generate() {
|
|
391
|
+
return this._contents;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// src/packages/library-package/files/add-file-generator.ts
|
|
396
|
+
var ADD_TS = `export function add(n1: number, n2: number): number {
|
|
397
|
+
return n1 + n2;
|
|
398
|
+
}
|
|
399
|
+
`;
|
|
400
|
+
var ADD_FILE_GENERATOR = new FileGeneratorImp("src/add.ts", ADD_TS);
|
|
401
|
+
|
|
402
|
+
// src/packages/library-package/files/add-spec-file-generator.ts
|
|
403
|
+
var ADD_SPEC_TS = `import { describe, it, expect } from 'vitest';
|
|
404
|
+
|
|
405
|
+
import { add } from '../add';
|
|
406
|
+
|
|
407
|
+
describe('add', () => {
|
|
408
|
+
it('adds two numbers', () => {
|
|
409
|
+
expect(add(2, 3)).toBe(5);
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
`;
|
|
413
|
+
var ADD_SPEC_FILE_GENERATOR = new FileGeneratorImp(
|
|
414
|
+
"src/spec/add.spec.ts",
|
|
415
|
+
ADD_SPEC_TS
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
// src/packages/library-package/files/eslint-config-file-generator.ts
|
|
419
|
+
var ESLINT_CONFIG = `import base from '@stack-dev/eslint-config/base.mjs';
|
|
420
|
+
|
|
421
|
+
export default [...base, { ignores: ['**/dist/**'] }];
|
|
422
|
+
`;
|
|
423
|
+
var ESLINT_CONFIG_FILE_GENERATOR = new FileGeneratorImp(
|
|
424
|
+
"eslint.config.mjs",
|
|
425
|
+
ESLINT_CONFIG
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
// src/packages/library-package/files/index-file-generator.ts
|
|
429
|
+
var INDEX_TS = `export * from './add';
|
|
430
|
+
`;
|
|
431
|
+
var INDEX_FILE_GENERATOR = new FileGeneratorImp(
|
|
432
|
+
"src/index.ts",
|
|
433
|
+
INDEX_TS
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
// src/packages/library-package/files/prettier-config-file-generator.ts
|
|
437
|
+
var PRETTIER_CONFIG = `import base from '@stack-dev/prettier-config/base.mjs';
|
|
438
|
+
|
|
439
|
+
export default base;
|
|
440
|
+
`;
|
|
441
|
+
var PRETTIER_CONFIG_FILE_GENERATOR = new FileGeneratorImp(
|
|
442
|
+
"prettier.config.mjs",
|
|
443
|
+
PRETTIER_CONFIG
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
// src/packages/library-package/files/tsconfig-file-generator.ts
|
|
447
|
+
var TSCONFIG = `{
|
|
448
|
+
"extends": "@stack-dev/typescript-config/tsconfig.base.json",
|
|
449
|
+
"compilerOptions": {
|
|
450
|
+
"outDir": "dist"
|
|
451
|
+
},
|
|
452
|
+
"include": ["src"]
|
|
453
|
+
}
|
|
454
|
+
`;
|
|
455
|
+
var TSCONFIG_FILE_GENERATOR = new FileGeneratorImp(
|
|
456
|
+
"tsconfig.json",
|
|
457
|
+
TSCONFIG
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
// src/packages/library-package/files/tsup-config-file-generator.ts
|
|
461
|
+
var TSUP_CONFIG = `import { defineConfig } from 'tsup';
|
|
462
|
+
|
|
463
|
+
export default defineConfig({
|
|
464
|
+
entry: ['src/index.ts'],
|
|
465
|
+
format: ['esm', 'cjs'],
|
|
466
|
+
dts: true,
|
|
467
|
+
sourcemap: true,
|
|
468
|
+
clean: true,
|
|
469
|
+
target: 'esnext',
|
|
470
|
+
outExtension({ format }) {
|
|
471
|
+
return {
|
|
472
|
+
js: format === 'esm' ? '.mjs' : '.js',
|
|
473
|
+
};
|
|
474
|
+
},
|
|
475
|
+
});
|
|
476
|
+
`;
|
|
477
|
+
var TSUP_CONFIG_FILE_GENERATOR = new FileGeneratorImp(
|
|
478
|
+
"tsup.config.ts",
|
|
479
|
+
TSUP_CONFIG
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
// src/packages/library-package/files/vitest-config-file-generator.ts
|
|
483
|
+
var VITEST_CONFIG = `import { defineConfig } from 'vitest/config';
|
|
484
|
+
|
|
485
|
+
export default defineConfig({
|
|
486
|
+
test: {
|
|
487
|
+
globals: true,
|
|
488
|
+
coverage: {
|
|
489
|
+
provider: 'v8',
|
|
490
|
+
},
|
|
491
|
+
environment: 'node',
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
`;
|
|
495
|
+
var VITEST_CONFIG_FILE_GENERATOR = new FileGeneratorImp(
|
|
496
|
+
"vitest.config.ts",
|
|
497
|
+
VITEST_CONFIG
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
// src/packages/library-package/create-library-package.ts
|
|
501
|
+
async function createLibraryPackage(name) {
|
|
502
|
+
const rootDir = await getWorkspaceRoot();
|
|
503
|
+
const directory = import_node_path3.default.join(rootDir, "packages", name);
|
|
504
|
+
const namespace = await getNamespace(rootDir);
|
|
505
|
+
const packageName = `${namespace}/${name}`;
|
|
506
|
+
console.log(`\u2728 Creating config package: ${packageName}`);
|
|
507
|
+
const generator = new PackageGenerator(
|
|
508
|
+
directory,
|
|
509
|
+
makePackageGenerator(packageName, namespace),
|
|
510
|
+
[
|
|
511
|
+
INDEX_FILE_GENERATOR,
|
|
512
|
+
ADD_FILE_GENERATOR,
|
|
513
|
+
ADD_SPEC_FILE_GENERATOR,
|
|
514
|
+
TSUP_CONFIG_FILE_GENERATOR,
|
|
515
|
+
TSCONFIG_FILE_GENERATOR,
|
|
516
|
+
PRETTIER_CONFIG_FILE_GENERATOR,
|
|
517
|
+
ESLINT_CONFIG_FILE_GENERATOR,
|
|
518
|
+
VITEST_CONFIG_FILE_GENERATOR
|
|
519
|
+
]
|
|
520
|
+
);
|
|
521
|
+
await generator.generate();
|
|
522
|
+
console.log(`\u2705 Config package created at: ${directory}`);
|
|
523
|
+
}
|
|
524
|
+
function makePackageGenerator(packageName, namespace) {
|
|
525
|
+
const packageJsonModel = new PackageJSON({
|
|
526
|
+
name: packageName,
|
|
527
|
+
devDependencies: [
|
|
528
|
+
new Dependency(`${namespace}/eslint-config`, "workspace:*"),
|
|
529
|
+
new Dependency(`${namespace}/prettier-config`, "workspace:*"),
|
|
530
|
+
new Dependency(`${namespace}/typescript-config`, "workspace:*"),
|
|
531
|
+
new Dependency("eslint", "^9.32.0"),
|
|
532
|
+
new Dependency("prettier", "^3.6.2"),
|
|
533
|
+
new Dependency("prettier-plugin-organize-imports", "^4.2.0"),
|
|
534
|
+
new Dependency("tsup", "^7.3.0"),
|
|
535
|
+
new Dependency("vitest", "^3.2.4"),
|
|
536
|
+
new Dependency("@vitest/coverage-v8", "^3.2.4")
|
|
537
|
+
],
|
|
538
|
+
additionalData: {
|
|
539
|
+
version: "0.1.0",
|
|
540
|
+
private: true,
|
|
541
|
+
main: "dist/index.js",
|
|
542
|
+
module: "dist/index.mjs",
|
|
543
|
+
types: "dist/index.d.ts",
|
|
544
|
+
exports: {
|
|
545
|
+
".": {
|
|
546
|
+
development: "./src/index.ts",
|
|
547
|
+
import: "./dist/index.mjs",
|
|
548
|
+
require: "./dist/index.js",
|
|
549
|
+
types: "./dist/index.d.ts"
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
scripts: {
|
|
553
|
+
build: "tsup",
|
|
554
|
+
lint: "eslint",
|
|
555
|
+
format: "prettier . --write",
|
|
556
|
+
test: "vitest run",
|
|
557
|
+
"test:watch": "vitest"
|
|
558
|
+
},
|
|
559
|
+
sideEffects: false
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
return new PackageJsonGenerator(packageJsonModel, namespace);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// src/packages/react-package/create-tailwind-react-package.ts
|
|
566
|
+
async function createTailwindReactPackage(name) {
|
|
567
|
+
throw new Error("Not implemented.");
|
|
568
|
+
}
|
|
569
|
+
var STYLED_BUTTON = `import React from 'react';
|
|
570
|
+
|
|
571
|
+
interface ButtonProps {
|
|
572
|
+
label: string;
|
|
573
|
+
onClick?: () => void;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export function TailwindButton(props: ButtonProps) {
|
|
577
|
+
const {label, onClick} = props;
|
|
578
|
+
|
|
579
|
+
return (
|
|
580
|
+
<button
|
|
581
|
+
onClick={onClick}
|
|
582
|
+
className="my-lib-bg-blue-600 my-lib-text-white my-lib-p-[10px] my-lib-border-none my-lib-rounded my-lib-cursor-pointer hover:my-lib-brightness-110"
|
|
583
|
+
>
|
|
584
|
+
{label}
|
|
585
|
+
</button>
|
|
586
|
+
);
|
|
587
|
+
};`;
|
|
588
|
+
var STYLED_BUTTON_FILE_GENERATOR = new FileGeneratorImp(
|
|
589
|
+
"styled-button.ts",
|
|
590
|
+
STYLED_BUTTON
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
// src/packages/react-package/create-unstyled-react-package.ts
|
|
594
|
+
async function createUnstyledReactPackage(name) {
|
|
595
|
+
throw new Error("Not implemented.");
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// src/packages/react-package/css-react-package/create-css-react-package.ts
|
|
599
|
+
var import_path2 = __toESM(require("path"));
|
|
600
|
+
|
|
601
|
+
// src/packages/react-package/css-react-package/files/button-css-module-file-generator.ts
|
|
602
|
+
var BUTTON_CSS_MODULE = `.styledButton {
|
|
603
|
+
background: blue;
|
|
604
|
+
color: white;
|
|
605
|
+
padding: 10px;
|
|
606
|
+
border: none;
|
|
607
|
+
border-radius: 4px;
|
|
608
|
+
cursor: pointer;
|
|
609
|
+
}
|
|
610
|
+
`;
|
|
611
|
+
var BUTTON_CSS_MODULE_FILE_GENERATOR = new FileGeneratorImp(
|
|
612
|
+
"src/button.module.css",
|
|
613
|
+
BUTTON_CSS_MODULE
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
// src/packages/react-package/css-react-package/files/button-file-generator.ts
|
|
617
|
+
var BUTTON = `import React from 'react';
|
|
618
|
+
import * as styles from './button.module.css';
|
|
619
|
+
|
|
620
|
+
export function Button(props: HTMLAttributes<HTMLButtonElement>) {
|
|
621
|
+
return <button className={styles.styledButton} {...props} />;
|
|
622
|
+
}
|
|
623
|
+
`;
|
|
624
|
+
var BUTTON_FILE_GENERATOR = new FileGeneratorImp(
|
|
625
|
+
"src/button.tsx",
|
|
626
|
+
BUTTON
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
// src/packages/react-package/css-react-package/files/button-spec-file-generator.ts
|
|
630
|
+
var BUTTON_SPEC = `import { render, screen, fireEvent } from '@testing-library/react';
|
|
631
|
+
import { Button } from './button';
|
|
632
|
+
|
|
633
|
+
describe('Button', () => {
|
|
634
|
+
it('renders the label correctly', () => {
|
|
635
|
+
render(<Button>Click Me</Button>);
|
|
636
|
+
expect(screen.getByText('Click Me')).toBeDefined();
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it('is a button element', () => {
|
|
640
|
+
render(<Button>Submit</Button>);
|
|
641
|
+
const buttonElement = screen.getByRole('button');
|
|
642
|
+
expect(buttonElement.tagName).toBe('BUTTON');
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
/* Note: Testing for specific CSS classes with CSS Modules is tricky
|
|
646
|
+
because class names are mangled (e.g., _styledButton_123).
|
|
647
|
+
Usually, we just test that the class attribute exists.
|
|
648
|
+
*/
|
|
649
|
+
it('applies a class name', () => {
|
|
650
|
+
render(<Button>Styled</Button>);
|
|
651
|
+
const buttonElement = screen.getByRole('button');
|
|
652
|
+
expect(buttonElement.className).toBeTruthy();
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
`;
|
|
656
|
+
var BUTTON_SPEC_FILE_GENERATOR = new FileGeneratorImp(
|
|
657
|
+
"src/button.spec.tsx",
|
|
658
|
+
BUTTON_SPEC
|
|
659
|
+
);
|
|
660
|
+
|
|
661
|
+
// src/packages/react-package/css-react-package/files/eslint-config-file-generator.ts
|
|
662
|
+
var ESLINT_CONFIG2 = `import base from '@stack-dev/eslint-config/base.mjs';
|
|
663
|
+
import react from '@stack-dev/eslint-config/react.mjs';
|
|
664
|
+
|
|
665
|
+
export default [
|
|
666
|
+
...base,
|
|
667
|
+
...react,
|
|
668
|
+
{
|
|
669
|
+
ignores: ['**/dist/**', '**/coverage/**']
|
|
670
|
+
}
|
|
671
|
+
];
|
|
672
|
+
`;
|
|
673
|
+
var ESLINT_CONFIG_FILE_GENERATOR2 = new FileGeneratorImp(
|
|
674
|
+
"eslint.config.mjs",
|
|
675
|
+
ESLINT_CONFIG2
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
// src/packages/react-package/css-react-package/files/index-file-generator.ts
|
|
679
|
+
var INDEX_TS2 = `export * from './button';
|
|
680
|
+
`;
|
|
681
|
+
var INDEX_FILE_GENERATOR2 = new FileGeneratorImp(
|
|
682
|
+
"src/index.ts",
|
|
683
|
+
INDEX_TS2
|
|
684
|
+
);
|
|
685
|
+
|
|
686
|
+
// src/packages/react-package/css-react-package/files/prettier-config-file-generator.ts
|
|
687
|
+
var PRETTIER_CONFIG2 = `import base from '@stack-dev/prettier-config/base.mjs';
|
|
688
|
+
|
|
689
|
+
export default base;
|
|
690
|
+
`;
|
|
691
|
+
var PRETTIER_CONFIG_FILE_GENERATOR2 = new FileGeneratorImp(
|
|
692
|
+
"prettier.config.mjs",
|
|
693
|
+
PRETTIER_CONFIG2
|
|
694
|
+
);
|
|
695
|
+
|
|
696
|
+
// src/packages/react-package/css-react-package/files/tsconfig-file-generator.ts
|
|
697
|
+
var TSCONFIG2 = `{
|
|
698
|
+
"extends": "@stack-dev/typescript-config/tsconfig.react.json",
|
|
699
|
+
"compilerOptions": {
|
|
700
|
+
"outDir": "dist"
|
|
701
|
+
},
|
|
702
|
+
"include": ["src"]
|
|
703
|
+
}
|
|
704
|
+
`;
|
|
705
|
+
var TSCONFIG_FILE_GENERATOR2 = new FileGeneratorImp(
|
|
706
|
+
"tsconfig.json",
|
|
707
|
+
TSCONFIG2
|
|
708
|
+
);
|
|
709
|
+
|
|
710
|
+
// src/packages/react-package/css-react-package/files/tsup-config-file-generator.ts
|
|
711
|
+
var TSUP_CONFIG2 = `import { defineConfig } from 'tsup';
|
|
712
|
+
|
|
713
|
+
export default defineConfig({
|
|
714
|
+
entry: ['src/index.ts'],
|
|
715
|
+
format: ['cjs', 'esm'],
|
|
716
|
+
dts: true,
|
|
717
|
+
minify: true,
|
|
718
|
+
clean: true,
|
|
719
|
+
injectStyle: true,
|
|
720
|
+
external: ['react', 'react-dom'],
|
|
721
|
+
outExtension({ format }) {
|
|
722
|
+
return {
|
|
723
|
+
js: format === 'esm' ? '.mjs' : '.js',
|
|
724
|
+
};
|
|
725
|
+
},
|
|
726
|
+
});
|
|
727
|
+
`;
|
|
728
|
+
var TSUP_CONFIG_FILE_GENERATOR2 = new FileGeneratorImp(
|
|
729
|
+
"tsup.config.ts",
|
|
730
|
+
TSUP_CONFIG2
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
// src/packages/react-package/css-react-package/files/vitest-config-file-generator.ts
|
|
734
|
+
var VITEST_CONFIG2 = `import { defineConfig } from 'vitest/config';
|
|
735
|
+
import react from '@vitejs/plugin-react';
|
|
736
|
+
|
|
737
|
+
export default defineConfig({
|
|
738
|
+
plugins: [react()],
|
|
739
|
+
test: {
|
|
740
|
+
globals: true,
|
|
741
|
+
environment: 'jsdom',
|
|
742
|
+
coverage: {
|
|
743
|
+
provider: 'v8',
|
|
744
|
+
reporter: ['text', 'json', 'html'],
|
|
745
|
+
},
|
|
746
|
+
css: true,
|
|
747
|
+
},
|
|
748
|
+
});
|
|
749
|
+
`;
|
|
750
|
+
var VITEST_CONFIG_FILE_GENERATOR2 = new FileGeneratorImp(
|
|
751
|
+
"vitest.config.ts",
|
|
752
|
+
VITEST_CONFIG2
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
// src/packages/react-package/css-react-package/create-css-react-package.ts
|
|
756
|
+
async function createCssReactPackage(name) {
|
|
757
|
+
const rootDir = await getWorkspaceRoot();
|
|
758
|
+
const directory = import_path2.default.join(rootDir, "packages", name);
|
|
759
|
+
const namespace = await getNamespace(rootDir);
|
|
760
|
+
const packageName = `${namespace}/${name}`;
|
|
761
|
+
console.log(`\u2728 Creating CSS Modules React library: ${packageName}`);
|
|
762
|
+
const generator = new PackageGenerator(
|
|
763
|
+
directory,
|
|
764
|
+
makePackageGenerator2(packageName, namespace),
|
|
765
|
+
[
|
|
766
|
+
INDEX_FILE_GENERATOR2,
|
|
767
|
+
BUTTON_FILE_GENERATOR,
|
|
768
|
+
BUTTON_CSS_MODULE_FILE_GENERATOR,
|
|
769
|
+
BUTTON_SPEC_FILE_GENERATOR,
|
|
770
|
+
TSUP_CONFIG_FILE_GENERATOR2,
|
|
771
|
+
TSCONFIG_FILE_GENERATOR2,
|
|
772
|
+
PRETTIER_CONFIG_FILE_GENERATOR2,
|
|
773
|
+
ESLINT_CONFIG_FILE_GENERATOR2,
|
|
774
|
+
VITEST_CONFIG_FILE_GENERATOR2
|
|
775
|
+
]
|
|
776
|
+
);
|
|
777
|
+
await generator.generate();
|
|
778
|
+
console.log(`\u2705 Library created at: ${directory}`);
|
|
779
|
+
}
|
|
780
|
+
function makePackageGenerator2(packageName, namespace) {
|
|
781
|
+
const packageJsonModel = new PackageJSON({
|
|
782
|
+
name: packageName,
|
|
783
|
+
peerDependencies: [
|
|
784
|
+
new Dependency("react", ">=18"),
|
|
785
|
+
new Dependency("react-dom", ">=18")
|
|
786
|
+
],
|
|
787
|
+
devDependencies: [
|
|
788
|
+
new Dependency(`${namespace}/eslint-config`, "workspace:*"),
|
|
789
|
+
new Dependency(`${namespace}/prettier-config`, "workspace:*"),
|
|
790
|
+
new Dependency(`${namespace}/typescript-config`, "workspace:*"),
|
|
791
|
+
// Development React binaries
|
|
792
|
+
new Dependency("react", "^18.3.1"),
|
|
793
|
+
new Dependency("react-dom", "^18.3.1"),
|
|
794
|
+
new Dependency("@types/react", "^18.3.1"),
|
|
795
|
+
new Dependency("@types/react-dom", "^18.3.1"),
|
|
796
|
+
// Linting & Formatting
|
|
797
|
+
new Dependency("eslint", "^9.32.0"),
|
|
798
|
+
new Dependency("prettier", "^3.6.2"),
|
|
799
|
+
new Dependency("prettier-plugin-organize-imports", "^4.2.0"),
|
|
800
|
+
// Build
|
|
801
|
+
new Dependency("tsup", "^8.0.0"),
|
|
802
|
+
new Dependency("postcss", "^8.4.0"),
|
|
803
|
+
// Testing
|
|
804
|
+
new Dependency("vitest", "^3.2.4"),
|
|
805
|
+
new Dependency("@vitest/coverage-v8", "^3.2.4"),
|
|
806
|
+
new Dependency("@testing-library/react", "^16.0.0"),
|
|
807
|
+
new Dependency("@testing-library/jest-dom", "^6.0.0"),
|
|
808
|
+
new Dependency("jsdom", "^25.0.0")
|
|
809
|
+
],
|
|
810
|
+
additionalData: {
|
|
811
|
+
version: "0.1.0",
|
|
812
|
+
private: true,
|
|
813
|
+
main: "dist/index.js",
|
|
814
|
+
module: "dist/index.mjs",
|
|
815
|
+
types: "dist/index.d.ts",
|
|
816
|
+
exports: {
|
|
817
|
+
".": {
|
|
818
|
+
development: "./src/index.ts",
|
|
819
|
+
import: "./dist/index.mjs",
|
|
820
|
+
require: "./dist/index.js",
|
|
821
|
+
types: "./dist/index.d.ts"
|
|
822
|
+
},
|
|
823
|
+
"./index.css": "./dist/index.css"
|
|
824
|
+
},
|
|
825
|
+
scripts: {
|
|
826
|
+
build: "tsup",
|
|
827
|
+
lint: "eslint .",
|
|
828
|
+
format: "prettier . --write",
|
|
829
|
+
test: "vitest run",
|
|
830
|
+
"test:watch": "vitest"
|
|
831
|
+
},
|
|
832
|
+
sideEffects: ["**/*.css"]
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
return new PackageJsonGenerator(packageJsonModel, namespace);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/packages/react-package/styled-components-react-package/create-styled-components-react-package.ts
|
|
839
|
+
var import_path3 = __toESM(require("path"));
|
|
840
|
+
|
|
841
|
+
// src/packages/react-package/styled-components-react-package/files/button-file-generator.ts
|
|
842
|
+
var BUTTON2 = `import React, { HTMLAttributes } from 'react';
|
|
843
|
+
import styled from 'styled-components';
|
|
844
|
+
|
|
845
|
+
// This is your "Styled" version of the button
|
|
846
|
+
// No more imports, no more "empty objects"
|
|
847
|
+
const StyledButton = styled.button\`
|
|
848
|
+
background-color: #007bff;
|
|
849
|
+
color: white;
|
|
850
|
+
padding: 10px 20px;
|
|
851
|
+
border: none;
|
|
852
|
+
border-radius: 4px;
|
|
853
|
+
cursor: pointer;
|
|
854
|
+
font-size: 16px;
|
|
855
|
+
|
|
856
|
+
&:hover {
|
|
857
|
+
background-color: #0056b3;
|
|
858
|
+
}
|
|
859
|
+
\`;
|
|
860
|
+
|
|
861
|
+
export function Button(props: HTMLAttributes<HTMLButtonElement>) {
|
|
862
|
+
return <StyledButton {...props} />;
|
|
863
|
+
}
|
|
864
|
+
`;
|
|
865
|
+
var BUTTON_FILE_GENERATOR2 = new FileGeneratorImp(
|
|
866
|
+
"src/button.tsx",
|
|
867
|
+
BUTTON2
|
|
868
|
+
);
|
|
869
|
+
|
|
870
|
+
// src/packages/react-package/styled-components-react-package/files/button-spec-file-generator.ts
|
|
871
|
+
var BUTTON_SPEC2 = `import { render, screen, fireEvent } from '@testing-library/react';
|
|
872
|
+
import { Button } from './button';
|
|
873
|
+
|
|
874
|
+
describe('Button', () => {
|
|
875
|
+
it('renders the label correctly', () => {
|
|
876
|
+
render(<Button>Click Me</Button>);
|
|
877
|
+
expect(screen.getByText('Click Me')).toBeDefined();
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
it('is a button element', () => {
|
|
881
|
+
render(<Button>Submit</Button>);
|
|
882
|
+
const buttonElement = screen.getByRole('button');
|
|
883
|
+
expect(buttonElement.tagName).toBe('BUTTON');
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
/* Note: Testing for specific CSS classes with CSS Modules is tricky
|
|
887
|
+
because class names are mangled (e.g., _styledButton_123).
|
|
888
|
+
Usually, we just test that the class attribute exists.
|
|
889
|
+
*/
|
|
890
|
+
it('applies a class name', () => {
|
|
891
|
+
render(<Button>Styled</Button>);
|
|
892
|
+
const buttonElement = screen.getByRole('button');
|
|
893
|
+
expect(buttonElement.className).toBeTruthy();
|
|
894
|
+
});
|
|
895
|
+
});
|
|
896
|
+
`;
|
|
897
|
+
var BUTTON_SPEC_FILE_GENERATOR2 = new FileGeneratorImp(
|
|
898
|
+
"src/button.spec.tsx",
|
|
899
|
+
BUTTON_SPEC2
|
|
900
|
+
);
|
|
901
|
+
|
|
902
|
+
// src/packages/react-package/styled-components-react-package/files/eslint-config-file-generator.ts
|
|
903
|
+
var ESLINT_CONFIG3 = `import base from '@stack-dev/eslint-config/base.mjs';
|
|
904
|
+
import react from '@stack-dev/eslint-config/react.mjs';
|
|
905
|
+
|
|
906
|
+
export default [
|
|
907
|
+
...base,
|
|
908
|
+
...react,
|
|
909
|
+
{
|
|
910
|
+
ignores: ['**/dist/**', '**/coverage/**']
|
|
911
|
+
}
|
|
912
|
+
];
|
|
913
|
+
`;
|
|
914
|
+
var ESLINT_CONFIG_FILE_GENERATOR3 = new FileGeneratorImp(
|
|
915
|
+
"eslint.config.mjs",
|
|
916
|
+
ESLINT_CONFIG3
|
|
917
|
+
);
|
|
918
|
+
|
|
919
|
+
// src/packages/react-package/styled-components-react-package/files/index-file-generator.ts
|
|
920
|
+
var INDEX_TS3 = `export * from './button';
|
|
921
|
+
`;
|
|
922
|
+
var INDEX_FILE_GENERATOR3 = new FileGeneratorImp(
|
|
923
|
+
"src/index.ts",
|
|
924
|
+
INDEX_TS3
|
|
925
|
+
);
|
|
926
|
+
|
|
927
|
+
// src/packages/react-package/styled-components-react-package/files/prettier-config-file-generator.ts
|
|
928
|
+
var PRETTIER_CONFIG3 = `import base from '@stack-dev/prettier-config/base.mjs';
|
|
929
|
+
|
|
930
|
+
export default base;
|
|
931
|
+
`;
|
|
932
|
+
var PRETTIER_CONFIG_FILE_GENERATOR3 = new FileGeneratorImp(
|
|
933
|
+
"prettier.config.mjs",
|
|
934
|
+
PRETTIER_CONFIG3
|
|
935
|
+
);
|
|
936
|
+
|
|
937
|
+
// src/packages/react-package/styled-components-react-package/files/tsconfig-file-generator.ts
|
|
938
|
+
var TSCONFIG3 = `{
|
|
939
|
+
"extends": "@stack-dev/typescript-config/tsconfig.react.json",
|
|
940
|
+
"compilerOptions": {
|
|
941
|
+
"outDir": "dist"
|
|
942
|
+
},
|
|
943
|
+
"include": ["src"]
|
|
944
|
+
}
|
|
945
|
+
`;
|
|
946
|
+
var TSCONFIG_FILE_GENERATOR3 = new FileGeneratorImp(
|
|
947
|
+
"tsconfig.json",
|
|
948
|
+
TSCONFIG3
|
|
949
|
+
);
|
|
950
|
+
|
|
951
|
+
// src/packages/react-package/styled-components-react-package/files/tsup-config-file-generator.ts
|
|
952
|
+
var TSUP_CONFIG3 = `import { defineConfig } from 'tsup';
|
|
953
|
+
|
|
954
|
+
export default defineConfig({
|
|
955
|
+
entry: ['src/index.ts'],
|
|
956
|
+
format: ['esm', 'cjs'],
|
|
957
|
+
dts: true,
|
|
958
|
+
clean: true,
|
|
959
|
+
external: ['react', 'react-dom', 'styled-components'],
|
|
960
|
+
outExtension({ format }) {
|
|
961
|
+
return {
|
|
962
|
+
js: format === 'esm' ? '.mjs' : '.js',
|
|
963
|
+
};
|
|
964
|
+
},
|
|
965
|
+
});`;
|
|
966
|
+
var TSUP_CONFIG_FILE_GENERATOR3 = new FileGeneratorImp(
|
|
967
|
+
"tsup.config.ts",
|
|
968
|
+
TSUP_CONFIG3
|
|
969
|
+
);
|
|
970
|
+
|
|
971
|
+
// src/packages/react-package/styled-components-react-package/files/vitest-config-file-generator.ts
|
|
972
|
+
var VITEST_CONFIG3 = `import { defineConfig } from 'vitest/config';
|
|
973
|
+
import react from '@vitejs/plugin-react';
|
|
974
|
+
|
|
975
|
+
export default defineConfig({
|
|
976
|
+
plugins: [react()],
|
|
977
|
+
test: {
|
|
978
|
+
globals: true,
|
|
979
|
+
environment: 'jsdom',
|
|
980
|
+
coverage: {
|
|
981
|
+
provider: 'v8',
|
|
982
|
+
reporter: ['text', 'json', 'html'],
|
|
983
|
+
},
|
|
984
|
+
css: true,
|
|
985
|
+
},
|
|
986
|
+
});
|
|
987
|
+
`;
|
|
988
|
+
var VITEST_CONFIG_FILE_GENERATOR3 = new FileGeneratorImp(
|
|
989
|
+
"vitest.config.ts",
|
|
990
|
+
VITEST_CONFIG3
|
|
991
|
+
);
|
|
992
|
+
|
|
993
|
+
// src/packages/react-package/styled-components-react-package/create-styled-components-react-package.ts
|
|
994
|
+
async function createStyledComponentsReactPackage(name) {
|
|
995
|
+
const rootDir = await getWorkspaceRoot();
|
|
996
|
+
const directory = import_path3.default.join(rootDir, "packages", name);
|
|
997
|
+
const namespace = await getNamespace(rootDir);
|
|
998
|
+
const packageName = `${namespace}/${name}`;
|
|
999
|
+
console.log(
|
|
1000
|
+
`\u2728 Creating Styled Components Modules React library: ${packageName}`
|
|
1001
|
+
);
|
|
1002
|
+
const generator = new PackageGenerator(
|
|
1003
|
+
directory,
|
|
1004
|
+
makePackageGenerator3(packageName, namespace),
|
|
1005
|
+
[
|
|
1006
|
+
INDEX_FILE_GENERATOR3,
|
|
1007
|
+
BUTTON_FILE_GENERATOR2,
|
|
1008
|
+
BUTTON_SPEC_FILE_GENERATOR2,
|
|
1009
|
+
TSUP_CONFIG_FILE_GENERATOR3,
|
|
1010
|
+
TSCONFIG_FILE_GENERATOR3,
|
|
1011
|
+
PRETTIER_CONFIG_FILE_GENERATOR3,
|
|
1012
|
+
ESLINT_CONFIG_FILE_GENERATOR3,
|
|
1013
|
+
VITEST_CONFIG_FILE_GENERATOR3
|
|
1014
|
+
]
|
|
1015
|
+
);
|
|
1016
|
+
await generator.generate();
|
|
1017
|
+
console.log(`\u2705 Library created at: ${directory}`);
|
|
1018
|
+
}
|
|
1019
|
+
function makePackageGenerator3(packageName, namespace) {
|
|
1020
|
+
const packageJsonModel = new PackageJSON({
|
|
1021
|
+
name: packageName,
|
|
1022
|
+
// Peer deps are crucial for Styled Components to prevent "Multiple instances" errors
|
|
1023
|
+
peerDependencies: [
|
|
1024
|
+
new Dependency("react", ">=18"),
|
|
1025
|
+
new Dependency("react-dom", ">=18"),
|
|
1026
|
+
new Dependency("styled-components", ">=6")
|
|
1027
|
+
],
|
|
1028
|
+
devDependencies: [
|
|
1029
|
+
new Dependency(`${namespace}/eslint-config`, "workspace:*"),
|
|
1030
|
+
new Dependency(`${namespace}/prettier-config`, "workspace:*"),
|
|
1031
|
+
new Dependency(`${namespace}/typescript-config`, "workspace:*"),
|
|
1032
|
+
// Development React binaries
|
|
1033
|
+
new Dependency("react", "^18.3.1"),
|
|
1034
|
+
new Dependency("react-dom", "^18.3.1"),
|
|
1035
|
+
new Dependency("@types/react", "^18.3.1"),
|
|
1036
|
+
new Dependency("@types/react-dom", "^18.3.1"),
|
|
1037
|
+
// Styled Components types and binary for build time
|
|
1038
|
+
new Dependency("styled-components", "^6.1.13"),
|
|
1039
|
+
new Dependency("@types/styled-components", "^5.1.34"),
|
|
1040
|
+
// Linting & Formatting
|
|
1041
|
+
new Dependency("eslint", "^9.32.0"),
|
|
1042
|
+
new Dependency("prettier", "^3.6.2"),
|
|
1043
|
+
new Dependency("prettier-plugin-organize-imports", "^4.2.0"),
|
|
1044
|
+
// Build
|
|
1045
|
+
new Dependency("tsup", "^8.0.0"),
|
|
1046
|
+
// Testing
|
|
1047
|
+
new Dependency("vitest", "^3.2.4"),
|
|
1048
|
+
new Dependency("@vitest/coverage-v8", "^3.2.4"),
|
|
1049
|
+
new Dependency("@testing-library/react", "^16.0.0"),
|
|
1050
|
+
new Dependency("@testing-library/jest-dom", "^6.0.0"),
|
|
1051
|
+
new Dependency("jsdom", "^25.0.0")
|
|
1052
|
+
],
|
|
1053
|
+
additionalData: {
|
|
1054
|
+
version: "0.1.0",
|
|
1055
|
+
private: true,
|
|
1056
|
+
type: "module",
|
|
1057
|
+
// Added this to ensure ESM consistency
|
|
1058
|
+
main: "dist/index.js",
|
|
1059
|
+
module: "dist/index.mjs",
|
|
1060
|
+
types: "dist/index.d.ts",
|
|
1061
|
+
exports: {
|
|
1062
|
+
".": {
|
|
1063
|
+
development: "./src/index.ts",
|
|
1064
|
+
import: "./dist/index.mjs",
|
|
1065
|
+
require: "./dist/index.js",
|
|
1066
|
+
types: "./dist/index.d.ts"
|
|
1067
|
+
}
|
|
1068
|
+
// Removed './index.css' as it's no longer produced by Styled Components
|
|
1069
|
+
},
|
|
1070
|
+
scripts: {
|
|
1071
|
+
build: "tsup",
|
|
1072
|
+
dev: "tsup --watch",
|
|
1073
|
+
// Helpful for local lib dev
|
|
1074
|
+
lint: "eslint .",
|
|
1075
|
+
format: "prettier . --write",
|
|
1076
|
+
test: "vitest run",
|
|
1077
|
+
"test:watch": "vitest"
|
|
1078
|
+
},
|
|
1079
|
+
// Set to false or removed because Styled Components are pure JS/TS
|
|
1080
|
+
sideEffects: false
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
return new PackageJsonGenerator(packageJsonModel, namespace);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// src/packages/react-package/create-react-package.ts
|
|
1087
|
+
async function createReactPackage(name, style) {
|
|
1088
|
+
switch (style) {
|
|
1089
|
+
case "tailwind":
|
|
1090
|
+
await createTailwindReactPackage(name);
|
|
1091
|
+
break;
|
|
1092
|
+
case "css-modules":
|
|
1093
|
+
await createCssReactPackage(name);
|
|
1094
|
+
break;
|
|
1095
|
+
case "styled-components":
|
|
1096
|
+
await createStyledComponentsReactPackage(name);
|
|
1097
|
+
break;
|
|
1098
|
+
case "none":
|
|
1099
|
+
await createUnstyledReactPackage(name);
|
|
1100
|
+
break;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// src/packages/create-config-package.ts
|
|
1105
|
+
var import_node_path4 = __toESM(require("path"));
|
|
1106
|
+
async function createConfigPackage(name) {
|
|
1107
|
+
const rootDir = await getWorkspaceRoot();
|
|
1108
|
+
const directory = import_node_path4.default.join(rootDir, "configs", name);
|
|
1109
|
+
const namespace = await getNamespace(rootDir);
|
|
1110
|
+
const packageName = `${namespace}/${name}`;
|
|
1111
|
+
const packageJsonModel = new PackageJSON({
|
|
1112
|
+
name: packageName,
|
|
1113
|
+
additionalData: {
|
|
1114
|
+
version: "0.1.0",
|
|
1115
|
+
private: true
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
const generator = new PackageGenerator(
|
|
1119
|
+
directory,
|
|
1120
|
+
new PackageJsonGenerator(packageJsonModel, namespace),
|
|
1121
|
+
[]
|
|
1122
|
+
);
|
|
1123
|
+
await generator.generate();
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// src/utils/package.ts
|
|
1127
|
+
var import_fast_glob = require("fast-glob");
|
|
1128
|
+
var import_node_path5 = __toESM(require("path"));
|
|
1129
|
+
async function getCurrentPackage(directory = process.cwd()) {
|
|
1130
|
+
const packageRoot = await getPackageRoot(directory);
|
|
1131
|
+
const packageJson = await getDirectoryPackageJson(packageRoot);
|
|
1132
|
+
return getPackageByName(packageJson.name);
|
|
1133
|
+
}
|
|
1134
|
+
async function getPackageRoot(directory = process.cwd()) {
|
|
1135
|
+
const parent = import_node_path5.default.dirname(directory);
|
|
1136
|
+
if (parent === directory) {
|
|
1137
|
+
throw new Error("Not a package.");
|
|
1138
|
+
}
|
|
1139
|
+
if (await isPackageRoot(directory)) {
|
|
1140
|
+
return directory;
|
|
1141
|
+
}
|
|
1142
|
+
return getPackageRoot(parent);
|
|
1143
|
+
}
|
|
1144
|
+
async function getPackageByName(name) {
|
|
1145
|
+
const all = await getAllPackages();
|
|
1146
|
+
const match = all.find((p) => p.name === name);
|
|
1147
|
+
if (match === void 0) {
|
|
1148
|
+
throw new Error(`No package with name "${name}".`);
|
|
1149
|
+
}
|
|
1150
|
+
return match;
|
|
1151
|
+
}
|
|
1152
|
+
async function getAllPackages(directory = process.cwd()) {
|
|
1153
|
+
const workspaceRoot = await getWorkspaceRoot(directory);
|
|
1154
|
+
const workspaceFile = await getDirectoryWorkspaceFile(workspaceRoot);
|
|
1155
|
+
const results = [];
|
|
1156
|
+
for (const seg of workspaceFile.packages) {
|
|
1157
|
+
const packageType = getPackageType(seg);
|
|
1158
|
+
const packageJsonPaths = await (0, import_fast_glob.glob)(`${workspaceRoot}/${seg}/package.json`);
|
|
1159
|
+
const packageDirectories = packageJsonPaths.map((p) => import_node_path5.default.dirname(p));
|
|
1160
|
+
for (const directory2 of packageDirectories) {
|
|
1161
|
+
const name = (await getDirectoryPackageJson(directory2)).name;
|
|
1162
|
+
results.push({
|
|
1163
|
+
name,
|
|
1164
|
+
directory: directory2,
|
|
1165
|
+
type: packageType
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
return results;
|
|
1170
|
+
}
|
|
1171
|
+
function getPackageType(segment) {
|
|
1172
|
+
if (segment.startsWith("app")) {
|
|
1173
|
+
return "App";
|
|
1174
|
+
} else if (segment.startsWith("config")) {
|
|
1175
|
+
return "Config";
|
|
1176
|
+
} else if (segment.startsWith("package") || segment.startsWith("lib")) {
|
|
1177
|
+
return "Library";
|
|
1178
|
+
} else {
|
|
1179
|
+
return "Unknown";
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
function comparePackages(a, b) {
|
|
1183
|
+
const packageTypeDifference = comparePackageTypes(a.type, b.type);
|
|
1184
|
+
if (packageTypeDifference !== 0) {
|
|
1185
|
+
return packageTypeDifference;
|
|
1186
|
+
} else {
|
|
1187
|
+
return a.name.localeCompare(b.name);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
function comparePackageTypes(a, b) {
|
|
1191
|
+
return getPackageTypeIndex(a) - getPackageTypeIndex(b);
|
|
1192
|
+
}
|
|
1193
|
+
function getPackageTypeIndex(packageType) {
|
|
1194
|
+
switch (packageType) {
|
|
1195
|
+
case "Library":
|
|
1196
|
+
return 0;
|
|
1197
|
+
case "Config":
|
|
1198
|
+
return 1;
|
|
1199
|
+
case "App":
|
|
1200
|
+
return 2;
|
|
1201
|
+
case "Unknown":
|
|
1202
|
+
return 3;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
async function isPackageRoot(directory) {
|
|
1206
|
+
return await fileExists(import_node_path5.default.join(directory, "package.json"));
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// src/utils/package-type.ts
|
|
1210
|
+
var import_enquirer = require("enquirer");
|
|
1211
|
+
var packageTypes = [
|
|
1212
|
+
"library",
|
|
1213
|
+
"config",
|
|
1214
|
+
"react",
|
|
1215
|
+
"vite",
|
|
1216
|
+
"fastify",
|
|
1217
|
+
"next",
|
|
1218
|
+
"cli"
|
|
1219
|
+
];
|
|
1220
|
+
async function pickPackageType(options) {
|
|
1221
|
+
if (options?.type && isPackageType(options.type)) {
|
|
1222
|
+
return options.type;
|
|
1223
|
+
} else if (options?.type && !isPackageType(options.type)) {
|
|
1224
|
+
throw new Error(
|
|
1225
|
+
`--type setting "${options.type}" is invalid, must be one of ${packageTypes.join(", ")}.`
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
const response = await (0, import_enquirer.prompt)({
|
|
1229
|
+
type: "select",
|
|
1230
|
+
name: "type",
|
|
1231
|
+
message: "What kind of package do you want?",
|
|
1232
|
+
choices: [...packageTypes]
|
|
1233
|
+
});
|
|
1234
|
+
if (!isPackageType(response.type)) {
|
|
1235
|
+
throw new Error(
|
|
1236
|
+
`Type "${response.type}" is invalid, must be one of ${packageTypes.join(", ")}.`
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
return response.type;
|
|
1240
|
+
}
|
|
1241
|
+
function isPackageType(s) {
|
|
1242
|
+
return packageTypes.some((p) => p === s);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// src/utils/style-type.ts
|
|
1246
|
+
var import_enquirer2 = require("enquirer");
|
|
1247
|
+
var styleTypes = [
|
|
1248
|
+
"tailwind",
|
|
1249
|
+
"css-modules",
|
|
1250
|
+
"styled-components",
|
|
1251
|
+
"none"
|
|
1252
|
+
];
|
|
1253
|
+
async function pickStyleType(options) {
|
|
1254
|
+
if (options?.style && isStyleType(options?.style)) {
|
|
1255
|
+
return options?.style;
|
|
1256
|
+
} else if (options?.style && !isStyleType(options?.style)) {
|
|
1257
|
+
throw new Error(
|
|
1258
|
+
`--style setting "${options.style}" is invalid, must be one of ${styleTypes.join(", ")}.`
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
const response = await (0, import_enquirer2.prompt)({
|
|
1262
|
+
type: "select",
|
|
1263
|
+
name: "type",
|
|
1264
|
+
message: "What kind of style do you want?",
|
|
1265
|
+
choices: [...styleTypes]
|
|
1266
|
+
});
|
|
1267
|
+
if (!isStyleType(response.type)) {
|
|
1268
|
+
throw new Error(
|
|
1269
|
+
`Type "${response.type}" is invalid, must be one of ${styleTypes.join(", ")}.`
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
return response.type;
|
|
1273
|
+
}
|
|
1274
|
+
function isStyleType(s) {
|
|
1275
|
+
return styleTypes.some((p) => p === s);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// src/index.ts
|
|
1279
|
+
var import_commander = require("commander");
|
|
1280
|
+
var import_enquirer3 = require("enquirer");
|
|
1281
|
+
|
|
1282
|
+
// src/link-packages.ts
|
|
1283
|
+
var import_promises4 = __toESM(require("fs/promises"));
|
|
1284
|
+
var import_node_path6 = __toESM(require("path"));
|
|
1285
|
+
|
|
1286
|
+
// src/tsconfig/tsconfig.ts
|
|
1287
|
+
var JSON52 = __toESM(require("json5"));
|
|
1288
|
+
var import_core3 = require("@stack-dev/core");
|
|
1289
|
+
var import_lodash3 = require("lodash");
|
|
1290
|
+
|
|
1291
|
+
// src/tsconfig/compiler-options.ts
|
|
1292
|
+
var import_core2 = require("@stack-dev/core");
|
|
1293
|
+
var import_lodash2 = require("lodash");
|
|
1294
|
+
var CompilerOptions = class _CompilerOptions {
|
|
1295
|
+
_additionalData;
|
|
1296
|
+
_paths;
|
|
1297
|
+
constructor(args) {
|
|
1298
|
+
this._paths = args?.paths ?? {};
|
|
1299
|
+
this._additionalData = args?.additionalData ?? {};
|
|
1300
|
+
}
|
|
1301
|
+
get paths() {
|
|
1302
|
+
return this._paths;
|
|
1303
|
+
}
|
|
1304
|
+
get additionalData() {
|
|
1305
|
+
return this._additionalData;
|
|
1306
|
+
}
|
|
1307
|
+
setPaths(paths) {
|
|
1308
|
+
return new _CompilerOptions({
|
|
1309
|
+
paths,
|
|
1310
|
+
additionalData: this._additionalData
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
format() {
|
|
1314
|
+
const json = {
|
|
1315
|
+
paths: this._paths,
|
|
1316
|
+
...this._additionalData
|
|
1317
|
+
};
|
|
1318
|
+
const ordered = (0, import_core2.sortKeys)(json, compareKeys);
|
|
1319
|
+
return JSON.stringify(ordered, null, 2);
|
|
1320
|
+
}
|
|
1321
|
+
equals(other) {
|
|
1322
|
+
if (other instanceof _CompilerOptions) {
|
|
1323
|
+
return (0, import_lodash2.isEqual)(this._paths, other._paths) && (0, import_lodash2.isEqual)(this._additionalData, other._additionalData);
|
|
1324
|
+
} else {
|
|
1325
|
+
return false;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
function compareKeys(a, b) {
|
|
1330
|
+
return getKeyIndex2(a) - getKeyIndex2(b);
|
|
1331
|
+
}
|
|
1332
|
+
function getKeyIndex2(s) {
|
|
1333
|
+
const order = [
|
|
1334
|
+
"target",
|
|
1335
|
+
"module",
|
|
1336
|
+
"moduleResolution",
|
|
1337
|
+
"esModuleInterop",
|
|
1338
|
+
"lib",
|
|
1339
|
+
"types",
|
|
1340
|
+
"strict",
|
|
1341
|
+
"allowJs"
|
|
1342
|
+
];
|
|
1343
|
+
if (order.every((key) => key !== s)) {
|
|
1344
|
+
return Number.MAX_VALUE;
|
|
1345
|
+
} else {
|
|
1346
|
+
return order.indexOf(s);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// src/tsconfig/reference.ts
|
|
1351
|
+
var Reference = class _Reference {
|
|
1352
|
+
_path;
|
|
1353
|
+
constructor(path14) {
|
|
1354
|
+
this._path = path14;
|
|
1355
|
+
}
|
|
1356
|
+
get path() {
|
|
1357
|
+
return this._path;
|
|
1358
|
+
}
|
|
1359
|
+
equals(other) {
|
|
1360
|
+
if (other instanceof _Reference) {
|
|
1361
|
+
return this._path === other._path;
|
|
1362
|
+
} else {
|
|
1363
|
+
return false;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1368
|
+
// src/tsconfig/tsconfig.ts
|
|
1369
|
+
var TSConfig = class _TSConfig {
|
|
1370
|
+
_compilerOptions;
|
|
1371
|
+
_references;
|
|
1372
|
+
_additionalData;
|
|
1373
|
+
constructor(args) {
|
|
1374
|
+
this._compilerOptions = args?.compilerOptions ?? new CompilerOptions();
|
|
1375
|
+
this._references = args?.references ?? [];
|
|
1376
|
+
this._additionalData = args?.additionalData ?? {};
|
|
1377
|
+
}
|
|
1378
|
+
get compilerOptions() {
|
|
1379
|
+
return this._compilerOptions;
|
|
1380
|
+
}
|
|
1381
|
+
addReference(reference) {
|
|
1382
|
+
return new _TSConfig({
|
|
1383
|
+
compilerOptions: this._compilerOptions,
|
|
1384
|
+
references: [...this._references, reference],
|
|
1385
|
+
additionalData: this._additionalData
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
setCompilerOptions(compilerOptions) {
|
|
1389
|
+
return new _TSConfig({
|
|
1390
|
+
compilerOptions,
|
|
1391
|
+
references: this._references,
|
|
1392
|
+
additionalData: this._additionalData
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
static parse(s) {
|
|
1396
|
+
const json = JSON52.parse(s);
|
|
1397
|
+
const references = _TSConfig.parseReferences(json);
|
|
1398
|
+
const compilerOptions = new CompilerOptions({
|
|
1399
|
+
paths: json.compilerOptions?.paths,
|
|
1400
|
+
...json.compilerOptions
|
|
1401
|
+
});
|
|
1402
|
+
const additionalData = { ...json };
|
|
1403
|
+
delete additionalData["compilerOptions"];
|
|
1404
|
+
delete additionalData["references"];
|
|
1405
|
+
return new _TSConfig({
|
|
1406
|
+
compilerOptions,
|
|
1407
|
+
references,
|
|
1408
|
+
additionalData
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
static parseReferences(json) {
|
|
1412
|
+
if (typeof json === "object" && json !== null && "references" in json && json.references instanceof Array) {
|
|
1413
|
+
return json.references.map(
|
|
1414
|
+
(r) => new Reference(r.path)
|
|
1415
|
+
);
|
|
1416
|
+
} else {
|
|
1417
|
+
return [];
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
format() {
|
|
1421
|
+
const compilerOptions = JSON52.parse(this.compilerOptions.format());
|
|
1422
|
+
const json = {
|
|
1423
|
+
compilerOptions,
|
|
1424
|
+
references: this._references.map((r) => ({ path: r.path })),
|
|
1425
|
+
...this._additionalData
|
|
1426
|
+
};
|
|
1427
|
+
const ordered = (0, import_core3.sortKeys)(json, compareKeys2);
|
|
1428
|
+
return JSON.stringify(ordered, null, 2);
|
|
1429
|
+
}
|
|
1430
|
+
equals(other) {
|
|
1431
|
+
if (other instanceof _TSConfig) {
|
|
1432
|
+
const sameReferences = (0, import_core3.haveSameItems)(
|
|
1433
|
+
this._references,
|
|
1434
|
+
other._references,
|
|
1435
|
+
(r1, r2) => r1.equals(r2)
|
|
1436
|
+
);
|
|
1437
|
+
return this._compilerOptions.equals(other._compilerOptions) && sameReferences && (0, import_lodash3.isEqual)(this._additionalData, other._additionalData);
|
|
1438
|
+
} else {
|
|
1439
|
+
return false;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
function compareKeys2(a, b) {
|
|
1444
|
+
return getKeyIndex3(a) - getKeyIndex3(b);
|
|
1445
|
+
}
|
|
1446
|
+
function getKeyIndex3(s) {
|
|
1447
|
+
const order = [
|
|
1448
|
+
"extends",
|
|
1449
|
+
"compilerOptions",
|
|
1450
|
+
"include",
|
|
1451
|
+
"exclude",
|
|
1452
|
+
"references"
|
|
1453
|
+
];
|
|
1454
|
+
if (order.every((key) => key !== s)) {
|
|
1455
|
+
return Number.MAX_VALUE;
|
|
1456
|
+
} else {
|
|
1457
|
+
return order.indexOf(s);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
// src/link-packages.ts
|
|
1462
|
+
async function linkPackages(current, target, development) {
|
|
1463
|
+
await updatePackageJSON(current, target, development);
|
|
1464
|
+
await updateTSConfig(current, target);
|
|
1465
|
+
}
|
|
1466
|
+
async function updatePackageJSON(current, target, development) {
|
|
1467
|
+
const namespace = await getNamespace();
|
|
1468
|
+
const packageJSON = await getDirectoryPackageJson(current.directory);
|
|
1469
|
+
const updated = addDependency(packageJSON, target, development);
|
|
1470
|
+
const packageJSONPath = getPackageJSONPath(current.directory);
|
|
1471
|
+
await import_promises4.default.writeFile(packageJSONPath, updated.format(namespace));
|
|
1472
|
+
}
|
|
1473
|
+
function addDependency(packageJSON, target, development) {
|
|
1474
|
+
const dependency = new Dependency(target.name, "workspace:*");
|
|
1475
|
+
if (development) {
|
|
1476
|
+
return packageJSON.addDevDependency(dependency);
|
|
1477
|
+
} else {
|
|
1478
|
+
return packageJSON.addDependency(dependency);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
async function updateTSConfig(current, target) {
|
|
1482
|
+
const tsconfigPath = import_node_path6.default.join(current.directory, "tsconfig.json");
|
|
1483
|
+
const tsconfigContents = await import_promises4.default.readFile(tsconfigPath, "utf8");
|
|
1484
|
+
const tsconfig = TSConfig.parse(tsconfigContents);
|
|
1485
|
+
const targetDirectory = import_node_path6.default.join(target.directory, "src", "index.ts");
|
|
1486
|
+
const updatedPaths = {
|
|
1487
|
+
...tsconfig.compilerOptions.paths,
|
|
1488
|
+
[target.name]: [import_node_path6.default.relative(current.directory, targetDirectory)]
|
|
1489
|
+
};
|
|
1490
|
+
const updatedCompilerOptions = tsconfig.compilerOptions.setPaths(updatedPaths);
|
|
1491
|
+
const updated = tsconfig.setCompilerOptions(updatedCompilerOptions);
|
|
1492
|
+
await import_promises4.default.writeFile(tsconfigPath, updated.format());
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/packages/vite-react-app/create-vite-react-app.ts
|
|
1496
|
+
var import_path4 = __toESM(require("path"));
|
|
1497
|
+
|
|
1498
|
+
// src/packages/vite-react-app/files/index-html-file-generator.ts
|
|
1499
|
+
var INDEX_HTML = `<!doctype html>
|
|
1500
|
+
<html lang="en">
|
|
1501
|
+
<head>
|
|
1502
|
+
<meta charset="UTF-8" />
|
|
1503
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1504
|
+
<title>Vite + React + Stack-Dev</title>
|
|
1505
|
+
</head>
|
|
1506
|
+
<body>
|
|
1507
|
+
<div id="root"></div>
|
|
1508
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
1509
|
+
</body>
|
|
1510
|
+
</html>
|
|
1511
|
+
`;
|
|
1512
|
+
var INDEX_HTML_FILE_GENERATOR = new FileGeneratorImp(
|
|
1513
|
+
"index.html",
|
|
1514
|
+
INDEX_HTML
|
|
1515
|
+
);
|
|
1516
|
+
|
|
1517
|
+
// src/packages/vite-react-app/files/main-file-generator.ts
|
|
1518
|
+
var MAIN = `import React from 'react';
|
|
1519
|
+
import ReactDOM from 'react-dom/client';
|
|
1520
|
+
import { App } from './App';
|
|
1521
|
+
|
|
1522
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
1523
|
+
<React.StrictMode>
|
|
1524
|
+
<App />
|
|
1525
|
+
</React.StrictMode>,
|
|
1526
|
+
);
|
|
1527
|
+
`;
|
|
1528
|
+
var MAIN_FILE_GENERATOR = new FileGeneratorImp("src/main.tsx", MAIN);
|
|
1529
|
+
|
|
1530
|
+
// src/packages/vite-react-app/files/vite-config-file-generator.ts
|
|
1531
|
+
var VITE_CONFIG = `import { defineConfig } from 'vite';
|
|
1532
|
+
import react from '@vitejs/plugin-react';
|
|
1533
|
+
|
|
1534
|
+
export default defineConfig({
|
|
1535
|
+
plugins: [react()],
|
|
1536
|
+
server: {
|
|
1537
|
+
port: 3000,
|
|
1538
|
+
},
|
|
1539
|
+
});
|
|
1540
|
+
`;
|
|
1541
|
+
var VITE_CONFIG_FILE_GENERATOR = new FileGeneratorImp(
|
|
1542
|
+
"vite.config.ts",
|
|
1543
|
+
VITE_CONFIG
|
|
1544
|
+
);
|
|
1545
|
+
|
|
1546
|
+
// src/packages/vite-react-app/files/app-file-generator.ts
|
|
1547
|
+
var APP = `import React, { useState } from 'react';
|
|
1548
|
+
|
|
1549
|
+
export function App() {
|
|
1550
|
+
const [count, setCount] = useState(0);
|
|
1551
|
+
|
|
1552
|
+
return (
|
|
1553
|
+
<div style={{
|
|
1554
|
+
padding: '2rem',
|
|
1555
|
+
fontFamily: 'system-ui, sans-serif',
|
|
1556
|
+
textAlign: 'center'
|
|
1557
|
+
}}>
|
|
1558
|
+
<h1>Stack-Dev App</h1>
|
|
1559
|
+
<div className="card">
|
|
1560
|
+
<button onClick={function() { setCount(count + 1) }}>
|
|
1561
|
+
Count is {count}
|
|
1562
|
+
</button>
|
|
1563
|
+
</div>
|
|
1564
|
+
<p>
|
|
1565
|
+
Edit <code>src/App.tsx</code> and save to test HMR
|
|
1566
|
+
</p>
|
|
1567
|
+
</div>
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1570
|
+
`;
|
|
1571
|
+
var APP_FILE_GENERATOR = new FileGeneratorImp("src/App.tsx", APP);
|
|
1572
|
+
|
|
1573
|
+
// src/packages/vite-react-app/files/eslint-config-file-generator.ts
|
|
1574
|
+
var ESLINT_CONFIG4 = `import base from '@stack-dev/eslint-config/base.mjs';
|
|
1575
|
+
|
|
1576
|
+
export default [...base, { ignores: ['**/dist/**'] }];
|
|
1577
|
+
`;
|
|
1578
|
+
var ESLINT_CONFIG_FILE_GENERATOR4 = new FileGeneratorImp(
|
|
1579
|
+
"eslint.config.mjs",
|
|
1580
|
+
ESLINT_CONFIG4
|
|
1581
|
+
);
|
|
1582
|
+
|
|
1583
|
+
// src/packages/vite-react-app/files/prettier-config-file-generator.ts
|
|
1584
|
+
var PRETTIER_CONFIG4 = `import base from '@stack-dev/prettier-config/base.mjs';
|
|
1585
|
+
|
|
1586
|
+
export default base;
|
|
1587
|
+
`;
|
|
1588
|
+
var PRETTIER_CONFIG_FILE_GENERATOR4 = new FileGeneratorImp(
|
|
1589
|
+
"prettier.config.mjs",
|
|
1590
|
+
PRETTIER_CONFIG4
|
|
1591
|
+
);
|
|
1592
|
+
|
|
1593
|
+
// src/packages/vite-react-app/files/tsconfig-file-generator.ts
|
|
1594
|
+
var TSCONFIG4 = `{
|
|
1595
|
+
"extends": "@stack-dev/typescript-config/tsconfig.react.json",
|
|
1596
|
+
"compilerOptions": {
|
|
1597
|
+
"outDir": "dist"
|
|
1598
|
+
},
|
|
1599
|
+
"include": ["src"]
|
|
1600
|
+
}
|
|
1601
|
+
`;
|
|
1602
|
+
var TSCONFIG_FILE_GENERATOR4 = new FileGeneratorImp(
|
|
1603
|
+
"tsconfig.json",
|
|
1604
|
+
TSCONFIG4
|
|
1605
|
+
);
|
|
1606
|
+
|
|
1607
|
+
// src/packages/vite-react-app/files/vitest-config-file-generator.ts
|
|
1608
|
+
var VITEST_CONFIG4 = `import { defineConfig } from 'vitest/config';
|
|
1609
|
+
|
|
1610
|
+
export default defineConfig({
|
|
1611
|
+
test: {
|
|
1612
|
+
globals: true,
|
|
1613
|
+
coverage: {
|
|
1614
|
+
provider: 'v8',
|
|
1615
|
+
},
|
|
1616
|
+
environment: 'node',
|
|
1617
|
+
},
|
|
1618
|
+
});
|
|
1619
|
+
`;
|
|
1620
|
+
var VITEST_CONFIG_FILE_GENERATOR4 = new FileGeneratorImp(
|
|
1621
|
+
"vitest.config.ts",
|
|
1622
|
+
VITEST_CONFIG4
|
|
1623
|
+
);
|
|
1624
|
+
|
|
1625
|
+
// src/packages/vite-react-app/create-vite-react-app.ts
|
|
1626
|
+
async function createViteReactApp(name) {
|
|
1627
|
+
const rootDir = await getWorkspaceRoot();
|
|
1628
|
+
const directory = import_path4.default.join(rootDir, "apps", name);
|
|
1629
|
+
const namespace = await getNamespace(rootDir);
|
|
1630
|
+
const packageName = `${namespace}/${name}`;
|
|
1631
|
+
console.log(`\u{1F680} Creating Vite React App: ${packageName}`);
|
|
1632
|
+
const generator = new PackageGenerator(
|
|
1633
|
+
directory,
|
|
1634
|
+
makeAppPackageGenerator(packageName, namespace),
|
|
1635
|
+
[
|
|
1636
|
+
VITE_CONFIG_FILE_GENERATOR,
|
|
1637
|
+
INDEX_HTML_FILE_GENERATOR,
|
|
1638
|
+
MAIN_FILE_GENERATOR,
|
|
1639
|
+
APP_FILE_GENERATOR,
|
|
1640
|
+
TSCONFIG_FILE_GENERATOR4,
|
|
1641
|
+
PRETTIER_CONFIG_FILE_GENERATOR4,
|
|
1642
|
+
ESLINT_CONFIG_FILE_GENERATOR4,
|
|
1643
|
+
VITEST_CONFIG_FILE_GENERATOR4
|
|
1644
|
+
]
|
|
1645
|
+
);
|
|
1646
|
+
await generator.generate();
|
|
1647
|
+
}
|
|
1648
|
+
function makeAppPackageGenerator(packageName, namespace) {
|
|
1649
|
+
const packageJsonModel = new PackageJSON({
|
|
1650
|
+
name: packageName,
|
|
1651
|
+
dependencies: [
|
|
1652
|
+
new Dependency("react", "^18.3.1"),
|
|
1653
|
+
new Dependency("react-dom", "^18.3.1")
|
|
1654
|
+
],
|
|
1655
|
+
devDependencies: [
|
|
1656
|
+
new Dependency(`${namespace}/eslint-config`, "workspace:*"),
|
|
1657
|
+
new Dependency(`${namespace}/prettier-config`, "workspace:*"),
|
|
1658
|
+
new Dependency(`${namespace}/typescript-config`, "workspace:*"),
|
|
1659
|
+
new Dependency("@types/react", "^18.3.1"),
|
|
1660
|
+
new Dependency("@types/react-dom", "^18.3.1"),
|
|
1661
|
+
new Dependency("@vitejs/plugin-react", "^4.3.1"),
|
|
1662
|
+
new Dependency("vite", "^5.4.2"),
|
|
1663
|
+
new Dependency("typescript", "^5.5.4"),
|
|
1664
|
+
new Dependency("eslint", "^9.32.0"),
|
|
1665
|
+
new Dependency("prettier", "^3.6.2")
|
|
1666
|
+
],
|
|
1667
|
+
additionalData: {
|
|
1668
|
+
version: "0.1.0",
|
|
1669
|
+
private: true,
|
|
1670
|
+
type: "module",
|
|
1671
|
+
scripts: {
|
|
1672
|
+
dev: "vite",
|
|
1673
|
+
build: "tsc && vite build",
|
|
1674
|
+
preview: "vite preview",
|
|
1675
|
+
start: "pnpm run preview",
|
|
1676
|
+
lint: "eslint .",
|
|
1677
|
+
format: "prettier . --write"
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
return new PackageJsonGenerator(packageJsonModel, namespace);
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
// src/unlink-packages.ts
|
|
1685
|
+
var import_promises5 = __toESM(require("fs/promises"));
|
|
1686
|
+
var import_node_path7 = __toESM(require("path"));
|
|
1687
|
+
async function unlinkPackages(current, target) {
|
|
1688
|
+
await updatePackageJSON2(current, target);
|
|
1689
|
+
await updateTSConfig2(current, target);
|
|
1690
|
+
}
|
|
1691
|
+
async function updatePackageJSON2(current, target) {
|
|
1692
|
+
const namespace = await getNamespace();
|
|
1693
|
+
const packageJSON = await getDirectoryPackageJson(current.directory);
|
|
1694
|
+
const updated = packageJSON.removeDependency(target.name).removeDevDependency(target.name);
|
|
1695
|
+
const packageJSONPath = getPackageJSONPath(current.directory);
|
|
1696
|
+
await import_promises5.default.writeFile(packageJSONPath, updated.format(namespace));
|
|
1697
|
+
}
|
|
1698
|
+
async function updateTSConfig2(current, target) {
|
|
1699
|
+
const tsconfigPath = import_node_path7.default.join(current.directory, "tsconfig.json");
|
|
1700
|
+
const tsconfigContents = await import_promises5.default.readFile(tsconfigPath, "utf8");
|
|
1701
|
+
const tsconfig = TSConfig.parse(tsconfigContents);
|
|
1702
|
+
const updatedPaths = Object.fromEntries(
|
|
1703
|
+
Object.entries(tsconfig.compilerOptions.paths).filter(
|
|
1704
|
+
([key]) => key !== target.name
|
|
1705
|
+
)
|
|
1706
|
+
);
|
|
1707
|
+
const updatedCompilerOptions = tsconfig.compilerOptions.setPaths(updatedPaths);
|
|
1708
|
+
const updated = tsconfig.setCompilerOptions(updatedCompilerOptions);
|
|
1709
|
+
await import_promises5.default.writeFile(tsconfigPath, updated.format());
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// src/workspace/create-workspace.ts
|
|
1713
|
+
var import_promises6 = __toESM(require("fs/promises"));
|
|
1714
|
+
var import_path6 = __toESM(require("path"));
|
|
1715
|
+
|
|
1716
|
+
// src/workspace/root-package.ts
|
|
1717
|
+
async function makeRootPackage(directory, name) {
|
|
1718
|
+
const packageJsonModel = new PackageJSON({
|
|
1719
|
+
name,
|
|
1720
|
+
devDependencies: [new Dependency("turbo", "^2.5.4")],
|
|
1721
|
+
additionalData: {
|
|
1722
|
+
description: "",
|
|
1723
|
+
keywords: [],
|
|
1724
|
+
author: "",
|
|
1725
|
+
license: "ISC",
|
|
1726
|
+
packageManager: "pnpm@10.13.1"
|
|
1727
|
+
}
|
|
1728
|
+
});
|
|
1729
|
+
const PNPM_WORKSPACE = new FileGeneratorImp(
|
|
1730
|
+
"pnpm-workspace.yaml",
|
|
1731
|
+
["packages:", " - apps/*", " - packages/*", " - configs/*"].join("\n")
|
|
1732
|
+
);
|
|
1733
|
+
const GITIGNORE = new FileGeneratorImp(".gitignore", GITIGNORE_CONTENT);
|
|
1734
|
+
const TURBO_JSON = new FileGeneratorImp(
|
|
1735
|
+
"turbo.json",
|
|
1736
|
+
JSON.stringify(
|
|
1737
|
+
{
|
|
1738
|
+
tasks: {
|
|
1739
|
+
build: {
|
|
1740
|
+
dependsOn: ["^build"],
|
|
1741
|
+
outputs: ["dist/**"]
|
|
1742
|
+
},
|
|
1743
|
+
lint: {},
|
|
1744
|
+
test: {}
|
|
1745
|
+
}
|
|
1746
|
+
},
|
|
1747
|
+
null,
|
|
1748
|
+
2
|
|
1749
|
+
)
|
|
1750
|
+
);
|
|
1751
|
+
return new PackageGenerator(
|
|
1752
|
+
directory,
|
|
1753
|
+
new PackageJsonGenerator(packageJsonModel, ""),
|
|
1754
|
+
[PNPM_WORKSPACE, GITIGNORE, TURBO_JSON]
|
|
1755
|
+
);
|
|
1756
|
+
}
|
|
1757
|
+
var GITIGNORE_CONTENT = `# Logs
|
|
1758
|
+
logs
|
|
1759
|
+
*.log
|
|
1760
|
+
npm-debug.log*
|
|
1761
|
+
yarn-debug.log*
|
|
1762
|
+
yarn-error.log*
|
|
1763
|
+
lerna-debug.log*
|
|
1764
|
+
|
|
1765
|
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
1766
|
+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
1767
|
+
|
|
1768
|
+
# Runtime data
|
|
1769
|
+
pids
|
|
1770
|
+
*.pid
|
|
1771
|
+
*.seed
|
|
1772
|
+
*.pid.lock
|
|
1773
|
+
|
|
1774
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
1775
|
+
lib-cov
|
|
1776
|
+
|
|
1777
|
+
# Coverage directory used by tools like istanbul
|
|
1778
|
+
coverage
|
|
1779
|
+
*.lcov
|
|
1780
|
+
|
|
1781
|
+
# nyc test coverage
|
|
1782
|
+
.nyc_output
|
|
1783
|
+
|
|
1784
|
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
1785
|
+
.grunt
|
|
1786
|
+
|
|
1787
|
+
# Bower dependency directory (https://bower.io/)
|
|
1788
|
+
bower_components
|
|
1789
|
+
|
|
1790
|
+
# node-waf configuration
|
|
1791
|
+
.lock-wscript
|
|
1792
|
+
|
|
1793
|
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
1794
|
+
build/Release
|
|
1795
|
+
|
|
1796
|
+
# Dependency directories
|
|
1797
|
+
node_modules/
|
|
1798
|
+
jspm_packages/
|
|
1799
|
+
|
|
1800
|
+
# Snowpack dependency directory (https://snowpack.dev/)
|
|
1801
|
+
web_modules/
|
|
1802
|
+
|
|
1803
|
+
# TypeScript cache
|
|
1804
|
+
*.tsbuildinfo
|
|
1805
|
+
|
|
1806
|
+
# Optional npm cache directory
|
|
1807
|
+
.npm
|
|
1808
|
+
|
|
1809
|
+
# Optional eslint cache
|
|
1810
|
+
.eslintcache
|
|
1811
|
+
|
|
1812
|
+
# Optional stylelint cache
|
|
1813
|
+
.stylelintcache
|
|
1814
|
+
|
|
1815
|
+
# Optional REPL history
|
|
1816
|
+
.node_repl_history
|
|
1817
|
+
|
|
1818
|
+
# Output of 'npm pack'
|
|
1819
|
+
*.tgz
|
|
1820
|
+
|
|
1821
|
+
# Yarn Integrity file
|
|
1822
|
+
.yarn-integrity
|
|
1823
|
+
|
|
1824
|
+
# dotenv environment variable files
|
|
1825
|
+
.env
|
|
1826
|
+
.env.*
|
|
1827
|
+
!.env.example
|
|
1828
|
+
|
|
1829
|
+
# parcel-bundler cache (https://parceljs.org/)
|
|
1830
|
+
.cache
|
|
1831
|
+
.parcel-cache
|
|
1832
|
+
|
|
1833
|
+
# Next.js build output
|
|
1834
|
+
.next
|
|
1835
|
+
out
|
|
1836
|
+
|
|
1837
|
+
# Nuxt.js build / generate output
|
|
1838
|
+
.nuxt
|
|
1839
|
+
dist
|
|
1840
|
+
|
|
1841
|
+
# Gatsby files
|
|
1842
|
+
.cache/
|
|
1843
|
+
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
1844
|
+
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
1845
|
+
# public
|
|
1846
|
+
|
|
1847
|
+
# vuepress build output
|
|
1848
|
+
.vuepress/dist
|
|
1849
|
+
|
|
1850
|
+
# vuepress v2.x temp and cache directory
|
|
1851
|
+
.temp
|
|
1852
|
+
.cache
|
|
1853
|
+
|
|
1854
|
+
# Sveltekit cache directory
|
|
1855
|
+
.svelte-kit/
|
|
1856
|
+
|
|
1857
|
+
# vitepress build output
|
|
1858
|
+
**/.vitepress/dist
|
|
1859
|
+
|
|
1860
|
+
# vitepress cache directory
|
|
1861
|
+
**/.vitepress/cache
|
|
1862
|
+
|
|
1863
|
+
# Docusaurus cache and generated files
|
|
1864
|
+
.docusaurus
|
|
1865
|
+
|
|
1866
|
+
# Serverless directories
|
|
1867
|
+
.serverless/
|
|
1868
|
+
|
|
1869
|
+
# FuseBox cache
|
|
1870
|
+
.fusebox/
|
|
1871
|
+
|
|
1872
|
+
# DynamoDB Local files
|
|
1873
|
+
.dynamodb/
|
|
1874
|
+
|
|
1875
|
+
# Firebase cache directory
|
|
1876
|
+
.firebase/
|
|
1877
|
+
|
|
1878
|
+
# TernJS port file
|
|
1879
|
+
.tern-port
|
|
1880
|
+
|
|
1881
|
+
# Stores VSCode versions used for testing VSCode extensions
|
|
1882
|
+
.vscode-test
|
|
1883
|
+
|
|
1884
|
+
# yarn v3
|
|
1885
|
+
.pnp.*
|
|
1886
|
+
.yarn/*
|
|
1887
|
+
!.yarn/patches
|
|
1888
|
+
!.yarn/plugins
|
|
1889
|
+
!.yarn/releases
|
|
1890
|
+
!.yarn/sdks
|
|
1891
|
+
!.yarn/versions
|
|
1892
|
+
|
|
1893
|
+
# Vite logs files
|
|
1894
|
+
vite.config.js.timestamp-*
|
|
1895
|
+
vite.config.ts.timestamp-*
|
|
1896
|
+
|
|
1897
|
+
.turbo
|
|
1898
|
+
`;
|
|
1899
|
+
|
|
1900
|
+
// src/workspace/typescript-config.ts
|
|
1901
|
+
var import_path5 = __toESM(require("path"));
|
|
1902
|
+
async function makeTypescriptConfig(directory, namespace) {
|
|
1903
|
+
const packageJsonModel = new PackageJSON({
|
|
1904
|
+
name: `${namespace}/typescript-config`,
|
|
1905
|
+
devDependencies: [new Dependency("typescript", "^5.8.3")],
|
|
1906
|
+
additionalData: {
|
|
1907
|
+
version: "0.1.0",
|
|
1908
|
+
private: true,
|
|
1909
|
+
files: ["*.json"]
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
const fullPath = import_path5.default.join(directory, "configs/typescript-config");
|
|
1913
|
+
return new PackageGenerator(
|
|
1914
|
+
fullPath,
|
|
1915
|
+
new PackageJsonGenerator(packageJsonModel, namespace),
|
|
1916
|
+
[BASE, REACT, NODE]
|
|
1917
|
+
);
|
|
1918
|
+
}
|
|
1919
|
+
var BASE = new FileGeneratorImp(
|
|
1920
|
+
"tsconfig.base.json",
|
|
1921
|
+
JSON.stringify(
|
|
1922
|
+
{
|
|
1923
|
+
compilerOptions: {
|
|
1924
|
+
target: "ES2022",
|
|
1925
|
+
module: "ESNext",
|
|
1926
|
+
moduleResolution: "bundler",
|
|
1927
|
+
resolveJsonModule: true,
|
|
1928
|
+
isolatedModules: true,
|
|
1929
|
+
strict: true,
|
|
1930
|
+
skipLibCheck: true,
|
|
1931
|
+
forceConsistentCasingInFileNames: true,
|
|
1932
|
+
esModuleInterop: true,
|
|
1933
|
+
allowSyntheticDefaultImports: true,
|
|
1934
|
+
noEmit: true,
|
|
1935
|
+
types: []
|
|
1936
|
+
}
|
|
1937
|
+
},
|
|
1938
|
+
null,
|
|
1939
|
+
2
|
|
1940
|
+
)
|
|
1941
|
+
);
|
|
1942
|
+
var REACT = new FileGeneratorImp(
|
|
1943
|
+
"tsconfig.react.json",
|
|
1944
|
+
JSON.stringify(
|
|
1945
|
+
{
|
|
1946
|
+
extends: "./tsconfig.base.json",
|
|
1947
|
+
compilerOptions: {
|
|
1948
|
+
jsx: "react-jsx",
|
|
1949
|
+
lib: ["DOM", "DOM.Iterable", "ES2022"],
|
|
1950
|
+
types: []
|
|
1951
|
+
}
|
|
1952
|
+
},
|
|
1953
|
+
null,
|
|
1954
|
+
2
|
|
1955
|
+
)
|
|
1956
|
+
);
|
|
1957
|
+
var NODE = new FileGeneratorImp(
|
|
1958
|
+
"tsconfig.node.json",
|
|
1959
|
+
JSON.stringify(
|
|
1960
|
+
{
|
|
1961
|
+
extends: "./tsconfig.base.json",
|
|
1962
|
+
compilerOptions: {
|
|
1963
|
+
lib: ["ES2022"],
|
|
1964
|
+
types: ["node"]
|
|
1965
|
+
}
|
|
1966
|
+
},
|
|
1967
|
+
null,
|
|
1968
|
+
2
|
|
1969
|
+
)
|
|
1970
|
+
);
|
|
1971
|
+
|
|
1972
|
+
// src/workspace/create-workspace.ts
|
|
1973
|
+
async function createWorkspace(name, directory) {
|
|
1974
|
+
await validateNotInWorkspace(directory);
|
|
1975
|
+
console.log(`\u2728 Creating workspace: @${name}`);
|
|
1976
|
+
const fullPath = import_path6.default.join(directory, name);
|
|
1977
|
+
await import_promises6.default.mkdir(fullPath, { recursive: true });
|
|
1978
|
+
const namespace = `@${name}`;
|
|
1979
|
+
const PACKAGES = [
|
|
1980
|
+
await makeRootPackage(fullPath, name),
|
|
1981
|
+
await makeTypescriptConfig(fullPath, namespace)
|
|
1982
|
+
];
|
|
1983
|
+
await Promise.all(PACKAGES.map((p) => p.generate()));
|
|
1984
|
+
await import_promises6.default.mkdir(import_path6.default.join(fullPath, "apps"));
|
|
1985
|
+
await import_promises6.default.mkdir(import_path6.default.join(fullPath, "configs"));
|
|
1986
|
+
await import_promises6.default.mkdir(import_path6.default.join(fullPath, "packages"));
|
|
1987
|
+
console.log(`\u2705 Workspace created at: ${fullPath}`);
|
|
1988
|
+
console.log("");
|
|
1989
|
+
console.log(`Run "cd ${fullPath}" followed by "pnpm install"`);
|
|
1990
|
+
}
|
|
1991
|
+
async function validateNotInWorkspace(directory) {
|
|
1992
|
+
const namespace = await getNamespace(directory);
|
|
1993
|
+
if (namespace !== void 0) {
|
|
1994
|
+
throw new Error(`Currently in workspace "${namespace}".`);
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// src/index.ts
|
|
1999
|
+
var program = new import_commander.Command();
|
|
2000
|
+
program.name("stack").description("Opinionated TypeScript workspace manager").version("0.1.0");
|
|
2001
|
+
program.command("create <name>").description("Create a new workspace").option(
|
|
2002
|
+
"-o, --output <dir>",
|
|
2003
|
+
"Target directory to create the workspace in",
|
|
2004
|
+
"."
|
|
2005
|
+
).action(async (name, options) => {
|
|
2006
|
+
const output = options.output ?? process.cwd();
|
|
2007
|
+
await createWorkspace(name, output);
|
|
2008
|
+
});
|
|
2009
|
+
program.command("g <name>").description("Generate a new package or app").option(
|
|
2010
|
+
"-t, --type <type>",
|
|
2011
|
+
`Type of package to generate (${packageTypes.join(", ")})`
|
|
2012
|
+
).option("--style <style>", `Styling system to use (${styleTypes.join(", ")})`).action(async (name, options) => {
|
|
2013
|
+
const type = await pickPackageType(options);
|
|
2014
|
+
switch (type) {
|
|
2015
|
+
case "library":
|
|
2016
|
+
await createLibraryPackage(name);
|
|
2017
|
+
break;
|
|
2018
|
+
case "config":
|
|
2019
|
+
await createConfigPackage(name);
|
|
2020
|
+
break;
|
|
2021
|
+
case "react":
|
|
2022
|
+
await createReactPackage(name, await pickStyleType(options));
|
|
2023
|
+
break;
|
|
2024
|
+
case "vite":
|
|
2025
|
+
await createViteReactApp(name);
|
|
2026
|
+
break;
|
|
2027
|
+
case "cli":
|
|
2028
|
+
break;
|
|
2029
|
+
case "fastify":
|
|
2030
|
+
break;
|
|
2031
|
+
case "next":
|
|
2032
|
+
break;
|
|
2033
|
+
}
|
|
2034
|
+
console.log("");
|
|
2035
|
+
console.log("Run pnpm install to finish linking.");
|
|
2036
|
+
});
|
|
2037
|
+
program.command("link [name]").alias("l").option("-D, --dev", "Whether to link as a devDependency.", false).description("Link to the specified package").action(async (name, options) => {
|
|
2038
|
+
name = name ?? await promptForPackageToLinkTo();
|
|
2039
|
+
const development = options.dev ?? false;
|
|
2040
|
+
if (!isValidPackageName(name)) {
|
|
2041
|
+
throw new Error(`Package name "${name}" is not a valid option.`);
|
|
2042
|
+
}
|
|
2043
|
+
const current = await getCurrentPackage();
|
|
2044
|
+
const target = await getPackageByName(name);
|
|
2045
|
+
await linkPackages(current, target, development);
|
|
2046
|
+
console.log("");
|
|
2047
|
+
console.log("Run pnpm install to finish linking.");
|
|
2048
|
+
});
|
|
2049
|
+
program.command("unlink [name]").alias("u").description("Unlink the specified package").action(async (name) => {
|
|
2050
|
+
name = name ?? await promptForPackageToUnlinkFrom();
|
|
2051
|
+
if (!await isValidPackageName(name)) {
|
|
2052
|
+
throw new Error(`Package name "${name}" is not a valid option.`);
|
|
2053
|
+
}
|
|
2054
|
+
const current = await getCurrentPackage();
|
|
2055
|
+
const target = await getPackageByName(name);
|
|
2056
|
+
await unlinkPackages(current, target);
|
|
2057
|
+
});
|
|
2058
|
+
async function promptForPackageToLinkTo() {
|
|
2059
|
+
const options = await getAllPackages();
|
|
2060
|
+
const currentPackage = await getCurrentPackage();
|
|
2061
|
+
const linked = await getLinkedPackageNames();
|
|
2062
|
+
const validOptions = options.filter((o) => o.name !== currentPackage.name).filter((o) => !linked.has(o.name)).toSorted(comparePackages);
|
|
2063
|
+
const response = await (0, import_enquirer3.prompt)({
|
|
2064
|
+
type: "select",
|
|
2065
|
+
name: "packageName",
|
|
2066
|
+
message: "What package do you want to link to?",
|
|
2067
|
+
choices: [...validOptions]
|
|
2068
|
+
});
|
|
2069
|
+
return response.packageName;
|
|
2070
|
+
}
|
|
2071
|
+
async function promptForPackageToUnlinkFrom() {
|
|
2072
|
+
const validOptions = await getLinkedPackageNames();
|
|
2073
|
+
const response = await (0, import_enquirer3.prompt)({
|
|
2074
|
+
type: "select",
|
|
2075
|
+
name: "packageName",
|
|
2076
|
+
message: "What package do you want to unlink from?",
|
|
2077
|
+
choices: [...validOptions]
|
|
2078
|
+
});
|
|
2079
|
+
return response.packageName;
|
|
2080
|
+
}
|
|
2081
|
+
async function getLinkedPackageNames() {
|
|
2082
|
+
const currentPackage = await getCurrentPackage();
|
|
2083
|
+
const packageJSON = await getDirectoryPackageJson(currentPackage.directory);
|
|
2084
|
+
const namespace = await getNamespace();
|
|
2085
|
+
const names = [...packageJSON.dependencies, ...packageJSON.devDependencies].map((d) => d.name).filter((n) => n.startsWith(namespace));
|
|
2086
|
+
return new Set(names);
|
|
2087
|
+
}
|
|
2088
|
+
program.parse();
|
|
2089
|
+
async function isValidPackageName(packageName) {
|
|
2090
|
+
const options = await getValidPackageNames();
|
|
2091
|
+
return options.some((o) => o === packageName);
|
|
2092
|
+
}
|
|
2093
|
+
async function getValidPackageNames() {
|
|
2094
|
+
const options = await getAllPackages();
|
|
2095
|
+
const currentPackage = await getCurrentPackage();
|
|
2096
|
+
return options.filter((o) => o.name !== currentPackage.name).map((o) => o.name);
|
|
2097
|
+
}
|