@spyglassmc/core 0.2.0 → 0.3.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.
Files changed (78) hide show
  1. package/lib/common/Dev.d.ts +11 -0
  2. package/lib/common/Dev.js +90 -0
  3. package/lib/{service → common}/Logger.d.ts +0 -0
  4. package/lib/{service → common}/Logger.js +0 -0
  5. package/lib/common/Operations.d.ts +12 -0
  6. package/lib/common/Operations.js +33 -0
  7. package/lib/common/ReadonlyProxy.d.ts +9 -0
  8. package/lib/common/ReadonlyProxy.js +23 -0
  9. package/lib/common/StateProxy.d.ts +35 -0
  10. package/lib/common/StateProxy.js +69 -0
  11. package/lib/common/externals/NodeJsExternals.js +1 -0
  12. package/lib/common/index.d.ts +6 -0
  13. package/lib/common/index.js +6 -0
  14. package/lib/common/util.d.ts +33 -5
  15. package/lib/common/util.js +43 -11
  16. package/lib/node/AstNode.d.ts +9 -8
  17. package/lib/node/CommentNode.d.ts +5 -4
  18. package/lib/node/CommentNode.js +4 -6
  19. package/lib/node/FileNode.d.ts +5 -1
  20. package/lib/node/FileNode.js +1 -1
  21. package/lib/node/FloatNode.d.ts +1 -1
  22. package/lib/node/IntegerNode.d.ts +1 -1
  23. package/lib/node/LiteralNode.d.ts +1 -1
  24. package/lib/node/LongNode.d.ts +1 -1
  25. package/lib/node/ResourceLocationNode.d.ts +3 -3
  26. package/lib/node/StringNode.d.ts +1 -1
  27. package/lib/node/SymbolNode.d.ts +1 -1
  28. package/lib/parser/resourceLocation.js +0 -8
  29. package/lib/parser/string.d.ts +2 -2
  30. package/lib/parser/symbol.js +1 -7
  31. package/lib/parser/util.js +0 -2
  32. package/lib/processor/InlayHintProvider.d.ts +2 -1
  33. package/lib/processor/SignatureHelpProvider.d.ts +2 -1
  34. package/lib/processor/binder/Binder.d.ts +26 -0
  35. package/lib/processor/binder/Binder.js +18 -0
  36. package/lib/processor/binder/builtin.d.ts +27 -0
  37. package/lib/processor/binder/builtin.js +116 -0
  38. package/lib/processor/binder/index.d.ts +3 -0
  39. package/lib/processor/binder/index.js +3 -0
  40. package/lib/processor/checker/builtin.js +5 -5
  41. package/lib/processor/colorizer/Colorizer.d.ts +2 -1
  42. package/lib/processor/completer/Completer.d.ts +2 -1
  43. package/lib/processor/completer/builtin.d.ts +3 -2
  44. package/lib/processor/completer/builtin.js +1 -1
  45. package/lib/processor/formatter/Formatter.d.ts +2 -1
  46. package/lib/processor/index.d.ts +1 -0
  47. package/lib/processor/index.js +1 -0
  48. package/lib/processor/linter/Linter.d.ts +2 -1
  49. package/lib/processor/linter/builtin.d.ts +2 -1
  50. package/lib/processor/util.d.ts +3 -13
  51. package/lib/processor/util.js +0 -10
  52. package/lib/service/CacheService.d.ts +2 -0
  53. package/lib/service/CacheService.js +3 -0
  54. package/lib/service/Context.d.ts +15 -12
  55. package/lib/service/Context.js +12 -6
  56. package/lib/service/Downloader.d.ts +1 -2
  57. package/lib/service/FileService.d.ts +1 -2
  58. package/lib/service/MetaRegistry.d.ts +8 -3
  59. package/lib/service/MetaRegistry.js +20 -1
  60. package/lib/service/Profiler.d.ts +3 -2
  61. package/lib/service/Profiler.js +58 -6
  62. package/lib/service/Project.d.ts +55 -24
  63. package/lib/service/Project.js +265 -166
  64. package/lib/service/Service.d.ts +1 -1
  65. package/lib/service/UriProcessor.d.ts +5 -0
  66. package/lib/service/UriProcessor.js +2 -0
  67. package/lib/service/index.d.ts +1 -2
  68. package/lib/service/index.js +1 -2
  69. package/lib/symbol/Symbol.d.ts +3 -2
  70. package/lib/symbol/SymbolUtil.d.ts +8 -7
  71. package/lib/symbol/SymbolUtil.js +31 -9
  72. package/lib/symbol/index.d.ts +0 -1
  73. package/lib/symbol/index.js +0 -1
  74. package/package.json +2 -2
  75. package/lib/service/Operations.d.ts +0 -8
  76. package/lib/service/Operations.js +0 -20
  77. package/lib/symbol/UriBinder.d.ts +0 -3
  78. package/lib/symbol/UriBinder.js +0 -2
