{"id":18879730,"url":"https://github.com/loilo/codepatch","last_synced_at":"2026-02-20T04:30:17.976Z","repository":{"id":196271459,"uuid":"695678900","full_name":"loilo/codepatch","owner":"loilo","description":"Collection of tools that make it easy to programmatically make simple modifications to code of various languages","archived":false,"fork":false,"pushed_at":"2023-09-24T12:40:55.000Z","size":238,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-27T05:20:57.763Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/loilo.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-23T21:47:45.000Z","updated_at":"2023-09-24T12:43:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"7348da84-d88a-4d60-8482-b84f9f973db9","html_url":"https://github.com/loilo/codepatch","commit_stats":null,"previous_names":["loilo/codepatch"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loilo%2Fcodepatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loilo%2Fcodepatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loilo%2Fcodepatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loilo%2Fcodepatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loilo","download_url":"https://codeload.github.com/loilo/codepatch/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239841742,"owners_count":19705981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T06:39:04.996Z","updated_at":"2026-02-20T04:30:17.917Z","avatar_url":"https://github.com/loilo.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"codepatch.svg\" width=\"220\" height=\"220\" alt=\"\"\u003e\n\n# Codepatch\n\n\u003c/div\u003e\n\nCodepatch is a collection of tools that make it easy to programmatically make simple modifications to code of various languages. It consists of a core library ([`@codepatch/core`](https://github.com/loilo/codepatch/tree/main/packages/core)) and a set of language-specific packages that are built on top of it.\n\n## Motivation\n\nIn Node.js (or any server-side JavaScript runtime, really), making programmatic modifications to code is a common but tedious task.\n\nIt can be done the easy way — through simple string replacements — but this is unreliable and often unsafe.\n\nDoing it properly though (by parsing the code into an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree), modifying the AST, and then generating code from the modified AST) tends to be a lot of work. Sometimes it's even straight-up impossible as there are languages that have a parser written in JavaScript, but no according code generator.\n\nCodepatch is tailored to make small \u0026 simple code modifications easy while not targeting more complex scenarios at all, so it aims to hit a middle ground between these two approaches. To achieve this, Codepatch parses the code into an AST, but instead of modifying the AST, it allows you to override individual AST nodes with new code snippet strings directly. Just like a patch on a piece of cloth.\n\n### Example\n\nHere's an example of how this approach works, using [`@codepatch/javascript`](https://github.com/loilo/codepatch/tree/main/packages/javascript) to add `.js` extensions to all relative imports in a JavaScript module:\n\n```js\nimport { modify } from '@codepatch/javascript'\n\nconst original = `\nimport foo from 'bar'\nimport baz from './qux'\n`\n\nconst result = modify(\n  original,\n  { parser: { sourceType: 'module' } },\n  (node, { source, parent, override }) =\u003e {\n    if (\n      // For patching, only consider (string) literals...\n      node.type === 'Literal' \u0026\u0026\n      // ...which are the 'source' property of their parent...\n      parent().source === node \u0026\u0026\n      // ...which itself is either an import or export.\n      [\n        'ImportExpression',\n        'ImportDeclaration',\n        'ExportAllDeclaration',\n        'ExportNamedDeclaration'\n      ].includes(parent().type) \u0026\u0026\n      // The literal must not already have a .js extension...\n      !node.value.endsWith('.js') \u0026\u0026\n      // ...and needs to be a relative path.\n      (node.value.startsWith('./') || node.value.startsWith('../'))\n    ) {\n      // Override the node with the same string, but with a .js extension\n      override(node.raw.slice(0, -1) + '.js' + node.raw.slice(-1))\n    }\n  }\n)\n\nconsole.log(result.code)\n```\n\n\u003e **Tip:** To simplify following along the code above, you can have a look at [the handled JavaScript code's AST](https://astexplorer.net/#/gist/54f993675fef79ca0e4f41080b57ea52/9e12658595d9b19d7a6b4b4de8369e377985f92d).\n\nOutput:\n\n```js\nimport foo from 'bar'\nimport baz from './qux.js'\n```\n\n## Official Modifiers\n\nFor now, the Codepatch project provides modifiers for the following languages:\n\n\u003c!-- prettier-ignore --\u003e\nLanguage | Parser | Package\n-|-|-\nJavaScript | [Acorn](https://github.com/acornjs/acorn) | [`@codepatch/javascript`](https://github.com/loilo/codepatch/tree/main/packages/javascript)\nCSS | [CSSTree](https://github.com/csstree/csstree) | [`@codepatch/css`](https://github.com/loilo/codepatch/tree/main/packages/css)\nHTML | [htmlparser2](https://github.com/fb55/htmlparser2) | [`@codepatch/html`](https://github.com/loilo/codepatch/tree/main/packages/html)\nPHP | [PHP Parser](https://github.com/glayzzle/php-parser) | [`@codepatch/php`](https://github.com/loilo/codepatch/tree/main/packages/php)\n\n## Implementing a Modifier\n\nUsing [`@codepatch/core`](https://github.com/loilo/codepatch/tree/main/packages/core) to implement a modifier for any other language is near trivial. Everything you need is a JavaScript-based parser for that language and the instructions in the core package.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floilo%2Fcodepatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floilo%2Fcodepatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floilo%2Fcodepatch/lists"}