@shopify/cli
Version:
A CLI tool to build for the Shopify platform
7 lines (6 loc) • 11.1 kB
JavaScript
import{F as N}from"./chunk-54CAKCYR.js";import{b as A}from"./chunk-7ESSIN27.js";import{a as y,b as H}from"./chunk-WFXRSKRK.js";import{j as D}from"./chunk-GZS44BUW.js";import{a as q}from"./chunk-VBUZWRUL.js";import{b as C,l as k,s as R}from"./chunk-6G6TMKXF.js";import{d as S}from"./chunk-M56NDIMD.js";import{Ca as b,Qb as l,Ta as T,Ua as _,bb as v,na as O,wa as g}from"./chunk-N5PQPIBF.js";import{f as L}from"./chunk-YTNDFQJT.js";import{d as m,e as u,g as w,i as F}from"./chunk-IU2ZQ6TE.js";import{e as X,g as f}from"./chunk-VPRTJUIN.js";f();f();var M=X(q(),1),G=200,K=6e4,U=200,Q=500,I=class{constructor(t,e,n=G){this.currentEvents=[];this.extensionPaths=[];this.ignored={};this.extensionWatchedFiles=new Map;this.emitEvents=()=>{let t=this.currentEvents;this.currentEvents=[];let e=`\u{1F509} ${t.length} EVENTS EMITTED in files: ${t.map(n=>n.path).join(`
`)}`;l(e,this.options.stdout),this.onChangeCallback?.(t)};this.handleFileEvent=(t,e)=>{let n=y(),i=u(e),s=e===this.app.configPath,r=e.endsWith(".extension.toml");if(l(`\u{1F300}: ${t} ${e.replace(this.app.directory,"")}
`),s)this.handleEventForExtension(t,e,this.app.directory,n,!1);else{let a=this.extensionWatchedFiles.get(i),p=a===void 0||a.size===0;if(p&&t==="add"&&!r){let d=this.discoverFileOwners(i);d.size>0&&(this.extensionWatchedFiles.set(i,d),a=d,p=!1)}if(p&&!r&&!s){l(`\u{1F300}: File ${e} is not watched by any extension`,this.options.stdout);return}for(let d of a??[]){let c=this.app.realExtensions.find(E=>E.handle===d),h=c?u(c.directory):this.app.directory;this.handleEventForExtension(t,e,h,n,!1,d)}p&&this.handleEventForExtension(t,e,this.app.directory,n,!0)}this.debouncedEmit()};this.close=()=>{this.watcher&&(l("Closing file watcher",this.options.stdout),this.watcher.close().then(()=>l("File watching closed",this.options.stdout)).catch(t=>l(`File watching failed to close: ${t.message}`,this.options.stderr)))};this.app=t,this.options=e,this.debouncedEmit=R(this.emitEvents.bind(this),n,{leading:!0,trailing:!0}),this.updateApp(t)}onChange(t){this.onChangeCallback=t}async start(){let e=[...this.app.configuration.extension_directories??["extensions"]].map(r=>m(this.app.directory,r));await Promise.all(e.map(async r=>{try{await g(r.replace(/\/\*+$/,""))}catch{}}));let n=[this.app.configPath,...e],i=this.getAllWatchedFiles();n.push(...i),this.close();let{default:s}=await import("./chokidar-G4ONJSK4.js");this.watcher=s.watch(n,{ignored:["**/node_modules/**","**/.git/**"],persistent:!0,ignoreInitial:!0}),this.watcher.on("all",this.handleFileEvent),this.addAbortListener(),l(`File watcher started with ${n.length} paths`,this.options.stdout)}updateApp(t){this.app=t,this.extensionPaths=this.app.nonConfigExtensions.map(e=>u(e.directory)).filter(e=>e!==this.app.directory),this.extensionPaths.forEach(e=>{this.ignored[e]??=this.createIgnoreInstance(e)})}addAbortListener(){this.options.signal.removeEventListener("abort",this.close),this.options.signal.addEventListener("abort",this.close)}getAllWatchedFiles(){this.extensionWatchedFiles.clear();let t=this.app.realExtensions.map(n=>({extension:n,watchedFiles:n.watchedFiles()})),e=new Set;for(let{extension:n,watchedFiles:i}of t)for(let s of i){let r=u(s);e.add(r);let a=this.extensionWatchedFiles.get(r)??new Set;a.add(n.handle),this.extensionWatchedFiles.set(r,a)}return Array.from(e)}pushEvent(t){this.shouldIgnoreEvent(t)||(t.type==="extension_folder_created"&&(this.ignored[t.path]=this.createIgnoreInstance(t.path)),!this.currentEvents.some(e=>e.path===t.path&&e.type===t.type&&e.extensionHandle===t.extensionHandle)&&this.currentEvents.push(t))}shouldIgnoreEvent(t){if(t.type==="extension_folder_deleted"||t.type==="extension_folder_created"||t.extensionHandle&&this.extensionWatchedFiles.get(u(t.path))?.has(t.extensionHandle))return!1;let n=(t.extensionHandle?this.app.realExtensions.find(s=>s.handle===t.extensionHandle):void 0)?.watchedFiles(),i=this.ignored[t.extensionPath];if(n)return!n.some(r=>v(t.path,r));if(i){let s=w(t.extensionPath,t.path);return i.ignores(s)}return!1}discoverFileOwners(t){let e=new Set;for(let n of this.app.realExtensions){let i=u(n.directory);i!==this.app.directory&&t.startsWith(`${i}/`)&&this.pathMatchesWatchPatterns(t,n)&&e.add(n.handle)}return e}pathMatchesWatchPatterns(t,e){let{paths:n,ignore:i}=e.watchPatterns(),s=w(u(e.directory),t);return i.some(r=>v(s,r))?!1:n.some(r=>v(s,r))}handleEventForExtension(t,e,n,i,s,r){let a=e.endsWith(".extension.toml"),p=e===this.app.configPath;switch(t){case"change":if(s)break;a||p?this.pushEvent({type:"extensions_config_updated",path:e,extensionPath:n,extensionHandle:r,startTime:i}):this.pushEvent({type:"file_updated",path:e,extensionPath:n,extensionHandle:r,startTime:i});break;case"add":if(!a){this.pushEvent({type:"file_created",path:e,extensionPath:n,extensionHandle:r,startTime:i});break}let d=0,c=F(e),h=setInterval(()=>{_(m(c,A.lockFile))?(l(`Waiting for extension to complete creation: ${e}
`),d+=U):(clearInterval(h),this.extensionPaths.push(c),this.pushEvent({type:"extension_folder_created",path:c,extensionPath:n,startTime:i}),this.debouncedEmit()),d>=K&&(clearInterval(h),this.options.stderr.write(`Error loading new extension at path: ${e}.
Please restart the process.`))},U);break;case"unlink":if(e.endsWith(A.lockFile))break;p?this.pushEvent({type:"app_config_deleted",path:e,extensionPath:n,startTime:i}):a?(this.extensionPaths=this.extensionPaths.filter(E=>E!==n),this.pushEvent({type:"extension_folder_deleted",path:n,extensionPath:n,startTime:i})):setTimeout(()=>{this.extensionPaths.includes(n)&&(this.pushEvent({type:"file_deleted",path:e,extensionPath:n,extensionHandle:r,startTime:i}),this.extensionWatchedFiles.delete(u(e)),this.debouncedEmit())},Q);break;case"addDir":case"unlinkDir":break}}createIgnoreInstance(t){let e=m(t,".gitignore");if(!_(e))return;let n=O(e).toString().split(`
`).map(i=>i.trim()).filter(i=>i!==""&&!i.startsWith("#"));return M.default.default().add(n)}};f();f();function $(o,t,e=!0){let n=o.realExtensions,i=n.map(c=>c.uid),s=t.realExtensions,r=s.map(c=>c.uid),a=s.filter(c=>!i.includes(c.uid)),p=n.filter(c=>!r.includes(c.uid)),d;return e&&(d=s.filter(c=>{let h=n.find(P=>P.uid===c.uid);if(!h)return!1;let E=JSON.stringify(h.configuration)!==JSON.stringify(c.configuration),x=h.configurationPath!==c.configurationPath;return E||x})),{created:a,updated:d??[],deleted:p}}async function z(o,t,e){if(o[0]===void 0)return;let n=o.some(r=>B.includes(r.type)),i=o.filter(r=>!B.includes(r.type));if(n)return te({event:o[0],app:t,options:e,extensions:[]});let s={app:t,extensionEvents:[],path:o[0].path,startTime:o[0].startTime};for(let r of i){let a=r.extensionHandle?t.realExtensions.filter(d=>d.handle===r.extensionHandle):t.realExtensions.filter(d=>d.directory===r.extensionPath),p=Y[r.type]({event:r,app:s.app,extensions:a,options:e});s.extensionEvents.push(...p.extensionEvents)}return s}var B=["extensions_config_updated","extension_folder_created"],Y={extension_folder_deleted:Z,file_created:W,file_deleted:W,file_updated:W,app_config_deleted:ee,extension_folder_created:j,extensions_config_updated:j};function Z({event:o,app:t,extensions:e}){let n=e.map(i=>(t.removeExtension(i.uid),{type:"deleted",extension:i}));return{app:t,extensionEvents:n,startTime:o.startTime,path:o.path}}function W({event:o,app:t,extensions:e}){let n=e.map(i=>({type:"changed",extension:i}));return{app:t,extensionEvents:n,startTime:o.startTime,path:o.path}}function j(o){return{app:o.app,extensionEvents:[],startTime:o.event.startTime,path:o.event.path}}function ee(o){throw new S("The active app.toml was deleted, exiting")}async function te({event:o,app:t}){let e=await ne(t),n=$(t,e,!0),i=n.created.map(p=>({type:"created",extension:p})),s=n.deleted.map(p=>({type:"deleted",extension:p})),r=n.updated.map(p=>({type:"changed",extension:p})),a=[...i,...s,...r];return{app:e,extensionEvents:a,startTime:o.startTime,path:o.path,appWasReloaded:!0}}async function ne(o){let t=y();try{let e=await N(o);return l(`App reloaded [${H(t)}ms]`),e}catch(e){let n=new Error(`Error reloading app: ${e.message}`);throw n.cause="validation-error",n}}import{formatMessagesSync as ie}from"esbuild";import se from"events";var V=class extends se{constructor(e,n,i,s){super();this.started=!1;this.ready=!1;this.initialEvents=[];this.app=e,this.appURL=n,this.buildOutputPath=i??m(e.directory,".shopify","dev-bundle"),this.options={stdout:process.stdout,stderr:process.stderr,signal:new C},this.fileWatcher=s}async start(e,n=!0){this.started||(this.started=!0,this.options=e??this.options,await T(this.buildOutputPath)&&await b(this.buildOutputPath,{force:!0}),await g(this.buildOutputPath),n&&(this.initialEvents=this.app.realExtensions.map(i=>({type:"changed",extension:i})),await this.buildExtensions(this.initialEvents)),this.fileWatcher=this.fileWatcher??new I(this.app,this.options),this.fileWatcher.onChange(i=>{z(i,this.app,this.options).then(async s=>{if(s?.extensionEvents.length===0&&l("Change detected, but no extensions were affected"),!s)return;this.app=s.app,s.appWasReloaded&&this.fileWatcher?.updateApp(this.app),await this.rescanImports(s);let r=s.extensionEvents.filter(a=>a.type!=="deleted");await this.buildExtensions(r),s.appWasReloaded||await this.app.generateExtensionTypes(),await this.deleteExtensionsBuildOutput(s),this.emit("all",s)}).catch(s=>{this.emit("error",s)})}),await this.fileWatcher.start(),this.ready=!0,this.emit("ready",{app:this.app,extensionEvents:this.initialEvents}))}onEvent(e){return this.addListener("all",e),this}onStart(e){if(this.ready){let n={app:this.app,extensionEvents:this.initialEvents,startTime:[0,0],path:""};e(n)?.catch(()=>{})}else this.once("ready",e);return this}onError(e){return this.addListener("error",e),this}async deleteExtensionsBuildOutput(e){let i=e.extensionEvents.filter(s=>s.type==="deleted").map(s=>s.extension).map(async s=>{let r=m(this.buildOutputPath,s.getOutputFolderId());return b(r,{force:!0})});await Promise.all(i)}async buildExtensions(e){let n=D(e,r=>r.extension.uid),i=[];for(let r of Object.values(n))r.length>0&&r[0]&&i.push({extension:r[0].extension,events:r});let s=i.map(async({extension:r,events:a})=>k({outputPrefix:r.handle,stripAnsi:!1},async()=>{try{await this.buildExtension(r);let p={status:"ok",uid:r.uid};a.forEach(d=>{d.buildResult=p})}catch(p){let d=p.errors??[],c=p.message,h;if(d.length){let x=d[0];c=x?.text,h=x?.location?.file,ie(d,{kind:"error",color:!L()}).forEach(J=>{this.options.stderr.write(J)})}else this.options.stderr.write(p.message);let E={status:"error",error:c,file:h,uid:r.uid};a.forEach(x=>{x.buildResult=E})}}));return Promise.all(s)}async buildExtension(e){let n={app:this.app,stdout:this.options.stdout,stderr:this.options.stderr,useTasks:!1,environment:"development",appURL:this.appURL};await e.buildForBundle(n,this.buildOutputPath)}async rescanImports(e){if(e.path.endsWith(".toml"))return;let i=e.extensionEvents.filter(s=>s.type!=="deleted").map(s=>s.extension);i.length>0&&(await Promise.all(i.map(async a=>a.rescanImports()))).some(a=>a)&&await this.fileWatcher?.start()}};export{V as a};