Commit Graph

15 Commits

Author SHA1 Message Date
overlookmotel ce03ac12dc docs(packages/codegen): fix JSDoc comments for printSync (#25722)
Follow-on after #25720. Fix inaccuracies in JSDoc comments, as pointed out by AI review https://github.com/oxc-project/oxc/pull/25720#pullrequestreview-4944174621. For some reason, it got merged before my change to that PR was integrated.
2026-08-15 16:24:28 +00:00
overlookmotel f91b7739a3 refactor(packages/codegen): re-order write* functions (#25719)
Pure refactor. Re-order `write*` functions, so `*NoLast` versions are grouped together.
2026-08-15 16:04:00 +00:00
overlookmotel cf0b935f7b refactor(packages/codegen): move debug asserts for non-empty code into write* functions (#25718)
Pure refactor.

Move debug asserts that `code` cannot be an empty string into the body of `write` and `writeWithMap`. This makes it clearer what the invariants of these functions are.
2026-08-15 16:04:00 +00:00
overlookmotel a5c4a88d0e refactor(packages/codegen): move setting debug state to last in write* functions (#25717)
Pure refactor. Move setting debug-only state to the end of `write*` functions, instead of start. This makes it clearer that it's setting up state for the _next_ call to reference.
2026-08-15 16:04:00 +00:00
overlookmotel 386a699e81 docs(packages/codegen): correct JSDoc comment (#25716)
Docs-only change. Just correct a JSDoc comment which was out of date.
2026-08-15 16:03:59 +00:00
overlookmotel 365274ea16 feat(packages/codegen)!: printSync return an object (#25720)
`oxc-codegen`'s current API requires passing in a `SourceMapGenerator` as an option to generate source maps. This is currently really slow, and I imagine we'll want to generate source maps internally (perhaps in Rust), and return a source map string from `printSync` instead.

Alter `printSync`'s return type now, to support that without a breaking change later.

- Before: `function printSync(node: ESTree.Node, options?: Options): string`
- After: `function printSync(node: ESTree.Node, options?: Options): { code: string }`

Later on, it can return `{ code: string, map: string }` and that won't break existing users.
2026-08-15 15:53:54 +00:00
camc314 0c68b7ff8b fix(estree): emit decorators on FormalParameterRest (#25582)
This PR adds support for emitting `decorators` when serializing an ast to ESTree (both with/without raw transfer).

Given the following code:
```
class C { method(@dec ...args) {} }
```

Before we emitted the following ESTree shape:
```json
"params": [
  {
    "type": "RestElement",
    "decorators": [],
    "argument": {
      "type": "Identifier",
      "decorators": [],
      "name": "args",
      "optional": false,
      "typeAnnotation": null,
    },
    "optional": false,
    "typeAnnotation": null,
    "value": null,
  }
],
```

Now we emit:
```json
"params": [
  {
    "type": "RestElement",
    "decorators": [
      {
        "type": "Decorator",
        "expression": { "type": "Identifier", "name": "dec" }
      }
    ],
    "argument": {
      "type": "Identifier",
      "decorators": [],
      "name": "args",
      "optional": false,
      "typeAnnotation": null,
    },
    "optional": false,
    "typeAnnotation": null,
    "value": null,
  },
],
```

fixes https://github.com/oxc-project/oxc/issues/18981
closes https://github.com/oxc-project/oxc/pull/24736
2026-08-13 10:43:14 +00:00
camc314 fd6235498c docs(codegen): revamp package readme (#25560)
## Summary

- reorganize the package README around installation, usage, and API reference
- document TypeScript, TSX, source map, and runtime requirements
- add parsed-source and manually constructed AST examples
- clarify package design, limitations, and benchmark presentation
2026-08-13 08:54:23 +00:00
camc314 5444cbfaf8 perf(codegen): skip escaping harmless < tokens (#25564)
## Summary

- Detect actual case-insensitive `</script` sequences in the initial string-escape scan.
- Keep strings containing only harmless `<` on the bulk-write fast path.
- Add regression coverage for script closers, controls, paired and lone surrogates, and template quasis.

## Benchmark methodology

No permanent microbenchmark is added. Measurements used release bundles built with `pnpm --filter oxc-codegen run build` on Node v26.5.0, a one-off focused harness over representative string-literal ASTs, and the existing `packages/codegen/bench.bench.ts` parsed-AST fixtures. The focused harness used ten warmup batches and 20 measured batches per case; Vitest fixtures used 1s warmup and 3s measurement windows (50/20 iteration minima).

The removed one-off harness is retained for reference at [bench.string.bench.ts](https://github.com/oxc-project/oxc/blob/49e7a9d43bdc55a8f01075363bb8701ca5a9380c/packages/codegen/bench.string.bench.ts).

Focused release results (ms/print, mean ± standard deviation):

| Case | Before | After | Change |
| --- | ---: | ---: | ---: |
| Short ordinary string | 0.00003 ± 0.00000 | 0.00003 ± 0.00000 | no material change |
| Long string without `<` | 0.02048 ± 0.00114 | 0.01906 ± 0.00038 | within noise / slightly faster |
| Dense harmless HTML/SVG-like `<` (15,360 chars) | 0.05625 ± 0.00152 | 0.01283 ± 0.00036 | 77% faster |
| Mixed text with harmless `<` | 0.04766 ± 0.00210 | 0.02371 ± 0.00072 | 50% faster |
| Frequent mixed-case `</script` closers | 0.04350 ± 0.00074 | 0.04366 ± 0.00079 | within noise |

Existing parsed-AST benchmark fixtures (Vitest RME 0.15–0.79%): Radix 0.0028 -> 0.0027 ms, React development 0.0981 -> 0.0976 ms. App.tsx varied from 0.6261 to 0.6657 ms after versus 0.6415 ms before, so this PR makes no throughput claim for that fixture and shows no consistent regression.

A release CPU profile of the dense harmless case reduced `printEscapedStringContents` from 1,099 of 1,459 samples, plus 124 `^</script` regex samples, to zero; the after profile spends 321 of 383 samples in the single initial scan.
2026-08-13 08:49:27 +00:00
camc314 ffa31535db docs(codegen): clarify raw transfer Node requirement (#25565)
My AI reviews keep on flagging this, so it's probably worth noting for clarity etc.
2026-08-13 08:37:59 +00:00
camc314 c5d406370d docs(codegen): clarify binary walk allocations (#25562)
## Summary
- Correct the binary-walk allocation claim: the implementation creates an initial visitor object and one for each nested left level.
- Retain and document the actual optimization: pending levels use `parent` links instead of a separate stack array.
2026-08-12 17:23:14 +00:00
camc314 5703d7a44f docs(codegen): correct stale printer comments (#25561)
## Summary

- Correct the three stale codegen comments identified in review.
2026-08-12 17:16:55 +00:00
camc314 46d237c9a7 chore(codegen,parser,tasks): pin benchmark fixtures by sha (#25557)
Pin the Codegen benchmark fixture to an immutable `benchmark-files` commit. This makes benchmark inputs reproducible and prevents `main` updates from silently changing results.
2026-08-12 15:56:52 +00:00
camc314 59e8895162 fix(codegen): validate starting indent level (#25550)
## Summary

Validate `startingIndentLevel` before printing to prevent unbounded indentation-cache growth.

- Reject non-finite, fractional, negative, and unsafe integer values with a `RangeError`.
- Document the option as a non-negative integer.
2026-08-12 15:46:26 +00:00
overlookmotel a4478e960a feat(codegen): add oxc-codegen package (#25488)
Add `oxc-codegen` package - a printer written in TS.

### Features

- Prints JS, JSX, TS, TSX.
- Matches `oxc_codegen` exactly on all Test262, TypeScript, Acorn-JSX fixtures.
- Very fast.

### Deficiencies

- Pretty-printing only (no compact/minified output).
- No support for printing comments.
- Source map support is semi-there, but largely untested, and poor API (design doc has some ideas on how to improve it).

### This PR adds

- The printer code.
- Conformance testing infra.
- Further tests for edge cases.
- README.
- Design doc - how it differs from `oxc_codegen` and why, what produces the perf.

### This PR doesn't add

- Not integrated into CI or release pipeline.

### Notes

This started as a slop port of `oxc_codegen`. I've iterated on that base, cleaned it up a lot, and at least skimmed through all of it. I think it's in fairly decent shape.

The design doc is I think worth a read. It explains the rationale for the choices, in particular the "1 codebase, 4 builds" approach.

I've put it in a new top-level directory called `packages`. It's not an app, so didn't seem to me to fit alongside `apps/oxlint` and `apps/oxfmt`. It's pure JS, so not like e.g. `napi/parser`. And it felt too heavyweight to put into `npm` dir. But maybe there's a better place for it.

Co-authored-by: Cameron <cameron.clark@hey.com>
2026-08-12 13:41:31 +00:00