Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/chilled-melons-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sveltejs/sv-utils': patch
'sv': patch
---

feat(sv-utils): all semantic colors now accept `string | string[]`
27 changes: 15 additions & 12 deletions packages/sv-utils/src/color.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { styleText } from 'node:util';

type ColorInput = string | string[];
const toStr = (input: ColorInput): string => (Array.isArray(input) ? input.join(' ') : input);

export const color = {
// Semantic colors
addon: (str: string): string => styleText('greenBright', str),
command: (str: string): string => styleText(['bold', 'cyanBright'], str),
env: (str: string): string => styleText('yellow', str),
path: (str: string): string => styleText('blueBright', str),
route: (str: string): string => styleText(['bold', 'underline'], str),
website: (str: string): string => styleText('cyan', str),
optional: (str: string): string => styleText('gray', str),
dim: (str: string): string => styleText(['gray', 'dim'], str), // needed for terminal that don't support `dim` well
addon: (str: ColorInput): string => styleText('greenBright', toStr(str)),
command: (str: ColorInput): string => styleText(['bold', 'cyanBright'], toStr(str)),
env: (str: ColorInput): string => styleText('yellow', toStr(str)),
path: (str: ColorInput): string => styleText('blueBright', toStr(str)),
route: (str: ColorInput): string => styleText(['bold', 'underline'], toStr(str)),
website: (str: ColorInput): string => styleText('cyan', toStr(str)),
optional: (str: ColorInput): string => styleText('gray', toStr(str)),
dim: (str: ColorInput): string => styleText(['gray', 'dim'], toStr(str)), // needed for terminal that don't support `dim` well

// Status colors
success: (str: string): string => styleText('green', str),
warning: (str: string): string => styleText('yellow', str),
error: (str: string): string => styleText('red', str),
success: (str: ColorInput): string => styleText('green', toStr(str)),
warning: (str: ColorInput): string => styleText('yellow', toStr(str)),
error: (str: ColorInput): string => styleText('red', toStr(str)),

// Visibility
hidden: (str: string): string => styleText('hidden', str)
hidden: (str: ColorInput): string => styleText('hidden', toStr(str))
};
11 changes: 11 additions & 0 deletions packages/sv-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import {
resolveCommand as _resolveCommand,
type Agent,
type Command
} from 'package-manager-detector';
import {
parseCss,
parseHtml,
Expand All @@ -20,6 +25,12 @@ export {
resolveCommand
} from 'package-manager-detector';

/** Resolves a package manager command and returns it as a string array (command + args). */
export function resolveCommandArray(agent: Agent, command: Command, args: string[]): string[] {
const cmd = _resolveCommand(agent, command, args)!;
return [cmd.command, ...cmd.args];
}

// Parsing & language namespaces
export * as css from './tooling/css/index.ts';
export * as js from './tooling/js/index.ts';
Expand Down
10 changes: 3 additions & 7 deletions packages/sv/src/addons/better-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
color,
dedent,
transforms,
resolveCommand,
resolveCommandArray,
createPrinter,
type TransformFn
} from '@sveltejs/sv-utils';
Expand Down Expand Up @@ -517,13 +517,9 @@ export default defineAddon({
},

nextSteps: ({ options, packageManager }) => {
const { command: authCmd, args: authArgs } = resolveCommand(packageManager, 'run', [
'auth:schema'
])!;
const { command: dbCmd, args: dbArgs } = resolveCommand(packageManager, 'run', ['db:push'])!;
const steps = [
`Run ${color.command(`${authCmd} ${authArgs.join(' ')}`)} to generate the auth schema`,
`Run ${color.command(`${dbCmd} ${dbArgs.join(' ')}`)} to update your database`,
`Run ${color.command(resolveCommandArray(packageManager, 'run', ['auth:schema']))} to generate the auth schema`,
`Run ${color.command(resolveCommandArray(packageManager, 'run', ['db:push']))} to update your database`,
`Check ${color.env('ORIGIN')} & ${color.env('BETTER_AUTH_SECRET')} in ${color.path('.env')} and adjust it to your needs`
];
if (options.demo.includes('github')) {
Expand Down
17 changes: 4 additions & 13 deletions packages/sv/src/addons/drizzle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
dedent,
type TransformFn,
transforms,
resolveCommand,
resolveCommandArray,
fileExists,
createPrinter
} from '@sveltejs/sv-utils';
Expand Down Expand Up @@ -481,35 +481,26 @@ export default defineAddon({
const steps: string[] = [];
if (options.database === 'd1') {
const ext = fileExists(cwd, 'wrangler.toml') ? 'toml' : 'jsonc';
const { command, args } = resolveCommand(packageManager, 'run', [
'wrangler',
'd1',
'create',
`<DATABASE_NAME>`
])!;

steps.push(
`Add your ${color.env('CLOUDFLARE_ACCOUNT_ID')}, ${color.env('CLOUDFLARE_DATABASE_ID')}, and ${color.env('CLOUDFLARE_D1_TOKEN')} to ${color.path('.env')}`
);
steps.push(
`Run ${color.command(`${command} ${args.join(' ')}`)} to generate a D1 database ID for your ${color.path(`wrangler.${ext}`)}`
`Run ${color.command(resolveCommandArray(packageManager, 'run', ['wrangler', 'd1', 'create', '<DATABASE_NAME>']))} to generate a D1 database ID for your ${color.path(`wrangler.${ext}`)}`
);
}

if (options.docker) {
const { command, args } = resolveCommand(packageManager, 'run', ['db:start'])!;
steps.push(
`Run ${color.command(`${command} ${args.join(' ')}`)} to start the docker container`
`Run ${color.command(resolveCommandArray(packageManager, 'run', ['db:start']))} to start the docker container`
);
} else if (options.database !== 'd1') {
steps.push(
`Check ${color.env('DATABASE_URL')} in ${color.path('.env')} and adjust it to your needs`
);
}

const { command, args } = resolveCommand(packageManager, 'run', ['db:push'])!;
steps.push(
`Run ${color.command(`${command} ${args.join(' ')}`)} to update your database schema`
`Run ${color.command(resolveCommandArray(packageManager, 'run', ['db:push']))} to update your database schema`
);

return steps;
Expand Down
5 changes: 2 additions & 3 deletions packages/sv/src/addons/sveltekit-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
color,
resolveCommand,
resolveCommandArray,
text,
transforms,
fileExists,
Expand Down Expand Up @@ -231,9 +231,8 @@ export default defineAddon({
nextSteps({ options, packageManager }) {
const steps: string[] = [];
if (options.adapter === 'cloudflare') {
const { command, args } = resolveCommand(packageManager, 'run', ['gen'])!;
steps.push(
`Run ${color.command(`${command} ${args.join(' ')}`)} to update ${color.addon('cloudflare')} types`
`Run ${color.command(resolveCommandArray(packageManager, 'run', ['gen']))} to update ${color.addon('cloudflare')} types`
);
}
return steps;
Expand Down
9 changes: 4 additions & 5 deletions packages/sv/src/cli/check.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { color, resolveCommand } from '@sveltejs/sv-utils';
import { color, resolveCommandArray } from '@sveltejs/sv-utils';
import { Command } from 'commander';
import * as resolve from 'empathic/resolve';
import { execSync } from 'node:child_process';
Expand Down Expand Up @@ -26,9 +26,8 @@ async function runCheck(cwd: string, args: string[]) {
// validates that `svelte-check` is locally installed
const resolved = resolve.from(cwd, 'svelte-check', true);
if (!resolved) {
const cmd = resolveCommand(pm, 'add', ['-D', 'svelte-check'])!;
console.error(
`'svelte-check' is not installed locally. Install it with: ${color.command(`${cmd.command} ${cmd.args.join(' ')}`)}`
`'svelte-check' is not installed locally. Install it with: ${color.command(resolveCommandArray(pm, 'add', ['-D', 'svelte-check']))}`
);
process.exit(1);
}
Expand All @@ -40,8 +39,8 @@ async function runCheck(cwd: string, args: string[]) {

// avoids printing the stack trace for `sv` when `svelte-check` exits with an error code
try {
const cmd = resolveCommand(pm, 'execute-local', ['svelte-check', ...args])!;
execSync(`${cmd.command} ${cmd.args.join(' ')}`, { stdio: 'inherit', cwd });
const cmd = resolveCommandArray(pm, 'execute-local', ['svelte-check', ...args]).join(' ');
execSync(cmd, { stdio: 'inherit', cwd });
} catch (error) {
forwardExitCode(error);
} finally {
Expand Down
9 changes: 3 additions & 6 deletions packages/sv/src/cli/create.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as p from '@clack/prompts';
import { color, resolveCommand, commonFilePaths, getPackageJson } from '@sveltejs/sv-utils';
import { color, resolveCommandArray, commonFilePaths, getPackageJson } from '@sveltejs/sv-utils';
import { Command, Option } from 'commander';
import fs from 'node:fs';
import path from 'node:path';
Expand Down Expand Up @@ -145,15 +145,12 @@ export const create = new Command('create')
);
}
if (!packageManager) {
const { args, command } = resolveCommand(pm, 'install', [])!;
initialSteps.push(` ${i++}: ${color.command(`${command} ${args.join(' ')}`)}`);
initialSteps.push(` ${i++}: ${color.command(resolveCommandArray(pm, 'install', []))}`);
}

const { args, command } = resolveCommand(pm, 'run', ['dev', '--open'])!;
const pmRunCmd = `${command} ${args.join(' ')}`;
const steps = [
...initialSteps,
` ${i++}: ${color.command(pmRunCmd)}`,
` ${i++}: ${color.command(resolveCommandArray(pm, 'run', ['dev', '--open']))}`,
'',
`To close the dev server, hit ${color.command('Ctrl-C')}`
];
Expand Down
5 changes: 2 additions & 3 deletions packages/sv/src/cli/migrate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { resolveCommand } from '@sveltejs/sv-utils';
import { resolveCommandArray } from '@sveltejs/sv-utils';
import { Command } from 'commander';
import { execSync } from 'node:child_process';
import process from 'node:process';
Expand All @@ -23,8 +23,7 @@ async function runMigrate(cwd: string, args: string[]) {
// skips the download confirmation prompt for `npx`
if (pm === 'npm') cmdArgs.unshift('--yes');

const cmd = resolveCommand(pm, 'execute', cmdArgs)!;
execSync(`${cmd.command} ${cmd.args.join(' ')}`, { stdio: 'inherit', cwd });
execSync(resolveCommandArray(pm, 'execute', cmdArgs).join(' '), { stdio: 'inherit', cwd });
} catch (error) {
forwardExitCode(error);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/sv/src/cli/tests/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('cli', () => {

it.for(testCases)(
'should create a new project with name $projectName',
{ timeout: 111_000 },
{ timeout: 123_000 },
async (testCase) => {
const { projectName, args, template = 'minimal' } = testCase;

Expand Down
7 changes: 4 additions & 3 deletions packages/sv/src/core/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as p from '@clack/prompts';
import {
type AgentName,
color,
resolveCommand,
resolveCommandArray,
isVersionUnsupportedBelow
} from '@sveltejs/sv-utils';
import type { Argument, Command, Help, HelpConfiguration, Option } from 'commander';
Expand Down Expand Up @@ -236,8 +236,9 @@ export function buildAndLogArgs(
if (agent === null || agent === undefined) allArgs.push('--no-install');
else allArgs.push('--install', agent);

const res = resolveCommand(agent ?? 'npm', 'execute', [...allArgs, ...lastArgs])!;
const message = [res.command, ...res.args].join(' ');
const message = resolveCommandArray(agent ?? 'npm', 'execute', [...allArgs, ...lastArgs]).join(
' '
);

p.log.message(color.optional(color.dim(`To skip prompts next time, run:`)));
p.log.info(color.optional(message), { spacing: -1 });
Expand Down
2 changes: 1 addition & 1 deletion packages/sv/src/core/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ async function runAddon({ addon, loaded, multiple, workspace, workspaceOptions }
const { command, args } = resolveCommand(workspace.packageManager, 'execute', commandArgs)!;

const addonPrefix = multiple ? `${addon.id}: ` : '';
const executedCommand = `${command} ${args.join(' ')}`;
const executedCommand = [command, ...args].join(' ');
if (!TESTING) {
p.log.step(
`${addonPrefix}Running external command ${color.optional(`(${executedCommand})`)}`
Expand Down
Loading