lenix 1.4.4 → 1.6.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.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Throws an error.
3
+ * @param error - The error to throw, can be a source of the error.
4
+ * @param cause - The cause of the error.
5
+ * @returns never, will crash the runtime.
6
+ * @example
7
+ * foo().catch(raise)
8
+ */
9
+ export const raise = (error: unknown, cause?: unknown): never => { throw new Error(String(error), { cause }) }
@@ -2,4 +2,6 @@
2
2
  * Delay execution for a given duration.
3
3
  * @param ms - Duration in milliseconds (1000ms = 1 second)
4
4
  */
5
- export const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
5
+ export const wait = async (ms: number): Promise<void> => {
6
+ await new Promise(resolve => { setTimeout(resolve, ms) })
7
+ }
package/oop/README.md CHANGED
@@ -7,12 +7,15 @@ Lua object oriented programming class module allow you to use oop similar to the
7
7
  Auto-configure Lua to use `./lua_modules` (like `node_modules`) instead of unorganized directories.
8
8
 
9
9
  ### Install
10
+
10
11
  - MAC
12
+
11
13
  ```bash
12
14
  npx mac-lua-modules
13
15
  ```
14
16
 
15
17
  ### Usage
18
+
16
19
  ```bash
17
20
  # Install Lua packages
18
21
  luarocks install --tree ./lua_modules inspect
@@ -24,4 +27,4 @@ print(inspect({name = "Lenix"}))
24
27
 
25
28
  ### What it does
26
29
 
27
- Adds environment variables to your shell config (for mac users: `~/.zshrc` or `~/.bashrc`) to automatically change your Lua modules configurations to `./lua_modules` instead of hidden nested directories.
30
+ Adds environment variables to your shell config (for mac users: `~/.zshrc` or `~/.bashrc`) to automatically change your Lua modules configurations to `./lua_modules` instead of hidden nested directories.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lenix",
3
- "version": "1.4.4",
3
+ "version": "1.6.0",
4
4
  "description": "The All-in-one Package",
5
5
  "author": "Lenix",
6
6
  "license": "GPL-3.0",
@@ -37,26 +37,32 @@
37
37
  ],
38
38
  "bin": {
39
39
  "mac-lua-modules": "oop/mac-lua-modules.sh",
40
- "lenix": "./lint/dist/lint.mjs"
40
+ "lenix": "./index.ts"
41
41
  },
42
42
  "dependencies": {
43
- "@eslint/js": "^10.0.1",
44
- "eslint": "^10.0.3",
43
+ "@clack/prompts": "^1.1.0",
45
44
  "eslint-plugin-import": "^2.32.0",
46
45
  "eslint-plugin-react": "^7.37.5",
47
- "eslint-plugin-react-hooks": "^7.0.1",
48
- "globals": "^17.4.0",
49
- "typescript-eslint": "^8.57.0"
46
+ "eslint-plugin-react-hooks": "^7.0.1"
50
47
  },
51
48
  "devDependencies": {
49
+ "@eslint/js": "^10.0.1",
52
50
  "@types/eslint": "^9.6.1",
53
51
  "@types/node": "^20.7.1",
52
+ "eslint": "^10.0.3",
53
+ "eslint-config-prettier": "10.1.8",
54
+ "globals": "^17.4.0",
55
+ "jiti": "^2.6.1",
56
+ "prettier": "3.8.1",
54
57
  "tsc-alias": "^1.8.16",
55
58
  "tsx": "^4.21.0",
56
- "typescript": "^5.3.3"
59
+ "typescript": "^5.3.3",
60
+ "typescript-eslint": "^8.57.0"
57
61
  },
58
62
  "scripts": {
59
63
  "build-lint": "tsc -p lint/src/tsconfig.json",
60
- "bump": "pnpm version patch"
64
+ "bump": "pnpm version patch",
65
+ "format": "pnpm exec prettier . --write",
66
+ "lint": "pnpm exec eslint ."
61
67
  }
62
68
  }
@@ -1,275 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs';
3
- import path from 'path';
4
- import eslintJs from '@eslint/js';
5
- import tseslint from 'typescript-eslint';
6
- const [, , cmd, ...args] = process.argv;
7
- if (cmd !== '--lint') {
8
- process.stdout.write('Usage: lenix --lint [--preset]\n');
9
- process.exit(0);
10
- }
11
- process.argv = [process.argv[0], process.argv[1], ...args];
12
- const c = { reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', cyan: '\x1b[36m', yellow: '\x1b[33m', green: '\x1b[32m', red: '\x1b[31m', blue: '\x1b[34m', magenta: '\x1b[35m', gray: '\x1b[90m' };
13
- const title = (s) => `${c.bold}${c.cyan}${s}${c.reset}`;
14
- const section = (s) => `\n${c.bold}${c.blue}━━ ${s} ━━${c.reset}`;
15
- const bold = (s) => `${c.bold}${s}${c.reset}`;
16
- const dim = (s) => `${c.dim}${s}${c.reset}`;
17
- const gray = (s) => `${c.gray}${s}${c.reset}`;
18
- const tag = (s, col) => `${col}[${s}]${c.reset}`;
19
- const pr = (s) => `${c.magenta}${s}${c.reset}`;
20
- const ttyFd = fs.openSync('/dev/tty', 'r');
21
- function readLine(question) {
22
- process.stdout.write(question);
23
- const buf = Buffer.alloc(1024);
24
- let result = '';
25
- while (true) {
26
- const n = fs.readSync(ttyFd, buf, 0, 1, null);
27
- if (n === 0)
28
- break;
29
- const ch = buf.toString('utf8', 0, n);
30
- if (ch === '\n')
31
- break;
32
- if (ch === '\r')
33
- continue;
34
- result += ch;
35
- }
36
- return result;
37
- }
38
- const CHECKPOINT = '.lint-preset.json';
39
- function saveCheckpoint(state) {
40
- const data = {
41
- outFile: state.outFile,
42
- rules: state.allRules,
43
- completedSections: [...state.completedSections],
44
- pausedSection: state.pausedSection,
45
- pausedAt: state.pausedAt,
46
- };
47
- fs.writeFileSync(CHECKPOINT, JSON.stringify(data, null, 2), 'utf8');
48
- }
49
- function loadCheckpoint() {
50
- try {
51
- if (!fs.existsSync(CHECKPOINT))
52
- return null;
53
- return JSON.parse(fs.readFileSync(CHECKPOINT, 'utf8'));
54
- }
55
- catch {
56
- return null;
57
- }
58
- }
59
- function buildPluginRules(rules, prefix) {
60
- return Object.entries(rules)
61
- .filter(([, r]) => !r.meta?.deprecated)
62
- .map(([name, r]) => ({
63
- fullName: `${prefix}/${name}`,
64
- description: r.meta?.docs?.description ?? '',
65
- fixable: !!r.meta?.fixable,
66
- recommended: !!(r.meta?.docs?.recommended),
67
- requiresTypeChecking: !!(r.meta?.docs?.requiresTypeChecking),
68
- url: r.meta?.docs?.url ?? '',
69
- }));
70
- }
71
- async function getCoreRules() {
72
- try {
73
- const { builtinRules } = await import('eslint/use-at-your-own-risk');
74
- const byCat = {};
75
- for (const [name, r] of builtinRules.entries()) {
76
- if (r.meta?.deprecated)
77
- continue;
78
- const cat = r.meta?.docs?.category ?? 'Other';
79
- if (!byCat[cat])
80
- byCat[cat] = [];
81
- byCat[cat].push({ fullName: name, description: r.meta?.docs?.description ?? '', fixable: !!r.meta?.fixable, recommended: !!(r.meta?.docs?.recommended), requiresTypeChecking: false, url: r.meta?.docs?.url ?? '' });
82
- }
83
- return byCat;
84
- }
85
- catch {
86
- return { 'Core': Object.keys(eslintJs.configs.all.rules ?? {}).map(n => ({ fullName: n, description: '', fixable: false, recommended: false, requiresTypeChecking: false, url: '' })) };
87
- }
88
- }
89
- function askRule(rule, idx, total) {
90
- const tags = [rule.recommended ? tag('recommended', c.green) : null, rule.fixable ? tag('fixable', c.yellow) : null, rule.requiresTypeChecking ? tag('type-aware', c.red) : null].filter(Boolean).join(' ');
91
- process.stdout.write(`\n${gray(`[${idx}/${total}]`)} ${bold(rule.fullName)} ${tags}\n`);
92
- if (rule.description)
93
- process.stdout.write(` ${dim(rule.description)}\n`);
94
- if (rule.url)
95
- process.stdout.write(` ${gray(rule.url)}\n`);
96
- const a = readLine(pr(' → off/warn/error/skip/save [o/w/e/s/q]: ')).trim().toLowerCase();
97
- if (!a || a === 's' || a === 'skip')
98
- return null;
99
- if (a === 'q' || a === 'save')
100
- return 'save';
101
- if (a === 'o' || a === 'off')
102
- return [rule.fullName, 'off'];
103
- if (a === 'w' || a === 'warn')
104
- return [rule.fullName, 'warn'];
105
- if (a === 'e' || a === 'error')
106
- return [rule.fullName, 'error'];
107
- process.stdout.write(gray(' Invalid, skipping.\n'));
108
- return null;
109
- }
110
- function askSection(label, rules, state) {
111
- if (state.completedSections.has(label)) {
112
- process.stdout.write(gray(` ✓ Already completed: ${label}\n`));
113
- return;
114
- }
115
- process.stdout.write(section(label) + '\n');
116
- process.stdout.write(gray(` ${rules.length} rules — Enter=skip q=save & exit\n`));
117
- const skip = readLine(pr(' Skip entire section? [y/N]: ')).trim().toLowerCase();
118
- if (skip === 'y') {
119
- state.completedSections.add(label);
120
- saveCheckpoint({ ...state, pausedSection: null, pausedAt: 0 });
121
- process.stdout.write(gray(' Skipped.\n'));
122
- return;
123
- }
124
- const startAt = state.pausedSection === label ? (state.pausedAt ?? 0) : 0;
125
- if (startAt > 0)
126
- process.stdout.write(gray(` Resuming from rule ${startAt + 1}/${rules.length}\n`));
127
- for (let i = startAt; i < rules.length; i++) {
128
- const entry = askRule(rules[i], i + 1, rules.length);
129
- if (entry === 'save') {
130
- saveCheckpoint({ ...state, pausedSection: label, pausedAt: i });
131
- process.stdout.write(`\n${tag('saved', c.green)} Progress saved to ${bold(CHECKPOINT)}\n`);
132
- process.stdout.write(dim('Run the lint again to resume.\n\n'));
133
- fs.closeSync(ttyFd);
134
- process.exit(0);
135
- }
136
- if (entry)
137
- state.allRules[entry[0]] = entry[1];
138
- saveCheckpoint({ ...state, pausedSection: label, pausedAt: i + 1 });
139
- }
140
- state.completedSections.add(label);
141
- saveCheckpoint({ ...state, pausedSection: null, pausedAt: 0 });
142
- }
143
- function generateConfig(allRules) {
144
- const core = {};
145
- const ts = {};
146
- for (const [k, v] of Object.entries(allRules)) {
147
- if (k.startsWith('@typescript-eslint/'))
148
- ts[k] = v;
149
- else
150
- core[k] = v;
151
- }
152
- const ind = (o) => JSON.stringify(o, null, 2).split('\n').map((l, i) => i === 0 ? l : ' ' + l).join('\n');
153
- return [
154
- `import js from '@eslint/js'`,
155
- `import globals from 'globals'`,
156
- `import tseslint from 'typescript-eslint'`,
157
- `import { dirname } from 'path'`,
158
- `import { fileURLToPath } from 'url'`,
159
- ``,
160
- `const __dirname = dirname(fileURLToPath(import.meta.url))`,
161
- ``,
162
- `export default [`,
163
- ` { ignores: ['node_modules', 'dist'] },`,
164
- ` js.configs.recommended,`,
165
- ` ...tseslint.configs.strictTypeChecked,`,
166
- ` {`,
167
- ` files: ['**/*.{ts,tsx,mts}'],`,
168
- ` languageOptions: {`,
169
- ` globals: { ...globals.browser, ...globals.node },`,
170
- ` parserOptions: {`,
171
- ` projectService: true,`,
172
- ` tsconfigRootDir: __dirname,`,
173
- ` },`,
174
- ` },`,
175
- ` rules: ${ind(core)},`,
176
- ` },`,
177
- Object.keys(ts).length > 0 ? ` {\n files: ['**/*.{ts,tsx,mts}'],\n rules: ${ind(ts)},\n },` : '',
178
- `]`,
179
- ].filter(Boolean).join('\n');
180
- }
181
- const clone = process.argv.includes('--clone');
182
- if (clone) {
183
- const src = path.join(process.env.HOME, '.lint-preset.json');
184
- const data = JSON.parse(fs.readFileSync(src, 'utf8'));
185
- const config = generateConfig(data.rules);
186
- fs.writeFileSync(data.outFile, config, 'utf8');
187
- process.stdout.write(`${tag('done', c.green)} Written to ${bold(data.outFile)}\n`);
188
- fs.closeSync(ttyFd);
189
- process.exit(0);
190
- }
191
- const preset = process.argv.includes('--preset');
192
- if (preset) {
193
- process.stdout.write(`${tag('IMPORTANT', c.red)}: This tool is deprecated, import our rules instead, e.g ${bold('import { lint } from "lenix"')}`);
194
- const res = await fetch('https://raw.githubusercontent.com/LenixDev/lenix/refs/heads/main/lint/src/lint-preset.json');
195
- const data = await res.json();
196
- const config = generateConfig(data.rules);
197
- fs.writeFileSync('eslint.config.mts', config, 'utf8');
198
- process.stdout.write(`${tag('done', c.green)} Written to ${bold('eslint.config.mts')}\n`);
199
- process.stdout.write(`${tag('notice', c.cyan)} Run: ${bold('npm add -D @eslint/js globals typescript-eslint')}\n`);
200
- fs.closeSync(ttyFd);
201
- process.exit(0);
202
- }
203
- async function main() {
204
- process.stdout.write(`${tag('IMPORTANT', c.red)}: This tool is deprecated')}`);
205
- process.stdout.write('\x1Bc');
206
- process.stdout.write(title('╔═══════════════════════╗\n'));
207
- process.stdout.write(title('║ ESLint Config ║\n'));
208
- process.stdout.write(title('╚═══════════════════════╝\n'));
209
- process.stdout.write(dim('\nWalks through every rule across all plugins.\n'));
210
- process.stdout.write(dim('o=off w=warn e=error s/Enter=skip q=save & exit\n\n'));
211
- const checkpoint = loadCheckpoint();
212
- const state = { allRules: {}, completedSections: new Set(), outFile: 'eslint.config.mts', pausedSection: null, pausedAt: 0 };
213
- if (checkpoint) {
214
- process.stdout.write(`${tag('found', c.yellow)} Saved progress detected (${Object.keys(checkpoint.rules).length} rules configured).\n`);
215
- const resume = readLine(pr('Resume? [Y/n]: ')).trim().toLowerCase();
216
- if (resume !== 'n') {
217
- state.outFile = checkpoint.outFile;
218
- state.allRules = checkpoint.rules;
219
- state.completedSections = new Set(checkpoint.completedSections);
220
- state.pausedSection = checkpoint.pausedSection ?? null;
221
- state.pausedAt = checkpoint.pausedAt ?? 0;
222
- }
223
- }
224
- const coreByCategory = await getCoreRules();
225
- for (const [cat, rules] of Object.entries(coreByCategory))
226
- askSection(`Core — ${cat}`, rules, state);
227
- const tsAll = buildPluginRules(tseslint.plugin.rules ?? {}, '@typescript-eslint');
228
- askSection('TypeScript', tsAll.filter(r => !r.requiresTypeChecking), state);
229
- askSection('TypeScript — type-aware', tsAll.filter(r => r.requiresTypeChecking), state);
230
- // askSection('React', buildPluginRules((react.rules ?? {}) as Record<string, any>, 'react'), state)
231
- // askSection('React Hooks', buildPluginRules((reactHooks.rules ?? {}) as Record<string, any>, 'react-hooks'), state)
232
- // askSection('Imports', buildPluginRules((importPlugin.rules ?? {}) as Record<string, any>, 'import'), state)
233
- const config = generateConfig(state.allRules);
234
- let outFile = state.outFile;
235
- if (fs.existsSync(outFile)) {
236
- const overwrite = readLine(pr(`\n${outFile} already exists. Overwrite? [y/N]: `)).trim().toLowerCase();
237
- if (overwrite !== 'y')
238
- outFile = readLine(pr('Enter new filename: ')).trim() || outFile;
239
- }
240
- fs.writeFileSync(outFile, config, 'utf8');
241
- // if (fs.existsSync(CHECKPOINT)) fs.unlinkSync(CHECKPOINT)
242
- process.stdout.write(`\n${tag('done', c.green)} Written to ${bold(outFile)}\n`);
243
- process.stdout.write(dim(`Rules configured: ${Object.keys(state.allRules).length}\n`));
244
- const hasTs = Object.keys(state.allRules).some(k => k.startsWith('@typescript-eslint/'));
245
- const hasReact = Object.keys(state.allRules).some(k => k.startsWith('react/') || k.startsWith('react-hooks/'));
246
- const hasImp = Object.keys(state.allRules).some(k => k.startsWith('import/'));
247
- const deps = [
248
- '@eslint/js',
249
- 'globals',
250
- hasTs ? 'typescript-eslint' : '',
251
- hasReact ? 'eslint-plugin-react eslint-plugin-react-hooks' : '',
252
- hasImp ? 'eslint-plugin-import' : '',
253
- ].filter(Boolean).join(' ');
254
- if (hasTs) {
255
- const tsconfig = {
256
- compilerOptions: {
257
- target: 'ESNext',
258
- module: 'NodeNext',
259
- moduleResolution: 'NodeNext',
260
- strict: true,
261
- },
262
- include: ['**/*.ts', '**/*.mts', '**/*.tsx'],
263
- exclude: ['node_modules'],
264
- };
265
- if (!fs.existsSync('tsconfig.json'))
266
- fs.writeFileSync('tsconfig.json', JSON.stringify(tsconfig, null, 2), 'utf8');
267
- else
268
- process.stdout.write(dim('tsconfig.json already exists, skipping.\n'));
269
- }
270
- const pm = fs.existsSync('pnpm-lock.yaml') ? 'pnpm' : fs.existsSync('yarn.lock') ? 'yarn' : 'npm';
271
- process.stdout.write(dim(`Run: ${pm} add -D ${deps}\n\n`));
272
- fs.closeSync(ttyFd);
273
- process.exit(0);
274
- }
275
- main().catch(e => { console.error(e); process.exit(1); });