schemashift-cli 0.8.0 → 0.9.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 +336 -16
- package/dist/index.cjs +75 -8
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +75 -8
- package/package.json +8 -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,16 +10,23 @@ 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";
|
|
24
31
|
import { createIoTsToZodHandler } from "@schemashift/io-ts-zod";
|
|
25
32
|
import { createJoiToZodHandler } from "@schemashift/joi-zod";
|
|
@@ -35827,7 +35834,13 @@ var TIER_FEATURES = {
|
|
|
35827
35834
|
maxRiskScoreThreshold: false,
|
|
35828
35835
|
formResolverMigration: false,
|
|
35829
35836
|
complexityEstimator: false,
|
|
35830
|
-
monorepoAware: false
|
|
35837
|
+
monorepoAware: false,
|
|
35838
|
+
behavioralWarnings: true,
|
|
35839
|
+
bundleEstimator: false,
|
|
35840
|
+
performanceAnalyzer: false,
|
|
35841
|
+
typeDeduplication: false,
|
|
35842
|
+
testScaffolding: false,
|
|
35843
|
+
auditLogging: false
|
|
35831
35844
|
},
|
|
35832
35845
|
[
|
|
35833
35846
|
"individual"
|
|
@@ -35854,7 +35867,13 @@ var TIER_FEATURES = {
|
|
|
35854
35867
|
maxRiskScoreThreshold: false,
|
|
35855
35868
|
formResolverMigration: true,
|
|
35856
35869
|
complexityEstimator: true,
|
|
35857
|
-
monorepoAware: false
|
|
35870
|
+
monorepoAware: false,
|
|
35871
|
+
behavioralWarnings: true,
|
|
35872
|
+
bundleEstimator: true,
|
|
35873
|
+
performanceAnalyzer: true,
|
|
35874
|
+
typeDeduplication: true,
|
|
35875
|
+
testScaffolding: false,
|
|
35876
|
+
auditLogging: false
|
|
35858
35877
|
},
|
|
35859
35878
|
[
|
|
35860
35879
|
"pro"
|
|
@@ -35867,7 +35886,9 @@ var TIER_FEATURES = {
|
|
|
35867
35886
|
"zod-v3->v4",
|
|
35868
35887
|
"io-ts->zod",
|
|
35869
35888
|
"zod->valibot",
|
|
35870
|
-
"any->valibot"
|
|
35889
|
+
"any->valibot",
|
|
35890
|
+
"zod->yup",
|
|
35891
|
+
"valibot->zod"
|
|
35871
35892
|
],
|
|
35872
35893
|
devices: 4,
|
|
35873
35894
|
ciSupport: true,
|
|
@@ -35888,7 +35909,13 @@ var TIER_FEATURES = {
|
|
|
35888
35909
|
maxRiskScoreThreshold: false,
|
|
35889
35910
|
formResolverMigration: true,
|
|
35890
35911
|
complexityEstimator: true,
|
|
35891
|
-
monorepoAware: true
|
|
35912
|
+
monorepoAware: true,
|
|
35913
|
+
behavioralWarnings: true,
|
|
35914
|
+
bundleEstimator: true,
|
|
35915
|
+
performanceAnalyzer: true,
|
|
35916
|
+
typeDeduplication: true,
|
|
35917
|
+
testScaffolding: true,
|
|
35918
|
+
auditLogging: false
|
|
35892
35919
|
},
|
|
35893
35920
|
[
|
|
35894
35921
|
"team"
|
|
@@ -35901,7 +35928,9 @@ var TIER_FEATURES = {
|
|
|
35901
35928
|
"zod-v3->v4",
|
|
35902
35929
|
"io-ts->zod",
|
|
35903
35930
|
"any->valibot",
|
|
35904
|
-
"zod->valibot"
|
|
35931
|
+
"zod->valibot",
|
|
35932
|
+
"zod->yup",
|
|
35933
|
+
"valibot->zod"
|
|
35905
35934
|
],
|
|
35906
35935
|
devices: Infinity,
|
|
35907
35936
|
ciSupport: true,
|
|
@@ -35922,7 +35951,13 @@ var TIER_FEATURES = {
|
|
|
35922
35951
|
maxRiskScoreThreshold: true,
|
|
35923
35952
|
formResolverMigration: true,
|
|
35924
35953
|
complexityEstimator: true,
|
|
35925
|
-
monorepoAware: true
|
|
35954
|
+
monorepoAware: true,
|
|
35955
|
+
behavioralWarnings: true,
|
|
35956
|
+
bundleEstimator: true,
|
|
35957
|
+
performanceAnalyzer: true,
|
|
35958
|
+
typeDeduplication: true,
|
|
35959
|
+
testScaffolding: true,
|
|
35960
|
+
auditLogging: true
|
|
35926
35961
|
}
|
|
35927
35962
|
};
|
|
35928
35963
|
function canUseMigration(tier, from, to) {
|
|
@@ -36199,9 +36234,9 @@ var LicenseManager = class {
|
|
|
36199
36234
|
};
|
|
36200
36235
|
|
|
36201
36236
|
// src/cli.ts
|
|
36202
|
-
import { createYupToZodHandler } from "@schemashift/yup-zod";
|
|
36237
|
+
import { createYupToZodHandler, createZodToYupHandler } from "@schemashift/yup-zod";
|
|
36203
36238
|
import { createZodV3ToV4Handler } from "@schemashift/zod-v3-v4";
|
|
36204
|
-
import { createZodToValibotHandler } from "@schemashift/zod-valibot";
|
|
36239
|
+
import { createValibotToZodHandler, createZodToValibotHandler } from "@schemashift/zod-valibot";
|
|
36205
36240
|
import { Command } from "commander";
|
|
36206
36241
|
import { glob as glob2 } from "glob";
|
|
36207
36242
|
import { Listr } from "listr2";
|
|
@@ -36883,6 +36918,12 @@ var WatchMode = class {
|
|
|
36883
36918
|
console.log(pc3.cyan(`
|
|
36884
36919
|
Watching ${files.length} files for changes...
|
|
36885
36920
|
`));
|
|
36921
|
+
if (options.dependents && options.dependents.size > 0) {
|
|
36922
|
+
console.log(
|
|
36923
|
+
pc3.dim(`Dependency-aware mode: ${options.dependents.size} files with dependents
|
|
36924
|
+
`)
|
|
36925
|
+
);
|
|
36926
|
+
}
|
|
36886
36927
|
console.log(pc3.dim("Press Ctrl+C to stop\n"));
|
|
36887
36928
|
const directories = new Set(files.map((f) => f.split("/").slice(0, -1).join("/")));
|
|
36888
36929
|
for (const dir of directories) {
|
|
@@ -36903,8 +36944,26 @@ Watching ${files.length} files for changes...
|
|
|
36903
36944
|
Changed: ${relative2(process.cwd(), fullPath)}`));
|
|
36904
36945
|
try {
|
|
36905
36946
|
await options.onTransform(fullPath);
|
|
36906
|
-
console.log(pc3.green(`Transformed successfully
|
|
36907
|
-
|
|
36947
|
+
console.log(pc3.green(`Transformed successfully`));
|
|
36948
|
+
const dependentFiles = options.dependents?.get(fullPath);
|
|
36949
|
+
if (dependentFiles && dependentFiles.length > 0) {
|
|
36950
|
+
console.log(
|
|
36951
|
+
pc3.cyan(` Re-transforming ${dependentFiles.length} dependent file(s)...`)
|
|
36952
|
+
);
|
|
36953
|
+
for (const depFile of dependentFiles) {
|
|
36954
|
+
try {
|
|
36955
|
+
await options.onTransform(depFile);
|
|
36956
|
+
console.log(pc3.green(` \u2713 ${relative2(process.cwd(), depFile)}`));
|
|
36957
|
+
} catch (error) {
|
|
36958
|
+
console.error(
|
|
36959
|
+
pc3.red(
|
|
36960
|
+
` \u2717 ${relative2(process.cwd(), depFile)}: ${error instanceof Error ? error.message : String(error)}`
|
|
36961
|
+
)
|
|
36962
|
+
);
|
|
36963
|
+
}
|
|
36964
|
+
}
|
|
36965
|
+
}
|
|
36966
|
+
console.log("");
|
|
36908
36967
|
} catch (error) {
|
|
36909
36968
|
console.error(
|
|
36910
36969
|
pc3.red(
|
|
@@ -36930,6 +36989,21 @@ Changed: ${relative2(process.cwd(), fullPath)}`));
|
|
|
36930
36989
|
}
|
|
36931
36990
|
this.debounceTimers.clear();
|
|
36932
36991
|
}
|
|
36992
|
+
/**
|
|
36993
|
+
* Build a reverse dependency map (file -> files that depend on it).
|
|
36994
|
+
* Takes the forward dependency map from SchemaDependencyResolver and inverts it.
|
|
36995
|
+
*/
|
|
36996
|
+
static buildDependentsMap(dependencies) {
|
|
36997
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
36998
|
+
for (const [file, deps] of dependencies) {
|
|
36999
|
+
for (const dep of deps) {
|
|
37000
|
+
const existing = dependents.get(dep) ?? [];
|
|
37001
|
+
existing.push(file);
|
|
37002
|
+
dependents.set(dep, existing);
|
|
37003
|
+
}
|
|
37004
|
+
}
|
|
37005
|
+
return dependents;
|
|
37006
|
+
}
|
|
36933
37007
|
matchesPatterns(file, include, exclude) {
|
|
36934
37008
|
const isIncluded = include.some((p) => minimatch(file, p));
|
|
36935
37009
|
const isExcluded = exclude.some((p) => minimatch(file, p));
|
|
@@ -36948,6 +37022,8 @@ engine.registerHandler("joi", "zod", createJoiToZodHandler());
|
|
|
36948
37022
|
engine.registerHandler("io-ts", "zod", createIoTsToZodHandler());
|
|
36949
37023
|
engine.registerHandler("zod-v3", "v4", createZodV3ToV4Handler());
|
|
36950
37024
|
engine.registerHandler("zod", "valibot", createZodToValibotHandler());
|
|
37025
|
+
engine.registerHandler("zod", "yup", createZodToYupHandler());
|
|
37026
|
+
engine.registerHandler("valibot", "zod", createValibotToZodHandler());
|
|
36951
37027
|
var POLAR_URL = "https://schemashift.qwady.app";
|
|
36952
37028
|
program.name("schemashift").version(pkg.version).description("TypeScript schema migration CLI");
|
|
36953
37029
|
program.command("init").description("Create .schemashiftrc.json config file").option("-f, --force", "Overwrite existing config").action((options) => {
|
|
@@ -36977,7 +37053,10 @@ program.command("init").description("Create .schemashiftrc.json config file").op
|
|
|
36977
37053
|
console.log(pc4.green("Created .schemashiftrc.json"));
|
|
36978
37054
|
console.log(pc4.dim("Edit the file to customize your migration settings."));
|
|
36979
37055
|
});
|
|
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+)").
|
|
37056
|
+
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(
|
|
37057
|
+
"--performance <migration>",
|
|
37058
|
+
"Show performance impact analysis, e.g. zod-v3->v4 (Individual+)"
|
|
37059
|
+
).option("--dedup", "Detect duplicate type definitions (Individual+)").action(async (targetPath, options) => {
|
|
36981
37060
|
const analyzer = new SchemaAnalyzer();
|
|
36982
37061
|
let files;
|
|
36983
37062
|
if (existsSync4(targetPath) && statSync(targetPath).isFile()) {
|
|
@@ -37158,12 +37237,140 @@ Migration Readiness: ${from} -> ${to}
|
|
|
37158
37237
|
}
|
|
37159
37238
|
}
|
|
37160
37239
|
}
|
|
37240
|
+
if (options.behavioral) {
|
|
37241
|
+
const migParts = options.behavioral.split("->");
|
|
37242
|
+
if (migParts.length !== 2) {
|
|
37243
|
+
console.error(pc4.red("Invalid format. Use: --behavioral yup->zod"));
|
|
37244
|
+
} else {
|
|
37245
|
+
const [bFrom, bTo] = migParts;
|
|
37246
|
+
const behavioralAnalyzer = new BehavioralWarningAnalyzer();
|
|
37247
|
+
const sourceFiles = analyzer.getProject().getSourceFiles();
|
|
37248
|
+
const behavioralResult = behavioralAnalyzer.analyze(
|
|
37249
|
+
sourceFiles,
|
|
37250
|
+
bFrom,
|
|
37251
|
+
bTo
|
|
37252
|
+
);
|
|
37253
|
+
if (behavioralResult.warnings.length > 0) {
|
|
37254
|
+
console.log(pc4.bold("\nBehavioral Difference Warnings\n"));
|
|
37255
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
37256
|
+
for (const w of behavioralResult.warnings) {
|
|
37257
|
+
const existing = byCategory.get(w.category) ?? [];
|
|
37258
|
+
existing.push(w);
|
|
37259
|
+
byCategory.set(w.category, existing);
|
|
37260
|
+
}
|
|
37261
|
+
for (const [category, catWarnings] of byCategory) {
|
|
37262
|
+
console.log(pc4.yellow(` [${category}] ${catWarnings.length} warning(s)`));
|
|
37263
|
+
for (const w of catWarnings.slice(0, 5)) {
|
|
37264
|
+
console.log(` ${w.message}`);
|
|
37265
|
+
console.log(` ${pc4.dim(w.detail)}`);
|
|
37266
|
+
}
|
|
37267
|
+
if (catWarnings.length > 5) {
|
|
37268
|
+
console.log(pc4.dim(` ... and ${catWarnings.length - 5} more`));
|
|
37269
|
+
}
|
|
37270
|
+
}
|
|
37271
|
+
} else {
|
|
37272
|
+
console.log(pc4.green("\nNo behavioral difference warnings found."));
|
|
37273
|
+
}
|
|
37274
|
+
}
|
|
37275
|
+
}
|
|
37276
|
+
if (options.bundle) {
|
|
37277
|
+
const validation = await licenseManager.validate();
|
|
37278
|
+
const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
|
|
37279
|
+
if (!tier.bundleEstimator) {
|
|
37280
|
+
console.error(pc4.red("\nBundle estimation requires Individual tier or higher."));
|
|
37281
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37282
|
+
} else {
|
|
37283
|
+
const migParts = options.bundle.split("->");
|
|
37284
|
+
if (migParts.length !== 2) {
|
|
37285
|
+
console.error(pc4.red("Invalid format. Use: --bundle zod->valibot"));
|
|
37286
|
+
} else {
|
|
37287
|
+
const [bFrom, bTo] = migParts;
|
|
37288
|
+
const bundleEstimator = new BundleEstimator();
|
|
37289
|
+
const sourceFiles = analyzer.getProject().getSourceFiles();
|
|
37290
|
+
const estimate = bundleEstimator.estimate(
|
|
37291
|
+
sourceFiles,
|
|
37292
|
+
bFrom,
|
|
37293
|
+
bTo
|
|
37294
|
+
);
|
|
37295
|
+
console.log(pc4.bold("\nBundle Size Estimation\n"));
|
|
37296
|
+
console.log(
|
|
37297
|
+
` ${estimate.from.library}: ~${pc4.cyan(`${estimate.from.minifiedGzipKb}kB`)}`
|
|
37298
|
+
);
|
|
37299
|
+
console.log(` ${estimate.to.library}: ~${pc4.cyan(`${estimate.to.minifiedGzipKb}kB`)}`);
|
|
37300
|
+
console.log(
|
|
37301
|
+
` Delta: ${pc4.yellow(`${estimate.estimatedDelta > 0 ? "+" : ""}${estimate.estimatedDelta.toFixed(1)}kB (${estimate.deltaPercent.toFixed(0)}%)`)}`
|
|
37302
|
+
);
|
|
37303
|
+
console.log(`
|
|
37304
|
+
${pc4.dim(estimate.summary)}`);
|
|
37305
|
+
}
|
|
37306
|
+
}
|
|
37307
|
+
}
|
|
37308
|
+
if (options.performance) {
|
|
37309
|
+
const validation = await licenseManager.validate();
|
|
37310
|
+
const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
|
|
37311
|
+
if (!tier.performanceAnalyzer) {
|
|
37312
|
+
console.error(pc4.red("\nPerformance analysis requires Individual tier or higher."));
|
|
37313
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37314
|
+
} else {
|
|
37315
|
+
const migParts = options.performance.split("->");
|
|
37316
|
+
if (migParts.length !== 2) {
|
|
37317
|
+
console.error(pc4.red("Invalid format. Use: --performance zod-v3->v4"));
|
|
37318
|
+
} else {
|
|
37319
|
+
const [pFrom, pTo] = migParts;
|
|
37320
|
+
const perfAnalyzer = new PerformanceAnalyzer();
|
|
37321
|
+
const sourceFiles = analyzer.getProject().getSourceFiles();
|
|
37322
|
+
const perfResult = perfAnalyzer.analyze(
|
|
37323
|
+
sourceFiles,
|
|
37324
|
+
pFrom,
|
|
37325
|
+
pTo
|
|
37326
|
+
);
|
|
37327
|
+
if (perfResult.warnings.length > 0) {
|
|
37328
|
+
console.log(pc4.bold("\nPerformance Impact Analysis\n"));
|
|
37329
|
+
for (const w of perfResult.warnings) {
|
|
37330
|
+
const color = w.severity === "error" ? pc4.red : w.severity === "warning" ? pc4.yellow : pc4.dim;
|
|
37331
|
+
console.log(` ${color(`[${w.severity}]`)} ${w.message}`);
|
|
37332
|
+
console.log(` ${pc4.dim(w.detail)}`);
|
|
37333
|
+
}
|
|
37334
|
+
console.log(`
|
|
37335
|
+
${pc4.dim(perfResult.recommendation)}`);
|
|
37336
|
+
} else {
|
|
37337
|
+
console.log(pc4.green("\nNo performance concerns detected."));
|
|
37338
|
+
}
|
|
37339
|
+
}
|
|
37340
|
+
}
|
|
37341
|
+
}
|
|
37342
|
+
if (options.dedup) {
|
|
37343
|
+
const validation = await licenseManager.validate();
|
|
37344
|
+
const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
|
|
37345
|
+
if (!tier.typeDeduplication) {
|
|
37346
|
+
console.error(pc4.red("\nType deduplication detection requires Individual tier or higher."));
|
|
37347
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37348
|
+
} else {
|
|
37349
|
+
const dedupDetector = new TypeDedupDetector();
|
|
37350
|
+
const sourceFiles = analyzer.getProject().getSourceFiles();
|
|
37351
|
+
const dedupResult = dedupDetector.detect(sourceFiles);
|
|
37352
|
+
if (dedupResult.candidates.length > 0) {
|
|
37353
|
+
console.log(pc4.bold("\nDuplicate Type Candidates\n"));
|
|
37354
|
+
for (const c of dedupResult.candidates.slice(0, 10)) {
|
|
37355
|
+
console.log(` ${pc4.cyan(c.typeName)} <-> ${pc4.cyan(c.schemaName)}`);
|
|
37356
|
+
console.log(` Type: ${pc4.dim(c.typeFilePath)}:${c.typeLineNumber}`);
|
|
37357
|
+
console.log(` Schema: ${pc4.dim(c.schemaFilePath)}:${c.schemaLineNumber}`);
|
|
37358
|
+
console.log(` Confidence: ${pc4.dim(c.confidence)} | ${pc4.dim(c.suggestion)}`);
|
|
37359
|
+
}
|
|
37360
|
+
if (dedupResult.candidates.length > 10) {
|
|
37361
|
+
console.log(pc4.dim(` ... and ${dedupResult.candidates.length - 10} more`));
|
|
37362
|
+
}
|
|
37363
|
+
} else {
|
|
37364
|
+
console.log(pc4.green("\nNo duplicate type candidates found."));
|
|
37365
|
+
}
|
|
37366
|
+
}
|
|
37367
|
+
}
|
|
37161
37368
|
});
|
|
37162
37369
|
program.command("migrate <path>").description("Migrate schemas from one library to another").requiredOption("-f, --from <library>", "Source library (yup, joi, io-ts, zod-v3, zod)").requiredOption("-t, --to <library>", "Target library (zod, v4, valibot)").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
37370
|
"--max-risk-score <score>",
|
|
37164
37371
|
"Exit 1 if any file exceeds risk score (Team+)",
|
|
37165
37372
|
Number.parseInt
|
|
37166
|
-
).action(async (targetPath, options) => {
|
|
37373
|
+
).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
37374
|
const startTime = Date.now();
|
|
37168
37375
|
if (options.maxRiskScore !== void 0 && Number.isNaN(options.maxRiskScore)) {
|
|
37169
37376
|
console.error(pc4.red("--max-risk-score must be a valid number."));
|
|
@@ -37318,6 +37525,41 @@ Compatibility score: ${pc4.cyan(compatResult.overallScore.toString())}%`);
|
|
|
37318
37525
|
console.log(pc4.yellow("No files found matching patterns."));
|
|
37319
37526
|
process.exit(0);
|
|
37320
37527
|
}
|
|
37528
|
+
const incrementalTracker = new IncrementalTracker(resolve2(targetPath));
|
|
37529
|
+
if (options.incrementalStatus) {
|
|
37530
|
+
const progress = incrementalTracker.getProgress();
|
|
37531
|
+
if (!progress) {
|
|
37532
|
+
console.log(pc4.yellow("No incremental migration in progress."));
|
|
37533
|
+
process.exit(0);
|
|
37534
|
+
}
|
|
37535
|
+
console.log(pc4.bold("\nIncremental Migration Status\n"));
|
|
37536
|
+
console.log(`Completed: ${pc4.green(progress.completed.toString())}`);
|
|
37537
|
+
console.log(`Remaining: ${pc4.cyan(progress.remaining.toString())}`);
|
|
37538
|
+
console.log(`Failed: ${pc4.red(progress.failed.toString())}`);
|
|
37539
|
+
console.log(`Total: ${progress.total}`);
|
|
37540
|
+
console.log(`Progress: ${pc4.cyan(`${progress.percent}%`)}`);
|
|
37541
|
+
process.exit(0);
|
|
37542
|
+
}
|
|
37543
|
+
if (options.resume) {
|
|
37544
|
+
const state = incrementalTracker.resume();
|
|
37545
|
+
if (!state) {
|
|
37546
|
+
console.error(pc4.red("No incremental migration to resume."));
|
|
37547
|
+
process.exit(1);
|
|
37548
|
+
}
|
|
37549
|
+
files = state.remainingFiles;
|
|
37550
|
+
console.log(pc4.dim(`Resuming incremental migration: ${state.migrationId}`));
|
|
37551
|
+
const progress = incrementalTracker.getProgress();
|
|
37552
|
+
if (progress) {
|
|
37553
|
+
console.log(
|
|
37554
|
+
pc4.dim(
|
|
37555
|
+
`Progress: ${progress.completed}/${progress.total} completed (${progress.percent}%)`
|
|
37556
|
+
)
|
|
37557
|
+
);
|
|
37558
|
+
}
|
|
37559
|
+
} else if (options.incremental) {
|
|
37560
|
+
incrementalTracker.start(files, options.from, options.to);
|
|
37561
|
+
console.log(pc4.dim("Started incremental migration."));
|
|
37562
|
+
}
|
|
37321
37563
|
if (files.length > features.maxFiles) {
|
|
37322
37564
|
console.error(
|
|
37323
37565
|
pc4.red(`File limit exceeded. Found ${files.length}, max ${features.maxFiles}.`)
|
|
@@ -37452,6 +37694,30 @@ Migrating ${displayPath}
|
|
|
37452
37694
|
}
|
|
37453
37695
|
}
|
|
37454
37696
|
}
|
|
37697
|
+
if (options.incremental || options.resume) {
|
|
37698
|
+
for (const result of results) {
|
|
37699
|
+
if (result.success) {
|
|
37700
|
+
incrementalTracker.markComplete(result.filePath);
|
|
37701
|
+
} else {
|
|
37702
|
+
incrementalTracker.markFailed(result.filePath);
|
|
37703
|
+
}
|
|
37704
|
+
}
|
|
37705
|
+
const progress = incrementalTracker.getProgress();
|
|
37706
|
+
if (progress) {
|
|
37707
|
+
console.log(
|
|
37708
|
+
pc4.bold(`
|
|
37709
|
+
Incremental: ${progress.completed}/${progress.total} (${progress.percent}%)`)
|
|
37710
|
+
);
|
|
37711
|
+
if (progress.remaining > 0) {
|
|
37712
|
+
console.log(
|
|
37713
|
+
pc4.dim(`Run with --resume to continue. ${progress.remaining} files remaining.`)
|
|
37714
|
+
);
|
|
37715
|
+
}
|
|
37716
|
+
if (progress.failed > 0) {
|
|
37717
|
+
console.log(pc4.yellow(`${progress.failed} file(s) failed. Run with --resume to retry.`));
|
|
37718
|
+
}
|
|
37719
|
+
}
|
|
37720
|
+
}
|
|
37455
37721
|
if (options.gitCommit && git.isAvailable() && !options.dryRun) {
|
|
37456
37722
|
const successFiles = results.filter((r) => r.success).map((r) => r.filePath);
|
|
37457
37723
|
if (successFiles.length > 0) {
|
|
@@ -37464,9 +37730,11 @@ Migrating ${displayPath}
|
|
|
37464
37730
|
if (options.report === "html" && !features.htmlReports) {
|
|
37465
37731
|
console.error(pc4.red("HTML reports require Individual tier or higher."));
|
|
37466
37732
|
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37733
|
+
process.exit(1);
|
|
37467
37734
|
} else if (options.report === "csv" && !features.csvExport) {
|
|
37468
37735
|
console.error(pc4.red("CSV export requires Individual tier or higher."));
|
|
37469
37736
|
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37737
|
+
process.exit(1);
|
|
37470
37738
|
} else {
|
|
37471
37739
|
const reporter = new ReportGenerator();
|
|
37472
37740
|
const includeRisk = features.riskScoring;
|
|
@@ -37489,6 +37757,58 @@ Migrating ${displayPath}
|
|
|
37489
37757
|
console.log(pc4.green(`Report saved: ${outputPath}`));
|
|
37490
37758
|
}
|
|
37491
37759
|
}
|
|
37760
|
+
if (options.scaffoldTests) {
|
|
37761
|
+
if (!features.testScaffolding) {
|
|
37762
|
+
console.error(pc4.red("\nTest scaffolding requires Pro tier or higher."));
|
|
37763
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37764
|
+
} else {
|
|
37765
|
+
const scaffolder = new TestScaffolder();
|
|
37766
|
+
const successfulFiles = results.filter((r) => r.success).map((r) => r.filePath);
|
|
37767
|
+
if (successfulFiles.length > 0) {
|
|
37768
|
+
const scaffoldAnalyzer = new SchemaAnalyzer();
|
|
37769
|
+
for (const f of successfulFiles) {
|
|
37770
|
+
scaffoldAnalyzer.addSourceFiles([f]);
|
|
37771
|
+
}
|
|
37772
|
+
const sourceFiles = scaffoldAnalyzer.getProject().getSourceFiles();
|
|
37773
|
+
const scaffoldResult = scaffolder.scaffold(sourceFiles, options.from, options.to);
|
|
37774
|
+
console.log(pc4.bold("\nTest Scaffolding\n"));
|
|
37775
|
+
console.log(
|
|
37776
|
+
` Generated ${pc4.cyan(scaffoldResult.tests.length.toString())} test file(s) for ${scaffoldResult.totalSchemas} schema(s)`
|
|
37777
|
+
);
|
|
37778
|
+
for (const test of scaffoldResult.tests) {
|
|
37779
|
+
console.log(` ${pc4.dim(test.filePath)} (${test.schemaCount} schemas)`);
|
|
37780
|
+
}
|
|
37781
|
+
}
|
|
37782
|
+
}
|
|
37783
|
+
}
|
|
37784
|
+
if (options.audit) {
|
|
37785
|
+
if (!features.auditLogging) {
|
|
37786
|
+
console.error(pc4.red("\nAudit logging requires Team tier."));
|
|
37787
|
+
console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
|
|
37788
|
+
} else {
|
|
37789
|
+
const projectPath = resolve2(targetPath);
|
|
37790
|
+
const auditLog = new MigrationAuditLog(projectPath);
|
|
37791
|
+
const migrationId = `${options.from}->${options.to}-${Date.now()}`;
|
|
37792
|
+
for (const result of results) {
|
|
37793
|
+
const entry = auditLog.createEntry({
|
|
37794
|
+
migrationId,
|
|
37795
|
+
filePath: result.filePath,
|
|
37796
|
+
from: options.from,
|
|
37797
|
+
to: options.to,
|
|
37798
|
+
originalCode: result.originalCode ?? "",
|
|
37799
|
+
transformedCode: result.transformedCode,
|
|
37800
|
+
success: result.success,
|
|
37801
|
+
warningCount: result.warnings.length,
|
|
37802
|
+
errorCount: result.errors.length
|
|
37803
|
+
});
|
|
37804
|
+
auditLog.append(entry);
|
|
37805
|
+
}
|
|
37806
|
+
console.log(
|
|
37807
|
+
pc4.dim(`
|
|
37808
|
+
Audit log saved to .schemashift/audit-log.json (${results.length} entries)`)
|
|
37809
|
+
);
|
|
37810
|
+
}
|
|
37811
|
+
}
|
|
37492
37812
|
if (options.dryRun) {
|
|
37493
37813
|
const diffOutput = generateDiffPreview(results);
|
|
37494
37814
|
if (diffOutput) {
|
|
@@ -37571,15 +37891,15 @@ program.command("watch <path>").description("Watch files and migrate on change")
|
|
|
37571
37891
|
};
|
|
37572
37892
|
}
|
|
37573
37893
|
const watchMode = new WatchMode();
|
|
37574
|
-
const analyzer = new SchemaAnalyzer();
|
|
37575
37894
|
await watchMode.start({
|
|
37576
37895
|
patterns: config2.include.map((p) => join3(targetPath, p)),
|
|
37577
37896
|
exclude: config2.exclude,
|
|
37578
37897
|
from: options.from,
|
|
37579
37898
|
to: options.to,
|
|
37580
37899
|
onTransform: async (file) => {
|
|
37581
|
-
|
|
37582
|
-
|
|
37900
|
+
const fileAnalyzer = new SchemaAnalyzer();
|
|
37901
|
+
fileAnalyzer.addSourceFiles([file]);
|
|
37902
|
+
const sourceFile = fileAnalyzer.getProject().getSourceFileOrThrow(resolve2(file));
|
|
37583
37903
|
const result = engine.transform(sourceFile, options.from, options.to, {
|
|
37584
37904
|
from: options.from,
|
|
37585
37905
|
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,9 @@ 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"
|
|
33835
33849
|
],
|
|
33836
33850
|
devices: 4,
|
|
33837
33851
|
ciSupport: true,
|
|
@@ -33852,7 +33866,13 @@ var TIER_FEATURES = {
|
|
|
33852
33866
|
maxRiskScoreThreshold: false,
|
|
33853
33867
|
formResolverMigration: true,
|
|
33854
33868
|
complexityEstimator: true,
|
|
33855
|
-
monorepoAware: true
|
|
33869
|
+
monorepoAware: true,
|
|
33870
|
+
behavioralWarnings: true,
|
|
33871
|
+
bundleEstimator: true,
|
|
33872
|
+
performanceAnalyzer: true,
|
|
33873
|
+
typeDeduplication: true,
|
|
33874
|
+
testScaffolding: true,
|
|
33875
|
+
auditLogging: false
|
|
33856
33876
|
},
|
|
33857
33877
|
[
|
|
33858
33878
|
"team"
|
|
@@ -33865,7 +33885,9 @@ var TIER_FEATURES = {
|
|
|
33865
33885
|
"zod-v3->v4",
|
|
33866
33886
|
"io-ts->zod",
|
|
33867
33887
|
"any->valibot",
|
|
33868
|
-
"zod->valibot"
|
|
33888
|
+
"zod->valibot",
|
|
33889
|
+
"zod->yup",
|
|
33890
|
+
"valibot->zod"
|
|
33869
33891
|
],
|
|
33870
33892
|
devices: Infinity,
|
|
33871
33893
|
ciSupport: true,
|
|
@@ -33886,7 +33908,13 @@ var TIER_FEATURES = {
|
|
|
33886
33908
|
maxRiskScoreThreshold: true,
|
|
33887
33909
|
formResolverMigration: true,
|
|
33888
33910
|
complexityEstimator: true,
|
|
33889
|
-
monorepoAware: true
|
|
33911
|
+
monorepoAware: true,
|
|
33912
|
+
behavioralWarnings: true,
|
|
33913
|
+
bundleEstimator: true,
|
|
33914
|
+
performanceAnalyzer: true,
|
|
33915
|
+
typeDeduplication: true,
|
|
33916
|
+
testScaffolding: true,
|
|
33917
|
+
auditLogging: true
|
|
33890
33918
|
}
|
|
33891
33919
|
};
|
|
33892
33920
|
var POLAR_ORG_ID = process.env.POLAR_ORG_ID || "79bbe935-1836-4b9e-9ca8-4c7a94217f5e";
|
|
@@ -34641,6 +34669,12 @@ var WatchMode = class {
|
|
|
34641
34669
|
console.log(import_picocolors.default.cyan(`
|
|
34642
34670
|
Watching ${files.length} files for changes...
|
|
34643
34671
|
`));
|
|
34672
|
+
if (options.dependents && options.dependents.size > 0) {
|
|
34673
|
+
console.log(
|
|
34674
|
+
import_picocolors.default.dim(`Dependency-aware mode: ${options.dependents.size} files with dependents
|
|
34675
|
+
`)
|
|
34676
|
+
);
|
|
34677
|
+
}
|
|
34644
34678
|
console.log(import_picocolors.default.dim("Press Ctrl+C to stop\n"));
|
|
34645
34679
|
const directories = new Set(files.map((f) => f.split("/").slice(0, -1).join("/")));
|
|
34646
34680
|
for (const dir of directories) {
|
|
@@ -34661,8 +34695,26 @@ Watching ${files.length} files for changes...
|
|
|
34661
34695
|
Changed: ${(0, import_node_path2.relative)(process.cwd(), fullPath)}`));
|
|
34662
34696
|
try {
|
|
34663
34697
|
await options.onTransform(fullPath);
|
|
34664
|
-
console.log(import_picocolors.default.green(`Transformed successfully
|
|
34665
|
-
|
|
34698
|
+
console.log(import_picocolors.default.green(`Transformed successfully`));
|
|
34699
|
+
const dependentFiles = options.dependents?.get(fullPath);
|
|
34700
|
+
if (dependentFiles && dependentFiles.length > 0) {
|
|
34701
|
+
console.log(
|
|
34702
|
+
import_picocolors.default.cyan(` Re-transforming ${dependentFiles.length} dependent file(s)...`)
|
|
34703
|
+
);
|
|
34704
|
+
for (const depFile of dependentFiles) {
|
|
34705
|
+
try {
|
|
34706
|
+
await options.onTransform(depFile);
|
|
34707
|
+
console.log(import_picocolors.default.green(` \u2713 ${(0, import_node_path2.relative)(process.cwd(), depFile)}`));
|
|
34708
|
+
} catch (error) {
|
|
34709
|
+
console.error(
|
|
34710
|
+
import_picocolors.default.red(
|
|
34711
|
+
` \u2717 ${(0, import_node_path2.relative)(process.cwd(), depFile)}: ${error instanceof Error ? error.message : String(error)}`
|
|
34712
|
+
)
|
|
34713
|
+
);
|
|
34714
|
+
}
|
|
34715
|
+
}
|
|
34716
|
+
}
|
|
34717
|
+
console.log("");
|
|
34666
34718
|
} catch (error) {
|
|
34667
34719
|
console.error(
|
|
34668
34720
|
import_picocolors.default.red(
|
|
@@ -34688,6 +34740,21 @@ Changed: ${(0, import_node_path2.relative)(process.cwd(), fullPath)}`));
|
|
|
34688
34740
|
}
|
|
34689
34741
|
this.debounceTimers.clear();
|
|
34690
34742
|
}
|
|
34743
|
+
/**
|
|
34744
|
+
* Build a reverse dependency map (file -> files that depend on it).
|
|
34745
|
+
* Takes the forward dependency map from SchemaDependencyResolver and inverts it.
|
|
34746
|
+
*/
|
|
34747
|
+
static buildDependentsMap(dependencies) {
|
|
34748
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
34749
|
+
for (const [file, deps] of dependencies) {
|
|
34750
|
+
for (const dep of deps) {
|
|
34751
|
+
const existing = dependents.get(dep) ?? [];
|
|
34752
|
+
existing.push(file);
|
|
34753
|
+
dependents.set(dep, existing);
|
|
34754
|
+
}
|
|
34755
|
+
}
|
|
34756
|
+
return dependents;
|
|
34757
|
+
}
|
|
34691
34758
|
matchesPatterns(file, include, exclude) {
|
|
34692
34759
|
const isIncluded = include.some((p) => (0, import_minimatch.minimatch)(file, p));
|
|
34693
34760
|
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,9 @@ 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"
|
|
33794
33808
|
],
|
|
33795
33809
|
devices: 4,
|
|
33796
33810
|
ciSupport: true,
|
|
@@ -33811,7 +33825,13 @@ var TIER_FEATURES = {
|
|
|
33811
33825
|
maxRiskScoreThreshold: false,
|
|
33812
33826
|
formResolverMigration: true,
|
|
33813
33827
|
complexityEstimator: true,
|
|
33814
|
-
monorepoAware: true
|
|
33828
|
+
monorepoAware: true,
|
|
33829
|
+
behavioralWarnings: true,
|
|
33830
|
+
bundleEstimator: true,
|
|
33831
|
+
performanceAnalyzer: true,
|
|
33832
|
+
typeDeduplication: true,
|
|
33833
|
+
testScaffolding: true,
|
|
33834
|
+
auditLogging: false
|
|
33815
33835
|
},
|
|
33816
33836
|
[
|
|
33817
33837
|
"team"
|
|
@@ -33824,7 +33844,9 @@ var TIER_FEATURES = {
|
|
|
33824
33844
|
"zod-v3->v4",
|
|
33825
33845
|
"io-ts->zod",
|
|
33826
33846
|
"any->valibot",
|
|
33827
|
-
"zod->valibot"
|
|
33847
|
+
"zod->valibot",
|
|
33848
|
+
"zod->yup",
|
|
33849
|
+
"valibot->zod"
|
|
33828
33850
|
],
|
|
33829
33851
|
devices: Infinity,
|
|
33830
33852
|
ciSupport: true,
|
|
@@ -33845,7 +33867,13 @@ var TIER_FEATURES = {
|
|
|
33845
33867
|
maxRiskScoreThreshold: true,
|
|
33846
33868
|
formResolverMigration: true,
|
|
33847
33869
|
complexityEstimator: true,
|
|
33848
|
-
monorepoAware: true
|
|
33870
|
+
monorepoAware: true,
|
|
33871
|
+
behavioralWarnings: true,
|
|
33872
|
+
bundleEstimator: true,
|
|
33873
|
+
performanceAnalyzer: true,
|
|
33874
|
+
typeDeduplication: true,
|
|
33875
|
+
testScaffolding: true,
|
|
33876
|
+
auditLogging: true
|
|
33849
33877
|
}
|
|
33850
33878
|
};
|
|
33851
33879
|
var POLAR_ORG_ID = process.env.POLAR_ORG_ID || "79bbe935-1836-4b9e-9ca8-4c7a94217f5e";
|
|
@@ -34608,6 +34636,12 @@ var WatchMode = class {
|
|
|
34608
34636
|
console.log(pc.cyan(`
|
|
34609
34637
|
Watching ${files.length} files for changes...
|
|
34610
34638
|
`));
|
|
34639
|
+
if (options.dependents && options.dependents.size > 0) {
|
|
34640
|
+
console.log(
|
|
34641
|
+
pc.dim(`Dependency-aware mode: ${options.dependents.size} files with dependents
|
|
34642
|
+
`)
|
|
34643
|
+
);
|
|
34644
|
+
}
|
|
34611
34645
|
console.log(pc.dim("Press Ctrl+C to stop\n"));
|
|
34612
34646
|
const directories = new Set(files.map((f) => f.split("/").slice(0, -1).join("/")));
|
|
34613
34647
|
for (const dir of directories) {
|
|
@@ -34628,8 +34662,26 @@ Watching ${files.length} files for changes...
|
|
|
34628
34662
|
Changed: ${relative2(process.cwd(), fullPath)}`));
|
|
34629
34663
|
try {
|
|
34630
34664
|
await options.onTransform(fullPath);
|
|
34631
|
-
console.log(pc.green(`Transformed successfully
|
|
34632
|
-
|
|
34665
|
+
console.log(pc.green(`Transformed successfully`));
|
|
34666
|
+
const dependentFiles = options.dependents?.get(fullPath);
|
|
34667
|
+
if (dependentFiles && dependentFiles.length > 0) {
|
|
34668
|
+
console.log(
|
|
34669
|
+
pc.cyan(` Re-transforming ${dependentFiles.length} dependent file(s)...`)
|
|
34670
|
+
);
|
|
34671
|
+
for (const depFile of dependentFiles) {
|
|
34672
|
+
try {
|
|
34673
|
+
await options.onTransform(depFile);
|
|
34674
|
+
console.log(pc.green(` \u2713 ${relative2(process.cwd(), depFile)}`));
|
|
34675
|
+
} catch (error) {
|
|
34676
|
+
console.error(
|
|
34677
|
+
pc.red(
|
|
34678
|
+
` \u2717 ${relative2(process.cwd(), depFile)}: ${error instanceof Error ? error.message : String(error)}`
|
|
34679
|
+
)
|
|
34680
|
+
);
|
|
34681
|
+
}
|
|
34682
|
+
}
|
|
34683
|
+
}
|
|
34684
|
+
console.log("");
|
|
34633
34685
|
} catch (error) {
|
|
34634
34686
|
console.error(
|
|
34635
34687
|
pc.red(
|
|
@@ -34655,6 +34707,21 @@ Changed: ${relative2(process.cwd(), fullPath)}`));
|
|
|
34655
34707
|
}
|
|
34656
34708
|
this.debounceTimers.clear();
|
|
34657
34709
|
}
|
|
34710
|
+
/**
|
|
34711
|
+
* Build a reverse dependency map (file -> files that depend on it).
|
|
34712
|
+
* Takes the forward dependency map from SchemaDependencyResolver and inverts it.
|
|
34713
|
+
*/
|
|
34714
|
+
static buildDependentsMap(dependencies) {
|
|
34715
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
34716
|
+
for (const [file, deps] of dependencies) {
|
|
34717
|
+
for (const dep of deps) {
|
|
34718
|
+
const existing = dependents.get(dep) ?? [];
|
|
34719
|
+
existing.push(file);
|
|
34720
|
+
dependents.set(dep, existing);
|
|
34721
|
+
}
|
|
34722
|
+
}
|
|
34723
|
+
return dependents;
|
|
34724
|
+
}
|
|
34658
34725
|
matchesPatterns(file, include, exclude) {
|
|
34659
34726
|
const isIncluded = include.some((p) => minimatch(file, p));
|
|
34660
34727
|
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.9.0",
|
|
4
4
|
"description": "TypeScript schema migration CLI - migrate between Zod, Yup, Joi, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"author": "Joseph May",
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@schemashift/core": "0.
|
|
53
|
-
"@schemashift/io-ts-zod": "0.
|
|
54
|
-
"@schemashift/joi-zod": "0.
|
|
55
|
-
"@schemashift/yup-zod": "0.
|
|
56
|
-
"@schemashift/zod-valibot": "0.
|
|
57
|
-
"@schemashift/zod-v3-v4": "0.
|
|
52
|
+
"@schemashift/core": "0.9.0",
|
|
53
|
+
"@schemashift/io-ts-zod": "0.9.0",
|
|
54
|
+
"@schemashift/joi-zod": "0.9.0",
|
|
55
|
+
"@schemashift/yup-zod": "0.9.0",
|
|
56
|
+
"@schemashift/zod-valibot": "0.9.0",
|
|
57
|
+
"@schemashift/zod-v3-v4": "0.9.0",
|
|
58
58
|
"commander": "14.0.2",
|
|
59
59
|
"cosmiconfig": "9.0.0",
|
|
60
60
|
"glob": "13.0.0",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"picocolors": "1.1.1"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@schemashift/license": "0.
|
|
66
|
+
"@schemashift/license": "0.9.0"
|
|
67
67
|
},
|
|
68
68
|
"publishConfig": {
|
|
69
69
|
"access": "public"
|