fractalpop 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/dist/core.d.ts +110 -0
  4. package/dist/core.js +313 -0
  5. package/dist/full.d.ts +1 -0
  6. package/dist/full.js +356 -0
  7. package/dist/gpu.d.ts +59 -0
  8. package/dist/gpu.js +215 -0
  9. package/dist/index.d.ts +108 -0
  10. package/dist/index.js +523 -0
  11. package/dist/lang/c.d.ts +5 -0
  12. package/dist/lang/c.js +90 -0
  13. package/dist/lang/cpp.d.ts +5 -0
  14. package/dist/lang/cpp.js +138 -0
  15. package/dist/lang/csharp.d.ts +5 -0
  16. package/dist/lang/csharp.js +148 -0
  17. package/dist/lang/css.d.ts +21 -0
  18. package/dist/lang/css.js +164 -0
  19. package/dist/lang/diff.d.ts +30 -0
  20. package/dist/lang/diff.js +18 -0
  21. package/dist/lang/dockerfile.d.ts +5 -0
  22. package/dist/lang/dockerfile.js +60 -0
  23. package/dist/lang/go.d.ts +5 -0
  24. package/dist/lang/go.js +91 -0
  25. package/dist/lang/graphql.d.ts +5 -0
  26. package/dist/lang/graphql.js +66 -0
  27. package/dist/lang/hcl.d.ts +5 -0
  28. package/dist/lang/hcl.js +51 -0
  29. package/dist/lang/html.d.ts +12 -0
  30. package/dist/lang/html.js +168 -0
  31. package/dist/lang/java.d.ts +5 -0
  32. package/dist/lang/java.js +96 -0
  33. package/dist/lang/javascript.d.ts +5 -0
  34. package/dist/lang/javascript.js +0 -0
  35. package/dist/lang/json.d.ts +5 -0
  36. package/dist/lang/json.js +47 -0
  37. package/dist/lang/kotlin.d.ts +5 -0
  38. package/dist/lang/kotlin.js +113 -0
  39. package/dist/lang/lua.d.ts +5 -0
  40. package/dist/lang/lua.js +65 -0
  41. package/dist/lang/markdown.d.ts +12 -0
  42. package/dist/lang/markdown.js +172 -0
  43. package/dist/lang/php.d.ts +5 -0
  44. package/dist/lang/php.js +129 -0
  45. package/dist/lang/plaintext.d.ts +7 -0
  46. package/dist/lang/plaintext.js +3 -0
  47. package/dist/lang/powershell.d.ts +5 -0
  48. package/dist/lang/powershell.js +74 -0
  49. package/dist/lang/python.d.ts +5 -0
  50. package/dist/lang/python.js +75 -0
  51. package/dist/lang/ruby.d.ts +5 -0
  52. package/dist/lang/ruby.js +84 -0
  53. package/dist/lang/rust.d.ts +5 -0
  54. package/dist/lang/rust.js +95 -0
  55. package/dist/lang/sass.d.ts +15 -0
  56. package/dist/lang/sass.js +201 -0
  57. package/dist/lang/scss.d.ts +14 -0
  58. package/dist/lang/scss.js +105 -0
  59. package/dist/lang/shell.d.ts +5 -0
  60. package/dist/lang/shell.js +64 -0
  61. package/dist/lang/sql.d.ts +5 -0
  62. package/dist/lang/sql.js +129 -0
  63. package/dist/lang/svelte.d.ts +15 -0
  64. package/dist/lang/svelte.js +0 -0
  65. package/dist/lang/swift.d.ts +5 -0
  66. package/dist/lang/swift.js +125 -0
  67. package/dist/lang/toml.d.ts +5 -0
  68. package/dist/lang/toml.js +45 -0
  69. package/dist/lang/typescript.d.ts +5 -0
  70. package/dist/lang/typescript.js +0 -0
  71. package/dist/lang/yaml.d.ts +5 -0
  72. package/dist/lang/yaml.js +64 -0
  73. package/dist/lang/zig.d.ts +5 -0
  74. package/dist/lang/zig.js +133 -0
  75. package/dist/lang.d.ts +30 -0
  76. package/dist/lang.js +345 -0
  77. package/package.json +68 -0
