@spyglassmc/core 0.1.2 → 0.2.0
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/README.md +7 -0
- package/lib/browser.d.ts +2 -0
- package/lib/browser.js +2 -0
- package/lib/common/TwoWayMap.js +4 -10
- package/lib/common/externals/BrowserExternals.d.ts +3 -0
- package/lib/common/externals/BrowserExternals.js +191 -0
- package/lib/common/externals/NodeJsExternals.d.ts +3 -0
- package/lib/common/externals/NodeJsExternals.js +151 -0
- package/lib/common/externals/downloader.d.ts +31 -0
- package/lib/common/externals/downloader.js +32 -0
- package/lib/common/externals/index.d.ts +96 -0
- package/lib/common/externals/index.js +2 -0
- package/lib/common/index.d.ts +2 -1
- package/lib/common/index.js +2 -17
- package/lib/common/util.d.ts +15 -15
- package/lib/common/util.js +30 -77
- package/lib/index.d.ts +7 -7
- package/lib/index.js +7 -23
- package/lib/node/AstNode.d.ts +3 -3
- package/lib/node/AstNode.js +10 -16
- package/lib/node/BooleanNode.d.ts +2 -2
- package/lib/node/BooleanNode.js +4 -7
- package/lib/node/CommentNode.d.ts +1 -1
- package/lib/node/CommentNode.js +2 -5
- package/lib/node/ErrorNode.d.ts +1 -1
- package/lib/node/ErrorNode.js +2 -5
- package/lib/node/FileNode.d.ts +3 -3
- package/lib/node/FileNode.js +2 -5
- package/lib/node/FloatNode.d.ts +2 -2
- package/lib/node/FloatNode.js +4 -7
- package/lib/node/IntegerNode.d.ts +2 -2
- package/lib/node/IntegerNode.js +4 -7
- package/lib/node/ListNode.d.ts +2 -2
- package/lib/node/ListNode.js +2 -5
- package/lib/node/LiteralNode.d.ts +3 -3
- package/lib/node/LiteralNode.js +4 -7
- package/lib/node/LongNode.d.ts +2 -2
- package/lib/node/LongNode.js +4 -7
- package/lib/node/RecordNode.d.ts +2 -2
- package/lib/node/RecordNode.js +2 -5
- package/lib/node/ResourceLocationNode.d.ts +5 -5
- package/lib/node/ResourceLocationNode.js +9 -12
- package/lib/node/Sequence.d.ts +2 -2
- package/lib/node/Sequence.js +4 -7
- package/lib/node/StringNode.d.ts +4 -4
- package/lib/node/StringNode.js +9 -12
- package/lib/node/SymbolNode.d.ts +3 -3
- package/lib/node/SymbolNode.js +4 -7
- package/lib/node/index.d.ts +15 -15
- package/lib/node/index.js +15 -31
- package/lib/nodejs.d.ts +2 -0
- package/lib/nodejs.js +2 -0
- package/lib/parser/Parser.d.ts +3 -3
- package/lib/parser/Parser.js +1 -4
- package/lib/parser/boolean.d.ts +2 -2
- package/lib/parser/boolean.js +3 -6
- package/lib/parser/comment.d.ts +2 -2
- package/lib/parser/comment.js +5 -9
- package/lib/parser/empty.d.ts +1 -1
- package/lib/parser/empty.js +1 -5
- package/lib/parser/error.d.ts +2 -2
- package/lib/parser/error.js +5 -9
- package/lib/parser/file.d.ts +3 -3
- package/lib/parser/file.js +9 -13
- package/lib/parser/float.d.ts +4 -4
- package/lib/parser/float.js +12 -16
- package/lib/parser/index.d.ts +16 -16
- package/lib/parser/index.js +16 -38
- package/lib/parser/integer.d.ts +4 -4
- package/lib/parser/integer.js +10 -14
- package/lib/parser/list.d.ts +2 -2
- package/lib/parser/list.js +15 -19
- package/lib/parser/literal.d.ts +2 -2
- package/lib/parser/literal.js +5 -9
- package/lib/parser/long.d.ts +4 -4
- package/lib/parser/long.js +10 -14
- package/lib/parser/record.d.ts +3 -3
- package/lib/parser/record.js +20 -24
- package/lib/parser/resourceLocation.d.ts +2 -2
- package/lib/parser/resourceLocation.js +14 -18
- package/lib/parser/string.d.ts +5 -5
- package/lib/parser/string.js +36 -42
- package/lib/parser/symbol.d.ts +3 -3
- package/lib/parser/symbol.js +3 -7
- package/lib/parser/util.d.ts +5 -5
- package/lib/parser/util.js +38 -56
- package/lib/processor/ColorInfoProvider.d.ts +1 -1
- package/lib/processor/ColorInfoProvider.js +6 -9
- package/lib/processor/InlayHintProvider.d.ts +2 -2
- package/lib/processor/InlayHintProvider.js +1 -2
- package/lib/processor/SignatureHelpProvider.d.ts +2 -2
- package/lib/processor/SignatureHelpProvider.js +1 -2
- package/lib/processor/checker/Checker.d.ts +2 -2
- package/lib/processor/checker/Checker.js +1 -5
- package/lib/processor/checker/builtin.d.ts +4 -4
- package/lib/processor/checker/builtin.js +19 -30
- package/lib/processor/checker/index.d.ts +2 -2
- package/lib/processor/checker/index.js +2 -31
- package/lib/processor/colorizer/Colorizer.d.ts +4 -4
- package/lib/processor/colorizer/Colorizer.js +8 -11
- package/lib/processor/colorizer/builtin.d.ts +3 -3
- package/lib/processor/colorizer/builtin.js +33 -46
- package/lib/processor/colorizer/index.d.ts +2 -2
- package/lib/processor/colorizer/index.js +2 -31
- package/lib/processor/completer/Completer.d.ts +4 -4
- package/lib/processor/completer/Completer.js +14 -33
- package/lib/processor/completer/builtin.d.ts +7 -7
- package/lib/processor/completer/builtin.js +46 -62
- package/lib/processor/completer/index.d.ts +2 -2
- package/lib/processor/completer/index.js +2 -31
- package/lib/processor/formatter/Formatter.d.ts +2 -2
- package/lib/processor/formatter/Formatter.js +2 -7
- package/lib/processor/formatter/builtin.d.ts +3 -3
- package/lib/processor/formatter/builtin.js +22 -36
- package/lib/processor/formatter/index.d.ts +2 -2
- package/lib/processor/formatter/index.js +2 -31
- package/lib/processor/index.d.ts +9 -9
- package/lib/processor/index.js +9 -25
- package/lib/processor/linter/Linter.d.ts +2 -2
- package/lib/processor/linter/Linter.js +1 -2
- package/lib/processor/linter/builtin/undeclaredSymbol.d.ts +2 -2
- package/lib/processor/linter/builtin/undeclaredSymbol.js +20 -24
- package/lib/processor/linter/builtin.d.ts +3 -3
- package/lib/processor/linter/builtin.js +19 -26
- package/lib/processor/linter/index.d.ts +2 -2
- package/lib/processor/linter/index.js +2 -31
- package/lib/processor/util.d.ts +2 -2
- package/lib/processor/util.js +4 -9
- package/lib/service/CacheService.d.ts +6 -6
- package/lib/service/CacheService.js +32 -56
- package/lib/service/Config.d.ts +11 -12
- package/lib/service/Config.js +50 -45
- package/lib/service/Context.d.ts +13 -13
- package/lib/service/Context.js +29 -32
- package/lib/service/Dependency.js +2 -5
- package/lib/service/Downloader.d.ts +10 -40
- package/lib/service/Downloader.js +37 -110
- package/lib/service/ErrorReporter.d.ts +2 -2
- package/lib/service/ErrorReporter.js +10 -14
- package/lib/service/FileService.d.ts +16 -14
- package/lib/service/FileService.js +55 -92
- package/lib/service/Hover.d.ts +2 -2
- package/lib/service/Hover.js +4 -7
- package/lib/service/Logger.js +2 -5
- package/lib/service/MetaRegistry.d.ts +12 -12
- package/lib/service/MetaRegistry.js +62 -73
- package/lib/service/Operations.js +3 -9
- package/lib/service/Profiler.d.ts +1 -1
- package/lib/service/Profiler.js +25 -41
- package/lib/service/Project.d.ts +47 -51
- package/lib/service/Project.js +199 -239
- package/lib/service/Service.d.ts +17 -27
- package/lib/service/Service.js +37 -43
- package/lib/service/SymbolLocations.d.ts +3 -3
- package/lib/service/SymbolLocations.js +4 -7
- package/lib/service/SymbolRegistrar.d.ts +1 -1
- package/lib/service/SymbolRegistrar.js +1 -2
- package/lib/service/fileUtil.d.ts +15 -45
- package/lib/service/fileUtil.js +38 -143
- package/lib/service/index.d.ts +17 -17
- package/lib/service/index.js +17 -35
- package/lib/source/IndexMap.d.ts +1 -1
- package/lib/source/IndexMap.js +7 -10
- package/lib/source/LanguageError.d.ts +2 -2
- package/lib/source/LanguageError.js +2 -5
- package/lib/source/Location.d.ts +3 -3
- package/lib/source/Location.js +6 -9
- package/lib/source/Offset.d.ts +1 -1
- package/lib/source/Offset.js +4 -7
- package/lib/source/Position.js +2 -5
- package/lib/source/PositionRange.d.ts +2 -2
- package/lib/source/PositionRange.js +14 -17
- package/lib/source/Range.d.ts +1 -1
- package/lib/source/Range.js +7 -10
- package/lib/source/Source.d.ts +3 -3
- package/lib/source/Source.js +28 -29
- package/lib/source/index.d.ts +8 -8
- package/lib/source/index.js +8 -24
- package/lib/symbol/Symbol.d.ts +2 -2
- package/lib/symbol/Symbol.js +49 -65
- package/lib/symbol/SymbolUtil.d.ts +22 -25
- package/lib/symbol/SymbolUtil.js +150 -151
- package/lib/symbol/UriBinder.d.ts +1 -1
- package/lib/symbol/UriBinder.js +1 -2
- package/lib/symbol/index.d.ts +3 -3
- package/lib/symbol/index.js +3 -19
- package/package.json +7 -4
package/lib/service/Project.js
CHANGED
|
@@ -1,125 +1,141 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
2
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
3
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
6
|
};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const events_1 = __importDefault(require("events"));
|
|
27
|
-
const p_limit_1 = __importDefault(require("p-limit"));
|
|
28
|
-
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
|
|
29
|
-
const _1 = require(".");
|
|
30
|
-
const common_1 = require("../common");
|
|
31
|
-
const node_1 = require("../node");
|
|
32
|
-
const parser_1 = require("../parser");
|
|
33
|
-
const processor_1 = require("../processor");
|
|
34
|
-
const source_1 = require("../source");
|
|
35
|
-
const symbol_1 = require("../symbol");
|
|
36
|
-
const CacheService_1 = require("./CacheService");
|
|
37
|
-
const Config_1 = require("./Config");
|
|
38
|
-
const Context_1 = require("./Context");
|
|
39
|
-
const Dependency_1 = require("./Dependency");
|
|
40
|
-
const Downloader_1 = require("./Downloader");
|
|
41
|
-
const ErrorReporter_1 = require("./ErrorReporter");
|
|
42
|
-
const FileService_1 = require("./FileService");
|
|
43
|
-
const fileUtil_1 = require("./fileUtil");
|
|
44
|
-
const Logger_1 = require("./Logger");
|
|
45
|
-
const MetaRegistry_1 = require("./MetaRegistry");
|
|
46
|
-
const Profiler_1 = require("./Profiler");
|
|
7
|
+
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
8
|
+
import { bufferToString, CachePromise } from '../common/index.js';
|
|
9
|
+
import { FileNode } from '../node/index.js';
|
|
10
|
+
import { file } from '../parser/index.js';
|
|
11
|
+
import { traversePreOrder } from '../processor/index.js';
|
|
12
|
+
import { Source } from '../source/index.js';
|
|
13
|
+
import { SymbolUtil } from '../symbol/index.js';
|
|
14
|
+
import { CacheService } from './CacheService.js';
|
|
15
|
+
import { ConfigService, LinterConfigValue } from './Config.js';
|
|
16
|
+
import { CheckerContext, LinterContext, ParserContext, UriBinderContext } from './Context.js';
|
|
17
|
+
import { DependencyKey } from './Dependency.js';
|
|
18
|
+
import { Downloader } from './Downloader.js';
|
|
19
|
+
import { LinterErrorReporter } from './ErrorReporter.js';
|
|
20
|
+
import { ArchiveUriSupporter, FileService, FileUriSupporter } from './FileService.js';
|
|
21
|
+
import { fileUtil } from './fileUtil.js';
|
|
22
|
+
import { Logger } from './Logger.js';
|
|
23
|
+
import { MetaRegistry } from './MetaRegistry.js';
|
|
24
|
+
import { ProfilerFactory } from './Profiler.js';
|
|
47
25
|
const CacheAutoSaveInterval = 600000; // 10 Minutes.
|
|
48
|
-
var ProjectData;
|
|
49
|
-
(function (ProjectData) {
|
|
50
|
-
function mock(data = {}) {
|
|
51
|
-
const cacheRoot = data.cacheRoot ?? '/some/random/garbage/path/that/definitely/does/not/exist';
|
|
52
|
-
const logger = data.logger ?? Logger_1.Logger.create();
|
|
53
|
-
const downloader = data.downloader ?? new Downloader_1.Downloader(cacheRoot, logger, _1.LowLevelDownloader.mock({ fixtures: {} }));
|
|
54
|
-
return {
|
|
55
|
-
cacheRoot,
|
|
56
|
-
config: data.config ?? Config_1.VanillaConfig,
|
|
57
|
-
ctx: data.ctx ?? {},
|
|
58
|
-
downloader,
|
|
59
|
-
ensureParsedAndChecked: data.ensureParsedAndChecked,
|
|
60
|
-
fs: data.fs ?? FileService_1.FileService.create('file:///cache/'),
|
|
61
|
-
get: data.get ?? (() => undefined),
|
|
62
|
-
logger,
|
|
63
|
-
meta: data.meta ?? new MetaRegistry_1.MetaRegistry(),
|
|
64
|
-
profilers: data.profilers ?? Profiler_1.ProfilerFactory.noop(),
|
|
65
|
-
projectRoot: data.projectRoot ?? 'file:///',
|
|
66
|
-
roots: data.roots ?? [],
|
|
67
|
-
symbols: data.symbols ?? new symbol_1.SymbolUtil({}),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
ProjectData.mock = mock;
|
|
71
|
-
})(ProjectData = exports.ProjectData || (exports.ProjectData = {}));
|
|
72
26
|
/* istanbul ignore next */
|
|
73
27
|
/**
|
|
74
28
|
* Manage all tracked documents and errors.
|
|
75
29
|
*/
|
|
76
|
-
class Project
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
30
|
+
export class Project {
|
|
31
|
+
static RootSuffix = '/pack.mcmeta';
|
|
32
|
+
#cacheSaverIntervalId;
|
|
33
|
+
cacheService;
|
|
34
|
+
/**
|
|
35
|
+
* URI of files that are currently managed by the language client.
|
|
36
|
+
*/
|
|
37
|
+
#clientManagedUris = new Set();
|
|
38
|
+
#configService;
|
|
39
|
+
#docAndNodes = new Map();
|
|
40
|
+
#eventEmitter;
|
|
41
|
+
#initializers;
|
|
42
|
+
#initPromise;
|
|
43
|
+
#readyPromise;
|
|
44
|
+
#watchedFiles = new Set();
|
|
45
|
+
#watcher;
|
|
46
|
+
#watcherReady = false;
|
|
47
|
+
#isReady = false;
|
|
48
|
+
get isReady() {
|
|
49
|
+
return this.#isReady;
|
|
50
|
+
}
|
|
51
|
+
config;
|
|
52
|
+
downloader;
|
|
53
|
+
externals;
|
|
54
|
+
fs;
|
|
55
|
+
logger;
|
|
56
|
+
meta = new MetaRegistry();
|
|
57
|
+
profilers;
|
|
58
|
+
projectRoot;
|
|
59
|
+
symbols;
|
|
60
|
+
#dependencyRoots;
|
|
61
|
+
#dependencyFiles;
|
|
62
|
+
#roots = [];
|
|
63
|
+
/**
|
|
64
|
+
* All tracked root URIs. Each URI in this array is guaranteed to end with a slash (`/`).
|
|
65
|
+
*
|
|
66
|
+
* Includes the roots of all dependencies, the project root, and all data pack roots identified
|
|
67
|
+
* by `pack.mcmeta` files.
|
|
68
|
+
*
|
|
69
|
+
* Some URIs in the array may overlap with each other. In such cases, the deeper ones are guaranteed to come
|
|
70
|
+
* before the shallower ones (e.g. `file:///foo/bar/` will come before `file:///foo/`).
|
|
71
|
+
*/
|
|
72
|
+
get roots() {
|
|
73
|
+
return this.#roots;
|
|
74
|
+
}
|
|
75
|
+
#ctx;
|
|
76
|
+
/**
|
|
77
|
+
* Arbitrary information that will be included in the `project` property of all `Context`s.
|
|
78
|
+
*/
|
|
79
|
+
get ctx() {
|
|
80
|
+
return this.#ctx;
|
|
81
|
+
}
|
|
82
|
+
#cacheRoot;
|
|
83
|
+
/**
|
|
84
|
+
* File URI to a directory where all cache files of Spyglass should be stored.
|
|
85
|
+
*/
|
|
86
|
+
get cacheRoot() {
|
|
87
|
+
return this.#cacheRoot;
|
|
88
|
+
}
|
|
89
|
+
updateRoots() {
|
|
90
|
+
const rawRoots = [...this.#dependencyRoots, this.projectRoot];
|
|
91
|
+
const ans = new Set(rawRoots);
|
|
92
|
+
// Identify roots indicated by `pack.mcmeta`.
|
|
93
|
+
for (const file of this.getTrackedFiles()) {
|
|
94
|
+
if (file.endsWith(Project.RootSuffix) && rawRoots.some(r => file.startsWith(r))) {
|
|
95
|
+
ans.add(file.slice(0, 1 - Project.RootSuffix.length));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
this.#roots = [...ans].sort((a, b) => b.length - a.length);
|
|
99
|
+
this.emit('rootsUpdated', { roots: this.#roots });
|
|
100
|
+
}
|
|
101
|
+
on(event, callbackFn) {
|
|
102
|
+
this.#eventEmitter.on(event, callbackFn);
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
once(event, callbackFn) {
|
|
106
|
+
this.#eventEmitter.once(event, callbackFn);
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
emit(event, ...args) {
|
|
110
|
+
return this.#eventEmitter.emit(event, ...args);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get all files that are tracked and supported.
|
|
114
|
+
*
|
|
115
|
+
* Files in cached archives may not show up in the result as those files
|
|
116
|
+
* are not loaded into the memory.
|
|
117
|
+
*/
|
|
118
|
+
getTrackedFiles() {
|
|
119
|
+
const extensions = this.meta.getSupportedFileExtensions();
|
|
120
|
+
return [...this.#dependencyFiles, ...this.#watchedFiles]
|
|
121
|
+
.filter(file => extensions.includes(fileUtil.extname(file) ?? ''));
|
|
122
|
+
}
|
|
123
|
+
constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoot, }) {
|
|
124
|
+
this.#cacheRoot = cacheRoot;
|
|
125
|
+
this.#eventEmitter = new externals.event.EventEmitter();
|
|
126
|
+
this.externals = externals;
|
|
113
127
|
this.fs = fs;
|
|
114
|
-
|
|
128
|
+
this.#initializers = initializers;
|
|
115
129
|
this.logger = logger;
|
|
116
130
|
this.profilers = profilers;
|
|
117
|
-
this.
|
|
118
|
-
this.
|
|
119
|
-
this
|
|
120
|
-
|
|
131
|
+
this.projectRoot = projectRoot;
|
|
132
|
+
this.cacheService = new CacheService(cacheRoot, this);
|
|
133
|
+
this.#configService = new ConfigService(this, defaultConfig);
|
|
134
|
+
this.downloader = downloader ?? new Downloader(cacheRoot, externals, logger);
|
|
135
|
+
this.symbols = new SymbolUtil({}, externals.event.EventEmitter);
|
|
136
|
+
this.#ctx = {};
|
|
121
137
|
this.logger.info(`[Project] [init] cacheRoot = “${cacheRoot}”`);
|
|
122
|
-
|
|
138
|
+
this.#configService
|
|
123
139
|
.on('changed', ({ config }) => {
|
|
124
140
|
this.config = config;
|
|
125
141
|
this.logger.info('[Project] [Config] Changed');
|
|
@@ -127,15 +143,15 @@ class Project extends events_1.default {
|
|
|
127
143
|
.on('error', ({ error, uri }) => this.logger.error(`[Project] [Config] Failed loading “${uri}”`, error));
|
|
128
144
|
this.setInitPromise();
|
|
129
145
|
this.setReadyPromise();
|
|
130
|
-
|
|
146
|
+
this.#cacheSaverIntervalId = setInterval(() => this.cacheService.save(), CacheAutoSaveInterval);
|
|
131
147
|
this
|
|
132
148
|
.on('documentUpdated', ({ doc, node }) => {
|
|
133
|
-
if (!
|
|
149
|
+
if (!this.#isReady) {
|
|
134
150
|
return;
|
|
135
151
|
}
|
|
136
152
|
this.emit('documentErrorred', {
|
|
137
153
|
doc,
|
|
138
|
-
errors:
|
|
154
|
+
errors: FileNode.getErrors(node),
|
|
139
155
|
node,
|
|
140
156
|
});
|
|
141
157
|
})
|
|
@@ -148,7 +164,7 @@ class Project extends events_1.default {
|
|
|
148
164
|
})
|
|
149
165
|
.on('fileModified', async ({ uri }) => {
|
|
150
166
|
if (this.isOnlyWatched(uri)) {
|
|
151
|
-
|
|
167
|
+
this.#docAndNodes.delete(uri);
|
|
152
168
|
await this.ensureParsedAndChecked(uri);
|
|
153
169
|
}
|
|
154
170
|
})
|
|
@@ -160,11 +176,11 @@ class Project extends events_1.default {
|
|
|
160
176
|
this.tryClearingCache(uri);
|
|
161
177
|
})
|
|
162
178
|
.on('ready', () => {
|
|
163
|
-
|
|
179
|
+
this.#isReady = true;
|
|
164
180
|
// Recheck client managed files.
|
|
165
181
|
const promises = [];
|
|
166
|
-
for (const uri of
|
|
167
|
-
const result =
|
|
182
|
+
for (const uri of this.#clientManagedUris) {
|
|
183
|
+
const result = this.#docAndNodes.get(uri);
|
|
168
184
|
if (result) {
|
|
169
185
|
promises.push(this.check(result.doc, result.node));
|
|
170
186
|
}
|
|
@@ -172,85 +188,36 @@ class Project extends events_1.default {
|
|
|
172
188
|
Promise.all(promises).catch(e => this.logger.error('[Project#ready] Error occurred when rechecking client managed files after ready', e));
|
|
173
189
|
});
|
|
174
190
|
}
|
|
175
|
-
get isReady() {
|
|
176
|
-
return __classPrivateFieldGet(this, _Project_isReady, "f");
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* All tracked root URIs. Each URI in this array is guaranteed to end with a slash (`/`).
|
|
180
|
-
*
|
|
181
|
-
* Includes the roots of all dependencies, the project root, and all data pack roots identified
|
|
182
|
-
* by `pack.mcmeta` files.
|
|
183
|
-
*
|
|
184
|
-
* Some URIs in the array may overlap with each other. In such cases, the deeper ones are guaranteed to come
|
|
185
|
-
* before the shallower ones (e.g. `file:///foo/bar/` will come before `file:///foo/`).
|
|
186
|
-
*/
|
|
187
|
-
get roots() {
|
|
188
|
-
return __classPrivateFieldGet(this, _Project_roots, "f");
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Arbitrary information that will be included in the `project` property of all `Context`s.
|
|
192
|
-
*/
|
|
193
|
-
get ctx() {
|
|
194
|
-
return __classPrivateFieldGet(this, _Project_ctx, "f");
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* File path to a directory where all cache files of Spyglass should be stored.
|
|
198
|
-
*/
|
|
199
|
-
get cacheRoot() {
|
|
200
|
-
return __classPrivateFieldGet(this, _Project_cacheRoot, "f");
|
|
201
|
-
}
|
|
202
|
-
updateRoots() {
|
|
203
|
-
const rawRoots = [...__classPrivateFieldGet(this, _Project_dependencyRoots, "f"), this.projectRoot];
|
|
204
|
-
const ans = new Set(rawRoots);
|
|
205
|
-
// Identify roots indicated by `pack.mcmeta`.
|
|
206
|
-
for (const file of this.getTrackedFiles()) {
|
|
207
|
-
if (file.endsWith(Project.RootSuffix) && rawRoots.some(r => file.startsWith(r))) {
|
|
208
|
-
ans.add(file.slice(0, 1 - Project.RootSuffix.length));
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
__classPrivateFieldSet(this, _Project_roots, [...ans].sort((a, b) => b.length - a.length), "f");
|
|
212
|
-
this.emit('rootsUpdated', { roots: __classPrivateFieldGet(this, _Project_roots, "f") });
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Get all files that are tracked and supported.
|
|
216
|
-
*
|
|
217
|
-
* Files in cached archives may not show up in the result as those files
|
|
218
|
-
* are not loaded into the memory.
|
|
219
|
-
*/
|
|
220
|
-
getTrackedFiles() {
|
|
221
|
-
const extensions = this.meta.getSupportedFileExtensions();
|
|
222
|
-
return [...__classPrivateFieldGet(this, _Project_dependencyFiles, "f"), ...__classPrivateFieldGet(this, _Project_watchedFiles, "f")]
|
|
223
|
-
.filter(file => extensions.includes(fileUtil_1.fileUtil.extname(file) ?? ''));
|
|
224
|
-
}
|
|
225
191
|
setInitPromise() {
|
|
226
192
|
const loadConfig = async () => {
|
|
227
|
-
this.config = await
|
|
193
|
+
this.config = await this.#configService.load();
|
|
228
194
|
};
|
|
229
195
|
const callIntializers = async () => {
|
|
230
196
|
const initCtx = {
|
|
231
197
|
cacheRoot: this.cacheRoot,
|
|
232
198
|
config: this.config,
|
|
233
199
|
downloader: this.downloader,
|
|
200
|
+
externals: this.externals,
|
|
234
201
|
logger: this.logger,
|
|
235
202
|
meta: this.meta,
|
|
236
203
|
projectRoot: this.projectRoot,
|
|
237
204
|
};
|
|
238
|
-
const results = await Promise.allSettled(
|
|
205
|
+
const results = await Promise.allSettled(this.#initializers.map(init => init(initCtx)));
|
|
239
206
|
let ctx = {};
|
|
240
207
|
results.forEach(async (r, i) => {
|
|
241
208
|
if (r.status === 'rejected') {
|
|
242
|
-
this.logger.error(`[Project] [callInitializers] [${i}] “${
|
|
209
|
+
this.logger.error(`[Project] [callInitializers] [${i}] “${this.#initializers[i].name}”`, r.reason);
|
|
243
210
|
}
|
|
244
211
|
else if (r.value) {
|
|
245
212
|
ctx = { ...ctx, ...r.value };
|
|
246
213
|
}
|
|
247
214
|
});
|
|
248
|
-
|
|
215
|
+
this.#ctx = ctx;
|
|
249
216
|
};
|
|
250
217
|
const init = async () => {
|
|
251
218
|
const __profiler = this.profilers.get('project#init');
|
|
252
219
|
const { symbols } = await this.cacheService.load();
|
|
253
|
-
this.symbols = new
|
|
220
|
+
this.symbols = new SymbolUtil(symbols, this.externals.event.EventEmitter);
|
|
254
221
|
this.symbols.buildCache();
|
|
255
222
|
__profiler.task('Load Cache');
|
|
256
223
|
await loadConfig();
|
|
@@ -258,13 +225,13 @@ class Project extends events_1.default {
|
|
|
258
225
|
await callIntializers();
|
|
259
226
|
__profiler.task('Initialize').finalize();
|
|
260
227
|
};
|
|
261
|
-
|
|
228
|
+
this.#initPromise = init();
|
|
262
229
|
}
|
|
263
230
|
setReadyPromise() {
|
|
264
231
|
const getDependencies = async () => {
|
|
265
232
|
const ans = [];
|
|
266
233
|
for (const dependency of this.config.env.dependencies) {
|
|
267
|
-
if (
|
|
234
|
+
if (DependencyKey.is(dependency)) {
|
|
268
235
|
const provider = this.meta.getDependencyProvider(dependency);
|
|
269
236
|
if (provider) {
|
|
270
237
|
try {
|
|
@@ -287,55 +254,51 @@ class Project extends events_1.default {
|
|
|
287
254
|
};
|
|
288
255
|
const listDependencyFiles = async () => {
|
|
289
256
|
const dependencies = await getDependencies();
|
|
290
|
-
const fileUriSupporter = await
|
|
291
|
-
const archiveUriSupporter = await
|
|
257
|
+
const fileUriSupporter = await FileUriSupporter.create(dependencies, this.externals, this.logger);
|
|
258
|
+
const archiveUriSupporter = await ArchiveUriSupporter.create(dependencies, this.externals, this.logger, this.cacheService.checksums.roots);
|
|
292
259
|
this.fs.register('file:', fileUriSupporter, true);
|
|
293
|
-
this.fs.register(
|
|
260
|
+
this.fs.register(ArchiveUriSupporter.Protocol, archiveUriSupporter, true);
|
|
294
261
|
};
|
|
295
262
|
const listProjectFiles = () => new Promise(resolve => {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
.watch(this.
|
|
263
|
+
this.#watcherReady = false;
|
|
264
|
+
this.#watcher = this.externals.fs
|
|
265
|
+
.watch(this.projectRoot)
|
|
299
266
|
.once('ready', () => {
|
|
300
|
-
|
|
267
|
+
this.#watcherReady = true;
|
|
301
268
|
resolve();
|
|
302
269
|
})
|
|
303
|
-
.on('add',
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (__classPrivateFieldGet(this, _Project_watcherReady, "f")) {
|
|
270
|
+
.on('add', uri => {
|
|
271
|
+
this.#watchedFiles.add(uri);
|
|
272
|
+
if (this.#watcherReady) {
|
|
307
273
|
this.emit('fileCreated', { uri });
|
|
308
274
|
}
|
|
309
275
|
})
|
|
310
|
-
.on('change',
|
|
311
|
-
|
|
312
|
-
if (__classPrivateFieldGet(this, _Project_watcherReady, "f")) {
|
|
276
|
+
.on('change', uri => {
|
|
277
|
+
if (this.#watcherReady) {
|
|
313
278
|
this.emit('fileModified', { uri });
|
|
314
279
|
}
|
|
315
280
|
})
|
|
316
|
-
.on('unlink',
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (__classPrivateFieldGet(this, _Project_watcherReady, "f")) {
|
|
281
|
+
.on('unlink', uri => {
|
|
282
|
+
this.#watchedFiles.delete(uri);
|
|
283
|
+
if (this.#watcherReady) {
|
|
320
284
|
this.emit('fileDeleted', { uri });
|
|
321
285
|
}
|
|
322
286
|
})
|
|
323
287
|
.on('error', e => {
|
|
324
288
|
this.logger.error('[Project] [chokidar]', e);
|
|
325
|
-
})
|
|
289
|
+
});
|
|
326
290
|
});
|
|
327
291
|
const ready = async () => {
|
|
328
292
|
await this.init();
|
|
329
293
|
const __profiler = this.profilers.get('project#ready');
|
|
330
|
-
const limit = (0, p_limit_1.default)(8);
|
|
331
294
|
const ensureParsed = this.ensureParsed.bind(this);
|
|
332
295
|
const ensureChecked = this.ensureChecked.bind(this);
|
|
333
296
|
await Promise.all([
|
|
334
297
|
listDependencyFiles(),
|
|
335
298
|
listProjectFiles(),
|
|
336
299
|
]);
|
|
337
|
-
|
|
338
|
-
|
|
300
|
+
this.#dependencyFiles = new Set(this.fs.listFiles());
|
|
301
|
+
this.#dependencyRoots = new Set(this.fs.listRoots());
|
|
339
302
|
this.updateRoots();
|
|
340
303
|
__profiler.task('List Files');
|
|
341
304
|
for (const [id, { checksum, registrar }] of this.meta.symbolRegistrars) {
|
|
@@ -370,27 +333,27 @@ class Project extends events_1.default {
|
|
|
370
333
|
__profiler.task('Check Files').finalize();
|
|
371
334
|
this.emit('ready', {});
|
|
372
335
|
};
|
|
373
|
-
|
|
336
|
+
this.#readyPromise = ready();
|
|
374
337
|
}
|
|
375
338
|
async init() {
|
|
376
|
-
await
|
|
339
|
+
await this.#initPromise;
|
|
377
340
|
return this;
|
|
378
341
|
}
|
|
379
342
|
async ready() {
|
|
380
|
-
await
|
|
343
|
+
await this.#readyPromise;
|
|
381
344
|
return this;
|
|
382
345
|
}
|
|
383
346
|
/**
|
|
384
347
|
* Behavior of the `Project` instance is undefined after this function has settled.
|
|
385
348
|
*/
|
|
386
349
|
async close() {
|
|
387
|
-
clearInterval(
|
|
388
|
-
await
|
|
350
|
+
clearInterval(this.#cacheSaverIntervalId);
|
|
351
|
+
await this.#watcher.close();
|
|
389
352
|
await this.cacheService.save();
|
|
390
353
|
}
|
|
391
354
|
async restart() {
|
|
392
355
|
try {
|
|
393
|
-
await
|
|
356
|
+
await this.#watcher.close();
|
|
394
357
|
this.setReadyPromise();
|
|
395
358
|
await this.ready();
|
|
396
359
|
}
|
|
@@ -402,14 +365,14 @@ class Project extends events_1.default {
|
|
|
402
365
|
return this.cacheService.reset();
|
|
403
366
|
}
|
|
404
367
|
normalizeUri(uri) {
|
|
405
|
-
return this.fs.mapFromDisk(
|
|
368
|
+
return this.fs.mapFromDisk(this.externals.uri.normalize(uri));
|
|
406
369
|
}
|
|
407
370
|
/**
|
|
408
371
|
* @returns The language ID of the file, or the file extension without the leading dot.
|
|
409
372
|
*/
|
|
410
373
|
getLanguageID(uri) {
|
|
411
374
|
uri = this.normalizeUri(uri);
|
|
412
|
-
const ext =
|
|
375
|
+
const ext = fileUtil.extname(uri) ?? '.plaintext';
|
|
413
376
|
return this.meta.getLanguageID(ext) ?? ext.slice(1);
|
|
414
377
|
}
|
|
415
378
|
/**
|
|
@@ -417,23 +380,23 @@ class Project extends events_1.default {
|
|
|
417
380
|
*/
|
|
418
381
|
get(uri) {
|
|
419
382
|
uri = this.normalizeUri(uri);
|
|
420
|
-
return
|
|
383
|
+
return this.#docAndNodes.get(uri);
|
|
421
384
|
}
|
|
422
385
|
/**
|
|
423
386
|
* @throws FS-related errors
|
|
424
387
|
*/
|
|
425
388
|
async ensureParsed(uri) {
|
|
426
389
|
uri = this.normalizeUri(uri);
|
|
427
|
-
if (
|
|
428
|
-
return
|
|
390
|
+
if (this.#docAndNodes.has(uri)) {
|
|
391
|
+
return this.#docAndNodes.get(uri);
|
|
429
392
|
}
|
|
430
393
|
const languageID = this.getLanguageID(uri);
|
|
431
394
|
if (!this.meta.isSupportedLanguage(languageID)) {
|
|
432
395
|
return undefined;
|
|
433
396
|
}
|
|
434
397
|
try {
|
|
435
|
-
const content =
|
|
436
|
-
const doc =
|
|
398
|
+
const content = bufferToString(await this.fs.readFile(uri));
|
|
399
|
+
const doc = TextDocument.create(uri, languageID, -1, content);
|
|
437
400
|
return this.parseAndCache(doc);
|
|
438
401
|
}
|
|
439
402
|
catch (e) {
|
|
@@ -446,22 +409,22 @@ class Project extends events_1.default {
|
|
|
446
409
|
return this.cache(doc, node);
|
|
447
410
|
}
|
|
448
411
|
parse(doc) {
|
|
449
|
-
const ctx =
|
|
450
|
-
const src = new
|
|
412
|
+
const ctx = ParserContext.create(this, { doc });
|
|
413
|
+
const src = new Source(doc.getText());
|
|
451
414
|
let ans;
|
|
452
415
|
ctx.symbols.clear({ contributor: 'parser', uri: doc.uri });
|
|
453
|
-
ctx.symbols.contributeAs('parser', () => ans =
|
|
416
|
+
ctx.symbols.contributeAs('parser', () => ans = file()(src, ctx));
|
|
454
417
|
return ans;
|
|
455
418
|
}
|
|
456
419
|
cache(doc, node) {
|
|
457
420
|
const data = { doc, node };
|
|
458
|
-
|
|
421
|
+
this.#docAndNodes.set(doc.uri, data);
|
|
459
422
|
this.emit('documentUpdated', data);
|
|
460
423
|
return data;
|
|
461
424
|
}
|
|
462
425
|
async check(doc, node) {
|
|
463
426
|
const checker = this.meta.getChecker(node.type);
|
|
464
|
-
const ctx =
|
|
427
|
+
const ctx = CheckerContext.create(this, { doc });
|
|
465
428
|
ctx.symbols.clear({ contributor: 'checker', uri: doc.uri });
|
|
466
429
|
await ctx.symbols.contributeAsAsync('checker', async () => {
|
|
467
430
|
await checker(node, ctx);
|
|
@@ -483,7 +446,7 @@ class Project extends events_1.default {
|
|
|
483
446
|
lint(doc, node) {
|
|
484
447
|
node.linterErrors = [];
|
|
485
448
|
for (const [ruleName, rawValue] of Object.entries(this.config.lint)) {
|
|
486
|
-
const result =
|
|
449
|
+
const result = LinterConfigValue.destruct(rawValue);
|
|
487
450
|
if (!result) {
|
|
488
451
|
// Rule is disabled (i.e. set to `null`) in the config.
|
|
489
452
|
continue;
|
|
@@ -494,13 +457,13 @@ class Project extends events_1.default {
|
|
|
494
457
|
// Config value is invalid.
|
|
495
458
|
continue;
|
|
496
459
|
}
|
|
497
|
-
const ctx =
|
|
460
|
+
const ctx = LinterContext.create(this, {
|
|
498
461
|
doc,
|
|
499
|
-
err: new
|
|
462
|
+
err: new LinterErrorReporter(ruleName, ruleSeverity),
|
|
500
463
|
ruleName,
|
|
501
464
|
ruleValue,
|
|
502
465
|
});
|
|
503
|
-
|
|
466
|
+
traversePreOrder(node, () => true, () => true, node => {
|
|
504
467
|
if (nodePredicate(node)) {
|
|
505
468
|
linter(node, ctx);
|
|
506
469
|
}
|
|
@@ -528,13 +491,13 @@ class Project extends events_1.default {
|
|
|
528
491
|
}
|
|
529
492
|
async ensureParsedAndCheckedOnlyWhenReady(uri) {
|
|
530
493
|
const result = await this.ensureParsed(uri);
|
|
531
|
-
if (
|
|
494
|
+
if (this.#isReady && result) {
|
|
532
495
|
await this.ensureChecked(result.doc, result.node);
|
|
533
496
|
}
|
|
534
497
|
return result;
|
|
535
498
|
}
|
|
536
499
|
bind(param) {
|
|
537
|
-
const ctx =
|
|
500
|
+
const ctx = UriBinderContext.create(this);
|
|
538
501
|
if (typeof param === 'string') {
|
|
539
502
|
ctx.symbols.clear({ contributor: 'uri_binder', uri: param });
|
|
540
503
|
}
|
|
@@ -550,13 +513,13 @@ class Project extends events_1.default {
|
|
|
550
513
|
*/
|
|
551
514
|
onDidOpen(uri, languageID, version, content) {
|
|
552
515
|
uri = this.normalizeUri(uri);
|
|
553
|
-
if (!
|
|
516
|
+
if (!fileUtil.isFileUri(uri)) {
|
|
554
517
|
return; // We only accept `file:` scheme for client-managed URIs.
|
|
555
518
|
}
|
|
556
|
-
|
|
557
|
-
const doc =
|
|
519
|
+
this.#clientManagedUris.add(uri);
|
|
520
|
+
const doc = TextDocument.create(uri, languageID, version, content);
|
|
558
521
|
const { node } = this.parseAndCache(doc);
|
|
559
|
-
if (
|
|
522
|
+
if (this.#isReady) {
|
|
560
523
|
this.check(doc, node);
|
|
561
524
|
}
|
|
562
525
|
}
|
|
@@ -566,16 +529,16 @@ class Project extends events_1.default {
|
|
|
566
529
|
*/
|
|
567
530
|
onDidChange(uri, changes, version) {
|
|
568
531
|
uri = this.normalizeUri(uri);
|
|
569
|
-
if (!
|
|
532
|
+
if (!fileUtil.isFileUri(uri)) {
|
|
570
533
|
return; // We only accept `file:` scheme for client-managed URIs.
|
|
571
534
|
}
|
|
572
535
|
const result = this.get(uri);
|
|
573
536
|
if (!result) {
|
|
574
537
|
throw new Error(`Document for “${uri}” is not cached. This should not happen. Did the language client send a didChange notification without sending a didOpen one?`);
|
|
575
538
|
}
|
|
576
|
-
|
|
539
|
+
TextDocument.update(result.doc, changes, version);
|
|
577
540
|
const { node } = this.parseAndCache(result.doc);
|
|
578
|
-
if (
|
|
541
|
+
if (this.#isReady) {
|
|
579
542
|
this.check(result.doc, node);
|
|
580
543
|
}
|
|
581
544
|
}
|
|
@@ -584,18 +547,18 @@ class Project extends events_1.default {
|
|
|
584
547
|
*/
|
|
585
548
|
onDidClose(uri) {
|
|
586
549
|
uri = this.normalizeUri(uri);
|
|
587
|
-
if (!
|
|
550
|
+
if (!fileUtil.isFileUri(uri)) {
|
|
588
551
|
return; // We only accept `file:` scheme for client-managed URIs.
|
|
589
552
|
}
|
|
590
|
-
|
|
553
|
+
this.#clientManagedUris.delete(uri);
|
|
591
554
|
this.tryClearingCache(uri);
|
|
592
555
|
}
|
|
593
556
|
async showCacheRoot() {
|
|
594
|
-
if (!
|
|
557
|
+
if (!this.#cacheRoot) {
|
|
595
558
|
return;
|
|
596
559
|
}
|
|
597
560
|
try {
|
|
598
|
-
await
|
|
561
|
+
await this.externals.fs.showFile(this.#cacheRoot);
|
|
599
562
|
}
|
|
600
563
|
catch (e) {
|
|
601
564
|
this.logger.error('[Service#showCacheRoot]', e);
|
|
@@ -603,33 +566,30 @@ class Project extends events_1.default {
|
|
|
603
566
|
}
|
|
604
567
|
tryClearingCache(uri) {
|
|
605
568
|
if (this.shouldRemove(uri)) {
|
|
606
|
-
|
|
569
|
+
this.#docAndNodes.delete(uri);
|
|
607
570
|
this.emit('documentRemoved', { uri });
|
|
608
571
|
}
|
|
609
572
|
}
|
|
610
573
|
shouldRemove(uri) {
|
|
611
|
-
return !
|
|
574
|
+
return !this.#clientManagedUris.has(uri) && !this.#dependencyFiles.has(uri) && !this.#watchedFiles.has(uri);
|
|
612
575
|
}
|
|
613
576
|
isOnlyWatched(uri) {
|
|
614
|
-
return
|
|
577
|
+
return this.#watchedFiles.has(uri) && !this.#clientManagedUris.has(uri) && !this.#dependencyFiles.has(uri);
|
|
615
578
|
}
|
|
616
579
|
}
|
|
617
|
-
_Project_cacheSaverIntervalId = new WeakMap(), _Project_clientManagedUris = new WeakMap(), _Project_configService = new WeakMap(), _Project_docAndNodes = new WeakMap(), _Project_initializers = new WeakMap(), _Project_initPromise = new WeakMap(), _Project_readyPromise = new WeakMap(), _Project_watchedFiles = new WeakMap(), _Project_watcher = new WeakMap(), _Project_watcherReady = new WeakMap(), _Project_isReady = new WeakMap(), _Project_dependencyRoots = new WeakMap(), _Project_dependencyFiles = new WeakMap(), _Project_roots = new WeakMap(), _Project_ctx = new WeakMap(), _Project_cacheRoot = new WeakMap();
|
|
618
|
-
Project.RootSuffix = '/pack.mcmeta';
|
|
619
580
|
__decorate([
|
|
620
|
-
|
|
581
|
+
CachePromise()
|
|
621
582
|
], Project.prototype, "ensureParsed", null);
|
|
622
583
|
__decorate([
|
|
623
|
-
|
|
584
|
+
CachePromise()
|
|
624
585
|
], Project.prototype, "check", null);
|
|
625
586
|
__decorate([
|
|
626
|
-
|
|
587
|
+
CachePromise()
|
|
627
588
|
], Project.prototype, "ensureChecked", null);
|
|
628
589
|
__decorate([
|
|
629
|
-
|
|
590
|
+
CachePromise()
|
|
630
591
|
], Project.prototype, "ensureParsedAndChecked", null);
|
|
631
592
|
__decorate([
|
|
632
|
-
|
|
593
|
+
CachePromise()
|
|
633
594
|
], Project.prototype, "ensureParsedAndCheckedOnlyWhenReady", null);
|
|
634
|
-
exports.Project = Project;
|
|
635
595
|
//# sourceMappingURL=Project.js.map
|