@spyglassmc/core 0.4.2 → 0.4.3

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.
@@ -79,6 +79,17 @@ export class FileServiceImpl {
79
79
  if (mappedUri === undefined) {
80
80
  mappedUri = `${this.virtualUrisRoot}${await this.externals.crypto
81
81
  .getSha1(virtualUri)}/${fileUtil.basename(virtualUri)}`;
82
+ // Delete old mapped file if it exists. This makes sure the
83
+ // readonly permission on the file is not removed by it being
84
+ // overwritten.
85
+ try {
86
+ await fileUtil.unlink(this.externals, mappedUri);
87
+ }
88
+ catch (e) {
89
+ if (!this.externals.error.isKind(e, 'ENOENT')) {
90
+ throw e;
91
+ }
92
+ }
82
93
  const buffer = await this.readFile(virtualUri);
83
94
  await fileUtil.writeFile(this.externals, mappedUri, buffer, 0o444);
84
95
  this.map.set(mappedUri, virtualUri);
@@ -148,7 +159,7 @@ export class FileUriSupporter {
148
159
  // return uri.protocol === Protocol && uri.hostname === Hostname
149
160
  // }
150
161
  // }
151
- class ArchiveUriSupporter {
162
+ export class ArchiveUriSupporter {
152
163
  externals;
153
164
  entries;
154
165
  static Protocol = 'archive:';
@@ -160,58 +171,58 @@ class ArchiveUriSupporter {
160
171
  ];
161
172
  protocol = ArchiveUriSupporter.Protocol;
162
173
  /**
163
- * @param entries A map from archive URIs to unzipped entries.
174
+ * @param entries A map from archive names to unzipped entries.
164
175
  */
165
176
  constructor(externals, entries) {
166
177
  this.externals = externals;
167
178
  this.entries = entries;
168
179
  }
169
180
  async hash(uri) {
170
- const { archiveUri, pathInArchive } = ArchiveUriSupporter.decodeUri(new Uri(uri));
181
+ const { archiveName, pathInArchive } = ArchiveUriSupporter.decodeUri(new Uri(uri));
171
182
  if (!pathInArchive) {
172
183
  // Hash the archive itself.
173
- return hashFile(this.externals, archiveUri);
184
+ return hashFile(this.externals, archiveName);
174
185
  }
175
186
  else {
176
187
  // Hash the corresponding file.
177
- return this.externals.crypto.getSha1(this.getDataInArchive(archiveUri, pathInArchive));
188
+ return this.externals.crypto.getSha1(this.getDataInArchive(archiveName, pathInArchive));
178
189
  }
179
190
  }
180
191
  async readFile(uri) {
181
- const { archiveUri, pathInArchive } = ArchiveUriSupporter.decodeUri(new Uri(uri));
182
- return this.getDataInArchive(archiveUri, pathInArchive);
192
+ const { archiveName, pathInArchive } = ArchiveUriSupporter.decodeUri(new Uri(uri));
193
+ return this.getDataInArchive(archiveName, pathInArchive);
183
194
  }
184
195
  /**
185
196
  * @throws
186
197
  */
187
- getDataInArchive(archiveUri, pathInArchive) {
188
- const entries = this.entries.get(archiveUri);
198
+ getDataInArchive(archiveName, pathInArchive) {
199
+ const entries = this.entries.get(archiveName);
189
200
  if (!entries) {
190
- throw new Error(`Archive “${archiveUri}” has not been loaded into the memory`);
201
+ throw new Error(`Archive “${archiveName}” has not been loaded into the memory`);
191
202
  }
192
203
  const entry = entries.get(pathInArchive);
193
204
  if (!entry) {
194
- throw new Error(`Path “${pathInArchive}” does not exist in archive “${archiveUri}”`);
205
+ throw new Error(`Path “${pathInArchive}” does not exist in archive “${archiveName}”`);
195
206
  }
196
207
  if (entry.type !== 'file') {
197
- throw new Error(`Path “${pathInArchive}” in archive “${archiveUri}” is not a file`);
208
+ throw new Error(`Path “${pathInArchive}” in archive “${archiveName}” is not a file`);
198
209
  }
199
210
  return entry.data;
200
211
  }
201
212
  *listFiles() {
202
- for (const [archiveUri, files] of this.entries.entries()) {
213
+ for (const [archiveName, files] of this.entries.entries()) {
203
214
  for (const file of files.values()) {
204
- yield ArchiveUriSupporter.getUri(archiveUri, file.path);
215
+ yield ArchiveUriSupporter.getUri(archiveName, file.path);
205
216
  }
206
217
  }
207
218
  }
208
219
  *listRoots() {
209
- for (const archiveUri of this.entries.keys()) {
210
- yield ArchiveUriSupporter.getUri(archiveUri);
220
+ for (const archiveName of this.entries.keys()) {
221
+ yield ArchiveUriSupporter.getUri(archiveName);
211
222
  }
212
223
  }
213
- static getUri(archiveUri, pathInArchive = '') {
214
- return `${ArchiveUriSupporter.Protocol}${encodeURIComponent(archiveUri)}?path=${encodeURIComponent(pathInArchive.replace(/\\/g, '/'))}`;
224
+ static getUri(archiveName, pathInArchive = '') {
225
+ return `${ArchiveUriSupporter.Protocol}//${archiveName}/${pathInArchive.replace(/\\/g, '/')}`;
215
226
  }
216
227
  /**
217
228
  * @throws When `uri` has the wrong protocol or hostname.
@@ -220,38 +231,32 @@ class ArchiveUriSupporter {
220
231
  if (uri.protocol !== ArchiveUriSupporter.Protocol) {
221
232
  throw new Error(`Expected protocol “${ArchiveUriSupporter.Protocol}” in “${uri}”`);
222
233
  }
223
- const path = uri.searchParams.get('path');
234
+ const path = uri.pathname;
224
235
  if (!path) {
225
236
  throw new Error(`Missing path in archive uri “${uri.toString()}”`);
226
237
  }
227
238
  return {
228
- archiveUri: decodeURIComponent(uri.pathname),
239
+ archiveName: uri.host,
229
240
  pathInArchive: path.charAt(0) === '/' ? path.slice(1) : path,
230
241
  };
231
242
  }
232
- static async create(dependencies, externals, logger, checksums) {
243
+ static async create(dependencies, externals, logger) {
233
244
  const entries = new Map();
234
245
  for (const { uri, info } of dependencies) {
235
246
  try {
236
247
  if (uri.startsWith('file:') &&
237
248
  ArchiveUriSupporter.SupportedArchiveExtnames.some((ext) => uri.endsWith(ext)) &&
238
249
  (await externals.fs.stat(uri)).isFile()) {
239
- const rootUri = ArchiveUriSupporter.getUri(uri);
240
- const cachedChecksum = checksums[rootUri];
241
- if (cachedChecksum !== undefined) {
242
- const checksum = await hashFile(externals, uri);
243
- if (cachedChecksum === checksum) {
244
- // The dependency has not changed since last cache.
245
- logger.info(`[SpyglassUriSupporter#create] Skipped decompressing “${uri}” thanks to cache ${checksum}`);
246
- continue;
247
- }
250
+ const archiveName = fileUtil.basename(uri);
251
+ if (entries.has(archiveName)) {
252
+ throw new Error(`A different URI with ${archiveName} already exists`);
248
253
  }
249
254
  const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), {
250
255
  stripLevel: typeof info?.startDepth === 'number'
251
256
  ? info.startDepth
252
257
  : 0,
253
258
  });
254
- entries.set(uri, new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f])));
259
+ entries.set(archiveName, new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f])));
255
260
  }
256
261
  }
257
262
  catch (e) {
@@ -261,7 +266,6 @@ class ArchiveUriSupporter {
261
266
  return new ArchiveUriSupporter(externals, entries);
262
267
  }
263
268
  }
264
- export { ArchiveUriSupporter };
265
269
  async function hashFile(externals, uri) {
266
270
  return externals.crypto.getSha1(await externals.fs.readFile(uri));
267
271
  }
@@ -21,7 +21,7 @@ import { ArchiveUriSupporter, FileService, FileUriSupporter, } from './FileServi
21
21
  import { fileUtil } from './fileUtil.js';
22
22
  import { MetaRegistry } from './MetaRegistry.js';
23
23
  import { ProfilerFactory } from './Profiler.js';
24
- const CacheAutoSaveInterval = 600000; // 10 Minutes.
24
+ const CacheAutoSaveInterval = 600_000; // 10 Minutes.
25
25
  /* istanbul ignore next */
26
26
  /**
27
27
  * Manage all tracked documents and errors.
@@ -60,7 +60,7 @@ const CacheAutoSaveInterval = 600000; // 10 Minutes.
60
60
  *
61
61
  * After the READY process is complete, editing text documents as signaled by the client or the file watcher results in the file being re-processed.
62
62
  */
63
- class Project {
63
+ export class Project {
64
64
  static RootSuffix = '/pack.mcmeta';
65
65
  /** Prevent circular binding. */
66
66
  #bindingInProgressUris = new Set();
@@ -290,7 +290,7 @@ class Project {
290
290
  const listDependencyFiles = async () => {
291
291
  const dependencies = await getDependencies();
292
292
  const fileUriSupporter = await FileUriSupporter.create(dependencies, this.externals, this.logger);
293
- const archiveUriSupporter = await ArchiveUriSupporter.create(dependencies, this.externals, this.logger, this.cacheService.checksums.roots);
293
+ const archiveUriSupporter = await ArchiveUriSupporter.create(dependencies, this.externals, this.logger);
294
294
  this.fs.register('file:', fileUriSupporter, true);
295
295
  this.fs.register(ArchiveUriSupporter.Protocol, archiveUriSupporter, true);
296
296
  };
@@ -721,5 +721,4 @@ __decorate([
721
721
  __decorate([
722
722
  SingletonPromise()
723
723
  ], Project.prototype, "ensureClientManagedChecked", null);
724
- export { Project };
725
724
  //# sourceMappingURL=Project.js.map
@@ -57,6 +57,7 @@ export declare namespace fileUtil {
57
57
  function chmod(externals: Externals, path: FsLocation, mode: number): Promise<void>;
58
58
  function ensureWritable(externals: Externals, path: FsLocation): Promise<void>;
59
59
  function markReadOnly(externals: Externals, path: FsLocation): Promise<void>;
60
+ function unlink(externals: Externals, path: FsLocation): Promise<void>;
60
61
  function readFile(externals: Externals, path: FsLocation): Promise<Uint8Array>;
61
62
  /**
62
63
  * @throws
@@ -123,6 +123,10 @@ export var fileUtil;
123
123
  return chmod(externals, path, 0o444);
124
124
  }
125
125
  fileUtil.markReadOnly = markReadOnly;
126
+ async function unlink(externals, path) {
127
+ return externals.fs.unlink(path);
128
+ }
129
+ fileUtil.unlink = unlink;
126
130
  async function readFile(externals, path) {
127
131
  return externals.fs.readFile(path);
128
132
  }
@@ -1,11 +1,11 @@
1
1
  import { Range } from './Range.js';
2
2
  export var IndexMap;
3
3
  (function (IndexMap) {
4
- function convertOffset(map, offset, from, to, isEndOffset) {
4
+ function convertOffset(map, offset, from, to) {
5
5
  let ans = offset;
6
6
  for (const pair of map) {
7
- if (Range.contains(pair[from], offset, isEndOffset)) {
8
- return isEndOffset ? pair[to].end : pair[to].start;
7
+ if (Range.contains(pair[from], offset)) {
8
+ return pair[to].start;
9
9
  }
10
10
  else if (Range.endsBefore(pair[from], offset)) {
11
11
  ans = offset - pair[from].end + pair[to].end;
@@ -17,19 +17,19 @@ export var IndexMap;
17
17
  return ans;
18
18
  }
19
19
  function toInnerOffset(map, offset) {
20
- return convertOffset(map, offset, 'outer', 'inner', false);
20
+ return convertOffset(map, offset, 'outer', 'inner');
21
21
  }
22
22
  IndexMap.toInnerOffset = toInnerOffset;
23
23
  function toInnerRange(map, outer) {
24
- return Range.create(toInnerOffset(map, outer.start), convertOffset(map, outer.end, 'outer', 'inner', true));
24
+ return Range.create(toInnerOffset(map, outer.start), toInnerOffset(map, outer.end));
25
25
  }
26
26
  IndexMap.toInnerRange = toInnerRange;
27
27
  function toOuterOffset(map, offset) {
28
- return convertOffset(map, offset, 'inner', 'outer', false);
28
+ return convertOffset(map, offset, 'inner', 'outer');
29
29
  }
30
30
  IndexMap.toOuterOffset = toOuterOffset;
31
31
  function toOuterRange(map, inner) {
32
- return Range.create(toOuterOffset(map, inner.start), convertOffset(map, inner.end, 'inner', 'outer', true));
32
+ return Range.create(toOuterOffset(map, inner.start), toOuterOffset(map, inner.end));
33
33
  }
34
34
  IndexMap.toOuterRange = toOuterRange;
35
35
  function merge(outerMap, innerMap) {
@@ -16,13 +16,13 @@ export interface LanguageError extends LanguageErrorData {
16
16
  export interface PosRangeLanguageError extends LanguageErrorData {
17
17
  posRange: PositionRange;
18
18
  }
19
- export declare const LanguageError: Readonly<{
20
- create(message: string, range: Range, severity?: ErrorSeverity, info?: LanguageErrorInfo): LanguageError;
19
+ export declare namespace LanguageError {
20
+ function create(message: string, range: Range, severity?: ErrorSeverity, info?: LanguageErrorInfo): LanguageError;
21
21
  /**
22
22
  * @returns A {@link PosRangeLanguageError}.
23
23
  */
24
- withPosRange(error: LanguageError, doc: TextDocument): PosRangeLanguageError;
25
- }>;
24
+ function withPosRange(error: LanguageError, doc: TextDocument): PosRangeLanguageError;
25
+ }
26
26
  export declare const enum ErrorSeverity {
27
27
  Hint = 0,
28
28
  Information = 1,
@@ -1,22 +1,25 @@
1
1
  import { PositionRange } from './PositionRange.js';
2
- export const LanguageError = Object.freeze({
3
- create(message, range, severity = 3 /* ErrorSeverity.Error */, info) {
2
+ export var LanguageError;
3
+ (function (LanguageError) {
4
+ function create(message, range, severity = 3 /* ErrorSeverity.Error */, info) {
4
5
  const ans = { range, message, severity };
5
6
  if (info) {
6
7
  ans.info = info;
7
8
  }
8
9
  return ans;
9
- },
10
+ }
11
+ LanguageError.create = create;
10
12
  /**
11
13
  * @returns A {@link PosRangeLanguageError}.
12
14
  */
13
- withPosRange(error, doc) {
15
+ function withPosRange(error, doc) {
14
16
  return {
15
17
  posRange: PositionRange.from(error.range, doc),
16
18
  message: error.message,
17
19
  severity: error.severity,
18
20
  ...(error.info && { info: error.info }),
19
21
  };
20
- },
21
- });
22
+ }
23
+ LanguageError.withPosRange = withPosRange;
24
+ })(LanguageError || (LanguageError = {}));
22
25
  //# sourceMappingURL=LanguageError.js.map
@@ -62,7 +62,7 @@ export declare class Source extends ReadonlySource {
62
62
  read(): string;
63
63
  /**
64
64
  * Skips the current character.
65
- * @param step The step to skip. @default 1
65
+ * @param step The step to skip. Defaults to 1
66
66
  */
67
67
  skip(step?: number): this;
68
68
  /**
@@ -110,11 +110,13 @@ export declare class Source extends ReadonlySource {
110
110
  skipUntilLineEnd(): this;
111
111
  readRemaining(): string;
112
112
  skipRemaining(): this;
113
- static isDigit(c: string): c is Digit;
114
- static isBrigadierQuote(c: string): c is '"' | "'";
115
- static isNewline(c: string): c is Newline;
116
- static isSpace(c: string): c is Space;
117
- static isWhitespace(c: string): c is Whitespace;
113
+ }
114
+ export declare namespace Source {
115
+ function isDigit(c: string): c is Digit;
116
+ function isBrigadierQuote(c: string): c is '"' | "'";
117
+ function isNewline(c: string): c is Newline;
118
+ function isSpace(c: string): c is Space;
119
+ function isWhitespace(c: string): c is Whitespace;
118
120
  }
119
121
  export {};
120
122
  //# sourceMappingURL=Source.d.ts.map
@@ -79,10 +79,10 @@ export class ReadonlySource {
79
79
  hasNonSpaceAheadInLine() {
80
80
  for (let cursor = this.innerCursor; cursor < this.string.length; cursor++) {
81
81
  const c = this.string.charAt(cursor);
82
- if (c === CR || c === LF) {
82
+ if (Source.isNewline(c)) {
83
83
  break;
84
84
  }
85
- if (!(c === ' ' || c === '\t')) {
85
+ if (!Source.isSpace(c)) {
86
86
  return true;
87
87
  }
88
88
  }
@@ -134,7 +134,7 @@ export class Source extends ReadonlySource {
134
134
  }
135
135
  /**
136
136
  * Skips the current character.
137
- * @param step The step to skip. @default 1
137
+ * @param step The step to skip. Defaults to 1
138
138
  */
139
139
  skip(step = 1) {
140
140
  this.innerCursor += step;
@@ -266,20 +266,27 @@ export class Source extends ReadonlySource {
266
266
  this.readRemaining();
267
267
  return this;
268
268
  }
269
- static isDigit(c) {
269
+ }
270
+ (function (Source) {
271
+ function isDigit(c) {
270
272
  return c >= '0' && c <= '9';
271
273
  }
272
- static isBrigadierQuote(c) {
274
+ Source.isDigit = isDigit;
275
+ function isBrigadierQuote(c) {
273
276
  return c === '"' || c === "'";
274
277
  }
275
- static isNewline(c) {
278
+ Source.isBrigadierQuote = isBrigadierQuote;
279
+ function isNewline(c) {
276
280
  return c === '\r\n' || c === '\r' || c === '\n';
277
281
  }
278
- static isSpace(c) {
282
+ Source.isNewline = isNewline;
283
+ function isSpace(c) {
279
284
  return c === ' ' || c === '\t';
280
285
  }
281
- static isWhitespace(c) {
286
+ Source.isSpace = isSpace;
287
+ function isWhitespace(c) {
282
288
  return Source.isSpace(c) || Source.isNewline(c);
283
289
  }
284
- }
290
+ Source.isWhitespace = isWhitespace;
291
+ })(Source || (Source = {}));
285
292
  //# sourceMappingURL=Source.js.map