Skip to content

Commit

Permalink
Merge pull request #10 from bancodobrasil/feat/handlebars-parser
Browse files Browse the repository at this point in the history
Feat/handlebars parser
  • Loading branch information
ralphg6 authored Mar 22, 2023
2 parents ac6656c + 55e9bf5 commit a4d313f
Show file tree
Hide file tree
Showing 15 changed files with 733 additions and 311 deletions.
31 changes: 24 additions & 7 deletions src/pages/Menu/EditTemplate/EditTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { Trans, useTranslation } from 'react-i18next';
import { useLazyQuery, useMutation, useQuery } from '@apollo/client';
import { useNavigate, useParams } from 'react-router-dom';
import CodeMirror from '@uiw/react-codemirror';
import { dracula } from '@uiw/codemirror-theme-dracula';
import { json } from '@codemirror/lang-json';
import { xml } from '@codemirror/lang-xml';
import { draculaInit } from '@uiw/codemirror-theme-dracula';
import { tags } from '@lezer/highlight';
import { jsonHandlebars } from '../../../utils/codemirror/json';
import { xmlHandlebars } from '../../../utils/codemirror/xml';
import { AppBreadcrumbs } from '../../../components/AppBreadcrumbs';
import MenuService from '../../../api/services/MenuService';
import Loading from '../../../components/Loading';
Expand Down Expand Up @@ -42,18 +43,18 @@ export const EditTemplateMenu = () => {
const [templateResult, setTemplateResult] = React.useState('');
const [loadedInitialTemplate, setLoadedInitialTemplate] = React.useState(false);

const [language, setLanguage] = React.useState(json);
const [language, setLanguage] = React.useState(jsonHandlebars);

React.useEffect(() => {
switch (templateFormat) {
case EnumTemplateFormat.JSON:
setLanguage(json);
setLanguage(jsonHandlebars);
break;
case EnumTemplateFormat.XML:
setLanguage(xml());
setLanguage(xmlHandlebars());
break;
case EnumTemplateFormat.PLAIN:
setLanguage(json);
setLanguage(jsonHandlebars);
break;
}
}, [templateFormat]);
Expand Down Expand Up @@ -184,6 +185,22 @@ export const EditTemplateMenu = () => {
});
}, [template, templateFormat, data, renderMenuTemplate]);

const dracula = React.useMemo(
() =>
draculaInit({
styles: [
{ tag: tags.variableName, color: '#ffd599' },
{ tag: tags.special(tags.variableName), color: '#e47f0c' },
{ tag: tags.special(tags.brace), color: '#ffd599' },
{ tag: tags.definitionKeyword, color: '#e47f0c' },
{ tag: tags.string, color: '#0ab20d' },
{ tag: tags.number, color: '#7ab0e6' },
{ tag: tags.bool, color: '#7ab0e6' },
],
}),
[],
);

const onChangeTemplateFormat = React.useCallback(event => {
setTemplateFormat(event.target.value);
}, []);
Expand Down
31 changes: 24 additions & 7 deletions src/pages/Menu/Items/EditTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { Trans, useTranslation } from 'react-i18next';
import { useLazyQuery, useMutation, useQuery } from '@apollo/client';
import { useNavigate, useParams } from 'react-router-dom';
import CodeMirror from '@uiw/react-codemirror';
import { dracula } from '@uiw/codemirror-theme-dracula';
import { json } from '@codemirror/lang-json';
import { xml } from '@codemirror/lang-xml';
import { draculaInit } from '@uiw/codemirror-theme-dracula';
import { tags } from '@lezer/highlight';
import { jsonHandlebars } from '../../../utils/codemirror/json';
import { xmlHandlebars } from '../../../utils/codemirror/xml';
import { AppBreadcrumbs } from '../../../components/AppBreadcrumbs';
import MenuItemService from '../../../api/services/MenuItemService';
import Loading from '../../../components/Loading';
Expand Down Expand Up @@ -43,18 +44,18 @@ export const EditTemplateItems = () => {
const [templateResult, setTemplateResult] = React.useState('');
const [loadedInitialTemplate, setLoadedInitialTemplate] = React.useState(false);

const [language, setLanguage] = React.useState(json);
const [language, setLanguage] = React.useState(jsonHandlebars);

React.useEffect(() => {
switch (templateFormat) {
case EnumTemplateFormat.JSON:
setLanguage(json);
setLanguage(jsonHandlebars);
break;
case EnumTemplateFormat.XML:
setLanguage(xml());
setLanguage(xmlHandlebars());
break;
case EnumTemplateFormat.PLAIN:
setLanguage(json);
setLanguage(jsonHandlebars);
break;
}
}, [templateFormat]);
Expand Down Expand Up @@ -177,6 +178,22 @@ export const EditTemplateItems = () => {
}
}, [template, templateFormat, data, itemId, renderMenuItemTemplate]);

const dracula = React.useMemo(
() =>
draculaInit({
styles: [
{ tag: tags.variableName, color: '#ffd599' },
{ tag: tags.special(tags.variableName), color: '#e47f0c' },
{ tag: tags.special(tags.brace), color: '#ffd599' },
{ tag: tags.definitionKeyword, color: '#e47f0c' },
{ tag: tags.string, color: '#0ab20d' },
{ tag: tags.number, color: '#7ab0e6' },
{ tag: tags.bool, color: '#7ab0e6' },
],
}),
[],
);

const onChangeTemplateFormat = React.useCallback(event => {
setTemplateFormat(event.target.value);
}, []);
Expand Down
45 changes: 0 additions & 45 deletions src/utils/codemirror/ejs-json.ts

This file was deleted.

39 changes: 0 additions & 39 deletions src/utils/codemirror/ejs-xml.ts

This file was deleted.

23 changes: 20 additions & 3 deletions src/utils/codemirror/json/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { styleTags, tags as t } from '@lezer/highlight';
import { parser } from './json.grammar.js';

export const jsonEjsLanguage = LRLanguage.define({
export const jsonHandlebarsLanguage = LRLanguage.define({
parser: parser.configure({
props: [
indentNodeProp.add({
Expand All @@ -29,15 +29,32 @@ export const jsonEjsLanguage = LRLanguage.define({
',': t.separator,
'[ ]': t.squareBracket,
'{ }': t.brace,
'OpeningExpression BlockExpressionOpen BlockExpressionEnd PartialBlockExpressionOpen InlinePartialExpressionOpen':
t.special(t.brace),
'ClosingExpression HTMLEscapedExpressionClose RawExpressionClose RawBlockExpressionClose':
t.special(t.brace),
'SubExpressionOpen SubExpressionClose': t.paren,
HelperOrContext: t.special(t.variableName),
Context: t.variableName,
HashArgumentProperty: t.variableName,
HashValue: t.special(t.string),
BlockParameterName: t.variableName,
TemplateComment: t.lineComment,
as: t.definitionKeyword,
}),
],
// wrap: parseMixed(node => {
// const { name } = node.type;
// console.log(name, node.from, node.to);
// return null;
// }),
}),
languageData: {
closeBrackets: { brackets: ['[', '{', '"'] },
indentOnInput: /^\s*[}\]]$/,
},
});

export function jsonEjs() {
return new LanguageSupport(jsonEjsLanguage, json().support);
export function jsonHandlebars() {
return new LanguageSupport(jsonHandlebarsLanguage, json().support);
}
69 changes: 59 additions & 10 deletions src/utils/codemirror/json/json.grammar
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@top JsonText { value }

value { True | False | Null | Number | String | Object | Array | EjsOutput }
value { True | False | Null | Number | String | Object | Array | handlebarsExpression }

String { string }
Object { "{" list<Property>? "}" }
Expand All @@ -9,18 +9,62 @@ Array { "[" list<value>? "]" }
Property { PropertyName ":" value }
PropertyName { string }

// EJS output (not working yet)
handlebarsExpression { Expression | BlockExpression | PartialBlockExpression | InlinePartialExpression | EscapedExpression }

HashValue { value | Context | SubExpression }
HashArgument { HashArgumentProperty "=" HashValue }
ExpressionContent { HelperOrContext (Context | SubExpression | HashArgument*)? }

blockExpressionEnd { HTMLEscapedExpressionClose value* BlockExpressionEnd HelperOrContext HTMLEscapedExpressionClose }

SubExpression { SubExpressionOpen ExpressionContent SubExpressionClose }

Expression { OpeningExpression (ExpressionContent | SubExpression) ClosingExpression }
BlockExpression { BlockExpressionOpen ExpressionContent BlockParameters? blockExpressionEnd }
PartialBlockExpression { PartialBlockExpressionOpen (ExpressionContent | SubExpression) blockExpressionEnd }
InlinePartialExpression { InlinePartialExpressionOpen HelperOrContext string blockExpressionEnd }
EscapedExpression { "\\" Expression }

@skip {} {
EjsOutput { output | '"' output '"' }
output { "<%=" JavascriptExpression tagClose }
Comment { "{{!" (CommentContent | commentNewLine)* commentEnd }
}

@local tokens {
tagClose { "%" $[_\-]? ">" }
@else JavascriptExpression
commentEnd { HTMLEscapedExpressionClose }
commentNewLine { "\n" }
@else CommentContent
}

@skip {} {
BlockParameters { "as" space+ pipe space* BlockParameterName (space+ BlockParameterName)* space* pipe }
}

@local tokens {
pipe { "|" }
space { whitespace }
@else BlockParameterName
}

@tokens {
OpeningExpression { HTMLEscapedExpressionOpen | RawExpressionOpen | RawBlockExpressionOpen | PartialExpressionOpen }
ClosingExpression { HTMLEscapedExpressionClose | RawExpressionClose | RawBlockExpressionClose }

HTMLEscapedExpressionOpen[closedBy=HTMLEscapedExpressionClose] { "{{" "~"? }
RawExpressionOpen[closedBy=RawBlockExpressionClose] { "{{{" }
RawBlockExpressionOpen[closedBy=RawBlockExpressionClose] { "{{{{" }
PartialExpressionOpen[closedBy=HTMLEscapedExpressionClose] { HTMLEscapedExpressionOpen ">" }
BlockExpressionOpen[closedBy=HTMLEscapedExpressionClose] { HTMLEscapedExpressionOpen "#" }
BlockExpressionEnd[closedBy=HTMLEscapedExpressionClose] { HTMLEscapedExpressionOpen "/" }
PartialBlockExpressionOpen[closedBy=HTMLEscapedExpressionClose] { BlockExpressionOpen ">" }
InlinePartialExpressionOpen[closedBy=HTMLEscapedExpressionClose] { BlockExpressionOpen "*" }

HTMLEscapedExpressionClose[openedBy=HTMLEscapedExpressionOpen] { "~"? "}}" ","? }
RawExpressionClose[openedBy=RawExpressionOpen] { "}}}" ","? }
RawBlockExpressionClose[openedBy=RawBlockExpressionOpen] { "}}}}" }

SubExpressionOpen { "(" }
SubExpressionClose { ")" }

True { "true" }
False { "false" }
Null { "null" }
Expand All @@ -35,14 +79,19 @@ PropertyName { string }
esc { $["\\\/bfnrt] | "u" hex hex hex hex }
hex { $[0-9a-fA-F] }

whitespace { $[ \n\r\t] }
whitespace[@export] { $[ \n\r\t] }

"{" "}" "[" "]"

"="
"as"
}

@precedence { value, empty }
@skip { whitespace | Comment }
list<item> { item ("," item)* }

@context trackShiftTerm from "./tokens"

@skip { whitespace }
list<item> { (!value item | !empty "") ("," (!value item | !empty ""))* }
@external tokens expressionToken from "./tokens" { Context, HelperOrContext, HashArgumentProperty }

@detectDelim
Loading

0 comments on commit a4d313f

Please sign in to comment.