Skip to content

Commit

Permalink
move create into it's own package
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianGonz97 committed Aug 20, 2024
1 parent abef027 commit eec977a
Show file tree
Hide file tree
Showing 96 changed files with 398 additions and 315 deletions.
172 changes: 53 additions & 119 deletions packages/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,134 +1,68 @@
import fs from 'node:fs';
import path from 'node:path';
import { mkdirp, copy, dist } from './utils.js';
import type { Common, Condition, File, Options, Types } from './types/internal';
#!/usr/bin/env node

// eslint-disable-next-line @typescript-eslint/require-await
export async function create(cwd: string, options: Options) {
mkdirp(cwd);
import { remoteControl, executeAdders, prompts } from '@svelte-cli/core/internal';
import pkg from './package.json';
import type {
AdderDetails,
AddersToApplySelectorParams,
ExecutingAdderInfo,
Question
} from '@svelte-cli/core';
import { adderCategories, categories, adderIds, type CategoryKeys } from '@svelte-cli/config';
import { getAdderDetails } from '@svelte-cli/adders';

write_template_files(options.template, options.types, options.name, cwd);
write_common_files(cwd, options, options.name);
}

function write_template_files(template: string, types: Types, name: string, cwd: string) {
const dir = dist(`templates/${template}`);
copy(`${dir}/assets`, cwd, (name: string) => name.replace('DOT-', '.'));
copy(`${dir}/package.json`, `${cwd}/package.json`);

const manifest = `${dir}/files.types=${types}.json`;
const files = JSON.parse(fs.readFileSync(manifest, 'utf-8')) as File[];

files.forEach((file) => {
const dest = path.join(cwd, file.name);
mkdirp(path.dirname(dest));

fs.writeFileSync(dest, file.contents.replace(/~TODO~/g, name));
});
}
void executeCli();

function write_common_files(cwd: string, options: Options, name: string) {
const shared = dist('shared.json');
const { files } = JSON.parse(fs.readFileSync(shared, 'utf-8')) as Common;
async function executeCli() {
remoteControl.enable();

const pkg_file = path.join(cwd, 'package.json');
const pkg = /** @type {any} */ JSON.parse(fs.readFileSync(pkg_file, 'utf-8'));
const adderDetails: Array<AdderDetails<Record<string, Question>>> = [];

sort_files(files).forEach((file) => {
const include = file.include.every((condition) => matches_condition(condition, options));
const exclude = file.exclude.some((condition) => matches_condition(condition, options));

if (exclude || !include) return;

if (file.name === 'package.json') {
const new_pkg = JSON.parse(file.contents);
merge(pkg, new_pkg);
} else {
const dest = path.join(cwd, file.name);
mkdirp(path.dirname(dest));
fs.writeFileSync(dest, file.contents);
}
});
for (const adderName of adderIds) {
const adder = await getAdderDetails(adderName);
adderDetails.push({ config: adder.config, checks: adder.checks });
}

pkg.dependencies = sort_keys(pkg.dependencies);
pkg.devDependencies = sort_keys(pkg.devDependencies);
pkg.name = to_valid_package_name(name);
const executingAdderInfo: ExecutingAdderInfo = {
name: pkg.name,
version: pkg.version
};

fs.writeFileSync(pkg_file, JSON.stringify(pkg, null, '\t') + '\n');
}
await executeAdders(adderDetails, executingAdderInfo, undefined, selectAddersToApply);

function matches_condition(condition: Condition, options: Options) {
if (condition === 'default' || condition === 'skeleton' || condition === 'skeletonlib') {
return options.template === condition;
}
if (condition === 'typescript' || condition === 'checkjs') {
return options.types === condition;
}
return !!options[condition];
remoteControl.disable();
}

function merge(target: any, source: any) {
for (const key in source) {
if (key in target) {
const target_value = target[key];
const source_value = source[key];

if (
typeof source_value !== typeof target_value ||
Array.isArray(source_value) !== Array.isArray(target_value)
) {
throw new Error('Mismatched values');
}
type AdderOption = { value: string; label: string; hint: string };
async function selectAddersToApply({ projectType, addersMetadata }: AddersToApplySelectorParams) {
const promptOptions: Record<string, AdderOption[]> = {};

for (const [categoryId, adderIds] of Object.entries(adderCategories)) {
const categoryDetails = categories[categoryId as CategoryKeys];
const options: AdderOption[] = [];
const adders = addersMetadata.filter((x) => adderIds.includes(x.id));

for (const adder of adders) {
// if we detected a kit project, and the adder is not available for kit, ignore it.
if (projectType === 'kit' && !adder.environments.kit) continue;
// if we detected a svelte project, and the adder is not available for svelte, ignore it.
if (projectType === 'svelte' && !adder.environments.svelte) continue;

options.push({
label: adder.name,
value: adder.id,
hint: adder.website?.documentation || ''
});
}

if (typeof source_value === 'object') {
merge(target_value, source_value);
} else {
target[key] = source_value;
}
} else {
target[key] = source[key];
if (options.length > 0) {
promptOptions[categoryDetails.name] = options;
}
}
}

function sort_keys(obj: Record<string, any>) {
if (!obj) return;

const sorted: Record<string, any> = {};
Object.keys(obj)
.sort()
.forEach((key) => {
sorted[key] = obj[key];
});

return sorted;
}

/**
* Sort files so that those which apply more generically come first so they
* can be overwritten by files for more precise cases later.
*
* @param {import('./types/internal.js').Common['files']} files
*/
function sort_files(files: Common['files']) {
return files.sort((f1, f2) => {
const f1_more_generic =
f1.include.every((include) => f2.include.includes(include)) &&
f1.exclude.every((exclude) => f2.exclude.includes(exclude));
const f2_more_generic =
f2.include.every((include) => f1.include.includes(include)) &&
f2.exclude.every((exclude) => f1.exclude.includes(exclude));
const same = f1_more_generic && f2_more_generic;
const different = !f1_more_generic && !f2_more_generic;
return same || different ? 0 : f1_more_generic ? -1 : 1;
});
}
const selectedAdders = await prompts.groupedMultiSelectPrompt(
'What would you like to add to your project?',
promptOptions
);

function to_valid_package_name(name: string) {
return name
.trim()
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/^[._]/, '')
.replace(/[^a-z0-9~.-]+/g, '-');
return selectedAdders;
}
26 changes: 4 additions & 22 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,20 @@
},
"license": "MIT",
"homepage": "https://kit.svelte.dev",
"bin": "./dist/bin.js",
"bin": "./dist/index.js",
"main": "./dist/index.js",
"devDependencies": {
"@svelte-cli/adders": "workspace:*",
"@svelte-cli/clack-prompts": "workspace:*",
"@svelte-cli/config": "workspace:*",
"@svelte-cli/core": "workspace:*",
"@types/gitignore-parser": "^0.0.3",
"gitignore-parser": "^0.0.2",
"picocolors": "^1.0.1",
"sucrase": "^3.34.0",
"svelte": "^4.2.10",
"tiny-glob": "^0.2.9",
"vitest": "^2.0.1"
"@svelte-cli/core": "workspace:*"
},
"scripts": {
"build": "pnpm build:templates",
"build:templates": "node scripts/build-templates",
"lint": "prettier --check . --config ../../.prettierrc --ignore-path ../../.gitignore --ignore-path .gitignore",
"format": "pnpm lint --write",
"test": "pnpm build && vitest run",
"check": "tsc",
"prepublishOnly": "pnpm build",
"postpublish": "echo \"Updating template repo\" && bash ./scripts/update-template-repo.sh"
"check": "tsc"
},
"files": [
"index.js",
"dist",
"bin.js",
"utils.js",
"types"
"dist"
],
"types": "types/index.d.ts",
"type": "module"
}
64 changes: 0 additions & 64 deletions packages/cli/svelte-add.ts

This file was deleted.

8 changes: 0 additions & 8 deletions packages/cli/types/index.d.ts

This file was deleted.

24 changes: 0 additions & 24 deletions packages/cli/types/internal.d.ts

This file was deleted.

14 changes: 11 additions & 3 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
],
"devDependencies": {
"@svelte-cli/clack-prompts": "workspace:*",
"@svelte-cli/create": "workspace:*",
"commander": "^12.1.0",
"dedent": "^1.5.3",
"package-manager-detector": "^0.1.0",
Expand All @@ -39,10 +40,17 @@
"url": "https://github.com/sveltejs/cli/tree/main/packages/core"
},
"keywords": [
"add",
"adder",
"create",
"new",
"project",
"starter",
"svelte",
"sveltekit",
"kit",
"svelte-kit"
"svelte-kit",
"template",
"wizard",
"add",
"adder"
]
}
Loading

0 comments on commit eec977a

Please sign in to comment.