suparisma 1.1.2 → 1.2.1
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/README.md +439 -14
- package/SEARCH_FEATURES.md +430 -0
- package/dist/generators/coreGenerator.js +152 -42
- package/dist/generators/typeGenerator.js +4 -21
- package/dist/index.js +206 -15
- package/dist/parser.js +47 -37
- package/package.json +1 -1
- package/prisma/schema.prisma +6 -1
package/dist/parser.js
CHANGED
|
@@ -70,10 +70,10 @@ function parseZodImport(comment) {
|
|
|
70
70
|
*/
|
|
71
71
|
function parsePrismaSchema(schemaPath) {
|
|
72
72
|
const schema = fs_1.default.readFileSync(schemaPath, 'utf-8');
|
|
73
|
-
const modelRegex = /model\s+(\w+)\s+{([^}]*)}/
|
|
73
|
+
const modelRegex = /model\s+(\w+)\s+{([^}]*)}/g;
|
|
74
74
|
const models = [];
|
|
75
75
|
// Extract enum names from the schema
|
|
76
|
-
const enumRegex = /enum\s+(\w+)\s+{[^}]*}/
|
|
76
|
+
const enumRegex = /enum\s+(\w+)\s+{[^}]*}/g;
|
|
77
77
|
const enumNames = [];
|
|
78
78
|
let enumMatch;
|
|
79
79
|
while ((enumMatch = enumRegex.exec(schema)) !== null) {
|
|
@@ -95,77 +95,87 @@ function parsePrismaSchema(schemaPath) {
|
|
|
95
95
|
const searchFields = [];
|
|
96
96
|
// Track zod imports at model level
|
|
97
97
|
const zodImports = [];
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
let
|
|
98
|
+
// Use EXACT same logic as analyzePrismaSchema for consistency
|
|
99
|
+
const bodyLines = modelBody.trim().split('\n');
|
|
100
|
+
let nextFieldShouldBeSearchable = false;
|
|
101
101
|
let pendingZodDirective;
|
|
102
|
-
for (let i = 0; i <
|
|
103
|
-
const
|
|
102
|
+
for (let i = 0; i < bodyLines.length; i++) {
|
|
103
|
+
const currentLine = bodyLines[i]?.trim();
|
|
104
104
|
// Skip blank lines and non-field lines
|
|
105
|
-
if (!
|
|
105
|
+
if (!currentLine || currentLine.startsWith('@@')) {
|
|
106
106
|
continue;
|
|
107
107
|
}
|
|
108
|
-
// Check for
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
name: lastFieldName,
|
|
112
|
-
type: lastFieldType,
|
|
113
|
-
});
|
|
108
|
+
// Check for /// @enableSearch directive (applies to NEXT field)
|
|
109
|
+
if (currentLine === '/// @enableSearch') {
|
|
110
|
+
nextFieldShouldBeSearchable = true;
|
|
114
111
|
continue;
|
|
115
112
|
}
|
|
116
|
-
// Check
|
|
117
|
-
if (
|
|
113
|
+
// Check for standalone // @enableSearch comment (applies to NEXT field)
|
|
114
|
+
if (currentLine === '// @enableSearch') {
|
|
115
|
+
nextFieldShouldBeSearchable = true;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// Check if line is a comment - SKIP ALL TYPES of comments but keep search flag
|
|
119
|
+
if (currentLine.startsWith('///') || currentLine.startsWith('//')) {
|
|
118
120
|
// Parse zod directives from comments
|
|
119
|
-
const zodDirective = parseZodDirective(
|
|
121
|
+
const zodDirective = parseZodDirective(currentLine);
|
|
120
122
|
if (zodDirective) {
|
|
121
123
|
pendingZodDirective = zodDirective;
|
|
122
124
|
}
|
|
123
125
|
// Parse zod imports from comments
|
|
124
|
-
const zodImportInfos = parseZodImport(
|
|
126
|
+
const zodImportInfos = parseZodImport(currentLine);
|
|
125
127
|
zodImports.push(...zodImportInfos);
|
|
126
128
|
continue;
|
|
127
129
|
}
|
|
128
|
-
// Parse field definition - Updated to handle array types
|
|
129
|
-
const fieldMatch =
|
|
130
|
+
// Parse field definition - Updated to handle array types and inline comments
|
|
131
|
+
const fieldMatch = currentLine.match(/^\s*(\w+)\s+(\w+)(\[\])?(\?)?\s*/);
|
|
130
132
|
if (fieldMatch) {
|
|
131
133
|
const fieldName = fieldMatch[1];
|
|
132
|
-
const baseFieldType = fieldMatch[2];
|
|
134
|
+
const baseFieldType = fieldMatch[2];
|
|
135
|
+
// Check if this field should be searchable due to @enableSearch directive
|
|
136
|
+
if (nextFieldShouldBeSearchable && fieldName && baseFieldType) {
|
|
137
|
+
searchFields.push({
|
|
138
|
+
name: fieldName,
|
|
139
|
+
type: baseFieldType,
|
|
140
|
+
});
|
|
141
|
+
nextFieldShouldBeSearchable = false; // Reset flag
|
|
142
|
+
}
|
|
143
|
+
// Check for inline // @enableSearch comment
|
|
144
|
+
if (currentLine.includes('// @enableSearch')) {
|
|
145
|
+
if (fieldName && baseFieldType && !searchFields.some(f => f.name === fieldName)) {
|
|
146
|
+
searchFields.push({
|
|
147
|
+
name: fieldName,
|
|
148
|
+
type: baseFieldType,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Continue with field processing for the fields array
|
|
133
153
|
const isArray = !!fieldMatch[3]; // [] makes it an array
|
|
134
154
|
const isOptional = !!fieldMatch[4]; // ? makes it optional
|
|
135
|
-
// Store for potential standalone @enableSearch comment
|
|
136
|
-
lastFieldName = fieldName || '';
|
|
137
|
-
lastFieldType = baseFieldType || '';
|
|
138
155
|
// Detect special fields
|
|
139
|
-
const isId =
|
|
156
|
+
const isId = currentLine.includes('@id');
|
|
140
157
|
const isCreatedAt = fieldName === 'created_at' || fieldName === 'createdAt';
|
|
141
158
|
const isUpdatedAt = fieldName === 'updated_at' || fieldName === 'updatedAt';
|
|
142
|
-
const hasDefaultValue =
|
|
159
|
+
const hasDefaultValue = currentLine.includes('@default');
|
|
143
160
|
// Extract default value if present
|
|
144
161
|
let defaultValue;
|
|
145
162
|
if (hasDefaultValue) {
|
|
146
|
-
const defaultMatch =
|
|
163
|
+
const defaultMatch = currentLine.match(/@default\(\s*(.+?)\s*\)/);
|
|
147
164
|
if (defaultMatch) {
|
|
148
165
|
defaultValue = defaultMatch[1];
|
|
149
166
|
}
|
|
150
167
|
}
|
|
151
168
|
// Improved relation detection
|
|
152
169
|
const primitiveTypes = ['String', 'Int', 'Float', 'Boolean', 'DateTime', 'Json', 'Bytes', 'Decimal', 'BigInt'];
|
|
153
|
-
const isRelation =
|
|
170
|
+
const isRelation = currentLine.includes('@relation') ||
|
|
154
171
|
(!!fieldName &&
|
|
155
172
|
(fieldName.endsWith('_id') || fieldName === 'userId' || fieldName === 'user_id')) ||
|
|
156
173
|
// Also detect relation fields by checking if the type is not a primitive type and not an enum
|
|
157
174
|
(!!baseFieldType && !primitiveTypes.includes(baseFieldType) && !enumNames.includes(baseFieldType));
|
|
158
|
-
// Check for inline @enableSearch comment
|
|
159
|
-
if (line.includes('// @enableSearch')) {
|
|
160
|
-
searchFields.push({
|
|
161
|
-
name: fieldName || '',
|
|
162
|
-
type: baseFieldType || '',
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
175
|
// Check for inline zod directive
|
|
166
176
|
let fieldZodDirective = pendingZodDirective;
|
|
167
|
-
if (
|
|
168
|
-
const inlineZodDirective = parseZodDirective(
|
|
177
|
+
if (currentLine.includes('/// @zod.')) {
|
|
178
|
+
const inlineZodDirective = parseZodDirective(currentLine);
|
|
169
179
|
if (inlineZodDirective) {
|
|
170
180
|
fieldZodDirective = inlineZodDirective;
|
|
171
181
|
}
|
package/package.json
CHANGED
package/prisma/schema.prisma
CHANGED
|
@@ -21,7 +21,9 @@ enum SomeEnum {
|
|
|
21
21
|
|
|
22
22
|
model User {
|
|
23
23
|
id String @id @default(uuid())
|
|
24
|
+
// @enableSearch
|
|
24
25
|
name String
|
|
26
|
+
// @enableSearch
|
|
25
27
|
email String @unique
|
|
26
28
|
things Thing[] // One-to-many relation
|
|
27
29
|
createdAt DateTime @default(now())
|
|
@@ -33,11 +35,14 @@ model Thing {
|
|
|
33
35
|
id String @id @default(uuid())
|
|
34
36
|
// @enableSearch
|
|
35
37
|
name String?
|
|
38
|
+
// @enableSearch
|
|
39
|
+
/// Somehting here
|
|
40
|
+
description String? /// @thing
|
|
36
41
|
stringArray String[]
|
|
37
42
|
someEnum SomeEnum @default(ONE)
|
|
38
43
|
someNumber Int?
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
// @enableSearch
|
|
41
46
|
someJson Json? /// @zod.custom.use(z.array(LLMNodeSchema).nullable())
|
|
42
47
|
userId String?
|
|
43
48
|
user User? @relation(fields: [userId], references: [id])
|