webspresso 0.0.5 → 0.0.7
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 +564 -0
- package/bin/webspresso.js +255 -0
- package/core/applySchema.js +49 -0
- package/core/compileSchema.js +69 -0
- package/core/orm/eager-loader.js +232 -0
- package/core/orm/index.js +148 -0
- package/core/orm/migrations/index.js +205 -0
- package/core/orm/migrations/scaffold.js +312 -0
- package/core/orm/model.js +178 -0
- package/core/orm/query-builder.js +430 -0
- package/core/orm/repository.js +346 -0
- package/core/orm/schema-helpers.js +416 -0
- package/core/orm/scopes.js +183 -0
- package/core/orm/seeder.js +585 -0
- package/core/orm/transaction.js +69 -0
- package/core/orm/types.js +237 -0
- package/core/orm/utils.js +127 -0
- package/index.js +13 -1
- package/package.json +29 -5
- package/src/plugin-manager.js +2 -0
- package/utils/schemaCache.js +60 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webspresso ORM - Type Definitions
|
|
3
|
+
* JSDoc types for IDE support and documentation
|
|
4
|
+
* @module core/orm/types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Column Metadata Types
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {'id'|'string'|'text'|'integer'|'bigint'|'float'|'decimal'|'boolean'|'date'|'datetime'|'timestamp'|'json'|'enum'|'uuid'} ColumnType
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} ColumnMeta
|
|
17
|
+
* @property {ColumnType} type - Database column type
|
|
18
|
+
* @property {boolean} [nullable=false] - Whether column allows NULL
|
|
19
|
+
* @property {boolean} [primary=false] - Whether column is primary key
|
|
20
|
+
* @property {boolean} [autoIncrement=false] - Whether column auto-increments
|
|
21
|
+
* @property {boolean} [unique=false] - Whether column has unique constraint
|
|
22
|
+
* @property {boolean} [index=false] - Whether column should be indexed
|
|
23
|
+
* @property {*} [default] - Default value for column
|
|
24
|
+
* @property {number} [maxLength] - Maximum length for string columns
|
|
25
|
+
* @property {number} [precision] - Precision for decimal columns
|
|
26
|
+
* @property {number} [scale] - Scale for decimal columns
|
|
27
|
+
* @property {string[]} [enumValues] - Allowed values for enum columns
|
|
28
|
+
* @property {string} [references] - Referenced table for foreign keys
|
|
29
|
+
* @property {string} [referenceColumn='id'] - Referenced column name
|
|
30
|
+
* @property {'create'|'update'} [auto] - Auto-set on create or update (for timestamps)
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Encoded column metadata stored in Zod .describe()
|
|
35
|
+
* @typedef {Object} EncodedColumnMeta
|
|
36
|
+
* @property {string} __wdb__ - Marker to identify ORM metadata
|
|
37
|
+
* @property {ColumnMeta} meta - The actual column metadata
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Relation Types
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {'belongsTo'|'hasMany'|'hasOne'} RelationType
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @typedef {Object} RelationDefinition
|
|
50
|
+
* @property {RelationType} type - Type of relation
|
|
51
|
+
* @property {() => ModelDefinition} model - Lazy reference to related model
|
|
52
|
+
* @property {string} foreignKey - Foreign key column name
|
|
53
|
+
* @property {string} [localKey='id'] - Local key column name (for hasMany/hasOne)
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @typedef {Object.<string, RelationDefinition>} RelationsMap
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
// ============================================================================
|
|
61
|
+
// Scope Types
|
|
62
|
+
// ============================================================================
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @typedef {Object} ScopeOptions
|
|
66
|
+
* @property {boolean} [softDelete=false] - Enable soft delete (deleted_at column)
|
|
67
|
+
* @property {boolean} [timestamps=false] - Enable auto timestamps (created_at, updated_at)
|
|
68
|
+
* @property {string} [tenant] - Tenant column name for multi-tenancy
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @typedef {Object} ScopeContext
|
|
73
|
+
* @property {*} [tenantId] - Current tenant ID for multi-tenant queries
|
|
74
|
+
* @property {boolean} [withTrashed=false] - Include soft-deleted records
|
|
75
|
+
* @property {boolean} [onlyTrashed=false] - Only soft-deleted records
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// Model Types
|
|
80
|
+
// ============================================================================
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @typedef {Object} ModelOptions
|
|
84
|
+
* @property {string} name - Model name (e.g., 'User')
|
|
85
|
+
* @property {string} table - Database table name (e.g., 'users')
|
|
86
|
+
* @property {import('zod').ZodObject} schema - Zod schema for validation
|
|
87
|
+
* @property {string} [primaryKey='id'] - Primary key column name
|
|
88
|
+
* @property {RelationsMap} [relations={}] - Relation definitions
|
|
89
|
+
* @property {ScopeOptions} [scopes={}] - Scope options
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @typedef {Object} ModelDefinition
|
|
94
|
+
* @property {string} name - Model name
|
|
95
|
+
* @property {string} table - Database table name
|
|
96
|
+
* @property {import('zod').ZodObject} schema - Zod schema
|
|
97
|
+
* @property {string} primaryKey - Primary key column name
|
|
98
|
+
* @property {RelationsMap} relations - Relation definitions
|
|
99
|
+
* @property {ScopeOptions} scopes - Scope options
|
|
100
|
+
* @property {Map<string, ColumnMeta>} columns - Parsed column metadata
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// Query Builder Types
|
|
105
|
+
// ============================================================================
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @typedef {'='|'!='|'>'|'>='|'<'|'<='|'like'|'ilike'|'in'|'not in'|'is null'|'is not null'} WhereOperator
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @typedef {Object} WhereClause
|
|
113
|
+
* @property {string} column - Column name
|
|
114
|
+
* @property {WhereOperator} operator - Comparison operator
|
|
115
|
+
* @property {*} value - Value to compare
|
|
116
|
+
* @property {'and'|'or'} [boolean='and'] - Boolean operator for chaining
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @typedef {Object} OrderByClause
|
|
121
|
+
* @property {string} column - Column name
|
|
122
|
+
* @property {'asc'|'desc'} [direction='asc'] - Sort direction
|
|
123
|
+
*/
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @typedef {Object} QueryState
|
|
127
|
+
* @property {WhereClause[]} wheres - WHERE clauses
|
|
128
|
+
* @property {OrderByClause[]} orderBys - ORDER BY clauses
|
|
129
|
+
* @property {string[]} selects - SELECT columns
|
|
130
|
+
* @property {string[]} withs - Relations to eager load
|
|
131
|
+
* @property {number} [limitValue] - LIMIT value
|
|
132
|
+
* @property {number} [offsetValue] - OFFSET value
|
|
133
|
+
* @property {ScopeContext} scopeContext - Current scope context
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// Repository Types
|
|
138
|
+
// ============================================================================
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @typedef {Object} FindOptions
|
|
142
|
+
* @property {string[]} [with=[]] - Relations to eager load
|
|
143
|
+
* @property {string[]} [select] - Columns to select
|
|
144
|
+
*/
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @typedef {Object} PaginationOptions
|
|
148
|
+
* @property {number} [page=1] - Page number (1-indexed)
|
|
149
|
+
* @property {number} [perPage=15] - Items per page
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @typedef {Object} PaginatedResult
|
|
154
|
+
* @property {Object[]} data - Result items
|
|
155
|
+
* @property {number} total - Total count
|
|
156
|
+
* @property {number} page - Current page
|
|
157
|
+
* @property {number} perPage - Items per page
|
|
158
|
+
* @property {number} totalPages - Total pages
|
|
159
|
+
*/
|
|
160
|
+
|
|
161
|
+
// ============================================================================
|
|
162
|
+
// Migration Types
|
|
163
|
+
// ============================================================================
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @typedef {Object} MigrationConfig
|
|
167
|
+
* @property {string} [directory='./migrations'] - Migrations directory
|
|
168
|
+
* @property {string} [tableName='knex_migrations'] - Migration tracking table
|
|
169
|
+
*/
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @typedef {Object} MigrationStatus
|
|
173
|
+
* @property {string} name - Migration filename
|
|
174
|
+
* @property {boolean} completed - Whether migration has run
|
|
175
|
+
* @property {Date} [ran_at] - When migration was run
|
|
176
|
+
* @property {number} [batch] - Migration batch number
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @typedef {Object} MigrationResult
|
|
181
|
+
* @property {number} batch - Batch number
|
|
182
|
+
* @property {string[]} migrations - Migration names run
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
// ============================================================================
|
|
186
|
+
// Database Types
|
|
187
|
+
// ============================================================================
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @typedef {Object} DatabaseConfig
|
|
191
|
+
* @property {string} client - Database client ('pg', 'mysql2', 'better-sqlite3')
|
|
192
|
+
* @property {string|Object} connection - Connection string or config object
|
|
193
|
+
* @property {MigrationConfig} [migrations] - Migration configuration
|
|
194
|
+
* @property {Object} [pool] - Connection pool settings
|
|
195
|
+
*/
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @typedef {Object} DatabaseInstance
|
|
199
|
+
* @property {import('knex').Knex} knex - Knex instance
|
|
200
|
+
* @property {function(ModelDefinition): Repository} createRepository - Create repository for model
|
|
201
|
+
* @property {function(function(TransactionContext): Promise): Promise} transaction - Run in transaction
|
|
202
|
+
* @property {MigrationManager} migrate - Migration manager
|
|
203
|
+
* @property {function(): Promise<void>} destroy - Close all connections
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @typedef {Object} TransactionContext
|
|
208
|
+
* @property {import('knex').Knex.Transaction} trx - Knex transaction
|
|
209
|
+
* @property {function(ModelDefinition): Repository} createRepository - Create repository in transaction
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @typedef {Object} Repository
|
|
214
|
+
* @property {function(number|string, FindOptions=): Promise<Object|null>} findById - Find by primary key
|
|
215
|
+
* @property {function(Object, FindOptions=): Promise<Object|null>} findOne - Find single record
|
|
216
|
+
* @property {function(FindOptions=): Promise<Object[]>} findAll - Find all records
|
|
217
|
+
* @property {function(Object): Promise<Object>} create - Create new record
|
|
218
|
+
* @property {function(number|string, Object): Promise<Object|null>} update - Update record
|
|
219
|
+
* @property {function(number|string): Promise<boolean>} delete - Delete record (soft if enabled)
|
|
220
|
+
* @property {function(number|string): Promise<boolean>} forceDelete - Hard delete record
|
|
221
|
+
* @property {function(): QueryBuilder} query - Get query builder
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @typedef {Object} MigrationManager
|
|
226
|
+
* @property {function(): Promise<MigrationResult>} latest - Run pending migrations
|
|
227
|
+
* @property {function(Object=): Promise<MigrationResult>} rollback - Rollback migrations
|
|
228
|
+
* @property {function(): Promise<MigrationStatus[]>} status - Get migration status
|
|
229
|
+
* @property {function(string, Object=): Promise<string>} make - Create new migration file
|
|
230
|
+
*/
|
|
231
|
+
|
|
232
|
+
// ============================================================================
|
|
233
|
+
// Exports (for type resolution)
|
|
234
|
+
// ============================================================================
|
|
235
|
+
|
|
236
|
+
module.exports = {};
|
|
237
|
+
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webspresso ORM - Utilities
|
|
3
|
+
* Internal helper functions
|
|
4
|
+
* @module core/orm/utils
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Pick specific keys from an object
|
|
9
|
+
* @param {Object} obj - Source object
|
|
10
|
+
* @param {string[]} keys - Keys to pick
|
|
11
|
+
* @returns {Object}
|
|
12
|
+
*/
|
|
13
|
+
function pick(obj, keys) {
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const key of keys) {
|
|
16
|
+
if (key in obj) {
|
|
17
|
+
result[key] = obj[key];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Omit specific keys from an object
|
|
25
|
+
* @param {Object} obj - Source object
|
|
26
|
+
* @param {string[]} keys - Keys to omit
|
|
27
|
+
* @returns {Object}
|
|
28
|
+
*/
|
|
29
|
+
function omit(obj, keys) {
|
|
30
|
+
const result = {};
|
|
31
|
+
const omitSet = new Set(keys);
|
|
32
|
+
for (const key in obj) {
|
|
33
|
+
if (!omitSet.has(key)) {
|
|
34
|
+
result[key] = obj[key];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Format date for database
|
|
42
|
+
* @param {Date} date - Date to format
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
function formatDateForDb(date) {
|
|
46
|
+
return date.toISOString();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Generate timestamp for migration filename
|
|
51
|
+
* @returns {string} Format: YYYYMMDD_HHmmss
|
|
52
|
+
*/
|
|
53
|
+
function generateMigrationTimestamp() {
|
|
54
|
+
const now = new Date();
|
|
55
|
+
const year = now.getFullYear();
|
|
56
|
+
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
57
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
58
|
+
const hours = String(now.getHours()).padStart(2, '0');
|
|
59
|
+
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
60
|
+
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
61
|
+
|
|
62
|
+
return `${year}${month}${day}_${hours}${minutes}${seconds}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Convert snake_case to camelCase
|
|
67
|
+
* @param {string} str - Snake case string
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function snakeToCamel(str) {
|
|
71
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Convert camelCase to snake_case
|
|
76
|
+
* @param {string} str - Camel case string
|
|
77
|
+
* @returns {string}
|
|
78
|
+
*/
|
|
79
|
+
function camelToSnake(str) {
|
|
80
|
+
return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Ensure a value is an array
|
|
85
|
+
* @param {*} value - Value to wrap
|
|
86
|
+
* @returns {Array}
|
|
87
|
+
*/
|
|
88
|
+
function ensureArray(value) {
|
|
89
|
+
if (value === undefined || value === null) {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
return Array.isArray(value) ? value : [value];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Deep clone an object (simple version, no circular refs)
|
|
97
|
+
* @param {Object} obj - Object to clone
|
|
98
|
+
* @returns {Object}
|
|
99
|
+
*/
|
|
100
|
+
function deepClone(obj) {
|
|
101
|
+
if (obj === null || typeof obj !== 'object') {
|
|
102
|
+
return obj;
|
|
103
|
+
}
|
|
104
|
+
if (obj instanceof Date) {
|
|
105
|
+
return new Date(obj);
|
|
106
|
+
}
|
|
107
|
+
if (Array.isArray(obj)) {
|
|
108
|
+
return obj.map(deepClone);
|
|
109
|
+
}
|
|
110
|
+
const cloned = {};
|
|
111
|
+
for (const key in obj) {
|
|
112
|
+
cloned[key] = deepClone(obj[key]);
|
|
113
|
+
}
|
|
114
|
+
return cloned;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
pick,
|
|
119
|
+
omit,
|
|
120
|
+
formatDateForDb,
|
|
121
|
+
generateMigrationTimestamp,
|
|
122
|
+
snakeToCamel,
|
|
123
|
+
camelToSnake,
|
|
124
|
+
ensureArray,
|
|
125
|
+
deepClone,
|
|
126
|
+
};
|
|
127
|
+
|
package/index.js
CHANGED
|
@@ -26,6 +26,12 @@ const {
|
|
|
26
26
|
resetPluginManager
|
|
27
27
|
} = require('./src/plugin-manager');
|
|
28
28
|
|
|
29
|
+
// ORM exports (lazy loaded)
|
|
30
|
+
const orm = require('./core/orm');
|
|
31
|
+
|
|
32
|
+
// Built-in plugins
|
|
33
|
+
const { schemaExplorerPlugin } = require('./plugins');
|
|
34
|
+
|
|
29
35
|
module.exports = {
|
|
30
36
|
// Main API
|
|
31
37
|
createApp,
|
|
@@ -52,6 +58,12 @@ module.exports = {
|
|
|
52
58
|
PluginManager,
|
|
53
59
|
createPluginManager,
|
|
54
60
|
getPluginManager,
|
|
55
|
-
resetPluginManager
|
|
61
|
+
resetPluginManager,
|
|
62
|
+
|
|
63
|
+
// ORM
|
|
64
|
+
...orm,
|
|
65
|
+
|
|
66
|
+
// Plugins
|
|
67
|
+
schemaExplorerPlugin,
|
|
56
68
|
};
|
|
57
69
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webspresso",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
"express",
|
|
19
19
|
"file-based-routing",
|
|
20
20
|
"i18n",
|
|
21
|
-
"framework"
|
|
21
|
+
"framework",
|
|
22
|
+
"orm",
|
|
23
|
+
"knex"
|
|
22
24
|
],
|
|
23
25
|
"author": "cond",
|
|
24
26
|
"license": "MIT",
|
|
@@ -29,25 +31,47 @@
|
|
|
29
31
|
"files": [
|
|
30
32
|
"index.js",
|
|
31
33
|
"bin/",
|
|
32
|
-
"src/"
|
|
34
|
+
"src/",
|
|
35
|
+
"utils/",
|
|
36
|
+
"core/"
|
|
33
37
|
],
|
|
34
38
|
"dependencies": {
|
|
35
39
|
"commander": "^11.1.0",
|
|
36
40
|
"express": "^4.18.2",
|
|
37
41
|
"helmet": "^7.2.0",
|
|
38
42
|
"inquirer": "^8.2.6",
|
|
39
|
-
"
|
|
43
|
+
"knex": "^3.1.0",
|
|
44
|
+
"nunjucks": "^3.2.4",
|
|
45
|
+
"zod": "^3.23.0"
|
|
40
46
|
},
|
|
41
47
|
"peerDependencies": {
|
|
42
|
-
"dotenv": "^16.0.0"
|
|
48
|
+
"dotenv": "^16.0.0",
|
|
49
|
+
"pg": "^8.0.0",
|
|
50
|
+
"mysql2": "^3.0.0",
|
|
51
|
+
"better-sqlite3": "^9.0.0",
|
|
52
|
+
"@faker-js/faker": "^9.0.0"
|
|
43
53
|
},
|
|
44
54
|
"peerDependenciesMeta": {
|
|
45
55
|
"dotenv": {
|
|
46
56
|
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"pg": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"mysql2": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"better-sqlite3": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"@faker-js/faker": {
|
|
68
|
+
"optional": true
|
|
47
69
|
}
|
|
48
70
|
},
|
|
49
71
|
"devDependencies": {
|
|
72
|
+
"@faker-js/faker": "^9.3.0",
|
|
50
73
|
"@vitest/coverage-v8": "^1.2.0",
|
|
74
|
+
"better-sqlite3": "^11.0.0",
|
|
51
75
|
"chokidar": "^3.5.3",
|
|
52
76
|
"dotenv": "^16.3.1",
|
|
53
77
|
"release-it": "^17.11.0",
|
package/src/plugin-manager.js
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema Cache
|
|
3
|
+
* Caches compiled Zod schemas per file path
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const cache = new Map();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get cached schema for a file path
|
|
10
|
+
* @param {string} filePath - Absolute file path
|
|
11
|
+
* @returns {Object|undefined} Compiled schema or undefined
|
|
12
|
+
*/
|
|
13
|
+
function get(filePath) {
|
|
14
|
+
return cache.get(filePath);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Set compiled schema for a file path
|
|
19
|
+
* @param {string} filePath - Absolute file path
|
|
20
|
+
* @param {Object} schema - Compiled schema object
|
|
21
|
+
*/
|
|
22
|
+
function set(filePath, schema) {
|
|
23
|
+
cache.set(filePath, schema);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check if schema exists in cache
|
|
28
|
+
* @param {string} filePath - Absolute file path
|
|
29
|
+
* @returns {boolean}
|
|
30
|
+
*/
|
|
31
|
+
function has(filePath) {
|
|
32
|
+
return cache.has(filePath);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Clear all cached schemas
|
|
37
|
+
* Useful for development hot-reload
|
|
38
|
+
*/
|
|
39
|
+
function clear() {
|
|
40
|
+
cache.clear();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Delete a specific schema from cache
|
|
45
|
+
* @param {string} filePath - Absolute file path
|
|
46
|
+
* @returns {boolean} True if deleted
|
|
47
|
+
*/
|
|
48
|
+
function del(filePath) {
|
|
49
|
+
return cache.delete(filePath);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
get,
|
|
54
|
+
set,
|
|
55
|
+
has,
|
|
56
|
+
clear,
|
|
57
|
+
del
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
|