diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7bc0fd50..601ea412 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,54 +23,9 @@ jobs: run: pnpm install - name: Build the CJS files run: pnpm build - - name: Fetch top commit from website repository + - name: Add new READMEs to website run: | - git remote add website https://github.com/intuita-inc/website.git - git fetch website master - - name: Push commit to master in website repository - run: | - git config --local user.email "intuita@intuita.io" - git config --local user.name "Intuita Team" - git fetch origin main - # Get the list of changed files between the current commit and origin/main - changed_files=$(git diff --name-only origin/main) - - # Filter for README files in the 'codemods' directory - readme_files=$(echo "$changed_files" | grep '^codemods/.*README\.md$' || true) - - if [ -z "$readme_files" ]; then - echo "No README.md file in 'codemods' directory changed." - exit 0 - fi - - # Prepare to store parsed README contents and paths - declare -A parsed_readmes - pnpm --filter @codemod-registry/readme-parser build - - # Iterate over the filtered README files - while IFS= read -r path_to_readme; do - generated_slug=$(echo "$path_to_readme" | sed 's/^[^/]*\///' | sed 's/\/README\.md$//' | tr '/' '-') - website_file_path="cms/automations/$generated_slug.md" - - # Parse the README and store the output with its path - parsed_readme=$("$PWD"/readme-parser/dist/index.js "$path_to_readme") - parsed_readmes["$website_file_path"]="$parsed_readme" - done <<< "$readme_files" - - # Checkout a new branch from the website master - git checkout -b update-codemods website/master - - # Iterate over parsed_readmes and create files - for website_file_path in "${!parsed_readmes[@]}"; do - echo "${parsed_readmes[$website_file_path]}" - echo $(git status) - echo "${parsed_readmes[$website_file_path]}" > "$website_file_path" - git add "$website_file_path" - git commit -m "$website_file_path" - echo $(ls "$website_file_path" -la) - done - - git push website HEAD:master + "$PWD"/readme-parser/dist/sync.js - name: Upload to S3 uses: jakejarvis/s3-sync-action@master with: diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0fe90e7b..a9bed5b1 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -17,24 +17,24 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the + overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery, and sexual attention or + advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email + address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Enforcement Responsibilities @@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an +standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within diff --git a/SECURITY.md b/SECURITY.md index 673256d5..1b66d84d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -12,4 +12,4 @@ The Intuita team may send a response indicating the next steps in handling your | Version | Supported | | ------- | ------------------ | -| >=1.0.0 | :white_check_mark: | +| >=1.0.0 | :white_check_mark: | diff --git a/codemods/bull/bullmq/README.md b/codemods/bull/bullmq/README.md index 83777a54..17693e2b 100644 --- a/codemods/bull/bullmq/README.md +++ b/codemods/bull/bullmq/README.md @@ -111,7 +111,7 @@ const worker = new Worker("unknown-name", async function (job) { ## Applicability Criteria -`bull` >= 1.0.0 +`bullmq` >= 1.0.0 ## Other Metadata @@ -129,8 +129,7 @@ v1.0.0 ### Estimated Time Saving -Up to 5 minutes per queue with one single job. -Another 5 minutes for changing the job startup in bullmq. +~10 minutes per occurence ### Owner diff --git a/codemods/msw/2/imports/README.md b/codemods/msw/2/imports/README.md index a85e7ea6..3ecb3c27 100644 --- a/codemods/msw/2/imports/README.md +++ b/codemods/msw/2/imports/README.md @@ -2,7 +2,7 @@ ## Description -Following the original msw [upgrade guide](https://mswjs.io/docs/migrations/1.x-to-2.x/#imports), there are certain imports that changed their location and/or naming. This codemod will import correct objects from appropriate paths to start your msw migration path. +Following the original msw [upgrade guide](https://mswjs.io/docs/migrations/1.x-to-2.x/#imports), there are certain imports that changed their location and/or naming. This codemod will adjust your imports to the new location and naming. - `setupWorker` is now imported from `msw/browser` - `rest` from `msw` is now named `http` @@ -55,7 +55,7 @@ v1.0.0 ### Estimated Time Saving -Up to 10 minutes per occurrence +~10 minutes per occurrence ### Owner diff --git a/codemods/msw/2/type-args/README.md b/codemods/msw/2/type-args/README.md index f2c41a8a..d9820ce0 100644 --- a/codemods/msw/2/type-args/README.md +++ b/codemods/msw/2/type-args/README.md @@ -2,7 +2,7 @@ ## Description -There is a change to generic type interface of rest.method() calls. This codemod puts the generic arguments in the correct order to keep type safety. +There is a change to generic type interface of `rest.method()` calls. This codemod puts the generic arguments in the correct order to keep type safety. ### WARNING @@ -112,7 +112,7 @@ v1.0.0 ### Estimated Time Saving -Up to 15 minutes per occurrence +~15 minutes per occurrence ### Owner diff --git a/codemods/pull_request_template.md b/codemods/pull_request_template.md index d9ea20a4..ebf4ecd2 100644 --- a/codemods/pull_request_template.md +++ b/codemods/pull_request_template.md @@ -55,17 +55,17 @@ Insert codemod version [e.g. v1.0.0] Can be: -- **Assistive**: The automation partially completes changes. Human involvement is needed to make changes ready to be pushed and merged. -- **Autonomous**: Changes can safely be pushed and merged without further human involvement. +- **Assistive**: The automation partially completes changes. Human involvement is needed to make changes ready to be pushed and merged. +- **Autonomous**: Changes can safely be pushed and merged without further human involvement. ### **Codemod Engine** Can be: -- [jscodeshift](https://github.com/facebook/jscodeshift) -- [ts-morph](https://github.com/dsherret/ts-morph) -- [filemod](https://github.com/intuita-inc/filemod/) -- [Uber Piranha](https://github.com/uber/piranha) +- [jscodeshift](https://github.com/facebook/jscodeshift) +- [ts-morph](https://github.com/dsherret/ts-morph) +- [filemod](https://github.com/intuita-inc/filemod/) +- [Uber Piranha](https://github.com/uber/piranha) ### Estimated Time Saving diff --git a/package.json b/package.json index d291c385..b7fa1179 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "author": "Intuita", "packageManager": "pnpm@8.9.0", "scripts": { - "build": "turbo run build:cjs && pnpm --filter @codemod-registry/builder build", + "build": "turbo run build:cjs && pnpm --filter @codemod-registry/builder build && pnpm --filter @codemod-registry/readme-parser build", "build:homedir": "turbo run build:cjs && pnpm --filter @codemod-registry/builder build:homedir", "build:cjs": "turbo run build:cjs --no-daemon", "create": "turbo run create", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 07a50930..0590d44b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4176,9 +4176,15 @@ importers: readme-parser: dependencies: + js-yaml: + specifier: 4.1.0 + version: 4.1.0 mdast-util-from-markdown: specifier: 2.0.0 version: 2.0.0 + simple-git: + specifier: ^3.21.0 + version: 3.21.0 valibot: specifier: ^0.24.1 version: 0.24.1 @@ -4186,6 +4192,9 @@ importers: '@codemod-registry/tsconfig': specifier: workspace:* version: link:../tsconfig + '@types/js-yaml': + specifier: 4.0.9 + version: 4.0.9 '@types/mdast': specifier: 4.0.3 version: 4.0.3 @@ -4195,6 +4204,9 @@ importers: esbuild: specifier: ^0.19.7 version: 0.19.7 + tsx: + specifier: ^4.7.0 + version: 4.7.0 typescript: specifier: 5.3.3 version: 5.3.3 @@ -5515,6 +5527,24 @@ packages: fast-check: 3.14.0 dev: false + /@esbuild/aix-ppc64@0.19.10: + resolution: {integrity: sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.10: + resolution: {integrity: sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.19.5: resolution: {integrity: sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==} engines: {node: '>=12'} @@ -5533,6 +5563,15 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.19.10: + resolution: {integrity: sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.19.5: resolution: {integrity: sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==} engines: {node: '>=12'} @@ -5551,6 +5590,15 @@ packages: dev: true optional: true + /@esbuild/android-x64@0.19.10: + resolution: {integrity: sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.19.5: resolution: {integrity: sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==} engines: {node: '>=12'} @@ -5569,6 +5617,15 @@ packages: dev: true optional: true + /@esbuild/darwin-arm64@0.19.10: + resolution: {integrity: sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.19.5: resolution: {integrity: sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==} engines: {node: '>=12'} @@ -5587,6 +5644,15 @@ packages: dev: true optional: true + /@esbuild/darwin-x64@0.19.10: + resolution: {integrity: sha512-alfGtT+IEICKtNE54hbvPg13xGBe4GkVxyGWtzr+yHO7HIiRJppPDhOKq3zstTcVf8msXb/t4eavW3jCDpMSmA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.19.5: resolution: {integrity: sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==} engines: {node: '>=12'} @@ -5605,6 +5671,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-arm64@0.19.10: + resolution: {integrity: sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.19.5: resolution: {integrity: sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==} engines: {node: '>=12'} @@ -5623,6 +5698,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-x64@0.19.10: + resolution: {integrity: sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.19.5: resolution: {integrity: sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==} engines: {node: '>=12'} @@ -5641,6 +5725,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm64@0.19.10: + resolution: {integrity: sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.19.5: resolution: {integrity: sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==} engines: {node: '>=12'} @@ -5659,6 +5752,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm@0.19.10: + resolution: {integrity: sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.19.5: resolution: {integrity: sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==} engines: {node: '>=12'} @@ -5677,6 +5779,15 @@ packages: dev: true optional: true + /@esbuild/linux-ia32@0.19.10: + resolution: {integrity: sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.19.5: resolution: {integrity: sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==} engines: {node: '>=12'} @@ -5695,6 +5806,15 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.19.10: + resolution: {integrity: sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.19.5: resolution: {integrity: sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==} engines: {node: '>=12'} @@ -5713,6 +5833,15 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.19.10: + resolution: {integrity: sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.19.5: resolution: {integrity: sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==} engines: {node: '>=12'} @@ -5731,6 +5860,15 @@ packages: dev: true optional: true + /@esbuild/linux-ppc64@0.19.10: + resolution: {integrity: sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.19.5: resolution: {integrity: sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==} engines: {node: '>=12'} @@ -5749,6 +5887,15 @@ packages: dev: true optional: true + /@esbuild/linux-riscv64@0.19.10: + resolution: {integrity: sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.19.5: resolution: {integrity: sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==} engines: {node: '>=12'} @@ -5767,6 +5914,15 @@ packages: dev: true optional: true + /@esbuild/linux-s390x@0.19.10: + resolution: {integrity: sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.19.5: resolution: {integrity: sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==} engines: {node: '>=12'} @@ -5785,6 +5941,15 @@ packages: dev: true optional: true + /@esbuild/linux-x64@0.19.10: + resolution: {integrity: sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.19.5: resolution: {integrity: sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==} engines: {node: '>=12'} @@ -5803,6 +5968,15 @@ packages: dev: true optional: true + /@esbuild/netbsd-x64@0.19.10: + resolution: {integrity: sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.19.5: resolution: {integrity: sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==} engines: {node: '>=12'} @@ -5821,6 +5995,15 @@ packages: dev: true optional: true + /@esbuild/openbsd-x64@0.19.10: + resolution: {integrity: sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.19.5: resolution: {integrity: sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==} engines: {node: '>=12'} @@ -5839,6 +6022,15 @@ packages: dev: true optional: true + /@esbuild/sunos-x64@0.19.10: + resolution: {integrity: sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.19.5: resolution: {integrity: sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==} engines: {node: '>=12'} @@ -5857,6 +6049,15 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.19.10: + resolution: {integrity: sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.19.5: resolution: {integrity: sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==} engines: {node: '>=12'} @@ -5875,6 +6076,15 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.19.10: + resolution: {integrity: sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.19.5: resolution: {integrity: sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==} engines: {node: '>=12'} @@ -5893,6 +6103,15 @@ packages: dev: true optional: true + /@esbuild/win32-x64@0.19.10: + resolution: {integrity: sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.19.5: resolution: {integrity: sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==} engines: {node: '>=12'} @@ -6029,6 +6248,18 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true + /@kwsites/file-exists@1.1.1: + resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /@kwsites/promise-deferred@1.1.1: + resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + dev: false + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -7168,6 +7399,37 @@ packages: is-symbol: 1.0.4 dev: true + /esbuild@0.19.10: + resolution: {integrity: sha512-S1Y27QGt/snkNYrRcswgRFqZjaTG5a5xM3EQo97uNBnH505pdzSNe/HLBq1v0RO7iK/ngdbhJB6mDAp0OK+iUA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.10 + '@esbuild/android-arm': 0.19.10 + '@esbuild/android-arm64': 0.19.10 + '@esbuild/android-x64': 0.19.10 + '@esbuild/darwin-arm64': 0.19.10 + '@esbuild/darwin-x64': 0.19.10 + '@esbuild/freebsd-arm64': 0.19.10 + '@esbuild/freebsd-x64': 0.19.10 + '@esbuild/linux-arm': 0.19.10 + '@esbuild/linux-arm64': 0.19.10 + '@esbuild/linux-ia32': 0.19.10 + '@esbuild/linux-loong64': 0.19.10 + '@esbuild/linux-mips64el': 0.19.10 + '@esbuild/linux-ppc64': 0.19.10 + '@esbuild/linux-riscv64': 0.19.10 + '@esbuild/linux-s390x': 0.19.10 + '@esbuild/linux-x64': 0.19.10 + '@esbuild/netbsd-x64': 0.19.10 + '@esbuild/openbsd-x64': 0.19.10 + '@esbuild/sunos-x64': 0.19.10 + '@esbuild/win32-arm64': 0.19.10 + '@esbuild/win32-ia32': 0.19.10 + '@esbuild/win32-x64': 0.19.10 + dev: true + /esbuild@0.19.5: resolution: {integrity: sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==} engines: {node: '>=12'} @@ -7638,6 +7900,12 @@ packages: get-intrinsic: 1.2.1 dev: true + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -9325,6 +9593,10 @@ packages: engines: {node: '>=4'} dev: true + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -9487,6 +9759,16 @@ packages: engines: {node: '>=14'} dev: true + /simple-git@3.21.0: + resolution: {integrity: sha512-oTzw9248AF5bDTMk9MrxsRzEzivMlY+DWH0yWS4VYpMhNLhDWnN06pCtaUyPnqv/FpsdeNmRqmZugMABHRPdDA==} + dependencies: + '@kwsites/file-exists': 1.1.1 + '@kwsites/promise-deferred': 1.1.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + /sinon@15.2.0: resolution: {integrity: sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==} deprecated: 16.1.1 @@ -9840,6 +10122,17 @@ packages: /tslib@2.6.0: resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} + /tsx@4.7.0: + resolution: {integrity: sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + esbuild: 0.19.10 + get-tsconfig: 4.7.2 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /turbo-darwin-64@1.10.16: resolution: {integrity: sha512-+Jk91FNcp9e9NCLYlvDDlp2HwEDp14F9N42IoW3dmHI5ZkGSXzalbhVcrx3DOox3QfiNUHxzWg4d7CnVNCuuMg==} cpu: [x64] diff --git a/pull_request_template.md b/pull_request_template.md index 153073ea..f4b6ad88 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1,22 +1,17 @@ - **Please check if the PR fulfills these requirements**: - -- [ ] The commit message follows [our code of conduct](https://github.com/intuita-inc/codemod-registry/blob/main/CODE_OF_CONDUCT.md) and [contributing guidelines](https://github.com/intuita-inc/codemod-registry/blob/main/CONTRIBUTING.md) -- [ ] Tests for the changes have been added (for bug fixes/features) -- [ ] Docs have been added / updated (for bug fixes / features) +**Please check if the PR fulfills these requirements**: - **Please include the following information in your pull request**: - -* **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) +- [ ] The commit message follows [our code of conduct](https://github.com/intuita-inc/codemod-registry/blob/main/CODE_OF_CONDUCT.md) and [contributing guidelines](https://github.com/intuita-inc/codemod-registry/blob/main/CONTRIBUTING.md) +- [ ] Tests for the changes have been added (for bug fixes/features) +- [ ] Docs have been added / updated (for bug fixes / features) + **Please include the following information in your pull request**: -* **What is the current behavior?** (You can also link to an open issue here) +* **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...) +* **What is the current behavior?** (You can also link to an open issue here) -* **What is the new behavior (if this is a feature change)?** +* **What is the new behavior (if this is a feature change)?** +* **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?) -* **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?) - - -* **Any other information (if needed)**: - +* **Any other information (if needed)**: diff --git a/readme-parser/build.ts b/readme-parser/build.ts new file mode 100644 index 00000000..538adb1f --- /dev/null +++ b/readme-parser/build.ts @@ -0,0 +1,29 @@ +import esbuild from 'esbuild'; + +const getOptions = (fileName: string): Parameters[0] => { + return { + entryPoints: [`${fileName}.ts`], + banner: { + js: ` + // BANNER START + const require = (await import("node:module")).createRequire(import.meta.url); + const __filename = (await import("node:url")).fileURLToPath(import.meta.url); + const __dirname = (await import("node:path")).dirname(__filename); + // BANNER END + `, + }, + bundle: true, + platform: 'node', + minify: true, + minifyWhitespace: true, + format: 'esm', + outfile: `./dist/${fileName}.js`, + }; +}; + +const build = async () => { + await esbuild.build(getOptions('parse')); + await esbuild.build(getOptions('sync')); +}; + +build(); diff --git a/readme-parser/index.ts b/readme-parser/index.ts deleted file mode 100644 index 305e57cc..00000000 --- a/readme-parser/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env node - -import { readFileSync } from 'fs'; -import { convertToYaml, parse } from './parse.js'; - -function accept() { - const path = process.argv.at(-1); - - if (!path) { - throw new Error('No filepath passed'); - } - - const data = readFileSync(path); - - const result = convertToYaml(parse(data.toString()), path); - - console.log(result); -} - -accept(); diff --git a/readme-parser/package.json b/readme-parser/package.json index 004a24cc..0e8b761f 100644 --- a/readme-parser/package.json +++ b/readme-parser/package.json @@ -2,22 +2,23 @@ "name": "@codemod-registry/readme-parser", "type": "module", "dependencies": { + "js-yaml": "4.1.0", "mdast-util-from-markdown": "2.0.0", + "simple-git": "^3.21.0", "valibot": "^0.24.1" }, - "bin": { - "readme-parser": "./dist/index.js" - }, "devDependencies": { "@codemod-registry/tsconfig": "workspace:*", + "@types/js-yaml": "4.0.9", "@types/mdast": "4.0.3", "@types/node": "20.10.4", "esbuild": "^0.19.7", + "tsx": "^4.7.0", "typescript": "5.3.3", "vitest": "1.0.4" }, "scripts": { - "build": "esbuild index.ts --bundle --platform=node --format=esm --outfile=dist/index.js", + "build": "tsx build.ts", "test": "vitest" } } diff --git a/readme-parser/parse.test.ts b/readme-parser/parse.test.ts index bb67cd5f..197bb142 100644 --- a/readme-parser/parse.test.ts +++ b/readme-parser/parse.test.ts @@ -14,6 +14,12 @@ This is an amazing codemod This codemod does the thing +Following the original msw [upgrade guide](https://mswjs.io/docs/migrations/1.x-to-2.x/#imports), there are certain imports that changed their location and/or naming. This codemod will adjust your imports to the new location and naming. + +- \`setupWorker\` is now imported from \`msw/browser\` +- \`rest\` from \`msw\` is now named \`http\` +- \`RestHandler\` from \`msw\` is now named \`HttpHandler\` + ## Example ### \`tsconfig.json\` @@ -71,6 +77,7 @@ v1.0.0 ### Estimated Time Saving 5 minutes per occurrence +Maybe more... ### Owner @@ -89,7 +96,12 @@ describe('parse/yaml', function () { deepEqual(parseResult, { name: 'Do the thing', description: - 'This is an amazing codemod\n### WARNING\nThis codemod does the thing', + 'This is an amazing codemod\n### WARNING\nThis codemod does the thing\n' + + 'Following the original msw [upgrade guide](https://mswjs.io/docs/migrations/1.x-to-2.x/#imports), ' + + 'there are certain imports that changed their location and/or naming. This codemod will adjust your imports to the new location and naming.\n' + + '- `setupWorker` is now imported from `msw/browser`\n' + + '- `rest` from `msw` is now named `http`\n' + + '- `RestHandler` from `msw` is now named `HttpHandler`', examples: '### tsconfig.json\n' + '### Before\n\n' + @@ -120,7 +132,7 @@ describe('parse/yaml', function () { version: '1.0.0', changeMode: 'assistive', engine: 'ts-morph', - timeSave: '5 minutes/occurrence', + timeSave: '5 minutes/occurrence\nMaybe more...', owner: 'Intuita', links: 'https://example.com/,https://example1.com/', }); @@ -151,7 +163,6 @@ describe('parse/yaml', function () { deepEqual( yaml, ` ---- created-on: ${date.toISOString()} f_long-description: >- ## Description @@ -159,7 +170,12 @@ f_long-description: >- This is an amazing codemod ### WARNING This codemod does the thing - \n + Following the original msw [upgrade guide](https://mswjs.io/docs/migrations/1.x-to-2.x/#imports), there are certain imports that changed their location and/or naming. This codemod will adjust your imports to the new location and naming. + - \`setupWorker\` is now imported from \`msw/browser\` + - \`rest\` from \`msw\` is now named \`http\` + - \`RestHandler\` from \`msw\` is now named \`HttpHandler\` + + ### tsconfig.json ### Before @@ -207,13 +223,14 @@ title: Do the thing f_slug-name: msw-2-imports f_codemod-engine: cms/codemod-engines/ts-morph.md f_change-mode-2: Assistive -f_estimated-time-saving: 5 minutes/occurrence +f_estimated-time-saving: >- + 5 minutes/occurrence + Maybe more... tags: automations updated-on: ${date.toISOString()} published-on: ${date.toISOString()} seo: n/a ---- -`.trim(), + `.trim(), ); }); }); diff --git a/readme-parser/parse.ts b/readme-parser/parse.ts index 9fa1e895..4d2c0917 100644 --- a/readme-parser/parse.ts +++ b/readme-parser/parse.ts @@ -6,8 +6,6 @@ import type { Heading, PhrasingContent, RootContent } from 'mdast'; import { fromMarkdown } from 'mdast-util-from-markdown'; import { is, object, optional, string } from 'valibot'; import { createHash } from 'crypto'; -import { fileURLToPath } from 'url'; -import { dirname } from 'path'; const configJsonSchema = object({ schemaVersion: optional(string()), @@ -15,7 +13,7 @@ const configJsonSchema = object({ engine: string(), }); -const UNESCAPED = ['inlineCode']; +const UNESCAPED = ['inlineCode', 'link']; const noFirstLetterLowerCase = (str: string) => str.length ? str[0] + str.slice(1).toLowerCase() : str; @@ -24,7 +22,8 @@ const capitalize = (str: string) => str[0] ? str[0].toUpperCase() + str.slice(1) : str; const getTextFromNode = ( - node: RootContent | PhrasingContent | undefined, + node: RootContent | PhrasingContent | null, + style?: boolean, ): string | null => { if (!node) { return null; @@ -35,7 +34,23 @@ const getTextFromNode = ( } if ('children' in node) { - return getTextFromNode(node.children[0]); + let textContent = ''; + for (const child of node.children) { + if (!style) { + textContent += getTextFromNode(child); + continue; + } + + if (child.type === 'listItem') { + textContent += `${getTextFromNode(child, style)}`; + } else if (child.type === 'inlineCode') { + textContent += `\`${getTextFromNode(child, style)}\``; + } else { + textContent += getTextFromNode(child); + } + } + + return textContent; } return null; @@ -118,6 +133,11 @@ const getTextByHeader = ( if ('children' in rc) { rc.children .map((child, idx, arr) => { + const isDescription = + getTextFromNode(heading)?.includes('Description'); + + const isLinks = getTextFromNode(heading)?.includes('Links'); + // Preserve ### on higher-depth headings if ( rc.type === 'heading' && @@ -140,13 +160,40 @@ const getTextByHeader = ( } if (child.type === 'listItem') { - return `${getUrlFromNode( + if (isDescription) { + return `- ${getTextFromNode( + child.children[0] ?? null, + true, + )}${delimiter}`; + } + + if (isLinks) { + return `${getUrlFromNode( + child.children[0] ?? null, + )}${delimiter}`; + } + + return `${getTextFromNode( child.children[0] ?? null, )}${delimiter}`; } - if (child.type === 'link' || child.type === 'strong') { - return getTextFromNode(child.children[0]); + if (child.type === 'link') { + if (isDescription) { + return `[${getTextFromNode( + child.children[0] ?? null, + true, + )}](${getUrlFromNode(child ?? null)})`; + } + + return getTextFromNode( + child.children[0] ?? null, + isDescription, + ); + } + + if (child.type === 'strong') { + return getTextFromNode(child.children[0] ?? null); } // Do not add new line after certain blocks (treated as separate AST nodes) @@ -322,8 +369,6 @@ export const convertToYaml = ( if (path) { cleanPath = path.split('/').slice(0, -1).join('/'); - const __filename = fileURLToPath(import.meta.url); - const __dirname = dirname(__filename); const parts = __dirname.split('/'); const pivot = parts.indexOf('readme-parser'); const pathToCodemod = nodePath.join( @@ -357,7 +402,6 @@ export const convertToYaml = ( } const res = ` ---- created-on: ${new Date().toISOString()} f_long-description: >- ## Description @@ -391,12 +435,15 @@ title: ${title} f_slug-name: ${slug ?? 'n/a'} f_codemod-engine: cms/codemod-engines/${engine}.md f_change-mode-2: ${capitalize(changeMode)} -f_estimated-time-saving: ${timeSave} +f_estimated-time-saving: ${ + timeSave.includes('\n') + ? `>-\n ${timeSave.replace(/\n/, '\n ')}` + : timeSave + } tags: automations updated-on: ${new Date().toISOString()} published-on: ${new Date().toISOString()} seo: n/a ---- `.trim(); return res; diff --git a/readme-parser/sync.ts b/readme-parser/sync.ts new file mode 100644 index 00000000..5585423a --- /dev/null +++ b/readme-parser/sync.ts @@ -0,0 +1,218 @@ +#!/usr/bin/env node + +import { writeFile } from 'fs/promises'; +import * as yaml from 'js-yaml'; +import { simpleGit } from 'simple-git'; +import { any, record, parse as valibotParse } from 'valibot'; +import { convertToYaml, parse } from './parse.js'; + +const findKeyLineRange = (yaml: string, key: string) => { + const splitYaml = yaml.split('\n'); + + let fieldStartLine: number | null = null; + let fieldEndLine: number | null = null; + let startFound = false; + + for (const [index, line] of splitYaml.entries()) { + if (startFound && line.match(/^\w+:\s/)) { + fieldEndLine = index; + break; + } + + if (line.match(`^${key}:\\s`)) { + fieldStartLine = index; + startFound = true; + } + } + + if (fieldStartLine === null) { + return null; + } + + if (fieldEndLine === null) { + fieldEndLine = splitYaml.length - 1; + } + + return [fieldStartLine, fieldEndLine] as const; +}; + +export const sync = async () => { + const git = simpleGit(); + + await git.addRemote( + 'website', + 'https://github.com/intuita-inc/website.git', + ); + await git.addConfig('user.email', 'intuita@intuita.io', false, 'local'); + await git.addConfig('user.name', 'Intuita Team', false, 'local'); + + await git.fetch(['website', 'master']); + await git.fetch(['origin', 'main']); + + const diff = await git.diff(['--name-only', 'origin/main']); + const readmesChanged = diff + .split('\n') + .filter((path) => path.match(/^codemods\/.*README\.md$/)); + + if (!readmesChanged.length) { + console.log('No READMEs changed. Exiting.'); + process.exit(0); + } + + const staged: Record = {}; + for (const path of readmesChanged) { + console.log(`Syncing ${path}`); + const generatedSlug = path.split('/').slice(1, -1).join('-'); + const websitePath = `cms/automations/${generatedSlug}.md`; + + let websiteFile: string | null; + let oldFile: string | null; + try { + websiteFile = await git.catFile([ + '-p', + `website/master:${websitePath}`, + ]); + } catch (err) { + websiteFile = null; + } + + try { + oldFile = await git.catFile(['-p', `origin/main:${path}`]); + } catch (err) { + oldFile = null; + } + + // Always exists + const newFile = await git.catFile(['-p', `HEAD:${path}`]); + const newReadmeYamlContent = convertToYaml(parse(newFile), path); + + // If !websiteFile, we just add the file + // If websiteFile is present, but oldFile is not, this means that + // the website somehow had that file prior to codemod being added to the registry, + // which technically should not be possible. + // In that case we just update the entire file with the new one anyways. + if (!websiteFile || !oldFile) { + staged[websitePath] = `---\n${newReadmeYamlContent}\n---`; + continue; + } + + // Otherwise: + // 1. Perform a diff between old file and new file, decide what do we need to filter + // 2. Iterate over filtered fields that have changed between commits + // 3. If the field's version from old readme is different from website, we remove it from update list + // 4. Otherwise, proceed and add update the fields in the object, based on website version + // 5. Commit the file + + const websiteContentSplit = websiteFile.split('---', 3); + + const websiteYamlContent = websiteContentSplit.at(1)?.trim(); + + if (!websiteYamlContent) { + console.error(`Could not parse website file ${websitePath}`); + process.exit(1); + } + + // Here, we are actually doing double-convert, json->yaml->json, but it's meant to be that way. + // Our content's source of truth is yaml from the beginning, plus it has a lot of multi-line strings, + // which would be a pain to handle in json. We are converting to json, just to be able to operate + // the fields just like any other JS object, to perform the comparison. + // Not using valibot's safeParse, because we can just error if that's not an object and we don't care + // about the fields to be of a specific type. + const oldContent = valibotParse( + record(any()), + yaml.load(convertToYaml(parse(oldFile), path)), + ); + const newContent = valibotParse( + record(any()), + yaml.load(newReadmeYamlContent), + ); + const websiteContent = valibotParse( + record(any()), + yaml.load(websiteYamlContent), + ); + + const changedKeys: string[] = []; + for (const key of Object.keys(newContent)) { + // Field did not change + if (oldContent[key] === newContent[key]) { + continue; + } + + // Field was changed in the CMS, no update + if (oldContent[key] !== websiteContent[key]) { + continue; + } + + // Field is already the same as in the new README version + if (newContent[key] === websiteContent[key]) { + continue; + } + + changedKeys.push(key); + } + + if (!changedKeys.length) { + console.log(`Nothing to update in path ${path}`); + continue; + } + + let updatedYaml = websiteYamlContent; + for (const key of changedKeys) { + const websiteRange = findKeyLineRange(updatedYaml, key); + if (!websiteRange) { + console.error( + `Could not find ${key} in website file ${websitePath}`, + ); + process.exit(1); + } + + const newFileRange = findKeyLineRange(newReadmeYamlContent, key); + if (!newFileRange) { + console.error(`Could not find ${key} in new file ${path}`); + process.exit(1); + } + + const [websiteStartIndex, websiteEndIndex] = websiteRange; + const [newFileStartIndex, newFileEndIndex] = newFileRange; + + const websiteLines = websiteYamlContent.split('\n'); + const newFileLines = newReadmeYamlContent.split('\n'); + + updatedYaml = [ + '---', + ...websiteLines.slice(0, websiteStartIndex), + ...newFileLines.slice(newFileStartIndex, newFileEndIndex), + ...websiteLines.slice(websiteEndIndex), + '---', + ].join('\n'); + } + + const websiteLeftoverDescription = websiteContentSplit.at(2)?.trim(); + if (websiteLeftoverDescription) { + updatedYaml += `\n${websiteLeftoverDescription}`; + } + + staged[websitePath] = updatedYaml; + } + + if (Object.keys(staged).length === 0) { + console.log('No commits were created. Skipping push...'); + process.exit(0); + } + + await git.checkout(['-b', 'update-codemods', 'website/master']); + + for (const [websitePath, newContent] of Object.entries(staged)) { + await writeFile(websitePath, newContent); + await git.add(websitePath); + await git.commit(`Syncs ${websitePath} from codemod-registry`); + console.log(`Created commit for ${websitePath}`); + } + + await git.push('website', 'HEAD:master'); + console.log('Successfully pushed to website repo'); + + process.exit(0); +}; + +sync();