brighterscript 1.0.0-alpha.3 → 1.0.0-alpha.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1249 -285
- package/README.md +61 -131
- package/bsconfig.schema.json +68 -2
- package/dist/ActionPipeline.d.ts +10 -0
- package/dist/ActionPipeline.js +40 -0
- package/dist/ActionPipeline.js.map +1 -0
- package/dist/AstValidationSegmenter.d.ts +42 -0
- package/dist/AstValidationSegmenter.js +232 -0
- package/dist/AstValidationSegmenter.js.map +1 -0
- package/dist/BsConfig.d.ts +51 -6
- package/dist/BusyStatusTracker.d.ts +31 -0
- package/dist/BusyStatusTracker.js +83 -0
- package/dist/BusyStatusTracker.js.map +1 -0
- package/dist/Cache.d.ts +5 -6
- package/dist/Cache.js +12 -11
- package/dist/Cache.js.map +1 -1
- package/dist/CacheVerifier.d.ts +7 -0
- package/dist/CacheVerifier.js +20 -0
- package/dist/CacheVerifier.js.map +1 -0
- package/dist/CodeActionUtil.d.ts +11 -2
- package/dist/CodeActionUtil.js +17 -3
- package/dist/CodeActionUtil.js.map +1 -1
- package/dist/CommentFlagProcessor.d.ts +7 -6
- package/dist/CommentFlagProcessor.js +10 -7
- package/dist/CommentFlagProcessor.js.map +1 -1
- package/dist/CrossScopeValidator.d.ts +67 -0
- package/dist/CrossScopeValidator.js +625 -0
- package/dist/CrossScopeValidator.js.map +1 -0
- package/dist/DependencyGraph.d.ts +8 -3
- package/dist/DependencyGraph.js +49 -16
- package/dist/DependencyGraph.js.map +1 -1
- package/dist/DiagnosticCollection.d.ts +5 -3
- package/dist/DiagnosticCollection.js +18 -16
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticFilterer.d.ts +8 -4
- package/dist/DiagnosticFilterer.js +77 -44
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticManager.d.ts +56 -0
- package/dist/DiagnosticManager.js +218 -0
- package/dist/DiagnosticManager.js.map +1 -0
- package/dist/DiagnosticMessages.d.ts +187 -20
- package/dist/DiagnosticMessages.js +247 -29
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
- package/dist/DiagnosticSeverityAdjuster.js +41 -0
- package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
- package/dist/FunctionScope.d.ts +28 -0
- package/dist/FunctionScope.js +52 -0
- package/dist/FunctionScope.js.map +1 -0
- package/dist/KeyedThrottler.d.ts +3 -3
- package/dist/KeyedThrottler.js +3 -3
- package/dist/KeyedThrottler.js.map +1 -1
- package/dist/LanguageServer.d.ts +72 -47
- package/dist/LanguageServer.js +544 -312
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Logger.d.ts +9 -10
- package/dist/Logger.js +36 -30
- package/dist/Logger.js.map +1 -1
- package/dist/PluginInterface.d.ts +29 -7
- package/dist/PluginInterface.js +90 -7
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +199 -100
- package/dist/Program.js +1056 -700
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +29 -18
- package/dist/ProgramBuilder.js +170 -132
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +144 -109
- package/dist/Scope.js +533 -552
- package/dist/Scope.js.map +1 -1
- package/dist/SemanticTokenUtils.d.ts +14 -0
- package/dist/SemanticTokenUtils.js +85 -0
- package/dist/SemanticTokenUtils.js.map +1 -0
- package/dist/Stopwatch.d.ts +4 -0
- package/dist/Stopwatch.js +8 -1
- package/dist/Stopwatch.js.map +1 -1
- package/dist/SymbolTable.d.ts +91 -24
- package/dist/SymbolTable.js +290 -64
- package/dist/SymbolTable.js.map +1 -1
- package/dist/SymbolTypeFlag.d.ts +9 -0
- package/dist/SymbolTypeFlag.js +14 -0
- package/dist/SymbolTypeFlag.js.map +1 -0
- package/dist/Throttler.d.ts +12 -0
- package/dist/Throttler.js +39 -0
- package/dist/Throttler.js.map +1 -1
- package/dist/Watcher.d.ts +0 -3
- package/dist/Watcher.js +0 -3
- package/dist/Watcher.js.map +1 -1
- package/dist/XmlScope.d.ts +5 -15
- package/dist/XmlScope.js +35 -87
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/CachedLookups.d.ts +50 -0
- package/dist/astUtils/CachedLookups.js +331 -0
- package/dist/astUtils/CachedLookups.js.map +1 -0
- package/dist/astUtils/Editor.d.ts +69 -0
- package/dist/astUtils/Editor.js +245 -0
- package/dist/astUtils/Editor.js.map +1 -0
- package/dist/astUtils/Editor.spec.js +258 -0
- package/dist/astUtils/Editor.spec.js.map +1 -0
- package/dist/astUtils/creators.d.ts +33 -10
- package/dist/astUtils/creators.js +224 -30
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/creators.spec.js +5 -5
- package/dist/astUtils/creators.spec.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +146 -82
- package/dist/astUtils/reflection.js +308 -132
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +267 -162
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/stackedVisitor.js.map +1 -1
- package/dist/astUtils/stackedVisitor.spec.js +14 -14
- package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +115 -53
- package/dist/astUtils/visitors.js +70 -13
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +465 -51
- package/dist/astUtils/visitors.spec.js.map +1 -1
- package/dist/astUtils/xml.d.ts +9 -8
- package/dist/astUtils/xml.js +10 -5
- package/dist/astUtils/xml.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +22 -1
- package/dist/bscPlugin/BscPlugin.js +88 -0
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
- package/dist/bscPlugin/CallExpressionInfo.js +131 -0
- package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
- package/dist/bscPlugin/FileWriter.d.ts +6 -0
- package/dist/bscPlugin/FileWriter.js +24 -0
- package/dist/bscPlugin/FileWriter.js.map +1 -0
- package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
- package/dist/bscPlugin/SignatureHelpUtil.js +137 -0
- package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +26 -17
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +94 -20
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +60 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js +601 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +2139 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
- package/dist/bscPlugin/definition/DefinitionProvider.js +210 -0
- package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
- package/dist/bscPlugin/definition/DefinitionProvider.spec.js +88 -0
- package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
- package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
- package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
- package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.d.ts +18 -0
- package/dist/bscPlugin/hover/HoverProcessor.js +218 -0
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.js +737 -0
- package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
- package/dist/bscPlugin/references/ReferencesProvider.js +56 -0
- package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.js +51 -0
- package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +14 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +144 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +504 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
- package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
- package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
- package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
- package/dist/bscPlugin/serialize/BslibManager.js +40 -0
- package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
- package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
- package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
- package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.d.ts +7 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js +22 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js.map +1 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js +291 -0
- package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.d.ts +7 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js +26 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js.map +1 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js +245 -0
- package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/symbols/symbolUtils.d.ts +5 -0
- package/dist/bscPlugin/symbols/symbolUtils.js +140 -0
- package/dist/bscPlugin/symbols/symbolUtils.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +21 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +199 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
- package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileAfterValidator.d.ts +7 -0
- package/dist/bscPlugin/validation/BrsFileAfterValidator.js +18 -0
- package/dist/bscPlugin/validation/BrsFileAfterValidator.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.d.ts +34 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js +462 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js +758 -0
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
- package/dist/bscPlugin/validation/ProgramValidator.d.ts +11 -0
- package/dist/bscPlugin/validation/ProgramValidator.js +33 -0
- package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.d.ts +123 -0
- package/dist/bscPlugin/validation/ScopeValidator.js +1026 -0
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js +2897 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
- package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
- package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
- package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
- package/dist/cli.js +117 -11
- package/dist/cli.js.map +1 -1
- package/dist/deferred.d.ts +3 -3
- package/dist/deferred.js.map +1 -1
- package/dist/diagnosticUtils.d.ts +10 -3
- package/dist/diagnosticUtils.js +58 -21
- package/dist/diagnosticUtils.js.map +1 -1
- package/dist/examples/plugins/removePrint.js +8 -12
- package/dist/examples/plugins/removePrint.js.map +1 -1
- package/dist/files/AssetFile.d.ts +24 -0
- package/dist/files/AssetFile.js +25 -0
- package/dist/files/AssetFile.js.map +1 -0
- package/dist/files/BrsFile.Class.spec.js +858 -153
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +147 -82
- package/dist/files/BrsFile.js +853 -911
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +3056 -836
- package/dist/files/BrsFile.spec.js.map +1 -1
- package/dist/files/BscFile.d.ts +101 -0
- package/dist/files/BscFile.js +15 -0
- package/dist/files/BscFile.js.map +1 -0
- package/dist/files/Factory.d.ts +25 -0
- package/dist/files/Factory.js +22 -0
- package/dist/files/Factory.js.map +1 -0
- package/dist/files/LazyFileData.d.ts +20 -0
- package/dist/files/LazyFileData.js +54 -0
- package/dist/files/LazyFileData.js.map +1 -0
- package/dist/files/LazyFileData.spec.d.ts +1 -0
- package/dist/files/LazyFileData.spec.js +27 -0
- package/dist/files/LazyFileData.spec.js.map +1 -0
- package/dist/files/XmlFile.d.ts +73 -41
- package/dist/files/XmlFile.js +126 -138
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +450 -318
- package/dist/files/XmlFile.spec.js.map +1 -1
- package/dist/files/tests/imports.spec.js +62 -52
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/files/tests/optionalChaning.spec.d.ts +1 -0
- package/dist/files/tests/optionalChaning.spec.js +152 -0
- package/dist/files/tests/optionalChaning.spec.js.map +1 -0
- package/dist/globalCallables.d.ts +3 -1
- package/dist/globalCallables.js +416 -162
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +25 -3
- package/dist/index.js +42 -5
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +717 -119
- package/dist/interfaces.js +21 -0
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/Character.spec.js +5 -5
- package/dist/lexer/Character.spec.js.map +1 -1
- package/dist/lexer/Lexer.d.ts +40 -9
- package/dist/lexer/Lexer.js +191 -49
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Lexer.spec.js +775 -563
- package/dist/lexer/Lexer.spec.js.map +1 -1
- package/dist/lexer/Token.d.ts +11 -3
- package/dist/lexer/Token.js +10 -2
- package/dist/lexer/Token.js.map +1 -1
- package/dist/lexer/TokenKind.d.ts +27 -1
- package/dist/lexer/TokenKind.js +112 -5
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/logging.d.ts +9 -0
- package/dist/logging.js +16 -0
- package/dist/logging.js.map +1 -0
- package/dist/parser/AstNode.d.ts +181 -0
- package/dist/parser/AstNode.js +246 -0
- package/dist/parser/AstNode.js.map +1 -0
- package/dist/parser/AstNode.spec.d.ts +1 -0
- package/dist/parser/AstNode.spec.js +165 -0
- package/dist/parser/AstNode.spec.js.map +1 -0
- package/dist/parser/BrsTranspileState.d.ts +12 -2
- package/dist/parser/BrsTranspileState.js +6 -0
- package/dist/parser/BrsTranspileState.js.map +1 -1
- package/dist/parser/Expression.d.ts +454 -210
- package/dist/parser/Expression.js +953 -498
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +200 -95
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.d.ts +106 -120
- package/dist/parser/Parser.js +1432 -931
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.d.ts +3 -1
- package/dist/parser/Parser.spec.js +1383 -456
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGParser.d.ts +44 -6
- package/dist/parser/SGParser.js +212 -185
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGParser.spec.js +30 -28
- package/dist/parser/SGParser.spec.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +293 -50
- package/dist/parser/SGTypes.js +540 -187
- package/dist/parser/SGTypes.js.map +1 -1
- package/dist/parser/Statement.d.ts +759 -247
- package/dist/parser/Statement.js +1785 -607
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/Statement.spec.js +45 -34
- package/dist/parser/Statement.spec.js.map +1 -1
- package/dist/parser/TranspileState.d.ts +18 -8
- package/dist/parser/TranspileState.js +76 -12
- package/dist/parser/TranspileState.js.map +1 -1
- package/dist/parser/tests/Parser.spec.d.ts +10 -9
- package/dist/parser/tests/Parser.spec.js +18 -14
- package/dist/parser/tests/Parser.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/For.spec.js +79 -69
- package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +53 -47
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/If.spec.js +217 -196
- package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
- package/dist/parser/tests/controlFlow/While.spec.js +48 -42
- package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
- package/dist/parser/tests/expression/Additive.spec.js +31 -31
- package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.js +157 -120
- package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +202 -139
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
- package/dist/parser/tests/expression/Boolean.spec.js +25 -25
- package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
- package/dist/parser/tests/expression/Call.spec.js +150 -41
- package/dist/parser/tests/expression/Call.spec.js.map +1 -1
- package/dist/parser/tests/expression/Exponential.spec.js +18 -18
- package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
- package/dist/parser/tests/expression/Function.spec.js +257 -257
- package/dist/parser/tests/expression/Function.spec.js.map +1 -1
- package/dist/parser/tests/expression/Indexing.spec.js +160 -90
- package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
- package/dist/parser/tests/expression/Multiplicative.spec.js +38 -38
- package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +196 -98
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.js +42 -42
- package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
- package/dist/parser/tests/expression/Primary.spec.js +42 -42
- package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +171 -0
- package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -0
- package/dist/parser/tests/expression/Relational.spec.js +44 -44
- package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +31 -31
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +230 -90
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +377 -148
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/TypeExpression.spec.js +126 -0
- package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
- package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
- package/dist/parser/tests/statement/AssignmentOperators.spec.js +37 -37
- package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
- package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
- package/dist/parser/tests/statement/ConstStatement.spec.js +262 -0
- package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
- package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
- package/dist/parser/tests/statement/Continue.spec.js +119 -0
- package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
- package/dist/parser/tests/statement/Declaration.spec.js +45 -45
- package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
- package/dist/parser/tests/statement/Dim.spec.js +22 -22
- package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
- package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
- package/dist/parser/tests/statement/Enum.spec.js +745 -0
- package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
- package/dist/parser/tests/statement/For.spec.d.ts +1 -0
- package/dist/parser/tests/statement/For.spec.js +45 -0
- package/dist/parser/tests/statement/For.spec.js.map +1 -0
- package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
- package/dist/parser/tests/statement/ForEach.spec.js +36 -0
- package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
- package/dist/parser/tests/statement/Function.spec.js +208 -198
- package/dist/parser/tests/statement/Function.spec.js.map +1 -1
- package/dist/parser/tests/statement/Goto.spec.js +16 -15
- package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
- package/dist/parser/tests/statement/Increment.spec.js +51 -51
- package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
- package/dist/parser/tests/statement/InterfaceStatement.spec.d.ts +1 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js +110 -0
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -0
- package/dist/parser/tests/statement/LibraryStatement.spec.js +18 -18
- package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Misc.spec.js +123 -163
- package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +125 -108
- package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/ReturnStatement.spec.js +51 -49
- package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/Set.spec.js +110 -97
- package/dist/parser/tests/statement/Set.spec.js.map +1 -1
- package/dist/parser/tests/statement/Stop.spec.js +13 -12
- package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
- package/dist/parser/tests/statement/Throw.spec.js +6 -6
- package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
- package/dist/parser/tests/statement/TryCatch.spec.js +26 -15
- package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
- package/dist/preprocessor/Manifest.d.ts +6 -6
- package/dist/preprocessor/Manifest.js +17 -38
- package/dist/preprocessor/Manifest.js.map +1 -1
- package/dist/preprocessor/Manifest.spec.d.ts +1 -0
- package/dist/preprocessor/Manifest.spec.js +78 -103
- package/dist/preprocessor/Manifest.spec.js.map +1 -1
- package/dist/roku-types/data.json +19369 -0
- package/dist/roku-types/index.d.ts +5497 -0
- package/dist/roku-types/index.js +11 -0
- package/dist/roku-types/index.js.map +1 -0
- package/dist/types/ArrayType.d.ts +9 -5
- package/dist/types/ArrayType.js +68 -24
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/ArrayType.spec.js +39 -11
- package/dist/types/ArrayType.spec.js.map +1 -1
- package/dist/types/AssociativeArrayType.d.ts +14 -0
- package/dist/types/AssociativeArrayType.js +60 -0
- package/dist/types/AssociativeArrayType.js.map +1 -0
- package/dist/types/BaseFunctionType.d.ts +9 -0
- package/dist/types/BaseFunctionType.js +25 -0
- package/dist/types/BaseFunctionType.js.map +1 -0
- package/dist/types/BooleanType.d.ts +10 -5
- package/dist/types/BooleanType.js +21 -9
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BooleanType.spec.js +10 -4
- package/dist/types/BooleanType.spec.js.map +1 -1
- package/dist/types/BscType.d.ts +29 -3
- package/dist/types/BscType.js +121 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/BscTypeKind.d.ts +25 -0
- package/dist/types/BscTypeKind.js +30 -0
- package/dist/types/BscTypeKind.js.map +1 -0
- package/dist/types/BuiltInInterfaceAdder.d.ts +25 -0
- package/dist/types/BuiltInInterfaceAdder.js +201 -0
- package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
- package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
- package/dist/types/BuiltInInterfaceAdder.spec.js +115 -0
- package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
- package/dist/types/ClassType.d.ts +16 -0
- package/dist/types/ClassType.js +57 -0
- package/dist/types/ClassType.js.map +1 -0
- package/dist/types/ClassType.spec.d.ts +1 -0
- package/dist/types/ClassType.spec.js +76 -0
- package/dist/types/ClassType.spec.js.map +1 -0
- package/dist/types/ComponentType.d.ts +27 -0
- package/dist/types/ComponentType.js +83 -0
- package/dist/types/ComponentType.js.map +1 -0
- package/dist/types/DoubleType.d.ts +10 -5
- package/dist/types/DoubleType.js +25 -18
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/DoubleType.spec.js +12 -4
- package/dist/types/DoubleType.spec.js.map +1 -1
- package/dist/types/DynamicType.d.ts +12 -5
- package/dist/types/DynamicType.js +22 -6
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/types/DynamicType.spec.js +16 -5
- package/dist/types/DynamicType.spec.js.map +1 -1
- package/dist/types/EnumType.d.ts +40 -0
- package/dist/types/EnumType.js +80 -0
- package/dist/types/EnumType.js.map +1 -0
- package/dist/types/EnumType.spec.d.ts +1 -0
- package/dist/types/EnumType.spec.js +33 -0
- package/dist/types/EnumType.spec.js.map +1 -0
- package/dist/types/FloatType.d.ts +10 -5
- package/dist/types/FloatType.js +25 -18
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/FloatType.spec.js +4 -4
- package/dist/types/FloatType.spec.js.map +1 -1
- package/dist/types/FunctionType.d.ts +10 -22
- package/dist/types/FunctionType.js +26 -63
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/InheritableType.d.ts +28 -0
- package/dist/types/InheritableType.js +157 -0
- package/dist/types/InheritableType.js.map +1 -0
- package/dist/types/IntegerType.d.ts +10 -5
- package/dist/types/IntegerType.js +25 -18
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/IntegerType.spec.js +8 -4
- package/dist/types/IntegerType.spec.js.map +1 -1
- package/dist/types/InterfaceType.d.ts +14 -6
- package/dist/types/InterfaceType.js +26 -15
- package/dist/types/InterfaceType.js.map +1 -1
- package/dist/types/InterfaceType.spec.d.ts +1 -0
- package/dist/types/InterfaceType.spec.js +227 -0
- package/dist/types/InterfaceType.spec.js.map +1 -0
- package/dist/types/InvalidType.d.ts +9 -5
- package/dist/types/InvalidType.js +20 -9
- package/dist/types/InvalidType.js.map +1 -1
- package/dist/types/InvalidType.spec.js +8 -4
- package/dist/types/InvalidType.spec.js.map +1 -1
- package/dist/types/LongIntegerType.d.ts +10 -5
- package/dist/types/LongIntegerType.js +25 -18
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/LongIntegerType.spec.js +10 -4
- package/dist/types/LongIntegerType.spec.js.map +1 -1
- package/dist/types/NamespaceType.d.ts +12 -0
- package/dist/types/NamespaceType.js +28 -0
- package/dist/types/NamespaceType.js.map +1 -0
- package/dist/types/ObjectType.d.ts +10 -5
- package/dist/types/ObjectType.js +23 -9
- package/dist/types/ObjectType.js.map +1 -1
- package/dist/types/ObjectType.spec.js +3 -3
- package/dist/types/ObjectType.spec.js.map +1 -1
- package/dist/types/ReferenceType.d.ts +79 -0
- package/dist/types/ReferenceType.js +522 -0
- package/dist/types/ReferenceType.js.map +1 -0
- package/dist/types/ReferenceType.spec.d.ts +1 -0
- package/dist/types/ReferenceType.spec.js +151 -0
- package/dist/types/ReferenceType.spec.js.map +1 -0
- package/dist/types/StringType.d.ts +13 -5
- package/dist/types/StringType.js +25 -9
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/StringType.spec.js +3 -3
- package/dist/types/StringType.spec.js.map +1 -1
- package/dist/types/TypedFunctionType.d.ts +33 -0
- package/dist/types/TypedFunctionType.js +106 -0
- package/dist/types/TypedFunctionType.js.map +1 -0
- package/dist/types/TypedFunctionType.spec.d.ts +1 -0
- package/dist/types/TypedFunctionType.spec.js +122 -0
- package/dist/types/TypedFunctionType.spec.js.map +1 -0
- package/dist/types/UninitializedType.d.ts +8 -6
- package/dist/types/UninitializedType.js +15 -9
- package/dist/types/UninitializedType.js.map +1 -1
- package/dist/types/UnionType.d.ts +20 -0
- package/dist/types/UnionType.js +127 -0
- package/dist/types/UnionType.js.map +1 -0
- package/dist/types/UnionType.spec.d.ts +1 -0
- package/dist/types/UnionType.spec.js +129 -0
- package/dist/types/UnionType.spec.js.map +1 -0
- package/dist/types/VoidType.d.ts +10 -5
- package/dist/types/VoidType.js +20 -9
- package/dist/types/VoidType.js.map +1 -1
- package/dist/types/VoidType.spec.js +3 -3
- package/dist/types/VoidType.spec.js.map +1 -1
- package/dist/types/helper.spec.d.ts +1 -0
- package/dist/types/helper.spec.js +144 -0
- package/dist/types/helper.spec.js.map +1 -0
- package/dist/types/helpers.d.ts +26 -0
- package/dist/types/helpers.js +191 -0
- package/dist/types/helpers.js.map +1 -0
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.js +39 -0
- package/dist/types/index.js.map +1 -0
- package/dist/util.d.ts +218 -106
- package/dist/util.js +1310 -320
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +9 -15
- package/dist/validators/ClassValidator.js +81 -134
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +169 -138
- package/dist/astUtils/index.d.ts +0 -7
- package/dist/astUtils/index.js +0 -26
- package/dist/astUtils/index.js.map +0 -1
- package/dist/lexer/index.d.ts +0 -3
- package/dist/lexer/index.js +0 -17
- package/dist/lexer/index.js.map +0 -1
- package/dist/parser/index.d.ts +0 -3
- package/dist/parser/index.js +0 -16
- package/dist/parser/index.js.map +0 -1
- package/dist/preprocessor/Chunk.d.ts +0 -82
- package/dist/preprocessor/Chunk.js +0 -77
- package/dist/preprocessor/Chunk.js.map +0 -1
- package/dist/preprocessor/Preprocessor.d.ts +0 -60
- package/dist/preprocessor/Preprocessor.js +0 -156
- package/dist/preprocessor/Preprocessor.js.map +0 -1
- package/dist/preprocessor/Preprocessor.spec.js +0 -152
- package/dist/preprocessor/Preprocessor.spec.js.map +0 -1
- package/dist/preprocessor/PreprocessorParser.d.ts +0 -61
- package/dist/preprocessor/PreprocessorParser.js +0 -194
- package/dist/preprocessor/PreprocessorParser.js.map +0 -1
- package/dist/preprocessor/PreprocessorParser.spec.js +0 -116
- package/dist/preprocessor/PreprocessorParser.spec.js.map +0 -1
- package/dist/preprocessor/index.d.ts +0 -3
- package/dist/preprocessor/index.js +0 -16
- package/dist/preprocessor/index.js.map +0 -1
- package/dist/types/CustomType.d.ts +0 -10
- package/dist/types/CustomType.js +0 -35
- package/dist/types/CustomType.js.map +0 -1
- package/dist/types/FunctionType.spec.js +0 -29
- package/dist/types/FunctionType.spec.js.map +0 -1
- package/dist/types/LazyType.d.ts +0 -15
- package/dist/types/LazyType.js +0 -32
- package/dist/types/LazyType.js.map +0 -1
- /package/dist/{preprocessor/Preprocessor.spec.d.ts → astUtils/Editor.spec.d.ts} +0 -0
- /package/dist/{preprocessor/PreprocessorParser.spec.d.ts → bscPlugin/completions/CompletionsProcessor.spec.d.ts} +0 -0
- /package/dist/{types/FunctionType.spec.d.ts → bscPlugin/definition/DefinitionProvider.spec.d.ts} +0 -0
package/dist/Program.js
CHANGED
|
@@ -4,35 +4,58 @@ exports.Program = void 0;
|
|
|
4
4
|
const assert = require("assert");
|
|
5
5
|
const fsExtra = require("fs-extra");
|
|
6
6
|
const path = require("path");
|
|
7
|
-
const vscode_languageserver_1 = require("vscode-languageserver");
|
|
8
7
|
const Scope_1 = require("./Scope");
|
|
9
8
|
const DiagnosticMessages_1 = require("./DiagnosticMessages");
|
|
10
|
-
const BrsFile_1 = require("./files/BrsFile");
|
|
11
|
-
const XmlFile_1 = require("./files/XmlFile");
|
|
12
9
|
const util_1 = require("./util");
|
|
13
10
|
const XmlScope_1 = require("./XmlScope");
|
|
14
|
-
const DiagnosticFilterer_1 = require("./DiagnosticFilterer");
|
|
15
11
|
const DependencyGraph_1 = require("./DependencyGraph");
|
|
16
|
-
const
|
|
12
|
+
const logging_1 = require("./logging");
|
|
17
13
|
const chalk_1 = require("chalk");
|
|
18
14
|
const globalCallables_1 = require("./globalCallables");
|
|
19
15
|
const Manifest_1 = require("./preprocessor/Manifest");
|
|
20
16
|
const vscode_uri_1 = require("vscode-uri");
|
|
21
17
|
const PluginInterface_1 = require("./PluginInterface");
|
|
22
18
|
const reflection_1 = require("./astUtils/reflection");
|
|
23
|
-
const parser_1 = require("./parser");
|
|
24
|
-
const lexer_1 = require("./lexer");
|
|
25
19
|
const BscPlugin_1 = require("./bscPlugin/BscPlugin");
|
|
20
|
+
const Editor_1 = require("./astUtils/Editor");
|
|
21
|
+
const CallExpressionInfo_1 = require("./bscPlugin/CallExpressionInfo");
|
|
22
|
+
const SignatureHelpUtil_1 = require("./bscPlugin/SignatureHelpUtil");
|
|
23
|
+
const IntegerType_1 = require("./types/IntegerType");
|
|
24
|
+
const StringType_1 = require("./types/StringType");
|
|
25
|
+
const BooleanType_1 = require("./types/BooleanType");
|
|
26
|
+
const DoubleType_1 = require("./types/DoubleType");
|
|
27
|
+
const DynamicType_1 = require("./types/DynamicType");
|
|
28
|
+
const FloatType_1 = require("./types/FloatType");
|
|
29
|
+
const LongIntegerType_1 = require("./types/LongIntegerType");
|
|
30
|
+
const ObjectType_1 = require("./types/ObjectType");
|
|
31
|
+
const VoidType_1 = require("./types/VoidType");
|
|
32
|
+
const FunctionType_1 = require("./types/FunctionType");
|
|
33
|
+
const Factory_1 = require("./files/Factory");
|
|
34
|
+
const ActionPipeline_1 = require("./ActionPipeline");
|
|
35
|
+
const LazyFileData_1 = require("./files/LazyFileData");
|
|
26
36
|
const roku_deploy_1 = require("roku-deploy");
|
|
27
|
-
const
|
|
28
|
-
const
|
|
37
|
+
const roku_types_1 = require("./roku-types");
|
|
38
|
+
const ComponentType_1 = require("./types/ComponentType");
|
|
39
|
+
const InterfaceType_1 = require("./types/InterfaceType");
|
|
40
|
+
const BuiltInInterfaceAdder_1 = require("./types/BuiltInInterfaceAdder");
|
|
41
|
+
const visitors_1 = require("./astUtils/visitors");
|
|
42
|
+
const Stopwatch_1 = require("./Stopwatch");
|
|
43
|
+
const thenby_1 = require("thenby");
|
|
44
|
+
const CrossScopeValidator_1 = require("./CrossScopeValidator");
|
|
45
|
+
const DiagnosticManager_1 = require("./DiagnosticManager");
|
|
46
|
+
const ProgramValidator_1 = require("./bscPlugin/validation/ProgramValidator");
|
|
47
|
+
const bslibNonAliasedRokuModulesPkgPath = (0, util_1.standardizePath) `source/roku_modules/rokucommunity_bslib/bslib.brs`;
|
|
48
|
+
const bslibAliasedRokuModulesPkgPath = (0, util_1.standardizePath) `source/roku_modules/bslib/bslib.brs`;
|
|
29
49
|
class Program {
|
|
30
50
|
constructor(
|
|
31
51
|
/**
|
|
32
52
|
* The root directory for this program
|
|
33
53
|
*/
|
|
34
|
-
options, logger, plugins) {
|
|
35
|
-
|
|
54
|
+
options, logger, plugins, diagnosticsManager) {
|
|
55
|
+
/**
|
|
56
|
+
* An editor that plugins can use to modify program-level things during the build flow. Don't use this to edit files (they have their own `.editor`)
|
|
57
|
+
*/
|
|
58
|
+
this.editor = new Editor_1.Editor();
|
|
36
59
|
/**
|
|
37
60
|
* A graph of all files and their dependencies.
|
|
38
61
|
* For example:
|
|
@@ -40,20 +63,26 @@ class Program {
|
|
|
40
63
|
* lib2.brs -> [lib3.brs] //via an import statement
|
|
41
64
|
*/
|
|
42
65
|
this.dependencyGraph = new DependencyGraph_1.DependencyGraph();
|
|
43
|
-
this.diagnosticFilterer = new DiagnosticFilterer_1.DiagnosticFilterer();
|
|
44
66
|
/**
|
|
45
|
-
* A
|
|
46
|
-
*
|
|
67
|
+
* A scope that contains all built-in global functions.
|
|
68
|
+
* All scopes should directly or indirectly inherit from this scope
|
|
47
69
|
*/
|
|
48
|
-
this.
|
|
70
|
+
this.globalScope = undefined;
|
|
71
|
+
this.fileSymbolInformation = new Map();
|
|
49
72
|
/**
|
|
50
|
-
* A map of every file loaded
|
|
73
|
+
* A map of every file loaded into this program, indexed by its original file location
|
|
51
74
|
*/
|
|
52
|
-
this.
|
|
75
|
+
this.files = {};
|
|
53
76
|
/**
|
|
54
|
-
* A map of every file loaded into this program, indexed by its
|
|
77
|
+
* A map of every file loaded into this program, indexed by its destPath
|
|
55
78
|
*/
|
|
56
|
-
this.
|
|
79
|
+
this.destMap = new Map();
|
|
80
|
+
/**
|
|
81
|
+
* Plugins can contribute multiple virtual files for a single physical file.
|
|
82
|
+
* This collection links the virtual files back to the physical file that produced them.
|
|
83
|
+
* The key is the standardized and lower-cased srcPath
|
|
84
|
+
*/
|
|
85
|
+
this.fileClusters = new Map();
|
|
57
86
|
this.scopes = {};
|
|
58
87
|
/**
|
|
59
88
|
* A map of every component currently loaded into the program, indexed by the component name.
|
|
@@ -62,28 +91,121 @@ class Program {
|
|
|
62
91
|
* but if you do, only ever use the component at index 0.
|
|
63
92
|
*/
|
|
64
93
|
this.components = {};
|
|
94
|
+
/**
|
|
95
|
+
* Keeps a set of all the components that need to have their types updated during the current validation cycle
|
|
96
|
+
*/
|
|
97
|
+
this.componentSymbolsToUpdate = new Set();
|
|
98
|
+
this.crossScopeValidation = new CrossScopeValidator_1.CrossScopeValidator(this);
|
|
99
|
+
this.isFirstValidation = true;
|
|
100
|
+
this.getTranspiledFileContentsPipeline = new ActionPipeline_1.ActionPipeline();
|
|
101
|
+
this.buildPipeline = new ActionPipeline_1.ActionPipeline();
|
|
65
102
|
this.options = util_1.util.normalizeConfig(options);
|
|
66
|
-
this.logger = logger
|
|
67
|
-
this.plugins = plugins || new PluginInterface_1.default([], this.logger);
|
|
103
|
+
this.logger = logger !== null && logger !== void 0 ? logger : (0, logging_1.createLogger)(options);
|
|
104
|
+
this.plugins = plugins || new PluginInterface_1.default([], { logger: this.logger });
|
|
105
|
+
this.diagnostics = diagnosticsManager || new DiagnosticManager_1.DiagnosticManager();
|
|
106
|
+
// initialize teh diagnostics Manager
|
|
107
|
+
this.diagnostics.logger = this.logger;
|
|
108
|
+
this.diagnostics.options = this.options;
|
|
68
109
|
//inject the bsc plugin as the first plugin in the stack.
|
|
69
110
|
this.plugins.addFirst(new BscPlugin_1.BscPlugin());
|
|
70
111
|
//normalize the root dir path
|
|
71
112
|
this.options.rootDir = util_1.util.getRootDir(this.options);
|
|
72
113
|
this.createGlobalScope();
|
|
114
|
+
this.fileFactory = new Factory_1.FileFactory(this);
|
|
73
115
|
}
|
|
74
116
|
createGlobalScope() {
|
|
75
117
|
//create the 'global' scope
|
|
76
118
|
this.globalScope = new Scope_1.Scope('global', this, 'scope:global');
|
|
77
119
|
this.globalScope.attachDependencyGraph(this.dependencyGraph);
|
|
78
120
|
this.scopes.global = this.globalScope;
|
|
121
|
+
this.populateGlobalSymbolTable();
|
|
79
122
|
//hardcode the files list for global scope to only contain the global file
|
|
80
123
|
this.globalScope.getAllFiles = () => [globalCallables_1.globalFile];
|
|
124
|
+
globalCallables_1.globalFile.isValidated = true;
|
|
81
125
|
this.globalScope.validate();
|
|
82
|
-
//for now, disable validation of global scope because the global files have some duplicate method declarations
|
|
83
|
-
this.globalScope.getDiagnostics = () => [];
|
|
84
126
|
//TODO we might need to fix this because the isValidated clears stuff now
|
|
85
127
|
this.globalScope.isValidated = true;
|
|
86
128
|
}
|
|
129
|
+
recursivelyAddNodeToSymbolTable(nodeData) {
|
|
130
|
+
if (!nodeData) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
let nodeType;
|
|
134
|
+
const nodeName = util_1.util.getSgNodeTypeName(nodeData.name);
|
|
135
|
+
if (!this.globalScope.symbolTable.hasSymbol(nodeName, 2 /* SymbolTypeFlag.typetime */)) {
|
|
136
|
+
let parentNode;
|
|
137
|
+
if (nodeData.extends) {
|
|
138
|
+
const parentNodeData = roku_types_1.nodes[nodeData.extends.name.toLowerCase()];
|
|
139
|
+
try {
|
|
140
|
+
parentNode = this.recursivelyAddNodeToSymbolTable(parentNodeData);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
this.logger.error(error, nodeData);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
nodeType = new ComponentType_1.ComponentType(nodeData.name, parentNode);
|
|
147
|
+
nodeType.addBuiltInInterfaces();
|
|
148
|
+
if (nodeData.name === 'Node') {
|
|
149
|
+
// Add `roSGNode` as shorthand for `roSGNodeNode`
|
|
150
|
+
this.globalScope.symbolTable.addSymbol('roSGNode', { description: nodeData.description }, nodeType, 2 /* SymbolTypeFlag.typetime */);
|
|
151
|
+
}
|
|
152
|
+
this.globalScope.symbolTable.addSymbol(nodeName, { description: nodeData.description }, nodeType, 2 /* SymbolTypeFlag.typetime */);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
nodeType = this.globalScope.symbolTable.getSymbolType(nodeName, { flags: 2 /* SymbolTypeFlag.typetime */ });
|
|
156
|
+
}
|
|
157
|
+
return nodeType;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Do all setup required for the global symbol table.
|
|
161
|
+
*/
|
|
162
|
+
populateGlobalSymbolTable() {
|
|
163
|
+
//Setup primitive types in global symbolTable
|
|
164
|
+
this.globalScope.symbolTable.addSymbol('boolean', undefined, BooleanType_1.BooleanType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
165
|
+
this.globalScope.symbolTable.addSymbol('double', undefined, DoubleType_1.DoubleType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
166
|
+
this.globalScope.symbolTable.addSymbol('dynamic', undefined, DynamicType_1.DynamicType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
167
|
+
this.globalScope.symbolTable.addSymbol('float', undefined, FloatType_1.FloatType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
168
|
+
this.globalScope.symbolTable.addSymbol('function', undefined, new FunctionType_1.FunctionType(), 2 /* SymbolTypeFlag.typetime */);
|
|
169
|
+
this.globalScope.symbolTable.addSymbol('integer', undefined, IntegerType_1.IntegerType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
170
|
+
this.globalScope.symbolTable.addSymbol('longinteger', undefined, LongIntegerType_1.LongIntegerType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
171
|
+
this.globalScope.symbolTable.addSymbol('object', undefined, new ObjectType_1.ObjectType(), 2 /* SymbolTypeFlag.typetime */);
|
|
172
|
+
this.globalScope.symbolTable.addSymbol('string', undefined, StringType_1.StringType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
173
|
+
this.globalScope.symbolTable.addSymbol('void', undefined, VoidType_1.VoidType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
174
|
+
BuiltInInterfaceAdder_1.BuiltInInterfaceAdder.getLookupTable = () => this.globalScope.symbolTable;
|
|
175
|
+
for (const callable of globalCallables_1.globalCallables) {
|
|
176
|
+
this.globalScope.symbolTable.addSymbol(callable.name, { description: callable.shortDescription }, callable.type, 1 /* SymbolTypeFlag.runtime */);
|
|
177
|
+
}
|
|
178
|
+
for (const ifaceData of Object.values(roku_types_1.interfaces)) {
|
|
179
|
+
const nodeType = new InterfaceType_1.InterfaceType(ifaceData.name);
|
|
180
|
+
nodeType.addBuiltInInterfaces();
|
|
181
|
+
this.globalScope.symbolTable.addSymbol(ifaceData.name, { description: ifaceData.description }, nodeType, 2 /* SymbolTypeFlag.typetime */);
|
|
182
|
+
}
|
|
183
|
+
for (const componentData of Object.values(roku_types_1.components)) {
|
|
184
|
+
const nodeType = new InterfaceType_1.InterfaceType(componentData.name);
|
|
185
|
+
nodeType.addBuiltInInterfaces();
|
|
186
|
+
if (componentData.name !== 'roSGNode') {
|
|
187
|
+
// we will add `roSGNode` as shorthand for `roSGNodeNode`, since all roSgNode components are SceneGraph nodes
|
|
188
|
+
this.globalScope.symbolTable.addSymbol(componentData.name, { description: componentData.description }, nodeType, 2 /* SymbolTypeFlag.typetime */);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
for (const nodeData of Object.values(roku_types_1.nodes)) {
|
|
192
|
+
this.recursivelyAddNodeToSymbolTable(nodeData);
|
|
193
|
+
}
|
|
194
|
+
for (const eventData of Object.values(roku_types_1.events)) {
|
|
195
|
+
const nodeType = new InterfaceType_1.InterfaceType(eventData.name);
|
|
196
|
+
nodeType.addBuiltInInterfaces();
|
|
197
|
+
this.globalScope.symbolTable.addSymbol(eventData.name, { description: eventData.description }, nodeType, 2 /* SymbolTypeFlag.typetime */);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
addFileSymbolInfo(file) {
|
|
201
|
+
this.fileSymbolInformation.set(file.pkgPath, {
|
|
202
|
+
provides: file.providedSymbols,
|
|
203
|
+
requires: file.requiredSymbols
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
getFileSymbolInfo(file) {
|
|
207
|
+
return this.fileSymbolInformation.get(file.pkgPath);
|
|
208
|
+
}
|
|
87
209
|
/**
|
|
88
210
|
* The path to bslib.brs (the BrightScript runtime for certain BrighterScript features)
|
|
89
211
|
*/
|
|
@@ -98,7 +220,7 @@ class Program {
|
|
|
98
220
|
//default to the embedded version
|
|
99
221
|
}
|
|
100
222
|
else {
|
|
101
|
-
return
|
|
223
|
+
return `${this.options.bslibDestinationDir}${path.sep}bslib.brs`;
|
|
102
224
|
}
|
|
103
225
|
}
|
|
104
226
|
get bslibPrefix() {
|
|
@@ -109,18 +231,8 @@ class Program {
|
|
|
109
231
|
return 'bslib';
|
|
110
232
|
}
|
|
111
233
|
}
|
|
112
|
-
/**
|
|
113
|
-
* Get a copy of the list of files currently loaded in the program
|
|
114
|
-
*/
|
|
115
|
-
getFiles() {
|
|
116
|
-
return Object.values(this.files);
|
|
117
|
-
}
|
|
118
234
|
addScope(scope) {
|
|
119
235
|
this.scopes[scope.name] = scope;
|
|
120
|
-
this.plugins.emit('afterScopeCreate', {
|
|
121
|
-
program: this,
|
|
122
|
-
scope: scope
|
|
123
|
-
});
|
|
124
236
|
}
|
|
125
237
|
/**
|
|
126
238
|
* Get the component with the specified name
|
|
@@ -129,19 +241,34 @@ class Program {
|
|
|
129
241
|
var _a;
|
|
130
242
|
if (componentName) {
|
|
131
243
|
//return the first compoment in the list with this name
|
|
132
|
-
//(components are ordered in this list by
|
|
244
|
+
//(components are ordered in this list by destPath to ensure consistency)
|
|
133
245
|
return (_a = this.components[componentName.toLowerCase()]) === null || _a === void 0 ? void 0 : _a[0];
|
|
134
246
|
}
|
|
135
247
|
else {
|
|
136
248
|
return undefined;
|
|
137
249
|
}
|
|
138
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Get the sorted names of custom components
|
|
253
|
+
*/
|
|
254
|
+
getSortedComponentNames() {
|
|
255
|
+
const componentNames = Object.keys(this.components);
|
|
256
|
+
componentNames.sort((a, b) => {
|
|
257
|
+
if (a < b) {
|
|
258
|
+
return -1;
|
|
259
|
+
}
|
|
260
|
+
else if (b < a) {
|
|
261
|
+
return 1;
|
|
262
|
+
}
|
|
263
|
+
return 0;
|
|
264
|
+
});
|
|
265
|
+
return componentNames;
|
|
266
|
+
}
|
|
139
267
|
/**
|
|
140
268
|
* Register (or replace) the reference to a component in the component map
|
|
141
269
|
*/
|
|
142
270
|
registerComponent(xmlFile, scope) {
|
|
143
|
-
|
|
144
|
-
const key = ((_b = (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : xmlFile.pkgPath).toLowerCase();
|
|
271
|
+
const key = this.getComponentKey(xmlFile);
|
|
145
272
|
if (!this.components[key]) {
|
|
146
273
|
this.components[key] = [];
|
|
147
274
|
}
|
|
@@ -149,15 +276,25 @@ class Program {
|
|
|
149
276
|
file: xmlFile,
|
|
150
277
|
scope: scope
|
|
151
278
|
});
|
|
152
|
-
this.components[key].sort((
|
|
279
|
+
this.components[key].sort((a, b) => {
|
|
280
|
+
const pathA = a.file.destPath.toLowerCase();
|
|
281
|
+
const pathB = b.file.destPath.toLowerCase();
|
|
282
|
+
if (pathA < pathB) {
|
|
283
|
+
return -1;
|
|
284
|
+
}
|
|
285
|
+
else if (pathA > pathB) {
|
|
286
|
+
return 1;
|
|
287
|
+
}
|
|
288
|
+
return 0;
|
|
289
|
+
});
|
|
153
290
|
this.syncComponentDependencyGraph(this.components[key]);
|
|
291
|
+
this.addDeferredComponentTypeSymbolCreation(xmlFile);
|
|
154
292
|
}
|
|
155
293
|
/**
|
|
156
294
|
* Remove the specified component from the components map
|
|
157
295
|
*/
|
|
158
296
|
unregisterComponent(xmlFile) {
|
|
159
|
-
|
|
160
|
-
const key = ((_b = (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : xmlFile.pkgPath).toLowerCase();
|
|
297
|
+
const key = this.getComponentKey(xmlFile);
|
|
161
298
|
const arr = this.components[key] || [];
|
|
162
299
|
for (let i = 0; i < arr.length; i++) {
|
|
163
300
|
if (arr[i].file === xmlFile) {
|
|
@@ -166,6 +303,44 @@ class Program {
|
|
|
166
303
|
}
|
|
167
304
|
}
|
|
168
305
|
this.syncComponentDependencyGraph(arr);
|
|
306
|
+
this.addDeferredComponentTypeSymbolCreation(xmlFile);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Adds a component described in an XML to the set of components that needs to be updated this validation cycle.
|
|
310
|
+
* @param xmlFile XML file with <component> tag
|
|
311
|
+
*/
|
|
312
|
+
addDeferredComponentTypeSymbolCreation(xmlFile) {
|
|
313
|
+
var _a;
|
|
314
|
+
this.componentSymbolsToUpdate.add({ componentKey: this.getComponentKey(xmlFile), componentName: (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text });
|
|
315
|
+
}
|
|
316
|
+
getComponentKey(xmlFile) {
|
|
317
|
+
var _a, _b;
|
|
318
|
+
return ((_b = (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : xmlFile.pkgPath).toLowerCase();
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Updates the global symbol table with the first component in this.components to have the same name as the component in the file
|
|
322
|
+
* @param componentKey key getting a component from `this.components`
|
|
323
|
+
* @param componentName the unprefixed name of the component that will be added (e.g. 'MyLabel' NOT 'roSgNodeMyLabel')
|
|
324
|
+
*/
|
|
325
|
+
updateComponentSymbolInGlobalScope(componentKey, componentName) {
|
|
326
|
+
const symbolName = componentName ? util_1.util.getSgNodeTypeName(componentName) : undefined;
|
|
327
|
+
if (!symbolName) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const components = this.components[componentKey] || [];
|
|
331
|
+
// Remove any existing symbols that match
|
|
332
|
+
this.globalScope.symbolTable.removeSymbol(symbolName);
|
|
333
|
+
// There is a component that can be added - use it.
|
|
334
|
+
if (components.length > 0) {
|
|
335
|
+
const componentScope = components[0].scope;
|
|
336
|
+
// TODO: May need to link symbol tables to get correct types for callfuncs
|
|
337
|
+
// componentScope.linkSymbolTable();
|
|
338
|
+
const componentType = componentScope.getComponentType();
|
|
339
|
+
if (componentType) {
|
|
340
|
+
this.globalScope.symbolTable.addSymbol(symbolName, {}, componentType, 2 /* SymbolTypeFlag.typetime */);
|
|
341
|
+
}
|
|
342
|
+
// TODO: Remember to unlink! componentScope.unlinkSymbolTable();
|
|
343
|
+
}
|
|
169
344
|
}
|
|
170
345
|
/**
|
|
171
346
|
* re-attach the dependency graph with a new key for any component who changed
|
|
@@ -179,6 +354,7 @@ class Program {
|
|
|
179
354
|
//attach (or re-attach) the dependencyGraph for every component whose position changed
|
|
180
355
|
if (file.dependencyGraphIndex !== i) {
|
|
181
356
|
file.dependencyGraphIndex = i;
|
|
357
|
+
this.dependencyGraph.addOrReplace(file.dependencyGraphKey, file.dependencies);
|
|
182
358
|
file.attachDependencyGraph(this.dependencyGraph);
|
|
183
359
|
scope.attachDependencyGraph(this.dependencyGraph);
|
|
184
360
|
}
|
|
@@ -190,9 +366,10 @@ class Program {
|
|
|
190
366
|
*/
|
|
191
367
|
getUnreferencedFiles() {
|
|
192
368
|
let result = [];
|
|
193
|
-
for (let
|
|
194
|
-
|
|
195
|
-
|
|
369
|
+
for (let filePath in this.files) {
|
|
370
|
+
let file = this.files[filePath];
|
|
371
|
+
//is this file part of a scope
|
|
372
|
+
if (!this.getFirstScopeForFile(file)) {
|
|
196
373
|
//no scopes reference this file. add it to the list
|
|
197
374
|
result.push(file);
|
|
198
375
|
}
|
|
@@ -200,37 +377,14 @@ class Program {
|
|
|
200
377
|
return result;
|
|
201
378
|
}
|
|
202
379
|
/**
|
|
203
|
-
* Get the list of errors for the entire program.
|
|
204
|
-
* by walking through every file, so call this sparingly.
|
|
380
|
+
* Get the list of errors for the entire program.
|
|
205
381
|
*/
|
|
206
382
|
getDiagnostics() {
|
|
207
|
-
return this.
|
|
208
|
-
let diagnostics = [...this.diagnostics];
|
|
209
|
-
//get the diagnostics from all scopes
|
|
210
|
-
for (let scopeName in this.scopes) {
|
|
211
|
-
let scope = this.scopes[scopeName];
|
|
212
|
-
diagnostics.push(...scope.getDiagnostics());
|
|
213
|
-
}
|
|
214
|
-
//get the diagnostics from all unreferenced files
|
|
215
|
-
let unreferencedFiles = this.getUnreferencedFiles();
|
|
216
|
-
for (let file of unreferencedFiles) {
|
|
217
|
-
diagnostics.push(...file.getDiagnostics());
|
|
218
|
-
}
|
|
219
|
-
const filteredDiagnostics = this.logger.time(Logger_1.LogLevel.debug, ['filter diagnostics'], () => {
|
|
220
|
-
//filter out diagnostics based on our diagnostic filters
|
|
221
|
-
let finalDiagnostics = this.diagnosticFilterer.filter(Object.assign(Object.assign({}, this.options), { rootDir: this.options.rootDir }), diagnostics);
|
|
222
|
-
return finalDiagnostics;
|
|
223
|
-
});
|
|
224
|
-
this.logger.info(`diagnostic counts: total=${chalk_1.default.yellow(diagnostics.length.toString())}, after filter=${chalk_1.default.yellow(filteredDiagnostics.length.toString())}`);
|
|
225
|
-
return filteredDiagnostics;
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
addDiagnostics(diagnostics) {
|
|
229
|
-
this.diagnostics.push(...diagnostics);
|
|
383
|
+
return this.diagnostics.getDiagnostics();
|
|
230
384
|
}
|
|
231
385
|
/**
|
|
232
386
|
* Determine if the specified file is loaded in this program right now.
|
|
233
|
-
* @param filePath
|
|
387
|
+
* @param filePath the absolute or relative path to the file
|
|
234
388
|
* @param normalizePath should the provided path be normalized before use
|
|
235
389
|
*/
|
|
236
390
|
hasFile(filePath, normalizePath = true) {
|
|
@@ -238,12 +392,15 @@ class Program {
|
|
|
238
392
|
}
|
|
239
393
|
/**
|
|
240
394
|
* roku filesystem is case INsensitive, so find the scope by key case insensitive
|
|
241
|
-
* @param scopeName
|
|
395
|
+
* @param scopeName xml scope names are their `destPath`. Source scope is stored with the key `"source"`
|
|
242
396
|
*/
|
|
243
397
|
getScopeByName(scopeName) {
|
|
244
398
|
if (!scopeName) {
|
|
245
399
|
return undefined;
|
|
246
400
|
}
|
|
401
|
+
//most scopes are xml file pkg paths. however, the ones that are not are single names like "global" and "scope",
|
|
402
|
+
//so it's safe to run the standardizePkgPath method
|
|
403
|
+
scopeName = (0, util_1.standardizePath) `${scopeName}`;
|
|
247
404
|
let key = Object.keys(this.scopes).find(x => x.toLowerCase() === scopeName.toLowerCase());
|
|
248
405
|
return this.scopes[key];
|
|
249
406
|
}
|
|
@@ -264,113 +421,170 @@ class Program {
|
|
|
264
421
|
* Update internal maps with this file reference
|
|
265
422
|
*/
|
|
266
423
|
assignFile(file) {
|
|
424
|
+
const fileAddEvent = {
|
|
425
|
+
file: file,
|
|
426
|
+
program: this
|
|
427
|
+
};
|
|
428
|
+
this.plugins.emit('beforeFileAdd', fileAddEvent);
|
|
267
429
|
this.files[file.srcPath.toLowerCase()] = file;
|
|
268
|
-
this.
|
|
430
|
+
this.destMap.set(file.destPath.toLowerCase(), file);
|
|
431
|
+
this.plugins.emit('afterFileAdd', fileAddEvent);
|
|
432
|
+
return file;
|
|
269
433
|
}
|
|
270
434
|
/**
|
|
271
435
|
* Remove this file from internal maps
|
|
272
436
|
*/
|
|
273
437
|
unassignFile(file) {
|
|
274
438
|
delete this.files[file.srcPath.toLowerCase()];
|
|
275
|
-
|
|
439
|
+
this.destMap.delete(file.destPath.toLowerCase());
|
|
440
|
+
return file;
|
|
276
441
|
}
|
|
277
|
-
setFile(fileParam,
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
let
|
|
281
|
-
|
|
282
|
-
//is
|
|
283
|
-
if (
|
|
284
|
-
|
|
285
|
-
srcPath = util_1.standardizePath `${this.options.rootDir}/${fileParam.substring(5)}`;
|
|
286
|
-
pkgPath = fileParam;
|
|
287
|
-
//is a srcPath (absolute path to src file location)
|
|
442
|
+
setFile(fileParam, fileData) {
|
|
443
|
+
//normalize the file paths
|
|
444
|
+
const { srcPath, destPath } = this.getPaths(fileParam, this.options.rootDir);
|
|
445
|
+
let file = this.logger.time(logging_1.LogLevel.debug, ['Program.setFile()', chalk_1.default.green(srcPath)], () => {
|
|
446
|
+
var _a, _b, _c;
|
|
447
|
+
//if the file is already loaded, remove it
|
|
448
|
+
if (this.hasFile(srcPath)) {
|
|
449
|
+
this.removeFile(srcPath, true, true);
|
|
288
450
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
451
|
+
const data = new LazyFileData_1.LazyFileData(fileData);
|
|
452
|
+
const event = new ProvideFileEventInternal(this, srcPath, destPath, data, this.fileFactory);
|
|
453
|
+
this.plugins.emit('beforeProvideFile', event);
|
|
454
|
+
this.plugins.emit('provideFile', event);
|
|
455
|
+
this.plugins.emit('afterProvideFile', event);
|
|
456
|
+
//if no files were provided, create a AssetFile to represent it.
|
|
457
|
+
if (event.files.length === 0) {
|
|
458
|
+
event.files.push(this.fileFactory.AssetFile({
|
|
459
|
+
srcPath: event.srcPath,
|
|
460
|
+
destPath: event.destPath,
|
|
461
|
+
pkgPath: event.destPath,
|
|
462
|
+
data: data
|
|
463
|
+
}));
|
|
294
464
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
465
|
+
//find the file instance for the srcPath that triggered this action.
|
|
466
|
+
const primaryFile = event.files.find(x => x.srcPath === srcPath);
|
|
467
|
+
if (!primaryFile) {
|
|
468
|
+
throw new Error(`No file provided for srcPath '${srcPath}'. Instead, received ${JSON.stringify(event.files.map(x => ({
|
|
469
|
+
type: x.type,
|
|
470
|
+
srcPath: x.srcPath,
|
|
471
|
+
destPath: x.destPath
|
|
472
|
+
})))}`);
|
|
473
|
+
}
|
|
474
|
+
//link the virtual files to the primary file
|
|
475
|
+
this.fileClusters.set((_a = primaryFile.srcPath) === null || _a === void 0 ? void 0 : _a.toLowerCase(), event.files);
|
|
476
|
+
for (const file of event.files) {
|
|
477
|
+
file.srcPath = (0, util_1.standardizePath)(file.srcPath);
|
|
478
|
+
if (file.destPath) {
|
|
479
|
+
file.destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(file.destPath, this.options.rootDir, '')}`;
|
|
480
|
+
}
|
|
481
|
+
if (file.pkgPath) {
|
|
482
|
+
file.pkgPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(file.pkgPath, this.options.rootDir, '')}`;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
file.pkgPath = file.destPath;
|
|
486
|
+
}
|
|
487
|
+
file.excludeFromOutput = file.excludeFromOutput === true;
|
|
488
|
+
//set the dependencyGraph key for every file to its destPath
|
|
489
|
+
file.dependencyGraphKey = file.destPath.toLowerCase();
|
|
490
|
+
this.assignFile(file);
|
|
491
|
+
//register a callback anytime this file's dependencies change
|
|
492
|
+
if (typeof file.onDependenciesChanged === 'function') {
|
|
493
|
+
(_b = file.disposables) !== null && _b !== void 0 ? _b : (file.disposables = []);
|
|
494
|
+
file.disposables.push(this.dependencyGraph.onchange(file.dependencyGraphKey, file.onDependenciesChanged.bind(file)));
|
|
495
|
+
}
|
|
496
|
+
//register this file (and its dependencies) with the dependency graph
|
|
497
|
+
this.dependencyGraph.addOrReplace(file.dependencyGraphKey, (_c = file.dependencies) !== null && _c !== void 0 ? _c : []);
|
|
498
|
+
//if this is a `source` file, add it to the source scope's dependency list
|
|
499
|
+
if (this.isSourceBrsFile(file)) {
|
|
500
|
+
this.createSourceScope();
|
|
501
|
+
this.dependencyGraph.addDependency('scope:source', file.dependencyGraphKey);
|
|
502
|
+
}
|
|
503
|
+
//if this is an xml file in the components folder, register it as a component
|
|
504
|
+
if (this.isComponentsXmlFile(file)) {
|
|
505
|
+
//create a new scope for this xml file
|
|
506
|
+
let scope = new XmlScope_1.XmlScope(file, this);
|
|
507
|
+
this.addScope(scope);
|
|
508
|
+
//register this compoent now that we have parsed it and know its component name
|
|
509
|
+
this.registerComponent(file, scope);
|
|
510
|
+
//notify plugins that the scope is created and the component is registered
|
|
511
|
+
this.plugins.emit('afterScopeCreate', {
|
|
512
|
+
program: this,
|
|
513
|
+
scope: scope
|
|
514
|
+
});
|
|
515
|
+
}
|
|
298
516
|
}
|
|
299
|
-
|
|
517
|
+
return primaryFile;
|
|
518
|
+
});
|
|
519
|
+
return file;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Given a srcPath, a destPath, or both, resolve whichever is missing, relative to rootDir.
|
|
523
|
+
* @param fileParam an object representing file paths
|
|
524
|
+
* @param rootDir must be a pre-normalized path
|
|
525
|
+
*/
|
|
526
|
+
getPaths(fileParam, rootDir) {
|
|
527
|
+
let srcPath;
|
|
528
|
+
let destPath;
|
|
529
|
+
assert.ok(fileParam, 'fileParam is required');
|
|
530
|
+
//lift the path vars from the incoming param
|
|
531
|
+
if (typeof fileParam === 'string') {
|
|
532
|
+
fileParam = this.removePkgPrefix(fileParam);
|
|
533
|
+
srcPath = (0, util_1.standardizePath) `${path.resolve(rootDir, fileParam)}`;
|
|
534
|
+
destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
|
|
300
535
|
}
|
|
301
536
|
else {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const lowerPkgPath = pkgPath.toLowerCase();
|
|
306
|
-
return this.logger.time(Logger_1.LogLevel.debug, ['Program.addOrReplaceFile()', chalk_1.default.green(srcPath)], () => {
|
|
307
|
-
assert.ok(srcPath, 'srcPath is required');
|
|
308
|
-
assert.ok(pkgPath, 'pkgPath is required');
|
|
309
|
-
//if the file is already loaded, remove it
|
|
310
|
-
if (this.hasFile(srcPath)) {
|
|
311
|
-
this.removeFile(srcPath);
|
|
537
|
+
let param = fileParam;
|
|
538
|
+
if (param.src) {
|
|
539
|
+
srcPath = (0, util_1.standardizePath) `${param.src}`;
|
|
312
540
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const beforeFileParseEvent = {
|
|
316
|
-
program: this,
|
|
317
|
-
srcPath: srcPath,
|
|
318
|
-
source: fileContents
|
|
319
|
-
};
|
|
320
|
-
if (fileExtension === '.brs' || fileExtension === '.bs') {
|
|
321
|
-
let brsFile = new BrsFile_1.BrsFile(srcPath, pkgPath, this);
|
|
322
|
-
//add file to the `source` dependency list
|
|
323
|
-
if (brsFile.pkgPath.startsWith('pkg:/source/')) {
|
|
324
|
-
this.createSourceScope();
|
|
325
|
-
this.dependencyGraph.addDependency('scope:source', brsFile.dependencyGraphKey);
|
|
326
|
-
}
|
|
327
|
-
//add the file to the program
|
|
328
|
-
this.assignFile(brsFile);
|
|
329
|
-
this.plugins.emit('beforeFileParse', beforeFileParseEvent);
|
|
330
|
-
this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
|
|
331
|
-
brsFile.parse(beforeFileParseEvent.source);
|
|
332
|
-
});
|
|
333
|
-
file = brsFile;
|
|
334
|
-
brsFile.attachDependencyGraph(this.dependencyGraph);
|
|
335
|
-
this.plugins.emit('afterFileParse', {
|
|
336
|
-
program: this,
|
|
337
|
-
file: brsFile
|
|
338
|
-
});
|
|
541
|
+
if (param.srcPath) {
|
|
542
|
+
srcPath = (0, util_1.standardizePath) `${param.srcPath}`;
|
|
339
543
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
fileExtension === '.xml' &&
|
|
343
|
-
//resides in the components folder (Roku will only parse xml files in the components folder)
|
|
344
|
-
lowerPkgPath.startsWith('pkg:/components/')) {
|
|
345
|
-
let xmlFile = new XmlFile_1.XmlFile(srcPath, pkgPath, this);
|
|
346
|
-
this.assignFile(xmlFile);
|
|
347
|
-
//add the file to the program
|
|
348
|
-
this.plugins.emit('beforeFileParse', beforeFileParseEvent);
|
|
349
|
-
this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
|
|
350
|
-
xmlFile.parse(beforeFileParseEvent.source);
|
|
351
|
-
});
|
|
352
|
-
file = xmlFile;
|
|
353
|
-
//create a new scope for this xml file
|
|
354
|
-
let scope = new XmlScope_1.XmlScope(xmlFile, this);
|
|
355
|
-
this.addScope(scope);
|
|
356
|
-
//register this compoent now that we have parsed it and know its component name
|
|
357
|
-
this.registerComponent(xmlFile, scope);
|
|
358
|
-
this.plugins.emit('afterFileParse', {
|
|
359
|
-
program: this,
|
|
360
|
-
file: xmlFile
|
|
361
|
-
});
|
|
544
|
+
if (param.dest) {
|
|
545
|
+
destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.dest)}`;
|
|
362
546
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
// let genericFile = this.files[srcPath] = <any>{
|
|
366
|
-
// srcPath: srcPath,
|
|
367
|
-
// pkgPath: pkgPath,
|
|
368
|
-
// wasProcessed: true
|
|
369
|
-
// } as File;
|
|
370
|
-
// file = <any>genericFile;
|
|
547
|
+
if (param.pkgPath) {
|
|
548
|
+
destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.pkgPath)}`;
|
|
371
549
|
}
|
|
372
|
-
|
|
373
|
-
|
|
550
|
+
}
|
|
551
|
+
//if there's no srcPath, use the destPath to build an absolute srcPath
|
|
552
|
+
if (!srcPath) {
|
|
553
|
+
srcPath = (0, util_1.standardizePath) `${rootDir}/${destPath}`;
|
|
554
|
+
}
|
|
555
|
+
//coerce srcPath to an absolute path
|
|
556
|
+
if (!path.isAbsolute(srcPath)) {
|
|
557
|
+
srcPath = util_1.util.standardizePath(srcPath);
|
|
558
|
+
}
|
|
559
|
+
//if destPath isn't set, compute it from the other paths
|
|
560
|
+
if (!destPath) {
|
|
561
|
+
destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
|
|
562
|
+
}
|
|
563
|
+
assert.ok(srcPath, 'fileEntry.src is required');
|
|
564
|
+
assert.ok(destPath, 'fileEntry.dest is required');
|
|
565
|
+
return {
|
|
566
|
+
srcPath: srcPath,
|
|
567
|
+
//remove leading slash
|
|
568
|
+
destPath: destPath.replace(/^[\/\\]+/, '')
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Remove any leading `pkg:/` found in the path
|
|
573
|
+
*/
|
|
574
|
+
removePkgPrefix(path) {
|
|
575
|
+
return path.replace(/^pkg:\//i, '');
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Is this file a .brs file found somewhere within the `pkg:/source/` folder?
|
|
579
|
+
*/
|
|
580
|
+
isSourceBrsFile(file) {
|
|
581
|
+
return !!/^(pkg:\/)?source[\/\\]/.exec(file.destPath);
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Is this file a .brs file found somewhere within the `pkg:/source/` folder?
|
|
585
|
+
*/
|
|
586
|
+
isComponentsXmlFile(file) {
|
|
587
|
+
return (0, reflection_1.isXmlFile)(file) && !!/^(pkg:\/)?components[\/\\]/.exec(file.destPath);
|
|
374
588
|
}
|
|
375
589
|
/**
|
|
376
590
|
* Ensure source scope is created.
|
|
@@ -381,238 +595,373 @@ class Program {
|
|
|
381
595
|
const sourceScope = new Scope_1.Scope('source', this, 'scope:source');
|
|
382
596
|
sourceScope.attachDependencyGraph(this.dependencyGraph);
|
|
383
597
|
this.addScope(sourceScope);
|
|
598
|
+
this.plugins.emit('afterScopeCreate', {
|
|
599
|
+
program: this,
|
|
600
|
+
scope: sourceScope
|
|
601
|
+
});
|
|
384
602
|
}
|
|
385
603
|
}
|
|
386
604
|
/**
|
|
387
605
|
* Remove a set of files from the program
|
|
388
|
-
* @param srcPaths
|
|
606
|
+
* @param srcPaths can be an array of srcPath or destPath strings
|
|
607
|
+
* @param normalizePath should this function repair and standardize the filePaths? Passing false should have a performance boost if you can guarantee your paths are already sanitized
|
|
389
608
|
*/
|
|
390
|
-
removeFiles(srcPaths) {
|
|
609
|
+
removeFiles(srcPaths, normalizePath = true) {
|
|
391
610
|
for (let srcPath of srcPaths) {
|
|
392
|
-
this.removeFile(srcPath);
|
|
611
|
+
this.removeFile(srcPath, normalizePath);
|
|
393
612
|
}
|
|
394
613
|
}
|
|
395
614
|
/**
|
|
396
615
|
* Remove a file from the program
|
|
397
|
-
* @param filePath can be a srcPath, a
|
|
616
|
+
* @param filePath can be a srcPath, a destPath, or a destPath with leading `pkg:/`
|
|
398
617
|
* @param normalizePath should this function repair and standardize the path? Passing false should have a performance boost if you can guarantee your path is already sanitized
|
|
399
|
-
|
|
400
618
|
*/
|
|
401
|
-
removeFile(filePath, normalizePath = true) {
|
|
619
|
+
removeFile(filePath, normalizePath = true, keepSymbolInformation = false) {
|
|
620
|
+
var _a, _b, _c, _d;
|
|
402
621
|
this.logger.debug('Program.removeFile()', filePath);
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
622
|
+
const paths = this.getPaths(filePath, this.options.rootDir);
|
|
623
|
+
//there can be one or more File entries for a single srcPath, so get all of them and remove them all
|
|
624
|
+
const files = (_b = this.fileClusters.get((_a = paths.srcPath) === null || _a === void 0 ? void 0 : _a.toLowerCase())) !== null && _b !== void 0 ? _b : [this.getFile(filePath, normalizePath)];
|
|
625
|
+
for (const file of files) {
|
|
626
|
+
//if a file has already been removed, nothing more needs to be done here
|
|
627
|
+
if (!file || !this.hasFile(file.srcPath)) {
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
this.diagnostics.clearForFile(file.srcPath);
|
|
631
|
+
const event = { file: file, program: this };
|
|
632
|
+
this.plugins.emit('beforeFileRemove', event);
|
|
409
633
|
//if there is a scope named the same as this file's path, remove it (i.e. xml scopes)
|
|
410
|
-
let scope = this.scopes[file.
|
|
634
|
+
let scope = this.scopes[file.destPath];
|
|
411
635
|
if (scope) {
|
|
412
|
-
|
|
636
|
+
const scopeDisposeEvent = {
|
|
413
637
|
program: this,
|
|
414
638
|
scope: scope
|
|
415
|
-
}
|
|
639
|
+
};
|
|
640
|
+
this.plugins.emit('beforeScopeDispose', scopeDisposeEvent);
|
|
641
|
+
this.plugins.emit('onScopeDispose', scopeDisposeEvent);
|
|
416
642
|
scope.dispose();
|
|
417
643
|
//notify dependencies of this scope that it has been removed
|
|
418
644
|
this.dependencyGraph.remove(scope.dependencyGraphKey);
|
|
419
|
-
delete this.scopes[file.
|
|
420
|
-
this.plugins.emit('afterScopeDispose',
|
|
421
|
-
program: this,
|
|
422
|
-
scope: scope
|
|
423
|
-
});
|
|
645
|
+
delete this.scopes[file.destPath];
|
|
646
|
+
this.plugins.emit('afterScopeDispose', scopeDisposeEvent);
|
|
424
647
|
}
|
|
425
648
|
//remove the file from the program
|
|
426
649
|
this.unassignFile(file);
|
|
427
650
|
this.dependencyGraph.remove(file.dependencyGraphKey);
|
|
428
651
|
//if this is a pkg:/source file, notify the `source` scope that it has changed
|
|
429
|
-
if (
|
|
652
|
+
if (this.isSourceBrsFile(file)) {
|
|
430
653
|
this.dependencyGraph.removeDependency('scope:source', file.dependencyGraphKey);
|
|
431
654
|
}
|
|
655
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
656
|
+
if (!keepSymbolInformation) {
|
|
657
|
+
this.fileSymbolInformation.delete(file.pkgPath);
|
|
658
|
+
}
|
|
659
|
+
this.crossScopeValidation.clearResolutionsForFile(file);
|
|
660
|
+
}
|
|
432
661
|
//if this is a component, remove it from our components map
|
|
433
|
-
if (reflection_1.isXmlFile(file)) {
|
|
662
|
+
if ((0, reflection_1.isXmlFile)(file)) {
|
|
434
663
|
this.unregisterComponent(file);
|
|
435
664
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* Remove all files from the program that are in the specified folder path (recursive)
|
|
444
|
-
* @param folderSrcPath The absolute path to the folder on disk
|
|
445
|
-
* @param normalizePath should the provided path be normalized before use?
|
|
446
|
-
*/
|
|
447
|
-
removeFilesInFolder(folderSrcPath, normalizePath = true) {
|
|
448
|
-
if (normalizePath) {
|
|
449
|
-
folderSrcPath = util_1.util.standardizePath(folderSrcPath);
|
|
450
|
-
}
|
|
451
|
-
const lowerFolderSrcPath = folderSrcPath.toLowerCase();
|
|
452
|
-
for (const key in this.files) {
|
|
453
|
-
const file = this.files[key];
|
|
454
|
-
const lowerSrcPath = file.srcPath.toLowerCase();
|
|
455
|
-
//if the file path starts with the parent path and the file path does not exactly match the folder path
|
|
456
|
-
if (lowerSrcPath.toLowerCase().startsWith(lowerFolderSrcPath) && lowerSrcPath !== lowerFolderSrcPath) {
|
|
457
|
-
this.removeFile(file.srcPath, false);
|
|
665
|
+
//dispose any disposable things on the file
|
|
666
|
+
for (const disposable of (_c = file === null || file === void 0 ? void 0 : file.disposables) !== null && _c !== void 0 ? _c : []) {
|
|
667
|
+
disposable();
|
|
458
668
|
}
|
|
669
|
+
//dispose file
|
|
670
|
+
(_d = file === null || file === void 0 ? void 0 : file.dispose) === null || _d === void 0 ? void 0 : _d.call(file);
|
|
671
|
+
this.plugins.emit('afterFileRemove', event);
|
|
459
672
|
}
|
|
460
673
|
}
|
|
461
674
|
/**
|
|
462
675
|
* Traverse the entire project, and validate all scopes
|
|
463
|
-
* @param force - if true, then all scopes are force to validate, even if they aren't marked as dirty
|
|
464
676
|
*/
|
|
465
677
|
validate() {
|
|
466
|
-
this.logger.time(
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
this.plugins.emit('beforeProgramValidate', {
|
|
678
|
+
this.logger.time(logging_1.LogLevel.log, ['Validating project'], () => {
|
|
679
|
+
this.diagnostics.clearForTag(ProgramValidator_1.ProgramValidatorDiagnosticsTag);
|
|
680
|
+
const programValidateEvent = {
|
|
470
681
|
program: this
|
|
471
|
-
}
|
|
682
|
+
};
|
|
683
|
+
this.plugins.emit('beforeProgramValidate', programValidateEvent);
|
|
684
|
+
this.plugins.emit('onProgramValidate', programValidateEvent);
|
|
685
|
+
const metrics = {
|
|
686
|
+
filesChanged: 0,
|
|
687
|
+
filesValidated: 0,
|
|
688
|
+
fileValidationTime: '',
|
|
689
|
+
crossScopeValidationTime: '',
|
|
690
|
+
scopesValidated: 0,
|
|
691
|
+
totalLinkTime: '',
|
|
692
|
+
totalScopeValidationTime: '',
|
|
693
|
+
componentValidationTime: ''
|
|
694
|
+
};
|
|
695
|
+
const validationStopwatch = new Stopwatch_1.Stopwatch();
|
|
472
696
|
//validate every file
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
697
|
+
const brsFilesValidated = [];
|
|
698
|
+
const afterValidateFiles = [];
|
|
699
|
+
metrics.fileValidationTime = validationStopwatch.getDurationTextFor(() => {
|
|
700
|
+
//sort files by path so we get consistent results
|
|
701
|
+
const files = Object.values(this.files).sort((0, thenby_1.firstBy)(x => x.srcPath));
|
|
702
|
+
for (const file of files) {
|
|
703
|
+
//for every unvalidated file, validate it
|
|
704
|
+
if (!file.isValidated) {
|
|
705
|
+
const validateFileEvent = {
|
|
706
|
+
program: this,
|
|
707
|
+
file: file
|
|
708
|
+
};
|
|
709
|
+
this.plugins.emit('beforeFileValidate', validateFileEvent);
|
|
710
|
+
//emit an event to allow plugins to contribute to the file validation process
|
|
711
|
+
this.plugins.emit('onFileValidate', validateFileEvent);
|
|
712
|
+
file.isValidated = true;
|
|
713
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
714
|
+
brsFilesValidated.push(file);
|
|
715
|
+
}
|
|
716
|
+
afterValidateFiles.push(file);
|
|
717
|
+
}
|
|
479
718
|
}
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
program: this,
|
|
484
|
-
file: file
|
|
485
|
-
});
|
|
486
|
-
//call file.validate() IF the file has that function defined
|
|
487
|
-
(_a = file.validate) === null || _a === void 0 ? void 0 : _a.call(file);
|
|
488
|
-
file.isValidated = true;
|
|
489
|
-
this.plugins.emit('afterFileValidate', {
|
|
719
|
+
// AfterFileValidate is after all files have been validated
|
|
720
|
+
for (const file of afterValidateFiles) {
|
|
721
|
+
const validateFileEvent = {
|
|
490
722
|
program: this,
|
|
491
723
|
file: file
|
|
492
|
-
}
|
|
724
|
+
};
|
|
725
|
+
this.plugins.emit('afterFileValidate', validateFileEvent);
|
|
493
726
|
}
|
|
727
|
+
}).durationText;
|
|
728
|
+
metrics.filesChanged = afterValidateFiles.length;
|
|
729
|
+
// Build component types for any component that changes
|
|
730
|
+
this.logger.time(logging_1.LogLevel.info, ['Build component types'], () => {
|
|
731
|
+
for (let { componentKey, componentName } of this.componentSymbolsToUpdate) {
|
|
732
|
+
this.updateComponentSymbolInGlobalScope(componentKey, componentName);
|
|
733
|
+
}
|
|
734
|
+
this.componentSymbolsToUpdate.clear();
|
|
735
|
+
});
|
|
736
|
+
const changedSymbolsMapArr = brsFilesValidated === null || brsFilesValidated === void 0 ? void 0 : brsFilesValidated.map(f => {
|
|
737
|
+
if ((0, reflection_1.isBrsFile)(f)) {
|
|
738
|
+
return f.providedSymbols.changes;
|
|
739
|
+
}
|
|
740
|
+
return null;
|
|
741
|
+
}).filter(x => x);
|
|
742
|
+
const changedSymbols = new Map();
|
|
743
|
+
for (const flag of [1 /* SymbolTypeFlag.runtime */, 2 /* SymbolTypeFlag.typetime */]) {
|
|
744
|
+
const changedSymbolsSetArr = changedSymbolsMapArr.map(symMap => symMap.get(flag));
|
|
745
|
+
changedSymbols.set(flag, new Set(...changedSymbolsSetArr));
|
|
494
746
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
747
|
+
const filesToBeValidatedInScopeContext = new Set(afterValidateFiles);
|
|
748
|
+
metrics.crossScopeValidationTime = validationStopwatch.getDurationTextFor(() => {
|
|
749
|
+
const scopesToCheck = this.getScopesForCrossScopeValidation();
|
|
750
|
+
this.crossScopeValidation.buildComponentsMap();
|
|
751
|
+
this.crossScopeValidation.addDiagnosticsForScopes(scopesToCheck);
|
|
752
|
+
const filesToRevalidate = this.crossScopeValidation.getFilesRequiringChangedSymbol(scopesToCheck, changedSymbols);
|
|
753
|
+
for (const file of filesToRevalidate) {
|
|
754
|
+
filesToBeValidatedInScopeContext.add(file);
|
|
755
|
+
}
|
|
756
|
+
}).durationText;
|
|
757
|
+
metrics.filesValidated = filesToBeValidatedInScopeContext.size;
|
|
758
|
+
let linkTime = 0;
|
|
759
|
+
let validationTime = 0;
|
|
760
|
+
let scopesValidated = 0;
|
|
761
|
+
let changedFiles = new Set(afterValidateFiles);
|
|
762
|
+
this.logger.time(logging_1.LogLevel.info, ['Validate all scopes'], () => {
|
|
763
|
+
//sort the scope names so we get consistent results
|
|
764
|
+
const scopeNames = this.getSortedScopeNames();
|
|
765
|
+
for (const file of filesToBeValidatedInScopeContext) {
|
|
766
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
767
|
+
file.validationSegmenter.unValidateAllSegments();
|
|
509
768
|
}
|
|
510
769
|
}
|
|
770
|
+
for (let scopeName of scopeNames) {
|
|
771
|
+
let scope = this.scopes[scopeName];
|
|
772
|
+
const scopeValidated = scope.validate({
|
|
773
|
+
filesToBeValidatedInScopeContext: filesToBeValidatedInScopeContext,
|
|
774
|
+
changedSymbols: changedSymbols,
|
|
775
|
+
changedFiles: changedFiles,
|
|
776
|
+
initialValidation: this.isFirstValidation
|
|
777
|
+
});
|
|
778
|
+
if (scopeValidated) {
|
|
779
|
+
scopesValidated++;
|
|
780
|
+
}
|
|
781
|
+
linkTime += scope.validationMetrics.linkTime;
|
|
782
|
+
validationTime += scope.validationMetrics.validationTime;
|
|
783
|
+
}
|
|
511
784
|
});
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
785
|
+
metrics.scopesValidated = scopesValidated;
|
|
786
|
+
validationStopwatch.totalMilliseconds = linkTime;
|
|
787
|
+
metrics.totalLinkTime = validationStopwatch.getDurationText();
|
|
788
|
+
validationStopwatch.totalMilliseconds = validationTime;
|
|
789
|
+
metrics.totalScopeValidationTime = validationStopwatch.getDurationText();
|
|
790
|
+
metrics.componentValidationTime = validationStopwatch.getDurationTextFor(() => {
|
|
791
|
+
this.detectDuplicateComponentNames();
|
|
792
|
+
}).durationText;
|
|
793
|
+
this.logValidationMetrics(metrics);
|
|
794
|
+
this.isFirstValidation = false;
|
|
795
|
+
this.plugins.emit('afterProgramValidate', programValidateEvent);
|
|
516
796
|
});
|
|
517
797
|
}
|
|
798
|
+
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
|
|
799
|
+
logValidationMetrics(metrics) {
|
|
800
|
+
let logs = [];
|
|
801
|
+
for (const key in metrics) {
|
|
802
|
+
logs.push(`${key}=${chalk_1.default.yellow(metrics[key].toString())}`);
|
|
803
|
+
}
|
|
804
|
+
this.logger.info(`Validation Metrics: ${logs.join(', ')}`);
|
|
805
|
+
}
|
|
806
|
+
getScopesForCrossScopeValidation() {
|
|
807
|
+
const scopesForCrossScopeValidation = [];
|
|
808
|
+
for (let scopeName of this.getSortedScopeNames()) {
|
|
809
|
+
let scope = this.scopes[scopeName];
|
|
810
|
+
if (this.globalScope !== scope && !scope.isValidated) {
|
|
811
|
+
scopesForCrossScopeValidation.push(scope);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
return scopesForCrossScopeValidation;
|
|
815
|
+
}
|
|
518
816
|
/**
|
|
519
817
|
* Flag all duplicate component names
|
|
520
818
|
*/
|
|
521
819
|
detectDuplicateComponentNames() {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const file = this.files[key];
|
|
820
|
+
const componentsByName = Object.keys(this.files).reduce((map, filePath) => {
|
|
821
|
+
var _a;
|
|
822
|
+
const file = this.files[filePath];
|
|
526
823
|
//if this is an XmlFile, and it has a valid `componentName` property
|
|
527
|
-
if (reflection_1.isXmlFile(file)) {
|
|
528
|
-
|
|
529
|
-
if (
|
|
530
|
-
|
|
531
|
-
componentsByName.set(componentNameLower, [file]);
|
|
532
|
-
}
|
|
533
|
-
else {
|
|
534
|
-
componentsByName.get(componentNameLower).push(file);
|
|
535
|
-
}
|
|
824
|
+
if ((0, reflection_1.isXmlFile)(file) && ((_a = file.componentName) === null || _a === void 0 ? void 0 : _a.text)) {
|
|
825
|
+
let lowerName = file.componentName.text.toLowerCase();
|
|
826
|
+
if (!map[lowerName]) {
|
|
827
|
+
map[lowerName] = [];
|
|
536
828
|
}
|
|
829
|
+
map[lowerName].push(file);
|
|
537
830
|
}
|
|
538
|
-
|
|
539
|
-
|
|
831
|
+
return map;
|
|
832
|
+
}, {});
|
|
833
|
+
for (let name in componentsByName) {
|
|
834
|
+
const xmlFiles = componentsByName[name];
|
|
540
835
|
//add diagnostics for every duplicate component with this name
|
|
541
836
|
if (xmlFiles.length > 1) {
|
|
542
837
|
for (let xmlFile of xmlFiles) {
|
|
543
838
|
const { componentName } = xmlFile;
|
|
544
|
-
this.diagnostics.
|
|
839
|
+
this.diagnostics.register(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateComponentName(componentName.text)), { range: xmlFile.componentName.range, file: xmlFile, relatedInformation: xmlFiles.filter(x => x !== xmlFile).map(x => {
|
|
840
|
+
var _a;
|
|
545
841
|
return {
|
|
546
|
-
location:
|
|
842
|
+
location: util_1.util.createLocation(vscode_uri_1.URI.file((_a = xmlFile.srcPath) !== null && _a !== void 0 ? _a : xmlFile.srcPath).toString(), x.componentName.range),
|
|
547
843
|
message: 'Also defined here'
|
|
548
844
|
};
|
|
549
|
-
}) }));
|
|
845
|
+
}) }), { tags: [ProgramValidator_1.ProgramValidatorDiagnosticsTag] });
|
|
550
846
|
}
|
|
551
847
|
}
|
|
552
848
|
}
|
|
553
849
|
}
|
|
554
850
|
/**
|
|
555
|
-
*
|
|
851
|
+
* Get the files for a list of filePaths
|
|
852
|
+
* @param filePaths can be an array of srcPath or a destPath strings
|
|
853
|
+
* @param normalizePath should this function repair and standardize the paths? Passing false should have a performance boost if you can guarantee your paths are already sanitized
|
|
556
854
|
*/
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
return false;
|
|
855
|
+
getFiles(filePaths, normalizePath = true) {
|
|
856
|
+
return filePaths
|
|
857
|
+
.map(filePath => this.getFile(filePath, normalizePath))
|
|
858
|
+
.filter(file => file !== undefined);
|
|
564
859
|
}
|
|
565
860
|
/**
|
|
566
861
|
* Get the file at the given path
|
|
567
|
-
* @param filePath can be a srcPath
|
|
862
|
+
* @param filePath can be a srcPath or a destPath
|
|
568
863
|
* @param normalizePath should this function repair and standardize the path? Passing false should have a performance boost if you can guarantee your path is already sanitized
|
|
569
864
|
*/
|
|
570
865
|
getFile(filePath, normalizePath = true) {
|
|
571
866
|
if (typeof filePath !== 'string') {
|
|
572
867
|
return undefined;
|
|
868
|
+
//is the path absolute (or the `virtual:` prefix)
|
|
573
869
|
}
|
|
574
|
-
else if (
|
|
870
|
+
else if (/^(?:(?:virtual:[\/\\])|(?:\w:)|(?:[\/\\]))/gmi.exec(filePath)) {
|
|
575
871
|
return this.files[(normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase()];
|
|
576
872
|
}
|
|
577
873
|
else {
|
|
578
|
-
return this.
|
|
874
|
+
return this.destMap.get((normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase());
|
|
579
875
|
}
|
|
580
876
|
}
|
|
877
|
+
/**
|
|
878
|
+
* Gets a sorted list of all scopeNames, always beginning with "global", "source", then any others in alphabetical order
|
|
879
|
+
*/
|
|
880
|
+
getSortedScopeNames() {
|
|
881
|
+
return Object.keys(this.scopes).sort((a, b) => {
|
|
882
|
+
if (a === 'global') {
|
|
883
|
+
return -1;
|
|
884
|
+
}
|
|
885
|
+
else if (b === 'global') {
|
|
886
|
+
return 1;
|
|
887
|
+
}
|
|
888
|
+
if (a === 'source') {
|
|
889
|
+
return -1;
|
|
890
|
+
}
|
|
891
|
+
else if (b === 'source') {
|
|
892
|
+
return 1;
|
|
893
|
+
}
|
|
894
|
+
if (a < b) {
|
|
895
|
+
return -1;
|
|
896
|
+
}
|
|
897
|
+
else if (b < a) {
|
|
898
|
+
return 1;
|
|
899
|
+
}
|
|
900
|
+
return 0;
|
|
901
|
+
});
|
|
902
|
+
}
|
|
581
903
|
/**
|
|
582
904
|
* Get a list of all scopes the file is loaded into
|
|
583
|
-
* @param file
|
|
905
|
+
* @param file the file
|
|
584
906
|
*/
|
|
585
907
|
getScopesForFile(file) {
|
|
908
|
+
const resolvedFile = typeof file === 'string' ? this.getFile(file) : file;
|
|
586
909
|
let result = [];
|
|
587
|
-
|
|
910
|
+
if (resolvedFile) {
|
|
911
|
+
const scopeKeys = this.getSortedScopeNames();
|
|
912
|
+
for (let key of scopeKeys) {
|
|
913
|
+
let scope = this.scopes[key];
|
|
914
|
+
if (scope.hasFile(resolvedFile)) {
|
|
915
|
+
result.push(scope);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return result;
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Get the first found scope for a file.
|
|
923
|
+
*/
|
|
924
|
+
getFirstScopeForFile(file) {
|
|
925
|
+
const scopeKeys = this.getSortedScopeNames();
|
|
926
|
+
for (let key of scopeKeys) {
|
|
588
927
|
let scope = this.scopes[key];
|
|
589
928
|
if (scope.hasFile(file)) {
|
|
590
|
-
|
|
929
|
+
return scope;
|
|
591
930
|
}
|
|
592
931
|
}
|
|
593
|
-
return result;
|
|
594
932
|
}
|
|
595
933
|
getStatementsByName(name, originFile, namespaceName) {
|
|
596
|
-
var _a, _b;
|
|
597
934
|
let results = new Map();
|
|
598
935
|
const filesSearched = new Set();
|
|
599
936
|
let lowerNamespaceName = namespaceName === null || namespaceName === void 0 ? void 0 : namespaceName.toLowerCase();
|
|
600
937
|
let lowerName = name === null || name === void 0 ? void 0 : name.toLowerCase();
|
|
938
|
+
function addToResults(statement, file) {
|
|
939
|
+
var _a, _b;
|
|
940
|
+
let parentNamespaceName = (_b = (_a = statement.findAncestor(reflection_1.isNamespaceStatement)) === null || _a === void 0 ? void 0 : _a.getName(originFile.parseMode)) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
941
|
+
if (statement.tokens.name.text.toLowerCase() === lowerName && (!lowerNamespaceName || parentNamespaceName === lowerNamespaceName)) {
|
|
942
|
+
if (!results.has(statement)) {
|
|
943
|
+
results.set(statement, { item: statement, file: file });
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
601
947
|
//look through all files in scope for matches
|
|
602
948
|
for (const scope of this.getScopesForFile(originFile)) {
|
|
603
949
|
for (const file of scope.getAllFiles()) {
|
|
604
|
-
|
|
950
|
+
//skip non-brs files, or files we've already processed
|
|
951
|
+
if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
|
|
605
952
|
continue;
|
|
606
953
|
}
|
|
607
954
|
filesSearched.add(file);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
955
|
+
file.ast.walk((0, visitors_1.createVisitor)({
|
|
956
|
+
FunctionStatement: (statement) => {
|
|
957
|
+
addToResults(statement, file);
|
|
958
|
+
},
|
|
959
|
+
MethodStatement: (statement) => {
|
|
960
|
+
addToResults(statement, file);
|
|
614
961
|
}
|
|
615
|
-
}
|
|
962
|
+
}), {
|
|
963
|
+
walkMode: visitors_1.WalkMode.visitStatements
|
|
964
|
+
});
|
|
616
965
|
}
|
|
617
966
|
}
|
|
618
967
|
return [...results.values()];
|
|
@@ -624,8 +973,8 @@ class Program {
|
|
|
624
973
|
//get all function names for the xml file and parents
|
|
625
974
|
let funcNames = new Set();
|
|
626
975
|
let currentScope = scope;
|
|
627
|
-
while (reflection_1.isXmlScope(currentScope)) {
|
|
628
|
-
for (let name of (_b = (_a = currentScope.xmlFile.ast.
|
|
976
|
+
while ((0, reflection_1.isXmlScope)(currentScope)) {
|
|
977
|
+
for (let name of (_b = (_a = currentScope.xmlFile.ast.componentElement.interfaceElement) === null || _a === void 0 ? void 0 : _a.functions.map((f) => f.name)) !== null && _b !== void 0 ? _b : []) {
|
|
629
978
|
if (!filterName || name === filterName) {
|
|
630
979
|
funcNames.add(name);
|
|
631
980
|
}
|
|
@@ -634,109 +983,128 @@ class Program {
|
|
|
634
983
|
}
|
|
635
984
|
//look through all files in scope for matches
|
|
636
985
|
for (const file of scope.getOwnFiles()) {
|
|
637
|
-
|
|
986
|
+
//skip non-brs files, or files we've already processed
|
|
987
|
+
if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
|
|
638
988
|
continue;
|
|
639
989
|
}
|
|
640
990
|
filesSearched.add(file);
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
if (
|
|
644
|
-
results.
|
|
991
|
+
file.ast.walk((0, visitors_1.createVisitor)({
|
|
992
|
+
FunctionStatement: (statement) => {
|
|
993
|
+
if (funcNames.has(statement.tokens.name.text)) {
|
|
994
|
+
if (!results.has(statement)) {
|
|
995
|
+
results.set(statement, { item: statement, file: file });
|
|
996
|
+
}
|
|
645
997
|
}
|
|
646
998
|
}
|
|
647
|
-
}
|
|
999
|
+
}), {
|
|
1000
|
+
walkMode: visitors_1.WalkMode.visitStatements
|
|
1001
|
+
});
|
|
648
1002
|
}
|
|
649
1003
|
return [...results.values()];
|
|
650
1004
|
}
|
|
651
1005
|
/**
|
|
652
1006
|
* Find all available completion items at the given position
|
|
653
|
-
* @param
|
|
654
|
-
* @param
|
|
655
|
-
* @param columnIndex
|
|
1007
|
+
* @param filePath can be a srcPath or a destPath
|
|
1008
|
+
* @param position the position (line & column) where completions should be found
|
|
656
1009
|
*/
|
|
657
|
-
getCompletions(
|
|
658
|
-
let file = this.getFile(
|
|
1010
|
+
getCompletions(filePath, position) {
|
|
1011
|
+
let file = this.getFile(filePath);
|
|
659
1012
|
if (!file) {
|
|
660
1013
|
return [];
|
|
661
1014
|
}
|
|
662
|
-
let result = [];
|
|
663
|
-
if (reflection_1.isBrsFile(file) && file.parser.isPositionNextToTokenKind(position, lexer_1.TokenKind.Callfunc)) {
|
|
664
|
-
// is next to a @. callfunc invocation - must be an interface method
|
|
665
|
-
for (const scope of this.getScopes().filter((s) => reflection_1.isXmlScope(s))) {
|
|
666
|
-
let fileLinks = this.getStatementsForXmlFile(scope);
|
|
667
|
-
for (let fileLink of fileLinks) {
|
|
668
|
-
result.push(scope.createCompletionFromFunctionStatement(fileLink.item));
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
//no other result is possible in this case
|
|
672
|
-
return result;
|
|
673
|
-
}
|
|
674
1015
|
//find the scopes for this file
|
|
675
1016
|
let scopes = this.getScopesForFile(file);
|
|
676
1017
|
//if there are no scopes, include the global scope so we at least get the built-in functions
|
|
677
1018
|
scopes = scopes.length > 0 ? scopes : [this.globalScope];
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
return result;
|
|
1019
|
+
const event = {
|
|
1020
|
+
program: this,
|
|
1021
|
+
file: file,
|
|
1022
|
+
scopes: scopes,
|
|
1023
|
+
position: position,
|
|
1024
|
+
completions: []
|
|
1025
|
+
};
|
|
1026
|
+
this.plugins.emit('beforeProvideCompletions', event);
|
|
1027
|
+
this.plugins.emit('provideCompletions', event);
|
|
1028
|
+
this.plugins.emit('afterProvideCompletions', event);
|
|
1029
|
+
return event.completions;
|
|
690
1030
|
}
|
|
691
1031
|
/**
|
|
692
1032
|
* Goes through each file and builds a list of workspace symbols for the program. Used by LanguageServer's onWorkspaceSymbol functionality
|
|
693
1033
|
*/
|
|
694
1034
|
getWorkspaceSymbols() {
|
|
695
|
-
const
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
return
|
|
1035
|
+
const event = {
|
|
1036
|
+
program: this,
|
|
1037
|
+
workspaceSymbols: []
|
|
1038
|
+
};
|
|
1039
|
+
this.plugins.emit('beforeProvideWorkspaceSymbols', event);
|
|
1040
|
+
this.plugins.emit('provideWorkspaceSymbols', event);
|
|
1041
|
+
this.plugins.emit('afterProvideWorkspaceSymbols', event);
|
|
1042
|
+
return event.workspaceSymbols;
|
|
703
1043
|
}
|
|
704
1044
|
/**
|
|
705
1045
|
* Given a position in a file, if the position is sitting on some type of identifier,
|
|
706
1046
|
* go to the definition of that identifier (where this thing was first defined)
|
|
707
|
-
* @param srcPath The absolute path to the source file on disk
|
|
708
1047
|
*/
|
|
709
1048
|
getDefinition(srcPath, position) {
|
|
710
1049
|
let file = this.getFile(srcPath);
|
|
711
1050
|
if (!file) {
|
|
712
1051
|
return [];
|
|
713
1052
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
}
|
|
1053
|
+
const event = {
|
|
1054
|
+
program: this,
|
|
1055
|
+
file: file,
|
|
1056
|
+
position: position,
|
|
1057
|
+
definitions: []
|
|
1058
|
+
};
|
|
1059
|
+
this.plugins.emit('beforeProvideDefinition', event);
|
|
1060
|
+
this.plugins.emit('provideDefinition', event);
|
|
1061
|
+
this.plugins.emit('afterProvideDefinition', event);
|
|
1062
|
+
return event.definitions;
|
|
725
1063
|
}
|
|
726
1064
|
/**
|
|
727
|
-
*
|
|
1065
|
+
* Get hover information for a file and position
|
|
728
1066
|
*/
|
|
729
1067
|
getHover(srcPath, position) {
|
|
730
|
-
//find the file
|
|
731
1068
|
let file = this.getFile(srcPath);
|
|
732
|
-
|
|
733
|
-
|
|
1069
|
+
let result;
|
|
1070
|
+
if (file) {
|
|
1071
|
+
const event = {
|
|
1072
|
+
program: this,
|
|
1073
|
+
file: file,
|
|
1074
|
+
position: position,
|
|
1075
|
+
scopes: this.getScopesForFile(file),
|
|
1076
|
+
hovers: []
|
|
1077
|
+
};
|
|
1078
|
+
this.plugins.emit('beforeProvideHover', event);
|
|
1079
|
+
this.plugins.emit('provideHover', event);
|
|
1080
|
+
this.plugins.emit('afterProvideHover', event);
|
|
1081
|
+
result = event.hovers;
|
|
1082
|
+
}
|
|
1083
|
+
return result !== null && result !== void 0 ? result : [];
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Get full list of document symbols for a file
|
|
1087
|
+
* @param srcPath path to the file
|
|
1088
|
+
*/
|
|
1089
|
+
getDocumentSymbols(srcPath) {
|
|
1090
|
+
let file = this.getFile(srcPath);
|
|
1091
|
+
if (file) {
|
|
1092
|
+
const event = {
|
|
1093
|
+
program: this,
|
|
1094
|
+
file: file,
|
|
1095
|
+
documentSymbols: []
|
|
1096
|
+
};
|
|
1097
|
+
this.plugins.emit('beforeProvideDocumentSymbols', event);
|
|
1098
|
+
this.plugins.emit('provideDocumentSymbols', event);
|
|
1099
|
+
this.plugins.emit('afterProvideDocumentSymbols', event);
|
|
1100
|
+
return event.documentSymbols;
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
return undefined;
|
|
734
1104
|
}
|
|
735
|
-
return Promise.resolve(file.getHover(position));
|
|
736
1105
|
}
|
|
737
1106
|
/**
|
|
738
1107
|
* Compute code actions for the given file and range
|
|
739
|
-
* @param srcPath The absolute path to the source file on disk
|
|
740
1108
|
*/
|
|
741
1109
|
getCodeActions(srcPath, range) {
|
|
742
1110
|
const codeActions = [];
|
|
@@ -748,7 +1116,7 @@ class Program {
|
|
|
748
1116
|
//only keep diagnostics related to this file
|
|
749
1117
|
.filter(x => x.file === file)
|
|
750
1118
|
//only keep diagnostics that touch this range
|
|
751
|
-
.filter(x => util_1.util.
|
|
1119
|
+
.filter(x => util_1.util.rangesIntersectOrTouch(x.range, range));
|
|
752
1120
|
const scopes = this.getScopesForFile(file);
|
|
753
1121
|
this.plugins.emit('onGetCodeActions', {
|
|
754
1122
|
program: this,
|
|
@@ -761,362 +1129,262 @@ class Program {
|
|
|
761
1129
|
}
|
|
762
1130
|
return codeActions;
|
|
763
1131
|
}
|
|
1132
|
+
/**
|
|
1133
|
+
* Get semantic tokens for the specified file
|
|
1134
|
+
*/
|
|
1135
|
+
getSemanticTokens(srcPath) {
|
|
1136
|
+
const file = this.getFile(srcPath);
|
|
1137
|
+
if (file) {
|
|
1138
|
+
const result = [];
|
|
1139
|
+
this.plugins.emit('onGetSemanticTokens', {
|
|
1140
|
+
program: this,
|
|
1141
|
+
file: file,
|
|
1142
|
+
scopes: this.getScopesForFile(file),
|
|
1143
|
+
semanticTokens: result
|
|
1144
|
+
});
|
|
1145
|
+
return result;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
764
1148
|
getSignatureHelp(filepath, position) {
|
|
765
|
-
var _a;
|
|
766
1149
|
let file = this.getFile(filepath);
|
|
767
|
-
if (!file || !reflection_1.isBrsFile(file)) {
|
|
1150
|
+
if (!file || !(0, reflection_1.isBrsFile)(file)) {
|
|
768
1151
|
return [];
|
|
769
1152
|
}
|
|
770
|
-
|
|
771
|
-
let
|
|
772
|
-
|
|
773
|
-
if (identifierInfo.statementType === '') {
|
|
774
|
-
// just general function calls
|
|
775
|
-
let statements = file.program.getStatementsByName(identifierInfo.name, file);
|
|
776
|
-
for (let statement of statements) {
|
|
777
|
-
//TODO better handling of collisions - if it's a namespace, then don't show any other overrides
|
|
778
|
-
//if we're on m - then limit scope to the current class, if present
|
|
779
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
780
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
781
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
782
|
-
results.set(sigHelp.key, sigHelp);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
else if (identifierInfo.statementType === '.') {
|
|
787
|
-
//if m class reference.. then
|
|
788
|
-
//only get statements from the class I am in..
|
|
789
|
-
if (functionExpression) {
|
|
790
|
-
let myClass = file.getClassFromMReference(position, file.parser.getTokenAt(position), functionExpression);
|
|
791
|
-
if (myClass) {
|
|
792
|
-
for (let scope of this.getScopesForFile(myClass.file)) {
|
|
793
|
-
let classes = scope.getClassHierarchy(myClass.item.getName(parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
794
|
-
//and anything from any class in scope to a non m class
|
|
795
|
-
for (let statement of [...classes].filter((i) => reflection_1.isClassMethodStatement(i.item))) {
|
|
796
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
797
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
798
|
-
results.set(sigHelp.key, sigHelp);
|
|
799
|
-
return;
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
if (identifierInfo.dotPart) {
|
|
806
|
-
//potential namespaces
|
|
807
|
-
let statements = file.program.getStatementsByName(identifierInfo.name, file, identifierInfo.dotPart);
|
|
808
|
-
if (statements.length === 0) {
|
|
809
|
-
//was not a namespaced function, it could be any method on any class now
|
|
810
|
-
statements = file.program.getStatementsByName(identifierInfo.name, file);
|
|
811
|
-
}
|
|
812
|
-
for (let statement of statements) {
|
|
813
|
-
//TODO better handling of collisions - if it's a namespace, then don't show any other overrides
|
|
814
|
-
//if we're on m - then limit scope to the current class, if present
|
|
815
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
816
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
817
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
818
|
-
results.set(sigHelp.key, sigHelp);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
else if (identifierInfo.statementType === '@.') {
|
|
824
|
-
for (const scope of this.getScopes().filter((s) => reflection_1.isXmlScope(s))) {
|
|
825
|
-
let fileLinks = this.getStatementsForXmlFile(scope, identifierInfo.name);
|
|
826
|
-
for (let fileLink of fileLinks) {
|
|
827
|
-
let sigHelp = fileLink.file.getSignatureHelpForStatement(fileLink.item);
|
|
828
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
829
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
830
|
-
results.set(sigHelp.key, sigHelp);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
else if (identifierInfo.statementType === 'new') {
|
|
836
|
-
let classItem = file.getClassFileLink(identifierInfo.dotPart ? `${identifierInfo.dotPart}.${identifierInfo.name}` : identifierInfo.name);
|
|
837
|
-
let sigHelp = (_a = classItem === null || classItem === void 0 ? void 0 : classItem.file) === null || _a === void 0 ? void 0 : _a.getClassSignatureHelp(classItem === null || classItem === void 0 ? void 0 : classItem.item);
|
|
838
|
-
if (sigHelp && !results.has(sigHelp.key)) {
|
|
839
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
840
|
-
results.set(sigHelp.key, sigHelp);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
return [...results.values()];
|
|
1153
|
+
let callExpressionInfo = new CallExpressionInfo_1.CallExpressionInfo(file, position);
|
|
1154
|
+
let signatureHelpUtil = new SignatureHelpUtil_1.SignatureHelpUtil();
|
|
1155
|
+
return signatureHelpUtil.getSignatureHelpItems(callExpressionInfo);
|
|
844
1156
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
let
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
1157
|
+
getReferences(srcPath, position) {
|
|
1158
|
+
//find the file
|
|
1159
|
+
let file = this.getFile(srcPath);
|
|
1160
|
+
const event = {
|
|
1161
|
+
program: this,
|
|
1162
|
+
file: file,
|
|
1163
|
+
position: position,
|
|
1164
|
+
references: []
|
|
1165
|
+
};
|
|
1166
|
+
this.plugins.emit('beforeProvideReferences', event);
|
|
1167
|
+
this.plugins.emit('provideReferences', event);
|
|
1168
|
+
this.plugins.emit('afterProvideReferences', event);
|
|
1169
|
+
return event.references;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Transpile a single file and get the result as a string.
|
|
1173
|
+
* This does not write anything to the file system.
|
|
1174
|
+
*
|
|
1175
|
+
* This should only be called by `LanguageServer`.
|
|
1176
|
+
* Internal usage should call `_getTranspiledFileContents` instead.
|
|
1177
|
+
* @param filePath can be a srcPath or a destPath
|
|
1178
|
+
*/
|
|
1179
|
+
async getTranspiledFileContents(filePath) {
|
|
1180
|
+
const file = this.getFile(filePath);
|
|
1181
|
+
return this.getTranspiledFileContentsPipeline.run(async () => {
|
|
1182
|
+
const result = {
|
|
1183
|
+
destPath: file.destPath,
|
|
1184
|
+
pkgPath: file.pkgPath,
|
|
1185
|
+
srcPath: file.srcPath
|
|
1186
|
+
};
|
|
1187
|
+
const expectedPkgPath = file.pkgPath.toLowerCase();
|
|
1188
|
+
const expectedMapPath = `${expectedPkgPath}.map`;
|
|
1189
|
+
const expectedTypedefPkgPath = expectedPkgPath.replace(/\.brs$/i, '.d.bs');
|
|
1190
|
+
//add a temporary plugin to tap into the file writing process
|
|
1191
|
+
const plugin = this.plugins.addFirst({
|
|
1192
|
+
name: 'getTranspiledFileContents',
|
|
1193
|
+
beforeWriteFile: (event) => {
|
|
1194
|
+
const pkgPath = event.file.pkgPath.toLowerCase();
|
|
1195
|
+
switch (pkgPath) {
|
|
1196
|
+
//this is the actual transpiled file
|
|
1197
|
+
case expectedPkgPath:
|
|
1198
|
+
result.code = event.file.data.toString();
|
|
1199
|
+
break;
|
|
1200
|
+
//this is the sourcemap
|
|
1201
|
+
case expectedMapPath:
|
|
1202
|
+
result.map = event.file.data.toString();
|
|
1203
|
+
break;
|
|
1204
|
+
//this is the typedef
|
|
1205
|
+
case expectedTypedefPkgPath:
|
|
1206
|
+
result.typedef = event.file.data.toString();
|
|
1207
|
+
break;
|
|
1208
|
+
default:
|
|
1209
|
+
//no idea what this file is. just ignore it
|
|
894
1210
|
}
|
|
1211
|
+
//mark every file as processed so it they don't get written to the output directory
|
|
1212
|
+
event.processedFiles.add(event.file);
|
|
895
1213
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1214
|
+
});
|
|
1215
|
+
try {
|
|
1216
|
+
//now that the plugin has been registered, run the build with just this file
|
|
1217
|
+
await this.build({
|
|
1218
|
+
files: [file]
|
|
1219
|
+
});
|
|
902
1220
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
name = name || line.substring(index, argStartIndex);
|
|
906
|
-
argStartIndex = index;
|
|
1221
|
+
finally {
|
|
1222
|
+
this.plugins.remove(plugin);
|
|
907
1223
|
}
|
|
908
|
-
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
|
|
1224
|
+
return result;
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Get the absolute output path for a file
|
|
1229
|
+
*/
|
|
1230
|
+
getOutputPath(file, stagingDir = this.getStagingDir()) {
|
|
1231
|
+
return (0, util_1.standardizePath) `${stagingDir}/${file.pkgPath}`;
|
|
1232
|
+
}
|
|
1233
|
+
getStagingDir(stagingDir) {
|
|
1234
|
+
var _a, _b;
|
|
1235
|
+
let result = (_a = stagingDir !== null && stagingDir !== void 0 ? stagingDir : this.options.stagingDir) !== null && _a !== void 0 ? _a : this.options.stagingDir;
|
|
1236
|
+
if (!result) {
|
|
1237
|
+
result = roku_deploy_1.rokuDeploy.getOptions(this.options).stagingDir;
|
|
912
1238
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
statementType: statementType,
|
|
916
|
-
name: name,
|
|
917
|
-
dotPart: dotPart
|
|
918
|
-
};
|
|
1239
|
+
result = (0, util_1.standardizePath) `${path.resolve((_b = this.options.cwd) !== null && _b !== void 0 ? _b : process.cwd(), result !== null && result !== void 0 ? result : '/')}`;
|
|
1240
|
+
return result;
|
|
919
1241
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
isArgStartFound: false
|
|
1242
|
+
/**
|
|
1243
|
+
* Prepare the program for building
|
|
1244
|
+
* @param files the list of files that should be prepared
|
|
1245
|
+
*/
|
|
1246
|
+
async prepare(files) {
|
|
1247
|
+
const programEvent = {
|
|
1248
|
+
program: this,
|
|
1249
|
+
editor: this.editor,
|
|
1250
|
+
files: files
|
|
930
1251
|
};
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
if
|
|
934
|
-
|
|
935
|
-
|
|
1252
|
+
//assign an editor to every file
|
|
1253
|
+
for (const file of files) {
|
|
1254
|
+
//if the file doesn't have an editor yet, assign one now
|
|
1255
|
+
if (!file.editor) {
|
|
1256
|
+
file.editor = new Editor_1.Editor();
|
|
936
1257
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1258
|
+
}
|
|
1259
|
+
files.sort((a, b) => {
|
|
1260
|
+
if (a.pkgPath < b.pkgPath) {
|
|
1261
|
+
return -1;
|
|
1262
|
+
}
|
|
1263
|
+
else if (a.pkgPath > b.pkgPath) {
|
|
1264
|
+
return 1;
|
|
941
1265
|
}
|
|
942
1266
|
else {
|
|
943
|
-
|
|
944
|
-
itemCounts.normal++;
|
|
945
|
-
}
|
|
946
|
-
if (currentChar === ']') {
|
|
947
|
-
itemCounts.square++;
|
|
948
|
-
}
|
|
949
|
-
if (currentChar === '}') {
|
|
950
|
-
itemCounts.curly++;
|
|
951
|
-
}
|
|
952
|
-
if (currentChar === ',' && itemCounts.normal <= 0 && itemCounts.curly <= 0 && itemCounts.square <= 0) {
|
|
953
|
-
itemCounts.comma++;
|
|
954
|
-
}
|
|
955
|
-
if (currentChar === '(') {
|
|
956
|
-
if (itemCounts.normal === 0) {
|
|
957
|
-
itemCounts.isArgStartFound = true;
|
|
958
|
-
itemCounts.argStartIndex = index;
|
|
959
|
-
}
|
|
960
|
-
else {
|
|
961
|
-
itemCounts.normal--;
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
if (currentChar === '[') {
|
|
965
|
-
itemCounts.square--;
|
|
966
|
-
}
|
|
967
|
-
if (currentChar === '{') {
|
|
968
|
-
itemCounts.curly--;
|
|
969
|
-
}
|
|
1267
|
+
return 1;
|
|
970
1268
|
}
|
|
971
|
-
|
|
1269
|
+
});
|
|
1270
|
+
await this.plugins.emitAsync('beforePrepareProgram', programEvent);
|
|
1271
|
+
await this.plugins.emitAsync('prepareProgram', programEvent);
|
|
1272
|
+
const stagingDir = this.getStagingDir();
|
|
1273
|
+
const entries = [];
|
|
1274
|
+
for (const file of files) {
|
|
1275
|
+
//if the file doesn't have an editor yet, assign one now
|
|
1276
|
+
if (!file.editor) {
|
|
1277
|
+
file.editor = new Editor_1.Editor();
|
|
1278
|
+
}
|
|
1279
|
+
const event = {
|
|
1280
|
+
program: this,
|
|
1281
|
+
file: file,
|
|
1282
|
+
editor: file.editor,
|
|
1283
|
+
outputPath: this.getOutputPath(file, stagingDir)
|
|
1284
|
+
};
|
|
1285
|
+
await this.plugins.emitAsync('beforePrepareFile', event);
|
|
1286
|
+
await this.plugins.emitAsync('prepareFile', event);
|
|
1287
|
+
await this.plugins.emitAsync('afterPrepareFile', event);
|
|
1288
|
+
//TODO remove this in v1
|
|
1289
|
+
entries.push(event);
|
|
972
1290
|
}
|
|
973
|
-
|
|
1291
|
+
await this.plugins.emitAsync('afterPrepareProgram', programEvent);
|
|
1292
|
+
return files;
|
|
974
1293
|
}
|
|
975
1294
|
/**
|
|
976
|
-
*
|
|
1295
|
+
* Generate the contents of every file
|
|
977
1296
|
*/
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
if (
|
|
982
|
-
|
|
1297
|
+
async serialize(files) {
|
|
1298
|
+
const allFiles = new Map();
|
|
1299
|
+
//exclude prunable files if that option is enabled
|
|
1300
|
+
if (this.options.pruneEmptyCodeFiles === true) {
|
|
1301
|
+
files = files.filter(x => x.canBePruned !== true);
|
|
983
1302
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
if (!resultPkgPaths[lowerPkgPath]) {
|
|
1009
|
-
resultPkgPaths[lowerPkgPath] = true;
|
|
1010
|
-
result.push({
|
|
1011
|
-
label: relativePath,
|
|
1012
|
-
detail: file.srcPath,
|
|
1013
|
-
kind: vscode_languageserver_1.CompletionItemKind.File,
|
|
1014
|
-
textEdit: {
|
|
1015
|
-
newText: relativePath,
|
|
1016
|
-
range: scriptImport.filePathRange
|
|
1017
|
-
}
|
|
1018
|
-
});
|
|
1019
|
-
//add the absolute path
|
|
1020
|
-
result.push({
|
|
1021
|
-
label: file.pkgPath,
|
|
1022
|
-
detail: file.srcPath,
|
|
1023
|
-
kind: vscode_languageserver_1.CompletionItemKind.File,
|
|
1024
|
-
textEdit: {
|
|
1025
|
-
newText: file.pkgPath,
|
|
1026
|
-
range: scriptImport.filePathRange
|
|
1027
|
-
}
|
|
1028
|
-
});
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1303
|
+
const serializeProgramEvent = await this.plugins.emitAsync('beforeSerializeProgram', {
|
|
1304
|
+
program: this,
|
|
1305
|
+
files: files,
|
|
1306
|
+
result: allFiles
|
|
1307
|
+
});
|
|
1308
|
+
await this.plugins.emitAsync('onSerializeProgram', {
|
|
1309
|
+
program: this,
|
|
1310
|
+
files: files,
|
|
1311
|
+
result: allFiles
|
|
1312
|
+
});
|
|
1313
|
+
//sort the entries to make transpiling more deterministic
|
|
1314
|
+
files = serializeProgramEvent.files.sort((a, b) => {
|
|
1315
|
+
return a.srcPath < b.srcPath ? -1 : 1;
|
|
1316
|
+
});
|
|
1317
|
+
// serialize each file
|
|
1318
|
+
for (const file of files) {
|
|
1319
|
+
const event = {
|
|
1320
|
+
program: this,
|
|
1321
|
+
file: file,
|
|
1322
|
+
result: allFiles
|
|
1323
|
+
};
|
|
1324
|
+
await this.plugins.emitAsync('beforeSerializeFile', event);
|
|
1325
|
+
await this.plugins.emitAsync('serializeFile', event);
|
|
1326
|
+
await this.plugins.emitAsync('afterSerializeFile', event);
|
|
1031
1327
|
}
|
|
1032
|
-
|
|
1328
|
+
this.plugins.emit('afterSerializeProgram', {
|
|
1329
|
+
program: this,
|
|
1330
|
+
files: files,
|
|
1331
|
+
result: allFiles
|
|
1332
|
+
});
|
|
1333
|
+
return allFiles;
|
|
1033
1334
|
}
|
|
1034
1335
|
/**
|
|
1035
|
-
*
|
|
1036
|
-
* This does not write anything to the file system.
|
|
1037
|
-
* @param srcPath The absolute path to the source file on disk
|
|
1336
|
+
* Write the entire project to disk
|
|
1038
1337
|
*/
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
let result = file.transpile();
|
|
1042
|
-
return Object.assign(Object.assign({}, result), { srcPath: file.srcPath, pkgPath: file.pkgPath });
|
|
1043
|
-
}
|
|
1044
|
-
async transpile(fileEntries, stagingFolderPath) {
|
|
1045
|
-
// map fileEntries using their path as key to avoid excessive "find()" operations
|
|
1046
|
-
const mappedFileEntries = fileEntries.reduce((collection, entry) => {
|
|
1047
|
-
collection[util_1.standardizePath `${entry.src}`] = entry;
|
|
1048
|
-
return collection;
|
|
1049
|
-
}, {});
|
|
1050
|
-
const entries = [];
|
|
1051
|
-
for (const key in this.files) {
|
|
1052
|
-
const file = this.files[key];
|
|
1053
|
-
let filePathObj = mappedFileEntries[util_1.standardizePath `${file.srcPath}`];
|
|
1054
|
-
if (!filePathObj) {
|
|
1055
|
-
//this file has been added in-memory, from a plugin, for example
|
|
1056
|
-
filePathObj = {
|
|
1057
|
-
//add an interpolated src path (since it doesn't actually exist in memory)
|
|
1058
|
-
src: `bsc-in-memory:/${util_1.util.removeProtocol(file.pkgPath)}`,
|
|
1059
|
-
dest: file.pkgPath
|
|
1060
|
-
};
|
|
1061
|
-
}
|
|
1062
|
-
//prep the output path
|
|
1063
|
-
let outputPath = filePathObj.dest
|
|
1064
|
-
//replace any leading protocol
|
|
1065
|
-
.replace(/^[-a-z_]+:\//, '')
|
|
1066
|
-
//change any .bs file extension to .brs
|
|
1067
|
-
.replace(/\.bs$/gi, '.brs');
|
|
1068
|
-
//prepend the staging folder path
|
|
1069
|
-
outputPath = util_1.standardizePath `${stagingFolderPath}/${outputPath}`;
|
|
1070
|
-
entries.push({
|
|
1071
|
-
file: file,
|
|
1072
|
-
outputPath: outputPath
|
|
1073
|
-
});
|
|
1074
|
-
}
|
|
1075
|
-
this.plugins.emit('beforeProgramTranspile', {
|
|
1338
|
+
async write(stagingDir, files) {
|
|
1339
|
+
const programEvent = await this.plugins.emitAsync('beforeWriteProgram', {
|
|
1076
1340
|
program: this,
|
|
1077
|
-
|
|
1341
|
+
files: files,
|
|
1342
|
+
stagingDir: stagingDir
|
|
1078
1343
|
});
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1344
|
+
//empty the staging directory
|
|
1345
|
+
await fsExtra.emptyDir(stagingDir);
|
|
1346
|
+
const serializedFiles = [...files]
|
|
1347
|
+
.map(([, serializedFiles]) => serializedFiles)
|
|
1348
|
+
.flat();
|
|
1349
|
+
//write all the files to disk (asynchronously)
|
|
1350
|
+
await Promise.all(serializedFiles.map(async (file) => {
|
|
1351
|
+
const event = await this.plugins.emitAsync('beforeWriteFile', {
|
|
1085
1352
|
program: this,
|
|
1086
|
-
file:
|
|
1087
|
-
outputPath:
|
|
1353
|
+
file: file,
|
|
1354
|
+
outputPath: this.getOutputPath(file, stagingDir),
|
|
1355
|
+
processedFiles: new Set()
|
|
1088
1356
|
});
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
await fsExtra.writeFile(typedefPath, typedef);
|
|
1105
|
-
}
|
|
1106
|
-
this.plugins.emit('afterFileTranspile', {
|
|
1357
|
+
await this.plugins.emitAsync('writeFile', event);
|
|
1358
|
+
await this.plugins.emitAsync('afterWriteFile', event);
|
|
1359
|
+
}));
|
|
1360
|
+
await this.plugins.emitAsync('afterWriteProgram', programEvent);
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Build the project. This transpiles/transforms/copies all files and moves them to the staging directory
|
|
1364
|
+
* @param options the list of options used to build the program
|
|
1365
|
+
*/
|
|
1366
|
+
async build(options) {
|
|
1367
|
+
//run a single build at a time
|
|
1368
|
+
await this.buildPipeline.run(async () => {
|
|
1369
|
+
var _a;
|
|
1370
|
+
const stagingDir = this.getStagingDir(options === null || options === void 0 ? void 0 : options.stagingDir);
|
|
1371
|
+
const event = await this.plugins.emitAsync('beforeBuildProgram', {
|
|
1107
1372
|
program: this,
|
|
1108
|
-
|
|
1109
|
-
|
|
1373
|
+
editor: this.editor,
|
|
1374
|
+
files: (_a = options === null || options === void 0 ? void 0 : options.files) !== null && _a !== void 0 ? _a : Object.values(this.files)
|
|
1110
1375
|
});
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1376
|
+
//prepare the program (and files) for building
|
|
1377
|
+
event.files = await this.prepare(event.files);
|
|
1378
|
+
//stage the entire program
|
|
1379
|
+
const serializedFilesByFile = await this.serialize(event.files);
|
|
1380
|
+
await this.write(stagingDir, serializedFilesByFile);
|
|
1381
|
+
await this.plugins.emitAsync('afterBuildProgram', event);
|
|
1382
|
+
//undo all edits for the program
|
|
1383
|
+
this.editor.undoAll();
|
|
1384
|
+
//undo all edits for each file
|
|
1385
|
+
for (const file of event.files) {
|
|
1386
|
+
file.editor.undoAll();
|
|
1387
|
+
}
|
|
1120
1388
|
});
|
|
1121
1389
|
}
|
|
1122
1390
|
/**
|
|
@@ -1127,10 +1395,11 @@ class Program {
|
|
|
1127
1395
|
const lowerFunctionName = functionName.toLowerCase();
|
|
1128
1396
|
//find every file with this function defined
|
|
1129
1397
|
for (const file of Object.values(this.files)) {
|
|
1130
|
-
if (reflection_1.isBrsFile(file)) {
|
|
1398
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1131
1399
|
//TODO handle namespace-relative function calls
|
|
1132
1400
|
//if the file has a function with this name
|
|
1133
|
-
|
|
1401
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1402
|
+
if (file['_cachedLookups'].functionStatementMap.get(lowerFunctionName)) {
|
|
1134
1403
|
files.push(file);
|
|
1135
1404
|
}
|
|
1136
1405
|
}
|
|
@@ -1138,55 +1407,142 @@ class Program {
|
|
|
1138
1407
|
return files;
|
|
1139
1408
|
}
|
|
1140
1409
|
/**
|
|
1141
|
-
* Find a list of files in the program that have a
|
|
1410
|
+
* Find a list of files in the program that have a class with the given name (case INsensitive)
|
|
1142
1411
|
*/
|
|
1143
1412
|
findFilesForClass(className) {
|
|
1144
1413
|
const files = [];
|
|
1145
1414
|
const lowerClassName = className.toLowerCase();
|
|
1146
1415
|
//find every file with this class defined
|
|
1147
1416
|
for (const file of Object.values(this.files)) {
|
|
1148
|
-
if (reflection_1.isBrsFile(file)) {
|
|
1417
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1149
1418
|
//TODO handle namespace-relative classes
|
|
1150
1419
|
//if the file has a function with this name
|
|
1151
|
-
|
|
1420
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1421
|
+
if (file['_cachedLookups'].classStatementMap.get(lowerClassName) !== undefined) {
|
|
1152
1422
|
files.push(file);
|
|
1153
1423
|
}
|
|
1154
1424
|
}
|
|
1155
1425
|
}
|
|
1156
1426
|
return files;
|
|
1157
1427
|
}
|
|
1428
|
+
findFilesForNamespace(name) {
|
|
1429
|
+
const files = [];
|
|
1430
|
+
const lowerName = name.toLowerCase();
|
|
1431
|
+
//find every file with this class defined
|
|
1432
|
+
for (const file of Object.values(this.files)) {
|
|
1433
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1434
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1435
|
+
if (file['_cachedLookups'].namespaceStatements.find((x) => {
|
|
1436
|
+
const namespaceName = x.name.toLowerCase();
|
|
1437
|
+
return (
|
|
1438
|
+
//the namespace name matches exactly
|
|
1439
|
+
namespaceName === lowerName ||
|
|
1440
|
+
//the full namespace starts with the name (honoring the part boundary)
|
|
1441
|
+
namespaceName.startsWith(lowerName + '.'));
|
|
1442
|
+
})) {
|
|
1443
|
+
files.push(file);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
return files;
|
|
1448
|
+
}
|
|
1449
|
+
findFilesForEnum(name) {
|
|
1450
|
+
const files = [];
|
|
1451
|
+
const lowerName = name.toLowerCase();
|
|
1452
|
+
//find every file with this enum defined
|
|
1453
|
+
for (const file of Object.values(this.files)) {
|
|
1454
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1455
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1456
|
+
if (file['_cachedLookups'].enumStatementMap.get(lowerName)) {
|
|
1457
|
+
files.push(file);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return files;
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Modify a parsed manifest map by reading `bs_const` and injecting values from `options.manifest.bs_const`
|
|
1465
|
+
* @param parsedManifest The manifest map to read from and modify
|
|
1466
|
+
*/
|
|
1467
|
+
buildBsConstsIntoParsedManifest(parsedManifest) {
|
|
1468
|
+
var _a, _b;
|
|
1469
|
+
// Lift the bs_consts defined in the manifest
|
|
1470
|
+
let bsConsts = (0, Manifest_1.getBsConst)(parsedManifest, false);
|
|
1471
|
+
// Override or delete any bs_consts defined in the bs config
|
|
1472
|
+
for (const key in (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.manifest) === null || _b === void 0 ? void 0 : _b.bs_const) {
|
|
1473
|
+
const value = this.options.manifest.bs_const[key];
|
|
1474
|
+
if (value === null) {
|
|
1475
|
+
bsConsts.delete(key);
|
|
1476
|
+
}
|
|
1477
|
+
else {
|
|
1478
|
+
bsConsts.set(key, value);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
// convert the new list of bs consts back into a string for the rest of the down stream systems to use
|
|
1482
|
+
let constString = '';
|
|
1483
|
+
for (const [key, value] of bsConsts) {
|
|
1484
|
+
constString += `${constString !== '' ? ';' : ''}${key}=${value.toString()}`;
|
|
1485
|
+
}
|
|
1486
|
+
// Set the updated bs_const value
|
|
1487
|
+
parsedManifest.set('bs_const', constString);
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Try to find and load the manifest into memory
|
|
1491
|
+
* @param manifestFileObj A pointer to a potential manifest file object found during loading
|
|
1492
|
+
* @param replaceIfAlreadyLoaded should we overwrite the internal `_manifest` if it already exists
|
|
1493
|
+
*/
|
|
1494
|
+
loadManifest(manifestFileObj, replaceIfAlreadyLoaded = true) {
|
|
1495
|
+
//if we already have a manifest instance, and should not replace...then don't replace
|
|
1496
|
+
if (!replaceIfAlreadyLoaded && this._manifest) {
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
let manifestPath = manifestFileObj
|
|
1500
|
+
? manifestFileObj.src
|
|
1501
|
+
: path.join(this.options.rootDir, 'manifest');
|
|
1502
|
+
try {
|
|
1503
|
+
// we only load this manifest once, so do it sync to improve speed downstream
|
|
1504
|
+
const contents = fsExtra.readFileSync(manifestPath, 'utf-8');
|
|
1505
|
+
const parsedManifest = (0, Manifest_1.parseManifest)(contents);
|
|
1506
|
+
this.buildBsConstsIntoParsedManifest(parsedManifest);
|
|
1507
|
+
this._manifest = parsedManifest;
|
|
1508
|
+
}
|
|
1509
|
+
catch (e) {
|
|
1510
|
+
this._manifest = new Map();
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1158
1513
|
/**
|
|
1159
1514
|
* Get a map of the manifest information
|
|
1160
1515
|
*/
|
|
1161
1516
|
getManifest() {
|
|
1162
1517
|
if (!this._manifest) {
|
|
1163
|
-
|
|
1164
|
-
//TODO update this to get the manifest from the files array or require it in the options...we shouldn't assume the location of the manifest
|
|
1165
|
-
let manifestPath = path.join(this.options.rootDir, 'manifest');
|
|
1166
|
-
let contents;
|
|
1167
|
-
try {
|
|
1168
|
-
//we only load this manifest once, so do it sync to improve speed downstream
|
|
1169
|
-
contents = fsExtra.readFileSync(manifestPath, 'utf-8');
|
|
1170
|
-
this._manifest = Manifest_1.parseManifest(contents);
|
|
1171
|
-
}
|
|
1172
|
-
catch (err) {
|
|
1173
|
-
this._manifest = new Map();
|
|
1174
|
-
}
|
|
1518
|
+
this.loadManifest();
|
|
1175
1519
|
}
|
|
1176
1520
|
return this._manifest;
|
|
1177
1521
|
}
|
|
1178
1522
|
dispose() {
|
|
1179
|
-
var _a, _b;
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
(_a =
|
|
1523
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1524
|
+
this.plugins.emit('beforeProgramDispose', { program: this });
|
|
1525
|
+
for (let filePath in this.files) {
|
|
1526
|
+
(_b = (_a = this.files[filePath]) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1183
1527
|
}
|
|
1184
1528
|
for (let name in this.scopes) {
|
|
1185
|
-
(
|
|
1529
|
+
(_d = (_c = this.scopes[name]) === null || _c === void 0 ? void 0 : _c.dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
1186
1530
|
}
|
|
1187
|
-
this.globalScope.dispose();
|
|
1188
|
-
this.dependencyGraph.dispose();
|
|
1531
|
+
(_f = (_e = this.globalScope) === null || _e === void 0 ? void 0 : _e.dispose) === null || _f === void 0 ? void 0 : _f.call(_e);
|
|
1532
|
+
(_h = (_g = this.dependencyGraph) === null || _g === void 0 ? void 0 : _g.dispose) === null || _h === void 0 ? void 0 : _h.call(_g);
|
|
1189
1533
|
}
|
|
1190
1534
|
}
|
|
1191
1535
|
exports.Program = Program;
|
|
1536
|
+
class ProvideFileEventInternal {
|
|
1537
|
+
constructor(program, srcPath, destPath, data, fileFactory) {
|
|
1538
|
+
var _a;
|
|
1539
|
+
this.program = program;
|
|
1540
|
+
this.srcPath = srcPath;
|
|
1541
|
+
this.destPath = destPath;
|
|
1542
|
+
this.data = data;
|
|
1543
|
+
this.fileFactory = fileFactory;
|
|
1544
|
+
this.files = [];
|
|
1545
|
+
this.srcExtension = (_a = path.extname(srcPath)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1192
1548
|
//# sourceMappingURL=Program.js.map
|