@spyglassmc/core 0.4.0 → 0.4.1
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/lib/common/Dev.js +5 -2
- package/lib/common/Operations.js +7 -3
- package/lib/common/ReadonlyProxy.js +3 -1
- package/lib/common/StateProxy.js +18 -7
- package/lib/common/externals/BrowserExternals.js +2 -9
- package/lib/common/externals/NodeJsExternals.js +7 -17
- package/lib/common/externals/index.d.ts +0 -3
- package/lib/common/util.d.ts +1 -0
- package/lib/common/util.js +14 -10
- package/lib/node/AstNode.js +6 -4
- package/lib/node/FileNode.js +6 -1
- package/lib/node/ResourceLocationNode.d.ts +2 -2
- package/lib/node/ResourceLocationNode.js +11 -5
- package/lib/parser/boolean.js +1 -1
- package/lib/parser/comment.d.ts +1 -1
- package/lib/parser/comment.js +1 -1
- package/lib/parser/float.js +2 -1
- package/lib/parser/integer.js +2 -1
- package/lib/parser/list.d.ts +1 -1
- package/lib/parser/list.js +3 -3
- package/lib/parser/long.js +2 -1
- package/lib/parser/record.d.ts +1 -1
- package/lib/parser/record.js +18 -8
- package/lib/parser/resourceLocation.js +61 -8
- package/lib/parser/string.js +75 -7
- package/lib/parser/util.js +7 -3
- package/lib/processor/ColorInfoProvider.js +20 -7
- package/lib/processor/binder/builtin.js +27 -17
- package/lib/processor/checker/builtin.d.ts +1 -2
- package/lib/processor/checker/builtin.js +10 -12
- package/lib/processor/colorizer/builtin.js +8 -7
- package/lib/processor/completer/Completer.js +4 -2
- package/lib/processor/completer/builtin.js +26 -23
- package/lib/processor/formatter/builtin.js +14 -12
- package/lib/processor/linter/builtin/undeclaredSymbol.js +47 -24
- package/lib/processor/linter/builtin.js +7 -8
- package/lib/service/CacheService.js +9 -6
- package/lib/service/Config.d.ts +2 -2
- package/lib/service/Config.js +23 -19
- package/lib/service/Downloader.js +12 -7
- package/lib/service/FileService.js +22 -8
- package/lib/service/MetaRegistry.js +7 -6
- package/lib/service/Profiler.js +10 -5
- package/lib/service/Project.js +36 -30
- package/lib/service/Service.js +19 -9
- package/lib/service/fileUtil.js +2 -1
- package/lib/source/IndexMap.js +1 -1
- package/lib/source/LanguageError.js +1 -1
- package/lib/source/Location.js +4 -1
- package/lib/source/Range.js +6 -3
- package/lib/source/Source.js +3 -1
- package/lib/symbol/Symbol.d.ts +7 -7
- package/lib/symbol/Symbol.js +22 -9
- package/lib/symbol/SymbolUtil.d.ts +2 -2
- package/lib/symbol/SymbolUtil.js +74 -43
- package/package.json +2 -2
|
@@ -28,7 +28,7 @@ export function nameConvention(key) {
|
|
|
28
28
|
export const quote = (node, ctx) => {
|
|
29
29
|
const config = ctx.ruleValue;
|
|
30
30
|
const mustValueBeQuoted = node.options.unquotable
|
|
31
|
-
? [...node.value].some(c => !isAllowedCharacter(c, node.options.unquotable))
|
|
31
|
+
? [...node.value].some((c) => !isAllowedCharacter(c, node.options.unquotable))
|
|
32
32
|
: true;
|
|
33
33
|
const isQuoteRequired = config.always || mustValueBeQuoted;
|
|
34
34
|
const isQuoteProhibited = config.always === false && !mustValueBeQuoted;
|
|
@@ -66,8 +66,7 @@ export var configValidator;
|
|
|
66
66
|
new RegExp(val);
|
|
67
67
|
}
|
|
68
68
|
catch (e) {
|
|
69
|
-
logger.error(wrapError(name, localize('')
|
|
70
|
-
), e);
|
|
69
|
+
logger.error(wrapError(name, localize('')), e);
|
|
71
70
|
return false;
|
|
72
71
|
}
|
|
73
72
|
return true;
|
|
@@ -82,27 +81,27 @@ export function registerLinters(meta) {
|
|
|
82
81
|
meta.registerLinter('nameOfObjective', {
|
|
83
82
|
configValidator: configValidator.nameConvention,
|
|
84
83
|
linter: nameConvention('value'),
|
|
85
|
-
nodePredicate: n => n.symbol && n.symbol.category === 'objective',
|
|
84
|
+
nodePredicate: (n) => n.symbol && n.symbol.category === 'objective',
|
|
86
85
|
});
|
|
87
86
|
meta.registerLinter('nameOfScoreHolder', {
|
|
88
87
|
configValidator: configValidator.nameConvention,
|
|
89
88
|
linter: nameConvention('value'),
|
|
90
|
-
nodePredicate: n => n.symbol && n.symbol.category === 'score_holder',
|
|
89
|
+
nodePredicate: (n) => n.symbol && n.symbol.category === 'score_holder',
|
|
91
90
|
});
|
|
92
91
|
meta.registerLinter('nameOfTag', {
|
|
93
92
|
configValidator: configValidator.nameConvention,
|
|
94
93
|
linter: nameConvention('value'),
|
|
95
|
-
nodePredicate: n => n.symbol && n.symbol.category === 'tag',
|
|
94
|
+
nodePredicate: (n) => n.symbol && n.symbol.category === 'tag',
|
|
96
95
|
});
|
|
97
96
|
meta.registerLinter('nameOfTeam', {
|
|
98
97
|
configValidator: configValidator.nameConvention,
|
|
99
98
|
linter: nameConvention('value'),
|
|
100
|
-
nodePredicate: n => n.symbol && n.symbol.category === 'team',
|
|
99
|
+
nodePredicate: (n) => n.symbol && n.symbol.category === 'team',
|
|
101
100
|
});
|
|
102
101
|
meta.registerLinter('undeclaredSymbol', {
|
|
103
102
|
configValidator: configValidator.symbolLinterConfig,
|
|
104
103
|
linter: undeclaredSymbol,
|
|
105
|
-
nodePredicate: n => n.symbol && !McdocCategories.includes(n.symbol.category),
|
|
104
|
+
nodePredicate: (n) => n.symbol && !McdocCategories.includes(n.symbol.category),
|
|
106
105
|
});
|
|
107
106
|
}
|
|
108
107
|
//# sourceMappingURL=builtin.js.map
|
|
@@ -36,7 +36,8 @@ export class CacheService {
|
|
|
36
36
|
}
|
|
37
37
|
try {
|
|
38
38
|
// TODO: Don't update this for every single change.
|
|
39
|
-
this.checksums.files[doc.uri] =
|
|
39
|
+
this.checksums.files[doc.uri] =
|
|
40
|
+
await this.project.externals.crypto.getSha1(doc.getText());
|
|
40
41
|
}
|
|
41
42
|
catch (e) {
|
|
42
43
|
if (!this.project.externals.error.isKind(e, 'EISDIR')) {
|
|
@@ -75,7 +76,7 @@ export class CacheService {
|
|
|
75
76
|
* @returns `${cacheRoot}symbols/${sha1(projectRoot)}.json`
|
|
76
77
|
*/
|
|
77
78
|
async getCacheFileUri() {
|
|
78
|
-
return this.#cacheFilePath ??= new Uri(`symbols/${await this.project.externals.crypto.getSha1(this.project.projectRoot)}.json.gz`, this.cacheRoot).toString();
|
|
79
|
+
return (this.#cacheFilePath ??= new Uri(`symbols/${await this.project.externals.crypto.getSha1(this.project.projectRoot)}.json.gz`, this.cacheRoot).toString());
|
|
79
80
|
}
|
|
80
81
|
async load() {
|
|
81
82
|
const __profiler = this.project.profilers.get('cache#load');
|
|
@@ -84,7 +85,7 @@ export class CacheService {
|
|
|
84
85
|
try {
|
|
85
86
|
filePath = await this.getCacheFileUri();
|
|
86
87
|
this.project.logger.info(`[CacheService#load] symbolCachePath = “${filePath}”`);
|
|
87
|
-
const cache = await fileUtil.readGzippedJson(this.project.externals, filePath);
|
|
88
|
+
const cache = (await fileUtil.readGzippedJson(this.project.externals, filePath));
|
|
88
89
|
__profiler.task('Read File');
|
|
89
90
|
if (cache.version === LatestCacheVersion) {
|
|
90
91
|
this.checksums = cache.checksums;
|
|
@@ -127,7 +128,7 @@ export class CacheService {
|
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
for (const [uri, checksum] of Object.entries(this.checksums.files)) {
|
|
130
|
-
if (unchangedRoots.some(root => uri.startsWith(root))) {
|
|
131
|
+
if (unchangedRoots.some((root) => uri.startsWith(root))) {
|
|
131
132
|
ans.unchangedFiles.push(uri);
|
|
132
133
|
continue;
|
|
133
134
|
}
|
|
@@ -141,7 +142,8 @@ export class CacheService {
|
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
catch (e) {
|
|
144
|
-
if (this.project.externals.error.isKind(e, 'ENOENT') ||
|
|
145
|
+
if (this.project.externals.error.isKind(e, 'ENOENT') ||
|
|
146
|
+
this.project.externals.error.isKind(e, 'EISDIR')) {
|
|
145
147
|
ans.removedFiles.push(uri);
|
|
146
148
|
}
|
|
147
149
|
else {
|
|
@@ -185,7 +187,8 @@ export class CacheService {
|
|
|
185
187
|
return false;
|
|
186
188
|
}
|
|
187
189
|
async hasFileChangedSinceCache(doc) {
|
|
188
|
-
return this.checksums.files[doc.uri] !==
|
|
190
|
+
return (this.checksums.files[doc.uri] !==
|
|
191
|
+
(await this.project.externals.crypto.getSha1(doc.getText())));
|
|
189
192
|
}
|
|
190
193
|
reset() {
|
|
191
194
|
this.#hasValidatedFiles = false;
|
package/lib/service/Config.d.ts
CHANGED
|
@@ -189,8 +189,8 @@ export declare namespace SymbolLinterConfig {
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
/**
|
|
192
|
-
* Config which simulates the default vanilla command system.
|
|
193
|
-
*/
|
|
192
|
+
* Config which simulates the default vanilla command system.
|
|
193
|
+
*/
|
|
194
194
|
export declare const VanillaConfig: Config;
|
|
195
195
|
declare type ConfigEvent = {
|
|
196
196
|
config: Config;
|
package/lib/service/Config.js
CHANGED
|
@@ -4,10 +4,10 @@ import { FileCategories, RegistryCategories } from '../symbol/index.js';
|
|
|
4
4
|
export var LinterSeverity;
|
|
5
5
|
(function (LinterSeverity) {
|
|
6
6
|
function is(value) {
|
|
7
|
-
return value === 'hint' ||
|
|
7
|
+
return (value === 'hint' ||
|
|
8
8
|
value === 'information' ||
|
|
9
9
|
value === 'warning' ||
|
|
10
|
-
value === 'error';
|
|
10
|
+
value === 'error');
|
|
11
11
|
}
|
|
12
12
|
LinterSeverity.is = is;
|
|
13
13
|
function toErrorSeverity(value) {
|
|
@@ -64,7 +64,8 @@ export var SymbolLinterConfig;
|
|
|
64
64
|
const value = v;
|
|
65
65
|
return ((value.if === undefined || Arrayable.is(value.if, Condition.is)) &&
|
|
66
66
|
(value.then === undefined || Action.is(value.then)) &&
|
|
67
|
-
(value.override === undefined ||
|
|
67
|
+
(value.override === undefined ||
|
|
68
|
+
Arrayable.is(value.override, Complex.is)));
|
|
68
69
|
}
|
|
69
70
|
Complex.is = is;
|
|
70
71
|
})(Complex = SymbolLinterConfig.Complex || (SymbolLinterConfig.Complex = {}));
|
|
@@ -75,22 +76,29 @@ export var SymbolLinterConfig;
|
|
|
75
76
|
return false;
|
|
76
77
|
}
|
|
77
78
|
const value = v;
|
|
78
|
-
return ((value.category === undefined ||
|
|
79
|
-
|
|
80
|
-
(value.
|
|
81
|
-
|
|
82
|
-
(value.
|
|
79
|
+
return ((value.category === undefined ||
|
|
80
|
+
Arrayable.is(value.category, TypePredicates.isString)) &&
|
|
81
|
+
(value.pattern === undefined ||
|
|
82
|
+
Arrayable.is(value.pattern, TypePredicates.isString)) &&
|
|
83
|
+
(value.excludePattern === undefined ||
|
|
84
|
+
Arrayable.is(value.excludePattern, TypePredicates.isString)) &&
|
|
85
|
+
(value.namespace === undefined ||
|
|
86
|
+
Arrayable.is(value.namespace, TypePredicates.isString)) &&
|
|
87
|
+
(value.excludeNamespace === undefined ||
|
|
88
|
+
Arrayable.is(value.excludeNamespace, TypePredicates.isString)));
|
|
83
89
|
}
|
|
84
90
|
Condition.is = is;
|
|
85
91
|
})(Condition = SymbolLinterConfig.Condition || (SymbolLinterConfig.Condition = {}));
|
|
86
92
|
let Action;
|
|
87
93
|
(function (Action) {
|
|
88
94
|
function isDeclare(value) {
|
|
89
|
-
return value !== undefined &&
|
|
95
|
+
return (value !== undefined &&
|
|
96
|
+
['block', 'file', 'public'].includes(value.declare));
|
|
90
97
|
}
|
|
91
98
|
Action.isDeclare = isDeclare;
|
|
92
99
|
function isReport(value) {
|
|
93
|
-
return value !== undefined &&
|
|
100
|
+
return (value !== undefined &&
|
|
101
|
+
['inherit', 'hint', 'information', 'warning', 'error'].includes(value.report));
|
|
94
102
|
}
|
|
95
103
|
Action.isReport = isReport;
|
|
96
104
|
function is(v) {
|
|
@@ -104,14 +112,12 @@ export var SymbolLinterConfig;
|
|
|
104
112
|
})(Action = SymbolLinterConfig.Action || (SymbolLinterConfig.Action = {}));
|
|
105
113
|
})(SymbolLinterConfig || (SymbolLinterConfig = {}));
|
|
106
114
|
/**
|
|
107
|
-
* Config which simulates the default vanilla command system.
|
|
108
|
-
*/
|
|
115
|
+
* Config which simulates the default vanilla command system.
|
|
116
|
+
*/
|
|
109
117
|
export const VanillaConfig = {
|
|
110
118
|
env: {
|
|
111
119
|
dataSource: 'GitHub',
|
|
112
|
-
dependencies: [
|
|
113
|
-
'@vanilla-mcdoc',
|
|
114
|
-
],
|
|
120
|
+
dependencies: ['@vanilla-mcdoc'],
|
|
115
121
|
feature: {
|
|
116
122
|
codeActions: true,
|
|
117
123
|
colors: true,
|
|
@@ -122,9 +128,7 @@ export const VanillaConfig = {
|
|
|
122
128
|
formatting: true,
|
|
123
129
|
hover: true,
|
|
124
130
|
inlayHint: {
|
|
125
|
-
enabledNodes: [
|
|
126
|
-
'mcfunction:command_child/unknown',
|
|
127
|
-
],
|
|
131
|
+
enabledNodes: ['mcfunction:command_child/unknown'],
|
|
128
132
|
},
|
|
129
133
|
semanticColoring: true,
|
|
130
134
|
selectionRanges: true,
|
|
@@ -253,7 +257,7 @@ export class ConfigService {
|
|
|
253
257
|
return ConfigService.merge(this.defaultConfig, ans);
|
|
254
258
|
}
|
|
255
259
|
static isConfigFile(uri) {
|
|
256
|
-
return ConfigService.ConfigFileNames.some(n => uri.endsWith(`/${n}`));
|
|
260
|
+
return ConfigService.ConfigFileNames.some((n) => uri.endsWith(`/${n}`));
|
|
257
261
|
}
|
|
258
262
|
static merge(base, ...overrides) {
|
|
259
263
|
// FIXME
|
|
@@ -30,17 +30,22 @@ export class Downloader {
|
|
|
30
30
|
out.cacheUri = cacheUri = new Uri(`downloader/${id}`, this.cacheRoot).toString();
|
|
31
31
|
cacheChecksumUri = new Uri(`downloader/${id}${checksumExtension}`, this.cacheRoot).toString();
|
|
32
32
|
try {
|
|
33
|
-
out.checksum = checksum = await this.download({
|
|
33
|
+
out.checksum = checksum = await this.download({
|
|
34
|
+
...checksumJob,
|
|
35
|
+
id: id + checksumExtension,
|
|
36
|
+
});
|
|
34
37
|
try {
|
|
35
|
-
const cacheChecksum = bufferToString(await fileUtil.readFile(this.externals, cacheChecksumUri))
|
|
36
|
-
.slice(0, -1); // Remove ending newline
|
|
38
|
+
const cacheChecksum = bufferToString(await fileUtil.readFile(this.externals, cacheChecksumUri)).slice(0, -1); // Remove ending newline
|
|
37
39
|
if (checksum === cacheChecksum) {
|
|
38
40
|
try {
|
|
39
41
|
const cachedBuffer = await fileUtil.readFile(this.externals, cacheUri);
|
|
40
42
|
if (ttl) {
|
|
41
|
-
this.#memoryCache.set(uri, {
|
|
43
|
+
this.#memoryCache.set(uri, {
|
|
44
|
+
buffer: cachedBuffer,
|
|
45
|
+
time: performance.now(),
|
|
46
|
+
});
|
|
42
47
|
}
|
|
43
|
-
const deserializer = cache.deserializer ?? (b => b);
|
|
48
|
+
const deserializer = cache.deserializer ?? ((b) => b);
|
|
44
49
|
const ans = await transformer(deserializer(cachedBuffer));
|
|
45
50
|
this.logger.info(`[Downloader] [${id}] Skipped downloading thanks to cache ${cacheChecksum}`);
|
|
46
51
|
return ans;
|
|
@@ -85,7 +90,7 @@ export class Downloader {
|
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
try {
|
|
88
|
-
const serializer = cache.serializer ?? (b => b);
|
|
93
|
+
const serializer = cache.serializer ?? ((b) => b);
|
|
89
94
|
await fileUtil.writeFile(this.externals, cacheUri, serializer(buffer));
|
|
90
95
|
}
|
|
91
96
|
catch (e) {
|
|
@@ -100,7 +105,7 @@ export class Downloader {
|
|
|
100
105
|
if (cache && cacheUri) {
|
|
101
106
|
try {
|
|
102
107
|
const cachedBuffer = await fileUtil.readFile(this.externals, cacheUri);
|
|
103
|
-
const deserializer = cache.deserializer ?? (b => b);
|
|
108
|
+
const deserializer = cache.deserializer ?? ((b) => b);
|
|
104
109
|
const ans = await transformer(deserializer(cachedBuffer));
|
|
105
110
|
this.logger.warn(`[Downloader] [${id}] Fell back to cached file “${cacheUri}”`);
|
|
106
111
|
return ans;
|
|
@@ -128,7 +128,8 @@ export class FileUriSupporter {
|
|
|
128
128
|
const files = new Map();
|
|
129
129
|
for (let { uri } of dependencies) {
|
|
130
130
|
try {
|
|
131
|
-
if (fileUtil.isFileUri(uri) &&
|
|
131
|
+
if (fileUtil.isFileUri(uri) &&
|
|
132
|
+
(await externals.fs.stat(uri)).isDirectory()) {
|
|
132
133
|
uri = fileUtil.ensureEndingSlash(uri);
|
|
133
134
|
roots.push(uri);
|
|
134
135
|
files.set(uri, await externals.fs.getAllFiles(uri));
|
|
@@ -150,7 +151,12 @@ export class ArchiveUriSupporter {
|
|
|
150
151
|
externals;
|
|
151
152
|
entries;
|
|
152
153
|
static Protocol = 'archive:';
|
|
153
|
-
static SupportedArchiveExtnames = [
|
|
154
|
+
static SupportedArchiveExtnames = [
|
|
155
|
+
'.tar',
|
|
156
|
+
'.tar.bz2',
|
|
157
|
+
'.tar.gz',
|
|
158
|
+
'.zip',
|
|
159
|
+
];
|
|
154
160
|
protocol = ArchiveUriSupporter.Protocol;
|
|
155
161
|
/**
|
|
156
162
|
* @param entries A map from archive URIs to unzipped entries.
|
|
@@ -204,7 +210,7 @@ export class ArchiveUriSupporter {
|
|
|
204
210
|
}
|
|
205
211
|
}
|
|
206
212
|
static getUri(archiveUri, pathInArchive = '') {
|
|
207
|
-
return `${ArchiveUriSupporter.Protocol}
|
|
213
|
+
return `${ArchiveUriSupporter.Protocol}${encodeURIComponent(archiveUri)}?path=${encodeURIComponent(pathInArchive.replace(/\\/g, '/'))}`;
|
|
208
214
|
}
|
|
209
215
|
/**
|
|
210
216
|
* @throws When `uri` has the wrong protocol or hostname.
|
|
@@ -213,16 +219,22 @@ export class ArchiveUriSupporter {
|
|
|
213
219
|
if (uri.protocol !== ArchiveUriSupporter.Protocol) {
|
|
214
220
|
throw new Error(`Expected protocol “${ArchiveUriSupporter.Protocol}” in “${uri}”`);
|
|
215
221
|
}
|
|
222
|
+
const path = uri.searchParams.get('path');
|
|
223
|
+
if (!path) {
|
|
224
|
+
throw new Error(`Missing path in archive uri “${uri.toString()}”`);
|
|
225
|
+
}
|
|
216
226
|
return {
|
|
217
|
-
archiveUri: decodeURIComponent(uri.
|
|
218
|
-
pathInArchive:
|
|
227
|
+
archiveUri: decodeURIComponent(uri.pathname),
|
|
228
|
+
pathInArchive: path.charAt(0) === '/' ? path.slice(1) : path,
|
|
219
229
|
};
|
|
220
230
|
}
|
|
221
231
|
static async create(dependencies, externals, logger, checksums) {
|
|
222
232
|
const entries = new Map();
|
|
223
233
|
for (const { uri, info } of dependencies) {
|
|
224
234
|
try {
|
|
225
|
-
if (uri.startsWith('file:') &&
|
|
235
|
+
if (uri.startsWith('file:') &&
|
|
236
|
+
ArchiveUriSupporter.SupportedArchiveExtnames.some((ext) => uri.endsWith(ext)) &&
|
|
237
|
+
(await externals.fs.stat(uri)).isFile()) {
|
|
226
238
|
const rootUri = ArchiveUriSupporter.getUri(uri);
|
|
227
239
|
const cachedChecksum = checksums[rootUri];
|
|
228
240
|
if (cachedChecksum !== undefined) {
|
|
@@ -233,8 +245,10 @@ export class ArchiveUriSupporter {
|
|
|
233
245
|
continue;
|
|
234
246
|
}
|
|
235
247
|
}
|
|
236
|
-
const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), {
|
|
237
|
-
|
|
248
|
+
const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), {
|
|
249
|
+
stripLevel: typeof info?.startDepth === 'number' ? info.startDepth : 0,
|
|
250
|
+
});
|
|
251
|
+
entries.set(uri, new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f])));
|
|
238
252
|
}
|
|
239
253
|
}
|
|
240
254
|
catch (e) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Lazy } from '../common/index.js';
|
|
2
|
-
import { binder, checker, colorizer, completer, formatter, linter } from '../processor/index.js';
|
|
2
|
+
import { binder, checker, colorizer, completer, formatter, linter, } from '../processor/index.js';
|
|
3
3
|
/* istanbul ignore next */
|
|
4
4
|
/**
|
|
5
5
|
* The meta registry of Spyglass. You can register new parsers, processors, and languages here.
|
|
@@ -51,13 +51,13 @@ export class MetaRegistry {
|
|
|
51
51
|
* An array of file extensions (including the leading dot (`.`)) that are supported.
|
|
52
52
|
*/
|
|
53
53
|
getSupportedFileExtensions() {
|
|
54
|
-
return [...this.#languages.values()].flatMap(v => v.extensions);
|
|
54
|
+
return [...this.#languages.values()].flatMap((v) => v.extensions);
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
57
|
* An array of characters that trigger a completion request.
|
|
58
58
|
*/
|
|
59
59
|
getTriggerCharacters() {
|
|
60
|
-
return Array.from(this.#languages.values()).flatMap(v => v.triggerCharacters ?? []);
|
|
60
|
+
return Array.from(this.#languages.values()).flatMap((v) => v.triggerCharacters ?? []);
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
63
|
* @param fileExtension The file extension including the leading dot. e.g. `".mcfunction"`.
|
|
@@ -109,7 +109,8 @@ export class MetaRegistry {
|
|
|
109
109
|
}
|
|
110
110
|
shouldComplete(languageID, triggerCharacter) {
|
|
111
111
|
const language = this.#languages.get(languageID);
|
|
112
|
-
return !triggerCharacter ||
|
|
112
|
+
return (!triggerCharacter ||
|
|
113
|
+
!!language?.triggerCharacters?.includes(triggerCharacter));
|
|
113
114
|
}
|
|
114
115
|
getCompleterForLanguageID(languageID) {
|
|
115
116
|
return this.#languages.get(languageID)?.completer ?? completer.fallback;
|
|
@@ -136,11 +137,11 @@ export class MetaRegistry {
|
|
|
136
137
|
return this.#inlayHintProviders;
|
|
137
138
|
}
|
|
138
139
|
getLinter(ruleName) {
|
|
139
|
-
return this.#linters.get(ruleName) ?? {
|
|
140
|
+
return (this.#linters.get(ruleName) ?? {
|
|
140
141
|
configValidator: () => false,
|
|
141
142
|
linter: linter.noop,
|
|
142
143
|
nodePredicate: () => false,
|
|
143
|
-
};
|
|
144
|
+
});
|
|
144
145
|
}
|
|
145
146
|
registerLinter(ruleName, options) {
|
|
146
147
|
this.#linters.set(ruleName, options);
|
package/lib/service/Profiler.js
CHANGED
|
@@ -42,7 +42,7 @@ class TopNImpl {
|
|
|
42
42
|
this.logger.info(`[Profiler: ${this.id}] Min/Avg/Max: ${this.#minTime} / ${totalDuration / this.#taskCount} / ${this.#maxTime} ms`);
|
|
43
43
|
this.logger.info(`[Profiler: ${this.id}] Top ${Math.min(this.n, this.#topTasks.length)} task(s):`);
|
|
44
44
|
for (const [name, time] of this.#topTasks) {
|
|
45
|
-
this.logger.info(`[Profiler: ${this.id}] ${name}${' '.repeat(longestTaskNameLength - name.length)} - ${time} ms (${time / totalDuration * 100}%)`);
|
|
45
|
+
this.logger.info(`[Profiler: ${this.id}] ${name}${' '.repeat(longestTaskNameLength - name.length)} - ${time} ms (${(time / totalDuration) * 100}%)`);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -83,7 +83,9 @@ class TotalImpl {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
class NoopImpl {
|
|
86
|
-
task() {
|
|
86
|
+
task() {
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
87
89
|
finalize() { }
|
|
88
90
|
}
|
|
89
91
|
export class ProfilerFactory {
|
|
@@ -96,9 +98,12 @@ export class ProfilerFactory {
|
|
|
96
98
|
get(id, style = 'total', n) {
|
|
97
99
|
if (this.#enabledProfilers.has(id)) {
|
|
98
100
|
switch (style) {
|
|
99
|
-
case 'top-n':
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
case 'top-n':
|
|
102
|
+
return new TopNImpl(id, this.logger, n);
|
|
103
|
+
case 'total':
|
|
104
|
+
return new TotalImpl(id, this.logger);
|
|
105
|
+
default:
|
|
106
|
+
return Dev.assertNever(style);
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
109
|
else {
|
package/lib/service/Project.js
CHANGED
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
8
|
-
import { bufferToString, Logger, SingletonPromise, StateProxy } from '../common/index.js';
|
|
8
|
+
import { bufferToString, Logger, normalizeUri, SingletonPromise, StateProxy, } from '../common/index.js';
|
|
9
9
|
import { FileNode } from '../node/index.js';
|
|
10
10
|
import { file } from '../parser/index.js';
|
|
11
11
|
import { traversePreOrder } from '../processor/index.js';
|
|
@@ -13,11 +13,11 @@ import { LanguageError, Source } from '../source/index.js';
|
|
|
13
13
|
import { SymbolUtil } from '../symbol/index.js';
|
|
14
14
|
import { CacheService } from './CacheService.js';
|
|
15
15
|
import { ConfigService, LinterConfigValue } from './Config.js';
|
|
16
|
-
import { BinderContext, CheckerContext, LinterContext, ParserContext, UriBinderContext } from './Context.js';
|
|
16
|
+
import { BinderContext, CheckerContext, LinterContext, ParserContext, UriBinderContext, } from './Context.js';
|
|
17
17
|
import { DependencyKey } from './Dependency.js';
|
|
18
18
|
import { Downloader } from './Downloader.js';
|
|
19
19
|
import { LinterErrorReporter } from './ErrorReporter.js';
|
|
20
|
-
import { ArchiveUriSupporter, FileService, FileUriSupporter } from './FileService.js';
|
|
20
|
+
import { ArchiveUriSupporter, FileService, FileUriSupporter, } from './FileService.js';
|
|
21
21
|
import { fileUtil } from './fileUtil.js';
|
|
22
22
|
import { MetaRegistry } from './MetaRegistry.js';
|
|
23
23
|
import { ProfilerFactory } from './Profiler.js';
|
|
@@ -125,7 +125,8 @@ export class Project {
|
|
|
125
125
|
const ans = new Set(rawRoots);
|
|
126
126
|
// Identify roots indicated by `pack.mcmeta`.
|
|
127
127
|
for (const file of this.getTrackedFiles()) {
|
|
128
|
-
if (file.endsWith(Project.RootSuffix) &&
|
|
128
|
+
if (file.endsWith(Project.RootSuffix) &&
|
|
129
|
+
rawRoots.some((r) => file.startsWith(r))) {
|
|
129
130
|
ans.add(file.slice(0, 1 - Project.RootSuffix.length));
|
|
130
131
|
}
|
|
131
132
|
}
|
|
@@ -151,8 +152,7 @@ export class Project {
|
|
|
151
152
|
*/
|
|
152
153
|
getTrackedFiles() {
|
|
153
154
|
const extensions = this.meta.getSupportedFileExtensions();
|
|
154
|
-
return [...this.#dependencyFiles, ...this.#watchedFiles]
|
|
155
|
-
.filter(file => extensions.includes(fileUtil.extname(file) ?? ''));
|
|
155
|
+
return [...this.#dependencyFiles, ...this.#watchedFiles].filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
|
|
156
156
|
}
|
|
157
157
|
constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoot, }) {
|
|
158
158
|
this.#cacheRoot = cacheRoot;
|
|
@@ -178,13 +178,12 @@ export class Project {
|
|
|
178
178
|
this.setInitPromise();
|
|
179
179
|
this.setReadyPromise();
|
|
180
180
|
this.#cacheSaverIntervalId = setInterval(() => this.cacheService.save(), CacheAutoSaveInterval);
|
|
181
|
-
this
|
|
182
|
-
.on('documentUpdated', ({ doc, node }) => {
|
|
181
|
+
this.on('documentUpdated', ({ doc, node }) => {
|
|
183
182
|
// if (!this.#isReady) {
|
|
184
183
|
// return
|
|
185
184
|
// }
|
|
186
185
|
this.emit('documentErrored', {
|
|
187
|
-
errors: FileNode.getErrors(node).map(e => LanguageError.withPosRange(e, doc)),
|
|
186
|
+
errors: FileNode.getErrors(node).map((e) => LanguageError.withPosRange(e, doc)),
|
|
188
187
|
uri: doc.uri,
|
|
189
188
|
version: doc.version,
|
|
190
189
|
});
|
|
@@ -237,7 +236,7 @@ export class Project {
|
|
|
237
236
|
meta: this.meta,
|
|
238
237
|
projectRoot: this.projectRoot,
|
|
239
238
|
};
|
|
240
|
-
const results = await Promise.allSettled(this.#initializers.map(init => init(initCtx)));
|
|
239
|
+
const results = await Promise.allSettled(this.#initializers.map((init) => init(initCtx)));
|
|
241
240
|
let ctx = {};
|
|
242
241
|
results.forEach(async (r, i) => {
|
|
243
242
|
if (r.status === 'rejected') {
|
|
@@ -294,7 +293,7 @@ export class Project {
|
|
|
294
293
|
this.fs.register('file:', fileUriSupporter, true);
|
|
295
294
|
this.fs.register(ArchiveUriSupporter.Protocol, archiveUriSupporter, true);
|
|
296
295
|
};
|
|
297
|
-
const listProjectFiles = () => new Promise(resolve => {
|
|
296
|
+
const listProjectFiles = () => new Promise((resolve) => {
|
|
298
297
|
this.#watchedFiles.clear();
|
|
299
298
|
this.#watcherReady = false;
|
|
300
299
|
this.#watcher = this.externals.fs
|
|
@@ -303,34 +302,31 @@ export class Project {
|
|
|
303
302
|
this.#watcherReady = true;
|
|
304
303
|
resolve();
|
|
305
304
|
})
|
|
306
|
-
.on('add', uri => {
|
|
305
|
+
.on('add', (uri) => {
|
|
307
306
|
this.#watchedFiles.add(uri);
|
|
308
307
|
if (this.#watcherReady) {
|
|
309
308
|
this.emit('fileCreated', { uri });
|
|
310
309
|
}
|
|
311
310
|
})
|
|
312
|
-
.on('change', uri => {
|
|
311
|
+
.on('change', (uri) => {
|
|
313
312
|
if (this.#watcherReady) {
|
|
314
313
|
this.emit('fileModified', { uri });
|
|
315
314
|
}
|
|
316
315
|
})
|
|
317
|
-
.on('unlink', uri => {
|
|
316
|
+
.on('unlink', (uri) => {
|
|
318
317
|
this.#watchedFiles.delete(uri);
|
|
319
318
|
if (this.#watcherReady) {
|
|
320
319
|
this.emit('fileDeleted', { uri });
|
|
321
320
|
}
|
|
322
321
|
})
|
|
323
|
-
.on('error', e => {
|
|
322
|
+
.on('error', (e) => {
|
|
324
323
|
this.logger.error('[Project] [chokidar]', e);
|
|
325
324
|
});
|
|
326
325
|
});
|
|
327
326
|
const ready = async () => {
|
|
328
327
|
await this.init();
|
|
329
328
|
const __profiler = this.profilers.get('project#ready');
|
|
330
|
-
await Promise.all([
|
|
331
|
-
listDependencyFiles(),
|
|
332
|
-
listProjectFiles(),
|
|
333
|
-
]);
|
|
329
|
+
await Promise.all([listDependencyFiles(), listProjectFiles()]);
|
|
334
330
|
this.#dependencyFiles = new Set(this.fs.listFiles());
|
|
335
331
|
this.#dependencyRoots = new Set(this.fs.listRoots());
|
|
336
332
|
this.updateRoots();
|
|
@@ -424,7 +420,7 @@ export class Project {
|
|
|
424
420
|
return this.restart();
|
|
425
421
|
}
|
|
426
422
|
normalizeUri(uri) {
|
|
427
|
-
return this.fs.mapFromDisk(
|
|
423
|
+
return this.fs.mapFromDisk(normalizeUri(uri));
|
|
428
424
|
}
|
|
429
425
|
static TextDocumentCacheMaxLength = 268435456;
|
|
430
426
|
#textDocumentCache = new Map();
|
|
@@ -574,7 +570,7 @@ export class Project {
|
|
|
574
570
|
ruleName,
|
|
575
571
|
ruleValue,
|
|
576
572
|
});
|
|
577
|
-
traversePreOrder(node, () => true, () => true, node => {
|
|
573
|
+
traversePreOrder(node, () => true, () => true, (node) => {
|
|
578
574
|
if (nodePredicate(node)) {
|
|
579
575
|
const proxy = StateProxy.create(node);
|
|
580
576
|
linter(proxy, ctx);
|
|
@@ -589,7 +585,9 @@ export class Project {
|
|
|
589
585
|
}
|
|
590
586
|
// @SingletonPromise()
|
|
591
587
|
async ensureBindingStarted(uri) {
|
|
592
|
-
|
|
588
|
+
uri = this.normalizeUri(uri);
|
|
589
|
+
if (this.#symbolUpToDateUris.has(uri) ||
|
|
590
|
+
this.#bindingInProgressUris.has(uri)) {
|
|
593
591
|
return;
|
|
594
592
|
}
|
|
595
593
|
this.#bindingInProgressUris.add(uri);
|
|
@@ -635,8 +633,8 @@ export class Project {
|
|
|
635
633
|
* @throws If there is no `TextDocument` corresponding to the URI.
|
|
636
634
|
*/
|
|
637
635
|
async onDidChange(uri, changes, version) {
|
|
638
|
-
this.#symbolUpToDateUris.delete(uri);
|
|
639
636
|
uri = this.normalizeUri(uri);
|
|
637
|
+
this.#symbolUpToDateUris.delete(uri);
|
|
640
638
|
if (!fileUtil.isFileUri(uri)) {
|
|
641
639
|
return; // We only accept `file:` scheme for client-managed URIs.
|
|
642
640
|
}
|
|
@@ -665,17 +663,21 @@ export class Project {
|
|
|
665
663
|
this.tryClearingCache(uri);
|
|
666
664
|
}
|
|
667
665
|
async ensureClientManagedChecked(uri) {
|
|
666
|
+
uri = this.normalizeUri(uri);
|
|
668
667
|
const result = this.#clientManagedDocAndNodes.get(uri);
|
|
669
|
-
if (result
|
|
668
|
+
if (result) {
|
|
670
669
|
const { doc, node } = result;
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
670
|
+
if (this.#isReady) {
|
|
671
|
+
await this.bind(doc, node);
|
|
672
|
+
await this.check(doc, node);
|
|
673
|
+
this.emit('documentUpdated', result);
|
|
674
|
+
}
|
|
675
|
+
return result;
|
|
675
676
|
}
|
|
676
677
|
return undefined;
|
|
677
678
|
}
|
|
678
679
|
getClientManaged(uri) {
|
|
680
|
+
uri = this.normalizeUri(uri);
|
|
679
681
|
return this.#clientManagedDocAndNodes.get(uri);
|
|
680
682
|
}
|
|
681
683
|
async showCacheRoot() {
|
|
@@ -696,10 +698,14 @@ export class Project {
|
|
|
696
698
|
}
|
|
697
699
|
}
|
|
698
700
|
shouldRemove(uri) {
|
|
699
|
-
return !this.#clientManagedUris.has(uri) &&
|
|
701
|
+
return (!this.#clientManagedUris.has(uri) &&
|
|
702
|
+
!this.#dependencyFiles.has(uri) &&
|
|
703
|
+
!this.#watchedFiles.has(uri));
|
|
700
704
|
}
|
|
701
705
|
isOnlyWatched(uri) {
|
|
702
|
-
return this.#watchedFiles.has(uri) &&
|
|
706
|
+
return (this.#watchedFiles.has(uri) &&
|
|
707
|
+
!this.#clientManagedUris.has(uri) &&
|
|
708
|
+
!this.#dependencyFiles.has(uri));
|
|
703
709
|
}
|
|
704
710
|
}
|
|
705
711
|
__decorate([
|