node_modules ignore

This commit is contained in:
2025-05-08 23:43:47 +02:00
parent e19d52f172
commit 4574544c9f
65041 changed files with 10593536 additions and 0 deletions

75
server/node_modules/node-plop/.circleci/config.yml generated vendored Normal file
View File

@@ -0,0 +1,75 @@
# This configuration was automatically generated from a CircleCI 1.0 config.
# It should include any build commands you had along with commands that CircleCI
# inferred from your project structure. We strongly recommend you read all the
# comments in this file to understand the structure of CircleCI 2.0, as the idiom
# for configuration has changed substantially in 2.0 to allow arbitrary jobs rather
# than the prescribed lifecycle of 1.0. In general, we recommend using this generated
# configuration as a reference rather than using it in production, though in most
# cases it should duplicate the execution of your original 1.0 config.
version: 2
jobs:
build:
working_directory: ~/amwmedia/node-plop
parallelism: 1
shell: /bin/bash --login
# CircleCI 2.0 does not support environment variables that refer to each other the same way as 1.0 did.
# If any of these refer to each other, rewrite them so that they don't or see https://circleci.com/docs/2.0/env-vars/#interpolating-environment-variables-to-set-other-environment-variables .
environment:
CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
CIRCLE_TEST_REPORTS: /tmp/circleci-test-results
# In CircleCI 1.0 we used a pre-configured image with a large number of languages and other packages.
# In CircleCI 2.0 you can now specify your own image, or use one of our pre-configured images.
# The following configuration line tells CircleCI to use the specified docker image as the runtime environment for you job.
# We have selected a pre-built image that mirrors the build environment we use on
# the 1.0 platform, but we recommend you choose an image more tailored to the needs
# of each job. For more information on choosing an image (or alternatively using a
# VM instead of a container) see https://circleci.com/docs/2.0/executor-types/
# To see the list of pre-built images that CircleCI provides for most common languages see
# https://circleci.com/docs/2.0/circleci-images/
docker:
- image: circleci/node:8.10.0-browsers
steps:
# Machine Setup
# If you break your build into multiple jobs with workflows, you will probably want to do the parts of this that are relevant in each
# The following `checkout` command checks out your code to your working directory. In 1.0 we did this implicitly. In 2.0 you can choose where in the course of a job your code should be checked out.
- checkout
# Prepare for artifact and test results collection equivalent to how it was done on 1.0.
# In many cases you can simplify this from what is generated here.
# 'See docs on artifact collection here https://circleci.com/docs/2.0/artifacts/'
- run: mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS
# Dependencies
# This would typically go in either a build or a build-and-test job when using workflows
# Restore the dependency cache
- restore_cache:
keys:
# This branch if available
- v1-dep-{{ .Branch }}-
# Default branch if not
- v1-dep-master-
# Any branch if there are none on the default branch - this should be unnecessary if you have your default branch configured correctly
- v1-dep-
# The following line was run implicitly in your 1.0 builds based on what CircleCI inferred about the structure of your project. In 2.0 you need to be explicit about which commands should be run. In some cases you can discard inferred commands if they are not relevant to your project.
- run: if [ -z "${NODE_ENV:-}" ]; then export NODE_ENV=test; fi
- run: export PATH="~/amwmedia/node-plop/node_modules/.bin:$PATH"
- run: npm install
# Save dependency cache
- save_cache:
key: v1-dep-{{ .Branch }}-{{ epoch }}
paths:
# This is a broad list of cache paths to include many possible development environments
# You can probably delete some of these entries
- ./node_modules
# Test
# This would typically be a build job when using workflows, possibly combined with build
# The following line was run implicitly in your 1.0 builds based on what CircleCI inferred about the structure of your project. In 2.0 you need to be explicit about which commands should be run. In some cases you can discard inferred commands if they are not relevant to your project.
- run: npm test
# Teardown
# If you break your build into multiple jobs with workflows, you will probably want to do the parts of this that are relevant in each
# Save test results
- store_test_results:
path: /tmp/circleci-test-results
# Save artifacts
- store_artifacts:
path: /tmp/circleci-artifacts
- store_artifacts:
path: /tmp/circleci-test-results

37
server/node_modules/node-plop/.eslintrc.js generated vendored Normal file
View File

@@ -0,0 +1,37 @@
const ts = {
files: ['**/*.ts'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
project: './tsconfig.json'
},
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/no-explicit-any': 0
}
};
module.exports = {
env: {
es6: true,
node: true
},
extends: 'eslint:recommended',
parserOptions: {
sourceType: 'module',
ecmaVersion: 2018
},
rules: {
'require-atomic-updates': 0,
indent: ['error', 'tab'],
quotes: ['error', 'single'],
semi: ['error', 'always']
},
overrides: [ts]
};

8
server/node_modules/node-plop/.idea/modules.xml generated vendored Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/node-plop.iml" filepath="$PROJECT_DIR$/.idea/node-plop.iml" />
</modules>
</component>
</project>

12
server/node_modules/node-plop/.idea/node-plop.iml generated vendored Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
server/node_modules/node-plop/.idea/vcs.xml generated vendored Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

21
server/node_modules/node-plop/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Andrew Worcester
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

22
server/node_modules/node-plop/README.md generated vendored Normal file
View File

