create-turbo-mono 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/README.md +182 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +118 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/scaffold.d.ts +8 -0
  8. package/dist/scaffold.d.ts.map +1 -0
  9. package/dist/scaffold.js +42 -0
  10. package/dist/scaffold.js.map +1 -0
  11. package/dist/templates/backend.d.ts +2 -0
  12. package/dist/templates/backend.d.ts.map +1 -0
  13. package/dist/templates/backend.js +424 -0
  14. package/dist/templates/backend.js.map +1 -0
  15. package/dist/templates/cicd.d.ts +3 -0
  16. package/dist/templates/cicd.d.ts.map +1 -0
  17. package/dist/templates/cicd.js +307 -0
  18. package/dist/templates/cicd.js.map +1 -0
  19. package/dist/templates/docker.d.ts +3 -0
  20. package/dist/templates/docker.d.ts.map +1 -0
  21. package/dist/templates/docker.js +458 -0
  22. package/dist/templates/docker.js.map +1 -0
  23. package/dist/templates/docs.d.ts +3 -0
  24. package/dist/templates/docs.d.ts.map +1 -0
  25. package/dist/templates/docs.js +71 -0
  26. package/dist/templates/docs.js.map +1 -0
  27. package/dist/templates/frontend.d.ts +2 -0
  28. package/dist/templates/frontend.d.ts.map +1 -0
  29. package/dist/templates/frontend.js +441 -0
  30. package/dist/templates/frontend.js.map +1 -0
  31. package/dist/templates/root.d.ts +3 -0
  32. package/dist/templates/root.d.ts.map +1 -0
  33. package/dist/templates/root.js +210 -0
  34. package/dist/templates/root.js.map +1 -0
  35. package/dist/templates/shared.d.ts +2 -0
  36. package/dist/templates/shared.d.ts.map +1 -0
  37. package/dist/templates/shared.js +696 -0
  38. package/dist/templates/shared.js.map +1 -0
  39. package/dist/utils.d.ts +5 -0
  40. package/dist/utils.d.ts.map +1 -0
  41. package/dist/utils.js +34 -0
  42. package/dist/utils.js.map +1 -0
  43. package/package.json +40 -0
  44. package/src/index.ts +138 -0
  45. package/src/scaffold.ts +51 -0
  46. package/src/templates/backend.ts +460 -0
  47. package/src/templates/cicd.ts +334 -0
  48. package/src/templates/docker.ts +503 -0
  49. package/src/templates/docs.ts +74 -0
  50. package/src/templates/frontend.ts +469 -0
  51. package/src/templates/root.ts +216 -0
  52. package/src/templates/shared.ts +820 -0
  53. package/src/utils.ts +31 -0
  54. package/tsconfig.json +20 -0
