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.
- package/LICENSE +21 -0
- package/README.md +232 -0
- package/dist/core.d.ts +110 -0
- package/dist/core.js +313 -0
- package/dist/full.d.ts +1 -0
- package/dist/full.js +356 -0
- package/dist/gpu.d.ts +59 -0
- package/dist/gpu.js +215 -0
- package/dist/index.d.ts +108 -0
- package/dist/index.js +523 -0
- package/dist/lang/c.d.ts +5 -0
- package/dist/lang/c.js +90 -0
- package/dist/lang/cpp.d.ts +5 -0
- package/dist/lang/cpp.js +138 -0
- package/dist/lang/csharp.d.ts +5 -0
- package/dist/lang/csharp.js +148 -0
- package/dist/lang/css.d.ts +21 -0
- package/dist/lang/css.js +164 -0
- package/dist/lang/diff.d.ts +30 -0
- package/dist/lang/diff.js +18 -0
- package/dist/lang/dockerfile.d.ts +5 -0
- package/dist/lang/dockerfile.js +60 -0
- package/dist/lang/go.d.ts +5 -0
- package/dist/lang/go.js +91 -0
- package/dist/lang/graphql.d.ts +5 -0
- package/dist/lang/graphql.js +66 -0
- package/dist/lang/hcl.d.ts +5 -0
- package/dist/lang/hcl.js +51 -0
- package/dist/lang/html.d.ts +12 -0
- package/dist/lang/html.js +168 -0
- package/dist/lang/java.d.ts +5 -0
- package/dist/lang/java.js +96 -0
- package/dist/lang/javascript.d.ts +5 -0
- package/dist/lang/javascript.js +0 -0
- package/dist/lang/json.d.ts +5 -0
- package/dist/lang/json.js +47 -0
- package/dist/lang/kotlin.d.ts +5 -0
- package/dist/lang/kotlin.js +113 -0
- package/dist/lang/lua.d.ts +5 -0
- package/dist/lang/lua.js +65 -0
- package/dist/lang/markdown.d.ts +12 -0
- package/dist/lang/markdown.js +172 -0
- package/dist/lang/php.d.ts +5 -0
- package/dist/lang/php.js +129 -0
- package/dist/lang/plaintext.d.ts +7 -0
- package/dist/lang/plaintext.js +3 -0
- package/dist/lang/powershell.d.ts +5 -0
- package/dist/lang/powershell.js +74 -0
- package/dist/lang/python.d.ts +5 -0
- package/dist/lang/python.js +75 -0
- package/dist/lang/ruby.d.ts +5 -0
- package/dist/lang/ruby.js +84 -0
- package/dist/lang/rust.d.ts +5 -0
- package/dist/lang/rust.js +95 -0
- package/dist/lang/sass.d.ts +15 -0
- package/dist/lang/sass.js +201 -0
- package/dist/lang/scss.d.ts +14 -0
- package/dist/lang/scss.js +105 -0
- package/dist/lang/shell.d.ts +5 -0
- package/dist/lang/shell.js +64 -0
- package/dist/lang/sql.d.ts +5 -0
- package/dist/lang/sql.js +129 -0
- package/dist/lang/svelte.d.ts +15 -0
- package/dist/lang/svelte.js +0 -0
- package/dist/lang/swift.d.ts +5 -0
- package/dist/lang/swift.js +125 -0
- package/dist/lang/toml.d.ts +5 -0
- package/dist/lang/toml.js +45 -0
- package/dist/lang/typescript.d.ts +5 -0
- package/dist/lang/typescript.js +0 -0
- package/dist/lang/yaml.d.ts +5 -0
- package/dist/lang/yaml.js +64 -0
- package/dist/lang/zig.d.ts +5 -0
- package/dist/lang/zig.js +133 -0
- package/dist/lang.d.ts +30 -0
- package/dist/lang.js +345 -0
- package/package.json +68 -0
package/dist/lang/c.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
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
|
+
"auto",
|
|
36
|
+
"break",
|
|
37
|
+
"case",
|
|
38
|
+
"const",
|
|
39
|
+
"continue",
|
|
40
|
+
"default",
|
|
41
|
+
"do",
|
|
42
|
+
"else",
|
|
43
|
+
"enum",
|
|
44
|
+
"extern",
|
|
45
|
+
"for",
|
|
46
|
+
"goto",
|
|
47
|
+
"if",
|
|
48
|
+
"inline",
|
|
49
|
+
"register",
|
|
50
|
+
"restrict",
|
|
51
|
+
"return",
|
|
52
|
+
"sizeof",
|
|
53
|
+
"static",
|
|
54
|
+
"struct",
|
|
55
|
+
"switch",
|
|
56
|
+
"typedef",
|
|
57
|
+
"union",
|
|
58
|
+
"volatile",
|
|
59
|
+
"while",
|
|
60
|
+
"_Alignas",
|
|
61
|
+
"_Alignof",
|
|
62
|
+
"_Atomic",
|
|
63
|
+
"_Generic",
|
|
64
|
+
"_Noreturn",
|
|
65
|
+
"_Static_assert",
|
|
66
|
+
"_Thread_local"
|
|
67
|
+
],
|
|
68
|
+
typeKeywords: [
|
|
69
|
+
"void",
|
|
70
|
+
"char",
|
|
71
|
+
"short",
|
|
72
|
+
"int",
|
|
73
|
+
"long",
|
|
74
|
+
"float",
|
|
75
|
+
"double",
|
|
76
|
+
"signed",
|
|
77
|
+
"unsigned",
|
|
78
|
+
"_Bool",
|
|
79
|
+
"_Complex",
|
|
80
|
+
"_Imaginary"
|
|
81
|
+
],
|
|
82
|
+
comments: {
|
|
83
|
+
"line": [
|
|
84
|
+
"//"
|
|
85
|
+
],
|
|
86
|
+
"block": true
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export { config };
|
package/dist/lang/cpp.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
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
|
+
"alignas",
|
|
36
|
+
"alignof",
|
|
37
|
+
"and",
|
|
38
|
+
"and_eq",
|
|
39
|
+
"asm",
|
|
40
|
+
"auto",
|
|
41
|
+
"bitand",
|
|
42
|
+
"bitor",
|
|
43
|
+
"break",
|
|
44
|
+
"case",
|
|
45
|
+
"catch",
|
|
46
|
+
"class",
|
|
47
|
+
"compl",
|
|
48
|
+
"concept",
|
|
49
|
+
"const",
|
|
50
|
+
"consteval",
|
|
51
|
+
"constexpr",
|
|
52
|
+
"constinit",
|
|
53
|
+
"const_cast",
|
|
54
|
+
"continue",
|
|
55
|
+
"co_await",
|
|
56
|
+
"co_return",
|
|
57
|
+
"co_yield",
|
|
58
|
+
"decltype",
|
|
59
|
+
"default",
|
|
60
|
+
"delete",
|
|
61
|
+
"do",
|
|
62
|
+
"dynamic_cast",
|
|
63
|
+
"else",
|
|
64
|
+
"enum",
|
|
65
|
+
"explicit",
|
|
66
|
+
"export",
|
|
67
|
+
"extern",
|
|
68
|
+
"false",
|
|
69
|
+
"for",
|
|
70
|
+
"friend",
|
|
71
|
+
"goto",
|
|
72
|
+
"if",
|
|
73
|
+
"inline",
|
|
74
|
+
"mutable",
|
|
75
|
+
"namespace",
|
|
76
|
+
"new",
|
|
77
|
+
"noexcept",
|
|
78
|
+
"not",
|
|
79
|
+
"not_eq",
|
|
80
|
+
"nullptr",
|
|
81
|
+
"operator",
|
|
82
|
+
"or",
|
|
83
|
+
"or_eq",
|
|
84
|
+
"private",
|
|
85
|
+
"protected",
|
|
86
|
+
"public",
|
|
87
|
+
"register",
|
|
88
|
+
"reinterpret_cast",
|
|
89
|
+
"requires",
|
|
90
|
+
"return",
|
|
91
|
+
"sizeof",
|
|
92
|
+
"static",
|
|
93
|
+
"static_assert",
|
|
94
|
+
"static_cast",
|
|
95
|
+
"struct",
|
|
96
|
+
"switch",
|
|
97
|
+
"template",
|
|
98
|
+
"this",
|
|
99
|
+
"thread_local",
|
|
100
|
+
"throw",
|
|
101
|
+
"true",
|
|
102
|
+
"try",
|
|
103
|
+
"typedef",
|
|
104
|
+
"typeid",
|
|
105
|
+
"typename",
|
|
106
|
+
"union",
|
|
107
|
+
"using",
|
|
108
|
+
"virtual",
|
|
109
|
+
"volatile",
|
|
110
|
+
"while",
|
|
111
|
+
"xor",
|
|
112
|
+
"xor_eq"
|
|
113
|
+
],
|
|
114
|
+
typeKeywords: [
|
|
115
|
+
"bool",
|
|
116
|
+
"char",
|
|
117
|
+
"char8_t",
|
|
118
|
+
"char16_t",
|
|
119
|
+
"char32_t",
|
|
120
|
+
"double",
|
|
121
|
+
"float",
|
|
122
|
+
"int",
|
|
123
|
+
"long",
|
|
124
|
+
"short",
|
|
125
|
+
"signed",
|
|
126
|
+
"unsigned",
|
|
127
|
+
"void",
|
|
128
|
+
"wchar_t"
|
|
129
|
+
],
|
|
130
|
+
comments: {
|
|
131
|
+
"line": [
|
|
132
|
+
"//"
|
|
133
|
+
],
|
|
134
|
+
"block": true
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export { config };
|
|
@@ -0,0 +1,148 @@
|
|
|
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
|
+
"abstract",
|
|
36
|
+
"as",
|
|
37
|
+
"async",
|
|
38
|
+
"await",
|
|
39
|
+
"base",
|
|
40
|
+
"break",
|
|
41
|
+
"case",
|
|
42
|
+
"catch",
|
|
43
|
+
"checked",
|
|
44
|
+
"class",
|
|
45
|
+
"const",
|
|
46
|
+
"continue",
|
|
47
|
+
"default",
|
|
48
|
+
"delegate",
|
|
49
|
+
"do",
|
|
50
|
+
"else",
|
|
51
|
+
"enum",
|
|
52
|
+
"event",
|
|
53
|
+
"explicit",
|
|
54
|
+
"extern",
|
|
55
|
+
"false",
|
|
56
|
+
"finally",
|
|
57
|
+
"fixed",
|
|
58
|
+
"for",
|
|
59
|
+
"foreach",
|
|
60
|
+
"from",
|
|
61
|
+
"get",
|
|
62
|
+
"global",
|
|
63
|
+
"goto",
|
|
64
|
+
"if",
|
|
65
|
+
"implicit",
|
|
66
|
+
"in",
|
|
67
|
+
"init",
|
|
68
|
+
"interface",
|
|
69
|
+
"internal",
|
|
70
|
+
"into",
|
|
71
|
+
"is",
|
|
72
|
+
"join",
|
|
73
|
+
"let",
|
|
74
|
+
"lock",
|
|
75
|
+
"namespace",
|
|
76
|
+
"new",
|
|
77
|
+
"null",
|
|
78
|
+
"on",
|
|
79
|
+
"operator",
|
|
80
|
+
"orderby",
|
|
81
|
+
"out",
|
|
82
|
+
"override",
|
|
83
|
+
"params",
|
|
84
|
+
"partial",
|
|
85
|
+
"private",
|
|
86
|
+
"protected",
|
|
87
|
+
"public",
|
|
88
|
+
"readonly",
|
|
89
|
+
"record",
|
|
90
|
+
"ref",
|
|
91
|
+
"remove",
|
|
92
|
+
"required",
|
|
93
|
+
"return",
|
|
94
|
+
"sealed",
|
|
95
|
+
"select",
|
|
96
|
+
"set",
|
|
97
|
+
"sizeof",
|
|
98
|
+
"stackalloc",
|
|
99
|
+
"static",
|
|
100
|
+
"struct",
|
|
101
|
+
"switch",
|
|
102
|
+
"this",
|
|
103
|
+
"throw",
|
|
104
|
+
"true",
|
|
105
|
+
"try",
|
|
106
|
+
"typeof",
|
|
107
|
+
"unchecked",
|
|
108
|
+
"unsafe",
|
|
109
|
+
"using",
|
|
110
|
+
"value",
|
|
111
|
+
"virtual",
|
|
112
|
+
"volatile",
|
|
113
|
+
"when",
|
|
114
|
+
"where",
|
|
115
|
+
"while",
|
|
116
|
+
"with",
|
|
117
|
+
"yield"
|
|
118
|
+
],
|
|
119
|
+
typeKeywords: [
|
|
120
|
+
"bool",
|
|
121
|
+
"byte",
|
|
122
|
+
"char",
|
|
123
|
+
"decimal",
|
|
124
|
+
"double",
|
|
125
|
+
"dynamic",
|
|
126
|
+
"float",
|
|
127
|
+
"int",
|
|
128
|
+
"long",
|
|
129
|
+
"nint",
|
|
130
|
+
"nuint",
|
|
131
|
+
"object",
|
|
132
|
+
"sbyte",
|
|
133
|
+
"short",
|
|
134
|
+
"string",
|
|
135
|
+
"uint",
|
|
136
|
+
"ulong",
|
|
137
|
+
"ushort",
|
|
138
|
+
"void"
|
|
139
|
+
],
|
|
140
|
+
comments: {
|
|
141
|
+
"line": [
|
|
142
|
+
"//"
|
|
143
|
+
],
|
|
144
|
+
"block": true
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
export { config };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ParseOptions } from '../core.js';
|
|
2
|
+
|
|
3
|
+
/** A lexer emits these: `[numericType, value]`. */
|
|
4
|
+
type Token = [number, string];
|
|
5
|
+
|
|
6
|
+
/** CSS preset. Runs the plain lexer, then post-processes to mark declarations
|
|
7
|
+
* (property before a `:` inside a block) and rejoin `--dashed-names`. */
|
|
8
|
+
|
|
9
|
+
declare const keywords: Set<string>;
|
|
10
|
+
declare const onCommentStart: (curr: string, next: string) => number;
|
|
11
|
+
declare const onCommentEnd: (prev: string, curr: string) => number;
|
|
12
|
+
declare const onLiteral: (curr: string, index: number, code: string) => number;
|
|
13
|
+
/** Rejoin CSS dashed identifiers split by the shared punctuation lexer. */
|
|
14
|
+
declare const mergeDashedNames: (tokens: Token[]) => void;
|
|
15
|
+
/** Mark `property:` declarations inside brace blocks. Shared with SCSS. */
|
|
16
|
+
declare const cssDeclarationPass: (tokens: Token[]) => void;
|
|
17
|
+
/** Add CSS declaration context after the shared plain lexer runs. */
|
|
18
|
+
declare const tokenize: (code: string, options?: ParseOptions) => Token[];
|
|
19
|
+
declare const config: ParseOptions;
|
|
20
|
+
|
|
21
|
+
export { config, cssDeclarationPass, keywords, mergeDashedNames, onCommentEnd, onCommentStart, onLiteral, tokenize };
|
package/dist/lang/css.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { tokenize as tokenize$1 } from '../core.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* fractalpop core — token model, line assembly, and rendering.
|
|
5
|
+
*
|
|
6
|
+
* Design: tokens are numeric `[type, value]` pairs during lexing (fast Set/array
|
|
7
|
+
* work); the string type names are resolved only at render. Output is an HTML
|
|
8
|
+
* string with no DOM required — so SSR and client produce identical markup.
|
|
9
|
+
*/ /** The stable, ordered token-type list. This list is the theming contract:
|
|
10
|
+
* each type maps to one CSS variable `--fp-<type>` and one class `fp__token--<type>`. */ const TokenTypes = [
|
|
11
|
+
'identifier',
|
|
12
|
+
'keyword',
|
|
13
|
+
'string',
|
|
14
|
+
'class',
|
|
15
|
+
'property',
|
|
16
|
+
'entity',
|
|
17
|
+
'jsxliterals',
|
|
18
|
+
'sign',
|
|
19
|
+
'comment',
|
|
20
|
+
'break',
|
|
21
|
+
'space'
|
|
22
|
+
];
|
|
23
|
+
// Numeric indices, used everywhere in the hot path.
|
|
24
|
+
const T_IDENTIFIER = 0;
|
|
25
|
+
const T_CLASS = 3;
|
|
26
|
+
const T_PROPERTY = 4;
|
|
27
|
+
const T_SIGN = 7;
|
|
28
|
+
const T_COMMENT = 8;
|
|
29
|
+
const T_BREAK = 9;
|
|
30
|
+
const T_SPACE = 10;
|
|
31
|
+
({
|
|
32
|
+
TokenMap: new Map(TokenTypes.map((type, index)=>[
|
|
33
|
+
type,
|
|
34
|
+
index
|
|
35
|
+
]))
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const keywords = new Set([
|
|
39
|
+
'@media',
|
|
40
|
+
'@import',
|
|
41
|
+
'@keyframes',
|
|
42
|
+
'@font-face',
|
|
43
|
+
'@supports',
|
|
44
|
+
'@page',
|
|
45
|
+
'@counter-style',
|
|
46
|
+
'@font-feature-values',
|
|
47
|
+
'@viewport',
|
|
48
|
+
'@document',
|
|
49
|
+
'@namespace',
|
|
50
|
+
'@charset',
|
|
51
|
+
'@layer',
|
|
52
|
+
'@container'
|
|
53
|
+
]);
|
|
54
|
+
const onCommentStart = (curr, next)=>curr + next === '/*' ? 1 : 0;
|
|
55
|
+
const onCommentEnd = (prev, curr)=>prev + curr === '*/' ? 1 : 0;
|
|
56
|
+
const onLiteral = (curr, index, code)=>{
|
|
57
|
+
if (curr !== '#') return 0;
|
|
58
|
+
return code.slice(index).match(/^#(?:[\da-f]{8}|[\da-f]{6}|[\da-f]{4}|[\da-f]{3})(?![\w-])/i)?.[0].length || 0;
|
|
59
|
+
};
|
|
60
|
+
const isIgnored = (type)=>type === T_SPACE || type === T_BREAK || type === T_COMMENT;
|
|
61
|
+
const isPropertyPart = ([type, value])=>type === T_IDENTIFIER || type === T_CLASS || type === T_SIGN && value === '-';
|
|
62
|
+
const isNamePart = ([type])=>type === T_IDENTIFIER || type === T_CLASS || type === T_PROPERTY;
|
|
63
|
+
const isNameStart = (token)=>isNamePart(token) && !/^\d/.test(token[1]);
|
|
64
|
+
const isHyphen = ([type, value])=>type === T_SIGN && value === '-';
|
|
65
|
+
/** Rejoin CSS dashed identifiers split by the shared punctuation lexer. */ const mergeDashedNames = (tokens)=>{
|
|
66
|
+
for(let index = 0; index < tokens.length; index++){
|
|
67
|
+
let firstWord = index;
|
|
68
|
+
let end = index;
|
|
69
|
+
if (isHyphen(tokens[end])) {
|
|
70
|
+
while(tokens[end] && isHyphen(tokens[end]))end++;
|
|
71
|
+
if (!tokens[end] || !isNameStart(tokens[end])) continue;
|
|
72
|
+
firstWord = end++;
|
|
73
|
+
} else if (isNameStart(tokens[end])) {
|
|
74
|
+
end++;
|
|
75
|
+
} else {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
let dashed = firstWord > index;
|
|
79
|
+
while(tokens[end] && isHyphen(tokens[end])){
|
|
80
|
+
const hyphenStart = end;
|
|
81
|
+
while(tokens[end] && isHyphen(tokens[end]))end++;
|
|
82
|
+
if (!tokens[end] || !isNamePart(tokens[end])) {
|
|
83
|
+
end = hyphenStart;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
dashed = true;
|
|
87
|
+
end++;
|
|
88
|
+
}
|
|
89
|
+
if (!dashed) continue;
|
|
90
|
+
const name = tokens.slice(index, end).map(([, value])=>value).join('');
|
|
91
|
+
tokens.splice(index, end - index, [
|
|
92
|
+
tokens[firstWord][0],
|
|
93
|
+
name
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
/** True when a colon opens a nested block (selector) rather than a declaration. */ const opensBlock = (tokens, start)=>{
|
|
98
|
+
let parentheses = 0;
|
|
99
|
+
let brackets = 0;
|
|
100
|
+
for(let index = start; index < tokens.length; index++){
|
|
101
|
+
const [type, value] = tokens[index];
|
|
102
|
+
if (type !== T_SIGN) continue;
|
|
103
|
+
if (value === '(') parentheses++;
|
|
104
|
+
else if (value === ')') parentheses--;
|
|
105
|
+
else if (value === '[') brackets++;
|
|
106
|
+
else if (value === ']') brackets--;
|
|
107
|
+
else if (!parentheses && !brackets && value === '{') return true;
|
|
108
|
+
else if (!parentheses && !brackets && (value === ';' || value === '}')) return false;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
};
|
|
112
|
+
/** Mark `property:` declarations inside brace blocks. Shared with SCSS. */ const cssDeclarationPass = (tokens)=>{
|
|
113
|
+
let blockDepth = 0;
|
|
114
|
+
let declarationStart = false;
|
|
115
|
+
for(let index = 0; index < tokens.length; index++){
|
|
116
|
+
const [type, value] = tokens[index];
|
|
117
|
+
if (type === T_SIGN && value === '{') {
|
|
118
|
+
blockDepth++;
|
|
119
|
+
declarationStart = true;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (type === T_SIGN && value === '}') {
|
|
123
|
+
blockDepth--;
|
|
124
|
+
declarationStart = false;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (type === T_SIGN && value === ';') {
|
|
128
|
+
declarationStart = blockDepth > 0;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (!declarationStart || isIgnored(type)) continue;
|
|
132
|
+
const propertyStart = index;
|
|
133
|
+
let propertyEnd = index;
|
|
134
|
+
while(propertyEnd < tokens.length && isPropertyPart(tokens[propertyEnd]))propertyEnd++;
|
|
135
|
+
let colon = propertyEnd;
|
|
136
|
+
while(colon < tokens.length && isIgnored(tokens[colon][0]))colon++;
|
|
137
|
+
if (propertyEnd > propertyStart && tokens[colon]?.[0] === T_SIGN && tokens[colon][1] === ':' && !opensBlock(tokens, colon + 1)) {
|
|
138
|
+
const property = tokens.slice(propertyStart, propertyEnd).map(([, part])=>part).join('');
|
|
139
|
+
tokens.splice(propertyStart, propertyEnd - propertyStart, [
|
|
140
|
+
T_PROPERTY,
|
|
141
|
+
property
|
|
142
|
+
]);
|
|
143
|
+
}
|
|
144
|
+
declarationStart = false;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
/** Add CSS declaration context after the shared plain lexer runs. */ const tokenize = (code, options)=>{
|
|
148
|
+
const tokens = tokenize$1(code, {
|
|
149
|
+
...options,
|
|
150
|
+
tokenize: undefined
|
|
151
|
+
});
|
|
152
|
+
mergeDashedNames(tokens);
|
|
153
|
+
cssDeclarationPass(tokens);
|
|
154
|
+
return tokens;
|
|
155
|
+
};
|
|
156
|
+
const config = {
|
|
157
|
+
keywords,
|
|
158
|
+
onCommentStart,
|
|
159
|
+
onCommentEnd,
|
|
160
|
+
onLiteral,
|
|
161
|
+
tokenize
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export { config, cssDeclarationPass, keywords, mergeDashedNames, onCommentEnd, onCommentStart, onLiteral, tokenize };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ParseOptions } from '../core.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* fractalpop core — token model, line assembly, and rendering.
|
|
5
|
+
*
|
|
6
|
+
* Design: tokens are numeric `[type, value]` pairs during lexing (fast Set/array
|
|
7
|
+
* work); the string type names are resolved only at render. Output is an HTML
|
|
8
|
+
* string with no DOM required — so SSR and client produce identical markup.
|
|
9
|
+
*/
|
|
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>`. */
|
|
12
|
+
declare const TokenTypes: readonly ["identifier", "keyword", "string", "class", "property", "entity", "jsxliterals", "sign", "comment", "break", "space"];
|
|
13
|
+
type TokenType = (typeof TokenTypes)[number];
|
|
14
|
+
interface ParsedToken {
|
|
15
|
+
type: TokenType;
|
|
16
|
+
value: string;
|
|
17
|
+
}
|
|
18
|
+
interface ParsedLine {
|
|
19
|
+
index: number;
|
|
20
|
+
value: string;
|
|
21
|
+
tokens: ParsedToken[];
|
|
22
|
+
annotations: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** diff / patch — line-annotation preset. Colors added/removed/hunk/meta lines. */
|
|
26
|
+
|
|
27
|
+
declare const annotateLine: (line: ParsedLine) => void;
|
|
28
|
+
declare const config: ParseOptions;
|
|
29
|
+
|
|
30
|
+
export { annotateLine, config };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** diff / patch — line-annotation preset. Colors added/removed/hunk/meta lines. */ const annotateLine = (line)=>{
|
|
2
|
+
let annotation = '';
|
|
3
|
+
if (line.value.startsWith('+') && !line.value.startsWith('+++')) annotation = 'diff-add';
|
|
4
|
+
else if (line.value.startsWith('-') && !line.value.startsWith('---')) annotation = 'diff-remove';
|
|
5
|
+
else if (line.value.startsWith('@@')) annotation = 'diff-hunk';
|
|
6
|
+
else if (/^(diff --git|index |--- |\+\+\+ )/.test(line.value)) {
|
|
7
|
+
annotation = 'diff-meta';
|
|
8
|
+
for (const token of line.tokens){
|
|
9
|
+
if (token.type === 'property') token.type = 'identifier';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
if (annotation) line.annotations.push(annotation);
|
|
13
|
+
};
|
|
14
|
+
const config = {
|
|
15
|
+
annotateLine
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { annotateLine, config };
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
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
|
+
"add",
|
|
36
|
+
"arg",
|
|
37
|
+
"cmd",
|
|
38
|
+
"copy",
|
|
39
|
+
"entrypoint",
|
|
40
|
+
"env",
|
|
41
|
+
"expose",
|
|
42
|
+
"from",
|
|
43
|
+
"healthcheck",
|
|
44
|
+
"label",
|
|
45
|
+
"maintainer",
|
|
46
|
+
"onbuild",
|
|
47
|
+
"run",
|
|
48
|
+
"shell",
|
|
49
|
+
"stopsignal",
|
|
50
|
+
"user",
|
|
51
|
+
"volume",
|
|
52
|
+
"workdir"
|
|
53
|
+
],
|
|
54
|
+
comments: {
|
|
55
|
+
"line": [
|
|
56
|
+
"#"
|
|
57
|
+
]
|
|
58
|
+
}});
|
|
59
|
+
|
|
60
|
+
export { config };
|