diff --git a/src/DiagnosticMessages.ts b/src/DiagnosticMessages.ts index e96d194dd..16f83f206 100644 --- a/src/DiagnosticMessages.ts +++ b/src/DiagnosticMessages.ts @@ -475,7 +475,7 @@ export let DiagnosticMessages = { code: 'function-not-found' }), xmlInvalidFieldType: (name: string) => ({ - message: `Invalid field type ${name}`, + message: `Invalid field type '${name}'`, legacyCode: 1068, severity: DiagnosticSeverity.Error, code: 'invalid-field-type' diff --git a/src/XmlScope.spec.ts b/src/XmlScope.spec.ts index 1517494f1..bce4d7abf 100644 --- a/src/XmlScope.spec.ts +++ b/src/XmlScope.spec.ts @@ -315,5 +315,111 @@ describe('XmlScope', () => { expectZeroDiagnostics(program); }); + describe('custom types', () => { + it('allows built-in node types as field types', () => { + program.setFile('components/Widget.xml', trim` + + + + + + + `); + program.validate(); + expectZeroDiagnostics(program); + const widgetTypeResult = program.globalScope.symbolTable.getSymbolType('roSGNodeWidget', { flags: SymbolTypeFlag.typetime }); + expectTypeToBe(widgetTypeResult, ComponentType); + const widgetType = widgetTypeResult as ComponentType; + const labelNodeType = widgetType.getMemberType('labelNode', { flags: SymbolTypeFlag.runtime }); + expectTypeToBe(labelNodeType, ComponentType); + expectTypeToBe(labelNodeType.getMemberType('text', { flags: SymbolTypeFlag.runtime }), StringType); + }); + + it('allows unions of primitive types as field types', () => { + program.setFile('components/Widget.xml', trim` + + + + + + + `); + program.validate(); + expectZeroDiagnostics(program); + const widgetTypeResult = program.globalScope.symbolTable.getSymbolType('roSGNodeWidget', { flags: SymbolTypeFlag.typetime }); + expectTypeToBe(widgetTypeResult, ComponentType); + const widgetType = widgetTypeResult as ComponentType; + const publicIdType = widgetType.getMemberType('publicId', { flags: SymbolTypeFlag.runtime }) as UnionType; + expectTypeToBe(publicIdType, UnionType); + expect(publicIdType.types).to.include(IntegerType.instance); + expect(publicIdType.types).to.include(StringType.instance); + }); + + it('disallows unknown types', () => { + program.setFile('components/Widget.xml', trim` + + + + + + + `); + program.validate(); + expectDiagnostics(program, [{ + ...DiagnosticMessages.xmlInvalidFieldType('UnknownType'), + location: { range: Range.create(3, 36, 3, 47) } + }]); + }); + + it('allows types defined in bs files in the scope', () => { + program.setFile('components/Widget.xml', trim` + + +