nalloc 0.2.2 → 0.5.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.
Files changed (67) hide show
  1. package/README.md +326 -178
  2. package/build/codemod-cli.cjs +153 -0
  3. package/build/codemod-cli.cjs.map +1 -0
  4. package/build/codemod-cli.d.ts +2 -0
  5. package/build/codemod-cli.js +103 -0
  6. package/build/codemod-cli.js.map +1 -0
  7. package/build/codemod.cjs +652 -0
  8. package/build/codemod.cjs.map +1 -0
  9. package/build/codemod.d.ts +29 -0
  10. package/build/codemod.js +634 -0
  11. package/build/codemod.js.map +1 -0
  12. package/build/eslint.cjs +221 -0
  13. package/build/eslint.cjs.map +1 -0
  14. package/build/eslint.d.ts +36 -0
  15. package/build/eslint.js +198 -0
  16. package/build/eslint.js.map +1 -0
  17. package/build/http.cjs +31 -0
  18. package/build/http.cjs.map +1 -0
  19. package/build/http.d.ts +31 -0
  20. package/build/http.js +13 -0
  21. package/build/http.js.map +1 -0
  22. package/build/nonempty.cjs +35 -0
  23. package/build/nonempty.cjs.map +1 -0
  24. package/build/nonempty.d.ts +34 -0
  25. package/build/nonempty.js +14 -0
  26. package/build/nonempty.js.map +1 -0
  27. package/build/option.cjs +1 -1
  28. package/build/option.cjs.map +1 -1
  29. package/build/option.d.ts +2 -2
  30. package/build/option.js +1 -1
  31. package/build/option.js.map +1 -1
  32. package/build/result.cjs +10 -18
  33. package/build/result.cjs.map +1 -1
  34. package/build/result.d.ts +3 -34
  35. package/build/result.js +10 -15
  36. package/build/result.js.map +1 -1
  37. package/build/safe.cjs +8 -0
  38. package/build/safe.cjs.map +1 -1
  39. package/build/safe.d.ts +3 -0
  40. package/build/safe.js +2 -0
  41. package/build/safe.js.map +1 -1
  42. package/build/schema.cjs +32 -0
  43. package/build/schema.cjs.map +1 -0
  44. package/build/schema.d.ts +44 -0
  45. package/build/schema.js +14 -0
  46. package/build/schema.js.map +1 -0
  47. package/package.json +63 -10
  48. package/src/__tests__/codemod.ts +211 -0
  49. package/src/__tests__/eslint.ts +99 -0
  50. package/src/__tests__/fixtures/tsconfig.json +10 -0
  51. package/src/__tests__/http.ts +64 -0
  52. package/src/__tests__/iter.ts +18 -0
  53. package/src/__tests__/nonempty.ts +46 -0
  54. package/src/__tests__/nonempty.types.ts +38 -0
  55. package/src/__tests__/option.ts +4 -0
  56. package/src/__tests__/result.ts +104 -129
  57. package/src/__tests__/result.types.ts +2 -2
  58. package/src/__tests__/schema.ts +58 -0
  59. package/src/codemod-cli.ts +108 -0
  60. package/src/codemod.ts +623 -0
  61. package/src/eslint.ts +145 -0
  62. package/src/http.ts +42 -0
  63. package/src/nonempty.ts +48 -0
  64. package/src/option.ts +3 -4
  65. package/src/result.ts +18 -49
  66. package/src/safe.ts +3 -0
  67. package/src/schema.ts +52 -0
