Skip to content

chore(xtask): scaffold global-types codegen and resolver builder#10249

Open
minseong0324 wants to merge 1 commit into
biomejs:mainfrom
minseong0324:chore/global-types-codegen-pr1
Open

chore(xtask): scaffold global-types codegen and resolver builder#10249
minseong0324 wants to merge 1 commit into
biomejs:mainfrom
minseong0324:chore/global-types-codegen-pr1

Conversation

@minseong0324
Copy link
Copy Markdown
Contributor

@minseong0324 minseong0324 commented May 5, 2026

This PR was implemented with AI assistance from Codex.

Summary

Foundation for #5977. Adds the global-types codegen scaffold, pinned TypeScript source acquisition, collector coverage, manifest-driven predefined globals, and stricter resolver-builder invariants.

Test Plan

Green CI

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 5, 2026

⚠️ No Changeset found

Latest commit: 220d304

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions Bot added A-Tooling Area: internal tools L-JavaScript Language: JavaScript and super languages A-Type-Inference Area: type inference labels May 5, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 5, 2026

Merging this PR will not alter performance

✅ 249 untouched benchmarks


Comparing minseong0324:chore/global-types-codegen-pr1 (220d304) with main (83f7385)

Open in CodSpeed

@minseong0324 minseong0324 force-pushed the chore/global-types-codegen-pr1 branch 24 times, most recently from 1482ec2 to 30a9e19 Compare May 9, 2026 18:11
@minseong0324 minseong0324 changed the title chore(xtask): scaffold global-types codegen with manifest-driven globals and strict resolver builder chore(xtask): scaffold global-types codegen and resolver builder May 9, 2026
@minseong0324 minseong0324 force-pushed the chore/global-types-codegen-pr1 branch 26 times, most recently from d26c0d6 to 6db64fb Compare May 17, 2026 19:35
@minseong0324 minseong0324 force-pushed the chore/global-types-codegen-pr1 branch from 6db64fb to 220d304 Compare May 17, 2026 19:42
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/biome_js_type_info/src/globals.rs (1)

298-311: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use T for the map callback parameter.

Line 304 types item as U, but Array.prototype.map passes the source element type into the callback. As written, this models map as U -> U instead of T -> U, so inference goes sideways rather quickly.

Suggested fix
         builder.set_manual_type_data(MAP_CALLBACK_ID_GLOBAL_TYPE_ID, || {
             TypeData::from(Function {
                 is_async: false,
                 type_parameters: Default::default(),
                 name: Some(Text::new_static(MAP_CALLBACK_ID_NAME)),
                 parameters: [FunctionParameter::Pattern(PatternFunctionParameter {
-                    ty: GLOBAL_U_ID.into(),
+                    ty: GLOBAL_T_ID.into(),
                     bindings: Default::default(),
                     is_optional: false,
                     is_rest: false,
                 })]
                 .into(),
                 return_type: ReturnType::Type(GLOBAL_U_ID.into()),
             })
         });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_js_type_info/src/globals.rs` around lines 298 - 311, The map
callback is currently modeled with its parameter typed as GLOBAL_U_ID which
makes map's signature U -> U; update the manual type data in
builder.set_manual_type_data for MAP_CALLBACK_ID_GLOBAL_TYPE_ID so the
Function's parameter PatternFunctionParameter uses GLOBAL_T_ID.into() for ty
(leaving the return_type as GLOBAL_U_ID.into()), i.e. change the parameter type
from GLOBAL_U_ID to GLOBAL_T_ID to correctly represent T -> U; adjust any
imports or constants if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/biome_js_type_info/src/globals_ids.rs`:
- Around line 91-97: The helper method
PredefinedGlobalRole::is_sentinel_projection currently omits the HostManual
variant so HostManual rows can be treated as migratable; update
is_sentinel_projection to include Self::HostManual in the matches! arm (i.e.,
change matches!(self, Self::Sentinel | Self::Primitive | Self::Helper) to also
include Self::HostManual) so MIGRATED_PREDEFINED_IDS and callers like
set_manual_type_data() will keep HostManual entries out of migration; adjust the
doc comment to mention HostManual if needed and run tests.

