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