@schemashift/io-ts-effect 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 ADDED
@@ -0,0 +1,110 @@
1
+ # @schemashift/io-ts-effect
2
+
3
+ io-ts → Effect Schema transformer for SchemaShift. Migrates io-ts codecs to their Effect Schema equivalents — the official successor to io-ts after fp-ts merged into Effect.
4
+
5
+ **Tier:** Pro+
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @schemashift/io-ts-effect
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { createIoTsToEffectHandler } from '@schemashift/io-ts-effect';
17
+ import { TransformEngine } from '@schemashift/core';
18
+
19
+ const engine = new TransformEngine();
20
+ engine.registerHandler('io-ts', 'effect', createIoTsToEffectHandler());
21
+ ```
22
+
23
+ ## Why This Migration Path?
24
+
25
+ - **io-ts is deprecated** — fp-ts merged into Effect-TS
26
+ - **Effect Schema is the official successor** for FP-oriented validation
27
+ - **Same philosophy** — both use branded types, codecs, and composable validation
28
+ - **Better DX** — Effect Schema has simpler API with better TypeScript inference
29
+
30
+ ## Transformation Mappings
31
+
32
+ ### Imports
33
+
34
+ | io-ts | Effect Schema |
35
+ |-------|---------------|
36
+ | `import * as t from 'io-ts'` | `import { Schema as S } from '@effect/schema'` |
37
+ | `import { pipe } from 'fp-ts/function'` | `import { pipe } from 'effect/Function'` |
38
+
39
+ ### Primitives
40
+
41
+ | io-ts | Effect Schema |
42
+ |-------|---------------|
43
+ | `t.string` | `S.String` |
44
+ | `t.number` | `S.Number` |
45
+ | `t.boolean` | `S.Boolean` |
46
+ | `t.bigint` | `S.BigInt` |
47
+ | `t.unknown` | `S.Unknown` |
48
+ | `t.never` | `S.Never` |
49
+ | `t.null` | `S.Null` |
50
+ | `t.undefined` | `S.Undefined` |
51
+ | `t.void` | `S.Void` |
52
+
53
+ ### Combinators
54
+
55
+ | io-ts | Effect Schema |
56
+ |-------|---------------|
57
+ | `t.type({...})` | `S.Struct({...})` |
58
+ | `t.partial({...})` | `S.partial(S.Struct({...}))` |
59
+ | `t.array(X)` | `S.Array(X)` |
60
+ | `t.record(K, V)` | `S.Record(K, V)` |
61
+ | `t.union([A, B])` | `S.Union(A, B)` |
62
+ | `t.tuple([A, B])` | `S.Tuple(A, B)` |
63
+ | `t.literal(X)` | `S.Literal(X)` |
64
+
65
+ ### Type Helpers
66
+
67
+ | io-ts | Effect Schema |
68
+ |-------|---------------|
69
+ | `t.TypeOf<typeof s>` | `S.Schema.Type<typeof s>` |
70
+ | `t.OutputOf<typeof s>` | `S.Schema.Type<typeof s>` |
71
+ | `t.InputOf<typeof s>` | `S.Schema.Encoded<typeof s>` |
72
+
73
+ ## Patterns Requiring Manual Review
74
+
75
+ ### `.decode()` / `.encode()`
76
+
77
+ ```typescript
78
+ // io-ts
79
+ const result = schema.decode(input);
80
+
81
+ // Effect Schema
82
+ const result = S.decodeUnknownSync(schema)(input);
83
+ // or for Either result:
84
+ const result = S.decodeUnknownEither(schema)(input);
85
+ ```
86
+
87
+ ### `t.brand()`
88
+
89
+ ```typescript
90
+ // io-ts
91
+ interface PositiveBrand { readonly Positive: unique symbol }
92
+ const Positive = t.brand(t.number, (n): n is t.Branded<number, PositiveBrand> => n > 0, 'Positive');
93
+
94
+ // Effect Schema
95
+ const Positive = pipe(S.Number, S.positive(), S.brand("Positive"));
96
+ ```
97
+
98
+ ### Recursive Types
99
+
100
+ ```typescript
101
+ // io-ts
102
+ const Tree = t.recursion('Tree', () => t.type({ children: t.array(Tree) }));
103
+
104
+ // Effect Schema
105
+ const Tree = S.Struct({ children: S.Array(S.suspend(() => Tree)) });
106
+ ```
107
+
108
+ ## License
109
+
110
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ FP_TS_PATTERNS: () => FP_TS_PATTERNS,
24
+ IMPORT_MAPPINGS: () => IMPORT_MAPPINGS,
25
+ IO_TS_TO_EFFECT_CODECS: () => IO_TS_TO_EFFECT_CODECS,
26
+ IO_TS_TO_EFFECT_COMBINATORS: () => IO_TS_TO_EFFECT_COMBINATORS,
27
+ MANUAL_REVIEW_PATTERNS: () => MANUAL_REVIEW_PATTERNS,
28
+ createIoTsToEffectHandler: () => createIoTsToEffectHandler
29
+ });
30
+ module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/mappings.ts
33
+ var IO_TS_TO_EFFECT_CODECS = {
34
+ "t.string": "S.String",
35
+ "t.number": "S.Number",
36
+ "t.boolean": "S.Boolean",
37
+ "t.bigint": "S.BigInt",
38
+ "t.unknown": "S.Unknown",
39
+ "t.never": "S.Never",
40
+ "t.null": "S.Null",
41
+ "t.undefined": "S.Undefined",
42
+ "t.void": "S.Void",
43
+ "t.any": "S.Unknown",
44
+ "t.Int": "pipe(S.Number, S.int())",
45
+ "t.literal": "S.Literal"
46
+ };
47
+ var IO_TS_TO_EFFECT_COMBINATORS = {
48
+ "t.type": "S.Struct",
49
+ "t.partial": "S.partial(S.Struct",
50
+ "t.array": "S.Array",
51
+ "t.record": "S.Record",
52
+ "t.union": "S.Union",
53
+ "t.intersection": "S.extend",
54
+ "t.tuple": "S.Tuple",
55
+ "t.readonly": "S.Struct",
56
+ // Effect Schema structs are readonly by default
57
+ "t.readonlyArray": "S.Array",
58
+ "t.exact": "S.Struct",
59
+ "t.strict": "S.Struct",
60
+ "t.keyof": "S.Literal"
61
+ };
62
+ var FP_TS_PATTERNS = [
63
+ "pipe",
64
+ "flow",
65
+ "Either",
66
+ "Option",
67
+ "TaskEither",
68
+ "fold",
69
+ "map",
70
+ "chain",
71
+ "getOrElse",
72
+ "isLeft",
73
+ "isRight"
74
+ ];
75
+ var MANUAL_REVIEW_PATTERNS = [
76
+ "branded",
77
+ "withMessage",
78
+ "withFallback",
79
+ "taggedUnion",
80
+ "recursion",
81
+ "exact",
82
+ "clean",
83
+ "alias"
84
+ ];
85
+ var IMPORT_MAPPINGS = {
86
+ ioTsToEffect: {
87
+ ioTsImport: "import * as t from 'io-ts'",
88
+ effectImport: "import { Schema as S } from '@effect/schema'",
89
+ pipeImport: "import { pipe } from 'effect/Function'"
90
+ }
91
+ };
92
+
93
+ // src/io-ts-to-effect-transformer.ts
94
+ var IoTsToEffectTransformer = class {
95
+ errors = [];
96
+ warnings = [];
97
+ needsPipe = false;
98
+ transform(sourceFile) {
99
+ this.errors = [];
100
+ this.warnings = [];
101
+ this.needsPipe = false;
102
+ const filePath = sourceFile.getFilePath();
103
+ const originalCode = sourceFile.getFullText();
104
+ try {
105
+ let text = originalCode;
106
+ text = this.transformCodecs(text, filePath);
107
+ text = this.transformTypeHelpers(text);
108
+ this.checkManualReviewPatterns(text, filePath);
109
+ text = this.rewriteImports(text, filePath);
110
+ sourceFile.replaceWithText(text);
111
+ return {
112
+ success: this.errors.length === 0,
113
+ filePath,
114
+ originalCode,
115
+ transformedCode: sourceFile.getFullText(),
116
+ errors: this.errors,
117
+ warnings: this.warnings
118
+ };
119
+ } catch (error) {
120
+ this.errors.push({
121
+ message: error instanceof Error ? error.message : "Unknown error"
122
+ });
123
+ return {
124
+ success: false,
125
+ filePath,
126
+ originalCode,
127
+ errors: this.errors,
128
+ warnings: this.warnings
129
+ };
130
+ }
131
+ }
132
+ rewriteImports(text, filePath) {
133
+ text = text.replace(
134
+ /import\s*\*\s*as\s*t\s*from\s*['"]io-ts['"]/g,
135
+ "import { Schema as S } from '@effect/schema'"
136
+ );
137
+ text = text.replace(
138
+ /import\s*\{[^}]+\}\s*from\s*['"]io-ts['"]/g,
139
+ "import { Schema as S } from '@effect/schema'"
140
+ );
141
+ text = text.replace(
142
+ /import\s+type\s*\{[^}]*\bTypeOf\b[^}]*\}\s*from\s*['"]io-ts['"]/g,
143
+ "import type { Schema } from '@effect/schema'"
144
+ );
145
+ if (this.needsPipe && !text.includes("from 'effect/Function'")) {
146
+ text = text.replace(
147
+ /import\s*\{[^}]*Schema[^}]*\}\s*from\s*['"]@effect\/schema['"]/,
148
+ (match) => `${match}
149
+ import { pipe } from 'effect/Function'`
150
+ );
151
+ }
152
+ if (/from\s*['"]fp-ts/.test(text)) {
153
+ this.warnings.push(
154
+ `${filePath}: fp-ts imports detected. Effect has built-in equivalents: pipe from effect/Function, Either from effect/Either, Option from effect/Option.`
155
+ );
156
+ }
157
+ text = text.replace(
158
+ /import\s*\{[^}]*\bpipe\b[^}]*\}\s*from\s*['"]fp-ts\/function['"]/g,
159
+ "import { pipe } from 'effect/Function'"
160
+ );
161
+ return text;
162
+ }
163
+ transformCodecs(text, filePath) {
164
+ for (const [ioTsCodec, effectCodec] of Object.entries(IO_TS_TO_EFFECT_CODECS)) {
165
+ if (text.includes(ioTsCodec)) {
166
+ const pattern = new RegExp(this.escapeRegex(ioTsCodec), "g");
167
+ text = text.replace(pattern, effectCodec);
168
+ if (effectCodec.includes("pipe(")) {
169
+ this.needsPipe = true;
170
+ }
171
+ }
172
+ }
173
+ for (const [ioTsCombinator, effectCombinator] of Object.entries(IO_TS_TO_EFFECT_COMBINATORS)) {
174
+ if (text.includes(ioTsCombinator)) {
175
+ const pattern = new RegExp(`${this.escapeRegex(ioTsCombinator)}\\(`, "g");
176
+ text = text.replace(pattern, `${effectCombinator}(`);
177
+ }
178
+ }
179
+ if (text.includes("S.partial(S.Struct(")) {
180
+ text = this.fixPartialClosingParens(text);
181
+ }
182
+ text = text.replace(/S\.Union\(\[([^\]]+)\]\)/g, "S.Union($1)");
183
+ text = text.replace(/S\.extend\(\[([^,\]]+),\s*([^\]]+)\]\)/g, (_m, a, b) => {
184
+ this.needsPipe = true;
185
+ return `pipe(${a.trim()}, S.extend(${b.trim()}))`;
186
+ });
187
+ text = text.replace(/t\.TypeOf<typeof\s+(\w+)>/g, "S.Schema.Type<typeof $1>");
188
+ text = text.replace(/t\.OutputOf<typeof\s+(\w+)>/g, "S.Schema.Type<typeof $1>");
189
+ text = text.replace(/t\.InputOf<typeof\s+(\w+)>/g, "S.Schema.Encoded<typeof $1>");
190
+ if (text.includes(".decode(")) {
191
+ this.warnings.push(
192
+ `${filePath}: io-ts .decode() should be converted to S.decodeUnknownSync() or S.decodeUnknownEither().`
193
+ );
194
+ }
195
+ if (text.includes(".encode(")) {
196
+ this.warnings.push(
197
+ `${filePath}: io-ts .encode() should be converted to S.encodeSync() or S.encodeEither().`
198
+ );
199
+ }
200
+ if (text.includes("t.brand(")) {
201
+ this.warnings.push(
202
+ `${filePath}: io-ts t.brand() should be converted to pipe(schema, S.brand("BrandName")).`
203
+ );
204
+ }
205
+ if (text.includes("isRight(") || text.includes("isLeft(")) {
206
+ this.warnings.push(
207
+ `${filePath}: fp-ts isRight/isLeft should use Effect's Either.isRight/Either.isLeft.`
208
+ );
209
+ }
210
+ if (/\bt\./.test(text)) {
211
+ this.warnings.push(
212
+ `${filePath}: Some io-ts patterns could not be auto-transformed to Effect Schema. Look for remaining t.* references and convert manually.`
213
+ );
214
+ }
215
+ return text;
216
+ }
217
+ transformTypeHelpers(text) {
218
+ text = text.replace(/\bt\.Type\b/g, "S.Schema");
219
+ text = text.replace(/\bt\.Mixed\b/g, "S.Schema<unknown>");
220
+ return text;
221
+ }
222
+ fixPartialClosingParens(text) {
223
+ let result = "";
224
+ let i = 0;
225
+ while (i < text.length) {
226
+ const partialIdx = text.indexOf("S.partial(S.Struct(", i);
227
+ if (partialIdx === -1) {
228
+ result += text.slice(i);
229
+ break;
230
+ }
231
+ result += text.slice(i, partialIdx);
232
+ const startParen = partialIdx + "S.partial(S.Struct(".length;
233
+ let depth = 1;
234
+ let j = startParen;
235
+ while (j < text.length && text[j] !== "{") j++;
236
+ j++;
237
+ depth = 1;
238
+ while (j < text.length && depth > 0) {
239
+ if (text[j] === "{") depth++;
240
+ if (text[j] === "}") depth--;
241
+ j++;
242
+ }
243
+ if (j < text.length && text[j] === ")") {
244
+ result += `S.partial(S.Struct(${text.slice(startParen, j + 1)})`;
245
+ i = j + 1;
246
+ } else {
247
+ result += text.slice(partialIdx, j);
248
+ i = j;
249
+ }
250
+ }
251
+ return result;
252
+ }
253
+ checkManualReviewPatterns(text, filePath) {
254
+ for (const pattern of MANUAL_REVIEW_PATTERNS) {
255
+ if (text.includes(`.${pattern}(`) || text.includes(`t.${pattern}`)) {
256
+ const guidance = this.getManualGuidance(pattern);
257
+ this.warnings.push(
258
+ `${filePath}: ${pattern} requires manual conversion to Effect Schema. ${guidance}`
259
+ );
260
+ }
261
+ }
262
+ }
263
+ getManualGuidance(pattern) {
264
+ const guidance = {
265
+ branded: 'Use pipe(schema, S.brand("Name")) in Effect Schema.',
266
+ withMessage: "Use S.message() or S.annotations({ message: ... }) in Effect Schema.",
267
+ withFallback: "Handle fallbacks at the application level or use S.optional with default.",
268
+ taggedUnion: "Effect Schema uses S.Union with S.Struct variants (discriminated automatically).",
269
+ recursion: "Use S.suspend(() => schema) for recursive types in Effect Schema.",
270
+ exact: "Effect Schema structs are exact by default (no extra keys).",
271
+ clean: "Not needed in Effect Schema \u2014 structs strip unknown keys by default.",
272
+ alias: "Not applicable in Effect Schema \u2014 use TypeScript type aliases directly."
273
+ };
274
+ return guidance[pattern] || "See Effect Schema documentation for equivalent pattern.";
275
+ }
276
+ escapeRegex(str) {
277
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
278
+ }
279
+ };
280
+
281
+ // src/io-ts-to-effect-handler.ts
282
+ function createIoTsToEffectHandler() {
283
+ return {
284
+ transform(sourceFile, _options) {
285
+ const transformer = new IoTsToEffectTransformer();
286
+ return transformer.transform(sourceFile);
287
+ }
288
+ };
289
+ }
290
+ // Annotate the CommonJS export names for ESM import in node:
291
+ 0 && (module.exports = {
292
+ FP_TS_PATTERNS,
293
+ IMPORT_MAPPINGS,
294
+ IO_TS_TO_EFFECT_CODECS,
295
+ IO_TS_TO_EFFECT_COMBINATORS,
296
+ MANUAL_REVIEW_PATTERNS,
297
+ createIoTsToEffectHandler
298
+ });
299
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/mappings.ts","../src/io-ts-to-effect-transformer.ts","../src/io-ts-to-effect-handler.ts"],"sourcesContent":["export { createIoTsToEffectHandler } from './io-ts-to-effect-handler.js';\nexport {\n FP_TS_PATTERNS,\n IMPORT_MAPPINGS,\n IO_TS_TO_EFFECT_CODECS,\n IO_TS_TO_EFFECT_COMBINATORS,\n MANUAL_REVIEW_PATTERNS,\n} from './mappings.js';\n","/**\n * io-ts → Effect Schema type mappings\n *\n * io-ts uses fp-ts style codecs:\n * io-ts: t.type({ name: t.string, age: t.number })\n * Effect Schema: S.Struct({ name: S.String, age: S.Number })\n *\n * Key differences:\n * - Effect Schema uses PascalCase for primitives (S.String, S.Number)\n * - Effect Schema uses S.Struct instead of t.type for objects\n * - Effect Schema uses S.Union instead of t.union\n * - Effect Schema uses branded types via S.brand()\n * - Effect Schema is pipe-based using Effect's pipe() utility\n */\n\n/** io-ts codec → Effect Schema equivalent */\nexport const IO_TS_TO_EFFECT_CODECS: Record<string, string> = {\n 't.string': 'S.String',\n 't.number': 'S.Number',\n 't.boolean': 'S.Boolean',\n 't.bigint': 'S.BigInt',\n 't.unknown': 'S.Unknown',\n 't.never': 'S.Never',\n 't.null': 'S.Null',\n 't.undefined': 'S.Undefined',\n 't.void': 'S.Void',\n 't.any': 'S.Unknown',\n 't.Int': 'pipe(S.Number, S.int())',\n 't.literal': 'S.Literal',\n};\n\n/** io-ts combinators → Effect Schema combinators */\nexport const IO_TS_TO_EFFECT_COMBINATORS: Record<string, string> = {\n 't.type': 'S.Struct',\n 't.partial': 'S.partial(S.Struct',\n 't.array': 'S.Array',\n 't.record': 'S.Record',\n 't.union': 'S.Union',\n 't.intersection': 'S.extend',\n 't.tuple': 'S.Tuple',\n 't.readonly': 'S.Struct', // Effect Schema structs are readonly by default\n 't.readonlyArray': 'S.Array',\n 't.exact': 'S.Struct',\n 't.strict': 'S.Struct',\n 't.keyof': 'S.Literal',\n};\n\n/** fp-ts imports that need transformation */\nexport const FP_TS_PATTERNS = [\n 'pipe',\n 'flow',\n 'Either',\n 'Option',\n 'TaskEither',\n 'fold',\n 'map',\n 'chain',\n 'getOrElse',\n 'isLeft',\n 'isRight',\n];\n\n/** Patterns requiring manual review */\nexport const MANUAL_REVIEW_PATTERNS = [\n 'branded',\n 'withMessage',\n 'withFallback',\n 'taggedUnion',\n 'recursion',\n 'exact',\n 'clean',\n 'alias',\n];\n\n/** Import mapping */\nexport const IMPORT_MAPPINGS = {\n ioTsToEffect: {\n ioTsImport: \"import * as t from 'io-ts'\",\n effectImport: \"import { Schema as S } from '@effect/schema'\",\n pipeImport: \"import { pipe } from 'effect/Function'\",\n },\n};\n","import type { TransformError, TransformResult } from '@schemashift/core';\nimport type { SourceFile } from 'ts-morph';\nimport {\n IO_TS_TO_EFFECT_CODECS,\n IO_TS_TO_EFFECT_COMBINATORS,\n MANUAL_REVIEW_PATTERNS,\n} from './mappings.js';\n\n/**\n * io-ts → Effect Schema Transformer\n *\n * Converts io-ts codecs to Effect Schema definitions.\n * This is the successor path for io-ts users since fp-ts merged into Effect.\n *\n * io-ts: t.type({ name: t.string, age: t.number })\n * Effect Schema: S.Struct({ name: S.String, age: S.Number })\n */\nexport class IoTsToEffectTransformer {\n private errors: TransformError[] = [];\n private warnings: string[] = [];\n private needsPipe = false;\n\n transform(sourceFile: SourceFile): TransformResult {\n this.errors = [];\n this.warnings = [];\n this.needsPipe = false;\n\n const filePath = sourceFile.getFilePath();\n const originalCode = sourceFile.getFullText();\n\n try {\n let text = originalCode;\n\n // Step 1: Transform codecs and combinators\n text = this.transformCodecs(text, filePath);\n\n // Step 2: Transform type helpers\n text = this.transformTypeHelpers(text);\n\n // Step 3: Check for patterns requiring manual review\n this.checkManualReviewPatterns(text, filePath);\n\n // Step 4: Rewrite imports (last, so we know if pipe is needed)\n text = this.rewriteImports(text, filePath);\n\n sourceFile.replaceWithText(text);\n\n return {\n success: this.errors.length === 0,\n filePath,\n originalCode,\n transformedCode: sourceFile.getFullText(),\n errors: this.errors,\n warnings: this.warnings,\n };\n } catch (error) {\n this.errors.push({\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n return {\n success: false,\n filePath,\n originalCode,\n errors: this.errors,\n warnings: this.warnings,\n };\n }\n }\n\n private rewriteImports(text: string, filePath: string): string {\n // Replace io-ts import\n text = text.replace(\n /import\\s*\\*\\s*as\\s*t\\s*from\\s*['\"]io-ts['\"]/g,\n \"import { Schema as S } from '@effect/schema'\",\n );\n\n // Replace named io-ts imports\n text = text.replace(\n /import\\s*\\{[^}]+\\}\\s*from\\s*['\"]io-ts['\"]/g,\n \"import { Schema as S } from '@effect/schema'\",\n );\n\n // Replace io-ts type imports\n text = text.replace(\n /import\\s+type\\s*\\{[^}]*\\bTypeOf\\b[^}]*\\}\\s*from\\s*['\"]io-ts['\"]/g,\n \"import type { Schema } from '@effect/schema'\",\n );\n\n // Add pipe import if needed\n if (this.needsPipe && !text.includes(\"from 'effect/Function'\")) {\n text = text.replace(\n /import\\s*\\{[^}]*Schema[^}]*\\}\\s*from\\s*['\"]@effect\\/schema['\"]/,\n (match) => `${match}\\nimport { pipe } from 'effect/Function'`,\n );\n }\n\n // Handle fp-ts imports — warn about them\n if (/from\\s*['\"]fp-ts/.test(text)) {\n this.warnings.push(\n `${filePath}: fp-ts imports detected. Effect has built-in equivalents: ` +\n 'pipe from effect/Function, Either from effect/Either, Option from effect/Option.',\n );\n }\n\n // Replace fp-ts pipe import\n text = text.replace(\n /import\\s*\\{[^}]*\\bpipe\\b[^}]*\\}\\s*from\\s*['\"]fp-ts\\/function['\"]/g,\n \"import { pipe } from 'effect/Function'\",\n );\n\n return text;\n }\n\n private transformCodecs(text: string, filePath: string): string {\n // Transform simple codecs: t.string → S.String, etc.\n for (const [ioTsCodec, effectCodec] of Object.entries(IO_TS_TO_EFFECT_CODECS)) {\n if (text.includes(ioTsCodec)) {\n const pattern = new RegExp(this.escapeRegex(ioTsCodec), 'g');\n text = text.replace(pattern, effectCodec);\n if (effectCodec.includes('pipe(')) {\n this.needsPipe = true;\n }\n }\n }\n\n // Transform combinators: t.type → S.Struct, etc.\n for (const [ioTsCombinator, effectCombinator] of Object.entries(IO_TS_TO_EFFECT_COMBINATORS)) {\n if (text.includes(ioTsCombinator)) {\n const pattern = new RegExp(`${this.escapeRegex(ioTsCombinator)}\\\\(`, 'g');\n text = text.replace(pattern, `${effectCombinator}(`);\n }\n }\n\n // Transform t.partial({...}) → S.partial(S.Struct({...}))\n // Already handled by combinator mapping, but need to close the extra paren\n // t.partial({...}) becomes S.partial(S.Struct({...})) — need closing paren\n if (text.includes('S.partial(S.Struct(')) {\n text = this.fixPartialClosingParens(text);\n }\n\n // Transform t.union([A, B]) → S.Union(A, B) — Effect Schema uses spread, not array\n text = text.replace(/S\\.Union\\(\\[([^\\]]+)\\]\\)/g, 'S.Union($1)');\n\n // Transform t.intersection([A, B]) → pipe(A, S.extend(B))\n text = text.replace(/S\\.extend\\(\\[([^,\\]]+),\\s*([^\\]]+)\\]\\)/g, (_m, a: string, b: string) => {\n this.needsPipe = true;\n return `pipe(${a.trim()}, S.extend(${b.trim()}))`;\n });\n\n // Transform TypeOf: t.TypeOf<typeof schema> → S.Schema.Type<typeof schema>\n text = text.replace(/t\\.TypeOf<typeof\\s+(\\w+)>/g, 'S.Schema.Type<typeof $1>');\n\n // Transform OutputOf: t.OutputOf<typeof schema> → S.Schema.Type<typeof schema>\n text = text.replace(/t\\.OutputOf<typeof\\s+(\\w+)>/g, 'S.Schema.Type<typeof $1>');\n\n // Transform InputOf: t.InputOf<typeof schema> → S.Schema.Encoded<typeof schema>\n text = text.replace(/t\\.InputOf<typeof\\s+(\\w+)>/g, 'S.Schema.Encoded<typeof $1>');\n\n // Transform decode/encode patterns\n if (text.includes('.decode(')) {\n this.warnings.push(\n `${filePath}: io-ts .decode() should be converted to S.decodeUnknownSync() or S.decodeUnknownEither().`,\n );\n }\n\n if (text.includes('.encode(')) {\n this.warnings.push(\n `${filePath}: io-ts .encode() should be converted to S.encodeSync() or S.encodeEither().`,\n );\n }\n\n // Transform t.brand — Effect Schema uses S.brand()\n if (text.includes('t.brand(')) {\n this.warnings.push(\n `${filePath}: io-ts t.brand() should be converted to pipe(schema, S.brand(\"BrandName\")).`,\n );\n }\n\n // Transform isRight/isLeft patterns\n if (text.includes('isRight(') || text.includes('isLeft(')) {\n this.warnings.push(\n `${filePath}: fp-ts isRight/isLeft should use Effect's Either.isRight/Either.isLeft.`,\n );\n }\n\n // Warn about remaining t.* patterns\n if (/\\bt\\./.test(text)) {\n this.warnings.push(\n `${filePath}: Some io-ts patterns could not be auto-transformed to Effect Schema. ` +\n 'Look for remaining t.* references and convert manually.',\n );\n }\n\n return text;\n }\n\n private transformTypeHelpers(text: string): string {\n // Handle any remaining type references\n text = text.replace(/\\bt\\.Type\\b/g, 'S.Schema');\n text = text.replace(/\\bt\\.Mixed\\b/g, 'S.Schema<unknown>');\n\n return text;\n }\n\n private fixPartialClosingParens(text: string): string {\n // Find S.partial(S.Struct({...}) and add closing paren\n // This is a simplified approach — handles single-level objects\n let result = '';\n let i = 0;\n while (i < text.length) {\n const partialIdx = text.indexOf('S.partial(S.Struct(', i);\n if (partialIdx === -1) {\n result += text.slice(i);\n break;\n }\n\n result += text.slice(i, partialIdx);\n const startParen = partialIdx + 'S.partial(S.Struct('.length;\n\n // Find matching closing brace for the object literal\n let depth = 1; // counting from the opening { after S.Struct(\n let j = startParen;\n // Find the opening brace\n while (j < text.length && text[j] !== '{') j++;\n j++; // skip the {\n depth = 1;\n\n while (j < text.length && depth > 0) {\n if (text[j] === '{') depth++;\n if (text[j] === '}') depth--;\n j++;\n }\n\n // Now j points right after the closing }\n // We expect ) for S.Struct closing, then we need to add ) for S.partial closing\n if (j < text.length && text[j] === ')') {\n result += `S.partial(S.Struct(${text.slice(startParen, j + 1)})`;\n i = j + 1;\n } else {\n result += text.slice(partialIdx, j);\n i = j;\n }\n }\n return result;\n }\n\n private checkManualReviewPatterns(text: string, filePath: string): void {\n for (const pattern of MANUAL_REVIEW_PATTERNS) {\n if (text.includes(`.${pattern}(`) || text.includes(`t.${pattern}`)) {\n const guidance = this.getManualGuidance(pattern);\n this.warnings.push(\n `${filePath}: ${pattern} requires manual conversion to Effect Schema. ${guidance}`,\n );\n }\n }\n }\n\n private getManualGuidance(pattern: string): string {\n const guidance: Record<string, string> = {\n branded: 'Use pipe(schema, S.brand(\"Name\")) in Effect Schema.',\n withMessage: 'Use S.message() or S.annotations({ message: ... }) in Effect Schema.',\n withFallback: 'Handle fallbacks at the application level or use S.optional with default.',\n taggedUnion:\n 'Effect Schema uses S.Union with S.Struct variants (discriminated automatically).',\n recursion: 'Use S.suspend(() => schema) for recursive types in Effect Schema.',\n exact: 'Effect Schema structs are exact by default (no extra keys).',\n clean: 'Not needed in Effect Schema — structs strip unknown keys by default.',\n alias: 'Not applicable in Effect Schema — use TypeScript type aliases directly.',\n };\n return guidance[pattern] || 'See Effect Schema documentation for equivalent pattern.';\n }\n\n private escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n }\n}\n","import type { TransformHandler, TransformOptions, TransformResult } from '@schemashift/core';\nimport type { SourceFile } from 'ts-morph';\nimport { IoTsToEffectTransformer } from './io-ts-to-effect-transformer.js';\n\nexport function createIoTsToEffectHandler(): TransformHandler {\n return {\n transform(sourceFile: SourceFile, _options: TransformOptions): TransformResult {\n const transformer = new IoTsToEffectTransformer();\n return transformer.transform(sourceFile);\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,36 @@
1
+ import { TransformHandler } from '@schemashift/core';
2
+
3
+ declare function createIoTsToEffectHandler(): TransformHandler;
4
+
5
+ /**
6
+ * io-ts → Effect Schema type mappings
7
+ *
8
+ * io-ts uses fp-ts style codecs:
9
+ * io-ts: t.type({ name: t.string, age: t.number })
10
+ * Effect Schema: S.Struct({ name: S.String, age: S.Number })
11
+ *
12
+ * Key differences:
13
+ * - Effect Schema uses PascalCase for primitives (S.String, S.Number)
14
+ * - Effect Schema uses S.Struct instead of t.type for objects
15
+ * - Effect Schema uses S.Union instead of t.union
16
+ * - Effect Schema uses branded types via S.brand()
17
+ * - Effect Schema is pipe-based using Effect's pipe() utility
18
+ */
19
+ /** io-ts codec → Effect Schema equivalent */
20
+ declare const IO_TS_TO_EFFECT_CODECS: Record<string, string>;
21
+ /** io-ts combinators → Effect Schema combinators */
22
+ declare const IO_TS_TO_EFFECT_COMBINATORS: Record<string, string>;
23
+ /** fp-ts imports that need transformation */
24
+ declare const FP_TS_PATTERNS: string[];
25
+ /** Patterns requiring manual review */
26
+ declare const MANUAL_REVIEW_PATTERNS: string[];
27
+ /** Import mapping */
28
+ declare const IMPORT_MAPPINGS: {
29
+ ioTsToEffect: {
30
+ ioTsImport: string;
31
+ effectImport: string;
32
+ pipeImport: string;
33
+ };
34
+ };
35
+
36
+ export { FP_TS_PATTERNS, IMPORT_MAPPINGS, IO_TS_TO_EFFECT_CODECS, IO_TS_TO_EFFECT_COMBINATORS, MANUAL_REVIEW_PATTERNS, createIoTsToEffectHandler };
@@ -0,0 +1,36 @@
1
+ import { TransformHandler } from '@schemashift/core';
2
+
3
+ declare function createIoTsToEffectHandler(): TransformHandler;
4
+
5
+ /**
6
+ * io-ts → Effect Schema type mappings
7
+ *
8
+ * io-ts uses fp-ts style codecs:
9
+ * io-ts: t.type({ name: t.string, age: t.number })
10
+ * Effect Schema: S.Struct({ name: S.String, age: S.Number })
11
+ *
12
+ * Key differences:
13
+ * - Effect Schema uses PascalCase for primitives (S.String, S.Number)
14
+ * - Effect Schema uses S.Struct instead of t.type for objects
15
+ * - Effect Schema uses S.Union instead of t.union
16
+ * - Effect Schema uses branded types via S.brand()
17
+ * - Effect Schema is pipe-based using Effect's pipe() utility
18
+ */
19
+ /** io-ts codec → Effect Schema equivalent */
20
+ declare const IO_TS_TO_EFFECT_CODECS: Record<string, string>;
21
+ /** io-ts combinators → Effect Schema combinators */
22
+ declare const IO_TS_TO_EFFECT_COMBINATORS: Record<string, string>;
23
+ /** fp-ts imports that need transformation */
24
+ declare const FP_TS_PATTERNS: string[];
25
+ /** Patterns requiring manual review */
26
+ declare const MANUAL_REVIEW_PATTERNS: string[];
27
+ /** Import mapping */
28
+ declare const IMPORT_MAPPINGS: {
29
+ ioTsToEffect: {
30
+ ioTsImport: string;
31
+ effectImport: string;
32
+ pipeImport: string;
33
+ };
34
+ };
35
+
36
+ export { FP_TS_PATTERNS, IMPORT_MAPPINGS, IO_TS_TO_EFFECT_CODECS, IO_TS_TO_EFFECT_COMBINATORS, MANUAL_REVIEW_PATTERNS, createIoTsToEffectHandler };
package/dist/index.js ADDED
@@ -0,0 +1,267 @@
1
+ // src/mappings.ts
2
+ var IO_TS_TO_EFFECT_CODECS = {
3
+ "t.string": "S.String",
4
+ "t.number": "S.Number",
5
+ "t.boolean": "S.Boolean",
6
+ "t.bigint": "S.BigInt",
7
+ "t.unknown": "S.Unknown",
8
+ "t.never": "S.Never",
9
+ "t.null": "S.Null",
10
+ "t.undefined": "S.Undefined",
11
+ "t.void": "S.Void",
12
+ "t.any": "S.Unknown",
13
+ "t.Int": "pipe(S.Number, S.int())",
14
+ "t.literal": "S.Literal"
15
+ };
16
+ var IO_TS_TO_EFFECT_COMBINATORS = {
17
+ "t.type": "S.Struct",
18
+ "t.partial": "S.partial(S.Struct",
19
+ "t.array": "S.Array",
20
+ "t.record": "S.Record",
21
+ "t.union": "S.Union",
22
+ "t.intersection": "S.extend",
23
+ "t.tuple": "S.Tuple",
24
+ "t.readonly": "S.Struct",
25
+ // Effect Schema structs are readonly by default
26
+ "t.readonlyArray": "S.Array",
27
+ "t.exact": "S.Struct",
28
+ "t.strict": "S.Struct",
29
+ "t.keyof": "S.Literal"
30
+ };
31
+ var FP_TS_PATTERNS = [
32
+ "pipe",
33
+ "flow",
34
+ "Either",
35
+ "Option",
36
+ "TaskEither",
37
+ "fold",
38
+ "map",
39
+ "chain",
40
+ "getOrElse",
41
+ "isLeft",
42
+ "isRight"
43
+ ];
44
+ var MANUAL_REVIEW_PATTERNS = [
45
+ "branded",
46
+ "withMessage",
47
+ "withFallback",
48
+ "taggedUnion",
49
+ "recursion",
50
+ "exact",
51
+ "clean",
52
+ "alias"
53
+ ];
54
+ var IMPORT_MAPPINGS = {
55
+ ioTsToEffect: {
56
+ ioTsImport: "import * as t from 'io-ts'",
57
+ effectImport: "import { Schema as S } from '@effect/schema'",
58
+ pipeImport: "import { pipe } from 'effect/Function'"
59
+ }
60
+ };
61
+
62
+ // src/io-ts-to-effect-transformer.ts
63
+ var IoTsToEffectTransformer = class {
64
+ errors = [];
65
+ warnings = [];
66
+ needsPipe = false;
67
+ transform(sourceFile) {
68
+ this.errors = [];
69
+ this.warnings = [];
70
+ this.needsPipe = false;
71
+ const filePath = sourceFile.getFilePath();
72
+ const originalCode = sourceFile.getFullText();
73
+ try {
74
+ let text = originalCode;
75
+ text = this.transformCodecs(text, filePath);
76
+ text = this.transformTypeHelpers(text);
77
+ this.checkManualReviewPatterns(text, filePath);
78
+ text = this.rewriteImports(text, filePath);
79
+ sourceFile.replaceWithText(text);
80
+ return {
81
+ success: this.errors.length === 0,
82
+ filePath,
83
+ originalCode,
84
+ transformedCode: sourceFile.getFullText(),
85
+ errors: this.errors,
86
+ warnings: this.warnings
87
+ };
88
+ } catch (error) {
89
+ this.errors.push({
90
+ message: error instanceof Error ? error.message : "Unknown error"
91
+ });
92
+ return {
93
+ success: false,
94
+ filePath,
95
+ originalCode,
96
+ errors: this.errors,
97
+ warnings: this.warnings
98
+ };
99
+ }
100
+ }
101
+ rewriteImports(text, filePath) {
102
+ text = text.replace(
103
+ /import\s*\*\s*as\s*t\s*from\s*['"]io-ts['"]/g,
104
+ "import { Schema as S } from '@effect/schema'"
105
+ );
106
+ text = text.replace(
107
+ /import\s*\{[^}]+\}\s*from\s*['"]io-ts['"]/g,
108
+ "import { Schema as S } from '@effect/schema'"
109
+ );
110
+ text = text.replace(
111
+ /import\s+type\s*\{[^}]*\bTypeOf\b[^}]*\}\s*from\s*['"]io-ts['"]/g,
112
+ "import type { Schema } from '@effect/schema'"
113
+ );
114
+ if (this.needsPipe && !text.includes("from 'effect/Function'")) {
115
+ text = text.replace(
116
+ /import\s*\{[^}]*Schema[^}]*\}\s*from\s*['"]@effect\/schema['"]/,
117
+ (match) => `${match}
118
+ import { pipe } from 'effect/Function'`
119
+ );
120
+ }
121
+ if (/from\s*['"]fp-ts/.test(text)) {
122
+ this.warnings.push(
123
+ `${filePath}: fp-ts imports detected. Effect has built-in equivalents: pipe from effect/Function, Either from effect/Either, Option from effect/Option.`
124
+ );
125
+ }
126
+ text = text.replace(
127
+ /import\s*\{[^}]*\bpipe\b[^}]*\}\s*from\s*['"]fp-ts\/function['"]/g,
128
+ "import { pipe } from 'effect/Function'"
129
+ );
130
+ return text;
131
+ }
132
+ transformCodecs(text, filePath) {
133
+ for (const [ioTsCodec, effectCodec] of Object.entries(IO_TS_TO_EFFECT_CODECS)) {
134
+ if (text.includes(ioTsCodec)) {
135
+ const pattern = new RegExp(this.escapeRegex(ioTsCodec), "g");
136
+ text = text.replace(pattern, effectCodec);
137
+ if (effectCodec.includes("pipe(")) {
138
+ this.needsPipe = true;
139
+ }
140
+ }
141
+ }
142
+ for (const [ioTsCombinator, effectCombinator] of Object.entries(IO_TS_TO_EFFECT_COMBINATORS)) {
143
+ if (text.includes(ioTsCombinator)) {
144
+ const pattern = new RegExp(`${this.escapeRegex(ioTsCombinator)}\\(`, "g");
145
+ text = text.replace(pattern, `${effectCombinator}(`);
146
+ }
147
+ }
148
+ if (text.includes("S.partial(S.Struct(")) {
149
+ text = this.fixPartialClosingParens(text);
150
+ }
151
+ text = text.replace(/S\.Union\(\[([^\]]+)\]\)/g, "S.Union($1)");
152
+ text = text.replace(/S\.extend\(\[([^,\]]+),\s*([^\]]+)\]\)/g, (_m, a, b) => {
153
+ this.needsPipe = true;
154
+ return `pipe(${a.trim()}, S.extend(${b.trim()}))`;
155
+ });
156
+ text = text.replace(/t\.TypeOf<typeof\s+(\w+)>/g, "S.Schema.Type<typeof $1>");
157
+ text = text.replace(/t\.OutputOf<typeof\s+(\w+)>/g, "S.Schema.Type<typeof $1>");
158
+ text = text.replace(/t\.InputOf<typeof\s+(\w+)>/g, "S.Schema.Encoded<typeof $1>");
159
+ if (text.includes(".decode(")) {
160
+ this.warnings.push(
161
+ `${filePath}: io-ts .decode() should be converted to S.decodeUnknownSync() or S.decodeUnknownEither().`
162
+ );
163
+ }
164
+ if (text.includes(".encode(")) {
165
+ this.warnings.push(
166
+ `${filePath}: io-ts .encode() should be converted to S.encodeSync() or S.encodeEither().`
167
+ );
168
+ }
169
+ if (text.includes("t.brand(")) {
170
+ this.warnings.push(
171
+ `${filePath}: io-ts t.brand() should be converted to pipe(schema, S.brand("BrandName")).`
172
+ );
173
+ }
174
+ if (text.includes("isRight(") || text.includes("isLeft(")) {
175
+ this.warnings.push(
176
+ `${filePath}: fp-ts isRight/isLeft should use Effect's Either.isRight/Either.isLeft.`
177
+ );
178
+ }
179
+ if (/\bt\./.test(text)) {
180
+ this.warnings.push(
181
+ `${filePath}: Some io-ts patterns could not be auto-transformed to Effect Schema. Look for remaining t.* references and convert manually.`
182
+ );
183
+ }
184
+ return text;
185
+ }
186
+ transformTypeHelpers(text) {
187
+ text = text.replace(/\bt\.Type\b/g, "S.Schema");
188
+ text = text.replace(/\bt\.Mixed\b/g, "S.Schema<unknown>");
189
+ return text;
190
+ }
191
+ fixPartialClosingParens(text) {
192
+ let result = "";
193
+ let i = 0;
194
+ while (i < text.length) {
195
+ const partialIdx = text.indexOf("S.partial(S.Struct(", i);
196
+ if (partialIdx === -1) {
197
+ result += text.slice(i);
198
+ break;
199
+ }
200
+ result += text.slice(i, partialIdx);
201
+ const startParen = partialIdx + "S.partial(S.Struct(".length;
202
+ let depth = 1;
203
+ let j = startParen;
204
+ while (j < text.length && text[j] !== "{") j++;
205
+ j++;
206
+ depth = 1;
207
+ while (j < text.length && depth > 0) {
208
+ if (text[j] === "{") depth++;
209
+ if (text[j] === "}") depth--;
210
+ j++;
211
+ }
212
+ if (j < text.length && text[j] === ")") {
213
+ result += `S.partial(S.Struct(${text.slice(startParen, j + 1)})`;
214
+ i = j + 1;
215
+ } else {
216
+ result += text.slice(partialIdx, j);
217
+ i = j;
218
+ }
219
+ }
220
+ return result;
221
+ }
222
+ checkManualReviewPatterns(text, filePath) {
223
+ for (const pattern of MANUAL_REVIEW_PATTERNS) {
224
+ if (text.includes(`.${pattern}(`) || text.includes(`t.${pattern}`)) {
225
+ const guidance = this.getManualGuidance(pattern);
226
+ this.warnings.push(
227
+ `${filePath}: ${pattern} requires manual conversion to Effect Schema. ${guidance}`
228
+ );
229
+ }
230
+ }
231
+ }
232
+ getManualGuidance(pattern) {
233
+ const guidance = {
234
+ branded: 'Use pipe(schema, S.brand("Name")) in Effect Schema.',
235
+ withMessage: "Use S.message() or S.annotations({ message: ... }) in Effect Schema.",
236
+ withFallback: "Handle fallbacks at the application level or use S.optional with default.",
237
+ taggedUnion: "Effect Schema uses S.Union with S.Struct variants (discriminated automatically).",
238
+ recursion: "Use S.suspend(() => schema) for recursive types in Effect Schema.",
239
+ exact: "Effect Schema structs are exact by default (no extra keys).",
240
+ clean: "Not needed in Effect Schema \u2014 structs strip unknown keys by default.",
241
+ alias: "Not applicable in Effect Schema \u2014 use TypeScript type aliases directly."
242
+ };
243
+ return guidance[pattern] || "See Effect Schema documentation for equivalent pattern.";
244
+ }
245
+ escapeRegex(str) {
246
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
247
+ }
248
+ };
249
+
250
+ // src/io-ts-to-effect-handler.ts
251
+ function createIoTsToEffectHandler() {
252
+ return {
253
+ transform(sourceFile, _options) {
254
+ const transformer = new IoTsToEffectTransformer();
255
+ return transformer.transform(sourceFile);
256
+ }
257
+ };
258
+ }
259
+ export {
260
+ FP_TS_PATTERNS,
261
+ IMPORT_MAPPINGS,
262
+ IO_TS_TO_EFFECT_CODECS,
263
+ IO_TS_TO_EFFECT_COMBINATORS,
264
+ MANUAL_REVIEW_PATTERNS,
265
+ createIoTsToEffectHandler
266
+ };
267
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mappings.ts","../src/io-ts-to-effect-transformer.ts","../src/io-ts-to-effect-handler.ts"],"sourcesContent":["/**\n * io-ts → Effect Schema type mappings\n *\n * io-ts uses fp-ts style codecs:\n * io-ts: t.type({ name: t.string, age: t.number })\n * Effect Schema: S.Struct({ name: S.String, age: S.Number })\n *\n * Key differences:\n * - Effect Schema uses PascalCase for primitives (S.String, S.Number)\n * - Effect Schema uses S.Struct instead of t.type for objects\n * - Effect Schema uses S.Union instead of t.union\n * - Effect Schema uses branded types via S.brand()\n * - Effect Schema is pipe-based using Effect's pipe() utility\n */\n\n/** io-ts codec → Effect Schema equivalent */\nexport const IO_TS_TO_EFFECT_CODECS: Record<string, string> = {\n 't.string': 'S.String',\n 't.number': 'S.Number',\n 't.boolean': 'S.Boolean',\n 't.bigint': 'S.BigInt',\n 't.unknown': 'S.Unknown',\n 't.never': 'S.Never',\n 't.null': 'S.Null',\n 't.undefined': 'S.Undefined',\n 't.void': 'S.Void',\n 't.any': 'S.Unknown',\n 't.Int': 'pipe(S.Number, S.int())',\n 't.literal': 'S.Literal',\n};\n\n/** io-ts combinators → Effect Schema combinators */\nexport const IO_TS_TO_EFFECT_COMBINATORS: Record<string, string> = {\n 't.type': 'S.Struct',\n 't.partial': 'S.partial(S.Struct',\n 't.array': 'S.Array',\n 't.record': 'S.Record',\n 't.union': 'S.Union',\n 't.intersection': 'S.extend',\n 't.tuple': 'S.Tuple',\n 't.readonly': 'S.Struct', // Effect Schema structs are readonly by default\n 't.readonlyArray': 'S.Array',\n 't.exact': 'S.Struct',\n 't.strict': 'S.Struct',\n 't.keyof': 'S.Literal',\n};\n\n/** fp-ts imports that need transformation */\nexport const FP_TS_PATTERNS = [\n 'pipe',\n 'flow',\n 'Either',\n 'Option',\n 'TaskEither',\n 'fold',\n 'map',\n 'chain',\n 'getOrElse',\n 'isLeft',\n 'isRight',\n];\n\n/** Patterns requiring manual review */\nexport const MANUAL_REVIEW_PATTERNS = [\n 'branded',\n 'withMessage',\n 'withFallback',\n 'taggedUnion',\n 'recursion',\n 'exact',\n 'clean',\n 'alias',\n];\n\n/** Import mapping */\nexport const IMPORT_MAPPINGS = {\n ioTsToEffect: {\n ioTsImport: \"import * as t from 'io-ts'\",\n effectImport: \"import { Schema as S } from '@effect/schema'\",\n pipeImport: \"import { pipe } from 'effect/Function'\",\n },\n};\n","import type { TransformError, TransformResult } from '@schemashift/core';\nimport type { SourceFile } from 'ts-morph';\nimport {\n IO_TS_TO_EFFECT_CODECS,\n IO_TS_TO_EFFECT_COMBINATORS,\n MANUAL_REVIEW_PATTERNS,\n} from './mappings.js';\n\n/**\n * io-ts → Effect Schema Transformer\n *\n * Converts io-ts codecs to Effect Schema definitions.\n * This is the successor path for io-ts users since fp-ts merged into Effect.\n *\n * io-ts: t.type({ name: t.string, age: t.number })\n * Effect Schema: S.Struct({ name: S.String, age: S.Number })\n */\nexport class IoTsToEffectTransformer {\n private errors: TransformError[] = [];\n private warnings: string[] = [];\n private needsPipe = false;\n\n transform(sourceFile: SourceFile): TransformResult {\n this.errors = [];\n this.warnings = [];\n this.needsPipe = false;\n\n const filePath = sourceFile.getFilePath();\n const originalCode = sourceFile.getFullText();\n\n try {\n let text = originalCode;\n\n // Step 1: Transform codecs and combinators\n text = this.transformCodecs(text, filePath);\n\n // Step 2: Transform type helpers\n text = this.transformTypeHelpers(text);\n\n // Step 3: Check for patterns requiring manual review\n this.checkManualReviewPatterns(text, filePath);\n\n // Step 4: Rewrite imports (last, so we know if pipe is needed)\n text = this.rewriteImports(text, filePath);\n\n sourceFile.replaceWithText(text);\n\n return {\n success: this.errors.length === 0,\n filePath,\n originalCode,\n transformedCode: sourceFile.getFullText(),\n errors: this.errors,\n warnings: this.warnings,\n };\n } catch (error) {\n this.errors.push({\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n return {\n success: false,\n filePath,\n originalCode,\n errors: this.errors,\n warnings: this.warnings,\n };\n }\n }\n\n private rewriteImports(text: string, filePath: string): string {\n // Replace io-ts import\n text = text.replace(\n /import\\s*\\*\\s*as\\s*t\\s*from\\s*['\"]io-ts['\"]/g,\n \"import { Schema as S } from '@effect/schema'\",\n );\n\n // Replace named io-ts imports\n text = text.replace(\n /import\\s*\\{[^}]+\\}\\s*from\\s*['\"]io-ts['\"]/g,\n \"import { Schema as S } from '@effect/schema'\",\n );\n\n // Replace io-ts type imports\n text = text.replace(\n /import\\s+type\\s*\\{[^}]*\\bTypeOf\\b[^}]*\\}\\s*from\\s*['\"]io-ts['\"]/g,\n \"import type { Schema } from '@effect/schema'\",\n );\n\n // Add pipe import if needed\n if (this.needsPipe && !text.includes(\"from 'effect/Function'\")) {\n text = text.replace(\n /import\\s*\\{[^}]*Schema[^}]*\\}\\s*from\\s*['\"]@effect\\/schema['\"]/,\n (match) => `${match}\\nimport { pipe } from 'effect/Function'`,\n );\n }\n\n // Handle fp-ts imports — warn about them\n if (/from\\s*['\"]fp-ts/.test(text)) {\n this.warnings.push(\n `${filePath}: fp-ts imports detected. Effect has built-in equivalents: ` +\n 'pipe from effect/Function, Either from effect/Either, Option from effect/Option.',\n );\n }\n\n // Replace fp-ts pipe import\n text = text.replace(\n /import\\s*\\{[^}]*\\bpipe\\b[^}]*\\}\\s*from\\s*['\"]fp-ts\\/function['\"]/g,\n \"import { pipe } from 'effect/Function'\",\n );\n\n return text;\n }\n\n private transformCodecs(text: string, filePath: string): string {\n // Transform simple codecs: t.string → S.String, etc.\n for (const [ioTsCodec, effectCodec] of Object.entries(IO_TS_TO_EFFECT_CODECS)) {\n if (text.includes(ioTsCodec)) {\n const pattern = new RegExp(this.escapeRegex(ioTsCodec), 'g');\n text = text.replace(pattern, effectCodec);\n if (effectCodec.includes('pipe(')) {\n this.needsPipe = true;\n }\n }\n }\n\n // Transform combinators: t.type → S.Struct, etc.\n for (const [ioTsCombinator, effectCombinator] of Object.entries(IO_TS_TO_EFFECT_COMBINATORS)) {\n if (text.includes(ioTsCombinator)) {\n const pattern = new RegExp(`${this.escapeRegex(ioTsCombinator)}\\\\(`, 'g');\n text = text.replace(pattern, `${effectCombinator}(`);\n }\n }\n\n // Transform t.partial({...}) → S.partial(S.Struct({...}))\n // Already handled by combinator mapping, but need to close the extra paren\n // t.partial({...}) becomes S.partial(S.Struct({...})) — need closing paren\n if (text.includes('S.partial(S.Struct(')) {\n text = this.fixPartialClosingParens(text);\n }\n\n // Transform t.union([A, B]) → S.Union(A, B) — Effect Schema uses spread, not array\n text = text.replace(/S\\.Union\\(\\[([^\\]]+)\\]\\)/g, 'S.Union($1)');\n\n // Transform t.intersection([A, B]) → pipe(A, S.extend(B))\n text = text.replace(/S\\.extend\\(\\[([^,\\]]+),\\s*([^\\]]+)\\]\\)/g, (_m, a: string, b: string) => {\n this.needsPipe = true;\n return `pipe(${a.trim()}, S.extend(${b.trim()}))`;\n });\n\n // Transform TypeOf: t.TypeOf<typeof schema> → S.Schema.Type<typeof schema>\n text = text.replace(/t\\.TypeOf<typeof\\s+(\\w+)>/g, 'S.Schema.Type<typeof $1>');\n\n // Transform OutputOf: t.OutputOf<typeof schema> → S.Schema.Type<typeof schema>\n text = text.replace(/t\\.OutputOf<typeof\\s+(\\w+)>/g, 'S.Schema.Type<typeof $1>');\n\n // Transform InputOf: t.InputOf<typeof schema> → S.Schema.Encoded<typeof schema>\n text = text.replace(/t\\.InputOf<typeof\\s+(\\w+)>/g, 'S.Schema.Encoded<typeof $1>');\n\n // Transform decode/encode patterns\n if (text.includes('.decode(')) {\n this.warnings.push(\n `${filePath}: io-ts .decode() should be converted to S.decodeUnknownSync() or S.decodeUnknownEither().`,\n );\n }\n\n if (text.includes('.encode(')) {\n this.warnings.push(\n `${filePath}: io-ts .encode() should be converted to S.encodeSync() or S.encodeEither().`,\n );\n }\n\n // Transform t.brand — Effect Schema uses S.brand()\n if (text.includes('t.brand(')) {\n this.warnings.push(\n `${filePath}: io-ts t.brand() should be converted to pipe(schema, S.brand(\"BrandName\")).`,\n );\n }\n\n // Transform isRight/isLeft patterns\n if (text.includes('isRight(') || text.includes('isLeft(')) {\n this.warnings.push(\n `${filePath}: fp-ts isRight/isLeft should use Effect's Either.isRight/Either.isLeft.`,\n );\n }\n\n // Warn about remaining t.* patterns\n if (/\\bt\\./.test(text)) {\n this.warnings.push(\n `${filePath}: Some io-ts patterns could not be auto-transformed to Effect Schema. ` +\n 'Look for remaining t.* references and convert manually.',\n );\n }\n\n return text;\n }\n\n private transformTypeHelpers(text: string): string {\n // Handle any remaining type references\n text = text.replace(/\\bt\\.Type\\b/g, 'S.Schema');\n text = text.replace(/\\bt\\.Mixed\\b/g, 'S.Schema<unknown>');\n\n return text;\n }\n\n private fixPartialClosingParens(text: string): string {\n // Find S.partial(S.Struct({...}) and add closing paren\n // This is a simplified approach — handles single-level objects\n let result = '';\n let i = 0;\n while (i < text.length) {\n const partialIdx = text.indexOf('S.partial(S.Struct(', i);\n if (partialIdx === -1) {\n result += text.slice(i);\n break;\n }\n\n result += text.slice(i, partialIdx);\n const startParen = partialIdx + 'S.partial(S.Struct('.length;\n\n // Find matching closing brace for the object literal\n let depth = 1; // counting from the opening { after S.Struct(\n let j = startParen;\n // Find the opening brace\n while (j < text.length && text[j] !== '{') j++;\n j++; // skip the {\n depth = 1;\n\n while (j < text.length && depth > 0) {\n if (text[j] === '{') depth++;\n if (text[j] === '}') depth--;\n j++;\n }\n\n // Now j points right after the closing }\n // We expect ) for S.Struct closing, then we need to add ) for S.partial closing\n if (j < text.length && text[j] === ')') {\n result += `S.partial(S.Struct(${text.slice(startParen, j + 1)})`;\n i = j + 1;\n } else {\n result += text.slice(partialIdx, j);\n i = j;\n }\n }\n return result;\n }\n\n private checkManualReviewPatterns(text: string, filePath: string): void {\n for (const pattern of MANUAL_REVIEW_PATTERNS) {\n if (text.includes(`.${pattern}(`) || text.includes(`t.${pattern}`)) {\n const guidance = this.getManualGuidance(pattern);\n this.warnings.push(\n `${filePath}: ${pattern} requires manual conversion to Effect Schema. ${guidance}`,\n );\n }\n }\n }\n\n private getManualGuidance(pattern: string): string {\n const guidance: Record<string, string> = {\n branded: 'Use pipe(schema, S.brand(\"Name\")) in Effect Schema.',\n withMessage: 'Use S.message() or S.annotations({ message: ... }) in Effect Schema.',\n withFallback: 'Handle fallbacks at the application level or use S.optional with default.',\n taggedUnion:\n 'Effect Schema uses S.Union with S.Struct variants (discriminated automatically).',\n recursion: 'Use S.suspend(() => schema) for recursive types in Effect Schema.',\n exact: 'Effect Schema structs are exact by default (no extra keys).',\n clean: 'Not needed in Effect Schema — structs strip unknown keys by default.',\n alias: 'Not applicable in Effect Schema — use TypeScript type aliases directly.',\n };\n return guidance[pattern] || 'See Effect Schema documentation for equivalent pattern.';\n }\n\n private escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n }\n}\n","import type { TransformHandler, TransformOptions, TransformResult } from '@schemashift/core';\nimport type { SourceFile } from 'ts-morph';\nimport { IoTsToEffectTransformer } from './io-ts-to-effect-transformer.js';\n\nexport function createIoTsToEffectHandler(): TransformHandler {\n return {\n transform(sourceFile: SourceFile, _options: TransformOptions): TransformResult {\n const transformer = new IoTsToEffectTransformer();\n return transformer.transform(sourceFile);\n },\n };\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@schemashift/io-ts-effect",
3
+ "version": "0.10.0",
4
+ "description": "io-ts → Effect Schema transformer for SchemaShift",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "test": "vitest run",
27
+ "typecheck": "tsc --noEmit"
28
+ },
29
+ "keywords": [
30
+ "schemashift",
31
+ "io-ts",
32
+ "effect",
33
+ "schema",
34
+ "migration",
35
+ "codemod"
36
+ ],
37
+ "author": "Joseph May",
38
+ "license": "MIT",
39
+ "engines": {
40
+ "node": ">=22.0.0"
41
+ },
42
+ "dependencies": {
43
+ "@schemashift/core": "0.10.0",
44
+ "ts-morph": "27.0.2"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ }
49
+ }