oakmac / oakmac/standard-clojure-style-js

gen-class: empty string values format to the literal text `undefined`

Open
#225 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

namespace v1 blocker
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

  1. Widen isStringNode to also accept the two-child (empty) shape, and make getTextFromStringNode return '' when there is no .body. Caution: isStringNode is shared with the ns docstring path and the :require string-libspec path, so this changes behavior beyond gen-class and needs test coverage for those paths (e.g. an empty docstring, (:require ["" :as x])).
  2. 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 to gen-class), and Standard Clojure Style already throws descriptive errors for other malformed gen-class values.
  3. 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.