ansimax 1.0.0 → 1.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 +201 -21
- package/README.es.md +697 -629
- package/README.md +444 -376
- package/dist/index.d.mts +1256 -336
- package/dist/index.d.ts +1256 -336
- package/dist/index.js +4391 -683
- package/dist/index.mjs +4293 -682
- package/examples/01-cli-installer.ts +96 -0
- package/examples/02-live-dashboard.ts +152 -0
- package/examples/03-pixel-art-game.ts +170 -0
- package/examples/04-interactive-deploy.ts +163 -0
- package/examples/05-tree-visualizations.ts +183 -0
- package/examples/06-everything-together.ts +466 -0
- package/examples/animations.ts +172 -0
- package/examples/demo.js +213 -0
- package/examples/demo.ts +212 -0
- package/examples/loaders.ts +254 -0
- package/examples/showcase.ts +174 -0
- package/examples/trees-basic.ts +99 -0
- package/examples/tsconfig.json +18 -0
- package/examples/tsconfig.vscode.json +25 -0
- package/package.json +20 -8
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────
|
|
2
|
+
// EXAMPLE 5 — Tree visualizations
|
|
3
|
+
//
|
|
4
|
+
// Demonstrates the new `trees` module with 4 real-world scenarios:
|
|
5
|
+
// 1. Filesystem tree with icons + per-node colors
|
|
6
|
+
// 2. Dependency tree with depth-based palette + collapsed nodes
|
|
7
|
+
// 3. JSON-as-tree with multiline values + max-depth truncation
|
|
8
|
+
// 4. Heavy-style decision tree with guide colors
|
|
9
|
+
//
|
|
10
|
+
// Run:
|
|
11
|
+
// npx ts-node examples/05-tree-visualizations.ts
|
|
12
|
+
// ─────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
trees, tree,
|
|
16
|
+
themes, color,
|
|
17
|
+
components,
|
|
18
|
+
} from '../dist/index.js';
|
|
19
|
+
|
|
20
|
+
const main = (): void => {
|
|
21
|
+
// ─────────────────────────────────────────────
|
|
22
|
+
// Scenario 1: Filesystem tree
|
|
23
|
+
// ─────────────────────────────────────────────
|
|
24
|
+
console.log();
|
|
25
|
+
console.log(components.section(themes.primary('Project structure'), { width: 60 }));
|
|
26
|
+
console.log();
|
|
27
|
+
|
|
28
|
+
const fs = tree({ label: 'my-app', icon: '📁', color: themes.primary });
|
|
29
|
+
const src = fs.add({ label: 'src', icon: '📁' });
|
|
30
|
+
src.addLeaf({ label: 'index.ts', icon: '📄', color: themes.accent })
|
|
31
|
+
.addLeaf({ label: 'app.ts', icon: '📄', color: themes.accent })
|
|
32
|
+
.addLeaf({ label: 'utils', icon: '📁' });
|
|
33
|
+
src.children![2]!.children = [
|
|
34
|
+
{ label: 'helpers.ts', icon: '📄', color: themes.accent },
|
|
35
|
+
{ label: 'constants.ts', icon: '📄', color: themes.accent },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const tests = fs.add({ label: 'tests', icon: '📁' });
|
|
39
|
+
tests.addLeaf({ label: 'app.test.ts', icon: '🧪', color: themes.warning })
|
|
40
|
+
.addLeaf({ label: 'utils.test.ts', icon: '🧪', color: themes.warning });
|
|
41
|
+
|
|
42
|
+
fs.add({ label: 'package.json', icon: '📦', color: themes.muted });
|
|
43
|
+
fs.add({ label: 'README.md', icon: '📖', color: themes.muted });
|
|
44
|
+
fs.add({ label: 'tsconfig.json', icon: '⚙️', color: themes.muted });
|
|
45
|
+
|
|
46
|
+
console.log(fs.render({ guideColor: themes.muted }));
|
|
47
|
+
|
|
48
|
+
// ─────────────────────────────────────────────
|
|
49
|
+
// Scenario 2: Dependency tree with collapsed branches
|
|
50
|
+
// ─────────────────────────────────────────────
|
|
51
|
+
console.log();
|
|
52
|
+
console.log(components.section(themes.primary('Dependency tree (with collapse)'), { width: 60 }));
|
|
53
|
+
console.log();
|
|
54
|
+
|
|
55
|
+
const deps = tree('myapp@1.0.0');
|
|
56
|
+
const react = deps.add('react@18.2.0');
|
|
57
|
+
react.addLeaf('scheduler@0.23.0').addLeaf('loose-envify@1.4.0');
|
|
58
|
+
|
|
59
|
+
const express = deps.add('express@4.18.2');
|
|
60
|
+
// 14 transitive deps — collapse to show only the last 3
|
|
61
|
+
express.add({
|
|
62
|
+
label: 'transitive dependencies',
|
|
63
|
+
collapse: 11,
|
|
64
|
+
children: [
|
|
65
|
+
{ label: 'accepts@1.3.8' },
|
|
66
|
+
{ label: 'array-flatten@1.1.1' },
|
|
67
|
+
{ label: 'body-parser@1.20.1' },
|
|
68
|
+
{ label: 'content-disposition@0.5.4' },
|
|
69
|
+
{ label: 'content-type@1.0.5' },
|
|
70
|
+
{ label: 'cookie@0.5.0' },
|
|
71
|
+
{ label: 'cookie-signature@1.0.6' },
|
|
72
|
+
{ label: 'debug@2.6.9' },
|
|
73
|
+
{ label: 'depd@2.0.0' },
|
|
74
|
+
{ label: 'encodeurl@1.0.2' },
|
|
75
|
+
{ label: 'escape-html@1.0.3' },
|
|
76
|
+
{ label: 'etag@1.8.1' },
|
|
77
|
+
{ label: 'finalhandler@1.2.0' },
|
|
78
|
+
{ label: 'fresh@0.5.2' },
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
deps.add('lodash@4.17.21');
|
|
83
|
+
|
|
84
|
+
console.log(deps.render({
|
|
85
|
+
palette: [
|
|
86
|
+
color.cyan, // depth 0 (root)
|
|
87
|
+
color.yellow, // depth 1 (direct deps)
|
|
88
|
+
color.gray, // depth 2+ (transitive)
|
|
89
|
+
],
|
|
90
|
+
guideColor: themes.muted,
|
|
91
|
+
style: 'rounded',
|
|
92
|
+
}));
|
|
93
|
+
|
|
94
|
+
// ─────────────────────────────────────────────
|
|
95
|
+
// Scenario 3: JSON-as-tree with maxDepth
|
|
96
|
+
// ─────────────────────────────────────────────
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(components.section(themes.primary('Config tree (maxDepth: 2)'), { width: 60 }));
|
|
99
|
+
console.log();
|
|
100
|
+
|
|
101
|
+
const cfg = tree({ label: 'tsconfig.json', icon: '⚙️' });
|
|
102
|
+
const compiler = cfg.add({ label: 'compilerOptions', icon: '🔧' });
|
|
103
|
+
compiler.addLeaf('target: "ES2022"')
|
|
104
|
+
.addLeaf('module: "ESNext"')
|
|
105
|
+
.addLeaf({ label: 'lib', children: [
|
|
106
|
+
{ label: '"ES2022"' },
|
|
107
|
+
{ label: '"DOM"' },
|
|
108
|
+
{ label: '"DOM.Iterable"' },
|
|
109
|
+
]})
|
|
110
|
+
.addLeaf({ label: 'paths', children: [
|
|
111
|
+
{ label: '"@/*": ["./src/*"]' },
|
|
112
|
+
{ label: '"@utils/*": ["./src/utils/*"]' },
|
|
113
|
+
]});
|
|
114
|
+
|
|
115
|
+
cfg.add({ label: 'include', children: [
|
|
116
|
+
{ label: '"src/**/*"' },
|
|
117
|
+
{ label: '"tests/**/*"' },
|
|
118
|
+
]});
|
|
119
|
+
cfg.add({ label: 'exclude', children: [
|
|
120
|
+
{ label: '"node_modules"' },
|
|
121
|
+
{ label: '"dist"' },
|
|
122
|
+
]});
|
|
123
|
+
|
|
124
|
+
console.log(cfg.render({
|
|
125
|
+
maxDepth: 2,
|
|
126
|
+
guideColor: themes.muted,
|
|
127
|
+
}));
|
|
128
|
+
|
|
129
|
+
// ─────────────────────────────────────────────
|
|
130
|
+
// Scenario 4: Decision tree with heavy style + multiline
|
|
131
|
+
// ─────────────────────────────────────────────
|
|
132
|
+
console.log();
|
|
133
|
+
console.log(components.section(themes.primary('Decision flow (heavy + multiline)'), { width: 60 }));
|
|
134
|
+
console.log();
|
|
135
|
+
|
|
136
|
+
const decision = tree({
|
|
137
|
+
label: 'User clicks "Deploy"',
|
|
138
|
+
icon: '🚀',
|
|
139
|
+
color: themes.primary,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const valid = decision.add({
|
|
143
|
+
label: 'Tests pass?\n(must include integration suite)',
|
|
144
|
+
color: color.cyan,
|
|
145
|
+
});
|
|
146
|
+
valid.add({ label: 'Yes → Deploy to production', color: themes.accent, icon: '✓' });
|
|
147
|
+
valid.add({
|
|
148
|
+
label: 'No → Block deployment\nNotify team via Slack',
|
|
149
|
+
color: themes.error,
|
|
150
|
+
icon: '✗',
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
decision.add({
|
|
154
|
+
label: 'Build artifact > 100MB?',
|
|
155
|
+
color: color.cyan,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
console.log(decision.render({
|
|
159
|
+
style: 'heavy',
|
|
160
|
+
guideColor: themes.warning,
|
|
161
|
+
}));
|
|
162
|
+
|
|
163
|
+
// ─────────────────────────────────────────────
|
|
164
|
+
// Bonus: walkTree to count nodes
|
|
165
|
+
// ─────────────────────────────────────────────
|
|
166
|
+
console.log();
|
|
167
|
+
let nodeCount = 0;
|
|
168
|
+
let leafCount = 0;
|
|
169
|
+
trees.walk(fs, (node) => {
|
|
170
|
+
nodeCount++;
|
|
171
|
+
if (!node.children || node.children.length === 0) leafCount++;
|
|
172
|
+
});
|
|
173
|
+
console.log(themes.muted(`📊 Project tree: ${nodeCount} nodes total, ${leafCount} leaves`));
|
|
174
|
+
|
|
175
|
+
// ─────────────────────────────────────────────
|
|
176
|
+
// Bonus: measureTree for layout
|
|
177
|
+
// ─────────────────────────────────────────────
|
|
178
|
+
const dims = trees.measure(fs, { guideColor: themes.muted });
|
|
179
|
+
console.log(themes.muted(`📐 Renders as ${dims.width}×${dims.height} characters`));
|
|
180
|
+
console.log();
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
main();
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ansimax — comprehensive showcase
|
|
3
|
+
*
|
|
4
|
+
* A fictional CLI for deploying a microservices stack. Demonstrates EVERY
|
|
5
|
+
* module of ansimax in a cohesive narrative.
|
|
6
|
+
*
|
|
7
|
+
* Run: npx tsx examples/06-everything-together.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
// Config
|
|
12
|
+
configure, getConfig, onConfigKeyChange, withConfig,
|
|
13
|
+
// Themes
|
|
14
|
+
createTheme, themes,
|
|
15
|
+
// Color
|
|
16
|
+
color, gradient, registerPreset,
|
|
17
|
+
// ASCII
|
|
18
|
+
ascii,
|
|
19
|
+
// Animate
|
|
20
|
+
animate,
|
|
21
|
+
// Loader
|
|
22
|
+
loader,
|
|
23
|
+
// Frames
|
|
24
|
+
frames,
|
|
25
|
+
// Components
|
|
26
|
+
components,
|
|
27
|
+
// Images
|
|
28
|
+
images, createCanvas, gradientRect,
|
|
29
|
+
// Trees
|
|
30
|
+
tree, findInTree, countNodes, walkTree,
|
|
31
|
+
// Utils — ANSI
|
|
32
|
+
setTitle, link, bell, cursor, createOutputBuffer, write,
|
|
33
|
+
// Utils — helpers
|
|
34
|
+
padBoth, safeJson, once, escapeRegex, sleep,
|
|
35
|
+
} from '../dist/index.js';
|
|
36
|
+
|
|
37
|
+
// ────────────────────────────────────────────────────────────────
|
|
38
|
+
// 0. Bootstrap
|
|
39
|
+
// ────────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
process.stdout.write(setTitle('ansimax demo — deploying stack'));
|
|
42
|
+
|
|
43
|
+
configure({
|
|
44
|
+
colorMode: 'auto',
|
|
45
|
+
animationSpeed: 'normal',
|
|
46
|
+
theme: 'dracula',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const offThemeListener = onConfigKeyChange('theme', (newTheme, oldTheme) => {
|
|
50
|
+
console.log(color.dim(` [config] theme: ${oldTheme} → ${newTheme}`));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Custom gradient preset
|
|
54
|
+
registerPreset('sunsetSky', ['#ff6b6b', '#feca57', '#48dbfb']);
|
|
55
|
+
|
|
56
|
+
// Reusable stops for section headers
|
|
57
|
+
const SECTION_STOPS = ['#ff6b6b', '#feca57', '#48dbfb'];
|
|
58
|
+
|
|
59
|
+
// ────────────────────────────────────────────────────────────────
|
|
60
|
+
// 1. Banner
|
|
61
|
+
// ────────────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
const printBanner = (): void => {
|
|
64
|
+
console.clear();
|
|
65
|
+
const banner = ascii.banner('ansimax', {
|
|
66
|
+
font: 'big',
|
|
67
|
+
align: 'center',
|
|
68
|
+
colorFn: (t: string) => gradient(t, ['#bd93f9', '#ff79c6', '#50fa7b']),
|
|
69
|
+
});
|
|
70
|
+
console.log(banner);
|
|
71
|
+
|
|
72
|
+
const subtitle = color.dim('comprehensive showcase — every module in one demo');
|
|
73
|
+
console.log(padBoth(subtitle, 80));
|
|
74
|
+
|
|
75
|
+
// ascii.divider — DividerOptions has only char/width/label/style (no color).
|
|
76
|
+
// Apply color externally via color.hex().
|
|
77
|
+
const { width } = ascii.measure('ansimax', 'big');
|
|
78
|
+
console.log(color.hex('#6272a4')(
|
|
79
|
+
ascii.divider({ width: Math.max(width, 60), char: '═' }),
|
|
80
|
+
));
|
|
81
|
+
console.log();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// ────────────────────────────────────────────────────────────────
|
|
85
|
+
// 2. Sections helper
|
|
86
|
+
// ────────────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
const section = (title: string): void => {
|
|
89
|
+
console.log();
|
|
90
|
+
console.log(gradient(`▸ ${title}`, SECTION_STOPS));
|
|
91
|
+
console.log(color.dim('─'.repeat(60)));
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// ────────────────────────────────────────────────────────────────
|
|
95
|
+
// 3. Theme demo
|
|
96
|
+
// ────────────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
const themeDemo = (): void => {
|
|
99
|
+
section('1 · Themes (per-instance isolation)');
|
|
100
|
+
|
|
101
|
+
const tenantA = createTheme('dracula');
|
|
102
|
+
const tenantB = createTheme('nord');
|
|
103
|
+
|
|
104
|
+
tenantA.register('corporate', {
|
|
105
|
+
name: 'Corporate',
|
|
106
|
+
primary: '#0066cc',
|
|
107
|
+
secondary: '#ffcc00',
|
|
108
|
+
accent: '#00aa66',
|
|
109
|
+
success: '#00aa66',
|
|
110
|
+
warning: '#ff8800',
|
|
111
|
+
error: '#cc0033',
|
|
112
|
+
info: '#0099ff',
|
|
113
|
+
muted: '#999999',
|
|
114
|
+
bg: '#ffffff',
|
|
115
|
+
surface: '#f5f5f5',
|
|
116
|
+
text: '#222222',
|
|
117
|
+
gradient: ['#0066cc', '#00aa66'],
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log(` ${tenantA.primary('tenantA')} themes: ${tenantA.list().length}`);
|
|
121
|
+
console.log(` ${tenantB.secondary('tenantB')} themes: ${tenantB.list().length} ${color.dim("(no 'corporate')")}`);
|
|
122
|
+
|
|
123
|
+
const switched = tenantA.tryUse('not-a-theme');
|
|
124
|
+
console.log(` tryUse('not-a-theme') → ${switched ? color.green('ok') : color.red('false (handled)')}`);
|
|
125
|
+
|
|
126
|
+
console.log(` ${tenantA.bgPrimary(' PRIMARY ')}${tenantA.bgAccent(' ACCENT ')}${tenantA.bgError(' ERROR ')}`);
|
|
127
|
+
|
|
128
|
+
console.log();
|
|
129
|
+
console.log(themes.preview());
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// ────────────────────────────────────────────────────────────────
|
|
133
|
+
// 4. Color showcase
|
|
134
|
+
// ────────────────────────────────────────────────────────────────
|
|
135
|
+
|
|
136
|
+
const colorDemo = (): void => {
|
|
137
|
+
section('2 · Colors (gradients, presets, composition)');
|
|
138
|
+
|
|
139
|
+
console.log(
|
|
140
|
+
' ' + color.red('red ') + color.green('green ') + color.blue('blue ') +
|
|
141
|
+
color.bold('bold ') + color.italic('italic ') + color.underline('underline'),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
console.log(' ' + gradient('multi-stop gradient — fire to ocean', ['#ff6b6b', '#feca57', '#48dbfb']));
|
|
145
|
+
|
|
146
|
+
// Built-in rainbow preset
|
|
147
|
+
console.log(' ' + color.rainbow('built-in rainbow preset'));
|
|
148
|
+
|
|
149
|
+
// Custom registered preset — registerPreset adds a stop list, accessed via gradient()
|
|
150
|
+
console.log(' ' + gradient('custom registered preset (sunsetSky)', ['#ff6b6b', '#feca57', '#48dbfb']));
|
|
151
|
+
|
|
152
|
+
// Compose: bold + red + underline
|
|
153
|
+
const danger = (s: string): string => color.bold(color.red(color.underline(s)));
|
|
154
|
+
console.log(' ' + danger('composed: bold + red + underline'));
|
|
155
|
+
|
|
156
|
+
// ColorFn signature is (text: string) — coerce non-strings ourselves
|
|
157
|
+
console.log(' ' + color.cyan(String(42)) + ' ' + color.magenta(String(true)));
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// ────────────────────────────────────────────────────────────────
|
|
161
|
+
// 5. Animations
|
|
162
|
+
// ────────────────────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
const animateDemo = async (): Promise<void> => {
|
|
165
|
+
section('3 · Animations (typewriter, parallel, delay)');
|
|
166
|
+
|
|
167
|
+
// TypewriterOptions: { speed, newline, colorFn, signal, reducedMotion, hooks }
|
|
168
|
+
await animate.typewriter(' Welcome to the deployment wizard...', { speed: 18 });
|
|
169
|
+
|
|
170
|
+
console.log(' ' + color.dim('Running 3 parallel checks (timeout=2s)...'));
|
|
171
|
+
await animate.parallel([
|
|
172
|
+
async () => { await sleep(400); console.log(' ' + color.green(' ✓') + ' network'); },
|
|
173
|
+
async () => { await sleep(600); console.log(' ' + color.green(' ✓') + ' DNS'); },
|
|
174
|
+
async () => { await sleep(800); console.log(' ' + color.green(' ✓') + ' TLS'); },
|
|
175
|
+
], { timeout: 2000 });
|
|
176
|
+
|
|
177
|
+
await animate.delay(200);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// ────────────────────────────────────────────────────────────────
|
|
181
|
+
// 6. Loaders — real Task shape: { text, fn, subtasks? }
|
|
182
|
+
// ────────────────────────────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
const loaderDemo = async (): Promise<void> => {
|
|
185
|
+
section('4 · Loaders (spin, progress, hierarchical tasks)');
|
|
186
|
+
|
|
187
|
+
const stop = loader.spin('Connecting to registry', { color: '#bd93f9' });
|
|
188
|
+
await sleep(700);
|
|
189
|
+
stop('Registry connected', true);
|
|
190
|
+
|
|
191
|
+
console.log();
|
|
192
|
+
await loader.progressAnimate(20, 'Downloading manifests', {
|
|
193
|
+
color: '#50fa7b', delay: 25,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
console.log();
|
|
197
|
+
await loader.tasks([
|
|
198
|
+
{
|
|
199
|
+
text: 'Backend',
|
|
200
|
+
fn: async () => undefined,
|
|
201
|
+
subtasks: [
|
|
202
|
+
{ text: 'API gateway', fn: async () => sleep(300) },
|
|
203
|
+
{ text: 'Auth service', fn: async () => sleep(400) },
|
|
204
|
+
{ text: 'User service', fn: async () => sleep(350) },
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
text: 'Frontend',
|
|
209
|
+
fn: async () => undefined,
|
|
210
|
+
subtasks: [
|
|
211
|
+
{ text: 'Build bundle', fn: async () => sleep(500) },
|
|
212
|
+
{ text: 'Optimize SVGs', fn: async () => sleep(200) },
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
], { parallel: true });
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// ────────────────────────────────────────────────────────────────
|
|
219
|
+
// 7. Components
|
|
220
|
+
// ────────────────────────────────────────────────────────────────
|
|
221
|
+
|
|
222
|
+
const componentsDemo = (): void => {
|
|
223
|
+
section('5 · Components (table, badge, status, columns, timeline)');
|
|
224
|
+
|
|
225
|
+
console.log();
|
|
226
|
+
console.log(components.table([
|
|
227
|
+
['Service', 'Status', 'Replicas', 'Region'],
|
|
228
|
+
['api-gateway', color.green('● running'), '3', 'us-east-1'],
|
|
229
|
+
['auth-service', color.green('● running'), '2', 'us-east-1'],
|
|
230
|
+
['user-service', color.yellow('● starting'),'1', 'us-west-2'],
|
|
231
|
+
['payments', color.red('● failed'), '0', 'eu-west-1'],
|
|
232
|
+
], { borderStyle: 'rounded' }));
|
|
233
|
+
|
|
234
|
+
console.log();
|
|
235
|
+
console.log(' ' + components.badge('env', 'production') +
|
|
236
|
+
' ' + components.badge('version', 'v1.2.3') +
|
|
237
|
+
' ' + components.badge('build', '#1234'));
|
|
238
|
+
|
|
239
|
+
console.log();
|
|
240
|
+
console.log(' ' + components.status('success', 'Database migrations complete'));
|
|
241
|
+
console.log(' ' + components.status('warn', 'Cache hit rate below threshold'));
|
|
242
|
+
console.log(' ' + components.status('error', 'Connection pool exhausted'));
|
|
243
|
+
console.log(' ' + components.status('info', 'Deployment scheduled for 14:30'));
|
|
244
|
+
|
|
245
|
+
console.log();
|
|
246
|
+
console.log(components.columns([
|
|
247
|
+
'api-gateway', 'auth-service', 'user-service',
|
|
248
|
+
'payments', 'notifications', 'analytics',
|
|
249
|
+
], { cols: 3, gap: 4 }));
|
|
250
|
+
|
|
251
|
+
console.log();
|
|
252
|
+
console.log(components.timeline([
|
|
253
|
+
{ label: 'Pull image', done: true, time: '14:00' },
|
|
254
|
+
{ label: 'Stop old version', done: true, time: '14:02' },
|
|
255
|
+
{ label: 'Health check', done: false, time: '14:03' },
|
|
256
|
+
{ label: 'Switch traffic', done: false, time: '14:05' },
|
|
257
|
+
]));
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// ────────────────────────────────────────────────────────────────
|
|
261
|
+
// 8. Images
|
|
262
|
+
// ────────────────────────────────────────────────────────────────
|
|
263
|
+
|
|
264
|
+
const imagesDemo = (): void => {
|
|
265
|
+
section('6 · Images (gradient rect + canvas + sprite)');
|
|
266
|
+
|
|
267
|
+
console.log();
|
|
268
|
+
console.log(gradientRect({
|
|
269
|
+
width: 50, height: 5,
|
|
270
|
+
colors: ['#ff79c6', '#bd93f9', '#8be9fd'],
|
|
271
|
+
style: 'horizontal',
|
|
272
|
+
dither: 'bayer',
|
|
273
|
+
}));
|
|
274
|
+
|
|
275
|
+
console.log();
|
|
276
|
+
const canvas = createCanvas(30, 8, { r: 18, g: 18, b: 38 });
|
|
277
|
+
|
|
278
|
+
for (let y = 0; y < 8; y++) {
|
|
279
|
+
const t = y / 7;
|
|
280
|
+
const r = Math.round(40 + 100 * t);
|
|
281
|
+
const g = Math.round(20 + 60 * t);
|
|
282
|
+
const b = Math.round(80 + 80 * (1 - t));
|
|
283
|
+
canvas.drawRect(0, y, 30, 1, { r, g, b }, true);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (images.sprites.heart) canvas.drawSprite(2, 2, images.sprites.heart.pixels);
|
|
287
|
+
if (images.sprites.star) canvas.drawSprite(12, 2, images.sprites.star.pixels);
|
|
288
|
+
if (images.sprites.smiley) canvas.drawSprite(22, 2, images.sprites.smiley.pixels);
|
|
289
|
+
canvas.print();
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
// ────────────────────────────────────────────────────────────────
|
|
293
|
+
// 9. Frames
|
|
294
|
+
// ────────────────────────────────────────────────────────────────
|
|
295
|
+
|
|
296
|
+
const framesDemo = async (): Promise<void> => {
|
|
297
|
+
section('7 · Frames (live render, morph, presets)');
|
|
298
|
+
|
|
299
|
+
console.log();
|
|
300
|
+
console.log(color.dim(' Loading bar preset:'));
|
|
301
|
+
const ctrl = frames.play(frames.presets.loadingBar({ width: 20, label: ' Progress' }), {
|
|
302
|
+
fps: 30, repeat: 1,
|
|
303
|
+
});
|
|
304
|
+
await ctrl.done;
|
|
305
|
+
|
|
306
|
+
console.log(color.dim(' Morph (text decryption):'));
|
|
307
|
+
const morphFrames = frames.morph('SECRET CODE', 'DEPLOY OK ', 12);
|
|
308
|
+
for (const f of morphFrames) {
|
|
309
|
+
process.stdout.write('\r ' + color.cyan(f));
|
|
310
|
+
await sleep(60);
|
|
311
|
+
}
|
|
312
|
+
console.log();
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// ────────────────────────────────────────────────────────────────
|
|
316
|
+
// 10. Trees
|
|
317
|
+
// ────────────────────────────────────────────────────────────────
|
|
318
|
+
|
|
319
|
+
const treesDemo = (): void => {
|
|
320
|
+
section('8 · Trees (builder + algorithms)');
|
|
321
|
+
|
|
322
|
+
const project = tree({ label: 'my-app', icon: '📦', color: color.bold });
|
|
323
|
+
|
|
324
|
+
const src = project.add({ label: 'src', icon: '📁' });
|
|
325
|
+
src.addLeaf({ label: 'index.ts', icon: '📄' });
|
|
326
|
+
src.addLeaf({ label: 'app.ts', icon: '📄' });
|
|
327
|
+
const utils = src.add({ label: 'utils', icon: '📁' });
|
|
328
|
+
utils.addLeaf({ label: 'helpers.ts', icon: '📄' });
|
|
329
|
+
utils.addLeaf({ label: 'ansi.ts', icon: '📄' });
|
|
330
|
+
|
|
331
|
+
const tests = project.add({ label: 'tests', icon: '🧪' });
|
|
332
|
+
tests.addLeaf({ label: 'app.test.ts', icon: '📄' });
|
|
333
|
+
|
|
334
|
+
project.addLeaf({ label: 'package.json', icon: '📋', color: color.yellow });
|
|
335
|
+
project.addLeaf({ label: 'README.md', icon: '📖' });
|
|
336
|
+
|
|
337
|
+
console.log();
|
|
338
|
+
console.log(project.render({
|
|
339
|
+
style: 'rounded',
|
|
340
|
+
palette: [color.cyan, color.green, color.magenta],
|
|
341
|
+
guideColor: color.dim,
|
|
342
|
+
}));
|
|
343
|
+
|
|
344
|
+
const found = findInTree(project, (n) => n.label === 'helpers.ts');
|
|
345
|
+
const total = countNodes(project);
|
|
346
|
+
|
|
347
|
+
let leafCount = 0;
|
|
348
|
+
walkTree(project, (n) => {
|
|
349
|
+
if (!n.children || n.children.length === 0) leafCount++;
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
console.log();
|
|
353
|
+
// ColorFn expects string — coerce numbers via String()
|
|
354
|
+
console.log(` ${color.dim('•')} total nodes: ${color.cyan(String(total))}`);
|
|
355
|
+
console.log(` ${color.dim('•')} leaf files: ${color.cyan(String(leafCount))}`);
|
|
356
|
+
console.log(` ${color.dim('•')} found: ${found ? color.green(found.label) : color.red('null')}`);
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// ────────────────────────────────────────────────────────────────
|
|
360
|
+
// 11. Utils
|
|
361
|
+
// ────────────────────────────────────────────────────────────────
|
|
362
|
+
|
|
363
|
+
const utilsDemo = (): void => {
|
|
364
|
+
section('9 · Utils (OutputBuffer, helpers, hyperlinks)');
|
|
365
|
+
|
|
366
|
+
const buf = createOutputBuffer();
|
|
367
|
+
const verbose = process.env.VERBOSE !== undefined;
|
|
368
|
+
buf
|
|
369
|
+
.push(' ')
|
|
370
|
+
.push(color.bold('Built with: '))
|
|
371
|
+
.push(link('ansimax', 'https://github.com/Brashkie/ansimax'))
|
|
372
|
+
.push(' · ')
|
|
373
|
+
.pushIf(verbose, color.dim('(verbose mode) '))
|
|
374
|
+
.push(color.dim('TypeScript + Node.js'))
|
|
375
|
+
.pushln();
|
|
376
|
+
buf.flush();
|
|
377
|
+
|
|
378
|
+
const obj: { name: string; count: bigint; self?: unknown } = {
|
|
379
|
+
name: 'demo', count: 9876543210123456789n,
|
|
380
|
+
};
|
|
381
|
+
obj.self = obj;
|
|
382
|
+
console.log(' ' + color.dim('safeJson:'));
|
|
383
|
+
console.log(' ' + safeJson(obj, 2).split('\n').join('\n '));
|
|
384
|
+
|
|
385
|
+
const userInput = 'a.b+c?(x)';
|
|
386
|
+
const re = new RegExp(escapeRegex(userInput));
|
|
387
|
+
console.log(' ' + color.dim('escapeRegex:'));
|
|
388
|
+
console.log(` /${color.cyan(escapeRegex(userInput))}/ matches "${userInput}": ${color.green(String(re.test(userInput)))}`);
|
|
389
|
+
|
|
390
|
+
let count = 0;
|
|
391
|
+
const init = once(() => { count++; return 'initialized'; });
|
|
392
|
+
init(); init(); init();
|
|
393
|
+
// String() to satisfy ColorFn signature
|
|
394
|
+
console.log(` ${color.dim('once:')} called 3x, fn ran ${color.cyan(String(count))} time(s)`);
|
|
395
|
+
|
|
396
|
+
console.log(' ' + color.dim('padBoth:'));
|
|
397
|
+
console.log(' ' + color.bgBlue(padBoth(' centered ', 30)));
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
// ────────────────────────────────────────────────────────────────
|
|
401
|
+
// 12. Finale
|
|
402
|
+
// ────────────────────────────────────────────────────────────────
|
|
403
|
+
|
|
404
|
+
const finale = async (): Promise<void> => {
|
|
405
|
+
section('10 · Finale (withConfig, bell)');
|
|
406
|
+
|
|
407
|
+
await withConfig({ animationSpeed: 'fast' }, async () => {
|
|
408
|
+
console.log();
|
|
409
|
+
console.log(' Speed temporarily: ' + color.green(getConfig().animationSpeed));
|
|
410
|
+
// TypewriterOptions uses `speed`, not `delay`
|
|
411
|
+
await animate.typewriter(' Fast typewriter inside withConfig block.', { speed: 8 });
|
|
412
|
+
});
|
|
413
|
+
console.log(' Speed restored to: ' + color.green(getConfig().animationSpeed));
|
|
414
|
+
|
|
415
|
+
// BoxOptions: padding/borderStyle/width only — no borderColor.
|
|
416
|
+
// Apply color externally with color.hex() wrapping.
|
|
417
|
+
const summary = color.hex('#50fa7b')(ascii.box(
|
|
418
|
+
color.bold(color.green('✓ Demo complete')) + '\n' +
|
|
419
|
+
color.dim('All modules exercised:') + '\n' +
|
|
420
|
+
' configure · themes · colors · ascii · animate\n' +
|
|
421
|
+
' loader · frames · components · images · trees · utils',
|
|
422
|
+
{ padding: 1 },
|
|
423
|
+
));
|
|
424
|
+
console.log();
|
|
425
|
+
console.log(summary);
|
|
426
|
+
|
|
427
|
+
process.stdout.write(bell());
|
|
428
|
+
|
|
429
|
+
offThemeListener();
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// ────────────────────────────────────────────────────────────────
|
|
433
|
+
// Main
|
|
434
|
+
// ────────────────────────────────────────────────────────────────
|
|
435
|
+
|
|
436
|
+
const main = async (): Promise<void> => {
|
|
437
|
+
const handleSigint = once((): void => {
|
|
438
|
+
write(cursor.show());
|
|
439
|
+
console.log('\n' + color.dim(' Interrupted. Cleaning up...'));
|
|
440
|
+
process.exit(130);
|
|
441
|
+
});
|
|
442
|
+
process.on('SIGINT', handleSigint);
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
printBanner();
|
|
446
|
+
themeDemo();
|
|
447
|
+
colorDemo();
|
|
448
|
+
await animateDemo();
|
|
449
|
+
await loaderDemo();
|
|
450
|
+
componentsDemo();
|
|
451
|
+
imagesDemo();
|
|
452
|
+
await framesDemo();
|
|
453
|
+
treesDemo();
|
|
454
|
+
utilsDemo();
|
|
455
|
+
await finale();
|
|
456
|
+
} catch (err) {
|
|
457
|
+
write(cursor.show());
|
|
458
|
+
console.error('\n' + color.red('Demo error:'), err);
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
main().catch((err) => {
|
|
464
|
+
console.error(color.red('Fatal:'), err);
|
|
465
|
+
process.exit(1);
|
|
466
|
+
});
|