Skip to content

Commit aff032a

Browse files
committed
start of better error messages
1 parent f9023ae commit aff032a

File tree

14 files changed

+162
-68
lines changed

14 files changed

+162
-68
lines changed

exampleVault/Buttons/Button Example.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,17 @@ actions:
275275
276276
```
277277

278+
```meta-bind-button
279+
label: Test
280+
hidden: false
281+
id: ""
282+
style: default
283+
actions:
284+
- type: aaaa
285+
- type: command
286+
command: obsidian-meta-bind-plugin:open-help
287+
288+
```
278289

279290
```meta-bind-button
280291
label: Test
@@ -286,3 +297,4 @@ actions:
286297
command: obsidian-meta-bind-plugin:open-help
287298
288299
```
300+

packages/core/src/api/API.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import {
4646
V_TableFieldOptions,
4747
V_ViewFieldOptions,
4848
} from 'packages/core/src/api/Validators';
49-
import { validate } from 'packages/core/src/utils/ZodUtils';
49+
import { validateAPIArgs } from 'packages/core/src/utils/ZodUtils';
5050
import { z } from 'zod';
5151
import { TableMountable } from 'packages/core/src/fields/metaBindTable/TableMountable';
5252
import {
@@ -131,7 +131,7 @@ export abstract class API<Plugin extends IPlugin> {
131131
options: FieldOptionMap[Type],
132132
honorExcludedSetting: boolean = true,
133133
): FieldMountable {
134-
validate(
134+
validateAPIArgs(
135135
z.object({
136136
type: V_FieldType,
137137
filePath: V_FilePath,
@@ -193,7 +193,7 @@ export abstract class API<Plugin extends IPlugin> {
193193
position?: NotePosition | undefined,
194194
honorExcludedSetting: boolean = true,
195195
): FieldMountable {
196-
validate(
196+
validateAPIArgs(
197197
z.object({
198198
fieldString: z.string(),
199199
filePath: V_FilePath,
@@ -251,7 +251,7 @@ export abstract class API<Plugin extends IPlugin> {
251251
position?: NotePosition | undefined,
252252
honorExcludedSetting: boolean = true,
253253
): FieldMountable {
254-
validate(
254+
validateAPIArgs(
255255
z.object({
256256
type: V_FieldType,
257257
declaration: z.string(),
@@ -314,7 +314,7 @@ export abstract class API<Plugin extends IPlugin> {
314314
* @param options
315315
*/
316316
public createInputFieldMountable(filePath: string, options: InputFieldOptions): InputFieldMountable {
317-
validate(
317+
validateAPIArgs(
318318
z.object({
319319
filePath: V_FilePath,
320320
options: V_InputFieldOptions,
@@ -348,7 +348,7 @@ export abstract class API<Plugin extends IPlugin> {
348348
* @param options
349349
*/
350350
public createViewFieldMountable(filePath: string, options: ViewFieldOptions): ViewFieldMountable {
351-
validate(
351+
validateAPIArgs(
352352
z.object({
353353
filePath: V_FilePath,
354354
options: V_ViewFieldOptions,
@@ -382,7 +382,7 @@ export abstract class API<Plugin extends IPlugin> {
382382
* @param options
383383
*/
384384
public createJsViewFieldMountable(filePath: string, options: JsViewFieldOptions): JsViewFieldMountable {
385-
validate(
385+
validateAPIArgs(
386386
z.object({
387387
filePath: V_FilePath,
388388
options: V_JsViewFieldOptions,
@@ -412,7 +412,7 @@ export abstract class API<Plugin extends IPlugin> {
412412
* @param options
413413
*/
414414
public createTableMountable(filePath: string, options: TableOptions): TableMountable {
415-
validate(
415+
validateAPIArgs(
416416
z.object({
417417
filePath: V_FilePath,
418418
options: V_TableFieldOptions,
@@ -435,7 +435,7 @@ export abstract class API<Plugin extends IPlugin> {
435435
* @param options
436436
*/
437437
public createButtonGroupMountable(filePath: string, options: ButtonGroupOptions): ButtonGroupMountable {
438-
validate(
438+
validateAPIArgs(
439439
z.object({
440440
filePath: V_FilePath,
441441
options: V_InlineButtonOptions,
@@ -472,7 +472,7 @@ export abstract class API<Plugin extends IPlugin> {
472472
* @param options
473473
*/
474474
public createButtonMountable(filePath: string, options: ButtonOptions): ButtonMountable {
475-
validate(
475+
validateAPIArgs(
476476
z.object({
477477
filePath: V_FilePath,
478478
options: V_ButtonOptions,
@@ -502,7 +502,7 @@ export abstract class API<Plugin extends IPlugin> {
502502
* @param options
503503
*/
504504
public createEmbedMountable(filePath: string, options: EmbedOptions): EmbedMountable {
505-
validate(
505+
validateAPIArgs(
506506
z.object({
507507
filePath: V_FilePath,
508508
options: V_EmbedOptions,
@@ -523,7 +523,7 @@ export abstract class API<Plugin extends IPlugin> {
523523
* @param filePath the file path that the field is located in or an empty string
524524
*/
525525
public createExcludedMountable(filePath: string): ExcludedMountable {
526-
validate(
526+
validateAPIArgs(
527527
z.object({
528528
filePath: V_FilePath,
529529
}),
@@ -542,7 +542,7 @@ export abstract class API<Plugin extends IPlugin> {
542542
* @param fieldType
543543
*/
544544
public getInlineFieldDeclarationPrefix(fieldType: FieldType): string {
545-
validate(
545+
validateAPIArgs(
546546
z.object({
547547
fieldType: V_FieldType,
548548
}),
@@ -573,7 +573,7 @@ export abstract class API<Plugin extends IPlugin> {
573573
* @param str the declaration string
574574
*/
575575
public isInlineFieldDeclaration(fieldType: FieldType, str: string): boolean {
576-
validate(
576+
validateAPIArgs(
577577
z.object({
578578
fieldType: V_FieldType,
579579
str: z.string(),
@@ -596,7 +596,7 @@ export abstract class API<Plugin extends IPlugin> {
596596
* @param str the declaration string
597597
*/
598598
public isInlineFieldDeclarationAndGetType(str: string): InlineFieldType | undefined {
599-
validate(
599+
validateAPIArgs(
600600
z.object({
601601
str: z.string(),
602602
}),
@@ -645,7 +645,7 @@ export abstract class API<Plugin extends IPlugin> {
645645
property: string[],
646646
listenToChildren: boolean = false,
647647
): BindTargetDeclaration {
648-
validate(
648+
validateAPIArgs(
649649
z.object({
650650
storageType: z.string(),
651651
storagePath: z.string(),
@@ -680,7 +680,7 @@ export abstract class API<Plugin extends IPlugin> {
680680
filePath: string,
681681
scope?: BindTargetScope,
682682
): BindTargetDeclaration {
683-
validate(
683+
validateAPIArgs(
684684
z.object({
685685
declarationString: z.string(),
686686
filePath: V_FilePath,
@@ -703,7 +703,7 @@ export abstract class API<Plugin extends IPlugin> {
703703
* @param value
704704
*/
705705
public setMetadata(bindTarget: BindTargetDeclaration, value: unknown): void {
706-
validate(
706+
validateAPIArgs(
707707
z.object({
708708
bindTarget: V_BindTargetDeclaration,
709709
}),
@@ -722,7 +722,7 @@ export abstract class API<Plugin extends IPlugin> {
722722
* @param bindTarget
723723
*/
724724
public getMetadata(bindTarget: BindTargetDeclaration): unknown {
725-
validate(
725+
validateAPIArgs(
726726
z.object({
727727
bindTarget: V_BindTargetDeclaration,
728728
}),
@@ -741,7 +741,7 @@ export abstract class API<Plugin extends IPlugin> {
741741
* @param updateFn a function that takes the current value and returns the new value
742742
*/
743743
public updateMetadata(bindTarget: BindTargetDeclaration, updateFn: (value: unknown) => unknown): void {
744-
validate(
744+
validateAPIArgs(
745745
z.object({
746746
bindTarget: V_BindTargetDeclaration,
747747
updateFn: z.function().args(z.any()).returns(z.any()),
@@ -771,7 +771,7 @@ export abstract class API<Plugin extends IPlugin> {
771771
lifecycleHook: LifecycleHook,
772772
callback: (value: unknown) => void,
773773
): void {
774-
validate(
774+
validateAPIArgs(
775775
z.object({
776776
bindTarget: V_BindTargetDeclaration,
777777
lifecycleHook: this.plugin.internal.getLifecycleHookValidator(),
@@ -807,7 +807,7 @@ export abstract class API<Plugin extends IPlugin> {
807807
* @param lineEnd
808808
*/
809809
public createNotePosition(lineStart: number, lineEnd: number): NotePosition {
810-
validate(
810+
validateAPIArgs(
811811
z.object({
812812
lineStart: z.number(),
813813
lineEnd: z.number(),

packages/core/src/api/SyntaxHighlightingAPI.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import { type Highlight } from 'packages/core/src/parsers/syntaxHighlighting/Highlight';
1212
import { SyntaxHighlighting } from 'packages/core/src/parsers/syntaxHighlighting/SyntaxHighlighting';
1313

14-
import { FieldType } from 'packages/core/src/config/APIConfigs';
14+
import { FieldType, type InlineFieldType } from 'packages/core/src/config/APIConfigs';
1515

1616
export class SyntaxHighlightingAPI {
1717
public readonly plugin: IPlugin;
@@ -32,16 +32,16 @@ export class SyntaxHighlightingAPI {
3232
return this.highlightWithParser(str, trimWhiteSpace, HLP_ButtonGroupDeclaration);
3333
}
3434

35-
highlight(str: string, mdrcType: FieldType, trimWhiteSpace: boolean): SyntaxHighlighting {
36-
if (mdrcType === FieldType.INPUT) {
35+
highlight(str: string, inlineFieldType: InlineFieldType, trimWhiteSpace: boolean): SyntaxHighlighting {
36+
if (inlineFieldType === FieldType.INPUT) {
3737
return this.highlightInputFieldDeclaration(str, trimWhiteSpace);
38-
} else if (mdrcType === FieldType.VIEW) {
38+
} else if (inlineFieldType === FieldType.VIEW) {
3939
return this.highlightViewFieldDeclaration(str, trimWhiteSpace);
40-
} else if (mdrcType === FieldType.BUTTON_GROUP) {
40+
} else if (inlineFieldType === FieldType.BUTTON_GROUP) {
4141
return this.highlightInlineButtonDeclaration(str, trimWhiteSpace);
4242
}
4343

44-
throw new Error(`Unknown MDRCType ${mdrcType}`);
44+
throw new Error(`Unknown MDRCType ${inlineFieldType}`);
4545
}
4646

4747
highlightBindTarget(str: string, trimWhiteSpace: boolean): SyntaxHighlighting {

packages/core/src/config/ButtonConfigValidators.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,43 +20,65 @@ import {
2020
import { oneOf, schemaForType } from 'packages/core/src/utils/ZodUtils';
2121
import { z } from 'zod';
2222

23+
function numberValidator(action: string, name: string, description: string) {
24+
return z.number({
25+
required_error: `The ${action} action requires a specified ${description} with the '${name}' field.`,
26+
invalid_type_error: `The ${action} action requires the value of the '${name}' fields to be a number.`,
27+
});
28+
}
29+
30+
function stringValidator(action: string, name: string, description: string) {
31+
return z.string({
32+
required_error: `The ${action} action requires a specified ${description} with the '${name}' field.`,
33+
invalid_type_error: `The ${action} action requires the value of the '${name}' fields to be a string.`,
34+
});
35+
}
36+
37+
function booleanValidator(action: string, name: string, description: string) {
38+
return z.boolean({
39+
required_error: `The ${action} action requires a specified ${description} with the '${name}' field.`,
40+
invalid_type_error: `The ${action} action requires the value of the '${name}' fields to be a boolean.`,
41+
});
42+
}
43+
2344
export const V_CommandButtonAction = schemaForType<CommandButtonAction>()(
2445
z.object({
2546
type: z.literal(ButtonActionType.COMMAND),
26-
command: z.string(),
47+
command: stringValidator('command', 'command', 'command to run'),
2748
}),
2849
);
2950

3051
export const V_JSButtonAction = schemaForType<JSButtonAction>()(
3152
z.object({
3253
type: z.literal(ButtonActionType.JS),
33-
file: z.string(),
54+
file: stringValidator('js', 'file', 'file path to the file to run'),
3455
args: z.record(z.unknown()).optional(),
3556
}),
3657
);
3758

3859
export const V_OpenButtonAction = schemaForType<OpenButtonAction>()(
3960
z.object({
4061
type: z.literal(ButtonActionType.OPEN),
41-
link: z.string(),
42-
newTab: z.boolean().optional(),
62+
link: stringValidator('open', 'link', 'link to open'),
63+
newTab: booleanValidator('open', 'newTab', '').optional(),
4364
}),
4465
);
4566

4667
export const V_InputButtonAction = schemaForType<InputButtonAction>()(
4768
z.object({
4869
type: z.literal(ButtonActionType.INPUT),
49-
str: z.string(),
70+
str: stringValidator('input', 'str', 'value to input'),
5071
}),
5172
);
5273

5374
export const V_SleepButtonAction = schemaForType<SleepButtonAction>()(
5475
z.object({
5576
type: z.literal(ButtonActionType.SLEEP),
56-
ms: z.number(),
77+
ms: numberValidator('sleep', 'ms', 'duration'),
5778
}),
5879
);
5980

81+
// TODO: more better error messages
6082
export const V_TemplaterCreateNoteButtonAction = schemaForType<TemplaterCreateNoteButtonAction>()(
6183
z.object({
6284
type: z.literal(ButtonActionType.TEMPLATER_CREATE_NOTE),
@@ -127,7 +149,7 @@ export const V_InlineJsButtonAction = schemaForType<InlineJsButtonAction>()(
127149
);
128150

129151
export const V_ButtonAction = schemaForType<ButtonAction>()(
130-
z.union([
152+
z.discriminatedUnion('type', [
131153
V_CommandButtonAction,
132154
V_JSButtonAction,
133155
V_OpenButtonAction,

packages/core/src/fields/button/ButtonActionRunner.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ export class ButtonActionRunner {
3838
if (resolvedFilePath === undefined) {
3939
throw new MetaBindParsingError({
4040
errorLevel: ErrorLevel.ERROR,
41-
cause: 'file not found',
42-
effect: `could not resolve path or link "${filePath}" relative to "${relativeFilePath}"`,
41+
cause: 'Could not find a file that matches "${filePath}".',
42+
effect: `Could not resolve path or link "${filePath}" relative to "${relativeFilePath}".`,
4343
});
4444
}
4545

packages/core/src/parsers/ButtonParser.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { V_ButtonConfig } from 'packages/core/src/config/ButtonConfigValidators'
88
import { ErrorLevel, MetaBindButtonError } from 'packages/core/src/utils/errors/MetaBindErrors';
99
import { DocsUtils } from 'packages/core/src/utils/DocsUtils';
1010
import { fromZodError } from 'zod-validation-error';
11+
import { validate } from 'packages/core/src/utils/ZodUtils';
1112

1213
const P_ButtonGroupDeclaration = P.sequenceMap(
1314
(_, b) => b,
@@ -81,19 +82,20 @@ export class ButtonParser {
8182
}
8283

8384
public validateConfig(config: unknown): ButtonConfig {
84-
const parsedConfig = V_ButtonConfig.safeParse(config);
85+
const parsedConfig = validate(V_ButtonConfig, config);
8586

8687
if (!parsedConfig.success) {
8788
const niceError = fromZodError(parsedConfig.error, {
8889
unionSeparator: '\nOR ',
8990
issueSeparator: ' AND ',
9091
prefix: null,
92+
includePath: false,
9193
});
9294

9395
throw new MetaBindButtonError({
9496
errorLevel: ErrorLevel.ERROR,
95-
effect: 'can not parse button config',
96-
cause: 'zod validation failed. Check your button syntax',
97+
effect: 'The validation for the button config failed.',
98+
cause: 'Your button syntax seems to be invalid. Check that your button config follows what is described in the docs.',
9799
positionContext: niceError.message,
98100
docs: [DocsUtils.linkToButtonConfig()],
99101
});

packages/core/src/parsers/ParsingError.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class ParsingError extends MetaBindError {
1919
constructor(errorLevel: ErrorLevel, source: string, str: string, parseFailure: ParseFailure) {
2020
super({
2121
errorLevel: errorLevel,
22-
effect: 'failed to parse',
22+
effect: 'Failed to parse. Check that your syntax is correct.',
2323
cause: `expected ${parseFailure.expected.sort().join(' or ')}`,
2424
});
2525

@@ -72,7 +72,12 @@ export class ParsingValidationError extends MetaBindError {
7272
position?: ParsingRange,
7373
docs?: string[],
7474
) {
75-
super({ errorLevel: errorLevel, effect: 'failed to validate parser result', cause: cause, docs: docs });
75+
super({
76+
errorLevel: errorLevel,
77+
effect: 'Failed to validate the result of the parser.',
78+
cause: cause,
79+
docs: docs,
80+
});
7681

7782
this.str = str;
7883
this.position = position;

0 commit comments

Comments
 (0)