diff --git a/docs/component-statement.md b/docs/component-statement.md index 89300dada..70a6e2409 100644 --- a/docs/component-statement.md +++ b/docs/component-statement.md @@ -4,7 +4,7 @@ You can define a component in code, similar to how you would define a class. ## Basic usage ```vb component MoviePoster extends "Poster" - sub init() + private sub init() print "MoviePoster init()" end sub end component @@ -102,7 +102,7 @@ end component Private properties are written to `m`. Private functions are transpiled to scope-level functions (i.e. not written to m) and we will remove the `m.` when calling those functions. ```vb component MoviePoster extends "Poster" - sub init() + private sub init() m.toggleSubtitles() end sub private areSubtitlesEnabled as boolean = true @@ -347,7 +347,7 @@ XML component templates can also be loaded from another file by using the `@Temp ```vb @TemplateUrl("./MoviePoster.xml") component MoviePoster extends "Poster" - sub init() + private sub init() print "MoviePoster" end sub end component diff --git a/src/bscPlugin/fileProviders/ComponentStatementProvider.ts b/src/bscPlugin/fileProviders/ComponentStatementProvider.ts index ebe04ef5e..c2f19e839 100644 --- a/src/bscPlugin/fileProviders/ComponentStatementProvider.ts +++ b/src/bscPlugin/fileProviders/ComponentStatementProvider.ts @@ -7,11 +7,12 @@ import { Cache } from '../../Cache'; import * as path from 'path'; import { util } from '../../util'; import type { ProvideFileEvent } from '../../interfaces'; -import { isDottedGetExpression, isFieldStatement, isMethodStatement, isVariableExpression } from '../../astUtils/reflection'; +import { isDottedGetExpression, isFieldStatement, isMethodStatement, isVariableExpression, isLiteralExpression, isTemplateStringExpression, isAnnotationExpression } from '../../astUtils/reflection'; import { createFunctionStatement, createFunctionExpression, createDottedSetStatement, createVariableExpression } from '../../astUtils/creators'; import type { Statement } from '../../parser/AstNode'; import { TokenKind } from '../../lexer/TokenKind'; import { VariableExpression } from '../../parser/Expression'; +import type { AnnotationExpression } from '../../parser/Expression'; export class ComponentStatementProvider { constructor( @@ -19,7 +20,6 @@ export class ComponentStatementProvider { ) { } - /** * Create virtual files for every component statement found in this physical file */ @@ -27,7 +27,7 @@ export class ComponentStatementProvider { const cache = new Cache(); file.ast.walk(createVisitor({ ComponentStatement: (node) => { - //force the desetPath for this component to be within the `pkg:/components` folder + //force the destPath for this component to be within the `pkg:/components` folder const destDir = cache.getOrAdd(file.srcPath, () => { return path.dirname(file.destPath).replace(/^(.+?)(?=[\/\\]|$)/, (match: string, firstDirName: string) => { return 'components'; @@ -56,31 +56,91 @@ export class ComponentStatementProvider { //declare interface field } else if (isFieldStatement(member) && member.accessModifier?.text.toLowerCase() === 'public') { - return ``; + return this.generateTagWithAttributes('field', { + id: member.name.text, + type: member.typeExpression.getName(), + alias: this.getAnnotationValue(member.annotations?.filter(x => x.name.toLowerCase() === 'alias')), + onChange: this.getAnnotationValue(member.annotations?.filter(x => x.name.toLowerCase() === 'onchange')), + alwaysNotify: this.getAnnotationValue(member.annotations?.filter(x => x.name.toLowerCase() === 'alwaysnotify')) === 'true' ? 'true' : '' + }, true); } else { return ''; } }).filter(x => !!x); + let componentChildren = ''; + const template = statement.annotations?.find(x => x.name.toLowerCase() === 'template'); + if (isAnnotationExpression(template)) { + // TODO: Better strip of component and children elements. + componentChildren = `${this.getAnnotationValue([template]).replaceAll('', '').replaceAll('', '').replaceAll('', '').replaceAll('', '')}`; + } + + let componentAttributes = { + name: name, + extends: statement.getParentName(ParseMode.BrightScript) ?? 'Group', + initialFocus: '' + }; + const initialFocus = statement.annotations?.find(x => x.name.toLowerCase() === 'initialfocus'); + if (isAnnotationExpression(initialFocus)) { + componentAttributes.initialFocus = this.getAnnotationValue([initialFocus]); + } xmlFile.parse(undent` - + ${this.generateTagWithAttributes('component', componentAttributes)};