@rtorcato/js-common 1.7.1 โ 1.8.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 +15 -0
- package/README.md +29 -29
- package/dist/chunks/chunk-6J7HIWG6.js +1 -0
- package/dist/chunks/chunk-FBDKWWIQ.js +3 -0
- package/dist/cli/cli.mjs +439 -0
- package/dist/cli/index.mjs +22 -436
- package/dist/env/index.js +1 -3
- package/dist/index.js +0 -1
- package/dist/logger/index.js +1 -0
- package/dist/logger/logger.js +1 -0
- package/package.json +18 -11
- package/dist/helloworld/index.js +0 -1
- package/dist/logging/index1.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [1.8.1](https://github.com/rtorcato/js-common/compare/v1.8.0...v1.8.1) (2026-05-29)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **deps:** move CLI deps to optionalDependencies ([52d1e9f](https://github.com/rtorcato/js-common/commit/52d1e9feda9ae86dc705f103678024cfb9772c68))
|
|
7
|
+
* publishing bugs and dead-code cleanup ([30b8d69](https://github.com/rtorcato/js-common/commit/30b8d693d6dfcdc4b6044438318f7d5cbaca0e86))
|
|
8
|
+
|
|
9
|
+
# [1.8.0](https://github.com/rtorcato/js-common/compare/v1.7.1...v1.8.0) (2026-05-29)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* **docs:** Astro Starlight site on GitHub Pages ([5139f6d](https://github.com/rtorcato/js-common/commit/5139f6d0d6652e54b3e6daa5ed77dcd67d7e59dc))
|
|
15
|
+
|
|
1
16
|
## [1.7.1](https://github.com/rtorcato/js-common/compare/v1.7.0...v1.7.1) (2026-05-29)
|
|
2
17
|
|
|
3
18
|
|
package/README.md
CHANGED
|
@@ -5,19 +5,20 @@
|
|
|
5
5
|
[](https://badge.fury.io/js/%40rtorcato%2Fjs-common)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
|
-
[](https://nodejs.org/)
|
|
9
|
+
[](https://rtorcato.github.io/js-common/)
|
|
10
10
|
|
|
11
11
|
A comprehensive set of common JavaScript and TypeScript utilities for Node.js projects.
|
|
12
12
|
|
|
13
|
+
๐ **Documentation:** <https://rtorcato.github.io/js-common/>
|
|
14
|
+
|
|
13
15
|
## โจ Features
|
|
14
16
|
|
|
15
|
-
-
|
|
16
|
-
- ๐ฆ **Tree-shakeable** - Import only what you need
|
|
17
|
+
- ๐ฆ **Tree-shakeable** - Import only what you need via subpath exports
|
|
17
18
|
- ๐ง **TypeScript** - Full type safety and IntelliSense
|
|
18
|
-
- ๐ฅ๏ธ **CLI included** -
|
|
19
|
-
- ๐ **Modular** -
|
|
20
|
-
- โก **
|
|
19
|
+
- ๐ฅ๏ธ **CLI included** - Optional binary for use in scripts and terminals
|
|
20
|
+
- ๐ **Modular** - One module per concern, ~40 subpaths
|
|
21
|
+
- โก **Minimal runtime deps** - Only `date-fns`, `luxon`, `pino`, `uuid`, `short-uuid`, `zod`. CLI packages (`chalk`, `commander`, `figlet`, โฆ) are `optionalDependencies` and only needed for the CLI.
|
|
21
22
|
- ๐งช **Well tested** - Comprehensive test coverage
|
|
22
23
|
|
|
23
24
|
## Installation
|
|
@@ -56,9 +57,6 @@ import { generateUUID, isValidUUID } from '@rtorcato/js-common/uuid'
|
|
|
56
57
|
import { sum, average, roundTo } from '@rtorcato/js-common/numbers'
|
|
57
58
|
import { capitalize, toTitleCase } from '@rtorcato/js-common/formatting'
|
|
58
59
|
|
|
59
|
-
// ๐ฆ Or import everything (larger bundle)
|
|
60
|
-
import * as jsCommon from '@rtorcato/js-common'
|
|
61
|
-
|
|
62
60
|
// Example usage
|
|
63
61
|
console.log(today()) // "2025-10-24"
|
|
64
62
|
console.log(sum([1, 2, 3, 4, 5])) // 15
|
|
@@ -68,15 +66,7 @@ console.log(generateUUID()) // "f47ac10b-58cc-4372-a567-0e02b2c3d479"
|
|
|
68
66
|
|
|
69
67
|
### Bundle Size Impact
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
// This adds ~50 bytes to your bundle
|
|
75
|
-
import { today } from '@rtorcato/js-common/date'
|
|
76
|
-
|
|
77
|
-
// This adds ~100 bytes to your bundle
|
|
78
|
-
import { sum, average } from '@rtorcato/js-common/numbers'
|
|
79
|
-
```
|
|
69
|
+
Each module is shipped as its own subpath export so bundlers only include what you import. Individual modules range from ~100 bytes (e.g. `sleep`) to ~2 KB (e.g. `currency`) when minified. Measure against your own bundle with [bundlejs.com](https://bundlejs.com/?q=@rtorcato/js-common/numbers).
|
|
80
70
|
|
|
81
71
|
### ๐ฏ **TypeScript Support**
|
|
82
72
|
|
|
@@ -157,7 +147,7 @@ import { sleep } from '@rtorcato/js-common/sleep'
|
|
|
157
147
|
|
|
158
148
|
## Requirements
|
|
159
149
|
|
|
160
|
-
- **Node.js** >=
|
|
150
|
+
- **Node.js** >= 22.0.0 (enforced via the `engines` field)
|
|
161
151
|
- **TypeScript** >= 5.0.0 (for TypeScript projects)
|
|
162
152
|
|
|
163
153
|
## Why This Library?
|
|
@@ -168,17 +158,10 @@ Unlike larger utility libraries, js-common is designed for modern applications:
|
|
|
168
158
|
- **Tree-shakeable** - Only import what you use
|
|
169
159
|
- **CLI included** - Use utilities in scripts and terminal
|
|
170
160
|
|
|
171
|
-
### ๐ฆ **Bundle Size Comparison**
|
|
172
|
-
```
|
|
173
|
-
lodash: ~70KB (full) / ~25KB (common functions)
|
|
174
|
-
ramda: ~60KB (full) / ~15KB (common functions)
|
|
175
|
-
js-common: 277 bytes (full) / ~50-200 bytes (individual modules)
|
|
176
|
-
```
|
|
177
|
-
|
|
178
161
|
### ๐ ๏ธ **Modern Development**
|
|
179
162
|
- Built with **TypeScript** for excellent DX
|
|
180
|
-
- **ESM-
|
|
181
|
-
- **
|
|
163
|
+
- **ESM-only**, native subpath exports
|
|
164
|
+
- **Minimal runtime deps** โ CLI packages (`chalk`, `commander`, `figlet`, โฆ) are `optionalDependencies` and only fetched when you opt in to the CLI
|
|
182
165
|
- Comprehensive **test coverage**
|
|
183
166
|
|
|
184
167
|
## Development
|
|
@@ -204,8 +187,25 @@ pnpm run check:fix
|
|
|
204
187
|
|
|
205
188
|
# Type checking
|
|
206
189
|
pnpm run typecheck
|
|
190
|
+
|
|
191
|
+
# Run micro-benchmarks (scripts/benchmark.mjs)
|
|
192
|
+
pnpm run benchmark
|
|
207
193
|
```
|
|
208
194
|
|
|
195
|
+
## Documentation site
|
|
196
|
+
|
|
197
|
+
The full documentation site lives in [`apps/doc`](./apps/doc) and is built with [Astro Starlight](https://starlight.astro.build/). It auto-deploys to GitHub Pages on every push to `main` that touches `apps/doc/**`.
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Run the docs locally (http://localhost:4321/js-common)
|
|
201
|
+
pnpm --filter @rtorcato/js-common-docs dev
|
|
202
|
+
|
|
203
|
+
# Build the static site
|
|
204
|
+
pnpm --filter @rtorcato/js-common-docs build
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Live site: <https://rtorcato.github.io/js-common/>
|
|
208
|
+
|
|
209
209
|
## Contributing
|
|
210
210
|
|
|
211
211
|
Contributions are welcome! Please read [CONTRIBUTORS.md](./CONTRIBUTORS.md) for guidelines.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as e}from"./chunk-FBDKWWIQ.js";import o from"pino";var i=e()?o({level:"debug",transport:{target:"pino-pretty",options:{colorize:!0,ignore:"pid,hostname,time",levelFirst:!1,singleLine:!0,customColors:"err:red,info:blue",translateTime:"HH:MM:ss"}}}):o({level:"info"});export{i as a};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{z as n}from"zod";var c=(r,o)=>{let e=process.env[r.toString()];if(e===void 0&&o!==void 0)return o;if(e===void 0){let t=`Undefined ENV variable - ${r.toString()}`;throw new Error(t)}return e},d=()=>process.env.NODE_ENV==="development",p=()=>process.env.NODE_ENV==="production",E=()=>process.env.NODE_ENV==="test",u=()=>process.env.NODE_ENV||"development";function a(r,o=process.env){try{return r.parse(o)}catch(e){if(e instanceof n.ZodError){let t=`Missing required values in .env:
|
|
2
|
+
`;t+=Object.keys(e.flatten().fieldErrors).join(`
|
|
3
|
+
`);let s=new Error(t);throw s.stack="",s}throw e}}var f=n.object({NODE_ENV:n.enum(["development","test","production"]).default("development"),LOG_LEVEL:n.enum(["debug","info","warn","error"]).default("info"),PORT:n.coerce.number().default(3e3)});export{c as a,d as b,p as c,E as d,u as e,a as f,f as g};
|
package/dist/cli/cli.mjs
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import { Separator, checkbox, select } from '@inquirer/prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import chalkAnimation from 'chalk-animation';
|
|
4
|
+
import { program } from 'commander';
|
|
5
|
+
import figlet from 'figlet';
|
|
6
|
+
import gradient from 'gradient-string';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { dirname, resolve } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
// Get current directory
|
|
11
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
// Get package version
|
|
13
|
+
const packageJson = JSON.parse(readFileSync(resolve(currentDir, '../../package.json'), 'utf-8'));
|
|
14
|
+
program
|
|
15
|
+
.name('js-common')
|
|
16
|
+
.description(chalk.cyan('โจ CLI utilities from @rtorcato/js-common'))
|
|
17
|
+
.version(packageJson.version);
|
|
18
|
+
// Function categories for list and interactive mode
|
|
19
|
+
const functionCategories = {
|
|
20
|
+
date: {
|
|
21
|
+
name: '๐
Date & Time',
|
|
22
|
+
functions: [
|
|
23
|
+
{ name: 'today', description: "Get today's date (YYYY-MM-DD)" },
|
|
24
|
+
{ name: 'now', description: 'Get current timestamp' },
|
|
25
|
+
{ name: 'between', description: 'Calculate days between dates' },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
math: {
|
|
29
|
+
name: '๐ข Mathematical',
|
|
30
|
+
functions: [
|
|
31
|
+
{ name: 'sum', description: 'Calculate sum of numbers' },
|
|
32
|
+
{ name: 'avg', description: 'Calculate average of numbers' },
|
|
33
|
+
{ name: 'random', description: 'Generate random number' },
|
|
34
|
+
{ name: 'round', description: 'Round to decimal places' },
|
|
35
|
+
{ name: 'clamp', description: 'Clamp between min/max' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
text: {
|
|
39
|
+
name: '๐ Text Formatting',
|
|
40
|
+
functions: [
|
|
41
|
+
{ name: 'capitalize', description: 'Capitalize first letter' },
|
|
42
|
+
{ name: 'title', description: 'Convert to title case' },
|
|
43
|
+
{ name: 'pad', description: 'Pad with leading zeros' },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
file: {
|
|
47
|
+
name: '๐ File Operations',
|
|
48
|
+
functions: [
|
|
49
|
+
{ name: 'exists', description: 'Check if file exists' },
|
|
50
|
+
{ name: 'ext', description: 'Get file extension' },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
security: {
|
|
54
|
+
name: '๐ Security',
|
|
55
|
+
functions: [
|
|
56
|
+
{ name: 'password', description: 'Check password strength' },
|
|
57
|
+
{ name: 'token', description: 'Generate secure token' },
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
validate: {
|
|
61
|
+
name: 'โ
Validation',
|
|
62
|
+
functions: [{ name: 'url', description: 'Validate URL format' }],
|
|
63
|
+
},
|
|
64
|
+
system: {
|
|
65
|
+
name: '๐ป System Info',
|
|
66
|
+
functions: [
|
|
67
|
+
{ name: 'pid', description: 'Get process ID' },
|
|
68
|
+
{ name: 'uptime', description: 'Get process uptime' },
|
|
69
|
+
{ name: 'ci', description: 'Check CI environment' },
|
|
70
|
+
{ name: 'node-version', description: 'Get Node.js version' },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
// List all functions - add as a separate command
|
|
75
|
+
program
|
|
76
|
+
.command('list')
|
|
77
|
+
.alias('ls')
|
|
78
|
+
.description('๐ List all available functions')
|
|
79
|
+
.action(() => {
|
|
80
|
+
console.log(chalk.cyan('\nโจ Available Functions:\n'));
|
|
81
|
+
Object.entries(functionCategories).forEach(([key, category]) => {
|
|
82
|
+
console.log(chalk.bold(category.name));
|
|
83
|
+
console.log(); // Add space after category header
|
|
84
|
+
category.functions.forEach((func) => {
|
|
85
|
+
console.log(chalk.gray(` js-common ${key} ${func.name}`) + chalk.dim(` - ${func.description}`));
|
|
86
|
+
});
|
|
87
|
+
console.log(); // Add space after function list
|
|
88
|
+
});
|
|
89
|
+
console.log(chalk.yellow('๐ก Use ') +
|
|
90
|
+
chalk.green('js-common add') +
|
|
91
|
+
chalk.yellow(' to integrate functions into your project'));
|
|
92
|
+
console.log(chalk.yellow('๐ก Use ') +
|
|
93
|
+
chalk.green('js-common interactive') +
|
|
94
|
+
chalk.yellow(' for interactive mode'));
|
|
95
|
+
console.log(chalk.yellow('๐ก Use ') +
|
|
96
|
+
chalk.green('js-common <command> --help') +
|
|
97
|
+
chalk.yellow(' for detailed help\n'));
|
|
98
|
+
});
|
|
99
|
+
// Also add as an option for compatibility
|
|
100
|
+
program.option('-l, --list', 'List all available functions');
|
|
101
|
+
// Interactive mode
|
|
102
|
+
program
|
|
103
|
+
.command('interactive')
|
|
104
|
+
.alias('i')
|
|
105
|
+
.description('๐ฎ Interactive mode with guided prompts')
|
|
106
|
+
.action(async () => {
|
|
107
|
+
// Welcome animation
|
|
108
|
+
const title = figlet.textSync('JS Common', { font: 'Small' });
|
|
109
|
+
console.log(gradient.pastel.multiline(title));
|
|
110
|
+
const rainbow = chalkAnimation.rainbow('\nโจ Welcome to JS Common Interactive Mode! โจ\n');
|
|
111
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
112
|
+
rainbow.stop();
|
|
113
|
+
try {
|
|
114
|
+
// Main interactive loop
|
|
115
|
+
while (true) {
|
|
116
|
+
const category = await select({
|
|
117
|
+
message: chalk.cyan('What would you like to do?'),
|
|
118
|
+
choices: Object.entries(functionCategories)
|
|
119
|
+
.reduce((acc, [key, cat], index) => {
|
|
120
|
+
acc.push({ name: cat.name, value: key });
|
|
121
|
+
if (index < Object.entries(functionCategories).length - 1) {
|
|
122
|
+
acc.push(new Separator(' '));
|
|
123
|
+
}
|
|
124
|
+
return acc;
|
|
125
|
+
}, [])
|
|
126
|
+
.concat([new Separator(' '), { name: chalk.red('โ Exit'), value: 'exit' }]),
|
|
127
|
+
pageSize: 17,
|
|
128
|
+
loop: false,
|
|
129
|
+
});
|
|
130
|
+
// Handle exit selection
|
|
131
|
+
if (category === 'exit') {
|
|
132
|
+
console.log(chalk.yellow('\n๐ Goodbye!\n'));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const selectedCategory = functionCategories[category];
|
|
136
|
+
// Function selection loop
|
|
137
|
+
while (true) {
|
|
138
|
+
const functionName = await select({
|
|
139
|
+
message: chalk.cyan(`Choose a ${selectedCategory.name} function:`),
|
|
140
|
+
choices: selectedCategory.functions
|
|
141
|
+
.reduce((acc, func, index) => {
|
|
142
|
+
acc.push({ name: `${func.name} - ${func.description}`, value: func.name });
|
|
143
|
+
if (index < selectedCategory.functions.length - 1) {
|
|
144
|
+
acc.push(new Separator(' '));
|
|
145
|
+
}
|
|
146
|
+
return acc;
|
|
147
|
+
}, [])
|
|
148
|
+
.concat([
|
|
149
|
+
new Separator(' '),
|
|
150
|
+
{ name: chalk.gray('โฌ
๏ธ Back to categories'), value: 'back' },
|
|
151
|
+
{ name: chalk.red('โ Exit'), value: 'exit' },
|
|
152
|
+
]),
|
|
153
|
+
pageSize: 12,
|
|
154
|
+
loop: false,
|
|
155
|
+
});
|
|
156
|
+
// Handle navigation options
|
|
157
|
+
if (functionName === 'exit') {
|
|
158
|
+
console.log(chalk.yellow('\n๐ Goodbye!\n'));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (functionName === 'back') {
|
|
162
|
+
break; // Break out of function selection loop, go back to categories
|
|
163
|
+
}
|
|
164
|
+
// Show the command
|
|
165
|
+
console.log(chalk.green(`\n๐ You can run this command:`));
|
|
166
|
+
console.log(chalk.yellow(`js-common ${category} ${functionName} [arguments]`));
|
|
167
|
+
console.log(chalk.gray(`\nFor detailed usage, run: js-common ${category} ${functionName} --help\n`));
|
|
168
|
+
return; // Exit after showing the command
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (error && typeof error === 'object' && 'isTtyError' in error) {
|
|
174
|
+
console.log(chalk.red('\nโ Interactive mode requires a TTY terminal'));
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
console.log(chalk.red('\nโ Something went wrong in interactive mode'));
|
|
178
|
+
}
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
// Add command - help developers integrate functions into their projects
|
|
183
|
+
program
|
|
184
|
+
.command('add')
|
|
185
|
+
.alias('a')
|
|
186
|
+
.description('๐ง Add utility functions to your project')
|
|
187
|
+
.action(async () => {
|
|
188
|
+
// Welcome message
|
|
189
|
+
console.log(gradient.pastel('\n๐ง Function Integration Helper\n'));
|
|
190
|
+
try {
|
|
191
|
+
const category = await select({
|
|
192
|
+
message: chalk.cyan('Which category of utilities do you need?'),
|
|
193
|
+
choices: Object.entries(functionCategories)
|
|
194
|
+
.reduce((acc, [key, cat], index) => {
|
|
195
|
+
acc.push({ name: cat.name, value: key });
|
|
196
|
+
if (index < Object.entries(functionCategories).length - 1) {
|
|
197
|
+
acc.push(new Separator(' '));
|
|
198
|
+
}
|
|
199
|
+
return acc;
|
|
200
|
+
}, [])
|
|
201
|
+
.concat([new Separator(' '), { name: chalk.red('โ Exit'), value: 'exit' }]),
|
|
202
|
+
pageSize: 17,
|
|
203
|
+
loop: false,
|
|
204
|
+
});
|
|
205
|
+
// Handle exit selection
|
|
206
|
+
if (category === 'exit') {
|
|
207
|
+
console.log(chalk.yellow('\n๐ Goodbye!\n'));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const selectedCategory = functionCategories[category];
|
|
211
|
+
const functions = await checkbox({
|
|
212
|
+
message: chalk.cyan(`Select ${selectedCategory.name} functions to add:`),
|
|
213
|
+
choices: selectedCategory.functions.map((func) => ({
|
|
214
|
+
name: `${func.name} - ${func.description}`,
|
|
215
|
+
value: func.name,
|
|
216
|
+
checked: false,
|
|
217
|
+
})),
|
|
218
|
+
pageSize: 10,
|
|
219
|
+
loop: false,
|
|
220
|
+
});
|
|
221
|
+
if (functions.length === 0) {
|
|
222
|
+
console.log(chalk.yellow('\n๐ No functions selected. Exiting...\n'));
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
console.log(chalk.green('\n๐ฆ Import Statement:'));
|
|
226
|
+
console.log(chalk.white(`import { ${functions.join(', ')} } from '@rtorcato/js-common/${category}'`));
|
|
227
|
+
console.log(chalk.green('\n๐ Usage Examples:'));
|
|
228
|
+
functions.forEach((func) => {
|
|
229
|
+
const funcInfo = selectedCategory.functions.find((f) => f.name === func);
|
|
230
|
+
if (funcInfo) {
|
|
231
|
+
console.log(chalk.gray(`\n// ${funcInfo.description}`));
|
|
232
|
+
generateUsageExample(category, func);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
console.log(chalk.green('\n๐ Documentation:'));
|
|
236
|
+
console.log(chalk.blue(`https://github.com/rtorcato/js-common#${category}-utilities`));
|
|
237
|
+
console.log(chalk.yellow('\n๐ก Tip: Run ') +
|
|
238
|
+
chalk.green(`js-common ${category} ${functions[0]} --help`) +
|
|
239
|
+
chalk.yellow(' for detailed CLI usage\n'));
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
if (error && typeof error === 'object' && 'isTtyError' in error) {
|
|
243
|
+
console.log(chalk.red('\nโ Interactive mode requires a TTY terminal'));
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
console.log(chalk.red('\nโ Something went wrong'));
|
|
247
|
+
}
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
// Helper function to generate usage examples
|
|
252
|
+
function generateUsageExample(category, functionName) {
|
|
253
|
+
const examples = {
|
|
254
|
+
date: {
|
|
255
|
+
today: `const today = today(); // "${new Date().toISOString().split('T')[0]}"`,
|
|
256
|
+
now: `const timestamp = now(); // ${Date.now()}`,
|
|
257
|
+
between: `const days = daysBetween('2023-01-01', '2023-12-31'); // 364`,
|
|
258
|
+
},
|
|
259
|
+
math: {
|
|
260
|
+
sum: `const total = sum([1, 2, 3, 4, 5]); // 15`,
|
|
261
|
+
avg: `const average = avg([10, 20, 30]); // 20`,
|
|
262
|
+
random: `const num = randomBetween(1, 100); // 42`,
|
|
263
|
+
round: `const rounded = roundTo(3.14159, 2); // 3.14`,
|
|
264
|
+
clamp: `const clamped = clamp(150, 0, 100); // 100`,
|
|
265
|
+
},
|
|
266
|
+
text: {
|
|
267
|
+
capitalize: `const text = capitalize('hello world'); // "Hello world"`,
|
|
268
|
+
title: `const title = toTitleCase('hello world'); // "Hello World"`,
|
|
269
|
+
pad: `const padded = padWithZeros(42, 5); // "00042"`,
|
|
270
|
+
},
|
|
271
|
+
file: {
|
|
272
|
+
exists: `const exists = await fileExists('package.json'); // true`,
|
|
273
|
+
ext: `const extension = getFileExtension('file.txt'); // "txt"`,
|
|
274
|
+
},
|
|
275
|
+
security: {
|
|
276
|
+
password: `const isStrong = checkPasswordStrength('MyPass123!'); // true`,
|
|
277
|
+
token: `const token = generateSecureToken(32); // "abc123..."`,
|
|
278
|
+
},
|
|
279
|
+
validate: {
|
|
280
|
+
url: `const isValid = isValidUrl('https://example.com'); // true`,
|
|
281
|
+
},
|
|
282
|
+
system: {
|
|
283
|
+
pid: `const processId = getProcessId(); // 12345`,
|
|
284
|
+
uptime: `const uptime = getProcessUptime(); // 123.45`,
|
|
285
|
+
ci: `const isCI = isCiEnvironment(); // false`,
|
|
286
|
+
'node-version': `const version = getNodeVersion(); // "18.17.0"`,
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
const example = examples[category]?.[functionName];
|
|
290
|
+
if (example) {
|
|
291
|
+
console.log(chalk.white(example));
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Date commands
|
|
295
|
+
const dateCmd = program.command('date').description('๐
Date and time utilities');
|
|
296
|
+
dateCmd
|
|
297
|
+
.command('today')
|
|
298
|
+
.description("Get today's date (YYYY-MM-DD)")
|
|
299
|
+
.action(() => {
|
|
300
|
+
console.log(new Date().toISOString().split('T')[0]);
|
|
301
|
+
});
|
|
302
|
+
dateCmd
|
|
303
|
+
.command('now')
|
|
304
|
+
.description('Get current timestamp')
|
|
305
|
+
.option('-i, --iso', 'ISO format')
|
|
306
|
+
.option('-t, --time', 'Time only')
|
|
307
|
+
.action((options) => {
|
|
308
|
+
if (options.iso) {
|
|
309
|
+
console.log(new Date().toISOString());
|
|
310
|
+
}
|
|
311
|
+
else if (options.time) {
|
|
312
|
+
console.log(new Date().toTimeString());
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
console.log(Date.now());
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
dateCmd
|
|
319
|
+
.command('between')
|
|
320
|
+
.description('Calculate days between dates')
|
|
321
|
+
.argument('<date1>', 'First date (YYYY-MM-DD)')
|
|
322
|
+
.argument('<date2>', 'Second date (YYYY-MM-DD)')
|
|
323
|
+
.action((date1, date2) => {
|
|
324
|
+
const d1 = new Date(date1);
|
|
325
|
+
const d2 = new Date(date2);
|
|
326
|
+
const timeDiff = Math.abs(d2.getTime() - d1.getTime());
|
|
327
|
+
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
|
|
328
|
+
console.log(`${daysDiff} days`);
|
|
329
|
+
});
|
|
330
|
+
// Math commands
|
|
331
|
+
const mathCmd = program.command('math').description('๐ข Mathematical utilities');
|
|
332
|
+
mathCmd
|
|
333
|
+
.command('sum')
|
|
334
|
+
.description('Calculate sum of numbers')
|
|
335
|
+
.argument('<numbers...>', 'Numbers to sum')
|
|
336
|
+
.action((numbers) => {
|
|
337
|
+
const nums = numbers.map(Number).filter((n) => !Number.isNaN(n));
|
|
338
|
+
console.log(nums.reduce((a, b) => a + b, 0));
|
|
339
|
+
});
|
|
340
|
+
mathCmd
|
|
341
|
+
.command('avg')
|
|
342
|
+
.description('Calculate average of numbers')
|
|
343
|
+
.argument('<numbers...>', 'Numbers to average')
|
|
344
|
+
.action((numbers) => {
|
|
345
|
+
const nums = numbers.map(Number).filter((n) => !Number.isNaN(n));
|
|
346
|
+
console.log(nums.reduce((a, b) => a + b, 0) / nums.length);
|
|
347
|
+
});
|
|
348
|
+
mathCmd
|
|
349
|
+
.command('random')
|
|
350
|
+
.description('Generate random number')
|
|
351
|
+
.argument('<min>', 'Minimum value')
|
|
352
|
+
.argument('<max>', 'Maximum value')
|
|
353
|
+
.action((min, max) => {
|
|
354
|
+
const minNum = Number(min);
|
|
355
|
+
const maxNum = Number(max);
|
|
356
|
+
console.log(Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
|
|
357
|
+
});
|
|
358
|
+
mathCmd
|
|
359
|
+
.command('round')
|
|
360
|
+
.description('Round to decimal places')
|
|
361
|
+
.argument('<number>', 'Number to round')
|
|
362
|
+
.argument('<decimals>', 'Decimal places')
|
|
363
|
+
.action((number, decimals) => {
|
|
364
|
+
const num = Number(number);
|
|
365
|
+
const dec = Number(decimals);
|
|
366
|
+
console.log(Number(num.toFixed(dec)));
|
|
367
|
+
});
|
|
368
|
+
mathCmd
|
|
369
|
+
.command('clamp')
|
|
370
|
+
.description('Clamp between min/max')
|
|
371
|
+
.argument('<number>', 'Number to clamp')
|
|
372
|
+
.argument('<min>', 'Minimum value')
|
|
373
|
+
.argument('<max>', 'Maximum value')
|
|
374
|
+
.action((number, min, max) => {
|
|
375
|
+
const num = Number(number);
|
|
376
|
+
const minVal = Number(min);
|
|
377
|
+
const maxVal = Number(max);
|
|
378
|
+
console.log(Math.min(Math.max(num, minVal), maxVal));
|
|
379
|
+
});
|
|
380
|
+
// Simple implementations for other commands
|
|
381
|
+
const textCmd = program.command('text').description('๐ Text formatting utilities');
|
|
382
|
+
textCmd
|
|
383
|
+
.command('capitalize')
|
|
384
|
+
.description('Capitalize first letter')
|
|
385
|
+
.argument('<text>', 'Text to capitalize')
|
|
386
|
+
.action((text) => {
|
|
387
|
+
console.log(text.charAt(0).toUpperCase() + text.slice(1));
|
|
388
|
+
});
|
|
389
|
+
textCmd
|
|
390
|
+
.command('title')
|
|
391
|
+
.description('Convert to title case')
|
|
392
|
+
.argument('<text>', 'Text to convert')
|
|
393
|
+
.action((text) => {
|
|
394
|
+
console.log(text.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase()));
|
|
395
|
+
});
|
|
396
|
+
// System commands
|
|
397
|
+
const systemCmd = program.command('system').description('๐ป System information utilities');
|
|
398
|
+
systemCmd
|
|
399
|
+
.command('pid')
|
|
400
|
+
.description('Get process ID')
|
|
401
|
+
.action(() => {
|
|
402
|
+
console.log(process.pid);
|
|
403
|
+
});
|
|
404
|
+
systemCmd
|
|
405
|
+
.command('uptime')
|
|
406
|
+
.description('Get process uptime')
|
|
407
|
+
.action(() => {
|
|
408
|
+
console.log(`${Math.floor(process.uptime())} seconds`);
|
|
409
|
+
});
|
|
410
|
+
systemCmd
|
|
411
|
+
.command('node-version')
|
|
412
|
+
.description('Get Node.js version')
|
|
413
|
+
.action(() => {
|
|
414
|
+
console.log(process.version);
|
|
415
|
+
});
|
|
416
|
+
// Handle --list option before parsing
|
|
417
|
+
if (process.argv.includes('--list') || process.argv.includes('-l')) {
|
|
418
|
+
console.log(chalk.cyan('\nโจ Available Functions:\n'));
|
|
419
|
+
Object.entries(functionCategories).forEach(([key, category]) => {
|
|
420
|
+
console.log(chalk.bold(category.name));
|
|
421
|
+
console.log(); // Add space after category header
|
|
422
|
+
category.functions.forEach((func) => {
|
|
423
|
+
console.log(chalk.gray(` js-common ${key} ${func.name}`) + chalk.dim(` - ${func.description}`));
|
|
424
|
+
});
|
|
425
|
+
console.log(); // Add space after function list
|
|
426
|
+
});
|
|
427
|
+
console.log(chalk.yellow('๐ก Use ') +
|
|
428
|
+
chalk.green('js-common add') +
|
|
429
|
+
chalk.yellow(' to integrate functions into your project'));
|
|
430
|
+
console.log(chalk.yellow('๐ก Use ') +
|
|
431
|
+
chalk.green('js-common interactive') +
|
|
432
|
+
chalk.yellow(' for interactive mode'));
|
|
433
|
+
console.log(chalk.yellow('๐ก Use ') +
|
|
434
|
+
chalk.green('js-common <command> --help') +
|
|
435
|
+
chalk.yellow(' for detailed help\n'));
|
|
436
|
+
process.exit(0);
|
|
437
|
+
}
|
|
438
|
+
// Parse command line arguments
|
|
439
|
+
program.parse();
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,440 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import { fileURLToPath } from 'node:url';
|
|
11
|
-
// Get current directory
|
|
12
|
-
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
// Get package version
|
|
14
|
-
const packageJson = JSON.parse(readFileSync(resolve(currentDir, '../../package.json'), 'utf-8'));
|
|
15
|
-
program
|
|
16
|
-
.name('js-common')
|
|
17
|
-
.description(chalk.cyan('โจ CLI utilities from @rtorcato/js-common'))
|
|
18
|
-
.version(packageJson.version);
|
|
19
|
-
// Function categories for list and interactive mode
|
|
20
|
-
const functionCategories = {
|
|
21
|
-
date: {
|
|
22
|
-
name: '๐
Date & Time',
|
|
23
|
-
functions: [
|
|
24
|
-
{ name: 'today', description: "Get today's date (YYYY-MM-DD)" },
|
|
25
|
-
{ name: 'now', description: 'Get current timestamp' },
|
|
26
|
-
{ name: 'between', description: 'Calculate days between dates' },
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
math: {
|
|
30
|
-
name: '๐ข Mathematical',
|
|
31
|
-
functions: [
|
|
32
|
-
{ name: 'sum', description: 'Calculate sum of numbers' },
|
|
33
|
-
{ name: 'avg', description: 'Calculate average of numbers' },
|
|
34
|
-
{ name: 'random', description: 'Generate random number' },
|
|
35
|
-
{ name: 'round', description: 'Round to decimal places' },
|
|
36
|
-
{ name: 'clamp', description: 'Clamp between min/max' },
|
|
37
|
-
],
|
|
38
|
-
},
|
|
39
|
-
text: {
|
|
40
|
-
name: '๐ Text Formatting',
|
|
41
|
-
functions: [
|
|
42
|
-
{ name: 'capitalize', description: 'Capitalize first letter' },
|
|
43
|
-
{ name: 'title', description: 'Convert to title case' },
|
|
44
|
-
{ name: 'pad', description: 'Pad with leading zeros' },
|
|
45
|
-
],
|
|
46
|
-
},
|
|
47
|
-
file: {
|
|
48
|
-
name: '๐ File Operations',
|
|
49
|
-
functions: [
|
|
50
|
-
{ name: 'exists', description: 'Check if file exists' },
|
|
51
|
-
{ name: 'ext', description: 'Get file extension' },
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
security: {
|
|
55
|
-
name: '๐ Security',
|
|
56
|
-
functions: [
|
|
57
|
-
{ name: 'password', description: 'Check password strength' },
|
|
58
|
-
{ name: 'token', description: 'Generate secure token' },
|
|
59
|
-
],
|
|
60
|
-
},
|
|
61
|
-
validate: {
|
|
62
|
-
name: 'โ
Validation',
|
|
63
|
-
functions: [{ name: 'url', description: 'Validate URL format' }],
|
|
64
|
-
},
|
|
65
|
-
system: {
|
|
66
|
-
name: '๐ป System Info',
|
|
67
|
-
functions: [
|
|
68
|
-
{ name: 'pid', description: 'Get process ID' },
|
|
69
|
-
{ name: 'uptime', description: 'Get process uptime' },
|
|
70
|
-
{ name: 'ci', description: 'Check CI environment' },
|
|
71
|
-
{ name: 'node-version', description: 'Get Node.js version' },
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
// List all functions - add as a separate command
|
|
76
|
-
program
|
|
77
|
-
.command('list')
|
|
78
|
-
.alias('ls')
|
|
79
|
-
.description('๐ List all available functions')
|
|
80
|
-
.action(() => {
|
|
81
|
-
console.log(chalk.cyan('\nโจ Available Functions:\n'));
|
|
82
|
-
Object.entries(functionCategories).forEach(([key, category]) => {
|
|
83
|
-
console.log(chalk.bold(category.name));
|
|
84
|
-
console.log(); // Add space after category header
|
|
85
|
-
category.functions.forEach((func) => {
|
|
86
|
-
console.log(chalk.gray(` js-common ${key} ${func.name}`) + chalk.dim(` - ${func.description}`));
|
|
87
|
-
});
|
|
88
|
-
console.log(); // Add space after function list
|
|
89
|
-
});
|
|
90
|
-
console.log(chalk.yellow('๐ก Use ') +
|
|
91
|
-
chalk.green('js-common add') +
|
|
92
|
-
chalk.yellow(' to integrate functions into your project'));
|
|
93
|
-
console.log(chalk.yellow('๐ก Use ') +
|
|
94
|
-
chalk.green('js-common interactive') +
|
|
95
|
-
chalk.yellow(' for interactive mode'));
|
|
96
|
-
console.log(chalk.yellow('๐ก Use ') +
|
|
97
|
-
chalk.green('js-common <command> --help') +
|
|
98
|
-
chalk.yellow(' for detailed help\n'));
|
|
99
|
-
});
|
|
100
|
-
// Also add as an option for compatibility
|
|
101
|
-
program.option('-l, --list', 'List all available functions');
|
|
102
|
-
// Interactive mode
|
|
103
|
-
program
|
|
104
|
-
.command('interactive')
|
|
105
|
-
.alias('i')
|
|
106
|
-
.description('๐ฎ Interactive mode with guided prompts')
|
|
107
|
-
.action(async () => {
|
|
108
|
-
// Welcome animation
|
|
109
|
-
const title = figlet.textSync('JS Common', { font: 'Small' });
|
|
110
|
-
console.log(gradient.pastel.multiline(title));
|
|
111
|
-
const rainbow = chalkAnimation.rainbow('\nโจ Welcome to JS Common Interactive Mode! โจ\n');
|
|
112
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
113
|
-
rainbow.stop();
|
|
114
|
-
try {
|
|
115
|
-
// Main interactive loop
|
|
116
|
-
while (true) {
|
|
117
|
-
const category = await select({
|
|
118
|
-
message: chalk.cyan('What would you like to do?'),
|
|
119
|
-
choices: Object.entries(functionCategories)
|
|
120
|
-
.reduce((acc, [key, cat], index) => {
|
|
121
|
-
acc.push({ name: cat.name, value: key });
|
|
122
|
-
if (index < Object.entries(functionCategories).length - 1) {
|
|
123
|
-
acc.push(new Separator(' '));
|
|
124
|
-
}
|
|
125
|
-
return acc;
|
|
126
|
-
}, [])
|
|
127
|
-
.concat([new Separator(' '), { name: chalk.red('โ Exit'), value: 'exit' }]),
|
|
128
|
-
pageSize: 17,
|
|
129
|
-
loop: false,
|
|
130
|
-
});
|
|
131
|
-
// Handle exit selection
|
|
132
|
-
if (category === 'exit') {
|
|
133
|
-
console.log(chalk.yellow('\n๐ Goodbye!\n'));
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
const selectedCategory = functionCategories[category];
|
|
137
|
-
// Function selection loop
|
|
138
|
-
while (true) {
|
|
139
|
-
const functionName = await select({
|
|
140
|
-
message: chalk.cyan(`Choose a ${selectedCategory.name} function:`),
|
|
141
|
-
choices: selectedCategory.functions
|
|
142
|
-
.reduce((acc, func, index) => {
|
|
143
|
-
acc.push({ name: `${func.name} - ${func.description}`, value: func.name });
|
|
144
|
-
if (index < selectedCategory.functions.length - 1) {
|
|
145
|
-
acc.push(new Separator(' '));
|
|
146
|
-
}
|
|
147
|
-
return acc;
|
|
148
|
-
}, [])
|
|
149
|
-
.concat([
|
|
150
|
-
new Separator(' '),
|
|
151
|
-
{ name: chalk.gray('โฌ
๏ธ Back to categories'), value: 'back' },
|
|
152
|
-
{ name: chalk.red('โ Exit'), value: 'exit' },
|
|
153
|
-
]),
|
|
154
|
-
pageSize: 12,
|
|
155
|
-
loop: false,
|
|
156
|
-
});
|
|
157
|
-
// Handle navigation options
|
|
158
|
-
if (functionName === 'exit') {
|
|
159
|
-
console.log(chalk.yellow('\n๐ Goodbye!\n'));
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
if (functionName === 'back') {
|
|
163
|
-
break; // Break out of function selection loop, go back to categories
|
|
164
|
-
}
|
|
165
|
-
// Show the command
|
|
166
|
-
console.log(chalk.green(`\n๐ You can run this command:`));
|
|
167
|
-
console.log(chalk.yellow(`js-common ${category} ${functionName} [arguments]`));
|
|
168
|
-
console.log(chalk.gray(`\nFor detailed usage, run: js-common ${category} ${functionName} --help\n`));
|
|
169
|
-
return; // Exit after showing the command
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
catch (error) {
|
|
174
|
-
if (error && typeof error === 'object' && 'isTtyError' in error) {
|
|
175
|
-
console.log(chalk.red('\nโ Interactive mode requires a TTY terminal'));
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
console.log(chalk.red('\nโ Something went wrong in interactive mode'));
|
|
179
|
-
}
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
// Add command - help developers integrate functions into their projects
|
|
184
|
-
program
|
|
185
|
-
.command('add')
|
|
186
|
-
.alias('a')
|
|
187
|
-
.description('๐ง Add utility functions to your project')
|
|
188
|
-
.action(async () => {
|
|
189
|
-
// Welcome message
|
|
190
|
-
console.log(gradient.pastel('\n๐ง Function Integration Helper\n'));
|
|
191
|
-
try {
|
|
192
|
-
const category = await select({
|
|
193
|
-
message: chalk.cyan('Which category of utilities do you need?'),
|
|
194
|
-
choices: Object.entries(functionCategories)
|
|
195
|
-
.reduce((acc, [key, cat], index) => {
|
|
196
|
-
acc.push({ name: cat.name, value: key });
|
|
197
|
-
if (index < Object.entries(functionCategories).length - 1) {
|
|
198
|
-
acc.push(new Separator(' '));
|
|
199
|
-
}
|
|
200
|
-
return acc;
|
|
201
|
-
}, [])
|
|
202
|
-
.concat([new Separator(' '), { name: chalk.red('โ Exit'), value: 'exit' }]),
|
|
203
|
-
pageSize: 17,
|
|
204
|
-
loop: false,
|
|
205
|
-
});
|
|
206
|
-
// Handle exit selection
|
|
207
|
-
if (category === 'exit') {
|
|
208
|
-
console.log(chalk.yellow('\n๐ Goodbye!\n'));
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
const selectedCategory = functionCategories[category];
|
|
212
|
-
const functions = await checkbox({
|
|
213
|
-
message: chalk.cyan(`Select ${selectedCategory.name} functions to add:`),
|
|
214
|
-
choices: selectedCategory.functions.map((func) => ({
|
|
215
|
-
name: `${func.name} - ${func.description}`,
|
|
216
|
-
value: func.name,
|
|
217
|
-
checked: false,
|
|
218
|
-
})),
|
|
219
|
-
pageSize: 10,
|
|
220
|
-
loop: false,
|
|
221
|
-
});
|
|
222
|
-
if (functions.length === 0) {
|
|
223
|
-
console.log(chalk.yellow('\n๐ No functions selected. Exiting...\n'));
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
console.log(chalk.green('\n๐ฆ Import Statement:'));
|
|
227
|
-
console.log(chalk.white(`import { ${functions.join(', ')} } from '@rtorcato/js-common/${category}'`));
|
|
228
|
-
console.log(chalk.green('\n๐ Usage Examples:'));
|
|
229
|
-
functions.forEach((func) => {
|
|
230
|
-
const funcInfo = selectedCategory.functions.find((f) => f.name === func);
|
|
231
|
-
if (funcInfo) {
|
|
232
|
-
console.log(chalk.gray(`\n// ${funcInfo.description}`));
|
|
233
|
-
generateUsageExample(category, func);
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
console.log(chalk.green('\n๐ Documentation:'));
|
|
237
|
-
console.log(chalk.blue(`https://github.com/rtorcato/js-common#${category}-utilities`));
|
|
238
|
-
console.log(chalk.yellow('\n๐ก Tip: Run ') +
|
|
239
|
-
chalk.green(`js-common ${category} ${functions[0]} --help`) +
|
|
240
|
-
chalk.yellow(' for detailed CLI usage\n'));
|
|
241
|
-
}
|
|
242
|
-
catch (error) {
|
|
243
|
-
if (error && typeof error === 'object' && 'isTtyError' in error) {
|
|
244
|
-
console.log(chalk.red('\nโ Interactive mode requires a TTY terminal'));
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
console.log(chalk.red('\nโ Something went wrong'));
|
|
248
|
-
}
|
|
249
|
-
process.exit(1);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
// Helper function to generate usage examples
|
|
253
|
-
function generateUsageExample(category, functionName) {
|
|
254
|
-
const examples = {
|
|
255
|
-
date: {
|
|
256
|
-
today: `const today = today(); // "${new Date().toISOString().split('T')[0]}"`,
|
|
257
|
-
now: `const timestamp = now(); // ${Date.now()}`,
|
|
258
|
-
between: `const days = daysBetween('2023-01-01', '2023-12-31'); // 364`,
|
|
259
|
-
},
|
|
260
|
-
math: {
|
|
261
|
-
sum: `const total = sum([1, 2, 3, 4, 5]); // 15`,
|
|
262
|
-
avg: `const average = avg([10, 20, 30]); // 20`,
|
|
263
|
-
random: `const num = randomBetween(1, 100); // 42`,
|
|
264
|
-
round: `const rounded = roundTo(3.14159, 2); // 3.14`,
|
|
265
|
-
clamp: `const clamped = clamp(150, 0, 100); // 100`,
|
|
266
|
-
},
|
|
267
|
-
text: {
|
|
268
|
-
capitalize: `const text = capitalize('hello world'); // "Hello world"`,
|
|
269
|
-
title: `const title = toTitleCase('hello world'); // "Hello World"`,
|
|
270
|
-
pad: `const padded = padWithZeros(42, 5); // "00042"`,
|
|
271
|
-
},
|
|
272
|
-
file: {
|
|
273
|
-
exists: `const exists = await fileExists('package.json'); // true`,
|
|
274
|
-
ext: `const extension = getFileExtension('file.txt'); // "txt"`,
|
|
275
|
-
},
|
|
276
|
-
security: {
|
|
277
|
-
password: `const isStrong = checkPasswordStrength('MyPass123!'); // true`,
|
|
278
|
-
token: `const token = generateSecureToken(32); // "abc123..."`,
|
|
279
|
-
},
|
|
280
|
-
validate: {
|
|
281
|
-
url: `const isValid = isValidUrl('https://example.com'); // true`,
|
|
282
|
-
},
|
|
283
|
-
system: {
|
|
284
|
-
pid: `const processId = getProcessId(); // 12345`,
|
|
285
|
-
uptime: `const uptime = getProcessUptime(); // 123.45`,
|
|
286
|
-
ci: `const isCI = isCiEnvironment(); // false`,
|
|
287
|
-
'node-version': `const version = getNodeVersion(); // "18.17.0"`,
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
|
-
const example = examples[category]?.[functionName];
|
|
291
|
-
if (example) {
|
|
292
|
-
console.log(chalk.white(example));
|
|
293
|
-
}
|
|
2
|
+
// Entry point for the js-common CLI binary.
|
|
3
|
+
// CLI-only npm deps (chalk, commander, figlet, โฆ) live under
|
|
4
|
+
// `optionalDependencies` to keep the install footprint small for
|
|
5
|
+
// library-only consumers. If any of them is missing at runtime we
|
|
6
|
+
// catch the resolution error and print install instructions instead
|
|
7
|
+
// of letting Node emit an opaque ERR_MODULE_NOT_FOUND trace.
|
|
8
|
+
try {
|
|
9
|
+
await import('./cli.mjs');
|
|
294
10
|
}
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
.option('-t, --time', 'Time only')
|
|
308
|
-
.action((options) => {
|
|
309
|
-
if (options.iso) {
|
|
310
|
-
console.log(new Date().toISOString());
|
|
311
|
-
}
|
|
312
|
-
else if (options.time) {
|
|
313
|
-
console.log(new Date().toTimeString());
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
console.log(Date.now());
|
|
11
|
+
catch (err) {
|
|
12
|
+
const isMissingModule = err !== null &&
|
|
13
|
+
typeof err === 'object' &&
|
|
14
|
+
'code' in err &&
|
|
15
|
+
err.code === 'ERR_MODULE_NOT_FOUND';
|
|
16
|
+
if (isMissingModule) {
|
|
17
|
+
process.stderr.write('The js-common CLI requires optional dependencies that are not installed.\n' +
|
|
18
|
+
'Install them globally to use the CLI:\n\n' +
|
|
19
|
+
' npm install -g @rtorcato/js-common\n\n' +
|
|
20
|
+
'Or run it ad-hoc with npx, which installs them on demand:\n\n' +
|
|
21
|
+
' npx @rtorcato/js-common@latest --help\n');
|
|
22
|
+
process.exit(1);
|
|
317
23
|
}
|
|
318
|
-
|
|
319
|
-
dateCmd
|
|
320
|
-
.command('between')
|
|
321
|
-
.description('Calculate days between dates')
|
|
322
|
-
.argument('<date1>', 'First date (YYYY-MM-DD)')
|
|
323
|
-
.argument('<date2>', 'Second date (YYYY-MM-DD)')
|
|
324
|
-
.action((date1, date2) => {
|
|
325
|
-
const d1 = new Date(date1);
|
|
326
|
-
const d2 = new Date(date2);
|
|
327
|
-
const timeDiff = Math.abs(d2.getTime() - d1.getTime());
|
|
328
|
-
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24));
|
|
329
|
-
console.log(`${daysDiff} days`);
|
|
330
|
-
});
|
|
331
|
-
// Math commands
|
|
332
|
-
const mathCmd = program.command('math').description('๐ข Mathematical utilities');
|
|
333
|
-
mathCmd
|
|
334
|
-
.command('sum')
|
|
335
|
-
.description('Calculate sum of numbers')
|
|
336
|
-
.argument('<numbers...>', 'Numbers to sum')
|
|
337
|
-
.action((numbers) => {
|
|
338
|
-
const nums = numbers.map(Number).filter((n) => !Number.isNaN(n));
|
|
339
|
-
console.log(nums.reduce((a, b) => a + b, 0));
|
|
340
|
-
});
|
|
341
|
-
mathCmd
|
|
342
|
-
.command('avg')
|
|
343
|
-
.description('Calculate average of numbers')
|
|
344
|
-
.argument('<numbers...>', 'Numbers to average')
|
|
345
|
-
.action((numbers) => {
|
|
346
|
-
const nums = numbers.map(Number).filter((n) => !Number.isNaN(n));
|
|
347
|
-
console.log(nums.reduce((a, b) => a + b, 0) / nums.length);
|
|
348
|
-
});
|
|
349
|
-
mathCmd
|
|
350
|
-
.command('random')
|
|
351
|
-
.description('Generate random number')
|
|
352
|
-
.argument('<min>', 'Minimum value')
|
|
353
|
-
.argument('<max>', 'Maximum value')
|
|
354
|
-
.action((min, max) => {
|
|
355
|
-
const minNum = Number(min);
|
|
356
|
-
const maxNum = Number(max);
|
|
357
|
-
console.log(Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
|
|
358
|
-
});
|
|
359
|
-
mathCmd
|
|
360
|
-
.command('round')
|
|
361
|
-
.description('Round to decimal places')
|
|
362
|
-
.argument('<number>', 'Number to round')
|
|
363
|
-
.argument('<decimals>', 'Decimal places')
|
|
364
|
-
.action((number, decimals) => {
|
|
365
|
-
const num = Number(number);
|
|
366
|
-
const dec = Number(decimals);
|
|
367
|
-
console.log(Number(num.toFixed(dec)));
|
|
368
|
-
});
|
|
369
|
-
mathCmd
|
|
370
|
-
.command('clamp')
|
|
371
|
-
.description('Clamp between min/max')
|
|
372
|
-
.argument('<number>', 'Number to clamp')
|
|
373
|
-
.argument('<min>', 'Minimum value')
|
|
374
|
-
.argument('<max>', 'Maximum value')
|
|
375
|
-
.action((number, min, max) => {
|
|
376
|
-
const num = Number(number);
|
|
377
|
-
const minVal = Number(min);
|
|
378
|
-
const maxVal = Number(max);
|
|
379
|
-
console.log(Math.min(Math.max(num, minVal), maxVal));
|
|
380
|
-
});
|
|
381
|
-
// Simple implementations for other commands
|
|
382
|
-
const textCmd = program.command('text').description('๐ Text formatting utilities');
|
|
383
|
-
textCmd
|
|
384
|
-
.command('capitalize')
|
|
385
|
-
.description('Capitalize first letter')
|
|
386
|
-
.argument('<text>', 'Text to capitalize')
|
|
387
|
-
.action((text) => {
|
|
388
|
-
console.log(text.charAt(0).toUpperCase() + text.slice(1));
|
|
389
|
-
});
|
|
390
|
-
textCmd
|
|
391
|
-
.command('title')
|
|
392
|
-
.description('Convert to title case')
|
|
393
|
-
.argument('<text>', 'Text to convert')
|
|
394
|
-
.action((text) => {
|
|
395
|
-
console.log(text.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase()));
|
|
396
|
-
});
|
|
397
|
-
// System commands
|
|
398
|
-
const systemCmd = program.command('system').description('๐ป System information utilities');
|
|
399
|
-
systemCmd
|
|
400
|
-
.command('pid')
|
|
401
|
-
.description('Get process ID')
|
|
402
|
-
.action(() => {
|
|
403
|
-
console.log(process.pid);
|
|
404
|
-
});
|
|
405
|
-
systemCmd
|
|
406
|
-
.command('uptime')
|
|
407
|
-
.description('Get process uptime')
|
|
408
|
-
.action(() => {
|
|
409
|
-
console.log(`${Math.floor(process.uptime())} seconds`);
|
|
410
|
-
});
|
|
411
|
-
systemCmd
|
|
412
|
-
.command('node-version')
|
|
413
|
-
.description('Get Node.js version')
|
|
414
|
-
.action(() => {
|
|
415
|
-
console.log(process.version);
|
|
416
|
-
});
|
|
417
|
-
// Handle --list option before parsing
|
|
418
|
-
if (process.argv.includes('--list') || process.argv.includes('-l')) {
|
|
419
|
-
console.log(chalk.cyan('\nโจ Available Functions:\n'));
|
|
420
|
-
Object.entries(functionCategories).forEach(([key, category]) => {
|
|
421
|
-
console.log(chalk.bold(category.name));
|
|
422
|
-
console.log(); // Add space after category header
|
|
423
|
-
category.functions.forEach((func) => {
|
|
424
|
-
console.log(chalk.gray(` js-common ${key} ${func.name}`) + chalk.dim(` - ${func.description}`));
|
|
425
|
-
});
|
|
426
|
-
console.log(); // Add space after function list
|
|
427
|
-
});
|
|
428
|
-
console.log(chalk.yellow('๐ก Use ') +
|
|
429
|
-
chalk.green('js-common add') +
|
|
430
|
-
chalk.yellow(' to integrate functions into your project'));
|
|
431
|
-
console.log(chalk.yellow('๐ก Use ') +
|
|
432
|
-
chalk.green('js-common interactive') +
|
|
433
|
-
chalk.yellow(' for interactive mode'));
|
|
434
|
-
console.log(chalk.yellow('๐ก Use ') +
|
|
435
|
-
chalk.green('js-common <command> --help') +
|
|
436
|
-
chalk.yellow(' for detailed help\n'));
|
|
437
|
-
process.exit(0);
|
|
24
|
+
throw err;
|
|
438
25
|
}
|
|
439
|
-
|
|
440
|
-
program.parse();
|
|
26
|
+
export {};
|
package/dist/env/index.js
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import"../chunks/chunk-ANN5UYCF.js";
|
|
2
|
-
`;t+=Object.keys(e.flatten().fieldErrors).join(`
|
|
3
|
-
`);let s=new Error(t);throw s.stack="",s}throw e}}var f=n.object({NODE_ENV:n.enum(["development","test","production"]).default("development"),LOG_LEVEL:n.enum(["debug","info","warn","error"]).default("info"),PORT:n.coerce.number().default(3e3)});export{f as RootApiEnvSchema,a as checkEnv,c as getENV,u as getNodeEnv,d as isDev,p as isProd,E as isTest};
|
|
1
|
+
import{a,b,c,d,e,f,g}from"../chunks/chunk-FBDKWWIQ.js";import"../chunks/chunk-ANN5UYCF.js";export{g as RootApiEnvSchema,f as checkEnv,a as getENV,e as getNodeEnv,b as isDev,c as isProd,d as isTest};
|
package/dist/index.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./chunks/chunk-ANN5UYCF.js";var t=()=>(console.log("test"),"testPackage");export{t as testPackage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as o}from"../chunks/chunk-6J7HIWG6.js";import"../chunks/chunk-FBDKWWIQ.js";import"../chunks/chunk-ANN5UYCF.js";export{o as logger};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a}from"../chunks/chunk-6J7HIWG6.js";import"../chunks/chunk-FBDKWWIQ.js";import"../chunks/chunk-ANN5UYCF.js";export{a as logger};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rtorcato/js-common",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "JavaScript and TypeScript common code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"scripts": {
|
|
29
29
|
"build-dev": "rimraf ./dist && cross-env NODE_ENV=development node build.mjs && tsc --emitDeclarationOnly --project tsconfig.build.json && npm run build-cli",
|
|
30
30
|
"build-prod": "rimraf ./dist && cross-env NODE_ENV=production node build.mjs && tsc --emitDeclarationOnly --project tsconfig.build.json && npm run build-cli",
|
|
31
|
-
"build-cli": "tsc src/cli/cli.ts --ignoreConfig --types node --outDir dist/cli --target ES2022 --module ES2022 --moduleResolution bundler --allowImportingTsExtensions false --esModuleInterop --skipLibCheck &&
|
|
31
|
+
"build-cli": "tsc src/cli/bootstrap.ts src/cli/cli.ts --ignoreConfig --types node --outDir dist/cli --target ES2022 --module ES2022 --moduleResolution bundler --allowImportingTsExtensions false --esModuleInterop --skipLibCheck && echo '#!/usr/bin/env node' > dist/cli/index.mjs && cat dist/cli/bootstrap.js >> dist/cli/index.mjs && rm dist/cli/bootstrap.js && mv dist/cli/cli.js dist/cli/cli.mjs && sed -i.bak \"s|'./cli.js'|'./cli.mjs'|g\" dist/cli/index.mjs && rm dist/cli/index.mjs.bak && chmod +x dist/cli/index.mjs",
|
|
32
32
|
"prepublishOnly": "npm run build-prod",
|
|
33
33
|
"==================== Common ====================": "",
|
|
34
34
|
"lint": "pnpm exec biome lint .",
|
|
@@ -116,6 +116,10 @@
|
|
|
116
116
|
"import": "./dist/file/index.js",
|
|
117
117
|
"types": "./dist/file/index.d.ts"
|
|
118
118
|
},
|
|
119
|
+
"./formatting": {
|
|
120
|
+
"import": "./dist/formatting/index.js",
|
|
121
|
+
"types": "./dist/formatting/index.d.ts"
|
|
122
|
+
},
|
|
119
123
|
"./functions": {
|
|
120
124
|
"import": "./dist/functions/index.js",
|
|
121
125
|
"types": "./dist/functions/index.d.ts"
|
|
@@ -249,7 +253,6 @@
|
|
|
249
253
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
250
254
|
"@types/chalk-animation": "^1.6.3",
|
|
251
255
|
"@types/figlet": "^1.7.0",
|
|
252
|
-
"@types/inquirer": "^9.0.9",
|
|
253
256
|
"@types/luxon": "^3.7.1",
|
|
254
257
|
"@types/node": "^24.9.1",
|
|
255
258
|
"@vitest/coverage-istanbul": "^4.0.17",
|
|
@@ -257,6 +260,7 @@
|
|
|
257
260
|
"esbuild": "^0.27.4",
|
|
258
261
|
"husky": "^9.1.7",
|
|
259
262
|
"jsdom": "^29.0.1",
|
|
263
|
+
"knip": "^6.14.2",
|
|
260
264
|
"lint-staged": "^16.2.6",
|
|
261
265
|
"rimraf": "^6.0.1",
|
|
262
266
|
"semantic-release": "^25.0.1",
|
|
@@ -264,22 +268,22 @@
|
|
|
264
268
|
"vitest": "^4.0.17"
|
|
265
269
|
},
|
|
266
270
|
"dependencies": {
|
|
267
|
-
"@inquirer/prompts": "^8.5.0",
|
|
268
|
-
"chalk": "^5.6.2",
|
|
269
|
-
"chalk-animation": "^2.0.3",
|
|
270
|
-
"commander": "^14.0.1",
|
|
271
271
|
"date-fns": "^4.1.0",
|
|
272
272
|
"date-fns-tz": "^3.2.0",
|
|
273
|
-
"figlet": "^1.9.3",
|
|
274
|
-
"gradient-string": "^3.0.0",
|
|
275
|
-
"inquirer": "^13.3.2",
|
|
276
273
|
"luxon": "^3.7.2",
|
|
277
|
-
"nanospinner": "^1.2.2",
|
|
278
274
|
"pino": "^10.1.0",
|
|
279
275
|
"short-uuid": "^6.0.3",
|
|
280
276
|
"uuid": "^13.0.0",
|
|
281
277
|
"zod": "^4.1.12"
|
|
282
278
|
},
|
|
279
|
+
"optionalDependencies": {
|
|
280
|
+
"@inquirer/prompts": "^8.5.0",
|
|
281
|
+
"chalk": "^5.6.2",
|
|
282
|
+
"chalk-animation": "^2.0.3",
|
|
283
|
+
"commander": "^14.0.1",
|
|
284
|
+
"figlet": "^1.9.3",
|
|
285
|
+
"gradient-string": "^3.0.0"
|
|
286
|
+
},
|
|
283
287
|
"config": {
|
|
284
288
|
"commitizen": {
|
|
285
289
|
"path": "cz-conventional-changelog"
|
|
@@ -299,5 +303,8 @@
|
|
|
299
303
|
},
|
|
300
304
|
"publishConfig": {
|
|
301
305
|
"access": "public"
|
|
306
|
+
},
|
|
307
|
+
"engines": {
|
|
308
|
+
"node": ">=22"
|
|
302
309
|
}
|
|
303
310
|
}
|
package/dist/helloworld/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"../chunks/chunk-ANN5UYCF.js";function l(){return"Hello, World!"}export{l as helloWorld};
|
package/dist/logging/index1.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"../chunks/chunk-ANN5UYCF.js";var t=(...o)=>{let n=new Date().toISOString();console.log(`[${n}]`,...o)},e=(...o)=>{console.warn("\x1B[33m%s\x1B[0m",...o)},s=(...o)=>{console.error("\x1B[31m%s\x1B[0m",...o)},r=(...o)=>{console.info("\x1B[34m%s\x1B[0m",...o)};export{s as error,r as info,t as logWithTimestamp,e as warn};
|