UNPKG

sv

Version:

A command line interface (CLI) for creating and maintaining Svelte applications

854 lines (853 loc) 24.4 kB
import { S as __toESM, b as __commonJSMin, f as R, i as addPnpmAllowBuilds, m as create, p as z, t as add, x as __require } from "../engine-DSL32Woe.mjs"; import fs from "node:fs"; import path from "node:path"; import process$1 from "node:process"; import { execSync } from "node:child_process"; //#region ../../node_modules/.pnpm/through@2.3.8/node_modules/through/index.js var require_through = /* @__PURE__ */ __commonJSMin(((exports, module) => { var Stream$4 = __require("stream"); exports = module.exports = through; through.through = through; function through(write, end, opts) { write = write || function(data) { this.queue(data); }; end = end || function() { this.queue(null); }; var ended = false, destroyed = false, buffer = [], _ended = false; var stream = new Stream$4(); stream.readable = stream.writable = true; stream.paused = false; stream.autoDestroy = !(opts && opts.autoDestroy === false); stream.write = function(data) { write.call(this, data); return !stream.paused; }; function drain() { while (buffer.length && !stream.paused) { var data = buffer.shift(); if (null === data) return stream.emit("end"); else stream.emit("data", data); } } stream.queue = stream.push = function(data) { if (_ended) return stream; if (data === null) _ended = true; buffer.push(data); drain(); return stream; }; stream.on("end", function() { stream.readable = false; if (!stream.writable && stream.autoDestroy) process.nextTick(function() { stream.destroy(); }); }); function _end() { stream.writable = false; end.call(stream); if (!stream.readable && stream.autoDestroy) stream.destroy(); } stream.end = function(data) { if (ended) return; ended = true; if (arguments.length) stream.write(data); _end(); return stream; }; stream.destroy = function() { if (destroyed) return; destroyed = true; ended = true; buffer.length = 0; stream.writable = stream.readable = false; stream.emit("close"); return stream; }; stream.pause = function() { if (stream.paused) return; stream.paused = true; return stream; }; stream.resume = function() { if (stream.paused) { stream.paused = false; stream.emit("resume"); } drain(); if (!stream.paused) stream.emit("drain"); return stream; }; return stream; } })); //#endregion //#region ../../node_modules/.pnpm/from@0.1.7/node_modules/from/index.js var require_from = /* @__PURE__ */ __commonJSMin(((exports, module) => { var Stream$3 = __require("stream"); module.exports = function from(source) { if (Array.isArray(source)) { var source_index = 0, source_len = source.length; return from(function(i) { if (source_index < source_len) this.emit("data", source[source_index++]); else this.emit("end"); return true; }); } var s = new Stream$3(), i = 0; s.ended = false; s.started = false; s.readable = true; s.writable = false; s.paused = false; s.ended = false; s.pause = function() { s.started = true; s.paused = true; }; function next() { s.started = true; if (s.ended) return; while (!s.ended && !s.paused && source.call(s, i++, function() { if (!s.ended && !s.paused) process.nextTick(next); })); } s.resume = function() { s.started = true; s.paused = false; next(); }; s.on("end", function() { s.ended = true; s.readable = false; process.nextTick(s.destroy); }); s.destroy = function() { s.ended = true; s.emit("close"); }; process.nextTick(function() { if (!s.started) s.resume(); }); return s; }; })); //#endregion //#region ../../node_modules/.pnpm/duplexer@0.1.2/node_modules/duplexer/index.js var require_duplexer = /* @__PURE__ */ __commonJSMin(((exports, module) => { var Stream$2 = __require("stream"); var writeMethods = [ "write", "end", "destroy" ]; var readMethods = ["resume", "pause"]; var readEvents = ["data", "close"]; var slice = Array.prototype.slice; module.exports = duplex; function forEach(arr, fn) { if (arr.forEach) return arr.forEach(fn); for (var i = 0; i < arr.length; i++) fn(arr[i], i); } function duplex(writer, reader) { var stream = new Stream$2(); var ended = false; forEach(writeMethods, proxyWriter); forEach(readMethods, proxyReader); forEach(readEvents, proxyStream); reader.on("end", handleEnd); writer.on("drain", function() { stream.emit("drain"); }); writer.on("error", reemit); reader.on("error", reemit); stream.writable = writer.writable; stream.readable = reader.readable; return stream; function proxyWriter(methodName) { stream[methodName] = method; function method() { return writer[methodName].apply(writer, arguments); } } function proxyReader(methodName) { stream[methodName] = method; function method() { stream.emit(methodName); var func = reader[methodName]; if (func) return func.apply(reader, arguments); reader.emit(methodName); } } function proxyStream(methodName) { reader.on(methodName, reemit); function reemit() { var args = slice.call(arguments); args.unshift(methodName); stream.emit.apply(stream, args); } } function handleEnd() { if (ended) return; ended = true; var args = slice.call(arguments); args.unshift("end"); stream.emit.apply(stream, args); } function reemit(err) { stream.emit("error", err); } } })); //#endregion //#region ../../node_modules/.pnpm/map-stream@0.1.0/node_modules/map-stream/index.js var require_map_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => { var Stream$1 = __require("stream").Stream; module.exports = function(mapper, opts) { var stream = new Stream$1(), self = this, inputs = 0, outputs = 0, ended = false, paused = false, destroyed = false, lastWritten = 0, inNext = false; this.opts = opts || {}; var errorEventName = this.opts.failures ? "failure" : "error"; var writeQueue = {}; stream.writable = true; stream.readable = true; function queueData(data, number) { var nextToWrite = lastWritten + 1; if (number === nextToWrite) { if (data !== void 0) stream.emit.apply(stream, ["data", data]); lastWritten++; nextToWrite++; } else writeQueue[number] = data; if (writeQueue.hasOwnProperty(nextToWrite)) { var dataToWrite = writeQueue[nextToWrite]; delete writeQueue[nextToWrite]; return queueData(dataToWrite, nextToWrite); } outputs++; if (inputs === outputs) { if (paused) paused = false, stream.emit("drain"); if (ended) end(); } } function next(err, data, number) { if (destroyed) return; inNext = true; if (!err || self.opts.failures) queueData(data, number); if (err) stream.emit.apply(stream, [errorEventName, err]); inNext = false; } function wrappedMapper(input, number, callback) { return mapper.call(null, input, function(err, data) { callback(err, data, number); }); } stream.write = function(data) { if (ended) throw new Error("map stream is not writable"); inNext = false; inputs++; try { paused = wrappedMapper(data, inputs, next) === false; return !paused; } catch (err) { if (inNext) throw err; next(err); return !paused; } }; function end(data) { ended = true; stream.writable = false; if (data !== void 0) return queueData(data, inputs); else if (inputs == outputs) stream.readable = false, stream.emit("end"), stream.destroy(); } stream.end = function(data) { if (ended) return; end(); }; stream.destroy = function() { ended = destroyed = true; stream.writable = stream.readable = paused = false; process.nextTick(function() { stream.emit("close"); }); }; stream.pause = function() { paused = true; }; stream.resume = function() { paused = false; }; return stream; }; })); //#endregion //#region ../../node_modules/.pnpm/pause-stream@0.0.11/node_modules/pause-stream/index.js var require_pause_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => { module.exports = require_through(); })); //#endregion //#region ../../node_modules/.pnpm/split@0.3.3/node_modules/split/index.js var require_split = /* @__PURE__ */ __commonJSMin(((exports, module) => { var through = require_through(); var Decoder = __require("string_decoder").StringDecoder; module.exports = split; function split(matcher, mapper, options) { var decoder = new Decoder(); var soFar = ""; var maxLength = options && options.maxLength; if ("function" === typeof matcher) mapper = matcher, matcher = null; if (!matcher) matcher = /\r?\n/; function emit(stream, piece) { if (mapper) { try { piece = mapper(piece); } catch (err) { return stream.emit("error", err); } if ("undefined" !== typeof piece) stream.queue(piece); } else stream.queue(piece); } function next(stream, buffer) { var pieces = ((soFar != null ? soFar : "") + buffer).split(matcher); soFar = pieces.pop(); if (maxLength && soFar.length > maxLength) stream.emit("error", /* @__PURE__ */ new Error("maximum buffer reached")); for (var i = 0; i < pieces.length; i++) { var piece = pieces[i]; emit(stream, piece); } } return through(function(b) { next(this, decoder.write(b)); }, function() { if (decoder.end) next(this, decoder.end()); if (soFar != null) emit(this, soFar); this.queue(null); }); } })); //#endregion //#region ../../node_modules/.pnpm/stream-combiner@0.0.4/node_modules/stream-combiner/index.js var require_stream_combiner = /* @__PURE__ */ __commonJSMin(((exports, module) => { var duplexer = require_duplexer(); module.exports = function() { var streams = [].slice.call(arguments), first = streams[0], last = streams[streams.length - 1], thepipe = duplexer(first, last); if (streams.length == 1) return streams[0]; else if (!streams.length) throw new Error("connect called with empty args"); function recurse(streams) { if (streams.length < 2) return; streams[0].pipe(streams[1]); recurse(streams.slice(1)); } recurse(streams); function onerror() { var args = [].slice.call(arguments); args.unshift("error"); thepipe.emit.apply(thepipe, args); } for (var i = 1; i < streams.length - 1; i++) streams[i].on("error", onerror); return thepipe; }; })); //#endregion //#region ../../node_modules/.pnpm/event-stream@3.3.4/node_modules/event-stream/index.js var require_event_stream = /* @__PURE__ */ __commonJSMin(((exports) => { var Stream = __require("stream").Stream, es$1 = exports, through = require_through(), from = require_from(), duplex = require_duplexer(), map = require_map_stream(), pause = require_pause_stream(), split = require_split(), pipeline = require_stream_combiner(), immediately = global.setImmediate || process.nextTick; es$1.Stream = Stream; es$1.through = through; es$1.from = from; es$1.duplex = duplex; es$1.map = map; es$1.pause = pause; es$1.split = split; es$1.pipeline = es$1.connect = es$1.pipe = pipeline; es$1.concat = es$1.merge = function() { var toMerge = [].slice.call(arguments); if (toMerge.length === 1 && toMerge[0] instanceof Array) toMerge = toMerge[0]; var stream = new Stream(); stream.setMaxListeners(0); var endCount = 0; stream.writable = stream.readable = true; if (toMerge.length) toMerge.forEach(function(e) { e.pipe(stream, { end: false }); var ended = false; e.on("end", function() { if (ended) return; ended = true; endCount++; if (endCount == toMerge.length) stream.emit("end"); }); }); else process.nextTick(function() { stream.emit("end"); }); stream.write = function(data) { this.emit("data", data); }; stream.destroy = function() { toMerge.forEach(function(e) { if (e.destroy) e.destroy(); }); }; return stream; }; es$1.writeArray = function(done) { if ("function" !== typeof done) throw new Error("function writeArray (done): done must be function"); var a = new Stream(), array = [], isDone = false; a.write = function(l) { array.push(l); }; a.end = function() { isDone = true; done(null, array); }; a.writable = true; a.readable = false; a.destroy = function() { a.writable = a.readable = false; if (isDone) return; done(/* @__PURE__ */ new Error("destroyed before end"), array); }; return a; }; es$1.readArray = function(array) { var stream = new Stream(), i = 0, paused = false, ended = false; stream.readable = true; stream.writable = false; if (!Array.isArray(array)) throw new Error("event-stream.read expects an array"); stream.resume = function() { if (ended) return; paused = false; var l = array.length; while (i < l && !paused && !ended) stream.emit("data", array[i++]); if (i == l && !ended) ended = true, stream.readable = false, stream.emit("end"); }; process.nextTick(stream.resume); stream.pause = function() { paused = true; }; stream.destroy = function() { ended = true; stream.emit("close"); }; return stream; }; es$1.readable = function(func, continueOnError) { var stream = new Stream(), i = 0, paused = false, ended = false, reading = false; stream.readable = true; stream.writable = false; if ("function" !== typeof func) throw new Error("event-stream.readable expects async function"); stream.on("end", function() { ended = true; }); function get(err, data) { if (err) { stream.emit("error", err); if (!continueOnError) stream.emit("end"); } else if (arguments.length > 1) stream.emit("data", data); immediately(function() { if (ended || paused || reading) return; try { reading = true; func.call(stream, i++, function() { reading = false; get.apply(null, arguments); }); } catch (err) { stream.emit("error", err); } }); } stream.resume = function() { paused = false; get(); }; process.nextTick(get); stream.pause = function() { paused = true; }; stream.destroy = function() { stream.emit("end"); stream.emit("close"); ended = true; }; return stream; }; es$1.mapSync = function(sync) { return es$1.through(function write(data) { var mappedData; try { mappedData = sync(data); } catch (err) { return this.emit("error", err); } if (mappedData !== void 0) this.emit("data", mappedData); }); }; es$1.log = function(name) { return es$1.through(function(data) { [].slice.call(arguments); if (name) console.error(name, data); else console.error(data); this.emit("data", data); }); }; es$1.child = function(child) { return es$1.duplex(child.stdin, child.stdout); }; es$1.parse = function(options) { var emitError = !!(options ? options.error : false); return es$1.through(function(data) { var obj; try { if (data) obj = JSON.parse(data.toString()); } catch (err) { if (emitError) return this.emit("error", err); return console.error(err, "attempting to parse:", data); } if (obj !== void 0) this.emit("data", obj); }); }; es$1.stringify = function() { var Buffer = __require("buffer").Buffer; return es$1.mapSync(function(e) { return JSON.stringify(Buffer.isBuffer(e) ? e.toString() : e) + "\n"; }); }; es$1.replace = function(from, to) { return es$1.pipeline(es$1.split(from), es$1.join(to)); }; es$1.join = function(str) { if ("function" === typeof str) return es$1.wait(str); var first = true; return es$1.through(function(data) { if (!first) this.emit("data", str); first = false; this.emit("data", data); return true; }); }; es$1.wait = function(callback) { var arr = []; return es$1.through(function(data) { arr.push(data); }, function() { var body = Buffer.isBuffer(arr[0]) ? Buffer.concat(arr) : arr.join(""); this.emit("data", body); this.emit("end"); if (callback) callback(null, body); }); }; es$1.pipeable = function() { throw new Error("[EVENT-STREAM] es.pipeable is deprecated"); }; })); //#endregion //#region src/testing.ts var import_ps_tree = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => { var spawn$1 = __require("child_process").spawn, es = require_event_stream(); module.exports = function childrenOfPid(pid, callback) { var headers = null; if (typeof callback !== "function") throw new Error("childrenOfPid(pid, callback) expects callback"); if (typeof pid === "number") pid = pid.toString(); var processLister; if (process.platform === "win32") processLister = spawn$1("wmic.exe", [ "PROCESS", "GET", "Name,ProcessId,ParentProcessId,Status" ]); else processLister = spawn$1("ps", [ "-A", "-o", "ppid,pid,stat,comm" ]); es.connect(processLister.stdout, es.split(), es.map(function(line, cb) { var columns = line.trim().split(/\s+/); if (!headers) { headers = columns; headers = headers.map(normalizeHeader); return cb(); } var row = {}; var h = headers.slice(); while (h.length) row[h.shift()] = h.length ? columns.shift() : columns.join(" "); return cb(null, row); }), es.writeArray(function(err, ps) { var parents = {}, children = []; parents[pid] = true; ps.forEach(function(proc) { if (parents[proc.PPID]) { parents[proc.PID] = true; children.push(proc); } }); callback(null, children); })).on("error", callback); }; /** * Normalizes the given header `str` from the Windows * title to the *nix title. * * @param {string} str Header string to normalize */ function normalizeHeader(str) { if (process.platform !== "win32") return str; switch (str) { case "Name": return "COMMAND"; case "ParentProcessId": return "PPID"; case "ProcessId": return "PID"; case "Status": return "STAT"; default: throw new Error("Unknown process listing header: " + str); } } })))(), 1); const variants = [ "kit-js", "kit-ts", "vite-js", "vite-ts" ]; const TEMPLATES_DIR = ".templates"; function setup({ cwd, clean = false, variants }) { const workingDir = path.resolve(cwd); if (clean && fs.existsSync(workingDir)) fs.rmSync(workingDir, { force: true, recursive: true }); const templatesDir = path.resolve(workingDir, TEMPLATES_DIR); fs.mkdirSync(templatesDir, { recursive: true }); for (const variant of variants) { const templatePath = path.resolve(templatesDir, variant); if (fs.existsSync(templatePath)) continue; if (variant === "kit-js") create({ cwd: templatePath, name: variant, template: "minimal", types: "checkjs" }); else if (variant === "kit-ts") create({ cwd: templatePath, name: variant, template: "minimal", types: "typescript" }); else if (variant === "vite-js") create({ cwd: templatePath, name: variant, template: "svelte", types: "none" }); else if (variant === "vite-ts") create({ cwd: templatePath, name: variant, template: "svelte", types: "typescript" }); else throw new Error(`Unknown project variant: ${variant}`); } return { templatesDir }; } function createProject({ cwd, testName, templatesDir }) { const testDir = path.resolve(cwd, testName); fs.mkdirSync(testDir, { recursive: true }); return ({ testId, variant, clean = true }) => { const targetDir = path.resolve(testDir, testId); if (clean && fs.existsSync(targetDir)) fs.rmSync(targetDir, { force: true, recursive: true }); const templatePath = path.resolve(templatesDir, variant); fs.cpSync(templatePath, targetDir, { recursive: true, force: true }); return targetDir; }; } async function startPreview({ cwd, command = "npm run preview" }) { const [cmd, ...args] = command.split(" "); const proc = z(cmd, args, { nodeOptions: { cwd, stdio: "pipe" }, throwOnError: true, timeout: 66999 }); const close = async () => { if (!proc.pid) return; await terminate(proc.pid); }; return await new Promise((resolve, reject) => { if (!proc.process?.stdout) return reject("impossible state"); proc.process.stdout.on("data", (data) => { const urls = data.toString().replace(/[^\x20-\xaf]+/g, "").replace(/\[[0-9]{1,2}m/g, "").match(/http:\/\/[^:\s]+:[0-9]+\//g); if (urls && urls.length > 0) { const url = urls[0]; resolve({ url, close }); } }); }); } async function getProcessTree(pid) { return new Promise((res, rej) => { (0, import_ps_tree.default)(pid, (err, children) => { if (err) rej(err); res(children); }); }); } async function terminate(pid) { if (process$1.platform === "win32") { await R("taskkill", [ "/PID", `${pid}`, "/T", "/F" ]); return; } const children = await getProcessTree(pid); for (let i = children.length - 1; i >= 0; i--) { const child = children[i]; kill(Number(child.PID)); } kill(pid); } function kill(pid) { try { process$1.kill(pid); } catch {} } function setupGlobal({ TEST_DIR, pre, post }) { return async function({ provide }) { await pre?.(); const { templatesDir } = setup({ cwd: TEST_DIR, variants }); provide("testDir", TEST_DIR); provide("templatesDir", templatesDir); provide("variants", variants); return async () => { await post?.(); }; }; } async function prepareServer({ cwd, page, buildCommand = "pnpm build", previewCommand = "pnpm preview" }) { if (buildCommand) execSync(buildCommand, { cwd, stdio: "pipe" }); const { url, close } = await startPreview({ cwd, command: previewCommand }); page.setDefaultNavigationTimeout(62e3); try { await page.goto(url); } catch (e) { await close(); throw e; } return { url, close }; } function createSetupTest(vitest, playwright) { return function setupTest(addons, options) { const { inject, test: vitestTest, beforeAll, beforeEach } = vitest; const test = vitestTest.extend({}); const cwd = inject("testDir"); const templatesDir = inject("templatesDir"); const variants = inject("variants"); const withBrowser = options?.browser ?? true; let create; let browser; if (withBrowser) beforeAll(async () => { let chromium; if (playwright) chromium = playwright.chromium; else try { ({chromium} = await import("@playwright/test")); } catch { throw new Error("Browser testing requires @playwright/test. Install it with: pnpm add -D @playwright/test"); } browser = await chromium.launch(); return async () => { await browser.close(); }; }); const testCases = []; for (const kind of options?.kinds ?? []) for (const variant of variants) { const addonTestCase = { variant, kind }; if (options?.filter === void 0 || options.filter(addonTestCase)) testCases.push(addonTestCase); } let testName; test.beforeAll(async (_ctx, suite) => { testName = path.dirname(suite.file.filepath).split("/").at(-1); create = createProject({ cwd, templatesDir, testName }); fs.writeFileSync(path.resolve(cwd, testName, "pnpm-workspace.yaml"), "packages:\n - '**/*'", "utf8"); fs.writeFileSync(path.resolve(cwd, testName, "package.json"), JSON.stringify({ name: `${testName}-workspace-root`, private: true })); for (const addonTestCase of testCases) { const { variant, kind } = addonTestCase; const cwd = create({ testId: `${kind.type}-${variant}`, variant }); const metaPath = path.resolve(cwd, "meta.json"); fs.writeFileSync(metaPath, JSON.stringify({ variant, kind }, null, " "), "utf8"); if (options?.preAdd) await options.preAdd({ addonTestCase, cwd }); await add({ cwd, addons, options: kind.options, packageManager: "pnpm" }); addPnpmAllowBuilds(cwd, "pnpm", "esbuild"); } execSync("pnpm install", { cwd: path.resolve(cwd, testName), stdio: "pipe" }); }); beforeEach(async (ctx) => { let browserCtx; if (withBrowser) { browserCtx = await browser.newContext(); ctx.page = await browserCtx.newPage(); } ctx.cwd = (addonTestCase) => { return path.join(cwd, testName, `${addonTestCase.kind.type}-${addonTestCase.variant}`); }; return async () => { if (withBrowser) await browserCtx.close(); }; }); return { test, testCases, prepareServer }; }; } //#endregion export { createSetupTest, prepareServer, setupGlobal, variants };