Skip to content

Commit 6a06b49

Browse files
committed
templates for new parser
1 parent dc7c668 commit 6a06b49

File tree

10 files changed

+117
-52
lines changed

10 files changed

+117
-52
lines changed

exampleVault/examples.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Domestic_tasks:
77
Meditate: 100
88
Slept: 00:00
99
select: option c
10+
toggle: false
1011
---
1112

1213
## In callouts

src/api/API.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import { IAPI } from './IAPI';
1414
export class API implements IAPI {
1515
public plugin: MetaBindPlugin;
1616
// public inputFieldParser: InputFieldDeclarationParser;
17-
public newInputFieldParser: NewInputFieldDeclarationParser;
18-
public viewFieldParser: ViewFieldDeclarationParser;
19-
public bindTargetParser: BindTargetParser;
17+
public readonly newInputFieldParser: NewInputFieldDeclarationParser;
18+
public readonly viewFieldParser: ViewFieldDeclarationParser;
19+
public readonly bindTargetParser: BindTargetParser;
2020

2121
public readonly inputField: InputFieldAPI;
2222

src/api/IAPI.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import { NewInputFieldDeclarationParser } from '../parsers/newInputFieldParser/I
22
import { ViewFieldDeclarationParser } from '../parsers/ViewFieldDeclarationParser';
33
import { BindTargetParser } from '../parsers/BindTargetParser';
44
import { IPlugin } from '../IPlugin';
5+
import { InputFieldAPI } from './InputFieldAPI';
56

67
export interface IAPI {
7-
plugin: IPlugin;
8-
newInputFieldParser: NewInputFieldDeclarationParser;
9-
viewFieldParser: ViewFieldDeclarationParser;
10-
bindTargetParser: BindTargetParser;
8+
readonly plugin: IPlugin;
9+
readonly newInputFieldParser: NewInputFieldDeclarationParser;
10+
readonly viewFieldParser: ViewFieldDeclarationParser;
11+
readonly bindTargetParser: BindTargetParser;
12+
readonly inputField: InputFieldAPI;
1113
}

src/api/InputFieldAPI.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import { InputFieldArgumentType, InputFieldType } from '../parsers/InputFieldDeclarationParser';
22
import { ErrorCollection } from '../utils/errors/ErrorCollection';
3-
import { API } from './API';
3+
44
import {
55
UnvalidatedBindTargetDeclaration,
66
UnvalidatedInputFieldArgument,
77
UnvalidatedInputFieldDeclaration,
88
} from '../parsers/newInputFieldParser/InputFieldDeclarationValidator';
9+
import { IAPI } from './IAPI';
910

1011
export class InputFieldAPI {
11-
private readonly api: API;
12+
private readonly api: IAPI;
1213

13-
constructor(api: API) {
14+
constructor(api: IAPI) {
1415
this.api = api;
1516
}
1617

@@ -100,6 +101,15 @@ export class InputFieldAPI {
100101
return unvalidatedDeclaration;
101102
}
102103

104+
public setTemplateName(unvalidatedDeclaration: UnvalidatedInputFieldDeclaration, templateName: string): UnvalidatedInputFieldDeclaration {
105+
unvalidatedDeclaration.templateName = { value: templateName };
106+
return unvalidatedDeclaration;
107+
}
108+
109+
public applyTemplate(unvalidatedDeclaration: UnvalidatedInputFieldDeclaration): UnvalidatedInputFieldDeclaration {
110+
return this.api.newInputFieldParser.applyTemplate(unvalidatedDeclaration);
111+
}
112+
103113
public getTemplate(templateName: string): Readonly<UnvalidatedInputFieldDeclaration> | undefined {
104114
return this.api.newInputFieldParser.getTemplate(templateName);
105115
}
@@ -120,7 +130,7 @@ export class InputFieldAPI {
120130
}
121131

122132
return {
123-
fullDeclaration: '',
133+
fullDeclaration: override.fullDeclaration,
124134
inputFieldType: override.inputFieldType !== undefined ? override.inputFieldType : unvalidatedDeclaration.inputFieldType,
125135
bindTarget: bindTarget,
126136
arguments: override.arguments.concat(unvalidatedDeclaration.arguments).reduce<UnvalidatedInputFieldArgument[]>((arr, currentValue) => {
@@ -130,7 +140,7 @@ export class InputFieldAPI {
130140
}
131141
return arr;
132142
}, []),
133-
errorCollection: unvalidatedDeclaration.errorCollection.merge(override.errorCollection),
143+
errorCollection: new ErrorCollection('input field declaration').merge(unvalidatedDeclaration.errorCollection).merge(override.errorCollection),
134144
};
135145
}
136146
}

src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export default class MetaBindPlugin extends Plugin implements IPlugin {
7474

7575
this.registerMarkdownCodeBlockProcessor('meta-bind', (source, el, ctx) => {
7676
const codeBlock = el;
77-
const content = source.replaceAll('\n', '').trim();
77+
const content = source.trim();
7878
const isInputField = content.startsWith('INPUT[') && content.endsWith(']');
7979
if (isInputField) {
8080
const inputField = this.api.createInputFieldFromString(content, RenderChildType.BLOCK, ctx.sourcePath, codeBlock, ctx);

src/parsers/ParsingError.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@ export class ParsingError extends MetaBindError {
2727
this.message = `[${this.getErrorType()}] "${this.effect}" caused by "${this.cause}"\n`;
2828
}
2929

30-
this.message += this.str + '\n';
31-
this.message += ' '.repeat(this.parseFailure.furthest.index) + '^' + '\n';
30+
const lines = this.str.split('\n');
31+
const failedLine = lines[this.parseFailure.furthest.line - 1]; // line is a one based index
32+
33+
const linePrefix = `${this.parseFailure.furthest.line} | `;
34+
this.message += `\n\n${linePrefix}${failedLine}`;
35+
this.message += `\n${' '.repeat(this.parseFailure.furthest.column - 1 + linePrefix.length)}^ (${this.cause})`;
3236
}
3337
}
3438

@@ -59,8 +63,14 @@ export class ParsingValidationError extends MetaBindError {
5963
}
6064

6165
if (this.str && this.position) {
62-
this.message += this.str + '\n';
63-
this.message += ' '.repeat(this.position.from.index) + '^'.repeat(this.position.to.index - this.position.from.index) + '\n';
66+
const lines = this.str.split('\n');
67+
const failedLine = lines[this.position.from.line - 1]; // line is a one based index
68+
69+
const linePrefix = `${this.position.from.line} | `;
70+
this.message += `\n\n${linePrefix}${failedLine}`;
71+
this.message += `\n${' '.repeat(this.position.from.column - 1 + linePrefix.length)}${'^'.repeat(
72+
(this.position.to.line === this.position.from.line ? this.position.to.index : failedLine.length) - this.position.from.index
73+
)} (${this.cause})`;
6474
}
6575
}
6676
}

src/parsers/newInputFieldParser/InputFieldDeclarationValidator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export interface ParsingResultNode {
1414
position?: ParsingRange;
1515
}
1616

17-
export function markerToResultNode(value: string, range: ParsingRange): ParsingResultNode {
17+
export function createResultNode(value: string, range: ParsingRange): ParsingResultNode {
1818
return {
1919
value: value,
2020
position: range,
@@ -33,6 +33,7 @@ export interface UnvalidatedInputFieldArgument {
3333

3434
export interface PartialUnvalidatedInputFieldDeclaration {
3535
inputFieldType?: ParsingResultNode;
36+
templateName?: ParsingResultNode;
3637
bindTarget?: UnvalidatedBindTargetDeclaration;
3738
arguments: UnvalidatedInputFieldArgument[];
3839
}

src/parsers/newInputFieldParser/InputFieldParser.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { deepFreeze } from '../../utils/Utils';
77
import { InputFieldDeclarationValidator, UnvalidatedInputFieldDeclaration } from './InputFieldDeclarationValidator';
88
import { ITemplateSupplier, TemplateSupplierTemplate } from './ITemplateSupplier';
99
import { INPUT_FIELD_FULL_DECLARATION, TEMPLATE_INPUT_FIELD_FULL_DECLARATION } from '../nomParsers/Parsers';
10+
import { ParsingValidationError } from '../ParsingError';
11+
import { ErrorLevel } from '../../utils/errors/MetaBindErrors';
1012

1113
export type InputFieldDeclarationTemplate = TemplateSupplierTemplate<UnvalidatedInputFieldDeclaration>;
1214

@@ -23,10 +25,12 @@ export class NewInputFieldDeclarationParser implements ITemplateSupplier<Unvalid
2325
const errorCollection = new ErrorCollection('InputFieldParser');
2426

2527
try {
26-
const parserResult = INPUT_FIELD_FULL_DECLARATION.parse(fullDeclaration) as UnvalidatedInputFieldDeclaration;
28+
let parserResult = INPUT_FIELD_FULL_DECLARATION.parse(fullDeclaration) as UnvalidatedInputFieldDeclaration;
2729
parserResult.fullDeclaration = fullDeclaration;
2830
parserResult.errorCollection = errorCollection;
2931

32+
parserResult = this.applyTemplate(parserResult);
33+
3034
const declarationValidator = new InputFieldDeclarationValidator(this.plugin, parserResult);
3135

3236
return declarationValidator.validate();
@@ -117,4 +121,38 @@ export class NewInputFieldDeclarationParser implements ITemplateSupplier<Unvalid
117121
public getTemplate(templateName: string): Readonly<UnvalidatedInputFieldDeclaration> | undefined {
118122
return this.templates.find(x => x.name === templateName)?.template;
119123
}
124+
125+
public applyTemplate(declaration: UnvalidatedInputFieldDeclaration): UnvalidatedInputFieldDeclaration {
126+
if (declaration.templateName === undefined) {
127+
return declaration;
128+
}
129+
130+
const template = this.getTemplate(declaration.templateName.value);
131+
132+
if (template === undefined) {
133+
if (declaration.templateName.position) {
134+
declaration.errorCollection.add(
135+
new ParsingValidationError(
136+
ErrorLevel.WARNING,
137+
'Input Field Parser',
138+
`Invalid template name. Could not find template with name '${declaration.templateName.value}'`,
139+
declaration.fullDeclaration,
140+
declaration.templateName.position
141+
)
142+
);
143+
} else {
144+
declaration.errorCollection.add(
145+
new ParsingValidationError(
146+
ErrorLevel.WARNING,
147+
'Input Field Parser',
148+
`Invalid template name. Could not find template with name '${declaration.templateName.value}'`
149+
)
150+
);
151+
}
152+
153+
return declaration;
154+
}
155+
156+
return this.plugin.api.inputField.merge(template, declaration);
157+
}
120158
}

src/parsers/nomParsers/Parsers.ts

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { P } from '@lemons_dev/parsinom/lib/ParsiNOM';
22
import { P_UTILS } from '@lemons_dev/parsinom/lib/ParserUtils';
33
import { Parser } from '@lemons_dev/parsinom/lib/Parser';
44
import {
5-
markerToResultNode,
5+
createResultNode,
66
ParsingResultNode,
77
PartialUnvalidatedInputFieldDeclaration,
88
UnvalidatedBindTargetDeclaration,
@@ -54,18 +54,18 @@ const filePath = P.noneOf('[]#^|:?')
5454
.map(x => x.join(''))
5555
.describe('file path');
5656

57-
const bracketMetadataPathPart: Parser<ParsingResultNode> = P.or(P_UTILS.digits(), createStr('"')).wrap(P.string('['), P.string(']')).node(markerToResultNode);
57+
const bracketMetadataPathPart: Parser<ParsingResultNode> = P.or(P_UTILS.digits(), createStr('"')).wrap(P.string('['), P.string(']')).node(createResultNode);
5858

5959
const firstMetadataPathPart: Parser<ParsingResultNode[]> = P.or(
6060
bracketMetadataPathPart.atLeast(1),
61-
P.sequenceMap((ident, brackets) => [ident, ...brackets], ident.node(markerToResultNode), bracketMetadataPathPart.many())
61+
P.sequenceMap((ident, brackets) => [ident, ...brackets], ident.node(createResultNode), bracketMetadataPathPart.many())
6262
);
6363

6464
const metadataPathPart: Parser<ParsingResultNode[]> = P.sequenceMap(
6565
(ident, brackets) => {
6666
return [ident, ...brackets];
6767
},
68-
ident.node(markerToResultNode),
68+
ident.node(createResultNode),
6969
bracketMetadataPathPart.many()
7070
);
7171

@@ -91,11 +91,11 @@ export const BIND_TARGET: Parser<UnvalidatedBindTargetDeclaration> = P.sequenceM
9191
};
9292
}
9393
},
94-
P.sequence(filePath.node(markerToResultNode), P.string('#')).optional(),
94+
P.sequence(filePath.node(createResultNode), P.string('#')).optional(),
9595
metadataPath
9696
);
9797

98-
const inputFieldArgumentValue: Parser<ParsingResultNode[]> = P.separateBy(value.node(markerToResultNode), P.string(',').trim(P_UTILS.optionalWhitespace()));
98+
const inputFieldArgumentValue: Parser<ParsingResultNode[]> = P.separateBy(value.node(createResultNode), P.string(',').trim(P_UTILS.optionalWhitespace()));
9999

100100
const inputFieldArgument: Parser<UnvalidatedInputFieldArgument> = P.sequenceMap(
101101
(name, value): UnvalidatedInputFieldArgument => {
@@ -104,7 +104,7 @@ const inputFieldArgument: Parser<UnvalidatedInputFieldArgument> = P.sequenceMap(
104104
value: value,
105105
};
106106
},
107-
ident.node(markerToResultNode),
107+
ident.node(createResultNode),
108108
inputFieldArgumentValue
109109
.trim(P_UTILS.optionalWhitespace())
110110
.wrap(P.string('('), P.string(')'))
@@ -116,14 +116,30 @@ const inputFieldArguments: Parser<UnvalidatedInputFieldArgument[]> = P.separateB
116116
export const INPUT_FIELD_DECLARATION: Parser<PartialUnvalidatedInputFieldDeclaration> = P.sequenceMap(
117117
(type, args, b) => {
118118
const bindTarget = b === undefined ? undefined : b[1];
119-
console.warn(type, args, b);
120119
return {
121120
inputFieldType: type,
122121
arguments: args,
123122
bindTarget: bindTarget,
124123
};
125124
},
126-
ident.node(markerToResultNode).describe('input field type'),
125+
ident.node(createResultNode).describe('input field type'),
126+
inputFieldArguments
127+
.trim(P_UTILS.optionalWhitespace())
128+
.wrap(P.string('('), P.string(')'))
129+
.optional([] as UnvalidatedInputFieldArgument[]),
130+
P.sequence(P.string(':'), BIND_TARGET).optional()
131+
);
132+
133+
export const PARTIAL_INPUT_FIELD_DECLARATION: Parser<PartialUnvalidatedInputFieldDeclaration> = P.sequenceMap(
134+
(type, args, b) => {
135+
const bindTarget = b === undefined ? undefined : b[1];
136+
return {
137+
inputFieldType: type,
138+
arguments: args,
139+
bindTarget: bindTarget,
140+
};
141+
},
142+
ident.node(createResultNode).optional().describe('input field type'),
127143
inputFieldArguments
128144
.trim(P_UTILS.optionalWhitespace())
129145
.wrap(P.string('('), P.string(')'))
@@ -134,13 +150,13 @@ export const INPUT_FIELD_DECLARATION: Parser<PartialUnvalidatedInputFieldDeclara
134150
export const INPUT_FIELD_FULL_DECLARATION: Parser<PartialUnvalidatedInputFieldDeclaration> = P.or(
135151
P.sequenceMap(
136152
(_1, templateName, _2, declaration, _3) => {
137-
console.warn('first');
153+
declaration.templateName = templateName;
138154
return declaration;
139155
},
140156
P.string('INPUT'),
141-
P.sequenceMap((_1, templateName, _2) => templateName, P.string('['), spaceIdent.describe('template name'), P.string(']')),
157+
P.sequenceMap((_1, templateName, _2) => templateName, P.string('['), spaceIdent.node(createResultNode).describe('template name'), P.string(']')),
142158
P.string('['),
143-
INPUT_FIELD_DECLARATION,
159+
PARTIAL_INPUT_FIELD_DECLARATION,
144160
P.string(']'),
145161
P_UTILS.eof()
146162
),
@@ -157,23 +173,6 @@ export const INPUT_FIELD_FULL_DECLARATION: Parser<PartialUnvalidatedInputFieldDe
157173
)
158174
);
159175

160-
export const PARTIAL_INPUT_FIELD_DECLARATION: Parser<PartialUnvalidatedInputFieldDeclaration> = P.sequenceMap(
161-
(type, args, b) => {
162-
const bindTarget = b === undefined ? undefined : b[1];
163-
return {
164-
inputFieldType: type,
165-
arguments: args,
166-
bindTarget: bindTarget,
167-
};
168-
},
169-
ident.node(markerToResultNode).describe('input field type'),
170-
inputFieldArguments
171-
.trim(P_UTILS.optionalWhitespace())
172-
.wrap(P.string('('), P.string(')'))
173-
.optional([] as UnvalidatedInputFieldArgument[]),
174-
P.sequence(P.string(':'), BIND_TARGET).optional()
175-
);
176-
177176
export const TEMPLATE_INPUT_FIELD_FULL_DECLARATION: Parser<PartialUnvalidatedInputFieldDeclaration> = P.sequenceMap(
178177
(_1, _2, declaration, _3) => {
179178
return declaration;

src/publish/PublishAPI.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,23 @@ import { PublishViewFieldMDRC } from './PublishViewFieldMDRC';
77
import { NewInputFieldDeclarationParser } from '../parsers/newInputFieldParser/InputFieldParser';
88
import { MarkdownPostProcessorContext } from 'obsidian/publish';
99
import { IAPI } from '../api/IAPI';
10+
import { InputFieldAPI } from '../api/InputFieldAPI';
1011

1112
export class PublishAPI implements IAPI {
12-
public plugin: IPlugin;
13-
public newInputFieldParser: NewInputFieldDeclarationParser;
14-
public viewFieldParser: ViewFieldDeclarationParser;
15-
public bindTargetParser: BindTargetParser;
13+
public readonly plugin: IPlugin;
14+
public readonly newInputFieldParser: NewInputFieldDeclarationParser;
15+
public readonly viewFieldParser: ViewFieldDeclarationParser;
16+
public readonly bindTargetParser: BindTargetParser;
17+
public readonly inputField: InputFieldAPI;
1618

1719
constructor(plugin: IPlugin) {
1820
this.plugin = plugin;
1921

2022
this.newInputFieldParser = new NewInputFieldDeclarationParser(this.plugin);
2123
this.viewFieldParser = new ViewFieldDeclarationParser(this.plugin);
2224
this.bindTargetParser = new BindTargetParser(this.plugin);
25+
26+
this.inputField = new InputFieldAPI(this);
2327
}
2428

2529
public createInputFieldFromString(

0 commit comments

Comments
 (0)