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