@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,66 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Flux Self-Hosted Source Map Generator
|
|
3
|
+
// src/self/sourcemap.flux — written in Flux, compiled by stage-0
|
|
4
|
+
//
|
|
5
|
+
// Source Map v3 — maps generated JS line/col back to original
|
|
6
|
+
// Flux source line/col.
|
|
7
|
+
// ============================================================
|
|
8
|
+
|
|
9
|
+
val BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
|
10
|
+
|
|
11
|
+
export fn encodeVLQ(value):
|
|
12
|
+
var vlq = value < 0 ? ((-value) << 1) | 1 : (value << 1)
|
|
13
|
+
var result = ''
|
|
14
|
+
var running = true
|
|
15
|
+
while running:
|
|
16
|
+
var digit = vlq & 0x1F
|
|
17
|
+
vlq = vlq >> 5
|
|
18
|
+
if vlq > 0: digit = digit | 0x20
|
|
19
|
+
result = result + BASE64[digit]
|
|
20
|
+
if vlq <= 0: running = false
|
|
21
|
+
return result
|
|
22
|
+
|
|
23
|
+
export class SourceMapBuilder:
|
|
24
|
+
sourceFile: string
|
|
25
|
+
sourceContent: string
|
|
26
|
+
mappings: any[]
|
|
27
|
+
|
|
28
|
+
fn addMapping(genLine, genCol, srcLine, srcCol):
|
|
29
|
+
while self.mappings.length <= genLine: self.mappings.push([])
|
|
30
|
+
self.mappings[genLine].push({ genCol, srcLine, srcCol })
|
|
31
|
+
|
|
32
|
+
fn encodeMappings():
|
|
33
|
+
var prevSrcLine = 0
|
|
34
|
+
var prevSrcCol = 0
|
|
35
|
+
val lines2 = []
|
|
36
|
+
for lineSegs in self.mappings:
|
|
37
|
+
var prevGenCol = 0
|
|
38
|
+
val segs = []
|
|
39
|
+
for seg in lineSegs:
|
|
40
|
+
val encoded = [
|
|
41
|
+
encodeVLQ(seg.genCol - prevGenCol),
|
|
42
|
+
encodeVLQ(0),
|
|
43
|
+
encodeVLQ(seg.srcLine - prevSrcLine),
|
|
44
|
+
encodeVLQ(seg.srcCol - prevSrcCol),
|
|
45
|
+
].join('')
|
|
46
|
+
prevGenCol = seg.genCol
|
|
47
|
+
prevSrcLine = seg.srcLine
|
|
48
|
+
prevSrcCol = seg.srcCol
|
|
49
|
+
segs.push(encoded)
|
|
50
|
+
lines2.push(segs.join(','))
|
|
51
|
+
return lines2.join(';')
|
|
52
|
+
|
|
53
|
+
fn toJSON(outputFile):
|
|
54
|
+
val file = outputFile ?? ''
|
|
55
|
+
return {
|
|
56
|
+
version: 3,
|
|
57
|
+
file: file,
|
|
58
|
+
sourceRoot: '',
|
|
59
|
+
sources: [self.sourceFile],
|
|
60
|
+
sourcesContent: [self.sourceContent],
|
|
61
|
+
names: [],
|
|
62
|
+
mappings: self.encodeMappings(),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fn toString(outputFile):
|
|
66
|
+
return JSON.stringify(self.toJSON(outputFile))
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// ── Flux stdlib ──
|
|
2
|
+
|
|
3
|
+
function join(arr, sep) { return arr.join(sep != null ? sep : ','); }
|
|
4
|
+
// ── end stdlib ──
|
|
5
|
+
|
|
6
|
+
// Generated by Flux Transpiler v3.1.0
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
const BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
10
|
+
function encodeVLQ(value) {
|
|
11
|
+
let vlq = ((value < 0) ? ((-value << 1) | 1) : (value << 1));
|
|
12
|
+
let result = "";
|
|
13
|
+
let running = true;
|
|
14
|
+
while (running) {
|
|
15
|
+
let digit = (vlq & 31);
|
|
16
|
+
vlq = (vlq >> 5);
|
|
17
|
+
if ((vlq > 0)) {
|
|
18
|
+
digit = (digit | 32);
|
|
19
|
+
}
|
|
20
|
+
result = (result + BASE64[digit]);
|
|
21
|
+
if ((vlq <= 0)) {
|
|
22
|
+
running = false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
module.exports.encodeVLQ = encodeVLQ;
|
|
28
|
+
class SourceMapBuilder {
|
|
29
|
+
constructor(sourceFile, sourceContent, mappings) {
|
|
30
|
+
this.sourceFile = sourceFile;
|
|
31
|
+
this.sourceContent = sourceContent;
|
|
32
|
+
this.mappings = mappings;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
addMapping(genLine, genCol, srcLine, srcCol) {
|
|
36
|
+
while ((this.mappings.length <= genLine)) {
|
|
37
|
+
this.mappings.push([]);
|
|
38
|
+
}
|
|
39
|
+
this.mappings[genLine].push({ genCol, srcLine, srcCol });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
encodeMappings() {
|
|
43
|
+
let prevSrcLine = 0;
|
|
44
|
+
let prevSrcCol = 0;
|
|
45
|
+
const lines2 = [];
|
|
46
|
+
for (const lineSegs of this.mappings) {
|
|
47
|
+
let prevGenCol = 0;
|
|
48
|
+
const segs = [];
|
|
49
|
+
for (const seg of lineSegs) {
|
|
50
|
+
const encoded = [encodeVLQ((seg.genCol - prevGenCol)), encodeVLQ(0), encodeVLQ((seg.srcLine - prevSrcLine)), encodeVLQ((seg.srcCol - prevSrcCol))].join("");
|
|
51
|
+
prevGenCol = seg.genCol;
|
|
52
|
+
prevSrcLine = seg.srcLine;
|
|
53
|
+
prevSrcCol = seg.srcCol;
|
|
54
|
+
segs.push(encoded);
|
|
55
|
+
}
|
|
56
|
+
lines2.push(segs.join(","));
|
|
57
|
+
}
|
|
58
|
+
return lines2.join(";");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
toJSON(outputFile) {
|
|
62
|
+
const file = (outputFile ?? "");
|
|
63
|
+
return { version: 3, file, sourceRoot: "", sources: [this.sourceFile], sourcesContent: [this.sourceContent], names: [], mappings: this.encodeMappings() };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
toString(outputFile) {
|
|
67
|
+
return JSON.stringify(this.toJSON(outputFile));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports.SourceMapBuilder = SourceMapBuilder;
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Flux Self-Hosted Standard Library
|
|
3
|
+
// src/self/stdlib.flux — written in Flux, compiled by stage-0
|
|
4
|
+
//
|
|
5
|
+
// Runtime helpers injected into compiled Flux programs.
|
|
6
|
+
// ============================================================
|
|
7
|
+
|
|
8
|
+
export val 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
|
+
'map', 'filter', 'reduce', 'forEach', 'find', 'findIndex',
|
|
18
|
+
'some', 'every', 'join', 'sort', 'flat', 'flatMap', 'includes',
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
fn makeSymbolRe(sym):
|
|
22
|
+
return new RegExp("\\b" + sym + "\\s*\\(", 'g')
|
|
23
|
+
|
|
24
|
+
export fn detectUsedSymbols(jsCode):
|
|
25
|
+
return STDLIB_SYMBOLS.filter(sym -> makeSymbolRe(sym).test(jsCode))
|
|
26
|
+
|
|
27
|
+
export fn buildStdlib(symbols):
|
|
28
|
+
var needed = new Set(STDLIB_SYMBOLS)
|
|
29
|
+
if symbols: needed = new Set(symbols.filter(s -> STDLIB_SYMBOLS.includes(s)))
|
|
30
|
+
|
|
31
|
+
if needed.size == 0: return ''
|
|
32
|
+
|
|
33
|
+
val parts = ['// ── Flux stdlib ──']
|
|
34
|
+
|
|
35
|
+
if needed.has('map'):
|
|
36
|
+
parts.push(`
|
|
37
|
+
function map(arr, fn) { return arr.map(fn); }`)
|
|
38
|
+
|
|
39
|
+
if needed.has('filter'):
|
|
40
|
+
parts.push(`
|
|
41
|
+
function filter(arr, fn) { return arr.filter(fn); }`)
|
|
42
|
+
|
|
43
|
+
if needed.has('reduce'):
|
|
44
|
+
parts.push(`
|
|
45
|
+
function reduce(arr, fn, init) { return arguments.length >= 3 ? arr.reduce(fn, init) : arr.reduce(fn); }`)
|
|
46
|
+
|
|
47
|
+
if needed.has('forEach'):
|
|
48
|
+
parts.push(`
|
|
49
|
+
function forEach(arr, fn) { arr.forEach(fn); return arr; }`)
|
|
50
|
+
|
|
51
|
+
if needed.has('find'):
|
|
52
|
+
parts.push(`
|
|
53
|
+
function find(arr, fn) { return arr.find(fn); }`)
|
|
54
|
+
|
|
55
|
+
if needed.has('findIndex'):
|
|
56
|
+
parts.push(`
|
|
57
|
+
function findIndex(arr, fn) { return arr.findIndex(fn); }`)
|
|
58
|
+
|
|
59
|
+
if needed.has('some'):
|
|
60
|
+
parts.push(`
|
|
61
|
+
function some(arr, fn) { return arr.some(fn); }`)
|
|
62
|
+
|
|
63
|
+
if needed.has('every'):
|
|
64
|
+
parts.push(`
|
|
65
|
+
function every(arr, fn) { return arr.every(fn); }`)
|
|
66
|
+
|
|
67
|
+
if needed.has('join'):
|
|
68
|
+
parts.push(`
|
|
69
|
+
function join(arr, sep) { return arr.join(sep != null ? sep : ','); }`)
|
|
70
|
+
|
|
71
|
+
if needed.has('sort'):
|
|
72
|
+
parts.push(`
|
|
73
|
+
function sort(arr, fn) { return arr.slice().sort(fn); }`)
|
|
74
|
+
|
|
75
|
+
if needed.has('flat'):
|
|
76
|
+
parts.push(`
|
|
77
|
+
function flat(arr, depth) { return arr.flat(depth != null ? depth : 1); }`)
|
|
78
|
+
|
|
79
|
+
if needed.has('flatMap'):
|
|
80
|
+
parts.push(`
|
|
81
|
+
function flatMap(arr, fn) { return arr.flatMap(fn); }`)
|
|
82
|
+
|
|
83
|
+
if needed.has('includes'):
|
|
84
|
+
parts.push(`
|
|
85
|
+
function includes(arr, val) { return arr.includes(val); }`)
|
|
86
|
+
|
|
87
|
+
if needed.has('range'):
|
|
88
|
+
parts.push(`
|
|
89
|
+
function range(start, end, step) {
|
|
90
|
+
if (arguments.length === 1) { end = start; start = 0; }
|
|
91
|
+
step = step || (end >= start ? 1 : -1);
|
|
92
|
+
const out = [];
|
|
93
|
+
if (step > 0) { for (let i = start; i < end; i += step) out.push(i); }
|
|
94
|
+
else { for (let i = start; i > end; i += step) out.push(i); }
|
|
95
|
+
return out;
|
|
96
|
+
}`)
|
|
97
|
+
|
|
98
|
+
if needed.has('zip'):
|
|
99
|
+
parts.push(`
|
|
100
|
+
function zip() {
|
|
101
|
+
const arrays = Array.from(arguments);
|
|
102
|
+
const len = Math.min.apply(null, arrays.map(function(a) { return a.length; }));
|
|
103
|
+
const out = [];
|
|
104
|
+
for (let i = 0; i < len; i++) out.push(arrays.map(function(a) { return a[i]; }));
|
|
105
|
+
return out;
|
|
106
|
+
}`)
|
|
107
|
+
|
|
108
|
+
if needed.has('enumerate'):
|
|
109
|
+
parts.push(`
|
|
110
|
+
function enumerate(arr, start) {
|
|
111
|
+
start = start || 0;
|
|
112
|
+
return arr.map(function(v, i) { return [i + start, v]; });
|
|
113
|
+
}`)
|
|
114
|
+
|
|
115
|
+
if needed.has('flatten'):
|
|
116
|
+
parts.push(`
|
|
117
|
+
function flatten(arr, depth) {
|
|
118
|
+
return depth == null ? arr.flat(Infinity) : arr.flat(depth);
|
|
119
|
+
}`)
|
|
120
|
+
|
|
121
|
+
if needed.has('chunk'):
|
|
122
|
+
parts.push(`
|
|
123
|
+
function chunk(arr, size) {
|
|
124
|
+
const out = [];
|
|
125
|
+
for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
|
|
126
|
+
return out;
|
|
127
|
+
}`)
|
|
128
|
+
|
|
129
|
+
if needed.has('unique'):
|
|
130
|
+
parts.push(`
|
|
131
|
+
function unique(arr) {
|
|
132
|
+
return Array.from(new Set(arr));
|
|
133
|
+
}`)
|
|
134
|
+
|
|
135
|
+
if needed.has('groupBy'):
|
|
136
|
+
parts.push(`
|
|
137
|
+
function groupBy(arr, fn) {
|
|
138
|
+
return arr.reduce(function(acc, v) {
|
|
139
|
+
var k = typeof fn === 'function' ? fn(v) : v[fn];
|
|
140
|
+
(acc[k] = acc[k] || []).push(v);
|
|
141
|
+
return acc;
|
|
142
|
+
}, {});
|
|
143
|
+
}`)
|
|
144
|
+
|
|
145
|
+
if needed.has('sortBy'):
|
|
146
|
+
parts.push(`
|
|
147
|
+
function sortBy(arr, fn) {
|
|
148
|
+
return arr.slice().sort(function(a, b) {
|
|
149
|
+
var ka = typeof fn === 'function' ? fn(a) : a[fn];
|
|
150
|
+
var kb = typeof fn === 'function' ? fn(b) : b[fn];
|
|
151
|
+
return ka < kb ? -1 : ka > kb ? 1 : 0;
|
|
152
|
+
});
|
|
153
|
+
}`)
|
|
154
|
+
|
|
155
|
+
if needed.has('clamp'):
|
|
156
|
+
parts.push(`
|
|
157
|
+
function clamp(val, min, max) {
|
|
158
|
+
return Math.min(Math.max(val, min), max);
|
|
159
|
+
}`)
|
|
160
|
+
|
|
161
|
+
if needed.has('sum'):
|
|
162
|
+
parts.push(`
|
|
163
|
+
function sum(arr) {
|
|
164
|
+
return arr.reduce(function(a, b) { return a + b; }, 0);
|
|
165
|
+
}`)
|
|
166
|
+
|
|
167
|
+
if needed.has('product'):
|
|
168
|
+
parts.push(`
|
|
169
|
+
function product(arr) {
|
|
170
|
+
return arr.reduce(function(a, b) { return a * b; }, 1);
|
|
171
|
+
}`)
|
|
172
|
+
|
|
173
|
+
if needed.has('randInt'):
|
|
174
|
+
parts.push(`
|
|
175
|
+
function randInt(min, max) {
|
|
176
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
177
|
+
}`)
|
|
178
|
+
|
|
179
|
+
if needed.has('sample'):
|
|
180
|
+
parts.push(`
|
|
181
|
+
function sample(arr) {
|
|
182
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
183
|
+
}`)
|
|
184
|
+
|
|
185
|
+
if needed.has('shuffle'):
|
|
186
|
+
parts.push(`
|
|
187
|
+
function shuffle(arr) {
|
|
188
|
+
var a = arr.slice();
|
|
189
|
+
for (var i = a.length - 1; i > 0; i--) {
|
|
190
|
+
var j = Math.floor(Math.random() * (i + 1));
|
|
191
|
+
var tmp = a[i]; a[i] = a[j]; a[j] = tmp;
|
|
192
|
+
}
|
|
193
|
+
return a;
|
|
194
|
+
}`)
|
|
195
|
+
|
|
196
|
+
if needed.has('pick'):
|
|
197
|
+
parts.push(`
|
|
198
|
+
function pick(obj, keys) {
|
|
199
|
+
var out = {};
|
|
200
|
+
keys.forEach(function(k) { if (Object.prototype.hasOwnProperty.call(obj, k)) out[k] = obj[k]; });
|
|
201
|
+
return out;
|
|
202
|
+
}`)
|
|
203
|
+
|
|
204
|
+
if needed.has('omit'):
|
|
205
|
+
parts.push(`
|
|
206
|
+
function omit(obj, keys) {
|
|
207
|
+
var ks = new Set(keys);
|
|
208
|
+
var out = {};
|
|
209
|
+
Object.keys(obj).forEach(function(k) { if (!ks.has(k)) out[k] = obj[k]; });
|
|
210
|
+
return out;
|
|
211
|
+
}`)
|
|
212
|
+
|
|
213
|
+
if needed.has('mapValues'):
|
|
214
|
+
parts.push(`
|
|
215
|
+
function mapValues(obj, fn) {
|
|
216
|
+
var out = {};
|
|
217
|
+
Object.keys(obj).forEach(function(k) { out[k] = fn(obj[k], k); });
|
|
218
|
+
return out;
|
|
219
|
+
}`)
|
|
220
|
+
|
|
221
|
+
if needed.has('filterValues'):
|
|
222
|
+
parts.push(`
|
|
223
|
+
function filterValues(obj, fn) {
|
|
224
|
+
var out = {};
|
|
225
|
+
Object.keys(obj).forEach(function(k) { if (fn(obj[k], k)) out[k] = obj[k]; });
|
|
226
|
+
return out;
|
|
227
|
+
}`)
|
|
228
|
+
|
|
229
|
+
if needed.has('fromEntries'):
|
|
230
|
+
parts.push(`
|
|
231
|
+
function fromEntries(entries) {
|
|
232
|
+
return Object.fromEntries(entries);
|
|
233
|
+
}`)
|
|
234
|
+
|
|
235
|
+
if needed.has('deepEqual'):
|
|
236
|
+
parts.push(`
|
|
237
|
+
function deepEqual(a, b) {
|
|
238
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
239
|
+
}`)
|
|
240
|
+
|
|
241
|
+
if needed.has('deepClone'):
|
|
242
|
+
parts.push(`
|
|
243
|
+
function deepClone(v) {
|
|
244
|
+
return JSON.parse(JSON.stringify(v));
|
|
245
|
+
}`)
|
|
246
|
+
|
|
247
|
+
if needed.has('sleep'):
|
|
248
|
+
parts.push(`
|
|
249
|
+
function sleep(ms) {
|
|
250
|
+
return new Promise(function(resolve) { setTimeout(resolve, ms); });
|
|
251
|
+
}`)
|
|
252
|
+
|
|
253
|
+
if needed.has('retry'):
|
|
254
|
+
parts.push(`
|
|
255
|
+
async function retry(fn, attempts, delay) {
|
|
256
|
+
attempts = attempts || 3;
|
|
257
|
+
delay = delay || 300;
|
|
258
|
+
for (var i = 0; i < attempts; i++) {
|
|
259
|
+
try { return await fn(); } catch(e) {
|
|
260
|
+
if (i === attempts - 1) throw e;
|
|
261
|
+
await sleep(delay * Math.pow(2, i));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}`)
|
|
265
|
+
|
|
266
|
+
if needed.has('memoize'):
|
|
267
|
+
parts.push(`
|
|
268
|
+
function memoize(fn) {
|
|
269
|
+
var cache = new Map();
|
|
270
|
+
return function() {
|
|
271
|
+
var key = JSON.stringify(arguments);
|
|
272
|
+
if (cache.has(key)) return cache.get(key);
|
|
273
|
+
var result = fn.apply(this, arguments);
|
|
274
|
+
cache.set(key, result);
|
|
275
|
+
return result;
|
|
276
|
+
};
|
|
277
|
+
}`)
|
|
278
|
+
|
|
279
|
+
if needed.has('pipe'):
|
|
280
|
+
parts.push(`
|
|
281
|
+
function pipe() {
|
|
282
|
+
var fns = Array.from(arguments);
|
|
283
|
+
return function(x) { return fns.reduce(function(v, f) { return f(v); }, x); };
|
|
284
|
+
}`)
|
|
285
|
+
|
|
286
|
+
if needed.has('compose'):
|
|
287
|
+
parts.push(`
|
|
288
|
+
function compose() {
|
|
289
|
+
var fns = Array.from(arguments);
|
|
290
|
+
return function(x) { return fns.reduceRight(function(v, f) { return f(v); }, x); };
|
|
291
|
+
}`)
|
|
292
|
+
|
|
293
|
+
if needed.has('partial'):
|
|
294
|
+
parts.push(`
|
|
295
|
+
function partial(fn) {
|
|
296
|
+
var args = Array.from(arguments).slice(1);
|
|
297
|
+
return function() { return fn.apply(this, args.concat(Array.from(arguments))); };
|
|
298
|
+
}`)
|
|
299
|
+
|
|
300
|
+
if needed.has('curry'):
|
|
301
|
+
parts.push(`
|
|
302
|
+
function curry(fn) {
|
|
303
|
+
return function curried() {
|
|
304
|
+
var args = Array.from(arguments);
|
|
305
|
+
if (args.length >= fn.length) return fn.apply(this, args);
|
|
306
|
+
return function() { return curried.apply(this, args.concat(Array.from(arguments))); };
|
|
307
|
+
};
|
|
308
|
+
}`)
|
|
309
|
+
|
|
310
|
+
if needed.has('capitalize'):
|
|
311
|
+
parts.push(`
|
|
312
|
+
function capitalize(s) {
|
|
313
|
+
return s ? s[0].toUpperCase() + s.slice(1) : s;
|
|
314
|
+
}`)
|
|
315
|
+
|
|
316
|
+
if needed.has('camelCase'):
|
|
317
|
+
parts.push(`
|
|
318
|
+
function camelCase(s) {
|
|
319
|
+
return s.replace(/[-_\\s]+(.)/g, function(_, c) { return c.toUpperCase(); }).replace(/^./, function(c) { return c.toLowerCase(); });
|
|
320
|
+
}`)
|
|
321
|
+
|
|
322
|
+
if needed.has('snakeCase'):
|
|
323
|
+
parts.push(`
|
|
324
|
+
function snakeCase(s) {
|
|
325
|
+
return s.replace(/([A-Z])/g, function(c) { return '_' + c.toLowerCase(); }).replace(/[-\\s]+/g, '_').replace(/^_/, '');
|
|
326
|
+
}`)
|
|
327
|
+
|
|
328
|
+
if needed.has('kebabCase'):
|
|
329
|
+
parts.push(`
|
|
330
|
+
function kebabCase(s) {
|
|
331
|
+
return s.replace(/([A-Z])/g, function(c) { return '-' + c.toLowerCase(); }).replace(/[_\\s]+/g, '-').replace(/^-/, '');
|
|
332
|
+
}`)
|
|
333
|
+
|
|
334
|
+
if needed.has('truncate'):
|
|
335
|
+
parts.push(`
|
|
336
|
+
function truncate(s, len, suffix) {
|
|
337
|
+
suffix = suffix != null ? suffix : '...';
|
|
338
|
+
if (s.length <= len) return s;
|
|
339
|
+
var cut = len - suffix.length;
|
|
340
|
+
if (cut <= 0) return suffix.slice(0, len);
|
|
341
|
+
return s.slice(0, cut) + suffix;
|
|
342
|
+
}`)
|
|
343
|
+
|
|
344
|
+
if needed.has('pad'):
|
|
345
|
+
parts.push(`
|
|
346
|
+
function pad(s, len, char) {
|
|
347
|
+
char = char || ' ';
|
|
348
|
+
s = String(s);
|
|
349
|
+
var total = len - s.length;
|
|
350
|
+
if (total <= 0) return s;
|
|
351
|
+
var half = Math.floor(total / 2);
|
|
352
|
+
return char.repeat(half) + s + char.repeat(total - half);
|
|
353
|
+
}`)
|
|
354
|
+
|
|
355
|
+
parts.push('// ── end stdlib ──\n')
|
|
356
|
+
return parts.join('\n')
|