Skip to content

Add read-only Prebuild RPC to rewrite-javascript#7935

Draft
knutwannheden wants to merge 1 commit into
mainfrom
js-rpc-prebuild
Draft

Add read-only Prebuild RPC to rewrite-javascript#7935
knutwannheden wants to merge 1 commit into
mainfrom
js-rpc-prebuild

Conversation

@knutwannheden

@knutwannheden knutwannheden commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Motivation

A long-running session can keep parsed state current for hours while an agent edits files, re-parsing changed files incrementally. For JVM languages, a consumer gets the repository's shape (projects, source sets, classpaths, config inputs) by invoking the build tool during a prebuild step. JavaScript/TypeScript has no equivalent: JS prebuild is a no-op today, so there is no workspace-aware notion of "what are the projects, which files are tests, and which config files should force a full re-parse when they change."

Prebuild is the JavaScript analog of "invoke the build tool". Given a repository (or partition) root it returns the independent, workspace-aware projects with their source sets, config-input watch-set, and parser settings — the build descriptor a consumer uses to drive JS/TS builds and incremental re-parsing. It produces only the descriptor; it does not parse sources (that stays with parseProject). v1 is read-only — no dependency install.

It mirrors the ParseProject RPC patterns but shares none of its code, so the two are independent.

Examples

PrebuildResult result = javaScriptRewriteRpc.prebuild(repositoryRoot);

for (PrebuildResult.ProjectDescriptor project : result.getProjects()) {
    project.getPath();            // "packages/app" (workspace member dir, relative)
    project.getPackageManager();  // NodeResolutionResult.PackageManager.YarnBerry
    project.getConfigInputs();    // ["packages/app/package.json", "package-lock.json",
                                  //  "packages/app/tsconfig.json", "tsconfig.base.json"]
    for (PrebuildResult.SourceSetDescriptor set : project.getSourceSets()) {
        set.getName();                              // "main" | "test"
        set.getParserSettings().getTsconfigPath();  // "packages/app/tsconfig.json"
    }
}

For a non-workspace repo it returns a single project; for an npm/yarn/bun (package.json#workspaces) or pnpm (pnpm-workspace.yaml) workspace it returns one project per member.

Summary

  • TS handler src/rpc/request/prebuild.ts (Prebuild + PrebuildResult), registered in rewrite-rpc.ts next to ParseProject.handle.
  • Discovery src/javascript/workspace-discovery.ts — workspace-aware project roots, main/test source-set split by convention globs, config-input watch-set (package.json, nearest lock file, local tsconfig extends chain + references, prettier/jest/vitest config), parser settings (nearest tsconfig).
    • Workspace member matching honors !negation exclusions, trailing-slash and brace globs.
    • packageManager detected from the nearest lock file (yarn Classic vs Berry content-sniffed), falling back to the corepack packageManager field, else Npm.
  • Java clientprebuild(...) on JavaScriptRewriteRpc plus PrebuildResult/ProjectDescriptor/SourceSetDescriptor/ParserSettings. packageManager is the canonical NodeResolutionResult.PackageManager enum so yarn Classic vs Berry stays distinct.
  • resolution is present but always null in v1; parseProject is untouched.

Deliberately not in this PR (additive follow-ups): install ownership, NodeResolutionResult on returned CUs, the per-file prod/test marker at parse time, and the stateful warm-session lifecycle. Source sets are modeled as a list with per-set parserSettings so divergent prod/test config is additive later.

Test plan

  • TS unit tests test/javascript/workspace-discovery.test.ts (15): standalone project, main/test split, configInputs extends chain + references (incl. directory-style reference, npm-package extends skipped), npm + pnpm workspace fan-out, yarn Berry vs Classic, nested-package.json pruning, !negation / trailing-slash / brace workspace globs, corepack packageManager fallback.
  • npm run typecheck clean; no regressions in test/rpc/ (57 passed).
  • Java integ test JavaScriptRewriteRpcTest.prebuild over a fixture repo (npm workspace + tsconfig extends chain + main/test files), run against the rebuilt TS server.
  • licenseFormat clean.

`Prebuild` is the JavaScript analog of "invoke the build tool": given a
repository (or partition) root it returns the independent, workspace-aware
projects with their source sets, config-input watch-set, and parser settings —
the build descriptor a consumer uses to drive JS/TS builds and incremental
re-parsing. It produces only the descriptor; it does not parse sources. v1 is
read-only (no dependency install).

The TS handler mirrors `ParseProject`; workspace/source-set/config-input
discovery lives in a new `workspace-discovery` module. The Java client adds a
`prebuild(...)` method plus `PrebuildResult`/`ProjectDescriptor`/
`SourceSetDescriptor`/`ParserSettings` types, with `packageManager` carried as
the canonical `NodeResolutionResult.PackageManager` enum so yarn Classic vs
Berry stays distinct.
@jkschneider jkschneider marked this pull request as draft June 9, 2026 02:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant