Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: replace prettier workspace property #76

Merged
merged 16 commits into from
Oct 11, 2024
4 changes: 2 additions & 2 deletions packages/adders/eslint/config/adder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const adder = defineAdder({
name: 'eslint-config-prettier',
version: '^9.1.0',
dev: true,
condition: ({ prettier }) => prettier
condition: ({ dependencyVersion }) => Boolean(dependencyVersion('prettier'))
}
],
files: [
Expand Down Expand Up @@ -155,7 +155,7 @@ export const adder = defineAdder({
},
{
name: () => 'eslint.config.js',
condition: ({ prettier }) => prettier,
condition: ({ dependencyVersion }) => Boolean(dependencyVersion('prettier')),
content: addEslintConfigPrettier
}
]
Expand Down
18 changes: 10 additions & 8 deletions packages/adders/prettier/config/adder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const adder = defineAdder({
name: 'eslint-config-prettier',
version: '^9.1.0',
dev: true,
condition: ({ dependencies }) => hasEslint(dependencies)
condition: ({ dependencyVersion }) => hasEslint(dependencyVersion)
}
],
files: [
Expand Down Expand Up @@ -70,14 +70,15 @@ export const adder = defineAdder({
},
{
name: () => 'package.json',
content: ({ content, dependencies }) => {
content: ({ content, dependencyVersion }) => {
const { data, generateCode } = parseJson(content);

data.scripts ??= {};
const scripts: Record<string, string> = data.scripts;
const CHECK_CMD = 'prettier --check .';
scripts['format'] ??= 'prettier --write .';

if (hasEslint(dependencies)) {
if (hasEslint(dependencyVersion)) {
scripts['lint'] ??= `${CHECK_CMD} && eslint .`;
if (!scripts['lint'].includes(CHECK_CMD)) scripts['lint'] += ` && ${CHECK_CMD}`;
} else {
Expand All @@ -88,17 +89,17 @@ export const adder = defineAdder({
},
{
name: () => 'eslint.config.js',
condition: ({ dependencies: deps }) => {
condition: ({ dependencyVersion }) => {
// We only want this to execute when it's `false`, not falsy

if (deps['eslint']?.startsWith(SUPPORTED_ESLINT_VERSION) === false) {
if (dependencyVersion('eslint')?.startsWith(SUPPORTED_ESLINT_VERSION) === false) {
log.warn(
`An older major version of ${colors.yellow(
'eslint'
)} was detected. Skipping ${colors.yellow('eslint-config-prettier')} installation.`
);
}
return hasEslint(deps);
return hasEslint(dependencyVersion);
},
content: addEslintConfigPrettier
}
Expand All @@ -107,6 +108,7 @@ export const adder = defineAdder({

const SUPPORTED_ESLINT_VERSION = '9';

function hasEslint(deps: Record<string, string>): boolean {
return !!deps['eslint'] && deps['eslint'].startsWith(SUPPORTED_ESLINT_VERSION);
function hasEslint(dependencyVersion: (pkg: string) => string | undefined): boolean {
const version = dependencyVersion('eslint');
return !!version && version.startsWith(SUPPORTED_ESLINT_VERSION);
}
4 changes: 2 additions & 2 deletions packages/adders/tailwindcss/config/adder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const adder = defineAdder({
name: 'prettier-plugin-tailwindcss',
version: '^0.6.5',
dev: true,
condition: ({ prettier }) => prettier
condition: ({ dependencyVersion }) => Boolean(dependencyVersion('prettier'))
}
],
files: [
Expand Down Expand Up @@ -142,7 +142,7 @@ export const adder = defineAdder({

return generateCode();
},
condition: ({ prettier }) => prettier
condition: ({ dependencyVersion }) => Boolean(dependencyVersion('prettier'))
}
]
});
8 changes: 6 additions & 2 deletions packages/cli/commands/add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ export async function runAddCommand(options: Options, adders: string[]): Promise
let installed = false;
installed = dependent.packages.every(
// we'll skip the conditions since we don't have any options to supply it
(p) => p.condition !== undefined || !!workspace.dependencies[p.name]
(p) => p.condition !== undefined || !!workspace.dependencyVersion(p.name)
);

if (installed) continue;
Expand Down Expand Up @@ -459,7 +459,11 @@ export async function runAddCommand(options: Options, adders: string[]): Promise

// format modified/created files with prettier (if available)
const workspace = createWorkspace(options.cwd);
if (filesToFormat.length > 0 && depsStatus === 'installed' && workspace.prettier) {
if (
filesToFormat.length > 0 &&
depsStatus === 'installed' &&
!!workspace.dependencyVersion('prettier')
) {
const { start, stop } = p.spinner();
start('Formatting modified files');
try {
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/commands/add/processor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fileExistsWorkspace, readFile, writeFile } from './utils.ts';
import { fileExists, readFile, writeFile } from './utils.ts';
import type { Workspace, OptionDefinition, FileType } from '@svelte-cli/core';

/**
Expand All @@ -17,8 +17,8 @@ export function createOrUpdateFiles<Args extends OptionDefinition>(
continue;
}

const exists = fileExistsWorkspace(workspace, fileDetails.name(workspace));
let content = exists ? readFile(workspace, fileDetails.name(workspace)) : '';
const exists = fileExists(workspace.cwd, fileDetails.name(workspace));
let content = exists ? readFile(workspace.cwd, fileDetails.name(workspace)) : '';
// process file
content = fileDetails.content({ content, ...workspace });

Expand Down
19 changes: 10 additions & 9 deletions packages/cli/commands/add/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,24 @@ export type Package = {
bugs?: string;
repository?: { type: string; url: string };
keywords?: string[];
workspaces?: string[];
};

export function getPackageJson(workspace: Workspace<any>) {
const packageText = readFile(workspace, commonFilePaths.packageJson);
export function getPackageJson(cwd: string) {
const packageText = readFile(cwd, commonFilePaths.packageJson);
if (!packageText) {
const pkgPath = path.join(workspace.cwd, commonFilePaths.packageJson);
const pkgPath = path.join(cwd, commonFilePaths.packageJson);
throw new Error(`Invalid workspace: missing '${pkgPath}'`);
}

const { data, generateCode } = parseJson(packageText);
return { source: packageText, data: data as Package, generateCode };
}

export function readFile(workspace: Workspace<any>, filePath: string): string {
const fullFilePath = getFilePath(workspace.cwd, filePath);
export function readFile(cwd: string, filePath: string): string {
const fullFilePath = getFilePath(cwd, filePath);

if (!fileExistsWorkspace(workspace, filePath)) {
if (!fileExists(cwd, filePath)) {
return '';
}

Expand All @@ -38,7 +39,7 @@ export function readFile(workspace: Workspace<any>, filePath: string): string {
}

export function installPackages(config: Adder<any>, workspace: Workspace<any>): string {
const { data, generateCode } = getPackageJson(workspace);
const { data, generateCode } = getPackageJson(workspace.cwd);

for (const dependency of config.packages) {
if (dependency.condition && !dependency.condition(workspace)) {
Expand Down Expand Up @@ -83,8 +84,8 @@ export function writeFile(workspace: Workspace<any>, filePath: string, content:
fs.writeFileSync(fullFilePath, content, 'utf8');
}

export function fileExistsWorkspace(workspace: Workspace<any>, filePath: string): boolean {
const fullFilePath = getFilePath(workspace.cwd, filePath);
export function fileExists(cwd: string, filePath: string): boolean {
const fullFilePath = getFilePath(cwd, filePath);
return fs.existsSync(fullFilePath);
}

Expand Down
46 changes: 34 additions & 12 deletions packages/cli/commands/add/workspace.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import fs from 'node:fs';
import path from 'node:path';
import * as find from 'empathic/find';
import * as resolve from 'empathic/resolve';
import { common, object, type AstTypes } from '@svelte-cli/core/js';
import { parseScript } from '@svelte-cli/core/parsers';
import { TESTING } from '../../env.ts';
Expand All @@ -13,7 +12,7 @@ export function createEmptyWorkspace<Args extends OptionDefinition>() {
return {
options: {},
cwd: '',
prettier: false,
dependencyVersion: (_pkg) => undefined,
typescript: false,
kit: undefined
} as Workspace<Args>;
Expand All @@ -33,23 +32,46 @@ export function createWorkspace<Args extends OptionDefinition>(cwd: string): Wor
usesTypescript ||= find.up(commonFilePaths.tsconfig, { cwd }) !== undefined;
}

const { data: packageJson } = getPackageJson(workspace);
let dependencies: Record<string, string> = {};
let directory = workspace.cwd;
const root = findRoot(workspace.cwd);
while (directory && directory !== root) {
const { data: packageJson } = getPackageJson(workspace.cwd);
dependencies = { ...packageJson.devDependencies, ...packageJson.dependencies, ...dependencies };
directory = path.dirname(directory);
}
// removes the version ranges (e.g. `^` is removed from: `^9.0.0`)
for (const [key, value] of Object.entries(dependencies)) {
dependencies[key] = value.replaceAll(/[^\d|.]/g, '');
}

workspace.dependencies = { ...packageJson.devDependencies, ...packageJson.dependencies };
workspace.dependencyVersion = (pkg) => {
return dependencies[pkg];
};
workspace.typescript = usesTypescript;
workspace.prettier = Boolean(resolve.from(cwd, 'prettier', true));
workspace.packageManager = detectPackageManager(cwd);
if ('@sveltejs/kit' in workspace.dependencies) workspace.kit = parseKitOptions(workspace);
for (const [key, value] of Object.entries(workspace.dependencies)) {
// removes the version ranges (e.g. `^` is removed from: `^9.0.0`)
workspace.dependencies[key] = value.replaceAll(/[^\d|.]/g, '');
}

if (workspace.dependencyVersion('@sveltejs/kit')) workspace.kit = parseKitOptions(workspace);
return workspace;
}

function findRoot(cwd: string): string {
const { root } = path.parse(cwd);
let directory = cwd;
while (directory && directory !== root) {
if (fs.existsSync(path.join(directory, 'pnpm-workspace.yaml'))) {
return directory;
}
const { data } = getPackageJson(directory);
if (data.workspaces) {
return directory;
}
directory = path.dirname(directory);
}
return root;
}

function parseKitOptions(workspace: Workspace<any>) {
const configSource = readFile(workspace, commonFilePaths.svelteConfig);
const configSource = readFile(workspace.cwd, commonFilePaths.svelteConfig);
const { ast } = parseScript(configSource);

const defaultExport = ast.body.find((s) => s.type === 'ExportDefaultDeclaration');
Expand Down
11 changes: 9 additions & 2 deletions packages/core/adder/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@ import type { OptionDefinition, OptionValues } from './options.ts';
export type Workspace<Args extends OptionDefinition> = {
options: OptionValues<Args>;
cwd: string;
dependencies: Record<string, string>;
prettier: boolean;
/**
* Returns the dependency version declared in the package.json.
* This may differ from the installed version.
* Includes both dependencies and devDependencies.
* Also checks parent package.json files if called in a monorepo.
* @param pkg the package to check for
* @returns the dependency version with any leading characters such as ^ or ~ removed
*/
dependencyVersion: (pkg: string) => string | undefined;
typescript: boolean;
kit: { libDirectory: string; routesDirectory: string } | undefined;
packageManager: 'npm' | 'yarn' | 'pnpm' | 'bun';
Expand Down