diff --git a/Syntax.js b/Syntax.js index 7d41375..b3a1b5d 100644 --- a/Syntax.js +++ b/Syntax.js @@ -237,12 +237,12 @@ export class Syntax { } catch (error) { throw new LanguageLoadError(name, path, {cause: error}); } - + // If the module exports a register function, call it with this instance if (typeof module.default === 'function') { module.default(this); } - + // After calling register, aliases have been registered. Re-resolve the name: let resolvedName = this.#aliases[name] || name; return loader.get(resolvedName); diff --git a/Syntax/CodeElement.js b/Syntax/CodeElement.js index 57c5176..ea24b35 100644 --- a/Syntax/CodeElement.js +++ b/Syntax/CodeElement.js @@ -83,7 +83,7 @@ export class CodeElement extends HTMLElement { constructor() { super(); - + /** * A promise that resolves when the current highlighting attempt completes. * Check `highlighted` before using line measurement APIs. @@ -105,10 +105,7 @@ export class CodeElement extends HTMLElement { } get language() { - return ( - this.getAttribute('language') || - this.#detectLanguageFromClass() - ); + return this.getAttribute('language') || this.#detectLanguageFromClass(); } set language(value) { @@ -150,26 +147,26 @@ export class CodeElement extends HTMLElement { */ getLineBoundingClientRect(lineNumber) { if (!this.#shadow) return null; - + const code = this.#shadow.querySelector('code'); if (!code) return null; - + const lines = code.children; if (lineNumber < 1 || lineNumber > lines.length) return null; - + return lines[lineNumber - 1].getBoundingClientRect(); } - + /** * Get the total number of rendered lines. * @returns {number} The line count, or 0 if not yet rendered. */ get lineCount() { if (!this.#shadow) return 0; - + const code = this.#shadow.querySelector('code'); if (!code) return 0; - + return code.children.length; } @@ -180,7 +177,7 @@ export class CodeElement extends HTMLElement { get highlighted() { return this.#highlighted; } - + connectedCallback() { // Detect if we're inside a
element and set wrap attribute
if (this.parentElement?.tagName === 'PRE') {
@@ -382,7 +379,8 @@ export function upgradeAll(selector, syntax = null) {
}
// Try to detect language from various sources
- let language = element.getAttribute('lang') || element.getAttribute('language');
+ let language =
+ element.getAttribute('lang') || element.getAttribute('language');
if (!language) {
// Check class names
diff --git a/Syntax/Language/html.js b/Syntax/Language/html.js
index 6dbe834..e0ceac3 100644
--- a/Syntax/Language/html.js
+++ b/Syntax/Language/html.js
@@ -8,7 +8,10 @@ language.push({
pattern: /';
+ const code =
+ '';
const matches = await language.getMatches(Syntax.default, code);
// Should have embedded JSON language
ok(matches.some(m => m.expression && m.expression.language === 'json'));
diff --git a/test/Syntax/Language/json.js b/test/Syntax/Language/json.js
index 395aa88..51c5f19 100644
--- a/test/Syntax/Language/json.js
+++ b/test/Syntax/Language/json.js
@@ -30,7 +30,9 @@ test('JSON: integer numbers', async () => {
const language = await getLanguage();
const code = '0 42 -17 999';
const matches = await language.getMatches(Syntax.default, code);
- const numbers = matches.filter(m => m.expression.type === 'constant' && /^-?\d/.test(m.value));
+ const numbers = matches.filter(
+ m => m.expression.type === 'constant' && /^-?\d/.test(m.value)
+ );
ok(numbers.length >= 4);
});
@@ -38,7 +40,9 @@ test('JSON: float numbers', async () => {
const language = await getLanguage();
const code = '3.14 -0.5 123.456';
const matches = await language.getMatches(Syntax.default, code);
- const numbers = matches.filter(m => m.expression.type === 'constant' && m.value.includes('.'));
+ const numbers = matches.filter(
+ m => m.expression.type === 'constant' && m.value.includes('.')
+ );
ok(numbers.length >= 3);
});
@@ -46,7 +50,9 @@ test('JSON: scientific notation', async () => {
const language = await getLanguage();
const code = '1e10 2.5e-3 -1.23E+5';
const matches = await language.getMatches(Syntax.default, code);
- const numbers = matches.filter(m => m.expression.type === 'constant' && /e/i.test(m.value));
+ const numbers = matches.filter(
+ m => m.expression.type === 'constant' && /e/i.test(m.value)
+ );
ok(numbers.length >= 3);
});
@@ -94,7 +100,8 @@ test('JSON: array', async () => {
test('JSON: complex structure', async () => {
const language = await getLanguage();
- const code = '{"items": [{"id": 1, "active": true}, {"id": 2, "active": false}]}';
+ const code =
+ '{"items": [{"id": 1, "active": true}, {"id": 2, "active": false}]}';
const matches = await language.getMatches(Syntax.default, code);
const keys = matches.filter(m => m.expression.type === 'key');
ok(keys.length >= 5);
diff --git a/test/Syntax/Language/markdown.js b/test/Syntax/Language/markdown.js
index 3c09c91..0e516a1 100644
--- a/test/Syntax/Language/markdown.js
+++ b/test/Syntax/Language/markdown.js
@@ -31,10 +31,10 @@ test('Markdown can match headers', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '# Heading 1';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'heading', '# Heading 1');
});
@@ -42,10 +42,10 @@ test('Markdown can match bold text', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '**bold text**';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'strong', '**bold text**');
});
@@ -53,10 +53,10 @@ test('Markdown can match italic text', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '*italic text*';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'emphasis', '*italic text*');
});
@@ -64,10 +64,10 @@ test('Markdown can match inline code', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '`code here`';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'code', '`code here`');
});
@@ -75,10 +75,10 @@ test('Markdown can match code blocks', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '```javascript\nconst x = 1;\n```';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'code', '```javascript\nconst x = 1;\n```');
});
@@ -86,10 +86,10 @@ test('Markdown can match links', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '[text](http://example.com)';
const matches = await language.getMatches(syntax, code);
-
+
// Should match the link text and URL as separate tokens
assertToken(code, matches, 'string', 'text');
assertToken(code, matches, 'link', 'http://example.com');
@@ -99,10 +99,10 @@ test('Markdown can match images', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'link', '');
});
@@ -110,10 +110,10 @@ test('Markdown can match blockquotes', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '> This is a quote';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'quote', '> This is a quote');
});
@@ -121,10 +121,10 @@ test('Markdown can match unordered lists', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '- List item';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'list-marker', '- ');
});
@@ -132,10 +132,10 @@ test('Markdown can match ordered lists', async () => {
const syntax = new Syntax();
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
-
+
const code = '1. List item';
const matches = await language.getMatches(syntax, code);
-
+
assertToken(code, matches, 'list-marker', '1. ');
});
@@ -144,7 +144,7 @@ test('Markdown: fenced block followed by inline code does not merge', async () =
registerMarkdown(syntax);
const language = await syntax.getLanguage('markdown');
- const code = "```\nfoo\n```\n\n`project`";
+ const code = '```\nfoo\n```\n\n`project`';
const matches = await language.getMatches(syntax, code);
// Expect a fenced code block token:
@@ -155,9 +155,10 @@ test('Markdown: fenced block followed by inline code does not merge', async () =
// Ensure there is no token that incorrectly spans the fence backticks
// and the following inline backtick (e.g., "````" boundary merge):
- const badSpan = matches.find(m =>
- m.type === 'code' &&
- code.substring(m.offset, m.offset + m.length).includes('````')
+ const badSpan = matches.find(
+ m =>
+ m.type === 'code' &&
+ code.substring(m.offset, m.offset + m.length).includes('````')
);
assert.strictEqual(badSpan, undefined);
});
diff --git a/update-examples.js b/update-examples.js
index 958d94b..43ba5ee 100755
--- a/update-examples.js
+++ b/update-examples.js
@@ -1,7 +1,7 @@
#!/usr/bin/env node
-import { readFileSync, writeFileSync, readdirSync } from 'fs';
-import { join } from 'path';
+import {readFileSync, writeFileSync, readdirSync} from 'fs';
+import {join} from 'path';
const examplesDir = './examples';
const excludeFiles = new Set([
@@ -20,44 +20,44 @@ const excludeFiles = new Set([
// Language name mappings
const languageNames = {
- 'apache': 'Apache',
- 'applescript': 'AppleScript',
- 'assembly': 'Assembly',
- 'bash': 'Bash',
- 'basic': 'BASIC/VB',
- 'c': 'C/C++',
- 'clang': 'C/C++',
- 'csharp': 'C#',
- 'diff': 'Diff/Patch',
- 'go': 'Go',
- 'haskell': 'Haskell',
- 'io': 'Io',
- 'json': 'JSON',
- 'lisp': 'Lisp',
- 'lua': 'Lua',
- 'mixed': 'Mixed Languages',
- 'nginx': 'Nginx',
- 'ocaml': 'OCaml',
- 'pascal': 'Pascal',
- 'perl5': 'Perl 5',
- 'php': 'PHP',
+ apache: 'Apache',
+ applescript: 'AppleScript',
+ assembly: 'Assembly',
+ bash: 'Bash',
+ basic: 'BASIC/VB',
+ c: 'C/C++',
+ clang: 'C/C++',
+ csharp: 'C#',
+ diff: 'Diff/Patch',
+ go: 'Go',
+ haskell: 'Haskell',
+ io: 'Io',
+ json: 'JSON',
+ lisp: 'Lisp',
+ lua: 'Lua',
+ mixed: 'Mixed Languages',
+ nginx: 'Nginx',
+ ocaml: 'OCaml',
+ pascal: 'Pascal',
+ perl5: 'Perl 5',
+ php: 'PHP',
'php-script': 'PHP Script',
- 'plain': 'Plain Text',
- 'protobuf': 'Protocol Buffers',
- 'scala': 'Scala',
- 'smalltalk': 'Smalltalk',
- 'sql': 'SQL',
+ plain: 'Plain Text',
+ protobuf: 'Protocol Buffers',
+ scala: 'Scala',
+ smalltalk: 'Smalltalk',
+ sql: 'SQL',
'super-collider': 'SuperCollider',
- 'swift': 'Swift',
+ swift: 'Swift',
'wrap-demo': 'Wrap Demo',
- 'xrb': 'XRB',
- 'xml': 'XML',
- 'yaml': 'YAML'
+ xrb: 'XRB',
+ xml: 'XML',
+ yaml: 'YAML'
};
// Process each file
-const files = readdirSync(examplesDir).filter(f =>
- f.endsWith('.html') && !excludeFiles.has(f)
+const files = readdirSync(examplesDir).filter(
+ f => f.endsWith('.html') && !excludeFiles.has(f)
);
console.log(`Processing ${files.length} files...`);
@@ -65,18 +65,18 @@ console.log(`Processing ${files.length} files...`);
files.forEach(file => {
const filePath = join(examplesDir, file);
let content = readFileSync(filePath, 'utf8');
-
+
const baseName = file.replace('.html', '');
const langName = languageNames[baseName] || baseName;
-
+
// Check if already updated
if (content.includes('examples.css')) {
console.log(`✓ ${file} already updated`);
return;
}
-
+
console.log(`Updating ${file}...`);
-
+
// Replace with inline styles
content = content.replace(
/[\s\S]*?<\/head>/,
@@ -87,7 +87,7 @@ files.forEach(file => {
`
);
-
+
// Add header if not present
if (!content.includes('')) {
content = content.replace(
@@ -105,7 +105,7 @@ files.forEach(file => {
`
);
}
-
+
// Wrap examples in div.example if needed
if (!content.includes('class="example"')) {
// Simple wrapping for code blocks
@@ -127,7 +127,7 @@ files.forEach(file => {
'$1\n\t\n\t\n\t