@@ -0,0 +1,22 @@
Node-Plop
======
[![npm](https://img.shields.io/npm/v/node-plop.svg)](https://www.npmjs.com/package/node-plop)
[![CircleCI](https://circleci.com/gh/plopjs/node-plop/tree/master.svg?style=svg)](https://circleci.com/gh/plopjs/node-plop/tree/master)
This is an early publication of the plop core logic being removed from the CLI tool. Main purpose for this is to make it easier for others to automate code generation through processes and tools OTHER than the command line. This also makes it easier to test the code functionality of PLOP without needing to test via the CLI interface.
Once I feel comfortable that this code functions as it should. I'll be driving the plop CLI tool using node-plop.
``` javascript
const nodePlop = require('node-plop');
// load an instance of plop from a plopfile
const plop = nodePlop(`./path/to/plopfile.js`);
// get a generator by name
const basicAdd = plop.getGenerator('basic-add');
// run all the generator actions using the data specified
basicAdd.runActions({name: 'this is a test'}).then(function (results) {
// do something after the actions have run
});
```

View File

@@ -0,0 +1,77 @@
"use strict";
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = addFile;
var _path = _interopRequireDefault(require("path"));
var _del = _interopRequireDefault(require("del"));
var _commonActionUtils = require("./_common-action-utils");
var _isbinaryfile = require("isbinaryfile");
var fspp = _interopRequireWildcard(require("../fs-promise-proxy"));
async function addFile(data, cfg, plop) {
const fileDestPath = (0, _commonActionUtils.makeDestPath)(data, cfg, plop);
const {
force,
skipIfExists = false
} = cfg;
try {
// check path
let destExists = await fspp.fileExists(fileDestPath); // if we are forcing and the file already exists, delete the file
if (force === true && destExists) {
await (0, _del.default)([fileDestPath], {
force
});
destExists = false;
} // we can't create files where one already exists
if (destExists) {
if (skipIfExists) {
return `[SKIPPED] ${fileDestPath} (exists)`;
}
throw `File already exists\n -> ${fileDestPath}`;
} else {
await fspp.makeDir(_path.default.dirname(fileDestPath));
const absTemplatePath = cfg.templateFile && _path.default.resolve(plop.getPlopfilePath(), cfg.templateFile) || null;
if (absTemplatePath != null && (0, _isbinaryfile.isBinaryFileSync)(absTemplatePath)) {
const rawTemplate = await fspp.readFileRaw(cfg.templateFile);
await fspp.writeFileRaw(fileDestPath, rawTemplate);
} else {
const renderedTemplate = await (0, _commonActionUtils.getRenderedTemplate)(data, cfg, plop);
const transformedTemplate = await (0, _commonActionUtils.getTransformedTemplate)(renderedTemplate, data, cfg);
await fspp.writeFile(fileDestPath, transformedTemplate);
} // keep the executable flags
if (absTemplatePath != null) {
const sourceStats = await fspp.stat(absTemplatePath);
const destStats = await fspp.stat(fileDestPath);
const executableFlags = sourceStats.mode & (fspp.constants.S_IXUSR | fspp.constants.S_IXGRP | fspp.constants.S_IXOTH);
await fspp.chmod(fileDestPath, destStats.mode | executableFlags);
}
} // return the added file path (relative to the destination path)
return (0, _commonActionUtils.getRelativeToBasePath)(fileDestPath, plop);
} catch (err) {
(0, _commonActionUtils.throwStringifiedError)(err);
}
}

View File

@@ -0,0 +1,51 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify"));
function _default(action, {
checkPath = true,
checkAbortOnFail = true
} = {}) {
// it's not even an object, you fail!
if (typeof action !== 'object') {
return `Invalid action object: ${(0, _stringify.default)(action)}`;
}
const {
path,
abortOnFail
} = action;
if (checkPath && (typeof path !== 'string' || path.length === 0)) {
return `Invalid path "${path}"`;
} // abortOnFail is optional, but if it's provided it needs to be a Boolean
if (checkAbortOnFail && abortOnFail !== undefined && typeof abortOnFail !== 'boolean') {
return `Invalid value for abortOnFail (${abortOnFail} is not a Boolean)`;
}
if ('transform' in action && typeof action.transform !== 'function') {
return `Invalid value for transform (${typeof action.transform} is not a function)`;
}
if (action.type === 'modify' && !('pattern' in action) && !('transform' in action)) {
return 'Invalid modify action (modify must have a pattern or transform function)';
}
if ('skip' in action && typeof action.skip !== 'function') {
return `Invalid value for skip (${typeof action.skip} is not a function)`;
}
return true;
}

View File

@@ -0,0 +1,97 @@
"use strict";
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.getRenderedTemplatePath = getRenderedTemplatePath;
exports.getTemplate = getTemplate;
exports.getRenderedTemplate = getRenderedTemplate;
exports.getTransformedTemplate = getTransformedTemplate;
exports.throwStringifiedError = exports.getRelativeToBasePath = exports.makeDestPath = exports.normalizePath = void 0;
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify"));
var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
var _path = _interopRequireDefault(require("path"));
var fspp = _interopRequireWildcard(require("../fs-promise-proxy"));
const getFullData = (data, cfg) => (0, _assign.default)({}, cfg.data, data);
const normalizePath = path => {
return !path.sep || path.sep === '\\' ? path.replace(/\\/g, '/') : path;
};
exports.normalizePath = normalizePath;
const makeDestPath = (data, cfg, plop) => {
return _path.default.resolve(plop.getDestBasePath(), plop.renderString(normalizePath(cfg.path) || '', getFullData(data, cfg)));
};
exports.makeDestPath = makeDestPath;
function getRenderedTemplatePath(data, cfg, plop) {
if (cfg.templateFile) {
const absTemplatePath = _path.default.resolve(plop.getPlopfilePath(), cfg.templateFile);
return plop.renderString(normalizePath(absTemplatePath), getFullData(data, cfg));
}
return null;
}
async function getTemplate(data, cfg, plop) {
const makeTmplPath = p => _path.default.resolve(plop.getPlopfilePath(), p);
let {
template
} = cfg;
if (cfg.templateFile) {
template = await fspp.readFile(makeTmplPath(cfg.templateFile));
}
if (template == null) {
template = '';
}
return template;
}
async function getRenderedTemplate(data, cfg, plop) {
const template = await getTemplate(data, cfg, plop);
return plop.renderString(template, getFullData(data, cfg));
}
const getRelativeToBasePath = (filePath, plop) => filePath.replace(_path.default.resolve(plop.getDestBasePath()), '');
exports.getRelativeToBasePath = getRelativeToBasePath;
const throwStringifiedError = err => {
if (typeof err === 'string') {
throw err;
} else {
throw err.message || (0, _stringify.default)(err);
}
};
exports.throwStringifiedError = throwStringifiedError;
async function getTransformedTemplate(template, data, cfg) {
// transform() was already typechecked at runtime in interface check
if ('transform' in cfg) {
const result = await cfg.transform(template, data);
if (typeof result !== 'string') throw new TypeError(`Invalid return value for transform (${(0, _stringify.default)(result)} is not a string)`);
return result;
} else {
return template;
}
}

28
server/node_modules/node-plop/lib/actions/add.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _commonActionInterfaceCheck = _interopRequireDefault(require("./_common-action-interface-check"));
var _commonActionAddFile = _interopRequireDefault(require("./_common-action-add-file"));
var _commonActionUtils = require("./_common-action-utils");
async function _default(data, cfg, plop) {
const interfaceTestResult = (0, _commonActionInterfaceCheck.default)(cfg);
if (interfaceTestResult !== true) {
throw interfaceTestResult;
}
cfg.templateFile = (0, _commonActionUtils.getRenderedTemplatePath)(data, cfg, plop);
return await (0, _commonActionAddFile.default)(data, cfg, plop);
}

137
server/node_modules/node-plop/lib/actions/addMany.js generated vendored Normal file
View File

@@ -0,0 +1,137 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));
var _startsWith = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/starts-with"));
var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter"));
var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat"));
var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map"));
var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
var _path = _interopRequireDefault(require("path"));
var _fs = _interopRequireDefault(require("fs"));
var _globby = _interopRequireDefault(require("globby"));
var _commonActionInterfaceCheck = _interopRequireDefault(require("./_common-action-interface-check"));
var _commonActionAddFile = _interopRequireDefault(require("./_common-action-add-file"));
var _commonActionUtils = require("./_common-action-utils");
const defaultConfig = {
verbose: true,
stripExtensions: ['hbs']
};
async function _default(data, userConfig, plop) {
var _context, _context2;
// shallow-merge default config and input config
const cfg = (0, _assign.default)({}, defaultConfig, userConfig); // check the common action interface attributes. skip path check because it's NA
const interfaceTestResult = (0, _commonActionInterfaceCheck.default)(cfg, {
checkPath: false
});
if (interfaceTestResult !== true) {
throw interfaceTestResult;
} // check that destination (instead of path) is a string value
const dest = cfg.destination;
if (typeof dest !== 'string' || dest.length === 0) {
throw `Invalid destination "${dest}"`;
}
if (cfg.base) {
cfg.base = plop.renderString(cfg.base, data);
}
if (typeof cfg.templateFiles === 'function') {
cfg.templateFiles = cfg.templateFiles();
}
cfg.templateFiles = (0, _map.default)(_context = (0, _concat.default)(_context2 = []).call(_context2, cfg.templateFiles) // Ensure `cfg.templateFiles` is an array, even if a string is passed.
).call(_context, file => plop.renderString(file, data)); // render the paths as hbs templates
const templateFiles = resolveTemplateFiles(cfg.templateFiles, cfg.base, cfg.globOptions, plop);
const filesAdded = [];
for (let templateFile of templateFiles) {
const absTemplatePath = _path.default.resolve(plop.getPlopfilePath(), templateFile);
const fileCfg = (0, _assign.default)({}, cfg, {
path: stripExtensions(cfg.stripExtensions, resolvePath(cfg.destination, templateFile, cfg.base)),
templateFile: absTemplatePath
});
const addedPath = await (0, _commonActionAddFile.default)(data, fileCfg, plop);
filesAdded.push(addedPath);
}
const summary = `${filesAdded.length} files added`;
if (!cfg.verbose) return summary;else return `${summary}\n -> ${filesAdded.join('\n -> ')}`;
}
function resolveTemplateFiles(templateFilesGlob, basePath, globOptions, plop) {
var _context3, _context4;
globOptions = (0, _assign.default)({
cwd: plop.getPlopfilePath()
}, globOptions);
return (0, _filter.default)(_context3 = (0, _filter.default)(_context4 = _globby.default.sync(templateFilesGlob, (0, _assign.default)({
braceExpansion: false
}, globOptions))).call(_context4, isUnder(basePath))).call(_context3, isAbsoluteOrRelativeFileTo(plop.getPlopfilePath()));
}
function isAbsoluteOrRelativeFileTo(relativePath) {
const isFile = file => _fs.default.existsSync(file) && _fs.default.lstatSync(file).isFile();
return file => isFile(file) || isFile(_path.default.join(relativePath, file));
}
function isUnder(basePath = '') {
return path => (0, _startsWith.default)(path).call(path, basePath);
}
function resolvePath(destination, file, rootPath) {
return (0, _commonActionUtils.normalizePath)(_path.default.join(destination, dropFileRootPath(file, rootPath)));
}
function dropFileRootPath(file, rootPath) {
return rootPath ? file.replace(rootPath, '') : dropFileRootFolder(file);
}
function dropFileRootFolder(file) {
const fileParts = _path.default.normalize(file).split(_path.default.sep);
fileParts.shift();
return fileParts.join(_path.default.sep);
}
function stripExtensions(shouldStrip, fileName) {
var _context5;
const maybeFile = _path.default.parse(fileName);
if ((0, _isArray.default)(shouldStrip) && !(0, _includes.default)(_context5 = (0, _map.default)(shouldStrip).call(shouldStrip, item => `.${item}`)).call(_context5, maybeFile.ext)) return fileName;
return _path.default.parse(maybeFile.name).ext !== '' ? _path.default.join(maybeFile.dir, maybeFile.name) : fileName;
}

76
server/node_modules/node-plop/lib/actions/append.js generated vendored Normal file
View File

@@ -0,0 +1,76 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var fspp = _interopRequireWildcard(require("../fs-promise-proxy"));
var _commonActionUtils = require("./_common-action-utils");
var _commonActionInterfaceCheck = _interopRequireDefault(require("./_common-action-interface-check"));
const doAppend = async function (data, cfg, plop, fileData) {
const stringToAppend = await (0, _commonActionUtils.getRenderedTemplate)(data, cfg, plop); // if the appended string should be unique (default),
// remove any occurence of it (but only if pattern would match)
const {
separator = '\n'
} = cfg;
if (cfg.unique !== false) {
// only remove after "pattern", so that we remove not too much accidentally
const parts = fileData.split(cfg.pattern);
const lastPart = parts[parts.length - 1];
const lastPartWithoutDuplicates = lastPart.replace(new RegExp(separator + stringToAppend, 'g'), '');
fileData = fileData.replace(lastPart, lastPartWithoutDuplicates);
} // add the appended string to the end of the "fileData" if "pattern"
// was not provided, i.e. null or false
if (!cfg.pattern) {
// make sure to add a "separator" if "fileData" is not empty
if (fileData.length > 0) {
fileData += separator;
}
return fileData + stringToAppend;
}
return fileData.replace(cfg.pattern, '$&' + separator + stringToAppend);
};
async function _default(data, cfg, plop) {
const interfaceTestResult = (0, _commonActionInterfaceCheck.default)(cfg);
if (interfaceTestResult !== true) {
throw interfaceTestResult;
}
const fileDestPath = (0, _commonActionUtils.makeDestPath)(data, cfg, plop);
try {
// check path
const pathExists = await fspp.fileExists(fileDestPath);
if (!pathExists) {
throw 'File does not exist';
} else {
let fileData = await fspp.readFile(fileDestPath);
fileData = await doAppend(data, cfg, plop, fileData);
await fspp.writeFile(fileDestPath, fileData);
}
return (0, _commonActionUtils.getRelativeToBasePath)(fileDestPath, plop);
} catch (err) {
(0, _commonActionUtils.throwStringifiedError)(err);
}
}

45
server/node_modules/node-plop/lib/actions/index.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
_Object$defineProperty(exports, "add", {
enumerable: true,
get: function () {
return _add.default;
}
});
_Object$defineProperty(exports, "addMany", {
enumerable: true,
get: function () {
return _addMany.default;
}
});
_Object$defineProperty(exports, "modify", {
enumerable: true,
get: function () {
return _modify.default;
}
});
_Object$defineProperty(exports, "append", {
enumerable: true,
get: function () {
return _append.default;
}
});
var _add = _interopRequireDefault(require("./add"));
var _addMany = _interopRequireDefault(require("./addMany"));
var _modify = _interopRequireDefault(require("./modify"));
var _append = _interopRequireDefault(require("./append"));

53
server/node_modules/node-plop/lib/actions/modify.js generated vendored Normal file
View File

@@ -0,0 +1,53 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var fspp = _interopRequireWildcard(require("../fs-promise-proxy"));
var _commonActionUtils = require("./_common-action-utils");
var _commonActionInterfaceCheck = _interopRequireDefault(require("./_common-action-interface-check"));
async function _default(data, cfg, plop) {
const interfaceTestResult = (0, _commonActionInterfaceCheck.default)(cfg);
if (interfaceTestResult !== true) {
throw interfaceTestResult;
}
const fileDestPath = (0, _commonActionUtils.makeDestPath)(data, cfg, plop);
try {
// check path
const pathExists = await fspp.fileExists(fileDestPath);
if (!pathExists) {
throw 'File does not exist';
} else {
let fileData = await fspp.readFile(fileDestPath);
cfg.templateFile = (0, _commonActionUtils.getRenderedTemplatePath)(data, cfg, plop);
const replacement = await (0, _commonActionUtils.getRenderedTemplate)(data, cfg, plop);
if (typeof cfg.pattern === 'string' || cfg.pattern instanceof RegExp) {
fileData = fileData.replace(cfg.pattern, replacement);
}
const transformed = await (0, _commonActionUtils.getTransformedTemplate)(fileData, data, cfg);
await fspp.writeFile(fileDestPath, transformed);
}
return (0, _commonActionUtils.getRelativeToBasePath)(fileDestPath, plop);
} catch (err) {
(0, _commonActionUtils.throwStringifiedError)(err);
}
}

31
server/node_modules/node-plop/lib/baked-in-helpers.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _changeCase = _interopRequireDefault(require("change-case"));
var _default = {
camelCase: _changeCase.default.camel,
snakeCase: _changeCase.default.snake,
dotCase: _changeCase.default.dot,
pathCase: _changeCase.default.path,
lowerCase: _changeCase.default.lower,
upperCase: _changeCase.default.upper,
sentenceCase: _changeCase.default.sentence,
constantCase: _changeCase.default.constant,
titleCase: _changeCase.default.title,
dashCase: _changeCase.default.param,
kabobCase: _changeCase.default.param,
kebabCase: _changeCase.default.param,
properCase: _changeCase.default.pascal,
pascalCase: _changeCase.default.pascal
};
exports.default = _default;

54
server/node_modules/node-plop/lib/fs-promise-proxy.js generated vendored Normal file
View File

@@ -0,0 +1,54 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.constants = exports.fileExists = exports.writeFileRaw = exports.readFileRaw = exports.writeFile = exports.readFile = exports.chmod = exports.stat = exports.readdir = exports.makeDir = void 0;
var _fs = _interopRequireDefault(require("fs"));
var _mkdirp = _interopRequireDefault(require("mkdirp"));
var _util = require("util");
const _readFile = (0, _util.promisify)(_fs.default.readFile);
const _writeFile = (0, _util.promisify)(_fs.default.writeFile);
const _access = (0, _util.promisify)(_fs.default.access);
const makeDir = (0, _util.promisify)(_mkdirp.default);
exports.makeDir = makeDir;
const readdir = (0, _util.promisify)(_fs.default.readdir);
exports.readdir = readdir;
const stat = (0, _util.promisify)(_fs.default.stat);
exports.stat = stat;
const chmod = (0, _util.promisify)(_fs.default.chmod);
exports.chmod = chmod;
const readFile = path => _readFile(path, 'utf8');
exports.readFile = readFile;
const writeFile = (path, data) => _writeFile(path, data, 'utf8');
exports.writeFile = writeFile;
const readFileRaw = path => _readFile(path, null);
exports.readFileRaw = readFileRaw;
const writeFileRaw = (path, data) => _writeFile(path, data, null);
exports.writeFileRaw = writeFileRaw;
const fileExists = path => _access(path).then(() => true, () => false);
exports.fileExists = fileExists;
const constants = _fs.default.constants;
exports.constants = constants;

238
server/node_modules/node-plop/lib/generator-runner.js generated vendored Normal file
View File

@@ -0,0 +1,238 @@
'use strict';
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty2 = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty2(exports, "__esModule", {
value: true
});
exports.default = _default;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/define-property"));
var _defineProperties = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/define-properties"));
var _getOwnPropertyDescriptors = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors"));
var _getOwnPropertyDescriptor = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor"));
var _getOwnPropertySymbols = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols"));
var _reduce = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/reduce"));
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));
var _forEach = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/for-each"));
var _keys = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/keys"));
var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter"));
var _defineProperty3 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
var _entries = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/entries"));
var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
var _promptBypass = _interopRequireDefault(require("./prompt-bypass"));
var buildInActions = _interopRequireWildcard(require("./actions"));
function ownKeys(object, enumerableOnly) { var keys = (0, _keys.default)(object); if (_getOwnPropertySymbols.default) { var symbols = (0, _getOwnPropertySymbols.default)(object); if (enumerableOnly) symbols = (0, _filter.default)(symbols).call(symbols, function (sym) { return (0, _getOwnPropertyDescriptor.default)(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context3; (0, _forEach.default)(_context3 = ownKeys(source, true)).call(_context3, function (key) { (0, _defineProperty3.default)(target, key, source[key]); }); } else if (_getOwnPropertyDescriptors.default) { (0, _defineProperties.default)(target, (0, _getOwnPropertyDescriptors.default)(source)); } else { var _context4; (0, _forEach.default)(_context4 = ownKeys(source)).call(_context4, function (key) { (0, _defineProperty2.default)(target, key, (0, _getOwnPropertyDescriptor.default)(source, key)); }); } } return target; }
function _default(plopfileApi, flags) {
let abort; // triggers inquirer with the correct prompts for this generator
// returns a promise that resolves with the user's answers
const runGeneratorPrompts = async function (genObject, bypassArr = []) {
const {
prompts
} = genObject;
if (prompts == null) {
throw Error(`${genObject.name} has no prompts`);
}
if (typeof prompts === 'function') {
return await prompts(plopfileApi.inquirer);
} // handle bypass data when provided
const [promptsAfterBypass, bypassAnswers] = (0, _promptBypass.default)(prompts, bypassArr, plopfileApi);
return await plopfileApi.inquirer.prompt(promptsAfterBypass).then(answers => (0, _assign.default)(answers, bypassAnswers));
}; // Run the actions for this generator
const runGeneratorActions = async function (genObject, data = {}, hooks = {}) {
const noop = () => {};
const {
onSuccess = noop,
// runs after each successful action
onFailure = noop,
// runs after each failed action
onComment = noop // runs for each comment line in the actions array
} = hooks;
const changes = []; // array of changed made by the actions
const failures = []; // array of actions that failed
let {
actions
} = genObject; // the list of actions to execute
const customActionTypes = getCustomActionTypes();
const actionTypes = (0, _assign.default)({}, customActionTypes, buildInActions);
abort = false; // if action is a function, run it to get our array of actions
if (typeof actions === 'function') {
actions = actions(data);
} // if actions are not defined... we cannot proceed.
if (actions == null) {
throw Error(`${genObject.name} has no actions`);
} // if actions are not an array, invalid!
if (!(actions instanceof Array)) {
throw Error(`${genObject.name} has invalid actions`);
}
for (let [actionIdx, action] of (0, _entries.default)(actions).call(actions)) {
// including strings in the actions array is used for commenting
if (typeof action === 'string' && abort) {
continue;
}
if (typeof action === 'string') {
onComment(action);
continue;
}
const actionIsFunction = typeof action === 'function';
const actionCfg = actionIsFunction ? {
type: 'function'
} : action;
const actionLogic = actionIsFunction ? action : actionTypes[actionCfg.type]; // bail out if a previous action aborted
if (abort) {
const failure = {
type: actionCfg.type || '',
path: actionCfg.path || '',
error: 'Aborted due to previous action failure'
};
onFailure(failure);
failures.push(failure);
continue;
}
actionCfg.force = flags.force === true || actionCfg.force === true;
if (typeof actionLogic !== 'function') {
if (actionCfg.abortOnFail !== false) {
abort = true;
}
const failure = {
type: actionCfg.type || '',
path: actionCfg.path || '',
error: `Invalid action (#${actionIdx + 1})`
};
onFailure(failure);
failures.push(failure);
continue;
}
try {
const actionResult = await executeActionLogic(actionLogic, actionCfg, data);
onSuccess(actionResult);
changes.push(actionResult);
} catch (failure) {
if (actionCfg.abortOnFail !== false) {
abort = true;
}
onFailure(failure);
failures.push(failure);
}
}
return {
changes,
failures
};
}; // handle action logic
const executeActionLogic = async function (action, cfg, data) {
var _context;
const type = cfg.type || '';
let cfgData = cfg.data || {}; // data can also be a function that returns a data object
if (typeof cfgData === 'function') {
cfgData = await cfgData();
} // check if action should run
if (typeof cfg.skip === 'function') {
// Merge main data and config data in new object
const reasonToSkip = await cfg.skip(_objectSpread({}, data, {}, cfgData));
if (typeof reasonToSkip === 'string') {
// Return actionResult instead of string
return {
type: 'skip',
path: reasonToSkip
};
}
} // track keys that can be applied to the main data scope
const cfgDataKeys = (0, _filter.default)(_context = (0, _keys.default)(cfgData)).call(_context, k => typeof data[k] === 'undefined'); // copy config data into main data scope so it's available for templates
(0, _forEach.default)(cfgDataKeys).call(cfgDataKeys, k => {
data[k] = cfgData[k];
});
return await _promise.default.resolve(action(data, cfg, plopfileApi)).then( // show the resolved value in the console
result => ({
type,
path: typeof result === 'string' ? result : (0, _stringify.default)(result)
}), // a rejected promise is treated as a failure
err => {
throw {
type,
path: '',
error: err.message || err.toString()
};
}) // cleanup main data scope so config data doesn't leak
.finally(() => (0, _forEach.default)(cfgDataKeys).call(cfgDataKeys, k => {
delete data[k];
}));
}; // request the list of custom actions from the plopfile
function getCustomActionTypes() {
var _context2;
return (0, _reduce.default)(_context2 = plopfileApi.getActionTypeList()).call(_context2, function (types, name) {
types[name] = plopfileApi.getActionType(name);
return types;
}, {});
}
return {
runGeneratorActions,
runGeneratorPrompts
};
}

14
server/node_modules/node-plop/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _nodePlop = _interopRequireDefault(require("./node-plop"));
/**
* Main node-plop module
*
* @param {string} plopfilePath - The absolute path to the plopfile we are interested in working with
* @param {object} plopCfg - A config object to be passed into the plopfile when it's executed
* @returns {object} the node-plop API for the plopfile requested
*/
module.exports = _nodePlop.default;

310
server/node_modules/node-plop/lib/node-plop.js generated vendored Normal file
View File

@@ -0,0 +1,310 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _reduce = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/reduce"));
var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map"));
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter"));
var _forEach = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/for-each"));
var _keys = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/keys"));
var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _inquirer = _interopRequireDefault(require("inquirer"));
var _handlebars = _interopRequireDefault(require("handlebars"));
var _lodash = _interopRequireDefault(require("lodash.get"));
var _resolve = _interopRequireDefault(require("resolve"));
var _bakedInHelpers = _interopRequireDefault(require("./baked-in-helpers"));
var _generatorRunner = _interopRequireDefault(require("./generator-runner"));
function nodePlop(plopfilePath = '', plopCfg = {}) {
let pkgJson = {};
let defaultInclude = {
generators: true
};
let welcomeMessage;
const {
destBasePath,
force
} = plopCfg;
const generators = {};
const partials = {};
const actionTypes = {};
const helpers = (0, _assign.default)({
pkg: propertyPath => (0, _lodash.default)(pkgJson, propertyPath, '')
}, _bakedInHelpers.default);
const baseHelpers = (0, _keys.default)(helpers);
const setPrompt = _inquirer.default.registerPrompt;
const setWelcomeMessage = message => {
welcomeMessage = message;
};
const setHelper = (name, fn) => {
helpers[name] = fn;
};
const setPartial = (name, str) => {
partials[name] = str;
};
const setActionType = (name, fn) => {
actionTypes[name] = fn;
};
function renderString(template, data) {
var _context, _context2;
(0, _forEach.default)(_context = (0, _keys.default)(helpers)).call(_context, h => _handlebars.default.registerHelper(h, helpers[h]));
(0, _forEach.default)(_context2 = (0, _keys.default)(partials)).call(_context2, p => _handlebars.default.registerPartial(p, partials[p]));
return _handlebars.default.compile(template)(data);
}
const getWelcomeMessage = () => welcomeMessage;
const getHelper = name => helpers[name];
const getPartial = name => partials[name];
const getActionType = name => actionTypes[name];
const getGenerator = name => generators[name];
function setGenerator(name = '', config = {}) {
// if no name is provided, use a default
name = name || `generator-${(0, _keys.default)(generators).length + 1}`; // add the generator to this context
generators[name] = (0, _assign.default)(config, {
name: name,
basePath: plopfilePath
});
return generators[name];
}
const getHelperList = () => {
var _context3;
return (0, _filter.default)(_context3 = (0, _keys.default)(helpers)).call(_context3, h => !(0, _includes.default)(baseHelpers).call(baseHelpers, h));
};
const getPartialList = () => (0, _keys.default)(partials);
const getActionTypeList = () => (0, _keys.default)(actionTypes);
function getGeneratorList() {
var _context4;
return (0, _map.default)(_context4 = (0, _keys.default)(generators)).call(_context4, function (name) {
const {
description
} = generators[name];
return {
name,
description
};
});
}
const setDefaultInclude = inc => defaultInclude = inc;
const getDefaultInclude = () => defaultInclude;
const getDestBasePath = () => destBasePath || plopfilePath;
const getPlopfilePath = () => plopfilePath;
const setPlopfilePath = filePath => {
const pathStats = _fs.default.statSync(filePath);
if (pathStats.isFile()) {
plopfilePath = _path.default.dirname(filePath);
} else {
plopfilePath = filePath;
}
};
function load(targets, loadCfg = {}, includeOverride) {
if (typeof targets === 'string') {
targets = [targets];
}
const config = (0, _assign.default)({
destBasePath: getDestBasePath()
}, loadCfg);
(0, _forEach.default)(targets).call(targets, function (target) {
var _context5;
const targetPath = _resolve.default.sync(target, {
basedir: getPlopfilePath()
});
const proxy = nodePlop(targetPath, config);
const proxyDefaultInclude = proxy.getDefaultInclude() || {};
const includeCfg = includeOverride || proxyDefaultInclude;
const include = (0, _assign.default)({
generators: false,
helpers: false,
partials: false,
actionTypes: false
}, includeCfg);
const genNameList = (0, _map.default)(_context5 = proxy.getGeneratorList()).call(_context5, g => g.name);
loadAsset(genNameList, include.generators, setGenerator, proxyName => ({
proxyName,
proxy
}));
loadAsset(proxy.getPartialList(), include.partials, setPartial, proxy.getPartial);
loadAsset(proxy.getHelperList(), include.helpers, setHelper, proxy.getHelper);
loadAsset(proxy.getActionTypeList(), include.actionTypes, setActionType, proxy.getActionType);
});
}
function loadAsset(nameList, include, addFunc, getFunc) {
var incArr;
if (include === true) {
incArr = nameList;
}
if (include instanceof Array) {
incArr = (0, _filter.default)(include).call(include, n => typeof n === 'string');
}
if (incArr != null) {
include = (0, _reduce.default)(incArr).call(incArr, function (inc, name) {
inc[name] = name;
return inc;
}, {});
}
if (include instanceof Object) {
var _context6;
(0, _forEach.default)(_context6 = (0, _keys.default)(include)).call(_context6, i => addFunc(include[i], getFunc(i)));
}
}
function loadPackageJson() {
// look for a package.json file to use for the "pkg" helper
try {
pkgJson = require(_path.default.join(getDestBasePath(), 'package.json'));
} catch (error) {
pkgJson = {};
}
} /////////
// the API that is exposed to the plopfile when it is executed
// it differs from the nodePlopApi in that it does not include the
// generator runner methods
//
const plopfileApi = {
// main methods for setting and getting plop context things
setPrompt,
setWelcomeMessage,
getWelcomeMessage,
setGenerator,
getGenerator,
getGeneratorList,
setPartial,
getPartial,
getPartialList,
setHelper,
getHelper,
getHelperList,
setActionType,
getActionType,
getActionTypeList,
// path context methods
setPlopfilePath,
getPlopfilePath,
getDestBasePath,
// plop.load functionality
load,
setDefaultInclude,
getDefaultInclude,
// render a handlebars template
renderString,
// passthrough properties
inquirer: _inquirer.default,
handlebars: _handlebars.default,
// passthroughs for backward compatibility
addPrompt: setPrompt,
addPartial: setPartial,
addHelper: setHelper
}; // the runner for this instance of the nodePlop api
const runner = (0, _generatorRunner.default)(plopfileApi, {
force
});
const nodePlopApi = (0, _assign.default)({}, plopfileApi, {
getGenerator(name) {
var generator = plopfileApi.getGenerator(name);
if (generator == null) {
throw Error(`Generator "${name}" does not exist.`);
} // if this generator was loaded from an external plopfile, proxy the
// generator request through to the external plop instance
if (generator.proxy) {
return generator.proxy.getGenerator(generator.proxyName);
}
return (0, _assign.default)({}, generator, {
runActions: (data, hooks) => runner.runGeneratorActions(generator, data, hooks),
runPrompts: (bypassArr = []) => runner.runGeneratorPrompts(generator, bypassArr)
});
},
setGenerator(name, config) {
const g = plopfileApi.setGenerator(name, config);
return this.getGenerator(g.name);
}
});
if (plopfilePath) {
plopfilePath = _path.default.resolve(plopfilePath);
const plopFileName = _path.default.basename(plopfilePath);
setPlopfilePath(plopfilePath);
loadPackageJson();
const plopFileExport = require(_path.default.join(plopfilePath, plopFileName));
const plop = typeof plopFileExport === 'function' ? plopFileExport : plopFileExport.default;
plop(plopfileApi, plopCfg);
} else {
setPlopfilePath(process.cwd());
loadPackageJson();
}
return nodePlopApi;
}
var _default = nodePlop;
exports.default = _default;

218
server/node_modules/node-plop/lib/prompt-bypass.js generated vendored Normal file
View File

@@ -0,0 +1,218 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));
var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map"));
var _some = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/some"));
var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter"));
var _find = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/find"));
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
/* ========================================================================
* PROMPT BYPASSING
* -----------------
* this allows a user to bypass a prompt by supplying input before
* the prompts are run. we handle input differently depending on the
* type of prompt that's in play (ie "y" means "true" for a confirm prompt)
* ======================================================================== */
/////
// HELPER FUNCTIONS
//
// pull the "value" out of a choice option
const getChoiceValue = choice => {
const isObject = typeof choice === 'object';
if (isObject && choice.value != null) {
return choice.value;
}
if (isObject && choice.name != null) {
return choice.name;
}
if (isObject && choice.key != null) {
return choice.key;
}
return choice;
}; // check if the choice value matches the bypass value
function checkChoiceValue(choiceValue, value) {
return typeof choiceValue === 'string' && choiceValue.toLowerCase() === value.toLowerCase();
} // check if a bypass value matches some aspect of
// a particular choice option (index, value, key, etc)
function choiceMatchesValue(choice, choiceIdx, value) {
return checkChoiceValue(choice, value) || checkChoiceValue(choice.value, value) || checkChoiceValue(choice.key, value) || checkChoiceValue(choice.name, value) || checkChoiceValue(choiceIdx.toString(), value);
} // check if a value matches a particular set of flagged input options
const isFlag = (list, v) => (0, _includes.default)(list).call(list, v.toLowerCase()); // input values that represent different types of responses
const flag = {
isTrue: v => isFlag(['yes', 'y', 'true', 't'], v),
isFalse: v => isFlag(['no', 'n', 'false', 'f'], v),
isPrompt: v => /^_+$/.test(v)
}; // generic list bypass function. used for all types of lists.
// accepts value, index, or key as matching criteria
const listTypeBypass = (v, prompt) => {
var _context;
const choice = (0, _find.default)(_context = prompt.choices).call(_context, (c, idx) => choiceMatchesValue(c, idx, v));
if (choice != null) {
return getChoiceValue(choice);
}
throw Error('invalid choice');
}; /////
// BYPASS FUNCTIONS
//
// list of prompt bypass functions by prompt type
const typeBypass = {
confirm(v) {
if (flag.isTrue(v)) {
return true;
}
if (flag.isFalse(v)) {
return false;
}
throw Error('invalid input');
},
checkbox(v, prompt) {
const valList = v.split(',');
const valuesNoMatch = (0, _filter.default)(valList).call(valList, val => {
var _context2;
return !(0, _some.default)(_context2 = prompt.choices).call(_context2, (c, idx) => choiceMatchesValue(c, idx, val));
});
if (valuesNoMatch.length) {
throw Error(`no match for "${valuesNoMatch.join('", "')}"`);
}
return (0, _map.default)(valList).call(valList, val => {
var _context3;
return getChoiceValue((0, _find.default)(_context3 = prompt.choices).call(_context3, (c, idx) => choiceMatchesValue(c, idx, val)));
});
},
list: listTypeBypass,
rawlist: listTypeBypass,
expand: listTypeBypass
}; /////
// MAIN LOGIC
//
// returns new prompts, initial answers object, and any failures
function _default(prompts, bypassArr, plop) {
const noop = [prompts, {}, []]; // bail out if we don't have prompts or bypass data
if (!(0, _isArray.default)(prompts)) {
return noop;
}
if (bypassArr.length === 0) {
return noop;
} // pull registered prompts out of inquirer
const {
prompts: inqPrompts
} = plop.inquirer.prompt;
const answers = {};
const bypassFailures = []; // generate a list of pompts that the user is bypassing
const bypassedPrompts = (0, _filter.default)(prompts).call(prompts, function (p, idx) {
// if the user didn't provide value for this prompt, skip it
if (idx >= bypassArr.length) {
return false;
}
const val = bypassArr[idx].toString(); // if the user asked to be given this prompt, skip it
if (flag.isPrompt(val)) {
return false;
} // if this prompt is dynamic, throw error because we can't know if
// the pompt bypass values given line up with the path this user
// has taken through the prompt tree.
if (typeof p.when === 'function') {
bypassFailures.push(`You can not bypass conditional prompts: ${p.name}`);
return false;
}
try {
const inqPrompt = inqPrompts[p.type] || {}; // try to find a bypass function to run
const bypass = p.bypass || inqPrompt.bypass || typeBypass[p.type] || null; // get the real answer data out of the bypass function and attach it
// to the answer data object
const bypassIsFunc = typeof bypass === 'function';
const value = bypassIsFunc ? bypass.call(null, val, p) : val; // if inquirer prompt has a filter function - call it
const answer = (0, _filter.default)(p) ? (0, _filter.default)(p).call(p, value, answers) : value; // if inquirer prompt has a validate function - call it
if (p.validate) {
const validation = p.validate(value, answers);
if (validation !== true) {
// if validation failed return validation error
bypassFailures.push(validation);
return false;
}
}
answers[p.name] = answer;
} catch (err) {
// if we encounter an error above... assume the bypass value was invalid
bypassFailures.push(`The "${p.name}" prompt did not recognize "${val}" as a valid ${p.type} value (ERROR: ${err.message})`);
return false;
} // if we got this far, we successfully bypassed this prompt
return true;
}); // rip out any prompts that have been bypassed
const promptsAfterBypass = [// first prompt will copy the bypass answer data so it's available
// for prompts and actions to use
{
when: data => ((0, _assign.default)(data, answers), false)
}, // inlcude any prompts that were NOT bypassed
...(0, _filter.default)(prompts).call(prompts, p => !(0, _includes.default)(bypassedPrompts).call(bypassedPrompts, p))]; // if we have failures, throw the first one
if (bypassFailures.length) {
throw Error(bypassFailures[0]);
} else {
// return the prompts that still need to be run
return [promptsAfterBypass, answers];
} // BOOM!
}

