# @codepatch/javascript

> Transform JavaScript code the easy way

Latest version **1.0.1** (published 2023-09-23) · MIT license · 0 weekly downloads

## Install

```sh
npm install @codepatch/javascript
pnpm add @codepatch/javascript
yarn add @codepatch/javascript
bun add @codepatch/javascript
```

## Health

**Score 30/100 (F)** — status: abandoned.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.1 |
| Published | 2023-09-23 |
| First published | 2023-09-23 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 16.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Author | Florian Reuschel |
| Maintainers | loilo |
| Keywords | javascript, falafel, yufka, ast, transform, rewrite, transpile, source, syntax, traverse, tree |

## Links

- npm: https://www.npmjs.com/package/@codepatch/javascript
- Repository: https://github.com/loilo/codepatch
- Homepage: https://github.com/loilo/codepatch/tree/main/packages/javascript#readme
- Issues: https://github.com/loilo/codepatch/issues
- npm.io page: https://npm.io/package/@codepatch/javascript

## Dependencies (1)

- [@codepatch/core](https://npm.io/package/@codepatch/core.md) ^1.0.1

## Alternatives

- [update-check](https://npm.io/package/update-check.md) — 4.0M weekly downloads
- [react-native-onesignal](https://npm.io/package/react-native-onesignal.md) — 134.5K weekly downloads
- [react-redux-toastr](https://npm.io/package/react-redux-toastr.md) — 33.7K weekly downloads
- [@nocobase/plugin-notification-manager](https://npm.io/package/@nocobase/plugin-notification-manager.md) — 2.0K weekly downloads
- [react-simple-toasts](https://npm.io/package/react-simple-toasts.md) — 1.9K weekly downloads

## Recent versions

- 1.0.1 (latest) — 2023-09-23
- 1.0.0 — 2023-09-23

## README

# `@codepatch/javascript`

> Make small changes to your JavaScript code the easy way

## Installation

```
npm install @codepatch/javascript
```

**IMPORTANT:** `@codepatch/javascript` is an ESM-only package. [Read more.](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c)

## Motivation

`@codepatch/javascript` is the ideal tool for programmatically making small & simple modifications to your JavaScript code. It works by parsing the code into an [AST](http://en.wikipedia.org/wiki/Abstract_syntax_tree) and then overriding parts of it. Learn more about the motivation behind Codepatch in [the main repository](https://github.com/loilo/codepatch#motivation).

As an introducing example, let's put a function wrapper around all array literals:

```js
import { modify } from '@codepatch/javascript'

const code = `
const xs = [1, 2, [3, 4]]
const ys = [5, 6]
console.log([xs, ys])
`

const result = modify(code, (node, { source, override }) => {
  if (node.type === 'ArrayExpression') {
    override(`wrap(${source()})`)
  }
})

console.log(result.code)
```

> **Tip:** To simplify following along the code above, you can have a look at [the handled JavaScript code's AST](https://astexplorer.net/#/gist/74ceb5bae1facb250f10a65621ad4980/a0d52a808b8255a04cec9429f8408cfc1238bc38).

Output:

```js
const xs = wrap([1, 2, wrap([3, 4])])
const ys = wrap([5, 6])
console.log(wrap([xs, ys]))
```

Note that Codepatch is not a transpiler, so it's not ideal for large or complex changes, you'd want something like [`@babel/traverse`](https://babeljs.io/docs/babel-traverse.html) for that.

## Usage

### How it Works

```ts
function modify(code, options = {}, manipulator)
```

Transform the `code` string with the function `manipulator`, returning an output object.

For every node in the AST, `manipulator(node, helpers)` is called. The recursive walk is an
[in-order, depth-first traversal](https://en.wikipedia.org/wiki/Tree_traversal#In-order,_LNR), so children are handled before their parents. This makes it easier to write manipulators that perform nested transformations as transforming parents often requires transforming their children first anyway.

The `modify()` return value is an object with two properties:

- `code` – contains the transformed source code
- `map` – holds the resulting source map object, [as generated by `magic-string`](https://github.com/rich-harris/magic-string#sgeneratemap-options-)

Type casting a Codepatch result object to a string will return its source `code`.

> **Pro Tip:**
> Don't know what a JavaScript AST looks like? Have a look at [astexplorer.net](https://astexplorer.net/) and select the "JavaScript" language with the "acorn" parser to get an idea.

### Options

All options are, as the name says, optional. If you want to provide an options object, its place is between the `code` string and the `manipulator` function.

#### Parser Options

Any options for the underlying [`acorn`](https://github.com/acorn/acorn) parser can be passed to `options.parser`:

```js
modify(code, { parser: { sourceType: 'module' } }, (node, helpers) => {
  // Parse the `code` as an ES module
})
```

#### Custom Parser

You may pass a custom acorn parser as `options.parser.customParser` to use that
instead of the default acorn version coming with this library:

```js
import acorn from 'acorn'
import jsx from from 'acorn-jsx'

const options = {
  parser: {
    customParser: acorn.Parser.extend(jsx())
  }
}

modify(code, options, (node, helpers) => {
  // Parse the `source` as JSX
})
```

#### Source Maps

Codepatch uses [`magic-string`](https://github.com/rich-harris/magic-string) under the hood to generate [source maps](https://developer.mozilla.org/docs/Tools/Debugger/How_to/Use_a_source_map) for your code modifications. You can pass its [source map options](https://github.com/rich-harris/magic-string#sgeneratemap-options-) as `options.sourceMap`:

```js
const options = {
  sourceMap: {
    hires: true
  }
}

modify(code, options, (node, helpers) => {
  // Create a high-resolution source map
})
```

### Helpers

The `helpers` object passed to the `manipulator` function exposes three methods. All of these methods handle the _current AST node_ (the one that has been passed to the manipulator as its first argument).

However, each of these methods takes an AST node as an optional first parameter if you want to access other nodes.

> **Example:**
>
> ```js
> modify('x = 1', (node, { source }) => {
>   if (node.type === 'AssignmentExpression') {
>     // `node` refers to the `x = 1` Expression
>     source() // returns "x = 1"
>     source(node.right) // returns "1"
>   }
> })
> ```

#### `source()`

Return the source code for the given node, including any modifications made to
child nodes:

```js
modify('true', (node, { source, override }) => {
  if (node.type === 'Literal') {
    source() // returns "true"
    override('false')
    source() // returns "false"
  }
})
```

#### `override(replacement)`

Replace the source of the affected node with the `replacement` string:

```js
const result = modify('4 + 2', (node, { source, override }) => {
  if (node.type === 'BinaryExpression') {
    override(source(node.left) + source(node.right))
  }
})

console.log(result.code)
```

Output:

```js
42
```

#### `parent(levels = 1)`

From the starting node, climb up the syntax tree `levels` times. Getting an ancestor node of the program root yields `undefined`.

```js
modify('x = [1]', (node, { parent }) => {
  if (node.type === 'Literal') {
    // `node` refers to the `1` literal
    parent() // same as parent(1), refers to the `[1]` expression
    parent(2) // refers to the `x = [1]` assignment expression
    parent(3) // refers to the `x = [1]` statement
    parent(4) // refers to the program as a whole (root node)
    parent(5) // yields `undefined`, same as parent(6), parent(7) etc.
  }
})
```

#### External Helper Access

If you want to extract manipulation behavior into standalone functions, you can import the helpers directly from the `@codepatch/javascript` package, where they are not bound to a specific node:

```js
import { override } from '@codepatch/php'

// Standalone function, increments node's value if it's a number
const increment = node => {
  if (node.type === 'Literal' && typeof node.value === 'number') {
    override(node, String(node.value + 1))
  }
}

const result = modify('x = 1', node => {
  increment(node)
})

console.log(result.code)
```

Output:

```js
x = 2
```

### Asynchronous Manipulations

The `manipulator` function may return a [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise). If it does, Codepatch will wait for that to resolve, making the whole `modify()` function return a Promise resolving to the result object (instead of returning the result object directly):

```js
const code = `
const content = curl("https://example.com")
`

const deferredResult = modify(code, async (node, { source, override }) => {
  if (node.type === 'CallExpression' && node.callee.name === 'curl') {
    // Replace all cUrl calls with their actual content

    // Get the URL (will only work for simple string literals)
    const url = node.arguments[0].value

    // Fetch the URL's contents
    const contents = await fetch(url).then(response => response.text())

    // Replace the cUrl() call with the fetched contents
    override(JSON.stringify(contents))
  }
})

// Result is not available immediately, we need to await it
deferredResult.then(result => {
  console.log(result.code)
})
```

Output:

```js
const content = '<!doctype html>\n<html>\n[...]\n</html>'
```

> **Note:** You _have_ to return a Promise if you want to commit updates asynchronously. Once the manipulator function is done running, any `override()` calls originating from it will throw an error.

## Related

`@codepatch/javascript` is part of the Codepatch family of tools. Codepatch is a collection of tools that make it easy to programmatically make simple modifications to code of various languages.

Check out the [Codepatch repository](https://github.com/loilo/codepatch) to find tools for other languages or information about how to write your own Codepatch modifier.

---
_Source: https://npm.io/package/@codepatch/javascript · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
