brighterscript 1.0.0-alpha.24 → 1.0.0-alpha.26
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 +521 -233
- package/README.md +45 -139
- package/bsconfig.schema.json +46 -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 +40 -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 +61 -13
- package/dist/DiagnosticMessages.js +116 -19
- 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 +150 -69
- 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 +158 -79
- package/dist/Program.js +841 -706
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +22 -12
- package/dist/ProgramBuilder.js +130 -103
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +86 -137
- package/dist/Scope.js +453 -519
- 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 +89 -34
- package/dist/SymbolTable.js +239 -114
- 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 -11
- package/dist/XmlScope.js +75 -88
- 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} +69 -65
- package/dist/astUtils/Editor.spec.js.map +1 -0
- package/dist/astUtils/creators.d.ts +10 -10
- package/dist/astUtils/creators.js +54 -24
- 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 -104
- package/dist/astUtils/reflection.js +220 -174
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +256 -157
- 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 +53 -35
- package/dist/astUtils/visitors.js +29 -3
- package/dist/astUtils/visitors.js.map +1 -1
- package/dist/astUtils/visitors.spec.js +208 -52
- 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 +11 -2
- package/dist/bscPlugin/BscPlugin.js +37 -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 +136 -0
- package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +16 -13
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +16 -16
- package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +52 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.js +517 -26
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
- package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
- package/dist/bscPlugin/definition/DefinitionProvider.js +210 -0
- package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
- package/dist/bscPlugin/definition/DefinitionProvider.spec.js +88 -0
- package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
- package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
- package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
- package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
- package/dist/bscPlugin/hover/HoverProcessor.d.ts +7 -7
- package/dist/bscPlugin/hover/HoverProcessor.js +123 -125
- package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
- package/dist/bscPlugin/hover/HoverProcessor.spec.js +371 -53
- package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +2 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +83 -23
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
- package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +83 -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/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
- package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +38 -12
- 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 +13 -5
- package/dist/bscPlugin/validation/BrsFileValidator.js +262 -52
- package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js +230 -14
- package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
- 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 +58 -27
- package/dist/bscPlugin/validation/ScopeValidator.js +514 -286
- 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 +2527 -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 +104 -13
- 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 +523 -493
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +111 -117
- package/dist/files/BrsFile.js +684 -1142
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +1783 -1233
- 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 -118
- 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 +48 -40
- package/dist/files/tests/imports.spec.js.map +1 -1
- package/dist/files/tests/optionalChaning.spec.js +84 -24
- package/dist/files/tests/optionalChaning.spec.js.map +1 -1
- package/dist/globalCallables.js +16 -21
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +421 -162
- 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 +181 -135
- 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 +8 -0
- package/dist/lexer/TokenKind.js +24 -4
- 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 +376 -283
- package/dist/parser/Expression.js +742 -585
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.Class.spec.js +151 -145
- package/dist/parser/Parser.Class.spec.js.map +1 -1
- package/dist/parser/Parser.d.ts +48 -201
- package/dist/parser/Parser.js +705 -1026
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.d.ts +3 -1
- package/dist/parser/Parser.spec.js +861 -848
- 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 +468 -272
- package/dist/parser/Statement.js +904 -631
- package/dist/parser/Statement.js.map +1 -1
- package/dist/parser/Statement.spec.js +47 -23
- 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 +62 -21
- 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 +92 -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 +59 -59
- 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 +96 -57
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +89 -89
- 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.js +82 -33
- package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
- 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 +98 -302
- 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 +36 -34
- 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 +2 -2
- 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 +5 -5
- 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 +5892 -10081
- package/dist/roku-types/index.d.ts +622 -1719
- 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 +171 -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 +9 -5
- package/dist/types/DynamicType.js +15 -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 +143 -139
- package/dist/util.js +864 -385
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.d.ts +8 -25
- package/dist/validators/ClassValidator.js +99 -179
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +165 -152
- package/dist/astUtils/AstEditor.js.map +0 -1
- package/dist/astUtils/AstEditor.spec.js.map +0 -1
- 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/definition/DefinitionProvider.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
|
+
this.logger.error(error, nodeData);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
nodeType = new ComponentType_1.ComponentType(nodeData.name, parentNode);
|
|
149
|
+
nodeType.addBuiltInInterfaces();
|
|
150
|
+
if (nodeData.name === 'Node') {
|
|
151
|
+
// Add `roSGNode` as shorthand for `roSGNodeNode`
|
|
152
|
+
this.globalScope.symbolTable.addSymbol('roSGNode', { description: nodeData.description }, nodeType, 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 ifaceData of Object.values(roku_types_1.interfaces)) {
|
|
181
|
+
const nodeType = new types_1.InterfaceType(ifaceData.name);
|
|
182
|
+
nodeType.addBuiltInInterfaces();
|
|
183
|
+
this.globalScope.symbolTable.addSymbol(ifaceData.name, { description: ifaceData.description }, nodeType, SymbolTable_1.SymbolTypeFlag.typetime);
|
|
184
|
+
}
|
|
185
|
+
for (const nodeData of Object.values(roku_types_1.nodes)) {
|
|
186
|
+
this.recursivelyAddNodeToSymbolTable(nodeData);
|
|
187
|
+
}
|
|
188
|
+
for (const componentData of Object.values(roku_types_1.components)) {
|
|
189
|
+
const nodeType = new types_1.InterfaceType(componentData.name);
|
|
190
|
+
nodeType.addBuiltInInterfaces();
|
|
191
|
+
if (componentData.name !== 'roSGNode') {
|
|
192
|
+
// we will add `roSGNode` as shorthand for `roSGNodeNode`, since all roSgNode components are SceneGraph nodes
|
|
193
|
+
this.globalScope.symbolTable.addSymbol(componentData.name, { description: componentData.description }, nodeType, SymbolTable_1.SymbolTypeFlag.typetime);
|
|
194
|
+
}
|
|
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
|
}
|
|
@@ -151,8 +263,8 @@ class Program {
|
|
|
151
263
|
scope: scope
|
|
152
264
|
});
|
|
153
265
|
this.components[key].sort((a, b) => {
|
|
154
|
-
const pathA = a.file.
|
|
155
|
-
const pathB = b.file.
|
|
266
|
+
const pathA = a.file.destPath.toLowerCase();
|
|
267
|
+
const pathB = b.file.destPath.toLowerCase();
|
|
156
268
|
if (pathA < pathB) {
|
|
157
269
|
return -1;
|
|
158
270
|
}
|
|
@@ -162,13 +274,13 @@ class Program {
|
|
|
162
274
|
return 0;
|
|
163
275
|
});
|
|
164
276
|
this.syncComponentDependencyGraph(this.components[key]);
|
|
277
|
+
this.addDeferredComponentTypeSymbolCreation(xmlFile);
|
|
165
278
|
}
|
|
166
279
|
/**
|
|
167
280
|
* Remove the specified component from the components map
|
|
168
281
|
*/
|
|
169
282
|
unregisterComponent(xmlFile) {
|
|
170
|
-
|
|
171
|
-
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);
|
|
172
284
|
const arr = this.components[key] || [];
|
|
173
285
|
for (let i = 0; i < arr.length; i++) {
|
|
174
286
|
if (arr[i].file === xmlFile) {
|
|
@@ -177,6 +289,44 @@ class Program {
|
|
|
177
289
|
}
|
|
178
290
|
}
|
|
179
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
|
+
}
|
|
180
330
|
}
|
|
181
331
|
/**
|
|
182
332
|
* re-attach the dependency graph with a new key for any component who changed
|
|
@@ -190,6 +340,7 @@ class Program {
|
|
|
190
340
|
//attach (or re-attach) the dependencyGraph for every component whose position changed
|
|
191
341
|
if (file.dependencyGraphIndex !== i) {
|
|
192
342
|
file.dependencyGraphIndex = i;
|
|
343
|
+
this.dependencyGraph.addOrReplace(file.dependencyGraphKey, file.dependencies);
|
|
193
344
|
file.attachDependencyGraph(this.dependencyGraph);
|
|
194
345
|
scope.attachDependencyGraph(this.dependencyGraph);
|
|
195
346
|
}
|
|
@@ -201,9 +352,10 @@ class Program {
|
|
|
201
352
|
*/
|
|
202
353
|
getUnreferencedFiles() {
|
|
203
354
|
let result = [];
|
|
204
|
-
for (let
|
|
205
|
-
|
|
206
|
-
|
|
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)) {
|
|
207
359
|
//no scopes reference this file. add it to the list
|
|
208
360
|
result.push(file);
|
|
209
361
|
}
|
|
@@ -225,13 +377,16 @@ class Program {
|
|
|
225
377
|
//get the diagnostics from all unreferenced files
|
|
226
378
|
let unreferencedFiles = this.getUnreferencedFiles();
|
|
227
379
|
for (let file of unreferencedFiles) {
|
|
228
|
-
diagnostics.push(...file.
|
|
380
|
+
diagnostics.push(...file.diagnostics);
|
|
229
381
|
}
|
|
230
382
|
const filteredDiagnostics = this.logger.time(Logger_1.LogLevel.debug, ['filter diagnostics'], () => {
|
|
231
383
|
//filter out diagnostics based on our diagnostic filters
|
|
232
384
|
let finalDiagnostics = this.diagnosticFilterer.filter(Object.assign(Object.assign({}, this.options), { rootDir: this.options.rootDir }), diagnostics);
|
|
233
385
|
return finalDiagnostics;
|
|
234
386
|
});
|
|
387
|
+
this.logger.time(Logger_1.LogLevel.debug, ['adjust diagnostics severity'], () => {
|
|
388
|
+
this.diagnosticAdjuster.adjust(this.options, diagnostics);
|
|
389
|
+
});
|
|
235
390
|
this.logger.info(`diagnostic counts: total=${chalk_1.default.yellow(diagnostics.length.toString())}, after filter=${chalk_1.default.yellow(filteredDiagnostics.length.toString())}`);
|
|
236
391
|
return filteredDiagnostics;
|
|
237
392
|
});
|
|
@@ -241,7 +396,7 @@ class Program {
|
|
|
241
396
|
}
|
|
242
397
|
/**
|
|
243
398
|
* Determine if the specified file is loaded in this program right now.
|
|
244
|
-
* @param filePath
|
|
399
|
+
* @param filePath the absolute or relative path to the file
|
|
245
400
|
* @param normalizePath should the provided path be normalized before use
|
|
246
401
|
*/
|
|
247
402
|
hasFile(filePath, normalizePath = true) {
|
|
@@ -249,12 +404,15 @@ class Program {
|
|
|
249
404
|
}
|
|
250
405
|
/**
|
|
251
406
|
* roku filesystem is case INsensitive, so find the scope by key case insensitive
|
|
252
|
-
* @param scopeName
|
|
407
|
+
* @param scopeName xml scope names are their `destPath`. Source scope is stored with the key `"source"`
|
|
253
408
|
*/
|
|
254
409
|
getScopeByName(scopeName) {
|
|
255
410
|
if (!scopeName) {
|
|
256
411
|
return undefined;
|
|
257
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}`;
|
|
258
416
|
let key = Object.keys(this.scopes).find(x => x.toLowerCase() === scopeName.toLowerCase());
|
|
259
417
|
return this.scopes[key];
|
|
260
418
|
}
|
|
@@ -275,8 +433,14 @@ class Program {
|
|
|
275
433
|
* Update internal maps with this file reference
|
|
276
434
|
*/
|
|
277
435
|
assignFile(file) {
|
|
436
|
+
const fileAddEvent = {
|
|
437
|
+
file: file,
|
|
438
|
+
program: this
|
|
439
|
+
};
|
|
440
|
+
this.plugins.emit('beforeFileAdd', fileAddEvent);
|
|
278
441
|
this.files[file.srcPath.toLowerCase()] = file;
|
|
279
|
-
this.
|
|
442
|
+
this.destMap.set(file.destPath.toLowerCase(), file);
|
|
443
|
+
this.plugins.emit('afterFileAdd', fileAddEvent);
|
|
280
444
|
return file;
|
|
281
445
|
}
|
|
282
446
|
/**
|
|
@@ -284,108 +448,155 @@ class Program {
|
|
|
284
448
|
*/
|
|
285
449
|
unassignFile(file) {
|
|
286
450
|
delete this.files[file.srcPath.toLowerCase()];
|
|
287
|
-
|
|
451
|
+
this.destMap.delete(file.destPath.toLowerCase());
|
|
288
452
|
return file;
|
|
289
453
|
}
|
|
290
|
-
setFile(fileParam,
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
let
|
|
294
|
-
|
|
295
|
-
//is
|
|
296
|
-
if (
|
|
297
|
-
|
|
298
|
-
srcPath = (0, util_1.standardizePath) `${this.options.rootDir}/${fileParam.substring(5)}`;
|
|
299
|
-
pkgPath = fileParam;
|
|
300
|
-
//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);
|
|
301
462
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
+
}));
|
|
307
476
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
+
})))}`);
|
|
311
485
|
}
|
|
312
|
-
//
|
|
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
|
+
}
|
|
528
|
+
}
|
|
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, '')}`;
|
|
313
547
|
}
|
|
314
548
|
else {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const lowerPkgPath = pkgPath.toLowerCase();
|
|
319
|
-
return this.logger.time(Logger_1.LogLevel.debug, ['Program.setFile()', chalk_1.default.green(srcPath)], () => {
|
|
320
|
-
assert.ok(srcPath, 'srcPath is required');
|
|
321
|
-
assert.ok(pkgPath, 'pkgPath is required');
|
|
322
|
-
//if the file is already loaded, remove it
|
|
323
|
-
if (this.hasFile(srcPath)) {
|
|
324
|
-
this.removeFile(srcPath);
|
|
549
|
+
let param = fileParam;
|
|
550
|
+
if (param.src) {
|
|
551
|
+
srcPath = (0, util_1.standardizePath) `${param.src}`;
|
|
325
552
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const beforeFileParseEvent = {
|
|
329
|
-
program: this,
|
|
330
|
-
srcPath: srcPath,
|
|
331
|
-
source: fileContents
|
|
332
|
-
};
|
|
333
|
-
if (fileExtension === '.brs' || fileExtension === '.bs') {
|
|
334
|
-
//add the file to the program
|
|
335
|
-
const brsFile = this.assignFile(new BrsFile_1.BrsFile(srcPath, pkgPath, this));
|
|
336
|
-
//add file to the `source` dependency list
|
|
337
|
-
if (brsFile.pkgPath.startsWith('pkg:/source/')) {
|
|
338
|
-
this.createSourceScope();
|
|
339
|
-
this.dependencyGraph.addDependency('scope:source', brsFile.dependencyGraphKey);
|
|
340
|
-
}
|
|
341
|
-
//add the file to the program
|
|
342
|
-
this.assignFile(brsFile);
|
|
343
|
-
this.plugins.emit('beforeFileParse', beforeFileParseEvent);
|
|
344
|
-
this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
|
|
345
|
-
brsFile.parse(beforeFileParseEvent.source);
|
|
346
|
-
});
|
|
347
|
-
//notify plugins that this file has finished parsing
|
|
348
|
-
this.plugins.emit('afterFileParse', {
|
|
349
|
-
program: this,
|
|
350
|
-
file: brsFile
|
|
351
|
-
});
|
|
352
|
-
file = brsFile;
|
|
353
|
-
brsFile.attachDependencyGraph(this.dependencyGraph);
|
|
553
|
+
if (param.srcPath) {
|
|
554
|
+
srcPath = (0, util_1.standardizePath) `${param.srcPath}`;
|
|
354
555
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
fileExtension === '.xml' &&
|
|
358
|
-
//resides in the components folder (Roku will only parse xml files in the components folder)
|
|
359
|
-
lowerPkgPath.startsWith('pkg:/components/')) {
|
|
360
|
-
//add the file to the program
|
|
361
|
-
const xmlFile = this.assignFile(new XmlFile_1.XmlFile(srcPath, pkgPath, this));
|
|
362
|
-
this.plugins.emit('beforeFileParse', beforeFileParseEvent);
|
|
363
|
-
this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
|
|
364
|
-
xmlFile.parse(beforeFileParseEvent.source);
|
|
365
|
-
});
|
|
366
|
-
//notify plugins that this file has finished parsing
|
|
367
|
-
this.plugins.emit('afterFileParse', {
|
|
368
|
-
program: this,
|
|
369
|
-
file: xmlFile
|
|
370
|
-
});
|
|
371
|
-
file = xmlFile;
|
|
372
|
-
//create a new scope for this xml file
|
|
373
|
-
let scope = new XmlScope_1.XmlScope(xmlFile, this);
|
|
374
|
-
this.addScope(scope);
|
|
375
|
-
//register this compoent now that we have parsed it and know its component name
|
|
376
|
-
this.registerComponent(xmlFile, scope);
|
|
556
|
+
if (param.dest) {
|
|
557
|
+
destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.dest)}`;
|
|
377
558
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
// let genericFile = this.files[srcPath] = <any>{
|
|
381
|
-
// srcPath: srcPath,
|
|
382
|
-
// pkgPath: pkgPath,
|
|
383
|
-
// wasProcessed: true
|
|
384
|
-
// } as File;
|
|
385
|
-
// file = <any>genericFile;
|
|
559
|
+
if (param.pkgPath) {
|
|
560
|
+
destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.pkgPath)}`;
|
|
386
561
|
}
|
|
387
|
-
|
|
388
|
-
|
|
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);
|
|
389
600
|
}
|
|
390
601
|
/**
|
|
391
602
|
* Ensure source scope is created.
|
|
@@ -396,11 +607,15 @@ class Program {
|
|
|
396
607
|
const sourceScope = new Scope_1.Scope('source', this, 'scope:source');
|
|
397
608
|
sourceScope.attachDependencyGraph(this.dependencyGraph);
|
|
398
609
|
this.addScope(sourceScope);
|
|
610
|
+
this.plugins.emit('afterScopeCreate', {
|
|
611
|
+
program: this,
|
|
612
|
+
scope: sourceScope
|
|
613
|
+
});
|
|
399
614
|
}
|
|
400
615
|
}
|
|
401
616
|
/**
|
|
402
617
|
* Remove a set of files from the program
|
|
403
|
-
* @param
|
|
618
|
+
* @param srcPaths can be an array of srcPath or destPath strings
|
|
404
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
|
|
405
620
|
*/
|
|
406
621
|
removeFiles(srcPaths, normalizePath = true) {
|
|
@@ -410,69 +625,58 @@ class Program {
|
|
|
410
625
|
}
|
|
411
626
|
/**
|
|
412
627
|
* Remove a file from the program
|
|
413
|
-
* @param filePath can be a srcPath, a
|
|
628
|
+
* @param filePath can be a srcPath, a destPath, or a destPath with leading `pkg:/`
|
|
414
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
|
|
415
630
|
*/
|
|
416
|
-
removeFile(filePath, normalizePath = true) {
|
|
631
|
+
removeFile(filePath, normalizePath = true, keepSymbolInformation = false) {
|
|
632
|
+
var _a, _b, _c, _d;
|
|
417
633
|
this.logger.debug('Program.removeFile()', filePath);
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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);
|
|
424
644
|
//if there is a scope named the same as this file's path, remove it (i.e. xml scopes)
|
|
425
|
-
let scope = this.scopes[file.
|
|
645
|
+
let scope = this.scopes[file.destPath];
|
|
426
646
|
if (scope) {
|
|
427
|
-
|
|
647
|
+
const scopeDisposeEvent = {
|
|
428
648
|
program: this,
|
|
429
649
|
scope: scope
|
|
430
|
-
}
|
|
650
|
+
};
|
|
651
|
+
this.plugins.emit('beforeScopeDispose', scopeDisposeEvent);
|
|
652
|
+
this.plugins.emit('onScopeDispose', scopeDisposeEvent);
|
|
431
653
|
scope.dispose();
|
|
432
654
|
//notify dependencies of this scope that it has been removed
|
|
433
655
|
this.dependencyGraph.remove(scope.dependencyGraphKey);
|
|
434
|
-
delete this.scopes[file.
|
|
435
|
-
this.plugins.emit('afterScopeDispose',
|
|
436
|
-
program: this,
|
|
437
|
-
scope: scope
|
|
438
|
-
});
|
|
656
|
+
delete this.scopes[file.destPath];
|
|
657
|
+
this.plugins.emit('afterScopeDispose', scopeDisposeEvent);
|
|
439
658
|
}
|
|
440
659
|
//remove the file from the program
|
|
441
660
|
this.unassignFile(file);
|
|
442
661
|
this.dependencyGraph.remove(file.dependencyGraphKey);
|
|
443
662
|
//if this is a pkg:/source file, notify the `source` scope that it has changed
|
|
444
|
-
if (
|
|
663
|
+
if (this.isSourceBrsFile(file)) {
|
|
445
664
|
this.dependencyGraph.removeDependency('scope:source', file.dependencyGraphKey);
|
|
665
|
+
if (!keepSymbolInformation) {
|
|
666
|
+
this.fileSymbolInformation.delete(file.pkgPath);
|
|
667
|
+
}
|
|
446
668
|
}
|
|
447
669
|
//if this is a component, remove it from our components map
|
|
448
670
|
if ((0, reflection_1.isXmlFile)(file)) {
|
|
449
671
|
this.unregisterComponent(file);
|
|
450
672
|
}
|
|
451
|
-
//dispose file
|
|
452
|
-
file === null || file === void 0 ? void 0 : file.
|
|
453
|
-
|
|
454
|
-
program: this,
|
|
455
|
-
file: file
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* Remove all files from the program that are in the specified folder path (recursive)
|
|
461
|
-
* @param folderSrcPath The absolute path to the folder on disk
|
|
462
|
-
* @param normalizePath should the provided path be normalized before use?
|
|
463
|
-
*/
|
|
464
|
-
removeFilesInFolder(folderSrcPath, normalizePath = true) {
|
|
465
|
-
if (normalizePath) {
|
|
466
|
-
folderSrcPath = util_1.util.standardizePath(folderSrcPath);
|
|
467
|
-
}
|
|
468
|
-
const lowerFolderSrcPath = folderSrcPath.toLowerCase();
|
|
469
|
-
for (const key in this.files) {
|
|
470
|
-
const file = this.files[key];
|
|
471
|
-
const lowerSrcPath = file.srcPath.toLowerCase();
|
|
472
|
-
//if the file path starts with the parent path and the file path does not exactly match the folder path
|
|
473
|
-
if (lowerSrcPath.toLowerCase().startsWith(lowerFolderSrcPath) && lowerSrcPath !== lowerFolderSrcPath) {
|
|
474
|
-
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();
|
|
475
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);
|
|
476
680
|
}
|
|
477
681
|
}
|
|
478
682
|
/**
|
|
@@ -480,78 +684,157 @@ class Program {
|
|
|
480
684
|
*/
|
|
481
685
|
validate() {
|
|
482
686
|
this.logger.time(Logger_1.LogLevel.log, ['Validating project'], () => {
|
|
483
|
-
var _a;
|
|
687
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
484
688
|
this.diagnostics = [];
|
|
485
|
-
|
|
689
|
+
const programValidateEvent = {
|
|
486
690
|
program: this
|
|
487
|
-
}
|
|
691
|
+
};
|
|
692
|
+
this.plugins.emit('beforeProgramValidate', programValidateEvent);
|
|
693
|
+
this.plugins.emit('onProgramValidate', programValidateEvent);
|
|
488
694
|
//validate every file
|
|
695
|
+
const brsFilesValidated = [];
|
|
489
696
|
for (const file of Object.values(this.files)) {
|
|
490
|
-
//find any files NOT loaded into a scope
|
|
491
|
-
if (!this.fileIsIncludedInAnyScope(file)) {
|
|
492
|
-
this.logger.debug('Program.validate(): fileNotReferenced by any scope', () => chalk_1.default.green(file === null || file === void 0 ? void 0 : file.pkgPath));
|
|
493
|
-
//the file is not loaded in any scope
|
|
494
|
-
this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.fileNotReferencedByAnyOtherFile()), { file: file, range: util_1.util.createRange(0, 0, 0, Number.MAX_VALUE) }));
|
|
495
|
-
}
|
|
496
697
|
//for every unvalidated file, validate it
|
|
497
698
|
if (!file.isValidated) {
|
|
498
|
-
|
|
699
|
+
const validateFileEvent = {
|
|
499
700
|
program: this,
|
|
500
701
|
file: file
|
|
501
|
-
}
|
|
702
|
+
};
|
|
703
|
+
this.plugins.emit('beforeFileValidate', validateFileEvent);
|
|
502
704
|
//emit an event to allow plugins to contribute to the file validation process
|
|
503
|
-
this.plugins.emit('onFileValidate',
|
|
504
|
-
program: this,
|
|
505
|
-
file: file
|
|
506
|
-
});
|
|
507
|
-
//call file.validate() IF the file has that function defined
|
|
508
|
-
(_a = file.validate) === null || _a === void 0 ? void 0 : _a.call(file);
|
|
705
|
+
this.plugins.emit('onFileValidate', validateFileEvent);
|
|
509
706
|
file.isValidated = true;
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
707
|
+
if ((0, reflection_1.isBrsFile)(file)) {
|
|
708
|
+
brsFilesValidated.push(file);
|
|
709
|
+
}
|
|
710
|
+
this.plugins.emit('afterFileValidate', validateFileEvent);
|
|
514
711
|
}
|
|
515
712
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
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
|
+
}
|
|
773
|
+
}
|
|
774
|
+
if (scopesAreInconsistent) {
|
|
775
|
+
fileInfo.symbolsNotConsistentAcrossScopes.push({ symbol: symbol, scopes: scopesDefiningSymbol });
|
|
524
776
|
}
|
|
525
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);
|
|
785
|
+
}
|
|
786
|
+
this.componentSymbolsToUpdate.clear();
|
|
526
787
|
});
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
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
|
+
}
|
|
530
804
|
});
|
|
805
|
+
this.detectDuplicateComponentNames();
|
|
806
|
+
this.plugins.emit('afterProgramValidate', programValidateEvent);
|
|
531
807
|
});
|
|
532
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
|
+
}
|
|
533
819
|
/**
|
|
534
820
|
* Flag all duplicate component names
|
|
535
821
|
*/
|
|
536
822
|
detectDuplicateComponentNames() {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
const file = this.files[key];
|
|
823
|
+
const componentsByName = Object.keys(this.files).reduce((map, filePath) => {
|
|
824
|
+
var _a;
|
|
825
|
+
const file = this.files[filePath];
|
|
541
826
|
//if this is an XmlFile, and it has a valid `componentName` property
|
|
542
|
-
if ((0, reflection_1.isXmlFile)(file)) {
|
|
543
|
-
|
|
544
|
-
if (
|
|
545
|
-
|
|
546
|
-
componentsByName.set(componentNameLower, [file]);
|
|
547
|
-
}
|
|
548
|
-
else {
|
|
549
|
-
componentsByName.get(componentNameLower).push(file);
|
|
550
|
-
}
|
|
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] = [];
|
|
551
831
|
}
|
|
832
|
+
map[lowerName].push(file);
|
|
552
833
|
}
|
|
553
|
-
|
|
554
|
-
|
|
834
|
+
return map;
|
|
835
|
+
}, {});
|
|
836
|
+
for (let name in componentsByName) {
|
|
837
|
+
const xmlFiles = componentsByName[name];
|
|
555
838
|
//add diagnostics for every duplicate component with this name
|
|
556
839
|
if (xmlFiles.length > 1) {
|
|
557
840
|
for (let xmlFile of xmlFiles) {
|
|
@@ -567,17 +850,6 @@ class Program {
|
|
|
567
850
|
}
|
|
568
851
|
}
|
|
569
852
|
}
|
|
570
|
-
/**
|
|
571
|
-
* Determine at least one scope has the file
|
|
572
|
-
*/
|
|
573
|
-
fileIsIncludedInAnyScope(file) {
|
|
574
|
-
for (let scope of Object.values(this.scopes)) {
|
|
575
|
-
if (scope.hasFile(file)) {
|
|
576
|
-
return true;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
return false;
|
|
580
|
-
}
|
|
581
853
|
/**
|
|
582
854
|
* Get the files for a list of filePaths
|
|
583
855
|
* @param filePaths can be an array of srcPath or a destPath strings
|
|
@@ -590,33 +862,32 @@ class Program {
|
|
|
590
862
|
}
|
|
591
863
|
/**
|
|
592
864
|
* Get the file at the given path
|
|
593
|
-
* @param filePath can be a srcPath
|
|
865
|
+
* @param filePath can be a srcPath or a destPath
|
|
594
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
|
|
595
867
|
*/
|
|
596
868
|
getFile(filePath, normalizePath = true) {
|
|
597
869
|
if (typeof filePath !== 'string') {
|
|
598
870
|
return undefined;
|
|
871
|
+
//is the path absolute (or the `virtual:` prefix)
|
|
599
872
|
}
|
|
600
|
-
else if (
|
|
873
|
+
else if (/^(?:(?:virtual:[\/\\])|(?:\w:)|(?:[\/\\]))/gmi.exec(filePath)) {
|
|
601
874
|
return this.files[(normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase()];
|
|
602
875
|
}
|
|
603
876
|
else {
|
|
604
|
-
return this.
|
|
877
|
+
return this.destMap.get((normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase());
|
|
605
878
|
}
|
|
606
879
|
}
|
|
607
880
|
/**
|
|
608
881
|
* Get a list of all scopes the file is loaded into
|
|
609
|
-
* @param file
|
|
882
|
+
* @param file the file
|
|
610
883
|
*/
|
|
611
884
|
getScopesForFile(file) {
|
|
612
|
-
|
|
613
|
-
file = this.getFile(file);
|
|
614
|
-
}
|
|
885
|
+
const resolvedFile = typeof file === 'string' ? this.getFile(file) : file;
|
|
615
886
|
let result = [];
|
|
616
|
-
if (
|
|
887
|
+
if (resolvedFile) {
|
|
617
888
|
for (let key in this.scopes) {
|
|
618
889
|
let scope = this.scopes[key];
|
|
619
|
-
if (scope.hasFile(
|
|
890
|
+
if (scope.hasFile(resolvedFile)) {
|
|
620
891
|
result.push(scope);
|
|
621
892
|
}
|
|
622
893
|
}
|
|
@@ -635,26 +906,37 @@ class Program {
|
|
|
635
906
|
}
|
|
636
907
|
}
|
|
637
908
|
getStatementsByName(name, originFile, namespaceName) {
|
|
638
|
-
var _a, _b;
|
|
639
909
|
let results = new Map();
|
|
640
910
|
const filesSearched = new Set();
|
|
641
911
|
let lowerNamespaceName = namespaceName === null || namespaceName === void 0 ? void 0 : namespaceName.toLowerCase();
|
|
642
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.tokens.name.text.toLowerCase() === lowerName && (!lowerNamespaceName || parentNamespaceName === lowerNamespaceName)) {
|
|
917
|
+
if (!results.has(statement)) {
|
|
918
|
+
results.set(statement, { item: statement, file: file });
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
643
922
|
//look through all files in scope for matches
|
|
644
923
|
for (const scope of this.getScopesForFile(originFile)) {
|
|
645
924
|
for (const file of scope.getAllFiles()) {
|
|
646
|
-
|
|
925
|
+
//skip non-brs files, or files we've already processed
|
|
926
|
+
if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
|
|
647
927
|
continue;
|
|
648
928
|
}
|
|
649
929
|
filesSearched.add(file);
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
930
|
+
file.ast.walk((0, visitors_1.createVisitor)({
|
|
931
|
+
FunctionStatement: (statement) => {
|
|
932
|
+
addToResults(statement, file);
|
|
933
|
+
},
|
|
934
|
+
MethodStatement: (statement) => {
|
|
935
|
+
addToResults(statement, file);
|
|
656
936
|
}
|
|
657
|
-
}
|
|
937
|
+
}), {
|
|
938
|
+
walkMode: visitors_1.WalkMode.visitStatements
|
|
939
|
+
});
|
|
658
940
|
}
|
|
659
941
|
}
|
|
660
942
|
return [...results.values()];
|
|
@@ -667,40 +949,41 @@ class Program {
|
|
|
667
949
|
let funcNames = new Set();
|
|
668
950
|
let currentScope = scope;
|
|
669
951
|
while ((0, reflection_1.isXmlScope)(currentScope)) {
|
|
670
|
-
for (let
|
|
671
|
-
if (
|
|
672
|
-
|
|
673
|
-
if (!filterName || name === filterName) {
|
|
674
|
-
funcNames.add(name);
|
|
675
|
-
}
|
|
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);
|
|
676
955
|
}
|
|
677
956
|
}
|
|
678
957
|
currentScope = currentScope.getParentScope();
|
|
679
958
|
}
|
|
680
959
|
//look through all files in scope for matches
|
|
681
960
|
for (const file of scope.getOwnFiles()) {
|
|
682
|
-
|
|
961
|
+
//skip non-brs files, or files we've already processed
|
|
962
|
+
if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
|
|
683
963
|
continue;
|
|
684
964
|
}
|
|
685
965
|
filesSearched.add(file);
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
if (
|
|
689
|
-
results.
|
|
966
|
+
file.ast.walk((0, visitors_1.createVisitor)({
|
|
967
|
+
FunctionStatement: (statement) => {
|
|
968
|
+
if (funcNames.has(statement.tokens.name.text)) {
|
|
969
|
+
if (!results.has(statement)) {
|
|
970
|
+
results.set(statement, { item: statement, file: file });
|
|
971
|
+
}
|
|
690
972
|
}
|
|
691
973
|
}
|
|
692
|
-
}
|
|
974
|
+
}), {
|
|
975
|
+
walkMode: visitors_1.WalkMode.visitStatements
|
|
976
|
+
});
|
|
693
977
|
}
|
|
694
978
|
return [...results.values()];
|
|
695
979
|
}
|
|
696
980
|
/**
|
|
697
981
|
* Find all available completion items at the given position
|
|
698
|
-
* @param
|
|
699
|
-
* @param
|
|
700
|
-
* @param columnIndex
|
|
982
|
+
* @param filePath can be a srcPath or a destPath
|
|
983
|
+
* @param position the position (line & column) where completions should be found
|
|
701
984
|
*/
|
|
702
|
-
getCompletions(
|
|
703
|
-
let file = this.getFile(
|
|
985
|
+
getCompletions(filePath, position) {
|
|
986
|
+
let file = this.getFile(filePath);
|
|
704
987
|
if (!file) {
|
|
705
988
|
return [];
|
|
706
989
|
}
|
|
@@ -724,40 +1007,37 @@ class Program {
|
|
|
724
1007
|
* Goes through each file and builds a list of workspace symbols for the program. Used by LanguageServer's onWorkspaceSymbol functionality
|
|
725
1008
|
*/
|
|
726
1009
|
getWorkspaceSymbols() {
|
|
727
|
-
const
|
|
728
|
-
for (const key in this.files) {
|
|
1010
|
+
const results = Object.keys(this.files).map(key => {
|
|
729
1011
|
const file = this.files[key];
|
|
730
1012
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
731
|
-
|
|
1013
|
+
return file.getWorkspaceSymbols();
|
|
732
1014
|
}
|
|
733
|
-
|
|
734
|
-
|
|
1015
|
+
return [];
|
|
1016
|
+
});
|
|
1017
|
+
return util_1.util.flatMap(results, c => c);
|
|
735
1018
|
}
|
|
736
1019
|
/**
|
|
737
1020
|
* Given a position in a file, if the position is sitting on some type of identifier,
|
|
738
1021
|
* go to the definition of that identifier (where this thing was first defined)
|
|
739
|
-
* @param srcPath The absolute path to the source file on disk
|
|
740
1022
|
*/
|
|
741
1023
|
getDefinition(srcPath, position) {
|
|
742
1024
|
let file = this.getFile(srcPath);
|
|
743
1025
|
if (!file) {
|
|
744
1026
|
return [];
|
|
745
1027
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
}
|
|
1028
|
+
const event = {
|
|
1029
|
+
program: this,
|
|
1030
|
+
file: file,
|
|
1031
|
+
position: position,
|
|
1032
|
+
definitions: []
|
|
1033
|
+
};
|
|
1034
|
+
this.plugins.emit('beforeProvideDefinition', event);
|
|
1035
|
+
this.plugins.emit('provideDefinition', event);
|
|
1036
|
+
this.plugins.emit('afterProvideDefinition', event);
|
|
1037
|
+
return event.definitions;
|
|
757
1038
|
}
|
|
758
1039
|
/**
|
|
759
1040
|
* Get hover information for a file and position
|
|
760
|
-
* @param srcPath The absolute path to the source file on disk
|
|
761
1041
|
*/
|
|
762
1042
|
getHover(srcPath, position) {
|
|
763
1043
|
let file = this.getFile(srcPath);
|
|
@@ -779,7 +1059,6 @@ class Program {
|
|
|
779
1059
|
}
|
|
780
1060
|
/**
|
|
781
1061
|
* Compute code actions for the given file and range
|
|
782
|
-
* @param srcPath The absolute path to the source file on disk
|
|
783
1062
|
*/
|
|
784
1063
|
getCodeActions(srcPath, range) {
|
|
785
1064
|
const codeActions = [];
|
|
@@ -821,277 +1100,23 @@ class Program {
|
|
|
821
1100
|
}
|
|
822
1101
|
}
|
|
823
1102
|
getSignatureHelp(filepath, position) {
|
|
824
|
-
var _a;
|
|
825
1103
|
let file = this.getFile(filepath);
|
|
826
1104
|
if (!file || !(0, reflection_1.isBrsFile)(file)) {
|
|
827
1105
|
return [];
|
|
828
1106
|
}
|
|
829
|
-
|
|
830
|
-
let
|
|
831
|
-
|
|
832
|
-
if (identifierInfo.statementType === '') {
|
|
833
|
-
// just general function calls
|
|
834
|
-
let statements = file.program.getStatementsByName(identifierInfo.name, file);
|
|
835
|
-
for (let statement of statements) {
|
|
836
|
-
//TODO better handling of collisions - if it's a namespace, then don't show any other overrides
|
|
837
|
-
//if we're on m - then limit scope to the current class, if present
|
|
838
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
839
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
840
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
841
|
-
results.set(sigHelp.key, sigHelp);
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
else if (identifierInfo.statementType === '.') {
|
|
846
|
-
//if m class reference.. then
|
|
847
|
-
//only get statements from the class I am in..
|
|
848
|
-
if (functionExpression) {
|
|
849
|
-
const currentToken = file.parser.getTokenAt(position);
|
|
850
|
-
for (let scope of this.getScopesForFile(file)) {
|
|
851
|
-
scope.linkSymbolTable();
|
|
852
|
-
let myClass = file.getClassFromToken(currentToken, functionExpression, scope);
|
|
853
|
-
if (myClass) {
|
|
854
|
-
let classes = scope.getClassHierarchy(myClass.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
|
|
855
|
-
//and anything from any class in scope to a non m class
|
|
856
|
-
for (let statement of [...classes].filter((i) => (0, reflection_1.isMethodStatement)(i.item))) {
|
|
857
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
858
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
859
|
-
results.set(sigHelp.key, sigHelp);
|
|
860
|
-
return;
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
scope.unlinkSymbolTable();
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
if (identifierInfo.dotPart) {
|
|
868
|
-
//potential namespaces
|
|
869
|
-
let statements = file.program.getStatementsByName(identifierInfo.name, file, identifierInfo.dotPart);
|
|
870
|
-
if (statements.length === 0) {
|
|
871
|
-
//was not a namespaced function, it could be any method on any class now
|
|
872
|
-
statements = file.program.getStatementsByName(identifierInfo.name, file);
|
|
873
|
-
}
|
|
874
|
-
for (let statement of statements) {
|
|
875
|
-
//TODO better handling of collisions - if it's a namespace, then don't show any other overrides
|
|
876
|
-
//if we're on m - then limit scope to the current class, if present
|
|
877
|
-
let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
|
|
878
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
879
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
880
|
-
results.set(sigHelp.key, sigHelp);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
else if (identifierInfo.statementType === '@.') {
|
|
886
|
-
for (const scope of this.getScopes().filter((s) => (0, reflection_1.isXmlScope)(s))) {
|
|
887
|
-
let fileLinks = this.getStatementsForXmlFile(scope, identifierInfo.name);
|
|
888
|
-
for (let fileLink of fileLinks) {
|
|
889
|
-
let sigHelp = fileLink.file.getSignatureHelpForStatement(fileLink.item);
|
|
890
|
-
if (sigHelp && !results.has[sigHelp.key]) {
|
|
891
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
892
|
-
results.set(sigHelp.key, sigHelp);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
else if (identifierInfo.statementType === 'new') {
|
|
898
|
-
let classItem = file.getClassFileLink(identifierInfo.dotPart ? `${identifierInfo.dotPart}.${identifierInfo.name}` : identifierInfo.name);
|
|
899
|
-
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);
|
|
900
|
-
if (sigHelp && !results.has(sigHelp.key)) {
|
|
901
|
-
sigHelp.index = identifierInfo.commaCount;
|
|
902
|
-
results.set(sigHelp.key, sigHelp);
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
return [...results.values()];
|
|
906
|
-
}
|
|
907
|
-
getPartialStatementInfo(file, position) {
|
|
908
|
-
let lines = util_1.util.splitIntoLines(file.fileContents);
|
|
909
|
-
let line = lines[position.line];
|
|
910
|
-
let index = position.character;
|
|
911
|
-
let itemCounts = this.getPartialItemCounts(line, index);
|
|
912
|
-
if (!itemCounts.isArgStartFound && line.charAt(index) === ')') {
|
|
913
|
-
//try previous char, in case we were on a close bracket..
|
|
914
|
-
index--;
|
|
915
|
-
itemCounts = this.getPartialItemCounts(line, index);
|
|
916
|
-
}
|
|
917
|
-
let argStartIndex = itemCounts.argStartIndex;
|
|
918
|
-
index = itemCounts.argStartIndex - 1;
|
|
919
|
-
let statementType = '';
|
|
920
|
-
let name;
|
|
921
|
-
let dotPart;
|
|
922
|
-
if (!itemCounts.isArgStartFound) {
|
|
923
|
-
//try to get sig help based on the name
|
|
924
|
-
index = position.character;
|
|
925
|
-
let currentToken = file.parser.getTokenAt(position);
|
|
926
|
-
if (currentToken && currentToken.kind !== TokenKind_1.TokenKind.Comment) {
|
|
927
|
-
name = file.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
|
|
928
|
-
if (!name) {
|
|
929
|
-
//try the previous token, incase we're on a bracket
|
|
930
|
-
currentToken = file.parser.getPreviousToken(currentToken);
|
|
931
|
-
name = file.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
|
|
932
|
-
}
|
|
933
|
-
if (name === null || name === void 0 ? void 0 : name.indexOf('.')) {
|
|
934
|
-
let parts = name.split('.');
|
|
935
|
-
name = parts[parts.length - 1];
|
|
936
|
-
}
|
|
937
|
-
index = currentToken.range.start.character;
|
|
938
|
-
argStartIndex = index;
|
|
939
|
-
}
|
|
940
|
-
else {
|
|
941
|
-
// invalid location
|
|
942
|
-
index = 0;
|
|
943
|
-
itemCounts.comma = 0;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
//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).
|
|
947
|
-
while (index >= -1) {
|
|
948
|
-
if (!(/[a-z0-9_\.\@]/i).test(line.charAt(index))) {
|
|
949
|
-
if (!name) {
|
|
950
|
-
name = line.substring(index + 1, argStartIndex);
|
|
951
|
-
}
|
|
952
|
-
else {
|
|
953
|
-
dotPart = line.substring(index + 1, argStartIndex);
|
|
954
|
-
if (dotPart.endsWith('.')) {
|
|
955
|
-
dotPart = dotPart.substr(0, dotPart.length - 1);
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
break;
|
|
959
|
-
}
|
|
960
|
-
if (line.substr(index - 2, 2) === '@.') {
|
|
961
|
-
statementType = '@.';
|
|
962
|
-
name = name || line.substring(index, argStartIndex);
|
|
963
|
-
break;
|
|
964
|
-
}
|
|
965
|
-
else if (line.charAt(index - 1) === '.' && statementType === '') {
|
|
966
|
-
statementType = '.';
|
|
967
|
-
name = name || line.substring(index, argStartIndex);
|
|
968
|
-
argStartIndex = index;
|
|
969
|
-
}
|
|
970
|
-
index--;
|
|
971
|
-
}
|
|
972
|
-
if (line.substring(0, index).trim().endsWith('new')) {
|
|
973
|
-
statementType = 'new';
|
|
974
|
-
}
|
|
975
|
-
return {
|
|
976
|
-
commaCount: itemCounts.comma,
|
|
977
|
-
statementType: statementType,
|
|
978
|
-
name: name,
|
|
979
|
-
dotPart: dotPart
|
|
980
|
-
};
|
|
1107
|
+
let callExpressionInfo = new CallExpressionInfo_1.CallExpressionInfo(file, position);
|
|
1108
|
+
let signatureHelpUtil = new SignatureHelpUtil_1.SignatureHelpUtil();
|
|
1109
|
+
return signatureHelpUtil.getSignatureHelpItems(callExpressionInfo);
|
|
981
1110
|
}
|
|
982
|
-
getPartialItemCounts(line, index) {
|
|
983
|
-
let isArgStartFound = false;
|
|
984
|
-
let itemCounts = {
|
|
985
|
-
normal: 0,
|
|
986
|
-
square: 0,
|
|
987
|
-
curly: 0,
|
|
988
|
-
comma: 0,
|
|
989
|
-
endIndex: 0,
|
|
990
|
-
argStartIndex: index,
|
|
991
|
-
isArgStartFound: false
|
|
992
|
-
};
|
|
993
|
-
while (index >= 0) {
|
|
994
|
-
const currentChar = line.charAt(index);
|
|
995
|
-
if (currentChar === '\'') { //found comment, invalid index
|
|
996
|
-
itemCounts.isArgStartFound = false;
|
|
997
|
-
break;
|
|
998
|
-
}
|
|
999
|
-
if (isArgStartFound) {
|
|
1000
|
-
if (currentChar !== ' ') {
|
|
1001
|
-
break;
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
else {
|
|
1005
|
-
if (currentChar === ')') {
|
|
1006
|
-
itemCounts.normal++;
|
|
1007
|
-
}
|
|
1008
|
-
if (currentChar === ']') {
|
|
1009
|
-
itemCounts.square++;
|
|
1010
|
-
}
|
|
1011
|
-
if (currentChar === '}') {
|
|
1012
|
-
itemCounts.curly++;
|
|
1013
|
-
}
|
|
1014
|
-
if (currentChar === ',' && itemCounts.normal <= 0 && itemCounts.curly <= 0 && itemCounts.square <= 0) {
|
|
1015
|
-
itemCounts.comma++;
|
|
1016
|
-
}
|
|
1017
|
-
if (currentChar === '(') {
|
|
1018
|
-
if (itemCounts.normal === 0) {
|
|
1019
|
-
itemCounts.isArgStartFound = true;
|
|
1020
|
-
itemCounts.argStartIndex = index;
|
|
1021
|
-
}
|
|
1022
|
-
else {
|
|
1023
|
-
itemCounts.normal--;
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
if (currentChar === '[') {
|
|
1027
|
-
itemCounts.square--;
|
|
1028
|
-
}
|
|
1029
|
-
if (currentChar === '{') {
|
|
1030
|
-
itemCounts.curly--;
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
index--;
|
|
1034
|
-
}
|
|
1035
|
-
return itemCounts;
|
|
1036
|
-
}
|
|
1037
|
-
/**
|
|
1038
|
-
* @param srcPath The absolute path to the source file on disk
|
|
1039
|
-
*/
|
|
1040
1111
|
getReferences(srcPath, position) {
|
|
1041
1112
|
//find the file
|
|
1042
1113
|
let file = this.getFile(srcPath);
|
|
1043
|
-
if (
|
|
1044
|
-
return
|
|
1114
|
+
if ((0, reflection_1.isBrsFile)(file) || (0, reflection_1.isXmlFile)(file)) {
|
|
1115
|
+
return file.getReferences(position);
|
|
1045
1116
|
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
/**
|
|
1049
|
-
* Get a list of all script imports, relative to the specified pkgPath
|
|
1050
|
-
* @param sourcePkgPath - the pkgPath of the source that wants to resolve script imports.
|
|
1051
|
-
*/
|
|
1052
|
-
getScriptImportCompletions(sourcePkgPath, scriptImport) {
|
|
1053
|
-
let lowerSourcePkgPath = sourcePkgPath.toLowerCase();
|
|
1054
|
-
let result = [];
|
|
1055
|
-
/**
|
|
1056
|
-
* hashtable to prevent duplicate results
|
|
1057
|
-
*/
|
|
1058
|
-
let resultPkgPaths = {};
|
|
1059
|
-
//restrict to only .brs files
|
|
1060
|
-
for (const key in this.files) {
|
|
1061
|
-
const file = this.files[key];
|
|
1062
|
-
if (
|
|
1063
|
-
//is a BrightScript or BrighterScript file
|
|
1064
|
-
(file.extension === '.bs' || file.extension === '.brs') &&
|
|
1065
|
-
//this file is not the current file
|
|
1066
|
-
lowerSourcePkgPath !== file.pkgPath.toLowerCase()) {
|
|
1067
|
-
//add the relative path
|
|
1068
|
-
let relativePath = util_1.util.getRelativePath(sourcePkgPath, file.pkgPath).replace(/\\/g, '/');
|
|
1069
|
-
const lowerPkgPath = file.pkgPath.toLowerCase();
|
|
1070
|
-
if (!resultPkgPaths[lowerPkgPath]) {
|
|
1071
|
-
resultPkgPaths[lowerPkgPath] = true;
|
|
1072
|
-
result.push({
|
|
1073
|
-
label: relativePath,
|
|
1074
|
-
detail: file.srcPath,
|
|
1075
|
-
kind: vscode_languageserver_1.CompletionItemKind.File,
|
|
1076
|
-
textEdit: {
|
|
1077
|
-
newText: relativePath,
|
|
1078
|
-
range: scriptImport.filePathRange
|
|
1079
|
-
}
|
|
1080
|
-
});
|
|
1081
|
-
//add the absolute path
|
|
1082
|
-
result.push({
|
|
1083
|
-
label: file.pkgPath,
|
|
1084
|
-
detail: file.srcPath,
|
|
1085
|
-
kind: vscode_languageserver_1.CompletionItemKind.File,
|
|
1086
|
-
textEdit: {
|
|
1087
|
-
newText: file.pkgPath,
|
|
1088
|
-
range: scriptImport.filePathRange
|
|
1089
|
-
}
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1117
|
+
else {
|
|
1118
|
+
return null;
|
|
1093
1119
|
}
|
|
1094
|
-
return result;
|
|
1095
1120
|
}
|
|
1096
1121
|
/**
|
|
1097
1122
|
* Transpile a single file and get the result as a string.
|
|
@@ -1102,160 +1127,215 @@ class Program {
|
|
|
1102
1127
|
* @param filePath can be a srcPath or a destPath
|
|
1103
1128
|
*/
|
|
1104
1129
|
async getTranspiledFileContents(filePath) {
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
|
|
1130
|
+
const file = this.getFile(filePath);
|
|
1131
|
+
return this.getTranspiledFileContentsPipeline.run(async () => {
|
|
1132
|
+
const result = {
|
|
1133
|
+
destPath: file.destPath,
|
|
1134
|
+
pkgPath: file.pkgPath,
|
|
1135
|
+
srcPath: file.srcPath
|
|
1136
|
+
};
|
|
1137
|
+
const expectedPkgPath = file.pkgPath.toLowerCase();
|
|
1138
|
+
const expectedMapPath = `${expectedPkgPath}.map`;
|
|
1139
|
+
const expectedTypedefPkgPath = expectedPkgPath.replace(/\.brs$/i, '.d.bs');
|
|
1140
|
+
//add a temporary plugin to tap into the file writing process
|
|
1141
|
+
const plugin = this.plugins.addFirst({
|
|
1142
|
+
name: 'getTranspiledFileContents',
|
|
1143
|
+
beforeWriteFile: (event) => {
|
|
1144
|
+
const pkgPath = event.file.pkgPath.toLowerCase();
|
|
1145
|
+
switch (pkgPath) {
|
|
1146
|
+
//this is the actual transpiled file
|
|
1147
|
+
case expectedPkgPath:
|
|
1148
|
+
result.code = event.file.data.toString();
|
|
1149
|
+
break;
|
|
1150
|
+
//this is the sourcemap
|
|
1151
|
+
case expectedMapPath:
|
|
1152
|
+
result.map = event.file.data.toString();
|
|
1153
|
+
break;
|
|
1154
|
+
//this is the typedef
|
|
1155
|
+
case expectedTypedefPkgPath:
|
|
1156
|
+
result.typedef = event.file.data.toString();
|
|
1157
|
+
break;
|
|
1158
|
+
default:
|
|
1159
|
+
//no idea what this file is. just ignore it
|
|
1160
|
+
}
|
|
1161
|
+
//mark every file as processed so it they don't get written to the output directory
|
|
1162
|
+
event.processedFiles.add(event.file);
|
|
1163
|
+
}
|
|
1164
|
+
});
|
|
1165
|
+
try {
|
|
1166
|
+
//now that the plugin has been registered, run the build with just this file
|
|
1167
|
+
await this.build({
|
|
1168
|
+
files: [file]
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
finally {
|
|
1172
|
+
this.plugins.remove(plugin);
|
|
1173
|
+
}
|
|
1174
|
+
return result;
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Get the absolute output path for a file
|
|
1179
|
+
*/
|
|
1180
|
+
getOutputPath(file, stagingDir = this.getStagingDir()) {
|
|
1181
|
+
return (0, util_1.standardizePath) `${stagingDir}/${file.pkgPath}`;
|
|
1182
|
+
}
|
|
1183
|
+
getStagingDir(stagingDir) {
|
|
1184
|
+
var _a, _b;
|
|
1185
|
+
let result = (_a = stagingDir !== null && stagingDir !== void 0 ? stagingDir : this.options.stagingDir) !== null && _a !== void 0 ? _a : this.options.stagingDir;
|
|
1186
|
+
if (!result) {
|
|
1187
|
+
result = roku_deploy_1.rokuDeploy.getOptions(this.options).stagingDir;
|
|
1188
|
+
}
|
|
1189
|
+
result = (0, util_1.standardizePath) `${path.resolve((_b = this.options.cwd) !== null && _b !== void 0 ? _b : process.cwd(), result !== null && result !== void 0 ? result : '/')}`;
|
|
1108
1190
|
return result;
|
|
1109
1191
|
}
|
|
1110
1192
|
/**
|
|
1111
|
-
*
|
|
1112
|
-
*
|
|
1193
|
+
* Prepare the program for building
|
|
1194
|
+
* @param files the list of files that should be prepared
|
|
1113
1195
|
*/
|
|
1114
|
-
|
|
1115
|
-
const
|
|
1116
|
-
this.plugins.emit('beforeFileTranspile', {
|
|
1196
|
+
async prepare(files) {
|
|
1197
|
+
const programEvent = {
|
|
1117
1198
|
program: this,
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1199
|
+
editor: this.editor,
|
|
1200
|
+
files: files
|
|
1201
|
+
};
|
|
1202
|
+
//assign an editor to every file
|
|
1203
|
+
for (const file of files) {
|
|
1204
|
+
//if the file doesn't have an editor yet, assign one now
|
|
1205
|
+
if (!file.editor) {
|
|
1206
|
+
file.editor = new Editor_1.Editor();
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
files.sort((a, b) => {
|
|
1210
|
+
if (a.pkgPath < b.pkgPath) {
|
|
1211
|
+
return -1;
|
|
1212
|
+
}
|
|
1213
|
+
else if (a.pkgPath > b.pkgPath) {
|
|
1214
|
+
return 1;
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
return 1;
|
|
1218
|
+
}
|
|
1121
1219
|
});
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1220
|
+
await this.plugins.emitAsync('beforePrepareProgram', programEvent);
|
|
1221
|
+
await this.plugins.emitAsync('prepareProgram', programEvent);
|
|
1222
|
+
const stagingDir = this.getStagingDir();
|
|
1223
|
+
const entries = [];
|
|
1224
|
+
for (const file of files) {
|
|
1225
|
+
//if the file doesn't have an editor yet, assign one now
|
|
1226
|
+
if (!file.editor) {
|
|
1227
|
+
file.editor = new Editor_1.Editor();
|
|
1228
|
+
}
|
|
1229
|
+
const event = {
|
|
1230
|
+
program: this,
|
|
1231
|
+
file: file,
|
|
1232
|
+
editor: file.editor,
|
|
1233
|
+
outputPath: this.getOutputPath(file, stagingDir)
|
|
1234
|
+
};
|
|
1235
|
+
await this.plugins.emitAsync('beforePrepareFile', event);
|
|
1236
|
+
await this.plugins.emitAsync('prepareFile', event);
|
|
1237
|
+
await this.plugins.emitAsync('afterPrepareFile', event);
|
|
1238
|
+
//TODO remove this in v1
|
|
1239
|
+
entries.push(event);
|
|
1133
1240
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
file: file,
|
|
1137
|
-
outputPath: outputPath,
|
|
1138
|
-
editor: editor,
|
|
1139
|
-
code: result.code,
|
|
1140
|
-
map: result.map,
|
|
1141
|
-
typedef: typedef
|
|
1142
|
-
};
|
|
1143
|
-
this.plugins.emit('afterFileTranspile', event);
|
|
1144
|
-
//undo all `editor` edits that may have been applied to this file.
|
|
1145
|
-
editor.undoAll();
|
|
1146
|
-
return {
|
|
1147
|
-
srcPath: file.srcPath,
|
|
1148
|
-
pkgPath: file.pkgPath,
|
|
1149
|
-
code: event.code,
|
|
1150
|
-
map: event.map,
|
|
1151
|
-
typedef: event.typedef
|
|
1152
|
-
};
|
|
1241
|
+
await this.plugins.emitAsync('afterPrepareProgram', programEvent);
|
|
1242
|
+
return files;
|
|
1153
1243
|
}
|
|
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
|
-
|
|
1180
|
-
|
|
1181
|
-
return {
|
|
1244
|
+
/**
|
|
1245
|
+
* Generate the contents of every file
|
|
1246
|
+
*/
|
|
1247
|
+
async serialize(files) {
|
|
1248
|
+
const allFiles = new Map();
|
|
1249
|
+
//exclude prunable files if that option is enabled
|
|
1250
|
+
if (this.options.pruneEmptyCodeFiles === true) {
|
|
1251
|
+
files = files.filter(x => x.canBePruned !== true);
|
|
1252
|
+
}
|
|
1253
|
+
const serializeProgramEvent = await this.plugins.emitAsync('beforeSerializeProgram', {
|
|
1254
|
+
program: this,
|
|
1255
|
+
files: files,
|
|
1256
|
+
result: allFiles
|
|
1257
|
+
});
|
|
1258
|
+
await this.plugins.emitAsync('onSerializeProgram', {
|
|
1259
|
+
program: this,
|
|
1260
|
+
files: files,
|
|
1261
|
+
result: allFiles
|
|
1262
|
+
});
|
|
1263
|
+
//sort the entries to make transpiling more deterministic
|
|
1264
|
+
files = serializeProgramEvent.files.sort((a, b) => {
|
|
1265
|
+
return a.srcPath < b.srcPath ? -1 : 1;
|
|
1266
|
+
});
|
|
1267
|
+
// serialize each file
|
|
1268
|
+
for (const file of files) {
|
|
1269
|
+
const event = {
|
|
1270
|
+
program: this,
|
|
1182
1271
|
file: file,
|
|
1183
|
-
|
|
1272
|
+
result: allFiles
|
|
1184
1273
|
};
|
|
1274
|
+
await this.plugins.emitAsync('beforeSerializeFile', event);
|
|
1275
|
+
await this.plugins.emitAsync('serializeFile', event);
|
|
1276
|
+
await this.plugins.emitAsync('afterSerializeFile', event);
|
|
1277
|
+
}
|
|
1278
|
+
this.plugins.emit('afterSerializeProgram', {
|
|
1279
|
+
program: this,
|
|
1280
|
+
files: files,
|
|
1281
|
+
result: allFiles
|
|
1185
1282
|
});
|
|
1186
|
-
|
|
1187
|
-
|
|
1283
|
+
return allFiles;
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Write the entire project to disk
|
|
1287
|
+
*/
|
|
1288
|
+
async write(stagingDir, files) {
|
|
1289
|
+
const programEvent = await this.plugins.emitAsync('beforeWriteProgram', {
|
|
1188
1290
|
program: this,
|
|
1189
|
-
|
|
1190
|
-
|
|
1291
|
+
files: files,
|
|
1292
|
+
stagingDir: stagingDir
|
|
1191
1293
|
});
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1294
|
+
//empty the staging directory
|
|
1295
|
+
await fsExtra.emptyDir(stagingDir);
|
|
1296
|
+
const serializedFiles = [...files]
|
|
1297
|
+
.map(([, serializedFiles]) => serializedFiles)
|
|
1298
|
+
.flat();
|
|
1299
|
+
//write all the files to disk (asynchronously)
|
|
1300
|
+
await Promise.all(serializedFiles.map(async (file) => {
|
|
1301
|
+
const event = await this.plugins.emitAsync('beforeWriteFile', {
|
|
1302
|
+
program: this,
|
|
1303
|
+
file: file,
|
|
1304
|
+
outputPath: this.getOutputPath(file, stagingDir),
|
|
1305
|
+
processedFiles: new Set()
|
|
1306
|
+
});
|
|
1307
|
+
await this.plugins.emitAsync('writeFile', event);
|
|
1308
|
+
await this.plugins.emitAsync('afterWriteFile', event);
|
|
1309
|
+
}));
|
|
1310
|
+
await this.plugins.emitAsync('afterWriteProgram', programEvent);
|
|
1197
1311
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
processedFiles.add(file);
|
|
1206
|
-
//skip transpiling typedef files
|
|
1207
|
-
if ((0, reflection_1.isBrsFile)(file) && file.isTypedef) {
|
|
1208
|
-
return;
|
|
1209
|
-
}
|
|
1210
|
-
const fileTranspileResult = this._getTranspiledFileContents(file, outputPath);
|
|
1211
|
-
//make sure the full dir path exists
|
|
1212
|
-
await fsExtra.ensureDir(path.dirname(outputPath));
|
|
1213
|
-
if (await fsExtra.pathExists(outputPath)) {
|
|
1214
|
-
throw new Error(`Error while transpiling "${file.srcPath}". A file already exists at "${outputPath}" and will not be overwritten.`);
|
|
1215
|
-
}
|
|
1216
|
-
const writeMapPromise = fileTranspileResult.map ? fsExtra.writeFile(`${outputPath}.map`, fileTranspileResult.map.toString()) : null;
|
|
1217
|
-
await Promise.all([
|
|
1218
|
-
fsExtra.writeFile(outputPath, fileTranspileResult.code),
|
|
1219
|
-
writeMapPromise
|
|
1220
|
-
]);
|
|
1221
|
-
if (fileTranspileResult.typedef) {
|
|
1222
|
-
const typedefPath = outputPath.replace(/\.brs$/i, '.d.bs');
|
|
1223
|
-
await fsExtra.writeFile(typedefPath, fileTranspileResult.typedef);
|
|
1224
|
-
}
|
|
1225
|
-
};
|
|
1226
|
-
let promises = entries.map(async (entry) => {
|
|
1312
|
+
/**
|
|
1313
|
+
* Build the project. This transpiles/transforms/copies all files and moves them to the staging directory
|
|
1314
|
+
* @param options the list of options used to build the program
|
|
1315
|
+
*/
|
|
1316
|
+
async build(options) {
|
|
1317
|
+
//run a single build at a time
|
|
1318
|
+
await this.buildPipeline.run(async () => {
|
|
1227
1319
|
var _a;
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
if (promises.length > 0) {
|
|
1246
|
-
this.logger.info(`Transpiling ${promises.length} new files`);
|
|
1247
|
-
await Promise.all(promises);
|
|
1320
|
+
const stagingDir = this.getStagingDir(options === null || options === void 0 ? void 0 : options.stagingDir);
|
|
1321
|
+
const event = await this.plugins.emitAsync('beforeBuildProgram', {
|
|
1322
|
+
program: this,
|
|
1323
|
+
editor: this.editor,
|
|
1324
|
+
files: (_a = options === null || options === void 0 ? void 0 : options.files) !== null && _a !== void 0 ? _a : Object.values(this.files)
|
|
1325
|
+
});
|
|
1326
|
+
//prepare the program (and files) for building
|
|
1327
|
+
event.files = await this.prepare(event.files);
|
|
1328
|
+
//stage the entire program
|
|
1329
|
+
const serializedFilesByFile = await this.serialize(event.files);
|
|
1330
|
+
await this.write(stagingDir, serializedFilesByFile);
|
|
1331
|
+
await this.plugins.emitAsync('afterBuildProgram', event);
|
|
1332
|
+
//undo all edits for the program
|
|
1333
|
+
this.editor.undoAll();
|
|
1334
|
+
//undo all edits for each file
|
|
1335
|
+
for (const file of event.files) {
|
|
1336
|
+
file.editor.undoAll();
|
|
1248
1337
|
}
|
|
1249
|
-
} while (promises.length > 0);
|
|
1250
|
-
this.afterProgramTranspile(entries, astEditor);
|
|
1251
|
-
}
|
|
1252
|
-
afterProgramTranspile(entries, astEditor) {
|
|
1253
|
-
this.plugins.emit('afterProgramTranspile', {
|
|
1254
|
-
program: this,
|
|
1255
|
-
entries: entries,
|
|
1256
|
-
editor: astEditor
|
|
1257
1338
|
});
|
|
1258
|
-
astEditor.undoAll();
|
|
1259
1339
|
}
|
|
1260
1340
|
/**
|
|
1261
1341
|
* Find a list of files in the program that have a function with the given name (case INsensitive)
|
|
@@ -1268,7 +1348,8 @@ class Program {
|
|
|
1268
1348
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1269
1349
|
//TODO handle namespace-relative function calls
|
|
1270
1350
|
//if the file has a function with this name
|
|
1271
|
-
|
|
1351
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1352
|
+
if (file['_cachedLookups'].functionStatementMap.get(lowerFunctionName)) {
|
|
1272
1353
|
files.push(file);
|
|
1273
1354
|
}
|
|
1274
1355
|
}
|
|
@@ -1286,7 +1367,8 @@ class Program {
|
|
|
1286
1367
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1287
1368
|
//TODO handle namespace-relative classes
|
|
1288
1369
|
//if the file has a function with this name
|
|
1289
|
-
|
|
1370
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1371
|
+
if (file['_cachedLookups'].classStatementMap.get(lowerClassName) !== undefined) {
|
|
1290
1372
|
files.push(file);
|
|
1291
1373
|
}
|
|
1292
1374
|
}
|
|
@@ -1299,7 +1381,8 @@ class Program {
|
|
|
1299
1381
|
//find every file with this class defined
|
|
1300
1382
|
for (const file of Object.values(this.files)) {
|
|
1301
1383
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1302
|
-
|
|
1384
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1385
|
+
if (file['_cachedLookups'].namespaceStatements.find((x) => {
|
|
1303
1386
|
const namespaceName = x.name.toLowerCase();
|
|
1304
1387
|
return (
|
|
1305
1388
|
//the namespace name matches exactly
|
|
@@ -1316,48 +1399,100 @@ class Program {
|
|
|
1316
1399
|
findFilesForEnum(name) {
|
|
1317
1400
|
const files = [];
|
|
1318
1401
|
const lowerName = name.toLowerCase();
|
|
1319
|
-
//find every file with this
|
|
1402
|
+
//find every file with this enum defined
|
|
1320
1403
|
for (const file of Object.values(this.files)) {
|
|
1321
1404
|
if ((0, reflection_1.isBrsFile)(file)) {
|
|
1322
|
-
|
|
1405
|
+
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
1406
|
+
if (file['_cachedLookups'].enumStatementMap.get(lowerName)) {
|
|
1323
1407
|
files.push(file);
|
|
1324
1408
|
}
|
|
1325
1409
|
}
|
|
1326
1410
|
}
|
|
1327
1411
|
return files;
|
|
1328
1412
|
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Modify a parsed manifest map by reading `bs_const` and injecting values from `options.manifest.bs_const`
|
|
1415
|
+
* @param parsedManifest The manifest map to read from and modify
|
|
1416
|
+
*/
|
|
1417
|
+
buildBsConstsIntoParsedManifest(parsedManifest) {
|
|
1418
|
+
var _a, _b;
|
|
1419
|
+
// Lift the bs_consts defined in the manifest
|
|
1420
|
+
let bsConsts = (0, Manifest_1.getBsConst)(parsedManifest, false);
|
|
1421
|
+
// Override or delete any bs_consts defined in the bs config
|
|
1422
|
+
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) {
|
|
1423
|
+
const value = this.options.manifest.bs_const[key];
|
|
1424
|
+
if (value === null) {
|
|
1425
|
+
bsConsts.delete(key);
|
|
1426
|
+
}
|
|
1427
|
+
else {
|
|
1428
|
+
bsConsts.set(key, value);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
// convert the new list of bs consts back into a string for the rest of the down stream systems to use
|
|
1432
|
+
let constString = '';
|
|
1433
|
+
for (const [key, value] of bsConsts) {
|
|
1434
|
+
constString += `${constString !== '' ? ';' : ''}${key}=${value.toString()}`;
|
|
1435
|
+
}
|
|
1436
|
+
// Set the updated bs_const value
|
|
1437
|
+
parsedManifest.set('bs_const', constString);
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Try to find and load the manifest into memory
|
|
1441
|
+
* @param manifestFileObj A pointer to a potential manifest file object found during loading
|
|
1442
|
+
* @param replaceIfAlreadyLoaded should we overwrite the internal `_manifest` if it already exists
|
|
1443
|
+
*/
|
|
1444
|
+
loadManifest(manifestFileObj, replaceIfAlreadyLoaded = true) {
|
|
1445
|
+
//if we already have a manifest instance, and should not replace...then don't replace
|
|
1446
|
+
if (!replaceIfAlreadyLoaded && this._manifest) {
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
let manifestPath = manifestFileObj
|
|
1450
|
+
? manifestFileObj.src
|
|
1451
|
+
: path.join(this.options.rootDir, 'manifest');
|
|
1452
|
+
try {
|
|
1453
|
+
// we only load this manifest once, so do it sync to improve speed downstream
|
|
1454
|
+
const contents = fsExtra.readFileSync(manifestPath, 'utf-8');
|
|
1455
|
+
const parsedManifest = (0, Manifest_1.parseManifest)(contents);
|
|
1456
|
+
this.buildBsConstsIntoParsedManifest(parsedManifest);
|
|
1457
|
+
this._manifest = parsedManifest;
|
|
1458
|
+
}
|
|
1459
|
+
catch (e) {
|
|
1460
|
+
this._manifest = new Map();
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1329
1463
|
/**
|
|
1330
1464
|
* Get a map of the manifest information
|
|
1331
1465
|
*/
|
|
1332
1466
|
getManifest() {
|
|
1333
1467
|
if (!this._manifest) {
|
|
1334
|
-
|
|
1335
|
-
//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
|
|
1336
|
-
let manifestPath = path.join(this.options.rootDir, 'manifest');
|
|
1337
|
-
let contents;
|
|
1338
|
-
try {
|
|
1339
|
-
//we only load this manifest once, so do it sync to improve speed downstream
|
|
1340
|
-
contents = fsExtra.readFileSync(manifestPath, 'utf-8');
|
|
1341
|
-
this._manifest = (0, Manifest_1.parseManifest)(contents);
|
|
1342
|
-
}
|
|
1343
|
-
catch (err) {
|
|
1344
|
-
this._manifest = new Map();
|
|
1345
|
-
}
|
|
1468
|
+
this.loadManifest();
|
|
1346
1469
|
}
|
|
1347
1470
|
return this._manifest;
|
|
1348
1471
|
}
|
|
1349
1472
|
dispose() {
|
|
1350
|
-
var _a, _b;
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
(_a =
|
|
1473
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1474
|
+
this.plugins.emit('beforeProgramDispose', { program: this });
|
|
1475
|
+
for (let filePath in this.files) {
|
|
1476
|
+
(_b = (_a = this.files[filePath]) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1354
1477
|
}
|
|
1355
1478
|
for (let name in this.scopes) {
|
|
1356
|
-
(
|
|
1479
|
+
(_d = (_c = this.scopes[name]) === null || _c === void 0 ? void 0 : _c.dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
1357
1480
|
}
|
|
1358
|
-
this.globalScope.dispose();
|
|
1359
|
-
this.dependencyGraph.dispose();
|
|
1481
|
+
(_f = (_e = this.globalScope) === null || _e === void 0 ? void 0 : _e.dispose) === null || _f === void 0 ? void 0 : _f.call(_e);
|
|
1482
|
+
(_h = (_g = this.dependencyGraph) === null || _g === void 0 ? void 0 : _g.dispose) === null || _h === void 0 ? void 0 : _h.call(_g);
|
|
1360
1483
|
}
|
|
1361
1484
|
}
|
|
1362
1485
|
exports.Program = Program;
|
|
1486
|
+
class ProvideFileEventInternal {
|
|
1487
|
+
constructor(program, srcPath, destPath, data, fileFactory) {
|
|
1488
|
+
var _a;
|
|
1489
|
+
this.program = program;
|
|
1490
|
+
this.srcPath = srcPath;
|
|
1491
|
+
this.destPath = destPath;
|
|
1492
|
+
this.data = data;
|
|
1493
|
+
this.fileFactory = fileFactory;
|
|
1494
|
+
this.files = [];
|
|
1495
|
+
this.srcExtension = (_a = path.extname(srcPath)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1363
1498
|
//# sourceMappingURL=Program.js.map
|