@spyglassmc/core 0.4.27 → 0.4.28
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/node/StringNode.d.ts +2 -2
- package/lib/node/StringNode.js +2 -1
- package/lib/service/CacheService.js +5 -1
- package/lib/service/Context.d.ts +5 -0
- package/lib/service/Context.js +7 -0
- package/lib/service/FileService.js +6 -4
- package/lib/service/MetaRegistry.d.ts +8 -5
- package/lib/service/MetaRegistry.js +2 -8
- package/lib/service/Project.d.ts +13 -1
- package/lib/service/Project.js +46 -25
- package/package.json +2 -2
package/lib/node/StringNode.d.ts
CHANGED
|
@@ -2,12 +2,12 @@ import type { Parser } from '../parser/index.js';
|
|
|
2
2
|
import type { ColorTokenType } from '../processor/index.js';
|
|
3
3
|
import type { IndexMap, RangeLike } from '../source/index.js';
|
|
4
4
|
import type { AstNode } from './AstNode.js';
|
|
5
|
-
export declare const EscapeChars: readonly ["\"", "'", "\\", "b", "f", "n", "r", "t"];
|
|
5
|
+
export declare const EscapeChars: readonly ["\"", "'", "\\", "b", "f", "n", "r", "s", "t"];
|
|
6
6
|
export type EscapeChar = (typeof EscapeChars)[number];
|
|
7
7
|
export declare namespace EscapeChar {
|
|
8
8
|
function is(expected: EscapeChar[] | undefined, c: string): c is EscapeChar;
|
|
9
9
|
}
|
|
10
|
-
export declare const EscapeTable: Map<"\"" | "'" | "\\" | "b" | "f" | "n" | "r" | "t", string>;
|
|
10
|
+
export declare const EscapeTable: Map<"\"" | "'" | "\\" | "b" | "f" | "n" | "r" | "s" | "t", string>;
|
|
11
11
|
export type Quote = "'" | '"';
|
|
12
12
|
export interface StringOptions {
|
|
13
13
|
colorTokenType?: ColorTokenType;
|
package/lib/node/StringNode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Range } from '../source/index.js';
|
|
2
|
-
export const EscapeChars = ['"', "'", '\\', 'b', 'f', 'n', 'r', 't'];
|
|
2
|
+
export const EscapeChars = ['"', "'", '\\', 'b', 'f', 'n', 'r', 's', 't'];
|
|
3
3
|
export var EscapeChar;
|
|
4
4
|
(function (EscapeChar) {
|
|
5
5
|
/* istanbul ignore next */
|
|
@@ -16,6 +16,7 @@ export const EscapeTable = new Map([
|
|
|
16
16
|
['f', '\f'],
|
|
17
17
|
['n', '\n'],
|
|
18
18
|
['r', '\r'],
|
|
19
|
+
['s', ' '],
|
|
19
20
|
['t', '\t'],
|
|
20
21
|
]);
|
|
21
22
|
export var StringBaseNode;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Uri } from '../common/index.js';
|
|
2
2
|
import { SymbolTable } from '../symbol/index.js';
|
|
3
|
+
import { ArchiveUriSupporter } from './FileService.js';
|
|
3
4
|
import { fileUtil } from './fileUtil.js';
|
|
4
5
|
/**
|
|
5
6
|
* The format version of the cache. Should be increased when any changes that
|
|
@@ -27,7 +28,10 @@ export class CacheService {
|
|
|
27
28
|
this.cacheRoot = cacheRoot;
|
|
28
29
|
this.project = project;
|
|
29
30
|
this.project.on('documentUpdated', async ({ doc }) => {
|
|
30
|
-
if (!this.#hasValidatedFiles
|
|
31
|
+
if (!this.#hasValidatedFiles
|
|
32
|
+
// Do not save checksums for file schemes that we cannot map to disk (e.g. 'untitled:'
|
|
33
|
+
// for untitled files in VS Code)
|
|
34
|
+
|| !(doc.uri.startsWith(ArchiveUriSupporter.Protocol) || doc.uri.startsWith('file:'))) {
|
|
31
35
|
return;
|
|
32
36
|
}
|
|
33
37
|
try {
|
package/lib/service/Context.d.ts
CHANGED
|
@@ -153,5 +153,10 @@ export interface UriBinderContext extends ContextBase {
|
|
|
153
153
|
export declare namespace UriBinderContext {
|
|
154
154
|
function create(project: ProjectData): UriBinderContext;
|
|
155
155
|
}
|
|
156
|
+
export interface UriPredicateContext extends ContextBase {
|
|
157
|
+
}
|
|
158
|
+
export declare namespace UriPredicateContext {
|
|
159
|
+
function create(project: ProjectData): UriPredicateContext;
|
|
160
|
+
}
|
|
156
161
|
export {};
|
|
157
162
|
//# sourceMappingURL=Context.d.ts.map
|
package/lib/service/Context.js
CHANGED
|
@@ -143,4 +143,11 @@ export var UriBinderContext;
|
|
|
143
143
|
}
|
|
144
144
|
UriBinderContext.create = create;
|
|
145
145
|
})(UriBinderContext || (UriBinderContext = {}));
|
|
146
|
+
export var UriPredicateContext;
|
|
147
|
+
(function (UriPredicateContext) {
|
|
148
|
+
function create(project) {
|
|
149
|
+
return { ...ContextBase.create(project) };
|
|
150
|
+
}
|
|
151
|
+
UriPredicateContext.create = create;
|
|
152
|
+
})(UriPredicateContext || (UriPredicateContext = {}));
|
|
146
153
|
//# sourceMappingURL=Context.js.map
|
|
@@ -200,10 +200,12 @@ export class ArchiveUriSupporter {
|
|
|
200
200
|
return entry.data;
|
|
201
201
|
}
|
|
202
202
|
*listFiles() {
|
|
203
|
-
for (const [archiveName,
|
|
204
|
-
this.logger.info(`[ArchiveUriSupporter#listFiles] Listing ${
|
|
205
|
-
for (const
|
|
206
|
-
|
|
203
|
+
for (const [archiveName, entries] of this.entries.entries()) {
|
|
204
|
+
this.logger.info(`[ArchiveUriSupporter#listFiles] Listing ${entries.size} entries from ${archiveName}`);
|
|
205
|
+
for (const entry of entries.values()) {
|
|
206
|
+
if (entry.type === 'file') {
|
|
207
|
+
yield ArchiveUriSupporter.getUri(archiveName, entry.path);
|
|
208
|
+
}
|
|
207
209
|
}
|
|
208
210
|
}
|
|
209
211
|
}
|
|
@@ -6,6 +6,7 @@ import type { Formatter } from '../processor/formatter/index.js';
|
|
|
6
6
|
import type { Binder, Checker, CodeActionProvider, Colorizer, Completer, InlayHintProvider } from '../processor/index.js';
|
|
7
7
|
import type { Linter } from '../processor/linter/Linter.js';
|
|
8
8
|
import type { SignatureHelpProvider } from '../processor/SignatureHelpProvider.js';
|
|
9
|
+
import type { UriPredicateContext } from '../service/index.js';
|
|
9
10
|
import type { DependencyKey, DependencyProvider } from './Dependency.js';
|
|
10
11
|
import type { FileExtension } from './fileUtil.js';
|
|
11
12
|
import type { SymbolRegistrar } from './SymbolRegistrar.js';
|
|
@@ -16,10 +17,16 @@ export interface LanguageOptions {
|
|
|
16
17
|
* An array of extensions of files corresponding to the language. Each extension should include the leading dot (`.`).
|
|
17
18
|
*/
|
|
18
19
|
extensions: FileExtension[];
|
|
20
|
+
/**
|
|
21
|
+
* If specified, the URI of the file must pass the predicate for it to be considered to be a file
|
|
22
|
+
* of this language.
|
|
23
|
+
*/
|
|
24
|
+
uriPredicate?: UriPredicate;
|
|
19
25
|
triggerCharacters?: string[];
|
|
20
26
|
parser?: Parser<AstNode>;
|
|
21
27
|
completer?: Completer<any>;
|
|
22
28
|
}
|
|
29
|
+
export type UriPredicate = (uri: string, ctx: UriPredicateContext) => boolean;
|
|
23
30
|
interface LinterRegistration {
|
|
24
31
|
configValidator: (ruleName: string, ruleValue: unknown, logger: Logger) => unknown;
|
|
25
32
|
linter: Linter<AstNode>;
|
|
@@ -50,11 +57,7 @@ export declare class MetaRegistry {
|
|
|
50
57
|
* An array of all registered language IDs.
|
|
51
58
|
*/
|
|
52
59
|
getLanguages(): string[];
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* An array of file extensions (including the leading dot (`.`)) that are supported.
|
|
56
|
-
*/
|
|
57
|
-
getSupportedFileExtensions(): FileExtension[];
|
|
60
|
+
getLanguageOptions(language: string): LanguageOptions | undefined;
|
|
58
61
|
/**
|
|
59
62
|
* An array of characters that trigger a completion request.
|
|
60
63
|
*/
|
|
@@ -48,14 +48,8 @@ export class MetaRegistry {
|
|
|
48
48
|
getLanguages() {
|
|
49
49
|
return Array.from(this.#languages.keys());
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
return this.#languages.
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* An array of file extensions (including the leading dot (`.`)) that are supported.
|
|
56
|
-
*/
|
|
57
|
-
getSupportedFileExtensions() {
|
|
58
|
-
return [...this.#languages.values()].flatMap((v) => v.extensions);
|
|
51
|
+
getLanguageOptions(language) {
|
|
52
|
+
return this.#languages.get(language);
|
|
59
53
|
}
|
|
60
54
|
/**
|
|
61
55
|
* An array of characters that trigger a completion request.
|
package/lib/service/Project.d.ts
CHANGED
|
@@ -199,7 +199,19 @@ export declare class Project implements ExternalEventEmitter {
|
|
|
199
199
|
ensureClientManagedChecked(uri: string): Promise<DocAndNode | undefined>;
|
|
200
200
|
getClientManaged(uri: string): DocAndNode | undefined;
|
|
201
201
|
showCacheRoot(): Promise<void>;
|
|
202
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Returns true iff the URI should be excluded from all Spyglass language support.
|
|
204
|
+
*
|
|
205
|
+
* @param language Optional. If ommitted, a language will be derived from the URI according to
|
|
206
|
+
* its file extension.
|
|
207
|
+
*/
|
|
208
|
+
shouldExclude(uri: string, language?: string): boolean;
|
|
209
|
+
private isSupportedLanguage;
|
|
210
|
+
/**
|
|
211
|
+
* Guess a language ID from a URI. The guessed language ID may or may not actually be supported.
|
|
212
|
+
*/
|
|
213
|
+
private guessLanguageID;
|
|
214
|
+
private isUserExcluded;
|
|
203
215
|
private tryClearingCache;
|
|
204
216
|
private shouldRemove;
|
|
205
217
|
private isOnlyWatched;
|
package/lib/service/Project.js
CHANGED
|
@@ -14,7 +14,7 @@ import { LanguageError, Range, Source } from '../source/index.js';
|
|
|
14
14
|
import { SymbolUtil } from '../symbol/index.js';
|
|
15
15
|
import { CacheService } from './CacheService.js';
|
|
16
16
|
import { ConfigService, LinterConfigValue } from './Config.js';
|
|
17
|
-
import { BinderContext, CheckerContext, LinterContext, ParserContext, UriBinderContext, } from './Context.js';
|
|
17
|
+
import { BinderContext, CheckerContext, LinterContext, ParserContext, UriBinderContext, UriPredicateContext, } from './Context.js';
|
|
18
18
|
import { DependencyKey } from './Dependency.js';
|
|
19
19
|
import { Downloader } from './Downloader.js';
|
|
20
20
|
import { LinterErrorReporter } from './ErrorReporter.js';
|
|
@@ -152,10 +152,7 @@ export class Project {
|
|
|
152
152
|
* are not loaded into the memory.
|
|
153
153
|
*/
|
|
154
154
|
getTrackedFiles() {
|
|
155
|
-
const
|
|
156
|
-
this.logger.info(`[Project#getTrackedFiles] Supported file extensions: ${extensions}`);
|
|
157
|
-
const supportedFiles = [...this.#dependencyFiles ?? [], ...this.#watchedFiles]
|
|
158
|
-
.filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
|
|
155
|
+
const supportedFiles = [...this.#dependencyFiles ?? [], ...this.#watchedFiles];
|
|
159
156
|
this.logger.info(`[Project#getTrackedFiles] Listed ${supportedFiles.length} supported files`);
|
|
160
157
|
return supportedFiles;
|
|
161
158
|
}
|
|
@@ -334,7 +331,8 @@ export class Project {
|
|
|
334
331
|
await this.init();
|
|
335
332
|
const __profiler = this.profilers.get('project#ready');
|
|
336
333
|
await Promise.all([listDependencyFiles(), listProjectFiles()]);
|
|
337
|
-
this.#dependencyFiles = new Set(this.fs.listFiles()
|
|
334
|
+
this.#dependencyFiles = new Set([...this.fs.listFiles()]
|
|
335
|
+
.filter((uri) => !this.shouldExclude(uri)));
|
|
338
336
|
this.#dependencyRoots = new Set(this.fs.listRoots());
|
|
339
337
|
this.updateRoots();
|
|
340
338
|
__profiler.task('List URIs');
|
|
@@ -451,13 +449,9 @@ export class Project {
|
|
|
451
449
|
this.#textDocumentCache.delete(uri);
|
|
452
450
|
}
|
|
453
451
|
async read(uri) {
|
|
454
|
-
const getLanguageID = (uri) => {
|
|
455
|
-
const ext = fileUtil.extname(uri) ?? '.plaintext';
|
|
456
|
-
return this.meta.getLanguageID(ext) ?? ext.slice(1);
|
|
457
|
-
};
|
|
458
452
|
const createTextDocument = async (uri) => {
|
|
459
|
-
const languageId =
|
|
460
|
-
if (!this.
|
|
453
|
+
const languageId = this.guessLanguageID(uri);
|
|
454
|
+
if (!this.isSupportedLanguage(uri, languageId)) {
|
|
461
455
|
return undefined;
|
|
462
456
|
}
|
|
463
457
|
try {
|
|
@@ -642,10 +636,10 @@ export class Project {
|
|
|
642
636
|
*/
|
|
643
637
|
async onDidOpen(uri, languageID, version, content) {
|
|
644
638
|
uri = this.normalizeUri(uri);
|
|
645
|
-
if (
|
|
646
|
-
return; // We
|
|
639
|
+
if (uri.startsWith(ArchiveUriSupporter.Protocol)) {
|
|
640
|
+
return; // We do not accept `archive:` scheme for client-managed URIs.
|
|
647
641
|
}
|
|
648
|
-
if (this.shouldExclude(uri)) {
|
|
642
|
+
if (this.shouldExclude(uri, languageID)) {
|
|
649
643
|
return;
|
|
650
644
|
}
|
|
651
645
|
const doc = TextDocument.create(uri, languageID, version, content);
|
|
@@ -664,15 +658,16 @@ export class Project {
|
|
|
664
658
|
async onDidChange(uri, changes, version) {
|
|
665
659
|
uri = this.normalizeUri(uri);
|
|
666
660
|
this.#symbolUpToDateUris.delete(uri);
|
|
667
|
-
if (
|
|
668
|
-
return; // We
|
|
669
|
-
}
|
|
670
|
-
if (this.shouldExclude(uri)) {
|
|
671
|
-
return;
|
|
661
|
+
if (uri.startsWith(ArchiveUriSupporter.Protocol)) {
|
|
662
|
+
return; // We do not accept `archive:` scheme for client-managed URIs.
|
|
672
663
|
}
|
|
673
664
|
const doc = this.#clientManagedDocAndNodes.get(uri)?.doc;
|
|
674
|
-
if (!doc) {
|
|
675
|
-
|
|
665
|
+
if (!doc || this.shouldExclude(uri, doc.languageId)) {
|
|
666
|
+
// If doc is undefined, it means the document was previously excluded by onDidOpen()
|
|
667
|
+
// based on the language ID supplied by the client, in which case we should return early.
|
|
668
|
+
// Otherwise, we perform the shouldExclude() check with the URI and the saved language ID
|
|
669
|
+
// as usual.
|
|
670
|
+
return;
|
|
676
671
|
}
|
|
677
672
|
TextDocument.update(doc, changes, version);
|
|
678
673
|
const node = this.parse(doc);
|
|
@@ -687,8 +682,8 @@ export class Project {
|
|
|
687
682
|
*/
|
|
688
683
|
onDidClose(uri) {
|
|
689
684
|
uri = this.normalizeUri(uri);
|
|
690
|
-
if (
|
|
691
|
-
return; // We
|
|
685
|
+
if (uri.startsWith(ArchiveUriSupporter.Protocol)) {
|
|
686
|
+
return; // We do not accept `archive:` scheme for client-managed URIs.
|
|
692
687
|
}
|
|
693
688
|
this.#clientManagedUris.delete(uri);
|
|
694
689
|
this.#clientManagedDocAndNodes.delete(uri);
|
|
@@ -724,7 +719,33 @@ export class Project {
|
|
|
724
719
|
this.logger.error('[Service#showCacheRoot]', e);
|
|
725
720
|
}
|
|
726
721
|
}
|
|
727
|
-
|
|
722
|
+
/**
|
|
723
|
+
* Returns true iff the URI should be excluded from all Spyglass language support.
|
|
724
|
+
*
|
|
725
|
+
* @param language Optional. If ommitted, a language will be derived from the URI according to
|
|
726
|
+
* its file extension.
|
|
727
|
+
*/
|
|
728
|
+
shouldExclude(uri, language) {
|
|
729
|
+
return !this.isSupportedLanguage(uri, language) || this.isUserExcluded(uri);
|
|
730
|
+
}
|
|
731
|
+
isSupportedLanguage(uri, language) {
|
|
732
|
+
language ??= this.guessLanguageID(uri);
|
|
733
|
+
const languageOptions = this.meta.getLanguageOptions(language);
|
|
734
|
+
if (!languageOptions) {
|
|
735
|
+
// Unsupported language.
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
const { uriPredicate } = languageOptions;
|
|
739
|
+
return uriPredicate?.(uri, UriPredicateContext.create(this)) ?? true;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Guess a language ID from a URI. The guessed language ID may or may not actually be supported.
|
|
743
|
+
*/
|
|
744
|
+
guessLanguageID(uri) {
|
|
745
|
+
const ext = fileUtil.extname(uri) ?? '.spyglassmc-unknown';
|
|
746
|
+
return this.meta.getLanguageID(ext) ?? ext.slice(1);
|
|
747
|
+
}
|
|
748
|
+
isUserExcluded(uri) {
|
|
728
749
|
if (this.config.env.exclude.length === 0) {
|
|
729
750
|
return false;
|
|
730
751
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spyglassmc/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.28",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"rfdc": "^1.3.0",
|
|
25
25
|
"vscode-languageserver-textdocument": "^1.0.4",
|
|
26
26
|
"whatwg-url": "^14.0.0",
|
|
27
|
-
"@spyglassmc/locales": "0.3.
|
|
27
|
+
"@spyglassmc/locales": "0.3.14"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/decompress": "^4.2.3",
|