codemod 1.0.0-rc.8 → 1.0.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 (2) hide show
  1. package/README.md +946 -0
  2. package/package.json +19 -10
package/README.md ADDED
@@ -0,0 +1,946 @@
1
+ # Codemod CLI
2
+
3
+ The Codemod CLI is a command-line interface for running and managing Butterflow workflows - a lightweight, self-hostable workflow engine designed for running large-scale code transformation jobs.
4
+
5
+ > **NOTE**: This CLI is currently in alpha and may change over time. So be careful when using it in production environments.
6
+ > For more information read the [blog post announcing the CLI](https://codemod.com/blog/new-codemod-cli).
7
+ > And any feedback is welcome!
8
+
9
+ ## Installation
10
+
11
+ ### Building from Source
12
+
13
+ ```bash
14
+ # Clone the repository
15
+ git clone https://github.com/codemod-com/codemod.git
16
+ cd codemod
17
+
18
+ # Build the project
19
+ cargo build --release
20
+
21
+ # The executable will be available at target/release/codemod
22
+ ```
23
+
24
+ ### From npm registry
25
+
26
+ ```bash
27
+ npm install -g codemod
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ 1. Create a workflow file `workflow.yaml`:
33
+
34
+ ```yaml
35
+ version: "1"
36
+ nodes:
37
+ - id: hello-world
38
+ name: Hello World
39
+ type: automatic
40
+ runtime:
41
+ type: direct
42
+ steps:
43
+ - id: hello
44
+ name: Say Hello
45
+ run: echo "Hello, World!"
46
+ ```
47
+
48
+ 2. Run the workflow:
49
+
50
+ ```bash
51
+ codemod run -w workflow.yaml
52
+ ```
53
+
54
+ ## Commands
55
+
56
+ ### `codemod init`
57
+
58
+ Initialize a new Butterflow workflow project with interactive setup:
59
+
60
+ ```bash
61
+ # Initialize a new project in current directory
62
+ codemod init
63
+
64
+ # Initialize a new project in a specific directory
65
+ codemod init my-project/
66
+
67
+ # Initialize with a specific name
68
+ codemod init --name my-workflow
69
+ ```
70
+
71
+ **Options:**
72
+ - `--name <NAME>`: Set the project name (defaults to directory name)
73
+ - `--force`: Overwrite existing files if they exist
74
+ - Positional argument: Target directory path (defaults to current directory)
75
+
76
+ **Interactive Setup:**
77
+
78
+ The init command will prompt you with several questions to customize your project:
79
+
80
+ 1. **Project Type Selection:**
81
+ ```
82
+ ? What type of workflow would you like to create?
83
+ ❯ AST-grep with JavaScript/TypeScript rules
84
+ AST-grep with YAML rules
85
+ Blank workflow (custom commands)
86
+ ```
87
+
88
+ 2. **Language Selection** (if AST-grep is chosen):
89
+ ```
90
+ ? Which language would you like to target?
91
+ ❯ JavaScript/TypeScript
92
+ Python
93
+ Rust
94
+ Go
95
+ Java
96
+ C/C++
97
+ Other
98
+ ```
99
+
100
+ 3. **Project Configuration:**
101
+ ```
102
+ ? Project name: my-codemod
103
+ ? Description: Converts legacy API calls to new format
104
+ ? Author: Your Name <your.email@example.com>
105
+ ```
106
+
107
+ **Generated Project Structure:**
108
+
109
+ Depending on your selections, the init command creates different project templates:
110
+
111
+ #### AST-grep JavaScript Project
112
+ ```
113
+ my-codemod/
114
+ ├── workflow.yaml # Main workflow definition
115
+ ├── package.json # Node.js dependencies
116
+ ├── rules/
117
+ │ └── example-rule.js # JavaScript AST transformation rules
118
+ ├── scripts/
119
+ │ └── apply-codemod.js # Script to apply transformations
120
+ ├── tests/
121
+ │ ├── input/ # Test input files
122
+ │ └── expected/ # Expected output files
123
+ └── README.md # Project documentation
124
+ ```
125
+
126
+ #### AST-grep YAML Project
127
+ ```
128
+ my-codemod/
129
+ ├── workflow.yaml # Main workflow definition
130
+ ├── rules/
131
+ │ └── example-rule.yml # YAML AST pattern rules
132
+ ├── scripts/
133
+ │ └── apply-rules.sh # Shell script to apply rules
134
+ ├── tests/
135
+ │ ├── input/ # Test input files
136
+ │ └── expected/ # Expected output files
137
+ └── README.md # Project documentation
138
+ ```
139
+
140
+ #### Blank Workflow Project
141
+ ```
142
+ my-workflow/
143
+ ├── workflow.yaml # Basic workflow template
144
+ ├── scripts/
145
+ │ └── example.sh # Example script
146
+ └── README.md # Project documentation
147
+ ```
148
+
149
+ **Example Usage:**
150
+
151
+ ```bash
152
+ # Create a new AST-grep JavaScript project
153
+ $ codemod init my-js-codemod
154
+ ? What type of workflow would you like to create? AST-grep with JavaScript/TypeScript rules
155
+ ? Which language would you like to target? JavaScript/TypeScript
156
+ ? Project name: my-js-codemod
157
+ ? Description: Migrate from React class components to hooks
158
+ ? Author: John Doe <john@example.com>
159
+
160
+ ✓ Created workflow.yaml
161
+ ✓ Created package.json with @ast-grep/cli dependency
162
+ ✓ Created rules/migrate-to-hooks.js
163
+ ✓ Created scripts/apply-codemod.js
164
+ ✓ Created test structure
165
+ ✓ Created README.md
166
+
167
+ Next steps:
168
+ cd my-js-codemod
169
+ npm install
170
+ codemod validate -w workflow.yaml
171
+ codemod run -w workflow.yaml
172
+ ```
173
+
174
+ ### `codemod run`
175
+
176
+ Execute a workflow from various sources:
177
+
178
+ ```bash
179
+ # Run from a specific workflow file
180
+ codemod run -w workflow.yaml
181
+ codemod run -w path/to/workflow.yaml
182
+
183
+ # Run from a workflow bundle directory (containing workflow.yaml)
184
+ codemod run ./my-workflow-bundle/
185
+
186
+ # Run from a registry (Conceptual)
187
+ # codemod run my-registry/react-19-codemods:latest
188
+ ```
189
+
190
+ **Options:**
191
+ - `-w, --workflow <FILE>`: Path to the workflow definition file
192
+ - Positional argument: Path to workflow file or bundle directory
193
+
194
+ ### `codemod resume`
195
+
196
+ Resume a paused workflow or trigger manual tasks:
197
+
198
+ ```bash
199
+ # Resume a workflow run by ID
200
+ codemod resume -i <workflow-run-id>
201
+
202
+ # Trigger a specific task by UUID
203
+ codemod resume -i <workflow-run-id> -t <task-uuid>
204
+
205
+ # Trigger all tasks currently awaiting manual triggers
206
+ codemod resume -i <workflow-run-id> --trigger-all
207
+ ```
208
+
209
+ **Options:**
210
+ - `-i, --id <UUID>`: Workflow run ID to resume
211
+ - `-t, --task <UUID>`: Specific task UUID to trigger
212
+ - `--trigger-all`: Trigger all tasks in `AwaitingTrigger` state
213
+
214
+ ### `codemod validate`
215
+
216
+ Validate a workflow definition without executing it:
217
+
218
+ ```bash
219
+ # Validate a workflow file
220
+ codemod validate -w workflow.yaml
221
+ codemod validate -w path/to/workflow.yaml
222
+
223
+ # Validate a workflow bundle
224
+ codemod validate ./my-workflow-bundle/
225
+ ```
226
+
227
+ **Validation Checks:**
228
+ - Schema validation
229
+ - Node ID uniqueness
230
+ - Step ID uniqueness within nodes
231
+ - Template ID uniqueness
232
+ - Dependency validation
233
+ - Cyclic dependency detection
234
+ - Template reference validation
235
+ - Matrix strategy validation
236
+ - State schema validation
237
+ - Variable reference syntax validation
238
+
239
+ **Example Output:**
240
+
241
+ Valid workflow:
242
+ ```bash
243
+ $ codemod validate -w valid-workflow.yaml
244
+ ✓ Workflow definition is valid
245
+ Schema validation: Passed
246
+ Node dependencies: Valid (3 nodes, 2 dependency relationships)
247
+ Template references: Valid (2 templates, 3 references)
248
+ Matrix strategies: Valid (1 matrix node)
249
+ State schema: Valid (2 schema definitions)
250
+ ```
251
+
252
+ Invalid workflow:
253
+ ```bash
254
+ $ codemod validate -w invalid-workflow.yaml
255
+ ✗ Workflow definition is invalid
256
+ Error at nodes[2].strategy: Matrix strategy requires 'values' or 'from_state' property
257
+ Error at nodes[1].depends_on[0]: Referenced node 'non-existent-node' does not exist
258
+ Error: Cyclic dependency detected: node-a → node-b → node-a
259
+ ```
260
+
261
+ ### `codemod login`
262
+
263
+ Authenticate with a Butterflow registry to publish and manage codemods:
264
+
265
+ ```bash
266
+ # Login to the default registry
267
+ codemod login
268
+
269
+ # Login to a specific registry
270
+ codemod login --registry https://registry.example.com
271
+
272
+ # Login with a token (for CI/CD)
273
+ codemod login --token <your-token>
274
+
275
+ # Login with username/password
276
+ codemod login --username <username>
277
+ ```
278
+
279
+ **Options:**
280
+ - `--registry <URL>`: Registry URL (defaults to official Butterflow registry)
281
+ - `--token <TOKEN>`: Authentication token (for non-interactive login)
282
+ - `--username <USERNAME>`: Username for interactive login
283
+ - `--scope <SCOPE>`: Organization or user scope for publishing
284
+
285
+ **Interactive Login:**
286
+
287
+ ```bash
288
+ $ codemod login
289
+ ? Registry URL: https://app.butterflow.com(default)
290
+ ? Username: john.doe
291
+ ? Password: ********
292
+ ? Organization (optional): my-org
293
+ ✓ Successfully logged in as john.doe
294
+ ✓ Default publish scope set to @my-org
295
+ ```
296
+
297
+ **Token-based Login (for CI/CD):**
298
+
299
+ ```bash
300
+ # Set authentication token
301
+ export BUTTERFLOW_TOKEN="your-registry-token"
302
+ codemod login --token $BUTTERFLOW_TOKEN
303
+ ```
304
+
305
+ ### `codemod publish`
306
+
307
+ Publish a codemod to a registry for sharing and reuse:
308
+
309
+ ```bash
310
+ # Publish current directory as a codemod
311
+ codemod publish
312
+
313
+ # Publish a specific codemod directory
314
+ codemod publish ./my-codemod/
315
+
316
+ # Publish with specific version
317
+ codemod publish --version 1.2.3
318
+
319
+ # Publish to specific registry
320
+ codemod publish --registry https://registry.example.com
321
+
322
+ # Dry run (validate without publishing)
323
+ codemod publish --dry-run
324
+ ```
325
+
326
+ **Options:**
327
+ - `--version <VERSION>`: Explicit version (overrides manifest version)
328
+ - `--registry <URL>`: Target registry URL
329
+ - `--tag <TAG>`: Tag for the release (e.g., `beta`, `latest`)
330
+ - `--access <LEVEL>`: Access level (`public` or `private`)
331
+ - `--dry-run`: Validate and pack without uploading
332
+ - `--force`: Override existing version (use with caution)
333
+
334
+ **Publishing Flow:**
335
+
336
+ ```bash
337
+ $ codemod publish
338
+ ✓ Validating codemod.yaml manifest
339
+ ✓ Validating workflow.yaml
340
+ ✓ Running tests (if present)
341
+ ✓ Building codemod bundle
342
+ ✓ Uploading to registry @my-org/react-hooks-migration@1.0.0
343
+ ✓ Published successfully!
344
+
345
+ Install with: codemod run @my-org/react-hooks-migration@1.0.0
346
+ ```
347
+
348
+ ## Codemod Manifest Standard
349
+
350
+ Published codemods must include a `codemod.yaml` manifest file that defines metadata, dependencies, and publishing information.
351
+
352
+ ### Manifest Schema
353
+
354
+ ```yaml
355
+ # codemod.yaml
356
+ name: react-hooks-migration
357
+ version: 1.0.0
358
+ description: Migrates React class components to functional components with hooks
359
+ author: John Doe <john@example.com>
360
+ license: MIT
361
+ repository: https://github.com/user/react-hooks-migration
362
+
363
+ registry:
364
+ access: public
365
+
366
+ targets:
367
+ languages:
368
+ - javascript
369
+ - typescript
370
+ frameworks:
371
+ - react
372
+ versions:
373
+ react: ">=16.8.0"
374
+ ```
375
+
376
+ ### Required Fields
377
+
378
+ | Field | Type | Description |
379
+ |-------|------|-------------|
380
+ | `name` | string | Codemod package name (must be unique in scope) |
381
+ | `version` | string | Semantic version (e.g., "1.0.0") |
382
+ | `description` | string | Brief description of what the codemod does |
383
+ | `author` | string | Author name and email |
384
+
385
+ ### Optional Fields
386
+
387
+ | Field | Type | Description |
388
+ |-------|------|-------------|
389
+ | `license` | string | License identifier (e.g., "MIT", "Apache-2.0") |
390
+ | `repository` | string | Repository URL for the codemod source code |
391
+ | `registry.access` | string | Access level: "public" or "private" |
392
+ | `targets.languages` | array | Supported programming languages |
393
+ | `targets.frameworks` | array | Supported frameworks or libraries |
394
+ | `targets.versions` | object | Version constraints for frameworks |
395
+
396
+ ### Publishing Examples
397
+
398
+ #### Basic Codemod
399
+
400
+ ```yaml
401
+ name: remove-console-logs
402
+ version: 1.0.0
403
+ description: Removes console.log statements from JavaScript/TypeScript files
404
+ author: Developer <dev@example.com>
405
+ license: MIT
406
+ repository: https://github.com/dev/remove-console-logs
407
+
408
+ targets:
409
+ languages: [javascript, typescript]
410
+ ```
411
+
412
+ #### Framework-Specific Codemod
413
+
414
+ ```yaml
415
+ name: api-migration-v2
416
+ version: 2.1.0
417
+ description: Migrates legacy API calls to new v2 endpoints
418
+ author: API Team <api-team@company.com>
419
+ license: Apache-2.0
420
+ repository: https://github.com/company/api-migration-v2
421
+
422
+ registry:
423
+ access: private
424
+
425
+ targets:
426
+ languages: [javascript, typescript]
427
+ frameworks: [react, vue, angular]
428
+ versions:
429
+ react: ">=16.0.0"
430
+ vue: ">=3.0.0"
431
+ ```
432
+
433
+ ## Workflow Sources
434
+
435
+ The CLI supports loading workflows from different sources:
436
+
437
+ ### File Path
438
+ ```bash
439
+ codemod run -w path/to/your/workflow.yaml
440
+ ```
441
+ Loads the specific file. The base path for execution is the directory containing this file.
442
+
443
+ ### Directory Path (Bundle)
444
+ ```bash
445
+ codemod run path/to/your/bundle/
446
+ ```
447
+ Butterflow looks for a standard workflow file (e.g., `workflow.yaml`) inside this directory. The base path for execution is this directory.
448
+
449
+ ### Registry Identifier
450
+ ```bash
451
+ # Install and run a published codemod
452
+ codemod run @my-org/react-hooks-migration@1.0.0
453
+
454
+ # Run latest version
455
+ codemod run @my-org/react-hooks-migration@latest
456
+
457
+ # Run with custom parameters
458
+ codemod run @my-org/api-migration-v2@2.1.0 --param api_base_url=https://staging-api.example.com
459
+ ```
460
+
461
+ When running from a registry, Butterflow:
462
+ 1. Downloads the codemod bundle from the registry
463
+ 2. Caches it locally for faster subsequent runs
464
+ 3. Validates the manifest and workflow
465
+ 4. Executes with the bundle directory as the base path
466
+
467
+ For your information the defautl registry is `https://app.codemod.com/`. and you can visualize codemods on the [Codemod Registry webapp](https://app.codemod.com/registry).
468
+
469
+ ## Workflow Bundles
470
+
471
+ A workflow bundle is a directory containing:
472
+ 1. The main workflow definition file (e.g., `workflow.yaml`)
473
+ 2. Any scripts, binaries, or configuration files referenced by the workflow steps
474
+ 3. Additional assets needed by the tasks
475
+
476
+ When running from a directory, Butterflow uses that directory as the root for resolving relative paths during execution.
477
+
478
+ ## Runtime Execution
479
+
480
+ ### Container Runtimes
481
+
482
+ The CLI supports multiple execution runtimes:
483
+
484
+ - **Docker**: Uses Docker daemon for container execution
485
+ - **Podman**: Uses Podman for container execution
486
+ - **Direct**: Runs commands directly on the host machine
487
+
488
+ When using `runtime: direct`, commands execute with the same working directory as the `codemod` CLI invocation. Use the `$CODEMOD_PATH` environment variable to access files within the workflow bundle.
489
+
490
+ ### Environment Variables
491
+
492
+ The CLI provides several environment variables to running tasks:
493
+
494
+ - `$STATE_OUTPUTS`: File descriptor for writing state updates
495
+ - `$CODEMOD_PATH`: Absolute path to the workflow bundle root (for `direct` runtime)
496
+ - `$BUTTERFLOW_STATE`: Path to state file for programmatic access
497
+
498
+ ## Manual Triggers and Resumption
499
+
500
+ ### Manual Nodes
501
+
502
+ Nodes with `type: manual` or `trigger: { type: manual }` will pause execution and await manual triggers:
503
+
504
+ ```yaml
505
+ nodes:
506
+ - id: deploy-prod
507
+ name: Deploy to Production
508
+ type: automatic
509
+ trigger:
510
+ type: manual # Requires manual approval
511
+ steps:
512
+ - id: deploy
513
+ run: ./deploy.sh production
514
+ ```
515
+
516
+ ### Triggering Manual Tasks
517
+
518
+ When a workflow pauses for manual triggers:
519
+
520
+ 1. The workflow state is persisted with tasks marked `AwaitingTrigger`
521
+ 2. The CLI provides task UUIDs for manual triggering
522
+ 3. Use `codemod resume` to trigger specific tasks or all awaiting tasks
523
+
524
+ ```bash
525
+ # Trigger specific deployment task
526
+ codemod resume -i abc123-workflow-run-id -t def456-task-uuid
527
+
528
+ # Trigger all awaiting tasks and continue
529
+ codemod resume -i abc123-workflow-run-id --trigger-all
530
+ ```
531
+
532
+ ## Error Handling
533
+
534
+ ### Automatic Validation
535
+
536
+ Validation is performed automatically when running workflows:
537
+
538
+ ```bash
539
+ $ codemod run -w invalid-workflow.yaml
540
+ ✗ Workflow definition is invalid
541
+ Error: Cyclic dependency detected: node-a → node-b → node-a
542
+ Workflow execution aborted
543
+ ```
544
+
545
+ ### Resume After Failures
546
+
547
+ If a workflow fails or is interrupted:
548
+
549
+ 1. The state is automatically persisted
550
+ 2. Use `codemod resume` to continue from the last checkpoint
551
+ 3. Failed tasks can be retried while preserving completed work
552
+
553
+ ## Examples
554
+
555
+ ### Basic Workflow Execution
556
+
557
+ ```bash
558
+ # Create and run a simple workflow
559
+ cat > hello.yaml << EOF
560
+ version: "1"
561
+ nodes:
562
+ - id: greet
563
+ name: Greeting
564
+ type: automatic
565
+ runtime:
566
+ type: direct
567
+ steps:
568
+ - id: hello
569
+ run: echo "Hello from Butterflow!"
570
+ EOF
571
+
572
+ codemod run -w hello.yaml
573
+ ```
574
+
575
+ ### Matrix Workflow with Manual Approval
576
+
577
+ ```bash
578
+ # Run matrix workflow requiring manual triggers
579
+ codemod run -w deploy-workflow.yaml
580
+
581
+ # When paused, trigger specific environments
582
+ codemod resume -i <run-id> -t <staging-task-uuid>
583
+ codemod resume -i <run-id> -t <prod-task-uuid>
584
+ ```
585
+
586
+ ### Workflow Validation and Publishing
587
+
588
+ ```bash
589
+ # Validate before running
590
+ codemod validate -w complex-workflow.yaml
591
+
592
+ # Run if validation passes
593
+ codemod run -w complex-workflow.yaml
594
+
595
+ # Login to registry and publish a codemod
596
+ codemod login
597
+ codemod publish ./my-codemod/
598
+
599
+ # Run published codemod
600
+ codemod run @my-org/my-codemod@1.0.0
601
+ ```
602
+
603
+ ### Publishing Workflow
604
+
605
+ ```bash
606
+ # Create and publish a new codemod
607
+ codemod init my-api-migration
608
+ cd my-api-migration
609
+
610
+ # Develop and test your codemod
611
+ # ... edit workflow.yaml, add rules, scripts, etc.
612
+
613
+ # Create manifest
614
+ cat > codemod.yaml << EOF
615
+ name: my-api-migration
616
+ version: 1.0.0
617
+ description: Migrates legacy API calls
618
+ author: Developer <dev@example.com>
619
+ workflow: workflow.yaml
620
+ targets:
621
+ languages: [javascript, typescript]
622
+ EOF
623
+
624
+ # Validate and publish
625
+ codemod validate
626
+ codemod publish --dry-run # Preview
627
+ codemod publish # Publish to registry
628
+ ```
629
+
630
+ ## Global Options
631
+
632
+ Most commands support these global options:
633
+
634
+ - `--help, -h`: Show help information
635
+ - `--version, -V`: Show version information
636
+ - `--verbose, -v`: Enable verbose output
637
+ - `--quiet, -q`: Suppress non-essential output
638
+
639
+ For detailed help on any command, use:
640
+
641
+ ```bash
642
+ codemod <command> --help
643
+ ```
644
+
645
+ ## JSSG (JavaScript AST-grep)
646
+
647
+ JSSG is a JavaScript/TypeScript codemod runner and testing framework inspired by [ast-grep](https://ast-grep.github.io/). It enables you to write codemods in JavaScript and apply them to codebases with powerful CLI and test automation support.
648
+
649
+ ### Running a Codemod
650
+
651
+ To run a JavaScript codemod on a target directory:
652
+
653
+ ```bash
654
+ codemod jssg run my-codemod.js ./src --language javascript
655
+ ```
656
+
657
+ **Options:**
658
+ - `--language <LANG>`: Target language (javascript, typescript, etc.)
659
+ - `--extensions <ext1,ext2>`: Comma-separated list of file extensions to process
660
+ - `--no-gitignore`: Do not respect .gitignore files
661
+ - `--include-hidden`: Include hidden files and directories
662
+ - `--max-threads <N>`: Maximum number of concurrent threads
663
+ - `--dry-run`: Perform a dry run without making changes
664
+
665
+ See `codemod jssg run --help` for all options.
666
+
667
+ ### Example
668
+
669
+ ```bash
670
+ codemod jssg run my-codemod.js ./src --language javascript --dry-run
671
+ ```
672
+
673
+ ---
674
+
675
+ # JSSG Testing Framework Usage Guide
676
+
677
+ ## Overview
678
+
679
+ The JSSG Testing Framework provides comprehensive testing capabilities for JavaScript codemods with before/after fixture files. It integrates with the existing ExecutionEngine and provides a familiar test runner interface.
680
+
681
+ ## Quick Start
682
+
683
+ ### 1. Basic Test Structure
684
+
685
+ Create a test directory with the following structure:
686
+
687
+ ```
688
+ tests/
689
+ ├── simple-transform/
690
+ │ ├── input.js
691
+ │ └── expected.js
692
+ ├── complex-case/
693
+ │ ├── input.ts
694
+ │ └── expected.ts
695
+ └── multi-file/
696
+ ├── input/
697
+ │ ├── file1.js
698
+ │ └── file2.js
699
+ └── expected/
700
+ ├── file1.js
701
+ └── file2.js
702
+ ```
703
+
704
+ ### 2. Running Tests
705
+
706
+ ```bash
707
+ # Basic test run
708
+ codemod jssg test my-codemod.js --language javascript
709
+
710
+ # With custom test directory
711
+ codemod jssg test my-codemod.js --language typescript --test-directory ./my-tests
712
+
713
+ # Update snapshots (create/update expected files)
714
+ codemod jssg test my-codemod.js --language javascript --update-snapshots
715
+
716
+ # Verbose output with detailed diffs
717
+ codemod jssg test my-codemod.js --language javascript --verbose
718
+
719
+ # Watch mode (re-run tests on file changes)
720
+ codemod jssg test my-codemod.js --language javascript --watch
721
+ ```
722
+
723
+ ## CLI Options
724
+
725
+ ### Required Arguments
726
+ - `codemod_file`: Path to the codemod JavaScript file
727
+ - `--language`: Target language (javascript, typescript, etc.)
728
+
729
+ ### Test Discovery
730
+ - `--test-directory`: Test directory (default: "tests")
731
+ - `--filter`: Run only tests matching pattern
732
+
733
+ ### Output Control
734
+ - `--reporter`: Output format (console, json, terse)
735
+ - `--verbose`: Show detailed output
736
+ - `--context-lines`: Number of diff context lines (default: 3)
737
+ - `--ignore-whitespace`: Ignore whitespace in comparisons
738
+
739
+ ### Test Execution
740
+ - `--timeout`: Test timeout in seconds (default: 30)
741
+ - `--max-threads`: Maximum concurrent threads
742
+ - `--sequential`: Run tests sequentially
743
+ - `--fail-fast`: Stop on first failure
744
+
745
+ ### Snapshot Management
746
+ - `--update-snapshots`: Create/update expected files
747
+ - `--expect-errors`: Comma-separated patterns for tests expected to fail
748
+
749
+ ### Development
750
+ - `--watch`: Watch for changes and re-run tests
751
+
752
+ ## Test File Formats
753
+
754
+ ### Single File Format
755
+ Each test case is a directory with `input.{ext}` and `expected.{ext}` files:
756
+
757
+ ```
758
+ test-case-name/
759
+ ├── input.js # Input code
760
+ └── expected.js # Expected output
761
+ ```
762
+
763
+ ### Multi-File Format
764
+ For testing multiple files, use `input/` and `expected/` directories:
765
+
766
+ ```
767
+ test-case-name/
768
+ ├── input/
769
+ │ ├── file1.js
770
+ │ └── file2.js
771
+ └── expected/
772
+ ├── file1.js
773
+ └── file2.js
774
+ ```
775
+
776
+ ## Language Support
777
+
778
+ The framework automatically detects input files based on language extensions:
779
+
780
+ - **JavaScript**: `.js`, `.jsx`, `.mjs`
781
+ - **TypeScript**: `.ts`, `.tsx`, `.mts`
782
+ - **Other languages**: Determined by `get_extensions_for_language()`
783
+
784
+ ## Error Handling
785
+
786
+ ### Missing Expected Files
787
+ ```bash
788
+ # Error: No expected file found
789
+ codemod jssg test my-codemod.js --language javascript
790
+ # Error: No expected file found for input.js in tests/my-test. Run with --update-snapshots to create it.
791
+
792
+ # Solution: Create expected files
793
+ codemod jssg test my-codemod.js --language javascript --update-snapshots
794
+ # Created expected file for my-test/input.js
795
+ ```
796
+
797
+ ### Ambiguous Input Files
798
+ ```bash
799
+ # Error: Multiple input files found
800
+ # tests/my-test/input.js and tests/my-test/input.ts both exist
801
+
802
+ # Solution: Use only one input file or organize into directories
803
+ ```
804
+
805
+ ### Expected Test Failures
806
+ ```bash
807
+ # Test cases that should fail
808
+ codemod jssg test my-codemod.js --language javascript --expect-errors "error-case,invalid-syntax"
809
+ ```
810
+
811
+ ## Output Formats
812
+
813
+ ### Console (Default)
814
+ ```
815
+ test my-test ... ok
816
+ test failing-test ... FAILED
817
+
818
+ failures:
819
+
820
+ ---- failing-test stdout ----
821
+ Output mismatch for file expected.js:
822
+ -const x = 1;
823
+ +const y = 1;
824
+
825
+ test result: FAILED. 1 passed; 1 failed; 0 ignored
826
+ ```
827
+
828
+ ### JSON
829
+ ```bash
830
+ codemod jssg test my-codemod.js --language javascript --reporter json
831
+ ```
832
+
833
+ ```json
834
+ {
835
+ "type": "suite",
836
+ "event": "started",
837
+ "test_count": 2
838
+ }
839
+ {
840
+ "type": "test",
841
+ "event": "started",
842
+ "name": "my-test"
843
+ }
844
+ {
845
+ "type": "test",
846
+ "name": "my-test",
847
+ "event": "ok"
848
+ }
849
+ ```
850
+
851
+ ### Terse
852
+ ```bash
853
+ codemod jssg test my-codemod.js --language javascript --reporter terse
854
+ ```
855
+
856
+ ```
857
+ ..F
858
+
859
+ failures:
860
+ ...
861
+ ```
862
+
863
+ ## Advanced Features
864
+
865
+ ### Snapshot Management
866
+ ```bash
867
+ # Create initial snapshots
868
+ codemod jssg test my-codemod.js --language javascript --update-snapshots
869
+
870
+ # Update specific test snapshots
871
+ codemod jssg test my-codemod.js --language javascript --filter "specific-test" --update-snapshots
872
+ ```
873
+
874
+ ### Test Filtering
875
+ ```bash
876
+ # Run tests matching pattern
877
+ codemod jssg test my-codemod.js --language javascript --filter "transform"
878
+
879
+ # Run specific test
880
+ codemod jssg test my-codemod.js --language javascript --filter "my-specific-test"
881
+ ```
882
+
883
+ ### Performance Tuning
884
+ ```bash
885
+ # Limit concurrent threads
886
+ codemod jssg test my-codemod.js --language javascript --max-threads 2
887
+
888
+ # Run sequentially for debugging
889
+ codemod jssg test my-codemod.js --language javascript --sequential
890
+
891
+ # Set custom timeout
892
+ codemod jssg test my-codemod.js --language javascript --timeout 60
893
+ ```
894
+
895
+ ### Diff Customization
896
+ ```bash
897
+ # More context in diffs
898
+ codemod jssg test my-codemod.js --language javascript --context-lines 5
899
+
900
+ # Ignore whitespace differences
901
+ codemod jssg test my-codemod.js --language javascript --ignore-whitespace
902
+ ```
903
+
904
+ ## Integration with Development Workflow
905
+
906
+ ### CI/CD Integration
907
+ ```yaml
908
+ # GitHub Actions example
909
+ - name: Run codemod tests
910
+ run: codemod jssg test my-codemod.js --language javascript --reporter json
911
+ ```
912
+
913
+ ### IDE Integration
914
+ The framework outputs standard test results that can be consumed by IDEs and test runners.
915
+
916
+ ### Watch Mode Development
917
+ ```bash
918
+ # Continuous testing during development
919
+ codemod jssg test my-codemod.js --language javascript --watch --verbose
920
+ ```
921
+
922
+ ## Best Practices
923
+
924
+ 1. **Organize tests by functionality**: Group related test cases in descriptive directories
925
+ 2. **Use meaningful test names**: Directory names become test names in output
926
+ 3. **Start with --update-snapshots**: Generate initial expected files, then review and commit
927
+ 4. **Use --expect-errors for negative tests**: Test error conditions explicitly
928
+ 5. **Leverage --filter during development**: Focus on specific tests while developing
929
+ 6. **Use --watch for rapid iteration**: Get immediate feedback on changes
930
+
931
+ ## Troubleshooting
932
+
933
+ ### Common Issues
934
+
935
+ 1. **No tests found**: Check test directory path and file extensions
936
+ 2. **Ambiguous input files**: Ensure only one input file per test case
937
+ 3. **Timeout errors**: Increase timeout for complex codemods
938
+ 4. **Memory issues**: Reduce max-threads for large test suites
939
+
940
+ ### Debug Mode
941
+ ```bash
942
+ # Verbose output for debugging
943
+ codemod jssg test my-codemod.js --language javascript --verbose --sequential
944
+ ```
945
+
946
+ This framework provides a robust foundation for testing JavaScript codemods with familiar tooling and comprehensive features.
package/package.json CHANGED
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "name": "codemod",
3
- "version": "1.0.0-rc.8",
3
+ "version": "1.0.0",
4
4
  "publishConfig": {
5
- "access": "public",
6
- "tag": "next"
5
+ "access": "public"
7
6
  },
8
7
  "description": "Codemod platform for semantic code transformations",
9
8
  "homepage": "https://codemod.com",
@@ -11,8 +10,18 @@
11
10
  "engines": {
12
11
  "node": ">= 16.0.0"
13
12
  },
14
- "keywords": ["codemod", "ast", "transformation", "refactoring", "migration"],
15
- "files": ["codemod", "postinstall.js"],
13
+ "keywords": [
14
+ "codemod",
15
+ "ast",
16
+ "transformation",
17
+ "refactoring",
18
+ "migration"
19
+ ],
20
+ "files": [
21
+ "codemod",
22
+ "postinstall.js",
23
+ "README.md"
24
+ ],
16
25
  "dependencies": {
17
26
  "detect-libc": "^2.0.3"
18
27
  },
@@ -20,11 +29,11 @@
20
29
  "postinstall": "node postinstall.js"
21
30
  },
22
31
  "optionalDependencies": {
23
- "@codemod.com/cli-darwin-arm64": "1.0.0-rc.8",
24
- "@codemod.com/cli-darwin-x64": "1.0.0-rc.8",
25
- "@codemod.com/cli-linux-arm64-gnu": "1.0.0-rc.8",
26
- "@codemod.com/cli-linux-x64-gnu": "1.0.0-rc.8",
27
- "@codemod.com/cli-win32-x64-msvc": "1.0.0-rc.8"
32
+ "@codemod.com/cli-darwin-arm64": "1.0.0",
33
+ "@codemod.com/cli-darwin-x64": "1.0.0",
34
+ "@codemod.com/cli-linux-arm64-gnu": "1.0.0",
35
+ "@codemod.com/cli-linux-x64-gnu": "1.0.0",
36
+ "@codemod.com/cli-win32-x64-msvc": "1.0.0"
28
37
  },
29
38
  "bin": {
30
39
  "codemod": "codemod"