UNPKG

psrworld

Version:

A TypeScript-powered project scaffolding tool with dual CommonJS/ESM build support

1,449 lines (1,363 loc) 60.1 kB
'use strict'; var fs$1 = require('node:fs'); var path$3 = require('node:path'); var require$$0$2 = require('child_process'); var require$$0$1 = require('path'); var require$$0 = require('fs'); function _mergeNamespaces(n, m) { m.forEach(function (e) { e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) { if (k !== 'default' && !(k in n)) { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); }); return Object.freeze(n); } var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var picocolors$1 = {exports: {}}; let p = process || {}, argv = p.argv || [], env = p.env || {}; let isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || ((p.stdout || {}).isTTY && env.TERM !== "dumb") || !!env.CI); let formatter = (open, close, replace = open) => input => { let string = "" + input, index = string.indexOf(close, open.length); return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close }; let replaceClose = (string, close, replace, index) => { let result = "", cursor = 0; do { result += string.substring(cursor, index) + replace; cursor = index + close.length; index = string.indexOf(close, cursor); } while (~index) return result + string.substring(cursor) }; let createColors = (enabled = isColorSupported) => { let f = enabled ? formatter : () => String; return { isColorSupported: enabled, reset: f("\x1b[0m", "\x1b[0m"), bold: f("\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m"), dim: f("\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m"), italic: f("\x1b[3m", "\x1b[23m"), underline: f("\x1b[4m", "\x1b[24m"), inverse: f("\x1b[7m", "\x1b[27m"), hidden: f("\x1b[8m", "\x1b[28m"), strikethrough: f("\x1b[9m", "\x1b[29m"), black: f("\x1b[30m", "\x1b[39m"), red: f("\x1b[31m", "\x1b[39m"), green: f("\x1b[32m", "\x1b[39m"), yellow: f("\x1b[33m", "\x1b[39m"), blue: f("\x1b[34m", "\x1b[39m"), magenta: f("\x1b[35m", "\x1b[39m"), cyan: f("\x1b[36m", "\x1b[39m"), white: f("\x1b[37m", "\x1b[39m"), gray: f("\x1b[90m", "\x1b[39m"), bgBlack: f("\x1b[40m", "\x1b[49m"), bgRed: f("\x1b[41m", "\x1b[49m"), bgGreen: f("\x1b[42m", "\x1b[49m"), bgYellow: f("\x1b[43m", "\x1b[49m"), bgBlue: f("\x1b[44m", "\x1b[49m"), bgMagenta: f("\x1b[45m", "\x1b[49m"), bgCyan: f("\x1b[46m", "\x1b[49m"), bgWhite: f("\x1b[47m", "\x1b[49m"), blackBright: f("\x1b[90m", "\x1b[39m"), redBright: f("\x1b[91m", "\x1b[39m"), greenBright: f("\x1b[92m", "\x1b[39m"), yellowBright: f("\x1b[93m", "\x1b[39m"), blueBright: f("\x1b[94m", "\x1b[39m"), magentaBright: f("\x1b[95m", "\x1b[39m"), cyanBright: f("\x1b[96m", "\x1b[39m"), whiteBright: f("\x1b[97m", "\x1b[39m"), bgBlackBright: f("\x1b[100m", "\x1b[49m"), bgRedBright: f("\x1b[101m", "\x1b[49m"), bgGreenBright: f("\x1b[102m", "\x1b[49m"), bgYellowBright: f("\x1b[103m", "\x1b[49m"), bgBlueBright: f("\x1b[104m", "\x1b[49m"), bgMagentaBright: f("\x1b[105m", "\x1b[49m"), bgCyanBright: f("\x1b[106m", "\x1b[49m"), bgWhiteBright: f("\x1b[107m", "\x1b[49m"), } }; picocolors$1.exports = createColors(); var createColors_1 = picocolors$1.exports.createColors = createColors; var picocolorsExports = picocolors$1.exports; var picocolors = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports); var colors = /*#__PURE__*/_mergeNamespaces({ __proto__: null, createColors: createColors_1, default: picocolors }, [picocolorsExports]); const { blue: blue$1, blueBright: blueBright$1, cyan: cyan$2, green: green$1, greenBright: greenBright$1, magenta: magenta$1, red: red$1, redBright: redBright$1, reset, yellow: yellow$1, gray: gray$1, } = colors; /** * Framework configurations for project scaffolding * Each framework contains variants with different setups and features */ const FRAMEWORKS = [ { name: 'vanilla', display: 'Vanilla', color: yellow$1, desc: 'Vanilla JavaScript with TypeScript, Vite, and modern tooling setup', variants: [ { name: 'vanilla-ts', display: 'TypeScript', color: blue$1, templateDir: 'template-vanilla-ts', desc: 'Vanilla JavaScript with TypeScript, Vite, and modern tooling setup', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-vanilla-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-vanilla-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'vanilla', display: 'JavaScript', color: yellow$1, templateDir: 'template-vanilla', desc: 'Pure vanilla JavaScript with Vite for fast development and building', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-vanilla', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-vanilla', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, ], }, { name: 'vue', display: 'Vue', color: green$1, variants: [ { name: 'vue-ts', display: 'TypeScript', color: blue$1, templateDir: 'template-vue-ts', desc: 'Vue 3 with TypeScript, Composition API, and single file components', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-vue-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-vue-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'vue', display: 'JavaScript', color: yellow$1, templateDir: 'template-vue', desc: 'Vue 3 with JavaScript, Composition API, and reactive components', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-vue', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-vue', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'custom-create-vue', display: 'Official Vue Starter ↗', color: green$1, customCommand: 'npm create vue@latest TARGET_DIR', desc: 'Official Vue project generator with customizable features and tooling', }, { name: 'custom-nuxt', display: 'Nuxt ↗', color: greenBright$1, customCommand: 'npm exec nuxi init TARGET_DIR', desc: 'Full-stack Vue framework with SSR, file-based routing, and auto-imports', }, ], }, { name: 'react', display: 'React', color: cyan$2, variants: [ { name: 'react-ts', display: 'TypeScript', color: blue$1, templateDir: 'template-react-ts', desc: 'React 18 with TypeScript, JSX, hooks, and modern development setup', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-react-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-react-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'react-swc-ts', display: 'TypeScript + SWC', color: blue$1, templateDir: 'template-react-swc-ts', desc: 'React with TypeScript and SWC compiler for faster builds and HMR', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-react-swc-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-react-swc-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'react', display: 'JavaScript', color: yellow$1, templateDir: 'template-react', desc: 'React 18 with JavaScript, JSX, and component-based architecture', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-react', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-react', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'react-swc', display: 'JavaScript + SWC', color: yellow$1, templateDir: 'template-react-swc', desc: 'React with JavaScript and SWC compiler for enhanced performance', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-react-swc', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-react-swc', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'custom-react-router', display: 'React Router v7 ↗', color: cyan$2, customCommand: 'npm create react-router@latest TARGET_DIR', desc: 'React with declarative routing, nested routes, and navigation management', }, { name: 'custom-tanstack-router', display: 'TanStack Router ↗', color: cyan$2, customCommand: 'npm create -- tsrouter-app@latest TARGET_DIR --framework React --interactive', desc: 'Type-safe router with search params, loaders, and advanced routing features', }, { name: 'redwoodsdk-standard', display: 'RedwoodSDK ↗', color: red$1, customCommand: 'npm exec degit redwoodjs/sdk/starters/standard TARGET_DIR', desc: 'Full-stack React framework with GraphQL, Prisma, and JAMstack architecture', }, { name: 'rsc', display: 'RSC ↗', color: magenta$1, customCommand: 'npm exec degit vitejs/vite-plugin-react/packages/plugin-rsc/examples/starter TARGET_DIR', desc: 'React Server Components with server-side rendering and streaming', }, ], }, { name: 'preact', display: 'Preact', color: magenta$1, variants: [ { name: 'preact-ts', display: 'TypeScript', color: blue$1, templateDir: 'template-preact-ts', desc: 'Lightweight React alternative with TypeScript and 3KB runtime', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-preact-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-preact-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'preact', display: 'JavaScript', color: yellow$1, templateDir: 'template-preact', desc: 'Fast 3KB React alternative with same modern API and ecosystem', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-preact', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-preact', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'custom-create-preact', display: 'Official Preact Starter ↗', color: magenta$1, customCommand: 'npm create preact@latest TARGET_DIR', desc: 'Official Preact generator with PWA features and optimized builds', }, ], }, { name: 'lit', display: 'Lit', color: redBright$1, variants: [ { name: 'lit-ts', display: 'TypeScript', color: blue$1, templateDir: 'template-lit-ts', desc: 'Web Components with Lit library, TypeScript, and reactive properties', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-lit-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-lit-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'lit', display: 'JavaScript', color: yellow$1, templateDir: 'template-lit', desc: 'Simple and fast web components using Lit library and templates', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-lit', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-lit', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, ], }, { name: 'svelte', display: 'Svelte', color: red$1, variants: [ { name: 'svelte-ts', display: 'TypeScript', color: blue$1, templateDir: 'template-svelte-ts', desc: 'Compile-time optimized framework with TypeScript and reactive state', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-svelte-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-svelte-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'svelte', display: 'JavaScript', color: yellow$1, templateDir: 'template-svelte', desc: 'No virtual DOM framework with compiled components and reactive updates', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-svelte', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-svelte', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'custom-svelte-kit', display: 'SvelteKit ↗', color: red$1, customCommand: 'npm exec sv create TARGET_DIR', desc: 'Full-stack Svelte framework with SSR, routing, and adapter system', }, ], }, { name: 'solid', display: 'Solid', color: blue$1, variants: [ { name: 'solid-ts', display: 'TypeScript', color: blue$1, templateDir: 'template-solid-ts', desc: 'Fine-grained reactive framework with TypeScript and JSX syntax', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-solid-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-solid-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'solid', display: 'JavaScript', color: yellow$1, templateDir: 'template-solid', desc: 'Performant reactive framework with signals and compiled templates', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-solid', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-solid', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'custom-tanstack-router', display: 'TanStack Router ↗', color: cyan$2, customCommand: 'npm create -- tsrouter-app@latest TARGET_DIR --framework Solid --interactive', desc: 'Solid with type-safe routing, search params, and data loading', }, ], }, { name: 'qwik', display: 'Qwik', color: blueBright$1, variants: [ { name: 'qwik-ts', display: 'TypeScript', color: blueBright$1, templateDir: 'template-qwik-ts', desc: 'Resumable framework with TypeScript and instant-on applications', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-qwik-ts', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-qwik-ts', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'qwik', display: 'JavaScript', color: yellow$1, templateDir: 'template-qwik', desc: 'Zero hydration framework with resumable execution and lazy loading', tailwindCssVariants: [ { name: 'tailwind-v4', display: 'Tailwind V4', color: green$1, templateDir: 'v4-template-qwik', desc: 'Tailwind CSS v4 with new CSS-first configuration and Lightning CSS engine', }, { name: 'tailwind-v3', display: 'Tailwind V3', color: blue$1, templateDir: 'v3-template-qwik', desc: 'Tailwind CSS v3 with traditional configuration and build process', }, ], }, { name: 'custom-qwik-city', display: 'QwikCity ↗', color: blueBright$1, customCommand: 'npm create qwik@latest basic TARGET_DIR', desc: 'Meta-framework for Qwik with routing, layouts, and SSR capabilities', }, ], }, { name: 'angular', display: 'Angular', color: red$1, desc: 'Full-featured TypeScript framework with dependency injection and comprehensive tooling', variants: [ { name: 'custom-angular', display: 'Angular ↗', color: red$1, customCommand: 'npm exec @angular/cli@latest new TARGET_DIR', desc: 'Full-featured framework with TypeScript, dependency injection, and CLI tools', }, { name: 'custom-analog', display: 'Analog ↗', color: yellow$1, customCommand: 'npm create analog@latest TARGET_DIR', desc: 'Angular meta-framework with file-based routing and server-side rendering', }, ], }, { name: 'marko', display: 'Marko', color: magenta$1, desc: "eBay's UI framework with streaming SSR and optimized performance", variants: [ { name: 'marko-run', display: 'Marko Run ↗', color: magenta$1, customCommand: 'npm create -- marko@latest --name TARGET_DIR', desc: "eBay's UI framework with streaming SSR and component compilation", }, ], }, { name: 'nextjs', display: 'Next.js', color: cyan$2, desc: 'Production-ready React framework with SSR and full-stack capabilities', variants: [ { name: 'custom-nextjs', display: 'Next.js ↗', color: cyan$2, customCommand: 'npm create next-app@latest TARGET_DIR', desc: 'React framework with SSR, API routes, file-based routing, and deployment optimization', }, ], }, { name: 'astro', display: 'Astro', color: magenta$1, desc: 'Content-focused framework with islands architecture and multi-framework support', variants: [ { name: 'custom-astro', display: 'Astro ↗', color: magenta$1, customCommand: 'npm create astro@latest TARGET_DIR', desc: 'Multi-framework static site generator with partial hydration and islands architecture', }, ], }, { name: 'remix', display: 'Remix', color: blue$1, desc: 'Full-stack React framework focused on web standards and user experience', variants: [ { name: 'custom-remix', display: 'Remix ↗', color: blue$1, customCommand: 'npx create-remix@latest TARGET_DIR', desc: 'Full-stack React framework focusing on web standards and progressive enhancement', }, ], }, { name: 'meteor', display: 'Meteor.js', color: gray$1, desc: 'Full-stack JavaScript platform with real-time capabilities and integrated toolchain', variants: [ { name: 'custom-meteor', display: 'Meteor.js ↗', color: gray$1, customCommand: 'meteor create TARGET_DIR', desc: 'Full-stack JavaScript platform with real-time data, MongoDB integration, and deployment tools', }, ], }, { name: 'gatsby', display: 'Gatsby', color: magenta$1, desc: 'React-based static site generator with GraphQL and performance optimization', variants: [ { name: 'custom-gatsby', display: 'Gatsby ↗', color: magenta$1, customCommand: 'npm init gatsby@latest TARGET_DIR', desc: 'React-based static site generator with GraphQL data layer and plugin ecosystem', }, ], }, { name: 'symfony', display: 'Symfony', color: blue$1, desc: 'Professional PHP framework with enterprise-grade components and architecture', variants: [ { name: 'custom-symfony', display: 'Symfony ↗', color: blue$1, customCommand: 'symfony new TARGET_DIR', desc: 'PHP framework with reusable components, dependency injection, and rapid development tools', }, ], }, { name: 'rails', display: 'Rails', color: redBright$1, desc: 'Ruby web framework with convention over configuration and rapid development', variants: [ { name: 'custom-rails', display: 'Rails ↗', color: redBright$1, customCommand: 'rails new TARGET_DIR', desc: 'Ruby web framework with convention over configuration and MVC architecture', }, ], }, { name: 'phoenix', display: 'Phoenix', color: cyan$2, desc: 'Elixir web framework with real-time features and fault-tolerant architecture', variants: [ { name: 'custom-phoenix', display: 'Phoenix ↗', color: cyan$2, customCommand: 'mix phx.new TARGET_DIR', desc: 'Elixir web framework with real-time features, fault tolerance, and high concurrency', }, ], }, { name: 'django', display: 'Django', color: green$1, desc: 'Python web framework with batteries included and rapid development focus', variants: [ { name: 'custom-django', display: 'Django ↗', color: green$1, customCommand: 'django-admin startproject TARGET_DIR', desc: 'Python web framework with batteries included, admin interface, and ORM', }, ], }, { name: 'flask', display: 'Flask', color: yellow$1, desc: 'Lightweight Python web framework with flexible architecture and simplicity', variants: [ { name: 'custom-flask', display: 'Flask ↗', color: yellow$1, customCommand: 'flask new TARGET_DIR', desc: 'Lightweight Python web framework with flexible architecture and extensibility', }, ], }, { name: 'blazor', display: 'Blazor', color: blueBright$1, desc: 'C# web framework running in browser with WebAssembly and .NET ecosystem', variants: [ { name: 'custom-blazor', display: 'Blazor ↗', color: blueBright$1, customCommand: 'dotnet new blazorwasm -o TARGET_DIR', desc: 'C# web framework running in browser via WebAssembly with .NET ecosystem', }, ], }, { name: 'hugo', display: 'Hugo', color: gray$1, desc: 'Fast static site generator written in Go with themes and content management', variants: [ { name: 'custom-hugo', display: 'Hugo ↗', color: gray$1, customCommand: 'hugo new site TARGET_DIR', desc: 'Fast static site generator written in Go with themes and content management', }, ], }, { name: 'others', display: 'Others', color: reset, desc: 'Additional starters and specialized project templates', variants: [ { name: 'create-vite-extra', display: 'Extra Vite Starters ↗', color: reset, customCommand: 'npm create vite-extra@latest TARGET_DIR', desc: 'Additional Vite templates and starters for various frameworks and setups', }, { name: 'create-electron-vite', display: 'Electron ↗', color: reset, customCommand: 'npm create electron-vite@latest TARGET_DIR', desc: 'Desktop applications with Electron, Vite, and modern web technologies', }, ], }, ]; /** * Find variant by name across all frameworks * @param frameworks - Array of framework configurations * @param variantName - Name of the variant to find * @returns Object with variant and framework, or null if not found */ function getVariantByName(frameworks, variantName) { for (const framework of frameworks) { if (framework.variants) { const variant = framework.variants.find(v => v.name === variantName); if (variant) { return { variant, framework }; } } } return null; } /** * Get Tailwind CSS variants for a specific framework variant * @param variant - Framework variant * @returns Array of Tailwind CSS variants or empty array if none */ function getTailwindVariants(variant) { return variant.tailwindCssVariants || []; } /** * Find Tailwind variant by name within a framework variant * @param variant - Framework variant * @param tailwindVariantName - Name of the Tailwind variant * @returns Tailwind variant or null if not found */ function getTailwindVariantByName(variant, tailwindVariantName) { if (!variant.tailwindCssVariants) return null; return (variant.tailwindCssVariants.find(tv => tv.name === tailwindVariantName) || null); } function formatTargetDir(targetDir) { return targetDir?.trim().replace(/\/+$/g, '') || ''; } function copy(src, dest) { const stat = fs$1.statSync(src); if (stat.isDirectory()) { copyDir(src, dest); } else { fs$1.copyFileSync(src, dest); } } function isValidPackageName(projectName) { return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName); } function toValidPackageName(projectName) { return projectName .trim() .toLowerCase() .replace(/\s+/g, '-') .replace(/^[._]/, '') .replace(/[^a-z0-9-~]+/g, '-') .replace(/^-+|-+$/g, '') // Remove leading and trailing hyphens .replace(/-+/g, '-'); // Replace multiple consecutive hyphens with single hyphen } function copyDir(srcDir, destDir) { fs$1.mkdirSync(destDir, { recursive: true }); for (const file of fs$1.readdirSync(srcDir)) { const srcFile = path$3.resolve(srcDir, file); const destFile = path$3.resolve(destDir, file); copy(srcFile, destFile); } } function writeTemplate(src, dest, projectName) { const stats = fs$1.statSync(src); if (stats.isDirectory()) { fs$1.mkdirSync(dest, { recursive: true }); for (const file of fs$1.readdirSync(src)) { const srcFile = path$3.resolve(src, file); const destFile = path$3.resolve(dest, file); writeTemplate(srcFile, destFile, projectName); } } else { let content = fs$1.readFileSync(src, 'utf-8'); // Generate a valid package name from the project name const packageName = toValidPackageName(projectName); // Replace template variables content = content.replace(/{{projectName}}/g, projectName); content = content.replace(/{{package}}/g, packageName); fs$1.writeFileSync(dest, content); } } function isEmpty(path) { const files = fs$1.readdirSync(path); return files.length === 0 || (files.length === 1 && files[0] === '.git'); } function emptyDir(dir) { if (!fs$1.existsSync(dir)) { return; } for (const file of fs$1.readdirSync(dir)) { if (file === '.git') { continue; } fs$1.rmSync(path$3.resolve(dir, file), { recursive: true, force: true }); } } function setupReactFiles(root, projectName) { // Update package.json name const pkgPath = path$3.join(root, 'package.json'); const pkg = JSON.parse(fs$1.readFileSync(pkgPath, 'utf-8')); pkg.name = projectName; fs$1.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2)); } // Debounce function function debounce(func, delay) { let timeoutId; return (...args) => { if (timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => { func(...args); }, delay); }; } // Simple Logger class class SimpleLogger { debug; constructor(debug = false) { this.debug = debug; } log(level, message, ...args) { const timestamp = new Date().toISOString(); const logLevel = level.toUpperCase(); const logMessage = `[${timestamp}] [${logLevel}]`; switch (level) { case 'info': console.log(logMessage, message, ...args); break; case 'warn': console.warn(logMessage, message, ...args); break; case 'error': console.error(logMessage, message, ...args); break; case 'debug': if (this.debug) { console.debug(logMessage, message, ...args); } break; } } } const { blue, blueBright, cyan: cyan$1, green, greenBright, magenta, red, redBright, yellow, gray, } = colors; const helpMessage = `\ Usage: create-mycustomlib [OPTION]... [DIRECTORY] Create a new project from a template. With no arguments, start the CLI in interactive mode. Options: -h, --help show this help message -t, --template NAME use a specific template -y, --yes use default options (vanilla-ts with Tailwind v4) Available templates: ${yellow('vanilla-ts vanilla')} ${green('vue-ts vue')} ${cyan$1('react-ts react')} ${cyan$1('react-swc-ts react-swc')} ${magenta('preact-ts preact')} ${redBright('lit-ts lit')} ${red('svelte-ts svelte')} ${blue('solid-ts solid')} ${blueBright('qwik-ts qwik')} ${cyan$1('custom-nextjs')} ${greenBright('nuxt nuxt')} ${magenta('astro astro')} ${blue('remix remix')} ${gray('meteor meteor')} ${magenta('gatsby gatsby')} ${blue('symfony symfony')} ${redBright('rails rails')} ${cyan$1('phoenix phoenix')} ${green('django django')} ${yellow('flask flask')} ${blueBright('blazor blazor')} ${gray('hugo hugo')}`; function printHelp() { console.log(helpMessage); } function pkgFromUserAgent(userAgent) { if (!userAgent) return undefined; const pkgSpec = userAgent.split(' ')[0]; const pkgSpecArr = pkgSpec.split('/'); return { name: pkgSpecArr[0], version: pkgSpecArr[1], }; } var crossSpawn = {exports: {}}; var windows; var hasRequiredWindows; function requireWindows () { if (hasRequiredWindows) return windows; hasRequiredWindows = 1; windows = isexe; isexe.sync = sync; var fs = require$$0; function checkPathExt (path, options) { var pathext = options.pathExt !== undefined ? options.pathExt : process.env.PATHEXT; if (!pathext) { return true } pathext = pathext.split(';'); if (pathext.indexOf('') !== -1) { return true } for (var i = 0; i < pathext.length; i++) { var p = pathext[i].toLowerCase(); if (p && path.substr(-p.length).toLowerCase() === p) { return true } } return false } function checkStat (stat, path, options) { if (!stat.isSymbolicLink() && !stat.isFile()) { return false } return checkPathExt(path, options) } function isexe (path, options, cb) { fs.stat(path, function (er, stat) { cb(er, er ? false : checkStat(stat, path, options)); }); } function sync (path, options) { return checkStat(fs.statSync(path), path, options) } return windows; } var mode; var hasRequiredMode; function requireMode () { if (hasRequiredMode) return mode; hasRequiredMode = 1; mode = isexe; isexe.sync = sync; var fs = require$$0; function isexe (path, options, cb) { fs.stat(path, function (er, stat) { cb(er, er ? false : checkStat(stat, options)); }); } function sync (path, options) { return checkStat(fs.statSync(path), options) } function checkStat (stat, options) { return stat.isFile() && checkMode(stat, options) } function checkMode (stat, options) { var mod = stat.mode; var uid = stat.uid; var gid = stat.gid; var myUid = options.uid !== undefined ? options.uid : process.getuid && process.getuid(); var myGid = options.gid !== undefined ? options.gid : process.getgid && process.getgid(); var u = parseInt('100', 8); var g = parseInt('010', 8); var o = parseInt('001', 8); var ug = u | g; var ret = (mod & o) || (mod & g) && gid === myGid || (mod & u) && uid === myUid || (mod & ug) && myUid === 0; return ret } return mode; } var core; if (process.platform === 'win32' || commonjsGlobal.TESTING_WINDOWS) { core = requireWindows(); } else { core = requireMode(); } var isexe_1 = isexe$1; isexe$1.sync = sync; function isexe$1 (path, options, cb) { if (typeof options === 'function') { cb = options; options = {}; } if (!cb) { if (typeof Promise !== 'function') { throw new TypeError('callback not provided') } return new Promise(function (resolve, reject) { isexe$1(path, options || {}, function (er, is) { if (er) { reject(er); } else { resolve(is); } }); }) } core(path, options || {}, function (er, is) { // ignore EACCES because that just means we aren't allowed to run it if (er) { if (er.code === 'EACCES' || options && options.ignoreErrors) { er = null; is = false; } } cb(er, is); }); } function sync (path, options) { // my kingdom for a filtered catch try { return core.sync(path, options || {}) } catch (er) { if (options && options.ignoreErrors || er.code === 'EACCES') { return false } else { throw er } } } const isWindows = process.platform === 'win32' || process.env.OSTYPE === 'cygwin' || process.env.OSTYPE === 'msys'; const path$2 = require$$0$1; const COLON = isWindows ? ';' : ':'; const isexe = isexe_1; const getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' }); const getPathInfo = (cmd, opt) => { const colon = opt.colon || COLON; // If it has a slash, then we don't bother searching the pathenv. // just check the file itself, and that's it. const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [''] : ( [ // windows always checks the cwd first ...(isWindows ? [process.cwd()] : []), ...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */ '').split(colon), ] ); const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM' : ''; const pathExt = isWindows ? pathExtExe.split(colon) : ['']; if (isWindows) { if (cmd.indexOf('.') !== -1 && pathExt[0] !== '') pathExt.unshift(''); } return { pathEnv, pathExt, pathExtExe, } }; const which$1 = (cmd, opt, cb) => { if (typeof opt === 'function') { cb = opt; opt = {}; } if (!opt) opt = {}; const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt); const found = []; const step = i => new Promise((resolve, reject) => { if (i === pathEnv.length) return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd)) const ppRaw = pathEnv[i]; const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw; const pCmd = path$2.join(pathPart, cmd); const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd; resolve(subStep(p, i, 0)); }); const subStep = (p, i, ii) => new Promise((resolve, reject) => { if (ii === pathExt.length) return resolve(step(i + 1)) const ext = pathExt[ii]; isexe(p + ext, { pathExt: pathExtExe }, (er, is) => { if (!er && is) { if (opt.all) found.push(p + ext); else return resolve(p + ext) } return resolve(subStep(p, i, ii + 1)) }); }); return cb ? step(0).then(res => cb(null, res), cb) : step(0) }; const whichSync = (cmd, opt) => { opt = opt || {}; const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt); const found = []; for (let i = 0; i < pathEnv.length; i ++) { const ppRaw = pathEnv[i]; const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw; const pCmd = path$2.join(pathPart, cmd); const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd; for (let j = 0; j < pathExt.length; j ++) { const cur = p + pathExt[j]; try { const is = isexe.sync(cur, { pathExt: pathExtExe }); if (is) { if (opt.all) found.push(cur); else return cur } } catch (ex) {} } } if (opt.all && found.length) return found if (opt.nothrow) return null throw getNotFoundError(cmd) }; var which_1 = which$1; which$1.sync = whichSync; var pathKey$1 = {exports: {}}; const pathKey = (options = {}) => { const environment = options.env || process.env; const platform = options.platform || process.platform; if (platform !== 'win32') { return 'PATH'; } return Object.keys(environment).reverse().find(key => key.toUpperCase() === 'PATH') || 'Path'; }; pathKey$1.exports = pathKey; // TODO: Remove this for the next major release pathKey$1.exports.default = pathKey; var pathKeyExports = pathKey$1.exports; const path$1 = require$$0$1; const which = which_1; const getPathKey = pathKeyExports; function resolveCommandAttempt(parsed, withoutPathExt) { const env = parsed.options.env || process.env; const cwd = process.cwd(); const hasCustomCwd = parsed.options.cwd != null; // Worker threads do not have process.chdir() const shouldSwitchCwd = hasCustomCwd && process.chdir !== undefined && !process.chdir.disabled; // If a custom `cwd` was specified, we need to change the process cwd // because `which` will do stat calls but does not support a custom cwd if (shouldSwitchCwd) { try { process.chdir(parsed.options.cwd); } catch (err) { /* Empty */ } } let resolved; try { resolved = which.sync(parsed.command, { path: env[getPathKey({ env })], pathExt: withoutPathExt ? path$1.delimiter : undefined, }); } catch (e) { /* Empty */ } finally { if (shouldSwitchCwd) { process.chdir(cwd); } } // If we successfully resolved, ensure that an absolute path is returned // Note that when a custom `cwd`