Demo for query storing
Change-Id: I947bcac841992c3f6cfd01ab337c265b0d01cb70
diff --git a/node_modules/grunt-contrib-watch/tasks/lib/livereload.js b/node_modules/grunt-contrib-watch/tasks/lib/livereload.js
new file mode 100644
index 0000000..55fc098
--- /dev/null
+++ b/node_modules/grunt-contrib-watch/tasks/lib/livereload.js
@@ -0,0 +1,63 @@
+/*
+ * grunt-contrib-watch
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2018 "Cowboy" Ben Alman, contributors
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+var tinylr = require('tiny-lr');
+var _ = require('lodash');
+
+// Holds the servers out of scope in case watch is reloaded
+var servers = Object.create(null);
+
+module.exports = function(grunt) {
+
+ var defaults = {port: 35729};
+
+ function LR(options) {
+ if (options === true) {
+ options = defaults;
+ } else if (typeof options === 'number') {
+ options = {port: options};
+ } else {
+ options = _.defaults(options, defaults);
+ }
+
+ var host = (options.host || '*') + ':' + options.port;
+
+ if (servers[host]) {
+ this.server = servers[host];
+ } else {
+ this.server = tinylr(options);
+ this.server.server.removeAllListeners('error');
+ this.server.server.on('error', function(err) {
+ if (err.code === 'EADDRINUSE') {
+ grunt.fatal('Port ' + options.port + ' is already in use by another process.');
+ } else {
+ grunt.fatal(err);
+ }
+ process.exit(1);
+ });
+ this.server.listen(options.port, options.host, function(err) {
+ if (err) {
+ return grunt.fatal(err);
+ }
+ grunt.log.verbose.writeln('Live reload server started on ' + host);
+ });
+ servers[host] = this.server;
+ }
+ }
+
+ LR.prototype.trigger = function(files) {
+ grunt.log.verbose.writeln('Live reloading ' + grunt.log.wordlist(files) + '...');
+ this.server.changed({body: {files: files}});
+ };
+
+ return function(options) {
+ return new LR(options);
+ };
+};
diff --git a/node_modules/grunt-contrib-watch/tasks/lib/taskrun.js b/node_modules/grunt-contrib-watch/tasks/lib/taskrun.js
new file mode 100644
index 0000000..34d0672
--- /dev/null
+++ b/node_modules/grunt-contrib-watch/tasks/lib/taskrun.js
@@ -0,0 +1,110 @@
+/*
+ * grunt-contrib-watch
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2018 "Cowboy" Ben Alman, contributors
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+module.exports = function(grunt) {
+
+ // Create a TaskRun on a target
+ function TaskRun(target) {
+ this.name = target.name || 0;
+ this.files = target.files || [];
+ this._getConfig = target._getConfig;
+ this.options = target.options;
+ this.startedAt = false;
+ this.spawned = null;
+ this.changedFiles = Object.create(null);
+ this.spawnTaskFailure = false;
+ this.livereloadOnError = true;
+ if (typeof this.options.livereloadOnError !== 'undefined') {
+ this.livereloadOnError = this.options.livereloadOnError;
+ }
+ }
+
+ var getErrorCount = function() {
+ if (typeof grunt.fail.forever_warncount !== 'undefined') {
+ return grunt.fail.forever_warncount + grunt.fail.forever_errorcount;
+ } else {
+ return grunt.fail.warncount + grunt.fail.errorcount;
+ }
+ };
+
+ // Run it
+ TaskRun.prototype.run = function(done) {
+ var self = this;
+
+ // Dont run if already running
+ if (self.startedAt !== false) {
+ return;
+ }
+
+ // Start this task run
+ self.startedAt = Date.now();
+
+ // reset before each run
+ self.spawnTaskFailure = false;
+ self.errorsAndWarningsCount = getErrorCount();
+
+ // pull the tasks here in case they were changed by a watch event listener
+ self.tasks = self._getConfig('tasks') || [];
+ if (typeof self.tasks === 'string') {
+ self.tasks = [self.tasks];
+ }
+
+ // If no tasks just call done to trigger potential livereload
+ if (self.tasks.length < 1) {
+ return done();
+ }
+
+ if (self.options.spawn === false || self.options.nospawn === true) {
+ grunt.task.run(self.tasks);
+ done();
+ } else {
+ self.spawned = grunt.util.spawn({
+ // Spawn with the grunt bin
+ grunt: true,
+ // Run from current working dir and inherit stdio from process
+ opts: {
+ cwd: self.options.cwd.spawn,
+ stdio: 'inherit'
+ },
+ // Run grunt this process uses, append the task to be run and any cli options
+ args: self.tasks.concat(self.options.cliArgs || [])
+ }, function(err, res, code) {
+ self.spawnTaskFailure = (code !== 0);
+ if (self.options.interrupt !== true || (code !== 130 && code !== 1)) {
+ // Spawn is done
+ self.spawned = null;
+ done();
+ }
+ });
+ }
+ };
+
+ // When the task run has completed
+ TaskRun.prototype.complete = function() {
+ var time = Date.now() - this.startedAt;
+ this.startedAt = false;
+ if (this.spawned) {
+ this.spawned.kill('SIGINT');
+ this.spawned = null;
+ }
+
+ var taskFailed = this.spawnTaskFailure || (getErrorCount() > this.errorsAndWarningsCount);
+ this.errorsAndWarningsCount = getErrorCount();
+
+ // Trigger livereload if necessary
+ if (this.livereload && (this.livereloadOnError || !taskFailed)) {
+ this.livereload.trigger(Object.keys(this.changedFiles));
+ this.changedFiles = Object.create(null);
+ }
+ return time;
+ };
+
+ return TaskRun;
+};
diff --git a/node_modules/grunt-contrib-watch/tasks/lib/taskrunner.js b/node_modules/grunt-contrib-watch/tasks/lib/taskrunner.js
new file mode 100644
index 0000000..fb8c1d6
--- /dev/null
+++ b/node_modules/grunt-contrib-watch/tasks/lib/taskrunner.js
@@ -0,0 +1,387 @@
+/*
+ * grunt-contrib-watch
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2018 "Cowboy" Ben Alman, contributors
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+var path = require('path');
+var EE = require('events').EventEmitter;
+var util = require('util');
+var _ = require('lodash');
+var async = require('async');
+
+// Track which targets to run after reload
+var reloadTargets = [];
+
+// A default target name for config where targets are not used (keep this unique)
+var defaultTargetName = '_$_default_$_';
+
+module.exports = function(grunt) {
+
+ var TaskRun = require('./taskrun')(grunt);
+ var livereload = require('./livereload')(grunt);
+
+ function Runner() {
+ EE.call(this);
+ // Name of the task
+ this.name = 'watch';
+ // Options for the runner
+ this.options = {};
+ // Function to close the task
+ this.done = function() {};
+ // Targets available to task run
+ this.targets = Object.create(null);
+ // The queue of task runs
+ this.queue = [];
+ // Whether we're actively running tasks
+ this.running = false;
+ // If a nospawn task has ran (and needs the watch to restart)
+ this.nospawn = false;
+ // Set to true before run() to reload task
+ this.reload = false;
+ // For re-queuing arguments with the task that originally ran this
+ this.nameArgs = [];
+ // A list of changed files to feed to task runs for livereload
+ this.changedFiles = Object.create(null);
+ }
+ util.inherits(Runner, EE);
+
+ // Init a task for taskrun
+ Runner.prototype.init = function init(name, defaults, done) {
+ var self = this;
+
+ self.name = name || grunt.task.current.name || 'watch';
+ self.options = self._options(grunt.config([self.name, 'options']) || {}, defaults || {});
+ self.reload = false;
+ self.nameArgs = grunt.task.current.nameArgs ? grunt.task.current.nameArgs : self.name;
+
+ // Normalize cwd option
+ if (typeof self.options.cwd === 'string') {
+ self.options.cwd = {files: self.options.cwd, spawn: self.options.cwd};
+ }
+
+ // Function to call when closing the task
+ self.done = done || grunt.task.current.async();
+
+ // If a default livereload server for all targets
+ // Use task level unless target level overrides
+ var taskLRConfig = grunt.config([self.name, 'options', 'livereload']);
+ if (self.options.target && taskLRConfig) {
+ var targetLRConfig = grunt.config([self.name, self.options.target, 'options', 'livereload']);
+ if (targetLRConfig) {
+ // Dont use task level as target level will be used instead
+ taskLRConfig = false;
+ }
+ }
+ if (taskLRConfig) {
+ self.livereload = livereload(taskLRConfig);
+ }
+
+ // Return the targets normalized
+ var targets = self._getTargets(self.name);
+
+ if (self.running) {
+ // If previously running, complete the last run
+ self.complete();
+ } else if (reloadTargets.length > 0) {
+ // If not previously running but has items in the queue, needs run
+ self.queue = reloadTargets;
+ reloadTargets = [];
+ self.run();
+ } else {
+ if (!self.hadError) {
+ // Check whether target's tasks should run at start w/ atBegin option
+ self.queue = targets.filter(function(tr) {
+ return tr.options.atBegin === true && tr.tasks.length > 0;
+ }).map(function(tr) {
+ return tr.name;
+ });
+ } else {
+ // There was an error in atBegin task, we can't re-run it, as this would
+ // create an infinite loop of failing tasks
+ // See https://github.com/gruntjs/grunt-contrib-watch/issues/169
+ self.queue = [];
+ self.hadError = false;
+ }
+ if (self.queue.length > 0) {
+ self.run();
+ }
+ }
+
+ return targets;
+ };
+
+ // Normalize targets from config
+ Runner.prototype._getTargets = function _getTargets(name) {
+ var self = this;
+
+ grunt.task.current.requiresConfig(name);
+ var config = grunt.config(name);
+ var onlyTarget = self.options.target ? self.options.target : false;
+
+ var targets = (onlyTarget ? [onlyTarget] : Object.keys(config)).filter(function(key) {
+ if (key === 'options') {
+ return false;
+ }
+ return typeof config[key] !== 'string' && !Array.isArray(config[key]);
+ }).map(function(target) {
+ // Fail if any required config properties have been omitted
+ grunt.task.current.requiresConfig([name, target, 'files']);
+ var cfg = grunt.config([name, target]);
+ cfg.name = target;
+ cfg.options = self._options(cfg.options || {}, self.options);
+ self.add(cfg);
+ return cfg;
+ }, self);
+
+ // Allow "basic" non-target format
+ if (typeof config.files === 'string' || Array.isArray(config.files)) {
+ var cfg = {
+ files: config.files,
+ tasks: config.tasks,
+ name: defaultTargetName,
+ options: self._options(config.options || {}, self.options)
+ };
+ targets.push(cfg);
+ self.add(cfg);
+ }
+
+ return targets;
+ };
+
+ // Default options
+ Runner.prototype._options = function _options() {
+ var args = Array.prototype.slice.call(arguments).concat({
+ // The cwd to spawn within
+ cwd: process.cwd(),
+ // Additional cli args to append when spawning
+ cliArgs: _.without.apply(null, [[].slice.call(process.argv, 2)].concat(grunt.cli.tasks)),
+ interrupt: false,
+ nospawn: false,
+ spawn: true,
+ atBegin: false,
+ event: ['all'],
+ target: null
+ });
+ return _.defaults.apply(_, args);
+ };
+
+ // Run the current queue of task runs
+ Runner.prototype.run = _.debounce(function run() {
+ var self = this;
+ if (self.queue.length < 1) {
+ self.running = false;
+ return;
+ }
+
+ // Re-grab task options in case they changed between runs
+ self.options = self._options(grunt.config([self.name, 'options']) || {}, self.options);
+
+ // If we should interrupt
+ if (self.running === true) {
+ var shouldInterrupt = true;
+ self.queue.forEach(function(name) {
+ var tr = self.targets[name];
+ if (tr && tr.options.interrupt !== true) {
+ shouldInterrupt = false;
+ return false;
+ }
+ });
+ if (shouldInterrupt === true) {
+ self.interrupt();
+ } else {
+ // Dont interrupt the tasks running
+ return;
+ }
+ }
+
+ // If we should reload
+ if (self.reload) {
+ return self.reloadTask();
+ }
+
+ // Trigger that tasks runs have started
+ self.emit('start');
+ self.running = true;
+
+ // Run each target
+ var shouldComplete = true;
+ async.forEachSeries(self.queue, function(name, next) {
+ var tr = self.targets[name];
+ if (!tr) {
+ return next();
+ }
+
+ // Re-grab options in case they changed between runs
+ tr.options = self._options(grunt.config([self.name, name, 'options']) || {}, tr.options, self.options);
+
+ if (tr.options.spawn === false || tr.options.nospawn === true) {
+ shouldComplete = false;
+ }
+ tr.run(next);
+ }, function() {
+ if (shouldComplete) {
+ self.complete();
+ } else {
+ grunt.task.mark().run(self.nameArgs);
+ self.done();
+ }
+ });
+ }, 250);
+
+ // Push targets onto the queue
+ Runner.prototype.add = function add(target) {
+ var self = this;
+ if (!this.targets[target.name || 0]) {
+
+ // Private method for getting latest config for a watch target
+ target._getConfig = function(name) {
+ var cfgPath = [self.name];
+ if (target.name !== defaultTargetName) {
+ cfgPath.push(target.name);
+ }
+ if (name) {
+ cfgPath.push(name);
+ }
+ return grunt.config(cfgPath);
+ };
+
+ // Create a new TaskRun instance
+ var tr = new TaskRun(target);
+
+ // Add livereload to task runs
+ // Get directly from config as task level options are merged.
+ // We only want a single default LR server and then
+ // allow each target to override their own.
+ var lrconfig = grunt.config([this.name, target.name || 0, 'options', 'livereload']);
+ if (lrconfig) {
+ tr.livereload = livereload(lrconfig);
+ } else if (this.livereload && lrconfig !== false) {
+ tr.livereload = this.livereload;
+ }
+
+ return this.targets[tr.name] = tr;
+ }
+ return false;
+ };
+
+ // Do this when queued task runs have completed/scheduled
+ Runner.prototype.complete = function complete() {
+ var self = this;
+ if (self.running === false) {
+ return;
+ }
+ self.running = false;
+ var time = 0;
+ for (var i = 0, len = self.queue.length; i < len; ++i) {
+ var name = self.queue[i];
+ var target = self.targets[name];
+ if (!target) {
+ return;
+ }
+ if (target.startedAt !== false) {
+ time += target.complete();
+ self.queue.splice(i--, 1);
+ len--;
+
+ // if we're just livereloading and no tasks
+ // it can happen too fast and we dont report it
+ if (target.options.livereload && target.tasks.length < 1) {
+ time += 0.0001;
+ }
+ }
+ }
+ var elapsed = (time > 0) ? Number(time / 1000) : 0;
+ self.changedFiles = Object.create(null);
+ self.emit('end', elapsed);
+ };
+
+ // Run through completing every target in the queue
+ Runner.prototype._completeQueue = function _completeQueue() {
+ var self = this;
+ self.queue.forEach(function(name) {
+ var target = self.targets[name];
+ if (!target) {
+ return;
+ }
+ target.complete();
+ });
+ };
+
+ // Interrupt the running tasks
+ Runner.prototype.interrupt = function interrupt() {
+ var self = this;
+ self._completeQueue();
+ grunt.task.clearQueue();
+ self.emit('interrupt');
+ };
+
+ // Attempt to make this task run forever
+ Runner.prototype.forever = function forever() {
+ var self = this;
+ function rerun() {
+ // Clear queue and rerun to prevent failing
+ self._completeQueue();
+ grunt.task.clearQueue();
+ grunt.task.run(self.nameArgs);
+ self.running = false;
+ // Mark that there was an error and we needed to rerun
+ self.hadError = true;
+ }
+ grunt.fail.forever_warncount = 0;
+ grunt.fail.forever_errorcount = 0;
+ grunt.warn = grunt.fail.warn = function(e) {
+ grunt.fail.forever_warncount ++;
+ var message = typeof e === 'string' ? e : e.message;
+ grunt.log.writeln(('Warning: ' + message).yellow);
+ if (!grunt.option('force')) {
+ rerun();
+ }
+ };
+ grunt.fatal = grunt.fail.fatal = function(e) {
+ grunt.fail.forever_errorcount ++;
+ var message = typeof e === 'string' ? e : e.message;
+ grunt.log.writeln(('Fatal error: ' + message).red);
+ rerun();
+ };
+ };
+
+ // Clear the require cache for all passed filepaths.
+ Runner.prototype.clearRequireCache = function() {
+ // If a non-string argument is passed, it's an array of filepaths, otherwise
+ // each filepath is passed individually.
+ var filepaths = typeof arguments[0] !== 'string' ? arguments[0] : Array.prototype.slice(arguments);
+ // For each filepath, clear the require cache, if necessary.
+ filepaths.forEach(function(filepath) {
+ var abspath = path.resolve(filepath);
+ if (require.cache[abspath]) {
+ grunt.verbose.write('Clearing require cache for "' + filepath + '" file...').ok();
+ delete require.cache[abspath];
+ }
+ });
+ };
+
+ // Reload this watch task, like when a Gruntfile is edited
+ Runner.prototype.reloadTask = function() {
+ var self = this;
+ // Which targets to run after reload
+ reloadTargets = self.queue;
+ self.emit('reload', reloadTargets);
+
+ // Re-init the watch task config
+ grunt.task.init([self.name]);
+
+ // Complete all running tasks
+ self._completeQueue();
+
+ // Run the watch task again
+ grunt.task.run(self.nameArgs);
+ self.done();
+ };
+
+ return new Runner();
+};
diff --git a/node_modules/grunt-contrib-watch/tasks/watch.js b/node_modules/grunt-contrib-watch/tasks/watch.js
new file mode 100644
index 0000000..8a8f8b3
--- /dev/null
+++ b/node_modules/grunt-contrib-watch/tasks/watch.js
@@ -0,0 +1,191 @@
+/*
+ * grunt-contrib-watch
+ * http://gruntjs.com/
+ *
+ * Copyright (c) 2018 "Cowboy" Ben Alman, contributors
+ * Licensed under the MIT license.
+ */
+
+'use strict';
+
+var path = require('path');
+var Gaze = require('gaze').Gaze;
+var _ = require('lodash');
+var waiting = 'Waiting...';
+var changedFiles = Object.create(null);
+var watchers = [];
+
+module.exports = function(grunt) {
+
+ var taskrun = require('./lib/taskrunner')(grunt);
+
+ // Default date format logged
+ var dateFormat = function(time) {
+ grunt.log.writeln(String(
+ 'Completed in ' +
+ time.toFixed(3) +
+ 's at ' +
+ (new Date()).toString()
+ ).cyan + ' - ' + waiting);
+ };
+
+ // When task runner has started
+ taskrun.on('start', function() {
+ Object.keys(changedFiles).forEach(function(filepath) {
+ // Log which file has changed, and how.
+ grunt.log.ok('File "' + filepath + '" ' + changedFiles[filepath] + '.');
+ });
+ // Reset changedFiles
+ changedFiles = Object.create(null);
+ });
+
+ // When task runner has ended
+ taskrun.on('end', function(time) {
+ if (time > 0) {
+ dateFormat(time);
+ }
+ });
+
+ // When a task run has been interrupted
+ taskrun.on('interrupt', function() {
+ grunt.log.writeln('').write('Scheduled tasks have been interrupted...'.yellow);
+ });
+
+ // When taskrun is reloaded
+ taskrun.on('reload', function() {
+ taskrun.clearRequireCache(Object.keys(changedFiles));
+ grunt.log.writeln('').writeln('Reloading watch config...'.cyan);
+ });
+
+ grunt.registerTask('watch', 'Run predefined tasks whenever watched files change.', function(target) {
+ var self = this;
+ var name = self.name || 'watch';
+
+ // Close any previously opened watchers
+ watchers.forEach(function(watcher) {
+ watcher.close();
+ });
+ watchers = [];
+
+ // Never gonna give you up, never gonna let you down
+ if (grunt.config([name, 'options', 'forever']) !== false) {
+ taskrun.forever();
+ }
+
+ // If a custom dateFormat function
+ var df = grunt.config([name, 'options', 'dateFormat']);
+ if (typeof df === 'function') {
+ dateFormat = df;
+ }
+
+ if (taskrun.running === false) {
+ grunt.log.writeln(waiting);
+ }
+
+ // Initialize taskrun
+ var targets = taskrun.init(name, {target: target});
+
+ targets.forEach(function(target) {
+ if (typeof target.files === 'string') {
+ target.files = [target.files];
+ }
+
+ // Process into raw patterns
+ var patterns = _.chain(target.files).flatten().map(function(pattern) {
+ return grunt.config.process(pattern);
+ }).value();
+
+ // Validate the event option
+ if (typeof target.options.event === 'string') {
+ target.options.event = [target.options.event];
+ }
+
+ var eventCwd = process.cwd();
+ if (target.options.cwd && target.options.cwd.event) {
+ eventCwd = target.options.cwd.event;
+ }
+
+ // Set cwd if options.cwd.file is set
+ if (typeof target.options.cwd !== 'string' && target.options.cwd.files) {
+ target.options.cwd = target.options.cwd.files;
+ }
+
+ // Create watcher per target
+ watchers.push(new Gaze(patterns, target.options, function(err) {
+ if (err) {
+ if (typeof err === 'string') {
+ err = new Error(err);
+ }
+ grunt.log.writeln('ERROR'.red);
+ grunt.fatal(err);
+ return taskrun.done();
+ }
+
+ // Log all watched files with --verbose set
+ if (grunt.option('verbose')) {
+ var watched = this.watched();
+ Object.keys(watched).forEach(function(watchedDir) {
+ watched[watchedDir].forEach(function(watchedFile) {
+ grunt.log.writeln('Watching ' + path.relative(process.cwd(), watchedFile) + ' for changes.');
+ });
+ });
+ }
+
+ // On changed/added/deleted
+ this.on('all', function(status, filepath) {
+
+ // Skip events not specified
+ if (!_.includes(target.options.event, 'all') &&
+ !_.includes(target.options.event, status)) {
+ return;
+ }
+
+ filepath = path.relative(eventCwd, filepath);
+
+ // Skip empty filepaths
+ if (filepath === '') {
+ return;
+ }
+
+ // If Gruntfile.js changed, reload self task
+ if (target.options.reload || /gruntfile\.(js|coffee)/i.test(filepath)) {
+ taskrun.reload = true;
+ }
+
+ // Emit watch events if anyone is listening
+ if (grunt.event.listeners('watch').length > 0) {
+ grunt.event.emit('watch', status, filepath, target.name);
+ }
+
+ // Group changed files only for display
+ changedFiles[filepath] = status;
+
+ // Add changed files to the target
+ if (taskrun.targets[target.name]) {
+ if (!taskrun.targets[target.name].changedFiles) {
+ taskrun.targets[target.name].changedFiles = Object.create(null);
+ }
+ taskrun.targets[target.name].changedFiles[filepath] = status;
+ }
+
+ // Queue the target
+ if (taskrun.queue.indexOf(target.name) === -1) {
+ taskrun.queue.push(target.name);
+ }
+
+ // Run the tasks
+ taskrun.run();
+ });
+
+ // On watcher error
+ this.on('error', function(err) {
+ if (typeof err === 'string') {
+ err = new Error(err);
+ }
+ grunt.log.error(err.message);
+ });
+ }));
+ });
+
+ });
+};