Skip to content

fix: parse quoted reserved words as string literals - #64

Merged
dprevost-LMI merged 4 commits into
webdriverio:mainfrom
titusfortner:fix/quoted-reserved-word-literals
Jul 1, 2026
Merged

fix: parse quoted reserved words as string literals#64
dprevost-LMI merged 4 commits into
webdriverio:mainfrom
titusfortner:fix/quoted-reserved-word-literals

Conversation

@titusfortner

Copy link
Copy Markdown
Contributor

What

A quoted string whose text matches a reserved type keyword ("null", "bool", "int", "text", …) or a boolean literal ("true"/"false") was parsed as the native type instead of a string literal, and that bug propagated into every code generator (cddl2java, cddl2ts, cddl2py, cddl2swift, cddl2kotlin).

The WebDriver BiDi grammar shows it directly. These two definitions are structurally identical — a single constant-string discriminator:

script.UndefinedValue = {
  type: "undefined",
}

script.NullValue = {
  type: "null",
}

…but they parsed differently:

// script.UndefinedValue → type
[{ "Type": "literal", "Value": "undefined", "Unwrapped": false }]   // correct

// script.NullValue → type  (BEFORE)
["null"]                                                            // wrong: bareword native type

// script.NullValue → type  (AFTER)
[{ "Type": "literal", "Value": "null", "Unwrapped": false }]        // matches UndefinedValue

"undefined" parsed correctly only because there is no undefined keyword case, which is what made the inconsistency visible.

Fixes

1. Parser (cddl)

In parsePropertyType(), the type switch keyed off curToken.Literal (the token text) rather than curToken.Type. A quoted "null" is a STRING token whose Literal is null, so it collided with case Type.NULL. Separately, the default branch checked BOOLEAN_LITERALS before the STRING branch, so "true"/"false" became real booleans.

The fix forces STRING tokens into the literal branch: the keyword switch is skipped for string tokens, and the STRING check now precedes the boolean-literal check. Bare reserved words (null, bool, true, …) are unaffected.

2. cddl2java

Consumes the AST directly, so it now generates script.NullValue the same way it already generates its sibling value types. Previously NullValue was the only discriminated *Value type with a settable Object field:

// before — anomaly
public NullValue(Object type) { this.type = type; }
private final Object type;

// after — matches UndefinedValue / StringValue / BooleanValue, which already do this
public NullValue() { this.type = "null"; }
private final String type;

3. cddl2ts, cddl2py, cddl2swift, cddl2kotlin

All four special-cased any reference with Value === 'null' and emitted the native null type, which intercepted the corrected string literal:

// cddl2ts     before: ScriptNullValue { type: null }       after: { type: "null" }            (matches ScriptUndefinedValue)
// cddl2py     before: class NullValue: type: None          after: type: Literal["null"]        (matches StringValue's Literal["string"])
// cddl2swift  before: struct NullValue { var type: Any? }  after: { var type: String }         (matches UndefinedValue)
// cddl2kotlin before: data class NullValue(val type: Any?) after: (val type: String)            (matches UndefinedValue)

In each generator the guard is narrowed to exclude string literals (&& !isLiteralWithValue(t)), so a bare null reference (e.g. id: js-uint / null) still maps to the nullable/native type, while a quoted "null" now renders as the string literal. This is what retires the downstream NULLABLE_DIFFERENCES workaround.

Tests

  • cddl/parser.test.ts: quoted reserved words parse as string literals; bare reserved words still resolve to native types / booleans.
  • cddl2ts / cddl2py / cddl2swift / cddl2kotlin transform tests: explicit assertions that a quoted "null" renders as the string-literal type, while a bare null in a union stays nullable.
  • Updated parser snapshots (webdriver-local / -remote), the cddl2java NullValue.java fixture, and the cddl2ts / cddl2py / cddl2swift / cddl2kotlin snapshots containing NullValue.
  • Regenerated the tracked cddl2ts cli-examples (local.ts / remote.ts), now ScriptNullValue { type: "null" }.

Full suite: 426 passed.

@titusfortner
titusfortner force-pushed the fix/quoted-reserved-word-literals branch from e5b2ee2 to 2eb87a5 Compare June 25, 2026 19:12
titusfortner added a commit to SeleniumHQ/selenium that referenced this pull request Jun 26, 2026
)

* [js] Add binding-neutral BiDi schema with cddl2ts-gated fidelity

* [js] Project NullValue's quoted "null" tag as a string const (works around webdriverio/cddl#64)
@dprevost-LMI
dprevost-LMI merged commit abcee40 into webdriverio:main Jul 1, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants