Skip to content

Commit

Permalink
fix(gjs): consistently highlight gjs blocks
Browse files Browse the repository at this point in the history
additionally, there are more tests to ensure that this happens.
also, glimmer-javascript is now a registered language with highlight.js
later, in a breaking version, gjs will be the preferred language tag,
instead of highjacking js
  • Loading branch information
NullVoxPopuli committed Nov 6, 2022
1 parent 158a348 commit abfdd2b
Show file tree
Hide file tree
Showing 9 changed files with 516 additions and 46 deletions.
57 changes: 55 additions & 2 deletions dist/glimmer.cjs.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,64 @@ function registerJavaScriptInjections(hljs) {
return;
}
js = js.rawDefinition(hljs);
setupHBSLiteral(hljs, js);
swapXMLForGlimmer(hljs, js);
setupTemplateTag(hljs, js);
hljs.registerLanguage("javascript", () => js);
hljs.registerLanguage("glimmer-javascript", () => js);
}
function setupHBSLiteral(hljs, js) {
let cssIndex = js.contains.findIndex((rule) => (rule == null ? void 0 : rule.begin) === "css`");
let css = js.contains[cssIndex];
js.contains.flatMap((contains) => (contains == null ? void 0 : contains.contains) || contains).filter((rule) => rule.subLanguage === "xml").forEach((rule) => rule.subLanguage = "glimmer");
const HBS_TEMPLATE = hljs.inherit(css, { begin: /hbs`/ });
HBS_TEMPLATE.starts.subLanguage = "glimmer";
js.contains.splice(cssIndex, 0, HBS_TEMPLATE);
hljs.registerLanguage("javascript", () => js);
}
function swapXMLForGlimmer(_hljs, js) {
js.contains.flatMap((contains) => (contains == null ? void 0 : contains.contains) || contains).filter((rule) => rule.subLanguage === "xml").forEach((rule) => rule.subLanguage = "glimmer");
}
function setupTemplateTag(_hljs, js) {
const GLIMMER_TEMPLATE_TAG = {
begin: /<template>/,
end: /<\/template>/,
isTrulyOpeningTag: (match, response) => {
const afterMatchIndex = match[0].length + match.index;
const nextChar = match.input[afterMatchIndex];
if (nextChar === "<" || nextChar === ",") {
response.ignoreMatch();
return;
}
if (nextChar === ">") {
if (!hasClosingTag(match, { after: afterMatchIndex })) {
response.ignoreMatch();
}
}
let m;
const afterMatch = match.input.substring(afterMatchIndex);
if (m = afterMatch.match(/^\s+extends\s+/)) {
if (m.index === 0) {
response.ignoreMatch();
return;
}
}
}
};
js.contains.unshift({
variants: [
{
begin: GLIMMER_TEMPLATE_TAG.begin,
"on:begin": GLIMMER_TEMPLATE_TAG.isTrulyOpeningTag,
end: GLIMMER_TEMPLATE_TAG.end
}
],
subLanguage: "glimmer",
contains: [
{
begin: GLIMMER_TEMPLATE_TAG.begin,
end: GLIMMER_TEMPLATE_TAG.end,
skip: true,
contains: ["self"]
}
]
});
}
2 changes: 1 addition & 1 deletion dist/glimmer.esm.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 11 additions & 13 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,13 @@
this._updateEditor();
this._updateHighlightDebug();
this._updatePreview();
}
};

_reHighlight = (code, language) => {
let preview = document.querySelector('pre code');

preview.innerHTML = hljs.highlight(code.trim(), { language }).value;
}
};

_handleInput = (event) => {
let formData = new FormData(event.currentTarget);
Expand All @@ -112,12 +112,12 @@
this._updateQp('language', data.language);

this._reHighlight(data.code, data.language);
}
};

_updatePreview = () => {
let form = document.querySelector('#editor');

form.dispatchEvent(new CustomEvent('submit', {cancelable: true}));
form.dispatchEvent(new CustomEvent('submit', { cancelable: true }));
};

_setupSampleNav = () => {
Expand Down Expand Up @@ -158,17 +158,17 @@
let info = state.currentSample;

code.value = info.sample;
language.value = code.language;
language.value = code.language;
}

if (state.qps.get('code')){
if (state.qps.get('code')) {
code.value = state.qps.get('code');
}

if (state.qps.get('language')){
if (state.qps.get('language')) {
language.value = state.qps.get('language');
}
}
};

_setupDebug = () => {
let debugLinks = document.querySelectorAll('#dev a');
Expand Down Expand Up @@ -207,7 +207,7 @@

state.navigateTo(`?${qps}`);
}
}
};

_updateQp = (name, value) => {
let qps = new URLSearchParams(state.qps);
Expand All @@ -217,7 +217,7 @@

state.navigateTo(`?${qps}`);
}
}
};

_updateDebug = () => {
let debugMode = document.querySelector('#dev a.debug');
Expand All @@ -240,9 +240,7 @@
} else {
form.classList.add('hidden');
}

}

};

_updateHighlightDebug = () => {
if (state.isDebugging) {
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ function registerJavaScriptInjections(hljs) {

js = js.rawDefinition(hljs);

setupHBSLiteral(js);
swapXMLForGlimmer(js);
setupTemplateTag(js);
setupHBSLiteral(hljs, js);
swapXMLForGlimmer(hljs, js);
setupTemplateTag(hljs, js);

hljs.registerLanguage('javascript', () => js);
hljs.registerLanguage('glimmer-javascript', () => js);
}

function setupHBSLiteral(js) {
function setupHBSLiteral(hljs, js) {
let cssIndex = js.contains.findIndex((rule) => rule?.begin === 'css`');
let css = js.contains[cssIndex];

Expand All @@ -52,7 +53,7 @@ function setupHBSLiteral(js) {
js.contains.splice(cssIndex, 0, HBS_TEMPLATE);
}

function swapXMLForGlimmer(js) {
function swapXMLForGlimmer(_hljs, js) {
// The default JSX grammar is actually just XML, which... is also wrong :D
js.contains
.flatMap((contains) => contains?.contains || contains)
Expand All @@ -63,7 +64,7 @@ function swapXMLForGlimmer(js) {
/**
* A lot of this is stolen from XML
*/
function setupTemplateTag(js) {
function setupTemplateTag(_hljs, js) {
const GLIMMER_TEMPLATE_TAG = {
begin: /<template>/,
end: /<\/template>/,
Expand Down
91 changes: 88 additions & 3 deletions tests-esm/-utils.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,103 @@
import { expect } from 'vitest';
import hljs from 'highlight.js';
import { registerLanguage } from 'highlightjs-glimmer';
import { setup } from 'highlightjs-glimmer';

registerLanguage(hljs);
setup(hljs);

import prettier from 'prettier';

// Used to resolve indentation issues.
// We don't care about that in these tests -- we only care about tag identification.
export function format(code) {
return prettier.format(code, { parser: 'html', htmlWhitespaceSensitivity: 'ignore' });
}

export function formattedEquals(actual, expected) {
expect(format(actual)).toEqual(format(expected));
}

export function parse(code, lang = 'glimmer') {
return hljs.highlight(code, { language: lang }).value;
}

export function glimmer(...children) {
return `<span class="language-glimmer">${children.join('')}</span>`;
}

export const templateTags = {
get begin() {
return tag('tag', ['&lt;', tag('title', 'template'), '&gt;']);
},
get end() {
return tag('tag', ['&lt;/', tag('title', 'template'), '&gt;']);
},
};

export function template(...content) {
return list(templateTags.begin, '\n', ...indentLines(content), '\n', templateTags.end);
}

export function selfClosing(name, attributes = []) {
return tag('tag', ['&lt;', tag('title', name), ...attributes, ' /&gt;']);
}

export function indentLines(lines, amount = 2) {
let indent = Array(amount + 1).join(' ');

return lines.map((line) => {
return `${indent}${line}`;
});
}

export function element(name, content = []) {
return list(
tag('tag', ['&lt;', tag('title', name), '&gt;']),
'\n',
...indentLines(content),
'\n',
tag('tag', ['&lt;/', tag('title', name), '&gt;'])
);
}

export function mustache(...content) {
return tag('punctuation mustache', ['{{', ...content, '}}']);
}

export function arg(name) {
return list(tag('punctuation', '@'), tag('params', name));
}

export const keyword = {
export: tag('keyword', 'export'),
const: tag('keyword', 'const'),
default: tag('keyword', 'default'),
};

export const operator = {
equals: tag('operator', '='),
};

export function string(content) {
return tag('string', ['&quot;', content, '&quot;']);
}

export const tags = {
template,
mustache,
element,
selfClosing,
arg,
keyword,
operator,
string,
};

export function tag(klass, children = []) {
let _children = Array.isArray(children) ? children : [children];

return `<span class="hljs-${klass}">${_children.join('')}</span>`;
}

export function list(children) {
export function list(...children) {
return children.join('');
}
1 change: 1 addition & 0 deletions tests-esm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"eslint": "^8.26.0",
"highlight.js": ">= 11.6.0",
"markdown-it": "^13.0.1",
"prettier": "^2.7.1",
"rehype": "^12.0.1",
"rehype-highlight": "^6.0.0",
"rehype-stringify": "^9.0.3",
Expand Down
Loading

0 comments on commit abfdd2b

Please sign in to comment.