@spyglassmc/mcdoc 0.3.8 → 0.3.10

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.
@@ -0,0 +1,22 @@
1
+ import * as core from '@spyglassmc/core';
2
+ import type { Attribute, StructTypePairField } from '../../type/index.js';
3
+ import type { McdocCheckerContext, SimplifiedMcdocType, SimplifiedMcdocTypeNoUnion } from '../checker/index.js';
4
+ import type { McdocCompleterContext } from '../completer/index.js';
5
+ import type { McdocAttributeValidator } from './validator.js';
6
+ export * as validator from './validator.js';
7
+ export interface McdocAttribute<C = unknown> {
8
+ checkInferred?: <T>(config: C, inferred: SimplifiedMcdocTypeNoUnion, ctx: McdocCheckerContext<T>) => boolean;
9
+ mapType?: <T>(config: C, typeDef: SimplifiedMcdocType, ctx: McdocCheckerContext<T>) => SimplifiedMcdocType;
10
+ mapField?: <T>(config: C, field: StructTypePairField, ctx: McdocCheckerContext<T>) => StructTypePairField;
11
+ filterElement?: (config: C, ctx: core.ContextBase) => boolean;
12
+ stringParser?: <T>(config: C, typeDef: SimplifiedMcdocTypeNoUnion, ctx: McdocCheckerContext<T>) => core.InfallibleParser<core.AstNode | undefined> | undefined;
13
+ stringMocker?: (config: C, typeDef: core.DeepReadonly<SimplifiedMcdocTypeNoUnion>, ctx: McdocCompleterContext) => core.AstNode | undefined;
14
+ }
15
+ export declare function registerAttribute<C extends core.Returnable>(meta: core.MetaRegistry, name: string, validator: McdocAttributeValidator<C>, attribute: McdocAttribute<C>): void;
16
+ interface AttributeInfo {
17
+ validator: McdocAttributeValidator<core.Returnable>;
18
+ attribute: McdocAttribute;
19
+ }
20
+ export declare function getAttribute(meta: core.MetaRegistry, name: string): AttributeInfo | undefined;
21
+ export declare function handleAttributes(attributes: core.DeepReadonly<Attribute[]> | undefined, ctx: core.ContextBase, fn: <C>(handler: McdocAttribute<C>, config: C) => void): void;
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,22 @@
1
+ import * as core from '@spyglassmc/core';
2
+ export * as validator from './validator.js';
3
+ export function registerAttribute(meta, name, validator, attribute) {
4
+ meta.registerCustom('mcdoc:attribute', name, { validator, attribute });
5
+ }
6
+ export function getAttribute(meta, name) {
7
+ return meta.getCustom('mcdoc:attribute')?.get(name);
8
+ }
9
+ export function handleAttributes(attributes, ctx, fn) {
10
+ for (const { name, value } of attributes ?? []) {
11
+ const handler = getAttribute(ctx.meta, name);
12
+ if (!handler) {
13
+ continue;
14
+ }
15
+ const config = handler.validator(value, ctx);
16
+ if (config === core.Failure) {
17
+ continue;
18
+ }
19
+ fn(handler.attribute, config);
20
+ }
21
+ }
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,16 @@
1
+ import * as core from '@spyglassmc/core';
2
+ import type { AttributeValue } from '../../type/index.js';
3
+ export type McdocAttributeValidator<C extends core.Returnable> = (value: core.DeepReadonly<AttributeValue> | undefined, ctx: core.ContextBase) => core.Result<C>;
4
+ export declare const string: McdocAttributeValidator<string>;
5
+ export declare const number: McdocAttributeValidator<number>;
6
+ export declare const boolean: McdocAttributeValidator<boolean>;
7
+ export declare function options<C extends string>(...options: C[]): McdocAttributeValidator<C>;
8
+ export declare function tree<C extends {
9
+ [K in keyof C]: core.Returnable;
10
+ }>(properties: {
11
+ [K in keyof C]: McdocAttributeValidator<C[K]>;
12
+ }): McdocAttributeValidator<C>;
13
+ export declare function optional<C extends core.Returnable>(validator: McdocAttributeValidator<C>): McdocAttributeValidator<C | undefined>;
14
+ export declare function map<C extends core.Returnable, D extends core.Returnable>(validator: McdocAttributeValidator<C>, mapper: (value: C) => D | typeof core.Failure): McdocAttributeValidator<D>;
15
+ export declare function alternatives<C extends core.Returnable>(...validators: McdocAttributeValidator<C>[]): McdocAttributeValidator<C>;
16
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1,85 @@
1
+ import * as core from '@spyglassmc/core';
2
+ export const string = (value) => {
3
+ if (value === undefined) {
4
+ return core.Failure;
5
+ }
6
+ if (value.kind === 'literal' && value.value.kind === 'string') {
7
+ return value.value.value;
8
+ }
9
+ if (value.kind === 'reference' && value.path) {
10
+ return value.path.replace(/.*::/, '');
11
+ }
12
+ return core.Failure;
13
+ };
14
+ export const number = (value) => {
15
+ if (value === undefined) {
16
+ return core.Failure;
17
+ }
18
+ if (value.kind === 'literal' && typeof value.value.value === 'number') {
19
+ return value.value.value;
20
+ }
21
+ return core.Failure;
22
+ };
23
+ export const boolean = (value) => {
24
+ if (value === undefined) {
25
+ return core.Failure;
26
+ }
27
+ if (value.kind === 'literal' && value.value.kind === 'boolean') {
28
+ return value.value.value;
29
+ }
30
+ return core.Failure;
31
+ };
32
+ export function options(...options) {
33
+ return (value, ctx) => {
34
+ const stringValue = string(value, ctx);
35
+ if (stringValue === core.Failure) {
36
+ return core.Failure;
37
+ }
38
+ if (options.includes(stringValue)) {
39
+ return stringValue;
40
+ }
41
+ return core.Failure;
42
+ };
43
+ }
44
+ export function tree(properties) {
45
+ return (value, ctx) => {
46
+ if (value?.kind !== 'tree') {
47
+ return core.Failure;
48
+ }
49
+ const result = {};
50
+ for (const key in properties) {
51
+ const validator = properties[key];
52
+ const propValue = value.values[key];
53
+ const property = validator(propValue, ctx);
54
+ if (property === core.Failure) {
55
+ return core.Failure;
56
+ }
57
+ result[key] = property;
58
+ }
59
+ return result;
60
+ };
61
+ }
62
+ export function optional(validator) {
63
+ return (value, ctx) => {
64
+ const config = validator(value, ctx);
65
+ return config === core.Failure ? undefined : config;
66
+ };
67
+ }
68
+ export function map(validator, mapper) {
69
+ return (value, ctx) => {
70
+ const config = validator(value, ctx);
71
+ return config === core.Failure ? core.Failure : mapper(config);
72
+ };
73
+ }
74
+ export function alternatives(...validators) {
75
+ return (value, ctx) => {
76
+ for (const validator of validators) {
77
+ const result = validator(value, ctx);
78
+ if (result !== core.Failure) {
79
+ return result;
80
+ }
81
+ }
82
+ return core.Failure;
83
+ };
84
+ }
85
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1,34 @@
1
+ import type * as core from '@spyglassmc/core';
2
+ import type { Attribute, EnumType, LiteralType, McdocType, UnionType } from '../../type/index.js';
3
+ import type { McdocRuntimeError } from './error.js';
4
+ import type { SimplifiedMcdocType, SimplifiedMcdocTypeNoUnion } from './index.js';
5
+ export type RuntimeUnion<T> = RuntimeNode<T>[] | RuntimePair<T>;
6
+ export interface RuntimeNode<T> {
7
+ originalNode: T;
8
+ inferredType: Exclude<McdocType, UnionType>;
9
+ }
10
+ export interface RuntimePair<T> {
11
+ attributes?: Attribute[];
12
+ key: RuntimeNode<T>;
13
+ possibleValues: RuntimeNode<T>[];
14
+ }
15
+ export type NodeEquivalenceChecker = (inferredNode: Exclude<SimplifiedMcdocTypeNoUnion, LiteralType | EnumType>, definition: Exclude<SimplifiedMcdocTypeNoUnion, LiteralType | EnumType>) => boolean;
16
+ export type TypeInfoAttacher<T> = (node: T, definition: SimplifiedMcdocType, description?: string) => void;
17
+ export type StringAttacher<T> = (node: T, attacher: (node: core.StringBaseNode) => void) => void;
18
+ export type ChildrenGetter<T> = (node: T, simplified: SimplifiedMcdocTypeNoUnion) => RuntimeUnion<T>[];
19
+ export type ErrorReporter<T> = (error: McdocRuntimeError<T>) => void;
20
+ export interface McdocCheckerContext<T> extends core.CheckerContext {
21
+ allowMissingKeys: boolean;
22
+ requireCanonical: boolean;
23
+ isEquivalent: NodeEquivalenceChecker;
24
+ getChildren: ChildrenGetter<T>;
25
+ reportError: ErrorReporter<T>;
26
+ attachTypeInfo?: TypeInfoAttacher<T>;
27
+ stringAttacher?: StringAttacher<T>;
28
+ }
29
+ type McdocCheckerContextOptions<T> = Partial<McdocCheckerContext<T>>;
30
+ export declare namespace McdocCheckerContext {
31
+ function create<T>(ctx: core.CheckerContext, options: McdocCheckerContextOptions<T>): McdocCheckerContext<T>;
32
+ }
33
+ export {};
34
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1,17 @@
1
+ export var McdocCheckerContext;
2
+ (function (McdocCheckerContext) {
3
+ function create(ctx, options) {
4
+ return {
5
+ ...ctx,
6
+ allowMissingKeys: options.allowMissingKeys ?? false,
7
+ requireCanonical: options.requireCanonical ?? false,
8
+ isEquivalent: options.isEquivalent ?? (() => false),
9
+ getChildren: options.getChildren ?? (() => []),
10
+ reportError: options.reportError ?? (() => { }),
11
+ attachTypeInfo: options.attachTypeInfo,
12
+ stringAttacher: options.stringAttacher,
13
+ };
14
+ }
15
+ McdocCheckerContext.create = create;
16
+ })(McdocCheckerContext || (McdocCheckerContext = {}));
17
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1,70 @@
1
+ import type { AstNode, CheckerContext, Range } from '@spyglassmc/core';
2
+ import { NumericRange } from '../../type/index.js';
3
+ import type { CheckerTreeDefinitionGroupNode, CheckerTreeDefinitionNode, ErrorReporter, RuntimeNode, SimplifiedMcdocTypeNoUnion } from './index.js';
4
+ export type McdocRuntimeError<T> = SimpleError<T> | UnknownKeyError<T> | RangeError<T> | TypeMismatchError<T> | MissingKeyError<T>;
5
+ export interface McdocRuntimeBaseError<T> {
6
+ node: RuntimeNode<T>;
7
+ /**
8
+ * This is set when this error may not need to be fixed if another error of the same kind is
9
+ * fixed instead. This contains a list of nodes with conflicting
10
+ */
11
+ nodesWithConflictingErrors?: RuntimeNode<T>[];
12
+ }
13
+ export interface SimpleError<T> extends McdocRuntimeBaseError<T> {
14
+ kind: 'duplicate_key' | 'unknown_key' | 'expected_key_value_pair' | 'unknown_tuple_element' | 'internal';
15
+ }
16
+ export declare namespace SimpleError {
17
+ function is<T>(error: McdocRuntimeError<T> | undefined): error is SimpleError<T>;
18
+ }
19
+ export interface UnknownKeyError<T> extends McdocRuntimeBaseError<T> {
20
+ kind: 'unknown_key';
21
+ }
22
+ export declare namespace UnknownKeyError {
23
+ function is<T>(error: McdocRuntimeError<T> | undefined): error is UnknownKeyError<T>;
24
+ }
25
+ export interface RangeError<T> extends McdocRuntimeBaseError<T> {
26
+ kind: 'invalid_collection_length' | 'invalid_string_length' | 'number_out_of_range';
27
+ /**
28
+ * A list of multiple mean the number (or length) has to be within one of these ranges. This is
29
+ * a result of merging errors from two conflicting definitions for the same value.
30
+ */
31
+ ranges: NumericRange[];
32
+ }
33
+ export declare namespace RangeError {
34
+ function is<T>(error: McdocRuntimeError<T> | undefined): error is RangeError<T>;
35
+ }
36
+ export interface MissingKeyError<T> extends McdocRuntimeBaseError<T> {
37
+ kind: 'missing_key';
38
+ /**
39
+ * A list of multiple are an alternative, and at least on e needs to be fixed, not neccessarily
40
+ * all of them.
41
+ *
42
+ * In case there are multiple non-conflicting missing keys, multiple errors will be reported on
43
+ * the same node instead.
44
+ *
45
+ * If this has a length > 1, there is at least one error that needs to be fixed, and at least one
46
+ * error that does not neccassarily need to be fixed.
47
+ */
48
+ keys: string[];
49
+ }
50
+ export declare namespace MissingKeyError {
51
+ function is<T>(error: McdocRuntimeError<T> | undefined): error is MissingKeyError<T>;
52
+ }
53
+ export interface TypeMismatchError<T> extends McdocRuntimeBaseError<T> {
54
+ kind: 'type_mismatch';
55
+ /**
56
+ * These are all valid definitions. The node needs to only fullfill one of them.
57
+ */
58
+ expected: SimplifiedMcdocTypeNoUnion[];
59
+ }
60
+ export declare namespace TypeMismatchError {
61
+ function is<T>(error: McdocRuntimeError<T> | undefined): error is TypeMismatchError<T>;
62
+ }
63
+ export interface ErrorCondensingDefinition<T> {
64
+ definition: CheckerTreeDefinitionNode<T>;
65
+ errors: McdocRuntimeError<T>[];
66
+ }
67
+ export declare function condenseAndPropagate<T>(definitionGroup: CheckerTreeDefinitionGroupNode<T>, definitionErrors: ErrorCondensingDefinition<T>[]): void;
68
+ export declare function getDefaultErrorRange<T extends AstNode>(node: RuntimeNode<T>, error: McdocRuntimeError<T>['kind']): Range;
69
+ export declare function getDefaultErrorReporter<T>(ctx: CheckerContext, getErrorRange: (node: RuntimeNode<T>, error: McdocRuntimeError<T>['kind']) => Range): ErrorReporter<T>;
70
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1,352 @@
1
+ import { ResourceLocation } from '@spyglassmc/core';
2
+ import { arrayToMessage, localeQuote, localize } from '@spyglassmc/locales';
3
+ import { RangeKind } from '../../node/index.js';
4
+ import { McdocType, NumericRange } from '../../type/index.js';
5
+ export var SimpleError;
6
+ (function (SimpleError) {
7
+ function is(error) {
8
+ return error?.kind === 'duplicate_key'
9
+ || error?.kind === 'unknown_key'
10
+ || error?.kind === 'expected_key_value_pair'
11
+ || error?.kind === 'unknown_tuple_element'
12
+ || error?.kind === 'internal';
13
+ }
14
+ SimpleError.is = is;
15
+ })(SimpleError || (SimpleError = {}));
16
+ export var UnknownKeyError;
17
+ (function (UnknownKeyError) {
18
+ function is(error) {
19
+ return error?.kind === 'unknown_key';
20
+ }
21
+ UnknownKeyError.is = is;
22
+ })(UnknownKeyError || (UnknownKeyError = {}));
23
+ export var RangeError;
24
+ (function (RangeError) {
25
+ function is(error) {
26
+ return error?.kind === 'invalid_collection_length'
27
+ || error?.kind === 'invalid_string_length'
28
+ || error?.kind === 'number_out_of_range';
29
+ }
30
+ RangeError.is = is;
31
+ })(RangeError || (RangeError = {}));
32
+ export var MissingKeyError;
33
+ (function (MissingKeyError) {
34
+ function is(error) {
35
+ return error?.kind === 'missing_key';
36
+ }
37
+ MissingKeyError.is = is;
38
+ })(MissingKeyError || (MissingKeyError = {}));
39
+ export var TypeMismatchError;
40
+ (function (TypeMismatchError) {
41
+ function is(error) {
42
+ return error?.kind === 'type_mismatch';
43
+ }
44
+ TypeMismatchError.is = is;
45
+ })(TypeMismatchError || (TypeMismatchError = {}));
46
+ export function condenseAndPropagate(definitionGroup, definitionErrors) {
47
+ const queue = [{ node: definitionGroup, errorsOnLayer: definitionErrors, depth: 0 }];
48
+ while (queue.length) {
49
+ const { node, errorsOnLayer, depth } = queue.shift();
50
+ const stillValidDefinitions = [];
51
+ const { definitions, condensedErrors } = condenseErrorsAndFilterSiblings(errorsOnLayer);
52
+ stillValidDefinitions.push(...definitions);
53
+ node.condensedErrors.push(condensedErrors);
54
+ if (node.validDefinitions.length !== stillValidDefinitions.length) {
55
+ filterChildDefinitions(node.validDefinitions.filter(d => !stillValidDefinitions.includes(d)), node.runtimeNode.children);
56
+ node.validDefinitions = stillValidDefinitions;
57
+ }
58
+ const parents = node.parents
59
+ .filter(parent => {
60
+ const lastDefWithNode = parent.groupNode.validDefinitions
61
+ .findLast(d => d.children.includes(node));
62
+ if (lastDefWithNode !== parent) {
63
+ // Wait for last definition that leads to this parent
64
+ return false;
65
+ }
66
+ const lastChild = parent.groupNode.validDefinitions
67
+ .flatMap(d => d.children)
68
+ .findLast(v => {
69
+ if (v.condensedErrors.length > depth) {
70
+ return true;
71
+ }
72
+ let children = [v];
73
+ for (let i = 0; i < depth; i++) {
74
+ children = children.flatMap(v => v.validDefinitions).flatMap(v => v.children);
75
+ }
76
+ return children.length > 0;
77
+ });
78
+ if (lastChild !== node) {
79
+ // Wait for all siblings to be evaluated first
80
+ return false;
81
+ }
82
+ return true;
83
+ })
84
+ .map(parent => ({
85
+ node: parent.groupNode,
86
+ depth: depth + 1,
87
+ errorsOnLayer: parent.groupNode.validDefinitions
88
+ .flatMap(d => ({
89
+ definition: d,
90
+ errors: d.children
91
+ .flatMap(c => c.condensedErrors.length > depth
92
+ ? c.condensedErrors[depth]
93
+ : []),
94
+ })),
95
+ }));
96
+ queue.push(...parents);
97
+ }
98
+ }
99
+ function filterChildDefinitions(removedDefs, children) {
100
+ for (const child of children) {
101
+ for (const childValue of child.possibleValues) {
102
+ const removedChildDefs = [];
103
+ for (let i = 0; i < childValue.definitionsByParent.length; i++) {
104
+ const definitionGroup = childValue.definitionsByParent[i];
105
+ definitionGroup.parents = definitionGroup.parents.filter(p => !removedDefs.includes(p));
106
+ if (definitionGroup.parents.length === 0) {
107
+ removedChildDefs.push(...definitionGroup.validDefinitions);
108
+ childValue.definitionsByParent.splice(i, 1);
109
+ i--;
110
+ }
111
+ }
112
+ if (removedChildDefs.length > 0) {
113
+ filterChildDefinitions(removedChildDefs, childValue.children);
114
+ }
115
+ }
116
+ }
117
+ }
118
+ function condenseErrorsAndFilterSiblings(definitions) {
119
+ if (definitions.length === 0) {
120
+ return { definitions: [], condensedErrors: [] };
121
+ }
122
+ let validDefinitions = definitions;
123
+ const errors = [];
124
+ const typeMismatchResult = condense(validDefinitions, TypeMismatchError.is, (a, b) => a.expected.length === b.expected.length
125
+ && !a.expected.some(d => !b.expected.some(od => McdocType.equals(d, od))), errors => ({
126
+ kind: 'type_mismatch',
127
+ node: errors[0].node,
128
+ expected: deduplicateGroups(errors.map(e => e.expected), McdocType.equals),
129
+ }));
130
+ validDefinitions = typeMismatchResult.filteredDefinitions;
131
+ errors.push(...typeMismatchResult.condensedErrors);
132
+ for (const kind of [
133
+ 'unknown_key',
134
+ 'expected_key_value_pair',
135
+ 'unknown_tuple_element',
136
+ ]) {
137
+ const simpleErrorResult = condense(validDefinitions, (e) => e.kind === kind, _ => true);
138
+ validDefinitions = simpleErrorResult.filteredDefinitions;
139
+ errors.push(...simpleErrorResult.condensedErrors);
140
+ }
141
+ const missingKeyResult = condense(validDefinitions, MissingKeyError.is, (a, b) => !a.keys.some(k => !b.keys.includes(k)), errors => ({
142
+ kind: 'missing_key',
143
+ node: errors[0].node,
144
+ keys: deduplicateGroups(errors.map(e => e.keys)),
145
+ }));
146
+ validDefinitions = missingKeyResult.filteredDefinitions;
147
+ errors.push(...missingKeyResult.condensedErrors);
148
+ for (const kind of [
149
+ 'invalid_collection_length',
150
+ 'invalid_string_length',
151
+ 'number_out_of_range',
152
+ ]) {
153
+ const rangeErrorResult = condense(validDefinitions, (e) => e.kind === kind, (a, b) => a.ranges.length === b.ranges.length
154
+ && !a.ranges.some(r => !b.ranges.some(or => NumericRange.equals(r, or))),
155
+ // TODO merge overlapping ranges better?
156
+ errors => ({
157
+ kind,
158
+ node: errors[0].node,
159
+ ranges: deduplicateGroups(errors.map(e => e.ranges), NumericRange.equals),
160
+ }));
161
+ validDefinitions = rangeErrorResult.filteredDefinitions;
162
+ errors.push(...rangeErrorResult.condensedErrors);
163
+ }
164
+ // No condensing needed for duplicate key. If a key is a duplicate in one definition, it really
165
+ // should have been reported by all of them
166
+ validDefinitions[0].errors.filter(e => e.kind === 'duplicate_key');
167
+ const internalErrorResult = condense(validDefinitions, (e) => e.kind === 'internal', _ => false);
168
+ validDefinitions = internalErrorResult.filteredDefinitions;
169
+ errors.push(...internalErrorResult.condensedErrors);
170
+ return {
171
+ definitions: validDefinitions.map(d => d.definition),
172
+ condensedErrors: errors,
173
+ };
174
+ }
175
+ function condense(validDefinitions, is, equals, combineAlternatives) {
176
+ // TODO a lot of O(n^2) in this function, may need optimization
177
+ const errorsOfType = validDefinitions
178
+ .map(def => ({ def, errors: def.errors.filter(is) }));
179
+ const definitionsWithoutError = errorsOfType
180
+ .filter(d => d.errors.length === 0)
181
+ .map(e => e.def);
182
+ if (definitionsWithoutError.length > 0) {
183
+ return { condensedErrors: [], filteredDefinitions: definitionsWithoutError };
184
+ }
185
+ const distinctErrorsPerNode = errorsOfType
186
+ .flatMap(d => d.errors.map(e => ({ definition: d.def, error: e })))
187
+ .reduce((entries, e) => {
188
+ const entry = entries.find(oe => oe.errors[0].error.node === e.error.node);
189
+ if (entry) {
190
+ const error = entry.errors.find(oe => equals(e.error, oe.error));
191
+ if (error) {
192
+ error.definitions.push(e.definition);
193
+ }
194
+ else {
195
+ entry.errors.push({ error: e.error, definitions: [e.definition] });
196
+ }
197
+ }
198
+ else {
199
+ entries.push({ errors: [{ error: e.error, definitions: [e.definition] }] });
200
+ }
201
+ return entries;
202
+ }, []);
203
+ const distinctErrors = distinctErrorsPerNode.flatMap(e => e.errors);
204
+ const commonErrors = distinctErrors
205
+ .filter(e => e.definitions.length == validDefinitions.length)
206
+ .map(e => e.error);
207
+ const definitionsWithUncommonErrors = distinctErrors
208
+ .filter(e => e.definitions.length < validDefinitions.length)
209
+ .flatMap(e => e.definitions);
210
+ const definitionsWithOnlyCommonErrors = validDefinitions
211
+ .filter(d => !definitionsWithUncommonErrors.includes(d));
212
+ if (definitionsWithOnlyCommonErrors.length > 0) {
213
+ return {
214
+ filteredDefinitions: definitionsWithOnlyCommonErrors,
215
+ condensedErrors: commonErrors,
216
+ };
217
+ }
218
+ const combinedErrors = combineAlternatives
219
+ ? distinctErrorsPerNode
220
+ .map(e => {
221
+ const uniqueDefinitions = deduplicateGroups(e.errors.map(e => e.definitions), (a, b) => McdocType.equals(a.definition.typeDef, b.definition.typeDef));
222
+ const ans = {
223
+ definitions: uniqueDefinitions,
224
+ error: combineAlternatives(e.errors
225
+ .filter(e => !commonErrors.includes(e.error))
226
+ .map(e => e.error)),
227
+ };
228
+ ans.error.nodesWithConflictingErrors = deduplicateGroups(e.errors.map(e => e.error.nodesWithConflictingErrors ?? []));
229
+ if (ans.error.nodesWithConflictingErrors.length === 0) {
230
+ ans.error.nodesWithConflictingErrors = undefined;
231
+ }
232
+ return ans;
233
+ })
234
+ : distinctErrorsPerNode.flatMap(e => e.errors
235
+ .map(ee => ({ definitions: ee.definitions, error: ee.error })));
236
+ const conflictingErrors = combinedErrors
237
+ .filter(e => e.definitions.length < validDefinitions.length);
238
+ const nodesWithConflictingErrors = conflictingErrors
239
+ .map(e => e.error.node)
240
+ .filter((n, i, arr) => arr.indexOf(n) === i);
241
+ for (const error of conflictingErrors) {
242
+ error.error.nodesWithConflictingErrors = nodesWithConflictingErrors;
243
+ }
244
+ return {
245
+ filteredDefinitions: validDefinitions,
246
+ condensedErrors: [...commonErrors, ...combinedErrors.map(e => e.error)],
247
+ };
248
+ }
249
+ /**
250
+ * Deduplicates groups assuming:
251
+ * - There are no duplicates within a group
252
+ * - A group with 1 element implies there is no duplicated group of length 1 with the same element
253
+ *
254
+ * When calling {@link condense}, if a group stems from an error, this should automatically be the
255
+ * case.
256
+ */
257
+ function deduplicateGroups(definitionGroups, predicate) {
258
+ const definitions = [];
259
+ for (let i = 0; i < definitionGroups.length; i++) {
260
+ const group = definitionGroups[i];
261
+ if (group.length === 1) {
262
+ definitions.push(group[0]);
263
+ continue;
264
+ }
265
+ definitions.push(...group
266
+ .filter(v => !definitionGroups.some((og, oi) => (oi > i || og.length === 1)
267
+ && predicate
268
+ ? og.some(ov => predicate(v, ov))
269
+ : og.includes(v))));
270
+ }
271
+ return definitions;
272
+ }
273
+ export function getDefaultErrorRange(node, error) {
274
+ const { range } = node.originalNode;
275
+ if (error === 'missing_key' || error === 'invalid_collection_length') {
276
+ return { start: range.start, end: range.start + 1 };
277
+ }
278
+ return range;
279
+ }
280
+ export function getDefaultErrorReporter(ctx, getErrorRange) {
281
+ return (error) => {
282
+ const defaultTranslationKey = error.kind.replaceAll('_', '-');
283
+ let localizedText;
284
+ let severity = 3 /* ErrorSeverity.Error */;
285
+ switch (error.kind) {
286
+ case 'unknown_tuple_element':
287
+ localizedText = localize('expected', localize('nothing'));
288
+ break;
289
+ case 'unknown_key':
290
+ if (error.nodesWithConflictingErrors) {
291
+ localizedText = localize('invalid-key-combination', arrayToMessage(error.nodesWithConflictingErrors.map(n => McdocType.toString(n.inferredType)), true, 'and'));
292
+ }
293
+ else {
294
+ localizedText = localize(defaultTranslationKey, error.node.inferredType.kind === 'literal'
295
+ ? localeQuote(error.node.inferredType.value.value.toString())
296
+ : `<${localize(`mcdoc.type.${error.node.inferredType.kind}`)}>`);
297
+ severity = 2 /* ErrorSeverity.Warning */;
298
+ }
299
+ break;
300
+ case 'missing_key':
301
+ if (error.keys.length === 1) {
302
+ localizedText = localize(defaultTranslationKey, localeQuote(error.keys[0]));
303
+ }
304
+ else {
305
+ localizedText = localize('mcdoc.runtime.checker.some-missing-keys', arrayToMessage(error.keys));
306
+ }
307
+ break;
308
+ case 'invalid_collection_length':
309
+ case 'invalid_string_length':
310
+ case 'number_out_of_range':
311
+ const baseKey = error.kind === 'invalid_collection_length'
312
+ ? 'mcdoc.runtime.checker.range.collection'
313
+ : error.kind === 'invalid_string_length'
314
+ ? 'mcdoc.runtime.checker.range.string'
315
+ : 'mcdoc.runtime.checker.range.number';
316
+ const rangeMessages = error.ranges.map(r => {
317
+ const left = r.min !== undefined
318
+ ? localize(RangeKind.isLeftExclusive(r.kind)
319
+ ? 'mcdoc.runtime.checker.range.left-exclusive'
320
+ : 'mcdoc.runtime.checker.range.left-inclusive', r.min)
321
+ : undefined;
322
+ const right = r.max !== undefined
323
+ ? localize(RangeKind.isLeftExclusive(r.kind)
324
+ ? 'mcdoc.runtime.checker.range.right-exclusive'
325
+ : 'mcdoc.runtime.checker.range.right-inclusive', r.max)
326
+ : undefined;
327
+ if (left !== undefined && right !== undefined) {
328
+ return localize('mcdoc.runtime.checker.range.concat', left, right);
329
+ }
330
+ return left ?? right;
331
+ }).filter(r => r !== undefined);
332
+ localizedText = localize('expected', localize(baseKey, arrayToMessage(rangeMessages, false)));
333
+ break;
334
+ case 'type_mismatch':
335
+ localizedText = localize('expected', arrayToMessage(error.expected.map(e => e.kind === 'enum'
336
+ ? arrayToMessage(e.values.map(v => ResourceLocation.shorten(v.value.toString())))
337
+ : e.kind === 'literal'
338
+ ? localeQuote(e.value.value.toString())
339
+ : localize(`mcdoc.type.${e.kind}`)), false));
340
+ break;
341
+ case 'expected_key_value_pair':
342
+ localizedText = localize(`mcdoc.runtime.checker.${defaultTranslationKey}`);
343
+ break;
344
+ case 'internal':
345
+ break;
346
+ default:
347
+ localizedText = localize(defaultTranslationKey);
348
+ }
349
+ ctx.err.report(localizedText, getErrorRange(error.node, error.kind), severity);
350
+ };
351
+ }
352
+ //# sourceMappingURL=error.js.map