1
server/node_modules/node-plop/node_modules/.bin/mkdirp generated vendored Symbolic link
View File

@@ -0,0 +1 @@
../mkdirp/bin/cmd.js

View File

@@ -0,0 +1,22 @@
Copyright (c) 2012 Simon Boudrias
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,481 @@
<img width="75px" height="75px" align="right" alt="Inquirer Logo" src="https://raw.githubusercontent.com/SBoudrias/Inquirer.js/master/assets/inquirer_readme.svg?sanitize=true" title="Inquirer.js"/>
# Inquirer.js
[![npm](https://badge.fury.io/js/inquirer.svg)](http://badge.fury.io/js/inquirer)
[![tests](https://travis-ci.org/SBoudrias/Inquirer.js.svg?branch=master)](http://travis-ci.org/SBoudrias/Inquirer.js)
[![Coverage Status](https://codecov.io/gh/SBoudrias/Inquirer.js/branch/master/graph/badge.svg)](https://codecov.io/gh/SBoudrias/Inquirer.js)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FSBoudrias%2FInquirer.js.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2FSBoudrias%2FInquirer.js?ref=badge_shield)
A collection of common interactive command line user interfaces.
## Table of Contents
1. [Documentation](#documentation)
1. [Installation](#installation)
2. [Examples](#examples)
3. [Methods](#methods)
4. [Objects](#objects)
5. [Questions](#questions)
6. [Answers](#answers)
7. [Separator](#separator)
8. [Prompt Types](#prompt)
2. [User Interfaces and Layouts](#layouts)
1. [Reactive Interface](#reactive)
3. [Support](#support)
4. [Known issues](#issues)
4. [News](#news)
5. [Contributing](#contributing)
6. [License](#license)
7. [Plugins](#plugins)
## Goal and Philosophy
**`Inquirer.js`** strives to be an easily embeddable and beautiful command line interface for [Node.js](https://nodejs.org/) (and perhaps the "CLI [Xanadu](https://en.wikipedia.org/wiki/Citizen_Kane)").
**`Inquirer.js`** should ease the process of
- providing _error feedback_
- _asking questions_
- _parsing_ input
- _validating_ answers
- managing _hierarchical prompts_
> **Note:** **`Inquirer.js`** provides the user interface and the inquiry session flow. If you're searching for a full blown command line program utility, then check out [commander](https://github.com/visionmedia/commander.js), [vorpal](https://github.com/dthree/vorpal) or [args](https://github.com/leo/args).
## [Documentation](#documentation)
<a name="documentation"></a>
### Installation
<a name="installation"></a>
```shell
npm install inquirer
```
```javascript
var inquirer = require('inquirer');
inquirer
.prompt([
/* Pass your questions in here */
])
.then(answers => {
// Use user feedback for... whatever!!
})
.catch(error => {
if(error.isTtyError) {
// Prompt couldn't be rendered in the current environment
} else {
// Something else when wrong
}
});
```
<a name="examples"></a>
### Examples (Run it and see it)
Check out the [`packages/inquirer/examples/`](https://github.com/SBoudrias/Inquirer.js/tree/master/packages/inquirer/examples) folder for code and interface examples.
```shell
node packages/inquirer/examples/pizza.js
node packages/inquirer/examples/checkbox.js
# etc...
```
### Methods
<a name="methods"></a>
#### `inquirer.prompt(questions) -> promise`
Launch the prompt interface (inquiry session)
- **questions** (Array) containing [Question Object](#question) (using the [reactive interface](#reactive-interface), you can also pass a `Rx.Observable` instance)
- returns a **Promise**
#### `inquirer.registerPrompt(name, prompt)`
Register prompt plugins under `name`.
- **name** (string) name of the this new prompt. (used for question `type`)
- **prompt** (object) the prompt object itself (the plugin)
#### `inquirer.createPromptModule() -> prompt function`
Create a self contained inquirer module. If you don't want to affect other libraries that also rely on inquirer when you overwrite or add new prompt types.
```js
var prompt = inquirer.createPromptModule();
prompt(questions).then(/* ... */);
```
### Objects
<a name="objects"></a>
#### Question
<a name="questions"></a>
A question object is a `hash` containing question related values:
- **type**: (String) Type of the prompt. Defaults: `input` - Possible values: `input`, `number`, `confirm`,
`list`, `rawlist`, `expand`, `checkbox`, `password`, `editor`
- **name**: (String) The name to use when storing the answer in the answers hash. If the name contains periods, it will define a path in the answers hash.
- **message**: (String|Function) The question to print. If defined as a function, the first parameter will be the current inquirer session answers. Defaults to the value of `name` (followed by a colon).
- **default**: (String|Number|Boolean|Array|Function) Default value(s) to use if nothing is entered, or a function that returns the default value(s). If defined as a function, the first parameter will be the current inquirer session answers.
- **choices**: (Array|Function) Choices array or a function returning a choices array. If defined as a function, the first parameter will be the current inquirer session answers.
Array values can be simple `numbers`, `strings`, or `objects` containing a `name` (to display in list), a `value` (to save in the answers hash), and a `short` (to display after selection) properties. The choices array can also contain [a `Separator`](#separator).
- **validate**: (Function) Receive the user input and answers hash. Should return `true` if the value is valid, and an error message (`String`) otherwise. If `false` is returned, a default error message is provided.
- **filter**: (Function) Receive the user input and answers hash. Returns the filtered value to be used inside the program. The value returned will be added to the _Answers_ hash.
- **transformer**: (Function) Receive the user input, answers hash and option flags, and return a transformed value to display to the user. The transformation only impacts what is shown while editing. It does not modify the answers hash.
- **when**: (Function, Boolean) Receive the current user answers hash and should return `true` or `false` depending on whether or not this question should be asked. The value can also be a simple boolean.
- **pageSize**: (Number) Change the number of lines that will be rendered when using `list`, `rawList`, `expand` or `checkbox`.
- **prefix**: (String) Change the default _prefix_ message.
- **suffix**: (String) Change the default _suffix_ message.
- **askAnswered**: (Boolean) Force to prompt the question if the answer already exists.
- **loop**: (Boolean) Enable list looping. Defaults: `true`
`default`, `choices`(if defined as functions), `validate`, `filter` and `when` functions can be called asynchronously. Either return a promise or use `this.async()` to get a callback you'll call with the final value.
```javascript
{
/* Preferred way: with promise */
filter() {
return new Promise(/* etc... */);
},
/* Legacy way: with this.async */
validate: function (input) {
// Declare function as asynchronous, and save the done callback
var done = this.async();
// Do async stuff
setTimeout(function() {
if (typeof input !== 'number') {
// Pass the return value in the done callback
done('You need to provide a number');
return;
}
// Pass the return value in the done callback
done(null, true);
}, 3000);
}
}
```
### Answers
<a name="answers"></a>
A key/value hash containing the client answers in each prompt.
- **Key** The `name` property of the _question_ object
- **Value** (Depends on the prompt)
- `confirm`: (Boolean)
- `input` : User input (filtered if `filter` is defined) (String)
- `number`: User input (filtered if `filter` is defined) (Number)
- `rawlist`, `list` : Selected choice value (or name if no value specified) (String)
### Separator
<a name="separator"></a>
A separator can be added to any `choices` array:
```
// In the question object
choices: [ "Choice A", new inquirer.Separator(), "choice B" ]
// Which'll be displayed this way
[?] What do you want to do?
> Order a pizza
Make a reservation
--------
Ask opening hours
Talk to the receptionist
```
The constructor takes a facultative `String` value that'll be use as the separator. If omitted, the separator will be `--------`.
Separator instances have a property `type` equal to `separator`. This should allow tools façading Inquirer interface from detecting separator types in lists.
<a name="prompt"></a>
### Prompt types
---
> **Note:**: _allowed options written inside square brackets (`[]`) are optional. Others are required._
#### List - `{type: 'list'}`
Take `type`, `name`, `message`, `choices`[, `default`, `filter`, `loop`] properties. (Note that
default must be the choice `index` in the array or a choice `value`)
![List prompt](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/list.svg)
---
#### Raw List - `{type: 'rawlist'}`
Take `type`, `name`, `message`, `choices`[, `default`, `filter`, `loop`] properties. (Note that
default must be the choice `index` in the array)
![Raw list prompt](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/rawlist.svg)
---
#### Expand - `{type: 'expand'}`
Take `type`, `name`, `message`, `choices`[, `default`] properties. (Note that
default must be the choice `index` in the array. If `default` key not provided, then `help` will be used as default choice)
Note that the `choices` object will take an extra parameter called `key` for the `expand` prompt. This parameter must be a single (lowercased) character. The `h` option is added by the prompt and shouldn't be defined by the user.
See `examples/expand.js` for a running example.
![Expand prompt closed](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/expand-y.svg)
![Expand prompt expanded](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/expand-d.svg)
---
#### Checkbox - `{type: 'checkbox'}`
Take `type`, `name`, `message`, `choices`[, `filter`, `validate`, `default`, `loop`] properties. `default` is expected to be an Array of the checked choices value.
Choices marked as `{checked: true}` will be checked by default.
Choices whose property `disabled` is truthy will be unselectable. If `disabled` is a string, then the string will be outputted next to the disabled choice, otherwise it'll default to `"Disabled"`. The `disabled` property can also be a synchronous function receiving the current answers as argument and returning a boolean or a string.
![Checkbox prompt](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/checkbox.svg)
---
#### Confirm - `{type: 'confirm'}`
Take `type`, `name`, `message`, [`default`] properties. `default` is expected to be a boolean if used.
![Confirm prompt](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/confirm.svg)
---
#### Input - `{type: 'input'}`
Take `type`, `name`, `message`[, `default`, `filter`, `validate`, `transformer`] properties.
![Input prompt](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/input.svg)
---
#### Input - `{type: 'number'}`
Take `type`, `name`, `message`[, `default`, `filter`, `validate`, `transformer`] properties.
---
#### Password - `{type: 'password'}`
Take `type`, `name`, `message`, `mask`,[, `default`, `filter`, `validate`] properties.
![Password prompt](https://cdn.rawgit.com/SBoudrias/Inquirer.js/28ae8337ba51d93e359ef4f7ee24e79b69898962/assets/screenshots/password.svg)
---
Note that `mask` is required to hide the actual user input.
#### Editor - `{type: 'editor'}`
Take `type`, `name`, `message`[, `default`, `filter`, `validate`] properties
Launches an instance of the users preferred editor on a temporary file. Once the user exits their editor, the contents of the temporary file are read in as the result. The editor to use is determined by reading the $VISUAL or $EDITOR environment variables. If neither of those are present, notepad (on Windows) or vim (Linux or Mac) is used.
<a name="layouts"></a>
### Use in Non-Interactive Environments
`prompt()` requires that it is run in an interactive environment. (I.e. [One where `process.stdin.isTTY` is `true`](https://nodejs.org/docs/latest-v12.x/api/process.html#process_a_note_on_process_i_o)). If `prompt()` is invoked outside of such an environment, then `prompt()` will return a rejected promise with an error. For convenience, the error will have a `isTtyError` property to programmatically indicate the cause.
## User Interfaces and layouts
Along with the prompts, Inquirer offers some basic text UI.
#### Bottom Bar - `inquirer.ui.BottomBar`
This UI present a fixed text at the bottom of a free text zone. This is useful to keep a message to the bottom of the screen while outputting command outputs on the higher section.
```javascript
var ui = new inquirer.ui.BottomBar();
// pipe a Stream to the log zone
outputStream.pipe(ui.log);
// Or simply write output
ui.log.write('something just happened.');
ui.log.write('Almost over, standby!');
// During processing, update the bottom bar content to display a loader
// or output a progress bar, etc
ui.updateBottomBar('new bottom bar content');
```
<a name="reactive"></a>
## Reactive interface
Internally, Inquirer uses the [JS reactive extension](https://github.com/ReactiveX/rxjs) to handle events and async flows.
This mean you can take advantage of this feature to provide more advanced flows. For example, you can dynamically add questions to be asked:
```js
var prompts = new Rx.Subject();
inquirer.prompt(prompts);
// At some point in the future, push new questions
prompts.next({
/* question... */
});
prompts.next({
/* question... */
});
// When you're done
prompts.complete();
```
And using the return value `process` property, you can access more fine grained callbacks:
```js
inquirer.prompt(prompts).ui.process.subscribe(onEachAnswer, onError, onComplete);
```
## Support (OS Terminals)
<a name="support"></a>
You should expect mostly good support for the CLI below. This does not mean we won't
look at issues found on other command line - feel free to report any!
- **Mac OS**:
- Terminal.app
- iTerm
- **Windows ([Known issues](#issues))**:
- [ConEmu](https://conemu.github.io/)
- cmd.exe
- Powershell
- Cygwin
- **Linux (Ubuntu, openSUSE, Arch Linux, etc)**:
- gnome-terminal (Terminal GNOME)
- konsole
## Know issues
<a name="issues"></a>
Running Inquirer together with network streams in Windows platform inside some terminals can result in process hang.
Workaround: run inside another terminal.
Please refer to the https://github.com/nodejs/node/issues/21771
## News on the march (Release notes)
<a name="news"></a>
Please refer to the [GitHub releases section for the changelog](https://github.com/SBoudrias/Inquirer.js/releases)
## Contributing
<a name="contributing"></a>
**Unit test**
Unit test are written in [Mocha](https://mochajs.org/). Please add a unit test for every new feature or bug fix. `npm test` to run the test suite.
**Documentation**
Add documentation for every API change. Feel free to send typo fixes and better docs!
We're looking to offer good support for multiple prompts and environments. If you want to
help, we'd like to keep a list of testers for each terminal/OS so we can contact you and
get feedback before release. Let us know if you want to be added to the list (just tweet
to [@vaxilart](https://twitter.com/Vaxilart)) or just add your name to [the wiki](https://github.com/SBoudrias/Inquirer.js/wiki/Testers)
## License
<a name="license"></a>
Copyright (c) 2016 Simon Boudrias (twitter: [@vaxilart](https://twitter.com/Vaxilart))
Licensed under the MIT license.
## Plugins
<a name="plugins"></a>
### Prompts
[**autocomplete**](https://github.com/mokkabonna/inquirer-autocomplete-prompt)<br>
Presents a list of options as the user types, compatible with other packages such as fuzzy (for search)<br>
<br>
![autocomplete prompt](https://github.com/mokkabonna/inquirer-autocomplete-prompt/raw/master/inquirer.gif)
[**checkbox-plus**](https://github.com/faressoft/inquirer-checkbox-plus-prompt)<br>
Checkbox list with autocomplete and other additions<br>
<br>
![checkbox-plus](https://github.com/faressoft/inquirer-checkbox-plus-prompt/raw/master/demo.gif)
[**datetime**](https://github.com/DerekTBrown/inquirer-datepicker-prompt)<br>
Customizable date/time selector using both number pad and arrow keys<br>
<br>
![Datetime Prompt](https://github.com/DerekTBrown/inquirer-datepicker-prompt/raw/master/example/datetime-prompt.png)
[**inquirer-select-line**](https://github.com/adam-golab/inquirer-select-line)<br>
Prompt for selecting index in array where add new element<br>
<br>
![inquirer-select-line gif](https://media.giphy.com/media/xUA7b1MxpngddUvdHW/giphy.gif)
[**command**](https://github.com/sullof/inquirer-command-prompt)<br>
Simple prompt with command history and dynamic autocomplete<br>
[**inquirer-fuzzy-path**](https://github.com/adelsz/inquirer-fuzzy-path)<br>
Prompt for fuzzy file/directory selection.<br>
<br>
![inquirer-fuzzy-path](https://raw.githubusercontent.com/adelsz/inquirer-fuzzy-path/master/recording.gif)
[**inquirer-emoji**](https://github.com/tannerntannern/inquirer-emoji)<br>
Prompt for inputting emojis.<br>
<br>
![inquirer-emoji](https://github.com/tannerntannern/inquirer-emoji/raw/master/demo.gif)
[**inquirer-chalk-pipe**](https://github.com/LitoMore/inquirer-chalk-pipe)<br>
Prompt for input chalk-pipe style strings<br>
<br>
![inquirer-chalk-pipe](https://github.com/LitoMore/inquirer-chalk-pipe/raw/master/screenshot.gif)
[**inquirer-search-checkbox**](https://github.com/clinyong/inquirer-search-checkbox)<br>
Searchable Inquirer checkbox<br>
[**inquirer-search-list**](https://github.com/robin-rpr/inquirer-search-list)<br>
Searchable Inquirer list<br>
<br>
![inquirer-search-list](https://github.com/robin-rpr/inquirer-search-list/blob/master/preview.gif)
[**inquirer-prompt-suggest**](https://github.com/olistic/inquirer-prompt-suggest)<br>
Inquirer prompt for your less creative users.<br>
<br>
![inquirer-prompt-suggest](https://user-images.githubusercontent.com/5600126/40391192-d4f3d6d0-5ded-11e8-932f-4b75b642c09e.gif)
[**inquirer-s3**](https://github.com/HQarroum/inquirer-s3)<br>
An S3 object selector for Inquirer.<br>
<br>
![inquirer-s3](https://github.com/HQarroum/inquirer-s3/raw/master/docs/inquirer-screenshot.png)
[**inquirer-autosubmit-prompt**](https://github.com/yaodingyd/inquirer-autosubmit-prompt)<br>
Auto submit based on your current input, saving one extra enter<br>
[**inquirer-file-tree-selection-prompt**](https://github.com/anc95/inquirer-file-tree-selection)<br>
Inquirer prompt for to select a file or directory in file tree<br>
<br>
![inquirer-file-tree-selection-prompt](https://github.com/anc95/inquirer-file-tree-selection/blob/master/example/screenshot.gif)
[**inquirer-table-prompt**](https://github.com/eduardoboucas/inquirer-table-prompt)<br>
A table-like prompt for Inquirer.<br>
<br>
![inquirer-table-prompt](https://raw.githubusercontent.com/eduardoboucas/inquirer-table-prompt/master/screen-capture.gif)

View File

@@ -0,0 +1,93 @@
'use strict';
/**
* Inquirer.js
* A collection of common interactive command line user interfaces.
*/
var inquirer = module.exports;
/**
* Client interfaces
*/
inquirer.prompts = {};
inquirer.Separator = require('./objects/separator');
inquirer.ui = {
BottomBar: require('./ui/bottom-bar'),
Prompt: require('./ui/prompt'),
};
/**
* Create a new self-contained prompt module.
*/
inquirer.createPromptModule = function (opt) {
var promptModule = function (questions, answers) {
var ui;
try {
ui = new inquirer.ui.Prompt(promptModule.prompts, opt);
} catch (error) {
return Promise.reject(error);
}
var promise = ui.run(questions, answers);
// Monkey patch the UI on the promise object so
// that it remains publicly accessible.
promise.ui = ui;
return promise;
};
promptModule.prompts = {};
/**
* Register a prompt type
* @param {String} name Prompt type name
* @param {Function} prompt Prompt constructor
* @return {inquirer}
*/
promptModule.registerPrompt = function (name, prompt) {
promptModule.prompts[name] = prompt;
return this;
};
/**
* Register the defaults provider prompts
*/
promptModule.restoreDefaultPrompts = function () {
this.registerPrompt('list', require('./prompts/list'));
this.registerPrompt('input', require('./prompts/input'));
this.registerPrompt('number', require('./prompts/number'));
this.registerPrompt('confirm', require('./prompts/confirm'));
this.registerPrompt('rawlist', require('./prompts/rawlist'));
this.registerPrompt('expand', require('./prompts/expand'));
this.registerPrompt('checkbox', require('./prompts/checkbox'));
this.registerPrompt('password', require('./prompts/password'));
this.registerPrompt('editor', require('./prompts/editor'));
};
promptModule.restoreDefaultPrompts();
return promptModule;
};
/**
* Public CLI helper interface
* @param {Array|Object|Rx.Observable} questions - Questions settings array
* @param {Function} cb - Callback being passed the user answers
* @return {inquirer.ui.Prompt}
*/
inquirer.prompt = inquirer.createPromptModule();
// Expose helper functions on the top level for easiest usage by common users
inquirer.registerPrompt = function (name, prompt) {
inquirer.prompt.registerPrompt(name, prompt);
};
inquirer.restoreDefaultPrompts = function () {
inquirer.prompt.restoreDefaultPrompts();
};

View File

@@ -0,0 +1,43 @@
'use strict';
var _ = {
isString: require('lodash/isString'),
isNumber: require('lodash/isNumber'),
extend: require('lodash/extend'),
isFunction: require('lodash/isFunction'),
};
/**
* Choice object
* Normalize input as choice object
* @constructor
* @param {Number|String|Object} val Choice value. If an object is passed, it should contains
* at least one of `value` or `name` property
*/
module.exports = class Choice {
constructor(val, answers) {
// Don't process Choice and Separator object
if (val instanceof Choice || val.type === 'separator') {
// eslint-disable-next-line no-constructor-return
return val;
}
if (_.isString(val) || _.isNumber(val)) {
this.name = String(val);
this.value = val;
this.short = String(val);
} else {
_.extend(this, val, {
name: val.name || val.value,
value: 'value' in val ? val.value : val.name,
short: val.short || val.name || val.value,
});
}
if (_.isFunction(val.disabled)) {
this.disabled = val.disabled(answers);
} else {
this.disabled = val.disabled;
}
}
};

View File

@@ -0,0 +1,127 @@
'use strict';
var assert = require('assert');
var _ = {
isNumber: require('lodash/isNumber'),
filter: require('lodash/filter'),
map: require('lodash/map'),
find: require('lodash/find'),
};
var Separator = require('./separator');
var Choice = require('./choice');
/**
* Choices collection
* Collection of multiple `choice` object
* @constructor
* @param {Array} choices All `choice` to keep in the collection
*/
module.exports = class Choices {
constructor(choices, answers) {
this.choices = choices.map((val) => {
if (val.type === 'separator') {
if (!(val instanceof Separator)) {
val = new Separator(val.line);
}
return val;
}
return new Choice(val, answers);
});
this.realChoices = this.choices
.filter(Separator.exclude)
.filter((item) => !item.disabled);
Object.defineProperty(this, 'length', {
get() {
return this.choices.length;
},
set(val) {
this.choices.length = val;
},
});
Object.defineProperty(this, 'realLength', {
get() {
return this.realChoices.length;
},
set() {
throw new Error('Cannot set `realLength` of a Choices collection');
},
});
}
/**
* Get a valid choice from the collection
* @param {Number} selector The selected choice index
* @return {Choice|Undefined} Return the matched choice or undefined
*/
getChoice(selector) {
assert(_.isNumber(selector));
return this.realChoices[selector];
}
/**
* Get a raw element from the collection
* @param {Number} selector The selected index value
* @return {Choice|Undefined} Return the matched choice or undefined
*/
get(selector) {
assert(_.isNumber(selector));
return this.choices[selector];
}
/**
* Match the valid choices against a where clause
* @param {Object} whereClause Lodash `where` clause
* @return {Array} Matching choices or empty array
*/
where(whereClause) {
return _.filter(this.realChoices, whereClause);
}
/**
* Pluck a particular key from the choices
* @param {String} propertyName Property name to select
* @return {Array} Selected properties
*/
pluck(propertyName) {
return _.map(this.realChoices, propertyName);
}
// Expose usual Array methods
indexOf() {
return this.choices.indexOf.apply(this.choices, arguments);
}
forEach() {
return this.choices.forEach.apply(this.choices, arguments);
}
filter() {
return this.choices.filter.apply(this.choices, arguments);
}
reduce() {
return this.choices.reduce.apply(this.choices, arguments);
}
find(func) {
return _.find(this.choices, func);
}
push() {
var objs = _.map(arguments, (val) => new Choice(val));
this.choices.push.apply(this.choices, objs);
this.realChoices = this.choices
.filter(Separator.exclude)
.filter((item) => !item.disabled);
return this.choices;
}
};

View File

@@ -0,0 +1,37 @@
'use strict';
var chalk = require('chalk');
var figures = require('figures');
/**
* Separator object
* Used to space/separate choices group
* @constructor
* @param {String} line Separation line content (facultative)
*/
class Separator {
constructor(line) {
this.type = 'separator';
this.line = chalk.dim(line || new Array(15).join(figures.line));
}
/**
* Stringify separator
* @return {String} the separator display string
*/
toString() {
return this.line;
}
}
/**
* Helper function returning false if object is a separator
* @param {Object} obj object to test against
* @return {Boolean} `false` if object is a separator
*/
Separator.exclude = function (obj) {
return obj.type !== 'separator';
};
module.exports = Separator;

View File

@@ -0,0 +1,154 @@
'use strict';
/**
* Base prompt implementation
* Should be extended by prompt types.
*/
var _ = {
assign: require('lodash/assign'),
defaults: require('lodash/defaults'),
clone: require('lodash/clone'),
};
var chalk = require('chalk');
var runAsync = require('run-async');
var { filter, flatMap, share, take, takeUntil } = require('rxjs/operators');
var Choices = require('../objects/choices');
var ScreenManager = require('../utils/screen-manager');
class Prompt {
constructor(question, rl, answers) {
// Setup instance defaults property
_.assign(this, {
answers: answers,
status: 'pending',
});
// Set defaults prompt options
this.opt = _.defaults(_.clone(question), {
validate: () => true,
filter: (val) => val,
when: () => true,
suffix: '',
prefix: chalk.green('?'),
});
// Make sure name is present
if (!this.opt.name) {
this.throwParamError('name');
}
// Set default message if no message defined
if (!this.opt.message) {
this.opt.message = this.opt.name + ':';
}
// Normalize choices
if (Array.isArray(this.opt.choices)) {
this.opt.choices = new Choices(this.opt.choices, answers);
}
this.rl = rl;
this.screen = new ScreenManager(this.rl);
}
/**
* Start the Inquiry session and manage output value filtering
* @return {Promise}
*/
run() {
return new Promise((resolve, reject) => {
this._run(
(value) => resolve(value),
(error) => reject(error)
);
});
}
// Default noop (this one should be overwritten in prompts)
_run(cb) {
cb();
}
/**
* Throw an error telling a required parameter is missing
* @param {String} name Name of the missing param
* @return {Throw Error}
*/
throwParamError(name) {
throw new Error('You must provide a `' + name + '` parameter');
}
/**
* Called when the UI closes. Override to do any specific cleanup necessary
*/
close() {
this.screen.releaseCursor();
}
/**
* Run the provided validation method each time a submit event occur.
* @param {Rx.Observable} submit - submit event flow
* @return {Object} Object containing two observables: `success` and `error`
*/
handleSubmitEvents(submit) {
var self = this;
var validate = runAsync(this.opt.validate);
var asyncFilter = runAsync(this.opt.filter);
var validation = submit.pipe(
flatMap((value) =>
asyncFilter(value, self.answers).then(
(filteredValue) =>
validate(filteredValue, self.answers).then(
(isValid) => ({ isValid: isValid, value: filteredValue }),
(err) => ({ isValid: err, value: filteredValue })
),
(err) => ({ isValid: err })
)
),
share()
);
var success = validation.pipe(
filter((state) => state.isValid === true),
take(1)
);
var error = validation.pipe(
filter((state) => state.isValid !== true),
takeUntil(success)
);
return {
success: success,
error: error,
};
}
/**
* Generate the prompt question string
* @return {String} prompt question string
*/
getQuestion() {
var message =
this.opt.prefix +
' ' +
chalk.bold(this.opt.message) +
this.opt.suffix +
chalk.reset(' ');
// Append the default if available, and if question isn't answered
if (this.opt.default != null && this.status !== 'answered') {
// If default password is supplied, hide it
if (this.opt.type === 'password') {
message += chalk.italic.dim('[hidden] ');
} else {
message += chalk.dim('(' + this.opt.default + ') ');
}
}
return message;
}
}
module.exports = Prompt;

View File

@@ -0,0 +1,279 @@
'use strict';
/**
* `list` type prompt
*/
var _ = {
isArray: require('lodash/isArray'),
map: require('lodash/map'),
isString: require('lodash/isString'),
};
var chalk = require('chalk');
var cliCursor = require('cli-cursor');
var figures = require('figures');
var { map, takeUntil } = require('rxjs/operators');
var Base = require('./base');
var observe = require('../utils/events');
var Paginator = require('../utils/paginator');
var incrementListIndex = require('../utils/incrementListIndex');
class CheckboxPrompt extends Base {
constructor(questions, rl, answers) {
super(questions, rl, answers);
if (!this.opt.choices) {
this.throwParamError('choices');
}
if (_.isArray(this.opt.default)) {
this.opt.choices.forEach(function (choice) {
if (this.opt.default.indexOf(choice.value) >= 0) {
choice.checked = true;
}
}, this);
}
this.pointer = 0;
// Make sure no default is set (so it won't be printed)
this.opt.default = null;
const shouldLoop = this.opt.loop === undefined ? true : this.opt.loop;
this.paginator = new Paginator(this.screen, { isInfinite: shouldLoop });
}
/**
* Start the Inquiry session
* @param {Function} cb Callback when prompt is done
* @return {this}
*/
_run(cb) {
this.done = cb;
var events = observe(this.rl);
var validation = this.handleSubmitEvents(
events.line.pipe(map(this.getCurrentValue.bind(this)))
);
validation.success.forEach(this.onEnd.bind(this));
validation.error.forEach(this.onError.bind(this));
events.normalizedUpKey
.pipe(takeUntil(validation.success))
.forEach(this.onUpKey.bind(this));
events.normalizedDownKey
.pipe(takeUntil(validation.success))
.forEach(this.onDownKey.bind(this));
events.numberKey
.pipe(takeUntil(validation.success))
.forEach(this.onNumberKey.bind(this));
events.spaceKey
.pipe(takeUntil(validation.success))
.forEach(this.onSpaceKey.bind(this));
events.aKey.pipe(takeUntil(validation.success)).forEach(this.onAllKey.bind(this));
events.iKey.pipe(takeUntil(validation.success)).forEach(this.onInverseKey.bind(this));
// Init the prompt
cliCursor.hide();
this.render();
this.firstRender = false;
return this;
}
/**
* Render the prompt to screen
* @return {CheckboxPrompt} self
*/
render(error) {
// Render question
var message = this.getQuestion();
var bottomContent = '';
if (!this.spaceKeyPressed) {
message +=
'(Press ' +
chalk.cyan.bold('<space>') +
' to select, ' +
chalk.cyan.bold('<a>') +
' to toggle all, ' +
chalk.cyan.bold('<i>') +
' to invert selection)';
}
// Render choices or answer depending on the state
if (this.status === 'answered') {
message += chalk.cyan(this.selection.join(', '));
} else {
var choicesStr = renderChoices(this.opt.choices, this.pointer);
var indexPosition = this.opt.choices.indexOf(
this.opt.choices.getChoice(this.pointer)
);
var realIndexPosition =
this.opt.choices.reduce(function (acc, value, i) {
// Dont count lines past the choice we are looking at
if (i > indexPosition) {
return acc;
}
// Add line if it's a separator
if (value.type === 'separator') {
return acc + 1;
}
var l = value.name;
// Non-strings take up one line
if (typeof l !== 'string') {
return acc + 1;
}
// Calculate lines taken up by string
l = l.split('\n');
return acc + l.length;
}, 0) - 1;
message +=
'\n' + this.paginator.paginate(choicesStr, realIndexPosition, this.opt.pageSize);
}
if (error) {
bottomContent = chalk.red('>> ') + error;
}
this.screen.render(message, bottomContent);
}
/**
* When user press `enter` key
*/
onEnd(state) {
this.status = 'answered';
this.spaceKeyPressed = true;
// Rerender prompt (and clean subline error)
this.render();
this.screen.done();
cliCursor.show();
this.done(state.value);
}
onError(state) {
this.render(state.isValid);
}
getCurrentValue() {
var choices = this.opt.choices.filter(function (choice) {
return Boolean(choice.checked) && !choice.disabled;
});
this.selection = _.map(choices, 'short');
return _.map(choices, 'value');
}
onUpKey() {
this.pointer = incrementListIndex(this.pointer, 'up', this.opt);
this.render();
}
onDownKey() {
this.pointer = incrementListIndex(this.pointer, 'down', this.opt);
this.render();
}
onNumberKey(input) {
if (input <= this.opt.choices.realLength) {
this.pointer = input - 1;
this.toggleChoice(this.pointer);
}
this.render();
}
onSpaceKey() {
this.spaceKeyPressed = true;
this.toggleChoice(this.pointer);
this.render();
}
onAllKey() {
var shouldBeChecked = Boolean(
this.opt.choices.find(function (choice) {
return choice.type !== 'separator' && !choice.checked;
})
);
this.opt.choices.forEach(function (choice) {
if (choice.type !== 'separator') {
choice.checked = shouldBeChecked;
}
});
this.render();
}
onInverseKey() {
this.opt.choices.forEach(function (choice) {
if (choice.type !== 'separator') {
choice.checked = !choice.checked;
}
});
this.render();
}
toggleChoice(index) {
var item = this.opt.choices.getChoice(index);
if (item !== undefined) {
this.opt.choices.getChoice(index).checked = !item.checked;
}
}
}
/**
* Function for rendering checkbox choices
* @param {Number} pointer Position of the pointer
* @return {String} Rendered content
*/
function renderChoices(choices, pointer) {
var output = '';
var separatorOffset = 0;
choices.forEach(function (choice, i) {
if (choice.type === 'separator') {
separatorOffset++;
output += ' ' + choice + '\n';
return;
}
if (choice.disabled) {
separatorOffset++;
output += ' - ' + choice.name;
output += ' (' + (_.isString(choice.disabled) ? choice.disabled : 'Disabled') + ')';
} else {
var line = getCheckbox(choice.checked) + ' ' + choice.name;
if (i - separatorOffset === pointer) {
output += chalk.cyan(figures.pointer + line);
} else {
output += ' ' + line;
}
}
output += '\n';
});
return output.replace(/\n$/, '');
}
/**
* Get the checkbox
* @param {Boolean} checked - add a X or not to the checkbox
* @return {String} Composited checkbox string
*/
function getCheckbox(checked) {
return checked ? chalk.green(figures.radioOn) : figures.radioOff;
}
module.exports = CheckboxPrompt;

View File

@@ -0,0 +1,102 @@
'use strict';
/**
* `confirm` type prompt
*/
var _ = {
extend: require('lodash/extend'),
isBoolean: require('lodash/isBoolean'),
};
var chalk = require('chalk');
var { take, takeUntil } = require('rxjs/operators');
var Base = require('./base');
var observe = require('../utils/events');
class ConfirmPrompt extends Base {
constructor(questions, rl, answers) {
super(questions, rl, answers);
var rawDefault = true;
_.extend(this.opt, {
filter: function (input) {
var value = rawDefault;
if (input != null && input !== '') {
value = /^y(es)?/i.test(input);
}
return value;
},
});
if (_.isBoolean(this.opt.default)) {
rawDefault = this.opt.default;
}
this.opt.default = rawDefault ? 'Y/n' : 'y/N';
}
/**
* Start the Inquiry session
* @param {Function} cb Callback when prompt is done
* @return {this}
*/
_run(cb) {
this.done = cb;
// Once user confirm (enter key)
var events = observe(this.rl);
events.keypress.pipe(takeUntil(events.line)).forEach(this.onKeypress.bind(this));
events.line.pipe(take(1)).forEach(this.onEnd.bind(this));
// Init
this.render();
return this;
}
/**
* Render the prompt to screen
* @return {ConfirmPrompt} self
*/
render(answer) {
var message = this.getQuestion();
if (typeof answer === 'boolean') {
message += chalk.cyan(answer ? 'Yes' : 'No');
} else {
message += this.rl.line;
}
this.screen.render(message);
return this;
}
/**
* When user press `enter` key
*/
onEnd(input) {
this.status = 'answered';
var output = this.opt.filter(input);
this.render(output);
this.screen.done();
this.done(output);
}
/**
* When user press a key
*/
onKeypress() {
this.render();
}
}
module.exports = ConfirmPrompt;

View File

@@ -0,0 +1,100 @@
'use strict';
/**
* `editor` type prompt
*/
var chalk = require('chalk');
var editAsync = require('external-editor').editAsync;
var Base = require('./base');
var observe = require('../utils/events');
var { Subject } = require('rxjs');
class EditorPrompt extends Base {
/**
* Start the Inquiry session
* @param {Function} cb Callback when prompt is done
* @return {this}
*/
_run(cb) {
this.done = cb;
this.editorResult = new Subject();
// Open Editor on "line" (Enter Key)
var events = observe(this.rl);
this.lineSubscription = events.line.subscribe(this.startExternalEditor.bind(this));
// Trigger Validation when editor closes
var validation = this.handleSubmitEvents(this.editorResult);
validation.success.forEach(this.onEnd.bind(this));
validation.error.forEach(this.onError.bind(this));
// Prevents default from being printed on screen (can look weird with multiple lines)
this.currentText = this.opt.default;
this.opt.default = null;
// Init
this.render();
return this;
}
/**
* Render the prompt to screen
* @return {EditorPrompt} self
*/
render(error) {
var bottomContent = '';
var message = this.getQuestion();
if (this.status === 'answered') {
message += chalk.dim('Received');
} else {
message += chalk.dim('Press <enter> to launch your preferred editor.');
}
if (error) {
bottomContent = chalk.red('>> ') + error;
}
this.screen.render(message, bottomContent);
}
/**
* Launch $EDITOR on user press enter
*/
startExternalEditor() {
// Pause Readline to prevent stdin and stdout from being modified while the editor is showing
this.rl.pause();
editAsync(this.currentText, this.endExternalEditor.bind(this));
}
endExternalEditor(error, result) {
this.rl.resume();
if (error) {
this.editorResult.error(error);
} else {
this.editorResult.next(result);
}
}
onEnd(state) {
this.editorResult.unsubscribe();
this.lineSubscription.unsubscribe();
this.answer = state.value;
this.status = 'answered';
// Re-render prompt
this.render();
this.screen.done();
this.done(this.answer);
}
onError(state) {
this.render(state.isValid);
}
}
module.exports = EditorPrompt;

View File

@@ -0,0 +1,281 @@
'use strict';
/**
* `rawlist` type prompt
*/
var _ = {
uniq: require('lodash/uniq'),
isString: require('lodash/isString'),
isNumber: require('lodash/isNumber'),
findIndex: require('lodash/findIndex'),
};
var chalk = require('chalk');
var { map, takeUntil } = require('rxjs/operators');
var Base = require('./base');
var Separator = require('../objects/separator');
var observe = require('../utils/events');
var Paginator = require('../utils/paginator');
class ExpandPrompt extends Base {
constructor(questions, rl, answers) {
super(questions, rl, answers);
if (!this.opt.choices) {
this.throwParamError('choices');
}
this.validateChoices(this.opt.choices);
// Add the default `help` (/expand) option
this.opt.choices.push({
key: 'h',
name: 'Help, list all options',
value: 'help',
});
this.opt.validate = (choice) => {
if (choice == null) {
return 'Please enter a valid command';
}
return choice !== 'help';
};
// Setup the default string (capitalize the default key)
this.opt.default = this.generateChoicesString(this.opt.choices, this.opt.default);
this.paginator = new Paginator(this.screen);
}
/**
* Start the Inquiry session
* @param {Function} cb Callback when prompt is done
* @return {this}
*/
_run(cb) {
this.done = cb;
// Save user answer and update prompt to show selected option.
var events = observe(this.rl);
var validation = this.handleSubmitEvents(
events.line.pipe(map(this.getCurrentValue.bind(this)))
);
validation.success.forEach(this.onSubmit.bind(this));
validation.error.forEach(this.onError.bind(this));
this.keypressObs = events.keypress
.pipe(takeUntil(validation.success))
.forEach(this.onKeypress.bind(this));
// Init the prompt
this.render();
return this;
}
/**
* Render the prompt to screen
* @return {ExpandPrompt} self
*/
render(error, hint) {
var message = this.getQuestion();
var bottomContent = '';
if (this.status === 'answered') {
message += chalk.cyan(this.answer);
} else if (this.status === 'expanded') {
var choicesStr = renderChoices(this.opt.choices, this.selectedKey);
message += this.paginator.paginate(choicesStr, this.selectedKey, this.opt.pageSize);
message += '\n Answer: ';
}
message += this.rl.line;
if (error) {
bottomContent = chalk.red('>> ') + error;
}
if (hint) {
bottomContent = chalk.cyan('>> ') + hint;
}
this.screen.render(message, bottomContent);
}
getCurrentValue(input) {
if (!input) {
input = this.rawDefault;
}
var selected = this.opt.choices.where({ key: input.toLowerCase().trim() })[0];
if (!selected) {
return null;
}
return selected.value;
}
/**
* Generate the prompt choices string
* @return {String} Choices string
*/
getChoices() {
var output = '';
this.opt.choices.forEach((choice) => {
output += '\n ';
if (choice.type === 'separator') {
output += ' ' + choice;
return;
}
var choiceStr = choice.key + ') ' + choice.name;
if (this.selectedKey === choice.key) {
choiceStr = chalk.cyan(choiceStr);
}
output += choiceStr;
});
return output;
}
onError(state) {
if (state.value === 'help') {
this.selectedKey = '';
this.status = 'expanded';
this.render();
return;
}
this.render(state.isValid);
}
/**
* When user press `enter` key
*/
onSubmit(state) {
this.status = 'answered';
var choice = this.opt.choices.where({ value: state.value })[0];
this.answer = choice.short || choice.name;
// Re-render prompt
this.render();
this.screen.done();
this.done(state.value);
}
/**
* When user press a key
*/
onKeypress() {
this.selectedKey = this.rl.line.toLowerCase();
var selected = this.opt.choices.where({ key: this.selectedKey })[0];
if (this.status === 'expanded') {
this.render();
} else {
this.render(null, selected ? selected.name : null);
}
}
/**
* Validate the choices
* @param {Array} choices
*/
validateChoices(choices) {
var formatError;
var errors = [];
var keymap = {};
choices.filter(Separator.exclude).forEach((choice) => {
if (!choice.key || choice.key.length !== 1) {
formatError = true;
}
if (keymap[choice.key]) {
errors.push(choice.key);
}
keymap[choice.key] = true;
choice.key = String(choice.key).toLowerCase();
});
if (formatError) {
throw new Error(
'Format error: `key` param must be a single letter and is required.'
);
}
if (keymap.h) {
throw new Error(
'Reserved key error: `key` param cannot be `h` - this value is reserved.'
);
}
if (errors.length) {
throw new Error(
'Duplicate key error: `key` param must be unique. Duplicates: ' +
_.uniq(errors).join(', ')
);
}
}
/**
* Generate a string out of the choices keys
* @param {Array} choices
* @param {Number|String} default - the choice index or name to capitalize
* @return {String} The rendered choices key string
*/
generateChoicesString(choices, defaultChoice) {
var defIndex = choices.realLength - 1;
if (_.isNumber(defaultChoice) && this.opt.choices.getChoice(defaultChoice)) {
defIndex = defaultChoice;
} else if (_.isString(defaultChoice)) {
let index = _.findIndex(
choices.realChoices,
({ value }) => value === defaultChoice
);
defIndex = index === -1 ? defIndex : index;
}
var defStr = this.opt.choices.pluck('key');
this.rawDefault = defStr[defIndex];
defStr[defIndex] = String(defStr[defIndex]).toUpperCase();
return defStr.join('');
}
}
/**
* Function for rendering checkbox choices
* @param {String} pointer Selected key
* @return {String} Rendered content
*/
function renderChoices(choices, pointer) {
var output = '';
choices.forEach((choice) => {
output += '\n ';
if (choice.type === 'separator') {
output += ' ' + choice;
return;
}
var choiceStr = choice.key + ') ' + choice.name;
if (pointer === choice.key) {
choiceStr = chalk.cyan(choiceStr);
}
output += choiceStr;
});
return output;
}
module.exports = ExpandPrompt;

View File

@@ -0,0 +1,113 @@
'use strict';
/**
* `input` type prompt
*/
var chalk = require('chalk');
var { map, takeUntil } = require('rxjs/operators');
var Base = require('./base');
var observe = require('../utils/events');
class InputPrompt extends Base {
/**
* Start the Inquiry session
* @param {Function} cb Callback when prompt is done
* @return {this}
*/
_run(cb) {
this.done = cb;
// Once user confirm (enter key)
var events = observe(this.rl);
var submit = events.line.pipe(map(this.filterInput.bind(this)));
var validation = this.handleSubmitEvents(submit);
validation.success.forEach(this.onEnd.bind(this));
validation.error.forEach(this.onError.bind(this));
events.keypress
.pipe(takeUntil(validation.success))
.forEach(this.onKeypress.bind(this));
// Init
this.render();
return this;
}
/**
* Render the prompt to screen
* @return {InputPrompt} self
*/
render(error) {
var bottomContent = '';
var appendContent = '';
var message = this.getQuestion();
var transformer = this.opt.transformer;
var isFinal = this.status === 'answered';
if (isFinal) {
appendContent = this.answer;
} else {
appendContent = this.rl.line;
}
if (transformer) {
message += transformer(appendContent, this.answers, { isFinal });
} else {
message += isFinal ? chalk.cyan(appendContent) : appendContent;
}
if (error) {
bottomContent = chalk.red('>> ') + error;
}
this.screen.render(message, bottomContent);
}
/**
* When user press `enter` key
*/
filterInput(input) {
if (!input) {
return this.opt.default == null ? '' : this.opt.default;
}
return input;
}
onEnd(state) {
this.answer = state.value;
this.status = 'answered';
// Re-render prompt
this.render();
this.screen.done();
this.done(state.value);
}
onError({ value = '', isValid }) {
this.rl.line += value;
this.rl.cursor += value.length;
this.render(isValid);
}
/**
* When user press a key
*/
onKeypress() {
// If user press a key, just clear the default value
if (this.opt.default) {
this.opt.default = undefined;
}
this.render();
}
}
module.exports = InputPrompt;

View File

@@ -0,0 +1,209 @@
'use strict';
/**
* `list` type prompt
*/
var _ = {
isNumber: require('lodash/isNumber'),
findIndex: require('lodash/findIndex'),
isString: require('lodash/isString'),
};
var chalk = require('chalk');
var figures = require('figures');
var cliCursor = require('cli-cursor');
var runAsync = require('run-async');
var { flatMap, map, take, takeUntil } = require('rxjs/operators');
var Base = require('./base');
var observe = require('../utils/events');
var Paginator = require('../utils/paginator');
var incrementListIndex = require('../utils/incrementListIndex');
class ListPrompt extends Base {
constructor(questions, rl, answers) {
super(questions, rl, answers);
if (!this.opt.choices) {
this.throwParamError('choices');
}
this.firstRender = true;
this.selected = 0;
var def = this.opt.default;
// If def is a Number, then use as index. Otherwise, check for value.
if (_.isNumber(def) && def >= 0 && def < this.opt.choices.realLength) {
this.selected = def;
} else if (!_.isNumber(def) && def != null) {
let index = _.findIndex(this.opt.choices.realChoices, ({ value }) => value === def);
this.selected = Math.max(index, 0);
}
// Make sure no default is set (so it won't be printed)
this.opt.default = null;
const shouldLoop = this.opt.loop === undefined ? true : this.opt.loop;
this.paginator = new Paginator(this.screen, { isInfinite: shouldLoop });
}
/**
* Start the Inquiry session
* @param {Function} cb Callback when prompt is done
* @return {this}
*/
_run(cb) {
this.done = cb;
var self = this;
var events = observe(this.rl);
events.normalizedUpKey.pipe(takeUntil(events.line)).forEach(this.onUpKey.bind(this));
events.normalizedDownKey
.pipe(takeUntil(events.line))
.forEach(this.onDownKey.bind(this));
events.numberKey.pipe(takeUntil(events.line)).forEach(this.onNumberKey.bind(this));
events.line
.pipe(
take(1),
map(this.getCurrentValue.bind(this)),
flatMap((value) => runAsync(self.opt.filter)(value).catch((err) => err))
)
.forEach(this.onSubmit.bind(this));
// Init the prompt
cliCursor.hide();
this.render();
return this;
}
/**
* Render the prompt to screen
* @return {ListPrompt} self
*/
render() {
// Render question
var message = this.getQuestion();
if (this.firstRender) {
message += chalk.dim('(Use arrow keys)');
}
// Render choices or answer depending on the state
if (this.status === 'answered') {
message += chalk.cyan(this.opt.choices.getChoice(this.selected).short);
} else {
var choicesStr = listRender(this.opt.choices, this.selected);
var indexPosition = this.opt.choices.indexOf(
this.opt.choices.getChoice(this.selected)
);
var realIndexPosition =
this.opt.choices.reduce(function (acc, value, i) {
// Dont count lines past the choice we are looking at
if (i > indexPosition) {
return acc;
}
// Add line if it's a separator
if (value.type === 'separator') {
return acc + 1;
}
var l = value.name;
// Non-strings take up one line
if (typeof l !== 'string') {
return acc + 1;
}
// Calculate lines taken up by string
l = l.split('\n');
return acc + l.length;
}, 0) - 1;
message +=
'\n' + this.paginator.paginate(choicesStr, realIndexPosition, this.opt.pageSize);
}
this.firstRender = false;
this.screen.render(message);
}
/**
* When user press `enter` key
*/
onSubmit(value) {
this.status = 'answered';
// Rerender prompt
this.render();
this.screen.done();
cliCursor.show();
this.done(value);
}
getCurrentValue() {
return this.opt.choices.getChoice(this.selected).value;
}
/**
* When user press a key
*/
onUpKey() {
this.selected = incrementListIndex(this.selected, 'up', this.opt);
this.render();
}
onDownKey() {
this.selected = incrementListIndex(this.selected, 'down', this.opt);
this.render();
}
onNumberKey(input) {
if (input <= this.opt.choices.realLength) {
this.selected = input - 1;
}
this.render();
}
}
/**
* Function for rendering list choices
* @param {Number} pointer Position of the pointer
* @return {String} Rendered content
*/
function listRender(choices, pointer) {
var output = '';
var separatorOffset = 0;
choices.forEach((choice, i) => {
if (choice.type === 'separator') {
separatorOffset++;
output += ' ' + choice + '\n';
return;
}
if (choice.disabled) {
separatorOffset++;
output += ' - ' + choice.name;
output += ' (' + (_.isString(choice.disabled) ? choice.disabled : 'Disabled') + ')';
output += '\n';
return;
}
var isSelected = i - separatorOffset === pointer;
var line = (isSelected ? figures.pointer + ' ' : ' ') + choice.name;
if (isSelected) {
line = chalk.cyan(line);
}
output += line + ' \n';
});
return output.replace(/\n$/, '');
}
module.exports = ListPrompt;

View File

@@ -0,0 +1,29 @@
'use strict';
/**
* `input` type prompt
*/
var Input = require('./input');
/**
* Extention of the Input prompt specifically for use with number inputs.
*/
class NumberPrompt extends Input {
filterInput(input) {
if (input && typeof input === 'string') {
input = input.trim();
// Match a number in the input
let numberMatch = input.match(/(^-?\d+|^\d+\.\d*|^\d*\.\d+)(e\d+)?$/);
// If a number is found, return that input.
if (numberMatch) {
return Number(numberMatch[0]);
}
}
// If the input was invalid return the default value.
return this.opt.default == null ? NaN : this.opt.default;
}
}
module.exports = NumberPrompt;

View File

@@ -0,0 +1,113 @@
'use strict';
/**
* `password` type prompt
*/
var chalk = require('chalk');
var { map, takeUntil } = require('rxjs/operators');
var Base = require('./base');
var observe = require('../utils/events');
function mask(input, maskChar) {
input = String(input);
maskChar = typeof maskChar === 'string' ? maskChar : '*';
if (input.length === 0) {
return '';
}
return new Array(input.length + 1).join(maskChar);
}
class PasswordPrompt extends Base {
/**
* Start the Inquiry session
* @param {Function} cb Callback when prompt is done
* @return {this}
*/
_run(cb) {
this.done = cb;
var events = observe(this.rl);
// Once user confirm (enter key)
var submit = events.line.pipe(map(this.filterInput.bind(this)));
var validation = this.handleSubmitEvents(submit);
validation.success.forEach(this.onEnd.bind(this));
validation.error.forEach(this.onError.bind(this));
events.keypress
.pipe(takeUntil(validation.success))
.forEach(this.onKeypress.bind(this));
// Init
this.render();
return this;
}
/**
* Render the prompt to screen
* @return {PasswordPrompt} self
*/
render(error) {
var message = this.getQuestion();
var bottomContent = '';
if (this.status === 'answered') {
message += this.opt.mask
? chalk.cyan(mask(this.answer, this.opt.mask))
: chalk.italic.dim('[hidden]');
} else if (this.opt.mask) {
message += mask(this.rl.line || '', this.opt.mask);
} else {
message += chalk.italic.dim('[input is hidden] ');
}
if (error) {
bottomContent = '\n' + chalk.red('>> ') + error;
}
this.screen.render(message, bottomContent);
}
/**
* When user press `enter` key
*/
filterInput(input) {
if (!input) {
return this.opt.default == null ? '' : this.opt.default;
}
return input;
}
onEnd(state) {
this.status = 'answered';
this.answer = state.value;
// Re-render prompt
this.render();
this.screen.done();
this.done(state.value);
}
onError(state) {
this.render(state.isValid);
}
onKeypress() {
// If user press a key, just clear the default value
if (this.opt.default) {
this.opt.default = undefined;
}
this.render();
}
}
module.exports = PasswordPrompt;

View File

@@ -0,0 +1,218 @@
'use strict';
/**
* `rawlist` type prompt
*/
var _ = {
extend: require('lodash/extend'),
isNumber: require('lodash/isNumber'),
findIndex: require('lodash/findIndex'),
};
var chalk = require('chalk');
var { map, takeUntil } = require('rxjs/operators');
var Base = require('./base');
var Separator = require('../objects/separator');
var observe = require('../utils/events');
var Paginator = require('../utils/paginator');
var incrementListIndex = require('../utils/incrementListIndex');
class RawListPrompt extends Base {
constructor(questions, rl, answers) {
super(questions, rl, answers);
if (!this.opt.choices) {
this.throwParamError('choices');
}
this.opt.validChoices = this.opt.choices.filter(Separator.exclude);
this.selected = 0;
this.rawDefault = 0;
_.extend(this.opt, {
validate: function (val) {
return val != null;
},
});
var def = this.opt.default;
if (_.isNumber(def) && def >= 0 && def < this.opt.choices.realLength) {
this.selected = def;
this.rawDefault = def;
} else if (!_.isNumber(def) && def != null) {
let index = _.findIndex(this.opt.choices.realChoices, ({ value }) => value === def);
let safeIndex = Math.max(index, 0);
this.selected = safeIndex;
this.rawDefault = safeIndex;
}
// Make sure no default is set (so it won't be printed)
this.opt.default = null;
const shouldLoop = this.opt.loop === undefined ? true : this.opt.loop;
this.paginator = new Paginator(undefined, { isInfinite: shouldLoop });
}
/**
* Start the Inquiry session
* @param {Function} cb Callback when prompt is done
* @return {this}
*/
_run(cb) {
this.done = cb;
// Once user confirm (enter key)
var events = observe(this.rl);
var submit = events.line.pipe(map(this.getCurrentValue.bind(this)));
var validation = this.handleSubmitEvents(submit);
validation.success.forEach(this.onEnd.bind(this));
validation.error.forEach(this.onError.bind(this));
events.normalizedUpKey.pipe(takeUntil(events.line)).forEach(this.onUpKey.bind(this));
events.normalizedDownKey
.pipe(takeUntil(events.line))
.forEach(this.onDownKey.bind(this));
events.keypress
.pipe(takeUntil(validation.success))
.forEach(this.onKeypress.bind(this));
// Init the prompt
this.render();
return this;
}
/**
* Render the prompt to screen
* @return {RawListPrompt} self
*/
render(error) {
// Render question
var message = this.getQuestion();
var bottomContent = '';
if (this.status === 'answered') {
message += chalk.cyan(this.answer);
} else {
var choicesStr = renderChoices(this.opt.choices, this.selected);
message +=
'\n' + this.paginator.paginate(choicesStr, this.selected, this.opt.pageSize);
message += '\n Answer: ';
}
message += this.rl.line;
if (error) {
bottomContent = '\n' + chalk.red('>> ') + error;
}
this.screen.render(message, bottomContent);
}
/**
* When user press `enter` key
*/
getCurrentValue(index) {
if (index == null) {
index = this.rawDefault;
} else if (index === '') {
index = this.selected;
} else {
index -= 1;
}
var choice = this.opt.choices.getChoice(index);
return choice ? choice.value : null;
}
onEnd(state) {
this.status = 'answered';
this.answer = state.value;
// Re-render prompt
this.render();
this.screen.done();
this.done(state.value);
}
onError() {
this.render('Please enter a valid index');
}
/**
* When user press a key
*/
onKeypress() {
var index = this.rl.line.length ? Number(this.rl.line) - 1 : 0;
if (this.opt.choices.getChoice(index)) {
this.selected = index;
} else {
this.selected = undefined;
}
this.render();
}
/**
* When user press up key
*/
onUpKey() {
this.onArrowKey('up');
}
/**
* When user press down key
*/
onDownKey() {
this.onArrowKey('down');
}
/**
* When user press up or down key
* @param {String} type Arrow type: up or down
*/
onArrowKey(type) {
this.selected = incrementListIndex(this.selected, type, this.opt);
this.rl.line = String(this.selected + 1);
}
}
/**
* Function for rendering list choices
* @param {Number} pointer Position of the pointer
* @return {String} Rendered content
*/
function renderChoices(choices, pointer) {
var output = '';
var separatorOffset = 0;
choices.forEach(function (choice, i) {
output += '\n ';
if (choice.type === 'separator') {
separatorOffset++;
output += ' ' + choice;
return;
}
var index = i - separatorOffset;
var display = index + 1 + ') ' + choice.name;
if (index === pointer) {
display = chalk.cyan(display);
}
output += display;
});
return output;
}
module.exports = RawListPrompt;

View File

@@ -0,0 +1,99 @@
'use strict';
var _ = {
extend: require('lodash/extend'),
omit: require('lodash/omit'),
};
var MuteStream = require('mute-stream');
var readline = require('readline');
/**
* Base interface class other can inherits from
*/
class UI {
constructor(opt) {
// Instantiate the Readline interface
// @Note: Don't reassign if already present (allow test to override the Stream)
if (!this.rl) {
this.rl = readline.createInterface(setupReadlineOptions(opt));
}
this.rl.resume();
this.onForceClose = this.onForceClose.bind(this);
// Make sure new prompt start on a newline when closing
process.on('exit', this.onForceClose);
// Terminate process on SIGINT (which will call process.on('exit') in return)
this.rl.on('SIGINT', this.onForceClose);
}
/**
* Handle the ^C exit
* @return {null}
*/
onForceClose() {
this.close();
process.kill(process.pid, 'SIGINT');
console.log('');
}
/**
* Close the interface and cleanup listeners
*/
close() {
// Remove events listeners
this.rl.removeListener('SIGINT', this.onForceClose);
process.removeListener('exit', this.onForceClose);
this.rl.output.unmute();
if (this.activePrompt && typeof this.activePrompt.close === 'function') {
this.activePrompt.close();
}
// Close the readline
this.rl.output.end();
this.rl.pause();
this.rl.close();
}
}
function setupReadlineOptions(opt) {
opt = opt || {};
// Inquirer 8.x:
// opt.skipTTYChecks = opt.skipTTYChecks === undefined ? opt.input !== undefined : opt.skipTTYChecks;
opt.skipTTYChecks = opt.skipTTYChecks === undefined ? true : opt.skipTTYChecks;
// Default `input` to stdin
var input = opt.input || process.stdin;
// Check if prompt is being called in TTY environment
// If it isn't return a failed promise
if (!opt.skipTTYChecks && !input.isTTY) {
const nonTtyError = new Error(
'Prompts can not be meaningfully rendered in non-TTY environments'
);
nonTtyError.isTtyError = true;
throw nonTtyError;
}
// Add mute capabilities to the output
var ms = new MuteStream();
ms.pipe(opt.output || process.stdout);
var output = ms;
return _.extend(
{
terminal: true,
input: input,
output: output,
},
_.omit(opt, ['input', 'output'])
);
}
module.exports = UI;

View File

@@ -0,0 +1,102 @@
'use strict';
/**
* Sticky bottom bar user interface
*/
var through = require('through');
var Base = require('./baseUI');
var rlUtils = require('../utils/readline');
var _ = {
last: require('lodash/last'),
};
class BottomBar extends Base {
constructor(opt) {
opt = opt || {};
super(opt);
this.log = through(this.writeLog.bind(this));
this.bottomBar = opt.bottomBar || '';
this.render();
}
/**
* Render the prompt to screen
* @return {BottomBar} self
*/
render() {
this.write(this.bottomBar);
return this;
}
clean() {
rlUtils.clearLine(this.rl, this.bottomBar.split('\n').length);
return this;
}
/**
* Update the bottom bar content and rerender
* @param {String} bottomBar Bottom bar content
* @return {BottomBar} self
*/
updateBottomBar(bottomBar) {
rlUtils.clearLine(this.rl, 1);
this.rl.output.unmute();
this.clean();
this.bottomBar = bottomBar;
this.render();
this.rl.output.mute();
return this;
}
/**
* Write out log data
* @param {String} data - The log data to be output
* @return {BottomBar} self
*/
writeLog(data) {
this.rl.output.unmute();
this.clean();
this.rl.output.write(this.enforceLF(data.toString()));
this.render();
this.rl.output.mute();
return this;
}
/**
* Make sure line end on a line feed
* @param {String} str Input string
* @return {String} The input string with a final line feed
*/
enforceLF(str) {
return str.match(/[\r\n]$/) ? str : str + '\n';
}
/**
* Helper for writing message in Prompt
* @param {BottomBar} prompt - The Prompt object that extends tty
* @param {String} message - The message to be output
*/
write(message) {
var msgLines = message.split(/\n/);
this.height = msgLines.length;
// Write message to screen and setPrompt to control backspace
this.rl.setPrompt(_.last(msgLines));
if (this.rl.output.rows === 0 && this.rl.output.columns === 0) {
/* When it's a tty through serial port there's no terminal info and the render will malfunction,
so we need enforce the cursor to locate to the leftmost position for rendering. */
rlUtils.left(this.rl, message.length + this.rl.line.length);
}
this.rl.output.write(message);
}
}
module.exports = BottomBar;

View File

@@ -0,0 +1,145 @@
'use strict';
var _ = {
isPlainObject: require('lodash/isPlainObject'),
clone: require('lodash/clone'),
isArray: require('lodash/isArray'),
set: require('lodash/set'),
isFunction: require('lodash/isFunction'),
};
var { defer, empty, from, of } = require('rxjs');
var { concatMap, filter, publish, reduce } = require('rxjs/operators');
var runAsync = require('run-async');
var utils = require('../utils/utils');
var Base = require('./baseUI');
/**
* Base interface class other can inherits from
*/
class PromptUI extends Base {
constructor(prompts, opt) {
super(opt);
this.prompts = prompts;
}
run(questions, answers) {
// Keep global reference to the answers
if (_.isPlainObject(answers)) {
this.answers = _.clone(answers);
} else {
this.answers = {};
}
// Make sure questions is an array.
if (_.isPlainObject(questions)) {
questions = [questions];
}
// Create an observable, unless we received one as parameter.
// Note: As this is a public interface, we cannot do an instanceof check as we won't
// be using the exact same object in memory.
var obs = _.isArray(questions) ? from(questions) : questions;
this.process = obs.pipe(
concatMap(this.processQuestion.bind(this)),
publish() // Creates a hot Observable. It prevents duplicating prompts.
);
this.process.connect();
return this.process
.pipe(
reduce((answers, answer) => {
_.set(answers, answer.name, answer.answer);
return answers;
}, this.answers)
)
.toPromise(Promise)
.then(this.onCompletion.bind(this), this.onError.bind(this));
}
/**
* Once all prompt are over
*/
onCompletion() {
this.close();
return this.answers;
}
onError(error) {
this.close();
return Promise.reject(error);
}
processQuestion(question) {
question = _.clone(question);
return defer(() => {
var obs = of(question);
return obs.pipe(
concatMap(this.setDefaultType.bind(this)),
concatMap(this.filterIfRunnable.bind(this)),
concatMap(() =>
utils.fetchAsyncQuestionProperty(question, 'message', this.answers)
),
concatMap(() =>
utils.fetchAsyncQuestionProperty(question, 'default', this.answers)
),
concatMap(() =>
utils.fetchAsyncQuestionProperty(question, 'choices', this.answers)
),
concatMap(this.fetchAnswer.bind(this))
);
});
}
fetchAnswer(question) {
var Prompt = this.prompts[question.type];
this.activePrompt = new Prompt(question, this.rl, this.answers);
return defer(() =>
from(
this.activePrompt
.run()
.then((answer) => ({ name: question.name, answer: answer }))
)
);
}
setDefaultType(question) {
// Default type to input
if (!this.prompts[question.type]) {
question.type = 'input';
}
return defer(() => of(question));
}
filterIfRunnable(question) {
if (question.askAnswered !== true && this.answers[question.name] !== undefined) {
return empty();
}
if (question.when === false) {
return empty();
}
if (!_.isFunction(question.when)) {
return of(question);
}
var answers = this.answers;
return defer(() =>
from(
runAsync(question.when)(answers).then((shouldRun) => {
if (shouldRun) {
return question;
}
})
).pipe(filter((val) => val != null))
);
}
}
module.exports = PromptUI;

View File

@@ -0,0 +1,54 @@
'use strict';
var { fromEvent } = require('rxjs');
var { filter, map, share, takeUntil } = require('rxjs/operators');
function normalizeKeypressEvents(value, key) {
return { value: value, key: key || {} };
}
module.exports = function (rl) {
var keypress = fromEvent(rl.input, 'keypress', normalizeKeypressEvents)
.pipe(takeUntil(fromEvent(rl, 'close')))
// Ignore `enter` key. On the readline, we only care about the `line` event.
.pipe(filter(({ key }) => key.name !== 'enter' && key.name !== 'return'));
return {
line: fromEvent(rl, 'line'),
keypress: keypress,
normalizedUpKey: keypress.pipe(
filter(
({ key }) =>
key.name === 'up' || key.name === 'k' || (key.name === 'p' && key.ctrl)
),
share()
),
normalizedDownKey: keypress.pipe(
filter(
({ key }) =>
key.name === 'down' || key.name === 'j' || (key.name === 'n' && key.ctrl)
),
share()
),
numberKey: keypress.pipe(
filter((e) => e.value && '123456789'.indexOf(e.value) >= 0),
map((e) => Number(e.value)),
share()
),
spaceKey: keypress.pipe(
filter(({ key }) => key && key.name === 'space'),
share()
),
aKey: keypress.pipe(
filter(({ key }) => key && key.name === 'a'),
share()
),
iKey: keypress.pipe(
filter(({ key }) => key && key.name === 'i'),
share()
),
};
};

View File

@@ -0,0 +1,19 @@
function incrementListIndex(current, dir, opt) {
var len = opt.choices.realLength;
var shouldLoop = 'loop' in opt ? Boolean(opt.loop) : true;
if (dir === 'up') {
if (current > 0) {
return current - 1;
}
return shouldLoop ? len - 1 : current;
}
if (dir === 'down') {
if (current < len - 1) {
return current + 1;
}
return shouldLoop ? 0 : current;
}
throw new Error('dir must be up or down');
}
module.exports = incrementListIndex;

View File

@@ -0,0 +1,78 @@
'use strict';
var _ = {
sum: require('lodash/sum'),
flatten: require('lodash/flatten'),
};
var chalk = require('chalk');
/**
* The paginator returns a subset of the choices if the list is too long.
*/
class Paginator {
constructor(screen, options = {}) {
const { isInfinite = true } = options;
this.lastIndex = 0;
this.screen = screen;
this.isInfinite = isInfinite;
}
paginate(output, active, pageSize) {
pageSize = pageSize || 7;
var lines = output.split('\n');
if (this.screen) {
lines = this.screen.breakLines(lines);
active = _.sum(lines.map((lineParts) => lineParts.length).splice(0, active));
lines = _.flatten(lines);
}
// Make sure there's enough lines to paginate
if (lines.length <= pageSize) {
return output;
}
const visibleLines = this.isInfinite
? this.getInfiniteLines(lines, active, pageSize)
: this.getFiniteLines(lines, active, pageSize);
this.lastIndex = active;
return (
visibleLines.join('\n') +
'\n' +
chalk.dim('(Move up and down to reveal more choices)')
);
}
getInfiniteLines(lines, active, pageSize) {
if (this.pointer === undefined) {
this.pointer = 0;
}
var middleOfList = Math.floor(pageSize / 2);
// Move the pointer only when the user go down and limit it to the middle of the list
if (
this.pointer < middleOfList &&
this.lastIndex < active &&
active - this.lastIndex < pageSize
) {
this.pointer = Math.min(middleOfList, this.pointer + active - this.lastIndex);
}
// Duplicate the lines so it give an infinite list look
var infinite = _.flatten([lines, lines, lines]);
var topIndex = Math.max(0, active + lines.length - this.pointer);
return infinite.splice(topIndex, pageSize);
}
getFiniteLines(lines, active, pageSize) {
var topIndex = active - pageSize / 2;
if (topIndex < 0) {
topIndex = 0;
} else if (topIndex + pageSize > lines.length) {
topIndex = lines.length - pageSize;
}
return lines.splice(topIndex, pageSize);
}
}
module.exports = Paginator;

View File

@@ -0,0 +1,51 @@
'use strict';
var ansiEscapes = require('ansi-escapes');
/**
* Move cursor left by `x`
* @param {Readline} rl - Readline instance
* @param {Number} x - How far to go left (default to 1)
*/
exports.left = function (rl, x) {
rl.output.write(ansiEscapes.cursorBackward(x));
};
/**
* Move cursor right by `x`
* @param {Readline} rl - Readline instance
* @param {Number} x - How far to go left (default to 1)
*/
exports.right = function (rl, x) {
rl.output.write(ansiEscapes.cursorForward(x));
};
/**
* Move cursor up by `x`
* @param {Readline} rl - Readline instance
* @param {Number} x - How far to go up (default to 1)
*/
exports.up = function (rl, x) {
rl.output.write(ansiEscapes.cursorUp(x));
};
/**
* Move cursor down by `x`
* @param {Readline} rl - Readline instance
* @param {Number} x - How far to go down (default to 1)
*/
exports.down = function (rl, x) {
rl.output.write(ansiEscapes.cursorDown(x));
};
/**
* Clear current line
* @param {Readline} rl - Readline instance
* @param {Number} len - number of line to delete
*/
exports.clearLine = function (rl, len) {
rl.output.write(ansiEscapes.eraseLines(len));
};

View File

@@ -0,0 +1,145 @@
'use strict';
var _ = {
last: require('lodash/last'),
flatten: require('lodash/flatten'),
};
var util = require('./readline');
var cliWidth = require('cli-width');
var stripAnsi = require('strip-ansi');
var stringWidth = require('string-width');
function height(content) {
return content.split('\n').length;
}
function lastLine(content) {
return _.last(content.split('\n'));
}
class ScreenManager {
constructor(rl) {
// These variables are keeping information to allow correct prompt re-rendering
this.height = 0;
this.extraLinesUnderPrompt = 0;
this.rl = rl;
}
render(content, bottomContent) {
this.rl.output.unmute();
this.clean(this.extraLinesUnderPrompt);
/**
* Write message to screen and setPrompt to control backspace
*/
var promptLine = lastLine(content);
var rawPromptLine = stripAnsi(promptLine);
// Remove the rl.line from our prompt. We can't rely on the content of
// rl.line (mainly because of the password prompt), so just rely on it's
// length.
var prompt = rawPromptLine;
if (this.rl.line.length) {
prompt = prompt.slice(0, -this.rl.line.length);
}
this.rl.setPrompt(prompt);
// SetPrompt will change cursor position, now we can get correct value
var cursorPos = this.rl._getCursorPos();
var width = this.normalizedCliWidth();
content = this.forceLineReturn(content, width);
if (bottomContent) {
bottomContent = this.forceLineReturn(bottomContent, width);
}
// Manually insert an extra line if we're at the end of the line.
// This prevent the cursor from appearing at the beginning of the
// current line.
if (rawPromptLine.length % width === 0) {
content += '\n';
}
var fullContent = content + (bottomContent ? '\n' + bottomContent : '');
this.rl.output.write(fullContent);
/**
* Re-adjust the cursor at the correct position.
*/
// We need to consider parts of the prompt under the cursor as part of the bottom
// content in order to correctly cleanup and re-render.
var promptLineUpDiff = Math.floor(rawPromptLine.length / width) - cursorPos.rows;
var bottomContentHeight =
promptLineUpDiff + (bottomContent ? height(bottomContent) : 0);
if (bottomContentHeight > 0) {
util.up(this.rl, bottomContentHeight);
}
// Reset cursor at the beginning of the line
util.left(this.rl, stringWidth(lastLine(fullContent)));
// Adjust cursor on the right
if (cursorPos.cols > 0) {
util.right(this.rl, cursorPos.cols);
}
/**
* Set up state for next re-rendering
*/
this.extraLinesUnderPrompt = bottomContentHeight;
this.height = height(fullContent);
this.rl.output.mute();
}
clean(extraLines) {
if (extraLines > 0) {
util.down(this.rl, extraLines);
}
util.clearLine(this.rl, this.height);
}
done() {
this.rl.setPrompt('');
this.rl.output.unmute();
this.rl.output.write('\n');
}
releaseCursor() {
if (this.extraLinesUnderPrompt > 0) {
util.down(this.rl, this.extraLinesUnderPrompt);
}
}
normalizedCliWidth() {
var width = cliWidth({
defaultWidth: 80,
output: this.rl.output,
});
return width;
}
breakLines(lines, width) {
// Break lines who're longer than the cli width so we can normalize the natural line
// returns behavior across terminals.
width = width || this.normalizedCliWidth();
var regex = new RegExp('(?:(?:\\033[[0-9;]*m)*.?){1,' + width + '}', 'g');
return lines.map((line) => {
var chunk = line.match(regex);
// Last match is always empty
chunk.pop();
return chunk || '';
});
}
forceLineReturn(content, width) {
width = width || this.normalizedCliWidth();
return _.flatten(this.breakLines(content.split('\n'), width)).join('\n');
}
}
module.exports = ScreenManager;

View File

@@ -0,0 +1,28 @@
'use strict';
var _ = {
isFunction: require('lodash/isFunction'),
};
var { from, of } = require('rxjs');
var runAsync = require('run-async');
/**
* Resolve a question property value if it is passed as a function.
* This method will overwrite the property on the question object with the received value.
* @param {Object} question - Question object
* @param {String} prop - Property to fetch name
* @param {Object} answers - Answers object
* @return {Rx.Observable} - Observable emitting once value is known
*/
exports.fetchAsyncQuestionProperty = function (question, prop, answers) {
if (!_.isFunction(question[prop])) {
return of(question);
}
return from(
runAsync(question[prop])(answers).then((value) => {
question[prop] = value;
return question;
})
);
};

View File

@@ -0,0 +1,55 @@
{
"name": "inquirer",
"version": "7.3.3",
"description": "A collection of common interactive command line user interfaces.",
"author": "Simon Boudrias <admin@simonboudrias.com>",
"files": [
"lib",
"README.md"
],
"main": "lib/inquirer.js",
"keywords": [
"command",
"prompt",
"stdin",
"cli",
"tty",
"menu"
],
"engines": {
"node": ">=8.0.0"
},
"devDependencies": {
"chai": "^4.2.0",
"chalk-pipe": "^4.0.0",
"cmdify": "^0.0.4",
"mocha": "^8.0.1",
"mockery": "^2.1.0",
"nyc": "^15.0.0",
"sinon": "^9.0.0"
},
"scripts": {
"test": "nyc mocha test/**/* -r ./test/before",
"posttest": "nyc report --reporter=text-lcov > ../../coverage/nyc-report.lcov",
"prepublishOnly": "cp ../../README.md .",
"postpublish": "rm -f README.md"
},
"repository": "SBoudrias/Inquirer.js",
"license": "MIT",
"dependencies": {
"ansi-escapes": "^4.2.1",
"chalk": "^4.1.0",
"cli-cursor": "^3.1.0",
"cli-width": "^3.0.0",
"external-editor": "^3.0.3",
"figures": "^3.0.0",
"lodash": "^4.17.19",
"mute-stream": "0.0.8",
"run-async": "^2.4.0",
"rxjs": "^6.6.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0",
"through": "^2.3.6"
},
"gitHead": "808d5538531c1ca1c34f832d77bc98dfd0ba4000"
}

View File

@@ -0,0 +1,21 @@
Copyright 2010 James Halliday (mail@substack.net)
This project is free software released under the MIT/X11 license:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

33
server/node_modules/node-plop/node_modules/mkdirp/bin/cmd.js generated vendored Executable file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env node
var mkdirp = require('../');
var minimist = require('minimist');
var fs = require('fs');
var argv = minimist(process.argv.slice(2), {
alias: { m: 'mode', h: 'help' },
string: [ 'mode' ]
});
if (argv.help) {
fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout);
return;
}
var paths = argv._.slice();
var mode = argv.mode ? parseInt(argv.mode, 8) : undefined;
(function next () {
if (paths.length === 0) return;
var p = paths.shift();
if (mode === undefined) mkdirp(p, cb)
else mkdirp(p, mode, cb)
function cb (err) {
if (err) {
console.error(err.message);
process.exit(1);
}
else next();
}
})();

View File

@@ -0,0 +1,12 @@
usage: mkdirp [DIR1,DIR2..] {OPTIONS}
Create each supplied directory including any necessary parent directories that
don't yet exist.
If the directory already exists, do nothing.
OPTIONS are:
-m, --mode If a directory needs to be created, set the mode as an octal
permission string.

View File

@@ -0,0 +1,102 @@
var path = require('path');
var fs = require('fs');
var _0777 = parseInt('0777', 8);
module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP;
function mkdirP (p, opts, f, made) {
if (typeof opts === 'function') {
f = opts;
opts = {};
}
else if (!opts || typeof opts !== 'object') {
opts = { mode: opts };
}
var mode = opts.mode;
var xfs = opts.fs || fs;
if (mode === undefined) {
mode = _0777
}
if (!made) made = null;
var cb = f || /* istanbul ignore next */ function () {};
p = path.resolve(p);
xfs.mkdir(p, mode, function (er) {
if (!er) {
made = made || p;
return cb(null, made);
}
switch (er.code) {
case 'ENOENT':
/* istanbul ignore if */
if (path.dirname(p) === p) return cb(er);
mkdirP(path.dirname(p), opts, function (er, made) {
/* istanbul ignore if */
if (er) cb(er, made);
else mkdirP(p, opts, cb, made);
});
break;
// In the case of any other error, just see if there's a dir
// there already. If so, then hooray! If not, then something
// is borked.
default:
xfs.stat(p, function (er2, stat) {
// if the stat fails, then that's super weird.
// let the original error be the failure reason.
if (er2 || !stat.isDirectory()) cb(er, made)
else cb(null, made);
});
break;
}
});
}
mkdirP.sync = function sync (p, opts, made) {
if (!opts || typeof opts !== 'object') {
opts = { mode: opts };
}
var mode = opts.mode;
var xfs = opts.fs || fs;
if (mode === undefined) {
mode = _0777
}
if (!made) made = null;
p = path.resolve(p);
try {
xfs.mkdirSync(p, mode);
made = made || p;
}
catch (err0) {
switch (err0.code) {
case 'ENOENT' :
made = sync(path.dirname(p), opts, made);
sync(p, opts, made);
break;
// In the case of any other error, just see if there's a dir
// there already. If so, then hooray! If not, then something
// is borked.
default:
var stat;
try {
stat = xfs.statSync(p);
}
catch (err1) /* istanbul ignore next */ {
throw err0;
}
/* istanbul ignore if */
if (!stat.isDirectory()) throw err0;
break;
}
}
return made;
};

View File

@@ -0,0 +1,33 @@
{
"name": "mkdirp",
"description": "Recursively mkdir, like `mkdir -p`",
"version": "0.5.6",
"publishConfig": {
"tag": "legacy"
},
"author": "James Halliday <mail@substack.net> (http://substack.net)",
"main": "index.js",
"keywords": [
"mkdir",
"directory"
],
"repository": {
"type": "git",
"url": "https://github.com/substack/node-mkdirp.git"
},
"scripts": {
"test": "tap test/*.js"
},
"dependencies": {
"minimist": "^1.2.6"
},
"devDependencies": {
"tap": "^16.0.1"
},
"bin": "bin/cmd.js",
"license": "MIT",
"files": [
"bin",
"index.js"
]
}

View File

@@ -0,0 +1,100 @@
# mkdirp
Like `mkdir -p`, but in node.js!
[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp)
# example
## pow.js
```js
var mkdirp = require('mkdirp');
mkdirp('/tmp/foo/bar/baz', function (err) {
if (err) console.error(err)
else console.log('pow!')
});
```
Output
```
pow!
```
And now /tmp/foo/bar/baz exists, huzzah!
# methods
```js
var mkdirp = require('mkdirp');
```
## mkdirp(dir, opts, cb)
Create a new directory and any necessary subdirectories at `dir` with octal
permission string `opts.mode`. If `opts` is a non-object, it will be treated as
the `opts.mode`.
If `opts.mode` isn't specified, it defaults to `0777`.
`cb(err, made)` fires with the error or the first directory `made`
that had to be created, if any.
You can optionally pass in an alternate `fs` implementation by passing in
`opts.fs`. Your implementation should have `opts.fs.mkdir(path, mode, cb)` and
`opts.fs.stat(path, cb)`.
## mkdirp.sync(dir, opts)
Synchronously create a new directory and any necessary subdirectories at `dir`
with octal permission string `opts.mode`. If `opts` is a non-object, it will be
treated as the `opts.mode`.
If `opts.mode` isn't specified, it defaults to `0777`.
Returns the first directory that had to be created, if any.
You can optionally pass in an alternate `fs` implementation by passing in
`opts.fs`. Your implementation should have `opts.fs.mkdirSync(path, mode)` and
`opts.fs.statSync(path)`.
# usage
This package also ships with a `mkdirp` command.
```
usage: mkdirp [DIR1,DIR2..] {OPTIONS}
Create each supplied directory including any necessary parent directories that
don't yet exist.
If the directory already exists, do nothing.
OPTIONS are:
-m, --mode If a directory needs to be created, set the mode as an octal
permission string.
```
# install
With [npm](http://npmjs.org) do:
```
npm install mkdirp
```
to get the library, or
```
npm install -g mkdirp
```
to get the command.
# license
MIT

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/AsyncSubject';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/AsyncSubject"));
//# sourceMappingURL=AsyncSubject.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AsyncSubject.js","sources":["src/AsyncSubject.ts"],"names":[],"mappings":";;;;;AAAA,8CAAyC"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/BehaviorSubject';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/BehaviorSubject"));
//# sourceMappingURL=BehaviorSubject.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BehaviorSubject.js","sources":["src/BehaviorSubject.ts"],"names":[],"mappings":";;;;;AAAA,iDAA4C"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/InnerSubscriber';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/InnerSubscriber"));
//# sourceMappingURL=InnerSubscriber.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"InnerSubscriber.js","sources":["src/InnerSubscriber.ts"],"names":[],"mappings":";;;;;AAAA,iDAA4C"}

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2015-2018 Google, Inc., Netflix, Inc., Microsoft Corp. and contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/Notification';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/Notification"));
//# sourceMappingURL=Notification.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Notification.js","sources":["src/Notification.ts"],"names":[],"mappings":";;;;;AAAA,8CAAyC"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/Observable';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/Observable"));
//# sourceMappingURL=Observable.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Observable.js","sources":["src/Observable.ts"],"names":[],"mappings":";;;;;AAAA,4CAAuC"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/Observer';

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=Observer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Observer.js","sources":["src/Observer.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/Operator';

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=Operator.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Operator.js","sources":["src/Operator.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/OuterSubscriber';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/OuterSubscriber"));
//# sourceMappingURL=OuterSubscriber.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"OuterSubscriber.js","sources":["src/OuterSubscriber.ts"],"names":[],"mappings":";;;;;AAAA,iDAA4C"}

View File

@@ -0,0 +1,147 @@
# <img src="docs_app/assets/Rx_Logo_S.png" alt="RxJS Logo" width="86" height="86"> RxJS: Reactive Extensions For JavaScript
[![CircleCI](https://circleci.com/gh/ReactiveX/rxjs/tree/6.x.svg?style=svg)](https://circleci.com/gh/ReactiveX/rxjs/tree/6.x)
[![npm version](https://badge.fury.io/js/%40reactivex%2Frxjs.svg)](http://badge.fury.io/js/%40reactivex%2Frxjs)
[![Join the chat at https://gitter.im/Reactive-Extensions/RxJS](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Reactive-Extensions/RxJS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# RxJS 6 Stable
### MIGRATION AND RELEASE INFORMATION:
Find out how to update to v6, **automatically update your TypeScript code**, and more!
- [Current home is MIGRATION.md](./docs_app/content/guide/v6/migration.md)
### FOR V 5.X PLEASE GO TO [THE 5.0 BRANCH](https://github.com/ReactiveX/rxjs/tree/5.x)
Reactive Extensions Library for JavaScript. This is a rewrite of [Reactive-Extensions/RxJS](https://github.com/Reactive-Extensions/RxJS) and is the latest production-ready version of RxJS. This rewrite is meant to have better performance, better modularity, better debuggable call stacks, while staying mostly backwards compatible, with some breaking changes that reduce the API surface.
[Apache 2.0 License](LICENSE.txt)
- [Code of Conduct](CODE_OF_CONDUCT.md)
- [Contribution Guidelines](CONTRIBUTING.md)
- [Maintainer Guidelines](doc_app/content/maintainer-guidelines.md)
- [API Documentation](https://rxjs.dev/)
## Versions In This Repository
- [master](https://github.com/ReactiveX/rxjs/commits/master) - This is all of the current, unreleased work, which is against v6 of RxJS right now
- [stable](https://github.com/ReactiveX/rxjs/commits/stable) - This is the branch for the latest version you'd get if you do `npm install rxjs`
## Important
By contributing or commenting on issues in this repository, whether you've read them or not, you're agreeing to the [Contributor Code of Conduct](CODE_OF_CONDUCT.md). Much like traffic laws, ignorance doesn't grant you immunity.
## Installation and Usage
### ES6 via npm
```sh
npm install rxjs
```
It's recommended to pull in the Observable creation methods you need directly from `'rxjs'` as shown below with `range`. And you can pull in any operator you need from one spot, under `'rxjs/operators'`.
```ts
import { range } from "rxjs";
import { map, filter } from "rxjs/operators";
range(1, 200)
.pipe(
filter(x => x % 2 === 1),
map(x => x + x)
)
.subscribe(x => console.log(x));
```
Here, we're using the built-in `pipe` method on Observables to combine operators. See [pipeable operators](https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md) for more information.
### CommonJS via npm
To install this library for CommonJS (CJS) usage, use the following command:
```sh
npm install rxjs
```
(Note: destructuring available in Node 8+)
```js
const { range } = require('rxjs');
const { map, filter } = require('rxjs/operators');
range(1, 200).pipe(
filter(x => x % 2 === 1),
map(x => x + x)
).subscribe(x => console.log(x));
```
### CDN
For CDN, you can use [unpkg](https://unpkg.com/):
https://unpkg.com/rxjs/bundles/rxjs.umd.min.js
The global namespace for rxjs is `rxjs`:
```js
const { range } = rxjs;
const { map, filter } = rxjs.operators;
range(1, 200)
.pipe(
filter(x => x % 2 === 1),
map(x => x + x)
)
.subscribe(x => console.log(x));
```
## Goals
- Smaller overall bundles sizes
- Provide better performance than preceding versions of RxJS
- To model/follow the [Observable Spec Proposal](https://github.com/zenparsing/es-observable) to the observable
- Provide more modular file structure in a variety of formats
- Provide more debuggable call stacks than preceding versions of RxJS
## Building/Testing
- `npm run build_all` - builds everything
- `npm test` - runs tests
- `npm run test_no_cache` - run test with `ts-node` set to false
## Performance Tests
Run `npm run build_perf` or `npm run perf` to run the performance tests with `protractor`.
Run `npm run perf_micro [operator]` to run micro performance test benchmarking operator.
## Adding documentation
We appreciate all contributions to the documentation of any type. All of the information needed to get the docs app up and running locally as well as how to contribute can be found in the [documentation directory](./docs_app).
## Generating PNG marble diagrams
The script `npm run tests2png` requires some native packages installed locally: `imagemagick`, `graphicsmagick`, and `ghostscript`.
For Mac OS X with [Homebrew](http://brew.sh/):
- `brew install imagemagick`
- `brew install graphicsmagick`
- `brew install ghostscript`
- You may need to install the Ghostscript fonts manually:
- Download the tarball from the [gs-fonts project](https://sourceforge.net/projects/gs-fonts)
- `mkdir -p /usr/local/share/ghostscript && tar zxvf /path/to/ghostscript-fonts.tar.gz -C /usr/local/share/ghostscript`
For Debian Linux:
- `sudo add-apt-repository ppa:dhor/myway`
- `apt-get install imagemagick`
- `apt-get install graphicsmagick`
- `apt-get install ghostscript`
For Windows and other Operating Systems, check the download instructions here:
- http://imagemagick.org
- http://www.graphicsmagick.org
- http://www.ghostscript.com/

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/ReplaySubject';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/ReplaySubject"));
//# sourceMappingURL=ReplaySubject.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ReplaySubject.js","sources":["src/ReplaySubject.ts"],"names":[],"mappings":";;;;;AAAA,+CAA0C"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat"));
//# sourceMappingURL=Rx.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Rx.js","sources":["src/Rx.ts"],"names":[],"mappings":";;;;;AACA,iCAA4B"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/Scheduler';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/Scheduler"));
//# sourceMappingURL=Scheduler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Scheduler.js","sources":["src/Scheduler.ts"],"names":[],"mappings":";;;;;AAAA,2CAAsC"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/Subject';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/Subject"));
//# sourceMappingURL=Subject.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Subject.js","sources":["src/Subject.ts"],"names":[],"mappings":";;;;;AAAA,yCAAoC"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/SubjectSubscription';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/SubjectSubscription"));
//# sourceMappingURL=SubjectSubscription.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SubjectSubscription.js","sources":["src/SubjectSubscription.ts"],"names":[],"mappings":";;;;;AAAA,qDAAgD"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/Subscriber';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/Subscriber"));
//# sourceMappingURL=Subscriber.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Subscriber.js","sources":["src/Subscriber.ts"],"names":[],"mappings":";;;;;AAAA,4CAAuC"}

View File

@@ -0,0 +1 @@
export * from 'rxjs-compat/Subscription';

View File

@@ -0,0 +1,7 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("rxjs-compat/Subscription"));
//# sourceMappingURL=Subscription.js.map

Some files were not shown because too many files have changed in this diff Show More