brighterscript 0.66.0-alpha.6 → 0.66.0-alpha.7
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 +52 -10
- package/README.md +16 -0
- 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/BsConfig.d.ts +15 -1
- package/dist/CommentFlagProcessor.d.ts +4 -3
- package/dist/CommentFlagProcessor.js.map +1 -1
- package/dist/DiagnosticMessages.d.ts +2 -0
- package/dist/DiagnosticMessages.js +25 -13
- package/dist/DiagnosticMessages.js.map +1 -1
- package/dist/LanguageServer.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 +84 -37
- package/dist/Program.js +390 -267
- package/dist/Program.js.map +1 -1
- package/dist/ProgramBuilder.d.ts +10 -4
- package/dist/ProgramBuilder.js +44 -54
- package/dist/ProgramBuilder.js.map +1 -1
- package/dist/Scope.d.ts +13 -13
- package/dist/Scope.js +28 -26
- package/dist/Scope.js.map +1 -1
- package/dist/XmlScope.d.ts +5 -4
- package/dist/XmlScope.js +11 -10
- 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/reflection.d.ts +9 -4
- package/dist/astUtils/reflection.js +23 -7
- package/dist/astUtils/reflection.js.map +1 -1
- package/dist/astUtils/reflection.spec.js +2 -2
- package/dist/astUtils/reflection.spec.js.map +1 -1
- package/dist/astUtils/visitors.d.ts +3 -3
- package/dist/astUtils/visitors.spec.js +7 -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/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.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +5 -0
- package/dist/bscPlugin/completions/CompletionsProcessor.js +38 -15
- package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +65 -3
- package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
- 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 +1 -7
- package/dist/bscPlugin/hover/HoverProcessor.js +1 -7
- package/dist/bscPlugin/hover/HoverProcessor.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} +25 -4
- 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/ScopeValidator.js +24 -15
- package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
- package/dist/bscPlugin/validation/ScopeValidator.spec.js +326 -0
- package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
- package/dist/bscPlugin/validation/XmlFileValidator.js +2 -2
- package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/cli.js.map +1 -1
- package/dist/deferred.d.ts +2 -2
- package/dist/deferred.js.map +1 -1
- package/dist/diagnosticUtils.d.ts +1 -0
- package/dist/diagnosticUtils.js +4 -3
- 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 +40 -40
- package/dist/files/BrsFile.Class.spec.js.map +1 -1
- package/dist/files/BrsFile.d.ts +42 -15
- package/dist/files/BrsFile.js +120 -78
- package/dist/files/BrsFile.js.map +1 -1
- package/dist/files/BrsFile.spec.js +266 -167
- 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 +55 -17
- package/dist/files/XmlFile.js +88 -47
- package/dist/files/XmlFile.js.map +1 -1
- package/dist/files/XmlFile.spec.js +64 -57
- 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 +1 -1
- package/dist/globalCallables.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +312 -84
- package/dist/interfaces.js.map +1 -1
- package/dist/lexer/Lexer.js +1 -1
- package/dist/lexer/TokenKind.js +0 -1
- package/dist/lexer/TokenKind.js.map +1 -1
- package/dist/parser/AstNode.d.ts +2 -2
- package/dist/parser/AstNode.js +1 -1
- 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 +1 -1
- package/dist/parser/Expression.js +3 -9
- package/dist/parser/Expression.js.map +1 -1
- package/dist/parser/Parser.js +3 -0
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/Parser.spec.js +15 -1
- package/dist/parser/Parser.spec.js.map +1 -1
- package/dist/parser/SGParser.d.ts +2 -2
- 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 +1 -1
- package/dist/parser/Statement.d.ts +3 -2
- package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +10 -10
- 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 +64 -36
- package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
- package/dist/parser/tests/expression/TernaryExpression.spec.js +34 -34
- package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
- package/dist/parser/tests/statement/ConstStatement.spec.js +16 -16
- 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 +26 -26
- 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 +12 -12
- package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
- package/dist/parser/tests/statement/PrintStatement.spec.js +10 -10
- package/dist/parser/tests/statement/PrintStatement.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 +81 -143
- package/dist/roku-types/index.d.ts +15 -11
- package/dist/types/ArrayType.d.ts +1 -1
- package/dist/types/ArrayType.js +4 -0
- package/dist/types/ArrayType.js.map +1 -1
- package/dist/types/ArrayType.spec.js +1 -1
- package/dist/types/ArrayType.spec.js.map +1 -1
- package/dist/types/AssociativeArrayType.d.ts +1 -1
- package/dist/types/AssociativeArrayType.js +1 -1
- package/dist/types/AssociativeArrayType.js.map +1 -1
- package/dist/types/BooleanType.js +2 -1
- package/dist/types/BooleanType.js.map +1 -1
- package/dist/types/BscType.js +2 -0
- package/dist/types/BscType.js.map +1 -1
- package/dist/types/BuiltInInterfaceAdder.d.ts +3 -0
- package/dist/types/BuiltInInterfaceAdder.js +32 -13
- package/dist/types/BuiltInInterfaceAdder.js.map +1 -1
- package/dist/types/ComponentType.js +3 -0
- package/dist/types/ComponentType.js.map +1 -1
- package/dist/types/DoubleType.js +3 -1
- package/dist/types/DoubleType.js.map +1 -1
- package/dist/types/FloatType.js +3 -1
- package/dist/types/FloatType.js.map +1 -1
- package/dist/types/IntegerType.js +3 -1
- package/dist/types/IntegerType.js.map +1 -1
- package/dist/types/InterfaceType.d.ts +1 -1
- package/dist/types/InterfaceType.js +1 -8
- package/dist/types/InterfaceType.js.map +1 -1
- package/dist/types/InterfaceType.spec.js +23 -0
- package/dist/types/InterfaceType.spec.js.map +1 -1
- package/dist/types/LongIntegerType.js +3 -1
- package/dist/types/LongIntegerType.js.map +1 -1
- package/dist/types/ObjectType.d.ts +1 -1
- package/dist/types/StringType.js +2 -2
- package/dist/types/StringType.js.map +1 -1
- package/dist/types/TypedFunctionType.d.ts +6 -1
- package/dist/types/TypedFunctionType.js +45 -15
- package/dist/types/TypedFunctionType.js.map +1 -1
- package/dist/types/TypedFunctionType.spec.js +99 -0
- package/dist/types/TypedFunctionType.spec.js.map +1 -1
- package/dist/types/UnionType.js +7 -0
- package/dist/types/UnionType.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 +3 -0
- package/dist/types/helpers.js +29 -1
- package/dist/types/helpers.js.map +1 -1
- package/dist/util.d.ts +11 -5
- package/dist/util.js +79 -40
- package/dist/util.js.map +1 -1
- package/dist/validators/ClassValidator.js.map +1 -1
- package/package.json +1 -1
- 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/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
- /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → serialize/BslibInjector.spec.d.ts} +0 -0
package/dist/Program.js
CHANGED
|
@@ -6,8 +6,6 @@ const fsExtra = require("fs-extra");
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const Scope_1 = require("./Scope");
|
|
8
8
|
const DiagnosticMessages_1 = require("./DiagnosticMessages");
|
|
9
|
-
const BrsFile_1 = require("./files/BrsFile");
|
|
10
|
-
const XmlFile_1 = require("./files/XmlFile");
|
|
11
9
|
const util_1 = require("./util");
|
|
12
10
|
const XmlScope_1 = require("./XmlScope");
|
|
13
11
|
const DiagnosticFilterer_1 = require("./DiagnosticFilterer");
|
|
@@ -20,8 +18,7 @@ const vscode_uri_1 = require("vscode-uri");
|
|
|
20
18
|
const PluginInterface_1 = require("./PluginInterface");
|
|
21
19
|
const reflection_1 = require("./astUtils/reflection");
|
|
22
20
|
const BscPlugin_1 = require("./bscPlugin/BscPlugin");
|
|
23
|
-
const
|
|
24
|
-
const roku_deploy_1 = require("roku-deploy");
|
|
21
|
+
const Editor_1 = require("./astUtils/Editor");
|
|
25
22
|
const CallExpressionInfo_1 = require("./bscPlugin/CallExpressionInfo");
|
|
26
23
|
const SignatureHelpUtil_1 = require("./bscPlugin/SignatureHelpUtil");
|
|
27
24
|
const DiagnosticSeverityAdjuster_1 = require("./DiagnosticSeverityAdjuster");
|
|
@@ -36,11 +33,14 @@ const LongIntegerType_1 = require("./types/LongIntegerType");
|
|
|
36
33
|
const ObjectType_1 = require("./types/ObjectType");
|
|
37
34
|
const VoidType_1 = require("./types/VoidType");
|
|
38
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");
|
|
39
40
|
const roku_types_1 = require("./roku-types");
|
|
40
41
|
const ComponentType_1 = require("./types/ComponentType");
|
|
41
42
|
const types_1 = require("./types");
|
|
42
43
|
const BuiltInInterfaceAdder_1 = require("./types/BuiltInInterfaceAdder");
|
|
43
|
-
const startOfSourcePkgPath = `source${path.sep}`;
|
|
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,6 +50,10 @@ class Program {
|
|
|
50
50
|
*/
|
|
51
51
|
options, logger, plugins) {
|
|
52
52
|
this.options = options;
|
|
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();
|
|
53
57
|
/**
|
|
54
58
|
* A graph of all files and their dependencies.
|
|
55
59
|
* For example:
|
|
@@ -68,7 +72,16 @@ class Program {
|
|
|
68
72
|
* A map of every file loaded into this program, indexed by its original file location
|
|
69
73
|
*/
|
|
70
74
|
this.files = {};
|
|
71
|
-
|
|
75
|
+
/**
|
|
76
|
+
* A map of every file loaded into this program, indexed by its destPath
|
|
77
|
+
*/
|
|
78
|
+
this.destMap = new Map();
|
|
79
|
+
/**
|
|
80
|
+
* Plugins can contribute multiple virtual files for a single physical file.
|
|
81
|
+
* This collection links the virtual files back to the physical file that produced them.
|
|
82
|
+
* The key is the standardized and lower-cased srcPath
|
|
83
|
+
*/
|
|
84
|
+
this.fileClusters = new Map();
|
|
72
85
|
this.scopes = {};
|
|
73
86
|
/**
|
|
74
87
|
* A map of every component currently loaded into the program, indexed by the component name.
|
|
@@ -81,6 +94,8 @@ class Program {
|
|
|
81
94
|
* Keeps a set of all the components that need to have their types updated during the current validation cycle
|
|
82
95
|
*/
|
|
83
96
|
this.componentSymbolsToUpdate = new Set();
|
|
97
|
+
this.getTranspiledFileContentsPipeline = new ActionPipeline_1.ActionPipeline();
|
|
98
|
+
this.buildPipeline = new ActionPipeline_1.ActionPipeline();
|
|
84
99
|
this.options = util_1.util.normalizeConfig(options);
|
|
85
100
|
this.logger = logger || new Logger_1.Logger(options.logLevel);
|
|
86
101
|
this.plugins = plugins || new PluginInterface_1.default([], { logger: this.logger });
|
|
@@ -89,6 +104,7 @@ class Program {
|
|
|
89
104
|
//normalize the root dir path
|
|
90
105
|
this.options.rootDir = util_1.util.getRootDir(this.options);
|
|
91
106
|
this.createGlobalScope();
|
|
107
|
+
this.fileFactory = new Factory_1.FileFactory(this);
|
|
92
108
|
}
|
|
93
109
|
createGlobalScope() {
|
|
94
110
|
//create the 'global' scope
|
|
@@ -126,7 +142,7 @@ class Program {
|
|
|
126
142
|
this.globalScope.symbolTable.addSymbol(nodeName, { description: nodeData.description }, nodeType, SymbolTable_1.SymbolTypeFlag.typetime);
|
|
127
143
|
}
|
|
128
144
|
else {
|
|
129
|
-
nodeType = this.globalScope.symbolTable.getSymbolType(
|
|
145
|
+
nodeType = this.globalScope.symbolTable.getSymbolType(nodeName, { flags: SymbolTable_1.SymbolTypeFlag.typetime });
|
|
130
146
|
}
|
|
131
147
|
return nodeType;
|
|
132
148
|
}
|
|
@@ -182,7 +198,7 @@ class Program {
|
|
|
182
198
|
//default to the embedded version
|
|
183
199
|
}
|
|
184
200
|
else {
|
|
185
|
-
return
|
|
201
|
+
return `${this.options.bslibDestinationDir}${path.sep}bslib.brs`;
|
|
186
202
|
}
|
|
187
203
|
}
|
|
188
204
|
get bslibPrefix() {
|
|
@@ -203,7 +219,7 @@ class Program {
|
|
|
203
219
|
var _a;
|
|
204
220
|
if (componentName) {
|
|
205
221
|
//return the first compoment in the list with this name
|
|
206
|
-
//(components are ordered in this list by
|
|
222
|
+
//(components are ordered in this list by destPath to ensure consistency)
|
|
207
223
|
return (_a = this.components[componentName.toLowerCase()]) === null || _a === void 0 ? void 0 : _a[0];
|
|
208
224
|
}
|
|
209
225
|
else {
|
|
@@ -223,8 +239,8 @@ class Program {
|
|
|
223
239
|
scope: scope
|
|
224
240
|
});
|
|
225
241
|
this.components[key].sort((a, b) => {
|
|
226
|
-
const pathA = a.file.
|
|
227
|
-
const pathB = b.file.
|
|
242
|
+
const pathA = a.file.destPath.toLowerCase();
|
|
243
|
+
const pathB = b.file.destPath.toLowerCase();
|
|
228
244
|
if (pathA < pathB) {
|
|
229
245
|
return -1;
|
|
230
246
|
}
|
|
@@ -300,6 +316,7 @@ class Program {
|
|
|
300
316
|
//attach (or re-attach) the dependencyGraph for every component whose position changed
|
|
301
317
|
if (file.dependencyGraphIndex !== i) {
|
|
302
318
|
file.dependencyGraphIndex = i;
|
|
319
|
+
this.dependencyGraph.addOrReplace(file.dependencyGraphKey, file.dependencies);
|
|
303
320
|
file.attachDependencyGraph(this.dependencyGraph);
|
|
304
321
|
scope.attachDependencyGraph(this.dependencyGraph);
|
|
305
322
|
}
|
|
@@ -336,7 +353,7 @@ class Program {
|
|
|
336
353
|
//get the diagnostics from all unreferenced files
|
|
337
354
|
let unreferencedFiles = this.getUnreferencedFiles();
|
|
338
355
|
for (let file of unreferencedFiles) {
|
|
339
|
-
diagnostics.push(...file.
|
|
356
|
+
diagnostics.push(...file.diagnostics);
|
|
340
357
|
}
|
|
341
358
|
const filteredDiagnostics = this.logger.time(Logger_1.LogLevel.debug, ['filter diagnostics'], () => {
|
|
342
359
|
//filter out diagnostics based on our diagnostic filters
|
|
@@ -361,11 +378,9 @@ class Program {
|
|
|
361
378
|
hasFile(filePath, normalizePath = true) {
|
|
362
379
|
return !!this.getFile(filePath, normalizePath);
|
|
363
380
|
}
|
|
364
|
-
getPkgPath(...args) {
|
|
365
|
-
throw new Error('Not implemented');
|
|
366
|
-
}
|
|
367
381
|
/**
|
|
368
382
|
* roku filesystem is case INsensitive, so find the scope by key case insensitive
|
|
383
|
+
* @param scopeName xml scope names are their `destPath`. Source scope is stored with the key `"source"`
|
|
369
384
|
*/
|
|
370
385
|
getScopeByName(scopeName) {
|
|
371
386
|
if (!scopeName) {
|
|
@@ -394,8 +409,14 @@ class Program {
|
|
|
394
409
|
* Update internal maps with this file reference
|
|
395
410
|
*/
|
|
396
411
|
assignFile(file) {
|
|
412
|
+
const fileAddEvent = {
|
|
413
|
+
file: file,
|
|
414
|
+
program: this
|
|
415
|
+
};
|
|
416
|
+
this.plugins.emit('beforeFileAdd', fileAddEvent);
|
|
397
417
|
this.files[file.srcPath.toLowerCase()] = file;
|
|
398
|
-
this.
|
|
418
|
+
this.destMap.set(file.destPath.toLowerCase(), file);
|
|
419
|
+
this.plugins.emit('afterFileAdd', fileAddEvent);
|
|
399
420
|
return file;
|
|
400
421
|
}
|
|
401
422
|
/**
|
|
@@ -403,104 +424,102 @@ class Program {
|
|
|
403
424
|
*/
|
|
404
425
|
unassignFile(file) {
|
|
405
426
|
delete this.files[file.srcPath.toLowerCase()];
|
|
406
|
-
|
|
427
|
+
this.destMap.delete(file.destPath.toLowerCase());
|
|
407
428
|
return file;
|
|
408
429
|
}
|
|
409
|
-
setFile(fileParam,
|
|
430
|
+
setFile(fileParam, fileData) {
|
|
410
431
|
//normalize the file paths
|
|
411
|
-
const { srcPath,
|
|
432
|
+
const { srcPath, destPath } = this.getPaths(fileParam, this.options.rootDir);
|
|
412
433
|
let file = this.logger.time(Logger_1.LogLevel.debug, ['Program.setFile()', chalk_1.default.green(srcPath)], () => {
|
|
434
|
+
var _a, _b, _c;
|
|
413
435
|
//if the file is already loaded, remove it
|
|
414
436
|
if (this.hasFile(srcPath)) {
|
|
415
437
|
this.removeFile(srcPath);
|
|
416
438
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
source: fileContents
|
|
431
|
-
};
|
|
432
|
-
this.plugins.emit('beforeFileParse', beforeFileParseEvent);
|
|
433
|
-
this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
|
|
434
|
-
brsFile.parse(beforeFileParseEvent.source);
|
|
435
|
-
});
|
|
436
|
-
//notify plugins that this file has finished parsing
|
|
437
|
-
this.plugins.emit('afterFileParse', {
|
|
438
|
-
program: this,
|
|
439
|
-
file: brsFile
|
|
440
|
-
});
|
|
441
|
-
file = brsFile;
|
|
442
|
-
brsFile.attachDependencyGraph(this.dependencyGraph);
|
|
439
|
+
const data = new LazyFileData_1.LazyFileData(fileData);
|
|
440
|
+
const event = new ProvideFileEventInternal(this, srcPath, destPath, data, this.fileFactory);
|
|
441
|
+
this.plugins.emit('beforeProvideFile', event);
|
|
442
|
+
this.plugins.emit('provideFile', event);
|
|
443
|
+
this.plugins.emit('afterProvideFile', event);
|
|
444
|
+
//if no files were provided, create a AssetFile to represent it.
|
|
445
|
+
if (event.files.length === 0) {
|
|
446
|
+
event.files.push(this.fileFactory.AssetFile({
|
|
447
|
+
srcPath: event.srcPath,
|
|
448
|
+
destPath: event.destPath,
|
|
449
|
+
pkgPath: event.destPath,
|
|
450
|
+
data: data
|
|
451
|
+
}));
|
|
443
452
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
program: this,
|
|
453
|
-
srcPath: srcPath,
|
|
454
|
-
source: fileContents
|
|
455
|
-
};
|
|
456
|
-
this.plugins.emit('beforeFileParse', event);
|
|
457
|
-
this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
|
|
458
|
-
xmlFile.parse(event.source);
|
|
459
|
-
});
|
|
460
|
-
//notify plugins that this file has finished parsing
|
|
461
|
-
this.plugins.emit('afterFileParse', {
|
|
462
|
-
program: this,
|
|
463
|
-
file: xmlFile
|
|
464
|
-
});
|
|
465
|
-
file = xmlFile;
|
|
466
|
-
//create a new scope for this xml file
|
|
467
|
-
let scope = new XmlScope_1.XmlScope(xmlFile, this);
|
|
468
|
-
this.addScope(scope);
|
|
469
|
-
//register this component now that we have parsed it and know its component name
|
|
470
|
-
this.registerComponent(xmlFile, scope);
|
|
471
|
-
//notify plugins that the scope is created and the component is registered
|
|
472
|
-
this.plugins.emit('afterScopeCreate', {
|
|
473
|
-
program: this,
|
|
474
|
-
scope: scope
|
|
475
|
-
});
|
|
453
|
+
//find the file instance for the srcPath that triggered this action.
|
|
454
|
+
const primaryFile = event.files.find(x => x.srcPath === srcPath);
|
|
455
|
+
if (!primaryFile) {
|
|
456
|
+
throw new Error(`No file provided for srcPath '${srcPath}'. Instead, received ${JSON.stringify(event.files.map(x => ({
|
|
457
|
+
type: x.type,
|
|
458
|
+
srcPath: x.srcPath,
|
|
459
|
+
destPath: x.destPath
|
|
460
|
+
})))}`);
|
|
476
461
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
462
|
+
//link the virtual files to the primary file
|
|
463
|
+
this.fileClusters.set((_a = primaryFile.srcPath) === null || _a === void 0 ? void 0 : _a.toLowerCase(), event.files);
|
|
464
|
+
for (const file of event.files) {
|
|
465
|
+
file.srcPath = (0, util_1.standardizePath)(file.srcPath);
|
|
466
|
+
if (file.destPath) {
|
|
467
|
+
file.destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(file.destPath, this.options.rootDir, '')}`;
|
|
468
|
+
}
|
|
469
|
+
if (file.pkgPath) {
|
|
470
|
+
file.pkgPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(file.pkgPath, this.options.rootDir, '')}`;
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
file.pkgPath = file.destPath;
|
|
474
|
+
}
|
|
475
|
+
file.excludeFromOutput = file.excludeFromOutput === true;
|
|
476
|
+
//set the dependencyGraph key for every file to its destPath
|
|
477
|
+
file.dependencyGraphKey = file.destPath.toLowerCase();
|
|
478
|
+
this.assignFile(file);
|
|
479
|
+
//register a callback anytime this file's dependencies change
|
|
480
|
+
if (typeof file.onDependenciesChanged === 'function') {
|
|
481
|
+
(_b = file.disposables) !== null && _b !== void 0 ? _b : (file.disposables = []);
|
|
482
|
+
file.disposables.push(this.dependencyGraph.onchange(file.dependencyGraphKey, file.onDependenciesChanged.bind(file)));
|
|
483
|
+
}
|
|
484
|
+
//register this file (and its dependencies) with the dependency graph
|
|
485
|
+
this.dependencyGraph.addOrReplace(file.dependencyGraphKey, (_c = file.dependencies) !== null && _c !== void 0 ? _c : []);
|
|
486
|
+
//if this is a `source` file, add it to the source scope's dependency list
|
|
487
|
+
if (this.isSourceBrsFile(file)) {
|
|
488
|
+
this.createSourceScope();
|
|
489
|
+
this.dependencyGraph.addDependency('scope:source', file.dependencyGraphKey);
|
|
490
|
+
}
|
|
491
|
+
//if this is an xml file in the components folder, register it as a component
|
|
492
|
+
if (this.isComponentsXmlFile(file)) {
|
|
493
|
+
//create a new scope for this xml file
|
|
494
|
+
let scope = new XmlScope_1.XmlScope(file, this);
|
|
495
|
+
this.addScope(scope);
|
|
496
|
+
//register this compoent now that we have parsed it and know its component name
|
|
497
|
+
this.registerComponent(file, scope);
|
|
498
|
+
//notify plugins that the scope is created and the component is registered
|
|
499
|
+
this.plugins.emit('afterScopeCreate', {
|
|
500
|
+
program: this,
|
|
501
|
+
scope: scope
|
|
502
|
+
});
|
|
503
|
+
}
|
|
485
504
|
}
|
|
486
|
-
return
|
|
505
|
+
return primaryFile;
|
|
487
506
|
});
|
|
488
507
|
return file;
|
|
489
508
|
}
|
|
490
509
|
/**
|
|
491
|
-
* Given a srcPath, a
|
|
510
|
+
* Given a srcPath, a destPath, or both, resolve whichever is missing, relative to rootDir.
|
|
492
511
|
* @param fileParam an object representing file paths
|
|
493
512
|
* @param rootDir must be a pre-normalized path
|
|
494
513
|
*/
|
|
495
514
|
getPaths(fileParam, rootDir) {
|
|
496
515
|
let srcPath;
|
|
497
|
-
let
|
|
516
|
+
let destPath;
|
|
498
517
|
assert.ok(fileParam, 'fileParam is required');
|
|
499
|
-
//lift the
|
|
518
|
+
//lift the path vars from the incoming param
|
|
500
519
|
if (typeof fileParam === 'string') {
|
|
501
520
|
fileParam = this.removePkgPrefix(fileParam);
|
|
502
521
|
srcPath = (0, util_1.standardizePath) `${path.resolve(rootDir, fileParam)}`;
|
|
503
|
-
|
|
522
|
+
destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
|
|
504
523
|
}
|
|
505
524
|
else {
|
|
506
525
|
let param = fileParam;
|
|
@@ -511,30 +530,30 @@ class Program {
|
|
|
511
530
|
srcPath = (0, util_1.standardizePath) `${param.srcPath}`;
|
|
512
531
|
}
|
|
513
532
|
if (param.dest) {
|
|
514
|
-
|
|
533
|
+
destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.dest)}`;
|
|
515
534
|
}
|
|
516
535
|
if (param.pkgPath) {
|
|
517
|
-
|
|
536
|
+
destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.pkgPath)}`;
|
|
518
537
|
}
|
|
519
538
|
}
|
|
520
|
-
//if there's no srcPath, use the
|
|
539
|
+
//if there's no srcPath, use the destPath to build an absolute srcPath
|
|
521
540
|
if (!srcPath) {
|
|
522
|
-
srcPath = (0, util_1.standardizePath) `${rootDir}/${
|
|
541
|
+
srcPath = (0, util_1.standardizePath) `${rootDir}/${destPath}`;
|
|
523
542
|
}
|
|
524
543
|
//coerce srcPath to an absolute path
|
|
525
544
|
if (!path.isAbsolute(srcPath)) {
|
|
526
545
|
srcPath = util_1.util.standardizePath(srcPath);
|
|
527
546
|
}
|
|
528
|
-
//if
|
|
529
|
-
if (!
|
|
530
|
-
|
|
547
|
+
//if destPath isn't set, compute it from the other paths
|
|
548
|
+
if (!destPath) {
|
|
549
|
+
destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
|
|
531
550
|
}
|
|
532
551
|
assert.ok(srcPath, 'fileEntry.src is required');
|
|
533
|
-
assert.ok(
|
|
552
|
+
assert.ok(destPath, 'fileEntry.dest is required');
|
|
534
553
|
return {
|
|
535
554
|
srcPath: srcPath,
|
|
536
|
-
//remove leading slash
|
|
537
|
-
|
|
555
|
+
//remove leading slash
|
|
556
|
+
destPath: destPath.replace(/^[\/\\]+/, '')
|
|
538
557
|
};
|
|
539
558
|
}
|
|
540
559
|
/**
|
|
@@ -543,6 +562,18 @@ class Program {
|
|
|
543
562
|
removePkgPrefix(path) {
|
|
544
563
|
return path.replace(/^pkg:\//i, '');
|
|
545
564
|
}
|
|
565
|
+
/**
|
|
566
|
+
* Is this file a .brs file found somewhere within the `pkg:/source/` folder?
|
|
567
|
+
*/
|
|
568
|
+
isSourceBrsFile(file) {
|
|
569
|
+
return !!/^(pkg:\/)?source[\/\\]/.exec(file.destPath);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Is this file a .brs file found somewhere within the `pkg:/source/` folder?
|
|
573
|
+
*/
|
|
574
|
+
isComponentsXmlFile(file) {
|
|
575
|
+
return (0, reflection_1.isXmlFile)(file) && !!/^(pkg:\/)?components[\/\\]/.exec(file.destPath);
|
|
576
|
+
}
|
|
546
577
|
/**
|
|
547
578
|
* Ensure source scope is created.
|
|
548
579
|
* Note: automatically called internally, and no-op if it exists already.
|
|
@@ -570,46 +601,55 @@ class Program {
|
|
|
570
601
|
}
|
|
571
602
|
/**
|
|
572
603
|
* Remove a file from the program
|
|
573
|
-
* @param filePath can be a srcPath, a
|
|
604
|
+
* @param filePath can be a srcPath, a destPath, or a destPath with leading `pkg:/`
|
|
574
605
|
* @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
|
|
575
606
|
*/
|
|
576
607
|
removeFile(filePath, normalizePath = true) {
|
|
608
|
+
var _a, _b, _c, _d;
|
|
577
609
|
this.logger.debug('Program.removeFile()', filePath);
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
610
|
+
const paths = this.getPaths(filePath, this.options.rootDir);
|
|
611
|
+
//there can be one or more File entries for a single srcPath, so get all of them and remove them all
|
|
612
|
+
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)];
|
|
613
|
+
for (const file of files) {
|
|
614
|
+
//if a file has already been removed, nothing more needs to be done here
|
|
615
|
+
if (!file || !this.hasFile(file.srcPath)) {
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
const event = { file: file, program: this };
|
|
619
|
+
this.plugins.emit('beforeFileRemove', event);
|
|
585
620
|
//if there is a scope named the same as this file's path, remove it (i.e. xml scopes)
|
|
586
|
-
let scope = this.scopes[file.
|
|
621
|
+
let scope = this.scopes[file.destPath];
|
|
587
622
|
if (scope) {
|
|
588
623
|
const scopeDisposeEvent = {
|
|
589
624
|
program: this,
|
|
590
625
|
scope: scope
|
|
591
626
|
};
|
|
592
627
|
this.plugins.emit('beforeScopeDispose', scopeDisposeEvent);
|
|
628
|
+
this.plugins.emit('onScopeDispose', scopeDisposeEvent);
|
|
593
629
|
scope.dispose();
|
|
594
630
|
//notify dependencies of this scope that it has been removed
|
|
595
631
|
this.dependencyGraph.remove(scope.dependencyGraphKey);
|
|
596
|
-
delete this.scopes[file.
|
|
632
|
+
delete this.scopes[file.destPath];
|
|
597
633
|
this.plugins.emit('afterScopeDispose', scopeDisposeEvent);
|
|
598
634
|
}
|
|
599
635
|
//remove the file from the program
|
|
600
636
|
this.unassignFile(file);
|
|
601
637
|
this.dependencyGraph.remove(file.dependencyGraphKey);
|
|
602
638
|
//if this is a pkg:/source file, notify the `source` scope that it has changed
|
|
603
|
-
if (
|
|
639
|
+
if (this.isSourceBrsFile(file)) {
|
|
604
640
|
this.dependencyGraph.removeDependency('scope:source', file.dependencyGraphKey);
|
|
605
641
|
}
|
|
606
642
|
//if this is a component, remove it from our components map
|
|
607
643
|
if ((0, reflection_1.isXmlFile)(file)) {
|
|
608
644
|
this.unregisterComponent(file);
|
|
609
645
|
}
|
|
646
|
+
//dispose any disposable things on the file
|
|
647
|
+
for (const disposable of (_c = file === null || file === void 0 ? void 0 : file.disposables) !== null && _c !== void 0 ? _c : []) {
|
|
648
|
+
disposable();
|
|
649
|
+
}
|
|
610
650
|
//dispose file
|
|
611
|
-
file === null || file === void 0 ? void 0 : file.dispose();
|
|
612
|
-
this.plugins.emit('
|
|
651
|
+
(_d = file === null || file === void 0 ? void 0 : file.dispose) === null || _d === void 0 ? void 0 : _d.call(file);
|
|
652
|
+
this.plugins.emit('afterFileRemove', event);
|
|
613
653
|
}
|
|
614
654
|
}
|
|
615
655
|
/**
|
|
@@ -622,6 +662,7 @@ class Program {
|
|
|
622
662
|
program: this
|
|
623
663
|
};
|
|
624
664
|
this.plugins.emit('beforeProgramValidate', programValidateEvent);
|
|
665
|
+
this.plugins.emit('onProgramValidate', programValidateEvent);
|
|
625
666
|
//validate every file
|
|
626
667
|
for (const file of Object.values(this.files)) {
|
|
627
668
|
//for every unvalidated file, validate it
|
|
@@ -706,12 +747,13 @@ class Program {
|
|
|
706
747
|
getFile(filePath, normalizePath = true) {
|
|
707
748
|
if (typeof filePath !== 'string') {
|
|
708
749
|
return undefined;
|
|
750
|
+
//is the path absolute (or the `virtual:` prefix)
|
|
709
751
|
}
|
|
710
|
-
else if (
|
|
752
|
+
else if (/^(?:(?:virtual:[\/\\])|(?:\w:)|(?:[\/\\]))/gmi.exec(filePath)) {
|
|
711
753
|
return this.files[(normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase()];
|
|
712
754
|
}
|
|
713
755
|
else {
|
|
714
|
-
return this.
|
|
756
|
+
return this.destMap.get((normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase());
|
|
715
757
|
}
|
|
716
758
|
}
|
|
717
759
|
/**
|
|
@@ -753,7 +795,8 @@ class Program {
|
|
|
753
795
|
//look through all files in scope for matches
|
|
754
796
|
for (const scope of this.getScopesForFile(originFile)) {
|
|
755
797
|
for (const file of scope.getAllFiles()) {
|
|
756
|
-
|
|
798
|
+
//skip non-brs files, or files we've already processed
|
|
799
|
+
if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
|
|
757
800
|
continue;
|
|
758
801
|
}
|
|
759
802
|
filesSearched.add(file);
|
|
@@ -786,7 +829,8 @@ class Program {
|
|
|
786
829
|
}
|
|
787
830
|
//look through all files in scope for matches
|
|
788
831
|
for (const file of scope.getOwnFiles()) {
|
|
789
|
-
|
|
832
|
+
//skip non-brs files, or files we've already processed
|
|
833
|
+
if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
|
|
790
834
|
continue;
|
|
791
835
|
}
|
|
792
836
|
filesSearched.add(file);
|
|
@@ -935,10 +979,12 @@ class Program {
|
|
|
935
979
|
getReferences(srcPath, position) {
|
|
936
980
|
//find the file
|
|
937
981
|
let file = this.getFile(srcPath);
|
|
938
|
-
if (
|
|
982
|
+
if ((0, reflection_1.isBrsFile)(file) || (0, reflection_1.isXmlFile)(file)) {
|
|
983
|
+
return file.getReferences(position);
|
|
984
|
+
}
|
|
985
|
+
else {
|
|
939
986
|
return null;
|
|
940
987
|
}
|
|
941
|
-
return file.getReferences(position);
|
|
942
988
|
}
|
|
943
989
|
/**
|
|
944
990
|
* Transpile a single file and get the result as a string.
|
|
@@ -949,168 +995,211 @@ class Program {
|
|
|
949
995
|
* @param filePath can be a srcPath or a destPath
|
|
950
996
|
*/
|
|
951
997
|
async getTranspiledFileContents(filePath) {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
998
|
+
const file = this.getFile(filePath);
|
|
999
|
+
return this.getTranspiledFileContentsPipeline.run(async () => {
|
|
1000
|
+
const result = {
|
|
1001
|
+
destPath: file.destPath,
|
|
1002
|
+
pkgPath: file.pkgPath,
|
|
1003
|
+
srcPath: file.srcPath
|
|
1004
|
+
};
|
|
1005
|
+
const expectedPkgPath = file.pkgPath.toLowerCase();
|
|
1006
|
+
const expectedMapPath = `${expectedPkgPath}.map`;
|
|
1007
|
+
const expectedTypedefPkgPath = expectedPkgPath.replace(/\.brs$/i, '.d.bs');
|
|
1008
|
+
//add a temporary plugin to tap into the file writing process
|
|
1009
|
+
const plugin = this.plugins.addFirst({
|
|
1010
|
+
name: 'getTranspiledFileContents',
|
|
1011
|
+
beforeWriteFile: (event) => {
|
|
1012
|
+
const pkgPath = event.file.pkgPath.toLowerCase();
|
|
1013
|
+
switch (pkgPath) {
|
|
1014
|
+
//this is the actual transpiled file
|
|
1015
|
+
case expectedPkgPath:
|
|
1016
|
+
result.code = event.file.data.toString();
|
|
1017
|
+
break;
|
|
1018
|
+
//this is the sourcemap
|
|
1019
|
+
case expectedMapPath:
|
|
1020
|
+
result.map = event.file.data.toString();
|
|
1021
|
+
break;
|
|
1022
|
+
//this is the typedef
|
|
1023
|
+
case expectedTypedefPkgPath:
|
|
1024
|
+
result.typedef = event.file.data.toString();
|
|
1025
|
+
break;
|
|
1026
|
+
default:
|
|
1027
|
+
//no idea what this file is. just ignore it
|
|
1028
|
+
}
|
|
1029
|
+
//mark every file as processed so it they don't get written to the output directory
|
|
1030
|
+
event.processedFiles.add(event.file);
|
|
1031
|
+
}
|
|
1032
|
+
});
|
|
1033
|
+
try {
|
|
1034
|
+
//now that the plugin has been registered, run the build with just this file
|
|
1035
|
+
await this.build({
|
|
1036
|
+
files: [file]
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
finally {
|
|
1040
|
+
this.plugins.remove(plugin);
|
|
958
1041
|
}
|
|
1042
|
+
return result;
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Get the absolute output path for a file
|
|
1047
|
+
*/
|
|
1048
|
+
getOutputPath(file, stagingDir = this.getStagingDir()) {
|
|
1049
|
+
return (0, util_1.standardizePath) `${stagingDir}/${file.pkgPath}`;
|
|
1050
|
+
}
|
|
1051
|
+
getStagingDir(stagingDir) {
|
|
1052
|
+
var _a, _b;
|
|
1053
|
+
let result = (_a = stagingDir !== null && stagingDir !== void 0 ? stagingDir : this.options.stagingDir) !== null && _a !== void 0 ? _a : this.options.stagingDir;
|
|
1054
|
+
if (!result) {
|
|
1055
|
+
result = roku_deploy_1.rokuDeploy.getOptions(this.options).stagingDir;
|
|
959
1056
|
}
|
|
960
|
-
|
|
961
|
-
const result = this._getTranspiledFileContents(this.getFile(filePath));
|
|
962
|
-
this.afterProgramTranspile(entries, astEditor);
|
|
1057
|
+
result = (0, util_1.standardizePath) `${path.resolve((_b = this.options.cwd) !== null && _b !== void 0 ? _b : process.cwd(), result !== null && result !== void 0 ? result : '/')}`;
|
|
963
1058
|
return result;
|
|
964
1059
|
}
|
|
965
1060
|
/**
|
|
966
|
-
*
|
|
967
|
-
*
|
|
1061
|
+
* Prepare the program for building
|
|
1062
|
+
* @param files the list of files that should be prepared
|
|
968
1063
|
*/
|
|
969
|
-
|
|
970
|
-
const
|
|
971
|
-
this.plugins.emit('beforeFileTranspile', {
|
|
1064
|
+
async prepare(files) {
|
|
1065
|
+
const programEvent = {
|
|
972
1066
|
program: this,
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
editor: editor
|
|
976
|
-
});
|
|
977
|
-
//if we have any edits, assume the file needs to be transpiled
|
|
978
|
-
if (editor.hasChanges) {
|
|
979
|
-
//use the `editor` because it'll track the previous value for us and revert later on
|
|
980
|
-
editor.setProperty(file, 'needsTranspiled', true);
|
|
981
|
-
}
|
|
982
|
-
//transpile the file
|
|
983
|
-
const result = file.transpile();
|
|
984
|
-
//generate the typedef if enabled
|
|
985
|
-
let typedef;
|
|
986
|
-
if ((0, reflection_1.isBrsFile)(file) && this.options.emitDefinitions) {
|
|
987
|
-
typedef = file.getTypedef();
|
|
988
|
-
}
|
|
989
|
-
const event = {
|
|
990
|
-
program: this,
|
|
991
|
-
file: file,
|
|
992
|
-
outputPath: outputPath,
|
|
993
|
-
editor: editor,
|
|
994
|
-
code: result.code,
|
|
995
|
-
map: result.map,
|
|
996
|
-
typedef: typedef
|
|
1067
|
+
editor: this.editor,
|
|
1068
|
+
files: files
|
|
997
1069
|
};
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
pkgPath: file.pkgPath,
|
|
1004
|
-
code: event.code,
|
|
1005
|
-
map: event.map,
|
|
1006
|
-
typedef: event.typedef
|
|
1007
|
-
};
|
|
1008
|
-
}
|
|
1009
|
-
beforeProgramTranspile(fileEntries, stagingDir) {
|
|
1010
|
-
// map fileEntries using their path as key, to avoid excessive "find()" operations
|
|
1011
|
-
const mappedFileEntries = fileEntries.reduce((collection, entry) => {
|
|
1012
|
-
collection[(0, util_1.standardizePath) `${entry.src}`] = entry;
|
|
1013
|
-
return collection;
|
|
1014
|
-
}, {});
|
|
1015
|
-
const getOutputPath = (file) => {
|
|
1016
|
-
let filePathObj = mappedFileEntries[(0, util_1.standardizePath) `${file.srcPath}`];
|
|
1017
|
-
if (!filePathObj) {
|
|
1018
|
-
//this file has been added in-memory, from a plugin, for example
|
|
1019
|
-
filePathObj = {
|
|
1020
|
-
//add an interpolated src path (since it doesn't actually exist in memory)
|
|
1021
|
-
src: `bsc:/${file.pkgPath}`,
|
|
1022
|
-
dest: file.pkgPath
|
|
1023
|
-
};
|
|
1070
|
+
//assign an editor to every file
|
|
1071
|
+
for (const file of files) {
|
|
1072
|
+
//if the file doesn't have an editor yet, assign one now
|
|
1073
|
+
if (!file.editor) {
|
|
1074
|
+
file.editor = new Editor_1.Editor();
|
|
1024
1075
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1076
|
+
}
|
|
1077
|
+
files.sort((a, b) => {
|
|
1078
|
+
if (a.pkgPath < b.pkgPath) {
|
|
1079
|
+
return -1;
|
|
1080
|
+
}
|
|
1081
|
+
else if (a.pkgPath > b.pkgPath) {
|
|
1082
|
+
return 1;
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
return 1;
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
1088
|
+
await this.plugins.emitAsync('beforePrepareProgram', programEvent);
|
|
1089
|
+
await this.plugins.emitAsync('prepareProgram', programEvent);
|
|
1090
|
+
const stagingDir = this.getStagingDir();
|
|
1091
|
+
const entries = [];
|
|
1092
|
+
for (const file of files) {
|
|
1093
|
+
//if the file doesn't have an editor yet, assign one now
|
|
1094
|
+
if (!file.editor) {
|
|
1095
|
+
file.editor = new Editor_1.Editor();
|
|
1096
|
+
}
|
|
1097
|
+
const event = {
|
|
1098
|
+
program: this,
|
|
1033
1099
|
file: file,
|
|
1034
|
-
|
|
1100
|
+
editor: file.editor,
|
|
1101
|
+
outputPath: this.getOutputPath(file, stagingDir)
|
|
1035
1102
|
};
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1103
|
+
await this.plugins.emitAsync('beforePrepareFile', event);
|
|
1104
|
+
await this.plugins.emitAsync('prepareFile', event);
|
|
1105
|
+
await this.plugins.emitAsync('afterPrepareFile', event);
|
|
1106
|
+
//TODO remove this in v1
|
|
1107
|
+
entries.push(event);
|
|
1108
|
+
}
|
|
1109
|
+
await this.plugins.emitAsync('afterPrepareProgram', programEvent);
|
|
1110
|
+
return files;
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Generate the contents of every file
|
|
1114
|
+
*/
|
|
1115
|
+
async serialize(files) {
|
|
1116
|
+
const allFiles = new Map();
|
|
1117
|
+
const serializeProgramEvent = await this.plugins.emitAsync('beforeSerializeProgram', {
|
|
1118
|
+
program: this,
|
|
1119
|
+
files: files,
|
|
1120
|
+
result: allFiles
|
|
1039
1121
|
});
|
|
1040
|
-
|
|
1041
|
-
this.plugins.emit('beforeProgramTranspile', {
|
|
1122
|
+
await this.plugins.emitAsync('onSerializeProgram', {
|
|
1042
1123
|
program: this,
|
|
1043
|
-
|
|
1044
|
-
|
|
1124
|
+
files: files,
|
|
1125
|
+
result: allFiles
|
|
1045
1126
|
});
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
astEditor: astEditor
|
|
1050
|
-
};
|
|
1051
|
-
}
|
|
1052
|
-
async transpile(fileEntries, stagingDir) {
|
|
1053
|
-
const { entries, getOutputPath, astEditor } = this.beforeProgramTranspile(fileEntries, stagingDir);
|
|
1054
|
-
const processedFiles = new Set();
|
|
1055
|
-
const transpileFile = async (srcPath, outputPath) => {
|
|
1056
|
-
//find the file in the program
|
|
1057
|
-
const file = this.getFile(srcPath);
|
|
1058
|
-
//mark this file as processed so we don't process it more than once
|
|
1059
|
-
processedFiles.add(outputPath === null || outputPath === void 0 ? void 0 : outputPath.toLowerCase());
|
|
1060
|
-
//skip transpiling typedef files
|
|
1061
|
-
if ((0, reflection_1.isBrsFile)(file) && file.isTypedef) {
|
|
1062
|
-
return;
|
|
1063
|
-
}
|
|
1064
|
-
const fileTranspileResult = this._getTranspiledFileContents(file, outputPath);
|
|
1065
|
-
//make sure the full dir path exists
|
|
1066
|
-
await fsExtra.ensureDir(path.dirname(outputPath));
|
|
1067
|
-
if (await fsExtra.pathExists(outputPath)) {
|
|
1068
|
-
throw new Error(`Error while transpiling "${file.srcPath}". A file already exists at "${outputPath}" and will not be overwritten.`);
|
|
1069
|
-
}
|
|
1070
|
-
const writeMapPromise = fileTranspileResult.map ? fsExtra.writeFile(`${outputPath}.map`, fileTranspileResult.map.toString()) : null;
|
|
1071
|
-
await Promise.all([
|
|
1072
|
-
fsExtra.writeFile(outputPath, fileTranspileResult.code),
|
|
1073
|
-
writeMapPromise
|
|
1074
|
-
]);
|
|
1075
|
-
if (fileTranspileResult.typedef) {
|
|
1076
|
-
const typedefPath = outputPath.replace(/\.brs$/i, '.d.bs');
|
|
1077
|
-
await fsExtra.writeFile(typedefPath, fileTranspileResult.typedef);
|
|
1078
|
-
}
|
|
1079
|
-
};
|
|
1080
|
-
let promises = entries.map(async (entry) => {
|
|
1081
|
-
var _a;
|
|
1082
|
-
return transpileFile((_a = entry === null || entry === void 0 ? void 0 : entry.file) === null || _a === void 0 ? void 0 : _a.srcPath, entry.outputPath);
|
|
1127
|
+
//sort the entries to make transpiling more deterministic
|
|
1128
|
+
files = serializeProgramEvent.files.sort((a, b) => {
|
|
1129
|
+
return a.srcPath < b.srcPath ? -1 : 1;
|
|
1083
1130
|
});
|
|
1084
|
-
//
|
|
1085
|
-
|
|
1086
|
-
|
|
1131
|
+
// serialize each file
|
|
1132
|
+
for (const file of files) {
|
|
1133
|
+
const event = {
|
|
1134
|
+
program: this,
|
|
1135
|
+
file: file,
|
|
1136
|
+
result: allFiles
|
|
1137
|
+
};
|
|
1138
|
+
await this.plugins.emitAsync('beforeSerializeFile', event);
|
|
1139
|
+
await this.plugins.emitAsync('serializeFile', event);
|
|
1140
|
+
await this.plugins.emitAsync('afterSerializeFile', event);
|
|
1087
1141
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
//this is a new file
|
|
1095
|
-
const outputPath = getOutputPath(file);
|
|
1096
|
-
if (!processedFiles.has(outputPath === null || outputPath === void 0 ? void 0 : outputPath.toLowerCase())) {
|
|
1097
|
-
promises.push(transpileFile(file === null || file === void 0 ? void 0 : file.srcPath, outputPath));
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
if (promises.length > 0) {
|
|
1101
|
-
this.logger.info(`Transpiling ${promises.length} new files`);
|
|
1102
|
-
await Promise.all(promises);
|
|
1103
|
-
}
|
|
1104
|
-
} while (promises.length > 0);
|
|
1105
|
-
this.afterProgramTranspile(entries, astEditor);
|
|
1142
|
+
this.plugins.emit('afterSerializeProgram', {
|
|
1143
|
+
program: this,
|
|
1144
|
+
files: files,
|
|
1145
|
+
result: allFiles
|
|
1146
|
+
});
|
|
1147
|
+
return allFiles;
|
|
1106
1148
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1149
|
+
/**
|
|
1150
|
+
* Write the entire project to disk
|
|
1151
|
+
*/
|
|
1152
|
+
async write(stagingDir, files) {
|
|
1153
|
+
const programEvent = await this.plugins.emitAsync('beforeWriteProgram', {
|
|
1109
1154
|
program: this,
|
|
1110
|
-
|
|
1111
|
-
|
|
1155
|
+
files: files,
|
|
1156
|
+
stagingDir: stagingDir
|
|
1157
|
+
});
|
|
1158
|
+
//empty the staging directory
|
|
1159
|
+
await fsExtra.emptyDir(stagingDir);
|
|
1160
|
+
const serializedFiles = [...files]
|
|
1161
|
+
.map(([, serializedFiles]) => serializedFiles)
|
|
1162
|
+
.flat();
|
|
1163
|
+
//write all the files to disk (asynchronously)
|
|
1164
|
+
await Promise.all(serializedFiles.map(async (file) => {
|
|
1165
|
+
const event = await this.plugins.emitAsync('beforeWriteFile', {
|
|
1166
|
+
program: this,
|
|
1167
|
+
file: file,
|
|
1168
|
+
outputPath: this.getOutputPath(file, stagingDir),
|
|
1169
|
+
processedFiles: new Set()
|
|
1170
|
+
});
|
|
1171
|
+
await this.plugins.emitAsync('writeFile', event);
|
|
1172
|
+
await this.plugins.emitAsync('afterWriteFile', event);
|
|
1173
|
+
}));
|
|
1174
|
+
await this.plugins.emitAsync('afterWriteProgram', programEvent);
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Build the project. This transpiles/transforms/copies all files and moves them to the staging directory
|
|
1178
|
+
* @param options the list of options used to build the program
|
|
1179
|
+
*/
|
|
1180
|
+
async build(options) {
|
|
1181
|
+
//run a single build at a time
|
|
1182
|
+
await this.buildPipeline.run(async () => {
|
|
1183
|
+
var _a;
|
|
1184
|
+
const stagingDir = this.getStagingDir(options === null || options === void 0 ? void 0 : options.stagingDir);
|
|
1185
|
+
const event = await this.plugins.emitAsync('beforeBuildProgram', {
|
|
1186
|
+
program: this,
|
|
1187
|
+
editor: this.editor,
|
|
1188
|
+
files: (_a = options === null || options === void 0 ? void 0 : options.files) !== null && _a !== void 0 ? _a : Object.values(this.files)
|
|
1189
|
+
});
|
|
1190
|
+
//prepare the program (and files) for building
|
|
1191
|
+
event.files = await this.prepare(event.files);
|
|
1192
|
+
//stage the entire program
|
|
1193
|
+
const serializedFilesByFile = await this.serialize(event.files);
|
|
1194
|
+
await this.write(stagingDir, serializedFilesByFile);
|
|
1195
|
+
await this.plugins.emitAsync('afterBuildProgram', event);
|
|
1196
|
+
//undo all edits for the program
|
|
1197
|
+
this.editor.undoAll();
|
|
1198
|
+
//undo all edits for each file
|
|
1199
|
+
for (const file of event.files) {
|
|
1200
|
+
file.editor.undoAll();
|
|
1201
|
+
}
|
|
1112
1202
|
});
|
|
1113
|
-
astEditor.undoAll();
|
|
1114
1203
|
}
|
|
1115
1204
|
/**
|
|
1116
1205
|
* Find a list of files in the program that have a function with the given name (case INsensitive)
|
|
@@ -1185,6 +1274,7 @@ class Program {
|
|
|
1185
1274
|
* Get a map of the manifest information
|
|
1186
1275
|
*/
|
|
1187
1276
|
getManifest() {
|
|
1277
|
+
var _a, _b;
|
|
1188
1278
|
if (!this._manifest) {
|
|
1189
1279
|
//load the manifest file.
|
|
1190
1280
|
//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
|
|
@@ -1193,7 +1283,27 @@ class Program {
|
|
|
1193
1283
|
try {
|
|
1194
1284
|
//we only load this manifest once, so do it sync to improve speed downstream
|
|
1195
1285
|
contents = fsExtra.readFileSync(manifestPath, 'utf-8');
|
|
1196
|
-
|
|
1286
|
+
let parsedManifest = (0, Manifest_1.parseManifest)(contents);
|
|
1287
|
+
// Lift the bs_consts defined in the manifest
|
|
1288
|
+
let bsConsts = (0, Manifest_1.getBsConst)(parsedManifest, false);
|
|
1289
|
+
// Override or delete any bs_consts defined in the bs config
|
|
1290
|
+
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) {
|
|
1291
|
+
const value = this.options.manifest.bs_const[key];
|
|
1292
|
+
if (value === null) {
|
|
1293
|
+
bsConsts.delete(key);
|
|
1294
|
+
}
|
|
1295
|
+
else {
|
|
1296
|
+
bsConsts.set(key, value);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
// convert the new list of bs consts back into a string for the rest of the down stream systems to use
|
|
1300
|
+
let constString = '';
|
|
1301
|
+
for (const [key, value] of bsConsts) {
|
|
1302
|
+
constString += `${constString !== '' ? ';' : ''}${key}=${value.toString()}`;
|
|
1303
|
+
}
|
|
1304
|
+
// Set the updated bs_const value
|
|
1305
|
+
parsedManifest.set('bs_const', constString);
|
|
1306
|
+
this._manifest = parsedManifest;
|
|
1197
1307
|
}
|
|
1198
1308
|
catch (err) {
|
|
1199
1309
|
this._manifest = new Map();
|
|
@@ -1202,16 +1312,29 @@ class Program {
|
|
|
1202
1312
|
return this._manifest;
|
|
1203
1313
|
}
|
|
1204
1314
|
dispose() {
|
|
1315
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1205
1316
|
this.plugins.emit('beforeProgramDispose', { program: this });
|
|
1206
1317
|
for (let filePath in this.files) {
|
|
1207
|
-
this.files[filePath].dispose();
|
|
1318
|
+
(_b = (_a = this.files[filePath]) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1208
1319
|
}
|
|
1209
1320
|
for (let name in this.scopes) {
|
|
1210
|
-
this.scopes[name].dispose();
|
|
1321
|
+
(_d = (_c = this.scopes[name]) === null || _c === void 0 ? void 0 : _c.dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
1211
1322
|
}
|
|
1212
|
-
this.globalScope.dispose();
|
|
1213
|
-
this.dependencyGraph.dispose();
|
|
1323
|
+
(_f = (_e = this.globalScope) === null || _e === void 0 ? void 0 : _e.dispose) === null || _f === void 0 ? void 0 : _f.call(_e);
|
|
1324
|
+
(_h = (_g = this.dependencyGraph) === null || _g === void 0 ? void 0 : _g.dispose) === null || _h === void 0 ? void 0 : _h.call(_g);
|
|
1214
1325
|
}
|
|
1215
1326
|
}
|
|
1216
1327
|
exports.Program = Program;
|
|
1328
|
+
class ProvideFileEventInternal {
|
|
1329
|
+
constructor(program, srcPath, destPath, data, fileFactory) {
|
|
1330
|
+
var _a;
|
|
1331
|
+
this.program = program;
|
|
1332
|
+
this.srcPath = srcPath;
|
|
1333
|
+
this.destPath = destPath;
|
|
1334
|
+
this.data = data;
|
|
1335
|
+
this.fileFactory = fileFactory;
|
|
1336
|
+
this.files = [];
|
|
1337
|
+
this.srcExtension = (_a = path.extname(srcPath)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1217
1340
|
//# sourceMappingURL=Program.js.map
|