@@ -0,0 +1,84 @@
1
+ /** Reusable comment-scanner bases shared by keyword-based language presets. */ /** Build onCommentStart/onCommentEnd for a mix of line + block comment styles.
2
+ * Line comments open as type 1 and close at `\n`; block comments open as type 2
3
+ * and close at the terminator — so a single onCommentEnd serves both. */ function commentRules(style) {
4
+ const line = style.line ?? [];
5
+ const hasSlash = line.includes('//');
6
+ const hasHash = line.includes('#');
7
+ const hasDash = line.includes('--');
8
+ const block = style.block ?? false;
9
+ return {
10
+ onCommentStart (curr, next) {
11
+ if (block && curr === '/' && next === '*') return 2;
12
+ if (hasSlash && curr === '/' && next === '/') return 1;
13
+ if (hasHash && curr === '#') return 1;
14
+ if (hasDash && curr === '-' && next === '-') return 1;
15
+ return 0;
16
+ },
17
+ onCommentEnd (prev, curr) {
18
+ if (curr === '\n') return 1;
19
+ if (block && prev === '*' && curr === '/') return 2;
20
+ return 0;
21
+ }
22
+ };
23
+ }
24
+ /** Assemble a keyword-based language config over the shared general lexer. */ function keywordLang(spec) {
25
+ const config = {};
26
+ if (spec.keywords) config.keywords = new Set(spec.keywords);
27
+ if (spec.typeKeywords) config.typeKeywords = new Set(spec.typeKeywords);
28
+ if (spec.caseInsensitive) config.caseInsensitive = true;
29
+ if (spec.comments) Object.assign(config, commentRules(spec.comments));
30
+ return config;
31
+ }
32
+
33
+ const config = keywordLang({
34
+ keywords: [
35
+ "BEGIN",
36
+ "END",
37
+ "__ENCODING__",
38
+ "__FILE__",
39
+ "__LINE__",
40
+ "alias",
41
+ "and",
42
+ "begin",
43
+ "break",
44
+ "case",
45
+ "class",
46
+ "def",
47
+ "defined",
48
+ "do",
49
+ "else",
50
+ "elsif",
51
+ "end",
52
+ "ensure",
53
+ "false",
54
+ "for",
55
+ "if",
56
+ "in",
57
+ "module",
58
+ "next",
59
+ "nil",
60
+ "not",
61
+ "or",
62
+ "redo",
63
+ "rescue",
64
+ "retry",
65
+ "return",
66
+ "self",
67
+ "super",
68
+ "then",
69
+ "true",
70
+ "undef",
71
+ "unless",
72
+ "until",
73
+ "when",
74
+ "while",
75
+ "yield"
76
+ ],
77
+ comments: {
78
+ "line": [
79
+ "#"
80
+ ]
81
+ }
82
+ });
83
+
84
+ export { config };
@@ -0,0 +1,5 @@
1
+ import { ParseOptions } from '../core.js';
2
+
3
+ declare const config: ParseOptions;
4
+
5
+ export { config };
@@ -0,0 +1,95 @@
1
+ /** Reusable comment-scanner bases shared by keyword-based language presets. */ /** Build onCommentStart/onCommentEnd for a mix of line + block comment styles.
2
+ * Line comments open as type 1 and close at `\n`; block comments open as type 2
3
+ * and close at the terminator — so a single onCommentEnd serves both. */ function commentRules(style) {
4
+ const line = style.line ?? [];
5
+ const hasSlash = line.includes('//');
6
+ const hasHash = line.includes('#');
7
+ const hasDash = line.includes('--');
8
+ const block = style.block ?? false;
9
+ return {
10
+ onCommentStart (curr, next) {
11
+ if (block && curr === '/' && next === '*') return 2;
12
+ if (hasSlash && curr === '/' && next === '/') return 1;
13
+ if (hasHash && curr === '#') return 1;
14
+ if (hasDash && curr === '-' && next === '-') return 1;
15
+ return 0;
16
+ },
17
+ onCommentEnd (prev, curr) {
18
+ if (curr === '\n') return 1;
19
+ if (block && prev === '*' && curr === '/') return 2;
20
+ return 0;
21
+ }
22
+ };
23
+ }
24
+ /** Assemble a keyword-based language config over the shared general lexer. */ function keywordLang(spec) {
25
+ const config = {};
26
+ if (spec.keywords) config.keywords = new Set(spec.keywords);
27
+ if (spec.typeKeywords) config.typeKeywords = new Set(spec.typeKeywords);
28
+ if (spec.caseInsensitive) config.caseInsensitive = true;
29
+ if (spec.comments) Object.assign(config, commentRules(spec.comments));
30
+ return config;
31
+ }
32
+
33
+ const config = keywordLang({
34
+ keywords: [
35
+ "as",
36
+ "break",
37
+ "const",
38
+ "continue",
39
+ "crate",
40
+ "else",
41
+ "enum",
42
+ "extern",
43
+ "false",
44
+ "fn",
45
+ "for",
46
+ "if",
47
+ "impl",
48
+ "in",
49
+ "let",
50
+ "loop",
51
+ "match",
52
+ "mod",
53
+ "move",
54
+ "mut",
55
+ "pub",
56
+ "ref",
57
+ "return",
58
+ "self",
59
+ "Self",
60
+ "static",
61
+ "struct",
62
+ "super",
63
+ "trait",
64
+ "true",
65
+ "type",
66
+ "unsafe",
67
+ "use",
68
+ "where",
69
+ "while",
70
+ "async",
71
+ "await",
72
+ "dyn",
73
+ "abstract",
74
+ "become",
75
+ "box",
76
+ "do",
77
+ "final",
78
+ "macro",
79
+ "override",
80
+ "priv",
81
+ "typeof",
82
+ "unsized",
83
+ "virtual",
84
+ "yield",
85
+ "try"
86
+ ],
87
+ comments: {
88
+ "line": [
89
+ "//"
90
+ ],
91
+ "block": true
92
+ }
93
+ });
94
+
95
+ export { config };
@@ -0,0 +1,15 @@
1
+ import { ParseOptions } from '../core.js';
2
+
3
+ /** A lexer emits these: `[numericType, value]`. */
4
+ type Token = [number, string];
5
+
6
+ /** Indented pure Sass (.sass) — no braces, no semicolons; structure is indentation.
7
+ * A line-oriented tokenizer classifies each line from its indent + leading token,
8
+ * then lexes the content. The property/selector colon ambiguity is resolved by
9
+ * looking ahead at the next line's indent (a selector has deeper-indented children;
10
+ * a bare declaration does not). See SPEC §6. */
11
+
12
+ declare const tokenize: (code: string) => Token[];
13
+ declare const config: ParseOptions;
14
+
15
+ export { config, tokenize };
@@ -0,0 +1,201 @@
1
+ import { tokenize as tokenize$1 } from '../core.js';
2
+ import { onLiteral } from './css.js';
3
+
4
+ /**
5
+ * fractalpop core — token model, line assembly, and rendering.
6
+ *
7
+ * Design: tokens are numeric `[type, value]` pairs during lexing (fast Set/array
8
+ * work); the string type names are resolved only at render. Output is an HTML
9
+ * string with no DOM required — so SSR and client produce identical markup.
10
+ */ /** The stable, ordered token-type list. This list is the theming contract:
11
+ * each type maps to one CSS variable `--fp-<type>` and one class `fp__token--<type>`. */ const TokenTypes = [
12
+ 'identifier',
13
+ 'keyword',
14
+ 'string',
15
+ 'class',
16
+ 'property',
17
+ 'entity',
18
+ 'jsxliterals',
19
+ 'sign',
20
+ 'comment',
21
+ 'break',
22
+ 'space'
23
+ ];
24
+ // Numeric indices, used everywhere in the hot path.
25
+ const T_IDENTIFIER = 0;
26
+ const T_KEYWORD = 1;
27
+ const T_CLASS = 3;
28
+ const T_PROPERTY = 4;
29
+ const T_ENTITY = 5;
30
+ const T_SIGN = 7;
31
+ const T_COMMENT = 8;
32
+ const T_BREAK = 9;
33
+ const T_SPACE = 10;
34
+ ({
35
+ TokenMap: new Map(TokenTypes.map((type, index)=>[
36
+ type,
37
+ index
38
+ ]))
39
+ });
40
+
41
+ const isNameType = (type)=>type === T_IDENTIFIER || type === T_CLASS || type === T_PROPERTY;
42
+ function applySassSymbols(tokens) {
43
+ for(let i = 0; i < tokens.length; i++){
44
+ const token = tokens[i];
45
+ const [type, value] = token;
46
+ // $variable — the plain lexer already keeps `$name` as one word token.
47
+ if (isNameType(type) && value[0] === '$') {
48
+ token[0] = T_PROPERTY;
49
+ continue;
50
+ }
51
+ if (type === T_SIGN) {
52
+ const next = tokens[i + 1];
53
+ // @at-rule: merge '@' + word → keyword (@mixin, @include, @if, @use, …).
54
+ if (value === '@' && next && isNameType(next[0])) {
55
+ tokens.splice(i, 2, [
56
+ T_KEYWORD,
57
+ '@' + next[1]
58
+ ]);
59
+ continue;
60
+ }
61
+ // %placeholder selector: merge '%' + word → class.
62
+ if (value === '%' && next && isNameType(next[0])) {
63
+ tokens.splice(i, 2, [
64
+ T_CLASS,
65
+ '%' + next[1]
66
+ ]);
67
+ continue;
68
+ }
69
+ // !flag: merge '!' + word → keyword (!default, !global, !important, !optional).
70
+ if (value === '!' && next && isNameType(next[0])) {
71
+ tokens.splice(i, 2, [
72
+ T_KEYWORD,
73
+ '!' + next[1]
74
+ ]);
75
+ continue;
76
+ }
77
+ }
78
+ // function / mixin call: a name directly before '(' → entity.
79
+ if (isNameType(type) && value[0] !== '$') {
80
+ const next = tokens[i + 1];
81
+ if (next && next[0] === T_SIGN && next[1] === '(') token[0] = T_ENTITY;
82
+ }
83
+ }
84
+ }
85
+
86
+ const onCommentStart = (curr, next)=>curr === '/' && next === '*' ? 2 : curr === '/' && next === '/' ? 1 : 0;
87
+ const onCommentEnd = (prev, curr)=>curr === '\n' ? 1 : prev === '*' && curr === '/' ? 2 : 0;
88
+ /** Lex a run of inline Sass content (a value or a selector) and color its symbols. */ function lexInline(text) {
89
+ const tokens = tokenize$1(text, {
90
+ onCommentStart,
91
+ onCommentEnd,
92
+ onLiteral
93
+ });
94
+ applySassSymbols(tokens);
95
+ return tokens;
96
+ }
97
+ /** In a selector line, promote `.name` / `#name` to class coloring. */ function retagSelector(tokens) {
98
+ for(let i = 0; i < tokens.length; i++){
99
+ const [type, value] = tokens[i];
100
+ if (type === T_SIGN && (value === '.' || value === '#')) {
101
+ const next = tokens[i + 1];
102
+ if (next && next[0] !== T_SPACE && next[0] !== T_BREAK) next[0] = T_CLASS;
103
+ }
104
+ }
105
+ }
106
+ const leadingWhitespace = (line)=>line.match(/^[ \t]*/)?.[0] ?? '';
107
+ const tokenize = (code)=>{
108
+ const out = [];
109
+ const lines = code.split('\n');
110
+ // Indent length of each non-blank line (-1 for blank), for child lookahead.
111
+ const indents = lines.map((line)=>line.trim() === '' ? -1 : leadingWhitespace(line).length);
112
+ const hasChildren = (index)=>{
113
+ const own = indents[index];
114
+ for(let j = index + 1; j < lines.length; j++){
115
+ const next = indents[j];
116
+ if (next === -1) continue;
117
+ return next > own;
118
+ }
119
+ return false;
120
+ };
121
+ let inBlockComment = false;
122
+ for(let l = 0; l < lines.length; l++){
123
+ const line = lines[l];
124
+ const indent = leadingWhitespace(line);
125
+ const content = line.slice(indent.length);
126
+ if (indent) out.push([
127
+ T_SPACE,
128
+ indent
129
+ ]);
130
+ if (inBlockComment) {
131
+ out.push([
132
+ T_COMMENT,
133
+ content
134
+ ]);
135
+ if (content.includes('*/')) inBlockComment = false;
136
+ } else if (content === '') ; else if (content.startsWith('//')) {
137
+ out.push([
138
+ T_COMMENT,
139
+ content
140
+ ]);
141
+ } else if (content.startsWith('/*')) {
142
+ out.push([
143
+ T_COMMENT,
144
+ content
145
+ ]);
146
+ if (!content.includes('*/')) inBlockComment = true;
147
+ } else if (content[0] === '@') {
148
+ // at-rule / control directive — symbols handled by applySassSymbols.
149
+ out.push(...lexInline(content));
150
+ } else if (content[0] === '=' || content[0] === '+') {
151
+ // indented-syntax mixin define (=name) / include (+name).
152
+ out.push([
153
+ T_SIGN,
154
+ content[0]
155
+ ]);
156
+ const rest = content.slice(1);
157
+ const nameMatch = rest.match(/^[\w-]+/)?.[0];
158
+ if (nameMatch) {
159
+ out.push([
160
+ T_ENTITY,
161
+ nameMatch
162
+ ]);
163
+ out.push(...lexInline(rest.slice(nameMatch.length)));
164
+ } else {
165
+ out.push(...lexInline(rest));
166
+ }
167
+ } else {
168
+ const decl = content.match(/^(\$?[\w-]+)\s*:(.*)$/);
169
+ const isPseudoSelector = decl ? hasChildren(l) && /^\S/.test(decl[2]) : false;
170
+ if (decl && !isPseudoSelector) {
171
+ // declaration: `prop: value` or `$var: value`
172
+ const [, prop, rest] = decl;
173
+ out.push([
174
+ T_PROPERTY,
175
+ prop
176
+ ]);
177
+ const colonAt = content.indexOf(':', prop.length);
178
+ out.push([
179
+ T_SIGN,
180
+ ':'
181
+ ]);
182
+ out.push(...lexInline(content.slice(colonAt + 1)));
183
+ } else {
184
+ // selector line
185
+ const tokens = lexInline(content);
186
+ retagSelector(tokens);
187
+ out.push(...tokens);
188
+ }
189
+ }
190
+ if (l < lines.length - 1) out.push([
191
+ T_BREAK,
192
+ '\n'
193
+ ]);
194
+ }
195
+ return out;
196
+ };
197
+ const config = {
198
+ tokenize
199
+ };
200
+
201
+ export { config, tokenize };
@@ -0,0 +1,14 @@
1
+ import { ParseOptions } from '../core.js';
2
+
3
+ /** A lexer emits these: `[numericType, value]`. */
4
+ type Token = [number, string];
5
+
6
+ /** SCSS — CSS brace/semicolon structure plus Sass features ($vars, @rules, %placeholder,
7
+ * #{} interpolation, // line comments, math, !flags). Structure is CSS's; symbols are Sass's. */
8
+
9
+ declare const onCommentStart: (curr: string, next: string) => number;
10
+ declare const onCommentEnd: (prev: string, curr: string) => number;
11
+ declare const tokenize: (code: string, options?: ParseOptions) => Token[];
12
+ declare const config: ParseOptions;
13
+
14
+ export { config, onCommentEnd, onCommentStart, tokenize };
@@ -0,0 +1,105 @@
1
+ import { tokenize as tokenize$1 } from '../core.js';
2
+ import { onLiteral, mergeDashedNames, cssDeclarationPass } from './css.js';
3
+
4
+ /**
5
+ * fractalpop core — token model, line assembly, and rendering.
6
+ *
7
+ * Design: tokens are numeric `[type, value]` pairs during lexing (fast Set/array
8
+ * work); the string type names are resolved only at render. Output is an HTML
9
+ * string with no DOM required — so SSR and client produce identical markup.
10
+ */ /** The stable, ordered token-type list. This list is the theming contract:
11
+ * each type maps to one CSS variable `--fp-<type>` and one class `fp__token--<type>`. */ const TokenTypes = [
12
+ 'identifier',
13
+ 'keyword',
14
+ 'string',
15
+ 'class',
16
+ 'property',
17
+ 'entity',
18
+ 'jsxliterals',
19
+ 'sign',
20
+ 'comment',
21
+ 'break',
22
+ 'space'
23
+ ];
24
+ // Numeric indices, used everywhere in the hot path.
25
+ const T_IDENTIFIER = 0;
26
+ const T_KEYWORD = 1;
27
+ const T_CLASS = 3;
28
+ const T_PROPERTY = 4;
29
+ const T_ENTITY = 5;
30
+ const T_SIGN = 7;
31
+ ({
32
+ TokenMap: new Map(TokenTypes.map((type, index)=>[
33
+ type,
34
+ index
35
+ ]))
36
+ });
37
+
38
+ const isNameType = (type)=>type === T_IDENTIFIER || type === T_CLASS || type === T_PROPERTY;
39
+ function applySassSymbols(tokens) {
40
+ for(let i = 0; i < tokens.length; i++){
41
+ const token = tokens[i];
42
+ const [type, value] = token;
43
+ // $variable — the plain lexer already keeps `$name` as one word token.
44
+ if (isNameType(type) && value[0] === '$') {
45
+ token[0] = T_PROPERTY;
46
+ continue;
47
+ }
48
+ if (type === T_SIGN) {
49
+ const next = tokens[i + 1];
50
+ // @at-rule: merge '@' + word → keyword (@mixin, @include, @if, @use, …).
51
+ if (value === '@' && next && isNameType(next[0])) {
52
+ tokens.splice(i, 2, [
53
+ T_KEYWORD,
54
+ '@' + next[1]
55
+ ]);
56
+ continue;
57
+ }
58
+ // %placeholder selector: merge '%' + word → class.
59
+ if (value === '%' && next && isNameType(next[0])) {
60
+ tokens.splice(i, 2, [
61
+ T_CLASS,
62
+ '%' + next[1]
63
+ ]);
64
+ continue;
65
+ }
66
+ // !flag: merge '!' + word → keyword (!default, !global, !important, !optional).
67
+ if (value === '!' && next && isNameType(next[0])) {
68
+ tokens.splice(i, 2, [
69
+ T_KEYWORD,
70
+ '!' + next[1]
71
+ ]);
72
+ continue;
73
+ }
74
+ }
75
+ // function / mixin call: a name directly before '(' → entity.
76
+ if (isNameType(type) && value[0] !== '$') {
77
+ const next = tokens[i + 1];
78
+ if (next && next[0] === T_SIGN && next[1] === '(') token[0] = T_ENTITY;
79
+ }
80
+ }
81
+ }
82
+
83
+ const onCommentStart = (curr, next)=>curr === '/' && next === '*' ? 2 : curr === '/' && next === '/' ? 1 : 0;
84
+ const onCommentEnd = (prev, curr)=>curr === '\n' ? 1 : prev === '*' && curr === '/' ? 2 : 0;
85
+ const tokenize = (code, options)=>{
86
+ const tokens = tokenize$1(code, {
87
+ ...options,
88
+ tokenize: undefined,
89
+ onCommentStart,
90
+ onCommentEnd,
91
+ onLiteral
92
+ });
93
+ mergeDashedNames(tokens);
94
+ cssDeclarationPass(tokens);
95
+ applySassSymbols(tokens);
96
+ return tokens;
97
+ };
98
+ const config = {
99
+ onCommentStart,
100
+ onCommentEnd,
101
+ onLiteral,
102
+ tokenize
103
+ };
104
+
105
+ export { config, onCommentEnd, onCommentStart, tokenize };
@@ -0,0 +1,5 @@
1
+ import { ParseOptions } from '../core.js';
2
+
3
+ declare const config: ParseOptions;
4
+
5
+ export { config };
@@ -0,0 +1,64 @@
1
+ /** Reusable comment-scanner bases shared by keyword-based language presets. */ /** Build onCommentStart/onCommentEnd for a mix of line + block comment styles.
2
+ * Line comments open as type 1 and close at `\n`; block comments open as type 2
3
+ * and close at the terminator — so a single onCommentEnd serves both. */ function commentRules(style) {
4
+ const line = style.line ?? [];
5
+ const hasSlash = line.includes('//');
6
+ const hasHash = line.includes('#');
7
+ const hasDash = line.includes('--');
8
+ const block = style.block ?? false;
9
+ return {
10
+ onCommentStart (curr, next) {
11
+ if (block && curr === '/' && next === '*') return 2;
12
+ if (hasSlash && curr === '/' && next === '/') return 1;
13
+ if (hasHash && curr === '#') return 1;
14
+ if (hasDash && curr === '-' && next === '-') return 1;
15
+ return 0;
16
+ },
17
+ onCommentEnd (prev, curr) {
18
+ if (curr === '\n') return 1;
19
+ if (block && prev === '*' && curr === '/') return 2;
20
+ return 0;
21
+ }
22
+ };
23
+ }
24
+ /** Assemble a keyword-based language config over the shared general lexer. */ function keywordLang(spec) {
25
+ const config = {};
26
+ if (spec.keywords) config.keywords = new Set(spec.keywords);
27
+ if (spec.typeKeywords) config.typeKeywords = new Set(spec.typeKeywords);
28
+ if (spec.caseInsensitive) config.caseInsensitive = true;
29
+ if (spec.comments) Object.assign(config, commentRules(spec.comments));
30
+ return config;
31
+ }
32
+
33
+ const config = keywordLang({
34
+ keywords: [
35
+ "case",
36
+ "coproc",
37
+ "do",
38
+ "done",
39
+ "elif",
40
+ "else",
41
+ "esac",
42
+ "export",
43
+ "fi",
44
+ "for",
45
+ "function",
46
+ "if",
47
+ "in",
48
+ "local",
49
+ "readonly",
50
+ "return",
51
+ "select",
52
+ "then",
53
+ "time",
54
+ "until",
55
+ "while"
56
+ ],
57
+ comments: {
58
+ "line": [
59
+ "#"
60
+ ]
61
+ }
62
+ });
63
+
64
+ export { config };
@@ -0,0 +1,5 @@
1
+ import { ParseOptions } from '../core.js';
2
+
3
+ declare const config: ParseOptions;
4
+
5
+ export { config };