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