@@ -0,0 +1,11 @@
1
+ export declare const Dev: Readonly<{
2
+ assertDefined<T>(value: T): asserts value is Exclude<T, undefined>;
3
+ assertNever(value: never): never;
4
+ assertTrue(value: boolean, message: string): void;
5
+ /**
6
+ * @returns An estimate of the memory taken by the given value, assuming objects are stored as array-like structures instead of dictionaries in the V8 engine.
7
+ */
8
+ estimateMemoryUsage(value: unknown): number;
9
+ stringify(value: unknown): string;
10
+ }>;
11
+ //# sourceMappingURL=Dev.d.ts.map
@@ -0,0 +1,90 @@
1
+ export const Dev = Object.freeze({
2
+ assertDefined(value) {
3
+ if (value === undefined) {
4
+ throw new Error(`'${Dev.stringify(value)}' is 'undefined'`);
5
+ }
6
+ },
7
+ assertNever(value) {
8
+ throw new Error(`'${Dev.stringify(value)}' is not of type 'never'`);
9
+ },
10
+ assertTrue(value, message) {
11
+ if (!value) {
12
+ throw new Error(`Assertion failed: ${message}. '${Dev.stringify(value)}' should be true.`);
13
+ }
14
+ },
15
+ /**
16
+ * @returns An estimate of the memory taken by the given value, assuming objects are stored as array-like structures instead of dictionaries in the V8 engine.
17
+ */
18
+ estimateMemoryUsage(value) {
19
+ const ByteToBits = 8;
20
+ const PointerSize = 8;
21
+ let ans = 0;
22
+ const calculatedObjects = new Set();
23
+ const stack = [value];
24
+ while (stack.length) {
25
+ const current = stack.pop();
26
+ switch (typeof current) {
27
+ case 'bigint': {
28
+ const bits = Math.ceil(Math.log2(Number(current)));
29
+ ans += (2 + Math.ceil(bits / (ByteToBits * PointerSize))) * PointerSize; // https://stackoverflow.com/a/54298760
30
+ break;
31
+ }
32
+ case 'boolean':
33
+ ans += PointerSize; // Aggressive alignment estimation.
34
+ break;
35
+ case 'number':
36
+ ans += 8;
37
+ break;
38
+ case 'object':
39
+ ans += PointerSize; // Reference pointer.
40
+ if (!current || calculatedObjects.has(current)) {
41
+ break;
42
+ }
43
+ ans += PointerSize; // Header pointer.
44
+ for (const value of Object.values(current)) {
45
+ stack.push(value);
46
+ ans += PointerSize; // Aggressive padding estimation.
47
+ }
48
+ calculatedObjects.add(current);
49
+ break;
50
+ case 'string':
51
+ ans += current.length * 2;
52
+ break;
53
+ case 'symbol':
54
+ ans += PointerSize;
55
+ break;
56
+ default:
57
+ break;
58
+ }
59
+ }
60
+ return ans;
61
+ },
62
+ stringify(value) {
63
+ if (value && typeof value === 'object') {
64
+ try {
65
+ const seen = new Set();
66
+ return JSON.stringify(value, (_k, v) => {
67
+ if (v && typeof v === 'object') {
68
+ return seen.has(v) ? '[Circular]' : (seen.add(v), v);
69
+ }
70
+ else {
71
+ return v;
72
+ }
73
+ });
74
+ }
75
+ catch (ignored) {
76
+ // Most likely "Maximum callstack size exceeded".
77
+ // Fall back to a shallow string representation.
78
+ return `{ ${Object.entries(value).map(([k, v]) => `'${k}': '${String(v)}'`).join(', ')} }`;
79
+ }
80
+ }
81
+ else if (typeof value === 'symbol') {
82
+ // JavaScript does not convert `Symbol`s to strings implicitly.
83
+ return String(value);
84
+ }
85
+ else {
86
+ return `${value}`;
87
+ }
88
+ },
89
+ });
90
+ //# sourceMappingURL=Dev.js.map
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ export declare class Operations {
2
+ private readonly parent?;
3
+ constructor(parent?: Operations | undefined);
4
+ private readonly undoOps;
5
+ private readonly redoOps;
6
+ private addUndoOp;
7
+ private addRedoOp;
8
+ set<O extends object, K extends keyof O>(obj: O, key: K, value: O[K], receiver?: any): void;
9
+ undo(): void;
10
+ redo(): void;
11
+ }
12
+ //# sourceMappingURL=Operations.d.ts.map
@@ -0,0 +1,33 @@
1
+ export class Operations {
2
+ parent;
3
+ constructor(parent) {
4
+ this.parent = parent;
5
+ }
6
+ undoOps = [];
7
+ redoOps = [];
8
+ addUndoOp(op) {
9
+ this.undoOps.push(op);
10
+ this.parent?.addUndoOp(op);
11
+ }
12
+ addRedoOp(op) {
13
+ this.redoOps.push(op);
14
+ this.parent?.addRedoOp(op);
15
+ }
16
+ set(obj, key, value, receiver = obj) {
17
+ const oldValue = Reflect.get(obj, key, receiver);
18
+ const op = () => { Reflect.set(obj, key, value, receiver); };
19
+ const undoOp = () => { Reflect.set(obj, key, oldValue, receiver); };
20
+ this.addRedoOp(op);
21
+ this.addUndoOp(undoOp);
22
+ op();
23
+ }
24
+ undo() {
25
+ for (let i = this.undoOps.length - 1; i >= 0; i--) {
26
+ this.undoOps[i]();
27
+ }
28
+ }
29
+ redo() {
30
+ this.redoOps.forEach(op => op());
31
+ }
32
+ }
33
+ //# sourceMappingURL=Operations.js.map
@@ -0,0 +1,9 @@
1
+ declare type Wrap<T> = T extends object ? DeepReadonly<T> : T;
2
+ export declare type DeepReadonly<T extends object> = {
3
+ readonly [K in keyof T]: Wrap<T[K]>;
4
+ };
5
+ export declare const ReadonlyProxy: Readonly<{
6
+ create<T extends object>(obj: T): DeepReadonly<T>;
7
+ }>;
8
+ export {};
9
+ //# sourceMappingURL=ReadonlyProxy.d.ts.map
@@ -0,0 +1,23 @@
1
+ import { emplaceMap, isObject } from './util.js';
2
+ export const ReadonlyProxy = Object.freeze({
3
+ create(obj) {
4
+ return new Proxy(obj, new ReadonlyProxyHandler());
5
+ },
6
+ });
7
+ class ReadonlyProxyHandler {
8
+ map = new Map();
9
+ get(target, p, receiver) {
10
+ const value = Reflect.get(target, p, receiver);
11
+ if (p !== 'prototype' && isObject(value)) {
12
+ return emplaceMap(this.map, p, { insert: () => ReadonlyProxy.create(value) });
13
+ }
14
+ return value;
15
+ }
16
+ set(_target, p, _value, _receiver) {
17
+ throw new TypeError(`Cannot set property '${String(p)}' on a readonly proxy`);
18
+ }
19
+ deleteProperty(_target, p) {
20
+ throw new TypeError(`Cannot delete property '${String(p)}' on a readonly proxy`);
21
+ }
22
+ }
23
+ //# sourceMappingURL=ReadonlyProxy.js.map
@@ -0,0 +1,35 @@
1
+ declare const BranchOff: unique symbol;
2
+ declare const Is: unique symbol;
3
+ declare const Origin: unique symbol;
4
+ declare const Redo: unique symbol;
5
+ declare const Undo: unique symbol;
6
+ declare type Wrap<T> = T extends object ? StateProxy<T> : T;
7
+ /**
8
+ * A proxy wrapped around an arbitrary object value.
9
+ * You can access and mutate the value as normal, but you also have the ability to revert all changes ever since the
10
+ * proxy was created using {@link StateProxy.redoChanges} and {@link StateProxy.undoChanges}.
11
+ *
12
+ * A new proxy can be branched off of an existing proxy using {@link StateProxy.branchOff} to have finer control
13
+ * over what changes to be reverted.
14
+ */
15
+ export declare type StateProxy<T extends object> = {
16
+ [K in keyof T]: Wrap<T[K]>;
17
+ } & {
18
+ [BranchOff]: () => StateProxy<T>;
19
+ [Is]: true;
20
+ [Origin]: T;
21
+ [Redo]: () => void;
22
+ [Undo]: () => void;
23
+ };
24
+ export declare const StateProxy: Readonly<{
25
+ branchOff<T extends object>(proxy: StateProxy<T>): StateProxy<T>;
26
+ create<T_1 extends object>(obj: T_1): T_1 extends StateProxy<any> ? void & {
27
+ _cannotCreateProxyFromProxy: never;
28
+ } : StateProxy<T_1>;
29
+ dereference<T_2 extends object>(value: T_2 | StateProxy<T_2>): T_2;
30
+ is(obj: any): obj is StateProxy<object>;
31
+ redoChanges(proxy: StateProxy<object>): void;
32
+ undoChanges(proxy: StateProxy<object>): void;
33
+ }>;
34
+ export {};
35
+ //# sourceMappingURL=StateProxy.d.ts.map
@@ -0,0 +1,69 @@
1
+ import { emplaceMap, isObject } from '../common/index.js';
2
+ import { Operations } from './Operations.js';
3
+ const BranchOff = Symbol('StateBranchOff');
4
+ const Is = Symbol('IsStateProxy');
5
+ const Origin = Symbol('OriginState');
6
+ const Redo = Symbol('RedoStateChanges');
7
+ const Undo = Symbol('UndoStateChanges');
8
+ export const StateProxy = Object.freeze({
9
+ branchOff(proxy) {
10
+ return proxy[BranchOff]();
11
+ },
12
+ create(obj) {
13
+ if (StateProxy.is(obj)) {
14
+ throw new TypeError('Cannot create a proxy over a proxy. You might want to use branchOff instead.');
15
+ }
16
+ return _createStateProxy(obj, new Operations());
17
+ },
18
+ dereference(value) {
19
+ return StateProxy.is(value) ? value[Origin] : value;
20
+ },
21
+ is(obj) {
22
+ return obj?.[Is];
23
+ },
24
+ redoChanges(proxy) {
25
+ proxy[Redo]();
26
+ },
27
+ undoChanges(proxy) {
28
+ proxy[Undo]();
29
+ },
30
+ });
31
+ class StateProxyHandler {
32
+ rootOps;
33
+ map = new Map();
34
+ constructor(
35
+ /**
36
+ * Shared across all handlers created for the same root state object under the same branch.
37
+ */
38
+ rootOps) {
39
+ this.rootOps = rootOps;
40
+ }
41
+ #branchOff(target) {
42
+ return _createStateProxy(target, new Operations(this.rootOps));
43
+ }
44
+ get(target, p, receiver) {
45
+ switch (p) {
46
+ case BranchOff: return () => this.#branchOff(target);
47
+ case Is: return true;
48
+ case Origin: return target;
49
+ case Redo: return () => this.rootOps.redo();
50
+ case Undo: return () => this.rootOps.undo();
51
+ }
52
+ const value = Reflect.get(target, p, receiver);
53
+ if (p !== 'prototype' && isObject(value)) {
54
+ return emplaceMap(this.map, p, { insert: () => _createStateProxy(value, this.rootOps) });
55
+ }
56
+ return value;
57
+ }
58
+ set(target, p, value, receiver) {
59
+ if (p === BranchOff || p === Is || p === Origin || p === Redo || p === Undo) {
60
+ throw new TypeError(`Cannot set ${String(p)}`);
61
+ }
62
+ this.rootOps.set(target, p, StateProxy.dereference(value), receiver);
63
+ return true;
64
+ }
65
+ }
66
+ function _createStateProxy(target, operations) {
67
+ return new Proxy(target, new StateProxyHandler(operations));
68
+ }
69
+ //# sourceMappingURL=StateProxy.js.map
@@ -1,3 +1,4 @@
1
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/60592
1
2
  import chokidar from 'chokidar';
