create-textmode 1.0.7 → 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/README.md +5 -5
- package/bin/index.js +2 -2
- package/package.json +74 -68
- package/src/args.js +43 -40
- package/src/banner.js +42 -42
- package/src/cli.js +137 -142
- package/src/constants.js +33 -33
- package/src/fs-utils.js +100 -103
- package/src/packageManager.js +13 -13
- package/src/prompts.js +66 -65
- package/src/runCommand.js +38 -38
- package/src/summary.js +28 -33
- package/src/textmodeVersion.js +46 -46
- package/src/usage.js +19 -17
- package/src/versions.js +36 -36
- package/templates/vanilla-js/package.json +7 -7
- package/templates/vanilla-js-tweakpane/package.json +7 -7
- package/templates/vanilla-ts/package.json +10 -10
- package/templates/vanilla-ts/tsconfig.json +1 -1
- package/templates/vanilla-ts-tweakpane/package.json +10 -10
- package/templates/vanilla-ts-tweakpane/tsconfig.json +1 -1
package/src/prompts.js
CHANGED
|
@@ -2,101 +2,102 @@ import path from 'path';
|
|
|
2
2
|
import { confirm, isCancel, cancel, multiselect, select, text } from '@clack/prompts';
|
|
3
3
|
import kleur from 'kleur';
|
|
4
4
|
import { uniqueNamesGenerator, adjectives, colors, animals } from 'unique-names-generator';
|
|
5
|
-
import { addons, templates } from './constants.js';
|
|
5
|
+
import { addons, templates, MIN_TEXTMODE_VERSION } from './constants.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Handle user cancellation uniformly.
|
|
9
|
-
*
|
|
10
|
-
* @
|
|
9
|
+
*
|
|
10
|
+
* @param value - The value returned from a prompt.
|
|
11
|
+
* @returns True if the user cancelled.
|
|
11
12
|
*/
|
|
12
13
|
export function handleCancel(value) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
if (isCancel(value)) {
|
|
15
|
+
cancel('Operation cancelled.');
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export async function promptTemplate() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
const choice = await select({
|
|
23
|
+
message: `${kleur.cyan('Select a template')} ${kleur.gray('(↑↓ move, ↵ confirm)')}`,
|
|
24
|
+
options: templates.map((t) => ({ value: t.name, label: t.label })),
|
|
25
|
+
initialValue: templates[0].name,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
handleCancel(choice);
|
|
29
|
+
return choice;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export async function promptAddons() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
const selection = await multiselect({
|
|
34
|
+
message: `${kleur.cyan('Select add-on libraries to pre-install')} ${kleur.gray('(space to toggle, ↵ confirm, none = skip)')}`,
|
|
35
|
+
options: addons.map((a) => ({ value: a.name, label: a.label, hint: a.description })),
|
|
36
|
+
required: false,
|
|
37
|
+
initialValue: [],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
handleCancel(selection);
|
|
41
|
+
return Array.isArray(selection) ? selection : [];
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
export function suggestProjectName() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
return uniqueNamesGenerator({
|
|
46
|
+
dictionaries: [adjectives, colors, animals],
|
|
47
|
+
separator: '-',
|
|
48
|
+
length: 3,
|
|
49
|
+
});
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export async function promptProjectName(defaultName) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
const name = await text({
|
|
54
|
+
message: `${kleur.cyan('Project name')} ${kleur.gray('(enter to accept default)')}`,
|
|
55
|
+
initialValue: defaultName,
|
|
56
|
+
validate: (value) => (value && value.trim().length > 0 ? undefined : 'Name cannot be empty'),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
handleCancel(name);
|
|
60
|
+
return name.trim();
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
export async function promptOverwrite(targetDir) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
const response = await confirm({
|
|
65
|
+
message: `Directory ${path.basename(targetDir)} is not empty. Continue?`,
|
|
66
|
+
initialValue: false,
|
|
67
|
+
});
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
handleCancel(response);
|
|
70
|
+
return response;
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
export async function promptInstall(pm) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
const decision = await confirm({
|
|
75
|
+
message: `Install dependencies with ${pm}?`,
|
|
76
|
+
initialValue: true,
|
|
77
|
+
});
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
handleCancel(decision);
|
|
80
|
+
return decision;
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
export async function promptRun(pm) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
const decision = await confirm({
|
|
85
|
+
message: `Run dev server now with ${pm}?`,
|
|
86
|
+
initialValue: false,
|
|
87
|
+
});
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
handleCancel(decision);
|
|
90
|
+
return decision;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
export async function promptTextmodeVersion(options) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
const choice = await select({
|
|
95
|
+
message: `${kleur.cyan('Select textmode.js version')} ${kleur.gray(`(latest recommended, >= ${MIN_TEXTMODE_VERSION})`)}`,
|
|
96
|
+
options,
|
|
97
|
+
initialValue: options[0]?.value,
|
|
98
|
+
maxItems: 5,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
handleCancel(choice);
|
|
102
|
+
return choice;
|
|
102
103
|
}
|
package/src/runCommand.js
CHANGED
|
@@ -2,45 +2,45 @@ import { spawn } from 'child_process';
|
|
|
2
2
|
import readline from 'readline';
|
|
3
3
|
|
|
4
4
|
export function runCommand(cmd, args, cwd) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
const child = spawn(cmd, args, {
|
|
7
|
+
cwd,
|
|
8
|
+
stdio: 'inherit',
|
|
9
|
+
shell: process.platform === 'win32',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
child.on('exit', (code) => {
|
|
13
|
+
if (code === 0) resolve();
|
|
14
|
+
else reject(new Error(`${cmd} ${args.join(' ')} exited with code ${code}`));
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
child.on('error', reject);
|
|
18
|
+
});
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function runCommandLogged(cmd, args, cwd, onLine) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const child = spawn(cmd, args, {
|
|
24
|
+
cwd,
|
|
25
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
26
|
+
shell: process.platform === 'win32',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const forward = (stream) => {
|
|
30
|
+
if (!stream) return;
|
|
31
|
+
const rl = readline.createInterface({ input: stream });
|
|
32
|
+
rl.on('line', (line) => onLine(line));
|
|
33
|
+
rl.on('error', () => {});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
forward(child.stdout);
|
|
37
|
+
forward(child.stderr);
|
|
38
|
+
|
|
39
|
+
child.on('exit', (code) => {
|
|
40
|
+
if (code === 0) resolve();
|
|
41
|
+
else reject(new Error(`${cmd} ${args.join(' ')} exited with code ${code}`));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
child.on('error', reject);
|
|
45
|
+
});
|
|
46
46
|
}
|
package/src/summary.js
CHANGED
|
@@ -2,42 +2,37 @@ import kleur from 'kleur';
|
|
|
2
2
|
import boxen from 'boxen';
|
|
3
3
|
|
|
4
4
|
export function printSummary({ projectName, pm, pmCmds, installDone, runDone, addons = [] }) {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const installCmd = `${pm} ${pmCmds.install.join(' ')}`;
|
|
6
|
+
const runCmd = `${pm} ${pmCmds.runDev.join(' ')}`;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const steps = [
|
|
9
|
+
`cd ${projectName}`,
|
|
10
|
+
installDone ? `✓ already ran ${installCmd}` : installCmd,
|
|
11
|
+
runDone ? `✓ dev server is running (${runCmd})` : runCmd,
|
|
12
|
+
]
|
|
13
|
+
.filter(Boolean)
|
|
14
|
+
.join('\n');
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
'',
|
|
21
|
-
kleur.bold().cyan('Add-ons installed:'),
|
|
22
|
-
addons.map((a) => ` ${a.label}`).join('\n')
|
|
23
|
-
].join('\n')
|
|
24
|
-
: '';
|
|
16
|
+
const addonLines =
|
|
17
|
+
addons.length > 0
|
|
18
|
+
? ['', '', kleur.bold().cyan('Add-ons installed:'), addons.map((a) => ` ${a.label}`).join('\n')].join('\n')
|
|
19
|
+
: '';
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
const infoLines = [
|
|
22
|
+
addonLines,
|
|
23
|
+
'',
|
|
24
|
+
kleur.bold().cyan('Helpful links:'),
|
|
25
|
+
`${kleur.cyan(' Documentation:')} https://code.textmode.art`,
|
|
26
|
+
`${kleur.cyan(' Community:')} https://discord.gg/sjrw8QXNks`,
|
|
27
|
+
`${kleur.cyan(' CLI issues:')} https://github.com/humanbydefinition/create-textmode/issues`,
|
|
28
|
+
].join('\n');
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
const boxed = boxen(`${kleur.bold().cyan('Next steps:')}\n${steps}${infoLines}`, {
|
|
31
|
+
padding: { top: 0, bottom: 0, left: 2, right: 2 },
|
|
32
|
+
margin: { top: 0, bottom: 0 },
|
|
33
|
+
borderStyle: 'round',
|
|
34
|
+
borderColor: 'cyan',
|
|
35
|
+
});
|
|
41
36
|
|
|
42
|
-
|
|
37
|
+
console.log(boxed);
|
|
43
38
|
}
|
package/src/textmodeVersion.js
CHANGED
|
@@ -3,55 +3,55 @@ import { compareSemverDesc, getTextmodeVersions, filterAtLeast } from './version
|
|
|
3
3
|
import { MIN_TEXTMODE_VERSION } from './constants.js';
|
|
4
4
|
|
|
5
5
|
export async function resolveTextmodeVersion(requestedTextmodeVersion, promptTextmodeVersion) {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
let textmodeVersion = 'latest';
|
|
7
|
+
let stableVersions;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
const versionSpinner = spinner();
|
|
10
|
+
versionSpinner.start('Fetching textmode.js versions...');
|
|
11
|
+
try {
|
|
12
|
+
stableVersions = await getTextmodeVersions();
|
|
13
|
+
if (stableVersions.length === 0) throw new Error('No versions found');
|
|
14
|
+
versionSpinner.stop('Fetched textmode.js versions.');
|
|
15
|
+
} catch {
|
|
16
|
+
versionSpinner.stop('Could not fetch versions.');
|
|
17
|
+
log.warn('Using latest version as fallback.');
|
|
18
|
+
stableVersions = [];
|
|
19
|
+
textmodeVersion = 'latest';
|
|
20
|
+
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
// Only offer versions at or above the global minimum (e.g. >= 0.17.1).
|
|
23
|
+
// Every official add-on peer-depends on a lower floor, so this also covers
|
|
24
|
+
// add-on compatibility.
|
|
25
|
+
const eligibleVersions = filterAtLeast(stableVersions, MIN_TEXTMODE_VERSION);
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
const latestVersion = eligibleVersions[0] || stableVersions[0];
|
|
28
|
+
const availableOptions = [
|
|
29
|
+
{
|
|
30
|
+
value: 'latest',
|
|
31
|
+
label: latestVersion ? `latest (${latestVersion})` : 'latest (recommended)',
|
|
32
|
+
},
|
|
33
|
+
...eligibleVersions.slice(1).map((v) => ({ value: v, label: v })),
|
|
34
|
+
];
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
36
|
+
if (requestedTextmodeVersion) {
|
|
37
|
+
const found = availableOptions.find((opt) => opt.value === requestedTextmodeVersion);
|
|
38
|
+
if (found) {
|
|
39
|
+
textmodeVersion = requestedTextmodeVersion;
|
|
40
|
+
} else if (stableVersions.includes(requestedTextmodeVersion)) {
|
|
41
|
+
textmodeVersion = requestedTextmodeVersion;
|
|
42
|
+
if (compareSemverDesc(requestedTextmodeVersion, MIN_TEXTMODE_VERSION) > 0) {
|
|
43
|
+
log.warn(
|
|
44
|
+
`textmode.js must be >= ${MIN_TEXTMODE_VERSION}, but ${requestedTextmodeVersion} is older. Upgrading to latest.`
|
|
45
|
+
);
|
|
46
|
+
textmodeVersion = 'latest';
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
log.warn(`Requested textmode.js@${requestedTextmodeVersion} not found; using latest instead.`);
|
|
50
|
+
textmodeVersion = 'latest';
|
|
51
|
+
}
|
|
52
|
+
} else if (eligibleVersions.length > 0) {
|
|
53
|
+
textmodeVersion = await promptTextmodeVersion(availableOptions);
|
|
54
|
+
}
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
return { textmodeVersion, stableVersions, availableOptions };
|
|
57
57
|
}
|
package/src/usage.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import { addons, templates } from './constants.js';
|
|
1
|
+
import { addons, templates, MIN_TEXTMODE_VERSION } from './constants.js';
|
|
2
2
|
|
|
3
3
|
export function printUsage() {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const list = templates.map((t) => ` - ${t.name}`).join('\n');
|
|
5
|
+
const addonList = addons.map((a) => ` - ${a.name} (${a.package})`).join('\n');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
console.log(`Usage: npm create textmode@latest [project-name] -- [options]\n`);
|
|
8
|
+
console.log('Options:');
|
|
9
|
+
console.log(' --template <name> Choose a template');
|
|
10
|
+
console.log(' --addons <name1,name2,...> Pre-install official textmode.js add-ons');
|
|
11
|
+
console.log(' --name <name> Project directory name (alias: positional arg)');
|
|
12
|
+
console.log(' --pm <npm|pnpm|yarn|bun> Force package manager (auto-detected if omitted)');
|
|
13
|
+
console.log(
|
|
14
|
+
` --textmode-version <ver> Pin textmode.js version (default: latest; only >= ${MIN_TEXTMODE_VERSION} offered)`
|
|
15
|
+
);
|
|
16
|
+
console.log(' --install / --no-install Install dependencies after scaffold');
|
|
17
|
+
console.log(' --run / --no-run Run dev server after install');
|
|
18
|
+
console.log(' --force Allow using a non-empty directory');
|
|
19
|
+
console.log(' --help Show this help');
|
|
20
|
+
console.log(' --version Show CLI version');
|
|
21
|
+
console.log('\nTemplates:\n' + list);
|
|
22
|
+
console.log('\nAdd-ons:\n' + addonList);
|
|
21
23
|
}
|
package/src/versions.js
CHANGED
|
@@ -3,54 +3,54 @@ import https from 'https';
|
|
|
3
3
|
let cachedVersions = null;
|
|
4
4
|
|
|
5
5
|
function fetchJson(url) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
https
|
|
8
|
+
.get(url, (res) => {
|
|
9
|
+
let data = '';
|
|
10
|
+
res.on('data', (chunk) => {
|
|
11
|
+
data += chunk;
|
|
12
|
+
});
|
|
13
|
+
res.on('end', () => {
|
|
14
|
+
try {
|
|
15
|
+
resolve(JSON.parse(data));
|
|
16
|
+
} catch (err) {
|
|
17
|
+
reject(err);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
})
|
|
21
|
+
.on('error', reject);
|
|
22
|
+
});
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export function isStable(version) {
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// Exclude prerelease tags like -beta, -rc, etc.
|
|
27
|
+
return !version.includes('-');
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export function compareSemverDesc(a, b) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
const pa = a.split('.').map(Number);
|
|
32
|
+
const pb = b.split('.').map(Number);
|
|
33
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i += 1) {
|
|
34
|
+
const va = pa[i] || 0;
|
|
35
|
+
const vb = pb[i] || 0;
|
|
36
|
+
if (va > vb) return -1;
|
|
37
|
+
if (va < vb) return 1;
|
|
38
|
+
}
|
|
39
|
+
return 0;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function filterAtLeast(versions, min) {
|
|
43
|
-
|
|
43
|
+
return versions.filter((v) => compareSemverDesc(v, min) <= 0);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export async function getTextmodeVersions(limit = 20) {
|
|
47
|
-
|
|
47
|
+
if (cachedVersions) return cachedVersions.slice(0, limit);
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
const data = await fetchJson('https://registry.npmjs.org/textmode.js');
|
|
50
|
+
const versions = Object.keys(data.versions || {})
|
|
51
|
+
.filter(isStable)
|
|
52
|
+
.sort(compareSemverDesc);
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
cachedVersions = versions;
|
|
55
|
+
return versions.slice(0, limit);
|
|
56
56
|
}
|
|
@@ -9,18 +9,18 @@
|
|
|
9
9
|
"preview": "vite preview",
|
|
10
10
|
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
|
11
11
|
"format:check": "prettier --check \"src/**/*.{js,ts}\"",
|
|
12
|
-
"lint": "eslint
|
|
13
|
-
"lint:fix": "eslint
|
|
12
|
+
"lint": "eslint .",
|
|
13
|
+
"lint:fix": "eslint . --fix"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"textmode.js": "latest"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@eslint/js": "^
|
|
20
|
-
"eslint": "^
|
|
19
|
+
"@eslint/js": "^10.0.1",
|
|
20
|
+
"eslint": "^10.8.1",
|
|
21
21
|
"eslint-config-prettier": "^10.1.8",
|
|
22
|
-
"globals": "^
|
|
23
|
-
"prettier": "^3.
|
|
24
|
-
"vite": "^
|
|
22
|
+
"globals": "^16.0.0",
|
|
23
|
+
"prettier": "^3.9.5",
|
|
24
|
+
"vite": "^8.1.3"
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -9,19 +9,19 @@
|
|
|
9
9
|
"preview": "vite preview",
|
|
10
10
|
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
|
11
11
|
"format:check": "prettier --check \"src/**/*.{js,ts}\"",
|
|
12
|
-
"lint": "eslint
|
|
13
|
-
"lint:fix": "eslint
|
|
12
|
+
"lint": "eslint .",
|
|
13
|
+
"lint:fix": "eslint . --fix"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"textmode.js": "latest",
|
|
17
17
|
"tweakpane": "^4.0.5"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@eslint/js": "^
|
|
21
|
-
"eslint": "^
|
|
20
|
+
"@eslint/js": "^10.0.1",
|
|
21
|
+
"eslint": "^10.8.1",
|
|
22
22
|
"eslint-config-prettier": "^10.1.8",
|
|
23
|
-
"globals": "^
|
|
24
|
-
"prettier": "^3.
|
|
25
|
-
"vite": "^
|
|
23
|
+
"globals": "^16.0.0",
|
|
24
|
+
"prettier": "^3.9.5",
|
|
25
|
+
"vite": "^8.1.3"
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -9,22 +9,22 @@
|
|
|
9
9
|
"preview": "vite preview",
|
|
10
10
|
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
|
11
11
|
"format:check": "prettier --check \"src/**/*.{js,ts}\"",
|
|
12
|
-
"lint": "eslint
|
|
13
|
-
"lint:fix": "eslint
|
|
12
|
+
"lint": "eslint .",
|
|
13
|
+
"lint:fix": "eslint . --fix",
|
|
14
14
|
"typecheck": "tsc --noEmit"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"textmode.js": "latest"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@eslint/js": "^
|
|
21
|
-
"@types/node": "^
|
|
22
|
-
"eslint": "^
|
|
20
|
+
"@eslint/js": "^10.0.1",
|
|
21
|
+
"@types/node": "^26.1.2",
|
|
22
|
+
"eslint": "^10.8.1",
|
|
23
23
|
"eslint-config-prettier": "^10.1.8",
|
|
24
|
-
"globals": "^
|
|
25
|
-
"prettier": "^3.
|
|
26
|
-
"typescript": "^
|
|
27
|
-
"typescript-eslint": "^8.
|
|
28
|
-
"vite": "^
|
|
24
|
+
"globals": "^16.0.0",
|
|
25
|
+
"prettier": "^3.9.5",
|
|
26
|
+
"typescript": "^6.0.3",
|
|
27
|
+
"typescript-eslint": "^8.66.0",
|
|
28
|
+
"vite": "^8.1.3"
|
|
29
29
|
}
|
|
30
30
|
}
|