In `@xtask/codegen/src/generate_global_types.rs`:
- Around line 150-172: The code currently uses args.verify for
checkout/SourceOptions.verify but relies on mode for emit/update behavior;
ensure a single source of truth by deriving a single bool (e.g. let verify =
matches!(mode, xtask_glue::Mode::Verify) or similar) and use that for
SourceOptions.verify and any verification logic, and then check that args.verify
(if passed) agrees with that derived value and bail with an error if they
disagree; update run_with_workspace_root to compute and use this unified verify
flag instead of mixing args.verify and mode.

---

Outside diff comments:
In `@crates/biome_js_type_info/src/globals.rs`:
- Around line 298-311: The map callback is currently modeled with its parameter
typed as GLOBAL_U_ID which makes map's signature U -> U; update the manual type
data in builder.set_manual_type_data for MAP_CALLBACK_ID_GLOBAL_TYPE_ID so the
Function's parameter PatternFunctionParameter uses GLOBAL_T_ID.into() for ty
(leaving the return_type as GLOBAL_U_ID.into()), i.e. change the parameter type
from GLOBAL_U_ID to GLOBAL_T_ID to correctly represent T -> U; adjust any
imports or constants if needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ae16dbbb-ee3d-44da-a807-08ef15b36dac

📥 Commits

Reviewing files that changed from the base of the PR and between dba36d1 and 220d304.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock and included by **
📒 Files selected for processing (37)
  • .github/workflows/autofix.yml
  • .github/workflows/pull_request.yml
  • Cargo.toml
  • crates/biome_js_type_info/Cargo.toml
  • crates/biome_js_type_info/src/codegen/global_types.rs
  • crates/biome_js_type_info/src/codegen/mod.rs
  • crates/biome_js_type_info/src/globals.rs
  • crates/biome_js_type_info/src/globals_builder.rs
  • crates/biome_js_type_info/src/globals_ids.rs
  • crates/biome_js_type_info/src/lib.rs
  • justfile
  • xtask/codegen/Cargo.toml
  • xtask/codegen/src/generate_global_types.rs
  • xtask/codegen/src/generate_global_types/collect.rs
  • xtask/codegen/src/generate_global_types/emit.rs
  • xtask/codegen/src/generate_global_types/source.rs
  • xtask/codegen/src/lib.rs
  • xtask/codegen/src/main.rs
  • xtask/codegen/tests/fixtures/global-types/collector.basic.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.basic.expected.txt
  • xtask/codegen/tests/fixtures/global-types/collector.declare-global.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.declare-global.expected.txt
  • xtask/codegen/tests/fixtures/global-types/collector.empty-external-module.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.empty-external-module.expected.txt
  • xtask/codegen/tests/fixtures/global-types/collector.export-unsupported.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.export-unsupported.expected.txt
  • xtask/codegen/tests/fixtures/global-types/collector.external-module.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.external-module.expected.txt
  • xtask/codegen/tests/fixtures/global-types/collector.multiple-var.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.multiple-var.expected.txt
  • xtask/codegen/tests/fixtures/global-types/collector.qualified-namespace.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.qualified-namespace.expected.txt
  • xtask/codegen/tests/fixtures/global-types/collector.recursive-scope-accounting.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.recursive-scope-accounting.expected.txt
  • xtask/codegen/tests/fixtures/global-types/collector.unsupported.d.ts
  • xtask/codegen/tests/fixtures/global-types/collector.unsupported.expected.txt
  • xtask/codegen/tests/global_types_codegen.rs

