@spyglassmc/core 0.4.17 → 0.4.19

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.
@@ -65,6 +65,10 @@ export declare namespace CompletionItem {
65
65
  * Escape `$`, `\`, and `}` in `textToInsert`
66
66
  */
67
67
  function escape(textToInsert: string): string;
68
+ /**
69
+ * Un-escape `$`, `\`, and `}` in `textToInsert`
70
+ */
71
+ function unescape(textToInsert: string): string;
68
72
  }
69
73
  export declare class InsertTextBuilder {
70
74
  #private;
@@ -35,6 +35,13 @@ export var CompletionItem;
35
35
  return textToInsert.replace(/([\\$}])/g, '\\$1');
36
36
  }
37
37
  CompletionItem.escape = escape;
38
+ /**
39
+ * Un-escape `$`, `\`, and `}` in `textToInsert`
40
+ */
41
+ function unescape(textToInsert) {
42
+ return textToInsert.replace(/\\([\\$}])/g, '$1');
43
+ }
44
+ CompletionItem.unescape = unescape;
38
45
  })(CompletionItem || (CompletionItem = {}));
39
46
  export class InsertTextBuilder {
40
47
  #ans = '';
@@ -199,7 +199,10 @@ export function escapeString(value, quote) {
199
199
  if (!quote) {
200
200
  return value;
201
201
  }
202
- return value.replaceAll('\\', '\\\\').replaceAll(quote, '\\"');
202
+ // Un-escape and then re-escape completion
203
+ value = CompletionItem.unescape(value);
204
+ value = value.replaceAll('\\', '\\\\').replaceAll(quote, '\\"');
205
+ return CompletionItem.escape(value);
203
206
  }
204
207
  export const symbol = (node, ctx) => {
205
208
  const path = node.options.parentPath ?? [];
@@ -53,7 +53,7 @@ export class Downloader {
53
53
  }
54
54
  const deserializer = cache.deserializer ?? ((b) => b);
55
55
  const ans = await transformer(deserializer(cachedBuffer));
56
- this.logger.info(`[Downloader] [${id}] Skipped downloading thanks to cache ${cacheChecksum}`);
56
+ this.logger.info(`[Downloader] [${id}] Skipped downloading thanks to cache ${cacheChecksum} (${cachedBuffer.length} bytes)`);
57
57
  return ans;
58
58
  }
59
59
  catch (e) {
@@ -103,7 +103,7 @@ export class Downloader {
103
103
  this.logger.error(`[Downloader] [${id}] Caching file ${cacheUri}`, e);
104
104
  }
105
105
  }
106
- this.logger.info(`[Downloader] [${id}] Downloaded from ${uri}`);
106
+ this.logger.info(`[Downloader] [${id}] Downloaded from ${uri} (${buffer.length} bytes)`);
107
107
  return await transformer(buffer);
108
108
  }
109
109
  catch (e) {
@@ -113,7 +113,7 @@ export class Downloader {
113
113
  const cachedBuffer = await fileUtil.readFile(this.externals, cacheUri);
114
114
  const deserializer = cache.deserializer ?? ((b) => b);
115
115
  const ans = await transformer(deserializer(cachedBuffer));
116
- this.logger.warn(`[Downloader] [${id}] Fell back to cached file ${cacheUri}`);
116
+ this.logger.warn(`[Downloader] [${id}] Fell back to cached file ${cacheUri} (${cachedBuffer.length} bytes)`);
117
117
  return ans;
118
118
  }
119
119
  catch (e) {
@@ -95,6 +95,7 @@ export declare class FileUriSupporter implements UriProtocolSupporter {
95
95
  }
96
96
  export declare class ArchiveUriSupporter implements UriProtocolSupporter {
97
97
  private readonly externals;
98
+ private readonly logger;
98
99
  private readonly entries;
99
100
  static readonly Protocol = "archive:";
100
101
  private static readonly SupportedArchiveExtnames;
@@ -154,6 +154,7 @@ export class FileUriSupporter {
154
154
  }
155
155
  export class ArchiveUriSupporter {
156
156
  externals;
157
+ logger;
157
158
  entries;
158
159
  static Protocol = 'archive:';
159
160
  static SupportedArchiveExtnames = ['.tar', '.tar.bz2', '.tar.gz', '.zip'];
@@ -161,8 +162,9 @@ export class ArchiveUriSupporter {
161
162
  /**
162
163
  * @param entries A map from archive names to unzipped entries.
163
164
  */
164
- constructor(externals, entries) {
165
+ constructor(externals, logger, entries) {
165
166
  this.externals = externals;
167
+ this.logger = logger;
166
168
  this.entries = entries;
167
169
  }
168
170
  async hash(uri) {
@@ -199,6 +201,7 @@ export class ArchiveUriSupporter {
199
201
  }
200
202
  *listFiles() {
201
203
  for (const [archiveName, files] of this.entries.entries()) {
204
+ this.logger.info(`[ArchiveUriSupporter#listFiles] Listing ${files.size} files from ${archiveName}`);
202
205
  for (const file of files.values()) {
203
206
  yield ArchiveUriSupporter.getUri(archiveName, file.path);
204
207
  }
@@ -237,14 +240,16 @@ export class ArchiveUriSupporter {
237
240
  throw new Error(`A different URI with ${archiveName} already exists`);
238
241
  }
239
242
  const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), { stripLevel: typeof info?.startDepth === 'number' ? info.startDepth : 0 });
243
+ /// Debug message for #1609
244
+ logger.info(`[ArchiveUriSupporter#create] Extracted ${files.length} files from ${archiveName}`);
240
245
  entries.set(archiveName, new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f])));
241
246
  }
242
247
  }
