@opensaas/stack-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/turbo-build.log +4 -0
- package/README.md +328 -0
- package/bin/opensaas.js +3 -0
- package/dist/commands/dev.d.ts +2 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +40 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/generate.d.ts +2 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +90 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +343 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/generator/context.d.ts +13 -0
- package/dist/generator/context.d.ts.map +1 -0
- package/dist/generator/context.js +69 -0
- package/dist/generator/context.js.map +1 -0
- package/dist/generator/index.d.ts +5 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +5 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/prisma.d.ts +10 -0
- package/dist/generator/prisma.d.ts.map +1 -0
- package/dist/generator/prisma.js +129 -0
- package/dist/generator/prisma.js.map +1 -0
- package/dist/generator/type-patcher.d.ts +13 -0
- package/dist/generator/type-patcher.d.ts.map +1 -0
- package/dist/generator/type-patcher.js +68 -0
- package/dist/generator/type-patcher.js.map +1 -0
- package/dist/generator/types.d.ts +10 -0
- package/dist/generator/types.d.ts.map +1 -0
- package/dist/generator/types.js +225 -0
- package/dist/generator/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/src/commands/dev.ts +48 -0
- package/src/commands/generate.ts +103 -0
- package/src/commands/init.ts +367 -0
- package/src/generator/context.ts +75 -0
- package/src/generator/index.ts +4 -0
- package/src/generator/prisma.ts +157 -0
- package/src/generator/type-patcher.ts +93 -0
- package/src/generator/types.ts +263 -0
- package/src/index.ts +34 -0
- package/tsconfig.json +13 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Patches Prisma's generated types based on field-level type patch configurations
|
|
5
|
+
*
|
|
6
|
+
* This reads Prisma's generated index.d.ts and replaces field types according to
|
|
7
|
+
* the `typePatch` configuration on each field. Fields can specify custom result types
|
|
8
|
+
* that will replace the original Prisma types in query results.
|
|
9
|
+
*
|
|
10
|
+
* The patched types are written to `.opensaas/prisma-client.d.ts` so users can
|
|
11
|
+
* import from there to get the transformed types.
|
|
12
|
+
*/
|
|
13
|
+
export function patchPrismaTypes(config, projectRoot) {
|
|
14
|
+
const opensaasPath = config.opensaasPath || '.opensaas';
|
|
15
|
+
// Prisma generates to opensaasPath/prisma-client
|
|
16
|
+
const prismaClientDir = path.join(projectRoot, opensaasPath, 'prisma-client');
|
|
17
|
+
const prismaIndexPath = path.join(prismaClientDir, 'index.d.ts');
|
|
18
|
+
// Check if Prisma types exist
|
|
19
|
+
if (!fs.existsSync(prismaIndexPath)) {
|
|
20
|
+
console.warn('ā ļø Prisma types not found. Run `npx prisma generate` first to generate Prisma Client.');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Read original Prisma types
|
|
24
|
+
const originalTypes = fs.readFileSync(prismaIndexPath, 'utf-8');
|
|
25
|
+
const fieldPatches = [];
|
|
26
|
+
for (const listConfig of Object.values(config.lists)) {
|
|
27
|
+
for (const [fieldName, fieldConfig] of Object.entries(listConfig.fields)) {
|
|
28
|
+
if (fieldConfig.typePatch) {
|
|
29
|
+
fieldPatches.push({
|
|
30
|
+
fieldName,
|
|
31
|
+
resultType: fieldConfig.typePatch.resultType,
|
|
32
|
+
patchScope: fieldConfig.typePatch.patchScope || 'scalars-only',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (fieldPatches.length === 0) {
|
|
38
|
+
// No fields need patching
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// Patch the types
|
|
42
|
+
let patchedTypes = originalTypes;
|
|
43
|
+
// For each field that needs patching, replace its type
|
|
44
|
+
for (const { fieldName, resultType, patchScope } of fieldPatches) {
|
|
45
|
+
if (patchScope === 'scalars-only') {
|
|
46
|
+
// Pattern matches: fieldName: <type> ONLY inside scalars: $Extensions.GetPayloadResult<{...}>
|
|
47
|
+
// This ensures we don't patch Input types (UserCreateInput, etc.)
|
|
48
|
+
// Example match:
|
|
49
|
+
// scalars: $Extensions.GetPayloadResult<{
|
|
50
|
+
// id: string
|
|
51
|
+
// password: string ā Replace this
|
|
52
|
+
// ...
|
|
53
|
+
const pattern = new RegExp(`(scalars:\\s*\\$Extensions\\.GetPayloadResult<\\{[^}]*?\\b${fieldName}:\\s*)[^,\\n}]+`, 'g');
|
|
54
|
+
patchedTypes = patchedTypes.replace(pattern, `$1${resultType}`);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// patchScope === 'all' - patch everywhere the field appears
|
|
58
|
+
// This is more aggressive and will patch input types too
|
|
59
|
+
const pattern = new RegExp(`(\\b${fieldName}:\\s*)[^,\\n}]+`, 'g');
|
|
60
|
+
patchedTypes = patchedTypes.replace(pattern, `$1${resultType}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Write patched types back to Prisma's index.d.ts
|
|
64
|
+
// This directly modifies the Prisma-generated file with our type patches
|
|
65
|
+
fs.writeFileSync(prismaIndexPath, patchedTypes, 'utf-8');
|
|
66
|
+
console.log(`ā
Patched Prisma types (${fieldPatches.length} field${fieldPatches.length === 1 ? '' : 's'})`);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=type-patcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-patcher.js","sourceRoot":"","sources":["../../src/generator/type-patcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAsB,EAAE,WAAmB;IAC1E,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,WAAW,CAAA;IAEvD,iDAAiD;IACjD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,EAAE,eAAe,CAAC,CAAA;IAC7E,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAA;IAEhE,8BAA8B;IAC9B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,IAAI,CACV,wFAAwF,CACzF,CAAA;QACD,OAAM;IACR,CAAC;IAED,6BAA6B;IAC7B,MAAM,aAAa,GAAG,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;IAS/D,MAAM,YAAY,GAAiB,EAAE,CAAA;IAErC,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACzE,IAAI,WAAW,CAAC,SAAS,EAAE,CAAC;gBAC1B,YAAY,CAAC,IAAI,CAAC;oBAChB,SAAS;oBACT,UAAU,EAAE,WAAW,CAAC,SAAS,CAAC,UAAU;oBAC5C,UAAU,EAAE,WAAW,CAAC,SAAS,CAAC,UAAU,IAAI,cAAc;iBAC/D,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,0BAA0B;QAC1B,OAAM;IACR,CAAC;IAED,kBAAkB;IAClB,IAAI,YAAY,GAAG,aAAa,CAAA;IAEhC,uDAAuD;IACvD,KAAK,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,YAAY,EAAE,CAAC;QACjE,IAAI,UAAU,KAAK,cAAc,EAAE,CAAC;YAClC,8FAA8F;YAC9F,kEAAkE;YAClE,iBAAiB;YACjB,0CAA0C;YAC1C,eAAe;YACf,qCAAqC;YACrC,QAAQ;YACR,MAAM,OAAO,GAAG,IAAI,MAAM,CACxB,6DAA6D,SAAS,iBAAiB,EACvF,GAAG,CACJ,CAAA;YAED,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,UAAU,EAAE,CAAC,CAAA;QACjE,CAAC;aAAM,CAAC;YACN,4DAA4D;YAC5D,yDAAyD;YACzD,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,OAAO,SAAS,iBAAiB,EAAE,GAAG,CAAC,CAAA;YAClE,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,UAAU,EAAE,CAAC,CAAA;QACjE,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,yEAAyE;IACzE,EAAE,CAAC,aAAa,CAAC,eAAe,EAAE,YAAY,EAAE,OAAO,CAAC,CAAA;IAExD,OAAO,CAAC,GAAG,CACT,2BAA2B,YAAY,CAAC,MAAM,SAAS,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAC/F,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { OpenSaasConfig } from '@opensaas/stack-core';
|
|
2
|
+
/**
|
|
3
|
+
* Generate all TypeScript types from config
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateTypes(config: OpenSaasConfig): string;
|
|
6
|
+
/**
|
|
7
|
+
* Write TypeScript types to file
|
|
8
|
+
*/
|
|
9
|
+
export declare function writeTypes(config: OpenSaasConfig, outputPath: string): void;
|
|
10
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/generator/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAkC,MAAM,sBAAsB,CAAA;AA0N1F;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CA0B5D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAU3E"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Map OpenSaas field types to TypeScript types
|
|
5
|
+
*/
|
|
6
|
+
function mapFieldTypeToTypeScript(field) {
|
|
7
|
+
// Relationships are handled separately
|
|
8
|
+
if (field.type === 'relationship') {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
// Use field's own TypeScript type generator if available
|
|
12
|
+
if (field.getTypeScriptType) {
|
|
13
|
+
const result = field.getTypeScriptType();
|
|
14
|
+
return result.type;
|
|
15
|
+
}
|
|
16
|
+
// Fallback for fields without generator methods
|
|
17
|
+
throw new Error(`Field type "${field.type}" does not implement getTypeScriptType method`);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check if a field is optional in the type
|
|
21
|
+
*/
|
|
22
|
+
function isFieldOptional(field) {
|
|
23
|
+
// Relationships are always nullable
|
|
24
|
+
if (field.type === 'relationship') {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
// Use field's own TypeScript type generator if available
|
|
28
|
+
if (field.getTypeScriptType) {
|
|
29
|
+
const result = field.getTypeScriptType();
|
|
30
|
+
return result.optional;
|
|
31
|
+
}
|
|
32
|
+
// Fallback: assume optional
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generate TypeScript interface for a model
|
|
37
|
+
*/
|
|
38
|
+
function generateModelType(listName, fields) {
|
|
39
|
+
const lines = [];
|
|
40
|
+
lines.push(`export type ${listName} = {`);
|
|
41
|
+
lines.push(' id: string');
|
|
42
|
+
for (const [fieldName, fieldConfig] of Object.entries(fields)) {
|
|
43
|
+
if (fieldConfig.type === 'relationship') {
|
|
44
|
+
const relField = fieldConfig;
|
|
45
|
+
const [targetList] = relField.ref.split('.');
|
|
46
|
+
if (relField.many) {
|
|
47
|
+
lines.push(` ${fieldName}: ${targetList}[]`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
lines.push(` ${fieldName}Id: string | null`);
|
|
51
|
+
lines.push(` ${fieldName}: ${targetList} | null`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const tsType = mapFieldTypeToTypeScript(fieldConfig);
|
|
56
|
+
if (!tsType)
|
|
57
|
+
continue; // Skip if no type returned
|
|
58
|
+
const optional = isFieldOptional(fieldConfig);
|
|
59
|
+
const nullability = optional ? ' | null' : '';
|
|
60
|
+
lines.push(` ${fieldName}: ${tsType}${nullability}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
lines.push(' createdAt: Date');
|
|
64
|
+
lines.push(' updatedAt: Date');
|
|
65
|
+
lines.push('}');
|
|
66
|
+
return lines.join('\n');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Generate CreateInput type
|
|
70
|
+
*/
|
|
71
|
+
function generateCreateInputType(listName, fields) {
|
|
72
|
+
const lines = [];
|
|
73
|
+
lines.push(`export type ${listName}CreateInput = {`);
|
|
74
|
+
for (const [fieldName, fieldConfig] of Object.entries(fields)) {
|
|
75
|
+
if (fieldConfig.type === 'relationship') {
|
|
76
|
+
const relField = fieldConfig;
|
|
77
|
+
if (relField.many) {
|
|
78
|
+
lines.push(` ${fieldName}?: { connect: Array<{ id: string }> }`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
lines.push(` ${fieldName}?: { connect: { id: string } }`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const tsType = mapFieldTypeToTypeScript(fieldConfig);
|
|
86
|
+
if (!tsType)
|
|
87
|
+
continue; // Skip if no type returned
|
|
88
|
+
const required = !isFieldOptional(fieldConfig) && !fieldConfig.defaultValue;
|
|
89
|
+
const optional = required ? '' : '?';
|
|
90
|
+
lines.push(` ${fieldName}${optional}: ${tsType}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
lines.push('}');
|
|
94
|
+
return lines.join('\n');
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Generate UpdateInput type
|
|
98
|
+
*/
|
|
99
|
+
function generateUpdateInputType(listName, fields) {
|
|
100
|
+
const lines = [];
|
|
101
|
+
lines.push(`export type ${listName}UpdateInput = {`);
|
|
102
|
+
for (const [fieldName, fieldConfig] of Object.entries(fields)) {
|
|
103
|
+
if (fieldConfig.type === 'relationship') {
|
|
104
|
+
const relField = fieldConfig;
|
|
105
|
+
if (relField.many) {
|
|
106
|
+
lines.push(` ${fieldName}?: { connect: Array<{ id: string }>, disconnect: Array<{ id: string }> }`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
lines.push(` ${fieldName}?: { connect: { id: string } } | { disconnect: true }`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const tsType = mapFieldTypeToTypeScript(fieldConfig);
|
|
114
|
+
if (!tsType)
|
|
115
|
+
continue; // Skip if no type returned
|
|
116
|
+
lines.push(` ${fieldName}?: ${tsType}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
lines.push('}');
|
|
120
|
+
return lines.join('\n');
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Generate WhereInput type (simplified)
|
|
124
|
+
*/
|
|
125
|
+
function generateWhereInputType(listName, fields) {
|
|
126
|
+
const lines = [];
|
|
127
|
+
lines.push(`export type ${listName}WhereInput = {`);
|
|
128
|
+
lines.push(' id?: string');
|
|
129
|
+
lines.push(' AND?: Array<' + listName + 'WhereInput>');
|
|
130
|
+
lines.push(' OR?: Array<' + listName + 'WhereInput>');
|
|
131
|
+
lines.push(' NOT?: ' + listName + 'WhereInput');
|
|
132
|
+
for (const [fieldName, fieldConfig] of Object.entries(fields)) {
|
|
133
|
+
if (fieldConfig.type === 'relationship') {
|
|
134
|
+
continue; // Skip for now
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
const tsType = mapFieldTypeToTypeScript(fieldConfig);
|
|
138
|
+
if (!tsType)
|
|
139
|
+
continue; // Skip if no type returned
|
|
140
|
+
lines.push(` ${fieldName}?: { equals?: ${tsType}, not?: ${tsType} }`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
lines.push('}');
|
|
144
|
+
return lines.join('\n');
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Generate Context type with all operations
|
|
148
|
+
*/
|
|
149
|
+
function generateContextType(config) {
|
|
150
|
+
const lines = [];
|
|
151
|
+
lines.push('export type Context = {');
|
|
152
|
+
lines.push(' db: {');
|
|
153
|
+
for (const listName of Object.keys(config.lists)) {
|
|
154
|
+
const lowerName = listName.toLowerCase();
|
|
155
|
+
lines.push(` ${lowerName}: {`);
|
|
156
|
+
lines.push(` findUnique: (args: {`);
|
|
157
|
+
lines.push(` where: { id: string }`);
|
|
158
|
+
lines.push(` include?: any`);
|
|
159
|
+
lines.push(` }) => Promise<${listName} | null>`);
|
|
160
|
+
lines.push(` findMany: (args?: {`);
|
|
161
|
+
lines.push(` where?: ${listName}WhereInput`);
|
|
162
|
+
lines.push(` take?: number`);
|
|
163
|
+
lines.push(` skip?: number`);
|
|
164
|
+
lines.push(` include?: any`);
|
|
165
|
+
lines.push(` }) => Promise<${listName}[]>`);
|
|
166
|
+
lines.push(` create: (args: {`);
|
|
167
|
+
lines.push(` data: ${listName}CreateInput`);
|
|
168
|
+
lines.push(` }) => Promise<${listName} | null>`);
|
|
169
|
+
lines.push(` update: (args: {`);
|
|
170
|
+
lines.push(` where: { id: string }`);
|
|
171
|
+
lines.push(` data: ${listName}UpdateInput`);
|
|
172
|
+
lines.push(` }) => Promise<${listName} | null>`);
|
|
173
|
+
lines.push(` delete: (args: {`);
|
|
174
|
+
lines.push(` where: { id: string }`);
|
|
175
|
+
lines.push(` }) => Promise<${listName} | null>`);
|
|
176
|
+
lines.push(` count: (args?: {`);
|
|
177
|
+
lines.push(` where?: ${listName}WhereInput`);
|
|
178
|
+
lines.push(` }) => Promise<number>`);
|
|
179
|
+
lines.push(` }`);
|
|
180
|
+
}
|
|
181
|
+
lines.push(' }');
|
|
182
|
+
lines.push(' session: any');
|
|
183
|
+
lines.push(' prisma: any // Your PrismaClient instance');
|
|
184
|
+
lines.push('}');
|
|
185
|
+
return lines.join('\n');
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Generate all TypeScript types from config
|
|
189
|
+
*/
|
|
190
|
+
export function generateTypes(config) {
|
|
191
|
+
const lines = [];
|
|
192
|
+
// Add header comment
|
|
193
|
+
lines.push('/**');
|
|
194
|
+
lines.push(' * Generated types from OpenSaas configuration');
|
|
195
|
+
lines.push(' * DO NOT EDIT - This file is automatically generated');
|
|
196
|
+
lines.push(' */');
|
|
197
|
+
lines.push('');
|
|
198
|
+
// Generate types for each list
|
|
199
|
+
for (const [listName, listConfig] of Object.entries(config.lists)) {
|
|
200
|
+
lines.push(generateModelType(listName, listConfig.fields));
|
|
201
|
+
lines.push('');
|
|
202
|
+
lines.push(generateCreateInputType(listName, listConfig.fields));
|
|
203
|
+
lines.push('');
|
|
204
|
+
lines.push(generateUpdateInputType(listName, listConfig.fields));
|
|
205
|
+
lines.push('');
|
|
206
|
+
lines.push(generateWhereInputType(listName, listConfig.fields));
|
|
207
|
+
lines.push('');
|
|
208
|
+
}
|
|
209
|
+
// Generate Context type
|
|
210
|
+
lines.push(generateContextType(config));
|
|
211
|
+
return lines.join('\n');
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Write TypeScript types to file
|
|
215
|
+
*/
|
|
216
|
+
export function writeTypes(config, outputPath) {
|
|
217
|
+
const types = generateTypes(config);
|
|
218
|
+
// Ensure directory exists
|
|
219
|
+
const dir = path.dirname(outputPath);
|
|
220
|
+
if (!fs.existsSync(dir)) {
|
|
221
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
222
|
+
}
|
|
223
|
+
fs.writeFileSync(outputPath, types, 'utf-8');
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/generator/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { generateCommand } from './commands/generate.js';
|
|
4
|
+
import { initCommand } from './commands/init.js';
|
|
5
|
+
import { devCommand } from './commands/dev.js';
|
|
6
|
+
const program = new Command();
|
|
7
|
+
program.name('opensaas').description('OpenSaas Stack CLI').version('0.1.0');
|
|
8
|
+
program
|
|
9
|
+
.command('generate')
|
|
10
|
+
.description('Generate Prisma schema and TypeScript types from opensaas.config.ts')
|
|
11
|
+
.action(async () => {
|
|
12
|
+
await generateCommand();
|
|
13
|
+
});
|
|
14
|
+
program
|
|
15
|
+
.command('init [project-name]')
|
|
16
|
+
.description('Create a new OpenSaas project')
|
|
17
|
+
.option('-t, --template <template>', 'Project template to use')
|
|
18
|
+
.action(async (projectName) => {
|
|
19
|
+
await initCommand(projectName);
|
|
20
|
+
});
|
|
21
|
+
program
|
|
22
|
+
.command('dev')
|
|
23
|
+
.description('Watch opensaas.config.ts and regenerate on changes')
|
|
24
|
+
.action(async () => {
|
|
25
|
+
await devCommand();
|
|
26
|
+
});
|
|
27
|
+
program.parse();
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;AAE3E,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,qEAAqE,CAAC;KAClF,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,eAAe,EAAE,CAAA;AACzB,CAAC,CAAC,CAAA;AAEJ,OAAO;KACJ,OAAO,CAAC,qBAAqB,CAAC;KAC9B,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,2BAA2B,EAAE,yBAAyB,CAAC;KAC9D,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE;IAC5B,MAAM,WAAW,CAAC,WAAW,CAAC,CAAA;AAChC,CAAC,CAAC,CAAA;AAEJ,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,oDAAoD,CAAC;KACjE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,UAAU,EAAE,CAAA;AACpB,CAAC,CAAC,CAAA;AAEJ,OAAO,CAAC,KAAK,EAAE,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opensaas/stack-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI tools for OpenSaas Stack",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./generator": {
|
|
14
|
+
"types": "./dist/generator/index.d.ts",
|
|
15
|
+
"default": "./dist/generator/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"opensaas": "./bin/opensaas.js"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"opensaas",
|
|
23
|
+
"cli",
|
|
24
|
+
"nextjs",
|
|
25
|
+
"prisma"
|
|
26
|
+
],
|
|
27
|
+
"author": "",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"commander": "^14.0.1",
|
|
31
|
+
"chalk": "^5.6.2",
|
|
32
|
+
"ora": "^9.0.0",
|
|
33
|
+
"prompts": "^2.4.2",
|
|
34
|
+
"chokidar": "^4.0.3",
|
|
35
|
+
"jiti": "^2.6.1",
|
|
36
|
+
"@opensaas/stack-core": "0.1.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^24.7.2",
|
|
40
|
+
"@types/prompts": "^2.4.9",
|
|
41
|
+
"typescript": "^5.9.3"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"dev": "tsc --watch",
|
|
46
|
+
"clean": "rm -rf .turbo dist tsconfig.tsbuildinfo"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as path from 'path'
|
|
2
|
+
import * as fs from 'fs'
|
|
3
|
+
import chalk from 'chalk'
|
|
4
|
+
import chokidar from 'chokidar'
|
|
5
|
+
import { generateCommand } from './generate.js'
|
|
6
|
+
|
|
7
|
+
export async function devCommand() {
|
|
8
|
+
const cwd = process.cwd()
|
|
9
|
+
const configPath = path.join(cwd, 'opensaas.config.ts')
|
|
10
|
+
|
|
11
|
+
// Check if config exists
|
|
12
|
+
if (!fs.existsSync(configPath)) {
|
|
13
|
+
console.error(chalk.red('Error: opensaas.config.ts not found in current directory'))
|
|
14
|
+
console.error(chalk.gray(' Please run this command from your project root'))
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log(chalk.bold.cyan('\nOpenSaas Dev Mode\n'))
|
|
19
|
+
console.log(chalk.gray('Watching for changes to opensaas.config.ts...\n'))
|
|
20
|
+
|
|
21
|
+
// Run initial generation
|
|
22
|
+
await generateCommand()
|
|
23
|
+
|
|
24
|
+
// Watch for changes
|
|
25
|
+
const watcher = chokidar.watch(configPath, {
|
|
26
|
+
persistent: true,
|
|
27
|
+
ignoreInitial: true,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
watcher.on('change', async () => {
|
|
31
|
+
console.log(chalk.yellow('\nConfig changed, regenerating...\n'))
|
|
32
|
+
await generateCommand()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
watcher.on('error', (error) => {
|
|
36
|
+
console.error(chalk.red('\nWatcher error:'), error)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// Keep the process running
|
|
40
|
+
console.log(chalk.gray('Press Ctrl+C to stop watching\n'))
|
|
41
|
+
|
|
42
|
+
// Handle graceful shutdown
|
|
43
|
+
process.on('SIGINT', () => {
|
|
44
|
+
console.log(chalk.yellow('\n\nStopping dev mode...'))
|
|
45
|
+
watcher.close()
|
|
46
|
+
process.exit(0)
|
|
47
|
+
})
|
|
48
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as path from 'path'
|
|
2
|
+
import * as fs from 'fs'
|
|
3
|
+
import { execSync } from 'child_process'
|
|
4
|
+
import chalk from 'chalk'
|
|
5
|
+
import ora from 'ora'
|
|
6
|
+
import { createJiti } from 'jiti'
|
|
7
|
+
import {
|
|
8
|
+
writePrismaSchema,
|
|
9
|
+
writeTypes,
|
|
10
|
+
writeContext,
|
|
11
|
+
patchPrismaTypes,
|
|
12
|
+
} from '../generator/index.js'
|
|
13
|
+
import type { OpenSaasConfig } from '@opensaas/stack-core'
|
|
14
|
+
|
|
15
|
+
export async function generateCommand() {
|
|
16
|
+
console.log(chalk.bold('\nš OpenSaas Generator\n'))
|
|
17
|
+
|
|
18
|
+
const cwd = process.cwd()
|
|
19
|
+
const configPath = path.join(cwd, 'opensaas.config.ts')
|
|
20
|
+
|
|
21
|
+
// Check if config exists
|
|
22
|
+
if (!fs.existsSync(configPath)) {
|
|
23
|
+
console.error(chalk.red('ā Error: opensaas.config.ts not found in current directory'))
|
|
24
|
+
console.error(chalk.gray(' Please run this command from your project root'))
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const spinner = ora('Loading configuration...').start()
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// Load config using jiti (supports TypeScript)
|
|
32
|
+
const jiti = createJiti(cwd, {
|
|
33
|
+
interopDefault: true,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const config = (await jiti.import(configPath)) as OpenSaasConfig
|
|
37
|
+
|
|
38
|
+
spinner.succeed(chalk.green('Configuration loaded'))
|
|
39
|
+
|
|
40
|
+
// Generate Prisma schema, types, and context
|
|
41
|
+
const generatorSpinner = ora('Generating schema and types...').start()
|
|
42
|
+
try {
|
|
43
|
+
writePrismaSchema(config, path.join(cwd, 'prisma', 'schema.prisma'))
|
|
44
|
+
writeTypes(config, path.join(cwd, '.opensaas', 'types.ts'))
|
|
45
|
+
writeContext(config, path.join(cwd, '.opensaas', 'context.ts'))
|
|
46
|
+
|
|
47
|
+
generatorSpinner.succeed(chalk.green('Schema generation complete'))
|
|
48
|
+
console.log(chalk.green('ā
Prisma schema generated'))
|
|
49
|
+
console.log(chalk.green('ā
TypeScript types generated'))
|
|
50
|
+
console.log(chalk.green('ā
Context factory generated'))
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
} catch (err: any) {
|
|
53
|
+
generatorSpinner.fail(chalk.red('Failed to generate'))
|
|
54
|
+
console.error(chalk.red('\nā Error:'), err.message)
|
|
55
|
+
if (err.stack) {
|
|
56
|
+
console.error(chalk.gray('\n' + err.stack))
|
|
57
|
+
}
|
|
58
|
+
process.exit(1)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Run Prisma generate to create the Prisma client
|
|
62
|
+
const prismaSpinner = ora('Generating Prisma client...').start()
|
|
63
|
+
try {
|
|
64
|
+
execSync('npx prisma generate', {
|
|
65
|
+
cwd,
|
|
66
|
+
encoding: 'utf-8',
|
|
67
|
+
stdio: 'pipe',
|
|
68
|
+
})
|
|
69
|
+
prismaSpinner.succeed(chalk.green('Prisma client generated'))
|
|
70
|
+
console.log(chalk.green('ā
Prisma client generated'))
|
|
71
|
+
} catch (err) {
|
|
72
|
+
prismaSpinner.fail(chalk.red('Failed to generate Prisma client'))
|
|
73
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
74
|
+
console.error(chalk.red('\nā Error:'), message)
|
|
75
|
+
process.exit(1)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Patch Prisma types with field transformations
|
|
79
|
+
const patchSpinner = ora('Patching Prisma types...').start()
|
|
80
|
+
try {
|
|
81
|
+
patchPrismaTypes(config, cwd)
|
|
82
|
+
patchSpinner.succeed(chalk.green('Type patching complete'))
|
|
83
|
+
} catch (err) {
|
|
84
|
+
patchSpinner.fail(chalk.red('Failed to patch types'))
|
|
85
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
86
|
+
console.error(chalk.red('\nā Error:'), message)
|
|
87
|
+
process.exit(1)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(chalk.bold('\n⨠Generation complete!\n'))
|
|
91
|
+
console.log(chalk.gray('Next steps:'))
|
|
92
|
+
console.log(chalk.gray(' 1. Run: npx prisma db push'))
|
|
93
|
+
console.log(chalk.gray(' 2. Start using your generated types!\n'))
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
95
|
+
} catch (error: any) {
|
|
96
|
+
spinner.fail(chalk.red('Generation failed'))
|
|
97
|
+
console.error(chalk.red('\nā Error:'), error.message)
|
|
98
|
+
if (error.stack) {
|
|
99
|
+
console.error(chalk.gray('\n' + error.stack))
|
|
100
|
+
}
|
|
101
|
+
process.exit(1)
|
|
102
|
+
}
|
|
103
|
+
}
|