create-defuss
Version:
Checks out git projects from sub-directories. Originally for jump-starting defuss projects from templates.
10 lines (8 loc) • 4.53 kB
JavaScript
;var $=Object.defineProperty;var f=(e,t)=>$(e,"name",{value:t,configurable:!0});var g=require("node:child_process"),s=require("node:path"),o=require("node:fs"),R=require("node:os");const S=/^(https:\/\/(?:github|gitlab|bitbucket)\.com)\/([^\/]+)\/([^\/]+)\/(?:tree|src)\/([^\/]+)\/(.+)$/,v=f((e,t,p=S)=>{try{const r=e.match(p);if(!r)throw new Error("Invalid URL format. Use a subdirectory URL (https) from GitHub, GitLab, or Bitbucket.");const[,i,c,u,n,d]=r;[c,u,n].forEach(m=>{if(!/^[\w\-]+$/.test(m))throw new Error(`Invalid characters in input: ${m}`)});const h=s.normalize(d);if(s.isAbsolute(h)||h.startsWith("..")||h.includes(`${s.sep}..${s.sep}`))throw new Error("Invalid subdirectory path.");const a=h,k=t||s.basename(a),w=s.resolve(process.cwd(),k);if(o.existsSync(w))throw new Error(`Destination folder "${k}" already exists.`);o.mkdirSync(w,{recursive:!0});const l=o.mkdtempSync(s.join(R.tmpdir(),"sparse-checkout-"));if(console.log("Cloning repository with sparse checkout into temporary directory..."),g.spawnSync("git",["clone","--no-checkout",`${i}/${c}/${u}.git`,l],{stdio:"inherit"}).status!==0)throw new Error("Git clone failed.");const y=s.resolve(l,a);if(!y.startsWith(l+s.sep)&&y!==l)throw new Error("Subdirectory path traversal detected.");if(console.log("Initializing sparse-checkout..."),g.spawnSync("git",["-C",l,"sparse-checkout","init"],{stdio:"inherit"}).status!==0)throw new Error("Git sparse-checkout init failed.");if(console.log(`Setting sparse-checkout to subdirectory: ${a}`),g.spawnSync("git",["-C",l,"sparse-checkout","set",a],{stdio:"inherit"}).status!==0)throw new Error("Git sparse-checkout set failed.");if(console.log(`Checking out branch: ${n}...`),g.spawnSync("git",["-C",l,"checkout",n],{stdio:"inherit"}).status!==0)throw new Error("Git checkout failed.");if(!o.existsSync(y))throw new Error(`Subdirectory "${a}" does not exist in the repository.`);if(console.log("Copying files to the destination directory..."),b(y,w),console.log("Replacing workspace:* versions with latest npm versions..."),x(w),console.log("Cleaning up temporary directory..."),o.rmSync(l,{recursive:!0,force:!0}),console.log("Initializing a new git repository..."),g.spawnSync("git",["init"],{cwd:w,stdio:"inherit"}).status!==0)throw new Error("Initializing new git repository failed.");console.log("\u{1F389} All done! Your new project has been set up!"),console.log(`
To get started, run the following commands:
cd ${k}
`)}catch(r){console.error("Error during sparse checkout:",r.message),process.exit(1)}},"performSparseCheckout");function E(e){const t=g.spawnSync("npm",["view",e,"version"],{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return t.status===0&&t.stdout?t.stdout.trim():null}f(E,"getNpmLatestVersion");function x(e){const t=s.join(e,"package.json");if(!o.existsSync(t)){console.log("No package.json found in the root, skipping workspace version replacement.");return}const p=o.readFileSync(t,"utf-8"),r=JSON.parse(p);let i=!1;const c=["dependencies","devDependencies","peerDependencies","optionalDependencies"];for(const u of c){const n=r[u];if(!(!n||typeof n!="object")){for(const[d,h]of Object.entries(n))if(typeof h=="string"&&h.startsWith("workspace:")){console.log(`Resolving latest npm version for ${d}...`);const a=E(d);a?(console.log(` ${d}: workspace:* -> ^${a}`),n[d]=`^${a}`,i=!0):console.warn(` Warning: Could not fetch latest version for ${d}, keeping workspace:* reference.`)}}}i?(o.writeFileSync(t,JSON.stringify(r,null,2)+`
`,"utf-8"),console.log("Updated package.json with resolved npm versions.")):console.log("No workspace:* versions found in package.json.")}f(x,"replaceWorkspaceVersions");function b(e,t){if(!o.existsSync(e))throw new Error(`Source directory "${e}" does not exist.`);const p=o.readdirSync(e);for(const r of p){const i=s.join(e,r),c=s.join(t,r),u=o.lstatSync(i);if(u.isDirectory())o.mkdirSync(c,{recursive:!0}),b(i,c);else if(u.isSymbolicLink()){const n=o.readlinkSync(i);o.symlinkSync(n,c)}else o.copyFileSync(i,c)}}f(b,"copyDirectoryContents");const C=f(async()=>{const e=process.argv.slice(2);(e.length<1||e.length>2)&&(console.error(`Usage: create-defuss <repo-url> [destination-folder]
Example: create-defuss https://github.com/kyr0/defuss/tree/main/examples/with-astro-ts ./my-new-project`),process.exit(1));const t=e[0],p=e[1];v(t,p)},"main");C().catch(e=>{console.error("Unexpected error:",e),process.exit(1)}),exports.defaultScmHostPattern=S,exports.performSparseCheckout=v;
//# sourceMappingURL=cli.cjs.map