From 49860387c2a8aa4f07ad9cdaa3b277857c490704 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Tue, 16 Jul 2019 23:07:22 +0800 Subject: [PATCH 01/15] remove the old reference file --- packages/event/src/event-service.js | 600 ---------------------------- 1 file changed, 600 deletions(-) delete mode 100644 packages/event/src/event-service.js diff --git a/packages/event/src/event-service.js b/packages/event/src/event-service.js deleted file mode 100644 index 3f26fcef..00000000 --- a/packages/event/src/event-service.js +++ /dev/null @@ -1,600 +0,0 @@ -// this is the new implementation without the hash key -// only using Map and Set instead -import { - NB_EVENT_SERVICE_PRIVATE_STORE, - NB_EVENT_SERVICE_PRIVATE_LAZY -} from './store' -import genHaskKey from './hash-code.js' -// export -export default class EventService { - protected logger: any; - - /** - * class constructor - */ - constructor(config = {}) { - if (config.logger && typeof config.logger === 'function') { - this.logger = config.logger; - } - this.keep = config.keep; - this.suspend = false; - // for the $done setter - this.result = config.keep ? [] : null; - // we need to init the store first otherwise it could be a lot of checking later - this.normalStore = new Map() - this.lazyStore = new Map() - } - - /** - * logger function for overwrite - */ - logger() {} - - ////////////////////////// - // PUBLIC METHODS // - ////////////////////////// - - /** - * Register your evt handler, note we don't check the type here, - * we expect you to be sensible and know what you are doing. - * @param {string} evt name of event - * @param {function} callback bind method --> if it's array or not - * @param {object} [context=null] to execute this call in - * @return {number} the size of the store - */ - $on(evt , callback , context = null) { - const type = 'on'; - this.validate(evt, callback) - // first need to check if this evt is in lazy store - let lazyStoreContent = this.takeFromStore(evt) - // this is normal register first then call later - if (lazyStoreContent === false) { - this.logger('$on', `${evt} callback is not in lazy store`) - // @TODO we need to check if there was other listener to this - // event and are they the same type then we could solve that - // register the different type to the same event name - - return this.addToNormalStore(evt, type, callback, context) - } - this.logger('$on', `${evt} found in lazy store`) - // this is when they call $trigger before register this callback - let size = 0; - lazyStoreContent.forEach(content => { - let [ payload, ctx, t ] = content; - if (t && t !== type) { - throw new Error(`You are trying to register an event already been taken by other type: ${t}`) - } - this.run(callback, payload, context || ctx) - size += this.addToNormalStore(evt, type, callback, context || ctx) - }) - return size; - } - - /** - * once only registered it once, there is no overwrite option here - * @NOTE change in v1.3.0 $once can add multiple listeners - * but once the event fired, it will remove this event (see $only) - * @param {string} evt name - * @param {function} callback to execute - * @param {object} [context=null] the handler execute in - * @return {boolean} result - */ - $once(evt , callback , context = null) { - this.validate(evt, callback) - const type = 'once'; - let lazyStoreContent = this.takeFromStore(evt) - // this is normal register before call $trigger - let nStore = this.normalStore; - if (lazyStoreContent === false) { - this.logger('$once', `${evt} not in the lazy store`) - // v1.3.0 $once now allow to add multiple listeners - return this.addToNormalStore(evt, type, callback, context) - } else { - // now this is the tricky bit - // there is a potential bug here that cause by the developer - // if they call $trigger first, the lazy won't know it's a once call - // so if in the middle they register any call with the same evt name - // then this $once call will be fucked - add this to the documentation - this.logger('$once', lazyStoreContent) - const list = Array.from(lazyStoreContent) - // should never have more than 1 - const [ payload, ctx, t ] = list[0] - if (t && t !== type) { - throw new Error(`You are trying to register an event already been taken by other type: ${t}`) - } - this.run(callback, payload, context || ctx) - // remove this evt from store - this.$off(evt) - } - } - - /** - * This one event can only bind one callbackback - * @param {string} evt event name - * @param {function} callback event handler - * @param {object} [context=null] the context the event handler execute in - * @return {boolean} true bind for first time, false already existed - */ - $only(evt, callback, context = null) { - this.validate(evt, callback) - const type = 'only'; - let added = false; - let lazyStoreContent = this.takeFromStore(evt) - // this is normal register before call $trigger - let nStore = this.normalStore; - if (!nStore.has(evt)) { - this.logger(`$only`, `${evt} add to store`) - added = this.addToNormalStore(evt, type, callback, context) - } - if (lazyStoreContent !== false) { - // there are data store in lazy store - this.logger('$only', `${evt} found data in lazy store to execute`) - const list = Array.from(lazyStoreContent) - // $only allow to trigger this multiple time on the single handler - list.forEach( l => { - const [ payload, ctx, t ] = l; - if (t && t !== type) { - throw new Error(`You are trying to register an event already been taken by other type: ${t}`) - } - this.run(callback, payload, context || ctx) - }) - } - return added; - } - - /** - * $only + $once this is because I found a very subtile bug when we pass a - * resolver, rejecter - and it never fire because that's OLD adeed in v1.4.0 - * @param {string} evt event name - * @param {function} callback to call later - * @param {object} [context=null] exeucte context - * @return {void} - */ - $onlyOnce(evt, callback, context = null) { - this.validate(evt, callback) - const type = 'onlyOnce'; - let added = false; - let lazyStoreContent = this.takeFromStore(evt) - // this is normal register before call $trigger - let nStore = this.normalStore; - if (!nStore.has(evt)) { - this.logger(`$onlyOnce`, `${evt} add to store`) - added = this.addToNormalStore(evt, type, callback, context) - } - if (lazyStoreContent !== false) { - // there are data store in lazy store - this.logger('$onlyOnce', lazyStoreContent) - const list = Array.from(lazyStoreContent) - // should never have more than 1 - const [ payload, ctx, t ] = list[0] - if (t && t !== 'onlyOnce') { - throw new Error(`You are trying to register an event already been taken by other type: ${t}`) - } - this.run(callback, payload, context || ctx) - // remove this evt from store - this.$off(evt) - } - return added; - } - - /** - * This is a shorthand of $off + $on added in V1.5.0 - * @param {string} evt event name - * @param {function} callback to exeucte - * @param {object} [context = null] or pass a string as type - * @param {string} [type=on] what type of method to replace - * @return {} - */ - $replace(evt, callback, context = null, type = 'on') { - if (this.validateType(type)) { - this.$off(evt) - let method = this['$' + type] - return Reflect.apply(method, this, [evt, callback, context]) - } - throw new Error(`${type} is not supported!`) - } - - /** - * trigger the event - * @param {string} evt name NOT allow array anymore! - * @param {mixed} [payload = []] pass to fn - * @param {object|string} [context = null] overwrite what stored - * @param {string} [type=false] if pass this then we need to add type to store too - * @return {number} if it has been execute how many times - */ - $trigger(evt , payload = [] , context = null, type = false) { - this.validateEvt(evt) - let found = 0; - // first check the normal store - let nStore = this.normalStore; - this.logger('$trigger', nStore) - if (nStore.has(evt)) { - this.logger('$trigger', evt, 'found') - let nSet = Array.from(nStore.get(evt)) - let ctn = nSet.length; - let hasOnce = false; - let hasOnly = false; - for (let i=0; i < ctn; ++i) { - ++found; - // this.logger('found', found) - let [ _, callback, ctx, type ] = nSet[i] - this.run(callback, payload, context || ctx) - if (type === 'once' || type === 'onlyOnce') { - hasOnce = true; - } - } - if (hasOnce) { - nStore.delete(evt) - } - return found; - } - // now this is not register yet - this.addToLazyStore(evt, payload, context, type) - return found; - } - - /** - * this is an alias to the $trigger - * @NOTE breaking change in V1.6.0 we swap the parameter around - * @param {string} evt event name - * @param {*} params pass to the callback - * @param {string} type of call - * @param {object} context what context callback execute in - * @return {*} from $trigger - */ - $call(evt, params, type = false, context = null) { - let args = [evt, params] - args.push(context, type) - return Reflect.apply(this.$trigger, this, args) - } - - /** - * remove the evt from all the stores - * @param {string} evt name - * @return {boolean} true actually delete something - */ - $off(evt) { - this.validateEvt(evt) - let stores = [ this.lazyStore, this.normalStore ] - let found = false; - stores.forEach(store => { - if (store.has(evt)) { - found = true; - store.delete(evt) - } - }) - return found; - } - - /** - * return all the listener from the event - * @param {string} evtName event name - * @param {boolean} [full=false] if true then return the entire content - * @return {array|boolean} listerner(s) or false when not found - */ - $get(evt, full = false) { - this.validateEvt(evt) - let store = this.normalStore; - if (store.has(evt)) { - return this - .mapToArr(store.get(evt)) - .map((value: any, index: number, arr: any[]) => { - if (full) { - return value; - } - let [key, callback, ] = value; - return callback; - }) - } - return false; - } - - /** - * Holding off all the event firing and put them back into the lazy store - * until the suspend been lifted - * @param {string} [type=all] what type of event should be suspended - * @return {void} - */ - $suspend(type = 'all') { - this.suspend = type === 'all' ? true : this.validateType(type); - } - - /** - * Lifted the suspend - * @return {void} - */ - $resume() { - this.suspend = false; - } - - /** - * store the return result from the run - * @param {*} value whatever return from callback - */ - set $done(value) { - this.logger('set $done', value) - if (this.keep) { - this.result.push(value) - } else { - this.result = value; - } - } - - /** - * @TODO is there any real use with the keep prop? - * getter for $done - * @return {*} whatever last store result - */ - get $done() { - if (this.keep) { - this.logger(this.result) - return this.result[this.result.length - 1] - } - return this.result; - } - - ///////////////////////////// - // PRIVATE METHODS // - ///////////////////////////// - - /** - * validate the event name - * @param {string} evt event name - * @return {boolean} true when OK - */ - validateEvt(evt) { - if (typeof evt === 'string') { - return true; - } - throw new Error(`event name must be string type!`) - } - - /** - * Simple quick check on the two main parameters - * @param {string} evt event name - * @param {function} callback function to call - * @return {boolean} true when OK - */ - validate(evt, callback) { - if (this.validateEvt(evt)) { - if (typeof callback === 'function') { - return true; - } - } - throw new Error(`callback required to be function type!`) - } - - /** - * Check if this type is correct or not added in V1.5.0 - * @param {string} type for checking - * @return {boolean} true on OK - */ - validateType(type) { - const types = ['on', 'only', 'once', 'onlyOnce'] - return !!types.filter(t => type === t).length; - } - - /** - * Run the callback - * @param {function} callback function to execute - * @param {array} payload for callback - * @param {object} ctx context or null - * @return {void} the result store in $done - */ - run(callback, payload, ctx) { - this.logger('run', callback, payload, ctx) - this.$done = Reflect.apply(callback, ctx, this.toArray(payload)) - } - - /** - * Take the content out and remove it from store id by the name - * @param {string} evt event name - * @param {string} [storeName = lazyStore] name of store - * @return {object|boolean} content or false on not found - */ - takeFromStore(evt, storeName = 'lazyStore') { - let store = this[storeName]; // it could be empty at this point - if (store) { - this.logger('takeFromStore', storeName, store) - if (store.has(evt)) { - let content = store.get(evt) - this.logger('takeFromStore', content) - store.delete(evt) - return content; - } - return false; - } - throw new Error(`${storeName} is not supported!`) - } - - /** - * The add to store step is similar so make it generic for resuse - * @param {object} store which store to use - * @param {string} evt event name - * @param {spread} args because the lazy store and normal store store different things - * @return {array} store and the size of the store - */ - addToStore(store, evt, ...args) { - let fnSet; - if (store.has(evt)) { - this.logger('addToStore', `${evt} existed`) - fnSet = store.get(evt) - } else { - this.logger('addToStore', `create new Set for ${evt}`) - // this is new - fnSet = new Set() - } - // lazy only store 2 items - this is not the case in V1.6.0 anymore - // we need to check the first parameter is string or not - if (args.length > 2) { - if (Array.isArray(args[0])) { // lazy store - // check if this type of this event already register in the lazy store - let [,,t] = args; - if (!this.checkTypeInLazyStore(evt, t)) { - fnSet.add(args) - } - } else { - if (!this.checkContentExist(args, fnSet)) { - this.logger('addToStore', `insert new`, args) - fnSet.add(args) - } - } - } else { // add straight to lazy store - fnSet.add(args) - } - store.set(evt, fnSet) - return [store, fnSet.size] - } - - /** - * @param {array} args for compare - * @param {object} fnSet A Set to search from - * @return {boolean} true on exist - */ - checkContentExist(args, fnSet) { - let list = Array.from(fnSet) - return !!list.filter(l => { - let [hash,] = l; - if (hash === args[0]) { - return true; - } - return false; - }).length; - } - - /** - * get the existing type to make sure no mix type add to the same store - * @param {string} evtName event name - * @param {string} type the type to check - * @return {boolean} true you can add, false then you can't add this type - */ - checkTypeInStore(evtName, type) { - this.validateEvt(evtName) - this.validateEvt(type) - let all = this.$get(evtName, true) - if (all === false) { - // pristine it means you can add - return true; - } - // it should only have ONE type in ONE event store - return !all.filter(list => { - let [ ,,,t ] = list; - return type !== t; - }).length; - } - - /** - * This is checking just the lazy store because the structure is different - * therefore we need to use a new method to check it - */ - checkTypeInLazyStore(evtName, type) { - this.validateEvt(evtName) - this.validateEvt(type) - let store = this.lazyStore.get(evtName) - this.logger('checkTypeInLazyStore', store) - if (store) { - return !!Array - .from(store) - .filter(l => { - let [,,t] = l; - return t !== type; - }).length - } - return false; - } - - /** - * wrapper to re-use the addToStore, - * V1.3.0 add extra check to see if this type can add to this evt - * @param {string} evt event name - * @param {string} type on or once - * @param {function} callback function - * @param {object} context the context the function execute in or null - * @return {number} size of the store - */ - addToNormalStore(evt, type, callback, context = null) { - this.logger('addToNormalStore', evt, type, 'add to normal store') - // @TODO we need to check the existing store for the type first! - if (this.checkTypeInStore(evt, type)) { - this.logger(`${type} can add to ${evt} store`) - let key = this.hashFnToKey(callback) - let args = [this.normalStore, evt, key, callback, context, type] - let [_store, size] = Reflect.apply(this.addToStore, this, args) - this.normalStore = _store; - return size; - } - return false; - } - - /** - * Add to lazy store this get calls when the callback is not register yet - * so we only get a payload object or even nothing - * @param {string} evt event name - * @param {array} payload of arguments or empty if there is none - * @param {object} [context=null] the context the callback execute in - * @param {string} [type=false] register a type so no other type can add to this evt - * @return {number} size of the store - */ - addToLazyStore(evt, payload = [], context = null, type = false) { - // this is add in V1.6.0 - // when there is type then we will need to check if this already added in lazy store - // and no other type can add to this lazy store - let args = [this.lazyStore, evt, this.toArray(payload), context] - if (type) { - args.push(type) - } - let [_store, size] = Reflect.apply(this.addToStore, this, args) - this.lazyStore = _store; - return size; - } - - /** - * make sure we store the argument correctly - * @param {*} arg could be array - * @return {array} make sured - */ - toArray(arg) { - return Array.isArray(arg) ? arg : [arg]; - } - - /** - * setter to store the Set in private - * @param {object} obj a Set - */ - set normalStore(obj) { - NB_EVENT_SERVICE_PRIVATE_STORE.set(this, obj) - } - - /** - * @return {object} Set object - */ - get normalStore() { - return NB_EVENT_SERVICE_PRIVATE_STORE.get(this) - } - - /** - * setter to store the Set in lazy store - * @param {object} obj a Set - */ - set lazyStore(obj) { - NB_EVENT_SERVICE_PRIVATE_LAZY.set(this , obj) - } - - /** - * @return {object} the lazy store Set - */ - get lazyStore() { - return NB_EVENT_SERVICE_PRIVATE_LAZY.get(this) - } - - /** - * generate a hashKey to identify the function call - * The build-in store some how could store the same values! - * @param {function} fn the converted to string function - * @return {string} hashKey - */ - hashFnToKey(fn) { - return genHaskKey(fn.toString()) + ''; - } - -} -- Gitee From 604b18ae4d355f8db4bf39804cafa637805d884a Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Tue, 16 Jul 2019 23:07:31 +0800 Subject: [PATCH 02/15] init the cli project --- packages/cli/package.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 packages/cli/package.json diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 00000000..1247faa5 --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,17 @@ +{ + "name": "@jsonql/cli", + "version": "0.1.0", + "description": "Interactive cli program to setup your jsonql dev environment", + "main": "index.js", + "scripts": { + "test": "ava" + }, + "keywords": [ + "jsonql", + "cli", + "interactive", + "shell" + ], + "author": "Joel Chu ", + "license": "ISC" +} -- Gitee From 0141d00eb94009db1fa28d7883703f6ef7159702 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 20:43:17 +0800 Subject: [PATCH 03/15] Add new options to finish the @TODO in the contract-cli --- packages/contract-cli/lib/generator/files.js | 3 ++- packages/contract-cli/lib/options.js | 3 +++ packages/contract-cli/lib/public-contract/index.js | 2 +- packages/contract-console/vue.config.js | 5 ++++- packages/koa/src/lib/config-check/options.js | 3 ++- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/contract-cli/lib/generator/files.js b/packages/contract-cli/lib/generator/files.js index c7cf0491..a9482eed 100644 --- a/packages/contract-cli/lib/generator/files.js +++ b/packages/contract-cli/lib/generator/files.js @@ -123,8 +123,9 @@ const readFilesOutContract = function(inDir, config, fileType) { */ const keepOrCleanContract = function(config, dist) { // @TODO we might want to keep the file based on the configuration - if (fsx.existsSync(dist)) { + if (fsx.existsSync(dist) && config.alwaysNew === true) { debug('[@TODO] Found existing contract [%s]', dist) + return fsx.removeSync(dist) } } diff --git a/packages/contract-cli/lib/options.js b/packages/contract-cli/lib/options.js index 30e31952..0d757acf 100644 --- a/packages/contract-cli/lib/options.js +++ b/packages/contract-cli/lib/options.js @@ -52,7 +52,10 @@ const defaultOptions = { // matching the name across the project - the above two will become alias to this resolverDir: createConfig(resolve(join(BASE_DIR, DEFAULT_RESOLVER_DIR)) , STRING_TYPE, {[ALIAS_KEY]: 'inDir'}), contractDir: createConfig(resolve(join(BASE_DIR, DEFAULT_CONTRACT_DIR)), STRING_TYPE, {[ALIAS_KEY]: 'outDir'}), + // show or hide the description field in the public contract contractWithDesc: createConfig(false, [BOOLEAN_TYPE]), + // remove the old one and always create a new one - useful during development + alwaysNew: createConfig(false, [BOOLEAN_TYPE]), // where to put the public method publicMethodDir: constructConfig(PUBLIC_KEY, STRING_TYPE), // just try this with string type first diff --git a/packages/contract-cli/lib/public-contract/index.js b/packages/contract-cli/lib/public-contract/index.js index 0e10e9ba..a5d25c31 100644 --- a/packages/contract-cli/lib/public-contract/index.js +++ b/packages/contract-cli/lib/public-contract/index.js @@ -41,7 +41,7 @@ const cleanForPublic = (json, config) => { } } // don't need this in the public json - debug(json.sourceType) + // debug(json.sourceType) delete json.sourceType; // export return json; diff --git a/packages/contract-console/vue.config.js b/packages/contract-console/vue.config.js index 8725416a..591c405d 100644 --- a/packages/contract-console/vue.config.js +++ b/packages/contract-console/vue.config.js @@ -1,3 +1,6 @@ module.exports = { - lintOnSave: false + lintOnSave: false, + devServer: { + open: true + } } diff --git a/packages/koa/src/lib/config-check/options.js b/packages/koa/src/lib/config-check/options.js index 4bbe97a0..83ec9034 100755 --- a/packages/koa/src/lib/config-check/options.js +++ b/packages/koa/src/lib/config-check/options.js @@ -60,7 +60,8 @@ const appProps = { jwtTokenOption: createConfig(false, [BOOLEAN_TYPE, OBJECT_TYPE]), // add in v1.3.0 enableJsonp: createConfig(false, [BOOLEAN_TYPE]), - + // show or hide the description field in the public contract + contractWithDesc: createConfig(false, [BOOLEAN_TYPE]), keysDir: createConfig(join(dirname, DEFAULT_KEYS_DIR), [STRING_TYPE]), publicKeyFileName: createConfig(DEFAULT_PUBLIC_KEY_FILE, [STRING_TYPE]), privateKeyFileName: createConfig(DEFAULT_PRIVATE_KEY_FILE, [STRING_TYPE]), -- Gitee From 1bb544ee648981049587f46f1cb406be64a2f40d Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 21:06:36 +0800 Subject: [PATCH 04/15] Add the watch option to the cli but it should not work at the moment --- packages/contract-cli/cli.js | 13 ++++--------- packages/contract-cli/lib/watcher/watcher.js | 4 ++-- packages/contract-cli/package.json | 6 ++---- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/contract-cli/cli.js b/packages/contract-cli/cli.js index fec3f681..66866223 100755 --- a/packages/contract-cli/cli.js +++ b/packages/contract-cli/cli.js @@ -62,15 +62,6 @@ require('yargs') // we must check the inDir run('create', argv) }) - /* // @TODO - .command('remote [hostname]', 'Get public contract file from remote host', yargs => { - yargs - .positional('hostname', { - describe: 'Where to get the remote contract file' - }) - }, argv => { - run('remote', argv) - }) */ .command('config [configFile]', 'Pass a config file to execute the command', yargs => { yargs .positional('configFile', { @@ -96,4 +87,8 @@ require('yargs') describe: 'Where to save your remote contract file', alias: 'o' }) + .option('watch', { + describe: 'Enable watch mode', + alias: 'w' + }) .argv diff --git a/packages/contract-cli/lib/watcher/watcher.js b/packages/contract-cli/lib/watcher/watcher.js index 5de77d0f..277df91a 100644 --- a/packages/contract-cli/lib/watcher/watcher.js +++ b/packages/contract-cli/lib/watcher/watcher.js @@ -38,7 +38,7 @@ module.exports = function(config) { const watcher = chokidar.watch(watchPath, {}) // create a fork process const ps = fork(join(__dirname, 'run.js')) - ps.send({ config }); + ps.send({ config }) // now watch const stream = kefir.stream(emitter => { watcher.on('raw', (evt, path, details) => { @@ -60,7 +60,7 @@ module.exports = function(config) { ps.on('message', msg => { if (msg.end) { console.info(colors.green('Watcher is shutting down')) - watcher.close(); + watcher.close() } else if (msg.txt) { console.log(colors.yellow(msg.txt)) } diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index c5d0172b..ca24d646 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-contract", - "version": "1.7.4", + "version": "1.7.5", "description": "An command line tool to generate the contract.json for jsonql", "main": "index.js", "files": [ @@ -9,12 +9,10 @@ "index.js" ], "scripts": { - "build": "rollup", "dev": "DEBUG=jsonql-contract:* node ./test.js", "coverage": "nyc ava --verbose", - "cli": "DEBUG=jsonql-contract* node ./cmd.js", + "cli": "DEBUG=jsonql-contract* node ./cli.js", "test:cli": "npm run cli configFile ./tests/fixtures/cmd-config-test.js", - "test:ts": "echo '@TODO'", "test": "DEBUG=jsonql-contract:jsdoc-api ava", "test:doc": "DEBUG=jsonql-contract:* ava ./tests/contract-with-doc.test.js", "test:gen": "DEBUG=jsonql-contract:* ava ./tests/generator.test.js", -- Gitee From ebacefc77fc3d923d9547b63e8d9a662c1ece6a3 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 21:08:49 +0800 Subject: [PATCH 05/15] update all the deps --- packages/contract-cli/package.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index ca24d646..7ab93def 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -37,26 +37,26 @@ "jsonql-contract": "./cli.js" }, "dependencies": { - "acorn": "^6.1.1", - "chokidar": "^3.0.1", + "acorn": "^6.2.0", + "chokidar": "^3.0.2", "colors": "^1.3.3", "fs-extra": "^8.1.0", "glob": "^7.1.4", - "jsdoc-api": "^5.0.1", + "jsdoc-api": "^5.0.2", "jsonql-constants": "^1.7.8", "jsonql-errors": "^1.0.9", "jsonql-params-validator": "^1.4.3", "kefir": "^3.8.6", - "lodash": "^4.17.11", + "lodash": "^4.17.15", "socket.io-client": "^2.2.0", "ts-node": "^8.3.0", - "typescript": "^3.5.2", - "ws": "^7.0.1", - "yargs": "^13.2.4" + "typescript": "^3.5.3", + "ws": "^7.1.0", + "yargs": "^13.3.0" }, "devDependencies": { - "@types/node": "^12.0.10", - "ava": "^2.1.0", + "@types/node": "^12.6.8", + "ava": "^2.2.0", "debug": "^4.1.1", "nyc": "^14.1.1", "request": "^2.88.0" -- Gitee From 5920ba7db64a86479363dfe9a2fbeda10a8d8461 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 21:33:26 +0800 Subject: [PATCH 06/15] Adding the watcher to the chain --- packages/contract-cli/cli.js | 14 +++++++++----- packages/contract-cli/index.js | 9 +++++++-- packages/contract-cli/lib/index.js | 6 +++++- packages/contract-cli/lib/utils.js | 12 ++++++------ packages/contract-cli/lib/watcher/watcher.js | 4 ++-- packages/contract-cli/package.json | 2 +- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/packages/contract-cli/cli.js b/packages/contract-cli/cli.js index 66866223..b810b8bb 100755 --- a/packages/contract-cli/cli.js +++ b/packages/contract-cli/cli.js @@ -5,7 +5,13 @@ const { version } = require('./package.json') * Using Jsdoc-api to generate our contract file * https://www.npmjs.com/package/jsdoc-api */ -const { applyDefaultOptions, generator, getPaths, checkFile } = require('./lib') +const { + applyDefaultOptions, + generator, + getPaths, + checkFile, + watcher +} = require('./lib') const { KEY_WORD } = require('jsonql-constants') const { join } = require('path') const debug = require('debug')('jsonql-contract:cli') @@ -28,12 +34,10 @@ const run = (cmd, argv) => { )) .then( ({result, config}) => ( - result.then(dist => ( - checkFile(config)(dist) - ) - ) + result.then(dist => checkFile(config)(dist)) ) ) + .then(watcher) .catch(err => { console.error('json:ql contract-cli error!', err) }) diff --git a/packages/contract-cli/index.js b/packages/contract-cli/index.js index 0b07cdd1..bcda3614 100755 --- a/packages/contract-cli/index.js +++ b/packages/contract-cli/index.js @@ -2,7 +2,8 @@ const { applyDefaultOptions, generator, - getPaths + getPaths, + watcher } = require('./lib') const { KEY_WORD } = require('jsonql-constants') // const debug = require('debug')('jsonql-contract:api'); @@ -10,6 +11,10 @@ const { KEY_WORD } = require('jsonql-constants') module.exports = function(config) { return applyDefaultOptions(config) .then( - opts => getPaths(opts).then(generator) + opts => getPaths(opts).then(generator).then(opts => opts) ) + .then(watcher) + .catch(err => { + console.error(`An error has occured`, err) + }) } diff --git a/packages/contract-cli/lib/index.js b/packages/contract-cli/lib/index.js index 7700c8ac..c1b06e86 100755 --- a/packages/contract-cli/lib/index.js +++ b/packages/contract-cli/lib/index.js @@ -1,10 +1,14 @@ const generator = require('./generator') const getPaths = require('./get-paths') const { checkFile, applyDefaultOptions } = require('./utils') +// export watcher +const watcher = require('./watcher') + // main module.exports = { applyDefaultOptions, generator, getPaths, - checkFile + checkFile, + watcher } diff --git a/packages/contract-cli/lib/utils.js b/packages/contract-cli/lib/utils.js index 838efc15..91083369 100644 --- a/packages/contract-cli/lib/utils.js +++ b/packages/contract-cli/lib/utils.js @@ -85,21 +85,21 @@ const applyDefaultOptions = (config, cmd = false) => ( /** * create a message to tell the user where the file is * @param {object} config clean supply - * @return {function} accept dist param + * @return {function} accept dist param --> return config */ const checkFile = config => { return dist => { if (config.returnAs === 'file') { - if (fsx.existsSync(dist)) { - return console.info('Your contract file generated in: %s', dist) - } - debug(dist) - throw new JsonqlError('File is not generated!', dist) + if (!fsx.existsSync(dist)) { + throw new JsonqlError('File is not generated!', dist) + } + console.info('Your contract file generated in: %s', dist) } else { if (!isObject(dist)) { throw new JsonqlError('Contract json not in the correct format!') } } + return config; // now keep returning the config for next op } } diff --git a/packages/contract-cli/lib/watcher/watcher.js b/packages/contract-cli/lib/watcher/watcher.js index 277df91a..e15067be 100644 --- a/packages/contract-cli/lib/watcher/watcher.js +++ b/packages/contract-cli/lib/watcher/watcher.js @@ -23,7 +23,7 @@ const isEnable = config => { return join( config.resolverDir, '**', ['*', ext].join('.')) } return false; -}; +} /** * main interface @@ -33,7 +33,7 @@ const isEnable = config => { module.exports = function(config) { let watchPath; if ((watchPath = isEnable(config)) !== false) { - debug('watch this', watchPath); + debug('watch this', watchPath) // create the watcher const watcher = chokidar.watch(watchPath, {}) // create a fork process diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index 7ab93def..17843bd5 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-contract", - "version": "1.7.5", + "version": "1.8.0", "description": "An command line tool to generate the contract.json for jsonql", "main": "index.js", "files": [ -- Gitee From ac3d760d15aa095fb3b69b0f7484613d785f583b Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 21:37:56 +0800 Subject: [PATCH 07/15] adding the watcher broken something --- packages/contract-cli/index.js | 5 +++-- packages/contract-cli/tests/config-params.test.js | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contract-cli/index.js b/packages/contract-cli/index.js index bcda3614..a07b04df 100755 --- a/packages/contract-cli/index.js +++ b/packages/contract-cli/index.js @@ -11,9 +11,10 @@ const { KEY_WORD } = require('jsonql-constants') module.exports = function(config) { return applyDefaultOptions(config) .then( - opts => getPaths(opts).then(generator).then(opts => opts) + opts => getPaths(opts) + .then(generator) + .then(opts => watcher(opts)) ) - .then(watcher) .catch(err => { console.error(`An error has occured`, err) }) diff --git a/packages/contract-cli/tests/config-params.test.js b/packages/contract-cli/tests/config-params.test.js index bed7c744..09b87353 100644 --- a/packages/contract-cli/tests/config-params.test.js +++ b/packages/contract-cli/tests/config-params.test.js @@ -23,7 +23,6 @@ const config = { test.before(async t => { t.context.result = await contractApi(config) - // debug(t.context.result); t.context.publicContract = await contractApi(extend(config, {public: true})) }) -- Gitee From a708862046589ee7ba5d2b73823998f5c2befd51 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 21:54:57 +0800 Subject: [PATCH 08/15] Fix the problem cause by adding watcher option --- packages/contract-cli/index.js | 7 ++++++- packages/contract-cli/lib/generator/es-extra.js | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/contract-cli/index.js b/packages/contract-cli/index.js index a07b04df..c5146a0b 100755 --- a/packages/contract-cli/index.js +++ b/packages/contract-cli/index.js @@ -13,7 +13,12 @@ module.exports = function(config) { .then( opts => getPaths(opts) .then(generator) - .then(opts => watcher(opts)) + .then(result => { + // let the watcher run + watcher(opts) + // always return the result for the next op + return result; + }) ) .catch(err => { console.error(`An error has occured`, err) diff --git a/packages/contract-cli/lib/generator/es-extra.js b/packages/contract-cli/lib/generator/es-extra.js index 6d387d7f..30f3fb61 100644 --- a/packages/contract-cli/lib/generator/es-extra.js +++ b/packages/contract-cli/lib/generator/es-extra.js @@ -86,7 +86,7 @@ const createResolverListFile = (contract, resolverDir) => { * @return {void} nothing */ module.exports = function postProcess(sourceType, resolverDir, contract) { - debug(sourceType, resolverDir) + debug('postProcess: sourceType:', sourceType, resolverDir) if (sourceType === MODULE_TYPE) { let src = join(__dirname , IMPORT_JS_TEMPLATE) let dist = join(resolverDir, DEFAULT_RESOLVER_IMPORT_FILE_NAME) -- Gitee From 685e4025dd8950dd55ffaae576062f6a5e7ddde6 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 22:04:10 +0800 Subject: [PATCH 09/15] remove the -w flag --- packages/contract-cli/tests/cmd.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contract-cli/tests/cmd.test.js b/packages/contract-cli/tests/cmd.test.js index 0b11c16f..84dd2362 100644 --- a/packages/contract-cli/tests/cmd.test.js +++ b/packages/contract-cli/tests/cmd.test.js @@ -25,9 +25,9 @@ test.cb('It should able to call the cmd and have correct output', t => { cliFile, 'create', inDir, - outDir, - '-w', - true + outDir + // '-w', + // true ]) t.plan(1) -- Gitee From 5b7157d3f809b9465c92a3717ddc5c61d373d1e4 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 22:06:21 +0800 Subject: [PATCH 10/15] Fix all the old test now try the new --- packages/contract-cli/tests/cmd.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contract-cli/tests/cmd.test.js b/packages/contract-cli/tests/cmd.test.js index 84dd2362..39e7b915 100644 --- a/packages/contract-cli/tests/cmd.test.js +++ b/packages/contract-cli/tests/cmd.test.js @@ -17,8 +17,8 @@ const cliFile = resolve(join(__dirname, '..' , 'cli.js')) test.after(t => { fsx.removeSync(join(outDir, DEFAULT_CONTRACT_FILE_NAME)) - // fsx.removeSync(configTestFile) -}); + fsx.removeSync(configTestFile) +}) test.cb('It should able to call the cmd and have correct output', t => { t.context.ps = spawn('node', [ -- Gitee From f6911082fe4674114d98c24cfb7812a2670a178e Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 22:09:04 +0800 Subject: [PATCH 11/15] update the clean up method post test --- packages/contract-cli/tests/cmd.test.js | 9 +++------ packages/contract-cli/tests/custom-login.test.js | 3 +-- packages/contract-cli/tests/extra-props.test.js | 7 +++---- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/contract-cli/tests/cmd.test.js b/packages/contract-cli/tests/cmd.test.js index 39e7b915..cd5fd870 100644 --- a/packages/contract-cli/tests/cmd.test.js +++ b/packages/contract-cli/tests/cmd.test.js @@ -16,8 +16,7 @@ const cliFile = resolve(join(__dirname, '..' , 'cli.js')) test.after(t => { - fsx.removeSync(join(outDir, DEFAULT_CONTRACT_FILE_NAME)) - fsx.removeSync(configTestFile) + fsx.removeSync( outDir ) }) test.cb('It should able to call the cmd and have correct output', t => { @@ -26,19 +25,17 @@ test.cb('It should able to call the cmd and have correct output', t => { 'create', inDir, outDir - // '-w', - // true ]) t.plan(1) t.context.ps.stdout.on('data', data => { debug('stdout: ', data.toString()) - }); + }) t.context.ps.stderr.on('data', data => { debug('stderr: ', data.toString()) - }); + }) t.context.ps.on('close', code => { debug(`(1) Exited with ${code}`) diff --git a/packages/contract-cli/tests/custom-login.test.js b/packages/contract-cli/tests/custom-login.test.js index 41dacd29..9ab87ac1 100644 --- a/packages/contract-cli/tests/custom-login.test.js +++ b/packages/contract-cli/tests/custom-login.test.js @@ -26,8 +26,7 @@ test.before(async t => { }) test.after(async t => { - fsx.removeSync(baseContractFile) - fsx.removeSync(publicContractFile) + fsx.removeSync(contractDir) }) test('It should able to pick up the customLogin method instead of login', t => { diff --git a/packages/contract-cli/tests/extra-props.test.js b/packages/contract-cli/tests/extra-props.test.js index 7f57e9da..35c5b5ee 100644 --- a/packages/contract-cli/tests/extra-props.test.js +++ b/packages/contract-cli/tests/extra-props.test.js @@ -21,12 +21,11 @@ test.before(async t => { enableAuth: true }) t.context.json = fsx.readJsonSync(baseContractFile) -}); +}) test.after(async t => { - fsx.removeSync(baseContractFile); - fsx.removeSync(publicContractFile); -}); + fsx.removeSync(contractDir) +}) test('Should able to pass the extraContractProps option and read it back', async t => { t.is(true, t.context.json.socketServerType === 'socket.io') -- Gitee From 61a87b0effc35f413c52cb444789d07bc1a3ad8e Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 22:46:25 +0800 Subject: [PATCH 12/15] update the watcher internal --- packages/contract-cli/lib/watcher/run.js | 16 ++++-- packages/contract-cli/lib/watcher/watcher.js | 30 +++++++---- packages/contract-cli/tests/watch.test.js | 57 ++++++++++++++++++-- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/packages/contract-cli/lib/watcher/run.js b/packages/contract-cli/lib/watcher/run.js index 1c5cb49e..400ce0cd 100644 --- a/packages/contract-cli/lib/watcher/run.js +++ b/packages/contract-cli/lib/watcher/run.js @@ -1,16 +1,24 @@ // this will get call to run the generator const generator = require('../generator') -const socketClient = require('./socket') -const debug = require('debug')('jsonql-contract:watcher:run') +// forget the socket client for now +// const socketClient = require('./socket') +// const debug = require('debug')('jsonql-contract:watcher:run') -let fn, config; +// let fn, config; process.on('message', m => { + if (m.change && m.config) { + generator(config) + .then(result => { + process.send({ result }) + }) + } + /* if (m.config) { config = m.config; fn = socketClient(m.config) } else { - generator(config) fn(m) } + */ }) diff --git a/packages/contract-cli/lib/watcher/watcher.js b/packages/contract-cli/lib/watcher/watcher.js index e15067be..bcc14395 100644 --- a/packages/contract-cli/lib/watcher/watcher.js +++ b/packages/contract-cli/lib/watcher/watcher.js @@ -28,27 +28,36 @@ const isEnable = config => { /** * main interface * @param {object} config clean options - * @return {void} + * @return {boolean | function} false if it's not enable */ module.exports = function(config) { let watchPath; if ((watchPath = isEnable(config)) !== false) { - debug('watch this', watchPath) + debug('watching this', watchPath) // create the watcher const watcher = chokidar.watch(watchPath, {}) + + const closeFn = () => watcher.close() + // create a fork process const ps = fork(join(__dirname, 'run.js')) - ps.send({ config }) + // modify the config to make sure the contract file(s) get clean + config.alwaysNew = true; + // kick start the process + // ps.send({ config }) // now watch const stream = kefir.stream(emitter => { - watcher.on('raw', (evt, path, details) => { + watcher.on('change', (evt, path, details) => { ++counter; debug(`(${counter}) got even here`, evt, path, details) - emitter.emit({evt, path, details}) - }); + emitter.emit({ + change: true, + config + }) + }) // call exit - return () => watcher.close() - }); + return closeFn; + }) stream.throttle(config.interval).observe({ value(value) { @@ -56,7 +65,7 @@ module.exports = function(config) { } }) - // we can remotely shut it down + // we can remotely shut it down - when using the socket option ps.on('message', msg => { if (msg.end) { console.info(colors.green('Watcher is shutting down')) @@ -65,5 +74,8 @@ module.exports = function(config) { console.log(colors.yellow(msg.txt)) } }) + // return the close method + return closeFn; } + return false; // nothing happen } diff --git a/packages/contract-cli/tests/watch.test.js b/packages/contract-cli/tests/watch.test.js index dff2e428..14b56fdf 100644 --- a/packages/contract-cli/tests/watch.test.js +++ b/packages/contract-cli/tests/watch.test.js @@ -1,8 +1,59 @@ const test = require('ava') +const { join, resolve } = require('path') +const { spawn } = require('child_process') +const fsx = require('fs-extra') +const { DEFAULT_CONTRACT_FILE_NAME } = require('jsonql-constants') -test.todo("It should able to watch the folder of files change") +const cliFile = resolve(join(__dirname, '..' , 'cli.js')) +const contractApi = require('../index') -test.todo("It should able to generate a new contract file") +const debug = require('debug')('jsonql-contract:test:watcher') -test.todo("It should able to call a socket end point to announce the change") +const srcDir = resolve(join(__dirname, 'fixtures', 'resolvers')) +const baseDir = resolve(join(__dirname, 'fixtures', 'tmp', 'watcher')) +const outDir = join(baseDir, 'contract') + +const srcFile = join(srcDir, 'mutation', 'set-with-destruction.js') + + +// first we copy everything from the resolvers directory to the outDir +// because we need to change the files +test.before( async t => { + const inDir = join(baseDir, 'resolvers') + await fsx.copy(srcDir, inDir) + t.context.inDir = inDir; + t.context.outDir = outDir; + // we remove one file from the folder then add it back later + fsx.removeSync( join(inDir, 'mutation', 'set-with-destruction.js') ) + + // first generate the contract file + t.context.result = await contractApi({ + resolverDir: inDir, + contractDir: outDir, + watch: true, + returnAs: 'json', + enableAuth: true + }) +}) + +test.after( async t => { + fsx.removeSync( baseDir ) +}) + +test.cb("It should able to watch the folder of files change", t => { + t.plan(1) + + t.falsy( t.context.result.mutation.setWithDestruction , 'It should not have a mutation.setDestruction method') + t.end() +}) + +test.todo('Using the cli should able to do the same thing') + + + +// this is really just the same as above +// test.todo("It should able to generate a new contract file") + +// this is not going to be in this release +// test.todo("It should able to call a socket end point to announce the change") -- Gitee From cc7e2cff651b44172a265c12d5c820a34f153721 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 22:56:39 +0800 Subject: [PATCH 13/15] watch is not working yet --- packages/contract-cli/tests/watch.test.js | 29 +++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/contract-cli/tests/watch.test.js b/packages/contract-cli/tests/watch.test.js index 14b56fdf..cc4dcf78 100644 --- a/packages/contract-cli/tests/watch.test.js +++ b/packages/contract-cli/tests/watch.test.js @@ -15,7 +15,7 @@ const baseDir = resolve(join(__dirname, 'fixtures', 'tmp', 'watcher')) const outDir = join(baseDir, 'contract') const srcFile = join(srcDir, 'mutation', 'set-with-destruction.js') - +const destFile = join(baseDir, 'resolvers', 'mutation', 'set-with-destruction.js') // first we copy everything from the resolvers directory to the outDir // because we need to change the files @@ -25,7 +25,7 @@ test.before( async t => { t.context.inDir = inDir; t.context.outDir = outDir; // we remove one file from the folder then add it back later - fsx.removeSync( join(inDir, 'mutation', 'set-with-destruction.js') ) + fsx.removeSync( destFile ) // first generate the contract file t.context.result = await contractApi({ @@ -42,10 +42,31 @@ test.after( async t => { }) test.cb("It should able to watch the folder of files change", t => { - t.plan(1) + t.plan(2) t.falsy( t.context.result.mutation.setWithDestruction , 'It should not have a mutation.setDestruction method') - t.end() + + setTimeout(() => { + // put the file back + fsx.copy(srcFile, destFile, (err) => { + if (err) { + console.error(err) + t.end() + return; + } + // wait a bit for the file to get generated + setTimeout(() => { + const json = fsx.readJsonSync( join(outDir, 'contract.json') ) + + t.truthy( json.mutation.setWithDestruction, 'Now it should have the setWithDestruction method' ) + t.end() + }, 1000) + + }) + }, 500) + + + }) test.todo('Using the cli should able to do the same thing') -- Gitee From 6bc96b3ddf290da46e4dbecb9ad22f0183b4d995 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Fri, 19 Jul 2019 23:02:01 +0800 Subject: [PATCH 14/15] unable to pass the -w option --- packages/contract-cli/cli.js | 7 ++----- packages/contract-cli/package.json | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/contract-cli/cli.js b/packages/contract-cli/cli.js index b810b8bb..9ec5386f 100755 --- a/packages/contract-cli/cli.js +++ b/packages/contract-cli/cli.js @@ -87,12 +87,9 @@ require('yargs') alias: 'r', default: false }) - .option('out', { - describe: 'Where to save your remote contract file', - alias: 'o' - }) .option('watch', { describe: 'Enable watch mode', - alias: 'w' + alias: 'w', + default: false }) .argv diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index 17843bd5..dcbcce7b 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -12,6 +12,7 @@ "dev": "DEBUG=jsonql-contract:* node ./test.js", "coverage": "nyc ava --verbose", "cli": "DEBUG=jsonql-contract* node ./cli.js", + "cli:watch": "npm run cli -- create ./tests/fixtures/resolvers ./tests/fixtures/tmp -w", "test:cli": "npm run cli configFile ./tests/fixtures/cmd-config-test.js", "test": "DEBUG=jsonql-contract:jsdoc-api ava", "test:doc": "DEBUG=jsonql-contract:* ava ./tests/contract-with-doc.test.js", -- Gitee From 0ee83ad91571df45f0f7733426b0d035e7b467a5 Mon Sep 17 00:00:00 2001 From: Joel Chu Date: Sat, 20 Jul 2019 10:11:54 +0800 Subject: [PATCH 15/15] Just pack this up and release it and test it real env --- packages/contract-cli/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index dcbcce7b..15b6c8bd 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-contract", - "version": "1.8.0", + "version": "1.7.5", "description": "An command line tool to generate the contract.json for jsonql", "main": "index.js", "files": [ @@ -12,7 +12,7 @@ "dev": "DEBUG=jsonql-contract:* node ./test.js", "coverage": "nyc ava --verbose", "cli": "DEBUG=jsonql-contract* node ./cli.js", - "cli:watch": "npm run cli -- create ./tests/fixtures/resolvers ./tests/fixtures/tmp -w", + "cli:watch": "npm run cli", "test:cli": "npm run cli configFile ./tests/fixtures/cmd-config-test.js", "test": "DEBUG=jsonql-contract:jsdoc-api ava", "test:doc": "DEBUG=jsonql-contract:* ava ./tests/contract-with-doc.test.js", -- Gitee