Skip to content
Open
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
415 changes: 400 additions & 15 deletions examples/languages/test.css

Large diffs are not rendered by default.

105 changes: 73 additions & 32 deletions examples/languages/test.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,75 @@
/* Multiline FIX
Comment */
/**
* js doc CHANGED x
* @param {String} param
* @return nothing
*/
const listener = Deno.listen({ port: 8000 });
console.log(.8 * 0. * (0.8 * .e8) * 0.e8 * 0x849, 0d0101, 0o987, 8_987_654.1789)
console?.log(`http://localhost:${PORT}/`.match(/:[0-9]{2,4}^/g));
// TODO other comment
for await (const conn of listener) {
if (false)
break;
(async () => {
const requests = Deno.serveHttp(conn);
for await (const { respondWith } of this.requests.new) {
respondWith(new Response('Hello\
world'));
}
})();
}
function test(test) {
let test = () => { console.log(test) };
return test;
* DataProcessor v2.1.0
* Tests regex, private fields, async generators, and complex nesting.
*/
import { EventEmitter } from 'events';

const CONFIG_SYMBOL = Symbol('orchestrator_config');

export default class DataOrchestrator extends EventEmitter {
#internalState = 'idle'; // Private class field
static MAX_RETRIES = 3;

constructor(options = {}) {
super();
this[CONFIG_SYMBOL] = {
timeout: 5000,
...options
};
}

/**
* Processes an incoming data stream with a regex filter.
* @param {Array<string>} rawData
*/
async process(rawData) {
this.#internalState = 'processing';
const regex = /data-id_([0-9a-fA-F]{8})/gi; // Complex Regex

try {
const results = await Promise.all(
rawData.map(async (item, index) => {
// Template literal with nested expression
const logMsg = `Item #${index + 1}: ${item.toUpperCase()}`;

if (regex.test(item)) {
return { id: item.match(regex)[0], status: 'valid' };
}

return { id: null, status: 'invalid' };
})
);

this.emit('complete', {
timestamp: Date.now(),
count: results.length
});

} catch (error) {
console.error(`Error code: ${error.code ?? 'UNKNOWN_ERR'}`);
} finally {
this.#internalState = 'idle';
}
}

// Async Generator for memory-efficient streaming
async *streamResults(items) {
for (const item of items) {
yield new Promise(resolve =>
setTimeout(() => resolve(`Processed: ${item}`), 100)
);
}
}
}
export default {
jsonData: a > 5,
match: /test/g,
type: `test
${'test'}hello
${test + 2.5}hello`,
'Hello world': true
}

// Function demonstrating destructuring and default parameters
const init = ({ host = 'localhost', port = 8080 } = {}) => {
const orchestrator = new DataOrchestrator({ host });
console.log(`Server running at ${host}:${port}`);
return orchestrator;
};

/* Block comment test:
Math: 10 / 2 * (5 + 5)
*/
const instance = init();
18 changes: 16 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export async function highlightText(src, lang, multiline = true, opt = {}) {
await tokenize(src, lang, (str, type) => tmp += toSpan(sanitize(str), type))

return multiline
? `<div><div class="shj-numbers">${'<div></div>'.repeat(!opt.hideLineNumbers && src.split('\n').length)}</div><div>${tmp}</div></div>`
? `<div><div class="shj-numbers">${'<div></div>'.repeat(!opt.hideLineNumbers && (src.match(/\n/g) || []).length + 1)}</div><div>${tmp}</div></div>`
: tmp;
}

Expand All @@ -145,7 +145,7 @@ export async function highlightText(src, lang, multiline = true, opt = {}) {
*/
export async function highlightElement(elm, lang = elm.className.match(/shj-lang-([\w-]+)/)?.[1], mode, opt) {
let txt = elm.textContent;
mode ??= `${elm.tagName == 'CODE' ? 'in' : (txt.split('\n').length < 2 ? 'one' : 'multi')}line`;
mode ??= `${elm.tagName == 'CODE' ? 'in' : (txt.includes('\n') ? 'multi' : 'one')}line`;
elm.dataset.lang = lang;
elm.className = `${[...elm.classList].filter(className => !className.startsWith('shj-')).join(' ')} shj-lang-${lang} shj-${mode}`;
elm.innerHTML = await highlightText(txt, lang, mode == 'multiline', opt);
Expand Down Expand Up @@ -184,3 +184,17 @@ export let highlightAll = async (opt) =>
export let loadLanguage = (languageName, language) => {
langs[languageName] = language;
}

/**
* Pre-load one or more languages
*
* @async
* @function preLoadLanguage
* @param {...string} languageNames The names of the languages to load
* @returns {Promise<void>} A promise that resolves when all languages have been preloaded
*/
export let preLoadLanguage = async (...languageNames) => {
await Promise.all(
languageNames.map(lang => langs[lang] ? Promise.resolve() : import(`./languages/${lang}.js`).then(module => langs[lang] = module))
);
}
2 changes: 1 addition & 1 deletion src/languages/bash.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ export default [
match: /(?<=\s|^)[\w_]+(?=\s*=)/g
},
variable
]
]
60 changes: 32 additions & 28 deletions src/languages/css.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,60 @@
export default [
{
match: /\/\*((?!\*\/)[^])*(\*\/)?/g,
match: /\/\*[\s\S]*?\*\/|\/\/.*/g,
sub: 'todo'
},
{
expand: 'str'
},
{
match: /url\((?:(['"])(?:(?!\1).)*\1|[^)]*)\)/g,
sub: [
{ type: 'func', match: /^url/g },
{ type: 'str', match: /[^()]+/g }
]
},
{
type: 'type',
match: /@[\w-]+\b/g
},
{
type: 'kwd',
match: /@\w+\b|\b(and|not|only|or)\b|\b[a-z-]+(?=[^{}]*{)/g
match: /!important\b/g
},
{
type: 'var',
match: /\b[\w-]+(?=\s*:)|(::?|\.)[\w-]+(?=[^{}]*{)/g
match: /--[\w-]+/g
},
{
type: 'func',
match: /#[\w-]+(?=[^{}]*{)/g
type: 'var',
match: /(?<=^[\s\t]*|[;{(]\s*|\*\/[\s\n\r]*)[\w-]+(?=\s*(?::(?:\s|\n|$|(?=.*[;}]))|<=|>=|<|>|=))/gm
},
{
type: 'num',
match: /#[\da-f]{3,8}/g
match: /#[\da-fA-F]{3,8}\b/g
},
{
type: 'num',
match: /\d+(\.\d+)?(cm|mm|in|px|pt|pc|em|ex|ch|rem|vm|vh|vmin|vmax|%)?/g,
sub: [
{
type: 'var',
match: /[a-z]+|%/g
}
]
match: /-?(?:\d+\.?\d*|\.\d+)(?:(?:cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|deg|rad|grad|turn|s|ms|fr|dpi|dpcm|dppx|q|lh|rlh|vi|vb|cqw|cqh|cqi|cqb|cqmin|cqmax|dvw|dvh|lvw|lvh|svw|svh)\b|%(?!\w))/gi
},
{
match: /url\([^)]*\)/g,
sub: [
{
type: 'func',
match: /url(?=\()/g
},
{
type: 'str',
match: /[^()]+/g
}
]
type: 'num',
match: /-?(?:\d+\.?\d*|\.\d+)(?!\w)/g
},
{
type: 'func',
match: /\b[a-zA-Z]\w*(?=\s*\()/g
match: /[\w-]+(?=\()/g
},
{
type: 'num',
match: /\b[a-z-]+\b/g
type: 'bool',
match: /(?<!-)\b(in|from|to|at|vs|nearest|up|down|always|stable|both|none|auto|inherit|initial|unset|revert|normal|all|transparent|currentColor|true|false|block|inline|flex|grid|subgrid|contents|table|absolute|relative|fixed|sticky|static|left|right|top|bottom|center|middle|start|end|baseline|stretch|bold|bolder|lighter|italic|oblique|underline|overline|pre|nowrap|wrap|clip|ellipsis|solid|dashed|dotted|double|groove|ridge|inset|outset|hidden|and|not|only|or|cover|contain|x|y|scroll|visible|pointer|default|zoom|row|column|ease|linear|step|overlay|safe|unsafe|self|first|last|legacy|dense|min|max|fit|available|border|list|flow|ruby|separate|collapse|mix|multiply|screen|darken|lighten|difference|exclusion|hue|saturation|luminosity)(?:-[\w-]+)?\b/g
},
{
type: 'section',
match: /::?[\w-]+\b/g
},
{
type: 'type',
match: /(?:\.|#|::?)[\w-]+|(?<!@[\w-]+\s+)(?<![-\w:])\b[a-z][\w\d-]*(?=[^{};]*\{)|(?<=\b:[a-z-]+\()[a-z][\w\d-]*(?=[^)]*\))/gmi
}
]
]
90 changes: 85 additions & 5 deletions src/languages/html.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,83 @@
import xml, { properties, xmlElement } from './xml.js'
import xml, { name, properties, xmlElement } from './xml.js'

export const htmlElement = {
match: RegExp(`<[\/!?]?${name}${properties}[\/!?]?>`, 'g'),
sub: [
{
type: 'var',
match: RegExp(`^<[\/!?]?${name}`, 'g'),
sub: [
{
type: 'oper',
match: /^<[\/!?]?/g
}
]
},
{
match: /style\s*=\s*('[^']*'|"[^"]*")/gi,
sub: [
{
match: /^style\s*=\s*/gi,
sub: [
{
type: 'class',
match: /^style/gi
},
{
type: 'oper',
match: /=/g
}
]
},
{
match: /('[^']*'|"[^"]*")/g,
sub: [
{
type: 'str', // quotes
match: /^['"]|['"]$/g
},
{
match: /[^"']+/g,
sub: 'css'
}
]
}
]
},
{
match: /on\w+\s*=\s*('[^']*'|"[^"]*")/gi,
sub: [
{
match: /^on\w+\s*=\s*/gi,
sub: [
{
type: 'class',
match: /^on\w+/gi
},
{
type: 'oper',
match: /=/g
}
]
},
{
match: /('[^']*'|"[^"]*")/g,
sub: [
{
type: 'str', // quotes
match: /^['"]|['"]$/g
},
{
match: /[^"']+/g,
sub: 'js'
}
]
}
]
},
...xmlElement.sub
]
};

export default [
{
Expand All @@ -24,28 +103,29 @@ export default [
sub: [
{
match: RegExp(`^<style${properties}>`, 'g'),
sub: xmlElement.sub
sub: htmlElement.sub
},
{
match: RegExp(`${xmlElement.match}|[^]*(?=</style\\s*>$)`, 'g'),
sub: 'css'
},
xmlElement
htmlElement
]
},
{
match: RegExp(`<script${properties}>((?!</script>)[^])*</script\\s*>`, 'g'),
sub: [
{
match: RegExp(`^<script${properties}>`, 'g'),
sub: xmlElement.sub
sub: htmlElement.sub
},
{
match: RegExp(`${xmlElement.match}|[^]*(?=</script\\s*>$)`, 'g'),
sub: 'js'
},
xmlElement
htmlElement
]
},
htmlElement,
...xml
]
Loading