diff --git a/apps/svelte.dev/scripts/sync-docs/index.ts b/apps/svelte.dev/scripts/sync-docs/index.ts index c40e37c674..4866a41787 100644 --- a/apps/svelte.dev/scripts/sync-docs/index.ts +++ b/apps/svelte.dev/scripts/sync-docs/index.ts @@ -1,6 +1,7 @@ import { preprocess } from '@sveltejs/site-kit/markdown/preprocess'; import path from 'node:path'; import fs from 'node:fs'; +import { parseArgs } from 'node:util'; import ts from 'typescript'; import glob from 'tiny-glob/sync'; import chokidar from 'chokidar'; @@ -19,6 +20,22 @@ interface Package { process_modules?: (modules: Modules, pkg: Package) => Promise; } +const parsed = parseArgs({ + args: process.argv.slice(2), + options: { + watch: { + type: 'boolean', + short: 'w' + }, + pull: { + type: 'boolean', + short: 'p' + } + }, + strict: true, + allowPositionals: true +}); + const dirname = fileURLToPath(new URL('.', import.meta.url)); const REPOS = path.join(dirname, '../../repos'); const DOCS = path.join(dirname, '../../content/docs'); @@ -111,29 +128,42 @@ const packages: Package[] = [ { name: 'cli', repo: 'sveltejs/cli', - branch: 'chore/add-docs', + branch: 'main', pkg: 'packages/cli', docs: 'documentation/docs', types: null } ]; +const unknown = parsed.positionals.filter((name) => !packages.some((pkg) => pkg.name === name)); + +if (unknown.length > 0) { + throw new Error( + `Valid repos are ${packages.map((pkg) => pkg.name).join(', ')} (saw ${unknown.join(', ')})` + ); +} + +const filtered = + parsed.positionals.length === 0 + ? packages + : packages.filter((pkg) => parsed.positionals.includes(pkg.name)); + /** * Depending on your setup, this will either clone the Svelte and SvelteKit repositories * or use the local paths you provided above to read the documentation files. * It will then copy them into the `content/docs` directory and process them to replace * placeholders for types with content from the generated types. */ -if (process.env.USE_GIT === 'true') { +if (parsed.values.pull) { try { fs.mkdirSync(REPOS); } catch { // ignore if it already exists } - await Promise.all( - packages.map((pkg) => clone_repo(`https://github.com/${pkg.repo}.git`, pkg.branch, REPOS)) - ); + for (const pkg of filtered) { + await clone_repo(`https://github.com/${pkg.repo}.git`, pkg.name, pkg.branch, REPOS); + } } async function sync(pkg: Package) { @@ -157,16 +187,18 @@ async function sync(pkg: Package) { } } -for (const pkg of packages) { +for (const pkg of filtered) { await sync(pkg); } -if (process.argv.includes('-w') || process.argv.includes('--watch')) { - for (const pkg of packages) { +if (parsed.values.watch) { + for (const pkg of filtered) { chokidar .watch(`${REPOS}/${pkg.name}/${pkg.docs}`, { ignoreInitial: true }) .on('all', (event) => { sync(pkg); }); } + + console.log(`\nwatching for changes in ${parsed.positionals.join(', ')}`); } diff --git a/apps/svelte.dev/scripts/sync-docs/utils.ts b/apps/svelte.dev/scripts/sync-docs/utils.ts index 2a925d131f..774bb2fe75 100644 --- a/apps/svelte.dev/scripts/sync-docs/utils.ts +++ b/apps/svelte.dev/scripts/sync-docs/utils.ts @@ -1,17 +1,21 @@ -import { spawn, type SpawnOptions } from 'node:child_process'; +import { execSync, spawn, type SpawnOptions } from 'node:child_process'; import fs from 'node:fs'; import glob from 'tiny-glob/sync'; -export async function clone_repo(repo: string, branch: string, cwd: string) { - const regex_result = /https:\/\/github.com\/\w+\/(\w+).git/.exec(repo); - if (!regex_result || regex_result.length < 2) { - throw new Error(`Expected https://github.com/xxx/xxx.git, but got ${repo}`); - } +export async function clone_repo(repo: string, name: string, branch: string, cwd: string) { + const dir = `${cwd}/${name}`; + + if (fs.existsSync(dir)) { + const opts = { cwd: dir }; + + if (execSync('git status -s', opts).toString() !== '') { + throw new Error(`${name} repo is dirty — aborting`); + } + + await invoke('git', ['checkout', branch], opts); + await invoke('git', ['pull'], opts); - const dirname = `${cwd}/${regex_result[1]}`; - if (fs.existsSync(dirname)) { - // TODO skip if we detect that same branch is already cloned - fs.rmSync(dirname, { recursive: true }); + return; } await invoke('git', ['clone', '--depth', '1', '--branch', branch, repo], { @@ -22,14 +26,15 @@ export async function clone_repo(repo: string, branch: string, cwd: string) { export function invoke(cmd: string, args: string[], opts: SpawnOptions) { const child = spawn(cmd, args, { ...opts, stdio: 'inherit' }); - return new Promise((resolve) => { + return new Promise((fulfil, reject) => { child.on('close', (code) => { - if (!code) { - console.log(`${[cmd, ...args].join(' ')} successfully completed`); + if (code) { + reject(new Error(`Exited with code ${code}`)); + return; } // Give it some extra time to finish writing files to disk - setTimeout(() => resolve(), 500); + setTimeout(fulfil, 500); }); }); }