@@ -0,0 +1,696 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createSharedPackages = createSharedPackages;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ async function createSharedPackages(targetDir) {
10
+ await createTsConfigPackage(targetDir);
11
+ await createDatabasePackage(targetDir);
12
+ await createSharedBackendPackage(targetDir);
13
+ await createSharedFrontendPackage(targetDir);
14
+ await createSharedCommonPackage(targetDir);
15
+ }
16
+ async function createTsConfigPackage(targetDir) {
17
+ const packageDir = path_1.default.join(targetDir, 'packages', 'tsconfig');
18
+ await fs_extra_1.default.ensureDir(packageDir);
19
+ // package.json
20
+ const packageJson = {
21
+ name: '@repo/tsconfig',
22
+ version: '1.0.0',
23
+ private: true,
24
+ };
25
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'package.json'), packageJson, {
26
+ spaces: 2,
27
+ });
28
+ // base.json
29
+ const baseConfig = {
30
+ compilerOptions: {
31
+ target: 'ES2020',
32
+ lib: ['ES2020'],
33
+ module: 'commonjs',
34
+ moduleResolution: 'node',
35
+ esModuleInterop: true,
36
+ skipLibCheck: true,
37
+ forceConsistentCasingInFileNames: true,
38
+ strict: true,
39
+ resolveJsonModule: true,
40
+ declaration: true,
41
+ declarationMap: true,
42
+ sourceMap: true,
43
+ incremental: true,
44
+ noUnusedLocals: true,
45
+ noUnusedParameters: true,
46
+ noImplicitReturns: true,
47
+ noFallthroughCasesInSwitch: true,
48
+ },
49
+ };
50
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'base.json'), baseConfig, {
51
+ spaces: 2,
52
+ });
53
+ // nestjs.json
54
+ const nestjsConfig = {
55
+ extends: './base.json',
56
+ compilerOptions: {
57
+ module: 'commonjs',
58
+ declaration: true,
59
+ removeComments: true,
60
+ emitDecoratorMetadata: true,
61
+ experimentalDecorators: true,
62
+ allowSyntheticDefaultImports: true,
63
+ target: 'ES2021',
64
+ sourceMap: true,
65
+ outDir: './dist',
66
+ baseUrl: './',
67
+ incremental: true,
68
+ skipLibCheck: true,
69
+ },
70
+ };
71
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'nestjs.json'), nestjsConfig, {
72
+ spaces: 2,
73
+ });
74
+ // nextjs.json
75
+ const nextjsConfig = {
76
+ extends: './base.json',
77
+ compilerOptions: {
78
+ target: 'ES2020',
79
+ lib: ['dom', 'dom.iterable', 'esnext'],
80
+ allowJs: true,
81
+ skipLibCheck: true,
82
+ strict: true,
83
+ forceConsistentCasingInFileNames: true,
84
+ noEmit: true,
85
+ esModuleInterop: true,
86
+ module: 'esnext',
87
+ moduleResolution: 'bundler',
88
+ resolveJsonModule: true,
89
+ isolatedModules: true,
90
+ jsx: 'preserve',
91
+ incremental: true,
92
+ plugins: [
93
+ {
94
+ name: 'next',
95
+ },
96
+ ],
97
+ },
98
+ };
99
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'nextjs.json'), nextjsConfig, {
100
+ spaces: 2,
101
+ });
102
+ // react-library.json
103
+ const reactLibConfig = {
104
+ extends: './base.json',
105
+ compilerOptions: {
106
+ target: 'ES2020',
107
+ lib: ['dom', 'dom.iterable', 'esnext'],
108
+ jsx: 'react-jsx',
109
+ module: 'esnext',
110
+ moduleResolution: 'bundler',
111
+ noEmit: false,
112
+ outDir: './dist',
113
+ },
114
+ };
115
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'react-library.json'), reactLibConfig, { spaces: 2 });
116
+ }
117
+ async function createDatabasePackage(targetDir) {
118
+ const packageDir = path_1.default.join(targetDir, 'packages', 'database');
119
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'prisma'));
120
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src'));
121
+ // package.json
122
+ const packageJson = {
123
+ name: '@repo/database',
124
+ version: '1.0.0',
125
+ private: true,
126
+ main: './src/index.ts',
127
+ types: './src/index.ts',
128
+ scripts: {
129
+ 'db:generate': 'prisma generate',
130
+ 'db:push': 'prisma db push',
131
+ 'db:migrate': 'prisma migrate dev',
132
+ 'db:studio': 'prisma studio',
133
+ build: 'tsc',
134
+ clean: 'rm -rf dist',
135
+ 'type-check': 'tsc --noEmit',
136
+ },
137
+ dependencies: {
138
+ '@prisma/client': '^5.7.1',
139
+ },
140
+ devDependencies: {
141
+ '@repo/tsconfig': 'workspace:*',
142
+ prisma: '^5.7.1',
143
+ typescript: '^5.3.3',
144
+ },
145
+ };
146
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'package.json'), packageJson, {
147
+ spaces: 2,
148
+ });
149
+ // tsconfig.json
150
+ const tsConfig = {
151
+ extends: '@repo/tsconfig/base.json',
152
+ compilerOptions: {
153
+ outDir: './dist',
154
+ rootDir: './src',
155
+ },
156
+ include: ['src/**/*'],
157
+ exclude: ['node_modules', 'dist'],
158
+ };
159
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'tsconfig.json'), tsConfig, {
160
+ spaces: 2,
161
+ });
162
+ // prisma/schema.prisma
163
+ const prismaSchema = `// This is your Prisma schema file,
164
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
165
+
166
+ generator client {
167
+ provider = "prisma-client-js"
168
+ output = "../node_modules/.prisma/client"
169
+ }
170
+
171
+ datasource db {
172
+ provider = "postgresql"
173
+ url = env("DATABASE_URL")
174
+ }
175
+
176
+ model User {
177
+ id String @id @default(cuid())
178
+ email String @unique
179
+ name String?
180
+ createdAt DateTime @default(now())
181
+ updatedAt DateTime @updatedAt
182
+
183
+ @@map("users")
184
+ }
185
+
186
+ model Post {
187
+ id String @id @default(cuid())
188
+ title String
189
+ content String?
190
+ published Boolean @default(false)
191
+ authorId String?
192
+ createdAt DateTime @default(now())
193
+ updatedAt DateTime @updatedAt
194
+
195
+ @@map("posts")
196
+ }
197
+ `;
198
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'prisma', 'schema.prisma'), prismaSchema);
199
+ // src/index.ts
200
+ const indexTs = `import { PrismaClient } from '@prisma/client';
201
+
202
+ declare global {
203
+ // eslint-disable-next-line no-var
204
+ var prisma: PrismaClient | undefined;
205
+ }
206
+
207
+ export const prisma =
208
+ global.prisma ||
209
+ new PrismaClient({
210
+ log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
211
+ });
212
+
213
+ if (process.env.NODE_ENV !== 'production') {
214
+ global.prisma = prisma;
215
+ }
216
+
217
+ export * from '@prisma/client';
218
+ `;
219
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'index.ts'), indexTs);
220
+ // .env.example
221
+ const envExample = `DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"
222
+ `;
223
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, '.env.example'), envExample);
224
+ // README.md
225
+ const readme = `# @repo/database
226
+
227
+ Shared Prisma database client and schema.
228
+
229
+ ## Usage
230
+
231
+ \`\`\`typescript
232
+ import { prisma } from '@repo/database';
233
+
234
+ // Use prisma client
235
+ const users = await prisma.user.findMany();
236
+ \`\`\`
237
+
238
+ ## Commands
239
+
240
+ \`\`\`bash
241
+ # Generate Prisma Client
242
+ pnpm db:generate
243
+
244
+ # Create and apply migrations
245
+ pnpm db:migrate
246
+
247
+ # Push schema changes without migration
248
+ pnpm db:push
249
+
250
+ # Open Prisma Studio
251
+ pnpm db:studio
252
+ \`\`\`
253
+ `;
254
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'README.md'), readme);
255
+ }
256
+ async function createSharedBackendPackage(targetDir) {
257
+ const packageDir = path_1.default.join(targetDir, 'packages', 'shared-backend');
258
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src'));
259
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'utils'));
260
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'middleware'));
261
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'types'));
262
+ // package.json
263
+ const packageJson = {
264
+ name: '@repo/shared-backend',
265
+ version: '1.0.0',
266
+ private: true,
267
+ main: './src/index.ts',
268
+ types: './src/index.ts',
269
+ scripts: {
270
+ build: 'tsc',
271
+ clean: 'rm -rf dist',
272
+ 'type-check': 'tsc --noEmit',
273
+ },
274
+ dependencies: {
275
+ '@repo/shared-common': 'workspace:*',
276
+ },
277
+ devDependencies: {
278
+ '@repo/tsconfig': 'workspace:*',
279
+ '@types/node': '^20.10.6',
280
+ typescript: '^5.3.3',
281
+ },
282
+ };
283
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'package.json'), packageJson, {
284
+ spaces: 2,
285
+ });
286
+ // tsconfig.json
287
+ const tsConfig = {
288
+ extends: '@repo/tsconfig/base.json',
289
+ compilerOptions: {
290
+ outDir: './dist',
291
+ rootDir: './src',
292
+ },
293
+ include: ['src/**/*'],
294
+ exclude: ['node_modules', 'dist'],
295
+ };
296
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'tsconfig.json'), tsConfig, {
297
+ spaces: 2,
298
+ });
299
+ // src/index.ts
300
+ const indexTs = `export * from './utils';
301
+ export * from './types';
302
+ `;
303
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'index.ts'), indexTs);
304
+ // src/utils/index.ts
305
+ const utilsIndexTs = `export * from './logger';
306
+ export * from './response';
307
+ `;
308
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'utils', 'index.ts'), utilsIndexTs);
309
+ // src/utils/logger.ts
310
+ const loggerTs = `export class Logger {
311
+ private context: string;
312
+
313
+ constructor(context: string) {
314
+ this.context = context;
315
+ }
316
+
317
+ log(message: string, ...args: any[]) {
318
+ console.log(\`[\${this.context}] \${message}\`, ...args);
319
+ }
320
+
321
+ error(message: string, ...args: any[]) {
322
+ console.error(\`[\${this.context}] ERROR: \${message}\`, ...args);
323
+ }
324
+
325
+ warn(message: string, ...args: any[]) {
326
+ console.warn(\`[\${this.context}] WARN: \${message}\`, ...args);
327
+ }
328
+
329
+ debug(message: string, ...args: any[]) {
330
+ if (process.env.NODE_ENV === 'development') {
331
+ console.debug(\`[\${this.context}] DEBUG: \${message}\`, ...args);
332
+ }
333
+ }
334
+ }
335
+ `;
336
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'utils', 'logger.ts'), loggerTs);
337
+ // src/utils/response.ts
338
+ const responseTs = `export interface ApiResponse<T = any> {
339
+ success: boolean;
340
+ data?: T;
341
+ message?: string;
342
+ error?: string;
343
+ }
344
+
345
+ export function successResponse<T>(data: T, message?: string): ApiResponse<T> {
346
+ return {
347
+ success: true,
348
+ data,
349
+ message,
350
+ };
351
+ }
352
+
353
+ export function errorResponse(error: string, message?: string): ApiResponse {
354
+ return {
355
+ success: false,
356
+ error,
357
+ message,
358
+ };
359
+ }
360
+ `;
361
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'utils', 'response.ts'), responseTs);
362
+ // src/types/index.ts
363
+ const typesIndexTs = `export interface PaginationParams {
364
+ page?: number;
365
+ limit?: number;
366
+ }
367
+
368
+ export interface PaginatedResponse<T> {
369
+ data: T[];
370
+ total: number;
371
+ page: number;
372
+ limit: number;
373
+ totalPages: number;
374
+ }
375
+ `;
376
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'types', 'index.ts'), typesIndexTs);
377
+ // README.md
378
+ const readme = `# @repo/shared-backend
379
+
380
+ Shared backend utilities, types, and middleware.
381
+
382
+ ## Usage
383
+
384
+ \`\`\`typescript
385
+ import { Logger, successResponse } from '@repo/shared-backend';
386
+
387
+ const logger = new Logger('MyService');
388
+ logger.log('Hello from shared backend');
389
+
390
+ const response = successResponse({ id: 1 }, 'User created');
391
+ \`\`\`
392
+ `;
393
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'README.md'), readme);
394
+ }
395
+ async function createSharedFrontendPackage(targetDir) {
396
+ const packageDir = path_1.default.join(targetDir, 'packages', 'shared-frontend');
397
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src'));
398
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'components'));
399
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'hooks'));
400
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'utils'));
401
+ // package.json
402
+ const packageJson = {
403
+ name: '@repo/shared-frontend',
404
+ version: '1.0.0',
405
+ private: true,
406
+ main: './src/index.ts',
407
+ types: './src/index.ts',
408
+ scripts: {
409
+ build: 'tsc',
410
+ clean: 'rm -rf dist',
411
+ 'type-check': 'tsc --noEmit',
412
+ lint: 'eslint "src/**/*.{ts,tsx}"',
413
+ },
414
+ dependencies: {
415
+ '@repo/shared-common': 'workspace:*',
416
+ react: '^18.2.0',
417
+ 'react-dom': '^18.2.0',
418
+ },
419
+ devDependencies: {
420
+ '@repo/tsconfig': 'workspace:*',
421
+ '@types/react': '^18.2.46',
422
+ '@types/react-dom': '^18.2.18',
423
+ typescript: '^5.3.3',
424
+ },
425
+ peerDependencies: {
426
+ react: '^18.2.0',
427
+ 'react-dom': '^18.2.0',
428
+ },
429
+ };
430
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'package.json'), packageJson, {
431
+ spaces: 2,
432
+ });
433
+ // tsconfig.json
434
+ const tsConfig = {
435
+ extends: '@repo/tsconfig/react-library.json',
436
+ compilerOptions: {
437
+ outDir: './dist',
438
+ rootDir: './src',
439
+ },
440
+ include: ['src/**/*'],
441
+ exclude: ['node_modules', 'dist'],
442
+ };
443
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'tsconfig.json'), tsConfig, {
444
+ spaces: 2,
445
+ });
446
+ // src/index.ts
447
+ const indexTs = `export * from './components';
448
+ export * from './hooks';
449
+ export * from './utils';
450
+ `;
451
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'index.ts'), indexTs);
452
+ // src/components/index.ts
453
+ const componentsIndexTs = `export * from './Button';
454
+ `;
455
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'components', 'index.ts'), componentsIndexTs);
456
+ // src/components/Button.tsx
457
+ const buttonTsx = `import React from 'react';
458
+
459
+ export interface ButtonProps
460
+ extends React.ButtonHTMLAttributes<HTMLButtonElement> {
461
+ variant?: 'primary' | 'secondary' | 'danger';
462
+ size?: 'sm' | 'md' | 'lg';
463
+ }
464
+
465
+ export function Button({
466
+ children,
467
+ variant = 'primary',
468
+ size = 'md',
469
+ className = '',
470
+ ...props
471
+ }: ButtonProps) {
472
+ const baseStyles = 'font-semibold rounded focus:outline-none focus:ring-2';
473
+
474
+ const variantStyles = {
475
+ primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
476
+ secondary: 'bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500',
477
+ danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',
478
+ };
479
+
480
+ const sizeStyles = {
481
+ sm: 'px-3 py-1.5 text-sm',
482
+ md: 'px-4 py-2 text-base',
483
+ lg: 'px-6 py-3 text-lg',
484
+ };
485
+
486
+ const combinedClassName = \`\${baseStyles} \${variantStyles[variant]} \${sizeStyles[size]} \${className}\`;
487
+
488
+ return (
489
+ <button className={combinedClassName} {...props}>
490
+ {children}
491
+ </button>
492
+ );
493
+ }
494
+ `;
495
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'components', 'Button.tsx'), buttonTsx);
496
+ // src/hooks/index.ts
497
+ const hooksIndexTs = `export * from './useLocalStorage';
498
+ `;
499
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'hooks', 'index.ts'), hooksIndexTs);
500
+ // src/hooks/useLocalStorage.ts
501
+ const useLocalStorageTs = `import { useState, useEffect } from 'react';
502
+
503
+ export function useLocalStorage<T>(
504
+ key: string,
505
+ initialValue: T
506
+ ): [T, (value: T) => void] {
507
+ const [storedValue, setStoredValue] = useState<T>(() => {
508
+ if (typeof window === 'undefined') {
509
+ return initialValue;
510
+ }
511
+
512
+ try {
513
+ const item = window.localStorage.getItem(key);
514
+ return item ? JSON.parse(item) : initialValue;
515
+ } catch (error) {
516
+ console.error(error);
517
+ return initialValue;
518
+ }
519
+ });
520
+
521
+ const setValue = (value: T) => {
522
+ try {
523
+ setStoredValue(value);
524
+ if (typeof window !== 'undefined') {
525
+ window.localStorage.setItem(key, JSON.stringify(value));
526
+ }
527
+ } catch (error) {
528
+ console.error(error);
529
+ }
530
+ };
531
+
532
+ return [storedValue, setValue];
533
+ }
534
+ `;
535
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'hooks', 'useLocalStorage.ts'), useLocalStorageTs);
536
+ // src/utils/index.ts
537
+ const utilsIndexTs = `export * from './cn';
538
+ `;
539
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'utils', 'index.ts'), utilsIndexTs);
540
+ // src/utils/cn.ts
541
+ const cnTs = `export function cn(...classes: (string | undefined | null | false)[]): string {
542
+ return classes.filter(Boolean).join(' ');
543
+ }
544
+ `;
545
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'utils', 'cn.ts'), cnTs);
546
+ // README.md
547
+ const readme = `# @repo/shared-frontend
548
+
549
+ Shared frontend components, hooks, and utilities.
550
+
551
+ ## Usage
552
+
553
+ \`\`\`typescript
554
+ import { Button, useLocalStorage } from '@repo/shared-frontend';
555
+
556
+ function MyComponent() {
557
+ const [value, setValue] = useLocalStorage('myKey', 'default');
558
+
559
+ return <Button onClick={() => setValue('new value')}>Click me</Button>;
560
+ }
561
+ \`\`\`
562
+ `;
563
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'README.md'), readme);
564
+ }
565
+ async function createSharedCommonPackage(targetDir) {
566
+ const packageDir = path_1.default.join(targetDir, 'packages', 'shared-common');
567
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src'));
568
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'utils'));
569
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'constants'));
570
+ await fs_extra_1.default.ensureDir(path_1.default.join(packageDir, 'src', 'types'));
571
+ // package.json
572
+ const packageJson = {
573
+ name: '@repo/shared-common',
574
+ version: '1.0.0',
575
+ private: true,
576
+ main: './src/index.ts',
577
+ types: './src/index.ts',
578
+ scripts: {
579
+ build: 'tsc',
580
+ clean: 'rm -rf dist',
581
+ 'type-check': 'tsc --noEmit',
582
+ },
583
+ devDependencies: {
584
+ '@repo/tsconfig': 'workspace:*',
585
+ typescript: '^5.3.3',
586
+ },
587
+ };
588
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'package.json'), packageJson, {
589
+ spaces: 2,
590
+ });
591
+ // tsconfig.json
592
+ const tsConfig = {
593
+ extends: '@repo/tsconfig/base.json',
594
+ compilerOptions: {
595
+ outDir: './dist',
596
+ rootDir: './src',
597
+ },
598
+ include: ['src/**/*'],
599
+ exclude: ['node_modules', 'dist'],
600
+ };
601
+ await fs_extra_1.default.writeJson(path_1.default.join(packageDir, 'tsconfig.json'), tsConfig, {
602
+ spaces: 2,
603
+ });
604
+ // src/index.ts
605
+ const indexTs = `export * from './utils';
606
+ export * from './constants';
607
+ export * from './types';
608
+ `;
609
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'index.ts'), indexTs);
610
+ // src/utils/index.ts
611
+ const utilsIndexTs = `export * from './validation';
612
+ export * from './formatting';
613
+ `;
614
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'utils', 'index.ts'), utilsIndexTs);
615
+ // src/utils/validation.ts
616
+ const validationTs = `export function isEmail(email: string): boolean {
617
+ const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;
618
+ return emailRegex.test(email);
619
+ }
620
+
621
+ export function isValidUrl(url: string): boolean {
622
+ try {
623
+ new URL(url);
624
+ return true;
625
+ } catch {
626
+ return false;
627
+ }
628
+ }
629
+
630
+ export function isEmpty(value: any): boolean {
631
+ if (value == null) return true;
632
+ if (typeof value === 'string') return value.trim().length === 0;
633
+ if (Array.isArray(value)) return value.length === 0;
634
+ if (typeof value === 'object') return Object.keys(value).length === 0;
635
+ return false;
636
+ }
637
+ `;
638
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'utils', 'validation.ts'), validationTs);
639
+ // src/utils/formatting.ts
640
+ const formattingTs = `export function formatDate(date: Date | string): string {
641
+ const d = typeof date === 'string' ? new Date(date) : date;
642
+ return d.toLocaleDateString('en-US', {
643
+ year: 'numeric',
644
+ month: 'long',
645
+ day: 'numeric',
646
+ });
647
+ }
648
+
649
+ export function capitalize(str: string): string {
650
+ if (!str) return '';
651
+ return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
652
+ }
653
+
654
+ export function truncate(str: string, maxLength: number): string {
655
+ if (str.length <= maxLength) return str;
656
+ return str.slice(0, maxLength - 3) + '...';
657
+ }
658
+ `;
659
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'utils', 'formatting.ts'), formattingTs);
660
+ // src/constants/index.ts
661
+ const constantsIndexTs = `export const APP_NAME = 'My App';
662
+ export const API_VERSION = 'v1';
663
+ export const DEFAULT_PAGE_SIZE = 20;
664
+ export const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
665
+ `;
666
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'constants', 'index.ts'), constantsIndexTs);
667
+ // src/types/index.ts
668
+ const typesIndexTs = `export interface BaseEntity {
669
+ id: string;
670
+ createdAt: Date;
671
+ updatedAt: Date;
672
+ }
673
+
674
+ export type Nullable<T> = T | null;
675
+
676
+ export type Optional<T> = T | undefined;
677
+ `;
678
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'src', 'types', 'index.ts'), typesIndexTs);
679
+ // README.md
680
+ const readme = `# @repo/shared-common
681
+
682
+ Universal utilities and types shared across all packages.
683
+
684
+ ## Usage
685
+
686
+ \`\`\`typescript
687
+ import { isEmail, formatDate, APP_NAME } from '@repo/shared-common';
688
+
689
+ console.log(isEmail('test@example.com')); // true
690
+ console.log(formatDate(new Date())); // "January 1, 2024"
691
+ console.log(APP_NAME); // "My App"
692
+ \`\`\`
693
+ `;
694
+ await fs_extra_1.default.writeFile(path_1.default.join(packageDir, 'README.md'), readme);
695
+ }
696
+ //# sourceMappingURL=shared.js.map