Make generated JavaScript identifiers hygienic
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 35/100
- Issue type
- Refactor
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- javascript
- Domain
- tooling
Research direction
Start by reading lib/constructs/operation.js, lib/constructs/interface.js, lib/parameters.js, the callback constructs, utils.formatArgs(), RequiresMap, and lib/transformer.js. Generate and run cases covering colliding arguments, imports, callbacks, constructors, processors, and strict-mode names. Done means generated code parses and runs without binding capture or redeclaration while preserving function length, conversions, errors, and implementation calls.
Written by the indexing model from the issue text.
Description
Created by GPT-5.6 Sol Extra High at the maintainer's request.
Problem
webidl2js does not consistently separate names derived from Web IDL from names owned by the JavaScript generator. Valid Web IDL identifiers can therefore collide with generated locals, captured bindings, imports, or strict-mode restrictions. Depending on the name and construct, the generated module can fail to parse or can run with subtly incorrect bindings.
This came up while investigating wrapper branding in #284 and #285. New generated code needed an interface descriptor and a fused receiver implementation local. An operation argument named interfaceDescriptor shadowed an unprefixed module binding, so the experimental implementation used $interfaceDescriptor and $impl: $ is valid in JavaScript identifiers but not in Web IDL identifiers. That prevents those specific collisions, but the same underlying problem already exists elsewhere in the generator.
For example, all of these argument names are valid Web IDL:
[Exposed=Window]
interface Example {
undefined hasDuplicateArgs(any args);
undefined hasDuplicateESValue(any esValue);
undefined shadowsRealm(any globalObject);
undefined shadowsType(Other Other);
};
callback ExampleCallback = undefined (any thisArg);
Current generation can produce failures equivalent to:
hasDuplicateArgs(args) {
const args = []; // SyntaxError
}
hasDuplicateESValue(esValue) {
const esValue = this; // SyntaxError
}
shadowsRealm(globalObject) {
// References intended for the captured realm now resolve to the argument.
}
shadowsType(Other) can shadow a generated const Other = require("./Other.js"), causing conversion code to call .convert() on the argument instead of the generated interface module. Callback-function and callback-interface adapters similarly declare locals such as thisArg, callResult, O, and X in scopes whose formal parameters come directly from Web IDL.
There are several related surfaces to audit:
lib/constructs/operation.jsand constructor generation inlib/constructs/interface.jsuse effective-overload argument names as JavaScript formal parameters, whilelib/parameters.jsintroduces fixed locals includingargsandcurArg.- Instance operation and attribute bodies capture fixed names such as
globalObject,utils,conversions,Impl,exports, and generated interface-module bindings. A same-named formal parameter can shadow them even when it does not cause a redeclaration error. lib/constructs/callback-function.jsandlib/constructs/callback-interface.jsuse Web IDL argument names directly and also introduce their own fixed locals. Some callback paths do not go throughutils.formatArgs()at all.utils.formatArgs()suffixes JavaScript keywords, but does not prevent collisions with generator-owned bindings. Its keyword set also does not cover strict-mode restricted binding names such asevalandarguments.RequiresMapdetects conflicting generated require keys within the map, but fixed module declarations (conversions,utils, andImpl) are added separately bylib/transformer.jsand are invisible to that check. Required Web IDL type names can therefore collide with fixed declarations instead of receiving aliases.- Generated interface and namespace names are emitted as JavaScript bindings. For example, an interface named
globalObjectwould collide with theglobalObjectparameter surrounding its generated class declaration. - Attribute, iterable, async-iterable, legacy-platform-object, dictionary, enumeration, mixin, namespace, callback, and processor-injected code should all be audited rather than assuming the operation examples above are exhaustive. Processor hooks should receive allocated binding references instead of having to guess or reserve names independently.
A quick scan of the current jsdom Web IDL corpus found no collision with the audited fixed local names, which likely explains why this has not appeared in downstream tests. The problematic inputs are nevertheless valid Web IDL.
Suggested direction
Introduce a single identifier-allocation/hygiene policy for generated lexical bindings instead of fixing collisions one at a time.
In particular:
- Do not use Web IDL argument spellings as JavaScript formal parameter names where only arity matters. Regular operations and constructors already read values from
arguments, so formals such as$0,$1, etc. can preserve the required functionlengthwithout exposing IDL names as bindings. - For callbacks, where the current body refers to formal parameters, allocate safe formals by index and maintain an explicit mapping from each IDL argument to its generated binding.
- Allocate or reserve all generator-owned locals, captures, class bindings, and imports consistently. A
$-prefixed namespace is attractive because Web IDL cannot supply such identifiers, but this should be centralized rather than applied ad hoc. A lexical-scope-aware name allocator is another option. - Route
RequiresMapand the fixed transformer imports through the same allocation mechanism, including collisions caused by path-to-key normalization. - Keep original Web IDL names where they are semantically observable or diagnostic—property keys and error messages—but not as untrusted lexical binding names.
- Give processor hooks the actual allocated identifiers they may reference.
The existing $interfaceDescriptor/$impl approach should be understood as a local mitigation and a useful test case, not as completion of this work.
Tests
Regression coverage should generate, load, and exercise code rather than relying only on snapshots. It should cover at least:
- Operation and constructor arguments named
args,curArg,esValue,globalObject,utils,conversions,Impl,exports, and the name of a referenced interface type. - Callback-function and callback-interface arguments named
thisArg,callResult,value,context,Reflect,O, andX. - Strict-mode restricted names such as
evalandarguments, plus JavaScript keywords currently handled byformatArgs(). - Web IDL interface/type names that collide with fixed imports, generated class/install locals, and normalized
RequiresMapkeys. - Non-overloaded and overloaded operations, static and namespace operations, constructors, callbacks, and generated code both with and without processors.
- Preservation of specified function
length, argument conversion behavior, realm-correct errors, and calls into implementations.
The end state should make it mechanically impossible for a valid Web IDL identifier to capture, redeclare, or alter the meaning of a generator-owned JavaScript binding.
- Dominant language
- JavaScript
- Stars
- 98
- Forks
- 35
- Avg merge
- 2h 13m
- Merged PRs (30d)
- 9
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from jsdom/webidl2js
-
Difficulty 1/5 Under an hour Newbie friendliness 35/100
jsdom/webidl2js#257 · 6 comments ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
jsdom/webidl2js#188 · 4 comments ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
jsdom/webidl2js#160 · 3 comments · 2 reactions ·
Maintainers usually reply within 1 day
-
Wrapper lazy instantiationPossibly taken @pmdartus claimed this 2487 days ago. Open
Difficulty 5/5 Over a week Newbie friendliness 25/100
jsdom/webidl2js#157 · 1 comment · 2 reactions ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 30/100
jsdom/webidl2js#84 · 4 comments ·
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 75/100
SACGF/variantgrid#2791 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
zilliztech/memsearch#853 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
MadiroGlobalHealth/UVL-EMR#580 ·
Maintainers usually reply within 1 day
-
ci enhancement need-triage
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
Maintainers usually reply within 1 day
-
[BUG] Mobile menu doesn't work on the Rabbit Behaviour pagePossibly taken @Aryamuh-ynah claimed this today. Openbug
Difficulty 1/5 Under an hour Newbie friendliness 88/100
Riya-Kharade/PetSathi#110 · 1 comment ·
Maintainers usually reply within 1 day