brighterscript 1.0.0-alpha.5 → 1.0.0-alpha.51
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/README.md +79 -138
- package/bsconfig.schema.json +196 -5
- 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 +45 -0
- package/dist/AstValidationSegmenter.js +322 -0
- package/dist/AstValidationSegmenter.js.map +1 -0
- package/dist/BsConfig.d.ts +161 -43
- package/dist/BusyStatusTracker.d.ts +61 -0
- package/dist/BusyStatusTracker.js +148 -0
- package/dist/BusyStatusTracker.js.map +1 -0
- package/dist/Cache.d.ts +3 -8
- package/dist/Cache.js +9 -14
- 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 +29 -4
- package/dist/CodeActionUtil.js +22 -5
- package/dist/CodeActionUtil.js.map +1 -1
- package/dist/CommentFlagProcessor.d.ts +20 -15
- package/dist/CommentFlagProcessor.js +143 -58
- package/dist/CommentFlagProcessor.js.map +1 -1
- package/dist/CrossScopeValidator.d.ts +68 -0
- package/dist/CrossScopeValidator.js +650 -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 +21 -5
- package/dist/DiagnosticCollection.js +77 -24
- package/dist/DiagnosticCollection.js.map +1 -1
- package/dist/DiagnosticFilterer.d.ts +27 -6
- package/dist/DiagnosticFilterer.js +273 -60
- package/dist/DiagnosticFilterer.js.map +1 -1
- package/dist/DiagnosticManager.d.ts +83 -0
- package/dist/DiagnosticManager.js +422 -0
- package/dist/DiagnosticManager.js.map +1 -0
- package/dist/DiagnosticMessages.d.ts +602 -196
- package/dist/DiagnosticMessages.js +926 -342
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
- package/dist/DiagnosticSeverityAdjuster.js +45 -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 +136 -104
- package/dist/LanguageServer.js +577 -741
- package/dist/LanguageServer.js.map +1 -1
- package/dist/Logger.d.ts +17 -13
- package/dist/Logger.js +64 -34
- package/dist/Logger.js.map +1 -1
- package/dist/PluginInterface.d.ts +32 -10
- package/dist/PluginInterface.js +117 -7
- package/dist/PluginInterface.js.map +1 -1
- package/dist/Program.d.ts +302 -98
- package/dist/Program.js +1613 -726
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +39 -22
- package/dist/ProgramBuilder.js +245 -179
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +227 -106
- package/dist/Scope.js +609 -557
- package/dist/Scope.js.map +1 -1
- package/dist/ScopeNamespaceLookup.d.ts +73 -0
- package/dist/ScopeNamespaceLookup.js +242 -0
- package/dist/ScopeNamespaceLookup.js.map +1 -0
- package/dist/SemanticTokenUtils.js +5 -1
- package/dist/SemanticTokenUtils.js.map +1 -1
- 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 +145 -26
- package/dist/SymbolTable.js +575 -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 +34 -90
- package/dist/XmlScope.js.map +1 -1
- package/dist/astUtils/CachedLookups.d.ts +50 -0
- package/dist/astUtils/CachedLookups.js +337 -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/creators.d.ts +54 -19
- package/dist/astUtils/creators.js +242 -42
- package/dist/astUtils/creators.js.map +1 -1
- package/dist/astUtils/reflection.d.ts +199 -85
- package/dist/astUtils/reflection.js +518 -145
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/stackedVisitor.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +117 -53
- package/dist/astUtils/visitors.js +95 -15
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/xml.d.ts +9 -8
- package/dist/astUtils/xml.js +12 -7
- package/dist/astUtils/xml.js.map +1 -1
- package/dist/bscPlugin/BscPlugin.d.ts +26 -4
- package/dist/bscPlugin/BscPlugin.js +96 -4
- package/dist/bscPlugin/BscPlugin.js.map +1 -1
- package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
- package/dist/bscPlugin/CallExpressionInfo.js +142 -0
- package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
- package/dist/bscPlugin/FileWriter.d.ts +19 -0
- package/dist/bscPlugin/FileWriter.js +79 -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 +109 -7
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +676 -26
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.d.ts +17 -0
- package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.js +66 -0
- package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.js.map +1 -0
- package/dist/bscPlugin/codeActions/codeActionHelpers.d.ts +18 -0
- package/dist/bscPlugin/codeActions/codeActionHelpers.js +31 -0
- package/dist/bscPlugin/codeActions/codeActionHelpers.js.map +1 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +65 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js +633 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
- package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
- package/dist/bscPlugin/definition/DefinitionProvider.js +220 -0
- package/dist/bscPlugin/definition/DefinitionProvider.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 +238 -0
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
- package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
- package/dist/bscPlugin/references/ReferencesProvider.js +57 -0
- package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
- package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.d.ts +7 -0
- package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.js +77 -0
- package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.js.map +1 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +14 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +164 -0
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
- package/dist/bscPlugin/serialize/BslibManager.d.ts +12 -0
- package/dist/bscPlugin/serialize/BslibManager.js +46 -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 +80 -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/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/symbolUtils.d.ts +5 -0
- package/dist/bscPlugin/symbols/symbolUtils.js +141 -0
- package/dist/bscPlugin/symbols/symbolUtils.js.map +1 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +34 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +504 -0
- package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.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 +51 -0
- package/dist/bscPlugin/validation/BrsFileValidator.js +714 -0
- package/dist/bscPlugin/validation/BrsFileValidator.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 +158 -0
- package/dist/bscPlugin/validation/ScopeValidator.js +1481 -0
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
- package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
- package/dist/bscPlugin/validation/XmlFileValidator.js +50 -0
- package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
- package/dist/cli.js +140 -28
- package/dist/cli.js.map +1 -1
- package/dist/common/Sequencer.d.ts +53 -0
- package/dist/common/Sequencer.js +233 -0
- package/dist/common/Sequencer.js.map +1 -0
- package/dist/deferred.d.ts +5 -3
- package/dist/deferred.js +10 -0
- package/dist/deferred.js.map +1 -1
- package/dist/diagnosticUtils.d.ts +61 -4
- package/dist/diagnosticUtils.js +285 -25
- package/dist/diagnosticUtils.js.map +1 -1
- package/dist/examples/plugins/removePrint.d.ts +2 -2
- 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.d.ts +161 -87
- package/dist/files/BrsFile.js +919 -936
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BscFile.d.ts +102 -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 +21 -0
- package/dist/files/LazyFileData.js +54 -0
- package/dist/files/LazyFileData.js.map +1 -0
- package/dist/files/XmlFile.d.ts +80 -41
- package/dist/files/XmlFile.js +162 -137
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/globalCallables.d.ts +3 -1
- package/dist/globalCallables.js +424 -184
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +32 -4
- package/dist/index.js +54 -7
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +987 -125
- package/dist/interfaces.js +21 -0
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/Lexer.d.ts +51 -12
- package/dist/lexer/Lexer.js +214 -65
- package/dist/lexer/Lexer.js.map +1 -1
- package/dist/lexer/Token.d.ts +27 -11
- package/dist/lexer/Token.js +10 -2
- package/dist/lexer/Token.js.map +1 -1
- package/dist/lexer/TokenKind.d.ts +48 -2
- package/dist/lexer/TokenKind.js +167 -10
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/logging.d.ts +14 -0
- package/dist/logging.js +29 -0
- package/dist/logging.js.map +1 -0
- package/dist/lsp/ActionQueue.d.ts +35 -0
- package/dist/lsp/ActionQueue.js +115 -0
- package/dist/lsp/ActionQueue.js.map +1 -0
- package/dist/lsp/DocumentManager.d.ts +63 -0
- package/dist/lsp/DocumentManager.js +122 -0
- package/dist/lsp/DocumentManager.js.map +1 -0
- package/dist/lsp/LspProject.d.ts +287 -0
- package/dist/lsp/LspProject.js +3 -0
- package/dist/lsp/LspProject.js.map +1 -0
- package/dist/lsp/PathFilterer.d.ts +75 -0
- package/dist/lsp/PathFilterer.js +196 -0
- package/dist/lsp/PathFilterer.js.map +1 -0
- package/dist/lsp/Project.d.ts +200 -0
- package/dist/lsp/Project.js +562 -0
- package/dist/lsp/Project.js.map +1 -0
- package/dist/lsp/ProjectManager.d.ts +288 -0
- package/dist/lsp/ProjectManager.js +967 -0
- package/dist/lsp/ProjectManager.js.map +1 -0
- package/dist/lsp/ReaderWriterManager.d.ts +21 -0
- package/dist/lsp/ReaderWriterManager.js +60 -0
- package/dist/lsp/ReaderWriterManager.js.map +1 -0
- package/dist/lsp/worker/MessageHandler.d.ts +99 -0
- package/dist/lsp/worker/MessageHandler.js +138 -0
- package/dist/lsp/worker/MessageHandler.js.map +1 -0
- package/dist/lsp/worker/WorkerPool.d.ts +38 -0
- package/dist/lsp/worker/WorkerPool.js +78 -0
- package/dist/lsp/worker/WorkerPool.js.map +1 -0
- package/dist/lsp/worker/WorkerThreadProject.d.ts +168 -0
- package/dist/lsp/worker/WorkerThreadProject.js +205 -0
- package/dist/lsp/worker/WorkerThreadProject.js.map +1 -0
- package/dist/lsp/worker/WorkerThreadProjectRunner.d.ts +15 -0
- package/dist/lsp/worker/WorkerThreadProjectRunner.js +58 -0
- package/dist/lsp/worker/WorkerThreadProjectRunner.js.map +1 -0
- package/dist/lsp/worker/run.js +14 -0
- package/dist/lsp/worker/run.js.map +1 -0
- package/dist/parser/AstNode.d.ts +205 -0
- package/dist/parser/AstNode.js +305 -0
- package/dist/parser/AstNode.js.map +1 -0
- package/dist/parser/BrightScriptDocParser.d.ts +56 -0
- package/dist/parser/BrightScriptDocParser.js +294 -0
- package/dist/parser/BrightScriptDocParser.js.map +1 -0
- package/dist/parser/BrsTranspileState.d.ts +22 -3
- package/dist/parser/BrsTranspileState.js +19 -0
- package/dist/parser/BrsTranspileState.js.map +1 -1
- package/dist/parser/Expression.d.ts +601 -220
- package/dist/parser/Expression.js +1516 -502
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.d.ts +137 -121
- package/dist/parser/Parser.js +1808 -982
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/SGParser.d.ts +30 -13
- package/dist/parser/SGParser.js +94 -56
- package/dist/parser/SGParser.js.map +1 -1
- package/dist/parser/SGTypes.d.ts +134 -46
- package/dist/parser/SGTypes.js +206 -115
- package/dist/parser/SGTypes.js.map +1 -1
- package/dist/parser/Statement.d.ts +854 -267
- package/dist/parser/Statement.js +2416 -621
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/TranspileState.d.ts +30 -14
- package/dist/parser/TranspileState.js +124 -27
- package/dist/parser/TranspileState.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/roku-types/data.json +20554 -0
- package/dist/roku-types/index.d.ts +5726 -0
- package/dist/roku-types/index.js +11 -0
- package/dist/roku-types/index.js.map +1 -0
- package/dist/types/ArrayType.d.ts +12 -5
- package/dist/types/ArrayType.js +95 -25
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/AssociativeArrayType.d.ts +15 -0
- package/dist/types/AssociativeArrayType.js +64 -0
- package/dist/types/AssociativeArrayType.js.map +1 -0
- package/dist/types/BaseFunctionType.d.ts +10 -0
- package/dist/types/BaseFunctionType.js +26 -0
- package/dist/types/BaseFunctionType.js.map +1 -0
- package/dist/types/BooleanType.d.ts +9 -5
- package/dist/types/BooleanType.js +19 -8
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BscType.d.ts +41 -3
- package/dist/types/BscType.js +152 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/BscTypeKind.d.ts +28 -0
- package/dist/types/BscTypeKind.js +33 -0
- package/dist/types/BscTypeKind.js.map +1 -0
- package/dist/types/BuiltInInterfaceAdder.d.ts +28 -0
- package/dist/types/BuiltInInterfaceAdder.js +212 -0
- package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
- package/dist/types/CallFuncableType.d.ts +24 -0
- package/dist/types/CallFuncableType.js +91 -0
- package/dist/types/CallFuncableType.js.map +1 -0
- package/dist/types/ClassType.d.ts +17 -0
- package/dist/types/ClassType.js +63 -0
- package/dist/types/ClassType.js.map +1 -0
- package/dist/types/ComponentType.d.ts +22 -0
- package/dist/types/ComponentType.js +110 -0
- package/dist/types/ComponentType.js.map +1 -0
- package/dist/types/DoubleType.d.ts +10 -5
- package/dist/types/DoubleType.js +21 -17
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/DynamicType.d.ts +13 -5
- package/dist/types/DynamicType.js +26 -5
- package/dist/types/DynamicType.js.map +1 -1
- package/dist/types/EnumType.d.ts +42 -0
- package/dist/types/EnumType.js +101 -0
- package/dist/types/EnumType.js.map +1 -0
- package/dist/types/FloatType.d.ts +10 -5
- package/dist/types/FloatType.js +21 -17
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/FunctionType.d.ts +8 -22
- package/dist/types/FunctionType.js +25 -63
- package/dist/types/FunctionType.js.map +1 -1
- package/dist/types/InheritableType.d.ts +29 -0
- package/dist/types/InheritableType.js +173 -0
- package/dist/types/InheritableType.js.map +1 -0
- package/dist/types/InlineInterfaceType.d.ts +5 -0
- package/dist/types/InlineInterfaceType.js +17 -0
- package/dist/types/InlineInterfaceType.js.map +1 -0
- package/dist/types/IntegerType.d.ts +10 -5
- package/dist/types/IntegerType.js +21 -17
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/InterfaceType.d.ts +14 -6
- package/dist/types/InterfaceType.js +30 -15
- package/dist/types/InterfaceType.js.map +1 -1
- package/dist/types/IntersectionType.d.ts +29 -0
- package/dist/types/IntersectionType.js +256 -0
- package/dist/types/IntersectionType.js.map +1 -0
- package/dist/types/InvalidType.d.ts +10 -5
- package/dist/types/InvalidType.js +21 -9
- package/dist/types/InvalidType.js.map +1 -1
- package/dist/types/LongIntegerType.d.ts +10 -5
- package/dist/types/LongIntegerType.js +21 -17
- package/dist/types/LongIntegerType.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 +12 -5
- package/dist/types/ObjectType.js +25 -8
- package/dist/types/ObjectType.js.map +1 -1
- package/dist/types/ReferenceType.d.ts +123 -0
- package/dist/types/ReferenceType.js +726 -0
- package/dist/types/ReferenceType.js.map +1 -0
- package/dist/types/StringType.d.ts +12 -5
- package/dist/types/StringType.js +23 -8
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/TypeStatementType.d.ts +19 -0
- package/dist/types/TypeStatementType.js +56 -0
- package/dist/types/TypeStatementType.js.map +1 -0
- package/dist/types/TypedFunctionType.d.ts +34 -0
- package/dist/types/TypedFunctionType.js +157 -0
- package/dist/types/TypedFunctionType.js.map +1 -0
- package/dist/types/UninitializedType.d.ts +11 -6
- package/dist/types/UninitializedType.js +20 -11
- package/dist/types/UninitializedType.js.map +1 -1
- package/dist/types/UnionType.d.ts +27 -0
- package/dist/types/UnionType.js +196 -0
- package/dist/types/UnionType.js.map +1 -0
- package/dist/types/VoidType.d.ts +11 -5
- package/dist/types/VoidType.js +22 -8
- package/dist/types/VoidType.js.map +1 -1
- package/dist/types/helpers.d.ts +51 -0
- package/dist/types/helpers.js +329 -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/types/roFunctionType.d.ts +11 -0
- package/dist/types/roFunctionType.js +37 -0
- package/dist/types/roFunctionType.js.map +1 -0
- package/dist/util.d.ts +325 -185
- package/dist/util.js +2135 -568
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +9 -15
- package/dist/validators/ClassValidator.js +93 -138
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +183 -138
- package/CHANGELOG.md +0 -1188
- package/dist/astUtils/creators.spec.js +0 -21
- package/dist/astUtils/creators.spec.js.map +0 -1
- 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/astUtils/reflection.spec.d.ts +0 -1
- package/dist/astUtils/reflection.spec.js +0 -292
- package/dist/astUtils/reflection.spec.js.map +0 -1
- package/dist/astUtils/stackedVisitor.spec.d.ts +0 -1
- package/dist/astUtils/stackedVisitor.spec.js +0 -79
- package/dist/astUtils/stackedVisitor.spec.js.map +0 -1
- package/dist/astUtils/visitors.spec.d.ts +0 -1
- package/dist/astUtils/visitors.spec.js +0 -854
- package/dist/astUtils/visitors.spec.js.map +0 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.d.ts +0 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +0 -194
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +0 -1
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.d.ts +0 -7
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js +0 -63
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js.map +0 -1
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.d.ts +0 -1
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js +0 -45
- package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +0 -1
- package/dist/files/BrsFile.Class.spec.d.ts +0 -1
- package/dist/files/BrsFile.Class.spec.js +0 -1081
- package/dist/files/BrsFile.Class.spec.js.map +0 -1
- package/dist/files/BrsFile.spec.d.ts +0 -1
- package/dist/files/BrsFile.spec.js +0 -2524
- package/dist/files/BrsFile.spec.js.map +0 -1
- package/dist/files/XmlFile.spec.d.ts +0 -1
- package/dist/files/XmlFile.spec.js +0 -1065
- package/dist/files/XmlFile.spec.js.map +0 -1
- package/dist/files/tests/imports.spec.d.ts +0 -1
- package/dist/files/tests/imports.spec.js +0 -241
- package/dist/files/tests/imports.spec.js.map +0 -1
- package/dist/lexer/Character.spec.d.ts +0 -1
- package/dist/lexer/Character.spec.js +0 -27
- package/dist/lexer/Character.spec.js.map +0 -1
- package/dist/lexer/Lexer.spec.d.ts +0 -1
- package/dist/lexer/Lexer.spec.js +0 -1101
- package/dist/lexer/Lexer.spec.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/Parser.Class.spec.d.ts +0 -1
- package/dist/parser/Parser.Class.spec.js +0 -390
- package/dist/parser/Parser.Class.spec.js.map +0 -1
- package/dist/parser/Parser.spec.d.ts +0 -4
- package/dist/parser/Parser.spec.js +0 -1216
- package/dist/parser/Parser.spec.js.map +0 -1
- package/dist/parser/SGParser.spec.d.ts +0 -1
- package/dist/parser/SGParser.spec.js +0 -145
- package/dist/parser/SGParser.spec.js.map +0 -1
- package/dist/parser/SGTypes.spec.d.ts +0 -1
- package/dist/parser/SGTypes.spec.js +0 -351
- package/dist/parser/SGTypes.spec.js.map +0 -1
- package/dist/parser/Statement.spec.d.ts +0 -1
- package/dist/parser/Statement.spec.js +0 -94
- package/dist/parser/Statement.spec.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/parser/tests/Parser.spec.d.ts +0 -18
- package/dist/parser/tests/Parser.spec.js +0 -35
- package/dist/parser/tests/Parser.spec.js.map +0 -1
- package/dist/parser/tests/controlFlow/For.spec.d.ts +0 -1
- package/dist/parser/tests/controlFlow/For.spec.js +0 -161
- package/dist/parser/tests/controlFlow/For.spec.js.map +0 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.d.ts +0 -1
- package/dist/parser/tests/controlFlow/ForEach.spec.js +0 -106
- package/dist/parser/tests/controlFlow/ForEach.spec.js.map +0 -1
- package/dist/parser/tests/controlFlow/If.spec.d.ts +0 -1
- package/dist/parser/tests/controlFlow/If.spec.js +0 -551
- package/dist/parser/tests/controlFlow/If.spec.js.map +0 -1
- package/dist/parser/tests/controlFlow/While.spec.d.ts +0 -1
- package/dist/parser/tests/controlFlow/While.spec.js +0 -107
- package/dist/parser/tests/controlFlow/While.spec.js.map +0 -1
- package/dist/parser/tests/expression/Additive.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Additive.spec.js +0 -99
- package/dist/parser/tests/expression/Additive.spec.js.map +0 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.d.ts +0 -1
- package/dist/parser/tests/expression/ArrayLiterals.spec.js +0 -254
- package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +0 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.d.ts +0 -1
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +0 -266
- package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +0 -1
- package/dist/parser/tests/expression/Boolean.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Boolean.spec.js +0 -83
- package/dist/parser/tests/expression/Boolean.spec.js.map +0 -1
- package/dist/parser/tests/expression/Call.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Call.spec.js +0 -134
- package/dist/parser/tests/expression/Call.spec.js.map +0 -1
- package/dist/parser/tests/expression/Exponential.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Exponential.spec.js +0 -37
- package/dist/parser/tests/expression/Exponential.spec.js.map +0 -1
- package/dist/parser/tests/expression/Function.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Function.spec.js +0 -403
- package/dist/parser/tests/expression/Function.spec.js.map +0 -1
- package/dist/parser/tests/expression/Indexing.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Indexing.spec.js +0 -219
- package/dist/parser/tests/expression/Indexing.spec.js.map +0 -1
- package/dist/parser/tests/expression/Multiplicative.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Multiplicative.spec.js +0 -67
- package/dist/parser/tests/expression/Multiplicative.spec.js.map +0 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.d.ts +0 -1
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +0 -201
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +0 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.d.ts +0 -1
- package/dist/parser/tests/expression/PrefixUnary.spec.js +0 -105
- package/dist/parser/tests/expression/PrefixUnary.spec.js.map +0 -1
- package/dist/parser/tests/expression/Primary.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Primary.spec.js +0 -149
- package/dist/parser/tests/expression/Primary.spec.js.map +0 -1
- package/dist/parser/tests/expression/Relational.spec.d.ts +0 -1
- package/dist/parser/tests/expression/Relational.spec.js +0 -83
- package/dist/parser/tests/expression/Relational.spec.js.map +0 -1
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.d.ts +0 -1
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +0 -201
- package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +0 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.d.ts +0 -1
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js +0 -202
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +0 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.d.ts +0 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +0 -323
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +0 -1
- package/dist/parser/tests/statement/AssignmentOperators.spec.d.ts +0 -1
- package/dist/parser/tests/statement/AssignmentOperators.spec.js +0 -79
- package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +0 -1
- package/dist/parser/tests/statement/Declaration.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Declaration.spec.js +0 -108
- package/dist/parser/tests/statement/Declaration.spec.js.map +0 -1
- package/dist/parser/tests/statement/Dim.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Dim.spec.js +0 -73
- package/dist/parser/tests/statement/Dim.spec.js.map +0 -1
- package/dist/parser/tests/statement/Function.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Function.spec.js +0 -332
- package/dist/parser/tests/statement/Function.spec.js.map +0 -1
- package/dist/parser/tests/statement/Goto.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Goto.spec.js +0 -50
- package/dist/parser/tests/statement/Goto.spec.js.map +0 -1
- package/dist/parser/tests/statement/Increment.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Increment.spec.js +0 -117
- package/dist/parser/tests/statement/Increment.spec.js.map +0 -1
- package/dist/parser/tests/statement/LibraryStatement.spec.d.ts +0 -1
- package/dist/parser/tests/statement/LibraryStatement.spec.js +0 -74
- package/dist/parser/tests/statement/LibraryStatement.spec.js.map +0 -1
- package/dist/parser/tests/statement/Misc.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Misc.spec.js +0 -333
- package/dist/parser/tests/statement/Misc.spec.js.map +0 -1
- package/dist/parser/tests/statement/PrintStatement.spec.d.ts +0 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +0 -181
- package/dist/parser/tests/statement/PrintStatement.spec.js.map +0 -1
- package/dist/parser/tests/statement/ReturnStatement.spec.d.ts +0 -1
- package/dist/parser/tests/statement/ReturnStatement.spec.js +0 -94
- package/dist/parser/tests/statement/ReturnStatement.spec.js.map +0 -1
- package/dist/parser/tests/statement/Set.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Set.spec.js +0 -218
- package/dist/parser/tests/statement/Set.spec.js.map +0 -1
- package/dist/parser/tests/statement/Stop.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Stop.spec.js +0 -37
- package/dist/parser/tests/statement/Stop.spec.js.map +0 -1
- package/dist/parser/tests/statement/Throw.spec.d.ts +0 -1
- package/dist/parser/tests/statement/Throw.spec.js +0 -35
- package/dist/parser/tests/statement/Throw.spec.js.map +0 -1
- package/dist/parser/tests/statement/TryCatch.spec.d.ts +0 -1
- package/dist/parser/tests/statement/TryCatch.spec.js +0 -140
- package/dist/parser/tests/statement/TryCatch.spec.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/Manifest.spec.d.ts +0 -0
- package/dist/preprocessor/Manifest.spec.js +0 -105
- package/dist/preprocessor/Manifest.spec.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.d.ts +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.d.ts +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/ArrayType.spec.d.ts +0 -1
- package/dist/types/ArrayType.spec.js +0 -30
- package/dist/types/ArrayType.spec.js.map +0 -1
- package/dist/types/BooleanType.spec.d.ts +0 -1
- package/dist/types/BooleanType.spec.js +0 -12
- package/dist/types/BooleanType.spec.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/DoubleType.spec.d.ts +0 -1
- package/dist/types/DoubleType.spec.js +0 -12
- package/dist/types/DoubleType.spec.js.map +0 -1
- package/dist/types/DynamicType.spec.d.ts +0 -1
- package/dist/types/DynamicType.spec.js +0 -12
- package/dist/types/DynamicType.spec.js.map +0 -1
- package/dist/types/FloatType.spec.d.ts +0 -1
- package/dist/types/FloatType.spec.js +0 -12
- package/dist/types/FloatType.spec.js.map +0 -1
- package/dist/types/FunctionType.spec.d.ts +0 -1
- package/dist/types/FunctionType.spec.js +0 -29
- package/dist/types/FunctionType.spec.js.map +0 -1
- package/dist/types/IntegerType.spec.d.ts +0 -1
- package/dist/types/IntegerType.spec.js +0 -12
- package/dist/types/IntegerType.spec.js.map +0 -1
- package/dist/types/InvalidType.spec.d.ts +0 -1
- package/dist/types/InvalidType.spec.js +0 -12
- package/dist/types/InvalidType.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/types/LongIntegerType.spec.d.ts +0 -1
- package/dist/types/LongIntegerType.spec.js +0 -12
- package/dist/types/LongIntegerType.spec.js.map +0 -1
- package/dist/types/ObjectType.spec.d.ts +0 -1
- package/dist/types/ObjectType.spec.js +0 -12
- package/dist/types/ObjectType.spec.js.map +0 -1
- package/dist/types/StringType.spec.d.ts +0 -1
- package/dist/types/StringType.spec.js +0 -12
- package/dist/types/StringType.spec.js.map +0 -1
- package/dist/types/VoidType.spec.d.ts +0 -1
- package/dist/types/VoidType.spec.js +0 -12
- package/dist/types/VoidType.spec.js.map +0 -1
- /package/dist/{astUtils/creators.spec.d.ts → lsp/worker/run.d.ts} +0 -0
package/dist/Program.js
CHANGED
|
@@ -6,33 +6,63 @@ const fsExtra = require("fs-extra");
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const vscode_languageserver_1 = require("vscode-languageserver");
|
|
8
8
|
const Scope_1 = require("./Scope");
|
|
9
|
+
const SymbolTable_1 = require("./SymbolTable");
|
|
9
10
|
const DiagnosticMessages_1 = require("./DiagnosticMessages");
|
|
10
|
-
const
|
|
11
|
-
const XmlFile_1 = require("./files/XmlFile");
|
|
11
|
+
const CodeActionUtil_1 = require("./CodeActionUtil");
|
|
12
12
|
const util_1 = require("./util");
|
|
13
13
|
const XmlScope_1 = require("./XmlScope");
|
|
14
|
-
const DiagnosticFilterer_1 = require("./DiagnosticFilterer");
|
|
15
14
|
const DependencyGraph_1 = require("./DependencyGraph");
|
|
16
|
-
const
|
|
15
|
+
const logging_1 = require("./logging");
|
|
17
16
|
const chalk_1 = require("chalk");
|
|
18
17
|
const globalCallables_1 = require("./globalCallables");
|
|
19
18
|
const Manifest_1 = require("./preprocessor/Manifest");
|
|
20
19
|
const vscode_uri_1 = require("vscode-uri");
|
|
21
20
|
const PluginInterface_1 = require("./PluginInterface");
|
|
22
21
|
const reflection_1 = require("./astUtils/reflection");
|
|
23
|
-
const parser_1 = require("./parser");
|
|
24
|
-
const lexer_1 = require("./lexer");
|
|
25
22
|
const BscPlugin_1 = require("./bscPlugin/BscPlugin");
|
|
23
|
+
const Editor_1 = require("./astUtils/Editor");
|
|
24
|
+
const IntegerType_1 = require("./types/IntegerType");
|
|
25
|
+
const StringType_1 = require("./types/StringType");
|
|
26
|
+
const BooleanType_1 = require("./types/BooleanType");
|
|
27
|
+
const DoubleType_1 = require("./types/DoubleType");
|
|
28
|
+
const DynamicType_1 = require("./types/DynamicType");
|
|
29
|
+
const FloatType_1 = require("./types/FloatType");
|
|
30
|
+
const LongIntegerType_1 = require("./types/LongIntegerType");
|
|
31
|
+
const ObjectType_1 = require("./types/ObjectType");
|
|
32
|
+
const VoidType_1 = require("./types/VoidType");
|
|
33
|
+
const FunctionType_1 = require("./types/FunctionType");
|
|
34
|
+
const Factory_1 = require("./files/Factory");
|
|
35
|
+
const ActionPipeline_1 = require("./ActionPipeline");
|
|
36
|
+
const LazyFileData_1 = require("./files/LazyFileData");
|
|
26
37
|
const roku_deploy_1 = require("roku-deploy");
|
|
27
|
-
const
|
|
28
|
-
const
|
|
38
|
+
const roku_types_1 = require("./roku-types");
|
|
39
|
+
const ComponentType_1 = require("./types/ComponentType");
|
|
40
|
+
const InterfaceType_1 = require("./types/InterfaceType");
|
|
41
|
+
const BuiltInInterfaceAdder_1 = require("./types/BuiltInInterfaceAdder");
|
|
42
|
+
const visitors_1 = require("./astUtils/visitors");
|
|
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 ReferenceType_1 = require("./types/ReferenceType");
|
|
48
|
+
const helpers_1 = require("./types/helpers");
|
|
49
|
+
const CallExpressionInfo_1 = require("./bscPlugin/CallExpressionInfo");
|
|
50
|
+
const SignatureHelpUtil_1 = require("./bscPlugin/SignatureHelpUtil");
|
|
51
|
+
const Sequencer_1 = require("./common/Sequencer");
|
|
52
|
+
const deferred_1 = require("./deferred");
|
|
53
|
+
const roFunctionType_1 = require("./types/roFunctionType");
|
|
54
|
+
const bslibNonAliasedRokuModulesPkgPath = (0, util_1.standardizePath) `source/roku_modules/rokucommunity_bslib/bslib.brs`;
|
|
55
|
+
const bslibAliasedRokuModulesPkgPath = (0, util_1.standardizePath) `source/roku_modules/bslib/bslib.brs`;
|
|
29
56
|
class Program {
|
|
30
57
|
constructor(
|
|
31
58
|
/**
|
|
32
59
|
* The root directory for this program
|
|
33
60
|
*/
|
|
34
|
-
options, logger, plugins) {
|
|
35
|
-
|
|
61
|
+
options, logger, plugins, diagnosticsManager) {
|
|
62
|
+
/**
|
|
63
|
+
* 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`)
|
|
64
|
+
*/
|
|
65
|
+
this.editor = new Editor_1.Editor();
|
|
36
66
|
/**
|
|
37
67
|
* A graph of all files and their dependencies.
|
|
38
68
|
* For example:
|
|
@@ -40,20 +70,37 @@ class Program {
|
|
|
40
70
|
* lib2.brs -> [lib3.brs] //via an import statement
|
|
41
71
|
*/
|
|
42
72
|
this.dependencyGraph = new DependencyGraph_1.DependencyGraph();
|
|
43
|
-
this.diagnosticFilterer = new DiagnosticFilterer_1.DiagnosticFilterer();
|
|
44
73
|
/**
|
|
45
|
-
* A
|
|
46
|
-
*
|
|
74
|
+
* A scope that contains all built-in global functions.
|
|
75
|
+
* All scopes should directly or indirectly inherit from this scope
|
|
76
|
+
*/
|
|
77
|
+
this.globalScope = undefined;
|
|
78
|
+
this.fileSymbolInformation = new Map();
|
|
79
|
+
/**
|
|
80
|
+
* Map of typetime symbols which depend upon the key symbol
|
|
47
81
|
*/
|
|
48
|
-
this.
|
|
82
|
+
this.symbolDependencies = new Map();
|
|
49
83
|
/**
|
|
50
|
-
*
|
|
84
|
+
* Symbol Table for storing custom component types
|
|
85
|
+
* This is a sibling to the global table (as Components can be used/referenced anywhere)
|
|
86
|
+
* Keeping custom components out of the global table and in a specific symbol table
|
|
87
|
+
* compartmentalizes their use
|
|
51
88
|
*/
|
|
52
|
-
this.
|
|
89
|
+
this.componentsTable = new SymbolTable_1.SymbolTable('Custom Components');
|
|
53
90
|
/**
|
|
54
|
-
* A map of every file loaded into this program, indexed by its
|
|
91
|
+
* A map of every file loaded into this program, indexed by its original file location
|
|
55
92
|
*/
|
|
56
93
|
this.files = {};
|
|
94
|
+
/**
|
|
95
|
+
* A map of every file loaded into this program, indexed by its destPath
|
|
96
|
+
*/
|
|
97
|
+
this.destMap = new Map();
|
|
98
|
+
/**
|
|
99
|
+
* Plugins can contribute multiple virtual files for a single physical file.
|
|
100
|
+
* This collection links the virtual files back to the physical file that produced them.
|
|
101
|
+
* The key is the standardized and lower-cased srcPath
|
|
102
|
+
*/
|
|
103
|
+
this.fileClusters = new Map();
|
|
57
104
|
this.scopes = {};
|
|
58
105
|
/**
|
|
59
106
|
* A map of every component currently loaded into the program, indexed by the component name.
|
|
@@ -62,28 +109,184 @@ class Program {
|
|
|
62
109
|
* but if you do, only ever use the component at index 0.
|
|
63
110
|
*/
|
|
64
111
|
this.components = {};
|
|
112
|
+
/**
|
|
113
|
+
* Keeps a set of all the components that need to have their types updated during the current validation cycle
|
|
114
|
+
* Map <componentKey, componentName>
|
|
115
|
+
*/
|
|
116
|
+
this.componentSymbolsToUpdate = new Map();
|
|
117
|
+
this.crossScopeValidation = new CrossScopeValidator_1.CrossScopeValidator(this);
|
|
118
|
+
this.isFirstValidation = true;
|
|
119
|
+
this.validationDetails = {
|
|
120
|
+
brsFilesValidated: [],
|
|
121
|
+
xmlFilesValidated: [],
|
|
122
|
+
changedSymbols: new Map(),
|
|
123
|
+
changedComponentTypes: [],
|
|
124
|
+
scopesToValidate: [],
|
|
125
|
+
filesToBeValidatedInScopeContext: new Set()
|
|
126
|
+
};
|
|
127
|
+
this.lastValidationInfo = {
|
|
128
|
+
brsFilesSrcPath: new Set(),
|
|
129
|
+
xmlFilesSrcPath: new Set(),
|
|
130
|
+
scopeNames: new Set(),
|
|
131
|
+
componentsRebuilt: new Set()
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Counter used to track which validation run is being logged
|
|
135
|
+
*/
|
|
136
|
+
this.validationRunSequence = 1;
|
|
137
|
+
/**
|
|
138
|
+
* How many milliseconds can pass while doing synchronous operations in validate before we register a short timeout (i.e. yield to the event loop)
|
|
139
|
+
*/
|
|
140
|
+
this.validationMinSyncDuration = 75;
|
|
141
|
+
this.getFilePathCache = new Map();
|
|
142
|
+
this.sortedScopeNames = undefined;
|
|
143
|
+
this.getTranspiledFileContentsPipeline = new ActionPipeline_1.ActionPipeline();
|
|
144
|
+
this.buildPipeline = new ActionPipeline_1.ActionPipeline();
|
|
65
145
|
this.options = util_1.util.normalizeConfig(options);
|
|
66
|
-
this.logger = logger
|
|
67
|
-
this.plugins = plugins || new PluginInterface_1.default([], this.logger);
|
|
146
|
+
this.logger = logger !== null && logger !== void 0 ? logger : (0, logging_1.createLogger)(options);
|
|
147
|
+
this.plugins = plugins || new PluginInterface_1.default([], { logger: this.logger });
|
|
148
|
+
this.diagnostics = diagnosticsManager || new DiagnosticManager_1.DiagnosticManager();
|
|
149
|
+
//try to find a location for the diagnostic if it doesn't have one
|
|
150
|
+
this.diagnostics.locationResolver = (args) => {
|
|
151
|
+
//find the first xml scope for this diagnostic
|
|
152
|
+
for (let context of args.contexts) {
|
|
153
|
+
if ((0, reflection_1.isXmlScope)(context.scope) && (0, reflection_1.isXmlFile)(context.scope.xmlFile)) {
|
|
154
|
+
return util_1.util.createLocation(0, 0, 0, 100, context.scope.xmlFile.srcPath);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//we couldn't find an xml scope for this, so try to find the manifest file instead
|
|
158
|
+
const manifest = this.getFile('manifest', false);
|
|
159
|
+
if (manifest) {
|
|
160
|
+
return util_1.util.createLocation(0, 0, 0, 100, manifest.srcPath);
|
|
161
|
+
}
|
|
162
|
+
//if we still don't have a manifest, try to find the first file in the program
|
|
163
|
+
for (const key in this.files) {
|
|
164
|
+
if ((0, reflection_1.isBrsFile)(this.files[key]) || (0, reflection_1.isXmlFile)(this.files[key])) {
|
|
165
|
+
return util_1.util.createLocation(0, 0, 0, 100, this.files[key].srcPath);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
this.logger.warn(`Unable to find a location for the diagnostic.`, args);
|
|
169
|
+
//we couldn't find any locations for the file, so just return undefined
|
|
170
|
+
return undefined;
|
|
171
|
+
};
|
|
172
|
+
// initialize the diagnostics Manager
|
|
173
|
+
this.diagnostics.logger = this.logger;
|
|
174
|
+
this.diagnostics.options = this.options;
|
|
175
|
+
this.diagnostics.program = this;
|
|
68
176
|
//inject the bsc plugin as the first plugin in the stack.
|
|
69
177
|
this.plugins.addFirst(new BscPlugin_1.BscPlugin());
|
|
70
178
|
//normalize the root dir path
|
|
71
179
|
this.options.rootDir = util_1.util.getRootDir(this.options);
|
|
72
180
|
this.createGlobalScope();
|
|
181
|
+
this.fileFactory = new Factory_1.FileFactory(this);
|
|
73
182
|
}
|
|
74
183
|
createGlobalScope() {
|
|
75
184
|
//create the 'global' scope
|
|
76
185
|
this.globalScope = new Scope_1.Scope('global', this, 'scope:global');
|
|
77
186
|
this.globalScope.attachDependencyGraph(this.dependencyGraph);
|
|
78
187
|
this.scopes.global = this.globalScope;
|
|
188
|
+
this.populateGlobalSymbolTable();
|
|
189
|
+
this.globalScope.symbolTable.addSibling(this.componentsTable);
|
|
79
190
|
//hardcode the files list for global scope to only contain the global file
|
|
80
191
|
this.globalScope.getAllFiles = () => [globalCallables_1.globalFile];
|
|
192
|
+
globalCallables_1.globalFile.isValidated = true;
|
|
81
193
|
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
194
|
//TODO we might need to fix this because the isValidated clears stuff now
|
|
85
195
|
this.globalScope.isValidated = true;
|
|
86
196
|
}
|
|
197
|
+
recursivelyAddNodeToSymbolTable(nodeData) {
|
|
198
|
+
if (!nodeData) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
let nodeType;
|
|
202
|
+
const nodeName = util_1.util.getSgNodeTypeName(nodeData.name);
|
|
203
|
+
if (!this.globalScope.symbolTable.hasSymbol(nodeName, 2 /* SymbolTypeFlag.typetime */)) {
|
|
204
|
+
let parentNode;
|
|
205
|
+
if (nodeData.extends) {
|
|
206
|
+
const parentNodeData = roku_types_1.nodes[nodeData.extends.name.toLowerCase()];
|
|
207
|
+
try {
|
|
208
|
+
parentNode = this.recursivelyAddNodeToSymbolTable(parentNodeData);
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
this.logger.error(error, nodeData);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
nodeType = new ComponentType_1.ComponentType(nodeData.name, parentNode);
|
|
215
|
+
nodeType.addBuiltInInterfaces();
|
|
216
|
+
nodeType.isBuiltIn = true;
|
|
217
|
+
if (nodeData.name === 'Node') {
|
|
218
|
+
// Add `roSGNode` as shorthand for `roSGNodeNode`
|
|
219
|
+
this.globalScope.symbolTable.addSymbol('roSGNode', { description: nodeData.description, isBuiltIn: true }, nodeType, 2 /* SymbolTypeFlag.typetime */);
|
|
220
|
+
}
|
|
221
|
+
this.globalScope.symbolTable.addSymbol(nodeName, { description: nodeData.description, isBuiltIn: true }, nodeType, 2 /* SymbolTypeFlag.typetime */);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
nodeType = this.globalScope.symbolTable.getSymbolType(nodeName, { flags: 2 /* SymbolTypeFlag.typetime */ });
|
|
225
|
+
}
|
|
226
|
+
return nodeType;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Do all setup required for the global symbol table.
|
|
230
|
+
*/
|
|
231
|
+
populateGlobalSymbolTable() {
|
|
232
|
+
//Setup primitive types in global symbolTable
|
|
233
|
+
const builtInSymbolData = { isBuiltIn: true };
|
|
234
|
+
this.globalScope.symbolTable.addSymbol('boolean', builtInSymbolData, BooleanType_1.BooleanType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
235
|
+
this.globalScope.symbolTable.addSymbol('double', builtInSymbolData, DoubleType_1.DoubleType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
236
|
+
this.globalScope.symbolTable.addSymbol('dynamic', builtInSymbolData, DynamicType_1.DynamicType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
237
|
+
this.globalScope.symbolTable.addSymbol('float', builtInSymbolData, FloatType_1.FloatType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
238
|
+
this.globalScope.symbolTable.addSymbol('function', builtInSymbolData, FunctionType_1.FunctionType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
239
|
+
this.globalScope.symbolTable.addSymbol('integer', builtInSymbolData, IntegerType_1.IntegerType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
240
|
+
this.globalScope.symbolTable.addSymbol('longinteger', builtInSymbolData, LongIntegerType_1.LongIntegerType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
241
|
+
this.globalScope.symbolTable.addSymbol('object', builtInSymbolData, ObjectType_1.ObjectType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
242
|
+
this.globalScope.symbolTable.addSymbol('string', builtInSymbolData, StringType_1.StringType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
243
|
+
this.globalScope.symbolTable.addSymbol('void', builtInSymbolData, VoidType_1.VoidType.instance, 2 /* SymbolTypeFlag.typetime */);
|
|
244
|
+
BuiltInInterfaceAdder_1.BuiltInInterfaceAdder.getLookupTable = () => this.globalScope.symbolTable;
|
|
245
|
+
for (const callable of globalCallables_1.globalCallables) {
|
|
246
|
+
this.globalScope.symbolTable.addSymbol(callable.name, Object.assign(Object.assign({}, builtInSymbolData), { description: callable.shortDescription }), callable.type, 1 /* SymbolTypeFlag.runtime */);
|
|
247
|
+
}
|
|
248
|
+
for (const ifaceData of Object.values(roku_types_1.interfaces)) {
|
|
249
|
+
const ifaceType = new InterfaceType_1.InterfaceType(ifaceData.name);
|
|
250
|
+
ifaceType.addBuiltInInterfaces();
|
|
251
|
+
ifaceType.isBuiltIn = true;
|
|
252
|
+
this.globalScope.symbolTable.addSymbol(ifaceData.name, Object.assign(Object.assign({}, builtInSymbolData), { description: ifaceData.description }), ifaceType, 2 /* SymbolTypeFlag.typetime */);
|
|
253
|
+
}
|
|
254
|
+
for (const componentData of Object.values(roku_types_1.components)) {
|
|
255
|
+
let roComponentType;
|
|
256
|
+
const lowerComponentName = componentData.name.toLowerCase();
|
|
257
|
+
if (lowerComponentName === 'rosgnode') {
|
|
258
|
+
// we will add `roSGNode` as shorthand for `roSGNodeNode`, since all roSgNode components are SceneGraph nodes
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (lowerComponentName === 'rofunction') {
|
|
262
|
+
roComponentType = new roFunctionType_1.roFunctionType();
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
roComponentType = new InterfaceType_1.InterfaceType(componentData.name);
|
|
266
|
+
}
|
|
267
|
+
roComponentType.addBuiltInInterfaces();
|
|
268
|
+
roComponentType.isBuiltIn = true;
|
|
269
|
+
this.globalScope.symbolTable.addSymbol(componentData.name, Object.assign(Object.assign({}, builtInSymbolData), { description: componentData.description }), roComponentType, 2 /* SymbolTypeFlag.typetime */);
|
|
270
|
+
}
|
|
271
|
+
for (const nodeData of Object.values(roku_types_1.nodes)) {
|
|
272
|
+
this.recursivelyAddNodeToSymbolTable(nodeData);
|
|
273
|
+
}
|
|
274
|
+
for (const eventData of Object.values(roku_types_1.events)) {
|
|
275
|
+
const eventType = new InterfaceType_1.InterfaceType(eventData.name);
|
|
276
|
+
eventType.addBuiltInInterfaces();
|
|
277
|
+
eventType.isBuiltIn = true;
|
|
278
|
+
this.globalScope.symbolTable.addSymbol(eventData.name, Object.assign(Object.assign({}, builtInSymbolData), { description: eventData.description }), eventType, 2 /* SymbolTypeFlag.typetime */);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
addFileSymbolInfo(file) {
|
|
282
|
+
this.fileSymbolInformation.set(file.pkgPath, {
|
|
283
|
+
provides: file.providedSymbols,
|
|
284
|
+
requires: file.requiredSymbols
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
getFileSymbolInfo(file) {
|
|
288
|
+
return this.fileSymbolInformation.get(file.pkgPath);
|
|
289
|
+
}
|
|
87
290
|
/**
|
|
88
291
|
* The path to bslib.brs (the BrightScript runtime for certain BrighterScript features)
|
|
89
292
|
*/
|
|
@@ -98,7 +301,7 @@ class Program {
|
|
|
98
301
|
//default to the embedded version
|
|
99
302
|
}
|
|
100
303
|
else {
|
|
101
|
-
return
|
|
304
|
+
return `${this.options.bslibDestinationDir}${path.sep}bslib.brs`;
|
|
102
305
|
}
|
|
103
306
|
}
|
|
104
307
|
get bslibPrefix() {
|
|
@@ -110,17 +313,126 @@ class Program {
|
|
|
110
313
|
}
|
|
111
314
|
}
|
|
112
315
|
/**
|
|
113
|
-
*
|
|
316
|
+
* Look up the set of `BrsFile`s that declare any part of the given namespace name
|
|
317
|
+
* (lowercased). Returns `undefined` when no file contributes.
|
|
318
|
+
* @internal
|
|
319
|
+
*/
|
|
320
|
+
getNamespaceContributors(namespaceNameLower) {
|
|
321
|
+
if (!this.namespaceContributors) {
|
|
322
|
+
this.namespaceContributors = this.buildNamespaceContributors();
|
|
323
|
+
}
|
|
324
|
+
return this.namespaceContributors.get(namespaceNameLower);
|
|
325
|
+
}
|
|
326
|
+
buildNamespaceContributors() {
|
|
327
|
+
const contributors = new Map();
|
|
328
|
+
for (const file of Object.values(this.files)) {
|
|
329
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
330
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
331
|
+
for (const nameLower of file['getNamespaceContributions']().keys()) {
|
|
332
|
+
let set = contributors.get(nameLower);
|
|
333
|
+
if (!set) {
|
|
334
|
+
set = new Set();
|
|
335
|
+
contributors.set(nameLower, set);
|
|
336
|
+
}
|
|
337
|
+
set.add(file);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return contributors;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Get or build the shared aggregate for a namespace whose in-scope contributors
|
|
345
|
+
* include more than one file. The aggregate's heavy fields are computed once per
|
|
346
|
+
* unique `(nameLower, contributing-files-set)` and reused across every scope that
|
|
347
|
+
* sees the same set.
|
|
348
|
+
* @internal
|
|
349
|
+
*/
|
|
350
|
+
getAggregateNamespaceContainer(nameLower, contributions) {
|
|
351
|
+
if (!this.aggregateNamespaceContainerCache) {
|
|
352
|
+
this.aggregateNamespaceContainerCache = new Map();
|
|
353
|
+
}
|
|
354
|
+
//sorted pkgPaths ensure two scopes with the same contributor set hit the same key
|
|
355
|
+
const key = nameLower + '|' + contributions
|
|
356
|
+
.map(c => c.file.pkgPath.toLowerCase())
|
|
357
|
+
.sort()
|
|
358
|
+
.join('|');
|
|
359
|
+
let aggregate = this.aggregateNamespaceContainerCache.get(key);
|
|
360
|
+
if (!aggregate) {
|
|
361
|
+
aggregate = this.buildAggregateNamespaceContainer(contributions);
|
|
362
|
+
this.aggregateNamespaceContainerCache.set(key, aggregate);
|
|
363
|
+
}
|
|
364
|
+
return aggregate;
|
|
365
|
+
}
|
|
366
|
+
buildAggregateNamespaceContainer(contributions) {
|
|
367
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
368
|
+
const first = contributions[0];
|
|
369
|
+
//field order matches the NamespaceContainer interface declaration so aggregates
|
|
370
|
+
//share a single V8 hidden class with the per-scope wrapper containers
|
|
371
|
+
const aggregate = {
|
|
372
|
+
file: first.file,
|
|
373
|
+
fullName: first.fullName,
|
|
374
|
+
nameRange: first.nameRange,
|
|
375
|
+
lastPartName: first.lastPartName,
|
|
376
|
+
namespaces: new Map(),
|
|
377
|
+
namespaceStatements: undefined,
|
|
378
|
+
statements: undefined,
|
|
379
|
+
classStatements: undefined,
|
|
380
|
+
functionStatements: undefined,
|
|
381
|
+
enumStatements: undefined,
|
|
382
|
+
constStatements: undefined,
|
|
383
|
+
symbolTable: undefined
|
|
384
|
+
};
|
|
385
|
+
for (const contribution of contributions) {
|
|
386
|
+
if ((_a = contribution.namespaceStatements) === null || _a === void 0 ? void 0 : _a.length) {
|
|
387
|
+
((_b = aggregate.namespaceStatements) !== null && _b !== void 0 ? _b : (aggregate.namespaceStatements = [])).push(...contribution.namespaceStatements);
|
|
388
|
+
}
|
|
389
|
+
if ((_c = contribution.statements) === null || _c === void 0 ? void 0 : _c.length) {
|
|
390
|
+
((_d = aggregate.statements) !== null && _d !== void 0 ? _d : (aggregate.statements = [])).push(...contribution.statements);
|
|
391
|
+
}
|
|
392
|
+
if (contribution.classStatements) {
|
|
393
|
+
aggregate.classStatements = Object.assign(Object.assign({}, ((_e = aggregate.classStatements) !== null && _e !== void 0 ? _e : {})), contribution.classStatements);
|
|
394
|
+
}
|
|
395
|
+
if (contribution.functionStatements) {
|
|
396
|
+
aggregate.functionStatements = Object.assign(Object.assign({}, ((_f = aggregate.functionStatements) !== null && _f !== void 0 ? _f : {})), contribution.functionStatements);
|
|
397
|
+
}
|
|
398
|
+
if (contribution.enumStatements) {
|
|
399
|
+
(_g = aggregate.enumStatements) !== null && _g !== void 0 ? _g : (aggregate.enumStatements = new Map());
|
|
400
|
+
for (const [key, value] of contribution.enumStatements) {
|
|
401
|
+
aggregate.enumStatements.set(key, value);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (contribution.constStatements) {
|
|
405
|
+
(_h = aggregate.constStatements) !== null && _h !== void 0 ? _h : (aggregate.constStatements = new Map());
|
|
406
|
+
for (const [key, value] of contribution.constStatements) {
|
|
407
|
+
aggregate.constStatements.set(key, value);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (contribution.symbolTable) {
|
|
411
|
+
(_j = aggregate.symbolTable) !== null && _j !== void 0 ? _j : (aggregate.symbolTable = new SymbolTable_1.SymbolTable(`Namespace Multi-File Aggregate: '${first.fullName}'`));
|
|
412
|
+
aggregate.symbolTable.mergeSymbolTable(contribution.symbolTable);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return aggregate;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Invalidate the program-level namespace contributors map and the slow-path aggregate
|
|
419
|
+
* cache. Called by `setFile` and `removeFile`; downstream scope namespace lookups
|
|
420
|
+
* already rebuild via the dependency-graph invalidation chain, so this only needs
|
|
421
|
+
* to drop the cached maps.
|
|
114
422
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
423
|
+
invalidateNamespaceContributorCache() {
|
|
424
|
+
this.namespaceContributors = undefined;
|
|
425
|
+
this.aggregateNamespaceContainerCache = undefined;
|
|
117
426
|
}
|
|
118
427
|
addScope(scope) {
|
|
119
428
|
this.scopes[scope.name] = scope;
|
|
120
|
-
this.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
429
|
+
delete this.sortedScopeNames;
|
|
430
|
+
}
|
|
431
|
+
removeScope(scope) {
|
|
432
|
+
if (this.scopes[scope.name]) {
|
|
433
|
+
delete this.scopes[scope.name];
|
|
434
|
+
delete this.sortedScopeNames;
|
|
435
|
+
}
|
|
124
436
|
}
|
|
125
437
|
/**
|
|
126
438
|
* Get the component with the specified name
|
|
@@ -129,19 +441,34 @@ class Program {
|
|
|
129
441
|
var _a;
|
|
130
442
|
if (componentName) {
|
|
131
443
|
//return the first compoment in the list with this name
|
|
132
|
-
//(components are ordered in this list by
|
|
444
|
+
//(components are ordered in this list by destPath to ensure consistency)
|
|
133
445
|
return (_a = this.components[componentName.toLowerCase()]) === null || _a === void 0 ? void 0 : _a[0];
|
|
134
446
|
}
|
|
135
447
|
else {
|
|
136
448
|
return undefined;
|
|
137
449
|
}
|
|
138
450
|
}
|
|
451
|
+
/**
|
|
452
|
+
* Get the sorted names of custom components
|
|
453
|
+
*/
|
|
454
|
+
getSortedComponentNames() {
|
|
455
|
+
const componentNames = Object.keys(this.components);
|
|
456
|
+
componentNames.sort((a, b) => {
|
|
457
|
+
if (a < b) {
|
|
458
|
+
return -1;
|
|
459
|
+
}
|
|
460
|
+
else if (b < a) {
|
|
461
|
+
return 1;
|
|
462
|
+
}
|
|
463
|
+
return 0;
|
|
464
|
+
});
|
|
465
|
+
return componentNames;
|
|
466
|
+
}
|
|
139
467
|
/**
|
|
140
468
|
* Register (or replace) the reference to a component in the component map
|
|
141
469
|
*/
|
|
142
470
|
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();
|
|
471
|
+
const key = this.getComponentKey(xmlFile);
|
|
145
472
|
if (!this.components[key]) {
|
|
146
473
|
this.components[key] = [];
|
|
147
474
|
}
|
|
@@ -149,15 +476,25 @@ class Program {
|
|
|
149
476
|
file: xmlFile,
|
|
150
477
|
scope: scope
|
|
151
478
|
});
|
|
152
|
-
this.components[key].sort((
|
|
479
|
+
this.components[key].sort((a, b) => {
|
|
480
|
+
const pathA = a.file.destPath.toLowerCase();
|
|
481
|
+
const pathB = b.file.destPath.toLowerCase();
|
|
482
|
+
if (pathA < pathB) {
|
|
483
|
+
return -1;
|
|
484
|
+
}
|
|
485
|
+
else if (pathA > pathB) {
|
|
486
|
+
return 1;
|
|
487
|
+
}
|
|
488
|
+
return 0;
|
|
489
|
+
});
|
|
153
490
|
this.syncComponentDependencyGraph(this.components[key]);
|
|
491
|
+
this.addDeferredComponentTypeSymbolCreation(xmlFile);
|
|
154
492
|
}
|
|
155
493
|
/**
|
|
156
494
|
* Remove the specified component from the components map
|
|
157
495
|
*/
|
|
158
496
|
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();
|
|
497
|
+
const key = this.getComponentKey(xmlFile);
|
|
161
498
|
const arr = this.components[key] || [];
|
|
162
499
|
for (let i = 0; i < arr.length; i++) {
|
|
163
500
|
if (arr[i].file === xmlFile) {
|
|
@@ -166,6 +503,84 @@ class Program {
|
|
|
166
503
|
}
|
|
167
504
|
}
|
|
168
505
|
this.syncComponentDependencyGraph(arr);
|
|
506
|
+
this.addDeferredComponentTypeSymbolCreation(xmlFile);
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Adds a component described in an XML to the set of components that needs to be updated this validation cycle.
|
|
510
|
+
* @param xmlFile XML file with <component> tag
|
|
511
|
+
*/
|
|
512
|
+
addDeferredComponentTypeSymbolCreation(xmlFile) {
|
|
513
|
+
var _a;
|
|
514
|
+
const componentKey = this.getComponentKey(xmlFile);
|
|
515
|
+
const componentName = (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text;
|
|
516
|
+
if (this.componentSymbolsToUpdate.has(componentKey)) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
this.componentSymbolsToUpdate.set(componentKey, componentName);
|
|
520
|
+
}
|
|
521
|
+
getComponentKey(xmlFile) {
|
|
522
|
+
var _a, _b;
|
|
523
|
+
return ((_b = (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : xmlFile.pkgPath).toLowerCase();
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Resolves symbol table with the first component in this.components to have the same name as the component in the file
|
|
527
|
+
* @param componentKey key getting a component from `this.components`
|
|
528
|
+
* @param componentName the unprefixed name of the component that will be added (e.g. 'MyLabel' NOT 'roSgNodeMyLabel')
|
|
529
|
+
*/
|
|
530
|
+
updateComponentSymbolInGlobalScope(componentKey, componentName) {
|
|
531
|
+
const symbolName = componentName ? util_1.util.getSgNodeTypeName(componentName) : undefined;
|
|
532
|
+
if (!symbolName) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const components = this.components[componentKey] || [];
|
|
536
|
+
const previousComponentType = this.componentsTable.getSymbolType(symbolName, { flags: 2 /* SymbolTypeFlag.typetime */ });
|
|
537
|
+
// Remove any existing symbols that match
|
|
538
|
+
this.componentsTable.removeSymbol(symbolName);
|
|
539
|
+
if (components.length > 0) {
|
|
540
|
+
// There is a component that can be added - use it.
|
|
541
|
+
const componentScope = components[0].scope;
|
|
542
|
+
this.componentsTable.removeSymbol(symbolName);
|
|
543
|
+
componentScope.linkSymbolTable();
|
|
544
|
+
const componentType = componentScope.getComponentType();
|
|
545
|
+
if (componentType) {
|
|
546
|
+
this.componentsTable.addSymbol(symbolName, {}, componentType, 2 /* SymbolTypeFlag.typetime */);
|
|
547
|
+
}
|
|
548
|
+
const typeData = {};
|
|
549
|
+
const isSameAsPrevious = previousComponentType && componentType.isEqual(previousComponentType, typeData);
|
|
550
|
+
const isComponentTypeDifferent = !previousComponentType || (0, reflection_1.isReferenceType)(previousComponentType) || !isSameAsPrevious;
|
|
551
|
+
componentScope.unlinkSymbolTable();
|
|
552
|
+
return isComponentTypeDifferent;
|
|
553
|
+
}
|
|
554
|
+
// There was a previous component type, but no new one, so it's different
|
|
555
|
+
return !!previousComponentType;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Adds a reference type to the global symbol table with the first component in this.components to have the same name as the component in the file
|
|
559
|
+
* This is so on a first validation, these types can be resolved in teh future (eg. when the actual component is created)
|
|
560
|
+
* If we don't add reference types at this top level, they will be created at the file level, and will never get resolved
|
|
561
|
+
* @param componentKey key getting a component from `this.components`
|
|
562
|
+
* @param componentName the unprefixed name of the component that will be added (e.g. 'MyLabel' NOT 'roSgNodeMyLabel')
|
|
563
|
+
*/
|
|
564
|
+
addComponentReferenceType(componentKey, componentName) {
|
|
565
|
+
const symbolName = componentName ? util_1.util.getSgNodeTypeName(componentName) : undefined;
|
|
566
|
+
if (!symbolName) {
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
const components = this.components[componentKey] || [];
|
|
570
|
+
if (components.length > 0) {
|
|
571
|
+
// There is a component that can be added,
|
|
572
|
+
if (!this.componentsTable.hasSymbol(symbolName, 2 /* SymbolTypeFlag.typetime */)) {
|
|
573
|
+
// it doesn't already exist in the table
|
|
574
|
+
const componentRefType = new ReferenceType_1.ReferenceType(symbolName, symbolName, 2 /* SymbolTypeFlag.typetime */, () => this.componentsTable);
|
|
575
|
+
if (componentRefType) {
|
|
576
|
+
this.componentsTable.addSymbol(symbolName, {}, componentRefType, 2 /* SymbolTypeFlag.typetime */);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
// there is no component. remove from table
|
|
582
|
+
this.componentsTable.removeSymbol(symbolName);
|
|
583
|
+
}
|
|
169
584
|
}
|
|
170
585
|
/**
|
|
171
586
|
* re-attach the dependency graph with a new key for any component who changed
|
|
@@ -179,6 +594,7 @@ class Program {
|
|
|
179
594
|
//attach (or re-attach) the dependencyGraph for every component whose position changed
|
|
180
595
|
if (file.dependencyGraphIndex !== i) {
|
|
181
596
|
file.dependencyGraphIndex = i;
|
|
597
|
+
this.dependencyGraph.addOrReplace(file.dependencyGraphKey, file.dependencies);
|
|
182
598
|
file.attachDependencyGraph(this.dependencyGraph);
|
|
183
599
|
scope.attachDependencyGraph(this.dependencyGraph);
|
|
184
600
|
}
|
|
@@ -190,9 +606,10 @@ class Program {
|
|
|
190
606
|
*/
|
|
191
607
|
getUnreferencedFiles() {
|
|
192
608
|
let result = [];
|
|
193
|
-
for (let
|
|
194
|
-
|
|
195
|
-
|
|
609
|
+
for (let filePath in this.files) {
|
|
610
|
+
let file = this.files[filePath];
|
|
611
|
+
//is this file part of a scope
|
|
612
|
+
if (!this.getFirstScopeForFile(file)) {
|
|
196
613
|
//no scopes reference this file. add it to the list
|
|
197
614
|
result.push(file);
|
|
198
615
|
}
|
|
@@ -200,37 +617,14 @@ class Program {
|
|
|
200
617
|
return result;
|
|
201
618
|
}
|
|
202
619
|
/**
|
|
203
|
-
* Get the list of errors for the entire program.
|
|
204
|
-
* by walking through every file, so call this sparingly.
|
|
620
|
+
* Get the list of errors for the entire program.
|
|
205
621
|
*/
|
|
206
622
|
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);
|
|
623
|
+
return this.diagnostics.getDiagnostics();
|
|
230
624
|
}
|
|
231
625
|
/**
|
|
232
626
|
* Determine if the specified file is loaded in this program right now.
|
|
233
|
-
* @param filePath
|
|
627
|
+
* @param filePath the absolute or relative path to the file
|
|
234
628
|
* @param normalizePath should the provided path be normalized before use
|
|
235
629
|
*/
|
|
236
630
|
hasFile(filePath, normalizePath = true) {
|
|
@@ -238,12 +632,15 @@ class Program {
|
|
|
238
632
|
}
|
|
239
633
|
/**
|
|
240
634
|
* roku filesystem is case INsensitive, so find the scope by key case insensitive
|
|
241
|
-
* @param scopeName
|
|
635
|
+
* @param scopeName xml scope names are their `destPath`. Source scope is stored with the key `"source"`
|
|
242
636
|
*/
|
|
243
637
|
getScopeByName(scopeName) {
|
|
244
638
|
if (!scopeName) {
|
|
245
639
|
return undefined;
|
|
246
640
|
}
|
|
641
|
+
//most scopes are xml file pkg paths. however, the ones that are not are single names like "global" and "scope",
|
|
642
|
+
//so it's safe to run the standardizePkgPath method
|
|
643
|
+
scopeName = (0, util_1.standardizePath) `${scopeName}`;
|
|
247
644
|
let key = Object.keys(this.scopes).find(x => x.toLowerCase() === scopeName.toLowerCase());
|
|
248
645
|
return this.scopes[key];
|
|
249
646
|
}
|
|
@@ -264,113 +661,181 @@ class Program {
|
|
|
264
661
|
* Update internal maps with this file reference
|
|
265
662
|
*/
|
|
266
663
|
assignFile(file) {
|
|
664
|
+
const fileAddEvent = {
|
|
665
|
+
file: file,
|
|
666
|
+
program: this
|
|
667
|
+
};
|
|
668
|
+
this.plugins.emit('beforeAddFile', fileAddEvent);
|
|
267
669
|
this.files[file.srcPath.toLowerCase()] = file;
|
|
268
|
-
this.
|
|
670
|
+
this.destMap.set(file.destPath.toLowerCase(), file);
|
|
671
|
+
this.plugins.emit('afterAddFile', fileAddEvent);
|
|
672
|
+
return file;
|
|
269
673
|
}
|
|
270
674
|
/**
|
|
271
675
|
* Remove this file from internal maps
|
|
272
676
|
*/
|
|
273
677
|
unassignFile(file) {
|
|
274
678
|
delete this.files[file.srcPath.toLowerCase()];
|
|
275
|
-
|
|
679
|
+
this.destMap.delete(file.destPath.toLowerCase());
|
|
680
|
+
return file;
|
|
276
681
|
}
|
|
277
|
-
setFile(fileParam,
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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)
|
|
288
|
-
}
|
|
289
|
-
else if (path.isAbsolute(fileParam)) {
|
|
290
|
-
srcPath = util_1.util.standardizePath(fileParam);
|
|
291
|
-
//assume the file path is a sub path of rootDir
|
|
292
|
-
pkgPath = util_1.util.sanitizePkgPath(roku_deploy_1.util.stringReplaceInsensitive(srcPath, this.options.rootDir, ''));
|
|
293
|
-
//is destPath (path relative to rootDir and `pkg:/`)
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
srcPath = util_1.standardizePath `${this.options.rootDir}/${fileParam}`;
|
|
297
|
-
pkgPath = util_1.util.sanitizePkgPath(fileParam);
|
|
298
|
-
}
|
|
299
|
-
//is a FileObj
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
srcPath = util_1.standardizePath `${fileParam.src}`;
|
|
303
|
-
pkgPath = util_1.util.sanitizePkgPath(fileParam.dest);
|
|
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');
|
|
682
|
+
setFile(fileParam, fileData) {
|
|
683
|
+
//normalize the file paths
|
|
684
|
+
const { srcPath, destPath } = this.getPaths(fileParam, this.options.rootDir);
|
|
685
|
+
//namespace contributions for the new/replaced file may differ; force the
|
|
686
|
+
//program-level contributors map to rebuild on next query
|
|
687
|
+
this.invalidateNamespaceContributorCache();
|
|
688
|
+
let file = this.logger.time(logging_1.LogLevel.debug, ['Program.setFile()', chalk_1.default.green(srcPath)], () => {
|
|
689
|
+
var _a, _b, _c;
|
|
309
690
|
//if the file is already loaded, remove it
|
|
310
691
|
if (this.hasFile(srcPath)) {
|
|
311
|
-
this.removeFile(srcPath);
|
|
692
|
+
this.removeFile(srcPath, true, true);
|
|
312
693
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
694
|
+
const data = new LazyFileData_1.LazyFileData(fileData);
|
|
695
|
+
const event = new ProvideFileEventInternal(this, srcPath, destPath, data, this.fileFactory);
|
|
696
|
+
this.plugins.emit('beforeProvideFile', event);
|
|
697
|
+
this.plugins.emit('provideFile', event);
|
|
698
|
+
this.plugins.emit('afterProvideFile', event);
|
|
699
|
+
//if no files were provided, create a AssetFile to represent it.
|
|
700
|
+
if (event.files.length === 0) {
|
|
701
|
+
event.files.push(this.fileFactory.AssetFile({
|
|
702
|
+
srcPath: event.srcPath,
|
|
703
|
+
destPath: event.destPath,
|
|
704
|
+
pkgPath: event.destPath,
|
|
705
|
+
data: data
|
|
706
|
+
}));
|
|
707
|
+
}
|
|
708
|
+
//find the file instance for the srcPath that triggered this action.
|
|
709
|
+
const primaryFile = event.files.find(x => x.srcPath === srcPath);
|
|
710
|
+
if (!primaryFile) {
|
|
711
|
+
throw new Error(`No file provided for srcPath '${srcPath}'. Instead, received ${JSON.stringify(event.files.map(x => ({
|
|
712
|
+
type: x.type,
|
|
713
|
+
srcPath: x.srcPath,
|
|
714
|
+
destPath: x.destPath
|
|
715
|
+
})))}`);
|
|
716
|
+
}
|
|
717
|
+
//link the virtual files to the primary file
|
|
718
|
+
this.fileClusters.set((_a = primaryFile.srcPath) === null || _a === void 0 ? void 0 : _a.toLowerCase(), event.files);
|
|
719
|
+
for (const file of event.files) {
|
|
720
|
+
file.srcPath = (0, util_1.standardizePath)(file.srcPath);
|
|
721
|
+
if (file.destPath) {
|
|
722
|
+
file.destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(file.destPath, this.options.rootDir, '')}`;
|
|
723
|
+
}
|
|
724
|
+
if (file.pkgPath) {
|
|
725
|
+
file.pkgPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(file.pkgPath, this.options.rootDir, '')}`;
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
file.pkgPath = file.destPath;
|
|
729
|
+
}
|
|
730
|
+
file.excludeFromOutput = file.excludeFromOutput === true;
|
|
731
|
+
//set the dependencyGraph key for every file to its destPath
|
|
732
|
+
file.dependencyGraphKey = file.destPath.toLowerCase();
|
|
733
|
+
this.assignFile(file);
|
|
734
|
+
//register a callback anytime this file's dependencies change
|
|
735
|
+
if (typeof file.onDependenciesChanged === 'function') {
|
|
736
|
+
(_b = file.disposables) !== null && _b !== void 0 ? _b : (file.disposables = []);
|
|
737
|
+
file.disposables.push(this.dependencyGraph.onchange(file.dependencyGraphKey, file.onDependenciesChanged.bind(file)));
|
|
738
|
+
}
|
|
739
|
+
//register this file (and its dependencies) with the dependency graph
|
|
740
|
+
this.dependencyGraph.addOrReplace(file.dependencyGraphKey, (_c = file.dependencies) !== null && _c !== void 0 ? _c : []);
|
|
741
|
+
//if this is a `source` file, add it to the source scope's dependency list
|
|
742
|
+
if (this.isSourceBrsFile(file)) {
|
|
324
743
|
this.createSourceScope();
|
|
325
|
-
this.dependencyGraph.addDependency('scope:source',
|
|
744
|
+
this.dependencyGraph.addDependency('scope:source', file.dependencyGraphKey);
|
|
745
|
+
}
|
|
746
|
+
//if this is an xml file in the components folder, register it as a component
|
|
747
|
+
if (this.isComponentsXmlFile(file)) {
|
|
748
|
+
this.plugins.emit('beforeProvideScope', {
|
|
749
|
+
program: this,
|
|
750
|
+
scope: undefined
|
|
751
|
+
});
|
|
752
|
+
//create a new scope for this xml file
|
|
753
|
+
let scope = new XmlScope_1.XmlScope(file, this);
|
|
754
|
+
this.addScope(scope);
|
|
755
|
+
//register this componet now that we have parsed it and know its component name
|
|
756
|
+
this.registerComponent(file, scope);
|
|
757
|
+
this.plugins.emit('provideScope', {
|
|
758
|
+
program: this,
|
|
759
|
+
scope: scope
|
|
760
|
+
});
|
|
761
|
+
//notify plugins that the scope is created and the component is registered
|
|
762
|
+
this.plugins.emit('afterProvideScope', {
|
|
763
|
+
program: this,
|
|
764
|
+
scope: scope
|
|
765
|
+
});
|
|
326
766
|
}
|
|
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
|
-
});
|
|
339
|
-
}
|
|
340
|
-
else if (
|
|
341
|
-
//is xml file
|
|
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
|
-
});
|
|
362
767
|
}
|
|
363
|
-
|
|
364
|
-
//TODO do we actually need to implement this? Figure out how to handle img paths
|
|
365
|
-
// let genericFile = this.files[srcPath] = <any>{
|
|
366
|
-
// srcPath: srcPath,
|
|
367
|
-
// pkgPath: pkgPath,
|
|
368
|
-
// wasProcessed: true
|
|
369
|
-
// } as File;
|
|
370
|
-
// file = <any>genericFile;
|
|
371
|
-
}
|
|
372
|
-
return file;
|
|
768
|
+
return primaryFile;
|
|
373
769
|
});
|
|
770
|
+
return file;
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Given a srcPath, a destPath, or both, resolve whichever is missing, relative to rootDir.
|
|
774
|
+
* @param fileParam an object representing file paths
|
|
775
|
+
* @param rootDir must be a pre-normalized path
|
|
776
|
+
*/
|
|
777
|
+
getPaths(fileParam, rootDir) {
|
|
778
|
+
let srcPath;
|
|
779
|
+
let destPath;
|
|
780
|
+
assert.ok(fileParam, 'fileParam is required');
|
|
781
|
+
//lift the path vars from the incoming param
|
|
782
|
+
if (typeof fileParam === 'string') {
|
|
783
|
+
fileParam = this.removePkgPrefix(fileParam);
|
|
784
|
+
srcPath = (0, util_1.standardizePath) `${path.resolve(rootDir, fileParam)}`;
|
|
785
|
+
destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
|
|
786
|
+
}
|
|
787
|
+
else {
|
|
788
|
+
let param = fileParam;
|
|
789
|
+
if (param.src) {
|
|
790
|
+
srcPath = (0, util_1.standardizePath) `${param.src}`;
|
|
791
|
+
}
|
|
792
|
+
if (param.srcPath) {
|
|
793
|
+
srcPath = (0, util_1.standardizePath) `${param.srcPath}`;
|
|
794
|
+
}
|
|
795
|
+
if (param.dest) {
|
|
796
|
+
destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.dest)}`;
|
|
797
|
+
}
|
|
798
|
+
if (param.pkgPath) {
|
|
799
|
+
destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.pkgPath)}`;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
//if there's no srcPath, use the destPath to build an absolute srcPath
|
|
803
|
+
if (!srcPath) {
|
|
804
|
+
srcPath = (0, util_1.standardizePath) `${rootDir}/${destPath}`;
|
|
805
|
+
}
|
|
806
|
+
//coerce srcPath to an absolute path
|
|
807
|
+
if (!path.isAbsolute(srcPath)) {
|
|
808
|
+
srcPath = util_1.util.standardizePath(srcPath);
|
|
809
|
+
}
|
|
810
|
+
//if destPath isn't set, compute it from the other paths
|
|
811
|
+
if (!destPath) {
|
|
812
|
+
destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
|
|
813
|
+
}
|
|
814
|
+
assert.ok(srcPath, 'fileEntry.src is required');
|
|
815
|
+
assert.ok(destPath, 'fileEntry.dest is required');
|
|
816
|
+
return {
|
|
817
|
+
srcPath: srcPath,
|
|
818
|
+
//remove leading slash
|
|
819
|
+
destPath: destPath.replace(/^[\/\\]+/, '')
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Remove any leading `pkg:/` found in the path
|
|
824
|
+
*/
|
|
825
|
+
removePkgPrefix(path) {
|
|
826
|
+
return path.replace(/^pkg:\//i, '');
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Is this file a .brs file found somewhere within the `pkg:/source/` folder?
|
|
830
|
+
*/
|
|
831
|
+
isSourceBrsFile(file) {
|
|
832
|
+
return !!/^(pkg:\/)?source[\/\\]/.exec(file.destPath);
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Is this file a .brs file found somewhere within the `pkg:/source/` folder?
|
|
836
|
+
*/
|
|
837
|
+
isComponentsXmlFile(file) {
|
|
838
|
+
return (0, reflection_1.isXmlFile)(file) && !!/^(pkg:\/)?components[\/\\]/.exec(file.destPath);
|
|
374
839
|
}
|
|
375
840
|
/**
|
|
376
841
|
* Ensure source scope is created.
|
|
@@ -381,238 +846,580 @@ class Program {
|
|
|
381
846
|
const sourceScope = new Scope_1.Scope('source', this, 'scope:source');
|
|
382
847
|
sourceScope.attachDependencyGraph(this.dependencyGraph);
|
|
383
848
|
this.addScope(sourceScope);
|
|
849
|
+
this.plugins.emit('afterProvideScope', {
|
|
850
|
+
program: this,
|
|
851
|
+
scope: sourceScope
|
|
852
|
+
});
|
|
384
853
|
}
|
|
385
854
|
}
|
|
386
855
|
/**
|
|
387
856
|
* Remove a set of files from the program
|
|
388
|
-
* @param srcPaths
|
|
857
|
+
* @param srcPaths can be an array of srcPath or destPath strings
|
|
858
|
+
* @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
859
|
*/
|
|
390
|
-
removeFiles(srcPaths) {
|
|
860
|
+
removeFiles(srcPaths, normalizePath = true) {
|
|
391
861
|
for (let srcPath of srcPaths) {
|
|
392
|
-
this.removeFile(srcPath);
|
|
862
|
+
this.removeFile(srcPath, normalizePath);
|
|
393
863
|
}
|
|
394
864
|
}
|
|
395
865
|
/**
|
|
396
866
|
* Remove a file from the program
|
|
397
|
-
* @param filePath can be a srcPath, a
|
|
867
|
+
* @param filePath can be a srcPath, a destPath, or a destPath with leading `pkg:/`
|
|
398
868
|
* @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
869
|
*/
|
|
401
|
-
removeFile(filePath, normalizePath = true) {
|
|
870
|
+
removeFile(filePath, normalizePath = true, keepSymbolInformation = false) {
|
|
871
|
+
var _a, _b, _c, _d;
|
|
402
872
|
this.logger.debug('Program.removeFile()', filePath);
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
873
|
+
const paths = this.getPaths(filePath, this.options.rootDir);
|
|
874
|
+
//namespace contributions may have included this file; force the program-level
|
|
875
|
+
//contributors map to rebuild on next query
|
|
876
|
+
this.invalidateNamespaceContributorCache();
|
|
877
|
+
//there can be one or more File entries for a single srcPath, so get all of them and remove them all
|
|
878
|
+
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)];
|
|
879
|
+
for (const file of files) {
|
|
880
|
+
//if a file has already been removed, nothing more needs to be done here
|
|
881
|
+
if (!file || !this.hasFile(file.srcPath)) {
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
this.diagnostics.clearForFile(file.srcPath);
|
|
885
|
+
const event = { file: file, program: this };
|
|
886
|
+
this.plugins.emit('beforeRemoveFile', event);
|
|
409
887
|
//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.
|
|
888
|
+
let scope = this.scopes[file.destPath];
|
|
411
889
|
if (scope) {
|
|
412
|
-
this.
|
|
890
|
+
this.logger.debug('Removing associated scope', scope.name);
|
|
891
|
+
const scopeRemoveEvent = {
|
|
413
892
|
program: this,
|
|
414
893
|
scope: scope
|
|
415
|
-
}
|
|
894
|
+
};
|
|
895
|
+
this.plugins.emit('beforeRemoveScope', scopeRemoveEvent);
|
|
896
|
+
this.plugins.emit('removeScope', scopeRemoveEvent);
|
|
416
897
|
scope.dispose();
|
|
417
898
|
//notify dependencies of this scope that it has been removed
|
|
418
899
|
this.dependencyGraph.remove(scope.dependencyGraphKey);
|
|
419
|
-
|
|
420
|
-
this.plugins.emit('
|
|
421
|
-
program: this,
|
|
422
|
-
scope: scope
|
|
423
|
-
});
|
|
900
|
+
this.removeScope(this.scopes[file.destPath]);
|
|
901
|
+
this.plugins.emit('afterRemoveScope', scopeRemoveEvent);
|
|
424
902
|
}
|
|
425
903
|
//remove the file from the program
|
|
426
904
|
this.unassignFile(file);
|
|
427
905
|
this.dependencyGraph.remove(file.dependencyGraphKey);
|
|
428
906
|
//if this is a pkg:/source file, notify the `source` scope that it has changed
|
|
429
|
-
if (
|
|
907
|
+
if (this.isSourceBrsFile(file)) {
|
|
430
908
|
this.dependencyGraph.removeDependency('scope:source', file.dependencyGraphKey);
|
|
431
909
|
}
|
|
910
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
911
|
+
this.logger.debug('Removing file symbol info', file.srcPath);
|
|
912
|
+
if (!keepSymbolInformation) {
|
|
913
|
+
this.fileSymbolInformation.delete(file.pkgPath);
|
|
914
|
+
}
|
|
915
|
+
this.crossScopeValidation.clearResolutionsForFile(file);
|
|
916
|
+
}
|
|
917
|
+
this.diagnostics.clearForFile(file.srcPath);
|
|
432
918
|
//if this is a component, remove it from our components map
|
|
433
|
-
if (reflection_1.isXmlFile(file)) {
|
|
919
|
+
if ((0, reflection_1.isXmlFile)(file)) {
|
|
920
|
+
this.logger.debug('Unregistering component', file.srcPath);
|
|
434
921
|
this.unregisterComponent(file);
|
|
435
922
|
}
|
|
436
|
-
this.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
923
|
+
this.logger.debug('Disposing file', file.srcPath);
|
|
924
|
+
//dispose any disposable things on the file
|
|
925
|
+
for (const disposable of (_c = file === null || file === void 0 ? void 0 : file.disposables) !== null && _c !== void 0 ? _c : []) {
|
|
926
|
+
disposable();
|
|
927
|
+
}
|
|
928
|
+
//dispose file
|
|
929
|
+
(_d = file === null || file === void 0 ? void 0 : file.dispose) === null || _d === void 0 ? void 0 : _d.call(file);
|
|
930
|
+
this.plugins.emit('afterRemoveFile', event);
|
|
440
931
|
}
|
|
441
932
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
933
|
+
validate(options) {
|
|
934
|
+
var _a;
|
|
935
|
+
const validationRunId = this.validationRunSequence++;
|
|
936
|
+
let previousValidationPromise = this.validatePromise;
|
|
937
|
+
const deferred = new deferred_1.Deferred();
|
|
938
|
+
if (options === null || options === void 0 ? void 0 : options.async) {
|
|
939
|
+
//we're async, so create a new promise chain to resolve after this validation is done
|
|
940
|
+
this.validatePromise = Promise.resolve(previousValidationPromise).then(() => {
|
|
941
|
+
return deferred.promise;
|
|
942
|
+
});
|
|
943
|
+
//we are not async but there's a pending promise, then we cannot run this validation
|
|
450
944
|
}
|
|
451
|
-
|
|
452
|
-
|
|
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);
|
|
458
|
-
}
|
|
945
|
+
else if (previousValidationPromise !== undefined) {
|
|
946
|
+
throw new Error('Cannot run synchronous validation while an async validation is in progress');
|
|
459
947
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
this.
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
948
|
+
let beforeValidateProgramWasEmitted = false;
|
|
949
|
+
const brsFilesValidated = this.validationDetails.brsFilesValidated;
|
|
950
|
+
const xmlFilesValidated = this.validationDetails.xmlFilesValidated;
|
|
951
|
+
const changedSymbols = this.validationDetails.changedSymbols;
|
|
952
|
+
const changedComponentTypes = this.validationDetails.changedComponentTypes;
|
|
953
|
+
const scopesToValidate = this.validationDetails.scopesToValidate;
|
|
954
|
+
const filesToBeValidatedInScopeContext = this.validationDetails.filesToBeValidatedInScopeContext;
|
|
955
|
+
//validate every file
|
|
956
|
+
let logValidateEnd = (status) => { };
|
|
957
|
+
//will be populated later on during the correspnding sequencer event
|
|
958
|
+
let filesToProcess;
|
|
959
|
+
const sequencer = new Sequencer_1.Sequencer({
|
|
960
|
+
name: 'program.validate',
|
|
961
|
+
cancellationToken: (_a = options === null || options === void 0 ? void 0 : options.cancellationToken) !== null && _a !== void 0 ? _a : new vscode_languageserver_1.CancellationTokenSource().token,
|
|
962
|
+
minSyncDuration: this.validationMinSyncDuration
|
|
963
|
+
});
|
|
964
|
+
//this sequencer allows us to run in both sync and async mode, depending on whether options.async is enabled.
|
|
965
|
+
//We use this to prevent starving the CPU during long validate cycles when running in a language server context
|
|
966
|
+
sequencer
|
|
967
|
+
.once('wait for previous run', () => {
|
|
968
|
+
//if running in async mode, return the previous validation promise to ensure we're only running one at a time
|
|
969
|
+
if (options === null || options === void 0 ? void 0 : options.async) {
|
|
970
|
+
return previousValidationPromise;
|
|
971
|
+
}
|
|
972
|
+
})
|
|
973
|
+
.once('before and on programValidate', () => {
|
|
974
|
+
logValidateEnd = this.logger.timeStart(logging_1.LogLevel.log, `Validating project${this.logger.logLevel > logging_1.LogLevel.log ? ` (run ${validationRunId})` : ''}`);
|
|
975
|
+
this.diagnostics.clearForTag(ProgramValidator_1.ProgramValidatorDiagnosticsTag);
|
|
976
|
+
this.plugins.emit('beforeValidateProgram', {
|
|
470
977
|
program: this
|
|
471
978
|
});
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
979
|
+
beforeValidateProgramWasEmitted = true;
|
|
980
|
+
this.plugins.emit('validateProgram', {
|
|
981
|
+
program: this
|
|
982
|
+
});
|
|
983
|
+
})
|
|
984
|
+
.once('get files to be validated', () => {
|
|
985
|
+
filesToProcess = Object.values(this.files).sort((0, thenby_1.firstBy)(x => x.srcPath)).filter(x => !x.isValidated);
|
|
986
|
+
for (const file of filesToProcess) {
|
|
987
|
+
filesToBeValidatedInScopeContext.add(file);
|
|
988
|
+
}
|
|
989
|
+
})
|
|
990
|
+
.once('add component reference types', () => {
|
|
991
|
+
// Create reference component types for any component that changes
|
|
992
|
+
for (let [componentKey, componentName] of this.componentSymbolsToUpdate.entries()) {
|
|
993
|
+
this.addComponentReferenceType(componentKey, componentName);
|
|
994
|
+
}
|
|
995
|
+
})
|
|
996
|
+
//run before/validate/after as a single per-file action so the Sequencer can't cancel
|
|
997
|
+
//between them. Splitting into three forEach steps would let cancellation land after
|
|
998
|
+
//`validateFile` (where BrsFileValidator pushes per-node symbols via addSymbol) but
|
|
999
|
+
//before `afterValidateFile` (where processSymbolInformation registers validation
|
|
1000
|
+
//segments) — leaving the file in a half-processed state. The next pass would either
|
|
1001
|
+
//re-run BrsFileValidator (pushing duplicate symbols → CrossScopeValidator name-
|
|
1002
|
+
//collision) or skip the file in scope validation (no segments to walk → no
|
|
1003
|
+
//diagnostics emitted). Atomic-per-file means either the file is fully processed or
|
|
1004
|
+
//it's untouched. Plugins that need an all-files-done signal should use
|
|
1005
|
+
//`afterValidateProgram` instead of `afterValidateFile`.
|
|
1006
|
+
.forEach('validateFile', () => filesToProcess, (file) => {
|
|
1007
|
+
this.plugins.emit('beforeValidateFile', {
|
|
1008
|
+
program: this,
|
|
1009
|
+
file: file
|
|
1010
|
+
});
|
|
1011
|
+
this.plugins.emit('validateFile', {
|
|
1012
|
+
program: this,
|
|
1013
|
+
file: file
|
|
1014
|
+
});
|
|
1015
|
+
this.plugins.emit('afterValidateFile', {
|
|
1016
|
+
program: this,
|
|
1017
|
+
file: file
|
|
1018
|
+
});
|
|
1019
|
+
file.isValidated = true;
|
|
1020
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1021
|
+
brsFilesValidated.push(file);
|
|
1022
|
+
}
|
|
1023
|
+
else if ((0, reflection_1.isXmlFile)(file)) {
|
|
1024
|
+
xmlFilesValidated.push(file);
|
|
1025
|
+
}
|
|
1026
|
+
})
|
|
1027
|
+
.forEach('do deferred component creation', () => [...brsFilesValidated, ...xmlFilesValidated], (file) => {
|
|
1028
|
+
if ((0, reflection_1.isXmlFile)(file)) {
|
|
1029
|
+
this.addDeferredComponentTypeSymbolCreation(file);
|
|
1030
|
+
}
|
|
1031
|
+
else if ((0, reflection_1.isBrsFile)(file)) {
|
|
1032
|
+
const fileHasChanges = file.providedSymbols.changes.get(1 /* SymbolTypeFlag.runtime */).size > 0 || file.providedSymbols.changes.get(2 /* SymbolTypeFlag.typetime */).size > 0;
|
|
1033
|
+
if (fileHasChanges) {
|
|
1034
|
+
for (const scope of this.getScopesForFile(file)) {
|
|
1035
|
+
if ((0, reflection_1.isXmlScope)(scope) && this.doesXmlFileRequireProvidedSymbols(scope.xmlFile, file.providedSymbols.changes)) {
|
|
1036
|
+
this.addDeferredComponentTypeSymbolCreation(scope.xmlFile);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
493
1039
|
}
|
|
494
1040
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
scope.isValidated = true;
|
|
505
|
-
this.plugins.emit('afterScopeValidate', {
|
|
506
|
-
program: this,
|
|
507
|
-
scope: scope
|
|
508
|
-
});
|
|
1041
|
+
})
|
|
1042
|
+
.once('build component types for any component that changes', () => {
|
|
1043
|
+
this.logger.time(logging_1.LogLevel.info, ['Build component types'], () => {
|
|
1044
|
+
this.logger.debug(`Component Symbols to update:`, [...this.componentSymbolsToUpdate.entries()].sort());
|
|
1045
|
+
this.lastValidationInfo.componentsRebuilt = new Set();
|
|
1046
|
+
for (let [componentKey, componentName] of this.componentSymbolsToUpdate.entries()) {
|
|
1047
|
+
this.lastValidationInfo.componentsRebuilt.add(componentName === null || componentName === void 0 ? void 0 : componentName.toLowerCase());
|
|
1048
|
+
if (this.updateComponentSymbolInGlobalScope(componentKey, componentName)) {
|
|
1049
|
+
changedComponentTypes.push(util_1.util.getSgNodeTypeName(componentName).toLowerCase());
|
|
509
1050
|
}
|
|
510
1051
|
}
|
|
1052
|
+
this.componentSymbolsToUpdate.clear();
|
|
511
1053
|
});
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
if (reflection_1.isXmlFile(file)) {
|
|
528
|
-
const componentNameLower = (_a = file.componentName) === null || _a === void 0 ? void 0 : _a.text.toLowerCase();
|
|
529
|
-
if (componentNameLower) {
|
|
530
|
-
if (!componentsByName.has(componentNameLower)) {
|
|
531
|
-
componentsByName.set(componentNameLower, [file]);
|
|
1054
|
+
})
|
|
1055
|
+
.once('track and update type-time and runtime symbol dependencies and changes', () => {
|
|
1056
|
+
var _a, _b, _c, _d;
|
|
1057
|
+
const changedSymbolsMapArr = (_a = [...brsFilesValidated, ...xmlFilesValidated]) === null || _a === void 0 ? void 0 : _a.map(f => {
|
|
1058
|
+
if ((0, reflection_1.isBrsFile)(f)) {
|
|
1059
|
+
return f.providedSymbols.changes;
|
|
1060
|
+
}
|
|
1061
|
+
return null;
|
|
1062
|
+
}).filter(x => x);
|
|
1063
|
+
// update the map of typetime dependencies
|
|
1064
|
+
for (const file of brsFilesValidated) {
|
|
1065
|
+
for (const [symbolName, provided] of file.providedSymbols.symbolMap.get(2 /* SymbolTypeFlag.typetime */).entries()) {
|
|
1066
|
+
// clear existing dependencies
|
|
1067
|
+
for (const values of this.symbolDependencies.values()) {
|
|
1068
|
+
values.delete(symbolName);
|
|
532
1069
|
}
|
|
533
|
-
|
|
534
|
-
|
|
1070
|
+
// map types to the set of types that depend upon them
|
|
1071
|
+
for (const dependentSymbol of (_c = (_b = provided.requiredSymbolNames) === null || _b === void 0 ? void 0 : _b.values()) !== null && _c !== void 0 ? _c : []) {
|
|
1072
|
+
const dependentSymbolLower = dependentSymbol.toLowerCase();
|
|
1073
|
+
if (!this.symbolDependencies.has(dependentSymbolLower)) {
|
|
1074
|
+
this.symbolDependencies.set(dependentSymbolLower, new Set());
|
|
1075
|
+
}
|
|
1076
|
+
const symbolsDependentUpon = this.symbolDependencies.get(dependentSymbolLower);
|
|
1077
|
+
symbolsDependentUpon.add(symbolName);
|
|
535
1078
|
}
|
|
536
1079
|
}
|
|
537
1080
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
return {
|
|
546
|
-
location: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(xmlFile.srcPath).toString(), x.componentName.range),
|
|
547
|
-
message: 'Also defined here'
|
|
548
|
-
};
|
|
549
|
-
}) }));
|
|
1081
|
+
for (const flag of [1 /* SymbolTypeFlag.runtime */, 2 /* SymbolTypeFlag.typetime */]) {
|
|
1082
|
+
const changedSymbolsSetArr = changedSymbolsMapArr.map(symMap => symMap.get(flag));
|
|
1083
|
+
const changedSymbolSet = new Set();
|
|
1084
|
+
for (const changeSet of changedSymbolsSetArr) {
|
|
1085
|
+
for (const change of changeSet) {
|
|
1086
|
+
changedSymbolSet.add(change);
|
|
1087
|
+
}
|
|
550
1088
|
}
|
|
551
|
-
|
|
1089
|
+
if (!changedSymbols.has(flag)) {
|
|
1090
|
+
changedSymbols.set(flag, changedSymbolSet);
|
|
1091
|
+
}
|
|
1092
|
+
else {
|
|
1093
|
+
changedSymbols.set(flag, new Set([...changedSymbols.get(flag), ...changedSymbolSet]));
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
// update changed symbol set with any changed component
|
|
1097
|
+
for (const changedComponentType of changedComponentTypes) {
|
|
1098
|
+
changedSymbols.get(2 /* SymbolTypeFlag.typetime */).add(changedComponentType);
|
|
1099
|
+
}
|
|
1100
|
+
// Add any additional types that depend on a changed type
|
|
1101
|
+
// as each iteration of the loop might add new types, need to keep checking until nothing new is added
|
|
1102
|
+
const dependentTypesChanged = new Set();
|
|
1103
|
+
let foundDependentTypes = false;
|
|
1104
|
+
const changedTypeSymbols = changedSymbols.get(2 /* SymbolTypeFlag.typetime */);
|
|
1105
|
+
do {
|
|
1106
|
+
foundDependentTypes = false;
|
|
1107
|
+
const allChangedTypesSofar = [...Array.from(changedTypeSymbols), ...Array.from(dependentTypesChanged)];
|
|
1108
|
+
for (const changedSymbol of allChangedTypesSofar) {
|
|
1109
|
+
const symbolsDependentUponChangedSymbol = (_d = this.symbolDependencies.get(changedSymbol)) !== null && _d !== void 0 ? _d : [];
|
|
1110
|
+
for (const symbolName of symbolsDependentUponChangedSymbol) {
|
|
1111
|
+
if (!changedTypeSymbols.has(symbolName) && !dependentTypesChanged.has(symbolName)) {
|
|
1112
|
+
foundDependentTypes = true;
|
|
1113
|
+
dependentTypesChanged.add(symbolName);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
} while (foundDependentTypes);
|
|
1118
|
+
changedSymbols.set(2 /* SymbolTypeFlag.typetime */, new Set([...changedSymbols.get(2 /* SymbolTypeFlag.typetime */), ...changedTypeSymbols, ...dependentTypesChanged]));
|
|
1119
|
+
this.lastValidationInfo.brsFilesSrcPath = new Set(this.validationDetails.brsFilesValidated.map(f => { var _a, _b; return (_b = (_a = f.srcPath) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : ''; }));
|
|
1120
|
+
this.lastValidationInfo.xmlFilesSrcPath = new Set(this.validationDetails.xmlFilesValidated.map(f => { var _a, _b; return (_b = (_a = f.srcPath) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : ''; }));
|
|
1121
|
+
// can reset filesValidatedList, because they are no longer needed
|
|
1122
|
+
this.validationDetails.brsFilesValidated = [];
|
|
1123
|
+
this.validationDetails.xmlFilesValidated = [];
|
|
1124
|
+
})
|
|
1125
|
+
.once('tracks changed symbols and prepares files and scopes for validation', () => {
|
|
1126
|
+
if (this.options.logLevel === logging_1.LogLevel.debug) {
|
|
1127
|
+
const changedRuntime = Array.from(changedSymbols.get(1 /* SymbolTypeFlag.runtime */)).sort();
|
|
1128
|
+
this.logger.debug('Changed Symbols (runTime):', changedRuntime.join(', '));
|
|
1129
|
+
const changedTypetime = Array.from(changedSymbols.get(2 /* SymbolTypeFlag.typetime */)).sort();
|
|
1130
|
+
this.logger.debug('Changed Symbols (typeTime):', changedTypetime.join(', '));
|
|
1131
|
+
}
|
|
1132
|
+
const didComponentChange = changedComponentTypes.length > 0;
|
|
1133
|
+
const didProvidedSymbolChange = changedSymbols.get(1 /* SymbolTypeFlag.runtime */).size > 0 || changedSymbols.get(2 /* SymbolTypeFlag.typetime */).size > 0;
|
|
1134
|
+
const scopesToCheck = this.getScopesForCrossScopeValidation(didComponentChange, didProvidedSymbolChange);
|
|
1135
|
+
this.crossScopeValidation.buildComponentsMap();
|
|
1136
|
+
this.logger.time(logging_1.LogLevel.info, ['addDiagnosticsForScopes'], () => {
|
|
1137
|
+
this.crossScopeValidation.addDiagnosticsForScopes(scopesToCheck);
|
|
1138
|
+
});
|
|
1139
|
+
const filesToRevalidate = this.crossScopeValidation.getFilesRequiringChangedSymbol(scopesToCheck, changedSymbols);
|
|
1140
|
+
for (const file of filesToRevalidate) {
|
|
1141
|
+
filesToBeValidatedInScopeContext.add(file);
|
|
1142
|
+
}
|
|
1143
|
+
this.currentScopeValidationOptions = {
|
|
1144
|
+
filesToBeValidatedInScopeContext: filesToBeValidatedInScopeContext,
|
|
1145
|
+
changedSymbols: changedSymbols,
|
|
1146
|
+
changedFiles: Array.from(filesToBeValidatedInScopeContext),
|
|
1147
|
+
initialValidation: this.isFirstValidation
|
|
1148
|
+
};
|
|
1149
|
+
//can reset changedComponent types
|
|
1150
|
+
this.validationDetails.changedComponentTypes = [];
|
|
1151
|
+
})
|
|
1152
|
+
.forEach('invalidate affected scopes', () => filesToBeValidatedInScopeContext, (file) => {
|
|
1153
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1154
|
+
file.validationSegmenter.unValidateAllSegments();
|
|
1155
|
+
for (const scope of this.getScopesForFile(file)) {
|
|
1156
|
+
scope.invalidate();
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
})
|
|
1160
|
+
.once('checking scopes to validate', () => {
|
|
1161
|
+
//sort the scope names so we get consistent results
|
|
1162
|
+
for (const scopeName of this.getSortedScopeNames()) {
|
|
1163
|
+
let scope = this.scopes[scopeName];
|
|
1164
|
+
if (scope.shouldValidate(this.currentScopeValidationOptions)) {
|
|
1165
|
+
scopesToValidate.push(scope);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
this.lastValidationInfo.scopeNames = new Set(scopesToValidate.map(s => { var _a, _b; return (_b = (_a = s.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : ''; }));
|
|
1169
|
+
})
|
|
1170
|
+
.forEach('beforeScopeValidate', () => scopesToValidate, (scope) => {
|
|
1171
|
+
this.plugins.emit('beforeValidateScope', {
|
|
1172
|
+
program: this,
|
|
1173
|
+
scope: scope
|
|
1174
|
+
});
|
|
1175
|
+
})
|
|
1176
|
+
.forEach('validate scope', () => scopesToValidate, (scope) => {
|
|
1177
|
+
scope.validate(this.currentScopeValidationOptions);
|
|
1178
|
+
})
|
|
1179
|
+
.forEach('afterValidateScope', () => scopesToValidate, (scope) => {
|
|
1180
|
+
this.plugins.emit('afterValidateScope', {
|
|
1181
|
+
program: this,
|
|
1182
|
+
scope: scope
|
|
1183
|
+
});
|
|
1184
|
+
})
|
|
1185
|
+
.once('detect duplicate component names', () => {
|
|
1186
|
+
this.detectDuplicateComponentNames();
|
|
1187
|
+
this.isFirstValidation = false;
|
|
1188
|
+
// can reset other validation details
|
|
1189
|
+
this.validationDetails.changedSymbols = new Map();
|
|
1190
|
+
this.validationDetails.scopesToValidate = [];
|
|
1191
|
+
this.validationDetails.filesToBeValidatedInScopeContext = new Set();
|
|
1192
|
+
})
|
|
1193
|
+
.onCancel(() => {
|
|
1194
|
+
logValidateEnd('cancelled');
|
|
1195
|
+
})
|
|
1196
|
+
.onSuccess(() => {
|
|
1197
|
+
logValidateEnd();
|
|
1198
|
+
})
|
|
1199
|
+
.onComplete(() => {
|
|
1200
|
+
var _a, _b;
|
|
1201
|
+
//if we emitted the beforeValidateProgram hook, emit the afterValidateProgram hook as well
|
|
1202
|
+
if (beforeValidateProgramWasEmitted) {
|
|
1203
|
+
const wasCancelled = (_b = (_a = options === null || options === void 0 ? void 0 : options.cancellationToken) === null || _a === void 0 ? void 0 : _a.isCancellationRequested) !== null && _b !== void 0 ? _b : false;
|
|
1204
|
+
this.plugins.emit('afterValidateProgram', {
|
|
1205
|
+
program: this,
|
|
1206
|
+
wasCancelled: wasCancelled
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
//log all the sequencer timing metrics if `info` logging is enabled
|
|
1210
|
+
this.logger.info(sequencer.formatMetrics({
|
|
1211
|
+
header: 'Program.validate metrics:',
|
|
1212
|
+
//only include loop iterations if `debug` logging is enabled
|
|
1213
|
+
includeLoopIterations: this.logger.isLogLevelEnabled(logging_1.LogLevel.debug)
|
|
1214
|
+
}));
|
|
1215
|
+
//regardless of the success of the validation, mark this run as complete
|
|
1216
|
+
deferred.resolve();
|
|
1217
|
+
//clear the validatePromise which means we're no longer running a validation
|
|
1218
|
+
this.validatePromise = undefined;
|
|
1219
|
+
});
|
|
1220
|
+
//run the sequencer in async mode if enabled
|
|
1221
|
+
if (options === null || options === void 0 ? void 0 : options.async) {
|
|
1222
|
+
return sequencer.run();
|
|
1223
|
+
//run the sequencer in sync mode
|
|
1224
|
+
}
|
|
1225
|
+
else {
|
|
1226
|
+
return sequencer.runSync();
|
|
552
1227
|
}
|
|
553
1228
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
1229
|
+
getScopesForCrossScopeValidation(someComponentTypeChanged, didProvidedSymbolChange) {
|
|
1230
|
+
const scopesForCrossScopeValidation = [];
|
|
1231
|
+
for (let scopeName of this.getSortedScopeNames()) {
|
|
1232
|
+
let scope = this.scopes[scopeName];
|
|
1233
|
+
if (this.globalScope === scope) {
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
if (someComponentTypeChanged) {
|
|
1237
|
+
scopesForCrossScopeValidation.push(scope);
|
|
1238
|
+
}
|
|
1239
|
+
if (didProvidedSymbolChange && !scope.isValidated) {
|
|
1240
|
+
scopesForCrossScopeValidation.push(scope);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
return scopesForCrossScopeValidation;
|
|
1244
|
+
}
|
|
1245
|
+
doesXmlFileRequireProvidedSymbols(file, providedSymbolsByFlag) {
|
|
1246
|
+
for (const required of file.requiredSymbols) {
|
|
1247
|
+
const symbolNameLower = required.name.toLowerCase();
|
|
1248
|
+
const requiredSymbolIsProvided = providedSymbolsByFlag.get(required.flags).has(symbolNameLower);
|
|
1249
|
+
if (requiredSymbolIsProvided) {
|
|
560
1250
|
return true;
|
|
561
1251
|
}
|
|
562
1252
|
}
|
|
563
1253
|
return false;
|
|
564
1254
|
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Flag all duplicate component names
|
|
1257
|
+
*/
|
|
1258
|
+
detectDuplicateComponentNames() {
|
|
1259
|
+
const componentsByName = Object.keys(this.files).reduce((map, filePath) => {
|
|
1260
|
+
var _a;
|
|
1261
|
+
const file = this.files[filePath];
|
|
1262
|
+
//if this is an XmlFile, and it has a valid `componentName` property
|
|
1263
|
+
if ((0, reflection_1.isXmlFile)(file) && ((_a = file.componentName) === null || _a === void 0 ? void 0 : _a.text)) {
|
|
1264
|
+
let lowerName = file.componentName.text.toLowerCase();
|
|
1265
|
+
if (!map[lowerName]) {
|
|
1266
|
+
map[lowerName] = [];
|
|
1267
|
+
}
|
|
1268
|
+
map[lowerName].push(file);
|
|
1269
|
+
}
|
|
1270
|
+
return map;
|
|
1271
|
+
}, {});
|
|
1272
|
+
for (let name in componentsByName) {
|
|
1273
|
+
const xmlFiles = componentsByName[name];
|
|
1274
|
+
//add diagnostics for every duplicate component with this name
|
|
1275
|
+
if (xmlFiles.length > 1) {
|
|
1276
|
+
for (let xmlFile of xmlFiles) {
|
|
1277
|
+
const { componentName } = xmlFile;
|
|
1278
|
+
this.diagnostics.register(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateComponentName(componentName.text)), { location: xmlFile.componentName.location, relatedInformation: xmlFiles.filter(x => x !== xmlFile).map(x => {
|
|
1279
|
+
return {
|
|
1280
|
+
location: x.componentName.location,
|
|
1281
|
+
message: 'Also defined here'
|
|
1282
|
+
};
|
|
1283
|
+
}) }), { tags: [ProgramValidator_1.ProgramValidatorDiagnosticsTag] });
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Get the files for a list of filePaths
|
|
1290
|
+
* @param filePaths can be an array of srcPath or a destPath strings
|
|
1291
|
+
* @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
|
|
1292
|
+
*/
|
|
1293
|
+
getFiles(filePaths, normalizePath = true) {
|
|
1294
|
+
return filePaths
|
|
1295
|
+
.map(filePath => this.getFile(filePath, normalizePath))
|
|
1296
|
+
.filter(file => file !== undefined);
|
|
1297
|
+
}
|
|
565
1298
|
/**
|
|
566
1299
|
* Get the file at the given path
|
|
567
|
-
* @param filePath can be a srcPath
|
|
1300
|
+
* @param filePath can be a srcPath or a destPath
|
|
568
1301
|
* @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
1302
|
*/
|
|
570
1303
|
getFile(filePath, normalizePath = true) {
|
|
1304
|
+
if (this.getFilePathCache.has(filePath)) {
|
|
1305
|
+
const cachedFilePath = this.getFilePathCache.get(filePath);
|
|
1306
|
+
if (cachedFilePath.isDestMap) {
|
|
1307
|
+
return this.destMap.get(cachedFilePath.path);
|
|
1308
|
+
}
|
|
1309
|
+
return this.files[cachedFilePath.path];
|
|
1310
|
+
}
|
|
571
1311
|
if (typeof filePath !== 'string') {
|
|
572
1312
|
return undefined;
|
|
1313
|
+
//is the path absolute (or the `virtual:` prefix)
|
|
1314
|
+
}
|
|
1315
|
+
else if (/^(?:(?:virtual:[\/\\])|(?:\w:)|(?:[\/\\]))/gmi.exec(filePath)) {
|
|
1316
|
+
const standardizedPath = (normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase();
|
|
1317
|
+
this.getFilePathCache.set(filePath, { path: standardizedPath });
|
|
1318
|
+
return this.files[standardizedPath];
|
|
573
1319
|
}
|
|
574
|
-
else if (
|
|
575
|
-
|
|
1320
|
+
else if (util_1.util.isUriLike(filePath)) {
|
|
1321
|
+
const path = vscode_uri_1.URI.parse(filePath).fsPath;
|
|
1322
|
+
const standardizedPath = (normalizePath ? util_1.util.standardizePath(path) : path).toLowerCase();
|
|
1323
|
+
this.getFilePathCache.set(filePath, { path: standardizedPath });
|
|
1324
|
+
return this.files[standardizedPath];
|
|
576
1325
|
}
|
|
577
1326
|
else {
|
|
578
|
-
|
|
1327
|
+
const standardizedPath = (normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase();
|
|
1328
|
+
this.getFilePathCache.set(filePath, { path: standardizedPath, isDestMap: true });
|
|
1329
|
+
return this.destMap.get(standardizedPath);
|
|
579
1330
|
}
|
|
580
1331
|
}
|
|
1332
|
+
/**
|
|
1333
|
+
* Gets a sorted list of all scopeNames, always beginning with "global", "source", then any others in alphabetical order
|
|
1334
|
+
*/
|
|
1335
|
+
getSortedScopeNames() {
|
|
1336
|
+
if (!this.sortedScopeNames) {
|
|
1337
|
+
this.sortedScopeNames = Object.keys(this.scopes).sort((a, b) => {
|
|
1338
|
+
if (a === 'global') {
|
|
1339
|
+
return -1;
|
|
1340
|
+
}
|
|
1341
|
+
else if (b === 'global') {
|
|
1342
|
+
return 1;
|
|
1343
|
+
}
|
|
1344
|
+
if (a === 'source') {
|
|
1345
|
+
return -1;
|
|
1346
|
+
}
|
|
1347
|
+
else if (b === 'source') {
|
|
1348
|
+
return 1;
|
|
1349
|
+
}
|
|
1350
|
+
if (a < b) {
|
|
1351
|
+
return -1;
|
|
1352
|
+
}
|
|
1353
|
+
else if (b < a) {
|
|
1354
|
+
return 1;
|
|
1355
|
+
}
|
|
1356
|
+
return 0;
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
return this.sortedScopeNames;
|
|
1360
|
+
}
|
|
581
1361
|
/**
|
|
582
1362
|
* Get a list of all scopes the file is loaded into
|
|
583
|
-
* @param file
|
|
1363
|
+
* @param file the file
|
|
584
1364
|
*/
|
|
585
1365
|
getScopesForFile(file) {
|
|
1366
|
+
const resolvedFile = typeof file === 'string' ? this.getFile(file) : file;
|
|
586
1367
|
let result = [];
|
|
587
|
-
|
|
1368
|
+
if (resolvedFile) {
|
|
1369
|
+
const scopeKeys = this.getSortedScopeNames();
|
|
1370
|
+
for (let key of scopeKeys) {
|
|
1371
|
+
let scope = this.scopes[key];
|
|
1372
|
+
if (scope.hasFile(resolvedFile)) {
|
|
1373
|
+
result.push(scope);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return result;
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Get the first found scope for a file.
|
|
1381
|
+
*/
|
|
1382
|
+
getFirstScopeForFile(file) {
|
|
1383
|
+
const scopeKeys = this.getSortedScopeNames();
|
|
1384
|
+
for (let key of scopeKeys) {
|
|
588
1385
|
let scope = this.scopes[key];
|
|
589
1386
|
if (scope.hasFile(file)) {
|
|
590
|
-
|
|
1387
|
+
return scope;
|
|
591
1388
|
}
|
|
592
1389
|
}
|
|
593
|
-
return result;
|
|
594
1390
|
}
|
|
595
1391
|
getStatementsByName(name, originFile, namespaceName) {
|
|
596
|
-
var _a, _b;
|
|
597
1392
|
let results = new Map();
|
|
598
1393
|
const filesSearched = new Set();
|
|
599
1394
|
let lowerNamespaceName = namespaceName === null || namespaceName === void 0 ? void 0 : namespaceName.toLowerCase();
|
|
600
1395
|
let lowerName = name === null || name === void 0 ? void 0 : name.toLowerCase();
|
|
1396
|
+
function addToResults(statement, file) {
|
|
1397
|
+
var _a, _b;
|
|
1398
|
+
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();
|
|
1399
|
+
if (statement.tokens.name.text.toLowerCase() === lowerName && (!lowerNamespaceName || parentNamespaceName === lowerNamespaceName)) {
|
|
1400
|
+
if (!results.has(statement)) {
|
|
1401
|
+
results.set(statement, { item: statement, file: file });
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
601
1405
|
//look through all files in scope for matches
|
|
602
1406
|
for (const scope of this.getScopesForFile(originFile)) {
|
|
603
1407
|
for (const file of scope.getAllFiles()) {
|
|
604
|
-
|
|
1408
|
+
//skip non-brs files, or files we've already processed
|
|
1409
|
+
if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
|
|
605
1410
|
continue;
|
|
606
1411
|
}
|
|
607
1412
|
filesSearched.add(file);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
1413
|
+
file.ast.walk((0, visitors_1.createVisitor)({
|
|
1414
|
+
FunctionStatement: (statement) => {
|
|
1415
|
+
addToResults(statement, file);
|
|
1416
|
+
},
|
|
1417
|
+
MethodStatement: (statement) => {
|
|
1418
|
+
addToResults(statement, file);
|
|
614
1419
|
}
|
|
615
|
-
}
|
|
1420
|
+
}), {
|
|
1421
|
+
walkMode: visitors_1.WalkMode.visitStatements
|
|
1422
|
+
});
|
|
616
1423
|
}
|
|
617
1424
|
}
|
|
618
1425
|
return [...results.values()];
|
|
@@ -624,136 +1431,186 @@ class Program {
|
|
|
624
1431
|
//get all function names for the xml file and parents
|
|
625
1432
|
let funcNames = new Set();
|
|
626
1433
|
let currentScope = scope;
|
|
627
|
-
while (reflection_1.isXmlScope(currentScope)) {
|
|
628
|
-
for (let
|
|
629
|
-
if (
|
|
630
|
-
|
|
631
|
-
if (!filterName || name === filterName) {
|
|
632
|
-
funcNames.add(name);
|
|
633
|
-
}
|
|
1434
|
+
while ((0, reflection_1.isXmlScope)(currentScope)) {
|
|
1435
|
+
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 : []) {
|
|
1436
|
+
if (!filterName || name === filterName) {
|
|
1437
|
+
funcNames.add(name);
|
|
634
1438
|
}
|
|
635
1439
|
}
|
|
636
1440
|
currentScope = currentScope.getParentScope();
|
|
637
1441
|
}
|
|
638
1442
|
//look through all files in scope for matches
|
|
639
1443
|
for (const file of scope.getOwnFiles()) {
|
|
640
|
-
|
|
1444
|
+
//skip non-brs files, or files we've already processed
|
|
1445
|
+
if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
|
|
641
1446
|
continue;
|
|
642
1447
|
}
|
|
643
1448
|
filesSearched.add(file);
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
if (
|
|
647
|
-
results.
|
|
1449
|
+
file.ast.walk((0, visitors_1.createVisitor)({
|
|
1450
|
+
FunctionStatement: (statement) => {
|
|
1451
|
+
if (funcNames.has(statement.tokens.name.text)) {
|
|
1452
|
+
if (!results.has(statement)) {
|
|
1453
|
+
results.set(statement, { item: statement, file: file });
|
|
1454
|
+
}
|
|
648
1455
|
}
|
|
649
1456
|
}
|
|
650
|
-
}
|
|
1457
|
+
}), {
|
|
1458
|
+
walkMode: visitors_1.WalkMode.visitStatements
|
|
1459
|
+
});
|
|
651
1460
|
}
|
|
652
1461
|
return [...results.values()];
|
|
653
1462
|
}
|
|
654
1463
|
/**
|
|
655
1464
|
* Find all available completion items at the given position
|
|
656
|
-
* @param
|
|
657
|
-
* @param
|
|
658
|
-
* @param columnIndex
|
|
1465
|
+
* @param filePath can be a srcPath or a destPath
|
|
1466
|
+
* @param position the position (line & column) where completions should be found
|
|
659
1467
|
*/
|
|
660
|
-
getCompletions(
|
|
661
|
-
let file = this.getFile(
|
|
1468
|
+
getCompletions(filePath, position) {
|
|
1469
|
+
let file = this.getFile(filePath);
|
|
662
1470
|
if (!file) {
|
|
663
1471
|
return [];
|
|
664
1472
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
677
|
-
//find the scopes for this file
|
|
678
|
-
let scopes = this.getScopesForFile(file);
|
|
679
|
-
//if there are no scopes, include the global scope so we at least get the built-in functions
|
|
680
|
-
scopes = scopes.length > 0 ? scopes : [this.globalScope];
|
|
681
|
-
//get the completions from all scopes for this file
|
|
682
|
-
let allCompletions = util_1.util.flatMap(scopes.map(ctx => file.getCompletions(position, ctx)), c => c);
|
|
683
|
-
//only keep completions common to every scope for this file
|
|
684
|
-
let keyCounts = {};
|
|
685
|
-
for (let completion of allCompletions) {
|
|
686
|
-
let key = `${completion.label}-${completion.kind}`;
|
|
687
|
-
keyCounts[key] = keyCounts[key] ? keyCounts[key] + 1 : 1;
|
|
688
|
-
if (keyCounts[key] === scopes.length) {
|
|
689
|
-
result.push(completion);
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
return result;
|
|
1473
|
+
const event = {
|
|
1474
|
+
program: this,
|
|
1475
|
+
file: file,
|
|
1476
|
+
scopes: this.getScopesForFile(file),
|
|
1477
|
+
position: position,
|
|
1478
|
+
completions: []
|
|
1479
|
+
};
|
|
1480
|
+
this.plugins.emit('beforeProvideCompletions', event);
|
|
1481
|
+
this.plugins.emit('provideCompletions', event);
|
|
1482
|
+
this.plugins.emit('afterProvideCompletions', event);
|
|
1483
|
+
return event.completions;
|
|
693
1484
|
}
|
|
694
1485
|
/**
|
|
695
1486
|
* Goes through each file and builds a list of workspace symbols for the program. Used by LanguageServer's onWorkspaceSymbol functionality
|
|
696
1487
|
*/
|
|
697
1488
|
getWorkspaceSymbols() {
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
return
|
|
1489
|
+
const event = {
|
|
1490
|
+
program: this,
|
|
1491
|
+
workspaceSymbols: []
|
|
1492
|
+
};
|
|
1493
|
+
this.plugins.emit('beforeProvideWorkspaceSymbols', event);
|
|
1494
|
+
this.plugins.emit('provideWorkspaceSymbols', event);
|
|
1495
|
+
this.plugins.emit('afterProvideWorkspaceSymbols', event);
|
|
1496
|
+
return event.workspaceSymbols;
|
|
706
1497
|
}
|
|
707
1498
|
/**
|
|
708
1499
|
* Given a position in a file, if the position is sitting on some type of identifier,
|
|
709
1500
|
* go to the definition of that identifier (where this thing was first defined)
|
|
710
|
-
* @param srcPath The absolute path to the source file on disk
|
|
711
1501
|
*/
|
|
712
1502
|
getDefinition(srcPath, position) {
|
|
713
1503
|
let file = this.getFile(srcPath);
|
|
714
1504
|
if (!file) {
|
|
715
1505
|
return [];
|
|
716
1506
|
}
|
|
717
|
-
|
|
718
|
-
|
|
1507
|
+
const event = {
|
|
1508
|
+
program: this,
|
|
1509
|
+
file: file,
|
|
1510
|
+
position: position,
|
|
1511
|
+
definitions: []
|
|
1512
|
+
};
|
|
1513
|
+
this.plugins.emit('beforeProvideDefinition', event);
|
|
1514
|
+
this.plugins.emit('provideDefinition', event);
|
|
1515
|
+
this.plugins.emit('afterProvideDefinition', event);
|
|
1516
|
+
return event.definitions;
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Get hover information for a file and position
|
|
1520
|
+
*/
|
|
1521
|
+
getHover(srcPath, position) {
|
|
1522
|
+
let file = this.getFile(srcPath);
|
|
1523
|
+
let result;
|
|
1524
|
+
if (file) {
|
|
1525
|
+
const event = {
|
|
1526
|
+
program: this,
|
|
1527
|
+
file: file,
|
|
1528
|
+
position: position,
|
|
1529
|
+
scopes: this.getScopesForFile(file),
|
|
1530
|
+
hovers: []
|
|
1531
|
+
};
|
|
1532
|
+
this.plugins.emit('beforeProvideHover', event);
|
|
1533
|
+
this.plugins.emit('provideHover', event);
|
|
1534
|
+
this.plugins.emit('afterProvideHover', event);
|
|
1535
|
+
result = event.hovers;
|
|
1536
|
+
}
|
|
1537
|
+
return result !== null && result !== void 0 ? result : [];
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Get full list of document symbols for a file
|
|
1541
|
+
* @param srcPath path to the file
|
|
1542
|
+
*/
|
|
1543
|
+
getDocumentSymbols(srcPath) {
|
|
1544
|
+
let file = this.getFile(srcPath);
|
|
1545
|
+
if (file) {
|
|
1546
|
+
const event = {
|
|
1547
|
+
program: this,
|
|
1548
|
+
file: file,
|
|
1549
|
+
documentSymbols: []
|
|
1550
|
+
};
|
|
1551
|
+
this.plugins.emit('beforeProvideDocumentSymbols', event);
|
|
1552
|
+
this.plugins.emit('provideDocumentSymbols', event);
|
|
1553
|
+
this.plugins.emit('afterProvideDocumentSymbols', event);
|
|
1554
|
+
return event.documentSymbols;
|
|
719
1555
|
}
|
|
720
1556
|
else {
|
|
721
|
-
|
|
722
|
-
const scopes = this.getScopesForFile(file);
|
|
723
|
-
for (const scope of scopes) {
|
|
724
|
-
results = results.concat(...scope.getDefinition(file, position));
|
|
725
|
-
}
|
|
726
|
-
return results;
|
|
1557
|
+
return undefined;
|
|
727
1558
|
}
|
|
728
1559
|
}
|
|
729
1560
|
/**
|
|
730
|
-
*
|
|
1561
|
+
* Get the selection ranges for the given positions in a file. Used for expand/shrink selection.
|
|
1562
|
+
* @param srcPath path to the file
|
|
1563
|
+
* @param positions the positions to get selection ranges for
|
|
731
1564
|
*/
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
1565
|
+
getSelectionRanges(srcPath, positions) {
|
|
1566
|
+
const file = this.getFile(srcPath);
|
|
1567
|
+
if (file) {
|
|
1568
|
+
const event = {
|
|
1569
|
+
program: this,
|
|
1570
|
+
file: file,
|
|
1571
|
+
positions: positions,
|
|
1572
|
+
selectionRanges: []
|
|
1573
|
+
};
|
|
1574
|
+
this.plugins.emit('beforeProvideSelectionRanges', event);
|
|
1575
|
+
this.plugins.emit('provideSelectionRanges', event);
|
|
1576
|
+
this.plugins.emit('afterProvideSelectionRanges', event);
|
|
1577
|
+
return event.selectionRanges;
|
|
737
1578
|
}
|
|
738
|
-
return
|
|
1579
|
+
return [];
|
|
739
1580
|
}
|
|
740
1581
|
/**
|
|
741
1582
|
* Compute code actions for the given file and range
|
|
742
|
-
* @param srcPath The absolute path to the source file on disk
|
|
743
1583
|
*/
|
|
744
1584
|
getCodeActions(srcPath, range) {
|
|
745
1585
|
const codeActions = [];
|
|
746
1586
|
const file = this.getFile(srcPath);
|
|
747
1587
|
if (file) {
|
|
1588
|
+
const fileUri = util_1.util.pathToUri(file === null || file === void 0 ? void 0 : file.srcPath);
|
|
748
1589
|
const diagnostics = this
|
|
749
1590
|
//get all current diagnostics (filtered by diagnostic filters)
|
|
750
1591
|
.getDiagnostics()
|
|
751
1592
|
//only keep diagnostics related to this file
|
|
752
|
-
.filter(x => x.
|
|
1593
|
+
.filter(x => { var _a; return ((_a = x.location) === null || _a === void 0 ? void 0 : _a.uri) === fileUri; })
|
|
753
1594
|
//only keep diagnostics that touch this range
|
|
754
|
-
.filter(x => util_1.util.
|
|
1595
|
+
.filter(x => util_1.util.rangesIntersectOrTouch(x.location.range, range));
|
|
755
1596
|
const scopes = this.getScopesForFile(file);
|
|
756
|
-
this.plugins.emit('
|
|
1597
|
+
this.plugins.emit('beforeProvideCodeActions', {
|
|
1598
|
+
program: this,
|
|
1599
|
+
file: file,
|
|
1600
|
+
range: range,
|
|
1601
|
+
diagnostics: diagnostics,
|
|
1602
|
+
scopes: scopes,
|
|
1603
|
+
codeActions: codeActions
|
|
1604
|
+
});
|
|
1605
|
+
this.plugins.emit('provideCodeActions', {
|
|
1606
|
+
program: this,
|
|
1607
|
+
file: file,
|
|
1608
|
+
range: range,
|
|
1609
|
+
diagnostics: diagnostics,
|
|
1610
|
+
scopes: scopes,
|
|
1611
|
+
codeActions: codeActions
|
|
1612
|
+
});
|
|
1613
|
+
this.plugins.emit('afterProvideCodeActions', {
|
|
757
1614
|
program: this,
|
|
758
1615
|
file: file,
|
|
759
1616
|
range: range,
|
|
@@ -764,14 +1621,53 @@ class Program {
|
|
|
764
1621
|
}
|
|
765
1622
|
return codeActions;
|
|
766
1623
|
}
|
|
1624
|
+
/**
|
|
1625
|
+
* Compute "source fix all" code actions for the given file.
|
|
1626
|
+
* Fires the `onGetSourceFixAllCodeActions` plugin event with all diagnostics for the file (no range filter),
|
|
1627
|
+
* then converts each contributed SourceFixAllCodeAction into an LSP CodeAction.
|
|
1628
|
+
*/
|
|
1629
|
+
getSourceFixAllCodeActions(srcPath) {
|
|
1630
|
+
const actions = [];
|
|
1631
|
+
const file = this.getFile(srcPath);
|
|
1632
|
+
if (file) {
|
|
1633
|
+
const fileUri = util_1.util.pathToUri(file.srcPath);
|
|
1634
|
+
const diagnostics = this
|
|
1635
|
+
.getDiagnostics()
|
|
1636
|
+
.filter(x => { var _a; return ((_a = x.location) === null || _a === void 0 ? void 0 : _a.uri) === fileUri; });
|
|
1637
|
+
const scopes = this.getScopesForFile(file);
|
|
1638
|
+
this.plugins.emit('onGetSourceFixAllCodeActions', {
|
|
1639
|
+
program: this,
|
|
1640
|
+
file: file,
|
|
1641
|
+
diagnostics: diagnostics,
|
|
1642
|
+
scopes: scopes,
|
|
1643
|
+
actions: actions
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
return actions.map(action => {
|
|
1647
|
+
var _a;
|
|
1648
|
+
return CodeActionUtil_1.codeActionUtil.createCodeAction(Object.assign(Object.assign({}, action), { kind: (_a = action.kind) !== null && _a !== void 0 ? _a : 'source.fixAll.brighterscript' }));
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
767
1651
|
/**
|
|
768
1652
|
* Get semantic tokens for the specified file
|
|
769
1653
|
*/
|
|
770
1654
|
getSemanticTokens(srcPath) {
|
|
771
1655
|
const file = this.getFile(srcPath);
|
|
772
1656
|
if (file) {
|
|
1657
|
+
this.plugins.emit('beforeProvideSemanticTokens', {
|
|
1658
|
+
program: this,
|
|
1659
|
+
file: file,
|
|
1660
|
+
scopes: this.getScopesForFile(file),
|
|
1661
|
+
semanticTokens: undefined
|
|
1662
|
+
});
|
|
773
1663
|
const result = [];
|
|
774
|
-
this.plugins.emit('
|
|
1664
|
+
this.plugins.emit('provideSemanticTokens', {
|
|
1665
|
+
program: this,
|
|
1666
|
+
file: file,
|
|
1667
|
+
scopes: this.getScopesForFile(file),
|
|
1668
|
+
semanticTokens: result
|
|
1669
|
+
});
|
|
1670
|
+
this.plugins.emit('afterProvideSemanticTokens', {
|
|
775
1671
|
program: this,
|
|
776
1672
|
file: file,
|
|
777
1673
|
scopes: this.getScopesForFile(file),
|
|
@@ -780,363 +1676,262 @@ class Program {
|
|
|
780
1676
|
return result;
|
|
781
1677
|
}
|
|
782
1678
|
}
|
|
783
|
-
getSignatureHelp(
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
if (!file || !reflection_1.isBrsFile(file)) {
|
|
1679
|
+
getSignatureHelp(filePath, position) {
|
|
1680
|
+
let file = this.getFile(filePath);
|
|
1681
|
+
if (!file || !(0, reflection_1.isBrsFile)(file)) {
|
|
787
1682
|
return [];
|
|
788
1683
|
}
|
|
789
|
-
|
|
790
|
-
let
|
|
791
|
-
|
|
792
|
-
if (identifierInfo.statementType === '') {
|
|
793
|
-
// just general function calls
|
|
794
|
-
let statements = file.program.getStatementsByName(identifierInfo.name, file);
|
|
795
|
-
for (let statement of statements) {
|
|
796
|
-
//TODO better handling of collisions - if it's a namespace, then don't show any other overrides
|
|
797
|
-
//if we're on m - then limit scope to the current class, if present
|
|
798
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
799
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
800
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
801
|
-
results.set(sigHelp.key, sigHelp);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
else if (identifierInfo.statementType === '.') {
|
|
806
|
-
//if m class reference.. then
|
|
807
|
-
//only get statements from the class I am in..
|
|
808
|
-
if (functionExpression) {
|
|
809
|
-
let myClass = file.getClassFromMReference(position, file.parser.getTokenAt(position), functionExpression);
|
|
810
|
-
if (myClass) {
|
|
811
|
-
for (let scope of this.getScopesForFile(myClass.file)) {
|
|
812
|
-
let classes = scope.getClassHierarchy(myClass.item.getName(parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
813
|
-
//and anything from any class in scope to a non m class
|
|
814
|
-
for (let statement of [...classes].filter((i) => reflection_1.isClassMethodStatement(i.item))) {
|
|
815
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
816
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
817
|
-
results.set(sigHelp.key, sigHelp);
|
|
818
|
-
return;
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
if (identifierInfo.dotPart) {
|
|
825
|
-
//potential namespaces
|
|
826
|
-
let statements = file.program.getStatementsByName(identifierInfo.name, file, identifierInfo.dotPart);
|
|
827
|
-
if (statements.length === 0) {
|
|
828
|
-
//was not a namespaced function, it could be any method on any class now
|
|
829
|
-
statements = file.program.getStatementsByName(identifierInfo.name, file);
|
|
830
|
-
}
|
|
831
|
-
for (let statement of statements) {
|
|
832
|
-
//TODO better handling of collisions - if it's a namespace, then don't show any other overrides
|
|
833
|
-
//if we're on m - then limit scope to the current class, if present
|
|
834
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
835
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
836
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
837
|
-
results.set(sigHelp.key, sigHelp);
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
else if (identifierInfo.statementType === '@.') {
|
|
843
|
-
for (const scope of this.getScopes().filter((s) => reflection_1.isXmlScope(s))) {
|
|
844
|
-
let fileLinks = this.getStatementsForXmlFile(scope, identifierInfo.name);
|
|
845
|
-
for (let fileLink of fileLinks) {
|
|
846
|
-
let sigHelp = fileLink.file.getSignatureHelpForStatement(fileLink.item);
|
|
847
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
848
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
849
|
-
results.set(sigHelp.key, sigHelp);
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
else if (identifierInfo.statementType === 'new') {
|
|
855
|
-
let classItem = file.getClassFileLink(identifierInfo.dotPart ? `${identifierInfo.dotPart}.${identifierInfo.name}` : identifierInfo.name);
|
|
856
|
-
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);
|
|
857
|
-
if (sigHelp && !results.has(sigHelp.key)) {
|
|
858
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
859
|
-
results.set(sigHelp.key, sigHelp);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
return [...results.values()];
|
|
1684
|
+
let callExpressionInfo = new CallExpressionInfo_1.CallExpressionInfo(file, position);
|
|
1685
|
+
let signatureHelpUtil = new SignatureHelpUtil_1.SignatureHelpUtil();
|
|
1686
|
+
return signatureHelpUtil.getSignatureHelpItems(callExpressionInfo);
|
|
863
1687
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
let
|
|
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
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1688
|
+
getReferences(srcPath, position) {
|
|
1689
|
+
//find the file
|
|
1690
|
+
let file = this.getFile(srcPath);
|
|
1691
|
+
const event = {
|
|
1692
|
+
program: this,
|
|
1693
|
+
file: file,
|
|
1694
|
+
position: position,
|
|
1695
|
+
references: []
|
|
1696
|
+
};
|
|
1697
|
+
this.plugins.emit('beforeProvideReferences', event);
|
|
1698
|
+
this.plugins.emit('provideReferences', event);
|
|
1699
|
+
this.plugins.emit('afterProvideReferences', event);
|
|
1700
|
+
return event.references;
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Transpile a single file and get the result as a string.
|
|
1704
|
+
* This does not write anything to the file system.
|
|
1705
|
+
*
|
|
1706
|
+
* This should only be called by `LanguageServer`.
|
|
1707
|
+
* Internal usage should call `_getTranspiledFileContents` instead.
|
|
1708
|
+
* @param filePath can be a srcPath or a destPath
|
|
1709
|
+
*/
|
|
1710
|
+
async getTranspiledFileContents(filePath) {
|
|
1711
|
+
const file = this.getFile(filePath);
|
|
1712
|
+
return this.getTranspiledFileContentsPipeline.run(async () => {
|
|
1713
|
+
const result = {
|
|
1714
|
+
destPath: file.destPath,
|
|
1715
|
+
pkgPath: file.pkgPath,
|
|
1716
|
+
srcPath: file.srcPath
|
|
1717
|
+
};
|
|
1718
|
+
const expectedPkgPath = file.pkgPath.toLowerCase();
|
|
1719
|
+
const expectedMapPath = `${expectedPkgPath}.map`;
|
|
1720
|
+
const expectedTypedefPkgPath = expectedPkgPath.replace(/\.brs$/i, '.d.bs');
|
|
1721
|
+
//add a temporary plugin to tap into the file writing process
|
|
1722
|
+
const plugin = this.plugins.addFirst({
|
|
1723
|
+
name: 'getTranspiledFileContents',
|
|
1724
|
+
beforeWriteFile: (event) => {
|
|
1725
|
+
const pkgPath = event.file.pkgPath.toLowerCase();
|
|
1726
|
+
switch (pkgPath) {
|
|
1727
|
+
//this is the actual transpiled file
|
|
1728
|
+
case expectedPkgPath:
|
|
1729
|
+
result.code = event.file.data.toString();
|
|
1730
|
+
break;
|
|
1731
|
+
//this is the sourcemap
|
|
1732
|
+
case expectedMapPath:
|
|
1733
|
+
result.map = event.file.data.toString();
|
|
1734
|
+
break;
|
|
1735
|
+
//this is the typedef
|
|
1736
|
+
case expectedTypedefPkgPath:
|
|
1737
|
+
result.typedef = event.file.data.toString();
|
|
1738
|
+
break;
|
|
1739
|
+
default:
|
|
1740
|
+
//no idea what this file is. just ignore it
|
|
913
1741
|
}
|
|
1742
|
+
//mark every file as processed so it they don't get written to the output directory
|
|
1743
|
+
event.processedFiles.add(event.file);
|
|
914
1744
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1745
|
+
});
|
|
1746
|
+
try {
|
|
1747
|
+
//now that the plugin has been registered, run the build with just this file
|
|
1748
|
+
await this.build({
|
|
1749
|
+
files: [file]
|
|
1750
|
+
});
|
|
921
1751
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
name = name || line.substring(index, argStartIndex);
|
|
925
|
-
argStartIndex = index;
|
|
1752
|
+
finally {
|
|
1753
|
+
this.plugins.remove(plugin);
|
|
926
1754
|
}
|
|
927
|
-
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
|
|
1755
|
+
return result;
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Get the absolute output path for a file
|
|
1760
|
+
*/
|
|
1761
|
+
getOutputPath(file, outDir = this.getOutDir()) {
|
|
1762
|
+
return (0, util_1.standardizePath) `${outDir}/${file.pkgPath}`;
|
|
1763
|
+
}
|
|
1764
|
+
getOutDir(outDir) {
|
|
1765
|
+
var _a, _b;
|
|
1766
|
+
let result = (_a = outDir !== null && outDir !== void 0 ? outDir : this.options.outDir) !== null && _a !== void 0 ? _a : this.options.outDir;
|
|
1767
|
+
if (!result) {
|
|
1768
|
+
result = roku_deploy_1.rokuDeploy.getOptions(this.options).outDir;
|
|
931
1769
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
statementType: statementType,
|
|
935
|
-
name: name,
|
|
936
|
-
dotPart: dotPart
|
|
937
|
-
};
|
|
1770
|
+
result = (0, util_1.standardizePath) `${path.resolve((_b = this.options.cwd) !== null && _b !== void 0 ? _b : process.cwd(), result !== null && result !== void 0 ? result : '/')}`;
|
|
1771
|
+
return result;
|
|
938
1772
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
isArgStartFound: false
|
|
1773
|
+
/**
|
|
1774
|
+
* Prepare the program for building
|
|
1775
|
+
* @param files the list of files that should be prepared
|
|
1776
|
+
*/
|
|
1777
|
+
async prepare(files) {
|
|
1778
|
+
const programEvent = {
|
|
1779
|
+
program: this,
|
|
1780
|
+
editor: this.editor,
|
|
1781
|
+
files: files
|
|
949
1782
|
};
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
if
|
|
953
|
-
|
|
954
|
-
|
|
1783
|
+
//assign an editor to every file
|
|
1784
|
+
for (const file of programEvent.files) {
|
|
1785
|
+
//if the file doesn't have an editor yet, assign one now
|
|
1786
|
+
if (!file.editor) {
|
|
1787
|
+
file.editor = new Editor_1.Editor();
|
|
955
1788
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1789
|
+
}
|
|
1790
|
+
//sort the entries to make transpiling more deterministic
|
|
1791
|
+
programEvent.files.sort((a, b) => {
|
|
1792
|
+
if (a.pkgPath < b.pkgPath) {
|
|
1793
|
+
return -1;
|
|
1794
|
+
}
|
|
1795
|
+
else if (a.pkgPath > b.pkgPath) {
|
|
1796
|
+
return 1;
|
|
960
1797
|
}
|
|
961
1798
|
else {
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
itemCounts.isArgStartFound = true;
|
|
977
|
-
itemCounts.argStartIndex = index;
|
|
978
|
-
}
|
|
979
|
-
else {
|
|
980
|
-
itemCounts.normal--;
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
if (currentChar === '[') {
|
|
984
|
-
itemCounts.square--;
|
|
985
|
-
}
|
|
986
|
-
if (currentChar === '{') {
|
|
987
|
-
itemCounts.curly--;
|
|
988
|
-
}
|
|
1799
|
+
return 1;
|
|
1800
|
+
}
|
|
1801
|
+
});
|
|
1802
|
+
await this.plugins.emitAsync('beforePrepareProgram', programEvent);
|
|
1803
|
+
await this.plugins.emitAsync('prepareProgram', programEvent);
|
|
1804
|
+
const outDir = this.getOutDir();
|
|
1805
|
+
const entries = [];
|
|
1806
|
+
for (const file of files) {
|
|
1807
|
+
const scope = this.getFirstScopeForFile(file);
|
|
1808
|
+
//link the symbol table for all the files in this scope
|
|
1809
|
+
scope === null || scope === void 0 ? void 0 : scope.linkSymbolTable();
|
|
1810
|
+
//if the file doesn't have an editor yet, assign one now
|
|
1811
|
+
if (!file.editor) {
|
|
1812
|
+
file.editor = new Editor_1.Editor();
|
|
989
1813
|
}
|
|
990
|
-
|
|
1814
|
+
const event = {
|
|
1815
|
+
program: this,
|
|
1816
|
+
file: file,
|
|
1817
|
+
editor: file.editor,
|
|
1818
|
+
scope: scope,
|
|
1819
|
+
outputPath: this.getOutputPath(file, outDir)
|
|
1820
|
+
};
|
|
1821
|
+
await this.plugins.emitAsync('beforePrepareFile', event);
|
|
1822
|
+
await this.plugins.emitAsync('prepareFile', event);
|
|
1823
|
+
await this.plugins.emitAsync('afterPrepareFile', event);
|
|
1824
|
+
//TODO remove this in v1
|
|
1825
|
+
entries.push(event);
|
|
1826
|
+
//unlink the symbolTable so the next loop iteration can link theirs
|
|
1827
|
+
scope === null || scope === void 0 ? void 0 : scope.unlinkSymbolTable();
|
|
991
1828
|
}
|
|
992
|
-
|
|
1829
|
+
await this.plugins.emitAsync('afterPrepareProgram', programEvent);
|
|
1830
|
+
return files;
|
|
993
1831
|
}
|
|
994
1832
|
/**
|
|
995
|
-
*
|
|
1833
|
+
* Generate the contents of every file
|
|
996
1834
|
*/
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
if (
|
|
1001
|
-
|
|
1835
|
+
async serialize(files) {
|
|
1836
|
+
const allFiles = new Map();
|
|
1837
|
+
//exclude prunable files if that option is enabled
|
|
1838
|
+
if (this.options.pruneEmptyCodeFiles === true) {
|
|
1839
|
+
files = files.filter(x => x.canBePruned !== true);
|
|
1002
1840
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
for (const key in this.files) {
|
|
1018
|
-
const file = this.files[key];
|
|
1019
|
-
if (
|
|
1020
|
-
//is a BrightScript or BrighterScript file
|
|
1021
|
-
(file.extension === '.bs' || file.extension === '.brs') &&
|
|
1022
|
-
//this file is not the current file
|
|
1023
|
-
lowerSourcePkgPath !== file.pkgPath.toLowerCase()) {
|
|
1024
|
-
//add the relative path
|
|
1025
|
-
let relativePath = util_1.util.getRelativePath(sourcePkgPath, file.pkgPath).replace(/\\/g, '/');
|
|
1026
|
-
const lowerPkgPath = file.pkgPath.toLowerCase();
|
|
1027
|
-
if (!resultPkgPaths[lowerPkgPath]) {
|
|
1028
|
-
resultPkgPaths[lowerPkgPath] = true;
|
|
1029
|
-
result.push({
|
|
1030
|
-
label: relativePath,
|
|
1031
|
-
detail: file.srcPath,
|
|
1032
|
-
kind: vscode_languageserver_1.CompletionItemKind.File,
|
|
1033
|
-
textEdit: {
|
|
1034
|
-
newText: relativePath,
|
|
1035
|
-
range: scriptImport.filePathRange
|
|
1036
|
-
}
|
|
1037
|
-
});
|
|
1038
|
-
//add the absolute path
|
|
1039
|
-
result.push({
|
|
1040
|
-
label: file.pkgPath,
|
|
1041
|
-
detail: file.srcPath,
|
|
1042
|
-
kind: vscode_languageserver_1.CompletionItemKind.File,
|
|
1043
|
-
textEdit: {
|
|
1044
|
-
newText: file.pkgPath,
|
|
1045
|
-
range: scriptImport.filePathRange
|
|
1046
|
-
}
|
|
1047
|
-
});
|
|
1048
|
-
}
|
|
1841
|
+
const serializeProgramEvent = await this.plugins.emitAsync('beforeSerializeProgram', {
|
|
1842
|
+
program: this,
|
|
1843
|
+
files: files,
|
|
1844
|
+
result: allFiles
|
|
1845
|
+
});
|
|
1846
|
+
await this.plugins.emitAsync('serializeProgram', serializeProgramEvent);
|
|
1847
|
+
// serialize each file
|
|
1848
|
+
for (const file of files) {
|
|
1849
|
+
let scope = this.getFirstScopeForFile(file);
|
|
1850
|
+
//if the file doesn't have a scope, create a temporary scope for the file so it can depend on scope-level items
|
|
1851
|
+
if (!scope) {
|
|
1852
|
+
scope = new Scope_1.Scope(`temporary-for-${file.pkgPath}`, this);
|
|
1853
|
+
scope.getAllFiles = () => [file];
|
|
1854
|
+
scope.getOwnFiles = scope.getAllFiles;
|
|
1049
1855
|
}
|
|
1856
|
+
//link the symbol table for all the files in this scope
|
|
1857
|
+
scope === null || scope === void 0 ? void 0 : scope.linkSymbolTable();
|
|
1858
|
+
const event = {
|
|
1859
|
+
program: this,
|
|
1860
|
+
file: file,
|
|
1861
|
+
scope: scope,
|
|
1862
|
+
result: allFiles
|
|
1863
|
+
};
|
|
1864
|
+
await this.plugins.emitAsync('beforeSerializeFile', event);
|
|
1865
|
+
await this.plugins.emitAsync('serializeFile', event);
|
|
1866
|
+
await this.plugins.emitAsync('afterSerializeFile', event);
|
|
1867
|
+
//unlink the symbolTable so the next loop iteration can link theirs
|
|
1868
|
+
scope === null || scope === void 0 ? void 0 : scope.unlinkSymbolTable();
|
|
1050
1869
|
}
|
|
1051
|
-
|
|
1870
|
+
this.plugins.emit('afterSerializeProgram', serializeProgramEvent);
|
|
1871
|
+
return allFiles;
|
|
1052
1872
|
}
|
|
1053
1873
|
/**
|
|
1054
|
-
*
|
|
1055
|
-
* This does not write anything to the file system.
|
|
1056
|
-
* @param srcPath The absolute path to the source file on disk
|
|
1874
|
+
* Write the entire project to disk
|
|
1057
1875
|
*/
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
let result = file.transpile();
|
|
1061
|
-
return Object.assign(Object.assign({}, result), { srcPath: file.srcPath, pkgPath: file.pkgPath });
|
|
1062
|
-
}
|
|
1063
|
-
async transpile(fileEntries, stagingFolderPath) {
|
|
1064
|
-
// map fileEntries using their path as key to avoid excessive "find()" operations
|
|
1065
|
-
const mappedFileEntries = fileEntries.reduce((collection, entry) => {
|
|
1066
|
-
collection[util_1.standardizePath `${entry.src}`] = entry;
|
|
1067
|
-
return collection;
|
|
1068
|
-
}, {});
|
|
1069
|
-
const entries = [];
|
|
1070
|
-
for (const key in this.files) {
|
|
1071
|
-
const file = this.files[key];
|
|
1072
|
-
let filePathObj = mappedFileEntries[util_1.standardizePath `${file.srcPath}`];
|
|
1073
|
-
if (!filePathObj) {
|
|
1074
|
-
//this file has been added in-memory, from a plugin, for example
|
|
1075
|
-
filePathObj = {
|
|
1076
|
-
//add an interpolated src path (since it doesn't actually exist in memory)
|
|
1077
|
-
src: `bsc-in-memory:/${util_1.util.removeProtocol(file.pkgPath)}`,
|
|
1078
|
-
dest: file.pkgPath
|
|
1079
|
-
};
|
|
1080
|
-
}
|
|
1081
|
-
//prep the output path
|
|
1082
|
-
let outputPath = filePathObj.dest
|
|
1083
|
-
//replace any leading protocol
|
|
1084
|
-
.replace(/^[-a-z_]+:\//, '')
|
|
1085
|
-
//change any .bs file extension to .brs
|
|
1086
|
-
.replace(/\.bs$/gi, '.brs');
|
|
1087
|
-
//prepend the staging folder path
|
|
1088
|
-
outputPath = util_1.standardizePath `${stagingFolderPath}/${outputPath}`;
|
|
1089
|
-
entries.push({
|
|
1090
|
-
file: file,
|
|
1091
|
-
outputPath: outputPath
|
|
1092
|
-
});
|
|
1093
|
-
}
|
|
1094
|
-
this.plugins.emit('beforeProgramTranspile', {
|
|
1876
|
+
async write(outDir, files) {
|
|
1877
|
+
const programEvent = await this.plugins.emitAsync('beforeWriteProgram', {
|
|
1095
1878
|
program: this,
|
|
1096
|
-
|
|
1879
|
+
files: files,
|
|
1880
|
+
outDir: outDir
|
|
1097
1881
|
});
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1882
|
+
//empty the out directory
|
|
1883
|
+
await fsExtra.emptyDir(outDir);
|
|
1884
|
+
const serializedFiles = [...files]
|
|
1885
|
+
.map(([, serializedFiles]) => serializedFiles)
|
|
1886
|
+
.flat();
|
|
1887
|
+
//write all the files to disk (asynchronously)
|
|
1888
|
+
await Promise.all(serializedFiles.map(async (file) => {
|
|
1889
|
+
const event = await this.plugins.emitAsync('beforeWriteFile', {
|
|
1104
1890
|
program: this,
|
|
1105
|
-
file:
|
|
1106
|
-
outputPath:
|
|
1891
|
+
file: file,
|
|
1892
|
+
outputPath: this.getOutputPath(file, outDir),
|
|
1893
|
+
processedFiles: new Set()
|
|
1107
1894
|
});
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
await fsExtra.writeFile(typedefPath, typedef);
|
|
1124
|
-
}
|
|
1125
|
-
this.plugins.emit('afterFileTranspile', {
|
|
1895
|
+
await this.plugins.emitAsync('writeFile', event);
|
|
1896
|
+
await this.plugins.emitAsync('afterWriteFile', event);
|
|
1897
|
+
}));
|
|
1898
|
+
await this.plugins.emitAsync('afterWriteProgram', programEvent);
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* Build the project. This transpiles/transforms/copies all files and moves them to the staging directory
|
|
1902
|
+
* @param options the list of options used to build the program
|
|
1903
|
+
*/
|
|
1904
|
+
async build(options) {
|
|
1905
|
+
//run a single build at a time
|
|
1906
|
+
await this.buildPipeline.run(async () => {
|
|
1907
|
+
var _a;
|
|
1908
|
+
const outDir = this.getOutDir(options === null || options === void 0 ? void 0 : options.outDir);
|
|
1909
|
+
const event = await this.plugins.emitAsync('beforeBuildProgram', {
|
|
1126
1910
|
program: this,
|
|
1127
|
-
|
|
1128
|
-
|
|
1911
|
+
editor: this.editor,
|
|
1912
|
+
files: (_a = options === null || options === void 0 ? void 0 : options.files) !== null && _a !== void 0 ? _a : Object.values(this.files)
|
|
1129
1913
|
});
|
|
1914
|
+
//prepare the program (and files) for building
|
|
1915
|
+
event.files = await this.prepare(event.files);
|
|
1916
|
+
//stage the entire program
|
|
1917
|
+
const serializedFilesByFile = await this.serialize(event.files);
|
|
1918
|
+
await this.write(outDir, serializedFilesByFile);
|
|
1919
|
+
await this.plugins.emitAsync('afterBuildProgram', event);
|
|
1920
|
+
//undo all edits for the program
|
|
1921
|
+
this.editor.undoAll();
|
|
1922
|
+
//undo all edits for each file
|
|
1923
|
+
for (const file of event.files) {
|
|
1924
|
+
file.editor.undoAll();
|
|
1925
|
+
}
|
|
1130
1926
|
});
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1927
|
+
this.logger.debug('Types Created', helpers_1.TypesCreated);
|
|
1928
|
+
let totalTypesCreated = 0;
|
|
1929
|
+
for (const key in helpers_1.TypesCreated) {
|
|
1930
|
+
if (helpers_1.TypesCreated.hasOwnProperty(key)) {
|
|
1931
|
+
totalTypesCreated += helpers_1.TypesCreated[key];
|
|
1932
|
+
}
|
|
1134
1933
|
}
|
|
1135
|
-
|
|
1136
|
-
this.plugins.emit('afterProgramTranspile', {
|
|
1137
|
-
program: this,
|
|
1138
|
-
entries: entries
|
|
1139
|
-
});
|
|
1934
|
+
this.logger.info('Total Types Created', totalTypesCreated);
|
|
1140
1935
|
}
|
|
1141
1936
|
/**
|
|
1142
1937
|
* Find a list of files in the program that have a function with the given name (case INsensitive)
|
|
@@ -1146,10 +1941,11 @@ class Program {
|
|
|
1146
1941
|
const lowerFunctionName = functionName.toLowerCase();
|
|
1147
1942
|
//find every file with this function defined
|
|
1148
1943
|
for (const file of Object.values(this.files)) {
|
|
1149
|
-
if (reflection_1.isBrsFile(file)) {
|
|
1944
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1150
1945
|
//TODO handle namespace-relative function calls
|
|
1151
1946
|
//if the file has a function with this name
|
|
1152
|
-
|
|
1947
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1948
|
+
if (file['_cachedLookups'].functionStatementMap.get(lowerFunctionName)) {
|
|
1153
1949
|
files.push(file);
|
|
1154
1950
|
}
|
|
1155
1951
|
}
|
|
@@ -1157,55 +1953,146 @@ class Program {
|
|
|
1157
1953
|
return files;
|
|
1158
1954
|
}
|
|
1159
1955
|
/**
|
|
1160
|
-
* Find a list of files in the program that have a
|
|
1956
|
+
* Find a list of files in the program that have a class with the given name (case INsensitive)
|
|
1161
1957
|
*/
|
|
1162
1958
|
findFilesForClass(className) {
|
|
1163
1959
|
const files = [];
|
|
1164
1960
|
const lowerClassName = className.toLowerCase();
|
|
1165
1961
|
//find every file with this class defined
|
|
1166
1962
|
for (const file of Object.values(this.files)) {
|
|
1167
|
-
if (reflection_1.isBrsFile(file)) {
|
|
1963
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1168
1964
|
//TODO handle namespace-relative classes
|
|
1169
1965
|
//if the file has a function with this name
|
|
1170
|
-
|
|
1966
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1967
|
+
if (file['_cachedLookups'].classStatementMap.get(lowerClassName) !== undefined) {
|
|
1968
|
+
files.push(file);
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
return files;
|
|
1973
|
+
}
|
|
1974
|
+
findFilesForNamespace(name) {
|
|
1975
|
+
const files = [];
|
|
1976
|
+
const lowerName = name.toLowerCase();
|
|
1977
|
+
//find every file with this class defined
|
|
1978
|
+
for (const file of Object.values(this.files)) {
|
|
1979
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1980
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1981
|
+
if (file['_cachedLookups'].namespaceStatements.find((x) => {
|
|
1982
|
+
const namespaceName = x.name.toLowerCase();
|
|
1983
|
+
return (
|
|
1984
|
+
//the namespace name matches exactly
|
|
1985
|
+
namespaceName === lowerName ||
|
|
1986
|
+
//the full namespace starts with the name (honoring the part boundary)
|
|
1987
|
+
namespaceName.startsWith(lowerName + '.'));
|
|
1988
|
+
})) {
|
|
1989
|
+
files.push(file);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
return files;
|
|
1994
|
+
}
|
|
1995
|
+
findFilesForEnum(name) {
|
|
1996
|
+
const files = [];
|
|
1997
|
+
const lowerName = name.toLowerCase();
|
|
1998
|
+
//find every file with this enum defined
|
|
1999
|
+
for (const file of Object.values(this.files)) {
|
|
2000
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
2001
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
2002
|
+
if (file['_cachedLookups'].enumStatementMap.get(lowerName)) {
|
|
1171
2003
|
files.push(file);
|
|
1172
2004
|
}
|
|
1173
2005
|
}
|
|
1174
2006
|
}
|
|
1175
2007
|
return files;
|
|
1176
2008
|
}
|
|
2009
|
+
/**
|
|
2010
|
+
* Modify a parsed manifest map by reading `bs_const` and injecting values from `options.manifest.bs_const`
|
|
2011
|
+
* @param parsedManifest The manifest map to read from and modify
|
|
2012
|
+
*/
|
|
2013
|
+
buildBsConstsIntoParsedManifest(parsedManifest) {
|
|
2014
|
+
var _a, _b;
|
|
2015
|
+
// Lift the bs_consts defined in the manifest
|
|
2016
|
+
let bsConsts = (0, Manifest_1.getBsConst)(parsedManifest, false);
|
|
2017
|
+
// Override or delete any bs_consts defined in the bs config
|
|
2018
|
+
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) {
|
|
2019
|
+
const value = this.options.manifest.bs_const[key];
|
|
2020
|
+
if (value === null) {
|
|
2021
|
+
bsConsts.delete(key);
|
|
2022
|
+
}
|
|
2023
|
+
else {
|
|
2024
|
+
bsConsts.set(key, value);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
// convert the new list of bs consts back into a string for the rest of the down stream systems to use
|
|
2028
|
+
let constString = '';
|
|
2029
|
+
for (const [key, value] of bsConsts) {
|
|
2030
|
+
constString += `${constString !== '' ? ';' : ''}${key}=${value.toString()}`;
|
|
2031
|
+
}
|
|
2032
|
+
// Set the updated bs_const value
|
|
2033
|
+
parsedManifest.set('bs_const', constString);
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Try to find and load the manifest into memory
|
|
2037
|
+
* @param manifestFileObj A pointer to a potential manifest file object found during loading
|
|
2038
|
+
* @param replaceIfAlreadyLoaded should we overwrite the internal `_manifest` if it already exists
|
|
2039
|
+
*/
|
|
2040
|
+
loadManifest(manifestFileObj, replaceIfAlreadyLoaded = true) {
|
|
2041
|
+
//if we already have a manifest instance, and should not replace...then don't replace
|
|
2042
|
+
if (!replaceIfAlreadyLoaded && this._manifest) {
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
let manifestPath = manifestFileObj
|
|
2046
|
+
? manifestFileObj.src
|
|
2047
|
+
: path.join(this.options.rootDir, 'manifest');
|
|
2048
|
+
//store the resolved manifest path so it can be used externally for change detection
|
|
2049
|
+
this.manifestPath = util_1.util.standardizePath(manifestPath);
|
|
2050
|
+
try {
|
|
2051
|
+
// we only load this manifest once, so do it sync to improve speed downstream
|
|
2052
|
+
const contents = fsExtra.readFileSync(manifestPath, 'utf-8');
|
|
2053
|
+
const parsedManifest = (0, Manifest_1.parseManifest)(contents);
|
|
2054
|
+
this.buildBsConstsIntoParsedManifest(parsedManifest);
|
|
2055
|
+
this._manifest = parsedManifest;
|
|
2056
|
+
}
|
|
2057
|
+
catch (e) {
|
|
2058
|
+
this._manifest = new Map();
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
1177
2061
|
/**
|
|
1178
2062
|
* Get a map of the manifest information
|
|
1179
2063
|
*/
|
|
1180
2064
|
getManifest() {
|
|
1181
2065
|
if (!this._manifest) {
|
|
1182
|
-
|
|
1183
|
-
//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
|
|
1184
|
-
let manifestPath = path.join(this.options.rootDir, 'manifest');
|
|
1185
|
-
let contents;
|
|
1186
|
-
try {
|
|
1187
|
-
//we only load this manifest once, so do it sync to improve speed downstream
|
|
1188
|
-
contents = fsExtra.readFileSync(manifestPath, 'utf-8');
|
|
1189
|
-
this._manifest = Manifest_1.parseManifest(contents);
|
|
1190
|
-
}
|
|
1191
|
-
catch (err) {
|
|
1192
|
-
this._manifest = new Map();
|
|
1193
|
-
}
|
|
2066
|
+
this.loadManifest();
|
|
1194
2067
|
}
|
|
1195
2068
|
return this._manifest;
|
|
1196
2069
|
}
|
|
1197
2070
|
dispose() {
|
|
1198
|
-
var _a, _b;
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
(_a =
|
|
2071
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2072
|
+
this.plugins.emit('beforeRemoveProgram', { program: this });
|
|
2073
|
+
for (let filePath in this.files) {
|
|
2074
|
+
(_b = (_a = this.files[filePath]) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1202
2075
|
}
|
|
1203
2076
|
for (let name in this.scopes) {
|
|
1204
|
-
(
|
|
2077
|
+
(_d = (_c = this.scopes[name]) === null || _c === void 0 ? void 0 : _c.dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
1205
2078
|
}
|
|
1206
|
-
this.globalScope.dispose();
|
|
1207
|
-
this.dependencyGraph.dispose();
|
|
2079
|
+
(_f = (_e = this.globalScope) === null || _e === void 0 ? void 0 : _e.dispose) === null || _f === void 0 ? void 0 : _f.call(_e);
|
|
2080
|
+
(_h = (_g = this.dependencyGraph) === null || _g === void 0 ? void 0 : _g.dispose) === null || _h === void 0 ? void 0 : _h.call(_g);
|
|
2081
|
+
this.plugins.emit('removeProgram', { program: this });
|
|
2082
|
+
this.plugins.emit('afterRemoveProgram', { program: this });
|
|
1208
2083
|
}
|
|
1209
2084
|
}
|
|
1210
2085
|
exports.Program = Program;
|
|
2086
|
+
class ProvideFileEventInternal {
|
|
2087
|
+
constructor(program, srcPath, destPath, data, fileFactory) {
|
|
2088
|
+
var _a;
|
|
2089
|
+
this.program = program;
|
|
2090
|
+
this.srcPath = srcPath;
|
|
2091
|
+
this.destPath = destPath;
|
|
2092
|
+
this.data = data;
|
|
2093
|
+
this.fileFactory = fileFactory;
|
|
2094
|
+
this.files = [];
|
|
2095
|
+
this.srcExtension = (_a = path.extname(srcPath)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
1211
2098
|
//# sourceMappingURL=Program.js.map
|