-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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