UNPKG

17.6 kBPlain TextView Raw
1#!/usr/bin/env node
2/* Copyright 2019 Ling Zhang
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License. */
15
16var t,e=(t=require("chalk"))&&"object"==typeof t&&"default"in t?t.default:t,s=require("semver"),i=require("path"),n=require("@agentframework/app"),o=require("fs"),r=require("rollup"),a=require("@agentframework/app-extras"),l=require("@agentframework/domain"),c=require("typescript"),p=require("child_process"),h=require("events");const g=require("fs-extra");function d(t,e,s){const n=i.join(t.settings.HOME_DIR,e),o=i.join(t.settings.RELEASE_DIR,s||e);return g.pathExistsSync(n)?(g.copySync(n,o),!0):!(!s||!g.pathExistsSync(i.join(t.settings.RELEASE_DIR,s)))&&(g.copySync(n,i.join(t.settings.RELEASE_DIR,s)),!0)}function u(t,e){const s=i.join(t.settings.RELEASE_DIR,"public",e);return!!g.pathExistsSync(s)&&(g.removeSync(s),!0)}const m=require("fs-extra"),y=require("fs");function S(t,e){let s={};for(let e=t.length-1;e>=0;--e)s[t[e]]=t[e];for(let t=e.length-1;t>=0;--t)s[e[t]]=e[t];let i=[];for(let t in s)s.hasOwnProperty(t)&&i.push(s[t]);return i}const f=["buffer","querystring","events","http","cluster","zlib","os","https","punycode","repl","readline","vm","child_process","url","dns","net","dgram","fs","path","string_decoder","tls","crypto","stream","util","assert","tty","domain","constants","module","process","v8","timers","console","async_hooks","http2","perf_hooks"];function E(t){const e=n.ParseJSON(n.Directory.withReadPermission(t.settings.HOME_DIR).file("package.json"));let s=f;if(e.dependencies){const t=Object.keys(e.dependencies);t.length&&(s=S(s,t))}if(e.devDependencies){const t=Object.keys(e.devDependencies);t.length&&(s=S(s,t))}for(let t=0;t<s.length;t++)if("tslib"===s[t]){s.splice(t,1);break}return s}const R=require("fs-extra"),v=require("rollup-plugin-typescript2");async function w(t,e,s,o="ES2018",r="cjs",a=!1){const l=n.ParseJSON(n.Directory.withReadPermission(t.settings.HOME_DIR).file(e)),c=i.join(t.settings.HOME_DIR,"tsconfig.release.json"),p=i.join(t.settings.HOME_DIR,"tsconfig.json");let h;h=R.pathExistsSync(c)?c:R.pathExistsSync(p)?p:"";const g={check:!1,cacheRoot:i.join(process.env.TMPDIR||"release",".rpt2_cache"),tsconfig:h,tsconfigOverride:{compilerOptions:{target:o,module:"es2015",declaration:!1}}},d={input:l.path,external:E(t),plugins:[v(g)]},u={file:i.join(t.settings.RELEASE_DIR,s),format:r,sourcemap:!0},m=l.path,y=u.file;return t.logger.info(`Building (${u.format} with ${o}) ${e} => ${s}`),{inputOptions:d,outputOptions:u,inputFile:m,outputFile:y}}function j(t,e,s){const n=i.join(t.path,e+"."+s);if(o.existsSync(n))try{return t.file(`${e}.${s}`)}catch(t){return}}class CustomApplicationSettingsLoader extends n.Resolvable{applySettings(t,e,s){if("object"!=typeof e)throw new n.InvalidSettingsFileException(t.path);const i=[];for(const t of Object.keys(e))s[t]=e[t],i.push(t);this.logger.info(`Applied ${i.length} key(s) from '${t.path}'`)}applyJsonFileSettings(t,e,s){const i=j(t,e,"json");return!!i&&(this.applySettings(i,n.ParseJSON(i),s),!0)}applyJsFileSettings(t,e,s){const i=j(t,e,"js");return!!i&&(this.applySettings(i,n.ParseJS(i),s),!0)}applyPropertiesFileSettings(t,e,s){const i=j(t,e,"properties");return!!i&&(this.applySettings(i,a.ParseProperties(i),s),!0)}applyYamlFileSettings(t,e,s){const i=j(t,e,"yaml")||j(t,e,"yml");return!!i&&(this.applySettings(i,a.ParseYAML(i),s),!0)}applyIniFileSettings(t,e,s){const i=j(t,e,"ini");return!!i&&(this.applySettings(i,a.ParseINI(i),s),!0)}applyJSON5FileSettings(t,e,s){const i=j(t,e,"json5");return!!i&&(this.applySettings(i,a.ParseJSON5(i),s),!0)}applyTypeScriptFileSettings(t,e,s){const i=j(t,e,"ts");return!!i&&(this.applySettings(i,a.ParseTypeScript(i),s),!0)}warnIgnoredSettingsFile(t,e,s){const n=i.resolve(t.path,e);this.logger.warn(`Application settings file '${n}.[${s}]' is not found, ignoring...`)}applyFileSettingsInSequence(t,e,s){this.applyJsonFileSettings(t,e,s)||this.applyJsFileSettings(t,e,s)||this.applyYamlFileSettings(t,e,s)||this.applyIniFileSettings(t,e,s)||this.applyJSON5FileSettings(t,e,s)||this.applyTypeScriptFileSettings(t,e,s)||this.applyPropertiesFileSettings(t,e,s)||this.applyJsonFileSettings(t,e,s)||this.applyJsFileSettings(t,e,s)||this.warnIgnoredSettingsFile(t,e,"yaml|yml|ini|json5|ts|properties|json|js")}loadSettings(t,e){let s;const i={};try{s=n.Directory.withReadPermission(t)}catch(t){return void this.logger.warn(`Settings folder '${t.directory}' is not found, ignoring...`)}return this.applyFileSettingsInSequence(s,"settings",i),"production"!==this.settings.CONF&&this.applyFileSettingsInSequence(s,"production",i),this.applyFileSettingsInSequence(s,e,i),this.applyFileSettingsInSequence(s,e+".local",i),i}}class CustomApplicationSettingsBuilder extends n.Resolvable{saveSettings(t,e){let s=["'use strict';"],i=null;const n=Object.keys(e).sort();for(const t of n){let n="";t[0]!==i&&(i=t[0],n="\n"),t.indexOf(".")>=0?n+=`exports["${t}"] = ${JSON.stringify(e[t])};`:n+=`exports.${t} = ${JSON.stringify(e[t])};`,s.push(n)}const r=s.join("\n");return o.writeFileSync(t,r,{encoding:"utf8"}),r}}const I=require("fs-extra");require("ts-node").register({transpileOnly:!0,compiler:function(t,e){try{return require.resolve(t,e)}catch(t){return""}}("typescript",{paths:[__dirname]})});class Compiler extends n.Application{async rollupStandalone(){const t=i.join(this.settings.HOME_DIR,"src/bin/standalone.ts");if(!o.existsSync(t))return void this.logger.warn(`ignore rollup bundle because '${t}' is not exists`);const{inputOptions:e,outputOptions:s,outputFile:n}=await w(this,"src/bin/standalone.ts","bin/standalone","ES2018"),a=await r.rollup(e);return await a.write(s),function(t,e){let s;const i={encoding:"utf8",mode:438,flags:"w"};try{s=o.readFileSync(t,i)}catch(t){s=""}o.writeFileSync(t,e+"\n"+s,i)}(n,"#!/usr/bin/env node")}async rollupServerless(){const t=i.join(this.settings.HOME_DIR,"handlers.ts");if(!o.existsSync(t))return void this.logger.warn(`ignore rollup bundle because '${t}' is not exists`);const e=this.settings.SERVERLESS;let s=this.settings.TARGET;e&&e.provider&&"nodejs8.10"===e.provider.runtime&&(s="ES2018");const{inputOptions:n,outputOptions:a}=await w(this,"handlers.ts","handlers.js",s),l=await r.rollup(n);await l.write(a)}async rollupLibrary(t){const e=t,s=i.join(this.settings.HOME_DIR,e);if(!o.existsSync(s))return void this.logger.warn(`ignore rollup cjs bundle because '${s}' is not exists`);const{inputOptions:n}=await w(this,e,"lib/index.js","ES2018","cjs",!0),a=await r.rollup(n);await a.write({file:i.join(this.settings.RELEASE_DIR,"lib/index.js"),format:"cjs",sourcemap:!0})}async buildConfiguration(t){I.ensureDirSync(i.join(this.settings.RELEASE_DIR,"conf"));const e=this.construct(CustomApplicationSettingsLoader).loadSettings(this.settings.CONF_DIR,t),s=this.construct(CustomApplicationSettingsBuilder),n=i.join(this.settings.RELEASE_DIR,"conf","settings.js");s.saveSettings(n,e),this.logger.info(`Load ${Object.keys(e).length} key(s) from ${t} and save to ${n}`)}async buildAssets(t){this.settings.PUBLIC_DIR&&I.pathExistsSync(this.settings.PUBLIC_DIR)&&(I.ensureDirSync(i.join(this.settings.RELEASE_DIR,"public")),I.copySync(this.settings.PUBLIC_DIR,i.join(this.settings.RELEASE_DIR,"public")))}async buildProject(t){if(await this.buildConfiguration(t),await this.buildAssets(t),d(this,"Dockerfile"),d(this,"COPYRIGHT"),d(this,"LICENSE"),d(this,"NOTICE"),d(this,"README.md"),d(this,"package-lock.json"),d(this,"yarn.lock"),function(t){const e=i.join(t.settings.HOME_DIR,"package.release.json"),s=i.join(t.settings.RELEASE_DIR,"package.json");if(m.pathExistsSync(e))m.copySync(e,s);else{const e=n.ParseJSON(n.Directory.withReadPermission(t.settings.HOME_DIR).file("package.json")),i={},o={name:e.name,version:e.version,engines:e.engines||{},bin:e.bin||i,description:e.description||"",author:e.author||"",main:e.main?"lib/index.js":void 0,module:e.module?"lib/index.mjs":void 0,typings:e.typings?"lib/index.d.ts":void 0,files:e.files||["lib"],dependencies:e.dependencies};o.bin===i&&delete o.bin,y.writeFileSync(s,JSON.stringify(o,null,2))}}(this),!d(this,"serverless.yml")){const e=await async function(t,e){let s={service:t.settings.NAME,package:{include:[`conf/${e}.js`]},functions:{server:{handler:"handlers.server",timeout:t.settings.SERVERLESS_TIMEOUT_IN_SECONDS,access:"public",events:[{http:{path:"",method:"get"}},{http:{path:"",method:"head"}},{http:{path:"",method:"options"}},{http:{path:"{route+}",method:"get"}},{http:{path:"{route+}",method:"head"}},{http:{path:"{route+}",method:"options"}},{http:{path:"{route+}",method:"post"}},{http:{path:"{route+}",method:"put"}},{http:{path:"{route+}",method:"delete"}}]}}};return t.settings.SERVERLESS&&Object.keys(t.settings.SERVERLESS).length&&(s=Object.assign(s,t.settings.SERVERLESS)),s}(this,t);a.DumpYAML(e,i.join(this.settings.RELEASE_DIR,"serverless.yml"))}u(this,"index.template.html"),u(this,".gitignore")}async build(t){I.removeSync(this.settings.RELEASE_DIR),I.ensureDirSync(this.settings.RELEASE_DIR);const e=require(this.settings.PACKAGE_FILE);e.main&&await this.rollupLibrary(e.main),"server"===t?await this.rollupStandalone():"serverless"===t?await this.rollupServerless():(await this.rollupStandalone(),await this.rollupServerless()),await this.buildProject("production")}}function b(t,e,s,i){var n,o=arguments.length,r=o<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,s):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,s,i);else for(var a=t.length-1;a>=0;a--)(n=t[a])&&(r=(o<3?n(r):o>3?n(e,s,r):n(e,s))||r);return o>3&&r&&Object.defineProperty(e,s,r),r}function _(t,e){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(t,e)}class CompilerSettings extends n.ApplicationSettings{constructor(){super(...arguments),this.RELEASE_DIR="release",this.TITLE="",this.PUBLIC_DIR="",this.PUBLIC_URL="",this.USE_EXTERNAL_CDN=!0,this.TARGET="ES2018",this.SERVERLESS_TIMEOUT_IN_SECONDS=30}}b([n.mandatory(),_("design:type",String)],CompilerSettings.prototype,"RELEASE_DIR",void 0),b([n.optional(),_("design:type",String)],CompilerSettings.prototype,"TITLE",void 0),b([n.optional(),_("design:type",String)],CompilerSettings.prototype,"PUBLIC_DIR",void 0),b([n.optional(),_("design:type",String)],CompilerSettings.prototype,"PUBLIC_URL",void 0),b([n.optional(),_("design:type",Boolean)],CompilerSettings.prototype,"USE_EXTERNAL_CDN",void 0),b([n.optional(),_("design:type",String)],CompilerSettings.prototype,"TARGET",void 0),b([n.optional(),_("design:type",Object)],CompilerSettings.prototype,"SERVERLESS",void 0),b([n.optional(),_("design:type",Number)],CompilerSettings.prototype,"SERVERLESS_TIMEOUT_IN_SECONDS",void 0);class Thread extends h.EventEmitter{constructor(t,e,s){super();const i=this.handler=p.fork(t,e,s);let n,o;i.unref(),this.started=new Promise(t=>{n=t}),this.stopped=new Promise(t=>{o=t}),i.on("message",t=>{this.initialized=!0,"required"===t.type&&(this.handler.removeAllListeners("message"),this.emit("start"),this.handler.send({type:"rs"}),n())}),this.handler.once("error",t=>{this.initialized=!0,console.log("fork process error exited",t),this.emit("error",t),o()}),i.once("close",t=>{this.initialized=!0,this.emit("stop",t),o()}),i.once("exit",t=>{this.initialized=!0,this.emit("stop",t),o()})}cache(t){this.initialized=!0,this.handler.send({type:"cache",value:t})}require(t){this.initialized=!0,this.handler.send({type:"require",value:t})}serve(){this.initialized=!0,this.handler.send({type:"server"})}progress(t,e){this.handler.send({type:"progress",value:{method:t,options:e}})}stop(){this.initialized=!0,this.handler.kill("SIGTERM")}}class TypeScriptProgram{constructor(t,e,s=!1,n="tsconfig.json"){this.runtimeFile=t,this.entryFile=e,this.server=s,this.currentCommand="",this.commands=[],this.thread=this.create(),this.files=new Map;const o=i.dirname(e),r=c.findConfigFile(__dirname,c.sys.fileExists,"package.json");if(!r)throw new Error('Could not find "package.json"');this.pkgPath=r;const a=c.findConfigFile(o,c.sys.fileExists,n);if(!a)throw new Error('Could not find "tsconfig.json"');this.configPath=a,this.thread.progress("info","(1/5) Load: "+a),this.sys=Object.assign({},c.sys,{writeFile:(t,e)=>{const s=t.slice(0,t.length-3)+".ts";this.files.set(s,e),3===this.phase&&this.progress("info","(3/5) Analysing...done",4),this.progress("start","(4/5) Compiling "+s)}})}create(){const t=this.thread=new Thread(this.runtimeFile,[this.entryFile],{cwd:process.cwd(),env:process.env});return t.on("start",()=>{this.started()}),t.on("error",t=>{this.stopped(t)}),t.on("stop",t=>{this.stopped(t)}),t}start(){if(this.currentCommand)return;if(this.thread&&this.thread.initialized)return;this.currentCommand="start";const t=this.thread=this.thread||this.create();for(const e of this.files.entries())t.cache(e);this.progress("info","(5/5) Executing "+this.entryFile),this.server?t.serve():t.require(this.entryFile)}started(){this.state="started",this.currentCommand="",this.next()}stop(){this.currentCommand||(this.thread?(this.currentCommand="stop",this.thread.stop()):this.stopped())}stopped(t){"started"!==this.state||this.currentCommand||12!==t&&null!==t||this.commands.push("start"),this.state="stopped",this.thread=void 0,this.currentCommand="",this.next()}progress(t,e,s){s&&(this.phase=s),this.thread&&this.thread.progress(t,e)}touch(t){"started"===this.state&&this.commands.push("stop"),t&&this.commands.push("start"),this.currentCommand||this.next()}next(){if(this.commands.length){const t=this.commands.shift();"start"===t?this.start():"stop"===t&&this.stop()}}}class TypeScriptWatcher{constructor(t){this.program=t,this.format={getCanonicalFileName:t=>t,getCurrentDirectory:c.sys.getCurrentDirectory,getNewLine:()=>c.sys.newLine}}start(){const t=c.createEmitAndSemanticDiagnosticsBuilderProgram,e=c.createWatchCompilerHost(this.program.configPath,{noEmit:!1,declaration:!1,sourceMap:!1,inlineSourceMap:!0,incremental:!0,tsBuildInfoFile:".tsbuildinfo.js"},this.program.sys,t,t=>{console.error("Compilation Error",t.code,":",c.flattenDiagnosticMessageText(t.messageText,this.format.getNewLine()))},t=>{t.code,6032===t.code&&this.program.touch(),6194===t.code&&"string"==typeof t.messageText&&t.messageText.startsWith("Found 0 errors")&&(this.program.progress("info","(4/5) Compiling...done"),setImmediate(()=>{this.program.touch(!0)}))}),s=e.createProgram;e.createProgram=((t,e,i,n)=>(this.program.progress("start","(2/5) Initializing..."),s(t,e,i,n)));const i=e.afterProgramCreate;e.afterProgramCreate=(t=>{this.program.progress("info","(2/5) Initializing...done"),this.program.progress("start","(3/5) Analysing...",3),i(t)}),this.watcher=c.createWatchProgram(e)}}const C=require("../package.json");s.satisfies(process.version,">=8")||(console.log(e.red(`You are using Node ${process.version}, but this version of @agentframework/cli `+"requires Node >=8.\nPlease upgrade your Node version.")),process.exit(1)),C&&C.version||(console.log(e.red("Package.json is not found. Please reinstall @agentframework/cli")),process.exit(1));const x=require("commander");x.version(C.version).usage("<command> [options]"),x.command("dev [file]").description("execute typescript file with incremental build and hot reload").action(t=>(function(t,s){const n=!t;if(n)try{const e=require(i.resolve(process.cwd(),"package.json"));e&&e.main?t=e.main:(console.log("Main file not found"),process.exit(1))}catch(t){console.log("Package file not found"),process.exit(1)}const r=i.isAbsolute(t)?t:i.resolve(process.cwd(),t),a=i.resolve(__dirname,s);o.existsSync(r)||(console.log("Entry file not found"),process.exit(1));const l=new TypeScriptProgram(a,r,n);console.log(e.yellow("[dev] agentframework "+require(l.pkgPath).version+", typescript "+require("typescript").version)),new TypeScriptWatcher(l).start()})(t,"../lib/index.js")),x.command("build").description("build current project").action(()=>(function(){process.env.NODE_ENV="build";const t=new l.InMemoryDomain;t.setType(n.SettingsLoader,a.ModernApplicationSettingsFileLoader);const e=t.construct(Compiler,[CompilerSettings]);return e.build().then(t=>{e.logger.info("Build project successfully"),process.exit(0)}).catch(t=>{e.logger.info(t,"Error build project"),process.exit(t.code||1)})})()),x.arguments("<command>").action(t=>{x.outputHelp(),console.log(" "+e.red(`Unknown command ${e.yellow(t)}.`)),console.log()}),x.on("--help",()=>{console.log(),console.log(` Current directory: ${process.cwd()}`),console.log(),console.log(` Run ${e.cyan("agent <command> --help")} for detailed usage of given command.`),console.log()}),x.commands.forEach(t=>t.on("--help",()=>console.log()));const O=(t,s)=>{x.Command.prototype[t]=function(...i){"unknownOption"===t&&this._allowUnknownOption||(this.outputHelp(),console.log(" "+e.red(s(...i))),console.log(),process.exit(1))}};O("missingArgument",t=>`Missing required argument ${e.yellow(`<${t}>`)}.`),O("unknownOption",t=>`Unknown option ${e.yellow(t)}.`),O("optionMissingArgument",(t,s)=>`Missing required argument for option ${e.yellow(t.flags)}`+(s?`, got ${e.yellow(s)}`:"")),x.parse(process.argv),process.argv.slice(2).length||x.outputHelp();
17//# sourceMappingURL=standalone.map