Skip to content
Merged
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
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true

[*.{js,json}]
indent_style = tab
indent_size = tab
tab_width = 4
trim_trailing_whitespace = true
25 changes: 25 additions & 0 deletions .github/workflows/eslint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: ESLint

on: [push, pull_request]

permissions:
contents: read

jobs:
check:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v7

- uses: actions/setup-node@v7
with:
node-version: "24"
cache: npm

- name: Install dependencies
run: npm ci

- name: Run ESLint
timeout-minutes: 5
run: npm run format:check
9 changes: 0 additions & 9 deletions .prettierrc.json

This file was deleted.

4 changes: 2 additions & 2 deletions Syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
16 changes: 8 additions & 8 deletions Syntax/CodeElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -150,26 +150,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;
}

Expand All @@ -180,7 +180,7 @@ export class CodeElement extends HTMLElement {
get highlighted() {
return this.#highlighted;
}

connectedCallback() {
// Detect if we're inside a <pre> element and set wrap attribute
if (this.parentElement?.tagName === 'PRE') {
Expand Down
10 changes: 5 additions & 5 deletions Syntax/Rule.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,14 @@ export class Rule {
* Create a conditional matcher that selects a rule based on another capture group.
* Tests a condition capture group against patterns to determine which rule to apply
* to a content capture group.
*
*
* @param {number} conditionIndex - Capture group index to test against patterns
* @param {number} contentIndex - Capture group index containing content to match
* @param {Array<{pattern?: RegExp, ...rule}>} conditions - Array of condition objects. Each can have:
* - pattern: RegExp to test against the condition group (optional - if omitted, acts as fallback)
* - Any rule properties (language, type, etc.) to apply when pattern matches
* @returns {Function} A matches function for use in language rules
*
*
* @example
* // Script tags with type-based language selection
* language.push({
Expand All @@ -152,7 +152,7 @@ export class Rule {
* {language: 'javascript'} // Fallback for no type or unknown types
* ])
* });
*
*
* @example
* // Code fence with language specifier
* language.push({
Expand All @@ -163,7 +163,7 @@ export class Rule {
* {language: 'plaintext'} // Fallback
* ])
* });
*
*
* @example
* // Conditional type based on prefix
* language.push({
Expand Down Expand Up @@ -201,7 +201,7 @@ export class Rule {

// Build syntax tree or create match based on rule properties
const offset = match.index + match[0].indexOf(content);

if (ruleProps.language) {
return [
await Language.buildTree(
Expand Down
14 changes: 7 additions & 7 deletions bin/syntax-ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import Syntax from '../Syntax.js';

async function main() {
const args = process.argv.slice(2);

if (args.length < 2) {
console.error('Usage: syntax-ast <language> <code>');
console.error('Example: syntax-ast javascript "const x = 1;"');
process.exit(1);
}

const [languageName, code] = args;

const syntax = new Syntax();

try {
const language = await syntax.getLanguage(languageName);
const matches = await language.getMatches(syntax, code);

console.log('Language:', languageName);
console.log('Code:', JSON.stringify(code));
console.log('\nMatches:', matches.length);
console.log('─'.repeat(80));

for (const match of matches) {
const text = code.substring(match.offset, match.offset + match.length);
console.log(`[${match.type}] @${match.offset}..${match.offset + match.length} (${match.length} chars)`);
Expand All @@ -32,7 +32,7 @@ async function main() {
console.log(` Children: ${match.children.length}`);
}
}

} catch (error) {
console.error('Error:', error.message);
process.exit(1);
Expand Down
44 changes: 44 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import stylistic from '@stylistic/eslint-plugin';

export default [
{
plugins: {
'@stylistic': stylistic
},
rules: {
'@stylistic/array-bracket-spacing': ['error', 'never'],
'@stylistic/arrow-parens': ['error', 'as-needed'],
'@stylistic/arrow-spacing': 'error',
'@stylistic/block-spacing': ['error', 'always'],
'@stylistic/brace-style': [
'error',
'1tbs',
{allowSingleLine: true}
],
'@stylistic/comma-dangle': ['error', 'never'],
'@stylistic/comma-spacing': 'error',
'@stylistic/computed-property-spacing': ['error', 'never'],
'@stylistic/eol-last': ['error', 'always'],
'@stylistic/function-call-spacing': ['error', 'never'],
'@stylistic/indent': ['error', 'tab', {SwitchCase: 1}],
'@stylistic/key-spacing': 'error',
'@stylistic/keyword-spacing': 'error',
'@stylistic/no-mixed-spaces-and-tabs': 'error',
'@stylistic/no-trailing-spaces': 'error',
'@stylistic/object-curly-spacing': ['error', 'never'],
'@stylistic/quotes': ['error', 'single', {avoidEscape: true}],
'@stylistic/rest-spread-spacing': ['error', 'never'],
'@stylistic/semi': ['error', 'always'],
'@stylistic/semi-spacing': 'error',
'@stylistic/space-before-blocks': 'error',
'@stylistic/space-before-function-paren': [
'error',
{anonymous: 'always', asyncArrow: 'always', named: 'never'}
],
'@stylistic/space-in-parens': ['error', 'never'],
'@stylistic/space-infix-ops': 'error',
'@stylistic/space-unary-ops': 'error',
'@stylistic/template-curly-spacing': ['error', 'never']
}
}
];
Loading