2
3
  import decompress from 'decompress';
3
4
  import followRedirects from 'follow-redirects';
@@ -1,3 +1,9 @@
1
+ export * from './Dev.js';
1
2
  export * from './externals/index.js';
3
+ export * from './Logger.js';
4
+ export * from './Operations.js';
5
+ export * from './ReadonlyProxy.js';
6
+ export * from './StateProxy.js';
7
+ export * from './TwoWayMap.js';
2
8
  export * from './util.js';
3
9
  //# sourceMappingURL=index.d.ts.map
@@ -1,3 +1,9 @@
1
+ export * from './Dev.js';
1
2
  export * from './externals/index.js';
3
+ export * from './Logger.js';
4
+ export * from './Operations.js';
5
+ export * from './ReadonlyProxy.js';
6
+ export * from './StateProxy.js';
7
+ export * from './TwoWayMap.js';
2
8
  export * from './util.js';
3
9
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,8 @@
1
1
  import externalBinarySearch from 'binary-search';
2
+ import type { AstNode } from '../node/index.js';
2
3
  import type { ProcessorContext } from '../service/index.js';
3
4
  import type { Externals } from './externals/index.js';
5
+ import type { DeepReadonly } from './ReadonlyProxy.js';
4
6
  export declare const Uri: {
5
7
  new (url: string | URL, base?: string | URL | undefined): URL;
6
8
  prototype: URL;
@@ -13,14 +15,14 @@ export declare type Uri = URL;
13
15
  */
14
16
  export declare type IntervalId = any;
15
17
  /**
16
- * @param getCacheKey A function that takes the actual arguments being passed into the decorated method, and returns anything.
17
- * The result of this function will be used as the key to cache the `Promise`. By default the first element in the argument
18
+ * @param getKey A function that takes the actual arguments being passed into the decorated method, and returns anything.
19
+ * The result of this function will be used as the key to identify the `Promise`. By default the first element in the argument
18
20
  * list will be used.
19
21
  *
20
22
  * This is a decorator for async methods. Decorated methods will return the same `Promise` for
21
- * the same arguments, provided that the cached `Promise` is still pending.
23
+ * the same key, provided that the previously returned `Promise` is still pending.
22
24
  */
23
- export declare function CachePromise(getCacheKey?: (args: any[]) => any): MethodDecorator;
25
+ export declare function SingletonPromise(getKey?: (args: any[]) => any): MethodDecorator;
24
26
  /**
25
27
  * This is a decorator for methods. Decorated methods will return the same non-`undefined` value no matter what.
26
28
  */
@@ -71,7 +73,10 @@ export declare namespace TypePredicates {
71
73
  }
72
74
  export declare function promisifyAsyncIterable<T, U>(iterable: AsyncIterable<T>, joiner: (chunks: T[]) => U): Promise<U>;
73
75
  export declare function parseGzippedJson(externals: Externals, buffer: Uint8Array): Promise<unknown>;
74
- export declare function isObject(value: unknown): value is Exclude<object, Array<any>>;
76
+ /**
77
+ * @returns Is Plain Old JavaScript Object (POJO).
78
+ */
79
+ export declare function isPojo(value: unknown): value is Record<string, unknown>;
75
80
  export declare function merge<T extends Record<string, any>>(a: T, b: Record<string, any>): T;
76
81
  export declare type Lazy<T> = T | Lazy.ComplexLazy<T>;
77
82
  export declare namespace Lazy {
@@ -100,4 +105,27 @@ export declare namespace Lazy {
100
105
  export declare function getStates(category: 'block' | 'fluid', ids: readonly string[], ctx: ProcessorContext): Record<string, string[]>;
101
106
  export declare const binarySearch: typeof externalBinarySearch;
102
107
  export declare function isIterable(value: unknown): value is Iterable<unknown>;
108
+ export declare function atArray<T>(array: readonly T[] | undefined, index: number): T | undefined;
109
+ export declare function emplaceMap<K, V>(map: Map<K, V>, key: K, handler: {
110
+ insert?: (key: K, map: Map<K, V>) => V;
111
+ update?: (existing: V, key: K, map: Map<K, V>) => V;
112
+ }): V;
113
+ /**
114
+ * @returns If `val` is an non-null object or a callable object (i.e. function).
115
+ */
116
+ export declare function isObject(val: unknown): val is object;
117
+ /**
118
+ * @example
119
+ * ```ts
120
+ * function isCommentNode<T extends DeepReadonly<AstNode> | undefined>(node: T): node is IsHelper<AstNode, CommentNode, T>
121
+ * ```
122
+ */
123
+ export declare type IsHelper<ROOT extends object, TARGET extends ROOT, INPUT extends DeepReadonly<ROOT> | undefined> = INPUT extends DeepReadonly<ROOT> ? INPUT & DeepReadonly<TARGET> : INPUT & TARGET;
124
+ /**
125
+ * @example
126
+ * ```ts
127
+ * function isCommentNode<T extends DeepReadonly<AstNode> | undefined>(node: T): node is NodeIsHelper<CommentNode, T>
128
+ * ```
129
+ */
130
+ export declare type NodeIsHelper<TARGET extends AstNode, INPUT extends DeepReadonly<AstNode> | undefined> = IsHelper<AstNode, TARGET, INPUT>;
103
131
  //# sourceMappingURL=util.d.ts.map
@@ -2,26 +2,26 @@ import externalBinarySearch from 'binary-search';
2
2
  import rfdc from 'rfdc';
3
3
  export const Uri = URL;
4
4
  /**
5
- * @param getCacheKey A function that takes the actual arguments being passed into the decorated method, and returns anything.
6
- * The result of this function will be used as the key to cache the `Promise`. By default the first element in the argument
5
+ * @param getKey A function that takes the actual arguments being passed into the decorated method, and returns anything.
6
+ * The result of this function will be used as the key to identify the `Promise`. By default the first element in the argument
7
7
  * list will be used.
8
8
  *
9
9
  * This is a decorator for async methods. Decorated methods will return the same `Promise` for
10
- * the same arguments, provided that the cached `Promise` is still pending.
10
+ * the same key, provided that the previously returned `Promise` is still pending.
11
11
  */
12
- export function CachePromise(getCacheKey = args => args[0]) {
12
+ export function SingletonPromise(getKey = args => args[0]) {
13
13
  return (_target, _key, descripter) => {
14
14
  const promises = new Map();
15
15
  const decoratedMethod = descripter.value;
16
16
  // The `function` syntax is used to preserve `this` context from the decorated method.
17
17
  descripter.value = function (...args) {
18
- const cacheKey = getCacheKey(args);
19
- if (promises.has(cacheKey)) {
20
- return promises.get(cacheKey);
18
+ const key = getKey(args);
19
+ if (promises.has(key)) {
20
+ return promises.get(key);
21
21
  }
22
22
  const ans = decoratedMethod.apply(this, args)
23
- .then(ans => (promises.delete(cacheKey), ans), e => (promises.delete(cacheKey), Promise.reject(e)));
24
- promises.set(cacheKey, ans);
23
+ .then(ans => (promises.delete(key), ans), e => (promises.delete(key), Promise.reject(e)));
24
+ promises.set(key, ans);
25
25
  return ans;
26
26
  };
27
27
  return descripter;
@@ -138,13 +138,16 @@ export function promisifyAsyncIterable(iterable, joiner) {
138
138
  export async function parseGzippedJson(externals, buffer) {
139
139
  return JSON.parse(bufferToString(await externals.archive.gunzip(buffer)));
140
140
  }
141
- export function isObject(value) {
141
+ /**
142
+ * @returns Is Plain Old JavaScript Object (POJO).
143
+ */
144
+ export function isPojo(value) {
142
145
  return !!value && typeof value === 'object' && !Array.isArray(value);
143
146
  }
144
147
  export function merge(a, b) {
145
148
  const ans = rfdc()(a);
146
149
  for (const [key, value] of Object.entries(b)) {
147
- if (isObject(ans[key]) && isObject(value)) {
150
+ if (isPojo(ans[key]) && isPojo(value)) {
148
151
  ans[key] = merge(ans[key], value);
149
152
  }
150
153
  else if (value === undefined) {
@@ -208,4 +211,33 @@ export const binarySearch = externalBinarySearch;
208
211
  export function isIterable(value) {
209
212
  return !!value[Symbol.iterator];
210
213
  }
214
+ //#region ESNext functions polyfill
215
+ export function atArray(array, index) {
216
+ return index >= 0 ? array?.[index] : array?.[array.length + index];
217
+ }
218
+ export function emplaceMap(map, key, handler) {
219
+ if (map.has(key)) {
220
+ let value = map.get(key);
221
+ if (handler.update) {
222
+ value = handler.update(value, key, map);
223
+ map.set(key, value);
224
+ }
225
+ return value;
226
+ }
227
+ else if (handler.insert) {
228
+ const value = handler.insert(key, map);
229
+ map.set(key, value);
230
+ return value;
231
+ }
232
+ else {
233
+ throw new Error(`No key ${key} in map and no insert handler provided`);
234
+ }
235
+ }
236
+ //#endregion
237
+ /**
238
+ * @returns If `val` is an non-null object or a callable object (i.e. function).
239
+ */
240
+ export function isObject(val) {
241
+ return typeof val === 'function' || (!!val && typeof val === 'object');
242
+ }
211
243
  //# sourceMappingURL=util.js.map
@@ -1,14 +1,15 @@
1
+ import type { DeepReadonly } from '../common/index.js';
1
2
  import type { Color, FormattableColor } from '../processor/index.js';
2
3
  import { Range } from '../source/index.js';
3
4
  import type { Symbol, SymbolTable } from '../symbol/index.js';
4
5
  export interface AstNode {
5
- readonly type: string;
6
- readonly range: Range;
6
+ type: string;
7
+ range: Range;
7
8
  /**
8
9
  * All child nodes of this AST node.
9
10
  */
10
- readonly children?: AstNode[];
11
- readonly parent?: AstNode;
11
+ children?: AstNode[];
12
+ parent?: AstNode;
12
13
  locals?: SymbolTable;
13
14
  symbol?: Symbol;
14
15
  hover?: string;
@@ -23,21 +24,21 @@ export declare namespace AstNode {
23
24
  /**
24
25
  * @param endInclusive Defaults to `false`.
25
26
  */
26
- export function findChildIndex(node: AstNode, needle: number | Range, endInclusive?: boolean): number;
27
+ export function findChildIndex(node: DeepReadonly<AstNode>, needle: number | Range, endInclusive?: boolean): number;
27
28
  /**
28
29
  * @param endInclusive Defaults to `false`.
29
30
  */
30
- export function findChild<N extends AstNode>(node: N, needle: number | Range, endInclusive?: boolean): Exclude<N['children'], undefined>[number] | undefined;
31
+ export function findChild<N extends DeepReadonly<AstNode>>(node: N, needle: number | Range, endInclusive?: boolean): Exclude<N['children'], undefined>[number] | undefined;
31
32
  /**
32
33
  * Returns the index of the last child node that ends before the `needle`.
33
34
  *
34
35
  * @param endInclusive Defaults to `false`.
35
36
  */
36
- export function findLastChildIndex(node: AstNode, needle: number | Range, endInclusive?: boolean): number;
37
+ export function findLastChildIndex(node: DeepReadonly<AstNode>, needle: number | Range, endInclusive?: boolean): number;
37
38
  /**
38
39
  * @param endInclusive Defaults to `false`.
39
40
  */
40
- export function findLastChild<N extends AstNode>(node: N, needle: number | Range, endInclusive?: boolean): (N['children'] extends unknown[] ? N['children'][number] : undefined) | undefined;
41
+ export function findLastChild<N extends DeepReadonly<AstNode>>(node: N, needle: number | Range, endInclusive?: boolean): (N['children'] extends readonly unknown[] ? N['children'][number] : undefined) | undefined;
41
42
  interface FindRecursivelyOptions<P = (node: AstNode) => boolean> {
42
43
  node: AstNode;
43
44
  needle: number;
@@ -1,12 +1,13 @@
1
+ import type { DeepReadonly } from '../common/index.js';
1
2
  import type { AstNode } from './AstNode.js';
2
3
  export interface CommentNode extends AstNode {
3
4
  readonly type: 'comment';
4
5
  /**
5
6
  * The actual comment with prefixes and suffixes removed.
6
7
  */
7
- readonly comment: string;
8
- }
9
- export declare namespace CommentNode {
10
- function is(obj: AstNode | undefined): obj is CommentNode;
8
+ comment: string;
11
9
  }
10
+ export declare const CommentNode: Readonly<{
11
+ is<T extends DeepReadonly<AstNode> | undefined>(obj: T): obj is import("../common/util.js").IsHelper<AstNode, CommentNode, T>;
12
+ }>;
12
13
  //# sourceMappingURL=CommentNode.d.ts.map
@@ -1,8 +1,6 @@
1
- export var CommentNode;
2
- (function (CommentNode) {
3
- function is(obj) {
1
+ export const CommentNode = Object.freeze({
2
+ is(obj) {
4
3
  return obj?.type === 'comment';
5
- }
6
- CommentNode.is = is;
7
- })(CommentNode || (CommentNode = {}));
4
+ },
5
+ });
8
6
  //# sourceMappingURL=CommentNode.js.map
@@ -5,7 +5,11 @@ export interface FileNode<CN extends AstNode> extends AstNode {
5
5
  readonly type: 'file';
6
6
  readonly children: CN[];
7
7
  locals: SymbolTable;
8
- readonly parserErrors: readonly LanguageError[];
8
+ parserErrors: readonly LanguageError[];
9
+ /**
10
+ * Only exists when the file has been bound.
11
+ */
12
+ binderErrors?: readonly LanguageError[];
9
13
  /**
10
14
  * Only exists when the file has been checked.
11
15
  */
@@ -1,7 +1,7 @@
1
1
  export var FileNode;
2
2
  (function (FileNode) {
3
3
  function getErrors(node) {
4
- return [...node.parserErrors, ...node.checkerErrors ?? [], ...node.linterErrors ?? []];
4
+ return [...node.parserErrors, ...node.binderErrors ?? [], ...node.checkerErrors ?? [], ...node.linterErrors ?? []];
5
5
  }
6
6
  FileNode.getErrors = getErrors;
7
7
  })(FileNode || (FileNode = {}));
@@ -1,7 +1,7 @@
1
1
  import type { RangeLike } from '../source/index.js';
2
2
  import type { AstNode } from './AstNode.js';
3
3
  export interface FloatBaseNode extends AstNode {
4
- readonly value: number;
4
+ value: number;
5
5
  }
6
6
  export interface FloatNode extends FloatBaseNode {
7
7
  readonly type: 'float';
@@ -1,7 +1,7 @@
1
1
  import type { RangeLike } from '../source/index.js';
2
2
  import type { AstNode } from './AstNode.js';
3
3
  export interface IntegerBaseNode extends AstNode {
4
- readonly value: number;
4
+ value: number;
5
5
  }
6
6
  export interface IntegerNode extends IntegerBaseNode {
7
7
  readonly type: 'integer';
@@ -7,7 +7,7 @@ export interface LiteralOptions {
7
7
  }
8
8
  export interface LiteralBaseNode extends AstNode {
9
9
  readonly options: LiteralOptions;
10
- readonly value: string;
10
+ value: string;
11
11
  }
12
12
  export interface LiteralNode extends LiteralBaseNode {
13
13
  readonly type: 'literal';
@@ -1,7 +1,7 @@
1
1
  import type { RangeLike } from '../source/index.js';
2
2
  import type { AstNode } from './AstNode.js';
3
3
  export interface LongBaseNode extends AstNode {
4
- readonly value: bigint;
4
+ value: bigint;
5
5
  }
6
6
  export interface LongNode extends LongBaseNode {
7
7
  readonly type: 'long';
@@ -1,4 +1,4 @@
1
- import type { FullResourceLocation } from '../common/index.js';
1
+ import type { DeepReadonly, FullResourceLocation } from '../common/index.js';
2
2
  import { ResourceLocation } from '../common/index.js';
3
3
  import type { RangeLike } from '../source/index.js';
4
4
  import type { ResourceLocationCategory, SymbolAccessType, SymbolUsageType, TaggableResourceLocationCategory } from '../symbol/index.js';
@@ -33,7 +33,7 @@ export interface ResourceLocationNode extends ResourceLocationBaseNode {
33
33
  export declare namespace ResourceLocationNode {
34
34
  function is(obj: AstNode | undefined): obj is ResourceLocationNode;
35
35
  function mock(range: RangeLike, options: ResourceLocationOptions): ResourceLocationNode;
36
- function toString(node: ResourceLocationBaseNode, type?: 'full'): FullResourceLocation;
37
- function toString(node: ResourceLocationBaseNode, type?: 'origin' | 'full' | 'short'): string;
36
+ function toString(node: DeepReadonly<ResourceLocationBaseNode>, type?: 'full'): FullResourceLocation;
37
+ function toString(node: DeepReadonly<ResourceLocationBaseNode>, type?: 'origin' | 'full' | 'short'): string;
38
38
  }
39
39
  //# sourceMappingURL=ResourceLocationNode.d.ts.map
@@ -50,7 +50,7 @@ export interface StringOptions {
50
50
  export declare type QuoteTypeConfig = 'always double' | 'always single' | 'prefer double' | 'prefer single';
51
51
  export interface StringBaseNode extends AstNode {
52
52
  readonly options: StringOptions;
53
- readonly value: string;
53
+ value: string;
54
54
  readonly valueMap: IndexMap;
55
55
  }
56
56
  export interface StringNode extends StringBaseNode {