Summary
With brighterscript-jsdocs-plugin@1.0.0-alpha.1 (paired with brighterscript@1.0.0-alpha.52), any class or interface field whose default value is an object literal ({}) crashes the whole file's doc generation — regardless of whether the field also has an explicit type annotation.
Repro
namespace BGE
class Foo
colliders as roAssociativeArray = {}
end class
end namespace
TypeError: this.getLookupTable is not a function
at BuiltInInterfaceAdder.addBuiltInInterfacesToType (.../brighterscript/dist/types/BuiltInInterfaceAdder.js:53:46)
at AssociativeArrayType.addBuiltInInterfaces (.../brighterscript/dist/types/BscType.js:150:59)
at AALiteralExpression.getType (.../brighterscript/dist/parser/Expression.js:998:20)
at FieldStatement.getType (.../brighterscript/dist/parser/Statement.js:2373:97)
at processClassField (.../brighterscript-jsdocs-plugin/convert-brighterscript-docs.js:379:47)
An array-literal default (items = []) does not crash — only object/associative-array literals.
Root cause
processClassField/processInterfaceField now call field.getType(typeGetOptions) to compute the @property type (a nice improvement over the old plain CustomType check!). FieldStatement.getType() unconditionally evaluates this.initialValue?.getType(...) first — even when an explicit typeExpression is present and takes precedence in the final return — so an initializer of {} always runs through AALiteralExpression.getType().
That method does:
const resultType = new AssociativeArrayType();
resultType.addBuiltInInterfaces();
which calls into BuiltInInterfaceAdder.addBuiltInInterfacesToType, which for roAssociativeArray (a component with interfaces) hits this unguarded line:
const ifaceType = this.getLookupTable()?.getSymbolType(...)
getLookupTable is a static hook normally installed by a full Program/Scope — since this plugin only lexes+parses a single file (no Program), it's never set. Note BuiltInInterfaceAdder already guards this exact check elsewhere in the same file (if (!this.getLookupTable) { ... } a few lines down) — this one call site is just missing the same guard. So this may really be a rokucommunity/brighterscript bug rather than one in this plugin, surfaced by this plugin's single-file (no-Program) usage pattern — but filing here first since I'm not sure which side should own the fix (worth a fast-follow issue against brighterscript too if so).
Impact
This isn't a rare pattern — foo as SomeType = {} / foo = {} field initializers are extremely common (used all over our own engine: Game.bs, GameEntity.bs, Drawable.bs, etc.), so this currently blocks doc generation entirely for any codebase that uses that style.
Suggested fix
Either:
- In
brighterscript, add the same if (!this.getLookupTable) return; guard to the interfacesToLoop branch of BuiltInInterfaceAdder.addBuiltInInterfacesToType that already exists a few lines later in the same file, or
- In this plugin, avoid triggering full
getType() evaluation of the initializer when an explicit typeExpression is present (or wrap the field.getType(...) call defensively).
Summary
With
brighterscript-jsdocs-plugin@1.0.0-alpha.1(paired withbrighterscript@1.0.0-alpha.52), any class or interface field whose default value is an object literal ({}) crashes the whole file's doc generation — regardless of whether the field also has an explicit type annotation.Repro
An array-literal default (
items = []) does not crash — only object/associative-array literals.Root cause
processClassField/processInterfaceFieldnow callfield.getType(typeGetOptions)to compute the@propertytype (a nice improvement over the old plainCustomTypecheck!).FieldStatement.getType()unconditionally evaluatesthis.initialValue?.getType(...)first — even when an explicittypeExpressionis present and takes precedence in the final return — so an initializer of{}always runs throughAALiteralExpression.getType().That method does:
which calls into
BuiltInInterfaceAdder.addBuiltInInterfacesToType, which forroAssociativeArray(a component withinterfaces) hits this unguarded line:getLookupTableis a static hook normally installed by a fullProgram/Scope— since this plugin only lexes+parses a single file (noProgram), it's never set. NoteBuiltInInterfaceAdderalready guards this exact check elsewhere in the same file (if (!this.getLookupTable) { ... }a few lines down) — this one call site is just missing the same guard. So this may really be arokucommunity/brighterscriptbug rather than one in this plugin, surfaced by this plugin's single-file (no-Program) usage pattern — but filing here first since I'm not sure which side should own the fix (worth a fast-follow issue againstbrighterscripttoo if so).Impact
This isn't a rare pattern —
foo as SomeType = {}/foo = {}field initializers are extremely common (used all over our own engine:Game.bs,GameEntity.bs,Drawable.bs, etc.), so this currently blocks doc generation entirely for any codebase that uses that style.Suggested fix
Either:
brighterscript, add the sameif (!this.getLookupTable) return;guard to theinterfacesToLoopbranch ofBuiltInInterfaceAdder.addBuiltInInterfacesToTypethat already exists a few lines later in the same file, orgetType()evaluation of the initializer when an explicittypeExpressionis present (or wrap thefield.getType(...)call defensively).