@@ -0,0 +1,652 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get migrateSource () {
13
+ return migrateSource;
14
+ },
15
+ get renderReport () {
16
+ return renderReport;
17
+ }
18
+ });
19
+ const _oxcparser = require("oxc-parser");
20
+ const INSTANCE_METHODS = new Map([
21
+ [
22
+ 'map',
23
+ {
24
+ fn: 'map',
25
+ ambiguous: true
26
+ }
27
+ ],
28
+ [
29
+ 'mapErr',
30
+ {
31
+ fn: 'mapErr'
32
+ }
33
+ ],
34
+ [
35
+ 'andThen',
36
+ {
37
+ fn: 'flatMap'
38
+ }
39
+ ],
40
+ [
41
+ 'orElse',
42
+ {
43
+ fn: 'orElse'
44
+ }
45
+ ],
46
+ [
47
+ 'match',
48
+ {
49
+ fn: 'match'
50
+ }
51
+ ],
52
+ [
53
+ 'unwrapOr',
54
+ {
55
+ fn: 'unwrapOr'
56
+ }
57
+ ],
58
+ [
59
+ 'isOk',
60
+ {
61
+ fn: 'isOk'
62
+ }
63
+ ],
64
+ [
65
+ 'isErr',
66
+ {
67
+ fn: 'isErr'
68
+ }
69
+ ],
70
+ [
71
+ 'andTee',
72
+ {
73
+ fn: 'tap'
74
+ }
75
+ ],
76
+ [
77
+ 'orTee',
78
+ {
79
+ fn: 'tapErr'
80
+ }
81
+ ],
82
+ [
83
+ '_unsafeUnwrap',
84
+ {
85
+ fn: 'unwrap'
86
+ }
87
+ ],
88
+ [
89
+ '_unsafeUnwrapErr',
90
+ {
91
+ fn: 'unwrapErr'
92
+ }
93
+ ]
94
+ ]);
95
+ const ASYNC_INSTANCE_METHODS = new Set([
96
+ 'asyncMap',
97
+ 'asyncAndThen',
98
+ 'asyncAndThrough'
99
+ ]);
100
+ const UNSUPPORTED_INSTANCE_METHODS = new Set([
101
+ 'andThrough',
102
+ 'safeUnwrap'
103
+ ]);
104
+ const ASYNC_IMPORTS = new Set([
105
+ 'ResultAsync',
106
+ 'okAsync',
107
+ 'errAsync',
108
+ 'fromSafePromise',
109
+ 'fromAsyncThrowable'
110
+ ]);
111
+ const STATIC_METHODS = new Map([
112
+ [
113
+ 'fromThrowable',
114
+ 'wrap'
115
+ ],
116
+ [
117
+ 'combine',
118
+ 'all'
119
+ ],
120
+ [
121
+ 'combineWithAllErrors',
122
+ 'collectAll'
123
+ ]
124
+ ]);
125
+ function isNode(value) {
126
+ return typeof value === 'object' && value !== null && typeof value.type === 'string';
127
+ }
128
+ function eachChild(node, visit) {
129
+ for (const key of Object.keys(node)){
130
+ const value = node[key];
131
+ if (Array.isArray(value)) {
132
+ for (const item of value){
133
+ if (isNode(item)) visit(item);
134
+ }
135
+ } else if (isNode(value)) {
136
+ visit(value);
137
+ }
138
+ }
139
+ }
140
+ function annotationTypeName(id) {
141
+ const annotation = id.typeAnnotation;
142
+ const ref = annotation?.typeAnnotation;
143
+ if (ref?.type !== 'TSTypeReference') return undefined;
144
+ const typeName = ref.typeName;
145
+ return typeName.type === 'Identifier' ? typeName.name : undefined;
146
+ }
147
+ function collectImports(program) {
148
+ const locals = new Map();
149
+ const declarations = [];
150
+ let hasNamespace = false;
151
+ for (const stmt of program.body){
152
+ if (stmt.type !== 'ImportDeclaration' || stmt.source.value !== 'neverthrow') continue;
153
+ declarations.push(stmt);
154
+ for (const spec of stmt.specifiers){
155
+ if (spec.type === 'ImportNamespaceSpecifier') {
156
+ hasNamespace = true;
157
+ } else if (spec.type === 'ImportSpecifier') {
158
+ const imported = spec.imported;
159
+ if (imported.type === 'Identifier') {
160
+ locals.set(spec.local.name, imported.name);
161
+ }
162
+ }
163
+ }
164
+ }
165
+ return {
166
+ locals,
167
+ declarations,
168
+ hasNamespace
169
+ };
170
+ }
171
+ class FileMigration {
172
+ file;
173
+ source;
174
+ imports;
175
+ edits = [];
176
+ skipped = [];
177
+ resultIds = new Set();
178
+ asyncIds = new Set();
179
+ wrappedFns = new Set();
180
+ resultFns = new Set();
181
+ conflicted = new Set();
182
+ residualNames = new Set();
183
+ converted = 0;
184
+ needsNamespace = false;
185
+ needsPipe = false;
186
+ needsResultType = false;
187
+ usedTypeNames = new Set();
188
+ constructor(file, source, imports){
189
+ this.file = file;
190
+ this.source = source;
191
+ this.imports = imports;
192
+ }
193
+ importedAs(local) {
194
+ return this.imports.locals.get(local);
195
+ }
196
+ isFromPromiseCall(node) {
197
+ return node.type === 'CallExpression' && node.callee.type === 'Identifier' && this.importedAs(node.callee.name) === 'fromPromise';
198
+ }
199
+ lineOf(offset) {
200
+ let line = 1;
201
+ for(let i = 0; i < offset; i++){
202
+ if (this.source.charCodeAt(i) === 10) line++;
203
+ }
204
+ return line;
205
+ }
206
+ report(reason, node) {
207
+ this.skipped.push({
208
+ file: this.file,
209
+ line: this.lineOf(node.start),
210
+ reason,
211
+ text: this.source.slice(node.start, Math.min(node.end, node.start + 120))
212
+ });
213
+ }
214
+ classify(node) {
215
+ if (node.type === 'Identifier') {
216
+ const name = node.name;
217
+ if (this.conflicted.has(name)) return undefined;
218
+ if (this.asyncIds.has(name)) return 'async';
219
+ if (this.resultIds.has(name)) return 'result';
220
+ return undefined;
221
+ }
222
+ if (node.type === 'AwaitExpression') {
223
+ if (this.isFromPromiseCall(node.argument)) return 'result';
224
+ return this.classify(node.argument) === 'async' ? 'async' : undefined;
225
+ }
226
+ if (node.type === 'CallExpression') {
227
+ const callee = node.callee;
228
+ if (callee.type === 'Identifier') {
229
+ const name = callee.name;
230
+ const imported = this.importedAs(name);
231
+ if (imported === 'ok' || imported === 'err' || imported === 'combine' || imported === 'combineWithAllErrors') return 'result';
232
+ if (imported !== undefined && (ASYNC_IMPORTS.has(imported) || imported === 'fromPromise')) return 'async';
233
+ if (this.wrappedFns.has(name) || this.resultFns.has(name)) return 'result';
234
+ return undefined;
235
+ }
236
+ if (callee.type === 'MemberExpression' && !callee.computed) {
237
+ const property = callee.property;
238
+ const object = callee.object;
239
+ if (property.type !== 'Identifier') return undefined;
240
+ const method = property.name;
241
+ if (object.type === 'Identifier') {
242
+ const objImported = this.importedAs(object.name);
243
+ if (objImported === 'Result' && STATIC_METHODS.has(method)) {
244
+ return method === 'fromThrowable' ? undefined : 'result';
245
+ }
246
+ if (objImported === 'ResultAsync') return 'async';
247
+ }
248
+ const receiver = this.classify(object);
249
+ if (receiver === 'async') return 'async';
250
+ if (receiver === 'result') {
251
+ if (ASYNC_INSTANCE_METHODS.has(method)) return 'async';
252
+ if (INSTANCE_METHODS.has(method)) return 'result';
253
+ }
254
+ return undefined;
255
+ }
256
+ }
257
+ return undefined;
258
+ }
259
+ classifyBinding(id, init) {
260
+ if (id.type !== 'Identifier') return;
261
+ const name = id.name;
262
+ const typeName = annotationTypeName(id);
263
+ const annotated = typeName !== undefined ? this.importedAs(typeName) : undefined;
264
+ const fromInit = (()=>{
265
+ if (init === null) return undefined;
266
+ if (init.type === 'CallExpression') {
267
+ const callee = init.callee;
268
+ const calleeImported = callee.type === 'Identifier' ? this.importedAs(callee.name) : undefined;
269
+ if (calleeImported === 'fromThrowable') return 'wrapped';
270
+ if (callee.type === 'MemberExpression') {
271
+ const object = callee.object;
272
+ const property = callee.property;
273
+ if (object.type === 'Identifier' && property.type === 'Identifier' && this.importedAs(object.name) === 'Result' && property.name === 'fromThrowable') {
274
+ return 'wrapped';
275
+ }
276
+ }
277
+ }
278
+ return this.classify(init);
279
+ })();
280
+ const kind = annotated === 'Result' || annotated === 'Ok' || annotated === 'Err' ? 'result' : annotated === 'ResultAsync' ? 'async' : fromInit;
281
+ if (kind === 'result') {
282
+ this.addClassified(name, this.resultIds);
283
+ } else if (kind === 'async') {
284
+ this.addClassified(name, this.asyncIds);
285
+ } else if (kind === 'wrapped') {
286
+ this.addClassified(name, this.wrappedFns);
287
+ } else {
288
+ if (this.resultIds.has(name) || this.asyncIds.has(name) || this.wrappedFns.has(name)) {
289
+ this.conflicted.add(name);
290
+ }
291
+ }
292
+ }
293
+ addClassified(name, target) {
294
+ if ((this.resultIds.has(name) || this.asyncIds.has(name) || this.wrappedFns.has(name)) && !target.has(name)) {
295
+ this.conflicted.add(name);
296
+ return;
297
+ }
298
+ target.add(name);
299
+ }
300
+ collectProvenance(node) {
301
+ if (node.type === 'VariableDeclarator') {
302
+ this.classifyBinding(node.id, node.init);
303
+ } else if (node.type === 'AssignmentExpression' && node.operator === '=') {
304
+ this.classifyBinding(node.left, node.right);
305
+ } else if (node.type === 'FunctionDeclaration' || node.type === 'TSDeclareFunction') {
306
+ const id = node.id;
307
+ const returnType = node.returnType;
308
+ if (id?.type === 'Identifier' && returnType !== null) {
309
+ const ref = returnType.typeAnnotation;
310
+ if (ref.type === 'TSTypeReference' && ref.typeName.type === 'Identifier') {
311
+ const imported = this.importedAs(ref.typeName.name);
312
+ if (imported === 'Result') this.resultFns.add(id.name);
313
+ }
314
+ }
315
+ for (const param of node.params){
316
+ this.classifyBinding(param, null);
317
+ }
318
+ } else if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {
319
+ for (const param of node.params){
320
+ this.classifyBinding(param, null);
321
+ }
322
+ }
323
+ eachChild(node, (child)=>this.collectProvenance(child));
324
+ }
325
+ takeEditsWithin(start, end) {
326
+ const inside = [];
327
+ for(let i = this.edits.length - 1; i >= 0; i--){
328
+ const edit = this.edits[i];
329
+ if (edit.start >= start && edit.end <= end) {
330
+ inside.push(edit);
331
+ this.edits.splice(i, 1);
332
+ }
333
+ }
334
+ return inside;
335
+ }
336
+ render(start, end) {
337
+ const inside = this.takeEditsWithin(start, end).sort((a, b)=>b.start - a.start);
338
+ let text = this.source.slice(start, end);
339
+ for (const edit of inside){
340
+ text = text.slice(0, edit.start - start) + edit.text + text.slice(edit.end - start);
341
+ }
342
+ return text;
343
+ }
344
+ renderArgs(args) {
345
+ if (args.length === 0) return '';
346
+ return this.render(args[0].start, args[args.length - 1].end);
347
+ }
348
+ convert(node, parent, grandparent) {
349
+ if (node.type === 'TSTypeReference') {
350
+ const typeName = node.typeName;
351
+ if (typeName.type === 'Identifier') {
352
+ const imported = this.importedAs(typeName.name);
353
+ if (imported === 'Result') {
354
+ this.edits.push({
355
+ start: typeName.start,
356
+ end: typeName.end,
357
+ text: 'ResultType'
358
+ });
359
+ this.needsResultType = true;
360
+ } else if (imported === 'Ok' || imported === 'Err') {
361
+ this.usedTypeNames.add(imported);
362
+ }
363
+ }
364
+ }
365
+ if (node.type === 'CallExpression') {
366
+ const consumedByOuterChain = parent?.type === 'MemberExpression' && parent.object === node && !parent.computed && parent.property.type === 'Identifier' && grandparent?.type === 'CallExpression' && grandparent.callee === parent && (INSTANCE_METHODS.has(parent.property.name) || ASYNC_INSTANCE_METHODS.has(parent.property.name) || UNSUPPORTED_INSTANCE_METHODS.has(parent.property.name));
367
+ if (!consumedByOuterChain && this.convertCall(node)) return;
368
+ }
369
+ eachChild(node, (child)=>this.convert(child, node, parent));
370
+ }
371
+ convertCall(node) {
372
+ const callee = node.callee;
373
+ if (callee.type === 'Identifier') {
374
+ const imported = this.importedAs(callee.name);
375
+ if (imported === undefined) return false;
376
+ if (imported === 'fromThrowable' || imported === 'combine' || imported === 'combineWithAllErrors') {
377
+ this.edits.push({
378
+ start: callee.start,
379
+ end: callee.end,
380
+ text: `Result.${STATIC_METHODS.get(imported)}`
381
+ });
382
+ this.needsNamespace = true;
383
+ this.converted++;
384
+ return false;
385
+ }
386
+ if (imported === 'safeTry') {
387
+ this.report('safe-try', node);
388
+ this.residualNames.add(callee.name);
389
+ return false;
390
+ }
391
+ if (ASYNC_IMPORTS.has(imported)) {
392
+ this.report('result-async', node);
393
+ this.residualNames.add(callee.name);
394
+ return false;
395
+ }
396
+ return false;
397
+ }
398
+ if (callee.type !== 'MemberExpression' || callee.computed || callee.property.type !== 'Identifier') {
399
+ return false;
400
+ }
401
+ const object = callee.object;
402
+ const method = callee.property.name;
403
+ if (object.type === 'Identifier') {
404
+ const objImported = this.importedAs(object.name);
405
+ if (objImported === 'Result' && STATIC_METHODS.has(method)) {
406
+ this.edits.push({
407
+ start: callee.start,
408
+ end: callee.end,
409
+ text: `Result.${STATIC_METHODS.get(method)}`
410
+ });
411
+ this.needsNamespace = true;
412
+ this.converted++;
413
+ return false;
414
+ }
415
+ if (objImported === 'ResultAsync') {
416
+ this.report('result-async', node);
417
+ this.residualNames.add(object.name);
418
+ return false;
419
+ }
420
+ }
421
+ if (!INSTANCE_METHODS.has(method) && !ASYNC_INSTANCE_METHODS.has(method) && !UNSUPPORTED_INSTANCE_METHODS.has(method)) {
422
+ return false;
423
+ }
424
+ const links = [];
425
+ let current = node;
426
+ let blocked;
427
+ while(true){
428
+ const currentCallee = current.callee;
429
+ const currentMethod = currentCallee.property.name;
430
+ if (ASYNC_INSTANCE_METHODS.has(currentMethod)) {
431
+ blocked = 'result-async';
432
+ break;
433
+ }
434
+ if (UNSUPPORTED_INSTANCE_METHODS.has(currentMethod)) {
435
+ blocked = 'unsupported';
436
+ break;
437
+ }
438
+ links.unshift({
439
+ call: current,
440
+ method: currentMethod
441
+ });
442
+ const receiver = currentCallee.object;
443
+ if (receiver.type === 'CallExpression' && receiver.callee.type === 'MemberExpression' && !receiver.callee.computed && receiver.callee.property.type === 'Identifier' && (INSTANCE_METHODS.has(receiver.callee.property.name) || ASYNC_INSTANCE_METHODS.has(receiver.callee.property.name) || UNSUPPORTED_INSTANCE_METHODS.has(receiver.callee.property.name))) {
444
+ current = receiver;
445
+ continue;
446
+ }
447
+ break;
448
+ }
449
+ if (blocked !== undefined) {
450
+ this.report(blocked, node);
451
+ const blockedCall = current;
452
+ eachChild(node, (child)=>{
453
+ if (child !== blockedCall) this.convert(child, node, undefined);
454
+ });
455
+ return true;
456
+ }
457
+ const base = links[0].call.callee.object;
458
+ const baseKind = this.classify(base);
459
+ if (baseKind === 'async') {
460
+ this.report('result-async', node);
461
+ return true;
462
+ }
463
+ const hasExclusive = links.some((link)=>!INSTANCE_METHODS.get(link.method).ambiguous);
464
+ if (baseKind !== 'result' && !hasExclusive) {
465
+ return false;
466
+ }
467
+ this.convert(base, undefined, undefined);
468
+ for (const link of links){
469
+ for (const arg of link.call.arguments){
470
+ this.convert(arg, link.call, undefined);
471
+ }
472
+ }
473
+ const baseText = this.render(base.start, base.end);
474
+ this.needsNamespace = true;
475
+ this.converted += links.length;
476
+ const replacement = (()=>{
477
+ if (links.length === 1) {
478
+ const { fn } = INSTANCE_METHODS.get(links[0].method);
479
+ const args = this.renderArgs(links[0].call.arguments);
480
+ return `Result.${fn}(${baseText}${args.length > 0 ? `, ${args}` : ''})`;
481
+ }
482
+ this.needsPipe = true;
483
+ const steps = links.map((link)=>{
484
+ const { fn } = INSTANCE_METHODS.get(link.method);
485
+ const args = this.renderArgs(link.call.arguments);
486
+ return `($r) => Result.${fn}($r${args.length > 0 ? `, ${args}` : ''})`;
487
+ });
488
+ return `pipe(${baseText}, ${steps.join(', ')})`;
489
+ })();
490
+ this.edits.push({
491
+ start: node.start,
492
+ end: node.end,
493
+ text: replacement
494
+ });
495
+ return true;
496
+ }
497
+ awaitedFromPromise = new Set();
498
+ convertAwaitedFromPromise(node) {
499
+ if (node.type === 'AwaitExpression' && this.isFromPromiseCall(node.argument)) {
500
+ const call = node.argument;
501
+ this.edits.push({
502
+ start: call.callee.start,
503
+ end: call.callee.end,
504
+ text: 'Result.fromPromise'
505
+ });
506
+ this.awaitedFromPromise.add(call);
507
+ this.needsNamespace = true;
508
+ this.converted++;
509
+ }
510
+ eachChild(node, (child)=>this.convertAwaitedFromPromise(child));
511
+ }
512
+ reportUnconvertedFromPromise(node) {
513
+ if (this.isFromPromiseCall(node) && !this.awaitedFromPromise.has(node)) {
514
+ this.report('result-async', node);
515
+ this.residualNames.add(node.callee.name);
516
+ }
517
+ eachChild(node, (child)=>this.reportUnconvertedFromPromise(child));
518
+ }
519
+ rewriteImports() {
520
+ const valueNames = [];
521
+ const typeNames = [];
522
+ for (const [local, imported] of this.imports.locals){
523
+ if (imported === 'ok' || imported === 'err') {
524
+ valueNames.push(imported === local ? imported : `${imported} as ${local}`);
525
+ }
526
+ }
527
+ if (this.needsNamespace) valueNames.push('Result');
528
+ if (this.needsPipe) valueNames.push('pipe');
529
+ if (this.needsResultType) typeNames.push('type ResultType');
530
+ for (const name of this.usedTypeNames)typeNames.push(`type ${name}`);
531
+ const statements = [];
532
+ const names = [
533
+ ...valueNames,
534
+ ...typeNames
535
+ ];
536
+ if (names.length > 0) {
537
+ statements.push(`import { ${names.join(', ')} } from 'nalloc';`);
538
+ }
539
+ const residual = [
540
+ ...this.residualNames
541
+ ].map((local)=>{
542
+ const imported = this.importedAs(local);
543
+ return imported === local ? imported : `${imported} as ${local}`;
544
+ });
545
+ if (residual.length > 0) {
546
+ statements.push(`import { ${residual.join(', ')} } from 'neverthrow';`);
547
+ }
548
+ const [first, ...rest] = this.imports.declarations;
549
+ this.edits.push({
550
+ start: first.start,
551
+ end: first.end,
552
+ text: statements.join('\n')
553
+ });
554
+ for (const decl of rest){
555
+ const end = this.source.charCodeAt(decl.end) === 10 ? decl.end + 1 : decl.end;
556
+ this.edits.push({
557
+ start: decl.start,
558
+ end,
559
+ text: ''
560
+ });
561
+ }
562
+ }
563
+ apply() {
564
+ const sorted = [
565
+ ...this.edits
566
+ ].sort((a, b)=>b.start - a.start);
567
+ let output = this.source;
568
+ for (const edit of sorted){
569
+ output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
570
+ }
571
+ return output;
572
+ }
573
+ }
574
+ function migrateSource(source, file) {
575
+ const parsed = (0, _oxcparser.parseSync)(file, source);
576
+ if (parsed.errors.some((e)=>e.severity === 'Error')) {
577
+ return {
578
+ output: source,
579
+ changed: false,
580
+ converted: 0,
581
+ skipped: [
582
+ {
583
+ file,
584
+ line: 1,
585
+ reason: 'unsupported',
586
+ text: 'file has parse errors'
587
+ }
588
+ ]
589
+ };
590
+ }
591
+ const program = parsed.program;
592
+ const imports = collectImports(program);
593
+ if (imports.declarations.length === 0) {
594
+ return {
595
+ output: source,
596
+ changed: false,
597
+ converted: 0,
598
+ skipped: []
599
+ };
600
+ }
601
+ const migration = new FileMigration(file, source, imports);
602
+ if (imports.hasNamespace) {
603
+ migration.report('namespace-import', imports.declarations[0]);
604
+ return {
605
+ output: source,
606
+ changed: false,
607
+ converted: 0,
608
+ skipped: migration.skipped
609
+ };
610
+ }
611
+ migration.collectProvenance(program);
612
+ migration.convertAwaitedFromPromise(program);
613
+ migration.convert(program, undefined, undefined);
614
+ migration.reportUnconvertedFromPromise(program);
615
+ migration.rewriteImports();
616
+ const output = migration.apply();
617
+ return {
618
+ output,
619
+ changed: output !== source,
620
+ converted: migration.converted,
621
+ skipped: migration.skipped
622
+ };
623
+ }
624
+ function renderReport(report) {
625
+ const lines = [
626
+ '# nalloc migration report',
627
+ '',
628
+ `Files changed: ${report.filesChanged}. Sites converted: ${report.converted}. Sites needing manual review: ${report.skipped.length}.`,
629
+ ''
630
+ ];
631
+ const byFile = new Map();
632
+ for (const site of report.skipped){
633
+ const sites = byFile.get(site.file);
634
+ if (sites === undefined) {
635
+ byFile.set(site.file, [
636
+ site
637
+ ]);
638
+ } else {
639
+ sites.push(site);
640
+ }
641
+ }
642
+ for (const [file, sites] of byFile){
643
+ lines.push(`## ${file}`, '');
644
+ for (const site of sites){
645
+ lines.push(`- line ${site.line} [${site.reason}]: \`${site.text}\``);
646
+ }
647
+ lines.push('');
648
+ }
649
+ return lines.join('\n');
650
+ }
651
+
652
+ //# sourceMappingURL=codemod.cjs.map