243
248
  catch (e) {
244
- logger.error(`[SpyglassUriSupporter#create] Bad dependency ${uri}`, e);
249
+ logger.error(`[ArchiveUriSupporter#create] Bad dependency ${uri}`, e);
245
250
  }
246
251
  }
247
- return new ArchiveUriSupporter(externals, entries);
252
+ return new ArchiveUriSupporter(externals, logger, entries);
248
253
  }
249
254
  }
250
255
  async function hashFile(externals, uri) {
@@ -155,9 +155,12 @@ export class Project {
155
155
  */
156
156
  getTrackedFiles() {
157
157
  const extensions = this.meta.getSupportedFileExtensions();
158
+ this.logger.info(`[Project#getTrackedFiles] Supported file extensions: ${extensions}`);
158
159
  const supportedFiles = [...this.#dependencyFiles ?? [], ...this.#watchedFiles]
159
160
  .filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
161
+ this.logger.info(`[Project#getTrackedFiles] Listed ${supportedFiles.length} supported files`);
160
162
  const filteredFiles = this.ignore.filter(supportedFiles);
163
+ this.logger.info(`[Project#getTrackedFiles] After ignoring, keeping ${filteredFiles.length} tracked files`);
161
164
  return filteredFiles;
162
165
  }
163
166
  constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], isDebugging = false, logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoots, }) {
@@ -390,6 +393,17 @@ export class Project {
390
393
  __profiler.task('Bind URIs');
391
394
  const files = [...addedFiles, ...changedFiles].sort(this.meta.uriSorter);
392
395
  __profiler.task('Sort URIs');
396
+ const fileCountByExtension = new Map();
397
+ for (const file of files) {
398
+ const ext = fileUtil.extname(file)?.replace(/^\./, '');
399
+ if (ext) {
400
+ fileCountByExtension.set(ext, (fileCountByExtension.get(ext) ?? 0) + 1);
401
+ }
402
+ }
403
+ this.logger.info(`[Project#ready] == Files to bind ==`);
404
+ for (const [ext, count] of fileCountByExtension.entries()) {
405
+ this.logger.info(`[Project#ready] File extension ${ext}: ${count}`);
406
+ }
393
407
  const __bindProfiler = this.profilers.get('project#ready#bind', 'top-n', 50);
394
408
  for (const uri of files) {
395
409
  await this.ensureBindingStarted(uri);
@@ -37,6 +37,8 @@ export declare class ReadonlySource {
37
37
  * @param offset The index to offset from cursor. Defaults to 0
38
38
  */
39
39
  peek(length?: number, offset?: number): string;
40
+ canRead(length?: number): boolean;
41
+ canReadInLine(): boolean;
40
42
  /**
41
43
  * If the `expectedValue` is right after the cursor, returns `true`. Otherwise returns `false`.
42
44
  *
@@ -48,8 +50,8 @@ export declare class ReadonlySource {
48
50
  tryPeekAfterWhitespace(expectedValue: string): boolean;
49
51
  peekUntil(...terminators: string[]): string;
50
52
  peekLine(): string;
51
- peekRemaining(): string;
52
- matchPattern(regex: RegExp): boolean;
53
+ peekRemaining(offset?: number): string;
54
+ matchPattern(regex: RegExp, offset?: number): boolean;
53
55
  /**
54
56
  * If there is a non-space character between `cursor + offset` (inclusive) and the next newline, returns `true`. Otherwise returns `false`.
55
57
  *
@@ -67,8 +69,6 @@ export declare class Source extends ReadonlySource {
67
69
  get cursor(): number;
68
70
  set cursor(cursor: number);
69
71
  clone(): Source;
70
- canRead(length?: number): boolean;
71
- canReadInLine(): boolean;
72
72
  read(): string;
73
73
  /**
74
74
  * Skips the current character.
@@ -59,6 +59,14 @@ export class ReadonlySource {
59
59
  peek(length = 1, offset = 0) {
60
60
  return this.string.slice(this.innerCursor + offset, this.innerCursor + offset + length);
61
61
  }
62
+ canRead(length = 1) {
63
+ const needed = this.innerCursor + length;
64
+ const available = this.string.length;
65
+ return this.innerCursor + length <= this.string.length;
66
+ }
67
+ canReadInLine() {
68
+ return this.canRead() && this.peek() !== CR && this.peek() !== LF;
69
+ }
62
70
  /**
63
71
  * If the `expectedValue` is right after the cursor, returns `true`. Otherwise returns `false`.
64
72
  *
@@ -93,11 +101,11 @@ export class ReadonlySource {
93
101
  peekLine() {
94
102
  return this.peekUntil(CR, LF);
95
103
  }
96
- peekRemaining() {
97
- return this.string.slice(this.innerCursor);
104
+ peekRemaining(offset = 0) {
105
+ return this.string.slice(this.innerCursor + offset);
98
106
  }
99
- matchPattern(regex) {
100
- return regex.test(this.peekRemaining());
107
+ matchPattern(regex, offset = 0) {
108
+ return regex.test(this.peekRemaining(offset));
101
109
  }
102
110
  /**
103
111
  * If there is a non-space character between `cursor + offset` (inclusive) and the next newline, returns `true`. Otherwise returns `false`.
@@ -149,12 +157,6 @@ export class Source extends ReadonlySource {
149
157
  ans.innerCursor = this.innerCursor;
150
158
  return ans;
151
159
  }
152
- canRead(length = 1) {
153
- return this.innerCursor + length <= this.string.length;
154
- }
155
- canReadInLine() {
156
- return this.canRead() && this.peek() !== CR && this.peek() !== LF;
157
- }
158
160
  read() {
159
161
  return this.string.charAt(this.innerCursor++);
160
162
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spyglassmc/core",
3
- "version": "0.4.17",
3
+ "version": "0.4.19",
4
4
  "type": "module",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",