@xnoxs/flux-lang 3.1.1
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/CHANGELOG.md +103 -0
- package/README.md +1089 -0
- package/bin/flux.js +1397 -0
- package/dist/flux.cjs.js +6664 -0
- package/dist/flux.esm.js +6674 -0
- package/dist/flux.min.js +263 -0
- package/index.d.ts +202 -0
- package/index.js +26 -0
- package/package.json +77 -0
- package/scripts/build.js +76 -0
- package/src/bundler.js +216 -0
- package/src/checker.js +322 -0
- package/src/codegen.js +785 -0
- package/src/css-preprocessor.js +399 -0
- package/src/formatter.js +140 -0
- package/src/jsx.js +480 -0
- package/src/lexer.js +518 -0
- package/src/linter.js +758 -0
- package/src/mangler.js +280 -0
- package/src/parser.js +1671 -0
- package/src/self/bundler.flux +167 -0
- package/src/self/bundler.js +187 -0
- package/src/self/checker.flux +249 -0
- package/src/self/checker.js +338 -0
- package/src/self/codegen.flux +555 -0
- package/src/self/codegen.js +784 -0
- package/src/self/css-preprocessor.flux +373 -0
- package/src/self/css-preprocessor.js +387 -0
- package/src/self/formatter.flux +93 -0
- package/src/self/formatter.js +114 -0
- package/src/self/jsx.flux +430 -0
- package/src/self/jsx.js +396 -0
- package/src/self/lexer.flux +529 -0
- package/src/self/lexer.js +709 -0
- package/src/self/lexer.stage2.js +700 -0
- package/src/self/linter.flux +515 -0
- package/src/self/linter.js +804 -0
- package/src/self/mangler.flux +253 -0
- package/src/self/mangler.js +348 -0
- package/src/self/parser.flux +1146 -0
- package/src/self/parser.js +1571 -0
- package/src/self/sourcemap.flux +66 -0
- package/src/self/sourcemap.js +72 -0
- package/src/self/stdlib.flux +356 -0
- package/src/self/stdlib.js +396 -0
- package/src/self/test-runner.flux +201 -0
- package/src/self/test-runner.js +132 -0
- package/src/self/transpiler.flux +123 -0
- package/src/self/transpiler.js +83 -0
- package/src/self/type-checker.flux +821 -0
- package/src/self/type-checker.js +1106 -0
- package/src/sourcemap.js +82 -0
- package/src/stdlib.js +436 -0
- package/src/test-runner.js +239 -0
- package/src/transpiler.js +172 -0
- package/src/type-checker.js +1206 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
// ── Flux stdlib ──
|
|
2
|
+
|
|
3
|
+
function includes(arr, val) { return arr.includes(val); }
|
|
4
|
+
// ── end stdlib ──
|
|
5
|
+
|
|
6
|
+
// Generated by Flux Transpiler v3.1.0
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
const CSS_PROP_MAP = { bg: "background", fg: "color", p: "padding", px: "padding-inline", py: "padding-block", pt: "padding-top", pb: "padding-bottom", pl: "padding-left", pr: "padding-right", m: "margin", mx: "margin-inline", my: "margin-block", mt: "margin-top", mb: "margin-bottom", ml: "margin-left", mr: "margin-right", radius: "border-radius", w: "width", h: "height", "min-w": "min-width", "max-w": "max-width", "min-h": "min-height", "max-h": "max-height", gap: "gap", "col-gap": "column-gap", "row-gap": "row-gap", text: "font-size", font: "font-family", weight: "font-weight", tracking: "letter-spacing", leading: "line-height", shadow: "box-shadow", opacity: "opacity", border: "border", outline: "outline", transition: "transition", cursor: "cursor", overflow: "overflow", "overflow-x": "overflow-x", "overflow-y": "overflow-y", z: "z-index", transform: "transform", content: "content", resize: "resize", appearance: "appearance", "object-fit": "object-fit", "accent-color": "accent-color", direction: "flex-direction", wrap: "flex-wrap", align: "align-items", justify: "justify-content", "align-self": "align-self", "justify-self": "justify-self", grow: "flex-grow", shrink: "flex-shrink", basis: "flex-basis", order: "order", cols: "grid-template-columns", rows: "grid-template-rows", "col-span": "grid-column", "row-span": "grid-row", "place-items": "place-items", "place-content": "place-content", "list-style": "list-style", "text-align": "text-align", decoration: "text-decoration", "text-transform": "text-transform", "white-space": "white-space", "word-break": "word-break", "user-select": "user-select", "pointer-events": "pointer-events", "vertical-align": "vertical-align", backdrop: "backdrop-filter", filter: "filter", clip: "clip-path", animation: "animation", position: "position", top: "top", right: "right", bottom: "bottom", left: "left", inset: "inset", color: "color", background: "background" };
|
|
10
|
+
module.exports.CSS_PROP_MAP = CSS_PROP_MAP;
|
|
11
|
+
const CSS_BOOL_MAP = { flex: "display: flex", grid: "display: grid", block: "display: block", inline: "display: inline", "inline-flex": "display: inline-flex", "inline-block": "display: inline-block", "inline-grid": "display: inline-grid", bold: "font-weight: 700", italic: "font-style: italic", relative: "position: relative", absolute: "position: absolute", fixed: "position: fixed", sticky: "position: sticky", hidden: "display: none", pointer: "cursor: pointer", underline: "text-decoration: underline", "line-through": "text-decoration: line-through", capitalize: "text-transform: capitalize", uppercase: "text-transform: uppercase", lowercase: "text-transform: lowercase", truncate: "overflow: hidden; text-overflow: ellipsis; white-space: nowrap", "select-none": "user-select: none", "no-wrap": "white-space: nowrap", "no-list": "list-style: none", "no-outline": "outline: none", "no-border": "border: none", "no-bg": "background: transparent", "no-padding": "padding: 0", "no-margin": "margin: 0", "no-resize": "resize: none", center: "text-align: center", "items-center": "align-items: center", "justify-center": "justify-content: center", "place-center": "place-items: center", "flex-col": "flex-direction: column", "flex-row": "flex-direction: row", "flex-wrap": "flex-wrap: wrap", "flex-1": "flex: 1", "w-full": "width: 100%", "h-full": "height: 100%", "w-screen": "width: 100vw", "h-screen": "height: 100vh", "box-border": "box-sizing: border-box" };
|
|
12
|
+
module.exports.CSS_BOOL_MAP = CSS_BOOL_MAP;
|
|
13
|
+
function expandProp(name) {
|
|
14
|
+
const t = name.trim();
|
|
15
|
+
return (CSS_PROP_MAP[t] ?? t);
|
|
16
|
+
}
|
|
17
|
+
function stripQuotes(v_) {
|
|
18
|
+
const v = v_.trim();
|
|
19
|
+
if ((v.length >= 2)) {
|
|
20
|
+
const q0 = v[0];
|
|
21
|
+
const ql = v[(v.length - 1)];
|
|
22
|
+
if ((((q0 == "\"") && (ql == "\"")) || ((q0 == "'") && (ql == "'")))) {
|
|
23
|
+
return v.slice(1, -1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return v;
|
|
27
|
+
}
|
|
28
|
+
function resolveSelector(sel, parent) {
|
|
29
|
+
const s = sel.trim();
|
|
30
|
+
if (!parent) {
|
|
31
|
+
return s;
|
|
32
|
+
}
|
|
33
|
+
if (s.startsWith("@")) {
|
|
34
|
+
return s;
|
|
35
|
+
}
|
|
36
|
+
if ((parent.startsWith("@keyframes") || parent.startsWith("@font-face"))) {
|
|
37
|
+
return s;
|
|
38
|
+
}
|
|
39
|
+
if (s.includes("&")) {
|
|
40
|
+
return s.replace(/&/g, parent);
|
|
41
|
+
}
|
|
42
|
+
return ((parent + " ") + s);
|
|
43
|
+
}
|
|
44
|
+
class CssBlockParser {
|
|
45
|
+
constructor(content, indentLevel, rules, atRuleSegs, selStack) {
|
|
46
|
+
this.content = content;
|
|
47
|
+
this.indentLevel = indentLevel;
|
|
48
|
+
this.rules = rules;
|
|
49
|
+
this.atRuleSegs = atRuleSegs;
|
|
50
|
+
this.selStack = selStack;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
curSel() {
|
|
54
|
+
if ((this.selStack.length == 0)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return this.selStack[(this.selStack.length - 1)];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
findOrCreateRule(sel) {
|
|
61
|
+
for (const entry of this.rules) {
|
|
62
|
+
if ((entry.sel == sel)) {
|
|
63
|
+
return entry;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const entry = { sel, decls: [] };
|
|
67
|
+
this.rules.push(entry);
|
|
68
|
+
return entry;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
addDecl(sel, d) {
|
|
72
|
+
const entry = this.findOrCreateRule(sel);
|
|
73
|
+
entry.decls.push(d);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
addDeclarationLine(line, sel) {
|
|
77
|
+
if (line.includes(";")) {
|
|
78
|
+
const parts = line.split(";");
|
|
79
|
+
for (const part of parts) {
|
|
80
|
+
const t = part.trim();
|
|
81
|
+
if (t) {
|
|
82
|
+
this.addDeclarationLine(t, sel);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const boolDecl = CSS_BOOL_MAP[line];
|
|
88
|
+
if (boolDecl) {
|
|
89
|
+
const bdParts = boolDecl.split(";");
|
|
90
|
+
for (const bd of bdParts) {
|
|
91
|
+
const t = bd.trim();
|
|
92
|
+
if (t) {
|
|
93
|
+
this.addDecl(sel, t);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const ci = line.indexOf(":");
|
|
99
|
+
if ((ci != -1)) {
|
|
100
|
+
const prop = expandProp(line.slice(0, ci));
|
|
101
|
+
const v = stripQuotes(line.slice((ci + 1)));
|
|
102
|
+
if ((v != "")) {
|
|
103
|
+
this.addDecl(sel, ((prop + ": ") + v));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
collectBlock(lines, startI) {
|
|
109
|
+
let depth = 1;
|
|
110
|
+
let inner = "";
|
|
111
|
+
let j = startI;
|
|
112
|
+
while (((j < lines.length) && (depth > 0))) {
|
|
113
|
+
const ln = lines[j];
|
|
114
|
+
j = (j + 1);
|
|
115
|
+
for (const ch of ln) {
|
|
116
|
+
if ((ch == "{")) {
|
|
117
|
+
depth = (depth + 1);
|
|
118
|
+
}
|
|
119
|
+
else if ((ch == "}")) {
|
|
120
|
+
depth = (depth - 1);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if ((depth > 0)) {
|
|
124
|
+
inner = ((inner + ln) + "\n");
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const ci = ln.lastIndexOf("}");
|
|
128
|
+
if ((ci > 0)) {
|
|
129
|
+
inner = ((inner + ln.slice(0, ci)) + "\n");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { inner, nextI: j };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
parse() {
|
|
137
|
+
const lines = this.content.split("\n");
|
|
138
|
+
let i = 0;
|
|
139
|
+
while ((i < lines.length)) {
|
|
140
|
+
const raw = lines[i];
|
|
141
|
+
i = (i + 1);
|
|
142
|
+
const line = raw.trim();
|
|
143
|
+
if ((!line || line.startsWith("//"))) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const ob = line.indexOf("{");
|
|
147
|
+
const cb = line.lastIndexOf("}");
|
|
148
|
+
if ((line.startsWith("@keyframes") || line.startsWith("@font-face"))) {
|
|
149
|
+
const atSel = ((ob != -1) ? line.slice(0, ob).trim() : line.trim());
|
|
150
|
+
let atBody = "";
|
|
151
|
+
if ((((ob != -1) && (cb != -1)) && (cb > ob))) {
|
|
152
|
+
atBody = line.slice((ob + 1), cb);
|
|
153
|
+
}
|
|
154
|
+
else if ((ob != -1)) {
|
|
155
|
+
const res = this.collectBlock(lines, i);
|
|
156
|
+
i = res.nextI;
|
|
157
|
+
atBody = res.inner;
|
|
158
|
+
}
|
|
159
|
+
const ind_ = " ".repeat((this.indentLevel ?? 0));
|
|
160
|
+
this.atRuleSegs.push((((((ind_ + atSel) + " {\n") + atBody) + ind_) + "}\n"));
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (((line.startsWith("@media") || line.startsWith("@supports")) || line.startsWith("@layer"))) {
|
|
164
|
+
const atSel = ((ob != -1) ? line.slice(0, ob).trim() : line.trim());
|
|
165
|
+
let atBody = "";
|
|
166
|
+
if ((((ob != -1) && (cb != -1)) && (cb > ob))) {
|
|
167
|
+
atBody = line.slice((ob + 1), cb);
|
|
168
|
+
}
|
|
169
|
+
else if ((ob != -1)) {
|
|
170
|
+
const res = this.collectBlock(lines, i);
|
|
171
|
+
i = res.nextI;
|
|
172
|
+
atBody = res.inner;
|
|
173
|
+
}
|
|
174
|
+
const innerCss = parseCssBlockContent(atBody, ((this.indentLevel ?? 0) + 1));
|
|
175
|
+
const ind_ = " ".repeat((this.indentLevel ?? 0));
|
|
176
|
+
this.atRuleSegs.push((((((ind_ + atSel) + " {\n") + innerCss) + ind_) + "}\n"));
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if ((((ob != -1) && (cb != -1)) && (cb > ob))) {
|
|
180
|
+
const sel = line.slice(0, ob).trim();
|
|
181
|
+
const inner = line.slice((ob + 1), cb).trim();
|
|
182
|
+
const full = resolveSelector(sel, this.curSel());
|
|
183
|
+
this.findOrCreateRule(full);
|
|
184
|
+
if (inner) {
|
|
185
|
+
this.addDeclarationLine(inner, full);
|
|
186
|
+
}
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if ((ob != -1)) {
|
|
190
|
+
const sel = line.slice(0, ob).trim();
|
|
191
|
+
const full = resolveSelector(sel, this.curSel());
|
|
192
|
+
this.selStack.push(full);
|
|
193
|
+
this.findOrCreateRule(full);
|
|
194
|
+
const tail = line.slice((ob + 1)).trim();
|
|
195
|
+
if (tail) {
|
|
196
|
+
this.addDeclarationLine(tail, full);
|
|
197
|
+
}
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (((line == "}") || (line == "};"))) {
|
|
201
|
+
this.selStack.pop();
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if ((this.selStack.length > 0)) {
|
|
205
|
+
this.addDeclarationLine(line, this.curSel());
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
emit() {
|
|
211
|
+
let css = "";
|
|
212
|
+
const ind = " ".repeat((this.indentLevel ?? 0));
|
|
213
|
+
const ind1 = (ind + " ");
|
|
214
|
+
for (const entry of this.rules) {
|
|
215
|
+
if ((entry.decls.length == 0)) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
css = (((css + ind) + entry.sel) + " {\n");
|
|
219
|
+
for (const d of entry.decls) {
|
|
220
|
+
css = (((css + ind1) + d) + ";\n");
|
|
221
|
+
}
|
|
222
|
+
css = ((css + ind) + "}\n");
|
|
223
|
+
}
|
|
224
|
+
for (const seg of this.atRuleSegs) {
|
|
225
|
+
css = (css + seg);
|
|
226
|
+
}
|
|
227
|
+
return css;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function parseCssBlockContent(content, indentLevel) {
|
|
233
|
+
const parser = new CssBlockParser(content, (indentLevel ?? 0), [], [], []);
|
|
234
|
+
parser.parse();
|
|
235
|
+
return parser.emit();
|
|
236
|
+
}
|
|
237
|
+
module.exports.parseCssBlockContent = parseCssBlockContent;
|
|
238
|
+
class CssPreprocessor {
|
|
239
|
+
constructor(src, pos, out) {
|
|
240
|
+
this.src = src;
|
|
241
|
+
this.pos = pos;
|
|
242
|
+
this.out = out;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
transform() {
|
|
246
|
+
while ((this.pos < this.src.length)) {
|
|
247
|
+
this.scan();
|
|
248
|
+
}
|
|
249
|
+
return this.out;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
scan() {
|
|
253
|
+
const c = this.src[this.pos];
|
|
254
|
+
if (((c == "/") && (this.src[(this.pos + 1)] == "/"))) {
|
|
255
|
+
const end_ = this.src.indexOf("\n", this.pos);
|
|
256
|
+
if ((end_ == -1)) {
|
|
257
|
+
this.out = (this.out + this.src.slice(this.pos));
|
|
258
|
+
this.pos = this.src.length;
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
this.out = (this.out + this.src.slice(this.pos, (end_ + 1)));
|
|
262
|
+
this.pos = (end_ + 1);
|
|
263
|
+
}
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (((c == "/") && (this.src[(this.pos + 1)] == "*"))) {
|
|
267
|
+
const end_ = this.src.indexOf("*/", (this.pos + 2));
|
|
268
|
+
if ((end_ == -1)) {
|
|
269
|
+
this.out = (this.out + this.src.slice(this.pos));
|
|
270
|
+
this.pos = this.src.length;
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
this.out = (this.out + this.src.slice(this.pos, (end_ + 2)));
|
|
274
|
+
this.pos = (end_ + 2);
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if ((c == "\"")) {
|
|
279
|
+
this.passString("\"");
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if ((c == "'")) {
|
|
283
|
+
this.passString("'");
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if ((c == "`")) {
|
|
287
|
+
this.passTemplate();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (((c == "c") && (this.src.slice(this.pos, (this.pos + 3)) == "css"))) {
|
|
291
|
+
const charBefore = ((this.pos > 0) ? this.src[(this.pos - 1)] : "\n");
|
|
292
|
+
const charAfter = (this.src[(this.pos + 3)] ?? "");
|
|
293
|
+
if ((!/[a-zA-Z0-9_]/.test(charBefore) && !/[a-zA-Z0-9_]/.test(charAfter))) {
|
|
294
|
+
let j = (this.pos + 3);
|
|
295
|
+
while (((j < this.src.length) && ((((this.src[j] == " ") || (this.src[j] == "\t")) || (this.src[j] == "\n")) || (this.src[j] == "\\r")))) {
|
|
296
|
+
j = (j + 1);
|
|
297
|
+
}
|
|
298
|
+
if ((this.src[j] == "{")) {
|
|
299
|
+
j = (j + 1);
|
|
300
|
+
let depth = 1;
|
|
301
|
+
const blockStart = j;
|
|
302
|
+
while (((j < this.src.length) && (depth > 0))) {
|
|
303
|
+
const ch = this.src[j];
|
|
304
|
+
if ((((ch == "\"") || (ch == "'")) || (ch == "`"))) {
|
|
305
|
+
const q = ch;
|
|
306
|
+
j = (j + 1);
|
|
307
|
+
while (((j < this.src.length) && (this.src[j] != q))) {
|
|
308
|
+
if ((this.src[j] == "\\")) {
|
|
309
|
+
j = (j + 1);
|
|
310
|
+
}
|
|
311
|
+
j = (j + 1);
|
|
312
|
+
}
|
|
313
|
+
j = (j + 1);
|
|
314
|
+
}
|
|
315
|
+
else if ((ch == "{")) {
|
|
316
|
+
depth = (depth + 1);
|
|
317
|
+
j = (j + 1);
|
|
318
|
+
}
|
|
319
|
+
else if ((ch == "}")) {
|
|
320
|
+
depth = (depth - 1);
|
|
321
|
+
j = (j + 1);
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
j = (j + 1);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const blockContent = this.src.slice(blockStart, (j - 1));
|
|
328
|
+
const css = parseCssBlockContent(blockContent, 0);
|
|
329
|
+
const BT = String.fromCharCode(96);
|
|
330
|
+
const escapedCss = css.replace(/\\/g, "\\\\").replace(new RegExp(BT, "g"), ("\\" + BT));
|
|
331
|
+
this.out = (((this.out + BT) + escapedCss) + BT);
|
|
332
|
+
this.pos = j;
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
this.out = (this.out + c);
|
|
338
|
+
this.pos = (this.pos + 1);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
passString(quote) {
|
|
342
|
+
this.out = (this.out + quote);
|
|
343
|
+
this.pos = (this.pos + 1);
|
|
344
|
+
while ((this.pos < this.src.length)) {
|
|
345
|
+
const c = this.src[this.pos];
|
|
346
|
+
if ((c == "\\")) {
|
|
347
|
+
this.out = ((this.out + c) + (this.src[(this.pos + 1)] ?? ""));
|
|
348
|
+
this.pos = (this.pos + 2);
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if ((c == quote)) {
|
|
352
|
+
this.out = (this.out + c);
|
|
353
|
+
this.pos = (this.pos + 1);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
this.out = (this.out + c);
|
|
357
|
+
this.pos = (this.pos + 1);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
passTemplate() {
|
|
362
|
+
this.out = (this.out + "`");
|
|
363
|
+
this.pos = (this.pos + 1);
|
|
364
|
+
while ((this.pos < this.src.length)) {
|
|
365
|
+
const c = this.src[this.pos];
|
|
366
|
+
if ((c == "\\")) {
|
|
367
|
+
this.out = ((this.out + c) + (this.src[(this.pos + 1)] ?? ""));
|
|
368
|
+
this.pos = (this.pos + 2);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if ((c == "`")) {
|
|
372
|
+
this.out = (this.out + c);
|
|
373
|
+
this.pos = (this.pos + 1);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
this.out = (this.out + c);
|
|
377
|
+
this.pos = (this.pos + 1);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
module.exports.CssPreprocessor = CssPreprocessor;
|
|
384
|
+
function transformCss(src) {
|
|
385
|
+
return new CssPreprocessor(src, 0, "").transform();
|
|
386
|
+
}
|
|
387
|
+
module.exports.transformCss = transformCss;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Flux Self-Hosted Formatter
|
|
3
|
+
// src/self/formatter.flux — written in Flux, compiled by stage-0
|
|
4
|
+
//
|
|
5
|
+
// Normalizes Flux source code:
|
|
6
|
+
// • 4-space indentation
|
|
7
|
+
// • Strips trailing whitespace
|
|
8
|
+
// • Max 1 consecutive blank line
|
|
9
|
+
// • Blank line after top-level fn/class/type declarations
|
|
10
|
+
// • Spacing around binary operators
|
|
11
|
+
// • Consistent colon / arrow spacing
|
|
12
|
+
// ============================================================
|
|
13
|
+
|
|
14
|
+
fn normalizeOperators(line):
|
|
15
|
+
if (line.match(/:/g) ?? []).length > 2: return line
|
|
16
|
+
var result = line
|
|
17
|
+
result = result.replace(/([^=!<>+\-*\/%])=(?!=|>)/g, '$1 = ')
|
|
18
|
+
result = result.replace(/\s{2,}=/g, ' =')
|
|
19
|
+
result = result.replace(/([^\s]) +/g, '$1 ')
|
|
20
|
+
result = result.replace(/,(?!\s)/g, ', ')
|
|
21
|
+
result = result.replace(/\s*->\s*/g, ' -> ')
|
|
22
|
+
result = result.replace(/\s*=>\s*/g, ' => ')
|
|
23
|
+
result = result.trimEnd()
|
|
24
|
+
return result
|
|
25
|
+
|
|
26
|
+
export fn format(source):
|
|
27
|
+
val lines = source.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n')
|
|
28
|
+
|
|
29
|
+
var indentUnit = 4
|
|
30
|
+
for line in lines:
|
|
31
|
+
val m = line.match(/^( +)\S/)
|
|
32
|
+
if m:
|
|
33
|
+
val w = m[1].length
|
|
34
|
+
if w > 0 and w < indentUnit: indentUnit = w
|
|
35
|
+
break
|
|
36
|
+
if indentUnit < 1: indentUnit = 4
|
|
37
|
+
|
|
38
|
+
fn normalizeLine(line):
|
|
39
|
+
val stripped = line.trimEnd()
|
|
40
|
+
if not stripped: return ''
|
|
41
|
+
val m2 = stripped.match(/^( *)/)
|
|
42
|
+
val spaces = m2 ? m2[1].length : 0
|
|
43
|
+
val level = Math.round(spaces / indentUnit)
|
|
44
|
+
val content = stripped.trimStart()
|
|
45
|
+
var formatted = normalizeOperators(content)
|
|
46
|
+
if content.startsWith('//') or content.startsWith('*'):
|
|
47
|
+
formatted = content
|
|
48
|
+
return ' '.repeat(level) + formatted
|
|
49
|
+
|
|
50
|
+
val normalized = lines.map(line -> normalizeLine(line))
|
|
51
|
+
|
|
52
|
+
val collapsed = []
|
|
53
|
+
var blankRun = 0
|
|
54
|
+
for line in normalized:
|
|
55
|
+
if line == '':
|
|
56
|
+
blankRun = blankRun + 1
|
|
57
|
+
if blankRun <= 1: collapsed.push('')
|
|
58
|
+
else:
|
|
59
|
+
blankRun = 0
|
|
60
|
+
collapsed.push(line)
|
|
61
|
+
|
|
62
|
+
val withSpacing = []
|
|
63
|
+
var i = 0
|
|
64
|
+
while i < collapsed.length:
|
|
65
|
+
withSpacing.push(collapsed[i])
|
|
66
|
+
val indent = (collapsed[i].match(/^( *)/) ?? ['', ''])[1].length
|
|
67
|
+
if i > 0:
|
|
68
|
+
val prevIndent = (collapsed[i - 1].match(/^( *)/) ?? ['', ''])[1].length
|
|
69
|
+
val cur = collapsed[i].trimStart()
|
|
70
|
+
if prevIndent >= 4 and indent == 0 and cur != '':
|
|
71
|
+
if withSpacing[withSpacing.length - 2] != '':
|
|
72
|
+
withSpacing.splice(withSpacing.length - 1, 0, '')
|
|
73
|
+
i = i + 1
|
|
74
|
+
|
|
75
|
+
var out = withSpacing
|
|
76
|
+
while out.length > 0 and out[0] == '': out.shift()
|
|
77
|
+
while out.length > 0 and out[out.length - 1] == '': out.pop()
|
|
78
|
+
out.push('')
|
|
79
|
+
return out.join('\n')
|
|
80
|
+
|
|
81
|
+
export fn diff(original, formatted):
|
|
82
|
+
val origLines = original.split('\n')
|
|
83
|
+
val fmtLines = formatted.split('\n')
|
|
84
|
+
val changes = []
|
|
85
|
+
val maxLen = Math.max(origLines.length, fmtLines.length)
|
|
86
|
+
var j = 0
|
|
87
|
+
while j < maxLen:
|
|
88
|
+
val o = origLines[j]
|
|
89
|
+
val f = fmtLines[j]
|
|
90
|
+
if o != f:
|
|
91
|
+
changes.push({ line: j + 1, original: o, formatted: f })
|
|
92
|
+
j = j + 1
|
|
93
|
+
return changes
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// ── Flux stdlib ──
|
|
2
|
+
|
|
3
|
+
function map(arr, fn) { return arr.map(fn); }
|
|
4
|
+
|
|
5
|
+
function join(arr, sep) { return arr.join(sep != null ? sep : ','); }
|
|
6
|
+
// ── end stdlib ──
|
|
7
|
+
|
|
8
|
+
// Generated by Flux Transpiler v3.1.0
|
|
9
|
+
"use strict";
|
|
10
|
+
|
|
11
|
+
function normalizeOperators(line) {
|
|
12
|
+
if (((line.match(/:/g) ?? []).length > 2)) {
|
|
13
|
+
return line;
|
|
14
|
+
}
|
|
15
|
+
let result = line;
|
|
16
|
+
result = result.replace(/([^=!<>+\-*\/%])=(?!=|>)/g, "$1 = ");
|
|
17
|
+
result = result.replace(/\s{2,}=/g, " =");
|
|
18
|
+
result = result.replace(/([^\s]) +/g, "$1 ");
|
|
19
|
+
result = result.replace(/,(?!\s)/g, ", ");
|
|
20
|
+
result = result.replace(/\s*->\s*/g, " -> ");
|
|
21
|
+
result = result.replace(/\s*=>\s*/g, " => ");
|
|
22
|
+
result = result.trimEnd();
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
function format(source) {
|
|
26
|
+
const lines = source.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
27
|
+
let indentUnit = 4;
|
|
28
|
+
for (const line of lines) {
|
|
29
|
+
const m = line.match(/^( +)\S/);
|
|
30
|
+
if (m) {
|
|
31
|
+
const w = m[1].length;
|
|
32
|
+
if (((w > 0) && (w < indentUnit))) {
|
|
33
|
+
indentUnit = w;
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if ((indentUnit < 1)) {
|
|
39
|
+
indentUnit = 4;
|
|
40
|
+
}
|
|
41
|
+
function normalizeLine(line) {
|
|
42
|
+
const stripped = line.trimEnd();
|
|
43
|
+
if (!stripped) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
const m2 = stripped.match(/^( *)/);
|
|
47
|
+
const spaces = (m2 ? m2[1].length : 0);
|
|
48
|
+
const level = Math.round((spaces / indentUnit));
|
|
49
|
+
const content = stripped.trimStart();
|
|
50
|
+
let formatted = normalizeOperators(content);
|
|
51
|
+
if ((content.startsWith("//") || content.startsWith("*"))) {
|
|
52
|
+
formatted = content;
|
|
53
|
+
}
|
|
54
|
+
return (" ".repeat(level) + formatted);
|
|
55
|
+
}
|
|
56
|
+
const normalized = lines.map((line) => normalizeLine(line));
|
|
57
|
+
const collapsed = [];
|
|
58
|
+
let blankRun = 0;
|
|
59
|
+
for (const line of normalized) {
|
|
60
|
+
if ((line == "")) {
|
|
61
|
+
blankRun = (blankRun + 1);
|
|
62
|
+
if ((blankRun <= 1)) {
|
|
63
|
+
collapsed.push("");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
blankRun = 0;
|
|
68
|
+
collapsed.push(line);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const withSpacing = [];
|
|
72
|
+
let i = 0;
|
|
73
|
+
while ((i < collapsed.length)) {
|
|
74
|
+
withSpacing.push(collapsed[i]);
|
|
75
|
+
const indent = (collapsed[i].match(/^( *)/) ?? ["", ""])[1].length;
|
|
76
|
+
if ((i > 0)) {
|
|
77
|
+
const prevIndent = (collapsed[(i - 1)].match(/^( *)/) ?? ["", ""])[1].length;
|
|
78
|
+
const cur = collapsed[i].trimStart();
|
|
79
|
+
if ((((prevIndent >= 4) && (indent == 0)) && (cur != ""))) {
|
|
80
|
+
if ((withSpacing[(withSpacing.length - 2)] != "")) {
|
|
81
|
+
withSpacing.splice((withSpacing.length - 1), 0, "");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
i = (i + 1);
|
|
86
|
+
}
|
|
87
|
+
let out = withSpacing;
|
|
88
|
+
while (((out.length > 0) && (out[0] == ""))) {
|
|
89
|
+
out.shift();
|
|
90
|
+
}
|
|
91
|
+
while (((out.length > 0) && (out[(out.length - 1)] == ""))) {
|
|
92
|
+
out.pop();
|
|
93
|
+
}
|
|
94
|
+
out.push("");
|
|
95
|
+
return out.join("\n");
|
|
96
|
+
}
|
|
97
|
+
module.exports.format = format;
|
|
98
|
+
function diff(original, formatted) {
|
|
99
|
+
const origLines = original.split("\n");
|
|
100
|
+
const fmtLines = formatted.split("\n");
|
|
101
|
+
const changes = [];
|
|
102
|
+
const maxLen = Math.max(origLines.length, fmtLines.length);
|
|
103
|
+
let j = 0;
|
|
104
|
+
while ((j < maxLen)) {
|
|
105
|
+
const o = origLines[j];
|
|
106
|
+
const f = fmtLines[j];
|
|
107
|
+
if ((o != f)) {
|
|
108
|
+
changes.push({ line: (j + 1), original: o, formatted: f });
|
|
109
|
+
}
|
|
110
|
+
j = (j + 1);
|
|
111
|
+
}
|
|
112
|
+
return changes;
|
|
113
|
+
}
|
|
114
|
+
module.exports.diff = diff;
|