@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.
Files changed (56) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +1089 -0
  3. package/bin/flux.js +1397 -0
  4. package/dist/flux.cjs.js +6664 -0
  5. package/dist/flux.esm.js +6674 -0
  6. package/dist/flux.min.js +263 -0
  7. package/index.d.ts +202 -0
  8. package/index.js +26 -0
  9. package/package.json +77 -0
  10. package/scripts/build.js +76 -0
  11. package/src/bundler.js +216 -0
  12. package/src/checker.js +322 -0
  13. package/src/codegen.js +785 -0
  14. package/src/css-preprocessor.js +399 -0
  15. package/src/formatter.js +140 -0
  16. package/src/jsx.js +480 -0
  17. package/src/lexer.js +518 -0
  18. package/src/linter.js +758 -0
  19. package/src/mangler.js +280 -0
  20. package/src/parser.js +1671 -0
  21. package/src/self/bundler.flux +167 -0
  22. package/src/self/bundler.js +187 -0
  23. package/src/self/checker.flux +249 -0
  24. package/src/self/checker.js +338 -0
  25. package/src/self/codegen.flux +555 -0
  26. package/src/self/codegen.js +784 -0
  27. package/src/self/css-preprocessor.flux +373 -0
  28. package/src/self/css-preprocessor.js +387 -0
  29. package/src/self/formatter.flux +93 -0
  30. package/src/self/formatter.js +114 -0
  31. package/src/self/jsx.flux +430 -0
  32. package/src/self/jsx.js +396 -0
  33. package/src/self/lexer.flux +529 -0
  34. package/src/self/lexer.js +709 -0
  35. package/src/self/lexer.stage2.js +700 -0
  36. package/src/self/linter.flux +515 -0
  37. package/src/self/linter.js +804 -0
  38. package/src/self/mangler.flux +253 -0
  39. package/src/self/mangler.js +348 -0
  40. package/src/self/parser.flux +1146 -0
  41. package/src/self/parser.js +1571 -0
  42. package/src/self/sourcemap.flux +66 -0
  43. package/src/self/sourcemap.js +72 -0
  44. package/src/self/stdlib.flux +356 -0
  45. package/src/self/stdlib.js +396 -0
  46. package/src/self/test-runner.flux +201 -0
  47. package/src/self/test-runner.js +132 -0
  48. package/src/self/transpiler.flux +123 -0
  49. package/src/self/transpiler.js +83 -0
  50. package/src/self/type-checker.flux +821 -0
  51. package/src/self/type-checker.js +1106 -0
  52. package/src/sourcemap.js +82 -0
  53. package/src/stdlib.js +436 -0
  54. package/src/test-runner.js +239 -0
  55. package/src/transpiler.js +172 -0
  56. package/src/type-checker.js +1206 -0
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Source Map v3 Generator
5
+ * Maps generated JS line/col back to original Flux source line/col.
6
+ */
7
+
8
+ const BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
9
+
10
+ function encodeVLQ(value) {
11
+ let vlq = value < 0 ? ((-value) << 1) | 1 : (value << 1);
12
+ let result = '';
13
+ do {
14
+ let digit = vlq & 0x1F;
15
+ vlq >>>= 5;
16
+ if (vlq > 0) digit |= 0x20;
17
+ result += BASE64[digit];
18
+ } while (vlq > 0);
19
+ return result;
20
+ }
21
+
22
+ class SourceMapBuilder {
23
+ constructor(sourceFile, sourceContent) {
24
+ this.sourceFile = sourceFile;
25
+ this.sourceContent = sourceContent;
26
+ // mappings[genLine] = [{ genCol, srcLine, srcCol }, ...]
27
+ // All indices are 0-based.
28
+ this.mappings = [];
29
+ }
30
+
31
+ /**
32
+ * Record one mapping.
33
+ * @param {number} genLine - 0-based generated (JS) line
34
+ * @param {number} genCol - 0-based generated column
35
+ * @param {number} srcLine - 0-based source (.flux) line
36
+ * @param {number} srcCol - 0-based source column
37
+ */
38
+ addMapping(genLine, genCol, srcLine, srcCol) {
39
+ while (this.mappings.length <= genLine) this.mappings.push([]);
40
+ this.mappings[genLine].push({ genCol, srcLine, srcCol });
41
+ }
42
+
43
+ // VLQ-encode all mappings into source map v3 "mappings" string
44
+ encodeMappings() {
45
+ let prevSrcLine = 0;
46
+ let prevSrcCol = 0;
47
+
48
+ return this.mappings.map(lineSegs => {
49
+ let prevGenCol = 0;
50
+ return lineSegs.map(seg => {
51
+ const encoded = [
52
+ encodeVLQ(seg.genCol - prevGenCol),
53
+ encodeVLQ(0), // source file index (always 0)
54
+ encodeVLQ(seg.srcLine - prevSrcLine),
55
+ encodeVLQ(seg.srcCol - prevSrcCol),
56
+ ].join('');
57
+ prevGenCol = seg.genCol;
58
+ prevSrcLine = seg.srcLine;
59
+ prevSrcCol = seg.srcCol;
60
+ return encoded;
61
+ }).join(',');
62
+ }).join(';');
63
+ }
64
+
65
+ toJSON(outputFile = '') {
66
+ return {
67
+ version: 3,
68
+ file: outputFile,
69
+ sourceRoot: '',
70
+ sources: [this.sourceFile],
71
+ sourcesContent: [this.sourceContent],
72
+ names: [],
73
+ mappings: this.encodeMappings(),
74
+ };
75
+ }
76
+
77
+ toString(outputFile = '') {
78
+ return JSON.stringify(this.toJSON(outputFile));
79
+ }
80
+ }
81
+
82
+ module.exports = { SourceMapBuilder, encodeVLQ };
package/src/stdlib.js ADDED
@@ -0,0 +1,436 @@
1
+ 'use strict';
2
+
3
+ // ── Flux Standard Library ─────────────────────────────────────────────────────
4
+ // Runtime helpers injected into compiled Flux programs.
5
+ // Each function is self-contained so tree-shaking can work later.
6
+
7
+ // ── Detection: which stdlib symbols appear in compiled JS? ───────────────────
8
+ const STDLIB_SYMBOLS = [
9
+ 'range', 'zip', 'enumerate', 'clamp', 'sum', 'product',
10
+ 'flatten', 'chunk', 'unique', 'groupBy', 'sortBy',
11
+ 'pick', 'omit', 'deepEqual', 'deepClone',
12
+ 'sleep', 'retry', 'memoize',
13
+ 'pipe', 'compose', 'partial', 'curry',
14
+ 'capitalize', 'camelCase', 'snakeCase', 'kebabCase', 'truncate', 'pad',
15
+ 'randInt', 'sample', 'shuffle',
16
+ 'mapValues', 'filterValues', 'fromEntries',
17
+ // Array pipe helpers — standalone wrappers around Array.prototype methods
18
+ 'map', 'filter', 'reduce', 'forEach', 'find', 'findIndex',
19
+ 'some', 'every', 'join', 'sort', 'flat', 'flatMap', 'includes',
20
+ ];
21
+
22
+ /**
23
+ * Build the stdlib preamble JavaScript string.
24
+ * If `symbols` is provided, only include helpers that are used.
25
+ * @param {string[]} [symbols] - list of stdlib names actually used in the output
26
+ * @returns {string}
27
+ */
28
+ function buildStdlib(symbols) {
29
+ const needed = symbols
30
+ ? new Set(symbols.filter(s => STDLIB_SYMBOLS.includes(s)))
31
+ : new Set(STDLIB_SYMBOLS);
32
+
33
+ if (needed.size === 0) return '';
34
+
35
+ const parts = ['// ── Flux stdlib ──'];
36
+
37
+ // ── Array pipe helpers ─────────────────────────────────────────────────────
38
+ // Standalone wrappers so |> map(...) / |> filter(...) etc. work correctly.
39
+
40
+ if (needed.has('map')) {
41
+ parts.push(`
42
+ function map(arr, fn) { return arr.map(fn); }`);
43
+ }
44
+
45
+ if (needed.has('filter')) {
46
+ parts.push(`
47
+ function filter(arr, fn) { return arr.filter(fn); }`);
48
+ }
49
+
50
+ if (needed.has('reduce')) {
51
+ parts.push(`
52
+ function reduce(arr, fn, init) { return arguments.length >= 3 ? arr.reduce(fn, init) : arr.reduce(fn); }`);
53
+ }
54
+
55
+ if (needed.has('forEach')) {
56
+ parts.push(`
57
+ function forEach(arr, fn) { arr.forEach(fn); return arr; }`);
58
+ }
59
+
60
+ if (needed.has('find')) {
61
+ parts.push(`
62
+ function find(arr, fn) { return arr.find(fn); }`);
63
+ }
64
+
65
+ if (needed.has('findIndex')) {
66
+ parts.push(`
67
+ function findIndex(arr, fn) { return arr.findIndex(fn); }`);
68
+ }
69
+
70
+ if (needed.has('some')) {
71
+ parts.push(`
72
+ function some(arr, fn) { return arr.some(fn); }`);
73
+ }
74
+
75
+ if (needed.has('every')) {
76
+ parts.push(`
77
+ function every(arr, fn) { return arr.every(fn); }`);
78
+ }
79
+
80
+ if (needed.has('join')) {
81
+ parts.push(`
82
+ function join(arr, sep) { return arr.join(sep != null ? sep : ','); }`);
83
+ }
84
+
85
+ if (needed.has('sort')) {
86
+ parts.push(`
87
+ function sort(arr, fn) { return arr.slice().sort(fn); }`);
88
+ }
89
+
90
+ if (needed.has('flat')) {
91
+ parts.push(`
92
+ function flat(arr, depth) { return arr.flat(depth != null ? depth : 1); }`);
93
+ }
94
+
95
+ if (needed.has('flatMap')) {
96
+ parts.push(`
97
+ function flatMap(arr, fn) { return arr.flatMap(fn); }`);
98
+ }
99
+
100
+ if (needed.has('includes')) {
101
+ parts.push(`
102
+ function includes(arr, val) { return arr.includes(val); }`);
103
+ }
104
+
105
+ // ── Sequences ──────────────────────────────────────────────────────────────
106
+
107
+ if (needed.has('range')) {
108
+ parts.push(`
109
+ function range(start, end, step) {
110
+ if (arguments.length === 1) { end = start; start = 0; }
111
+ step = step || (end >= start ? 1 : -1);
112
+ const out = [];
113
+ if (step > 0) { for (let i = start; i < end; i += step) out.push(i); }
114
+ else { for (let i = start; i > end; i += step) out.push(i); }
115
+ return out;
116
+ }`);
117
+ }
118
+
119
+ if (needed.has('zip')) {
120
+ parts.push(`
121
+ function zip() {
122
+ const arrays = Array.from(arguments);
123
+ const len = Math.min.apply(null, arrays.map(function(a) { return a.length; }));
124
+ const out = [];
125
+ for (let i = 0; i < len; i++) out.push(arrays.map(function(a) { return a[i]; }));
126
+ return out;
127
+ }`);
128
+ }
129
+
130
+ if (needed.has('enumerate')) {
131
+ parts.push(`
132
+ function enumerate(arr, start) {
133
+ start = start || 0;
134
+ return arr.map(function(v, i) { return [i + start, v]; });
135
+ }`);
136
+ }
137
+
138
+ if (needed.has('flatten')) {
139
+ parts.push(`
140
+ function flatten(arr, depth) {
141
+ return depth == null ? arr.flat(Infinity) : arr.flat(depth);
142
+ }`);
143
+ }
144
+
145
+ if (needed.has('chunk')) {
146
+ parts.push(`
147
+ function chunk(arr, size) {
148
+ const out = [];
149
+ for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
150
+ return out;
151
+ }`);
152
+ }
153
+
154
+ if (needed.has('unique')) {
155
+ parts.push(`
156
+ function unique(arr) {
157
+ return Array.from(new Set(arr));
158
+ }`);
159
+ }
160
+
161
+ if (needed.has('groupBy')) {
162
+ parts.push(`
163
+ function groupBy(arr, fn) {
164
+ return arr.reduce(function(acc, v) {
165
+ var k = typeof fn === 'function' ? fn(v) : v[fn];
166
+ (acc[k] = acc[k] || []).push(v);
167
+ return acc;
168
+ }, {});
169
+ }`);
170
+ }
171
+
172
+ if (needed.has('sortBy')) {
173
+ parts.push(`
174
+ function sortBy(arr, fn) {
175
+ return arr.slice().sort(function(a, b) {
176
+ var ka = typeof fn === 'function' ? fn(a) : a[fn];
177
+ var kb = typeof fn === 'function' ? fn(b) : b[fn];
178
+ return ka < kb ? -1 : ka > kb ? 1 : 0;
179
+ });
180
+ }`);
181
+ }
182
+
183
+ // ── Math ───────────────────────────────────────────────────────────────────
184
+
185
+ if (needed.has('clamp')) {
186
+ parts.push(`
187
+ function clamp(val, min, max) {
188
+ return Math.min(Math.max(val, min), max);
189
+ }`);
190
+ }
191
+
192
+ if (needed.has('sum')) {
193
+ parts.push(`
194
+ function sum(arr) {
195
+ return arr.reduce(function(a, b) { return a + b; }, 0);
196
+ }`);
197
+ }
198
+
199
+ if (needed.has('product')) {
200
+ parts.push(`
201
+ function product(arr) {
202
+ return arr.reduce(function(a, b) { return a * b; }, 1);
203
+ }`);
204
+ }
205
+
206
+ if (needed.has('randInt')) {
207
+ parts.push(`
208
+ function randInt(min, max) {
209
+ return Math.floor(Math.random() * (max - min + 1)) + min;
210
+ }`);
211
+ }
212
+
213
+ if (needed.has('sample')) {
214
+ parts.push(`
215
+ function sample(arr) {
216
+ return arr[Math.floor(Math.random() * arr.length)];
217
+ }`);
218
+ }
219
+
220
+ if (needed.has('shuffle')) {
221
+ parts.push(`
222
+ function shuffle(arr) {
223
+ var a = arr.slice();
224
+ for (var i = a.length - 1; i > 0; i--) {
225
+ var j = Math.floor(Math.random() * (i + 1));
226
+ var tmp = a[i]; a[i] = a[j]; a[j] = tmp;
227
+ }
228
+ return a;
229
+ }`);
230
+ }
231
+
232
+ // ── Objects ────────────────────────────────────────────────────────────────
233
+
234
+ if (needed.has('pick')) {
235
+ parts.push(`
236
+ function pick(obj, keys) {
237
+ var out = {};
238
+ keys.forEach(function(k) { if (Object.prototype.hasOwnProperty.call(obj, k)) out[k] = obj[k]; });
239
+ return out;
240
+ }`);
241
+ }
242
+
243
+ if (needed.has('omit')) {
244
+ parts.push(`
245
+ function omit(obj, keys) {
246
+ var ks = new Set(keys);
247
+ var out = {};
248
+ Object.keys(obj).forEach(function(k) { if (!ks.has(k)) out[k] = obj[k]; });
249
+ return out;
250
+ }`);
251
+ }
252
+
253
+ if (needed.has('mapValues')) {
254
+ parts.push(`
255
+ function mapValues(obj, fn) {
256
+ var out = {};
257
+ Object.keys(obj).forEach(function(k) { out[k] = fn(obj[k], k); });
258
+ return out;
259
+ }`);
260
+ }
261
+
262
+ if (needed.has('filterValues')) {
263
+ parts.push(`
264
+ function filterValues(obj, fn) {
265
+ var out = {};
266
+ Object.keys(obj).forEach(function(k) { if (fn(obj[k], k)) out[k] = obj[k]; });
267
+ return out;
268
+ }`);
269
+ }
270
+
271
+ if (needed.has('fromEntries')) {
272
+ parts.push(`
273
+ function fromEntries(entries) {
274
+ return Object.fromEntries(entries);
275
+ }`);
276
+ }
277
+
278
+ if (needed.has('deepEqual')) {
279
+ parts.push(`
280
+ function deepEqual(a, b) {
281
+ return JSON.stringify(a) === JSON.stringify(b);
282
+ }`);
283
+ }
284
+
285
+ if (needed.has('deepClone')) {
286
+ parts.push(`
287
+ function deepClone(v) {
288
+ return JSON.parse(JSON.stringify(v));
289
+ }`);
290
+ }
291
+
292
+ // ── Async ──────────────────────────────────────────────────────────────────
293
+
294
+ if (needed.has('sleep')) {
295
+ parts.push(`
296
+ function sleep(ms) {
297
+ return new Promise(function(resolve) { setTimeout(resolve, ms); });
298
+ }`);
299
+ }
300
+
301
+ if (needed.has('retry')) {
302
+ parts.push(`
303
+ async function retry(fn, attempts, delay) {
304
+ attempts = attempts || 3;
305
+ delay = delay || 300;
306
+ for (var i = 0; i < attempts; i++) {
307
+ try { return await fn(); } catch(e) {
308
+ if (i === attempts - 1) throw e;
309
+ await sleep(delay * Math.pow(2, i));
310
+ }
311
+ }
312
+ }`);
313
+ }
314
+
315
+ if (needed.has('memoize')) {
316
+ parts.push(`
317
+ function memoize(fn) {
318
+ var cache = new Map();
319
+ return function() {
320
+ var key = JSON.stringify(arguments);
321
+ if (cache.has(key)) return cache.get(key);
322
+ var result = fn.apply(this, arguments);
323
+ cache.set(key, result);
324
+ return result;
325
+ };
326
+ }`);
327
+ }
328
+
329
+ // ── Functional ─────────────────────────────────────────────────────────────
330
+
331
+ if (needed.has('pipe')) {
332
+ parts.push(`
333
+ function pipe() {
334
+ var fns = Array.from(arguments);
335
+ return function(x) { return fns.reduce(function(v, f) { return f(v); }, x); };
336
+ }`);
337
+ }
338
+
339
+ if (needed.has('compose')) {
340
+ parts.push(`
341
+ function compose() {
342
+ var fns = Array.from(arguments);
343
+ return function(x) { return fns.reduceRight(function(v, f) { return f(v); }, x); };
344
+ }`);
345
+ }
346
+
347
+ if (needed.has('partial')) {
348
+ parts.push(`
349
+ function partial(fn) {
350
+ var args = Array.from(arguments).slice(1);
351
+ return function() { return fn.apply(this, args.concat(Array.from(arguments))); };
352
+ }`);
353
+ }
354
+
355
+ if (needed.has('curry')) {
356
+ parts.push(`
357
+ function curry(fn) {
358
+ return function curried() {
359
+ var args = Array.from(arguments);
360
+ if (args.length >= fn.length) return fn.apply(this, args);
361
+ return function() { return curried.apply(this, args.concat(Array.from(arguments))); };
362
+ };
363
+ }`);
364
+ }
365
+
366
+ // ── Strings ────────────────────────────────────────────────────────────────
367
+
368
+ if (needed.has('capitalize')) {
369
+ parts.push(`
370
+ function capitalize(s) {
371
+ return s ? s[0].toUpperCase() + s.slice(1) : s;
372
+ }`);
373
+ }
374
+
375
+ if (needed.has('camelCase')) {
376
+ parts.push(`
377
+ function camelCase(s) {
378
+ return s.replace(/[-_\\s]+(.)/g, function(_, c) { return c.toUpperCase(); }).replace(/^./, function(c) { return c.toLowerCase(); });
379
+ }`);
380
+ }
381
+
382
+ if (needed.has('snakeCase')) {
383
+ parts.push(`
384
+ function snakeCase(s) {
385
+ return s.replace(/([A-Z])/g, function(c) { return '_' + c.toLowerCase(); }).replace(/[-\\s]+/g, '_').replace(/^_/, '');
386
+ }`);
387
+ }
388
+
389
+ if (needed.has('kebabCase')) {
390
+ parts.push(`
391
+ function kebabCase(s) {
392
+ return s.replace(/([A-Z])/g, function(c) { return '-' + c.toLowerCase(); }).replace(/[_\\s]+/g, '-').replace(/^-/, '');
393
+ }`);
394
+ }
395
+
396
+ if (needed.has('truncate')) {
397
+ parts.push(`
398
+ function truncate(s, len, suffix) {
399
+ suffix = suffix != null ? suffix : '...';
400
+ if (s.length <= len) return s;
401
+ // FIX: guard against suffix longer than len to avoid negative slice index
402
+ var cut = len - suffix.length;
403
+ if (cut <= 0) return suffix.slice(0, len);
404
+ return s.slice(0, cut) + suffix;
405
+ }`);
406
+ }
407
+
408
+ if (needed.has('pad')) {
409
+ parts.push(`
410
+ function pad(s, len, char) {
411
+ char = char || ' ';
412
+ s = String(s);
413
+ var total = len - s.length;
414
+ if (total <= 0) return s;
415
+ var half = Math.floor(total / 2);
416
+ return char.repeat(half) + s + char.repeat(total - half);
417
+ }`);
418
+ }
419
+
420
+ parts.push('// ── end stdlib ──\n');
421
+ return parts.join('\n');
422
+ }
423
+
424
+ /**
425
+ * Detect which stdlib symbols are referenced in a JS string.
426
+ * @param {string} jsCode
427
+ * @returns {string[]}
428
+ */
429
+ function detectUsedSymbols(jsCode) {
430
+ return STDLIB_SYMBOLS.filter(sym => {
431
+ const re = new RegExp(`\\b${sym}\\s*\\(`, 'g');
432
+ return re.test(jsCode);
433
+ });
434
+ }
435
+
436
+ module.exports = { buildStdlib, detectUsedSymbols, STDLIB_SYMBOLS };