Static class properties incorrectly parsed with instance scope instead of static scope
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 15.5k
- Forks
- 1.5k
- Avg merge
- 10d 23h
- Merged PRs (30d)
- 1
Description
Bug Description
JSDoc incorrectly parses static class properties with instance scope (#) instead of static scope (.), resulting in wrong longnames and scope classification.
Expected Behavior
Static class properties should be parsed with:
- Longname:
ClassName.propertyName(using.separator) - Scope:
static
Actual Behavior
Static class properties are parsed with:
- Longname:
ClassName#propertyName(using#separator) - Scope:
instance
Minimal Test Case
Input JavaScript:
/** Sample class with static and instance properties. */
class TestClass {
/** Instance property. */
instanceProp = 'instance';
/** Static property. */
static staticProp = 'static';
/** Static method (works correctly). */
static staticMethod() {
return 'static method';
}
}
Expected JSDoc Output:
TestClass#instancePropwith scopeinstance✅TestClass.staticPropwith scopestatic❌ (currently fails)TestClass.staticMethodwith scopestatic✅
Actual JSDoc Output:
TestClass#instancePropwith scopeinstance✅TestClass#staticPropwith scopeinstance❌ (incorrect)TestClass.staticMethodwith scopestatic✅
Environment
- JSDoc version: 4.x (latest)
- Node.js version: 23.1.0
- Operating System: MacOS 15.6.1 (24G90)
Root Cause Analysis
The bug is located in packages/jsdoc-parse/lib/parser.js at lines 366-373 in the astnodeToMemberof() function:
} else if (isClassProperty(node)) {
doclet = this._getDocletById(node.enclosingScope.nodeId);
if (!doclet) {
result.memberof = LONGNAMES.ANONYMOUS + SCOPE.PUNC.INSTANCE;
} else {
result.memberof = doclet.longname + SCOPE.PUNC.INSTANCE; // ❌ Always uses INSTANCE
}
}
This code always uses SCOPE.PUNC.INSTANCE (#) for class properties, regardless of whether they are static or not.
Proposed Fix
The fix should check the node.static property, similar to how static methods are handled in lines 384-390:
} else if (isClassProperty(node)) {
doclet = this._getDocletById(node.enclosingScope.nodeId);
if (!doclet) {
result.memberof = LONGNAMES.ANONYMOUS + (node.static === true ? SCOPE.PUNC.STATIC : SCOPE.PUNC.INSTANCE);
} else {
result.memberof = doclet.longname + (node.static === true ? SCOPE.PUNC.STATIC : SCOPE.PUNC.INSTANCE);
}
}
Test Case
I can provide a complete test case that demonstrates this bug:
Test fixture: test/fixtures/staticproperties.js fixtures-staticproperties.js
Test spec: test/specs/documentation/staticproperties.js specs-staticproperties.js
The test shows that:
- Static methods are parsed correctly ✅
- Static getters/setters are parsed correctly ✅
- Static properties are parsed incorrectly ❌
Impact
This bug affects:
- Documentation generation for classes with static properties
- Template engines that rely on correct scope classification
- Any tooling that processes JSDoc output and expects correct longnames
Additional Notes
- Static methods and static getters/setters work correctly
- Only static properties (field declarations) are affected
- The bug has been confirmed with a minimal reproducible test case
Contributor guide
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 in packages/jsdoc-parse/lib/parser.js, especially astnodeToMemberof() around lines 366-373, and compare it with the static-method handling around lines 384-390. Run test/specs/documentation/staticproperties.js with test/fixtures/staticproperties.js and verify that static properties produce the expected dot-separated longname and static scope while instance properties remain unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- documentation
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100