Comment on lines +91 to +97
impl PredefinedGlobalRole {
/// True when the role belongs to the hand-maintained sentinel projection
/// (`Sentinel` / `Primitive` / `Helper`) that must never appear in
/// `MIGRATED_PREDEFINED_IDS`.
pub(crate) const fn is_sentinel_projection(self) -> bool {
matches!(self, Self::Sentinel | Self::Primitive | Self::Helper)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Keep HostManual out of the migratable set.

PredefinedGlobalRole::HostManual is documented as “must stay manual”, but this helper excludes it. That leaves rows like FETCH_ID outside the protected set, so a future MIGRATED_PREDEFINED_IDS entry would make set_manual_type_data() skip the hand-written fallback without any invariant barking. Please enforce the non-migratable contract for HostManual too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/biome_js_type_info/src/globals_ids.rs` around lines 91 - 97, The
helper method PredefinedGlobalRole::is_sentinel_projection currently omits the
HostManual variant so HostManual rows can be treated as migratable; update
is_sentinel_projection to include Self::HostManual in the matches! arm (i.e.,
change matches!(self, Self::Sentinel | Self::Primitive | Self::Helper) to also
include Self::HostManual) so MIGRATED_PREDEFINED_IDS and callers like
set_manual_type_data() will keep HostManual entries out of migration; adjust the
doc comment to mention HostManual if needed and run tests.

Comment on lines +150 to +172
pub fn run_with_workspace_root(
args: GlobalTypesArgs,
mode: xtask_glue::Mode,
workspace_root: &Path,
) -> anyhow::Result<()> {
if args.verify && (args.ts_tag.is_some() || args.ts_sha.is_some()) {
anyhow::bail!(
"--verify cannot be combined with --ts-tag or --ts-sha; verification always uses the default pin"
);
}
if args.ts_tag.is_some() != args.ts_sha.is_some() {
anyhow::bail!("--ts-tag and --ts-sha must be supplied together");
}

let pin = SourcePin::new(
args.ts_tag.as_deref().unwrap_or(DEFAULT_TYPESCRIPT_TAG),
args.ts_sha.as_deref().unwrap_or(DEFAULT_TYPESCRIPT_SHA),
)?;
let opts = source::SourceOptions {
offline: args.offline,
verify: args.verify,
repo_url_override: None,
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use one source of truth for verify mode.

run_with_workspace_root drives checkout validation from args.verify, but emit/update behaviour comes from mode. If those ever drift, a “verify” run can still fetch with overwrite semantics, or vice versa. Please derive both from the same flag, or bail if they disagree.

Possible tidy fix
 pub fn run_with_workspace_root(
     args: GlobalTypesArgs,
     mode: xtask_glue::Mode,
     workspace_root: &Path,
 ) -> anyhow::Result<()> {
-    if args.verify && (args.ts_tag.is_some() || args.ts_sha.is_some()) {
+    let verify = matches!(mode, xtask_glue::Mode::Verify);
+    if args.verify != verify {
+        anyhow::bail!("internal error: args.verify and mode must agree");
+    }
+
+    if verify && (args.ts_tag.is_some() || args.ts_sha.is_some()) {
         anyhow::bail!(
             "--verify cannot be combined with --ts-tag or --ts-sha; verification always uses the default pin"
         );
     }
     if args.ts_tag.is_some() != args.ts_sha.is_some() {
@@
     let opts = source::SourceOptions {
         offline: args.offline,
-        verify: args.verify,
+        verify,
         repo_url_override: None,
     };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@xtask/codegen/src/generate_global_types.rs` around lines 150 - 172, The code
currently uses args.verify for checkout/SourceOptions.verify but relies on mode
for emit/update behavior; ensure a single source of truth by deriving a single
bool (e.g. let verify = matches!(mode, xtask_glue::Mode::Verify) or similar) and
use that for SourceOptions.verify and any verification logic, and then check
that args.verify (if passed) agrees with that derived value and bail with an
error if they disagree; update run_with_workspace_root to compute and use this
unified verify flag instead of mixing args.verify and mode.

Comment on lines +842 to +849
let Ok(owner) = read_acquire_lock_owner(path) else {
return Ok(false);
};
let Some(pid) = owner
.split_once(':')
.and_then(|(pid, _)| pid.parse::<u32>().ok())
else {
return Ok(false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Unreadable lock owners never recover.

If a process dies after create_dir() but before writing owner, this branch returns Ok(false) on every poll. The next run then sleeps for ~60 seconds and fails, even though the lock is already orphaned. Please add a reclaim path for missing/corrupt owner files after a bounded grace period.

Copy link
Copy Markdown
Contributor

@dyc3 dyc3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a quick review, I don't really notice anything fundamentally wrong. nice work.

would be a good idea to check if any of the coderabbit comments are applicable

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: our usual convention is to put generated code in a generated folder. replace codegen with generated

Ok(())
}

#[test]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all these tests should be at the bottom, in a #[cfg(test)] mod tests {} block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Tooling Area: internal tools A-Type-Inference Area: type inference L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants