oakmac / oakmac/standard-clojure-style-js
gen-class: empty string values format to the literal text `undefined`
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 137
- Forks
- 8
- PR merge metrics
- No merged PRs in 30d
Description
gen-class: empty string values format to the literal text undefined
Description
When a :gen-class key has an empty string ("") as its value, Standard Clojure Style silently corrupts the output by printing the literal text undefined in place of the value. The result is not valid Clojure.
This is pre-existing behavior on master (reproducible before the Issue #31 metadata/strings work), but it became easier to reach now that string values are supported for the name-like keys (:name, :extends, :init, :post-init, :factory, :state, :impl-ns) in addition to :prefix.
Reproduction
(ns foo (:gen-class :prefix ""))
Formats to:
(ns foo
(:gen-class
:prefix undefined))
Same result for :name "" and the other name-like keys. Note the output is idempotent (reformatting it does not error), so the corruption can go unnoticed.
Root cause
An empty string parses to a string node with only two children (.open and .close) — there is no .body node:
{
"name": "string",
"children": [
{ "name": ".open", "text": "\"" },
{ "name": ".close", "text": "\"" }
]
}
isStringNode requires exactly three children with a .body in the middle:
function isStringNode (n) {
return n && n.name === 'string' && isArray(n.children) && arraySize(n.children) === 3 && n.children[1].name === '.body'
}
So "" is never recognized as a string. None of the gen-class value branches match it, result.genClass[key].value is never assigned, and the printer emits ' ' + undefined.
Possible fixes
- Widen
isStringNodeto also accept the two-child (empty) shape, and makegetTextFromStringNodereturn''when there is no.body. Caution:isStringNodeis shared with the ns docstring path and the:requirestring-libspec path, so this changes behavior beyond gen-class and needs test coverage for those paths (e.g. an empty docstring,(:require ["" :as x])). - Throw a parse error for empty-string gen-class values.
""is almost certainly a mistake in the source (an empty class name / prefix is not meaningful togen-class), and Standard Clojure Style already throws descriptive errors for other malformed gen-class values. - Defensive printer check: never print an
undefined/unset gen-class value; throw instead. This would also catch any other future branch-miss of this kind rather than silently corrupting output.
Options 2 and 3 are complementary and lower-risk than option 1.
Related
- Discovered during review of Issue #31 (gen-class metadata and string values work, PR #224).
Contributor guide
No contributing guide indexed for this repository
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.
Research direction
Start at isStringNode and getTextFromStringNode, then trace the gen-class value branches and printer described in the issue. Reproduce the empty-string cases for :prefix and the other name-like keys, and add coverage for the chosen handling, including the shared ns docstring and :require paths if isStringNode changes. Done means no output contains literal undefined and the behavior is covered by tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100