schemashift-cli 0.8.0 → 0.10.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 +18 -0
- package/dist/cli.js +371 -20
- package/dist/index.cjs +85 -8
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +85 -8
- package/package.json +14 -8
package/README.md
CHANGED
|
@@ -33,6 +33,10 @@ schemashift analyze <path> [options]
|
|
|
33
33
|
| `--detailed` | Full stats with complexity scoring | Individual+ |
|
|
34
34
|
| `--readiness <path>` | Migration readiness report, e.g. `yup->zod` | Individual+ |
|
|
35
35
|
| `--complexity` | Per-schema complexity scores | Individual+ |
|
|
36
|
+
| `--behavioral <migration>` | Behavioral difference warnings, e.g. `yup->zod` | Free |
|
|
37
|
+
| `--bundle <migration>` | Bundle size estimation, e.g. `zod->valibot` | Individual+ |
|
|
38
|
+
| `--performance <migration>` | Performance impact analysis, e.g. `zod-v3->v4` | Individual+ |
|
|
39
|
+
| `--dedup` | Detect duplicate type definitions | Individual+ |
|
|
36
40
|
|
|
37
41
|
### `migrate`
|
|
38
42
|
|
|
@@ -73,6 +77,8 @@ schemashift migrate <path> [options]
|
|
|
73
77
|
| `--compat-check` | Run compatibility check before migration | Pro+ |
|
|
74
78
|
| `--fail-on-warnings` | Exit 1 if any warnings | Team |
|
|
75
79
|
| `--max-risk-score <n>` | Exit 1 if any file exceeds risk score | Team |
|
|
80
|
+
| `--scaffold-tests` | Generate validation tests after migration | Pro+ |
|
|
81
|
+
| `--audit` | Enable migration audit logging | Team |
|
|
76
82
|
|
|
77
83
|
### `watch`
|
|
78
84
|
|
|
@@ -193,6 +199,18 @@ schemashift migrate ./src --chain yup->zod->valibot
|
|
|
193
199
|
# CI mode
|
|
194
200
|
schemashift migrate ./src --from yup --to zod --ci --report json
|
|
195
201
|
|
|
202
|
+
# Backward migration: Zod→Yup
|
|
203
|
+
schemashift migrate ./src --from zod --to yup
|
|
204
|
+
|
|
205
|
+
# Backward migration: Valibot→Zod
|
|
206
|
+
schemashift migrate ./src --from valibot --to zod
|
|
207
|
+
|
|
208
|
+
# Analyze with behavioral warnings and bundle estimation
|
|
209
|
+
schemashift analyze ./src --behavioral yup->zod --bundle yup->zod
|
|
210
|
+
|
|
211
|
+
# Migrate with test scaffolding
|
|
212
|
+
schemashift migrate ./src --from yup --to zod --scaffold-tests
|
|
213
|
+
|
|
196
214
|
# Rollback last migration
|
|
197
215
|
schemashift rollback
|
|
198
216
|
```
|
package/dist/cli.js
CHANGED
|
@@ -10,17 +10,25 @@ import { existsSync as existsSync4, readFileSync as readFileSync4, statSync, wri
|
|
|
10
10
|
import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
|
|
11
11
|
import { fileURLToPath } from "url";
|
|
12
12
|
import {
|
|
13
|
+
BehavioralWarningAnalyzer,
|
|
14
|
+
BundleEstimator,
|
|
13
15
|
CompatibilityAnalyzer,
|
|
14
16
|
DetailedAnalyzer,
|
|
15
17
|
detectFormLibraries,
|
|
16
18
|
GovernanceEngine,
|
|
19
|
+
IncrementalTracker,
|
|
17
20
|
loadConfig,
|
|
21
|
+
MigrationAuditLog,
|
|
18
22
|
MigrationChain,
|
|
23
|
+
PerformanceAnalyzer,
|
|
19
24
|
PluginLoader,
|
|
20
25
|
SchemaAnalyzer,
|
|
21
26
|
SchemaDependencyResolver,
|
|
22
|
-
|
|
27
|
+
TestScaffolder,
|
|
28
|
+
TransformEngine,
|
|
29
|
+
TypeDedupDetector
|
|
23
30
|
} from "@schemashift/core";
|
|
31
|
+
import { createIoTsToEffectHandler } from "@schemashift/io-ts-effect";
|
|
24
32
|
import { createIoTsToZodHandler } from "@schemashift/io-ts-zod";
|
|
25
33
|
import { createJoiToZodHandler } from "@schemashift/joi-zod";
|
|
26
34
|
|
|
@@ -35827,7 +35835,13 @@ var TIER_FEATURES = {
|
|
|
35827
35835
|
maxRiskScoreThreshold: false,
|
|
35828
35836
|
formResolverMigration: false,
|
|
35829
35837
|
complexityEstimator: false,
|
|
35830
|
-
monorepoAware: false
|
|
35838
|
+
monorepoAware: false,
|
|
35839
|
+
behavioralWarnings: true,
|
|
35840
|
+
bundleEstimator: false,
|
|
35841
|
+
performanceAnalyzer: false,
|
|
35842
|
+
typeDeduplication: false,
|
|
35843
|
+
testScaffolding: false,
|
|
35844
|
+
auditLogging: false
|
|
35831
35845
|
},
|
|
35832
35846
|
[
|
|
35833
35847
|
"individual"
|
|
@@ -35854,7 +35868,13 @@ var TIER_FEATURES = {
|
|
|
35854
35868
|
maxRiskScoreThreshold: false,
|
|
35855
35869
|
formResolverMigration: true,
|
|
35856
35870
|
complexityEstimator: true,
|
|
35857
|
-
monorepoAware: false
|
|
35871
|
+
monorepoAware: false,
|
|
35872
|
+
behavioralWarnings: true,
|
|
35873
|
+
bundleEstimator: true,
|
|
35874
|
+
performanceAnalyzer: true,
|
|
35875
|
+
typeDeduplication: true,
|
|
35876
|
+
testScaffolding: false,
|
|
35877
|
+
auditLogging: false
|
|
35858
35878
|
},
|
|
35859
35879
|
[
|
|
35860
35880
|
"pro"
|
|
@@ -35867,7 +35887,14 @@ var TIER_FEATURES = {
|
|
|
35867
35887
|
"zod-v3->v4",
|
|
35868
35888
|
"io-ts->zod",
|
|
35869
35889
|
"zod->valibot",
|
|
35870
|
-
"any->valibot"
|
|
35890
|
+
"any->valibot",
|
|
35891
|
+
"zod->yup",
|
|
35892
|
+
"valibot->zod",
|
|
35893
|
+
"zod->arktype",
|
|
35894
|
+
"arktype->zod",
|
|
35895
|
+
"zod->superstruct",
|
|
35896
|
+
"superstruct->zod",
|
|
35897
|
+
"io-ts->effect"
|
|
35871
35898
|
],
|
|
35872
35899
|
devices: 4,
|
|
35873
35900
|
ciSupport: true,
|
|
@@ -35888,7 +35915,13 @@ var TIER_FEATURES = {
|
|
|
35888
35915
|
maxRiskScoreThreshold: false,
|
|
35889
35916
|
formResolverMigration: true,
|
|
35890
35917
|
complexityEstimator: true,
|
|
35891
|
-
monorepoAware: true
|
|
35918
|
+
monorepoAware: true,
|
|
35919
|
+
behavioralWarnings: true,
|
|
35920
|
+
bundleEstimator: true,
|
|
35921
|
+
performanceAnalyzer: true,
|
|
35922
|
+
typeDeduplication: true,
|
|
35923
|
+
testScaffolding: true,
|
|
35924
|
+
auditLogging: false
|
|
35892
35925
|
},
|
|
35893
35926
|
[
|
|
35894
35927
|
"team"
|
|
@@ -35901,7 +35934,14 @@ var TIER_FEATURES = {
|
|
|
35901
35934
|
"zod-v3->v4",
|
|
35902
35935
|
"io-ts->zod",
|
|
35903
35936
|
"any->valibot",
|
|
35904
|
-
"zod->valibot"
|
|
35937
|
+
"zod->valibot",
|
|
35938
|
+
"zod->yup",
|
|
35939
|
+
"valibot->zod",
|
|
35940
|
+
"zod->arktype",
|
|
35941
|
+
"arktype->zod",
|
|
35942
|
+
"zod->superstruct",
|
|
35943
|
+
"superstruct->zod",
|
|
35944
|
+
"io-ts->effect"
|
|
35905
35945
|
],
|
|
35906
35946
|
devices: Infinity,
|
|
35907
35947
|
ciSupport: true,
|
|
@@ -35922,7 +35962,13 @@ var TIER_FEATURES = {
|
|
|
35922
35962
|
maxRiskScoreThreshold: true,
|
|
35923
35963
|
formResolverMigration: true,
|
|
35924
35964
|
complexityEstimator: true,
|
|
35925
|
-
monorepoAware: true
|
|
35965
|
+
monorepoAware: true,
|
|
35966
|
+
behavioralWarnings: true,
|
|
35967
|
+
bundleEstimator: true,
|
|
35968
|
+
performanceAnalyzer: true,
|
|
35969
|
+
typeDeduplication: true,
|
|
35970
|
+
testScaffolding: true,
|
|
35971
|
+
auditLogging: true
|
|
35926
35972
|
}
|
|
35927
35973
|
};
|
|
35928
35974
|
function canUseMigration(tier, from, to) {
|
|
@@ -36199,9 +36245,14 @@ var LicenseManager = class {
|
|
|
36199
36245
|
};
|
|
36200
36246
|
|
|
36201
36247
|
// src/cli.ts
|
|
36202
|
-
import { createYupToZodHandler } from "@schemashift/yup-zod";
|
|
36248
|
+
import { createYupToZodHandler, createZodToYupHandler } from "@schemashift/yup-zod";
|
|
36249
|
+
import { createArktypeToZodHandler, createZodToArktypeHandler } from "@schemashift/zod-arktype";
|
|
36250
|
+
import {
|
|
36251
|
+
createSuperstructToZodHandler,
|
|
36252
|
+
createZodToSuperstructHandler
|
|
36253
|
+
} from "@schemashift/zod-superstruct";
|
|
36203
36254
|
import { createZodV3ToV4Handler } from "@schemashift/zod-v3-v4";
|
|
36204
|
-
import { createZodToValibotHandler } from "@schemashift/zod-valibot";
|
|
36255
|
+
import { createValibotToZodHandler, createZodToValibotHandler } from "@schemashift/zod-valibot";
|
|
36205
36256
|
import { Command } from "commander";
|
|
36206
36257
|
import { glob as glob2 } from "glob";
|
|
36207
36258
|
import { Listr } from "listr2";
|
|
@@ -36883,6 +36934,12 @@ var WatchMode = class {
|
|
|
36883
36934
|
console.log(pc3.cyan(`
|
|
36884
36935
|
Watching ${files.length} files for changes...
|
|
36885
36936
|
`));
|
|
36937
|
+
if (options.dependents && options.dependents.size > 0) {
|
|
36938
|
+
console.log(
|
|
36939
|
+
pc3.dim(`Dependency-aware mode: ${options.dependents.size} files with dependents
|
|
36940
|
+
`)
|
|
36941
|
+
);
|
|
36942
|
+
}
|
|
36886
36943
|
console.log(pc3.dim("Press Ctrl+C to stop\n"));
|
|
36887
36944
|
const directories = new Set(files.map((f) => f.split("/").slice(0, -1).join("/")));
|
|
36888
36945
|
for (const dir of directories) {
|
|
@@ -36903,8 +36960,26 @@ Watching ${files.length} files for changes...
|
|
|
36903
36960
|
Changed: ${relative2(process.cwd(), fullPath)}`));
|
|
36904
36961
|
try {
|
|
36905
36962
|
await options.onTransform(fullPath);
|
|
36906
|
-
console.log(pc3.green(`Transformed successfully
|
|
36907
|
-
|
|
36963
|
+
console.log(pc3.green(`Transformed successfully`));
|
|
36964
|
+
const dependentFiles = options.dependents?.get(fullPath);
|
|
36965
|
+
if (dependentFiles && dependentFiles.length > 0) {
|
|
36966
|
+
console.log(
|
|
36967
|
+
pc3.cyan(` Re-transforming ${dependentFiles.length} dependent file(s)...`)
|
|
36968
|
+
);
|
|
36969
|
+
for (const depFile of dependentFiles) {
|
|
36970
|
+
try {
|
|
36971
|
+
await options.onTransform(depFile);
|
|
36972
|
+
console.log(pc3.green(` \u2713 ${relative2(process.cwd(), depFile)}`));
|
|
36973
|
+
} catch (error) {
|
|
36974
|
+
console.error(
|
|
36975
|
+
pc3.red(
|
|
36976
|
+
` \u2717 ${relative2(process.cwd(), depFile)}: ${error instanceof Error ? error.message : String(error)}`
|
|
36977
|
+
)
|
|
36978
|
+
);
|
|
36979
|
+
}
|
|
36980
|
+
}
|
|
36981
|
+
}
|
|
36982
|
+
console.log("");
|
|
36908
36983
|
} catch (error) {
|
|
36909
36984
|
console.error(
|
|
36910
36985
|
pc3.red(
|
|
@@ -36930,6 +37005,21 @@ Changed: ${relative2(process.cwd(), fullPath)}`));
|
|
|
36930
37005
|
}
|
|
36931
37006
|
this.debounceTimers.clear();
|
|
36932
37007
|
}
|
|
37008
|
+
/**
|
|
37009
|
+
* Build a reverse dependency map (file -> files that depend on it).
|
|
37010
|
+
* Takes the forward dependency map from SchemaDependencyResolver and inverts it.
|
|
37011
|
+
*/
|
|
37012
|
+
static buildDependentsMap(dependencies) {
|
|
37013
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
37014
|
+
for (const [file, deps] of dependencies) {
|
|
37015
|
+
for (const dep of deps) {
|
|
37016
|
+
const existing = dependents.get(dep) ?? [];
|
|
37017
|
+
existing.push(file);
|
|
37018
|
+
dependents.set(dep, existing);
|
|
37019
|
+
}
|
|
37020
|
+
}
|
|
37021
|
+
return dependents;
|
|
37022
|
+
}
|
|
36933
37023
|
matchesPatterns(file, include, exclude) {
|
|
36934
37024
|
const isIncluded = include.some((p) => minimatch(file, p));
|
|
36935
37025
|
const isExcluded = exclude.some((p) => minimatch(file, p));
|
|
@@ -36948,6 +37038,13 @@ engine.registerHandler("joi", "zod", createJoiToZodHandler());
|
|
|
36948
37038
|
engine.registerHandler("io-ts", "zod", createIoTsToZodHandler());
|
|
36949
37039
|
engine.registerHandler("zod-v3", "v4", createZodV3ToV4Handler());
|
|
36950
37040
|
engine.registerHandler("zod", "valibot", createZodToValibotHandler());
|
|
37041
|
+
engine.registerHandler("zod", "yup", createZodToYupHandler());
|
|
37042
|
+
engine.registerHandler("valibot", "zod", createValibotToZodHandler());
|
|
37043
|
+
engine.registerHandler("zod", "arktype", createZodToArktypeHandler());
|
|
37044
|
+
engine.registerHandler("arktype", "zod", createArktypeToZodHandler());
|
|
37045
|
+
engine.registerHandler("zod", "superstruct", createZodToSuperstructHandler());
|
|
37046
|
+
engine.registerHandler("superstruct", "zod", createSuperstructToZodHandler());
|
|
37047
|
+
engine.registerHandler("io-ts", "effect", createIoTsToEffectHandler());
|
|
36951
37048
|
var POLAR_URL = "https://schemashift.qwady.app";
|
|
36952
37049
|
program.name("schemashift").version(pkg.version).description("TypeScript schema migration CLI");
|
|
36953
37050
|
program.command("init").description("Create .schemashiftrc.json config file").option("-f, --force", "Overwrite existing config").action((options) => {
|
|
@@ -36977,7 +37074,10 @@ program.command("init").description("Create .schemashiftrc.json config file").op
|
|
|
36977
37074
|
console.log(pc4.green("Created .schemashiftrc.json"));
|
|
36978
37075
|
console.log(pc4.dim("Edit the file to customize your migration settings."));
|
|
36979
37076
|
});
|
|
36980
|
-
program.command("analyze <path>").description("Analyze schemas in your project").option("--json", "Output as JSON").option("-v, --verbose", "Show detailed analysis").option("--detailed", "Show complexity analysis (Individual+)").option("--readiness <migration>", "Check migration readiness, e.g. yup->zod (Individual+)").option("--complexity", "Show per-schema complexity scores (Individual+)").
|
|
37077
|
+
program.command("analyze <path>").description("Analyze schemas in your project").option("--json", "Output as JSON").option("-v, --verbose", "Show detailed analysis").option("--detailed", "Show complexity analysis (Individual+)").option("--readiness <migration>", "Check migration readiness, e.g. yup->zod (Individual+)").option("--complexity", "Show per-schema complexity scores (Individual+)").option("--behavioral <migration>", "Show behavioral difference warnings, e.g. yup->zod").option("--bundle <migration>", "Show bundle size estimation, e.g. zod->valibot (Individual+)").option(
|
|
37078
|
+
"--performance <migration>",
|
|
37079
|
+
"Show performance impact analysis, e.g. zod-v3->v4 (Individual+)"
|
|
37080
|
+
).option("--dedup", "Detect duplicate type definitions (Individual+)").action(async (targetPath, options) => {
|
|
36981
37081
|
const analyzer = new SchemaAnalyzer();
|
|
36982
37082
|
let files;
|
|
36983
37083
|
if (existsSync4(targetPath) && statSync(targetPath).isFile()) {
|
|
@@ -37158,13 +37258,147 @@ Migration Readiness: ${from} -> ${to}
|
|
|
37158
37258
|
}
|
|
37159
37259
|
}
|
|
37160
37260
|
}
|
|
37261
|
+
if (options.behavioral) {
|
|
37262
|
+
const migParts = options.behavioral.split("->");
|
|
37263
|
+
if (migParts.length !== 2) {
|
|
37264
|
+
console.error(pc4.red("Invalid format. Use: --behavioral yup->zod"));
|
|
37265
|
+
} else {
|
|
37266
|
+
const [bFrom, bTo] = migParts;
|
|
37267
|
+
const behavioralAnalyzer = new BehavioralWarningAnalyzer();
|
|
37268
|
+
const sourceFiles = analyzer.getProject().getSourceFiles();
|
|
37269
|
+
const behavioralResult = behavioralAnalyzer.analyze(
|
|
37270
|
+
sourceFiles,
|
|
37271
|
+
bFrom,
|
|
37272
|
+
bTo
|
|
37273
|
+
);
|
|
37274
|
+
if (behavioralResult.warnings.length > 0) {
|
|
37275
|
+
console.log(pc4.bold("\nBehavioral Difference Warnings\n"));
|
|
37276
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
37277
|
+
for (const w of behavioralResult.warnings) {
|
|
37278
|
+
const existing = byCategory.get(w.category) ?? [];
|
|
37279
|
+
existing.push(w);
|
|
37280
|
+
byCategory.set(w.category, existing);
|
|
37281
|
+
}
|
|
37282
|
+
for (const [category, catWarnings] of byCategory) {
|
|
37283
|
+
console.log(pc4.yellow(` [${category}] ${catWarnings.length} warning(s)`));
|
|
37284
|
+
for (const w of catWarnings.slice(0, 5)) {
|
|
37285
|
+
console.log(` ${w.message}`);
|
|
37286
|
+
console.log(` ${pc4.dim(w.detail)}`);
|
|
37287
|
+
}
|
|
37288
|
+
if (catWarnings.length > 5) {
|
|
37289
|
+
console.log(pc4.dim(` ... and ${catWarnings.length - 5} more`));
|
|
37290
|
+
}
|
|
37291
|
+
}
|
|
37292
|
+
} else {
|
|
37293
|
+
console.log(pc4.green("\nNo behavioral difference warnings found."));
|
|
37294
|
+
}
|
|
37295
|
+
}
|
|
37296
|
+
}
|
|
37297
|
+
if (options.bundle) {
|
|
37298
|
+
const validation = await licenseManager.validate();
|
|
37299
|
+
const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
|
|
37300
|
+
if (!tier.bundleEstimator) {
|
|
37301
|
+
console.error(pc4.red("\nBundle estimation requires Individual tier or higher."));
|
|
37302
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37303
|
+
} else {
|
|
37304
|
+
const migParts = options.bundle.split("->");
|
|
37305
|
+
if (migParts.length !== 2) {
|
|
37306
|
+
console.error(pc4.red("Invalid format. Use: --bundle zod->valibot"));
|
|
37307
|
+
} else {
|
|
37308
|
+
const [bFrom, bTo] = migParts;
|
|
37309
|
+
const bundleEstimator = new BundleEstimator();
|
|
37310
|
+
const sourceFiles = analyzer.getProject().getSourceFiles();
|
|
37311
|
+
const estimate = bundleEstimator.estimate(
|
|
37312
|
+
sourceFiles,
|
|
37313
|
+
bFrom,
|
|
37314
|
+
bTo
|
|
37315
|
+
);
|
|
37316
|
+
console.log(pc4.bold("\nBundle Size Estimation\n"));
|
|
37317
|
+
console.log(
|
|
37318
|
+
` ${estimate.from.library}: ~${pc4.cyan(`${estimate.from.minifiedGzipKb}kB`)}`
|
|
37319
|
+
);
|
|
37320
|
+
console.log(` ${estimate.to.library}: ~${pc4.cyan(`${estimate.to.minifiedGzipKb}kB`)}`);
|
|
37321
|
+
console.log(
|
|
37322
|
+
` Delta: ${pc4.yellow(`${estimate.estimatedDelta > 0 ? "+" : ""}${estimate.estimatedDelta.toFixed(1)}kB (${estimate.deltaPercent.toFixed(0)}%)`)}`
|
|
37323
|
+
);
|
|
37324
|
+
console.log(`
|
|
37325
|
+
${pc4.dim(estimate.summary)}`);
|
|
37326
|
+
}
|
|
37327
|
+
}
|
|
37328
|
+
}
|
|
37329
|
+
if (options.performance) {
|
|
37330
|
+
const validation = await licenseManager.validate();
|
|
37331
|
+
const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
|
|
37332
|
+
if (!tier.performanceAnalyzer) {
|
|
37333
|
+
console.error(pc4.red("\nPerformance analysis requires Individual tier or higher."));
|
|
37334
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37335
|
+
} else {
|
|
37336
|
+
const migParts = options.performance.split("->");
|
|
37337
|
+
if (migParts.length !== 2) {
|
|
37338
|
+
console.error(pc4.red("Invalid format. Use: --performance zod-v3->v4"));
|
|
37339
|
+
} else {
|
|
37340
|
+
const [pFrom, pTo] = migParts;
|
|
37341
|
+
const perfAnalyzer = new PerformanceAnalyzer();
|
|
37342
|
+
const sourceFiles = analyzer.getProject().getSourceFiles();
|
|
37343
|
+
const perfResult = perfAnalyzer.analyze(
|
|
37344
|
+
sourceFiles,
|
|
37345
|
+
pFrom,
|
|
37346
|
+
pTo
|
|
37347
|
+
);
|
|
37348
|
+
if (perfResult.warnings.length > 0) {
|
|
37349
|
+
console.log(pc4.bold("\nPerformance Impact Analysis\n"));
|
|
37350
|
+
for (const w of perfResult.warnings) {
|
|
37351
|
+
const color = w.severity === "error" ? pc4.red : w.severity === "warning" ? pc4.yellow : pc4.dim;
|
|
37352
|
+
console.log(` ${color(`[${w.severity}]`)} ${w.message}`);
|
|
37353
|
+
console.log(` ${pc4.dim(w.detail)}`);
|
|
37354
|
+
}
|
|
37355
|
+
console.log(`
|
|
37356
|
+
${pc4.dim(perfResult.recommendation)}`);
|
|
37357
|
+
} else {
|
|
37358
|
+
console.log(pc4.green("\nNo performance concerns detected."));
|
|
37359
|
+
}
|
|
37360
|
+
}
|
|
37361
|
+
}
|
|
37362
|
+
}
|
|
37363
|
+
if (options.dedup) {
|
|
37364
|
+
const validation = await licenseManager.validate();
|
|
37365
|
+
const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
|
|
37366
|
+
if (!tier.typeDeduplication) {
|
|
37367
|
+
console.error(pc4.red("\nType deduplication detection requires Individual tier or higher."));
|
|
37368
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37369
|
+
} else {
|
|
37370
|
+
const dedupDetector = new TypeDedupDetector();
|
|
37371
|
+
const sourceFiles = analyzer.getProject().getSourceFiles();
|
|
37372
|
+
const dedupResult = dedupDetector.detect(sourceFiles);
|
|
37373
|
+
if (dedupResult.candidates.length > 0) {
|
|
37374
|
+
console.log(pc4.bold("\nDuplicate Type Candidates\n"));
|
|
37375
|
+
for (const c of dedupResult.candidates.slice(0, 10)) {
|
|
37376
|
+
console.log(` ${pc4.cyan(c.typeName)} <-> ${pc4.cyan(c.schemaName)}`);
|
|
37377
|
+
console.log(` Type: ${pc4.dim(c.typeFilePath)}:${c.typeLineNumber}`);
|
|
37378
|
+
console.log(` Schema: ${pc4.dim(c.schemaFilePath)}:${c.schemaLineNumber}`);
|
|
37379
|
+
console.log(` Confidence: ${pc4.dim(c.confidence)} | ${pc4.dim(c.suggestion)}`);
|
|
37380
|
+
}
|
|
37381
|
+
if (dedupResult.candidates.length > 10) {
|
|
37382
|
+
console.log(pc4.dim(` ... and ${dedupResult.candidates.length - 10} more`));
|
|
37383
|
+
}
|
|
37384
|
+
} else {
|
|
37385
|
+
console.log(pc4.green("\nNo duplicate type candidates found."));
|
|
37386
|
+
}
|
|
37387
|
+
}
|
|
37388
|
+
}
|
|
37161
37389
|
});
|
|
37162
|
-
program.command("migrate <path>").description("Migrate schemas from one library to another").
|
|
37390
|
+
program.command("migrate <path>").description("Migrate schemas from one library to another").option("-f, --from <library>", "Source library (yup, joi, io-ts, zod-v3, zod)").option("-t, --to <library>", "Target library (zod, v4, valibot, yup, arktype, superstruct)").option("-d, --dry-run", "Preview changes without writing files").option("-v, --verbose", "Show detailed transformation info").option("-c, --config <path>", "Path to config file").option("--report <format>", "Generate report (json, html, csv)").option("--report-output <path>", "Report output path").option("--git-branch", "Create git branch for changes").option("--git-commit", "Auto-commit changes").option("--no-backup", "Skip backup creation").option("--yes", "Skip confirmation prompt").option("--ci", "CI mode (non-interactive, exit code on failure)").option("--cross-file", "Resolve cross-file schema dependencies (Pro+)").option("--chain <path>", "Chain migrations, e.g. yup->zod->valibot (Pro+)").option("--compat-check", "Run compatibility check before migration (Pro+)").option("--fail-on-warnings", "Exit 1 if any warnings (Team+)").option(
|
|
37163
37391
|
"--max-risk-score <score>",
|
|
37164
37392
|
"Exit 1 if any file exceeds risk score (Team+)",
|
|
37165
37393
|
Number.parseInt
|
|
37166
|
-
).action(async (targetPath, options) => {
|
|
37394
|
+
).option("--incremental", "Enable incremental migration (file-by-file with progress tracking)").option("--resume", "Resume a previously started incremental migration").option("--incremental-status", "Show incremental migration progress").option("--scaffold-tests", "Generate validation tests after migration (Pro+)").option("--audit", "Enable migration audit logging (Team+)").action(async (targetPath, options) => {
|
|
37167
37395
|
const startTime = Date.now();
|
|
37396
|
+
if (!options.chain && (!options.from || !options.to)) {
|
|
37397
|
+
console.error(pc4.red("Either --from and --to, or --chain must be specified."));
|
|
37398
|
+
console.error(pc4.dim(" Single-step: schemashift migrate <path> -f yup -t zod"));
|
|
37399
|
+
console.error(pc4.dim(" Chain: schemashift migrate <path> --chain yup->zod->valibot"));
|
|
37400
|
+
process.exit(1);
|
|
37401
|
+
}
|
|
37168
37402
|
if (options.maxRiskScore !== void 0 && Number.isNaN(options.maxRiskScore)) {
|
|
37169
37403
|
console.error(pc4.red("--max-risk-score must be a valid number."));
|
|
37170
37404
|
process.exit(1);
|
|
@@ -37288,10 +37522,14 @@ Compatibility score: ${pc4.cyan(compatResult.overallScore.toString())}%`);
|
|
|
37288
37522
|
if (options.chain) {
|
|
37289
37523
|
const migrationChain = new MigrationChain();
|
|
37290
37524
|
chainSteps = migrationChain.parseChain(options.chain);
|
|
37291
|
-
|
|
37292
|
-
|
|
37525
|
+
if (chainSteps.length > 0) {
|
|
37526
|
+
if (!options.from) options.from = chainSteps[0]?.from;
|
|
37527
|
+
if (!options.to) options.to = chainSteps[chainSteps.length - 1]?.to;
|
|
37528
|
+
}
|
|
37529
|
+
const chainValidation = migrationChain.validateChain(chainSteps, engine);
|
|
37530
|
+
if (!chainValidation.valid) {
|
|
37293
37531
|
console.error(pc4.red("Chain migration validation failed:"));
|
|
37294
|
-
for (const err of
|
|
37532
|
+
for (const err of chainValidation.errors) {
|
|
37295
37533
|
console.error(` ${pc4.red(err)}`);
|
|
37296
37534
|
}
|
|
37297
37535
|
process.exit(1);
|
|
@@ -37318,6 +37556,41 @@ Compatibility score: ${pc4.cyan(compatResult.overallScore.toString())}%`);
|
|
|
37318
37556
|
console.log(pc4.yellow("No files found matching patterns."));
|
|
37319
37557
|
process.exit(0);
|
|
37320
37558
|
}
|
|
37559
|
+
const incrementalTracker = new IncrementalTracker(resolve2(targetPath));
|
|
37560
|
+
if (options.incrementalStatus) {
|
|
37561
|
+
const progress = incrementalTracker.getProgress();
|
|
37562
|
+
if (!progress) {
|
|
37563
|
+
console.log(pc4.yellow("No incremental migration in progress."));
|
|
37564
|
+
process.exit(0);
|
|
37565
|
+
}
|
|
37566
|
+
console.log(pc4.bold("\nIncremental Migration Status\n"));
|
|
37567
|
+
console.log(`Completed: ${pc4.green(progress.completed.toString())}`);
|
|
37568
|
+
console.log(`Remaining: ${pc4.cyan(progress.remaining.toString())}`);
|
|
37569
|
+
console.log(`Failed: ${pc4.red(progress.failed.toString())}`);
|
|
37570
|
+
console.log(`Total: ${progress.total}`);
|
|
37571
|
+
console.log(`Progress: ${pc4.cyan(`${progress.percent}%`)}`);
|
|
37572
|
+
process.exit(0);
|
|
37573
|
+
}
|
|
37574
|
+
if (options.resume) {
|
|
37575
|
+
const state = incrementalTracker.resume();
|
|
37576
|
+
if (!state) {
|
|
37577
|
+
console.error(pc4.red("No incremental migration to resume."));
|
|
37578
|
+
process.exit(1);
|
|
37579
|
+
}
|
|
37580
|
+
files = state.remainingFiles;
|
|
37581
|
+
console.log(pc4.dim(`Resuming incremental migration: ${state.migrationId}`));
|
|
37582
|
+
const progress = incrementalTracker.getProgress();
|
|
37583
|
+
if (progress) {
|
|
37584
|
+
console.log(
|
|
37585
|
+
pc4.dim(
|
|
37586
|
+
`Progress: ${progress.completed}/${progress.total} completed (${progress.percent}%)`
|
|
37587
|
+
)
|
|
37588
|
+
);
|
|
37589
|
+
}
|
|
37590
|
+
} else if (options.incremental) {
|
|
37591
|
+
incrementalTracker.start(files, options.from, options.to);
|
|
37592
|
+
console.log(pc4.dim("Started incremental migration."));
|
|
37593
|
+
}
|
|
37321
37594
|
if (files.length > features.maxFiles) {
|
|
37322
37595
|
console.error(
|
|
37323
37596
|
pc4.red(`File limit exceeded. Found ${files.length}, max ${features.maxFiles}.`)
|
|
@@ -37452,6 +37725,30 @@ Migrating ${displayPath}
|
|
|
37452
37725
|
}
|
|
37453
37726
|
}
|
|
37454
37727
|
}
|
|
37728
|
+
if (options.incremental || options.resume) {
|
|
37729
|
+
for (const result of results) {
|
|
37730
|
+
if (result.success) {
|
|
37731
|
+
incrementalTracker.markComplete(result.filePath);
|
|
37732
|
+
} else {
|
|
37733
|
+
incrementalTracker.markFailed(result.filePath);
|
|
37734
|
+
}
|
|
37735
|
+
}
|
|
37736
|
+
const progress = incrementalTracker.getProgress();
|
|
37737
|
+
if (progress) {
|
|
37738
|
+
console.log(
|
|
37739
|
+
pc4.bold(`
|
|
37740
|
+
Incremental: ${progress.completed}/${progress.total} (${progress.percent}%)`)
|
|
37741
|
+
);
|
|
37742
|
+
if (progress.remaining > 0) {
|
|
37743
|
+
console.log(
|
|
37744
|
+
pc4.dim(`Run with --resume to continue. ${progress.remaining} files remaining.`)
|
|
37745
|
+
);
|
|
37746
|
+
}
|
|
37747
|
+
if (progress.failed > 0) {
|
|
37748
|
+
console.log(pc4.yellow(`${progress.failed} file(s) failed. Run with --resume to retry.`));
|
|
37749
|
+
}
|
|
37750
|
+
}
|
|
37751
|
+
}
|
|
37455
37752
|
if (options.gitCommit && git.isAvailable() && !options.dryRun) {
|
|
37456
37753
|
const successFiles = results.filter((r) => r.success).map((r) => r.filePath);
|
|
37457
37754
|
if (successFiles.length > 0) {
|
|
@@ -37464,9 +37761,11 @@ Migrating ${displayPath}
|
|
|
37464
37761
|
if (options.report === "html" && !features.htmlReports) {
|
|
37465
37762
|
console.error(pc4.red("HTML reports require Individual tier or higher."));
|
|
37466
37763
|
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37764
|
+
process.exit(1);
|
|
37467
37765
|
} else if (options.report === "csv" && !features.csvExport) {
|
|
37468
37766
|
console.error(pc4.red("CSV export requires Individual tier or higher."));
|
|
37469
37767
|
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37768
|
+
process.exit(1);
|
|
37470
37769
|
} else {
|
|
37471
37770
|
const reporter = new ReportGenerator();
|
|
37472
37771
|
const includeRisk = features.riskScoring;
|
|
@@ -37489,6 +37788,58 @@ Migrating ${displayPath}
|
|
|
37489
37788
|
console.log(pc4.green(`Report saved: ${outputPath}`));
|
|
37490
37789
|
}
|
|
37491
37790
|
}
|
|
37791
|
+
if (options.scaffoldTests) {
|
|
37792
|
+
if (!features.testScaffolding) {
|
|
37793
|
+
console.error(pc4.red("\nTest scaffolding requires Pro tier or higher."));
|
|
37794
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37795
|
+
} else {
|
|
37796
|
+
const scaffolder = new TestScaffolder();
|
|
37797
|
+
const successfulFiles = results.filter((r) => r.success).map((r) => r.filePath);
|
|
37798
|
+
if (successfulFiles.length > 0) {
|
|
37799
|
+
const scaffoldAnalyzer = new SchemaAnalyzer();
|
|
37800
|
+
for (const f of successfulFiles) {
|
|
37801
|
+
scaffoldAnalyzer.addSourceFiles([f]);
|
|
37802
|
+
}
|
|
37803
|
+
const sourceFiles = scaffoldAnalyzer.getProject().getSourceFiles();
|
|
37804
|
+
const scaffoldResult = scaffolder.scaffold(sourceFiles, options.from, options.to);
|
|
37805
|
+
console.log(pc4.bold("\nTest Scaffolding\n"));
|
|
37806
|
+
console.log(
|
|
37807
|
+
` Generated ${pc4.cyan(scaffoldResult.tests.length.toString())} test file(s) for ${scaffoldResult.totalSchemas} schema(s)`
|
|
37808
|
+
);
|
|
37809
|
+
for (const test of scaffoldResult.tests) {
|
|
37810
|
+
console.log(` ${pc4.dim(test.filePath)} (${test.schemaCount} schemas)`);
|
|
37811
|
+
}
|
|
37812
|
+
}
|
|
37813
|
+
}
|
|
37814
|
+
}
|
|
37815
|
+
if (options.audit) {
|
|
37816
|
+
if (!features.auditLogging) {
|
|
37817
|
+
console.error(pc4.red("\nAudit logging requires Team tier."));
|
|
37818
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37819
|
+
} else {
|
|
37820
|
+
const projectPath = resolve2(targetPath);
|
|
37821
|
+
const auditLog = new MigrationAuditLog(projectPath);
|
|
37822
|
+
const migrationId = `${options.from}->${options.to}-${Date.now()}`;
|
|
37823
|
+
for (const result of results) {
|
|
37824
|
+
const entry = auditLog.createEntry({
|
|
37825
|
+
migrationId,
|
|
37826
|
+
filePath: result.filePath,
|
|
37827
|
+
from: options.from,
|
|
37828
|
+
to: options.to,
|
|
37829
|
+
originalCode: result.originalCode ?? "",
|
|
37830
|
+
transformedCode: result.transformedCode,
|
|
37831
|
+
success: result.success,
|
|
37832
|
+
warningCount: result.warnings.length,
|
|
37833
|
+
errorCount: result.errors.length
|
|
37834
|
+
});
|
|
37835
|
+
auditLog.append(entry);
|
|
37836
|
+
}
|
|
37837
|
+
console.log(
|
|
37838
|
+
pc4.dim(`
|
|
37839
|
+
Audit log saved to .schemashift/audit-log.json (${results.length} entries)`)
|
|
37840
|
+
);
|
|
37841
|
+
}
|
|
37842
|
+
}
|
|
37492
37843
|
if (options.dryRun) {
|
|
37493
37844
|
const diffOutput = generateDiffPreview(results);
|
|
37494
37845
|
if (diffOutput) {
|
|
@@ -37571,15 +37922,15 @@ program.command("watch <path>").description("Watch files and migrate on change")
|
|
|
37571
37922
|
};
|
|
37572
37923
|
}
|
|
37573
37924
|
const watchMode = new WatchMode();
|
|
37574
|
-
const analyzer = new SchemaAnalyzer();
|
|
37575
37925
|
await watchMode.start({
|
|
37576
37926
|
patterns: config2.include.map((p) => join3(targetPath, p)),
|
|
37577
37927
|
exclude: config2.exclude,
|
|
37578
37928
|
from: options.from,
|
|
37579
37929
|
to: options.to,
|
|
37580
37930
|
onTransform: async (file) => {
|
|
37581
|
-
|
|
37582
|
-
|
|
37931
|
+
const fileAnalyzer = new SchemaAnalyzer();
|
|
37932
|
+
fileAnalyzer.addSourceFiles([file]);
|
|
37933
|
+
const sourceFile = fileAnalyzer.getProject().getSourceFileOrThrow(resolve2(file));
|
|
37583
37934
|
const result = engine.transform(sourceFile, options.from, options.to, {
|
|
37584
37935
|
from: options.from,
|
|
37585
37936
|
to: options.to,
|
package/dist/index.cjs
CHANGED
|
@@ -33791,7 +33791,13 @@ var TIER_FEATURES = {
|
|
|
33791
33791
|
maxRiskScoreThreshold: false,
|
|
33792
33792
|
formResolverMigration: false,
|
|
33793
33793
|
complexityEstimator: false,
|
|
33794
|
-
monorepoAware: false
|
|
33794
|
+
monorepoAware: false,
|
|
33795
|
+
behavioralWarnings: true,
|
|
33796
|
+
bundleEstimator: false,
|
|
33797
|
+
performanceAnalyzer: false,
|
|
33798
|
+
typeDeduplication: false,
|
|
33799
|
+
testScaffolding: false,
|
|
33800
|
+
auditLogging: false
|
|
33795
33801
|
},
|
|
33796
33802
|
[
|
|
33797
33803
|
"individual"
|
|
@@ -33818,7 +33824,13 @@ var TIER_FEATURES = {
|
|
|
33818
33824
|
maxRiskScoreThreshold: false,
|
|
33819
33825
|
formResolverMigration: true,
|
|
33820
33826
|
complexityEstimator: true,
|
|
33821
|
-
monorepoAware: false
|
|
33827
|
+
monorepoAware: false,
|
|
33828
|
+
behavioralWarnings: true,
|
|
33829
|
+
bundleEstimator: true,
|
|
33830
|
+
performanceAnalyzer: true,
|
|
33831
|
+
typeDeduplication: true,
|
|
33832
|
+
testScaffolding: false,
|
|
33833
|
+
auditLogging: false
|
|
33822
33834
|
},
|
|
33823
33835
|
[
|
|
33824
33836
|
"pro"
|
|
@@ -33831,7 +33843,14 @@ var TIER_FEATURES = {
|
|
|
33831
33843
|
"zod-v3->v4",
|
|
33832
33844
|
"io-ts->zod",
|
|
33833
33845
|
"zod->valibot",
|
|
33834
|
-
"any->valibot"
|
|
33846
|
+
"any->valibot",
|
|
33847
|
+
"zod->yup",
|
|
33848
|
+
"valibot->zod",
|
|
33849
|
+
"zod->arktype",
|
|
33850
|
+
"arktype->zod",
|
|
33851
|
+
"zod->superstruct",
|
|
33852
|
+
"superstruct->zod",
|
|
33853
|
+
"io-ts->effect"
|
|
33835
33854
|
],
|
|
33836
33855
|
devices: 4,
|
|
33837
33856
|
ciSupport: true,
|
|
@@ -33852,7 +33871,13 @@ var TIER_FEATURES = {
|
|
|
33852
33871
|
maxRiskScoreThreshold: false,
|
|
33853
33872
|
formResolverMigration: true,
|
|
33854
33873
|
complexityEstimator: true,
|
|
33855
|
-
monorepoAware: true
|
|
33874
|
+
monorepoAware: true,
|
|
33875
|
+
behavioralWarnings: true,
|
|
33876
|
+
bundleEstimator: true,
|
|
33877
|
+
performanceAnalyzer: true,
|
|
33878
|
+
typeDeduplication: true,
|
|
33879
|
+
testScaffolding: true,
|
|
33880
|
+
auditLogging: false
|
|
33856
33881
|
},
|
|
33857
33882
|
[
|
|
33858
33883
|
"team"
|
|
@@ -33865,7 +33890,14 @@ var TIER_FEATURES = {
|
|
|
33865
33890
|
"zod-v3->v4",
|
|
33866
33891
|
"io-ts->zod",
|
|
33867
33892
|
"any->valibot",
|
|
33868
|
-
"zod->valibot"
|
|
33893
|
+
"zod->valibot",
|
|
33894
|
+
"zod->yup",
|
|
33895
|
+
"valibot->zod",
|
|
33896
|
+
"zod->arktype",
|
|
33897
|
+
"arktype->zod",
|
|
33898
|
+
"zod->superstruct",
|
|
33899
|
+
"superstruct->zod",
|
|
33900
|
+
"io-ts->effect"
|
|
33869
33901
|
],
|
|
33870
33902
|
devices: Infinity,
|
|
33871
33903
|
ciSupport: true,
|
|
@@ -33886,7 +33918,13 @@ var TIER_FEATURES = {
|
|
|
33886
33918
|
maxRiskScoreThreshold: true,
|
|
33887
33919
|
formResolverMigration: true,
|
|
33888
33920
|
complexityEstimator: true,
|
|
33889
|
-
monorepoAware: true
|
|
33921
|
+
monorepoAware: true,
|
|
33922
|
+
behavioralWarnings: true,
|
|
33923
|
+
bundleEstimator: true,
|
|
33924
|
+
performanceAnalyzer: true,
|
|
33925
|
+
typeDeduplication: true,
|
|
33926
|
+
testScaffolding: true,
|
|
33927
|
+
auditLogging: true
|
|
33890
33928
|
}
|
|
33891
33929
|
};
|
|
33892
33930
|
var POLAR_ORG_ID = process.env.POLAR_ORG_ID || "79bbe935-1836-4b9e-9ca8-4c7a94217f5e";
|
|
@@ -34641,6 +34679,12 @@ var WatchMode = class {
|
|
|
34641
34679
|
console.log(import_picocolors.default.cyan(`
|
|
34642
34680
|
Watching ${files.length} files for changes...
|
|
34643
34681
|
`));
|
|
34682
|
+
if (options.dependents && options.dependents.size > 0) {
|
|
34683
|
+
console.log(
|
|
34684
|
+
import_picocolors.default.dim(`Dependency-aware mode: ${options.dependents.size} files with dependents
|
|
34685
|
+
`)
|
|
34686
|
+
);
|
|
34687
|
+
}
|
|
34644
34688
|
console.log(import_picocolors.default.dim("Press Ctrl+C to stop\n"));
|
|
34645
34689
|
const directories = new Set(files.map((f) => f.split("/").slice(0, -1).join("/")));
|
|
34646
34690
|
for (const dir of directories) {
|
|
@@ -34661,8 +34705,26 @@ Watching ${files.length} files for changes...
|
|
|
34661
34705
|
Changed: ${(0, import_node_path2.relative)(process.cwd(), fullPath)}`));
|
|
34662
34706
|
try {
|
|
34663
34707
|
await options.onTransform(fullPath);
|
|
34664
|
-
console.log(import_picocolors.default.green(`Transformed successfully
|
|
34665
|
-
|
|
34708
|
+
console.log(import_picocolors.default.green(`Transformed successfully`));
|
|
34709
|
+
const dependentFiles = options.dependents?.get(fullPath);
|
|
34710
|
+
if (dependentFiles && dependentFiles.length > 0) {
|
|
34711
|
+
console.log(
|
|
34712
|
+
import_picocolors.default.cyan(` Re-transforming ${dependentFiles.length} dependent file(s)...`)
|
|
34713
|
+
);
|
|
34714
|
+
for (const depFile of dependentFiles) {
|
|
34715
|
+
try {
|
|
34716
|
+
await options.onTransform(depFile);
|
|
34717
|
+
console.log(import_picocolors.default.green(` \u2713 ${(0, import_node_path2.relative)(process.cwd(), depFile)}`));
|
|
34718
|
+
} catch (error) {
|
|
34719
|
+
console.error(
|
|
34720
|
+
import_picocolors.default.red(
|
|
34721
|
+
` \u2717 ${(0, import_node_path2.relative)(process.cwd(), depFile)}: ${error instanceof Error ? error.message : String(error)}`
|
|
34722
|
+
)
|
|
34723
|
+
);
|
|
34724
|
+
}
|
|
34725
|
+
}
|
|
34726
|
+
}
|
|
34727
|
+
console.log("");
|
|
34666
34728
|
} catch (error) {
|
|
34667
34729
|
console.error(
|
|
34668
34730
|
import_picocolors.default.red(
|
|
@@ -34688,6 +34750,21 @@ Changed: ${(0, import_node_path2.relative)(process.cwd(), fullPath)}`));
|
|
|
34688
34750
|
}
|
|
34689
34751
|
this.debounceTimers.clear();
|
|
34690
34752
|
}
|
|
34753
|
+
/**
|
|
34754
|
+
* Build a reverse dependency map (file -> files that depend on it).
|
|
34755
|
+
* Takes the forward dependency map from SchemaDependencyResolver and inverts it.
|
|
34756
|
+
*/
|
|
34757
|
+
static buildDependentsMap(dependencies) {
|
|
34758
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
34759
|
+
for (const [file, deps] of dependencies) {
|
|
34760
|
+
for (const dep of deps) {
|
|
34761
|
+
const existing = dependents.get(dep) ?? [];
|
|
34762
|
+
existing.push(file);
|
|
34763
|
+
dependents.set(dep, existing);
|
|
34764
|
+
}
|
|
34765
|
+
}
|
|
34766
|
+
return dependents;
|
|
34767
|
+
}
|
|
34691
34768
|
matchesPatterns(file, include, exclude) {
|
|
34692
34769
|
const isIncluded = include.some((p) => (0, import_minimatch.minimatch)(file, p));
|
|
34693
34770
|
const isExcluded = exclude.some((p) => (0, import_minimatch.minimatch)(file, p));
|
package/dist/index.d.cts
CHANGED
|
@@ -91,12 +91,19 @@ interface WatchOptions {
|
|
|
91
91
|
from: string;
|
|
92
92
|
to: string;
|
|
93
93
|
onTransform: (file: string) => Promise<void>;
|
|
94
|
+
/** Optional: dependency map from SchemaDependencyResolver. Keys are file paths, values are lists of files that depend on the key. */
|
|
95
|
+
dependents?: Map<string, string[]>;
|
|
94
96
|
}
|
|
95
97
|
declare class WatchMode {
|
|
96
98
|
private watchers;
|
|
97
99
|
private debounceTimers;
|
|
98
100
|
start(options: WatchOptions): Promise<void>;
|
|
99
101
|
stop(): void;
|
|
102
|
+
/**
|
|
103
|
+
* Build a reverse dependency map (file -> files that depend on it).
|
|
104
|
+
* Takes the forward dependency map from SchemaDependencyResolver and inverts it.
|
|
105
|
+
*/
|
|
106
|
+
static buildDependentsMap(dependencies: Map<string, string[]>): Map<string, string[]>;
|
|
100
107
|
private matchesPatterns;
|
|
101
108
|
}
|
|
102
109
|
|
package/dist/index.d.ts
CHANGED
|
@@ -91,12 +91,19 @@ interface WatchOptions {
|
|
|
91
91
|
from: string;
|
|
92
92
|
to: string;
|
|
93
93
|
onTransform: (file: string) => Promise<void>;
|
|
94
|
+
/** Optional: dependency map from SchemaDependencyResolver. Keys are file paths, values are lists of files that depend on the key. */
|
|
95
|
+
dependents?: Map<string, string[]>;
|
|
94
96
|
}
|
|
95
97
|
declare class WatchMode {
|
|
96
98
|
private watchers;
|
|
97
99
|
private debounceTimers;
|
|
98
100
|
start(options: WatchOptions): Promise<void>;
|
|
99
101
|
stop(): void;
|
|
102
|
+
/**
|
|
103
|
+
* Build a reverse dependency map (file -> files that depend on it).
|
|
104
|
+
* Takes the forward dependency map from SchemaDependencyResolver and inverts it.
|
|
105
|
+
*/
|
|
106
|
+
static buildDependentsMap(dependencies: Map<string, string[]>): Map<string, string[]>;
|
|
100
107
|
private matchesPatterns;
|
|
101
108
|
}
|
|
102
109
|
|
package/dist/index.js
CHANGED
|
@@ -33750,7 +33750,13 @@ var TIER_FEATURES = {
|
|
|
33750
33750
|
maxRiskScoreThreshold: false,
|
|
33751
33751
|
formResolverMigration: false,
|
|
33752
33752
|
complexityEstimator: false,
|
|
33753
|
-
monorepoAware: false
|
|
33753
|
+
monorepoAware: false,
|
|
33754
|
+
behavioralWarnings: true,
|
|
33755
|
+
bundleEstimator: false,
|
|
33756
|
+
performanceAnalyzer: false,
|
|
33757
|
+
typeDeduplication: false,
|
|
33758
|
+
testScaffolding: false,
|
|
33759
|
+
auditLogging: false
|
|
33754
33760
|
},
|
|
33755
33761
|
[
|
|
33756
33762
|
"individual"
|
|
@@ -33777,7 +33783,13 @@ var TIER_FEATURES = {
|
|
|
33777
33783
|
maxRiskScoreThreshold: false,
|
|
33778
33784
|
formResolverMigration: true,
|
|
33779
33785
|
complexityEstimator: true,
|
|
33780
|
-
monorepoAware: false
|
|
33786
|
+
monorepoAware: false,
|
|
33787
|
+
behavioralWarnings: true,
|
|
33788
|
+
bundleEstimator: true,
|
|
33789
|
+
performanceAnalyzer: true,
|
|
33790
|
+
typeDeduplication: true,
|
|
33791
|
+
testScaffolding: false,
|
|
33792
|
+
auditLogging: false
|
|
33781
33793
|
},
|
|
33782
33794
|
[
|
|
33783
33795
|
"pro"
|
|
@@ -33790,7 +33802,14 @@ var TIER_FEATURES = {
|
|
|
33790
33802
|
"zod-v3->v4",
|
|
33791
33803
|
"io-ts->zod",
|
|
33792
33804
|
"zod->valibot",
|
|
33793
|
-
"any->valibot"
|
|
33805
|
+
"any->valibot",
|
|
33806
|
+
"zod->yup",
|
|
33807
|
+
"valibot->zod",
|
|
33808
|
+
"zod->arktype",
|
|
33809
|
+
"arktype->zod",
|
|
33810
|
+
"zod->superstruct",
|
|
33811
|
+
"superstruct->zod",
|
|
33812
|
+
"io-ts->effect"
|
|
33794
33813
|
],
|
|
33795
33814
|
devices: 4,
|
|
33796
33815
|
ciSupport: true,
|
|
@@ -33811,7 +33830,13 @@ var TIER_FEATURES = {
|
|
|
33811
33830
|
maxRiskScoreThreshold: false,
|
|
33812
33831
|
formResolverMigration: true,
|
|
33813
33832
|
complexityEstimator: true,
|
|
33814
|
-
monorepoAware: true
|
|
33833
|
+
monorepoAware: true,
|
|
33834
|
+
behavioralWarnings: true,
|
|
33835
|
+
bundleEstimator: true,
|
|
33836
|
+
performanceAnalyzer: true,
|
|
33837
|
+
typeDeduplication: true,
|
|
33838
|
+
testScaffolding: true,
|
|
33839
|
+
auditLogging: false
|
|
33815
33840
|
},
|
|
33816
33841
|
[
|
|
33817
33842
|
"team"
|
|
@@ -33824,7 +33849,14 @@ var TIER_FEATURES = {
|
|
|
33824
33849
|
"zod-v3->v4",
|
|
33825
33850
|
"io-ts->zod",
|
|
33826
33851
|
"any->valibot",
|
|
33827
|
-
"zod->valibot"
|
|
33852
|
+
"zod->valibot",
|
|
33853
|
+
"zod->yup",
|
|
33854
|
+
"valibot->zod",
|
|
33855
|
+
"zod->arktype",
|
|
33856
|
+
"arktype->zod",
|
|
33857
|
+
"zod->superstruct",
|
|
33858
|
+
"superstruct->zod",
|
|
33859
|
+
"io-ts->effect"
|
|
33828
33860
|
],
|
|
33829
33861
|
devices: Infinity,
|
|
33830
33862
|
ciSupport: true,
|
|
@@ -33845,7 +33877,13 @@ var TIER_FEATURES = {
|
|
|
33845
33877
|
maxRiskScoreThreshold: true,
|
|
33846
33878
|
formResolverMigration: true,
|
|
33847
33879
|
complexityEstimator: true,
|
|
33848
|
-
monorepoAware: true
|
|
33880
|
+
monorepoAware: true,
|
|
33881
|
+
behavioralWarnings: true,
|
|
33882
|
+
bundleEstimator: true,
|
|
33883
|
+
performanceAnalyzer: true,
|
|
33884
|
+
typeDeduplication: true,
|
|
33885
|
+
testScaffolding: true,
|
|
33886
|
+
auditLogging: true
|
|
33849
33887
|
}
|
|
33850
33888
|
};
|
|
33851
33889
|
var POLAR_ORG_ID = process.env.POLAR_ORG_ID || "79bbe935-1836-4b9e-9ca8-4c7a94217f5e";
|
|
@@ -34608,6 +34646,12 @@ var WatchMode = class {
|
|
|
34608
34646
|
console.log(pc.cyan(`
|
|
34609
34647
|
Watching ${files.length} files for changes...
|
|
34610
34648
|
`));
|
|
34649
|
+
if (options.dependents && options.dependents.size > 0) {
|
|
34650
|
+
console.log(
|
|
34651
|
+
pc.dim(`Dependency-aware mode: ${options.dependents.size} files with dependents
|
|
34652
|
+
`)
|
|
34653
|
+
);
|
|
34654
|
+
}
|
|
34611
34655
|
console.log(pc.dim("Press Ctrl+C to stop\n"));
|
|
34612
34656
|
const directories = new Set(files.map((f) => f.split("/").slice(0, -1).join("/")));
|
|
34613
34657
|
for (const dir of directories) {
|
|
@@ -34628,8 +34672,26 @@ Watching ${files.length} files for changes...
|
|
|
34628
34672
|
Changed: ${relative2(process.cwd(), fullPath)}`));
|
|
34629
34673
|
try {
|
|
34630
34674
|
await options.onTransform(fullPath);
|
|
34631
|
-
console.log(pc.green(`Transformed successfully
|
|
34632
|
-
|
|
34675
|
+
console.log(pc.green(`Transformed successfully`));
|
|
34676
|
+
const dependentFiles = options.dependents?.get(fullPath);
|
|
34677
|
+
if (dependentFiles && dependentFiles.length > 0) {
|
|
34678
|
+
console.log(
|
|
34679
|
+
pc.cyan(` Re-transforming ${dependentFiles.length} dependent file(s)...`)
|
|
34680
|
+
);
|
|
34681
|
+
for (const depFile of dependentFiles) {
|
|
34682
|
+
try {
|
|
34683
|
+
await options.onTransform(depFile);
|
|
34684
|
+
console.log(pc.green(` \u2713 ${relative2(process.cwd(), depFile)}`));
|
|
34685
|
+
} catch (error) {
|
|
34686
|
+
console.error(
|
|
34687
|
+
pc.red(
|
|
34688
|
+
` \u2717 ${relative2(process.cwd(), depFile)}: ${error instanceof Error ? error.message : String(error)}`
|
|
34689
|
+
)
|
|
34690
|
+
);
|
|
34691
|
+
}
|
|
34692
|
+
}
|
|
34693
|
+
}
|
|
34694
|
+
console.log("");
|
|
34633
34695
|
} catch (error) {
|
|
34634
34696
|
console.error(
|
|
34635
34697
|
pc.red(
|
|
@@ -34655,6 +34717,21 @@ Changed: ${relative2(process.cwd(), fullPath)}`));
|
|
|
34655
34717
|
}
|
|
34656
34718
|
this.debounceTimers.clear();
|
|
34657
34719
|
}
|
|
34720
|
+
/**
|
|
34721
|
+
* Build a reverse dependency map (file -> files that depend on it).
|
|
34722
|
+
* Takes the forward dependency map from SchemaDependencyResolver and inverts it.
|
|
34723
|
+
*/
|
|
34724
|
+
static buildDependentsMap(dependencies) {
|
|
34725
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
34726
|
+
for (const [file, deps] of dependencies) {
|
|
34727
|
+
for (const dep of deps) {
|
|
34728
|
+
const existing = dependents.get(dep) ?? [];
|
|
34729
|
+
existing.push(file);
|
|
34730
|
+
dependents.set(dep, existing);
|
|
34731
|
+
}
|
|
34732
|
+
}
|
|
34733
|
+
return dependents;
|
|
34734
|
+
}
|
|
34658
34735
|
matchesPatterns(file, include, exclude) {
|
|
34659
34736
|
const isIncluded = include.some((p) => minimatch(file, p));
|
|
34660
34737
|
const isExcluded = exclude.some((p) => minimatch(file, p));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "schemashift-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "TypeScript schema migration CLI - migrate between Zod, Yup, Joi, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -48,13 +48,19 @@
|
|
|
48
48
|
},
|
|
49
49
|
"author": "Joseph May",
|
|
50
50
|
"license": "MIT",
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=22.0.0"
|
|
53
|
+
},
|
|
51
54
|
"dependencies": {
|
|
52
|
-
"@schemashift/core": "0.
|
|
53
|
-
"@schemashift/io-ts-
|
|
54
|
-
"@schemashift/
|
|
55
|
-
"@schemashift/
|
|
56
|
-
"@schemashift/zod
|
|
57
|
-
"@schemashift/zod-
|
|
55
|
+
"@schemashift/core": "0.10.0",
|
|
56
|
+
"@schemashift/io-ts-effect": "0.10.0",
|
|
57
|
+
"@schemashift/io-ts-zod": "0.10.0",
|
|
58
|
+
"@schemashift/joi-zod": "0.10.0",
|
|
59
|
+
"@schemashift/yup-zod": "0.10.0",
|
|
60
|
+
"@schemashift/zod-arktype": "0.10.0",
|
|
61
|
+
"@schemashift/zod-superstruct": "0.10.0",
|
|
62
|
+
"@schemashift/zod-valibot": "0.10.0",
|
|
63
|
+
"@schemashift/zod-v3-v4": "0.10.0",
|
|
58
64
|
"commander": "14.0.2",
|
|
59
65
|
"cosmiconfig": "9.0.0",
|
|
60
66
|
"glob": "13.0.0",
|
|
@@ -63,7 +69,7 @@
|
|
|
63
69
|
"picocolors": "1.1.1"
|
|
64
70
|
},
|
|
65
71
|
"devDependencies": {
|
|
66
|
-
"@schemashift/license": "0.
|
|
72
|
+
"@schemashift/license": "0.10.0"
|
|
67
73
|
},
|
|
68
74
|
"publishConfig": {
|
|
69
75
|
"access": "public"
|