@schemashift/core 0.2.0 → 0.7.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/README.md +330 -41
- package/dist/index.cjs +1332 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +360 -11
- package/dist/index.d.ts +360 -11
- package/dist/index.js +1312 -1
- package/dist/index.js.map +1 -1
- package/package.json +18 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @schemashift/core
|
|
2
2
|
|
|
3
|
-
Core functionality for SchemaShift schema migrations. Provides schema analysis, detection, and
|
|
3
|
+
Core functionality for SchemaShift schema migrations. Provides schema analysis, detection, transformation engine, ecosystem analysis, governance, and migration utilities.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -26,21 +26,262 @@ console.log(`Found ${result.schemas.length} schemas in ${result.filesWithSchemas
|
|
|
26
26
|
|
|
27
27
|
#### Methods
|
|
28
28
|
|
|
29
|
-
- `addSourceFiles(patterns: string[])`
|
|
30
|
-
- `analyze(): AnalysisResult`
|
|
31
|
-
- `getProject(): Project`
|
|
29
|
+
- `addSourceFiles(patterns: string[])` — Add files to analyze by glob patterns
|
|
30
|
+
- `analyze(): AnalysisResult` — Run analysis and return results
|
|
31
|
+
- `getProject(): Project` — Get the underlying ts-morph Project
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
### TransformEngine
|
|
34
|
+
|
|
35
|
+
Manages transformation handlers and executes migrations.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { TransformEngine } from '@schemashift/core';
|
|
39
|
+
import { createYupToZodHandler } from '@schemashift/yup-zod';
|
|
40
|
+
|
|
41
|
+
const engine = new TransformEngine();
|
|
42
|
+
engine.registerHandler('yup', 'zod', createYupToZodHandler());
|
|
43
|
+
|
|
44
|
+
const sourceFile = project.getSourceFileOrThrow('schema.ts');
|
|
45
|
+
const result = engine.transform(sourceFile, 'yup', 'zod');
|
|
46
|
+
|
|
47
|
+
if (result.success) {
|
|
48
|
+
console.log(result.transformedCode);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Methods
|
|
53
|
+
|
|
54
|
+
- `registerHandler(from, to, handler)` — Register a transformation handler
|
|
55
|
+
- `getHandler(from, to)` — Get a registered handler
|
|
56
|
+
- `transform(sourceFile, from, to)` — Transform a source file
|
|
57
|
+
|
|
58
|
+
### DetailedAnalyzer
|
|
59
|
+
|
|
60
|
+
Provides complexity scoring, migration readiness analysis, and library version detection.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { DetailedAnalyzer, SchemaAnalyzer } from '@schemashift/core';
|
|
64
|
+
|
|
65
|
+
const analyzer = new SchemaAnalyzer();
|
|
66
|
+
analyzer.addSourceFiles(['src/**/*.ts']);
|
|
67
|
+
|
|
68
|
+
const detailed = new DetailedAnalyzer();
|
|
69
|
+
|
|
70
|
+
// Complexity scoring per-schema
|
|
71
|
+
const complexities = detailed.analyzeComplexity(analyzer);
|
|
72
|
+
for (const c of complexities) {
|
|
73
|
+
console.log(`${c.schemaName}: score=${c.score}, level=${c.level}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Migration readiness
|
|
77
|
+
const readiness = detailed.analyzeReadiness(schemas, 'yup', 'zod', supportedMethods);
|
|
78
|
+
console.log(`${readiness.readinessPercent}% ready, risk: ${readiness.riskLevel}`);
|
|
79
|
+
|
|
80
|
+
// Library versions from package.json
|
|
81
|
+
const versions = detailed.detectLibraryVersions('./project');
|
|
82
|
+
// [{ library: 'zod', version: '^3.22.0' }, ...]
|
|
83
|
+
|
|
84
|
+
// Full detailed result
|
|
85
|
+
const result = detailed.generateDetailedResult(complexities, './project');
|
|
86
|
+
console.log(`Average complexity: ${result.averageComplexity}`);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### EcosystemAnalyzer
|
|
90
|
+
|
|
91
|
+
Detects ecosystem packages affected by a migration. Checks for compatibility issues with tRPC, drizzle-zod, zod-validation-error, @hookform/resolvers, Formik, Mantine, OpenAPI generators, and more.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { EcosystemAnalyzer } from '@schemashift/core';
|
|
95
|
+
|
|
96
|
+
const ecosystem = new EcosystemAnalyzer();
|
|
97
|
+
const report = ecosystem.analyze('./project', 'zod-v3', 'v4');
|
|
98
|
+
|
|
99
|
+
// Blockers — packages that will break
|
|
100
|
+
for (const blocker of report.blockers) {
|
|
101
|
+
console.error(blocker);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Warnings — packages that may need updating
|
|
105
|
+
for (const warning of report.warnings) {
|
|
106
|
+
console.warn(warning);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Full issue details
|
|
110
|
+
for (const dep of report.dependencies) {
|
|
111
|
+
console.log(`${dep.package}@${dep.installedVersion}: ${dep.issue}`);
|
|
112
|
+
console.log(` Suggestion: ${dep.suggestion}`);
|
|
113
|
+
console.log(` Severity: ${dep.severity}, Category: ${dep.category}`);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Detected Packages
|
|
118
|
+
|
|
119
|
+
| Package | Migration | Category |
|
|
120
|
+
|---------|-----------|----------|
|
|
121
|
+
| `drizzle-zod` | zod-v3→v4 | ORM |
|
|
122
|
+
| `zod-prisma` / `zod-prisma-types` | zod-v3→v4 | ORM |
|
|
123
|
+
| `@trpc/server` | zod-v3→v4 | API |
|
|
124
|
+
| `trpc-ui` | zod-v3→v4 | UI |
|
|
125
|
+
| `zod-validation-error` | zod-v3→v4 | Validation |
|
|
126
|
+
| `@hookform/resolvers` | all→zod, zod-v3→v4 | Form |
|
|
127
|
+
| `formik` | yup→zod, joi→zod | Form |
|
|
128
|
+
| `@mantine/form` | yup→zod, joi→zod | Form |
|
|
129
|
+
| `zod-openapi` / `@asteasolutions/zod-to-openapi` | zod-v3→v4 | OpenAPI |
|
|
130
|
+
|
|
131
|
+
### PackageUpdater
|
|
132
|
+
|
|
133
|
+
Plans and applies dependency changes to `package.json` after migration.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { PackageUpdater } from '@schemashift/core';
|
|
137
|
+
|
|
138
|
+
const updater = new PackageUpdater();
|
|
139
|
+
|
|
140
|
+
// Plan changes (doesn't modify files)
|
|
141
|
+
const plan = updater.plan('./project', 'yup', 'zod');
|
|
142
|
+
console.log('Add:', plan.add); // { zod: '^3.24.0' }
|
|
143
|
+
console.log('Remove:', plan.remove); // ['yup'] (suggested, not auto-removed)
|
|
144
|
+
console.log('Warnings:', plan.warnings);
|
|
145
|
+
|
|
146
|
+
// Apply the additions to package.json
|
|
147
|
+
updater.apply('./project', plan);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### IncrementalTracker
|
|
151
|
+
|
|
152
|
+
Tracks progress for file-by-file incremental migrations. State is persisted in `.schemashift/incremental.json`.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { IncrementalTracker } from '@schemashift/core';
|
|
156
|
+
|
|
157
|
+
const tracker = new IncrementalTracker('./project');
|
|
158
|
+
|
|
159
|
+
// Start a new incremental migration
|
|
160
|
+
const state = tracker.start(['a.ts', 'b.ts', 'c.ts'], 'yup', 'zod');
|
|
161
|
+
|
|
162
|
+
// Process files in batches
|
|
163
|
+
const batch = tracker.getNextBatch(2); // ['a.ts', 'b.ts']
|
|
164
|
+
|
|
165
|
+
// Mark files as complete or failed
|
|
166
|
+
tracker.markComplete('a.ts');
|
|
167
|
+
tracker.markFailed('b.ts');
|
|
168
|
+
|
|
169
|
+
// Check progress
|
|
170
|
+
const progress = tracker.getProgress();
|
|
171
|
+
// { completed: 1, remaining: 1, failed: 1, total: 3, percent: 33 }
|
|
172
|
+
|
|
173
|
+
// Resume a previous migration
|
|
174
|
+
const resumed = tracker.resume();
|
|
175
|
+
|
|
176
|
+
// Clear state when done
|
|
177
|
+
tracker.clear();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### GovernanceEngine
|
|
181
|
+
|
|
182
|
+
Enforces schema quality rules across a codebase.
|
|
34
183
|
|
|
35
184
|
```typescript
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
185
|
+
import { GovernanceEngine } from '@schemashift/core';
|
|
186
|
+
import { Project } from 'ts-morph';
|
|
187
|
+
|
|
188
|
+
const engine = new GovernanceEngine();
|
|
189
|
+
engine.configure({
|
|
190
|
+
'naming-convention': { pattern: '.*Schema$' },
|
|
191
|
+
'max-complexity': { threshold: 80 },
|
|
192
|
+
'no-any': {},
|
|
193
|
+
'required-validations': {},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const project = new Project();
|
|
197
|
+
project.addSourceFilesAtPaths(['src/**/*.ts']);
|
|
198
|
+
|
|
199
|
+
const result = engine.analyze(project);
|
|
200
|
+
console.log(`Passed: ${result.passed}`);
|
|
201
|
+
console.log(`Files scanned: ${result.filesScanned}`);
|
|
202
|
+
console.log(`Schemas checked: ${result.schemasChecked}`);
|
|
203
|
+
|
|
204
|
+
for (const v of result.violations) {
|
|
205
|
+
console.log(`[${v.severity}] ${v.rule}: ${v.message} (${v.filePath}:${v.lineNumber})`);
|
|
41
206
|
}
|
|
42
207
|
```
|
|
43
208
|
|
|
209
|
+
#### Built-in Rules
|
|
210
|
+
|
|
211
|
+
| Rule | Description | Severity |
|
|
212
|
+
|------|-------------|----------|
|
|
213
|
+
| `naming-convention` | Schemas must match a regex pattern | warning |
|
|
214
|
+
| `max-complexity` | Reject schemas exceeding a complexity score | warning |
|
|
215
|
+
| `no-any` | Disallow `.any()` usage | error |
|
|
216
|
+
| `required-validations` | String schemas must include `.max()` | warning |
|
|
217
|
+
|
|
218
|
+
### CompatibilityAnalyzer
|
|
219
|
+
|
|
220
|
+
Checks schema library version compatibility before migration.
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { CompatibilityAnalyzer } from '@schemashift/core';
|
|
224
|
+
|
|
225
|
+
const compat = new CompatibilityAnalyzer();
|
|
226
|
+
const result = compat.checkCompatibility('./project', 'zod-v3', 'v4');
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### MigrationChain
|
|
230
|
+
|
|
231
|
+
Executes multi-step migrations (e.g., `yup→zod→valibot`).
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import { MigrationChain } from '@schemashift/core';
|
|
235
|
+
|
|
236
|
+
const chain = new MigrationChain(engine);
|
|
237
|
+
const result = chain.execute(sourceFile, [
|
|
238
|
+
{ from: 'yup', to: 'zod' },
|
|
239
|
+
{ from: 'zod', to: 'valibot' },
|
|
240
|
+
]);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### SchemaDependencyResolver
|
|
244
|
+
|
|
245
|
+
Resolves cross-file schema imports for dependency-ordered transformations.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { SchemaDependencyResolver } from '@schemashift/core';
|
|
249
|
+
|
|
250
|
+
const resolver = new SchemaDependencyResolver();
|
|
251
|
+
const graph = resolver.resolve(project, files);
|
|
252
|
+
// graph.order: files sorted by dependency (leaves first)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### PluginLoader
|
|
256
|
+
|
|
257
|
+
Loads custom transform plugins from file paths or npm packages.
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { PluginLoader } from '@schemashift/core';
|
|
261
|
+
|
|
262
|
+
const loader = new PluginLoader();
|
|
263
|
+
const result = loader.load('./my-plugin.js');
|
|
264
|
+
if (result.success) {
|
|
265
|
+
engine.registerHandler(result.plugin.from, result.plugin.to, result.plugin.handler);
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### detectStandardSchema
|
|
270
|
+
|
|
271
|
+
Detects Standard Schema-compatible libraries in a project.
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
import { detectStandardSchema } from '@schemashift/core';
|
|
275
|
+
|
|
276
|
+
const info = detectStandardSchema('./project');
|
|
277
|
+
if (info.detected) {
|
|
278
|
+
console.log('Compatible libraries:', info.compatibleLibraries);
|
|
279
|
+
console.log(info.recommendation);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Supports: Zod 3.23+, Valibot 1.0+, ArkType 2.0+, @effect/schema, TypeBox 0.34+.
|
|
284
|
+
|
|
44
285
|
### detectSchemaLibrary
|
|
45
286
|
|
|
46
287
|
Detects which schema library a module import refers to.
|
|
@@ -56,45 +297,40 @@ detectSchemaLibrary('valibot'); // 'valibot'
|
|
|
56
297
|
detectSchemaLibrary('lodash'); // 'unknown'
|
|
57
298
|
```
|
|
58
299
|
|
|
59
|
-
###
|
|
300
|
+
### detectFormLibraries
|
|
60
301
|
|
|
61
|
-
|
|
302
|
+
Detects form libraries (React Hook Form, Formik, Mantine) in use.
|
|
62
303
|
|
|
63
304
|
```typescript
|
|
64
|
-
import {
|
|
65
|
-
import { createYupToZodHandler } from '@schemashift/yup-zod';
|
|
66
|
-
|
|
67
|
-
const engine = new TransformEngine();
|
|
68
|
-
engine.registerHandler('yup', 'zod', createYupToZodHandler());
|
|
69
|
-
|
|
70
|
-
const sourceFile = project.getSourceFileOrThrow('schema.ts');
|
|
71
|
-
const result = engine.transform(sourceFile, 'yup', 'zod');
|
|
305
|
+
import { detectFormLibraries } from '@schemashift/core';
|
|
72
306
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
} else {
|
|
76
|
-
console.error(result.errors);
|
|
77
|
-
}
|
|
307
|
+
const forms = detectFormLibraries(project);
|
|
308
|
+
// [{ library: 'react-hook-form', resolverUsed: 'yupResolver' }]
|
|
78
309
|
```
|
|
79
310
|
|
|
80
|
-
|
|
311
|
+
### AST Utilities
|
|
312
|
+
|
|
313
|
+
Low-level helpers for working with schema ASTs:
|
|
81
314
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
315
|
+
```typescript
|
|
316
|
+
import {
|
|
317
|
+
parseCallChain,
|
|
318
|
+
buildCallChain,
|
|
319
|
+
isInsideStringLiteral,
|
|
320
|
+
isInsideComment,
|
|
321
|
+
startsWithBase,
|
|
322
|
+
transformMethodChain,
|
|
323
|
+
} from '@schemashift/core';
|
|
324
|
+
|
|
325
|
+
// Parse z.string().email().min(5) into structured chain info
|
|
326
|
+
const chain = parseCallChain(callExpression);
|
|
327
|
+
// { base: 'z', factoryMethod: 'string', factoryArgs: [], methods: [...] }
|
|
328
|
+
```
|
|
85
329
|
|
|
86
|
-
|
|
330
|
+
## Types
|
|
87
331
|
|
|
88
332
|
```typescript
|
|
89
|
-
type SchemaLibrary =
|
|
90
|
-
| 'zod'
|
|
91
|
-
| 'zod-v3'
|
|
92
|
-
| 'yup'
|
|
93
|
-
| 'joi'
|
|
94
|
-
| 'io-ts'
|
|
95
|
-
| 'valibot'
|
|
96
|
-
| 'v4'
|
|
97
|
-
| 'unknown';
|
|
333
|
+
type SchemaLibrary = 'zod' | 'zod-v3' | 'yup' | 'joi' | 'io-ts' | 'valibot' | 'v4' | 'unknown';
|
|
98
334
|
|
|
99
335
|
interface SchemaInfo {
|
|
100
336
|
name: string;
|
|
@@ -119,8 +355,61 @@ interface TransformError {
|
|
|
119
355
|
code?: string;
|
|
120
356
|
}
|
|
121
357
|
|
|
122
|
-
interface
|
|
123
|
-
|
|
358
|
+
interface EcosystemReport {
|
|
359
|
+
dependencies: EcosystemIssue[];
|
|
360
|
+
warnings: string[];
|
|
361
|
+
blockers: string[];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
interface EcosystemIssue {
|
|
365
|
+
package: string;
|
|
366
|
+
installedVersion: string;
|
|
367
|
+
migration: string;
|
|
368
|
+
issue: string;
|
|
369
|
+
suggestion: string;
|
|
370
|
+
severity: 'info' | 'warning' | 'error';
|
|
371
|
+
category: 'orm' | 'form' | 'api' | 'validation-util' | 'openapi' | 'ui';
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
interface PackageUpdatePlan {
|
|
375
|
+
add: Record<string, string>;
|
|
376
|
+
remove: string[];
|
|
377
|
+
warnings: string[];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
interface IncrementalState {
|
|
381
|
+
migrationId: string;
|
|
382
|
+
from: SchemaLibrary;
|
|
383
|
+
to: SchemaLibrary;
|
|
384
|
+
startedAt: string;
|
|
385
|
+
completedFiles: string[];
|
|
386
|
+
remainingFiles: string[];
|
|
387
|
+
failedFiles: string[];
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
interface StandardSchemaInfo {
|
|
391
|
+
detected: boolean;
|
|
392
|
+
compatibleLibraries: Array<{ name: string; version: string }>;
|
|
393
|
+
recommendation: string;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
interface SchemaComplexity {
|
|
397
|
+
schemaName: string;
|
|
398
|
+
filePath: string;
|
|
399
|
+
library: SchemaLibrary;
|
|
400
|
+
lineNumber: number;
|
|
401
|
+
chainLength: number;
|
|
402
|
+
nestedDepth: number;
|
|
403
|
+
validationCount: number;
|
|
404
|
+
score: number;
|
|
405
|
+
level: 'low' | 'medium' | 'high' | 'critical';
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
interface GovernanceResult {
|
|
409
|
+
violations: GovernanceViolation[];
|
|
410
|
+
filesScanned: number;
|
|
411
|
+
schemasChecked: number;
|
|
412
|
+
passed: boolean;
|
|
124
413
|
}
|
|
125
414
|
```
|
|
126
415
|
|