kadence-lang 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/kadence-lang.svg?style=flat-square)](https://www.npmjs.com/package/kadence-lang)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
5
- [![Build Status](https://img.shields.io/badge/build-passing-brightgreen?style=flat-square)](https://github.com/kadence-lang/kadence-lang)
5
+ [![Build Status](https://img.shields.io/badge/build-passing-brightgreen?style=flat-square)](https://github.com/Down2EarthGG/Kadence-lang)
6
6
 
7
7
  **A human-readable programming language that feels like poetry.**
8
8
 
@@ -135,22 +135,32 @@ Kadence ships with a comprehensive set of modules for common tasks.
135
135
 
136
136
  | Module | Core Functionality |
137
137
  | :--- | :--- |
138
- | `list` | `first`, `lastOf`, `shuffle`, `range`, `unique` |
139
- | `string` | `trimmed`, `repeated`, `toCamelCase`, `padStart`, `words` |
140
- | `math` | `clamp`, `randomFloat`, `toRadians`, `hypotenuse` |
141
- | `datetime` | `the time now`, `the date today`, `diffDays`, `toIso` |
142
- | `file` | `readFile`, `writeFile`, `copyDir`, `removeDir`, `stat` |
138
+ | `array` | `flatten`, `zip`, `chunk`, `partition`, `take`, `drop`, `reverse`, `findIndex` |
139
+ | `async` | `delay`, `timeout`, `retry`, `debounce`, `throttle`, `parallel`, `sequential`, `waterfall` |
140
+ | `list` | `first`, `lastOf`, `shuffle`, `makeRange`, `unique`, `sort`, `sortBy` |
141
+ | `string` | `trimmed`, `repeated`, `toCamelCase`, `padStart`, `words`, `lines`, `capitalized` |
142
+ | `map` | `keys`, `values`, `entries`, `merge`, `pick`, `omit`, `mapValues`, `deepClone`, `fromPairs` |
143
+ | `set` | `union`, `intersection`, `difference`, `isSubset`, `isSuperset`, `cartesianProduct` |
144
+ | `format` | `currency`, `fileSize`, `ordinal`, `plural`, `titleCase`, `snakeCase`, `kebabCase` |
145
+ | `validation` | `isEmail`, `isUrl`, `isNumeric`, `isAlpha`, `isInRange`, `isHexColor`, `isCreditCard` |
146
+ | `math` | `clamp`, `randomFloat`, `hypotenuse`, `areaOfCircle`, `isEven`, `toRadians` |
147
+ | `datetime` | `currentTime`, `today`, `year`, `month`, `day`, `toIso`, `addDays` |
148
+ | `file` | `readFile`, `writeFile`, `copyDir`, `removeDir`, `stat`, `listDir`, `exists` |
143
149
  | `path` | `joinPaths`, `resolve`, `basename`, `dirname`, `extension` |
144
- | `env` | `getEnv`, `hasEnv` (Environment Variables) |
150
+ | `env` | `getEnv`, `hasEnv` |
145
151
  | `process` | `args`, `exit`, `cwd` |
146
- | `system` | `platform`, `arch`, `totalMemory`, `freeMemory` |
147
- | `network` | `serve`, `fetchJson` (Simple HTTP Server) |
152
+ | `system` | `platform`, `arch`, `totalMemory`, `freeMemory`, `cpus`, `homedir` |
153
+ | `network` | `serve`, `fetchJson` |
148
154
  | `json` | `readJson`, `writeJson`, `format`, `parseSafe` |
149
- | `check` | `isNumber`, `isString`, `isEmail`, `between` |
155
+ | `check` | `isNumber`, `isString`, `isEmail`, `between`, `coalesce` |
150
156
  | `test` | `suite`, `assertEquals`, `assertTrue`, `assertThrows` |
151
- | `color` | `randomHex`, `rgbToHex`, `hexToRgb` |
152
- | `html` | `div`, `span`, `p`, `img`, `link` (Browser only) |
153
- | `crypto` | `hash`, `randomBytes`, `uuid` |
157
+ | `color` | `rgb`, `rgba`, `hex`, `randomHex` |
158
+ | `html` | `tag`, `div`, `span`, `p`, `img`, `link`, `h1` |
159
+ | `crypto` | `hash`, `randomBytes` |
160
+ | `uuid` | `v4`, `validate` |
161
+ | `random` | `float`, `integer`, `choice`, `shuffle` |
162
+ | `stream` | `createReader`, `readAll`, `pipe` |
163
+ | `url` | `parseUrl`, `buildUrl`, `getSearchParam` |
154
164
 
155
165
  *Usage Example:*
156
166
  ```kadence
package/bin/kadence.js CHANGED
@@ -5,7 +5,7 @@ const readline = require("readline");
5
5
  const { execSync } = require("child_process");
6
6
  const { compile } = require("../src/compiler");
7
7
 
8
- const VERSION = "0.2.0";
8
+ const VERSION = "0.2.2";
9
9
 
10
10
  const colors = {
11
11
  reset: "\x1b[0m",
@@ -34,26 +34,32 @@ function getPkgName(pkg) {
34
34
 
35
35
  function printHelp() {
36
36
  log(`Kadence CLI v${VERSION}`, colors.bright + colors.cyan);
37
+ log("A human-readable programming language that feels like poetry", colors.dim);
37
38
  console.log(`
38
39
  Usage:
40
+ npx kadence-lang [command] [options]
41
+
42
+ Core Commands:
39
43
  kadence Start interactive REPL
40
44
  kadence <file> Compile and run a .kade file
41
45
  kadence -c <file> Compile to JavaScript only
42
- kadence -c <file> -o <out> --target browser Compile for browser (no Node APIs)
43
- kadence -c <file> -o <out> --sourcemap Emit source map for debugging
44
- kadence create <name> [--web] [--yes] Create project folder and run npm install
45
- kadence init [--web] Initialize a new project in current directory
46
- kadence install <pkg> Install a package (npm/github)
47
- kadence uninstall <pkg> Remove a package
48
- kadence update Update all dependencies
49
- kadence list List installed packages
50
- kadence run <script> Run a script from kadence.json
51
- kadence build Compile all .kade files in project
52
- kadence test Run all .test.kade files
53
- kadence docs Generate documentation from comments
54
- kadence dev Start Vite development server
55
- kadence -v Show version
56
- kadence help Show this help
46
+
47
+ Project Commands:
48
+ kadence create <name> [--web] Create a new project from a template
49
+ kadence init [--web] Initialize Kadence in existing folder
50
+ kadence dev Start Vite development server (Web only)
51
+ kadence build Compile all .kade files in project
52
+ kadence test Run all .test.kade files
53
+
54
+ Package Management:
55
+ kadence install <pkg> Install a package (kadence or npm)
56
+ kadence uninstall <pkg> Remove a package
57
+ kadence update Update all dependencies
58
+ kadence list List installed packages
59
+
60
+ Other Options:
61
+ kadence -v Show version
62
+ kadence help Show this help
57
63
  `);
58
64
  }
59
65
 
@@ -138,7 +144,7 @@ function writeScaffold(targetDir, opts) {
138
144
  const config = {
139
145
  name: projectName,
140
146
  version: version || "1.0.0",
141
- description: description || "",
147
+ description: description || "A beautiful Kadence project",
142
148
  author: author || "",
143
149
  scripts: isWeb
144
150
  ? { dev: "kadence dev", build: "kadence build --web", preview: "vite preview" }
@@ -148,19 +154,97 @@ function writeScaffold(targetDir, opts) {
148
154
 
149
155
  const mainKade = path.join(targetDir, "src", "main.kade");
150
156
  if (!fs.existsSync(mainKade)) {
151
- fs.writeFileSync(mainKade, "// Welcome to your new Kadence project!\nsay \"Hello, World!\"\n", "utf8");
157
+ if (isWeb) {
158
+ fs.writeFileSync(
159
+ mainKade,
160
+ `// Welcome to your new Kadence Web App!
161
+ say "Kadence is running!"
162
+
163
+ // Simple reactive counter example
164
+ let count = 0
165
+
166
+ function increment() {
167
+ count = count + 1
168
+ updateUI()
169
+ }
170
+
171
+ function updateUI() {
172
+ const el = document.getElementById("counter")
173
+ if el {
174
+ el.innerText = "Count: " + count
175
+ }
176
+ }
177
+
178
+ // Initialize
179
+ updateUI()
180
+
181
+ // Expose increment to window for button clicks
182
+ window.increment = increment
183
+ `,
184
+ "utf8"
185
+ );
186
+ } else {
187
+ fs.writeFileSync(
188
+ mainKade,
189
+ `// Welcome to your new Kadence Tool!
190
+ import math
191
+
192
+ say "Hello from Kadence!"
193
+ say "The square root of 144 is " + math.sqrt(144)
194
+
195
+ // Try running with: kadence src/main.kade
196
+ `,
197
+ "utf8"
198
+ );
199
+ }
152
200
  }
153
201
 
154
202
  const gitignore = path.join(targetDir, ".gitignore");
155
203
  if (!fs.existsSync(gitignore)) {
156
- fs.writeFileSync(gitignore, "node_modules/\ndist/\n*.js\n*.js.map\n", "utf8");
204
+ fs.writeFileSync(gitignore, "node_modules/\ndist/\n*.js\n*.js.map\n.DS_Store\n", "utf8");
205
+ }
206
+
207
+ const readme = path.join(targetDir, "README.md");
208
+ if (!fs.existsSync(readme)) {
209
+ fs.writeFileSync(
210
+ readme,
211
+ `# ${projectName}
212
+
213
+ ${description || "A new Kadence project."}
214
+
215
+ ## Getting Started
216
+
217
+ 1. Install dependencies:
218
+ \`\`\`bash
219
+ npm install
220
+ \`\`\`
221
+
222
+ 2. Start the project:
223
+ \`\`\`bash
224
+ ${isWeb ? "npm run dev" : "npm run start"}
225
+ \`\`\`
226
+
227
+ ## Project Structure
228
+
229
+ - \`src/\`: Source files (.kade)
230
+ - \`dist/\`: Compiled JavaScript
231
+ - \`kadence.json\`: Kadence project configuration
232
+ `,
233
+ "utf8"
234
+ );
157
235
  }
158
236
 
159
237
  const kadenceConfig = path.join(targetDir, "kadence.config.js");
160
238
  if (!fs.existsSync(kadenceConfig)) {
161
239
  fs.writeFileSync(
162
240
  kadenceConfig,
163
- "/** @type {import('kadence-lang').Config} */\nmodule.exports = {\n outDir: 'dist',\n srcDir: 'src',\n target: 'node'\n};\n",
241
+ `/** @type {import('kadence-lang').Config} */
242
+ module.exports = {
243
+ outDir: 'dist',
244
+ srcDir: 'src',
245
+ target: '${isWeb ? "browser" : "node"}'
246
+ };
247
+ `,
164
248
  "utf8"
165
249
  );
166
250
  }
@@ -172,11 +256,13 @@ function writeScaffold(targetDir, opts) {
172
256
  const pkg = {
173
257
  name: projectName,
174
258
  version: version || "1.0.0",
259
+ description: description || "",
175
260
  type: "commonjs",
176
- dependencies: { "kadence-lang": "latest" },
261
+ scripts: config.scripts,
262
+ dependencies: { "kadence-lang": "^0.2.1" },
177
263
  };
178
264
  if (isWeb) {
179
- pkg.devDependencies = { vite: "latest", "vite-plugin-kadence": "latest" };
265
+ pkg.devDependencies = { vite: "latest", "vite-plugin-kadence": "^0.2.1" };
180
266
  }
181
267
  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
182
268
  }
@@ -187,18 +273,146 @@ function writeScaffold(targetDir, opts) {
187
273
  fs.writeFileSync(
188
274
  indexHtml,
189
275
  `<!DOCTYPE html>
190
- <html>
276
+ <html lang="en">
191
277
  <head>
192
- <title>${projectName}</title>
278
+ <meta charset="UTF-8">
279
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
280
+ <title>${projectName} | Kadence</title>
281
+ <link rel="stylesheet" href="/src/style.css">
282
+ <link rel="preconnect" href="https://fonts.googleapis.com">
283
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
284
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600&display=swap" rel="stylesheet">
193
285
  </head>
194
286
  <body>
195
- <div id="app"></div>
287
+ <div class="container">
288
+ <header>
289
+ <div class="logo">♪</div>
290
+ <h1>${projectName}</h1>
291
+ <p class="subtitle">Built with Kadence</p>
292
+ </header>
293
+
294
+ <main>
295
+ <div class="card">
296
+ <h2 id="counter">Count: 0</h2>
297
+ <button onclick="increment()">Increment</button>
298
+ </div>
299
+
300
+ <div class="info">
301
+ <p>Edit <code>src/main.kade</code> to get started.</p>
302
+ </div>
303
+ </main>
304
+ </div>
196
305
  <script type="module" src="/src/main.kade"></script>
197
306
  </body>
198
307
  </html>`,
199
308
  "utf8"
200
309
  );
201
310
  }
311
+
312
+ const styleCss = path.join(targetDir, "src", "style.css");
313
+ if (!fs.existsSync(styleCss)) {
314
+ fs.writeFileSync(
315
+ styleCss,
316
+ `body {
317
+ margin: 0;
318
+ padding: 0;
319
+ font-family: 'Outfit', sans-serif;
320
+ background: radial-gradient(circle at top right, #1a1a2e, #0f0f1b);
321
+ color: white;
322
+ min-height: 100vh;
323
+ display: flex;
324
+ justify-content: center;
325
+ align-items: center;
326
+ }
327
+
328
+ .container {
329
+ text-align: center;
330
+ max-width: 600px;
331
+ padding: 2rem;
332
+ }
333
+
334
+ header {
335
+ margin-bottom: 3rem;
336
+ }
337
+
338
+ .logo {
339
+ font-size: 4rem;
340
+ margin-bottom: 1rem;
341
+ background: linear-gradient(135deg, #00f2fe 0%, #4facfe 100%);
342
+ -webkit-background-clip: text;
343
+ -webkit-text-fill-color: transparent;
344
+ }
345
+
346
+ h1 {
347
+ font-weight: 600;
348
+ font-size: 2.5rem;
349
+ margin: 0;
350
+ }
351
+
352
+ .subtitle {
353
+ color: #94a3b8;
354
+ font-size: 1.1rem;
355
+ margin-top: 0.5rem;
356
+ }
357
+
358
+ .card {
359
+ background: rgba(255, 255, 255, 0.05);
360
+ backdrop-filter: blur(10px);
361
+ border: 1px solid rgba(255, 255, 255, 0.1);
362
+ padding: 2.5rem;
363
+ border-radius: 24px;
364
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
365
+ margin-bottom: 2rem;
366
+ transition: transform 0.3s ease;
367
+ }
368
+
369
+ .card:hover {
370
+ transform: translateY(-5px);
371
+ }
372
+
373
+ h2 {
374
+ font-size: 2rem;
375
+ margin-bottom: 1.5rem;
376
+ }
377
+
378
+ button {
379
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
380
+ border: none;
381
+ color: white;
382
+ padding: 0.75rem 2rem;
383
+ font-size: 1.1rem;
384
+ font-weight: 600;
385
+ border-radius: 12px;
386
+ cursor: pointer;
387
+ transition: all 0.2s ease;
388
+ box-shadow: 0 10px 15px -3px rgba(79, 172, 254, 0.3);
389
+ }
390
+
391
+ button:hover {
392
+ transform: scale(1.05);
393
+ box-shadow: 0 20px 25px -5px rgba(79, 172, 254, 0.4);
394
+ }
395
+
396
+ button:active {
397
+ transform: scale(0.98);
398
+ }
399
+
400
+ .info {
401
+ color: #64748b;
402
+ font-size: 0.9rem;
403
+ }
404
+
405
+ code {
406
+ background: rgba(255, 255, 255, 0.1);
407
+ padding: 0.2rem 0.4rem;
408
+ border-radius: 4px;
409
+ color: #e2e8f0;
410
+ }
411
+ `,
412
+ "utf8"
413
+ );
414
+ }
415
+
202
416
  const viteConfig = path.join(targetDir, "vite.config.js");
203
417
  if (!fs.existsSync(viteConfig)) {
204
418
  fs.writeFileSync(
@@ -207,7 +421,11 @@ function writeScaffold(targetDir, opts) {
207
421
  import { kadencePlugin } from './vite-plugin-kadence';
208
422
 
209
423
  export default defineConfig({
210
- plugins: [kadencePlugin()]
424
+ plugins: [kadencePlugin()],
425
+ server: {
426
+ port: 3000,
427
+ open: true
428
+ }
211
429
  });`,
212
430
  "utf8"
213
431
  );
package/icon.svg ADDED
@@ -0,0 +1,76 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
3
+ <defs>
4
+ <!-- Premium Dark Gradient Background -->
5
+ <linearGradient id="bgGradient" x1="0%" y1="0%" x2="100%" y2="100%">
6
+ <stop offset="0%" style="stop-color:#1a1a2e;stop-opacity:1" />
7
+ <stop offset="100%" style="stop-color:#16213e;stop-opacity:1" />
8
+ </linearGradient>
9
+
10
+ <!-- Vibrant Accent Gradient (vertical) -->
11
+ <linearGradient id="accentGradient" x1="0%" y1="0%" x2="0%" y2="100%">
12
+ <stop offset="0%" style="stop-color:#06d6a0;stop-opacity:1" />
13
+ <stop offset="50%" style="stop-color:#118ab2;stop-opacity:1" />
14
+ <stop offset="100%" style="stop-color:#7b2cbf;stop-opacity:1" />
15
+ </linearGradient>
16
+
17
+ <!-- Outer Glow Effect -->
18
+ <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
19
+ <feGaussianBlur stdDeviation="6" result="coloredBlur"/>
20
+ <feMerge>
21
+ <feMergeNode in="coloredBlur"/>
22
+ <feMergeNode in="SourceGraphic"/>
23
+ </feMerge>
24
+ </filter>
25
+
26
+ <!-- Subtle Drop Shadow -->
27
+ <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
28
+ <feDropShadow dx="0" dy="4" stdDeviation="10" flood-color="#000000" flood-opacity="0.3"/>
29
+ </filter>
30
+ </defs>
31
+
32
+ <!-- Background Container with Rounded Corners -->
33
+ <rect x="24" y="24" width="464" height="464" rx="96" fill="url(#bgGradient)" filter="url(#shadow)"/>
34
+
35
+ <!-- Subtle Border Ring -->
36
+ <rect x="24" y="24" width="464" height="464" rx="96" fill="none" stroke="url(#accentGradient)" stroke-width="3" opacity="0.4"/>
37
+
38
+ <!-- Rebuilt, unified Kadence "K" -->
39
+ <g filter="url(#glow)">
40
+ <!-- Single sculpted K shape using negative space logic -->
41
+ <path
42
+ d="
43
+ M 120 116
44
+ L 160 116
45
+ L 160 220
46
+ L 230 160
47
+ Q 244 148 262 148
48
+ L 292 148
49
+ L 292 188
50
+ Q 276 188 266 196
51
+ L 200 252
52
+ L 270 320
53
+ Q 284 334 304 334
54
+ L 332 334
55
+ L 332 374
56
+ L 296 374
57
+ Q 270 374 252 356
58
+ L 180 286
59
+ L 160 304
60
+ L 160 396
61
+ L 120 396
62
+ Z
63
+ "
64
+ fill="url(#accentGradient)"
65
+ />
66
+
67
+ <!-- Accent rhythm bars to the right -->
68
+ <rect x="320" y="196" width="24" height="120" rx="12" fill="#06d6a0" opacity="0.9"/>
69
+ <rect x="360" y="161" width="24" height="190" rx="12" fill="#118ab2" opacity="0.85"/>
70
+ <rect x="400" y="216" width="24" height="80" rx="12" fill="#7b2cbf" opacity="0.8"/>
71
+ </g>
72
+
73
+ <!-- Small accent dots for visual interest -->
74
+ <circle cx="420" cy="100" r="8" fill="#06d6a0" opacity="0.6"/>
75
+ <circle cx="100" cy="420" r="6" fill="#7b2cbf" opacity="0.5"/>
76
+ </svg>
package/package.json CHANGED
@@ -1,25 +1,28 @@
1
1
  {
2
2
  "name": "kadence-lang",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "A human-readable programming language that feels like poetry",
5
+ "icon": "icon.svg",
5
6
  "main": "src/compiler.js",
6
7
  "bin": {
7
- "kadence": "./bin/kadence.js"
8
+ "kadence": "./bin/kadence.js",
9
+ "kadence-lang": "./bin/kadence.js"
8
10
  },
9
11
  "repository": {
10
12
  "type": "git",
11
- "url": "git+https://github.com/kadence-lang/kadence-lang.git"
13
+ "url": "git+https://github.com/Down2EarthGG/Kadence-lang.git"
12
14
  },
13
15
  "bugs": {
14
- "url": "https://github.com/kadence-lang/kadence-lang/issues"
16
+ "url": "https://github.com/Down2EarthGG/Kadence-lang/issues"
15
17
  },
16
- "homepage": "https://github.com/kadence-lang/kadence-lang#readme",
18
+ "homepage": "https://github.com/Down2EarthGG/Kadence-lang#readme",
17
19
  "files": [
18
20
  "src/",
19
21
  "bin/",
20
22
  "stdlib/",
21
23
  "README.md",
22
- "LICENSE"
24
+ "LICENSE",
25
+ "icon.svg"
23
26
  ],
24
27
  "engines": {
25
28
  "node": ">=14.0.0"
@@ -28,9 +31,9 @@
28
31
  "dev": "npm run serve:demo",
29
32
  "demo": "npm run serve:demo",
30
33
  "build:demo": "node scripts/build-demo.js",
31
- "serve:demo": "npm run build:demo && serve . -p 3000",
34
+ "serve:demo": "npm run build:demo && serve apps/website -p 3000",
32
35
  "build:apps": "node scripts/build-apps.js",
33
- "serve:apps": "npm run build:apps && serve . -p 3000",
36
+ "serve:apps": "npm run build:apps && serve apps/website -p 3000",
34
37
  "test": "vitest run",
35
38
  "lint": "eslint .",
36
39
  "lint:fix": "eslint . --fix",
@@ -48,10 +51,7 @@
48
51
  "author": "The Kadence Team",
49
52
  "license": "MIT",
50
53
  "dependencies": {
51
- "lodash": "^4.17.23",
52
54
  "ohm-js": "^17.3.0",
53
- "readline-sync": "^1.4.10",
54
- "safe-eval": "^0.4.1",
55
55
  "source-map": "^0.7.4"
56
56
  },
57
57
  "devDependencies": {
@@ -0,0 +1,92 @@
1
+ # Review: New stdlib Libraries
2
+
3
+ Summary of the new/untracked stdlib modules and fixes applied.
4
+
5
+ ---
6
+
7
+ ## 1. **array.kade** ✓
8
+
9
+ Pure Kadence array utilities: `flatten`, `zip`, `chunk`, `partition`, `take`, `drop`, `reverse`, `findIndex`.
10
+
11
+ - **Style**: Uses `list`, `add … to result`, `size of`, `increment`/`decrement` consistently.
12
+ - **Note**: `flatten` treats any `elem` with `typeof "object"` and `elem.length` as nested array; that matches array-like values. Consider documenting that only one level of “array-like” is assumed if you want to avoid surprises with non-Array objects.
13
+
14
+ ---
15
+
16
+ ## 2. **async.kade** + **async-helpers.js** ✓
17
+
18
+ Kadence wrapper over JS helpers: `delay`, `timeout`, `retry`, `debounce`, `throttle`, `parallel`, `race`, `sequential`, `waterfall`, `batch`.
19
+
20
+ - **Pattern**: Same as other `.kade` + `-helpers.js` pairs: Kadence exports call `run require "./async-helpers.js"` and `run mod.<name> …`.
21
+ - **async-helpers.js**: Clear, no extra dependencies; `batch` expects `processFn(batchItems)` to return an array of results.
22
+ - **async.js**: Generated output; contains leftover `__kadence_*` and `fs` at the top. Prefer regenerating from `async.kade` or trimming the stub so only the actual exports remain.
23
+
24
+ ---
25
+
26
+ ## 3. **format.kade** + **format-helpers.js** ✓ (ordinal fixed)
27
+
28
+ Formatting: `currency`, `formatNumber`, `percentage`, `fileSize`, `ordinal`, `plural`, `truncate`, `ellipsis`, `padNumber`, `phoneNumber`, `titleCase`, `snakeCase`, `kebabCase`.
29
+
30
+ - **ordinal**: Logic was wrong for both remainder and 11/12/13. Updated to use `floor` for integer-like behavior and to treat 11–13 correctly (e.g. 11th, 12th, 13th, 21st, 22nd).
31
+ - **format-helpers.js**: Only `currency` and `phoneNumber`; used via `require`. Fine as-is.
32
+ - **titleCase**: Uses `split`/`join`/`uppercase`/`lowercase`; consistent with language reference.
33
+
34
+ ---
35
+
36
+ ## 4. **map.kade** + **map.js** + **object-helpers.js** ✓
37
+
38
+ Map/object utilities: `keys`, `values`, `entries`, `hasKey`, `merge`, `pick`, `omit`, `mapValues`, `mapKeys`, `invert`, `isEmpty`, `fromPairs`.
39
+
40
+ - **map.kade**: Delegates to `object-helpers.js` for everything except `isEmpty` (uses `Object.keys`) and `fromPairs` (inline loop). Good split.
41
+ - **object-helpers.js**: Provides `pick`, `omit`, `deepClone`, `get`, `defaults`, plus key/values/entries/hasKey/merge/mapValues/mapKeys/invert. `map.kade` does not yet expose `deepClone`, `get`, or `defaults`; add wrappers in `map.kade` if you want them in the public API.
42
+ - **fromPairs**: Uses `let result = {}` and `result[pair[0]] = pair[1]`. For consistency with LANGUAGE_REFERENCE (“Object: object { key: val }”), you could use `object {}` and `set … of result to …` if the compiler supports empty `object {}` and property set.
43
+
44
+ ---
45
+
46
+ ## 5. **set.kade** ✓
47
+
48
+ Set operations on lists (no native Set): `union`, `intersection`, `difference`, `symmetricDifference`, `isSubset`, `isSuperset`, `areDisjoint`, `cartesianProduct`.
49
+
50
+ - **Style**: Pure Kadence, no JS helpers; uses nested `for each` and equality. Readable.
51
+ - **Cost**: O(n²) in many places (e.g. membership via linear search). Acceptable for small sets; for large sets consider a JS helper backed by `Set` and call it from a thin `.kade` wrapper (like async/format).
52
+
53
+ ---
54
+
55
+ ## 6. **validation.kade** ✓ (comparisons fixed)
56
+
57
+ Validators: `isEmail`, `isUrl`, `isNumeric`, `isAlpha`, `isAlphanumeric`, `isInteger`, `isPositive`, `isNegative`, `isInRange`, `isLength`, `isEmpty`/`isNotEmpty`, `isHexColor`, `isIpAddress`, `isPhoneNumber`, `isCreditCard` (Luhn), `isStrongPassword`.
58
+
59
+ - **Comparisons**: The compiler only supports `at least` / `at most` for ≥/≤ (see `CompareOp` in grammar). Replaced “more than or equals” / “less than or equals” with “at least” / “at most” in `isInRange`, `isLength`, `isPhoneNumber`, and the Luhn loop.
60
+ - **Name clash**: Resolved by renaming string “blank” check from `isEmpty` to `isBlank`; `isNotEmpty` now calls `isBlank`.
61
+ - **Luhn**: Logic for `isCreditCard` is correct; `(sum / 10) * 10 equals sum` is a valid way to express “sum divisible by 10” without a mod operator.
62
+
63
+ ---
64
+
65
+ ## 7. **object-helpers.js** (modified)
66
+
67
+ Shared implementation for object/map operations. Used by **map.kade**; no issues found. Exports are consistent with what **map.kade** calls.
68
+
69
+ ---
70
+
71
+ ## 8. **.object.kade.js**
72
+
73
+ Appears to be compiled output (e.g. from a file like `object.kade`). Typically such files are generated; consider adding them to `.gitignore` or generating them in a build step so they aren’t committed as source.
74
+
75
+ ---
76
+
77
+ ## Summary of changes made
78
+
79
+ | File | Change |
80
+ |------------------|------------------------------------------------------------------------|
81
+ | **validation.kade** | Replaced “more than or equals” / “less than or equals” with “at least” / “at most” in four places so the code parses and runs. |
82
+ | **format.kade** | Reworked `ordinal` to use `floor` for tens/remainder and to handle 11–13 correctly (e.g. 11th, 21st). |
83
+
84
+ ---
85
+
86
+ ## Recommendations (implemented)
87
+
88
+ 1. **Consistency**: Use “at least” / “at most” everywhere; **validation.kade** and **test-reverse.kade** were updated.
89
+ 2. **validation.kade** `isEmpty`: Renamed to `isBlank`; `isNotEmpty` now calls `isBlank`.
90
+ 3. **map.kade**: Exposes `deepClone`, `get`, and `defaults` from **object-helpers.js**; **map.js** updated to match.
91
+ 4. **async.js / map.js**: Removed `__kadence_*` and `fs` stubs so the emitted JS is minimal.
92
+ 5. **.object.kade.js**: Added `stdlib/.object.kade.js` to **.gitignore** so generated output is not committed.