Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/@glimmer/syntax/lib/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,18 @@ export abstract class Parser {
>
> = null;
public tokenizer: EventedTokenizer;
protected continueOnError: boolean;

constructor(
source: src.Source,
entityParser = new EntityParser(namedCharRefs),
mode: 'precompile' | 'codemod' = 'precompile'
mode: 'precompile' | 'codemod' = 'precompile',
continueOnError = false,
) {
this.source = source;
this.lines = source.source.split(/\r\n?|\n/u);
this.tokenizer = new EventedTokenizer(this, entityParser, mode);
this.continueOnError = continueOnError;
}

offset(): src.SourceOffset {
Expand Down
45 changes: 25 additions & 20 deletions packages/@glimmer/syntax/lib/parser/handlebars-node-visitors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ export abstract class HandlebarsNodeVisitors extends Parser {
return node;
}

triggerError(message: string, loc: SourceSpan): ASTv1.ErrorNode {
if(this.continueOnError) {
let error = b.error({ loc, message });
appendChild(this.currentElement(), error);
return error;
}
throw generateSyntaxError(message, loc);
}

BlockStatement(block: HBS.BlockStatement): ASTv1.BlockStatement | void {
if (this.tokenizer.state === 'comment') {
this.appendToCommentData(this.sourceForNode(block));
Expand Down Expand Up @@ -355,32 +364,28 @@ export abstract class HandlebarsNodeVisitors extends Parser {
return comment;
}

PartialStatement(partial: HBS.PartialStatement): never {
throw generateSyntaxError(
`Handlebars partials are not supported`,
this.source.spanFor(partial.loc)
);
PartialStatement(partial: HBS.PartialStatement): ASTv1.ErrorNode {
const loc = this.source.spanFor(partial.loc);
const message = `Handlebars partials are not supported`;
return this.triggerError(message, loc);
}

PartialBlockStatement(partialBlock: HBS.PartialBlockStatement): never {
throw generateSyntaxError(
`Handlebars partial blocks are not supported`,
this.source.spanFor(partialBlock.loc)
);
PartialBlockStatement(partialBlock: HBS.PartialBlockStatement): ASTv1.ErrorNode {
const loc = this.source.spanFor(partialBlock.loc);
const message = `Handlebars partial blocks are not supported`;
return this.triggerError(message, loc);
}

Decorator(decorator: HBS.Decorator): never {
throw generateSyntaxError(
`Handlebars decorators are not supported`,
this.source.spanFor(decorator.loc)
);
Decorator(decorator: HBS.Decorator): ASTv1.ErrorNode {
const loc = this.source.spanFor(decorator.loc);
const message = `Handlebars decorators are not supported`;
return this.triggerError(message, loc);
}

DecoratorBlock(decoratorBlock: HBS.DecoratorBlock): never {
throw generateSyntaxError(
`Handlebars decorator blocks are not supported`,
this.source.spanFor(decoratorBlock.loc)
);
DecoratorBlock(decoratorBlock: HBS.DecoratorBlock): ASTv1.ErrorNode {
const loc = this.source.spanFor(decoratorBlock.loc);
const message = `Handlebars decorator blocks are not supported`;
return this.triggerError(message, loc);
}

SubExpression(sexpr: HBS.SubExpression): ASTv1.SubExpression {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ export interface PreprocessOptions {
escaping/unescaping of HTML entity codes.
*/
mode?: 'codemod' | 'precompile' | undefined;
continueOnError?: boolean | undefined;
}

export interface Syntax {
Expand Down Expand Up @@ -786,7 +787,7 @@ export function preprocess(
end: offsets.endPosition,
};

let template = new TokenizerEventHandlers(source, entityParser, mode).parse(
let template = new TokenizerEventHandlers(source, entityParser, mode, options.continueOnError).parse(
ast,
options.locals ?? []
);
Expand Down
8 changes: 4 additions & 4 deletions packages/@glimmer/syntax/lib/v1/handlebars-ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ export interface CommonNode {
export interface NodeMap {
Program: { input: Program; output: ASTv1.Block };
MustacheStatement: { input: MustacheStatement; output: ASTv1.MustacheStatement | void };
Decorator: { input: Decorator; output: never };
Decorator: { input: Decorator; output: ASTv1.ErrorNode };
BlockStatement: { input: BlockStatement; output: ASTv1.BlockStatement | void };
DecoratorBlock: { input: DecoratorBlock; output: never };
PartialStatement: { input: PartialStatement; output: never };
PartialBlockStatement: { input: PartialBlockStatement; output: never };
DecoratorBlock: { input: DecoratorBlock; output: ASTv1.ErrorNode };
PartialStatement: { input: PartialStatement; output: ASTv1.ErrorNode };
PartialBlockStatement: { input: PartialBlockStatement; output: ASTv1.ErrorNode };
ContentStatement: { input: ContentStatement; output: void };
CommentStatement: { input: CommentStatement; output: ASTv1.MustacheCommentStatement | null };
SubExpression: { input: SubExpression; output: ASTv1.SubExpression };
Expand Down
8 changes: 8 additions & 0 deletions packages/@glimmer/syntax/lib/v1/nodes-v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export type StatementName =
| 'BlockStatement'
| 'MustacheCommentStatement'
| 'TextNode'
| 'ErrorNode'
| 'ElementNode';

export interface AttrNode extends BaseNode {
Expand Down Expand Up @@ -288,6 +289,11 @@ export interface HashPair extends BaseNode {
value: Expression;
}

export interface ErrorNode extends BaseNode {
type: 'ErrorNode';
message: string;
}

export interface StripFlags {
open: boolean;
close: boolean;
Expand Down Expand Up @@ -318,6 +324,8 @@ export type Nodes = {

Hash: Hash;
HashPair: HashPair;

ErrorNode: ErrorNode;
};

export type NodeType = keyof Nodes;
Expand Down
8 changes: 8 additions & 0 deletions packages/@glimmer/syntax/lib/v1/parser-builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,14 @@ class Builders {
}): T {
return buildLegacyLiteral({ type, value, loc });
}

error({ message, loc }: { message: string; loc: SourceSpan }): ASTv1.ErrorNode {
return {
type: 'ErrorNode',
message,
loc,
};
}
}

const b = new Builders();
Expand Down
8 changes: 8 additions & 0 deletions packages/@glimmer/syntax/lib/v1/public-builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,13 @@ function buildLoc(
}
}

function buildError(message = '', loc?: SourceLocation): ASTv1.ErrorNode {
return b.error({
message,
loc: buildLoc(loc || null),
});
}

export default {
mustache: buildMustache,
block: buildBlock,
Expand All @@ -503,6 +510,7 @@ export default {
template: buildTemplate,
loc: buildLoc,
pos: buildPosition,
error: buildError,

path: buildPath,

Expand Down
30 changes: 30 additions & 0 deletions packages/@glimmer/syntax/test/parser-node-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,15 @@ test('Handlebars partial should error', (assert) => {
);
});

test('Continue on error - Handlebars partial should error', () => {
let t = '<img id="one">{{> foo}}<img id="two">';
astEqual(t, b.template([
element('img', ['attrs', ['id', 'one']]),
b.error('Handlebars partials are not supported'),
element('img', ['attrs', ['id', 'two']])
]), undefined, { continueOnError: true });
});

test('Handlebars partial block should error', (assert) => {
assert.throws(
() => {
Expand All @@ -915,6 +924,13 @@ test('Handlebars partial block should error', (assert) => {
);
});

test('Continue on error - Handlebars partial block should error', () => {
let t = '{{#> foo}}{{/foo}}';
astEqual(t, b.template([
b.error('Handlebars partial blocks are not supported'),
]), undefined, { continueOnError: true });
});

test('Handlebars decorator should error', (assert) => {
assert.throws(
() => {
Expand All @@ -924,6 +940,13 @@ test('Handlebars decorator should error', (assert) => {
);
});

test('Continue on error - Handlebars decorator should error', () => {
let t = '{{* foo}}';
astEqual(t, b.template([
b.error('Handlebars decorators are not supported'),
]), undefined, { continueOnError: true });
});

test('Handlebars decorator block should error', (assert) => {
assert.throws(
() => {
Expand All @@ -939,6 +962,13 @@ test('Handlebars decorator block should error', (assert) => {
);
});

test('Continue on error - Handlebars decorator block should error', () => {
let t = '{{#* foo}}{{/foo}}';
astEqual(t, b.template([
b.error('Handlebars decorator blocks are not supported'),
]), undefined, { continueOnError: true });
});

test('disallowed mustaches in the tagName space', (assert) => {
assert.throws(
() => {
Expand Down