Your commit message
This commit is contained in:
parent
4cbb962963
commit
33e22a421c
|
@ -1,19 +1,18 @@
|
||||||
{
|
{
|
||||||
"env": {
|
"parser": "@typescript-eslint/parser",
|
||||||
"browser": true,
|
|
||||||
"jquery": true
|
|
||||||
},
|
|
||||||
"parser": "@babel/eslint-parser",
|
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2020,
|
"ecmaVersion": 2020,
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"prettier"
|
"prettier",
|
||||||
|
"@typescript-eslint"
|
||||||
],
|
],
|
||||||
"extends": [
|
"extends": [
|
||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
"prettier"
|
"plugin:prettier/recommended",
|
||||||
|
"prettier",
|
||||||
|
"plugin:@typescript-eslint/recommended"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
|
@ -27,6 +26,4 @@
|
||||||
"window": "readonly",
|
"window": "readonly",
|
||||||
"console": "readonly"
|
"console": "readonly"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
|
@ -0,0 +1 @@
|
||||||
|
_
|
|
@ -1,11 +1,13 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
# Run JS/CSS checks
|
# Run JS/CSS checks
|
||||||
.husky/pre-commit-js-css
|
.husky/pre-commit-js-css
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "JS/CSS checks failed"
|
echo "JS/CSS checks failed"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get the list of staged PHP files
|
# Get the list of staged PHP files
|
||||||
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$')
|
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$')
|
||||||
|
|
||||||
|
@ -41,26 +43,38 @@ if [ $SYNTAX_ERRORS -ne 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run PHPCBF to auto-fix issues
|
|
||||||
echo "Running PHPCBF..."
|
|
||||||
for FILE in $STAGED_FILES; do
|
|
||||||
/home/aissel/.config/composer/vendor/bin/phpcbf --standard=/var/www/html/google_forms/phpcs.xml "$FILE" || true
|
|
||||||
done
|
|
||||||
|
|
||||||
# Run PHP CS Fixer to auto-fix issues
|
# Run PHP CS Fixer to auto-fix issues
|
||||||
echo "Running PHP CS Fixer..."
|
echo "Running PHP CS Fixer..."
|
||||||
for FILE in $STAGED_FILES; do
|
for FILE in $STAGED_FILES; do
|
||||||
/home/aissel/.config/composer/vendor/bin/php-cs-fixer fix "$FILE"
|
/home/aissel/.config/composer/vendor/bin/php-cs-fixer fix "$FILE"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Re-run PHPCS to check for unresolved coding standard violations
|
|
||||||
|
|
||||||
|
# Run PHPCS to check for unresolv//cheks for the file path & the nampespaceed coding standard violations
|
||||||
echo "Running PHPCS..."
|
echo "Running PHPCS..."
|
||||||
|
ERROR_FILE="/var/www/html/google_forms/phpcs_errors.json" # Specify your error file path and format here
|
||||||
|
|
||||||
|
# Run PHPCS, display errors in the terminal, and store them in the JSON file
|
||||||
|
echo "$STAGED_FILES" | xargs -n 1 /home/aissel/.config/composer/vendor/bin/phpcs --standard=/var/www/html/google_forms/phpcs.xml --report=json | tee "$ERROR_FILE"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Additionally, run PHPCS to show output in terminal in standard format
|
||||||
echo "$STAGED_FILES" | xargs -n 1 /home/aissel/.config/composer/vendor/bin/phpcs --standard=/var/www/html/google_forms/phpcs.xml
|
echo "$STAGED_FILES" | xargs -n 1 /home/aissel/.config/composer/vendor/bin/phpcs --standard=/var/www/html/google_forms/phpcs.xml
|
||||||
|
|
||||||
|
# Check if there were any errors reported
|
||||||
|
|
||||||
|
if grep -q '"errors":' "$ERROR_FILE"; then
|
||||||
|
echo "PHPCS errors detected. Please fix them before committing."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Add the fixed files back to the staging area
|
# Add the fixed files back to the staging area
|
||||||
for FILE in $STAGED_FILES; do
|
for FILE in $STAGED_FILES; do
|
||||||
git add "$FILE"
|
git add "$FILE"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
echo "Pre-commit checks completed."
|
echo "Pre-commit checks completed."
|
||||||
|
|
|
@ -24,14 +24,17 @@ for FILE in $STAGED_FILES; do
|
||||||
npx prettier --write "$FILE"
|
npx prettier --write "$FILE"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Run ESLint
|
|
||||||
|
# Run ESLint for JS/TS files only
|
||||||
echo "Running ESLint..."
|
echo "Running ESLint..."
|
||||||
ESLINT_ERRORS=0
|
ESLINT_ERRORS=0
|
||||||
for FILE in $STAGED_FILES; do
|
for FILE in $STAGED_FILES; do
|
||||||
|
if echo "$FILE" | grep -E '\.(js|jsx|ts|tsx)$' > /dev/null; then
|
||||||
ESLINT_OUTPUT=$(npx eslint "$FILE" 2>&1)
|
ESLINT_OUTPUT=$(npx eslint "$FILE" 2>&1)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
display_errors "$ESLINT_OUTPUT"
|
display_errors "$ESLINT_OUTPUT"
|
||||||
ESLINT_ERRORS=1
|
ESLINT_ERRORS=1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$finder = PhpCsFixer\Finder::create()
|
||||||
|
->in(__DIR__)
|
||||||
|
->name('*.php')
|
||||||
|
->notName('*.blade.php')
|
||||||
|
->exclude('vendor')
|
||||||
|
->exclude('storage');
|
||||||
|
|
||||||
|
return (new PhpCsFixer\Config())
|
||||||
|
->setRiskyAllowed(false) // Equivalent to "php-cs-fixer.allowRisky": false
|
||||||
|
->setIndent(" ") // Use four spaces for indentation
|
||||||
|
->setLineEnding("\n") // Ensure line endings are consistent
|
||||||
|
->setRules([
|
||||||
|
'@PSR12' => true, // Apply PSR-12 standard
|
||||||
|
'blank_line_after_namespace' => true, // Ensure there is a blank line after namespace declarations
|
||||||
|
'blank_line_after_opening_tag' => true, // Ensure there is a blank line after the opening PHP tag
|
||||||
|
'blank_line_before_statement' => [
|
||||||
|
'statements' => ['return'], // Ensure a blank line before return statements
|
||||||
|
],
|
||||||
|
'no_extra_blank_lines' => [
|
||||||
|
'tokens' => [
|
||||||
|
'curly_brace_block',
|
||||||
|
'extra',
|
||||||
|
'parenthesis_brace_block',
|
||||||
|
'square_brace_block',
|
||||||
|
'throw',
|
||||||
|
'use',
|
||||||
|
],
|
||||||
|
], // Remove extra blank lines
|
||||||
|
'no_whitespace_in_blank_line' => true, // Remove whitespace in blank lines
|
||||||
|
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'], // Ensure consistent method argument spacing
|
||||||
|
'trim_array_spaces' => true, // Remove spaces around array elements
|
||||||
|
'binary_operator_spaces' => ['default' => 'align'], // Align binary operators
|
||||||
|
'no_trailing_whitespace' => true, // Remove trailing whitespace
|
||||||
|
'no_trailing_whitespace_in_comment' => true, // Remove trailing whitespace in comments
|
||||||
|
'whitespace_after_comma_in_array' => true, // Ensure there is space after commas in arrays
|
||||||
|
'single_blank_line_at_eof' => true, // Ensure there is a single blank line at the end of the file
|
||||||
|
'single_class_element_per_statement' => ['elements' => ['property']], // Ensure single class element per statement
|
||||||
|
'class_attributes_separation' => [
|
||||||
|
'elements' => [
|
||||||
|
'method' => 'one', // Ensure one blank line between methods
|
||||||
|
'property' => 'one', // Ensure one blank line between properties
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'space_after_semicolon' => ['remove_in_empty_for_expressions' => true], // Handle space after semicolons
|
||||||
|
'no_unused_imports' => true, // Remove unused use statements
|
||||||
|
])
|
||||||
|
->setFinder($finder);
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"jsxSingleQuote": true,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"parser": "babel-ts",
|
||||||
|
"requirePragma": false,
|
||||||
|
"insertPragma": false,
|
||||||
|
"proseWrap": "preserve",
|
||||||
|
"htmlWhitespaceSensitivity": "css",
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"embeddedLanguageFormatting": "off"
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,5 @@
|
||||||
# Ignore node_modules directory
|
node_modules
|
||||||
node_modules/
|
dist
|
||||||
|
build
|
||||||
# Ignore build directory
|
|
||||||
build/
|
|
||||||
|
|
||||||
# Ignore all minified JavaScript files
|
|
||||||
*.min.js
|
*.min.js
|
||||||
|
*.min.css
|
||||||
|
|
||||||
# Ignore specific files
|
|
||||||
public/vendor/jquery.js
|
|
||||||
public/vendor/bootstrap.js
|
|
||||||
|
|
||||||
# Ignore all files in a specific directory
|
|
||||||
src/vendor/
|
|
||||||
|
|
||||||
# Ignore specific file
|
|
||||||
path/to/specific/file.js
|
|
||||||
|
|
||||||
# Ignore all JavaScript files in a specific directory
|
|
||||||
src/vendor/*.js
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"tabWidth": 2,
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true,
|
|
||||||
"jsxSingleQuote": true,
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"parser": "babel-ts",
|
|
||||||
"requirePragma": false,
|
|
||||||
"insertPragma": false,
|
|
||||||
"proseWrap": "preserve",
|
|
||||||
"htmlWhitespaceSensitivity": "css",
|
|
||||||
"endOfLine": "lf",
|
|
||||||
"embeddedLanguageFormatting": "off"
|
|
||||||
}
|
|
|
@ -186,9 +186,9 @@ $config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
$config['enable_query_strings'] = false;
|
$config['enable_query_strings'] = false;
|
||||||
$config['controller_trigger'] = 'c';
|
$config['controller_trigger'] = 'c';
|
||||||
$config['function_trigger'] = 'm';
|
$config['function_trigger'] = 'm';
|
||||||
$config['directory_trigger'] = 'd';
|
$config['directory_trigger'] = 'd';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@ -384,13 +384,13 @@ $config['encryption_key'] = '';
|
||||||
| except for 'cookie_prefix' and 'cookie_httponly', which are ignored here.
|
| except for 'cookie_prefix' and 'cookie_httponly', which are ignored here.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
$config['sess_driver'] = 'files';
|
$config['sess_driver'] = 'files';
|
||||||
$config['sess_cookie_name'] = 'ci_session';
|
$config['sess_cookie_name'] = 'ci_session';
|
||||||
$config['sess_samesite'] = 'Lax';
|
$config['sess_samesite'] = 'Lax';
|
||||||
$config['sess_expiration'] = 7200;
|
$config['sess_expiration'] = 7200;
|
||||||
$config['sess_save_path'] = null;
|
$config['sess_save_path'] = null;
|
||||||
$config['sess_match_ip'] = false;
|
$config['sess_match_ip'] = false;
|
||||||
$config['sess_time_to_update'] = 300;
|
$config['sess_time_to_update'] = 300;
|
||||||
$config['sess_regenerate_destroy'] = false;
|
$config['sess_regenerate_destroy'] = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -458,11 +458,11 @@ $config['global_xss_filtering'] = false;
|
||||||
| 'csrf_regenerate' = Regenerate token on every submission
|
| 'csrf_regenerate' = Regenerate token on every submission
|
||||||
| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks
|
| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks
|
||||||
*/
|
*/
|
||||||
$config['csrf_protection'] = false;
|
$config['csrf_protection'] = false;
|
||||||
$config['csrf_token_name'] = 'csrf_test_name';
|
$config['csrf_token_name'] = 'csrf_test_name';
|
||||||
$config['csrf_cookie_name'] = 'csrf_cookie_name';
|
$config['csrf_cookie_name'] = 'csrf_cookie_name';
|
||||||
$config['csrf_expire'] = 7200;
|
$config['csrf_expire'] = 7200;
|
||||||
$config['csrf_regenerate'] = true;
|
$config['csrf_regenerate'] = true;
|
||||||
$config['csrf_exclude_uris'] = array();
|
$config['csrf_exclude_uris'] = array();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -530,4 +530,26 @@ $config['rewrite_short_tags'] = false;
|
||||||
| Comma-separated: '10.0.1.200,192.168.5.0/24'
|
| Comma-separated: '10.0.1.200,192.168.5.0/24'
|
||||||
| Array: array('10.0.1.200', '192.168.5.0/24')
|
| Array: array('10.0.1.200', '192.168.5.0/24')
|
||||||
*/
|
*/
|
||||||
$config['proxy_ips'] = '';
|
// Autoload function to support namespaces in CodeIgniter 3
|
||||||
|
// spl_autoload_register(function ($class) {
|
||||||
|
// // Convert namespace to the full file path
|
||||||
|
// $file = APPPATH . str_replace('\\', '/', $class) . '.php';
|
||||||
|
|
||||||
|
// // Check if the file exists and include it
|
||||||
|
// if (file_exists($file)) {
|
||||||
|
// require_once $file;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// define('APPPATH', '/var/www/html/google_forms/');
|
||||||
|
|
||||||
|
spl_autoload_extensions('.php'); // Only Autoload PHP Files
|
||||||
|
|
||||||
|
spl_autoload_register(function ($classname) {
|
||||||
|
// Convert namespace to the full file path
|
||||||
|
$classfile = APPPATH . str_replace('\\', '/', $classname) . '.php';
|
||||||
|
|
||||||
|
// Check if the file exists and include it
|
||||||
|
if (file_exists($classfile)) {
|
||||||
|
require_once($classfile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// namespace application\controllers;
|
|
||||||
|
|
||||||
defined('BASEPATH') or exit('No direct script access allowed');
|
|
||||||
|
|
||||||
class Form extends CI_Controller
|
|
||||||
{
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
$this->load->model('Form_model');
|
|
||||||
}
|
|
||||||
public function submit()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!$this->session->userdata('logged_in')) {
|
|
||||||
// If not logged in, redirect to login page
|
|
||||||
redirect('users/login');
|
|
||||||
}$form_data = json_decode($this->input->raw_input_stream, true);
|
|
||||||
$this->load->model('Form_model');
|
|
||||||
if ($this->Form_model->save_form($form_data)) {
|
|
||||||
$response = array('status' => 'success', 'message' => 'Form submitted successfully.');
|
|
||||||
} else {
|
|
||||||
$response = array('status' => 'error', 'message' => 'Error submitting form.');
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode($response);
|
|
||||||
}
|
|
||||||
public function view($form_id)
|
|
||||||
{
|
|
||||||
$data['title'] = $this->Form_model->get_form_title($form_id);
|
|
||||||
if ($data['title'] === null) {
|
|
||||||
show_404(); // Show 404 if form_id is invalid
|
|
||||||
}$this->load->view('templates/forms_ui', $data);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,16 +15,18 @@ class Form_controller extends CI_Controller
|
||||||
// If not logged in, redirect to login page
|
// If not logged in, redirect to login page
|
||||||
redirect('users/login');
|
redirect('users/login');
|
||||||
}
|
}
|
||||||
$user_id = $this->session->userdata('user_id');
|
$user_id = $this->session->userdata('user_id')
|
||||||
|
|
||||||
// Retrieve form title from the forms table using form_id
|
|
||||||
$form_title = 'Untitled Form'; // Default title
|
|
||||||
if ($form_id) {
|
// Retrieve form title from the forms table using form_id
|
||||||
$form = $this->Frontend_model->getFormById($form_id);
|
$form_title = 'Untitled Form'; // Default title
|
||||||
if ($form) {
|
if ($form_id) {
|
||||||
$form_title = $form['title'];
|
$form = $this->Frontend_model->getFormById($form_id);
|
||||||
}
|
if ($form) {
|
||||||
}
|
$form_title = $form['title'];
|
||||||
|
}
|
||||||
|
}
|
||||||
// Fetch data from models
|
// Fetch data from models
|
||||||
$data['total_forms'] = $this->Form_model->get_total_forms($user_id);
|
$data['total_forms'] = $this->Form_model->get_total_forms($user_id);
|
||||||
$data['published_forms'] = $this->Form_model->get_published_forms($user_id);
|
$data['published_forms'] = $this->Form_model->get_published_forms($user_id);
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace application\controllers\Testing;
|
||||||
|
|
||||||
|
use CI_Controller;
|
||||||
|
|
||||||
|
class Dummy extends CI_Controller
|
||||||
|
{
|
||||||
|
private ExampleModel $model;
|
||||||
|
|
||||||
|
public function show(int $id): void
|
||||||
|
{
|
||||||
|
$a = $b = 5;
|
||||||
|
// This will trigger Squiz.PHP.DisallowMultipleAssignments
|
||||||
|
|
||||||
|
$item = $this->model->find($id);
|
||||||
|
|
||||||
|
if ($item === null) {
|
||||||
|
$this->notFound();
|
||||||
|
echo "r";
|
||||||
|
|
||||||
|
// This will trigger Squiz.PHP.NonExecutableCode
|
||||||
|
return;
|
||||||
|
|
||||||
|
echo "This will never be executed";
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will trigger Squiz.PHP.DiscouragedFunctions
|
||||||
|
eval('$x = 10;');
|
||||||
|
|
||||||
|
$this->render('views/item_view.php', ['item' => $item]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the index view with data.
|
||||||
|
*
|
||||||
|
* Retrieves data from the model and renders the index view.
|
||||||
|
*/
|
||||||
|
public function index(): void
|
||||||
|
{
|
||||||
|
// This will trigger Squiz.PHP.DisallowComparisonAssignment
|
||||||
|
$isValid = ($user->status === 'active');
|
||||||
|
|
||||||
|
// This will trigger Squiz.PHP.GlobalKeyword
|
||||||
|
global $db;
|
||||||
|
|
||||||
|
$data = $this->model->getData();
|
||||||
|
|
||||||
|
// This introduces an undefined variable, but won't be caught by the specified sniffs
|
||||||
|
$this->render('views/example_view.php', ['data' => $data, 'user' => $userData]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace application\controllers\Testing;
|
||||||
|
|
||||||
|
// defined('BASEPATH') or exit('No direct script access allowed')
|
||||||
|
|
||||||
|
final class Form extends CI_Controller
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->load->model('Form_model');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function submit(): void
|
||||||
|
{
|
||||||
|
if (!$this->session->userdata('logged_in')) {
|
||||||
|
// If not logged in, redirect to login page
|
||||||
|
redirect('users/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->Form_model->save_form($form_data) ? array('status' => 'success', 'message' => 'Form submitted successfully.')
|
||||||
|
: array('status' => 'error', 'message' => 'Error submitting form.');
|
||||||
|
|
||||||
|
echo json_encode($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function view($form_id): void
|
||||||
|
{
|
||||||
|
$data['title'] = $this->Form_model->get_form_title($form_id);
|
||||||
|
|
||||||
|
if ($data['title'] === null) {
|
||||||
|
// Show 404 if form_id is invalid
|
||||||
|
show_404();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->load->view('templates/forms_ui', $data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace MyProject\Controllers;
|
|
||||||
|
|
||||||
use MyProject\Models\ExampleModel;
|
|
||||||
|
|
||||||
class ExampleController
|
|
||||||
{
|
|
||||||
private ExampleModel $model;
|
|
||||||
|
|
||||||
public function show(int $id): void
|
|
||||||
{
|
|
||||||
$item = $this->model->find($id);
|
|
||||||
|
|
||||||
if ($item === null) {
|
|
||||||
$this->notFound();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->render('views/item_view.php', ['item' => $item]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the index view with data.
|
|
||||||
*
|
|
||||||
* Retrieves data from the model and renders the index view.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function index(): void
|
|
||||||
{
|
|
||||||
$data = $this->model->getData();
|
|
||||||
|
|
||||||
$this->render('views/example_view.php', ['data' => $data]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-title,
|
.form-title,
|
||||||
.form-description {
|
.form- description {
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
|
|
@ -1,133 +1,72 @@
|
||||||
$(document).ready(function () {
|
$(document).ready(function () { var base_url = '<?php echo base_url(); ?>' //
|
||||||
var base_url = '<?php echo base_url(); ?>';
|
// Add section button functionality
|
||||||
|
$('#add-section-btn').on('click', function () {
|
||||||
// Add section button functionality
|
var sectionHtml = `
|
||||||
$('#add-section-btn').on('click', function () {
|
<div class="form-section" data-type="">
|
||||||
var sectionHtml = `
|
<div class="header-row">
|
||||||
<div class="form-section" data-type="">
|
<textarea
|
||||||
<div class="header-row">
|
class="form-control untitled-question"
|
||||||
<textarea class="form-control untitled-question" placeholder="Untitled Question" rows="1"></textarea>
|
placeholder="Untitled Question"
|
||||||
<select class="custom-select">
|
rows="1"
|
||||||
<option value="short-answer">Short Answer</option>
|
></textarea>
|
||||||
<option value="paragraph">Paragraph</option>
|
<select class="custom-select">
|
||||||
<option value="multiple-choice">Multiple Choice</option>
|
<option value="short-answer">Short Answer</option>
|
||||||
<option value="checkboxes">Checkboxes</option>
|
<option value="paragraph">Paragraph</option>
|
||||||
<option value="dropdown">Dropdown</option>
|
<option value="multiple-choice">Multiple Choice</option>
|
||||||
</select>
|
<option value="checkboxes">Checkboxes</option>
|
||||||
<label class="toggle-switch">
|
<option value="dropdown">Dropdown</option>
|
||||||
<input type="checkbox" class="required-toggle">
|
</select>
|
||||||
<span class="slider"></span>
|
<label class="toggle-switch">
|
||||||
</label>
|
<input type="checkbox" class="required-toggle" />
|
||||||
<span class="delete-section-icon"><i class="fas fa-trash-alt"></i></span>
|
<span class="slider"></span>
|
||||||
</div>
|
</label>
|
||||||
<div class="options-container"></div>
|
<span class="delete-section-icon"><i class="fas fa-trash-alt"></i></span>
|
||||||
<button class="btn btn-secondary add-option-btn" style="display: none;">Add Option</button></div>
|
</div>
|
||||||
`; $('#form-container').append(sectionHtml);
|
<div class="options-container"></div>
|
||||||
});
|
<button class="btn btn-secondary add-option-btn" style="display: none;">
|
||||||
|
Add Option
|
||||||
// Add option button functionality
|
</button>
|
||||||
$(document).on('click', '.add-option-btn', function () {
|
</div>
|
||||||
var optionHtml = `
|
` $('#form-container').append(sectionHtml) }) // Add option button functionality
|
||||||
<div class="option">
|
$(document).on('click', '.add-option-btn', function () { var optionHtml = `
|
||||||
<input type="text" class="form-control option-label" placeholder="Option">
|
<div class="option">
|
||||||
<span class="delete-option-icon">×</span>
|
<input type="text" class="form-control option-label" placeholder="Option" />
|
||||||
</div>
|
<span class="delete-option-icon">×</span>
|
||||||
`;
|
</div>
|
||||||
$(this).siblings('.options-container').append(optionHtml);
|
` $(this).siblings('.options-container').append(optionHtml) }) // Delete option
|
||||||
});
|
functionality $(document).on('click', '.delete-option-icon', function () {
|
||||||
|
$(this).parent().remove() }) // Delete section functionality
|
||||||
// Delete option functionality
|
$(document).on('click', '.delete-section-icon', function () {
|
||||||
$(document).on('click', '.delete-option-icon', function () {
|
$(this).closest('.form-section').remove() }) // Show/Hide "Add Option" button
|
||||||
$(this).parent().remove();
|
based on question type $(document) .on('change', '.custom-select', function () {
|
||||||
});
|
var type = $(this).val() var $section = $(this).closest('.form-section') if (
|
||||||
|
type === 'multiple-choice' || type === 'checkboxes' || type === 'dropdown' ) {
|
||||||
// Delete section functionality
|
$section.find('.add-option-btn').show() } else {
|
||||||
$(document).on('click', '.delete-section-icon', function () {
|
$section.find('.add-option-btn').hide() } }) .trigger('change') // Trigger
|
||||||
$(this).closest('.form-section').remove();
|
change to apply to existing sections // Submit button functionality
|
||||||
});
|
$('#submit-btn').on('click', function () { var formData = collectFormData()
|
||||||
|
formData['form_id'] = /* eslint-disable */ <? php echo $form['id']; ?>; /*
|
||||||
// Show/Hide "Add Option" button based on question type
|
eslint-enable */ let validation = validateFormData(formData) if
|
||||||
$(document).on('change', '.custom-select', function () {
|
(!validation.isValid) { alert(validation.message) return } $.ajax({ url:
|
||||||
var type = $(this).val();
|
base_url + 'Form_controller/update_form', type: 'POST', data: { formData:
|
||||||
var $section = $(this).closest('.form-section');
|
formData }, dataType: 'JSON', success: function (response) { if (response.status
|
||||||
if (type === 'multiple-choice' || type === 'checkboxes' || type === 'dropdown') {
|
=== 'success') { alert('Form updated successfully!') window.location.href =
|
||||||
$section.find('.add-option-btn').show();
|
base_url + 'Form_controller/index_forms_draft' } else { alert(response.message)
|
||||||
} else {
|
} }, error: function (error) { alert('Error updating form!') console.log(error)
|
||||||
$section.find('.add-option-btn').hide();
|
}, }) }) // Collect form data function function collectFormData() { var formData
|
||||||
}
|
= { title: $('#form-title').val(), description: $('#form-description').val(),
|
||||||
}).trigger('change'); // Trigger change to apply to existing sections
|
questions: [], } $('.form-section').each(function () { var questionData = { id:
|
||||||
|
$(this).data('index'), text: $(this).find('.untitled-question').val(), type:
|
||||||
// Submit button functionality
|
$(this).find('.custom-select').val(), required:
|
||||||
$('#submit-btn').on('click', function () {
|
$(this).find('.required-toggle').is(':checked') ? 1 : 0, // Correctly capture
|
||||||
var formData = collectFormData();
|
the required value options: [], } $(this) .find('.option-label') .each(function
|
||||||
formData['form_id'] = <? php echo $form['id']; ?>;
|
() { questionData.options.push($(this).val()) })
|
||||||
|
formData.questions.push(questionData) }) return formData } function
|
||||||
let validation = validateFormData(formData);
|
validateFormData(formData) { for (let question of formData.questions) { if
|
||||||
if (!validation.isValid) {
|
(!question.text.trim()) { return { isValid: false, message: 'All questions must
|
||||||
alert(validation.message);
|
have text.' } } if ( (question.type === 'multiple-choice' || question.type ===
|
||||||
return;
|
'checkboxes' || question.type === 'dropdown') && question.options.length === 0 )
|
||||||
}
|
{ return { isValid: false, message: 'All options-based questions must have at
|
||||||
|
least one option.', } } for (let option of question.options) { if
|
||||||
$.ajax({
|
(!option.trim()) { return { isValid: false, message: 'All options must have
|
||||||
url: base_url + 'Form_controller/update_form',
|
text.' } } } } return { isValid: true } } })
|
||||||
type: 'POST',
|
|
||||||
data: { formData: formData },
|
|
||||||
dataType: 'JSON',
|
|
||||||
success: function (response) {
|
|
||||||
if (response.status === 'success') {
|
|
||||||
alert('Form updated successfully!');
|
|
||||||
window.location.href = base_url + 'Form_controller/index_forms_draft';
|
|
||||||
} else {
|
|
||||||
alert(response.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function (error) {
|
|
||||||
alert('Error updating form!');
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collect form data function
|
|
||||||
function collectFormData() {
|
|
||||||
var formData = {
|
|
||||||
title: $('#form-title').val(),
|
|
||||||
description: $('#form-description').val(),
|
|
||||||
questions: []
|
|
||||||
};
|
|
||||||
|
|
||||||
$('.form-section').each(function () {
|
|
||||||
var questionData = {
|
|
||||||
id: $(this).data('index'),
|
|
||||||
text: $(this).find('.untitled-question').val(),
|
|
||||||
type: $(this).find('.custom-select').val(),
|
|
||||||
required: $(this).find('.required-toggle').is(':checked') ? 1 : 0, // Correctly capture the required value
|
|
||||||
options: []
|
|
||||||
};
|
|
||||||
|
|
||||||
$(this).find('.option-label').each(function () {
|
|
||||||
questionData.options.push($(this).val());
|
|
||||||
});
|
|
||||||
|
|
||||||
formData.questions.push(questionData);
|
|
||||||
});
|
|
||||||
|
|
||||||
return formData;
|
|
||||||
}
|
|
||||||
function validateFormData(formData) {
|
|
||||||
for (let question of formData.questions) {
|
|
||||||
if (!question.text.trim()) {
|
|
||||||
return { isValid: false, message: 'All questions must have text.' };
|
|
||||||
}
|
|
||||||
if ((question.type === 'multiple-choice' || question.type === 'checkboxes' || question.type === 'dropdown') && question.options.length === 0) {
|
|
||||||
return { isValid: false, message: 'All options-based questions must have at least one option.' };
|
|
||||||
}
|
|
||||||
for (let option of question.options) {
|
|
||||||
if (!option.trim()) {
|
|
||||||
return { isValid: false, message: 'All options must have text.' };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { isValid: true };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
let index = 1
|
let index = 1;
|
||||||
let activeSection = null
|
let activeSection = null;
|
||||||
|
|
||||||
function addOption(type, container) {
|
function addOption(type, container) {
|
||||||
// let optionIndex = container.children().length + 1;
|
// let optionIndex = container.children().length + 1;
|
||||||
let optionHtml
|
let optionHtml;
|
||||||
if (type === 'multiple-choice' || type === 'checkboxes') {
|
if (type === "multiple-choice" || type === "checkboxes") {
|
||||||
optionHtml = `
|
optionHtml = `
|
||||||
<div class="option">
|
<div class="option">
|
||||||
<input type="${type === 'multiple-choice' ? 'radio' : 'checkbox'}" disabled>
|
<input type="${type === "multiple-choice" ? "radio" : "checkbox"}" disabled>
|
||||||
<input type="text" class="form-control option-label" >
|
<input type="text" class="form-control option-label" >
|
||||||
<span class="delete-option-icon">×</span>
|
<span class="delete-option-icon">×</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
} else if (type === 'dropdown') {
|
} else if (type === "dropdown") {
|
||||||
optionHtml = `
|
optionHtml = `
|
||||||
<div class="option">
|
<div class="option">
|
||||||
<input type="text" class="form-control option-label">
|
<input type="text" class="form-control option-label">
|
||||||
<span class="delete-option-icon">×</span>
|
<span class="delete-option-icon">×</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
}
|
}
|
||||||
container.append(optionHtml)
|
container.append(optionHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFormSection() {
|
function createFormSection() {
|
||||||
let newSection = `
|
let newSection = `
|
||||||
<div class="form-section" data-index="${index}">
|
<div class="form-section" data-index="${index}">
|
||||||
<div class="header-row">
|
<div class="header-row">
|
||||||
${index === 1 ? '<div class="violet-border"></div>' : ''}
|
${index === 1 ? '<div class="violet-border"></div>' : ""}
|
||||||
<input type="text" class="form-control untitled-question" placeholder="Untitled Question" rows="1"> <select class="custom-select">
|
<input type="text" class="form-control untitled-question" placeholder="Untitled Question" rows="1"> <select class="custom-select">
|
||||||
<option value="short-answer">Short Answer</option>
|
<option value="short-answer">Short Answer</option>
|
||||||
<option value="paragraph">Paragraph</option>
|
<option value="paragraph">Paragraph</option>
|
||||||
|
@ -44,100 +44,100 @@ $(document).ready(function () {
|
||||||
</div>
|
</div>
|
||||||
<div class="options-container"></div>
|
<div class="options-container"></div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
$('#form-container').append(newSection)
|
$("#form-container").append(newSection);
|
||||||
index++
|
index++;
|
||||||
positionAddSectionButton()
|
positionAddSectionButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
function positionAddSectionButton() {
|
function positionAddSectionButton() {
|
||||||
if (activeSection) {
|
if (activeSection) {
|
||||||
let position = activeSection.position()
|
let position = activeSection.position();
|
||||||
let buttonWidth = $('#add-section-btn').outerWidth()
|
let buttonWidth = $("#add-section-btn").outerWidth();
|
||||||
let buttonHeight = $('#add-section-btn').outerHeight()
|
let buttonHeight = $("#add-section-btn").outerHeight();
|
||||||
|
|
||||||
$('#add-section-btn').css({
|
$("#add-section-btn").css({
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
left: position.left - buttonWidth - 47 + 'px',
|
left: position.left - buttonWidth - 47 + "px",
|
||||||
top:
|
top:
|
||||||
position.top + activeSection.height() / 2 - buttonHeight / 2 + 'px',
|
position.top + activeSection.height() / 2 - buttonHeight / 2 + "px",
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#add-section-btn').on('click', function () {
|
$("#add-section-btn").on("click", function () {
|
||||||
createFormSection()
|
createFormSection();
|
||||||
$('.form-section').removeClass('active')
|
$(".form-section").removeClass("active");
|
||||||
activeSection = $('.form-section').last()
|
activeSection = $(".form-section").last();
|
||||||
activeSection.addClass('active')
|
activeSection.addClass("active");
|
||||||
positionAddSectionButton()
|
positionAddSectionButton();
|
||||||
})
|
});
|
||||||
|
|
||||||
$(document).on('change', '.custom-select', function () {
|
$(document).on("change", ".custom-select", function () {
|
||||||
let type = $(this).val()
|
let type = $(this).val();
|
||||||
let container = $(this).closest('.form-section').find('.options-container')
|
let container = $(this).closest(".form-section").find(".options-container");
|
||||||
container.empty()
|
container.empty();
|
||||||
$(this).closest('.form-section').find('.add-option-btn').remove()
|
$(this).closest(".form-section").find(".add-option-btn").remove();
|
||||||
|
|
||||||
if (type === 'short-answer') {
|
if (type === "short-answer") {
|
||||||
container.append(
|
container.append(
|
||||||
'<input type="text" class="form-control" disabled placeholder="Short answer text">'
|
'<input type="text" class="form-control" disabled placeholder="Short answer text">',
|
||||||
)
|
);
|
||||||
} else if (type === 'paragraph') {
|
} else if (type === "paragraph") {
|
||||||
container.append(
|
container.append(
|
||||||
'<textarea class="form-control" disabled placeholder="Paragraph text"></textarea>'
|
'<textarea class="form-control" disabled placeholder="Paragraph text"></textarea>',
|
||||||
)
|
);
|
||||||
} else {
|
} else {
|
||||||
addOption(type, container)
|
addOption(type, container);
|
||||||
$(this)
|
$(this)
|
||||||
.closest('.form-section')
|
.closest(".form-section")
|
||||||
.append(
|
.append(
|
||||||
'<button class="btn btn-secondary add-option-btn">Add Option</button>'
|
'<button class="btn btn-secondary add-option-btn">Add Option</button>',
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
$(document).on('click', '.add-option-btn', function () {
|
$(document).on("click", ".add-option-btn", function () {
|
||||||
let type = $(this).closest('.form-section').find('.custom-select').val()
|
let type = $(this).closest(".form-section").find(".custom-select").val();
|
||||||
let container = $(this).closest('.form-section').find('.options-container')
|
let container = $(this).closest(".form-section").find(".options-container");
|
||||||
addOption(type, container)
|
addOption(type, container);
|
||||||
})
|
});
|
||||||
|
|
||||||
$(document).on('click', '.delete-section-icon', function () {
|
$(document).on("click", ".delete-section-icon", function () {
|
||||||
let section = $(this).closest('.form-section')
|
let section = $(this).closest(".form-section");
|
||||||
let prevSection = section.prev('.form-section')
|
let prevSection = section.prev(".form-section");
|
||||||
let nextSection = section.next('.form-section')
|
let nextSection = section.next(".form-section");
|
||||||
section.remove()
|
section.remove();
|
||||||
if (section.hasClass('active')) {
|
if (section.hasClass("active")) {
|
||||||
activeSection = null
|
activeSection = null;
|
||||||
}
|
}
|
||||||
if (prevSection.length > 0) {
|
if (prevSection.length > 0) {
|
||||||
prevSection
|
prevSection
|
||||||
.find('.delete-section-icon')
|
.find(".delete-section-icon")
|
||||||
.appendTo(prevSection.find('.form-section'))
|
.appendTo(prevSection.find(".form-section"));
|
||||||
activeSection = prevSection
|
activeSection = prevSection;
|
||||||
row
|
row;
|
||||||
} else if (nextSection.length > 0) {
|
} else if (nextSection.length > 0) {
|
||||||
nextSection
|
nextSection
|
||||||
.find('.delete-section-icon')
|
.find(".delete-section-icon")
|
||||||
.appendTo(nextSection.find('.form-header'))
|
.appendTo(nextSection.find(".form-header"));
|
||||||
activeSection = nextSection
|
activeSection = nextSection;
|
||||||
}
|
}
|
||||||
positionAddSectionButton()
|
positionAddSectionButton();
|
||||||
})
|
});
|
||||||
|
|
||||||
$(document).on('click', '.delete-option-icon', function () {
|
$(document).on("click", ".delete-option-icon", function () {
|
||||||
let option = $(this).closest('.option')
|
let option = $(this).closest(".option");
|
||||||
let container = option.closest('.options-container')
|
let container = option.closest(".options-container");
|
||||||
option.remove()
|
option.remove();
|
||||||
})
|
});
|
||||||
|
|
||||||
$(document).on('click', '.required-toggle', function () {
|
$(document).on("click", ".required-toggle", function () {
|
||||||
$(this).closest('.form-section').toggleClass('required')
|
$(this).closest(".form-section").toggleClass("required");
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#preview-btn').on('click', function () {
|
$("#preview-btn").on("click", function () {
|
||||||
let previewWindow = window.open('', '_blank')
|
let previewWindow = window.open("", "_blank");
|
||||||
let previewContent = `
|
let previewContent = `
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -157,189 +157,189 @@ $(document).ready(function () {
|
||||||
<div class="form-header">
|
<div class="form-header">
|
||||||
<h3>Form Preview</h3>
|
<h3>Form Preview</h3>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
$('.form-section').each(function () {
|
$(".form-section").each(function () {
|
||||||
previewContent += '<div class="form-section">'
|
previewContent += '<div class="form-section">';
|
||||||
previewContent += '<div class="question-section">'
|
previewContent += '<div class="question-section">';
|
||||||
previewContent +=
|
previewContent +=
|
||||||
'<div class="question-label">' +
|
'<div class="question-label">' +
|
||||||
$(this).find('.untitled-question').val() +
|
$(this).find(".untitled-question").val() +
|
||||||
'</div>'
|
"</div>";
|
||||||
previewContent += '</div>'
|
previewContent += "</div>";
|
||||||
let type = $(this).find('.custom-select').val()
|
let type = $(this).find(".custom-select").val();
|
||||||
let optionsContainer = $(this).find('.options-container')
|
let optionsContainer = $(this).find(".options-container");
|
||||||
|
|
||||||
if (type === 'multiple-choice') {
|
if (type === "multiple-choice") {
|
||||||
optionsContainer.find('.option').each(function () {
|
optionsContainer.find(".option").each(function () {
|
||||||
previewContent += `
|
previewContent += `
|
||||||
<div class="option">
|
<div class="option">
|
||||||
<input type="radio" name="option-${index}">
|
<input type="radio" name="option-${index}">
|
||||||
<label>${$(this).find('.option-label').val()}</label>
|
<label>${$(this).find(".option-label").val()}</label>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
})
|
});
|
||||||
} else if (type === 'checkboxes') {
|
} else if (type === "checkboxes") {
|
||||||
optionsContainer.find('.option').each(function () {
|
optionsContainer.find(".option").each(function () {
|
||||||
previewContent += `
|
previewContent += `
|
||||||
<div class="option">
|
<div class="option">
|
||||||
<input type="checkbox">
|
<input type="checkbox">
|
||||||
<label>${$(this).find('.option-label').val()}</label>
|
<label>${$(this).find(".option-label").val()}</label>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
})
|
});
|
||||||
} else if (type === 'short-answer') {
|
} else if (type === "short-answer") {
|
||||||
previewContent +=
|
previewContent +=
|
||||||
'<input type="text" class="form-control" placeholder="Short answer text">'
|
'<input type="text" class="form-control" placeholder="Short answer text">';
|
||||||
} else if (type === 'paragraph') {
|
} else if (type === "paragraph") {
|
||||||
previewContent +=
|
previewContent +=
|
||||||
'<textarea class="form-control" placeholder="Paragraph text"></textarea>'
|
'<textarea class="form-control" placeholder="Paragraph text"></textarea>';
|
||||||
} else if (type === 'dropdown') {
|
} else if (type === "dropdown") {
|
||||||
let dropdownHtml = '<select class="form-control">'
|
let dropdownHtml = '<select class="form-control">';
|
||||||
optionsContainer.find('.option .option-label').each(function () {
|
optionsContainer.find(".option .option-label").each(function () {
|
||||||
dropdownHtml += `<option>${$(this).val()}</option>`
|
dropdownHtml += `<option>${$(this).val()}</option>`;
|
||||||
})
|
});
|
||||||
dropdownHtml += '</select>'
|
dropdownHtml += "</select>";
|
||||||
previewContent += dropdownHtml
|
previewContent += dropdownHtml;
|
||||||
}
|
}
|
||||||
previewContent += '</div>'
|
previewContent += "</div>";
|
||||||
})
|
});
|
||||||
previewContent += `
|
previewContent += `
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`
|
`;
|
||||||
previewWindow.document.write(previewContent)
|
previewWindow.document.write(previewContent);
|
||||||
previewWindow.document.close()
|
previewWindow.document.close();
|
||||||
})
|
});
|
||||||
|
|
||||||
$(document).on('click', '.form-section', function () {
|
$(document).on("click", ".form-section", function () {
|
||||||
$('.form-section').removeClass('active')
|
$(".form-section").removeClass("active");
|
||||||
$(this).addClass('active')
|
$(this).addClass("active");
|
||||||
activeSection = $(this)
|
activeSection = $(this);
|
||||||
positionAddSectionButton()
|
positionAddSectionButton();
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#form-container').sortable({
|
$("#form-container").sortable({
|
||||||
placeholder: 'ui-state-highlight',
|
placeholder: "ui-state-highlight",
|
||||||
start: function (event, ui) {
|
start: function (event, ui) {
|
||||||
ui.placeholder.height(ui.item.height())
|
ui.placeholder.height(ui.item.height());
|
||||||
},
|
},
|
||||||
stop: function (event, ui) {
|
stop: function (event, ui) {
|
||||||
positionAddSectionButton()
|
positionAddSectionButton();
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
function collectFormData() {
|
function collectFormData() {
|
||||||
var formData = {
|
var formData = {
|
||||||
questions: [],
|
questions: [],
|
||||||
}
|
};
|
||||||
|
|
||||||
$('.form-section').each(function () {
|
$(".form-section").each(function () {
|
||||||
var questionType = $(this).find('.custom-select').val()
|
var questionType = $(this).find(".custom-select").val();
|
||||||
var questionData = {
|
var questionData = {
|
||||||
text: $(this).find('.untitled-question').val(),
|
text: $(this).find(".untitled-question").val(),
|
||||||
type: questionType,
|
type: questionType,
|
||||||
is_required: $(this).find('.required-toggle').is(':checked'),
|
is_required: $(this).find(".required-toggle").is(":checked"),
|
||||||
options: [],
|
options: [],
|
||||||
}
|
};
|
||||||
|
|
||||||
// Only add options if the question type supports them
|
// Only add options if the question type supports them
|
||||||
if (
|
if (
|
||||||
questionType === 'multiple-choice' ||
|
questionType === "multiple-choice" ||
|
||||||
questionType === 'checkboxes' ||
|
questionType === "checkboxes" ||
|
||||||
questionType === 'dropdown'
|
questionType === "dropdown"
|
||||||
) {
|
) {
|
||||||
$(this)
|
$(this)
|
||||||
.find('.option-label')
|
.find(".option-label")
|
||||||
.each(function () {
|
.each(function () {
|
||||||
questionData.options.push($(this).val())
|
questionData.options.push($(this).val());
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formData.questions.push(questionData)
|
formData.questions.push(questionData);
|
||||||
})
|
});
|
||||||
|
|
||||||
console.log(formData)
|
console.log(formData);
|
||||||
return formData
|
return formData;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateFormData(formData) {
|
function validateFormData(formData) {
|
||||||
for (let question of formData.questions) {
|
for (let question of formData.questions) {
|
||||||
if (!question.text.trim()) {
|
if (!question.text.trim()) {
|
||||||
return { isValid: false, message: 'All questions must have text.' }
|
return { isValid: false, message: "All questions must have text." };
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(question.type === 'multiple-choice' ||
|
(question.type === "multiple-choice" ||
|
||||||
question.type === 'checkboxes' ||
|
question.type === "checkboxes" ||
|
||||||
question.type === 'dropdown') &&
|
question.type === "dropdown") &&
|
||||||
question.options.length === 0
|
question.options.length === 0
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
message: 'All options-based questions must have at least one option.',
|
message: "All options-based questions must have at least one option.",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
for (let option of question.options) {
|
for (let option of question.options) {
|
||||||
if (!option.trim()) {
|
if (!option.trim()) {
|
||||||
return { isValid: false, message: 'All options must have text.' }
|
return { isValid: false, message: "All options must have text." };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { isValid: true }
|
return { isValid: true };
|
||||||
}
|
}
|
||||||
$('#submit-btn').on('click', function () {
|
$("#submit-btn").on("click", function () {
|
||||||
let formData = collectFormData()
|
let formData = collectFormData();
|
||||||
console.log(formData)
|
console.log(formData);
|
||||||
|
|
||||||
let validation = validateFormData(formData)
|
let validation = validateFormData(formData);
|
||||||
if (!validation.isValid) {
|
if (!validation.isValid) {
|
||||||
alert(validation.message)
|
alert(validation.message);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: base_url + 'New_form_controller/submit_form',
|
url: base_url + "New_form_controller/submit_form",
|
||||||
type: 'POST',
|
type: "POST",
|
||||||
data: { formData: formData },
|
data: { formData: formData },
|
||||||
dataType: 'JSON',
|
dataType: "JSON",
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (response.status === 'success') {
|
if (response.status === "success") {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Success!',
|
title: "Success!",
|
||||||
text: 'Form submitted successfully!',
|
text: "Form submitted successfully!",
|
||||||
icon: 'success',
|
icon: "success",
|
||||||
confirmButtonText: 'OK',
|
confirmButtonText: "OK",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
window.location.href = base_url
|
window.location.href = base_url;
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Error!',
|
title: "Error!",
|
||||||
text: response.message,
|
text: response.message,
|
||||||
icon: 'error',
|
icon: "error",
|
||||||
confirmButtonText: 'OK',
|
confirmButtonText: "OK",
|
||||||
})
|
});
|
||||||
console.log(response)
|
console.log(response);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (error) {
|
error: function (error) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Error!',
|
title: "Error!",
|
||||||
text: 'Error submitting form!',
|
text: "Error submitting form!",
|
||||||
icon: 'error',
|
icon: "error",
|
||||||
confirmButtonText: 'OK',
|
confirmButtonText: "OK",
|
||||||
width: '400px',
|
width: "400px",
|
||||||
height: '300px',
|
height: "300px",
|
||||||
padding: 'auto',
|
padding: "auto",
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
window.location.href = home
|
window.location.href = home;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
console.log(error)
|
console.log(error);
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
$('#form-container').disableSelection()
|
$("#form-container").disableSelection();
|
||||||
})
|
});
|
||||||
|
|
|
@ -1,35 +1,36 @@
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
let index = 1
|
let index = 1;
|
||||||
let activeSection = null
|
let activeSection = null;
|
||||||
|
|
||||||
function addOption(type, container) {
|
function addOption(type, container) {
|
||||||
let optionHtml
|
let optionHtml;
|
||||||
|
|
||||||
if (type === 'multiple-choice' || type === 'checkboxes') {
|
if (type === "multiple-choice" || type === "checkboxes") {
|
||||||
optionHtml = `
|
optionHtml = `
|
||||||
<div class="option">
|
|
||||||
<input type="${type === 'multiple-choice' ? 'radio' : 'checkbox'}" disabled>
|
<div class="option">
|
||||||
<input type="text" class="form-control option-label">
|
<input type="${type === "multiple-choice" ? "radio" : "checkbox"}" disabled>
|
||||||
|
<input type="text" class="form-control option-label">
|
||||||
|
|
||||||
<span class="delete-option-icon">×</span>
|
<span class="delete-option-icon">×</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
} else if (type === 'dropdown') {
|
} else if (type === "dropdown") {
|
||||||
optionHtml = `
|
optionHtml = `
|
||||||
<div class="option">
|
<div class="option">
|
||||||
<input type="text" class="form-control option-label">
|
<input type="text" class="form-control option-label">
|
||||||
<span class="delete-option-icon">×</span>
|
<span class="delete-option-icon">×</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
}
|
}
|
||||||
container.append(optionHtml)
|
container.append(optionHtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFormSection() {
|
function createFormSection() {
|
||||||
let newSection = `
|
let newSection = `
|
||||||
<div class="form-section" data-index="${index}">
|
<div class="form-section" data-index="${index}">
|
||||||
<div class="header-row">
|
<div class="header-row">
|
||||||
${index === 1 ? '<div class="violet-border"></div>' : ''}
|
${index === 1 ? '<div class="violet-border"></div>' : ""}
|
||||||
<textarea class="form-control untitled-question" placeholder="Untitled Question" rows="1"></textarea>
|
<textarea class="form-control untitled-question" placeholder="Untitled Question" rows="1"></textarea>
|
||||||
<select class="custom-select">
|
<select class="custom-select">
|
||||||
<option value="short-answer">Short Answer</option>
|
<option value="short-answer">Short Answer</option>
|
||||||
|
@ -46,58 +47,58 @@ $(document).ready(function () {
|
||||||
</div>
|
</div>
|
||||||
<div class="options-container"></div>
|
<div class="options-container"></div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
$('#form-container').append(newSection)
|
$("#form-container").append(newSection);
|
||||||
index++
|
index++;
|
||||||
|
|
||||||
positionAddSectionButton()
|
positionAddSectionButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
function positionAddSectionButton() {
|
function positionAddSectionButton() {
|
||||||
if (activeSection) {
|
if (activeSection) {
|
||||||
let position = activeSection.position()
|
let position = activeSection.position();
|
||||||
let buttonWidth = $('#add-section-btn').outerWidth()
|
let buttonWidth = $("#add-section-btn").outerWidth();
|
||||||
let buttonHeight = $('#add-section-btn').outerHeight()
|
let buttonHeight = $("#add-section-btn").outerHeight();
|
||||||
|
|
||||||
$('#add-section-btn').css({
|
$("#add-section-btn").css({
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
left: position.left - buttonWidth - 47 + 'px',
|
left: position.left - buttonWidth - 47 + "px",
|
||||||
top:
|
top:
|
||||||
position.top + activeSection.height() / 2 - buttonHeight / 2 + 'px',
|
position.top + activeSection.height() / 2 - buttonHeight / 2 + "px",
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#add-section-btn').on('click', function () {
|
$("#add-section-btn").on("click", function () {
|
||||||
createFormSection()
|
createFormSection();
|
||||||
$('.form-section').removeClass('active')
|
$(".form-section").removeClass("active");
|
||||||
activeSection = $('.form-section').last()
|
activeSection = $(".form-section").last();
|
||||||
activeSection.addClass('active')
|
activeSection.addClass("active");
|
||||||
positionAddSectionButton()
|
positionAddSectionButton();
|
||||||
})
|
});
|
||||||
|
|
||||||
$(document).on('change', '.custom-select', function () {
|
$(document).on("change", ".custom-select", function () {
|
||||||
let type = $(this).val()
|
let type = $(this).val();
|
||||||
let container = $(this).closest('.form-section').find('.options-container')
|
let container = $(this).closest(".form-section").find(".options-container");
|
||||||
container.empty()
|
container.empty();
|
||||||
|
|
||||||
$(this).closest('.form-section').find('.add-option-btn').remove()
|
$(this).closest(".form-section").find(".add-option-btn").remove();
|
||||||
|
|
||||||
if (type === 'short-answer') {
|
if (type === "short-answer") {
|
||||||
container.append(
|
container.append(
|
||||||
'<input type="text" class="form-control" disabled placeholder="Short answer text">'
|
'<input type="text" class="form-control" disabled placeholder="Short answer text">',
|
||||||
)
|
);
|
||||||
} else if (type === 'paragraph') {
|
} else if (type === "paragraph") {
|
||||||
container.append(
|
container.append(
|
||||||
'<textarea class="form-control" disabled placeholder="Paragraph text"></textarea>'
|
'<textarea class="form-control" disabled placeholder="Paragraph text"></textarea>',
|
||||||
)
|
);
|
||||||
} else {
|
} else {
|
||||||
addOption(type, container)
|
addOption(type, container);
|
||||||
$(this)
|
$(this)
|
||||||
.closest('.form-section')
|
.closest(".form-section")
|
||||||
.append(
|
.append(
|
||||||
'<button class="btn btn-secondary add-option-btn">Add Option</button>'
|
'<button class="btn btn-secondary add-option-btn">Add Option</button>',
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/custom_sniffs/Sniffs/NamespaceMatchesDirectorySniff.php';
|
||||||
|
echo "Bootstrap file loaded.\n";
|
|
@ -10,9 +10,9 @@
|
||||||
"slack": "https://codeigniterchat.slack.com",
|
"slack": "https://codeigniterchat.slack.com",
|
||||||
"source": "https://github.com/bcit-ci/CodeIgniter"
|
"source": "https://github.com/bcit-ci/CodeIgniter"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.7"
|
"php": ">=7.4"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"paragonie/random_compat": "Provides better randomness in PHP 5.x"
|
"paragonie/random_compat": "Provides better randomness in PHP 5.x"
|
||||||
},
|
},
|
||||||
|
@ -31,6 +31,19 @@
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mikey179/vfsstream": "1.6.*",
|
"mikey179/vfsstream": "1.6.*",
|
||||||
"phpunit/phpunit": "4.* || 5.* || 9.*",
|
"phpunit/phpunit": "4.* || 5.* || 9.*",
|
||||||
"squizlabs/php_codesniffer": "^3.5"
|
"squizlabs/php_codesniffer": "^3.10",
|
||||||
|
"slevomat/coding-standard": "^8.15"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
,
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"CustomSniffs\\": "custom_sniffs/",
|
||||||
|
"App\\": "application/"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,87 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "e56478c624f38d66a8457b936ab02732",
|
"content-hash": "3aa20e9993bebd9d273b0335f238881f",
|
||||||
"packages": [],
|
"packages": [],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
|
{
|
||||||
|
"name": "dealerdirect/phpcodesniffer-composer-installer",
|
||||||
|
"version": "v1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/PHPCSStandards/composer-installer.git",
|
||||||
|
"reference": "4be43904336affa5c2f70744a348312336afd0da"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da",
|
||||||
|
"reference": "4be43904336affa5c2f70744a348312336afd0da",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer-plugin-api": "^1.0 || ^2.0",
|
||||||
|
"php": ">=5.4",
|
||||||
|
"squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"composer/composer": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"php-parallel-lint/php-parallel-lint": "^1.3.1",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.0",
|
||||||
|
"yoast/phpunit-polyfills": "^1.0"
|
||||||
|
},
|
||||||
|
"type": "composer-plugin",
|
||||||
|
"extra": {
|
||||||
|
"class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Franck Nijhof",
|
||||||
|
"email": "franck.nijhof@dealerdirect.com",
|
||||||
|
"homepage": "http://www.frenck.nl",
|
||||||
|
"role": "Developer / IT Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Contributors",
|
||||||
|
"homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP_CodeSniffer Standards Composer Installer Plugin",
|
||||||
|
"homepage": "http://www.dealerdirect.com",
|
||||||
|
"keywords": [
|
||||||
|
"PHPCodeSniffer",
|
||||||
|
"PHP_CodeSniffer",
|
||||||
|
"code quality",
|
||||||
|
"codesniffer",
|
||||||
|
"composer",
|
||||||
|
"installer",
|
||||||
|
"phpcbf",
|
||||||
|
"phpcs",
|
||||||
|
"plugin",
|
||||||
|
"qa",
|
||||||
|
"quality",
|
||||||
|
"standard",
|
||||||
|
"standards",
|
||||||
|
"style guide",
|
||||||
|
"stylecheck",
|
||||||
|
"tests"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/PHPCSStandards/composer-installer/issues",
|
||||||
|
"source": "https://github.com/PHPCSStandards/composer-installer"
|
||||||
|
},
|
||||||
|
"time": "2023-01-05T11:28:13+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/instantiator",
|
"name": "doctrine/instantiator",
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
|
@ -41,7 +119,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["MIT"],
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Marco Pivetta",
|
"name": "Marco Pivetta",
|
||||||
|
@ -51,7 +131,10 @@
|
||||||
],
|
],
|
||||||
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
||||||
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
|
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
|
||||||
"keywords": ["constructor", "instantiate"],
|
"keywords": [
|
||||||
|
"constructor",
|
||||||
|
"instantiate"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/doctrine/instantiator/issues",
|
"issues": "https://github.com/doctrine/instantiator/issues",
|
||||||
"source": "https://github.com/doctrine/instantiator/tree/1.5.0"
|
"source": "https://github.com/doctrine/instantiator/tree/1.5.0"
|
||||||
|
@ -104,7 +187,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Frank Kleine",
|
"name": "Frank Kleine",
|
||||||
|
@ -150,15 +235,25 @@
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": ["src/DeepCopy/deep_copy.php"],
|
"files": [
|
||||||
|
"src/DeepCopy/deep_copy.php"
|
||||||
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"DeepCopy\\": "src/DeepCopy/"
|
"DeepCopy\\": "src/DeepCopy/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["MIT"],
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
"description": "Create deep copies (clones) of your objects",
|
"description": "Create deep copies (clones) of your objects",
|
||||||
"keywords": ["clone", "copy", "duplicate", "object", "object graph"],
|
"keywords": [
|
||||||
|
"clone",
|
||||||
|
"copy",
|
||||||
|
"duplicate",
|
||||||
|
"object",
|
||||||
|
"object graph"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
|
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
|
||||||
|
@ -195,7 +290,9 @@
|
||||||
"ircmaxell/php-yacc": "^0.0.7",
|
"ircmaxell/php-yacc": "^0.0.7",
|
||||||
"phpunit/phpunit": "^9.0"
|
"phpunit/phpunit": "^9.0"
|
||||||
},
|
},
|
||||||
"bin": ["bin/php-parse"],
|
"bin": [
|
||||||
|
"bin/php-parse"
|
||||||
|
],
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
|
@ -208,14 +305,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Nikita Popov"
|
"name": "Nikita Popov"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "A PHP parser written in PHP",
|
"description": "A PHP parser written in PHP",
|
||||||
"keywords": ["parser", "php"],
|
"keywords": [
|
||||||
|
"parser",
|
||||||
|
"php"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0"
|
"source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0"
|
||||||
|
@ -251,10 +353,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Arne Blankerts",
|
"name": "Arne Blankerts",
|
||||||
|
@ -304,10 +410,14 @@
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Arne Blankerts",
|
"name": "Arne Blankerts",
|
||||||
|
@ -332,6 +442,53 @@
|
||||||
},
|
},
|
||||||
"time": "2022-02-21T01:04:05+00:00"
|
"time": "2022-02-21T01:04:05+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "phpstan/phpdoc-parser",
|
||||||
|
"version": "1.29.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||||
|
"reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/fcaefacf2d5c417e928405b71b400d4ce10daaf4",
|
||||||
|
"reference": "fcaefacf2d5c417e928405b71b400d4ce10daaf4",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/annotations": "^2.0",
|
||||||
|
"nikic/php-parser": "^4.15",
|
||||||
|
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||||
|
"phpstan/extension-installer": "^1.0",
|
||||||
|
"phpstan/phpstan": "^1.5",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.1",
|
||||||
|
"phpstan/phpstan-strict-rules": "^1.0",
|
||||||
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"symfony/process": "^5.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PHPStan\\PhpDocParser\\": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||||
|
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.1"
|
||||||
|
},
|
||||||
|
"time": "2024-05-31T08:52:43+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "9.2.31",
|
"version": "9.2.31",
|
||||||
|
@ -375,10 +532,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -388,7 +549,11 @@
|
||||||
],
|
],
|
||||||
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
|
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
|
||||||
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
|
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
|
||||||
"keywords": ["coverage", "testing", "xunit"],
|
"keywords": [
|
||||||
|
"coverage",
|
||||||
|
"testing",
|
||||||
|
"xunit"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||||
|
@ -429,10 +594,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -442,7 +611,10 @@
|
||||||
],
|
],
|
||||||
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
|
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
|
||||||
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
|
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
|
||||||
"keywords": ["filesystem", "iterator"],
|
"keywords": [
|
||||||
|
"filesystem",
|
||||||
|
"iterator"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
|
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
|
||||||
|
@ -486,10 +658,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -499,7 +675,9 @@
|
||||||
],
|
],
|
||||||
"description": "Invoke callables with a timeout",
|
"description": "Invoke callables with a timeout",
|
||||||
"homepage": "https://github.com/sebastianbergmann/php-invoker/",
|
"homepage": "https://github.com/sebastianbergmann/php-invoker/",
|
||||||
"keywords": ["process"],
|
"keywords": [
|
||||||
|
"process"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-invoker/issues",
|
"issues": "https://github.com/sebastianbergmann/php-invoker/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
|
"source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
|
||||||
|
@ -539,10 +717,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -552,7 +734,9 @@
|
||||||
],
|
],
|
||||||
"description": "Simple template engine.",
|
"description": "Simple template engine.",
|
||||||
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
|
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
|
||||||
"keywords": ["template"],
|
"keywords": [
|
||||||
|
"template"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
|
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
|
"source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
|
||||||
|
@ -592,10 +776,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -605,7 +793,9 @@
|
||||||
],
|
],
|
||||||
"description": "Utility class for timing",
|
"description": "Utility class for timing",
|
||||||
"homepage": "https://github.com/sebastianbergmann/php-timer/",
|
"homepage": "https://github.com/sebastianbergmann/php-timer/",
|
||||||
"keywords": ["timer"],
|
"keywords": [
|
||||||
|
"timer"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
|
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
|
"source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
|
||||||
|
@ -665,7 +855,9 @@
|
||||||
"ext-soap": "To be able to generate mocks based on WSDL files",
|
"ext-soap": "To be able to generate mocks based on WSDL files",
|
||||||
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
|
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
|
||||||
},
|
},
|
||||||
"bin": ["phpunit"],
|
"bin": [
|
||||||
|
"phpunit"
|
||||||
|
],
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
|
@ -673,11 +865,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": ["src/Framework/Assert/Functions.php"],
|
"files": [
|
||||||
"classmap": ["src/"]
|
"src/Framework/Assert/Functions.php"
|
||||||
|
],
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -687,7 +885,11 @@
|
||||||
],
|
],
|
||||||
"description": "The PHP Unit Testing framework.",
|
"description": "The PHP Unit Testing framework.",
|
||||||
"homepage": "https://phpunit.de/",
|
"homepage": "https://phpunit.de/",
|
||||||
"keywords": ["phpunit", "testing", "xunit"],
|
"keywords": [
|
||||||
|
"phpunit",
|
||||||
|
"testing",
|
||||||
|
"xunit"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||||
|
@ -736,10 +938,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -788,10 +994,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -840,10 +1050,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -893,10 +1107,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -917,7 +1135,11 @@
|
||||||
],
|
],
|
||||||
"description": "Provides the functionality to compare PHP values for equality",
|
"description": "Provides the functionality to compare PHP values for equality",
|
||||||
"homepage": "https://github.com/sebastianbergmann/comparator",
|
"homepage": "https://github.com/sebastianbergmann/comparator",
|
||||||
"keywords": ["comparator", "compare", "equality"],
|
"keywords": [
|
||||||
|
"comparator",
|
||||||
|
"compare",
|
||||||
|
"equality"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
|
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
|
||||||
|
@ -958,10 +1180,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1011,10 +1237,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1027,7 +1257,12 @@
|
||||||
],
|
],
|
||||||
"description": "Diff implementation",
|
"description": "Diff implementation",
|
||||||
"homepage": "https://github.com/sebastianbergmann/diff",
|
"homepage": "https://github.com/sebastianbergmann/diff",
|
||||||
"keywords": ["diff", "udiff", "unidiff", "unified diff"],
|
"keywords": [
|
||||||
|
"diff",
|
||||||
|
"udiff",
|
||||||
|
"unidiff",
|
||||||
|
"unified diff"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
"issues": "https://github.com/sebastianbergmann/diff/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
|
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
|
||||||
|
@ -1070,10 +1305,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1082,7 +1321,11 @@
|
||||||
],
|
],
|
||||||
"description": "Provides functionality to handle HHVM/PHP environments",
|
"description": "Provides functionality to handle HHVM/PHP environments",
|
||||||
"homepage": "http://www.github.com/sebastianbergmann/environment",
|
"homepage": "http://www.github.com/sebastianbergmann/environment",
|
||||||
"keywords": ["Xdebug", "environment", "hhvm"],
|
"keywords": [
|
||||||
|
"Xdebug",
|
||||||
|
"environment",
|
||||||
|
"hhvm"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/environment/issues",
|
"issues": "https://github.com/sebastianbergmann/environment/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
|
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
|
||||||
|
@ -1124,10 +1367,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1152,7 +1399,10 @@
|
||||||
],
|
],
|
||||||
"description": "Provides the functionality to export PHP variables for visualization",
|
"description": "Provides the functionality to export PHP variables for visualization",
|
||||||
"homepage": "https://www.github.com/sebastianbergmann/exporter",
|
"homepage": "https://www.github.com/sebastianbergmann/exporter",
|
||||||
"keywords": ["export", "exporter"],
|
"keywords": [
|
||||||
|
"export",
|
||||||
|
"exporter"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
"issues": "https://github.com/sebastianbergmann/exporter/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
|
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
|
||||||
|
@ -1198,10 +1448,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1210,7 +1464,9 @@
|
||||||
],
|
],
|
||||||
"description": "Snapshotting of global state",
|
"description": "Snapshotting of global state",
|
||||||
"homepage": "http://www.github.com/sebastianbergmann/global-state",
|
"homepage": "http://www.github.com/sebastianbergmann/global-state",
|
||||||
"keywords": ["global state"],
|
"keywords": [
|
||||||
|
"global state"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
"issues": "https://github.com/sebastianbergmann/global-state/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
|
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
|
||||||
|
@ -1251,10 +1507,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1305,10 +1565,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1356,10 +1620,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1407,10 +1675,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1466,10 +1738,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1516,10 +1792,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1565,10 +1845,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Sebastian Bergmann",
|
"name": "Sebastian Bergmann",
|
||||||
|
@ -1590,6 +1874,71 @@
|
||||||
],
|
],
|
||||||
"time": "2020-09-28T06:39:44+00:00"
|
"time": "2020-09-28T06:39:44+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "slevomat/coding-standard",
|
||||||
|
"version": "8.15.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/slevomat/coding-standard.git",
|
||||||
|
"reference": "7d1d957421618a3803b593ec31ace470177d7817"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817",
|
||||||
|
"reference": "7d1d957421618a3803b593ec31ace470177d7817",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0",
|
||||||
|
"php": "^7.2 || ^8.0",
|
||||||
|
"phpstan/phpdoc-parser": "^1.23.1",
|
||||||
|
"squizlabs/php_codesniffer": "^3.9.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phing/phing": "2.17.4",
|
||||||
|
"php-parallel-lint/php-parallel-lint": "1.3.2",
|
||||||
|
"phpstan/phpstan": "1.10.60",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "1.1.4",
|
||||||
|
"phpstan/phpstan-phpunit": "1.3.16",
|
||||||
|
"phpstan/phpstan-strict-rules": "1.5.2",
|
||||||
|
"phpunit/phpunit": "8.5.21|9.6.8|10.5.11"
|
||||||
|
},
|
||||||
|
"type": "phpcodesniffer-standard",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "8.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"SlevomatCodingStandard\\": "SlevomatCodingStandard/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.",
|
||||||
|
"keywords": [
|
||||||
|
"dev",
|
||||||
|
"phpcs"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/slevomat/coding-standard/issues",
|
||||||
|
"source": "https://github.com/slevomat/coding-standard/tree/8.15.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/kukulich",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-03-09T15:20:58+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "squizlabs/php_codesniffer",
|
"name": "squizlabs/php_codesniffer",
|
||||||
"version": "3.10.2",
|
"version": "3.10.2",
|
||||||
|
@ -1613,7 +1962,10 @@
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
|
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4"
|
||||||
},
|
},
|
||||||
"bin": ["bin/phpcbf", "bin/phpcs"],
|
"bin": [
|
||||||
|
"bin/phpcbf",
|
||||||
|
"bin/phpcs"
|
||||||
|
],
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
|
@ -1621,7 +1973,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Greg Sherwood",
|
"name": "Greg Sherwood",
|
||||||
|
@ -1638,7 +1992,11 @@
|
||||||
],
|
],
|
||||||
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
||||||
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
|
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
|
||||||
"keywords": ["phpcs", "standards", "static analysis"],
|
"keywords": [
|
||||||
|
"phpcs",
|
||||||
|
"standards",
|
||||||
|
"static analysis"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
|
"issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
|
||||||
"security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
|
"security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
|
||||||
|
@ -1683,10 +2041,14 @@
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": ["BSD-3-Clause"],
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Arne Blankerts",
|
"name": "Arne Blankerts",
|
||||||
|
@ -1714,7 +2076,7 @@
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": ">=5.3.7"
|
"php": ">=7.4"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "2.6.0"
|
"plugin-api-version": "2.6.0"
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace CustomSniffs\Sniffs;
|
||||||
|
|
||||||
|
use PHP_CodeSniffer\Sniffs\Sniff;
|
||||||
|
use PHP_CodeSniffer\Files\File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom sniff to check if the namespace matches the directory structure.
|
||||||
|
*/
|
||||||
|
class NamespaceSniff implements Sniff
|
||||||
|
{
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
return [T_NAMESPACE];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process(File $phpcsFile, $stackPtr)
|
||||||
|
{
|
||||||
|
$tokens = $phpcsFile->getTokens();
|
||||||
|
$namespace = $this->getNamespace($phpcsFile, $stackPtr);
|
||||||
|
|
||||||
|
// Get the file path relative to the project root
|
||||||
|
$filePath = $phpcsFile->getFilename();
|
||||||
|
$projectRoot = '/var/www/html/google_forms/'; // Adjust this path as necessary
|
||||||
|
$relativePath = str_replace([$projectRoot, '.php'], '', $filePath);
|
||||||
|
|
||||||
|
// Convert the file path to a namespace-like format
|
||||||
|
$expectedNamespace = str_replace('/', '\\', $relativePath);
|
||||||
|
|
||||||
|
// Compare the file path with the namespace
|
||||||
|
if ($namespace !== $expectedNamespace) {
|
||||||
|
$error = sprintf(
|
||||||
|
'Namespace "%s" does not match file path. Expected namespace: "%s"',
|
||||||
|
$namespace,
|
||||||
|
$expectedNamespace
|
||||||
|
);
|
||||||
|
$phpcsFile->addError($error, $stackPtr, 'InvalidNamespace');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getNamespace(File $phpcsFile, $stackPtr)
|
||||||
|
{
|
||||||
|
$tokens = $phpcsFile->getTokens();
|
||||||
|
$namespace = '';
|
||||||
|
|
||||||
|
for ($i = $stackPtr + 2; $i < $phpcsFile->numTokens; $i++) {
|
||||||
|
$namespace .= $tokens[$i]['content'];
|
||||||
|
|
||||||
|
if ($tokens[$i]['code'] === T_SEMICOLON) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim($namespace);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
../esprima/bin/esparse.js
|
|
|
@ -1 +0,0 @@
|
||||||
../esprima/bin/esvalidate.js
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,50 +0,0 @@
|
||||||
v0.4.3 - July 17, 2021
|
|
||||||
|
|
||||||
* [`ce78027`](https://github.com/eslint/eslintrc/commit/ce78027f6a319a29fdf0b78ac1e7071373acffc4) Fix: ensure config files are files (#42) (Tom Jenkinson)
|
|
||||||
* [`95b1c9b`](https://github.com/eslint/eslintrc/commit/95b1c9b30267479a75cd07768f8f9e9cfa63c105) Chore: pin fs-teardown@0.1.1 (#45) (Milos Djermanovic)
|
|
||||||
* [`593fbe3`](https://github.com/eslint/eslintrc/commit/593fbe3c2c1c5f723f71810963ed21a56caed4c1) Chore: fix failing test (#44) (Tom Jenkinson)
|
|
||||||
|
|
||||||
v0.4.2 - June 4, 2021
|
|
||||||
|
|
||||||
* [`cc79a4d`](https://github.com/eslint/eslintrc/commit/cc79a4db45a2ca0236a846ed8eba28eea07d4db5) Upgrade: update globals to version 13.6 (#32) (Rouven Weßling)
|
|
||||||
|
|
||||||
v0.4.1 - May 7, 2021
|
|
||||||
|
|
||||||
* [`aa38ef4`](https://github.com/eslint/eslintrc/commit/aa38ef40c3123f8f534c7f9b0b7c306f5f011dce) Fix: Properly export module resolver (#34) (Richie Bendall)
|
|
||||||
* [`62ea4bd`](https://github.com/eslint/eslintrc/commit/62ea4bd74b78fbeff12ffb21f1f978817601d4d1) Build: add node v16 (#33) (薛定谔的猫)
|
|
||||||
* [`7c43d77`](https://github.com/eslint/eslintrc/commit/7c43d7784e39cf0b7b102af64f703cade11252bb) Chore: add tests for built-in rules config schema validation (fixes #15) (#31) (Milos Djermanovic)
|
|
||||||
* [`d8ea601`](https://github.com/eslint/eslintrc/commit/d8ea601ecb4b9f81cdc332b012b6b1bbc984366c) Chore: Test on Node 15.x (#30) (Milos Djermanovic)
|
|
||||||
* [`0b2f80d`](https://github.com/eslint/eslintrc/commit/0b2f80d6f6b33e4c5e168b08468867653f726754) Chore: lint test files (#18) (Milos Djermanovic)
|
|
||||||
|
|
||||||
v0.4.0 - February 27, 2021
|
|
||||||
|
|
||||||
* [`d9a527b`](https://github.com/eslint/eslintrc/commit/d9a527bdb16af46a28d37fa9022131149970a438) New: Implement DotCompat class (#20) (Nicholas C. Zakas)
|
|
||||||
* [`dac76c0`](https://github.com/eslint/eslintrc/commit/dac76c035a9ab9d315050f688867373966aab288) Chore: Replace usage of lodash with cache set (#29) (Tim van der Lippe)
|
|
||||||
* [`3ae2d77`](https://github.com/eslint/eslintrc/commit/3ae2d770cb810c026de817e6861e25dac111da9f) Update: add AggregateError global to es2021 environment (#28) (Milos Djermanovic)
|
|
||||||
|
|
||||||
v0.3.0 - January 15, 2021
|
|
||||||
|
|
||||||
* [`5184490`](https://github.com/eslint/eslintrc/commit/51844902bc4132f264f05a0614f2cdeb89290f68) Upgrade: lodash@4.17.20 (#24) (Milos Djermanovic)
|
|
||||||
* [`f1179c5`](https://github.com/eslint/eslintrc/commit/f1179c587ae09fabb5c3402598363cfcec2494f7) Update: Implement missing functionality from ESLint port (fixes #12) (#23) (Nicholas C. Zakas)
|
|
||||||
|
|
||||||
v0.2.2 - December 5, 2020
|
|
||||||
|
|
||||||
* [`1746840`](https://github.com/eslint/eslintrc/commit/17468407c1baf05747cb261c91f7f7b7c2a82422) Fix: include loadRules in internalSlotsMap cache (#19) (Henry Q. Dineen)
|
|
||||||
* [`f30bb49`](https://github.com/eslint/eslintrc/commit/f30bb4935aaf3f4c1b268490da495a59647e58d8) Chore: Test fixes for CascadingConfigArrayFactory (#17) (Nicholas C. Zakas)
|
|
||||||
* [`4440df8`](https://github.com/eslint/eslintrc/commit/4440df8237a127e15cbde5c697353e1224f12ec1) Chore: Fix config-array tests (#16) (Nicholas C. Zakas)
|
|
||||||
* [`7890e02`](https://github.com/eslint/eslintrc/commit/7890e027df530a0fb53bcf5751c8c7a008b2a494) Chore: Test fixes for config-array-factory.js (#13) (Nicholas C. Zakas)
|
|
||||||
|
|
||||||
v0.2.1 - October 26, 2020
|
|
||||||
|
|
||||||
* [`8b202ff`](https://github.com/eslint/eslintrc/commit/8b202ff866a39efdaad6394fde9f88372afbfca8) Fix: validate schema for built-in rules (#14) (Milos Djermanovic)
|
|
||||||
* [`04f3cae`](https://github.com/eslint/eslintrc/commit/04f3cae17fe07b2fd0b74fd3e88482b3094e75e3) Fix: cache compiled config schema (#9) (Milos Djermanovic)
|
|
||||||
|
|
||||||
v0.2.0 - October 16, 2020
|
|
||||||
|
|
||||||
* [`cb12255`](https://github.com/eslint/eslintrc/commit/cb12255b85390e932e1942e479c2c97310149390) Update: Allow eslint:all and eslint:recommended paths to be passed in (#11) (Nicholas C. Zakas)
|
|
||||||
* [`a75bacd`](https://github.com/eslint/eslintrc/commit/a75bacd9a743a7bbcdb8c59e5d4f9de3dc8b0f20) Chore: use GitHub Actions (#10) (Milos Djermanovic)
|
|
||||||
|
|
||||||
v0.1.3 - September 1, 2020
|
|
||||||
|
|
||||||
* [`8647a61`](https://github.com/eslint/eslintrc/commit/8647a61991fe121f923d33e96232475209b78210) Fix: version number and eslint-release version (refs #6) (Nicholas C. Zakas)
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
MIT License
|
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
||||||
|
|
||||||
Copyright (c) 2020 ESLint
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -9,13 +7,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in
|
||||||
copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# ESLintRC Library
|
# ESLintRC Library
|
||||||
|
|
||||||
This repository contains the legacy ESLintRC configuration file format for ESLint.
|
This repository contains the legacy ESLintRC configuration file format for ESLint. This package is not intended for use outside of the ESLint ecosystem. It is ESLint-specific and not intended for use in other programs.
|
||||||
|
|
||||||
**Note:** This package is not intended for use outside of the ESLint ecosystem. It is ESLint-specific and not intended for use in other programs.
|
**Note:** This package is frozen except for critical bug fixes as ESLint moves to a new config system.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -16,33 +16,87 @@ npm install @eslint/eslintrc --save-dev
|
||||||
yarn add @eslint/eslintrc -D
|
yarn add @eslint/eslintrc -D
|
||||||
```
|
```
|
||||||
|
|
||||||
## Future Usage
|
## Usage (ESM)
|
||||||
|
|
||||||
**Note:** This package is not intended for public use at this time. The following is an example of how it will be used in the future.
|
|
||||||
|
|
||||||
The primary class in this package is `FlatCompat`, which is a utility to translate ESLintRC-style configs into flat configs. Here's how you use it inside of your `eslint.config.js` file:
|
The primary class in this package is `FlatCompat`, which is a utility to translate ESLintRC-style configs into flat configs. Here's how you use it inside of your `eslint.config.js` file:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { FlatCompat } from "@eslint/eslintrc";
|
import { FlatCompat } from "@eslint/eslintrc";
|
||||||
|
import js from "@eslint/js";
|
||||||
|
import path from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
const compat = new FlatCompat();
|
// mimic CommonJS variables -- not needed if using CommonJS
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
const compat = new FlatCompat({
|
||||||
|
baseDirectory: __dirname, // optional; default: process.cwd()
|
||||||
|
resolvePluginsRelativeTo: __dirname, // optional
|
||||||
|
recommendedConfig: js.configs.recommended, // optional
|
||||||
|
allConfig: js.configs.all, // optional
|
||||||
|
});
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
|
|
||||||
// mimic ESLintRC-style extends
|
// mimic ESLintRC-style extends
|
||||||
compat.extends("standard", "example"),
|
...compat.extends("standard", "example"),
|
||||||
|
|
||||||
// mimic environments
|
// mimic environments
|
||||||
compat.env({
|
...compat.env({
|
||||||
es2020: true,
|
es2020: true,
|
||||||
node: true
|
node: true
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// mimic plugins
|
// mimic plugins
|
||||||
compat.plugins("airbnb", "react"),
|
...compat.plugins("airbnb", "react"),
|
||||||
|
|
||||||
// translate an entire config
|
// translate an entire config
|
||||||
compat.config({
|
...compat.config({
|
||||||
|
plugins: ["airbnb", "react"],
|
||||||
|
extends: "standard",
|
||||||
|
env: {
|
||||||
|
es2020: true,
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
semi: "error"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage (CommonJS)
|
||||||
|
|
||||||
|
Using `FlatCompat` in CommonJS files is similar to ESM, but you'll use `require()` and `module.exports` instead of `import` and `export`. Here's how you use it inside of your `eslint.config.js` CommonJS file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { FlatCompat } = require("@eslint/eslintrc");
|
||||||
|
const js = require("@eslint/js");
|
||||||
|
|
||||||
|
const compat = new FlatCompat({
|
||||||
|
baseDirectory: __dirname, // optional; default: process.cwd()
|
||||||
|
resolvePluginsRelativeTo: __dirname, // optional
|
||||||
|
recommendedConfig: js.configs.recommended, // optional
|
||||||
|
allConfig: js.configs.all, // optional
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
|
||||||
|
// mimic ESLintRC-style extends
|
||||||
|
...compat.extends("standard", "example"),
|
||||||
|
|
||||||
|
// mimic environments
|
||||||
|
...compat.env({
|
||||||
|
es2020: true,
|
||||||
|
node: true
|
||||||
|
}),
|
||||||
|
|
||||||
|
// mimic plugins
|
||||||
|
...compat.plugins("airbnb", "react"),
|
||||||
|
|
||||||
|
// translate an entire config
|
||||||
|
...compat.config({
|
||||||
plugins: ["airbnb", "react"],
|
plugins: ["airbnb", "react"],
|
||||||
extends: "standard",
|
extends: "standard",
|
||||||
env: {
|
env: {
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* @author Sylvan Mably
|
* @author Sylvan Mably
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const baseConfigProperties = {
|
const baseConfigProperties = {
|
||||||
$schema: { type: "string" },
|
$schema: { type: "string" },
|
||||||
env: { type: "object" },
|
env: { type: "object" },
|
||||||
|
@ -78,4 +76,4 @@ const configSchema = {
|
||||||
$ref: "#/definitions/objectConfig"
|
$ref: "#/definitions/objectConfig"
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = configSchema;
|
export default configSchema;
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
* @fileoverview Defines environment settings and globals.
|
* @fileoverview Defines environment settings and globals.
|
||||||
* @author Elan Shanker
|
* @author Elan Shanker
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const globals = require("globals");
|
import globals from "globals";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -55,7 +54,7 @@ const newGlobals2021 = {
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
/** @type {Map<string, import("../lib/shared/types").Environment>} */
|
/** @type {Map<string, import("../lib/shared/types").Environment>} */
|
||||||
module.exports = new Map(Object.entries({
|
export default new Map(Object.entries({
|
||||||
|
|
||||||
// Language
|
// Language
|
||||||
builtin: {
|
builtin: {
|
||||||
|
@ -73,12 +72,30 @@ module.exports = new Map(Object.entries({
|
||||||
ecmaVersion: 6
|
ecmaVersion: 6
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
es2016: {
|
||||||
|
globals: newGlobals2015,
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 7
|
||||||
|
}
|
||||||
|
},
|
||||||
es2017: {
|
es2017: {
|
||||||
globals: { ...newGlobals2015, ...newGlobals2017 },
|
globals: { ...newGlobals2015, ...newGlobals2017 },
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 8
|
ecmaVersion: 8
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
es2018: {
|
||||||
|
globals: { ...newGlobals2015, ...newGlobals2017 },
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 9
|
||||||
|
}
|
||||||
|
},
|
||||||
|
es2019: {
|
||||||
|
globals: { ...newGlobals2015, ...newGlobals2017 },
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 10
|
||||||
|
}
|
||||||
|
},
|
||||||
es2020: {
|
es2020: {
|
||||||
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020 },
|
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020 },
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
|
@ -91,6 +108,24 @@ module.exports = new Map(Object.entries({
|
||||||
ecmaVersion: 12
|
ecmaVersion: 12
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
es2022: {
|
||||||
|
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 13
|
||||||
|
}
|
||||||
|
},
|
||||||
|
es2023: {
|
||||||
|
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
es2024: {
|
||||||
|
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020, ...newGlobals2021 },
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 15
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Platforms
|
// Platforms
|
||||||
browser: {
|
browser: {
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
/**
|
|
||||||
* @fileoverview Stub eslint:all config
|
|
||||||
* @author Nicholas C. Zakas
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
settings: {
|
|
||||||
"eslint:all": true
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,12 +0,0 @@
|
||||||
/**
|
|
||||||
* @fileoverview Stub eslint:recommended config
|
|
||||||
* @author Nicholas C. Zakas
|
|
||||||
*/
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
settings: {
|
|
||||||
"eslint:recommended": true
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -17,19 +17,25 @@
|
||||||
*
|
*
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const os = require("os");
|
import debugOrig from "debug";
|
||||||
const path = require("path");
|
import os from "os";
|
||||||
const ConfigValidator = require("./shared/config-validator");
|
import path from "path";
|
||||||
const { emitDeprecationWarning } = require("./shared/deprecation-warnings");
|
|
||||||
const { ConfigArrayFactory } = require("./config-array-factory");
|
import { ConfigArrayFactory } from "./config-array-factory.js";
|
||||||
const { ConfigArray, ConfigDependency, IgnorePattern } = require("./config-array");
|
import {
|
||||||
const debug = require("debug")("eslintrc:cascading-config-array-factory");
|
ConfigArray,
|
||||||
|
ConfigDependency,
|
||||||
|
IgnorePattern
|
||||||
|
} from "./config-array/index.js";
|
||||||
|
import ConfigValidator from "./shared/config-validator.js";
|
||||||
|
import { emitDeprecationWarning } from "./shared/deprecation-warnings.js";
|
||||||
|
|
||||||
|
const debug = debugOrig("eslintrc:cascading-config-array-factory");
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -56,7 +62,9 @@ const debug = require("debug")("eslintrc:cascading-config-array-factory");
|
||||||
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
|
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
|
||||||
* @property {Object} [resolver=ModuleResolver] The module resolver object.
|
* @property {Object} [resolver=ModuleResolver] The module resolver object.
|
||||||
* @property {string} eslintAllPath The path to the definitions for eslint:all.
|
* @property {string} eslintAllPath The path to the definitions for eslint:all.
|
||||||
|
* @property {Function} getEslintAllConfig Returns the config data for eslint:all.
|
||||||
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
|
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
|
||||||
|
* @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,7 +85,9 @@ const debug = require("debug")("eslintrc:cascading-config-array-factory");
|
||||||
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
|
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
|
||||||
* @property {Object} [resolver=ModuleResolver] The module resolver object.
|
* @property {Object} [resolver=ModuleResolver] The module resolver object.
|
||||||
* @property {string} eslintAllPath The path to the definitions for eslint:all.
|
* @property {string} eslintAllPath The path to the definitions for eslint:all.
|
||||||
|
* @property {Function} getEslintAllConfig Returns the config data for eslint:all.
|
||||||
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
|
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
|
||||||
|
* @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @type {WeakMap<CascadingConfigArrayFactory, CascadingConfigArrayFactoryInternalSlots>} */
|
/** @type {WeakMap<CascadingConfigArrayFactory, CascadingConfigArrayFactoryInternalSlots>} */
|
||||||
|
@ -218,7 +228,9 @@ class CascadingConfigArrayFactory {
|
||||||
loadRules,
|
loadRules,
|
||||||
resolver,
|
resolver,
|
||||||
eslintRecommendedPath,
|
eslintRecommendedPath,
|
||||||
eslintAllPath
|
getEslintRecommendedConfig,
|
||||||
|
eslintAllPath,
|
||||||
|
getEslintAllConfig
|
||||||
} = {}) {
|
} = {}) {
|
||||||
const configArrayFactory = new ConfigArrayFactory({
|
const configArrayFactory = new ConfigArrayFactory({
|
||||||
additionalPluginPool,
|
additionalPluginPool,
|
||||||
|
@ -227,7 +239,9 @@ class CascadingConfigArrayFactory {
|
||||||
builtInRules,
|
builtInRules,
|
||||||
resolver,
|
resolver,
|
||||||
eslintRecommendedPath,
|
eslintRecommendedPath,
|
||||||
eslintAllPath
|
getEslintRecommendedConfig,
|
||||||
|
eslintAllPath,
|
||||||
|
getEslintAllConfig
|
||||||
});
|
});
|
||||||
|
|
||||||
internalSlotsMap.set(this, {
|
internalSlotsMap.set(this, {
|
||||||
|
@ -236,8 +250,7 @@ class CascadingConfigArrayFactory {
|
||||||
configArrayFactory,
|
configArrayFactory,
|
||||||
cwd,
|
cwd,
|
||||||
rulePaths,
|
rulePaths,
|
||||||
loadRules,
|
loadRules
|
||||||
resolver
|
|
||||||
}),
|
}),
|
||||||
baseConfigData,
|
baseConfigData,
|
||||||
cliConfigArray: createCLIConfigArray({
|
cliConfigArray: createCLIConfigArray({
|
||||||
|
@ -516,4 +529,4 @@ class CascadingConfigArrayFactory {
|
||||||
// Public Interface
|
// Public Interface
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
module.exports = { CascadingConfigArrayFactory };
|
export { CascadingConfigArrayFactory };
|
||||||
|
|
|
@ -33,26 +33,31 @@
|
||||||
*
|
*
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const fs = require("fs");
|
import debugOrig from "debug";
|
||||||
const path = require("path");
|
import fs from "fs";
|
||||||
const importFresh = require("import-fresh");
|
import importFresh from "import-fresh";
|
||||||
const stripComments = require("strip-json-comments");
|
import { createRequire } from "module";
|
||||||
const ConfigValidator = require("./shared/config-validator");
|
import path from "path";
|
||||||
const naming = require("./shared/naming");
|
import stripComments from "strip-json-comments";
|
||||||
const ModuleResolver = require("./shared/relative-module-resolver");
|
|
||||||
const {
|
import {
|
||||||
ConfigArray,
|
ConfigArray,
|
||||||
ConfigDependency,
|
ConfigDependency,
|
||||||
IgnorePattern,
|
IgnorePattern,
|
||||||
OverrideTester
|
OverrideTester
|
||||||
} = require("./config-array");
|
} from "./config-array/index.js";
|
||||||
const debug = require("debug")("eslintrc:config-array-factory");
|
import ConfigValidator from "./shared/config-validator.js";
|
||||||
|
import * as naming from "./shared/naming.js";
|
||||||
|
import * as ModuleResolver from "./shared/relative-module-resolver.js";
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
|
const debug = debugOrig("eslintrc:config-array-factory");
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -86,7 +91,9 @@ const configFilenames = [
|
||||||
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
|
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
|
||||||
* @property {Object} [resolver=ModuleResolver] The module resolver object.
|
* @property {Object} [resolver=ModuleResolver] The module resolver object.
|
||||||
* @property {string} eslintAllPath The path to the definitions for eslint:all.
|
* @property {string} eslintAllPath The path to the definitions for eslint:all.
|
||||||
|
* @property {Function} getEslintAllConfig Returns the config data for eslint:all.
|
||||||
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
|
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
|
||||||
|
* @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,7 +104,9 @@ const configFilenames = [
|
||||||
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
|
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
|
||||||
* @property {Object} [resolver=ModuleResolver] The module resolver object.
|
* @property {Object} [resolver=ModuleResolver] The module resolver object.
|
||||||
* @property {string} eslintAllPath The path to the definitions for eslint:all.
|
* @property {string} eslintAllPath The path to the definitions for eslint:all.
|
||||||
|
* @property {Function} getEslintAllConfig Returns the config data for eslint:all.
|
||||||
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
|
* @property {string} eslintRecommendedPath The path to the definitions for eslint:recommended.
|
||||||
|
* @property {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,6 +129,9 @@ const configFilenames = [
|
||||||
/** @type {WeakMap<ConfigArrayFactory, ConfigArrayFactoryInternalSlots>} */
|
/** @type {WeakMap<ConfigArrayFactory, ConfigArrayFactoryInternalSlots>} */
|
||||||
const internalSlotsMap = new WeakMap();
|
const internalSlotsMap = new WeakMap();
|
||||||
|
|
||||||
|
/** @type {WeakMap<object, Plugin>} */
|
||||||
|
const normalizedPlugins = new WeakMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a given string is a file path.
|
* Check if a given string is a file path.
|
||||||
* @param {string} nameOrPath A module name or file path.
|
* @param {string} nameOrPath A module name or file path.
|
||||||
|
@ -158,7 +170,7 @@ function loadYAMLConfigFile(filePath) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// empty YAML file can be null, so always use
|
// empty YAML file can be null, so always use
|
||||||
return yaml.safeLoad(readFile(filePath)) || {};
|
return yaml.load(readFile(filePath)) || {};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debug(`Error reading YAML file: ${filePath}`);
|
debug(`Error reading YAML file: ${filePath}`);
|
||||||
e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
|
e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
|
||||||
|
@ -204,7 +216,7 @@ function loadLegacyConfigFile(filePath) {
|
||||||
const yaml = require("js-yaml");
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return yaml.safeLoad(stripComments(readFile(filePath))) || /* istanbul ignore next */ {};
|
return yaml.load(stripComments(readFile(filePath))) || /* istanbul ignore next */ {};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debug("Error reading YAML file: %s\n%o", filePath, e);
|
debug("Error reading YAML file: %s\n%o", filePath, e);
|
||||||
e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
|
e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
|
||||||
|
@ -396,12 +408,25 @@ function createContext(
|
||||||
* @returns {Plugin} The normalized plugin.
|
* @returns {Plugin} The normalized plugin.
|
||||||
*/
|
*/
|
||||||
function normalizePlugin(plugin) {
|
function normalizePlugin(plugin) {
|
||||||
return {
|
|
||||||
|
// first check the cache
|
||||||
|
let normalizedPlugin = normalizedPlugins.get(plugin);
|
||||||
|
|
||||||
|
if (normalizedPlugin) {
|
||||||
|
return normalizedPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizedPlugin = {
|
||||||
configs: plugin.configs || {},
|
configs: plugin.configs || {},
|
||||||
environments: plugin.environments || {},
|
environments: plugin.environments || {},
|
||||||
processors: plugin.processors || {},
|
processors: plugin.processors || {},
|
||||||
rules: plugin.rules || {}
|
rules: plugin.rules || {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// save the reference for later
|
||||||
|
normalizedPlugins.set(plugin, normalizedPlugin);
|
||||||
|
|
||||||
|
return normalizedPlugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -424,7 +449,9 @@ class ConfigArrayFactory {
|
||||||
builtInRules,
|
builtInRules,
|
||||||
resolver = ModuleResolver,
|
resolver = ModuleResolver,
|
||||||
eslintAllPath,
|
eslintAllPath,
|
||||||
eslintRecommendedPath
|
getEslintAllConfig,
|
||||||
|
eslintRecommendedPath,
|
||||||
|
getEslintRecommendedConfig
|
||||||
} = {}) {
|
} = {}) {
|
||||||
internalSlotsMap.set(this, {
|
internalSlotsMap.set(this, {
|
||||||
additionalPluginPool,
|
additionalPluginPool,
|
||||||
|
@ -435,7 +462,9 @@ class ConfigArrayFactory {
|
||||||
builtInRules,
|
builtInRules,
|
||||||
resolver,
|
resolver,
|
||||||
eslintAllPath,
|
eslintAllPath,
|
||||||
eslintRecommendedPath
|
getEslintAllConfig,
|
||||||
|
eslintRecommendedPath,
|
||||||
|
getEslintRecommendedConfig
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,20 +822,41 @@ class ConfigArrayFactory {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_loadExtendedBuiltInConfig(extendName, ctx) {
|
_loadExtendedBuiltInConfig(extendName, ctx) {
|
||||||
const { eslintAllPath, eslintRecommendedPath } = internalSlotsMap.get(this);
|
const {
|
||||||
|
eslintAllPath,
|
||||||
|
getEslintAllConfig,
|
||||||
|
eslintRecommendedPath,
|
||||||
|
getEslintRecommendedConfig
|
||||||
|
} = internalSlotsMap.get(this);
|
||||||
|
|
||||||
if (extendName === "eslint:recommended") {
|
if (extendName === "eslint:recommended") {
|
||||||
|
const name = `${ctx.name} » ${extendName}`;
|
||||||
|
|
||||||
|
if (getEslintRecommendedConfig) {
|
||||||
|
if (typeof getEslintRecommendedConfig !== "function") {
|
||||||
|
throw new Error(`getEslintRecommendedConfig must be a function instead of '${getEslintRecommendedConfig}'`);
|
||||||
|
}
|
||||||
|
return this._normalizeConfigData(getEslintRecommendedConfig(), { ...ctx, name, filePath: "" });
|
||||||
|
}
|
||||||
return this._loadConfigData({
|
return this._loadConfigData({
|
||||||
...ctx,
|
...ctx,
|
||||||
filePath: eslintRecommendedPath,
|
name,
|
||||||
name: `${ctx.name} » ${extendName}`
|
filePath: eslintRecommendedPath
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (extendName === "eslint:all") {
|
if (extendName === "eslint:all") {
|
||||||
|
const name = `${ctx.name} » ${extendName}`;
|
||||||
|
|
||||||
|
if (getEslintAllConfig) {
|
||||||
|
if (typeof getEslintAllConfig !== "function") {
|
||||||
|
throw new Error(`getEslintAllConfig must be a function instead of '${getEslintAllConfig}'`);
|
||||||
|
}
|
||||||
|
return this._normalizeConfigData(getEslintAllConfig(), { ...ctx, name, filePath: "" });
|
||||||
|
}
|
||||||
return this._loadConfigData({
|
return this._loadConfigData({
|
||||||
...ctx,
|
...ctx,
|
||||||
filePath: eslintAllPath,
|
name,
|
||||||
name: `${ctx.name} » ${extendName}`
|
filePath: eslintAllPath
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -922,11 +972,11 @@ class ConfigArrayFactory {
|
||||||
_loadParser(nameOrPath, ctx) {
|
_loadParser(nameOrPath, ctx) {
|
||||||
debug("Loading parser %j from %s", nameOrPath, ctx.filePath);
|
debug("Loading parser %j from %s", nameOrPath, ctx.filePath);
|
||||||
|
|
||||||
const { cwd } = internalSlotsMap.get(this);
|
const { cwd, resolver } = internalSlotsMap.get(this);
|
||||||
const relativeTo = ctx.filePath || path.join(cwd, "__placeholder__.js");
|
const relativeTo = ctx.filePath || path.join(cwd, "__placeholder__.js");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const filePath = ModuleResolver.resolve(nameOrPath, relativeTo);
|
const filePath = resolver.resolve(nameOrPath, relativeTo);
|
||||||
|
|
||||||
writeDebugLogForLoading(nameOrPath, relativeTo, filePath);
|
writeDebugLogForLoading(nameOrPath, relativeTo, filePath);
|
||||||
|
|
||||||
|
@ -973,7 +1023,7 @@ class ConfigArrayFactory {
|
||||||
_loadPlugin(name, ctx) {
|
_loadPlugin(name, ctx) {
|
||||||
debug("Loading plugin %j from %s", name, ctx.filePath);
|
debug("Loading plugin %j from %s", name, ctx.filePath);
|
||||||
|
|
||||||
const { additionalPluginPool } = internalSlotsMap.get(this);
|
const { additionalPluginPool, resolver } = internalSlotsMap.get(this);
|
||||||
const request = naming.normalizePackageName(name, "eslint-plugin");
|
const request = naming.normalizePackageName(name, "eslint-plugin");
|
||||||
const id = naming.getShorthandName(request, "eslint-plugin");
|
const id = naming.getShorthandName(request, "eslint-plugin");
|
||||||
const relativeTo = path.join(ctx.pluginBasePath, "__placeholder__.js");
|
const relativeTo = path.join(ctx.pluginBasePath, "__placeholder__.js");
|
||||||
|
@ -1003,6 +1053,7 @@ class ConfigArrayFactory {
|
||||||
if (plugin) {
|
if (plugin) {
|
||||||
return new ConfigDependency({
|
return new ConfigDependency({
|
||||||
definition: normalizePlugin(plugin),
|
definition: normalizePlugin(plugin),
|
||||||
|
original: plugin,
|
||||||
filePath: "", // It's unknown where the plugin came from.
|
filePath: "", // It's unknown where the plugin came from.
|
||||||
id,
|
id,
|
||||||
importerName: ctx.name,
|
importerName: ctx.name,
|
||||||
|
@ -1014,7 +1065,7 @@ class ConfigArrayFactory {
|
||||||
let error;
|
let error;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filePath = ModuleResolver.resolve(request, relativeTo);
|
filePath = resolver.resolve(request, relativeTo);
|
||||||
} catch (resolveError) {
|
} catch (resolveError) {
|
||||||
error = resolveError;
|
error = resolveError;
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
|
@ -1039,6 +1090,7 @@ class ConfigArrayFactory {
|
||||||
|
|
||||||
return new ConfigDependency({
|
return new ConfigDependency({
|
||||||
definition: normalizePlugin(pluginDefinition),
|
definition: normalizePlugin(pluginDefinition),
|
||||||
|
original: pluginDefinition,
|
||||||
filePath,
|
filePath,
|
||||||
id,
|
id,
|
||||||
importerName: ctx.name,
|
importerName: ctx.name,
|
||||||
|
@ -1096,4 +1148,4 @@ class ConfigArrayFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { ConfigArrayFactory, createContext };
|
export { ConfigArrayFactory, createContext };
|
||||||
|
|
|
@ -24,14 +24,13 @@
|
||||||
*
|
*
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const { ExtractedConfig } = require("./extracted-config");
|
import { ExtractedConfig } from "./extracted-config.js";
|
||||||
const { IgnorePattern } = require("./ignore-pattern");
|
import { IgnorePattern } from "./ignore-pattern.js";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -504,21 +503,21 @@ class ConfigArray extends Array {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportObject = {
|
/**
|
||||||
|
* Get the used extracted configs.
|
||||||
|
* CLIEngine will use this method to collect used deprecated rules.
|
||||||
|
* @param {ConfigArray} instance The config array object to get.
|
||||||
|
* @returns {ExtractedConfig[]} The used extracted configs.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getUsedExtractedConfigs(instance) {
|
||||||
|
const { cache } = internalSlotsMap.get(instance);
|
||||||
|
|
||||||
|
return Array.from(cache.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
ConfigArray,
|
ConfigArray,
|
||||||
|
getUsedExtractedConfigs
|
||||||
/**
|
|
||||||
* Get the used extracted configs.
|
|
||||||
* CLIEngine will use this method to collect used deprecated rules.
|
|
||||||
* @param {ConfigArray} instance The config array object to get.
|
|
||||||
* @returns {ExtractedConfig[]} The used extracted configs.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
getUsedExtractedConfigs(instance) {
|
|
||||||
const { cache } = internalSlotsMap.get(instance);
|
|
||||||
|
|
||||||
return Array.from(cache.values());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = exportObject;
|
|
||||||
|
|
|
@ -14,9 +14,8 @@
|
||||||
*
|
*
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const util = require("util");
|
import util from "util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class is to store parsers or plugins.
|
* The class is to store parsers or plugins.
|
||||||
|
@ -29,6 +28,7 @@ class ConfigDependency {
|
||||||
* Initialize this instance.
|
* Initialize this instance.
|
||||||
* @param {Object} data The dependency data.
|
* @param {Object} data The dependency data.
|
||||||
* @param {T} [data.definition] The dependency if the loading succeeded.
|
* @param {T} [data.definition] The dependency if the loading succeeded.
|
||||||
|
* @param {T} [data.original] The original, non-normalized dependency if the loading succeeded.
|
||||||
* @param {Error} [data.error] The error object if the loading failed.
|
* @param {Error} [data.error] The error object if the loading failed.
|
||||||
* @param {string} [data.filePath] The actual path to the dependency if the loading succeeded.
|
* @param {string} [data.filePath] The actual path to the dependency if the loading succeeded.
|
||||||
* @param {string} data.id The ID of this dependency.
|
* @param {string} data.id The ID of this dependency.
|
||||||
|
@ -37,6 +37,7 @@ class ConfigDependency {
|
||||||
*/
|
*/
|
||||||
constructor({
|
constructor({
|
||||||
definition = null,
|
definition = null,
|
||||||
|
original = null,
|
||||||
error = null,
|
error = null,
|
||||||
filePath = null,
|
filePath = null,
|
||||||
id,
|
id,
|
||||||
|
@ -50,6 +51,12 @@ class ConfigDependency {
|
||||||
*/
|
*/
|
||||||
this.definition = definition;
|
this.definition = definition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The original dependency as loaded directly from disk if the loading succeeded.
|
||||||
|
* @type {T|null}
|
||||||
|
*/
|
||||||
|
this.original = original;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The error object if the loading failed.
|
* The error object if the loading failed.
|
||||||
* @type {Error|null}
|
* @type {Error|null}
|
||||||
|
@ -102,7 +109,8 @@ class ConfigDependency {
|
||||||
*/
|
*/
|
||||||
[util.inspect.custom]() {
|
[util.inspect.custom]() {
|
||||||
const {
|
const {
|
||||||
definition: _ignore, // eslint-disable-line no-unused-vars
|
definition: _ignore1, // eslint-disable-line no-unused-vars
|
||||||
|
original: _ignore2, // eslint-disable-line no-unused-vars
|
||||||
...obj
|
...obj
|
||||||
} = this;
|
} = this;
|
||||||
|
|
||||||
|
@ -113,4 +121,4 @@ class ConfigDependency {
|
||||||
/** @typedef {ConfigDependency<import("../../shared/types").Parser>} DependentParser */
|
/** @typedef {ConfigDependency<import("../../shared/types").Parser>} DependentParser */
|
||||||
/** @typedef {ConfigDependency<import("../../shared/types").Plugin>} DependentPlugin */
|
/** @typedef {ConfigDependency<import("../../shared/types").Plugin>} DependentPlugin */
|
||||||
|
|
||||||
module.exports = { ConfigDependency };
|
export { ConfigDependency };
|
||||||
|
|
|
@ -14,9 +14,8 @@
|
||||||
*
|
*
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const { IgnorePattern } = require("./ignore-pattern");
|
import { IgnorePattern } from "./ignore-pattern.js";
|
||||||
|
|
||||||
// For VSCode intellisense
|
// For VSCode intellisense
|
||||||
/** @typedef {import("../../shared/types").ConfigData} ConfigData */
|
/** @typedef {import("../../shared/types").ConfigData} ConfigData */
|
||||||
|
@ -143,4 +142,4 @@ class ExtractedConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { ExtractedConfig };
|
export { ExtractedConfig };
|
||||||
|
|
|
@ -27,16 +27,17 @@
|
||||||
*
|
*
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const assert = require("assert");
|
import assert from "assert";
|
||||||
const path = require("path");
|
import path from "path";
|
||||||
const ignore = require("ignore");
|
import ignore from "ignore";
|
||||||
const debug = require("debug")("eslintrc:ignore-pattern");
|
import debugOrig from "debug";
|
||||||
|
|
||||||
|
const debug = debugOrig("eslintrc:ignore-pattern");
|
||||||
|
|
||||||
/** @typedef {ReturnType<import("ignore").default>} Ignore */
|
/** @typedef {ReturnType<import("ignore").default>} Ignore */
|
||||||
|
|
||||||
|
@ -155,8 +156,8 @@ class IgnorePattern {
|
||||||
const patterns = [].concat(
|
const patterns = [].concat(
|
||||||
...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
|
...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
|
||||||
);
|
);
|
||||||
const ig = ignore().add([...DotPatterns, ...patterns]);
|
const ig = ignore({ allowRelativePaths: true }).add([...DotPatterns, ...patterns]);
|
||||||
const dotIg = ignore().add(patterns);
|
const dotIg = ignore({ allowRelativePaths: true }).add(patterns);
|
||||||
|
|
||||||
debug(" processed: %o", { basePath, patterns });
|
debug(" processed: %o", { basePath, patterns });
|
||||||
|
|
||||||
|
@ -234,4 +235,4 @@ class IgnorePattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { IgnorePattern };
|
export { IgnorePattern };
|
||||||
|
|
|
@ -2,15 +2,14 @@
|
||||||
* @fileoverview `ConfigArray` class.
|
* @fileoverview `ConfigArray` class.
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const { ConfigArray, getUsedExtractedConfigs } = require("./config-array");
|
import { ConfigArray, getUsedExtractedConfigs } from "./config-array.js";
|
||||||
const { ConfigDependency } = require("./config-dependency");
|
import { ConfigDependency } from "./config-dependency.js";
|
||||||
const { ExtractedConfig } = require("./extracted-config");
|
import { ExtractedConfig } from "./extracted-config.js";
|
||||||
const { IgnorePattern } = require("./ignore-pattern");
|
import { IgnorePattern } from "./ignore-pattern.js";
|
||||||
const { OverrideTester } = require("./override-tester");
|
import { OverrideTester } from "./override-tester.js";
|
||||||
|
|
||||||
module.exports = {
|
export {
|
||||||
ConfigArray,
|
ConfigArray,
|
||||||
ConfigDependency,
|
ConfigDependency,
|
||||||
ExtractedConfig,
|
ExtractedConfig,
|
||||||
|
|
|
@ -16,12 +16,14 @@
|
||||||
*
|
*
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const assert = require("assert");
|
import assert from "assert";
|
||||||
const path = require("path");
|
import path from "path";
|
||||||
const util = require("util");
|
import util from "util";
|
||||||
const { Minimatch } = require("minimatch");
|
import minimatch from "minimatch";
|
||||||
|
|
||||||
|
const { Minimatch } = minimatch;
|
||||||
|
|
||||||
const minimatchOpts = { dot: true, matchBase: true };
|
const minimatchOpts = { dot: true, matchBase: true };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,4 +222,4 @@ class OverrideTester {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { OverrideTester };
|
export { OverrideTester };
|
||||||
|
|
|
@ -3,16 +3,15 @@
|
||||||
* @author Nicholas C. Zakas
|
* @author Nicholas C. Zakas
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
const path = require("path");
|
import createDebug from "debug";
|
||||||
const environments = require("../conf/environments");
|
import path from "path";
|
||||||
const createDebug = require("debug");
|
|
||||||
const { ConfigArrayFactory } = require("./config-array-factory");
|
import environments from "../conf/environments.js";
|
||||||
|
import { ConfigArrayFactory } from "./config-array-factory.js";
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -54,17 +53,6 @@ function translateESLintRC(eslintrcConfig, {
|
||||||
const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
|
const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
|
||||||
const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"];
|
const linterOptionsKeysToCopy = ["noInlineConfig", "reportUnusedDisableDirectives"];
|
||||||
|
|
||||||
// check for special settings for eslint:all and eslint:recommended:
|
|
||||||
if (eslintrcConfig.settings) {
|
|
||||||
if (eslintrcConfig.settings["eslint:all"] === true) {
|
|
||||||
return ["eslint:all"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eslintrcConfig.settings["eslint:recommended"] === true) {
|
|
||||||
return ["eslint:recommended"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy over simple translations
|
// copy over simple translations
|
||||||
for (const key of keysToCopy) {
|
for (const key of keysToCopy) {
|
||||||
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
|
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
|
||||||
|
@ -144,7 +132,7 @@ function translateESLintRC(eslintrcConfig, {
|
||||||
debug(`Translating plugin: ${pluginName}`);
|
debug(`Translating plugin: ${pluginName}`);
|
||||||
debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
|
debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
|
||||||
|
|
||||||
const { definition: plugin, error } = eslintrcConfig.plugins[pluginName];
|
const { original: plugin, error } = eslintrcConfig.plugins[pluginName];
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -180,14 +168,20 @@ function translateESLintRC(eslintrcConfig, {
|
||||||
if (environments.has(envName)) {
|
if (environments.has(envName)) {
|
||||||
|
|
||||||
// built-in environments should be defined first
|
// built-in environments should be defined first
|
||||||
configs.unshift(...translateESLintRC(environments.get(envName), {
|
configs.unshift(...translateESLintRC({
|
||||||
|
criteria: eslintrcConfig.criteria,
|
||||||
|
...environments.get(envName)
|
||||||
|
}, {
|
||||||
resolveConfigRelativeTo,
|
resolveConfigRelativeTo,
|
||||||
resolvePluginsRelativeTo
|
resolvePluginsRelativeTo
|
||||||
}));
|
}));
|
||||||
} else if (pluginEnvironments.has(envName)) {
|
} else if (pluginEnvironments.has(envName)) {
|
||||||
|
|
||||||
// if the environment comes from a plugin, it should come after the plugin config
|
// if the environment comes from a plugin, it should come after the plugin config
|
||||||
configs.push(...translateESLintRC(pluginEnvironments.get(envName), {
|
configs.push(...translateESLintRC({
|
||||||
|
criteria: eslintrcConfig.criteria,
|
||||||
|
...pluginEnvironments.get(envName)
|
||||||
|
}, {
|
||||||
resolveConfigRelativeTo,
|
resolveConfigRelativeTo,
|
||||||
resolvePluginsRelativeTo
|
resolvePluginsRelativeTo
|
||||||
}));
|
}));
|
||||||
|
@ -216,15 +210,31 @@ class FlatCompat {
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
baseDirectory = process.cwd(),
|
baseDirectory = process.cwd(),
|
||||||
resolvePluginsRelativeTo = baseDirectory
|
resolvePluginsRelativeTo = baseDirectory,
|
||||||
|
recommendedConfig,
|
||||||
|
allConfig
|
||||||
} = {}) {
|
} = {}) {
|
||||||
this.baseDirectory = baseDirectory;
|
this.baseDirectory = baseDirectory;
|
||||||
this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
|
this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
|
||||||
this[cafactory] = new ConfigArrayFactory({
|
this[cafactory] = new ConfigArrayFactory({
|
||||||
cwd: baseDirectory,
|
cwd: baseDirectory,
|
||||||
resolvePluginsRelativeTo,
|
resolvePluginsRelativeTo,
|
||||||
eslintAllPath: path.resolve(__dirname, "../conf/eslint-all.js"),
|
getEslintAllConfig: () => {
|
||||||
eslintRecommendedPath: path.resolve(__dirname, "../conf/eslint-recommended.js")
|
|
||||||
|
if (!allConfig) {
|
||||||
|
throw new TypeError("Missing parameter 'allConfig' in FlatCompat constructor.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return allConfig;
|
||||||
|
},
|
||||||
|
getEslintRecommendedConfig: () => {
|
||||||
|
|
||||||
|
if (!recommendedConfig) {
|
||||||
|
throw new TypeError("Missing parameter 'recommendedConfig' in FlatCompat constructor.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return recommendedConfig;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +284,7 @@ class FlatCompat {
|
||||||
/**
|
/**
|
||||||
* Translates the `env` section of an ESLintRC-style config.
|
* Translates the `env` section of an ESLintRC-style config.
|
||||||
* @param {Object} envConfig The `env` section of an ESLintRC config.
|
* @param {Object} envConfig The `env` section of an ESLintRC config.
|
||||||
* @returns {Object} A flag-config object representing the environments.
|
* @returns {Object[]} An array of flag-config objects representing the environments.
|
||||||
*/
|
*/
|
||||||
env(envConfig) {
|
env(envConfig) {
|
||||||
return this.config({
|
return this.config({
|
||||||
|
@ -285,7 +295,7 @@ class FlatCompat {
|
||||||
/**
|
/**
|
||||||
* Translates the `extends` section of an ESLintRC-style config.
|
* Translates the `extends` section of an ESLintRC-style config.
|
||||||
* @param {...string} configsToExtend The names of the configs to load.
|
* @param {...string} configsToExtend The names of the configs to load.
|
||||||
* @returns {Object} A flag-config object representing the config.
|
* @returns {Object[]} An array of flag-config objects representing the config.
|
||||||
*/
|
*/
|
||||||
extends(...configsToExtend) {
|
extends(...configsToExtend) {
|
||||||
return this.config({
|
return this.config({
|
||||||
|
@ -296,7 +306,7 @@ class FlatCompat {
|
||||||
/**
|
/**
|
||||||
* Translates the `plugins` section of an ESLintRC-style config.
|
* Translates the `plugins` section of an ESLintRC-style config.
|
||||||
* @param {...string} plugins The names of the plugins to load.
|
* @param {...string} plugins The names of the plugins to load.
|
||||||
* @returns {Object} A flag-config object representing the plugins.
|
* @returns {Object[]} An array of flag-config objects representing the plugins.
|
||||||
*/
|
*/
|
||||||
plugins(...plugins) {
|
plugins(...plugins) {
|
||||||
return this.config({
|
return this.config({
|
||||||
|
@ -305,4 +315,4 @@ class FlatCompat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.FlatCompat = FlatCompat;
|
export { FlatCompat };
|
||||||
|
|
|
@ -2,52 +2,54 @@
|
||||||
* @fileoverview Package exports for @eslint/eslintrc
|
* @fileoverview Package exports for @eslint/eslintrc
|
||||||
* @author Nicholas C. Zakas
|
* @author Nicholas C. Zakas
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const {
|
import {
|
||||||
ConfigArrayFactory,
|
ConfigArrayFactory,
|
||||||
createContext: createConfigArrayFactoryContext
|
createContext as createConfigArrayFactoryContext
|
||||||
} = require("./config-array-factory");
|
} from "./config-array-factory.js";
|
||||||
|
|
||||||
const { CascadingConfigArrayFactory } = require("./cascading-config-array-factory");
|
import { CascadingConfigArrayFactory } from "./cascading-config-array-factory.js";
|
||||||
const ModuleResolver = require("./shared/relative-module-resolver");
|
import * as ModuleResolver from "./shared/relative-module-resolver.js";
|
||||||
const { ConfigArray, getUsedExtractedConfigs } = require("./config-array");
|
import { ConfigArray, getUsedExtractedConfigs } from "./config-array/index.js";
|
||||||
const { ConfigDependency } = require("./config-array/config-dependency");
|
import { ConfigDependency } from "./config-array/config-dependency.js";
|
||||||
const { ExtractedConfig } = require("./config-array/extracted-config");
|
import { ExtractedConfig } from "./config-array/extracted-config.js";
|
||||||
const { IgnorePattern } = require("./config-array/ignore-pattern");
|
import { IgnorePattern } from "./config-array/ignore-pattern.js";
|
||||||
const { OverrideTester } = require("./config-array/override-tester");
|
import { OverrideTester } from "./config-array/override-tester.js";
|
||||||
const ConfigOps = require("./shared/config-ops");
|
import * as ConfigOps from "./shared/config-ops.js";
|
||||||
const ConfigValidator = require("./shared/config-validator");
|
import ConfigValidator from "./shared/config-validator.js";
|
||||||
const naming = require("./shared/naming");
|
import * as naming from "./shared/naming.js";
|
||||||
const { FlatCompat } = require("./flat-compat");
|
import { FlatCompat } from "./flat-compat.js";
|
||||||
|
import environments from "../conf/environments.js";
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Exports
|
// Exports
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module.exports = {
|
const Legacy = {
|
||||||
|
ConfigArray,
|
||||||
|
createConfigArrayFactoryContext,
|
||||||
|
CascadingConfigArrayFactory,
|
||||||
|
ConfigArrayFactory,
|
||||||
|
ConfigDependency,
|
||||||
|
ExtractedConfig,
|
||||||
|
IgnorePattern,
|
||||||
|
OverrideTester,
|
||||||
|
getUsedExtractedConfigs,
|
||||||
|
environments,
|
||||||
|
|
||||||
Legacy: {
|
// shared
|
||||||
ConfigArray,
|
ConfigOps,
|
||||||
createConfigArrayFactoryContext,
|
ConfigValidator,
|
||||||
CascadingConfigArrayFactory,
|
ModuleResolver,
|
||||||
ConfigArrayFactory,
|
naming
|
||||||
ConfigDependency,
|
};
|
||||||
ExtractedConfig,
|
|
||||||
IgnorePattern,
|
|
||||||
OverrideTester,
|
|
||||||
getUsedExtractedConfigs,
|
|
||||||
|
|
||||||
// shared
|
export {
|
||||||
ConfigOps,
|
|
||||||
ConfigValidator,
|
Legacy,
|
||||||
ModuleResolver,
|
|
||||||
naming
|
|
||||||
},
|
|
||||||
|
|
||||||
FlatCompat
|
FlatCompat
|
||||||
|
|
||||||
|
|
|
@ -2,20 +2,177 @@
|
||||||
* @fileoverview The instance of Ajv validator.
|
* @fileoverview The instance of Ajv validator.
|
||||||
* @author Evgeny Poberezkin
|
* @author Evgeny Poberezkin
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const Ajv = require("ajv"),
|
import Ajv from "ajv";
|
||||||
metaSchema = require("ajv/lib/refs/json-schema-draft-04.json");
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copied from ajv/lib/refs/json-schema-draft-04.json
|
||||||
|
* The MIT License (MIT)
|
||||||
|
* Copyright (c) 2015-2017 Evgeny Poberezkin
|
||||||
|
*/
|
||||||
|
const metaSchema = {
|
||||||
|
id: "http://json-schema.org/draft-04/schema#",
|
||||||
|
$schema: "http://json-schema.org/draft-04/schema#",
|
||||||
|
description: "Core schema meta-schema",
|
||||||
|
definitions: {
|
||||||
|
schemaArray: {
|
||||||
|
type: "array",
|
||||||
|
minItems: 1,
|
||||||
|
items: { $ref: "#" }
|
||||||
|
},
|
||||||
|
positiveInteger: {
|
||||||
|
type: "integer",
|
||||||
|
minimum: 0
|
||||||
|
},
|
||||||
|
positiveIntegerDefault0: {
|
||||||
|
allOf: [{ $ref: "#/definitions/positiveInteger" }, { default: 0 }]
|
||||||
|
},
|
||||||
|
simpleTypes: {
|
||||||
|
enum: ["array", "boolean", "integer", "null", "number", "object", "string"]
|
||||||
|
},
|
||||||
|
stringArray: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
minItems: 1,
|
||||||
|
uniqueItems: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
$schema: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: "string"
|
||||||
|
},
|
||||||
|
default: { },
|
||||||
|
multipleOf: {
|
||||||
|
type: "number",
|
||||||
|
minimum: 0,
|
||||||
|
exclusiveMinimum: true
|
||||||
|
},
|
||||||
|
maximum: {
|
||||||
|
type: "number"
|
||||||
|
},
|
||||||
|
exclusiveMaximum: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
minimum: {
|
||||||
|
type: "number"
|
||||||
|
},
|
||||||
|
exclusiveMinimum: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxLength: { $ref: "#/definitions/positiveInteger" },
|
||||||
|
minLength: { $ref: "#/definitions/positiveIntegerDefault0" },
|
||||||
|
pattern: {
|
||||||
|
type: "string",
|
||||||
|
format: "regex"
|
||||||
|
},
|
||||||
|
additionalItems: {
|
||||||
|
anyOf: [
|
||||||
|
{ type: "boolean" },
|
||||||
|
{ $ref: "#" }
|
||||||
|
],
|
||||||
|
default: { }
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
anyOf: [
|
||||||
|
{ $ref: "#" },
|
||||||
|
{ $ref: "#/definitions/schemaArray" }
|
||||||
|
],
|
||||||
|
default: { }
|
||||||
|
},
|
||||||
|
maxItems: { $ref: "#/definitions/positiveInteger" },
|
||||||
|
minItems: { $ref: "#/definitions/positiveIntegerDefault0" },
|
||||||
|
uniqueItems: {
|
||||||
|
type: "boolean",
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxProperties: { $ref: "#/definitions/positiveInteger" },
|
||||||
|
minProperties: { $ref: "#/definitions/positiveIntegerDefault0" },
|
||||||
|
required: { $ref: "#/definitions/stringArray" },
|
||||||
|
additionalProperties: {
|
||||||
|
anyOf: [
|
||||||
|
{ type: "boolean" },
|
||||||
|
{ $ref: "#" }
|
||||||
|
],
|
||||||
|
default: { }
|
||||||
|
},
|
||||||
|
definitions: {
|
||||||
|
type: "object",
|
||||||
|
additionalProperties: { $ref: "#" },
|
||||||
|
default: { }
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
type: "object",
|
||||||
|
additionalProperties: { $ref: "#" },
|
||||||
|
default: { }
|
||||||
|
},
|
||||||
|
patternProperties: {
|
||||||
|
type: "object",
|
||||||
|
additionalProperties: { $ref: "#" },
|
||||||
|
default: { }
|
||||||
|
},
|
||||||
|
dependencies: {
|
||||||
|
type: "object",
|
||||||
|
additionalProperties: {
|
||||||
|
anyOf: [
|
||||||
|
{ $ref: "#" },
|
||||||
|
{ $ref: "#/definitions/stringArray" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enum: {
|
||||||
|
type: "array",
|
||||||
|
minItems: 1,
|
||||||
|
uniqueItems: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
anyOf: [
|
||||||
|
{ $ref: "#/definitions/simpleTypes" },
|
||||||
|
{
|
||||||
|
type: "array",
|
||||||
|
items: { $ref: "#/definitions/simpleTypes" },
|
||||||
|
minItems: 1,
|
||||||
|
uniqueItems: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
format: { type: "string" },
|
||||||
|
allOf: { $ref: "#/definitions/schemaArray" },
|
||||||
|
anyOf: { $ref: "#/definitions/schemaArray" },
|
||||||
|
oneOf: { $ref: "#/definitions/schemaArray" },
|
||||||
|
not: { $ref: "#" }
|
||||||
|
},
|
||||||
|
dependencies: {
|
||||||
|
exclusiveMaximum: ["maximum"],
|
||||||
|
exclusiveMinimum: ["minimum"]
|
||||||
|
},
|
||||||
|
default: { }
|
||||||
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Public Interface
|
// Public Interface
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
module.exports = (additionalOptions = {}) => {
|
export default (additionalOptions = {}) => {
|
||||||
const ajv = new Ajv({
|
const ajv = new Ajv({
|
||||||
meta: false,
|
meta: false,
|
||||||
useDefaults: true,
|
useDefaults: true,
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* so no Node-specific code can be here.
|
* so no Node-specific code can be here.
|
||||||
* @author Nicholas C. Zakas
|
* @author Nicholas C. Zakas
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Private
|
// Private
|
||||||
|
@ -20,111 +19,117 @@ const RULE_SEVERITY_STRINGS = ["off", "warn", "error"],
|
||||||
// Public Interface
|
// Public Interface
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
module.exports = {
|
/**
|
||||||
|
* Normalizes the severity value of a rule's configuration to a number
|
||||||
|
* @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally
|
||||||
|
* received from the user. A valid config value is either 0, 1, 2, the string "off" (treated the same as 0),
|
||||||
|
* the string "warn" (treated the same as 1), the string "error" (treated the same as 2), or an array
|
||||||
|
* whose first element is one of the above values. Strings are matched case-insensitively.
|
||||||
|
* @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.
|
||||||
|
*/
|
||||||
|
function getRuleSeverity(ruleConfig) {
|
||||||
|
const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
||||||
|
|
||||||
/**
|
if (severityValue === 0 || severityValue === 1 || severityValue === 2) {
|
||||||
* Normalizes the severity value of a rule's configuration to a number
|
return severityValue;
|
||||||
* @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally
|
|
||||||
* received from the user. A valid config value is either 0, 1, 2, the string "off" (treated the same as 0),
|
|
||||||
* the string "warn" (treated the same as 1), the string "error" (treated the same as 2), or an array
|
|
||||||
* whose first element is one of the above values. Strings are matched case-insensitively.
|
|
||||||
* @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.
|
|
||||||
*/
|
|
||||||
getRuleSeverity(ruleConfig) {
|
|
||||||
const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
|
||||||
|
|
||||||
if (severityValue === 0 || severityValue === 1 || severityValue === 2) {
|
|
||||||
return severityValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof severityValue === "string") {
|
|
||||||
return RULE_SEVERITY[severityValue.toLowerCase()] || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts old-style severity settings (0, 1, 2) into new-style
|
|
||||||
* severity settings (off, warn, error) for all rules. Assumption is that severity
|
|
||||||
* values have already been validated as correct.
|
|
||||||
* @param {Object} config The config object to normalize.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
normalizeToStrings(config) {
|
|
||||||
|
|
||||||
if (config.rules) {
|
|
||||||
Object.keys(config.rules).forEach(ruleId => {
|
|
||||||
const ruleConfig = config.rules[ruleId];
|
|
||||||
|
|
||||||
if (typeof ruleConfig === "number") {
|
|
||||||
config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0];
|
|
||||||
} else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === "number") {
|
|
||||||
ruleConfig[0] = RULE_SEVERITY_STRINGS[ruleConfig[0]] || RULE_SEVERITY_STRINGS[0];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the severity for the given rule configuration represents an error.
|
|
||||||
* @param {int|string|Array} ruleConfig The configuration for an individual rule.
|
|
||||||
* @returns {boolean} True if the rule represents an error, false if not.
|
|
||||||
*/
|
|
||||||
isErrorSeverity(ruleConfig) {
|
|
||||||
return module.exports.getRuleSeverity(ruleConfig) === 2;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether a given config has valid severity or not.
|
|
||||||
* @param {number|string|Array} ruleConfig The configuration for an individual rule.
|
|
||||||
* @returns {boolean} `true` if the configuration has valid severity.
|
|
||||||
*/
|
|
||||||
isValidSeverity(ruleConfig) {
|
|
||||||
let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
|
||||||
|
|
||||||
if (typeof severity === "string") {
|
|
||||||
severity = severity.toLowerCase();
|
|
||||||
}
|
|
||||||
return VALID_SEVERITIES.indexOf(severity) !== -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether every rule of a given config has valid severity or not.
|
|
||||||
* @param {Object} config The configuration for rules.
|
|
||||||
* @returns {boolean} `true` if the configuration has valid severity.
|
|
||||||
*/
|
|
||||||
isEverySeverityValid(config) {
|
|
||||||
return Object.keys(config).every(ruleId => this.isValidSeverity(config[ruleId]));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalizes a value for a global in a config
|
|
||||||
* @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
|
|
||||||
* a global directive comment
|
|
||||||
* @returns {("readable"|"writeable"|"off")} The value normalized as a string
|
|
||||||
* @throws Error if global value is invalid
|
|
||||||
*/
|
|
||||||
normalizeConfigGlobal(configuredValue) {
|
|
||||||
switch (configuredValue) {
|
|
||||||
case "off":
|
|
||||||
return "off";
|
|
||||||
|
|
||||||
case true:
|
|
||||||
case "true":
|
|
||||||
case "writeable":
|
|
||||||
case "writable":
|
|
||||||
return "writable";
|
|
||||||
|
|
||||||
case null:
|
|
||||||
case false:
|
|
||||||
case "false":
|
|
||||||
case "readable":
|
|
||||||
case "readonly":
|
|
||||||
return "readonly";
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error(`'${configuredValue}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof severityValue === "string") {
|
||||||
|
return RULE_SEVERITY[severityValue.toLowerCase()] || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts old-style severity settings (0, 1, 2) into new-style
|
||||||
|
* severity settings (off, warn, error) for all rules. Assumption is that severity
|
||||||
|
* values have already been validated as correct.
|
||||||
|
* @param {Object} config The config object to normalize.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function normalizeToStrings(config) {
|
||||||
|
|
||||||
|
if (config.rules) {
|
||||||
|
Object.keys(config.rules).forEach(ruleId => {
|
||||||
|
const ruleConfig = config.rules[ruleId];
|
||||||
|
|
||||||
|
if (typeof ruleConfig === "number") {
|
||||||
|
config.rules[ruleId] = RULE_SEVERITY_STRINGS[ruleConfig] || RULE_SEVERITY_STRINGS[0];
|
||||||
|
} else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === "number") {
|
||||||
|
ruleConfig[0] = RULE_SEVERITY_STRINGS[ruleConfig[0]] || RULE_SEVERITY_STRINGS[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the severity for the given rule configuration represents an error.
|
||||||
|
* @param {int|string|Array} ruleConfig The configuration for an individual rule.
|
||||||
|
* @returns {boolean} True if the rule represents an error, false if not.
|
||||||
|
*/
|
||||||
|
function isErrorSeverity(ruleConfig) {
|
||||||
|
return getRuleSeverity(ruleConfig) === 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a given config has valid severity or not.
|
||||||
|
* @param {number|string|Array} ruleConfig The configuration for an individual rule.
|
||||||
|
* @returns {boolean} `true` if the configuration has valid severity.
|
||||||
|
*/
|
||||||
|
function isValidSeverity(ruleConfig) {
|
||||||
|
let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
||||||
|
|
||||||
|
if (typeof severity === "string") {
|
||||||
|
severity = severity.toLowerCase();
|
||||||
|
}
|
||||||
|
return VALID_SEVERITIES.indexOf(severity) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether every rule of a given config has valid severity or not.
|
||||||
|
* @param {Object} config The configuration for rules.
|
||||||
|
* @returns {boolean} `true` if the configuration has valid severity.
|
||||||
|
*/
|
||||||
|
function isEverySeverityValid(config) {
|
||||||
|
return Object.keys(config).every(ruleId => isValidSeverity(config[ruleId]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a value for a global in a config
|
||||||
|
* @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
|
||||||
|
* a global directive comment
|
||||||
|
* @returns {("readable"|"writeable"|"off")} The value normalized as a string
|
||||||
|
* @throws Error if global value is invalid
|
||||||
|
*/
|
||||||
|
function normalizeConfigGlobal(configuredValue) {
|
||||||
|
switch (configuredValue) {
|
||||||
|
case "off":
|
||||||
|
return "off";
|
||||||
|
|
||||||
|
case true:
|
||||||
|
case "true":
|
||||||
|
case "writeable":
|
||||||
|
case "writable":
|
||||||
|
return "writable";
|
||||||
|
|
||||||
|
case null:
|
||||||
|
case false:
|
||||||
|
case "false":
|
||||||
|
case "readable":
|
||||||
|
case "readonly":
|
||||||
|
return "readonly";
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`'${configuredValue}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getRuleSeverity,
|
||||||
|
normalizeToStrings,
|
||||||
|
isErrorSeverity,
|
||||||
|
isValidSeverity,
|
||||||
|
isEverySeverityValid,
|
||||||
|
normalizeConfigGlobal
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,22 +3,21 @@
|
||||||
* @author Brandon Mills
|
* @author Brandon Mills
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint class-methods-use-this: "off" */
|
/* eslint class-methods-use-this: "off" */
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const
|
import util from "util";
|
||||||
util = require("util"),
|
import * as ConfigOps from "./config-ops.js";
|
||||||
configSchema = require("../../conf/config-schema"),
|
import { emitDeprecationWarning } from "./deprecation-warnings.js";
|
||||||
BuiltInEnvironments = require("../../conf/environments"),
|
import ajvOrig from "./ajv.js";
|
||||||
ConfigOps = require("./config-ops"),
|
import configSchema from "../../conf/config-schema.js";
|
||||||
{ emitDeprecationWarning } = require("./deprecation-warnings");
|
import BuiltInEnvironments from "../../conf/environments.js";
|
||||||
|
|
||||||
|
const ajv = ajvOrig();
|
||||||
|
|
||||||
const ajv = require("./ajv")();
|
|
||||||
const ruleValidators = new WeakMap();
|
const ruleValidators = new WeakMap();
|
||||||
const noop = Function.prototype;
|
const noop = Function.prototype;
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ const validated = new WeakSet();
|
||||||
// Exports
|
// Exports
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module.exports = class ConfigValidator {
|
export default class ConfigValidator {
|
||||||
constructor({ builtInRules = new Map() } = {}) {
|
constructor({ builtInRules = new Map() } = {}) {
|
||||||
this.builtInRules = builtInRules;
|
this.builtInRules = builtInRules;
|
||||||
}
|
}
|
||||||
|
@ -323,4 +322,4 @@ module.exports = class ConfigValidator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
* @fileoverview Provide the function that emits deprecation warnings.
|
* @fileoverview Provide the function that emits deprecation warnings.
|
||||||
* @author Toru Nagashima <http://github.com/mysticatea>
|
* @author Toru Nagashima <http://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Requirements
|
// Requirements
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
const path = require("path");
|
import path from "path";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Private
|
// Private
|
||||||
|
@ -59,6 +58,6 @@ function emitDeprecationWarning(source, errorCode) {
|
||||||
// Public Interface
|
// Public Interface
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
module.exports = {
|
export {
|
||||||
emitDeprecationWarning
|
emitDeprecationWarning
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* @fileoverview Common helpers for naming of plugins, formatters and configs
|
* @fileoverview Common helpers for naming of plugins, formatters and configs
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const NAMESPACE_REGEX = /^@.*\//iu;
|
const NAMESPACE_REGEX = /^@.*\//iu;
|
||||||
|
|
||||||
|
@ -90,7 +89,7 @@ function getNamespaceFromTerm(term) {
|
||||||
// Public Interface
|
// Public Interface
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
module.exports = {
|
export {
|
||||||
normalizePackageName,
|
normalizePackageName,
|
||||||
getShorthandName,
|
getShorthandName,
|
||||||
getNamespaceFromTerm
|
getNamespaceFromTerm
|
||||||
|
|
|
@ -3,42 +3,40 @@
|
||||||
* @author Teddy Katz
|
* @author Teddy Katz
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
import Module from "module";
|
||||||
|
|
||||||
const Module = require("module");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* `Module.createRequire` is added in v12.2.0. It supports URL as well.
|
* `Module.createRequire` is added in v12.2.0. It supports URL as well.
|
||||||
* We only support the case where the argument is a filepath, not a URL.
|
* We only support the case where the argument is a filepath, not a URL.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line node/no-unsupported-features/node-builtins, node/no-deprecated-api
|
const createRequire = Module.createRequire;
|
||||||
const createRequire = Module.createRequire || Module.createRequireFromPath;
|
|
||||||
|
|
||||||
module.exports = {
|
/**
|
||||||
|
* Resolves a Node module relative to another module
|
||||||
|
* @param {string} moduleName The name of a Node module, or a path to a Node module.
|
||||||
|
* @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
|
||||||
|
* a file rather than a directory, but the file need not actually exist.
|
||||||
|
* @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
|
||||||
|
*/
|
||||||
|
function resolve(moduleName, relativeToPath) {
|
||||||
|
try {
|
||||||
|
return createRequire(relativeToPath).resolve(moduleName);
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
/**
|
// This `if` block is for older Node.js than 12.0.0. We can remove this block in the future.
|
||||||
* Resolves a Node module relative to another module
|
if (
|
||||||
* @param {string} moduleName The name of a Node module, or a path to a Node module.
|
typeof error === "object" &&
|
||||||
* @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
|
error !== null &&
|
||||||
* a file rather than a directory, but the file need not actually exist.
|
error.code === "MODULE_NOT_FOUND" &&
|
||||||
* @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
|
!error.requireStack &&
|
||||||
*/
|
error.message.includes(moduleName)
|
||||||
resolve(moduleName, relativeToPath) {
|
) {
|
||||||
try {
|
error.message += `\nRequire stack:\n- ${relativeToPath}`;
|
||||||
return createRequire(relativeToPath).resolve(moduleName);
|
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
// This `if` block is for older Node.js than 12.0.0. We can remove this block in the future.
|
|
||||||
if (
|
|
||||||
typeof error === "object" &&
|
|
||||||
error !== null &&
|
|
||||||
error.code === "MODULE_NOT_FOUND" &&
|
|
||||||
!error.requireStack &&
|
|
||||||
error.message.includes(moduleName)
|
|
||||||
) {
|
|
||||||
error.message += `\nRequire stack:\n- ${relativeToPath}`;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
resolve
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
* @fileoverview Define common types for input completion.
|
* @fileoverview Define common types for input completion.
|
||||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||||
*/
|
*/
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/** @type {any} */
|
/** @type {any} */
|
||||||
module.exports = {};
|
export default {};
|
||||||
|
|
||||||
/** @typedef {boolean | "off" | "readable" | "readonly" | "writable" | "writeable"} GlobalConf */
|
/** @typedef {boolean | "off" | "readable" | "readonly" | "writable" | "writeable"} GlobalConf */
|
||||||
/** @typedef {0 | 1 | 2 | "off" | "warn" | "error"} SeverityConf */
|
/** @typedef {0 | 1 | 2 | "off" | "warn" | "error"} SeverityConf */
|
||||||
|
|
|
@ -1,27 +1,44 @@
|
||||||
{
|
{
|
||||||
"name": "@eslint/eslintrc",
|
"name": "@eslint/eslintrc",
|
||||||
"version": "0.4.3",
|
"version": "2.1.4",
|
||||||
"description": "The legacy ESLintRC config file format for ESLint",
|
"description": "The legacy ESLintRC config file format for ESLint",
|
||||||
"main": "lib/index.js",
|
"type": "module",
|
||||||
|
"main": "./dist/eslintrc.cjs",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./lib/index.js",
|
||||||
|
"require": "./dist/eslintrc.cjs"
|
||||||
|
},
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
"./universal": {
|
||||||
|
"import": "./lib/index-universal.js",
|
||||||
|
"require": "./dist/eslintrc-universal.cjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"lib",
|
"lib",
|
||||||
"conf",
|
"conf",
|
||||||
"LICENSE"
|
"LICENSE",
|
||||||
|
"dist",
|
||||||
|
"universal.js"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build": "rollup -c",
|
||||||
"lint": "eslint . --report-unused-disable-directives",
|
"lint": "eslint . --report-unused-disable-directives",
|
||||||
"fix": "npm run lint -- --fix",
|
"lint:fix": "npm run lint -- --fix",
|
||||||
"test": "mocha -R progress -c 'tests/lib/**/*.js'",
|
"prepare": "npm run build",
|
||||||
"generate-release": "eslint-generate-release",
|
"release:generate:latest": "eslint-generate-release",
|
||||||
"generate-alpharelease": "eslint-generate-prerelease alpha",
|
"release:generate:alpha": "eslint-generate-prerelease alpha",
|
||||||
"generate-betarelease": "eslint-generate-prerelease beta",
|
"release:generate:beta": "eslint-generate-prerelease beta",
|
||||||
"generate-rcrelease": "eslint-generate-prerelease rc",
|
"release:generate:rc": "eslint-generate-prerelease rc",
|
||||||
"publish-release": "eslint-publish-release"
|
"release:publish": "eslint-publish-release",
|
||||||
|
"test": "mocha -R progress -c 'tests/lib/*.cjs' && c8 mocha -R progress -c 'tests/lib/**/*.js'"
|
||||||
},
|
},
|
||||||
"repository": "eslint/eslintrc",
|
"repository": "eslint/eslintrc",
|
||||||
|
"funding": "https://opencollective.com/eslint",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ESLint",
|
"ESLint",
|
||||||
"ESLintRC",
|
"ESLintRC",
|
||||||
|
@ -34,30 +51,32 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/eslint/eslintrc#readme",
|
"homepage": "https://github.com/eslint/eslintrc#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^4.2.0",
|
"c8": "^7.7.3",
|
||||||
"eslint": "^7.21.0",
|
"chai": "^4.3.4",
|
||||||
|
"eslint": "^7.31.0",
|
||||||
"eslint-config-eslint": "^7.0.0",
|
"eslint-config-eslint": "^7.0.0",
|
||||||
"eslint-plugin-jsdoc": "^32.2.0",
|
"eslint-plugin-jsdoc": "^35.4.1",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-release": "^3.1.2",
|
"eslint-release": "^3.2.0",
|
||||||
"fs-teardown": "0.1.1",
|
"fs-teardown": "^0.1.3",
|
||||||
"mocha": "^8.1.1",
|
"mocha": "^9.0.3",
|
||||||
|
"rollup": "^2.70.1",
|
||||||
"shelljs": "^0.8.4",
|
"shelljs": "^0.8.4",
|
||||||
"sinon": "^9.2.0",
|
"sinon": "^11.1.2",
|
||||||
"temp-dir": "^2.0.0"
|
"temp-dir": "^2.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.3.2",
|
||||||
"espree": "^7.3.0",
|
"espree": "^9.6.0",
|
||||||
"globals": "^13.9.0",
|
"globals": "^13.19.0",
|
||||||
"ignore": "^4.0.6",
|
"ignore": "^5.2.0",
|
||||||
"import-fresh": "^3.2.1",
|
"import-fresh": "^3.2.1",
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^4.1.0",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.1.2",
|
||||||
"strip-json-comments": "^3.1.1"
|
"strip-json-comments": "^3.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^10.12.0 || >=12.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@eslint/js",
|
"name": "@eslint/js",
|
||||||
"version": "9.8.0",
|
"version": "9.9.0",
|
||||||
"description": "ESLint JavaScript language implementation",
|
"description": "ESLint JavaScript language implementation",
|
||||||
"main": "./src/index.js",
|
"main": "./src/index.js",
|
||||||
"scripts": {},
|
"scripts": {},
|
||||||
|
|
|
@ -74,11 +74,11 @@ const configs = new ConfigArray(rawConfigs, {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
This example reads in an object or array from `my.config.js` and passes it into the `ConfigArray` constructor as the first argument. The second argument is an object specifying the `basePath` (the directoy in which `my.config.js` is found) and a `schema` to define the additional properties of a config object beyond `files`, `ignores`, and `name`.
|
This example reads in an object or array from `my.config.js` and passes it into the `ConfigArray` constructor as the first argument. The second argument is an object specifying the `basePath` (the directory in which `my.config.js` is found) and a `schema` to define the additional properties of a config object beyond `files`, `ignores`, and `name`.
|
||||||
|
|
||||||
### Specifying a Schema
|
### Specifying a Schema
|
||||||
|
|
||||||
The `schema` option is required for you to use additional properties in config objects. The schema is object that follows the format of an [`ObjectSchema`](https://npmjs.com/package/@humanwhocodes/object-schema). The schema specifies both validation and merge rules that the `ConfigArray` instance needs to combine configs when there are multiple matches. Here's an example:
|
The `schema` option is required for you to use additional properties in config objects. The schema is an object that follows the format of an [`ObjectSchema`](https://npmjs.com/package/@humanwhocodes/object-schema). The schema specifies both validation and merge rules that the `ConfigArray` instance needs to combine configs when there are multiple matches. Here's an example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const configFilename = path.resolve(process.cwd(), "my.config.js");
|
const configFilename = path.resolve(process.cwd(), "my.config.js");
|
||||||
|
@ -106,14 +106,17 @@ const configs = new ConfigArray(rawConfigs, {
|
||||||
// the path to match filenames from
|
// the path to match filenames from
|
||||||
basePath: process.cwd(),
|
basePath: process.cwd(),
|
||||||
|
|
||||||
// additional items in each config
|
// additional item schemas in each config
|
||||||
schema: mySchema
|
schema: mySchema,
|
||||||
|
|
||||||
|
// additional config types supported (default: [])
|
||||||
|
extraConfigTypes: ["array", "function"];
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Config Arrays
|
### Config Arrays
|
||||||
|
|
||||||
Config arrays can be multidimensional, so it's possible for a config array to contain another config array, such as:
|
Config arrays can be multidimensional, so it's possible for a config array to contain another config array when `extraConfigTypes` contains `"array"`, such as:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export default [
|
export default [
|
||||||
|
@ -171,11 +174,44 @@ If the `files` array contains a function, then that function is called with the
|
||||||
|
|
||||||
If the `files` array contains an item that is an array of strings and functions, then all patterns must match in order for the config to match. In the preceding examples, both `*.test.*` and `*.js` must match in order for the config object to be used.
|
If the `files` array contains an item that is an array of strings and functions, then all patterns must match in order for the config to match. In the preceding examples, both `*.test.*` and `*.js` must match in order for the config object to be used.
|
||||||
|
|
||||||
If a pattern in the files array begins with `!` then it excludes that pattern. In the preceding example, any filename that doesn't end with `.js` will automatically getting a `settings.js` property set to `false`.
|
If a pattern in the files array begins with `!` then it excludes that pattern. In the preceding example, any filename that doesn't end with `.js` will automatically get a `settings.js` property set to `false`.
|
||||||
|
|
||||||
|
You can also specify an `ignores` key that will force files matching those patterns to not be included. If the `ignores` key is in a config object without any other keys, then those ignores will always be applied; otherwise those ignores act as exclusions. Here's an example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default [
|
||||||
|
|
||||||
|
// Always ignored
|
||||||
|
{
|
||||||
|
ignores: ["**/.git/**", "**/node_modules/**"]
|
||||||
|
},
|
||||||
|
|
||||||
|
// .eslintrc.js file is ignored only when .js file matches
|
||||||
|
{
|
||||||
|
files: ["**/*.js"],
|
||||||
|
ignores: [".eslintrc.js"]
|
||||||
|
handler: jsHandler
|
||||||
|
}
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use negated patterns in `ignores` to exclude a file that was already ignored, such as:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default [
|
||||||
|
|
||||||
|
// Ignore all JSON files except tsconfig.json
|
||||||
|
{
|
||||||
|
files: ["**/*"],
|
||||||
|
ignores: ["**/*.json", "!tsconfig.json"]
|
||||||
|
},
|
||||||
|
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
### Config Functions
|
### Config Functions
|
||||||
|
|
||||||
Config arrays can also include config functions. A config function accepts a single parameter, `context` (defined by you), and must return either a config object or a config array (it cannot return another function). Config functions allow end users to execute code in the creation of appropriate config objects. Here's an example:
|
Config arrays can also include config functions when `extraConfigTypes` contains `"function"`. A config function accepts a single parameter, `context` (defined by you), and must return either a config object or a config array (it cannot return another function). Config functions allow end users to execute code in the creation of appropriate config objects. Here's an example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export default [
|
export default [
|
||||||
|
@ -210,7 +246,7 @@ export default [
|
||||||
|
|
||||||
When a config array is normalized, each function is executed and replaced in the config array with the return value.
|
When a config array is normalized, each function is executed and replaced in the config array with the return value.
|
||||||
|
|
||||||
**Note:** Config functions cannot be async. This will be added in a future version.
|
**Note:** Config functions can also be async.
|
||||||
|
|
||||||
### Normalizing Config Arrays
|
### Normalizing Config Arrays
|
||||||
|
|
||||||
|
@ -226,6 +262,14 @@ await configs.normalize({
|
||||||
|
|
||||||
The `normalize()` method returns a promise, so be sure to use the `await` operator. The config array instance is normalized in-place, so you don't need to create a new variable.
|
The `normalize()` method returns a promise, so be sure to use the `await` operator. The config array instance is normalized in-place, so you don't need to create a new variable.
|
||||||
|
|
||||||
|
If you want to disallow async config functions, you can call `normalizeSync()` instead. This method is completely synchronous and does not require using the `await` operator as it does not return a promise:
|
||||||
|
|
||||||
|
```js
|
||||||
|
await configs.normalizeSync({
|
||||||
|
name: "MyApp"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
**Important:** Once a `ConfigArray` is normalized, it cannot be changed further. You can, however, create a new `ConfigArray` and pass in the normalized instance to create an unnormalized copy.
|
**Important:** Once a `ConfigArray` is normalized, it cannot be changed further. You can, however, create a new `ConfigArray` and pass in the normalized instance to create an unnormalized copy.
|
||||||
|
|
||||||
### Getting Config for a File
|
### Getting Config for a File
|
||||||
|
@ -244,6 +288,46 @@ A few things to keep in mind:
|
||||||
* You must pass in the absolute filename to get a config for.
|
* You must pass in the absolute filename to get a config for.
|
||||||
* The returned config object never has `files`, `ignores`, or `name` properties; the only properties on the object will be the other configuration options specified.
|
* The returned config object never has `files`, `ignores`, or `name` properties; the only properties on the object will be the other configuration options specified.
|
||||||
* The config array caches configs, so subsequent calls to `getConfig()` with the same filename will return in a fast lookup rather than another calculation.
|
* The config array caches configs, so subsequent calls to `getConfig()` with the same filename will return in a fast lookup rather than another calculation.
|
||||||
|
* A config will only be generated if the filename matches an entry in a `files` key. A config will not be generated without matching a `files` key (configs without a `files` key are only applied when another config with a `files` key is applied; configs without `files` are never applied on their own). Any config with a `files` key entry ending with `/**` or `/*` will only be applied if another entry in the same `files` key matches or another config matches.
|
||||||
|
|
||||||
|
## Determining Ignored Paths
|
||||||
|
|
||||||
|
You can determine if a file is ignored by using the `isFileIgnored()` method and passing in the absolute path of any file, as in this example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const ignored = configs.isFileIgnored('/foo/bar/baz.txt');
|
||||||
|
```
|
||||||
|
|
||||||
|
A file is considered ignored if any of the following is true:
|
||||||
|
|
||||||
|
* **It's parent directory is ignored.** For example, if `foo` is in `ignores`, then `foo/a.js` is considered ignored.
|
||||||
|
* **It has an ancestor directory that is ignored.** For example, if `foo` is in `ignores`, then `foo/baz/a.js` is considered ignored.
|
||||||
|
* **It matches an ignored file pattern.** For example, if `**/a.js` is in `ignores`, then `foo/a.js` and `foo/baz/a.js` are considered ignored.
|
||||||
|
* **If it matches an entry in `files` and also in `ignores`.** For example, if `**/*.js` is in `files` and `**/a.js` is in `ignores`, then `foo/a.js` and `foo/baz/a.js` are considered ignored.
|
||||||
|
* **The file is outside the `basePath`.** If the `basePath` is `/usr/me`, then `/foo/a.js` is considered ignored.
|
||||||
|
|
||||||
|
For directories, use the `isDirectoryIgnored()` method and pass in the absolute path of any directory, as in this example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const ignored = configs.isDirectoryIgnored('/foo/bar/');
|
||||||
|
```
|
||||||
|
|
||||||
|
A directory is considered ignored if any of the following is true:
|
||||||
|
|
||||||
|
* **It's parent directory is ignored.** For example, if `foo` is in `ignores`, then `foo/baz` is considered ignored.
|
||||||
|
* **It has an ancestor directory that is ignored.** For example, if `foo` is in `ignores`, then `foo/bar/baz/a.js` is considered ignored.
|
||||||
|
* **It matches and ignored file pattern.** For example, if `**/a.js` is in `ignores`, then `foo/a.js` and `foo/baz/a.js` are considered ignored.
|
||||||
|
* **If it matches an entry in `files` and also in `ignores`.** For example, if `**/*.js` is in `files` and `**/a.js` is in `ignores`, then `foo/a.js` and `foo/baz/a.js` are considered ignored.
|
||||||
|
* **The file is outside the `basePath`.** If the `basePath` is `/usr/me`, then `/foo/a.js` is considered ignored.
|
||||||
|
|
||||||
|
**Important:** A pattern such as `foo/**` means that `foo` and `foo/` are *not* ignored whereas `foo/bar` is ignored. If you want to ignore `foo` and all of its subdirectories, use the pattern `foo` or `foo/` in `ignores`.
|
||||||
|
|
||||||
|
## Caching Mechanisms
|
||||||
|
|
||||||
|
Each `ConfigArray` aggressively caches configuration objects to avoid unnecessary work. This caching occurs in two ways:
|
||||||
|
|
||||||
|
1. **File-based Caching.** For each filename that is passed into a method, the resulting config is cached against that filename so you're always guaranteed to get the same object returned from `getConfig()` whenever you pass the same filename in.
|
||||||
|
2. **Index-based Caching.** Whenever a config is calculated, the config elements that were used to create the config are also cached. So if a given filename matches elements 1, 5, and 7, the resulting config is cached with a key of `1,5,7`. That way, if another file is passed that matches the same config elements, the result is already known and doesn't have to be recalculated. That means two files that match all the same elements will return the same config from `getConfig()`.
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
Object.defineProperty(exports, '__esModule', { value: true });
|
var path = require('path');
|
||||||
|
var minimatch = require('minimatch');
|
||||||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
var createDebug = require('debug');
|
||||||
|
|
||||||
var path = _interopDefault(require('path'));
|
|
||||||
var minimatch = _interopDefault(require('minimatch'));
|
|
||||||
var createDebug = _interopDefault(require('debug'));
|
|
||||||
var objectSchema = require('@humanwhocodes/object-schema');
|
var objectSchema = require('@humanwhocodes/object-schema');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,31 +14,13 @@ var objectSchema = require('@humanwhocodes/object-schema');
|
||||||
// Helpers
|
// Helpers
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
const NOOP_STRATEGY = {
|
||||||
* Assets that a given value is an array.
|
required: false,
|
||||||
* @param {*} value The value to check.
|
merge() {
|
||||||
* @returns {void}
|
return undefined;
|
||||||
* @throws {TypeError} When the value is not an array.
|
},
|
||||||
*/
|
validate() { }
|
||||||
function assertIsArray(value) {
|
};
|
||||||
if (!Array.isArray(value)) {
|
|
||||||
throw new TypeError('Expected value to be an array.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assets that a given value is an array containing only strings and functions.
|
|
||||||
* @param {*} value The value to check.
|
|
||||||
* @returns {void}
|
|
||||||
* @throws {TypeError} When the value is not an array of strings and functions.
|
|
||||||
*/
|
|
||||||
function assertIsArrayOfStringsAndFunctions(value, name) {
|
|
||||||
assertIsArray(value);
|
|
||||||
|
|
||||||
if (value.some(item => typeof item !== 'string' && typeof item !== 'function')) {
|
|
||||||
throw new TypeError('Expected array to only contain strings.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Exports
|
// Exports
|
||||||
|
@ -64,6 +42,66 @@ const baseSchema = Object.freeze({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
files: NOOP_STRATEGY,
|
||||||
|
ignores: NOOP_STRATEGY
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview ConfigSchema
|
||||||
|
* @author Nicholas C. Zakas
|
||||||
|
*/
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that a given value is an array.
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {void}
|
||||||
|
* @throws {TypeError} When the value is not an array.
|
||||||
|
*/
|
||||||
|
function assertIsArray(value) {
|
||||||
|
if (!Array.isArray(value)) {
|
||||||
|
throw new TypeError('Expected value to be an array.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that a given value is an array containing only strings and functions.
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {void}
|
||||||
|
* @throws {TypeError} When the value is not an array of strings and functions.
|
||||||
|
*/
|
||||||
|
function assertIsArrayOfStringsAndFunctions(value, name) {
|
||||||
|
assertIsArray(value);
|
||||||
|
|
||||||
|
if (value.some(item => typeof item !== 'string' && typeof item !== 'function')) {
|
||||||
|
throw new TypeError('Expected array to only contain strings and functions.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that a given value is a non-empty array.
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {void}
|
||||||
|
* @throws {TypeError} When the value is not an array or an empty array.
|
||||||
|
*/
|
||||||
|
function assertIsNonEmptyArray(value) {
|
||||||
|
if (!Array.isArray(value) || value.length === 0) {
|
||||||
|
throw new TypeError('Expected value to be a non-empty array.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Exports
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The schema for `files` and `ignores` that every ConfigArray uses.
|
||||||
|
* @type Object
|
||||||
|
*/
|
||||||
|
const filesAndIgnoresSchema = Object.freeze({
|
||||||
files: {
|
files: {
|
||||||
required: false,
|
required: false,
|
||||||
merge() {
|
merge() {
|
||||||
|
@ -72,7 +110,7 @@ const baseSchema = Object.freeze({
|
||||||
validate(value) {
|
validate(value) {
|
||||||
|
|
||||||
// first check if it's an array
|
// first check if it's an array
|
||||||
assertIsArray(value);
|
assertIsNonEmptyArray(value);
|
||||||
|
|
||||||
// then check each member
|
// then check each member
|
||||||
value.forEach(item => {
|
value.forEach(item => {
|
||||||
|
@ -99,16 +137,25 @@ const baseSchema = Object.freeze({
|
||||||
* @author Nicholas C. Zakas
|
* @author Nicholas C. Zakas
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const Minimatch = minimatch.Minimatch;
|
||||||
|
const minimatchCache = new Map();
|
||||||
|
const negatedMinimatchCache = new Map();
|
||||||
const debug = createDebug('@hwc/config-array');
|
const debug = createDebug('@hwc/config-array');
|
||||||
|
|
||||||
const MINIMATCH_OPTIONS = {
|
const MINIMATCH_OPTIONS = {
|
||||||
matchBase: true
|
// matchBase: true,
|
||||||
|
dot: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CONFIG_TYPES = new Set(['array', 'function']);
|
||||||
|
|
||||||
|
const FILES_AND_IGNORES_SCHEMA = new objectSchema.ObjectSchema(filesAndIgnoresSchema);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shorthand for checking if a value is a string.
|
* Shorthand for checking if a value is a string.
|
||||||
* @param {any} value The value to check.
|
* @param {any} value The value to check.
|
||||||
|
@ -118,27 +165,143 @@ function isString(value) {
|
||||||
return typeof value === 'string';
|
return typeof value === 'string';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the files and ignores keys of a config object are valid as per base schema.
|
||||||
|
* @param {object} config The config object to check.
|
||||||
|
* @returns {void}
|
||||||
|
* @throws {TypeError} If the files and ignores keys of a config object are not valid.
|
||||||
|
*/
|
||||||
|
function assertValidFilesAndIgnores(config) {
|
||||||
|
if (!config || typeof config !== 'object') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const validateConfig = { };
|
||||||
|
if ('files' in config) {
|
||||||
|
validateConfig.files = config.files;
|
||||||
|
}
|
||||||
|
if ('ignores' in config) {
|
||||||
|
validateConfig.ignores = config.ignores;
|
||||||
|
}
|
||||||
|
FILES_AND_IGNORES_SCHEMA.validate(validateConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around minimatch that caches minimatch patterns for
|
||||||
|
* faster matching speed over multiple file path evaluations.
|
||||||
|
* @param {string} filepath The file path to match.
|
||||||
|
* @param {string} pattern The glob pattern to match against.
|
||||||
|
* @param {object} options The minimatch options to use.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function doMatch(filepath, pattern, options = {}) {
|
||||||
|
|
||||||
|
let cache = minimatchCache;
|
||||||
|
|
||||||
|
if (options.flipNegate) {
|
||||||
|
cache = negatedMinimatchCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
let matcher = cache.get(pattern);
|
||||||
|
|
||||||
|
if (!matcher) {
|
||||||
|
matcher = new Minimatch(pattern, Object.assign({}, MINIMATCH_OPTIONS, options));
|
||||||
|
cache.set(pattern, matcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matcher.match(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalizes a `ConfigArray` by flattening it and executing any functions
|
* Normalizes a `ConfigArray` by flattening it and executing any functions
|
||||||
* that are found inside.
|
* that are found inside.
|
||||||
* @param {Array} items The items in a `ConfigArray`.
|
* @param {Array} items The items in a `ConfigArray`.
|
||||||
* @param {Object} context The context object to pass into any function
|
* @param {Object} context The context object to pass into any function
|
||||||
* found.
|
* found.
|
||||||
* @returns {Array} A flattened array containing only config objects.
|
* @param {Array<string>} extraConfigTypes The config types to check.
|
||||||
|
* @returns {Promise<Array>} A flattened array containing only config objects.
|
||||||
* @throws {TypeError} When a config function returns a function.
|
* @throws {TypeError} When a config function returns a function.
|
||||||
*/
|
*/
|
||||||
async function normalize(items, context) {
|
async function normalize(items, context, extraConfigTypes) {
|
||||||
|
|
||||||
// TODO: Allow async config functions
|
const allowFunctions = extraConfigTypes.includes('function');
|
||||||
|
const allowArrays = extraConfigTypes.includes('array');
|
||||||
|
|
||||||
function *flatTraverse(array) {
|
async function* flatTraverse(array) {
|
||||||
for (let item of array) {
|
for (let item of array) {
|
||||||
if (typeof item === 'function') {
|
if (typeof item === 'function') {
|
||||||
|
if (!allowFunctions) {
|
||||||
|
throw new TypeError('Unexpected function.');
|
||||||
|
}
|
||||||
|
|
||||||
item = item(context);
|
item = item(context);
|
||||||
|
if (item.then) {
|
||||||
|
item = await item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(item)) {
|
if (Array.isArray(item)) {
|
||||||
yield * flatTraverse(item);
|
if (!allowArrays) {
|
||||||
|
throw new TypeError('Unexpected array.');
|
||||||
|
}
|
||||||
|
yield* flatTraverse(item);
|
||||||
|
} else if (typeof item === 'function') {
|
||||||
|
throw new TypeError('A config function can only return an object or array.');
|
||||||
|
} else {
|
||||||
|
yield item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Async iterables cannot be used with the spread operator, so we need to manually
|
||||||
|
* create the array to return.
|
||||||
|
*/
|
||||||
|
const asyncIterable = await flatTraverse(items);
|
||||||
|
const configs = [];
|
||||||
|
|
||||||
|
for await (const config of asyncIterable) {
|
||||||
|
configs.push(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return configs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a `ConfigArray` by flattening it and executing any functions
|
||||||
|
* that are found inside.
|
||||||
|
* @param {Array} items The items in a `ConfigArray`.
|
||||||
|
* @param {Object} context The context object to pass into any function
|
||||||
|
* found.
|
||||||
|
* @param {Array<string>} extraConfigTypes The config types to check.
|
||||||
|
* @returns {Array} A flattened array containing only config objects.
|
||||||
|
* @throws {TypeError} When a config function returns a function.
|
||||||
|
*/
|
||||||
|
function normalizeSync(items, context, extraConfigTypes) {
|
||||||
|
|
||||||
|
const allowFunctions = extraConfigTypes.includes('function');
|
||||||
|
const allowArrays = extraConfigTypes.includes('array');
|
||||||
|
|
||||||
|
function* flatTraverse(array) {
|
||||||
|
for (let item of array) {
|
||||||
|
if (typeof item === 'function') {
|
||||||
|
|
||||||
|
if (!allowFunctions) {
|
||||||
|
throw new TypeError('Unexpected function.');
|
||||||
|
}
|
||||||
|
|
||||||
|
item = item(context);
|
||||||
|
if (item.then) {
|
||||||
|
throw new TypeError('Async config functions are not supported.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(item)) {
|
||||||
|
|
||||||
|
if (!allowArrays) {
|
||||||
|
throw new TypeError('Unexpected array.');
|
||||||
|
}
|
||||||
|
|
||||||
|
yield* flatTraverse(item);
|
||||||
} else if (typeof item === 'function') {
|
} else if (typeof item === 'function') {
|
||||||
throw new TypeError('A config function can only return an object or array.');
|
throw new TypeError('A config function can only return an object or array.');
|
||||||
} else {
|
} else {
|
||||||
|
@ -150,43 +313,111 @@ async function normalize(items, context) {
|
||||||
return [...flatTraverse(items)];
|
return [...flatTraverse(items)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a given file path should be ignored based on the given
|
||||||
|
* matcher.
|
||||||
|
* @param {Array<string|() => boolean>} ignores The ignore patterns to check.
|
||||||
|
* @param {string} filePath The absolute path of the file to check.
|
||||||
|
* @param {string} relativeFilePath The relative path of the file to check.
|
||||||
|
* @returns {boolean} True if the path should be ignored and false if not.
|
||||||
|
*/
|
||||||
|
function shouldIgnorePath(ignores, filePath, relativeFilePath) {
|
||||||
|
|
||||||
|
// all files outside of the basePath are ignored
|
||||||
|
if (relativeFilePath.startsWith('..')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignores.reduce((ignored, matcher) => {
|
||||||
|
|
||||||
|
if (!ignored) {
|
||||||
|
|
||||||
|
if (typeof matcher === 'function') {
|
||||||
|
return matcher(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't check negated patterns because we're not ignored yet
|
||||||
|
if (!matcher.startsWith('!')) {
|
||||||
|
return doMatch(relativeFilePath, matcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise we're still not ignored
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// only need to check negated patterns because we're ignored
|
||||||
|
if (typeof matcher === 'string' && matcher.startsWith('!')) {
|
||||||
|
return !doMatch(relativeFilePath, matcher, {
|
||||||
|
flipNegate: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignored;
|
||||||
|
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a given file path is matched by a config based on
|
||||||
|
* `ignores` only.
|
||||||
|
* @param {string} filePath The absolute file path to check.
|
||||||
|
* @param {string} basePath The base path for the config.
|
||||||
|
* @param {Object} config The config object to check.
|
||||||
|
* @returns {boolean} True if the file path is matched by the config,
|
||||||
|
* false if not.
|
||||||
|
*/
|
||||||
|
function pathMatchesIgnores(filePath, basePath, config) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For both files and ignores, functions are passed the absolute
|
||||||
|
* file path while strings are compared against the relative
|
||||||
|
* file path.
|
||||||
|
*/
|
||||||
|
const relativeFilePath = path.relative(basePath, filePath);
|
||||||
|
|
||||||
|
return Object.keys(config).length > 1 &&
|
||||||
|
!shouldIgnorePath(config.ignores, filePath, relativeFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if a given file path is matched by a config. If the config
|
* Determines if a given file path is matched by a config. If the config
|
||||||
* has no `files` field, then it matches; otherwise, if a `files` field
|
* has no `files` field, then it matches; otherwise, if a `files` field
|
||||||
* is present then we match the globs in `files` and exclude any globs in
|
* is present then we match the globs in `files` and exclude any globs in
|
||||||
* `ignores`.
|
* `ignores`.
|
||||||
* @param {string} filePath The absolute file path to check.
|
* @param {string} filePath The absolute file path to check.
|
||||||
|
* @param {string} basePath The base path for the config.
|
||||||
* @param {Object} config The config object to check.
|
* @param {Object} config The config object to check.
|
||||||
* @returns {boolean} True if the file path is matched by the config,
|
* @returns {boolean} True if the file path is matched by the config,
|
||||||
* false if not.
|
* false if not.
|
||||||
*/
|
*/
|
||||||
function pathMatches(filePath, basePath, config) {
|
function pathMatches(filePath, basePath, config) {
|
||||||
|
|
||||||
// a config without a `files` field always matches
|
/*
|
||||||
if (!config.files) {
|
* For both files and ignores, functions are passed the absolute
|
||||||
return true;
|
* file path while strings are compared against the relative
|
||||||
}
|
* file path.
|
||||||
|
*/
|
||||||
// if files isn't an array, throw an error
|
|
||||||
if (!Array.isArray(config.files) || config.files.length === 0) {
|
|
||||||
throw new TypeError('The files key must be a non-empty array.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const relativeFilePath = path.relative(basePath, filePath);
|
const relativeFilePath = path.relative(basePath, filePath);
|
||||||
|
|
||||||
// match both strings and functions
|
// match both strings and functions
|
||||||
const match = pattern => {
|
const match = pattern => {
|
||||||
|
|
||||||
if (isString(pattern)) {
|
if (isString(pattern)) {
|
||||||
return minimatch(relativeFilePath, pattern, MINIMATCH_OPTIONS);
|
return doMatch(relativeFilePath, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof pattern === 'function') {
|
if (typeof pattern === 'function') {
|
||||||
return pattern(filePath);
|
return pattern(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new TypeError(`Unexpected matcher type ${pattern}.`);
|
||||||
};
|
};
|
||||||
|
|
||||||
// check for all matches to config.files
|
// check for all matches to config.files
|
||||||
let matches = config.files.some(pattern => {
|
let filePathMatchesPattern = config.files.some(pattern => {
|
||||||
if (Array.isArray(pattern)) {
|
if (Array.isArray(pattern)) {
|
||||||
return pattern.every(match);
|
return pattern.every(match);
|
||||||
}
|
}
|
||||||
|
@ -198,13 +429,11 @@ function pathMatches(filePath, basePath, config) {
|
||||||
* If the file path matches the config.files patterns, then check to see
|
* If the file path matches the config.files patterns, then check to see
|
||||||
* if there are any files to ignore.
|
* if there are any files to ignore.
|
||||||
*/
|
*/
|
||||||
if (matches && config.ignores) {
|
if (filePathMatchesPattern && config.ignores) {
|
||||||
matches = !config.ignores.some(pattern => {
|
filePathMatchesPattern = !shouldIgnorePath(config.ignores, filePath, relativeFilePath);
|
||||||
return minimatch(filePath, pattern, MINIMATCH_OPTIONS);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches;
|
return filePathMatchesPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,6 +449,24 @@ function assertNormalized(configArray) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that config types are valid.
|
||||||
|
* @param {Array<string>} extraConfigTypes The config types to check.
|
||||||
|
* @returns {void}
|
||||||
|
* @throws {Error} When the config types array is invalid.
|
||||||
|
*/
|
||||||
|
function assertExtraConfigTypes(extraConfigTypes) {
|
||||||
|
if (extraConfigTypes.length > 2) {
|
||||||
|
throw new TypeError('configTypes must be an array with at most two items.');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const configType of extraConfigTypes) {
|
||||||
|
if (!CONFIG_TYPES.has(configType)) {
|
||||||
|
throw new TypeError(`Unexpected config type "${configType}" found. Expected one of: "object", "array", "function".`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Public Interface
|
// Public Interface
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -232,6 +479,9 @@ const ConfigArraySymbol = {
|
||||||
preprocessConfig: Symbol('preprocessConfig')
|
preprocessConfig: Symbol('preprocessConfig')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// used to store calculate data for faster lookup
|
||||||
|
const dataCache = new WeakMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an array of config objects and provides method for working with
|
* Represents an array of config objects and provides method for working with
|
||||||
* those config objects.
|
* those config objects.
|
||||||
|
@ -247,8 +497,15 @@ class ConfigArray extends Array {
|
||||||
* configs have already been normalized.
|
* configs have already been normalized.
|
||||||
* @param {Object} [options.schema] The additional schema
|
* @param {Object} [options.schema] The additional schema
|
||||||
* definitions to use for the ConfigArray schema.
|
* definitions to use for the ConfigArray schema.
|
||||||
|
* @param {Array<string>} [options.configTypes] List of config types supported.
|
||||||
*/
|
*/
|
||||||
constructor(configs, { basePath = '', normalized = false, schema: customSchema } = {}) {
|
constructor(configs, {
|
||||||
|
basePath = '',
|
||||||
|
normalized = false,
|
||||||
|
schema: customSchema,
|
||||||
|
extraConfigTypes = []
|
||||||
|
} = {}
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,10 +522,9 @@ class ConfigArray extends Array {
|
||||||
* @type ObjectSchema
|
* @type ObjectSchema
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this[ConfigArraySymbol.schema] = new objectSchema.ObjectSchema({
|
this[ConfigArraySymbol.schema] = new objectSchema.ObjectSchema(
|
||||||
...customSchema,
|
Object.assign({}, customSchema, baseSchema)
|
||||||
...baseSchema
|
);
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path of the config file that this array was loaded from.
|
* The path of the config file that this array was loaded from.
|
||||||
|
@ -278,6 +534,15 @@ class ConfigArray extends Array {
|
||||||
*/
|
*/
|
||||||
this.basePath = basePath;
|
this.basePath = basePath;
|
||||||
|
|
||||||
|
assertExtraConfigTypes(extraConfigTypes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The supported config types.
|
||||||
|
* @property configTypes
|
||||||
|
* @type Array<string>
|
||||||
|
*/
|
||||||
|
this.extraConfigTypes = Object.freeze([...extraConfigTypes]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache to store calculated configs for faster repeat lookup.
|
* A cache to store calculated configs for faster repeat lookup.
|
||||||
* @property configCache
|
* @property configCache
|
||||||
|
@ -286,6 +551,14 @@ class ConfigArray extends Array {
|
||||||
*/
|
*/
|
||||||
this[ConfigArraySymbol.configCache] = new Map();
|
this[ConfigArraySymbol.configCache] = new Map();
|
||||||
|
|
||||||
|
// init cache
|
||||||
|
dataCache.set(this, {
|
||||||
|
explicitMatches: new Map(),
|
||||||
|
directoryMatches: new Map(),
|
||||||
|
files: undefined,
|
||||||
|
ignores: undefined
|
||||||
|
});
|
||||||
|
|
||||||
// load the configs into this array
|
// load the configs into this array
|
||||||
if (Array.isArray(configs)) {
|
if (Array.isArray(configs)) {
|
||||||
this.push(...configs);
|
this.push(...configs);
|
||||||
|
@ -308,54 +581,79 @@ class ConfigArray extends Array {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the `files` globs from every config object in the array.
|
* Returns the `files` globs from every config object in the array.
|
||||||
* Negated patterns (those beginning with `!`) are not returned.
|
|
||||||
* This can be used to determine which files will be matched by a
|
* This can be used to determine which files will be matched by a
|
||||||
* config array or to use as a glob pattern when no patterns are provided
|
* config array or to use as a glob pattern when no patterns are provided
|
||||||
* for a command line interface.
|
* for a command line interface.
|
||||||
* @returns {string[]} An array of string patterns.
|
* @returns {Array<string|Function>} An array of matchers.
|
||||||
*/
|
*/
|
||||||
get files() {
|
get files() {
|
||||||
|
|
||||||
assertNormalized(this);
|
assertNormalized(this);
|
||||||
|
|
||||||
|
// if this data has been cached, retrieve it
|
||||||
|
const cache = dataCache.get(this);
|
||||||
|
|
||||||
|
if (cache.files) {
|
||||||
|
return cache.files;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise calculate it
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
|
|
||||||
for (const config of this) {
|
for (const config of this) {
|
||||||
if (config.files) {
|
if (config.files) {
|
||||||
config.files.forEach(filePattern => {
|
config.files.forEach(filePattern => {
|
||||||
if (Array.isArray(filePattern)) {
|
result.push(filePattern);
|
||||||
result.push(...filePattern.filter(pattern => {
|
|
||||||
return isString(pattern) && !pattern.startsWith('!');
|
|
||||||
}));
|
|
||||||
} else if (isString(filePattern) && !filePattern.startsWith('!')) {
|
|
||||||
result.push(filePattern);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// store result
|
||||||
|
cache.files = result;
|
||||||
|
dataCache.set(this, cache);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the file globs that should always be ignored regardless of
|
* Returns ignore matchers that should always be ignored regardless of
|
||||||
* the matching `files` fields in any configs. This is necessary to mimic
|
* the matching `files` fields in any configs. This is necessary to mimic
|
||||||
* the behavior of things like .gitignore and .eslintignore, allowing a
|
* the behavior of things like .gitignore and .eslintignore, allowing a
|
||||||
* globbing operation to be faster.
|
* globbing operation to be faster.
|
||||||
* @returns {string[]} An array of string patterns to be ignored.
|
* @returns {string[]} An array of string patterns and functions to be ignored.
|
||||||
*/
|
*/
|
||||||
get ignores() {
|
get ignores() {
|
||||||
|
|
||||||
assertNormalized(this);
|
assertNormalized(this);
|
||||||
|
|
||||||
|
// if this data has been cached, retrieve it
|
||||||
|
const cache = dataCache.get(this);
|
||||||
|
|
||||||
|
if (cache.ignores) {
|
||||||
|
return cache.ignores;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise calculate it
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
|
|
||||||
for (const config of this) {
|
for (const config of this) {
|
||||||
if (config.ignores && !config.files) {
|
|
||||||
result.push(...config.ignores.filter(isString));
|
/*
|
||||||
|
* We only count ignores if there are no other keys in the object.
|
||||||
|
* In this case, it acts list a globally ignored pattern. If there
|
||||||
|
* are additional keys, then ignores act like exclusions.
|
||||||
|
*/
|
||||||
|
if (config.ignores && Object.keys(config).length === 1) {
|
||||||
|
result.push(...config.ignores);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// store result
|
||||||
|
cache.ignores = result;
|
||||||
|
dataCache.set(this, cache);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,14 +669,37 @@ class ConfigArray extends Array {
|
||||||
* Normalizes a config array by flattening embedded arrays and executing
|
* Normalizes a config array by flattening embedded arrays and executing
|
||||||
* config functions.
|
* config functions.
|
||||||
* @param {ConfigContext} context The context object for config functions.
|
* @param {ConfigContext} context The context object for config functions.
|
||||||
* @returns {ConfigArray} A new ConfigArray instance that is normalized.
|
* @returns {Promise<ConfigArray>} The current ConfigArray instance.
|
||||||
*/
|
*/
|
||||||
async normalize(context = {}) {
|
async normalize(context = {}) {
|
||||||
|
|
||||||
if (!this.isNormalized()) {
|
if (!this.isNormalized()) {
|
||||||
const normalizedConfigs = await normalize(this, context);
|
const normalizedConfigs = await normalize(this, context, this.extraConfigTypes);
|
||||||
this.length = 0;
|
this.length = 0;
|
||||||
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig]));
|
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig].bind(this)));
|
||||||
|
this.forEach(assertValidFilesAndIgnores);
|
||||||
|
this[ConfigArraySymbol.isNormalized] = true;
|
||||||
|
|
||||||
|
// prevent further changes
|
||||||
|
Object.freeze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes a config array by flattening embedded arrays and executing
|
||||||
|
* config functions.
|
||||||
|
* @param {ConfigContext} context The context object for config functions.
|
||||||
|
* @returns {ConfigArray} The current ConfigArray instance.
|
||||||
|
*/
|
||||||
|
normalizeSync(context = {}) {
|
||||||
|
|
||||||
|
if (!this.isNormalized()) {
|
||||||
|
const normalizedConfigs = normalizeSync(this, context, this.extraConfigTypes);
|
||||||
|
this.length = 0;
|
||||||
|
this.push(...normalizedConfigs.map(this[ConfigArraySymbol.preprocessConfig].bind(this)));
|
||||||
|
this.forEach(assertValidFilesAndIgnores);
|
||||||
this[ConfigArraySymbol.isNormalized] = true;
|
this[ConfigArraySymbol.isNormalized] = true;
|
||||||
|
|
||||||
// prevent further changes
|
// prevent further changes
|
||||||
|
@ -411,6 +732,56 @@ class ConfigArray extends Array {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a given file path explicitly matches a `files` entry
|
||||||
|
* and also doesn't match an `ignores` entry. Configs that don't have
|
||||||
|
* a `files` property are not considered an explicit match.
|
||||||
|
* @param {string} filePath The complete path of a file to check.
|
||||||
|
* @returns {boolean} True if the file path matches a `files` entry
|
||||||
|
* or false if not.
|
||||||
|
*/
|
||||||
|
isExplicitMatch(filePath) {
|
||||||
|
|
||||||
|
assertNormalized(this);
|
||||||
|
|
||||||
|
const cache = dataCache.get(this);
|
||||||
|
|
||||||
|
// first check the cache to avoid duplicate work
|
||||||
|
let result = cache.explicitMatches.get(filePath);
|
||||||
|
|
||||||
|
if (typeof result == 'boolean') {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Maybe move elsewhere? Maybe combine with getConfig() logic?
|
||||||
|
const relativeFilePath = path.relative(this.basePath, filePath);
|
||||||
|
|
||||||
|
if (shouldIgnorePath(this.ignores, filePath, relativeFilePath)) {
|
||||||
|
debug(`Ignoring ${filePath}`);
|
||||||
|
|
||||||
|
// cache and return result
|
||||||
|
cache.explicitMatches.set(filePath, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filePath isn't automatically ignored, so try to find a match
|
||||||
|
|
||||||
|
for (const config of this) {
|
||||||
|
|
||||||
|
if (!config.files) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathMatches(filePath, this.basePath, config)) {
|
||||||
|
debug(`Matching config found for ${filePath}`);
|
||||||
|
cache.explicitMatches.set(filePath, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the config object for a given file path.
|
* Returns the config object for a given file path.
|
||||||
* @param {string} filePath The complete path of a file to get a config for.
|
* @param {string} filePath The complete path of a file to get a config for.
|
||||||
|
@ -420,37 +791,239 @@ class ConfigArray extends Array {
|
||||||
|
|
||||||
assertNormalized(this);
|
assertNormalized(this);
|
||||||
|
|
||||||
// first check the cache to avoid duplicate work
|
const cache = this[ConfigArraySymbol.configCache];
|
||||||
let finalConfig = this[ConfigArraySymbol.configCache].get(filePath);
|
|
||||||
|
|
||||||
if (finalConfig) {
|
// first check the cache for a filename match to avoid duplicate work
|
||||||
|
if (cache.has(filePath)) {
|
||||||
|
return cache.get(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
let finalConfig;
|
||||||
|
|
||||||
|
// next check to see if the file should be ignored
|
||||||
|
|
||||||
|
// check if this should be ignored due to its directory
|
||||||
|
if (this.isDirectoryIgnored(path.dirname(filePath))) {
|
||||||
|
debug(`Ignoring ${filePath} based on directory pattern`);
|
||||||
|
|
||||||
|
// cache and return result - finalConfig is undefined at this point
|
||||||
|
cache.set(filePath, finalConfig);
|
||||||
return finalConfig;
|
return finalConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No config found in cache, so calculate a new one
|
// TODO: Maybe move elsewhere?
|
||||||
|
const relativeFilePath = path.relative(this.basePath, filePath);
|
||||||
|
|
||||||
const matchingConfigs = [];
|
if (shouldIgnorePath(this.ignores, filePath, relativeFilePath)) {
|
||||||
|
debug(`Ignoring ${filePath} based on file pattern`);
|
||||||
|
|
||||||
for (const config of this) {
|
// cache and return result - finalConfig is undefined at this point
|
||||||
if (pathMatches(filePath, this.basePath, config)) {
|
cache.set(filePath, finalConfig);
|
||||||
debug(`Matching config found for ${filePath}`);
|
return finalConfig;
|
||||||
matchingConfigs.push(config);
|
|
||||||
} else {
|
|
||||||
debug(`No matching config found for ${filePath}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finalConfig = matchingConfigs.reduce((result, config) => {
|
// filePath isn't automatically ignored, so try to construct config
|
||||||
return this[ConfigArraySymbol.schema].merge(result, config);
|
|
||||||
|
const matchingConfigIndices = [];
|
||||||
|
let matchFound = false;
|
||||||
|
const universalPattern = /\/\*{1,2}$/;
|
||||||
|
|
||||||
|
this.forEach((config, index) => {
|
||||||
|
|
||||||
|
if (!config.files) {
|
||||||
|
|
||||||
|
if (!config.ignores) {
|
||||||
|
debug(`Anonymous universal config found for ${filePath}`);
|
||||||
|
matchingConfigIndices.push(index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathMatchesIgnores(filePath, this.basePath, config)) {
|
||||||
|
debug(`Matching config found for ${filePath} (based on ignores: ${config.ignores})`);
|
||||||
|
matchingConfigIndices.push(index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(`Skipped config found for ${filePath} (based on ignores: ${config.ignores})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a config has a files pattern ending in /** or /*, and the
|
||||||
|
* filePath only matches those patterns, then the config is only
|
||||||
|
* applied if there is another config where the filePath matches
|
||||||
|
* a file with a specific extensions such as *.js.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const universalFiles = config.files.filter(
|
||||||
|
pattern => universalPattern.test(pattern)
|
||||||
|
);
|
||||||
|
|
||||||
|
// universal patterns were found so we need to check the config twice
|
||||||
|
if (universalFiles.length) {
|
||||||
|
|
||||||
|
debug('Universal files patterns found. Checking carefully.');
|
||||||
|
|
||||||
|
const nonUniversalFiles = config.files.filter(
|
||||||
|
pattern => !universalPattern.test(pattern)
|
||||||
|
);
|
||||||
|
|
||||||
|
// check that the config matches without the non-universal files first
|
||||||
|
if (
|
||||||
|
nonUniversalFiles.length &&
|
||||||
|
pathMatches(
|
||||||
|
filePath, this.basePath,
|
||||||
|
{ files: nonUniversalFiles, ignores: config.ignores }
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
debug(`Matching config found for ${filePath}`);
|
||||||
|
matchingConfigIndices.push(index);
|
||||||
|
matchFound = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there wasn't a match then check if it matches with universal files
|
||||||
|
if (
|
||||||
|
universalFiles.length &&
|
||||||
|
pathMatches(
|
||||||
|
filePath, this.basePath,
|
||||||
|
{ files: universalFiles, ignores: config.ignores }
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
debug(`Matching config found for ${filePath}`);
|
||||||
|
matchingConfigIndices.push(index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we make here, then there was no match
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the normal case
|
||||||
|
if (pathMatches(filePath, this.basePath, config)) {
|
||||||
|
debug(`Matching config found for ${filePath}`);
|
||||||
|
matchingConfigIndices.push(index);
|
||||||
|
matchFound = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// if matching both files and ignores, there will be no config to create
|
||||||
|
if (!matchFound) {
|
||||||
|
debug(`No matching configs found for ${filePath}`);
|
||||||
|
|
||||||
|
// cache and return result - finalConfig is undefined at this point
|
||||||
|
cache.set(filePath, finalConfig);
|
||||||
|
return finalConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check to see if there is a config cached by indices
|
||||||
|
finalConfig = cache.get(matchingConfigIndices.toString());
|
||||||
|
|
||||||
|
if (finalConfig) {
|
||||||
|
|
||||||
|
// also store for filename for faster lookup next time
|
||||||
|
cache.set(filePath, finalConfig);
|
||||||
|
|
||||||
|
return finalConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise construct the config
|
||||||
|
|
||||||
|
finalConfig = matchingConfigIndices.reduce((result, index) => {
|
||||||
|
return this[ConfigArraySymbol.schema].merge(result, this[index]);
|
||||||
}, {}, this);
|
}, {}, this);
|
||||||
|
|
||||||
finalConfig = this[ConfigArraySymbol.finalizeConfig](finalConfig);
|
finalConfig = this[ConfigArraySymbol.finalizeConfig](finalConfig);
|
||||||
|
|
||||||
this[ConfigArraySymbol.configCache].set(filePath, finalConfig);
|
cache.set(filePath, finalConfig);
|
||||||
|
cache.set(matchingConfigIndices.toString(), finalConfig);
|
||||||
|
|
||||||
return finalConfig;
|
return finalConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the given filepath is ignored based on the configs.
|
||||||
|
* @param {string} filePath The complete path of a file to check.
|
||||||
|
* @returns {boolean} True if the path is ignored, false if not.
|
||||||
|
* @deprecated Use `isFileIgnored` instead.
|
||||||
|
*/
|
||||||
|
isIgnored(filePath) {
|
||||||
|
return this.isFileIgnored(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the given filepath is ignored based on the configs.
|
||||||
|
* @param {string} filePath The complete path of a file to check.
|
||||||
|
* @returns {boolean} True if the path is ignored, false if not.
|
||||||
|
*/
|
||||||
|
isFileIgnored(filePath) {
|
||||||
|
return this.getConfig(filePath) === undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the given directory is ignored based on the configs.
|
||||||
|
* This checks only default `ignores` that don't have `files` in the
|
||||||
|
* same config. A pattern such as `/foo` be considered to ignore the directory
|
||||||
|
* while a pattern such as `/foo/**` is not considered to ignore the
|
||||||
|
* directory because it is matching files.
|
||||||
|
* @param {string} directoryPath The complete path of a directory to check.
|
||||||
|
* @returns {boolean} True if the directory is ignored, false if not. Will
|
||||||
|
* return true for any directory that is not inside of `basePath`.
|
||||||
|
* @throws {Error} When the `ConfigArray` is not normalized.
|
||||||
|
*/
|
||||||
|
isDirectoryIgnored(directoryPath) {
|
||||||
|
|
||||||
|
assertNormalized(this);
|
||||||
|
|
||||||
|
const relativeDirectoryPath = path.relative(this.basePath, directoryPath)
|
||||||
|
.replace(/\\/g, '/');
|
||||||
|
|
||||||
|
if (relativeDirectoryPath.startsWith('..')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first check the cache
|
||||||
|
const cache = dataCache.get(this).directoryMatches;
|
||||||
|
|
||||||
|
if (cache.has(relativeDirectoryPath)) {
|
||||||
|
return cache.get(relativeDirectoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const directoryParts = relativeDirectoryPath.split('/');
|
||||||
|
let relativeDirectoryToCheck = '';
|
||||||
|
let result = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In order to get the correct gitignore-style ignores, where an
|
||||||
|
* ignored parent directory cannot have any descendants unignored,
|
||||||
|
* we need to check every directory starting at the parent all
|
||||||
|
* the way down to the actual requested directory.
|
||||||
|
*
|
||||||
|
* We aggressively cache all of this info to make sure we don't
|
||||||
|
* have to recalculate everything for every call.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
|
||||||
|
relativeDirectoryToCheck += directoryParts.shift() + '/';
|
||||||
|
|
||||||
|
result = shouldIgnorePath(
|
||||||
|
this.ignores,
|
||||||
|
path.join(this.basePath, relativeDirectoryToCheck),
|
||||||
|
relativeDirectoryToCheck
|
||||||
|
);
|
||||||
|
|
||||||
|
cache.set(relativeDirectoryToCheck, result);
|
||||||
|
|
||||||
|
} while (!result && directoryParts.length);
|
||||||
|
|
||||||
|
// also cache the result for the requested path
|
||||||
|
cache.set(relativeDirectoryPath, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.ConfigArray = ConfigArray;
|
exports.ConfigArray = ConfigArray;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@humanwhocodes/config-array",
|
"name": "@humanwhocodes/config-array",
|
||||||
"version": "0.5.0",
|
"version": "0.11.14",
|
||||||
"description": "Glob-based configuration matching.",
|
"description": "Glob-based configuration matching.",
|
||||||
"author": "Nicholas C. Zakas",
|
"author": "Nicholas C. Zakas",
|
||||||
"main": "api.js",
|
"main": "api.js",
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
"build": "rollup -c",
|
"build": "rollup -c",
|
||||||
"format": "nitpik",
|
"format": "nitpik",
|
||||||
"lint": "eslint *.config.js src/*.js tests/*.js",
|
"lint": "eslint *.config.js src/*.js tests/*.js",
|
||||||
|
"lint:fix": "eslint --fix *.config.js src/*.js tests/*.js",
|
||||||
"prepublish": "npm run build",
|
"prepublish": "npm run build",
|
||||||
"test:coverage": "nyc --include src/*.js npm run test",
|
"test:coverage": "nyc --include src/*.js npm run test",
|
||||||
"test": "mocha -r esm tests/ --recursive"
|
"test": "mocha -r esm tests/ --recursive"
|
||||||
|
@ -28,7 +29,6 @@
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.js": [
|
"*.js": [
|
||||||
"nitpik",
|
|
||||||
"eslint --fix --ignore-pattern '!.eslintrc.js'"
|
"eslint --fix --ignore-pattern '!.eslintrc.js'"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -42,20 +42,20 @@
|
||||||
"node": ">=10.10.0"
|
"node": ">=10.10.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@humanwhocodes/object-schema": "^1.2.0",
|
"@humanwhocodes/object-schema": "^2.0.2",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.3.1",
|
||||||
"minimatch": "^3.0.4"
|
"minimatch": "^3.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nitpik/javascript": "^0.3.3",
|
"@nitpik/javascript": "0.4.0",
|
||||||
"@nitpik/node": "0.0.5",
|
"@nitpik/node": "0.0.5",
|
||||||
"chai": "^4.2.0",
|
"chai": "4.3.10",
|
||||||
"eslint": "^6.7.1",
|
"eslint": "8.52.0",
|
||||||
"esm": "^3.2.25",
|
"esm": "3.2.25",
|
||||||
"lint-staged": "^10.2.8",
|
"lint-staged": "15.0.2",
|
||||||
"mocha": "^6.1.4",
|
"mocha": "6.2.3",
|
||||||
"nyc": "^14.1.1",
|
"nyc": "15.1.0",
|
||||||
"rollup": "^1.12.3",
|
"rollup": "3.28.1",
|
||||||
"yorkie": "^2.0.0"
|
"yorkie": "2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
"env": {
|
|
||||||
"commonjs": true,
|
|
||||||
"es6": true,
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"extends": "eslint:recommended",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2018
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"indent": [
|
|
||||||
"error",
|
|
||||||
4
|
|
||||||
],
|
|
||||||
"linebreak-style": [
|
|
||||||
"error",
|
|
||||||
"unix"
|
|
||||||
],
|
|
||||||
"quotes": [
|
|
||||||
"error",
|
|
||||||
"double"
|
|
||||||
],
|
|
||||||
"semi": [
|
|
||||||
"error",
|
|
||||||
"always"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,27 +0,0 @@
|
||||||
name: Node CI
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [windows-latest, macOS-latest, ubuntu-latest]
|
|
||||||
node: [8.x, 10.x, 12.x, 14.x]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
- name: npm install, build, and test
|
|
||||||
run: |
|
|
||||||
npm install
|
|
||||||
npm run build --if-present
|
|
||||||
npm test
|
|
||||||
env:
|
|
||||||
CI: true
|
|
39
node_modules/@humanwhocodes/object-schema/.github/workflows/release-please.yml
generated
vendored
39
node_modules/@humanwhocodes/object-schema/.github/workflows/release-please.yml
generated
vendored
|
@ -1,39 +0,0 @@
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
name: release-please
|
|
||||||
jobs:
|
|
||||||
release-please:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: GoogleCloudPlatform/release-please-action@v2
|
|
||||||
id: release
|
|
||||||
with:
|
|
||||||
release-type: node
|
|
||||||
package-name: test-release-please
|
|
||||||
# The logic below handles the npm publication:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
# these if statements ensure that a publication only occurs when
|
|
||||||
# a new release is created:
|
|
||||||
if: ${{ steps.release.outputs.release_created }}
|
|
||||||
- uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 12
|
|
||||||
registry-url: 'https://registry.npmjs.org'
|
|
||||||
if: ${{ steps.release.outputs.release_created }}
|
|
||||||
- run: npm ci
|
|
||||||
if: ${{ steps.release.outputs.release_created }}
|
|
||||||
- run: npm publish
|
|
||||||
env:
|
|
||||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
|
||||||
if: ${{ steps.release.outputs.release_created }}
|
|
||||||
|
|
||||||
# Tweets out release announcement
|
|
||||||
- run: 'npx @humanwhocodes/tweet "Object Schema v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}.${{ steps.release.outputs.patch }} has been released!\n\n${{ github.event.release.html_url }}"'
|
|
||||||
if: ${{ steps.release.outputs.release_created }}
|
|
||||||
env:
|
|
||||||
TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }}
|
|
||||||
TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }}
|
|
||||||
TWITTER_ACCESS_TOKEN_KEY: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }}
|
|
||||||
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
|
|
|
@ -1,5 +1,37 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [2.0.3](https://github.com/humanwhocodes/object-schema/compare/v2.0.2...v2.0.3) (2024-04-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Ensure test files are not including in package ([6eeb32c](https://github.com/humanwhocodes/object-schema/commit/6eeb32cc76a3e37d76b2990bd603d72061c816e0)), closes [#19](https://github.com/humanwhocodes/object-schema/issues/19)
|
||||||
|
|
||||||
|
## [2.0.2](https://github.com/humanwhocodes/object-schema/compare/v2.0.1...v2.0.2) (2024-01-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* WrapperError should be an actual error ([2523f01](https://github.com/humanwhocodes/object-schema/commit/2523f014168167e5a40bb63e0cc03231b2c0f1bf))
|
||||||
|
|
||||||
|
## [2.0.1](https://github.com/humanwhocodes/object-schema/compare/v2.0.0...v2.0.1) (2023-10-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Custom properties should be available on thrown errors ([6ca80b0](https://github.com/humanwhocodes/object-schema/commit/6ca80b001a4ffb678b9b5544fc53322117374376))
|
||||||
|
|
||||||
|
## [2.0.0](https://github.com/humanwhocodes/object-schema/compare/v1.2.1...v2.0.0) (2023-10-18)
|
||||||
|
|
||||||
|
|
||||||
|
### ⚠ BREAKING CHANGES
|
||||||
|
|
||||||
|
* Throw custom errors instead of generics.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Throw custom errors instead of generics. ([c6c01d7](https://github.com/humanwhocodes/object-schema/commit/c6c01d71eb354bf7b1fb3e883c40f7bd9b61647c))
|
||||||
|
|
||||||
### [1.2.1](https://www.github.com/humanwhocodes/object-schema/compare/v1.2.0...v1.2.1) (2021-11-02)
|
### [1.2.1](https://www.github.com/humanwhocodes/object-schema/compare/v1.2.0...v1.2.1) (2021-11-02)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
{
|
{
|
||||||
"name": "@humanwhocodes/object-schema",
|
"name": "@humanwhocodes/object-schema",
|
||||||
"version": "1.2.1",
|
"version": "2.0.3",
|
||||||
"description": "An object schema merger/validator",
|
"description": "An object schema merger/validator",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
|
"files": [
|
||||||
|
"src",
|
||||||
|
"LICENSE",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
"directories": {
|
"directories": {
|
||||||
"test": "tests"
|
"test": "tests"
|
||||||
},
|
},
|
||||||
|
|
|
@ -62,9 +62,77 @@ function validateDefinition(name, strategy) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Errors
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error when an unexpected key is found.
|
||||||
|
*/
|
||||||
|
class UnexpectedKeyError extends Error {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
* @param {string} key The key that was unexpected.
|
||||||
|
*/
|
||||||
|
constructor(key) {
|
||||||
|
super(`Unexpected key "${key}" found.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error when a required key is missing.
|
||||||
|
*/
|
||||||
|
class MissingKeyError extends Error {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
* @param {string} key The key that was missing.
|
||||||
|
*/
|
||||||
|
constructor(key) {
|
||||||
|
super(`Missing required key "${key}".`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error when a key requires other keys that are missing.
|
||||||
|
*/
|
||||||
|
class MissingDependentKeysError extends Error {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
* @param {string} key The key that was unexpected.
|
||||||
|
* @param {Array<string>} requiredKeys The keys that are required.
|
||||||
|
*/
|
||||||
|
constructor(key, requiredKeys) {
|
||||||
|
super(`Key "${key}" requires keys "${requiredKeys.join("\", \"")}".`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper error for errors occuring during a merge or validate operation.
|
||||||
|
*/
|
||||||
|
class WrapperError extends Error {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
* @param {string} key The object key causing the error.
|
||||||
|
* @param {Error} source The source error.
|
||||||
|
*/
|
||||||
|
constructor(key, source) {
|
||||||
|
super(`Key "${key}": ${source.message}`, { cause: source });
|
||||||
|
|
||||||
|
// copy over custom properties that aren't represented
|
||||||
|
for (const key of Object.keys(source)) {
|
||||||
|
if (!(key in this)) {
|
||||||
|
this[key] = source[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Class
|
// Main
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,11 +227,11 @@ class ObjectSchema {
|
||||||
|
|
||||||
// double check arguments
|
// double check arguments
|
||||||
if (objects.length < 2) {
|
if (objects.length < 2) {
|
||||||
throw new Error("merge() requires at least two arguments.");
|
throw new TypeError("merge() requires at least two arguments.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objects.some(object => (object == null || typeof object !== "object"))) {
|
if (objects.some(object => (object == null || typeof object !== "object"))) {
|
||||||
throw new Error("All arguments must be objects.");
|
throw new TypeError("All arguments must be objects.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return objects.reduce((result, object) => {
|
return objects.reduce((result, object) => {
|
||||||
|
@ -179,8 +247,7 @@ class ObjectSchema {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
ex.message = `Key "${key}": ` + ex.message;
|
throw new WrapperError(key, ex);
|
||||||
throw ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -200,7 +267,7 @@ class ObjectSchema {
|
||||||
|
|
||||||
// check to see if the key is defined
|
// check to see if the key is defined
|
||||||
if (!this.hasKey(key)) {
|
if (!this.hasKey(key)) {
|
||||||
throw new Error(`Unexpected key "${key}" found.`);
|
throw new UnexpectedKeyError(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate existing keys
|
// validate existing keys
|
||||||
|
@ -209,7 +276,7 @@ class ObjectSchema {
|
||||||
// first check to see if any other keys are required
|
// first check to see if any other keys are required
|
||||||
if (Array.isArray(strategy.requires)) {
|
if (Array.isArray(strategy.requires)) {
|
||||||
if (!strategy.requires.every(otherKey => otherKey in object)) {
|
if (!strategy.requires.every(otherKey => otherKey in object)) {
|
||||||
throw new Error(`Key "${key}" requires keys "${strategy.requires.join("\", \"")}".`);
|
throw new MissingDependentKeysError(key, strategy.requires);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,15 +284,14 @@ class ObjectSchema {
|
||||||
try {
|
try {
|
||||||
strategy.validate.call(strategy, object[key]);
|
strategy.validate.call(strategy, object[key]);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
ex.message = `Key "${key}": ` + ex.message;
|
throw new WrapperError(key, ex);
|
||||||
throw ex;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure required keys aren't missing
|
// ensure required keys aren't missing
|
||||||
for (const [key] of this[requiredKeys]) {
|
for (const [key] of this[requiredKeys]) {
|
||||||
if (!(key in object)) {
|
if (!(key in object)) {
|
||||||
throw new Error(`Missing required key "${key}".`);
|
throw new MissingKeyError(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
/**
|
|
||||||
* @filedescription Merge Strategy Tests
|
|
||||||
*/
|
|
||||||
/* global it, describe, beforeEach */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Requirements
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
const assert = require("chai").assert;
|
|
||||||
const { MergeStrategy } = require("../src/");
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Class
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
describe("MergeStrategy", () => {
|
|
||||||
|
|
||||||
|
|
||||||
describe("overwrite()", () => {
|
|
||||||
|
|
||||||
it("should overwrite the first value with the second when the second is defined", () => {
|
|
||||||
const result = MergeStrategy.overwrite(1, 2);
|
|
||||||
assert.strictEqual(result, 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should overwrite the first value with the second when the second is undefined", () => {
|
|
||||||
const result = MergeStrategy.overwrite(1, undefined);
|
|
||||||
assert.strictEqual(result, undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("replace()", () => {
|
|
||||||
|
|
||||||
it("should overwrite the first value with the second when the second is defined", () => {
|
|
||||||
const result = MergeStrategy.replace(1, 2);
|
|
||||||
assert.strictEqual(result, 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return the first value when the second is undefined", () => {
|
|
||||||
const result = MergeStrategy.replace(1, undefined);
|
|
||||||
assert.strictEqual(result, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("assign()", () => {
|
|
||||||
|
|
||||||
it("should merge properties from two objects when called", () => {
|
|
||||||
|
|
||||||
const object1 = { foo: 1, bar: 3 };
|
|
||||||
const object2 = { foo: 2 };
|
|
||||||
|
|
||||||
const result = MergeStrategy.assign(object1, object2);
|
|
||||||
assert.deepStrictEqual(result, {
|
|
||||||
foo: 2,
|
|
||||||
bar: 3
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,611 +0,0 @@
|
||||||
/**
|
|
||||||
* @filedescription Object Schema Tests
|
|
||||||
*/
|
|
||||||
/* global it, describe, beforeEach */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Requirements
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
const assert = require("chai").assert;
|
|
||||||
const { ObjectSchema } = require("../src/");
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Class
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
describe("ObjectSchema", () => {
|
|
||||||
|
|
||||||
let schema;
|
|
||||||
|
|
||||||
describe("new ObjectSchema()", () => {
|
|
||||||
|
|
||||||
it("should add a new key when a strategy is passed", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {},
|
|
||||||
validate() {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.isTrue(schema.hasKey("foo"));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when a strategy is missing a merge() method", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
validate() { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, /Definition for key "foo" must have a merge property/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when a strategy is missing a merge() method", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
schema = new ObjectSchema();
|
|
||||||
}, /Schema definitions missing/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when a strategy is missing a validate() method", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() { },
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, /Definition for key "foo" must have a validate\(\) method/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when merge is an invalid string", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge: "bar",
|
|
||||||
validate() { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, /key "foo" missing valid merge strategy/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when validate is an invalid string", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge: "assign",
|
|
||||||
validate: "s"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, /key "foo" missing valid validation strategy/);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe("merge()", () => {
|
|
||||||
|
|
||||||
it("should throw an error when an unexpected key is found", () => {
|
|
||||||
let schema = new ObjectSchema({});
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.merge({ foo: true }, { foo: true });
|
|
||||||
}, /Unexpected key "foo"/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when merge() throws an error", () => {
|
|
||||||
let schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
throw new Error("Boom!");
|
|
||||||
},
|
|
||||||
validate() {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.merge({ foo: true }, { foo: true });
|
|
||||||
}, /Key "foo": Boom!/);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the merge() strategy for one key when called", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge({ foo: true }, { foo: false });
|
|
||||||
assert.propertyVal(result, "foo", "bar");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not call the merge() strategy when both objects don't contain the key", () => {
|
|
||||||
|
|
||||||
let called = false;
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
called = true;
|
|
||||||
},
|
|
||||||
validate() {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
schema.merge({}, {});
|
|
||||||
assert.isFalse(called, "The merge() strategy should not have been called.");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should omit returning the key when the merge() strategy returns undefined", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
validate() { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge({ foo: true }, { foo: false });
|
|
||||||
assert.notProperty(result, "foo");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the merge() strategy for two keys when called", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() { }
|
|
||||||
},
|
|
||||||
bar: {
|
|
||||||
merge() {
|
|
||||||
return "baz";
|
|
||||||
},
|
|
||||||
validate() {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge({ foo: true, bar: 1 }, { foo: true, bar: 2 });
|
|
||||||
assert.propertyVal(result, "foo", "bar");
|
|
||||||
assert.propertyVal(result, "bar", "baz");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the merge() strategy for two keys when called on three objects", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() { }
|
|
||||||
},
|
|
||||||
bar: {
|
|
||||||
merge() {
|
|
||||||
return "baz";
|
|
||||||
},
|
|
||||||
validate() { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge(
|
|
||||||
{ foo: true, bar: 1 },
|
|
||||||
{ foo: true, bar: 3 },
|
|
||||||
{ foo: false, bar: 2 }
|
|
||||||
);
|
|
||||||
assert.propertyVal(result, "foo", "bar");
|
|
||||||
assert.propertyVal(result, "bar", "baz");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the merge() strategy when defined as 'overwrite'", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge: "overwrite",
|
|
||||||
validate() { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge(
|
|
||||||
{ foo: true },
|
|
||||||
{ foo: false }
|
|
||||||
);
|
|
||||||
assert.propertyVal(result, "foo", false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the merge() strategy when defined as 'assign'", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge: "assign",
|
|
||||||
validate() { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge(
|
|
||||||
{ foo: { bar: true } },
|
|
||||||
{ foo: { baz: false } }
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(result.foo.bar, true);
|
|
||||||
assert.strictEqual(result.foo.baz, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should call the merge strategy when there's a subschema", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
name: {
|
|
||||||
schema: {
|
|
||||||
first: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
},
|
|
||||||
last: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge({
|
|
||||||
name: {
|
|
||||||
first: "n",
|
|
||||||
last: "z"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
name: {
|
|
||||||
first: "g"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.strictEqual(result.name.first, "g");
|
|
||||||
assert.strictEqual(result.name.last, "z");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return separate objects when using subschema", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
age: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "number"
|
|
||||||
},
|
|
||||||
address: {
|
|
||||||
schema: {
|
|
||||||
street: {
|
|
||||||
schema: {
|
|
||||||
number: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "number"
|
|
||||||
},
|
|
||||||
streetName: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const baseObject = {
|
|
||||||
address: {
|
|
||||||
street: {
|
|
||||||
number: 100,
|
|
||||||
streetName: "Foo St"
|
|
||||||
},
|
|
||||||
state: "HA"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = schema.merge(baseObject, {
|
|
||||||
age: 29
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.notStrictEqual(result.address.street, baseObject.address.street);
|
|
||||||
assert.deepStrictEqual(result.address, baseObject.address);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not error when calling the merge strategy when there's a subschema and no matching key in second object", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
name: {
|
|
||||||
schema: {
|
|
||||||
first: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
},
|
|
||||||
last: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge({
|
|
||||||
name: {
|
|
||||||
first: "n",
|
|
||||||
last: "z"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.strictEqual(result.name.first, "n");
|
|
||||||
assert.strictEqual(result.name.last, "z");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not error when calling the merge strategy when there's multiple subschemas and no matching key in second object", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
user: {
|
|
||||||
schema: {
|
|
||||||
name: {
|
|
||||||
schema: {
|
|
||||||
first: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
},
|
|
||||||
last: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = schema.merge({
|
|
||||||
user: {
|
|
||||||
name: {
|
|
||||||
first: "n",
|
|
||||||
last: "z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.strictEqual(result.user.name.first, "n");
|
|
||||||
assert.strictEqual(result.user.name.last, "z");
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("validate()", () => {
|
|
||||||
|
|
||||||
it("should throw an error when an unexpected key is found", () => {
|
|
||||||
let schema = new ObjectSchema({});
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.validate({ foo: true });
|
|
||||||
}, /Unexpected key "foo"/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not throw an error when an expected key is found", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
schema.validate({ foo: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should pass the property value into validate() when key is found", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate(value) {
|
|
||||||
assert.isTrue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
schema.validate({ foo: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not throw an error when expected keys are found", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() {}
|
|
||||||
},
|
|
||||||
bar: {
|
|
||||||
merge() {
|
|
||||||
return "baz";
|
|
||||||
},
|
|
||||||
validate() {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
schema.validate({ foo: true, bar: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not throw an error when expected keys are found with required keys", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() { }
|
|
||||||
},
|
|
||||||
bar: {
|
|
||||||
requires: ["foo"],
|
|
||||||
merge() {
|
|
||||||
return "baz";
|
|
||||||
},
|
|
||||||
validate() { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
schema.validate({ foo: true, bar: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when expected keys are found without required keys", () => {
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() { }
|
|
||||||
},
|
|
||||||
baz: {
|
|
||||||
merge() {
|
|
||||||
return "baz";
|
|
||||||
},
|
|
||||||
validate() { }
|
|
||||||
},
|
|
||||||
bar: {
|
|
||||||
name: "bar",
|
|
||||||
requires: ["foo", "baz"],
|
|
||||||
merge() { },
|
|
||||||
validate() { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.validate({ bar: true });
|
|
||||||
}, /Key "bar" requires keys "foo", "baz"./);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it("should throw an error when an expected key is found but is invalid", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() {
|
|
||||||
throw new Error("Invalid key.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.validate({ foo: true });
|
|
||||||
}, /Key "foo": Invalid key/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when an expected key is found but is invalid with a string validator", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate: "string"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.validate({ foo: true });
|
|
||||||
}, /Key "foo": Expected a string/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when an expected key is found but is invalid with a number validator", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate: "number"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.validate({ foo: true });
|
|
||||||
}, /Key "foo": Expected a number/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when a required key is missing", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
foo: {
|
|
||||||
required: true,
|
|
||||||
merge() {
|
|
||||||
return "bar";
|
|
||||||
},
|
|
||||||
validate() {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.validate({});
|
|
||||||
}, /Missing required key "foo"/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when a subschema is provided and the value doesn't validate", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
name: {
|
|
||||||
schema: {
|
|
||||||
first: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
},
|
|
||||||
last: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.throws(() => {
|
|
||||||
schema.validate({
|
|
||||||
name: {
|
|
||||||
first: 123,
|
|
||||||
last: "z"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}, /Key "name": Key "first": Expected a string/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not throw an error when a subschema is provided and the value validates", () => {
|
|
||||||
|
|
||||||
schema = new ObjectSchema({
|
|
||||||
name: {
|
|
||||||
schema: {
|
|
||||||
first: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
},
|
|
||||||
last: {
|
|
||||||
merge: "replace",
|
|
||||||
validate: "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
schema.validate({
|
|
||||||
name: {
|
|
||||||
first: "n",
|
|
||||||
last: "z"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,186 +0,0 @@
|
||||||
/**
|
|
||||||
* @filedescription Merge Strategy Tests
|
|
||||||
*/
|
|
||||||
/* global it, describe, beforeEach */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Requirements
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
const assert = require("chai").assert;
|
|
||||||
const { ValidationStrategy } = require("../src/");
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Class
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
describe("ValidationStrategy", () => {
|
|
||||||
|
|
||||||
describe("boolean", () => {
|
|
||||||
it("should not throw an error when the value is a boolean", () => {
|
|
||||||
ValidationStrategy.boolean(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is null", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.boolean(null);
|
|
||||||
}, /Expected a Boolean/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is a string", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.boolean("foo");
|
|
||||||
}, /Expected a Boolean/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is a number", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.boolean(123);
|
|
||||||
}, /Expected a Boolean/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is an object", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.boolean({});
|
|
||||||
}, /Expected a Boolean/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("number", () => {
|
|
||||||
it("should not throw an error when the value is a number", () => {
|
|
||||||
ValidationStrategy.number(25);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is null", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.number(null);
|
|
||||||
}, /Expected a number/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is a string", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.number("foo");
|
|
||||||
}, /Expected a number/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is a boolean", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.number(true);
|
|
||||||
}, /Expected a number/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is an object", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.number({});
|
|
||||||
}, /Expected a number/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("object", () => {
|
|
||||||
it("should not throw an error when the value is an object", () => {
|
|
||||||
ValidationStrategy.object({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is null", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.object(null);
|
|
||||||
}, /Expected an object/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is a string", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.object("");
|
|
||||||
}, /Expected an object/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("array", () => {
|
|
||||||
it("should not throw an error when the value is an array", () => {
|
|
||||||
ValidationStrategy.array([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is null", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.array(null);
|
|
||||||
}, /Expected an array/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is a string", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.array("");
|
|
||||||
}, /Expected an array/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is an object", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.array({});
|
|
||||||
}, /Expected an array/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("object?", () => {
|
|
||||||
it("should not throw an error when the value is an object", () => {
|
|
||||||
ValidationStrategy["object?"]({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not throw an error when the value is null", () => {
|
|
||||||
ValidationStrategy["object?"](null);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is a string", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy["object?"]("");
|
|
||||||
}, /Expected an object/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("string", () => {
|
|
||||||
it("should not throw an error when the value is a string", () => {
|
|
||||||
ValidationStrategy.string("foo");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not throw an error when the value is an empty string", () => {
|
|
||||||
ValidationStrategy.string("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is null", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.string(null);
|
|
||||||
}, /Expected a string/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is an object", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy.string({});
|
|
||||||
}, /Expected a string/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("string!", () => {
|
|
||||||
it("should not throw an error when the value is an string", () => {
|
|
||||||
ValidationStrategy["string!"]("foo");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is an empty string", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy["string!"]("");
|
|
||||||
}, /Expected a non-empty string/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is null", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy["string!"](null);
|
|
||||||
}, /Expected a non-empty string/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw an error when the value is an object", () => {
|
|
||||||
assert.throws(() => {
|
|
||||||
ValidationStrategy["string!"]({});
|
|
||||||
}, /Expected a non-empty string/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,3 +1,293 @@
|
||||||
|
## 8.12.1 (2024-07-03)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a regression that caused Acorn to no longer run on Node versions <8.10.
|
||||||
|
|
||||||
|
## 8.12.0 (2024-06-14)
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Support ES2025 duplicate capture group names in regular expressions.
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Include `VariableDeclarator` in the `AnyNode` type so that walker objects can refer to it without getting a type error.
|
||||||
|
|
||||||
|
Properly raise a parse error for invalid `for`/`of` statements using `async` as binding name.
|
||||||
|
|
||||||
|
Properly recognize \"use strict\" when preceded by a string with an escaped newline.
|
||||||
|
|
||||||
|
Mark the `Parser` constructor as protected, not private, so plugins can extend it without type errors.
|
||||||
|
|
||||||
|
Fix a bug where some invalid `delete` expressions were let through when the operand was parenthesized and `preserveParens` was enabled.
|
||||||
|
|
||||||
|
Properly normalize line endings in raw strings of invalid template tokens.
|
||||||
|
|
||||||
|
Properly track line numbers for escaped newlines in strings.
|
||||||
|
|
||||||
|
Fix a bug that broke line number accounting after a template literal with invalid escape sequences.
|
||||||
|
|
||||||
|
## 8.11.3 (2023-12-29)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Add `Function` and `Class` to the `AggregateType` type, so that they can be used in walkers without raising a type error.
|
||||||
|
|
||||||
|
Make sure `onToken` get an `import` keyword token when parsing `import.meta`.
|
||||||
|
|
||||||
|
Fix a bug where `.loc.start` could be undefined for `new.target` `meta` nodes.
|
||||||
|
|
||||||
|
## 8.11.2 (2023-10-27)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a bug that caused regular expressions after colon tokens to not be properly tokenized in some circumstances.
|
||||||
|
|
||||||
|
## 8.11.1 (2023-10-26)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a regression where `onToken` would receive 'name' tokens for 'new' keyword tokens.
|
||||||
|
|
||||||
|
## 8.11.0 (2023-10-26)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix an issue where tokenizing (without parsing) an object literal with a property named `class` or `function` could, in some circumstance, put the tokenizer into an invalid state.
|
||||||
|
|
||||||
|
Fix an issue where a slash after a call to a propery named the same as some keywords would be tokenized as a regular expression.
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Upgrade to Unicode 15.1.
|
||||||
|
|
||||||
|
Use a set of new, much more precise, TypeScript types.
|
||||||
|
|
||||||
|
## 8.10.0 (2023-07-05)
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Add a `checkPrivateFields` option that disables strict checking of private property use.
|
||||||
|
|
||||||
|
## 8.9.0 (2023-06-16)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Forbid dynamic import after `new`, even when part of a member expression.
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Add Unicode properties for ES2023.
|
||||||
|
|
||||||
|
Add support for the `v` flag to regular expressions.
|
||||||
|
|
||||||
|
## 8.8.2 (2023-01-23)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a bug that caused `allowHashBang` to be set to false when not provided, even with `ecmaVersion >= 14`.
|
||||||
|
|
||||||
|
Fix an exception when passing no option object to `parse` or `new Parser`.
|
||||||
|
|
||||||
|
Fix incorrect parse error on `if (0) let\n[astral identifier char]`.
|
||||||
|
|
||||||
|
## 8.8.1 (2022-10-24)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Make type for `Comment` compatible with estree types.
|
||||||
|
|
||||||
|
## 8.8.0 (2022-07-21)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Allow parentheses around spread args in destructuring object assignment.
|
||||||
|
|
||||||
|
Fix an issue where the tree contained `directive` properties in when parsing with a language version that doesn't support them.
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Support hashbang comments by default in ECMAScript 2023 and later.
|
||||||
|
|
||||||
|
## 8.7.1 (2021-04-26)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Stop handling `"use strict"` directives in ECMAScript versions before 5.
|
||||||
|
|
||||||
|
Fix an issue where duplicate quoted export names in `export *` syntax were incorrectly checked.
|
||||||
|
|
||||||
|
Add missing type for `tokTypes`.
|
||||||
|
|
||||||
|
## 8.7.0 (2021-12-27)
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Support quoted export names.
|
||||||
|
|
||||||
|
Upgrade to Unicode 14.
|
||||||
|
|
||||||
|
Add support for Unicode 13 properties in regular expressions.
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Use a loop to find line breaks, because the existing regexp search would overrun the end of the searched range and waste a lot of time in minified code.
|
||||||
|
|
||||||
|
## 8.6.0 (2021-11-18)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a bug where an object literal with multiple `__proto__` properties would incorrectly be accepted if a later property value held an assigment.
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Support class private fields with the `in` operator.
|
||||||
|
|
||||||
|
## 8.5.0 (2021-09-06)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Improve context-dependent tokenization in a number of corner cases.
|
||||||
|
|
||||||
|
Fix location tracking after a 0x2028 or 0x2029 character in a string literal (which before did not increase the line number).
|
||||||
|
|
||||||
|
Fix an issue where arrow function bodies in for loop context would inappropriately consume `in` operators.
|
||||||
|
|
||||||
|
Fix wrong end locations stored on SequenceExpression nodes.
|
||||||
|
|
||||||
|
Implement restriction that `for`/`of` loop LHS can't start with `let`.
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Add support for ES2022 class static blocks.
|
||||||
|
|
||||||
|
Allow multiple input files to be passed to the CLI tool.
|
||||||
|
|
||||||
|
## 8.4.1 (2021-06-24)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a bug where `allowAwaitOutsideFunction` would allow `await` in class field initializers, and setting `ecmaVersion` to 13 or higher would allow top-level await in non-module sources.
|
||||||
|
|
||||||
|
## 8.4.0 (2021-06-11)
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
A new option, `allowSuperOutsideMethod`, can be used to suppress the error when `super` is used in the wrong context.
|
||||||
|
|
||||||
|
## 8.3.0 (2021-05-31)
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Default `allowAwaitOutsideFunction` to true for ECMAScript 2022 an higher.
|
||||||
|
|
||||||
|
Add support for the `d` ([indices](https://github.com/tc39/proposal-regexp-match-indices)) regexp flag.
|
||||||
|
|
||||||
|
## 8.2.4 (2021-05-04)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix spec conformity in corner case 'for await (async of ...)'.
|
||||||
|
|
||||||
|
## 8.2.3 (2021-05-04)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix an issue where the library couldn't parse 'for (async of ...)'.
|
||||||
|
|
||||||
|
Fix a bug in UTF-16 decoding that would read characters incorrectly in some circumstances.
|
||||||
|
|
||||||
|
## 8.2.2 (2021-04-29)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a bug where a class field initialized to an async arrow function wouldn't allow await inside it. Same issue existed for generator arrow functions with yield.
|
||||||
|
|
||||||
|
## 8.2.1 (2021-04-24)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a regression introduced in 8.2.0 where static or async class methods with keyword names fail to parse.
|
||||||
|
|
||||||
|
## 8.2.0 (2021-04-24)
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Add support for ES2022 class fields and private methods.
|
||||||
|
|
||||||
|
## 8.1.1 (2021-04-12)
|
||||||
|
|
||||||
|
### Various
|
||||||
|
|
||||||
|
Stop shipping source maps in the NPM package.
|
||||||
|
|
||||||
|
## 8.1.0 (2021-03-09)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a spurious error in nested destructuring arrays.
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
Expose `allowAwaitOutsideFunction` in CLI interface.
|
||||||
|
|
||||||
|
Make `allowImportExportAnywhere` also apply to `import.meta`.
|
||||||
|
|
||||||
|
## 8.0.5 (2021-01-25)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Adjust package.json to work with Node 12.16.0 and 13.0-13.6.
|
||||||
|
|
||||||
|
## 8.0.4 (2020-10-05)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Make `await x ** y` an error, following the spec.
|
||||||
|
|
||||||
|
Fix potentially exponential regular expression.
|
||||||
|
|
||||||
|
## 8.0.3 (2020-10-02)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Fix a wasteful loop during `Parser` creation when setting `ecmaVersion` to `"latest"`.
|
||||||
|
|
||||||
|
## 8.0.2 (2020-09-30)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Make the TypeScript types reflect the current allowed values for `ecmaVersion`.
|
||||||
|
|
||||||
|
Fix another regexp/division tokenizer issue.
|
||||||
|
|
||||||
|
## 8.0.1 (2020-08-12)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Provide the correct value in the `version` export.
|
||||||
|
|
||||||
|
## 8.0.0 (2020-08-12)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
Disallow expressions like `(a = b) = c`.
|
||||||
|
|
||||||
|
Make non-octal escape sequences a syntax error in strict mode.
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
The package can now be loaded directly as an ECMAScript module in node 13+.
|
||||||
|
|
||||||
|
Update to the set of Unicode properties from ES2021.
|
||||||
|
|
||||||
|
### Breaking changes
|
||||||
|
|
||||||
|
The `ecmaVersion` option is now required. For the moment, omitting it will still work with a warning, but that will change in a future release.
|
||||||
|
|
||||||
|
Some changes to method signatures that may be used by plugins.
|
||||||
|
|
||||||
## 7.4.0 (2020-08-03)
|
## 7.4.0 (2020-08-03)
|
||||||
|
|
||||||
### New features
|
### New features
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (C) 2012-2018 by various contributors (see AUTHORS)
|
Copyright (C) 2012-2022 by various contributors (see AUTHORS)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -9,9 +9,7 @@ Acorn is open source software released under an
|
||||||
|
|
||||||
You are welcome to
|
You are welcome to
|
||||||
[report bugs](https://github.com/acornjs/acorn/issues) or create pull
|
[report bugs](https://github.com/acornjs/acorn/issues) or create pull
|
||||||
requests on [github](https://github.com/acornjs/acorn). For questions
|
requests on [github](https://github.com/acornjs/acorn).
|
||||||
and discussion, please use the
|
|
||||||
[Tern discussion forum](https://discuss.ternjs.net).
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -32,14 +30,14 @@ npm install
|
||||||
## Interface
|
## Interface
|
||||||
|
|
||||||
**parse**`(input, options)` is the main interface to the library. The
|
**parse**`(input, options)` is the main interface to the library. The
|
||||||
`input` parameter is a string, `options` can be undefined or an object
|
`input` parameter is a string, `options` must be an object setting
|
||||||
setting some of the options listed below. The return value will be an
|
some of the options listed below. The return value will be an abstract
|
||||||
abstract syntax tree object as specified by the [ESTree
|
syntax tree object as specified by the [ESTree
|
||||||
spec](https://github.com/estree/estree).
|
spec](https://github.com/estree/estree).
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let acorn = require("acorn");
|
let acorn = require("acorn");
|
||||||
console.log(acorn.parse("1 + 1"));
|
console.log(acorn.parse("1 + 1", {ecmaVersion: 2020}));
|
||||||
```
|
```
|
||||||
|
|
||||||
When encountering a syntax error, the parser will raise a
|
When encountering a syntax error, the parser will raise a
|
||||||
|
@ -48,18 +46,19 @@ have a `pos` property that indicates the string offset at which the
|
||||||
error occurred, and a `loc` object that contains a `{line, column}`
|
error occurred, and a `loc` object that contains a `{line, column}`
|
||||||
object referring to that same position.
|
object referring to that same position.
|
||||||
|
|
||||||
Options can be provided by passing a second argument, which should be
|
Options are provided by in a second argument, which should be an
|
||||||
an object containing any of these fields:
|
object containing any of these fields (only `ecmaVersion` is
|
||||||
|
required):
|
||||||
|
|
||||||
- **ecmaVersion**: Indicates the ECMAScript version to parse. Must be
|
- **ecmaVersion**: Indicates the ECMAScript version to parse. Can be a
|
||||||
either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), 10 (2019) or 11
|
number, either in year (`2022`) or plain version number (`6`) form,
|
||||||
(2020, partial support). This influences support for strict mode,
|
or `"latest"` (the latest the library supports). This influences
|
||||||
the set of reserved words, and support for new syntax features.
|
support for strict mode, the set of reserved words, and support for
|
||||||
Default is 10.
|
new syntax features.
|
||||||
|
|
||||||
**NOTE**: Only 'stage 4' (finalized) ECMAScript features are being
|
**NOTE**: Only 'stage 4' (finalized) ECMAScript features are being
|
||||||
implemented by Acorn. Other proposed new features can be implemented
|
implemented by Acorn. Other proposed new features must be
|
||||||
through plugins.
|
implemented through plugins.
|
||||||
|
|
||||||
- **sourceType**: Indicate the mode the code should be parsed in. Can be
|
- **sourceType**: Indicate the mode the code should be parsed in. Can be
|
||||||
either `"script"` or `"module"`. This influences global strict mode
|
either `"script"` or `"module"`. This influences global strict mode
|
||||||
|
@ -89,16 +88,27 @@ an object containing any of these fields:
|
||||||
|
|
||||||
- **allowImportExportEverywhere**: By default, `import` and `export`
|
- **allowImportExportEverywhere**: By default, `import` and `export`
|
||||||
declarations can only appear at a program's top level. Setting this
|
declarations can only appear at a program's top level. Setting this
|
||||||
option to `true` allows them anywhere where a statement is allowed.
|
option to `true` allows them anywhere where a statement is allowed,
|
||||||
|
and also allows `import.meta` expressions to appear in scripts
|
||||||
- **allowAwaitOutsideFunction**: By default, `await` expressions can
|
(when `sourceType` is not `"module"`).
|
||||||
only appear inside `async` functions. Setting this option to
|
|
||||||
`true` allows to have top-level `await` expressions. They are
|
|
||||||
still not allowed in non-`async` functions, though.
|
|
||||||
|
|
||||||
- **allowHashBang**: When this is enabled (off by default), if the
|
- **allowAwaitOutsideFunction**: If `false`, `await` expressions can
|
||||||
code starts with the characters `#!` (as in a shellscript), the
|
only appear inside `async` functions. Defaults to `true` in modules
|
||||||
first line will be treated as a comment.
|
for `ecmaVersion` 2022 and later, `false` for lower versions.
|
||||||
|
Setting this option to `true` allows to have top-level `await`
|
||||||
|
expressions. They are still not allowed in non-`async` functions,
|
||||||
|
though.
|
||||||
|
|
||||||
|
- **allowSuperOutsideMethod**: By default, `super` outside a method
|
||||||
|
raises an error. Set this to `true` to accept such code.
|
||||||
|
|
||||||
|
- **allowHashBang**: When this is enabled, if the code starts with the
|
||||||
|
characters `#!` (as in a shellscript), the first line will be
|
||||||
|
treated as a comment. Defaults to true when `ecmaVersion` >= 2023.
|
||||||
|
|
||||||
|
- **checkPrivateFields**: By default, the parser will verify that
|
||||||
|
private properties are only used in places where they are valid and
|
||||||
|
have been declared. Set this to false to turn such checks off.
|
||||||
|
|
||||||
- **locations**: When `true`, each node has a `loc` object attached
|
- **locations**: When `true`, each node has a `loc` object attached
|
||||||
with `start` and `end` subobjects, each of which contains the
|
with `start` and `end` subobjects, each of which contains the
|
||||||
|
@ -191,6 +201,13 @@ option is enabled). When the token's type is `tokTypes.eof`, you
|
||||||
should stop calling the method, since it will keep returning that same
|
should stop calling the method, since it will keep returning that same
|
||||||
token forever.
|
token forever.
|
||||||
|
|
||||||
|
Note that tokenizing JavaScript without parsing it is, in modern
|
||||||
|
versions of the language, not really possible due to the way syntax is
|
||||||
|
overloaded in ways that can only be disambiguated by the parse
|
||||||
|
context. This package applies a bunch of heuristics to try and do a
|
||||||
|
reasonable job, but you are advised to use `parse` with the `onToken`
|
||||||
|
option instead of this.
|
||||||
|
|
||||||
In ES6 environment, returned result can be used as any other
|
In ES6 environment, returned result can be used as any other
|
||||||
protocol-compliant iterable:
|
protocol-compliant iterable:
|
||||||
|
|
||||||
|
@ -224,7 +241,7 @@ you can use its static `extend` method.
|
||||||
var acorn = require("acorn");
|
var acorn = require("acorn");
|
||||||
var jsx = require("acorn-jsx");
|
var jsx = require("acorn-jsx");
|
||||||
var JSXParser = acorn.Parser.extend(jsx());
|
var JSXParser = acorn.Parser.extend(jsx());
|
||||||
JSXParser.parse("foo(<bar/>)");
|
JSXParser.parse("foo(<bar/>)", {ecmaVersion: 2020});
|
||||||
```
|
```
|
||||||
|
|
||||||
The `extend` method takes any number of plugin values, and returns a
|
The `extend` method takes any number of plugin values, and returns a
|
||||||
|
@ -249,6 +266,9 @@ options:
|
||||||
- `--allow-hash-bang`: If the code starts with the characters #! (as
|
- `--allow-hash-bang`: If the code starts with the characters #! (as
|
||||||
in a shellscript), the first line will be treated as a comment.
|
in a shellscript), the first line will be treated as a comment.
|
||||||
|
|
||||||
|
- `--allow-await-outside-function`: Allows top-level `await` expressions.
|
||||||
|
See the `allowAwaitOutsideFunction` option for more information.
|
||||||
|
|
||||||
- `--compact`: No whitespace is used in the AST output.
|
- `--compact`: No whitespace is used in the AST output.
|
||||||
|
|
||||||
- `--silent`: Do not output the AST, just return the exit status.
|
- `--silent`: Do not output the AST, just return the exit status.
|
||||||
|
@ -260,10 +280,3 @@ The utility spits out the syntax tree as JSON data.
|
||||||
## Existing plugins
|
## Existing plugins
|
||||||
|
|
||||||
- [`acorn-jsx`](https://github.com/RReverser/acorn-jsx): Parse [Facebook JSX syntax extensions](https://github.com/facebook/jsx)
|
- [`acorn-jsx`](https://github.com/RReverser/acorn-jsx): Parse [Facebook JSX syntax extensions](https://github.com/facebook/jsx)
|
||||||
|
|
||||||
Plugins for ECMAScript proposals:
|
|
||||||
|
|
||||||
- [`acorn-stage3`](https://github.com/acornjs/acorn-stage3): Parse most stage 3 proposals, bundling:
|
|
||||||
- [`acorn-class-fields`](https://github.com/acornjs/acorn-class-fields): Parse [class fields proposal](https://github.com/tc39/proposal-class-fields)
|
|
||||||
- [`acorn-import-meta`](https://github.com/acornjs/acorn-import-meta): Parse [import.meta proposal](https://github.com/tc39/proposal-import-meta)
|
|
||||||
- [`acorn-private-methods`](https://github.com/acornjs/acorn-private-methods): parse [private methods, getters and setters proposal](https://github.com/tc39/proposal-private-methods)n
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
'use strict';
|
"use strict"
|
||||||
|
|
||||||
require('../dist/bin.js');
|
require("../dist/bin.js")
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -1,2 +0,0 @@
|
||||||
import * as acorn from "./acorn";
|
|
||||||
export = acorn;
|
|
File diff suppressed because one or more lines are too long
|
@ -4,22 +4,45 @@ var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var acorn = require('./acorn.js');
|
var acorn = require('./acorn.js');
|
||||||
|
|
||||||
var infile, forceFile, silent = false, compact = false, tokenize = false;
|
function _interopNamespaceDefault(e) {
|
||||||
|
var n = Object.create(null);
|
||||||
|
if (e) {
|
||||||
|
Object.keys(e).forEach(function (k) {
|
||||||
|
if (k !== 'default') {
|
||||||
|
var d = Object.getOwnPropertyDescriptor(e, k);
|
||||||
|
Object.defineProperty(n, k, d.get ? d : {
|
||||||
|
enumerable: true,
|
||||||
|
get: function () { return e[k]; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
n.default = e;
|
||||||
|
return Object.freeze(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
var acorn__namespace = /*#__PURE__*/_interopNamespaceDefault(acorn);
|
||||||
|
|
||||||
|
var inputFilePaths = [], forceFileName = false, fileMode = false, silent = false, compact = false, tokenize = false;
|
||||||
var options = {};
|
var options = {};
|
||||||
|
|
||||||
function help(status) {
|
function help(status) {
|
||||||
var print = (status === 0) ? console.log : console.error;
|
var print = (status === 0) ? console.log : console.error;
|
||||||
print("usage: " + path.basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|...|--ecma2015|--ecma2016|--ecma2017|--ecma2018|...]");
|
print("usage: " + path.basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|...|--ecma2015|--ecma2016|--ecma2017|--ecma2018|...]");
|
||||||
print(" [--tokenize] [--locations] [---allow-hash-bang] [--compact] [--silent] [--module] [--help] [--] [infile]");
|
print(" [--tokenize] [--locations] [--allow-hash-bang] [--allow-await-outside-function] [--compact] [--silent] [--module] [--help] [--] [<infile>...]");
|
||||||
process.exit(status);
|
process.exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 2; i < process.argv.length; ++i) {
|
for (var i = 2; i < process.argv.length; ++i) {
|
||||||
var arg = process.argv[i];
|
var arg = process.argv[i];
|
||||||
if ((arg === "-" || arg[0] !== "-") && !infile) { infile = arg; }
|
if (arg[0] !== "-" || arg === "-") { inputFilePaths.push(arg); }
|
||||||
else if (arg === "--" && !infile && i + 2 === process.argv.length) { forceFile = infile = process.argv[++i]; }
|
else if (arg === "--") {
|
||||||
else if (arg === "--locations") { options.locations = true; }
|
inputFilePaths.push.apply(inputFilePaths, process.argv.slice(i + 1));
|
||||||
|
forceFileName = true;
|
||||||
|
break
|
||||||
|
} else if (arg === "--locations") { options.locations = true; }
|
||||||
else if (arg === "--allow-hash-bang") { options.allowHashBang = true; }
|
else if (arg === "--allow-hash-bang") { options.allowHashBang = true; }
|
||||||
|
else if (arg === "--allow-await-outside-function") { options.allowAwaitOutsideFunction = true; }
|
||||||
else if (arg === "--silent") { silent = true; }
|
else if (arg === "--silent") { silent = true; }
|
||||||
else if (arg === "--compact") { compact = true; }
|
else if (arg === "--compact") { compact = true; }
|
||||||
else if (arg === "--help") { help(0); }
|
else if (arg === "--help") { help(0); }
|
||||||
|
@ -34,31 +57,34 @@ for (var i = 2; i < process.argv.length; ++i) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function run(code) {
|
function run(codeList) {
|
||||||
var result;
|
var result = [], fileIdx = 0;
|
||||||
try {
|
try {
|
||||||
if (!tokenize) {
|
codeList.forEach(function (code, idx) {
|
||||||
result = acorn.parse(code, options);
|
fileIdx = idx;
|
||||||
} else {
|
if (!tokenize) {
|
||||||
result = [];
|
result = acorn__namespace.parse(code, options);
|
||||||
var tokenizer = acorn.tokenizer(code, options), token;
|
options.program = result;
|
||||||
do {
|
} else {
|
||||||
token = tokenizer.getToken();
|
var tokenizer = acorn__namespace.tokenizer(code, options), token;
|
||||||
result.push(token);
|
do {
|
||||||
} while (token.type !== acorn.tokTypes.eof)
|
token = tokenizer.getToken();
|
||||||
}
|
result.push(token);
|
||||||
|
} while (token.type !== acorn__namespace.tokTypes.eof)
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(infile && infile !== "-" ? e.message.replace(/\(\d+:\d+\)$/, function (m) { return m.slice(0, 1) + infile + " " + m.slice(1); }) : e.message);
|
console.error(fileMode ? e.message.replace(/\(\d+:\d+\)$/, function (m) { return m.slice(0, 1) + inputFilePaths[fileIdx] + " " + m.slice(1); }) : e.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (!silent) { console.log(JSON.stringify(result, null, compact ? null : 2)); }
|
if (!silent) { console.log(JSON.stringify(result, null, compact ? null : 2)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forceFile || infile && infile !== "-") {
|
if (fileMode = inputFilePaths.length && (forceFileName || !inputFilePaths.includes("-") || inputFilePaths.length !== 1)) {
|
||||||
run(fs.readFileSync(infile, "utf8"));
|
run(inputFilePaths.map(function (path) { return fs.readFileSync(path, "utf8"); }));
|
||||||
} else {
|
} else {
|
||||||
var code = "";
|
var code = "";
|
||||||
process.stdin.resume();
|
process.stdin.resume();
|
||||||
process.stdin.on("data", function (chunk) { return code += chunk; });
|
process.stdin.on("data", function (chunk) { return code += chunk; });
|
||||||
process.stdin.on("end", function () { return run(code); });
|
process.stdin.on("end", function () { return run([code]); });
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,21 @@
|
||||||
"main": "dist/acorn.js",
|
"main": "dist/acorn.js",
|
||||||
"types": "dist/acorn.d.ts",
|
"types": "dist/acorn.d.ts",
|
||||||
"module": "dist/acorn.mjs",
|
"module": "dist/acorn.mjs",
|
||||||
"version": "7.4.1",
|
"exports": {
|
||||||
"engines": {"node": ">=0.4.0"},
|
".": [
|
||||||
|
{
|
||||||
|
"import": "./dist/acorn.mjs",
|
||||||
|
"require": "./dist/acorn.js",
|
||||||
|
"default": "./dist/acorn.js"
|
||||||
|
},
|
||||||
|
"./dist/acorn.js"
|
||||||
|
],
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
},
|
||||||
|
"version": "8.12.1",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
},
|
||||||
"maintainers": [
|
"maintainers": [
|
||||||
{
|
{
|
||||||
"name": "Marijn Haverbeke",
|
"name": "Marijn Haverbeke",
|
||||||
|
@ -25,11 +38,13 @@
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/acornjs/acorn.git"
|
"url": "git+https://github.com/acornjs/acorn.git"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "cd ..; npm run build:main && npm run build:bin"
|
"prepare": "cd ..; npm run build:main"
|
||||||
},
|
},
|
||||||
"bin": {"acorn": "./bin/acorn"}
|
"bin": {
|
||||||
|
"acorn": "bin/acorn"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015-present, Brian Woodward.
|
|
||||||
|
|
||||||
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.
|
|
|
@ -1,315 +0,0 @@
|
||||||
# ansi-colors [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W8YFZ425KND68) [![NPM version](https://img.shields.io/npm/v/ansi-colors.svg?style=flat)](https://www.npmjs.com/package/ansi-colors) [![NPM monthly downloads](https://img.shields.io/npm/dm/ansi-colors.svg?style=flat)](https://npmjs.org/package/ansi-colors) [![NPM total downloads](https://img.shields.io/npm/dt/ansi-colors.svg?style=flat)](https://npmjs.org/package/ansi-colors) [![Linux Build Status](https://img.shields.io/travis/doowb/ansi-colors.svg?style=flat&label=Travis)](https://travis-ci.org/doowb/ansi-colors)
|
|
||||||
|
|
||||||
> Easily add ANSI colors to your text and symbols in the terminal. A faster drop-in replacement for chalk, kleur and turbocolor (without the dependencies and rendering bugs).
|
|
||||||
|
|
||||||
Please consider following this project's author, [Brian Woodward](https://github.com/doowb), and consider starring the project to show your :heart: and support.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
Install with [npm](https://www.npmjs.com/):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ npm install --save ansi-colors
|
|
||||||
```
|
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/383994/39635445-8a98a3a6-4f8b-11e8-89c1-068c45d4fff8.png)
|
|
||||||
|
|
||||||
## Why use this?
|
|
||||||
|
|
||||||
ansi-colors is _the fastest Node.js library for terminal styling_. A more performant drop-in replacement for chalk, with no dependencies.
|
|
||||||
|
|
||||||
* _Blazing fast_ - Fastest terminal styling library in node.js, 10-20x faster than chalk!
|
|
||||||
|
|
||||||
* _Drop-in replacement_ for [chalk](https://github.com/chalk/chalk).
|
|
||||||
* _No dependencies_ (Chalk has 7 dependencies in its tree!)
|
|
||||||
|
|
||||||
* _Safe_ - Does not modify the `String.prototype` like [colors](https://github.com/Marak/colors.js).
|
|
||||||
* Supports [nested colors](#nested-colors), **and does not have the [nested styling bug](#nested-styling-bug) that is present in [colorette](https://github.com/jorgebucaran/colorette), [chalk](https://github.com/chalk/chalk), and [kleur](https://github.com/lukeed/kleur)**.
|
|
||||||
* Supports [chained colors](#chained-colors).
|
|
||||||
* [Toggle color support](#toggle-color-support) on or off.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
const c = require('ansi-colors');
|
|
||||||
|
|
||||||
console.log(c.red('This is a red string!'));
|
|
||||||
console.log(c.green('This is a red string!'));
|
|
||||||
console.log(c.cyan('This is a cyan string!'));
|
|
||||||
console.log(c.yellow('This is a yellow string!'));
|
|
||||||
```
|
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/383994/39653848-a38e67da-4fc0-11e8-89ae-98c65ebe9dcf.png)
|
|
||||||
|
|
||||||
## Chained colors
|
|
||||||
|
|
||||||
```js
|
|
||||||
console.log(c.bold.red('this is a bold red message'));
|
|
||||||
console.log(c.bold.yellow.italic('this is a bold yellow italicized message'));
|
|
||||||
console.log(c.green.bold.underline('this is a bold green underlined message'));
|
|
||||||
```
|
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/383994/39635780-7617246a-4f8c-11e8-89e9-05216cc54e38.png)
|
|
||||||
|
|
||||||
## Nested colors
|
|
||||||
|
|
||||||
```js
|
|
||||||
console.log(c.yellow(`foo ${c.red.bold('red')} bar ${c.cyan('cyan')} baz`));
|
|
||||||
```
|
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/383994/39635817-8ed93d44-4f8c-11e8-8afd-8c3ea35f5fbe.png)
|
|
||||||
|
|
||||||
### Nested styling bug
|
|
||||||
|
|
||||||
`ansi-colors` does not have the nested styling bug found in [colorette](https://github.com/jorgebucaran/colorette), [chalk](https://github.com/chalk/chalk), and [kleur](https://github.com/lukeed/kleur).
|
|
||||||
|
|
||||||
```js
|
|
||||||
const { bold, red } = require('ansi-styles');
|
|
||||||
console.log(bold(`foo ${red.dim('bar')} baz`));
|
|
||||||
|
|
||||||
const colorette = require('colorette');
|
|
||||||
console.log(colorette.bold(`foo ${colorette.red(colorette.dim('bar'))} baz`));
|
|
||||||
|
|
||||||
const kleur = require('kleur');
|
|
||||||
console.log(kleur.bold(`foo ${kleur.red.dim('bar')} baz`));
|
|
||||||
|
|
||||||
const chalk = require('chalk');
|
|
||||||
console.log(chalk.bold(`foo ${chalk.red.dim('bar')} baz`));
|
|
||||||
```
|
|
||||||
|
|
||||||
**Results in the following**
|
|
||||||
|
|
||||||
(sans icons and labels)
|
|
||||||
|
|
||||||
![image](https://user-images.githubusercontent.com/383994/47280326-d2ee0580-d5a3-11e8-9611-ea6010f0a253.png)
|
|
||||||
|
|
||||||
## Toggle color support
|
|
||||||
|
|
||||||
Easily enable/disable colors.
|
|
||||||
|
|
||||||
```js
|
|
||||||
const c = require('ansi-colors');
|
|
||||||
|
|
||||||
// disable colors manually
|
|
||||||
c.enabled = false;
|
|
||||||
|
|
||||||
// or use a library to automatically detect support
|
|
||||||
c.enabled = require('color-support').hasBasic;
|
|
||||||
|
|
||||||
console.log(c.red('I will only be colored red if the terminal supports colors'));
|
|
||||||
```
|
|
||||||
|
|
||||||
## Strip ANSI codes
|
|
||||||
|
|
||||||
Use the `.unstyle` method to strip ANSI codes from a string.
|
|
||||||
|
|
||||||
```js
|
|
||||||
console.log(c.unstyle(c.blue.bold('foo bar baz')));
|
|
||||||
//=> 'foo bar baz'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Available styles
|
|
||||||
|
|
||||||
**Note** that bright and bright-background colors are not always supported.
|
|
||||||
|
|
||||||
| Colors | Background Colors | Bright Colors | Bright Background Colors |
|
|
||||||
| ------- | ----------------- | ------------- | ------------------------ |
|
|
||||||
| black | bgBlack | blackBright | bgBlackBright |
|
|
||||||
| red | bgRed | redBright | bgRedBright |
|
|
||||||
| green | bgGreen | greenBright | bgGreenBright |
|
|
||||||
| yellow | bgYellow | yellowBright | bgYellowBright |
|
|
||||||
| blue | bgBlue | blueBright | bgBlueBright |
|
|
||||||
| magenta | bgMagenta | magentaBright | bgMagentaBright |
|
|
||||||
| cyan | bgCyan | cyanBright | bgCyanBright |
|
|
||||||
| white | bgWhite | whiteBright | bgWhiteBright |
|
|
||||||
| gray | | | |
|
|
||||||
| grey | | | |
|
|
||||||
|
|
||||||
_(`gray` is the U.S. spelling, `grey` is more commonly used in the Canada and U.K.)_
|
|
||||||
|
|
||||||
### Style modifiers
|
|
||||||
|
|
||||||
* dim
|
|
||||||
* **bold**
|
|
||||||
|
|
||||||
* hidden
|
|
||||||
* _italic_
|
|
||||||
|
|
||||||
* underline
|
|
||||||
* inverse
|
|
||||||
* ~~strikethrough~~
|
|
||||||
|
|
||||||
* reset
|
|
||||||
|
|
||||||
## Aliases
|
|
||||||
|
|
||||||
Create custom aliases for styles.
|
|
||||||
|
|
||||||
```js
|
|
||||||
const colors = require('ansi-colors');
|
|
||||||
|
|
||||||
colors.alias('primary', colors.yellow);
|
|
||||||
colors.alias('secondary', colors.bold);
|
|
||||||
|
|
||||||
console.log(colors.primary.secondary('Foo'));
|
|
||||||
```
|
|
||||||
|
|
||||||
## Themes
|
|
||||||
|
|
||||||
A theme is an object of custom aliases.
|
|
||||||
|
|
||||||
```js
|
|
||||||
const colors = require('ansi-colors');
|
|
||||||
|
|
||||||
colors.theme({
|
|
||||||
danger: colors.red,
|
|
||||||
dark: colors.dim.gray,
|
|
||||||
disabled: colors.gray,
|
|
||||||
em: colors.italic,
|
|
||||||
heading: colors.bold.underline,
|
|
||||||
info: colors.cyan,
|
|
||||||
muted: colors.dim,
|
|
||||||
primary: colors.blue,
|
|
||||||
strong: colors.bold,
|
|
||||||
success: colors.green,
|
|
||||||
underline: colors.underline,
|
|
||||||
warning: colors.yellow
|
|
||||||
});
|
|
||||||
|
|
||||||
// Now, we can use our custom styles alongside the built-in styles!
|
|
||||||
console.log(colors.danger.strong.em('Error!'));
|
|
||||||
console.log(colors.warning('Heads up!'));
|
|
||||||
console.log(colors.info('Did you know...'));
|
|
||||||
console.log(colors.success.bold('It worked!'));
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
**Libraries tested**
|
|
||||||
|
|
||||||
* ansi-colors v3.0.4
|
|
||||||
* chalk v2.4.1
|
|
||||||
|
|
||||||
### Mac
|
|
||||||
|
|
||||||
> MacBook Pro, Intel Core i7, 2.3 GHz, 16 GB.
|
|
||||||
|
|
||||||
**Load time**
|
|
||||||
|
|
||||||
Time it takes to load the first time `require()` is called:
|
|
||||||
|
|
||||||
* ansi-colors - `1.915ms`
|
|
||||||
* chalk - `12.437ms`
|
|
||||||
|
|
||||||
**Benchmarks**
|
|
||||||
|
|
||||||
```
|
|
||||||
# All Colors
|
|
||||||
ansi-colors x 173,851 ops/sec ±0.42% (91 runs sampled)
|
|
||||||
chalk x 9,944 ops/sec ±2.53% (81 runs sampled)))
|
|
||||||
|
|
||||||
# Chained colors
|
|
||||||
ansi-colors x 20,791 ops/sec ±0.60% (88 runs sampled)
|
|
||||||
chalk x 2,111 ops/sec ±2.34% (83 runs sampled)
|
|
||||||
|
|
||||||
# Nested colors
|
|
||||||
ansi-colors x 59,304 ops/sec ±0.98% (92 runs sampled)
|
|
||||||
chalk x 4,590 ops/sec ±2.08% (82 runs sampled)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Windows
|
|
||||||
|
|
||||||
> Windows 10, Intel Core i7-7700k CPU @ 4.2 GHz, 32 GB
|
|
||||||
|
|
||||||
**Load time**
|
|
||||||
|
|
||||||
Time it takes to load the first time `require()` is called:
|
|
||||||
|
|
||||||
* ansi-colors - `1.494ms`
|
|
||||||
* chalk - `11.523ms`
|
|
||||||
|
|
||||||
**Benchmarks**
|
|
||||||
|
|
||||||
```
|
|
||||||
# All Colors
|
|
||||||
ansi-colors x 193,088 ops/sec ±0.51% (95 runs sampled))
|
|
||||||
chalk x 9,612 ops/sec ±3.31% (77 runs sampled)))
|
|
||||||
|
|
||||||
# Chained colors
|
|
||||||
ansi-colors x 26,093 ops/sec ±1.13% (94 runs sampled)
|
|
||||||
chalk x 2,267 ops/sec ±2.88% (80 runs sampled))
|
|
||||||
|
|
||||||
# Nested colors
|
|
||||||
ansi-colors x 67,747 ops/sec ±0.49% (93 runs sampled)
|
|
||||||
chalk x 4,446 ops/sec ±3.01% (82 runs sampled))
|
|
||||||
```
|
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><strong>Contributing</strong></summary>
|
|
||||||
|
|
||||||
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><strong>Running Tests</strong></summary>
|
|
||||||
|
|
||||||
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ npm install && npm test
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><strong>Building docs</strong></summary>
|
|
||||||
|
|
||||||
_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
|
|
||||||
|
|
||||||
To generate the readme, run the following command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ npm install -g verbose/verb#dev verb-generate-readme && verb
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Related projects
|
|
||||||
|
|
||||||
You might also be interested in these projects:
|
|
||||||
|
|
||||||
* [ansi-wrap](https://www.npmjs.com/package/ansi-wrap): Create ansi colors by passing the open and close codes. | [homepage](https://github.com/jonschlinkert/ansi-wrap "Create ansi colors by passing the open and close codes.")
|
|
||||||
* [strip-color](https://www.npmjs.com/package/strip-color): Strip ANSI color codes from a string. No dependencies. | [homepage](https://github.com/jonschlinkert/strip-color "Strip ANSI color codes from a string. No dependencies.")
|
|
||||||
|
|
||||||
### Contributors
|
|
||||||
|
|
||||||
| **Commits** | **Contributor** |
|
|
||||||
| --- | --- |
|
|
||||||
| 48 | [jonschlinkert](https://github.com/jonschlinkert) |
|
|
||||||
| 42 | [doowb](https://github.com/doowb) |
|
|
||||||
| 6 | [lukeed](https://github.com/lukeed) |
|
|
||||||
| 2 | [Silic0nS0ldier](https://github.com/Silic0nS0ldier) |
|
|
||||||
| 1 | [dwieeb](https://github.com/dwieeb) |
|
|
||||||
| 1 | [jorgebucaran](https://github.com/jorgebucaran) |
|
|
||||||
| 1 | [madhavarshney](https://github.com/madhavarshney) |
|
|
||||||
| 1 | [chapterjason](https://github.com/chapterjason) |
|
|
||||||
|
|
||||||
### Author
|
|
||||||
|
|
||||||
**Brian Woodward**
|
|
||||||
|
|
||||||
* [GitHub Profile](https://github.com/doowb)
|
|
||||||
* [Twitter Profile](https://twitter.com/doowb)
|
|
||||||
* [LinkedIn Profile](https://linkedin.com/in/woodwardbrian)
|
|
||||||
|
|
||||||
### License
|
|
||||||
|
|
||||||
Copyright © 2019, [Brian Woodward](https://github.com/doowb).
|
|
||||||
Released under the [MIT License](LICENSE).
|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on July 01, 2019._
|
|
|
@ -1,184 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
|
|
||||||
|
|
||||||
/* eslint-disable no-control-regex */
|
|
||||||
// this is a modified version of https://github.com/chalk/ansi-regex (MIT License)
|
|
||||||
const ANSI_REGEX = /[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g;
|
|
||||||
|
|
||||||
const hasColor = () => {
|
|
||||||
if (typeof process !== 'undefined') {
|
|
||||||
return process.env.FORCE_COLOR !== '0';
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const create = () => {
|
|
||||||
const colors = {
|
|
||||||
enabled: hasColor(),
|
|
||||||
visible: true,
|
|
||||||
styles: {},
|
|
||||||
keys: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ansi = style => {
|
|
||||||
let open = style.open = `\u001b[${style.codes[0]}m`;
|
|
||||||
let close = style.close = `\u001b[${style.codes[1]}m`;
|
|
||||||
let regex = style.regex = new RegExp(`\\u001b\\[${style.codes[1]}m`, 'g');
|
|
||||||
style.wrap = (input, newline) => {
|
|
||||||
if (input.includes(close)) input = input.replace(regex, close + open);
|
|
||||||
let output = open + input + close;
|
|
||||||
// see https://github.com/chalk/chalk/pull/92, thanks to the
|
|
||||||
// chalk contributors for this fix. However, we've confirmed that
|
|
||||||
// this issue is also present in Windows terminals
|
|
||||||
return newline ? output.replace(/\r*\n/g, `${close}$&${open}`) : output;
|
|
||||||
};
|
|
||||||
return style;
|
|
||||||
};
|
|
||||||
|
|
||||||
const wrap = (style, input, newline) => {
|
|
||||||
return typeof style === 'function' ? style(input) : style.wrap(input, newline);
|
|
||||||
};
|
|
||||||
|
|
||||||
const style = (input, stack) => {
|
|
||||||
if (input === '' || input == null) return '';
|
|
||||||
if (colors.enabled === false) return input;
|
|
||||||
if (colors.visible === false) return '';
|
|
||||||
let str = '' + input;
|
|
||||||
let nl = str.includes('\n');
|
|
||||||
let n = stack.length;
|
|
||||||
if (n > 0 && stack.includes('unstyle')) {
|
|
||||||
stack = [...new Set(['unstyle', ...stack])].reverse();
|
|
||||||
}
|
|
||||||
while (n-- > 0) str = wrap(colors.styles[stack[n]], str, nl);
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
const define = (name, codes, type) => {
|
|
||||||
colors.styles[name] = ansi({ name, codes });
|
|
||||||
let keys = colors.keys[type] || (colors.keys[type] = []);
|
|
||||||
keys.push(name);
|
|
||||||
|
|
||||||
Reflect.defineProperty(colors, name, {
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true,
|
|
||||||
set(value) {
|
|
||||||
colors.alias(name, value);
|
|
||||||
},
|
|
||||||
get() {
|
|
||||||
let color = input => style(input, color.stack);
|
|
||||||
Reflect.setPrototypeOf(color, colors);
|
|
||||||
color.stack = this.stack ? this.stack.concat(name) : [name];
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
define('reset', [0, 0], 'modifier');
|
|
||||||
define('bold', [1, 22], 'modifier');
|
|
||||||
define('dim', [2, 22], 'modifier');
|
|
||||||
define('italic', [3, 23], 'modifier');
|
|
||||||
define('underline', [4, 24], 'modifier');
|
|
||||||
define('inverse', [7, 27], 'modifier');
|
|
||||||
define('hidden', [8, 28], 'modifier');
|
|
||||||
define('strikethrough', [9, 29], 'modifier');
|
|
||||||
|
|
||||||
define('black', [30, 39], 'color');
|
|
||||||
define('red', [31, 39], 'color');
|
|
||||||
define('green', [32, 39], 'color');
|
|
||||||
define('yellow', [33, 39], 'color');
|
|
||||||
define('blue', [34, 39], 'color');
|
|
||||||
define('magenta', [35, 39], 'color');
|
|
||||||
define('cyan', [36, 39], 'color');
|
|
||||||
define('white', [37, 39], 'color');
|
|
||||||
define('gray', [90, 39], 'color');
|
|
||||||
define('grey', [90, 39], 'color');
|
|
||||||
|
|
||||||
define('bgBlack', [40, 49], 'bg');
|
|
||||||
define('bgRed', [41, 49], 'bg');
|
|
||||||
define('bgGreen', [42, 49], 'bg');
|
|
||||||
define('bgYellow', [43, 49], 'bg');
|
|
||||||
define('bgBlue', [44, 49], 'bg');
|
|
||||||
define('bgMagenta', [45, 49], 'bg');
|
|
||||||
define('bgCyan', [46, 49], 'bg');
|
|
||||||
define('bgWhite', [47, 49], 'bg');
|
|
||||||
|
|
||||||
define('blackBright', [90, 39], 'bright');
|
|
||||||
define('redBright', [91, 39], 'bright');
|
|
||||||
define('greenBright', [92, 39], 'bright');
|
|
||||||
define('yellowBright', [93, 39], 'bright');
|
|
||||||
define('blueBright', [94, 39], 'bright');
|
|
||||||
define('magentaBright', [95, 39], 'bright');
|
|
||||||
define('cyanBright', [96, 39], 'bright');
|
|
||||||
define('whiteBright', [97, 39], 'bright');
|
|
||||||
|
|
||||||
define('bgBlackBright', [100, 49], 'bgBright');
|
|
||||||
define('bgRedBright', [101, 49], 'bgBright');
|
|
||||||
define('bgGreenBright', [102, 49], 'bgBright');
|
|
||||||
define('bgYellowBright', [103, 49], 'bgBright');
|
|
||||||
define('bgBlueBright', [104, 49], 'bgBright');
|
|
||||||
define('bgMagentaBright', [105, 49], 'bgBright');
|
|
||||||
define('bgCyanBright', [106, 49], 'bgBright');
|
|
||||||
define('bgWhiteBright', [107, 49], 'bgBright');
|
|
||||||
|
|
||||||
colors.ansiRegex = ANSI_REGEX;
|
|
||||||
colors.hasColor = colors.hasAnsi = str => {
|
|
||||||
colors.ansiRegex.lastIndex = 0;
|
|
||||||
return typeof str === 'string' && str !== '' && colors.ansiRegex.test(str);
|
|
||||||
};
|
|
||||||
|
|
||||||
colors.alias = (name, color) => {
|
|
||||||
let fn = typeof color === 'string' ? colors[color] : color;
|
|
||||||
|
|
||||||
if (typeof fn !== 'function') {
|
|
||||||
throw new TypeError('Expected alias to be the name of an existing color (string) or a function');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fn.stack) {
|
|
||||||
Reflect.defineProperty(fn, 'name', { value: name });
|
|
||||||
colors.styles[name] = fn;
|
|
||||||
fn.stack = [name];
|
|
||||||
}
|
|
||||||
|
|
||||||
Reflect.defineProperty(colors, name, {
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true,
|
|
||||||
set(value) {
|
|
||||||
colors.alias(name, value);
|
|
||||||
},
|
|
||||||
get() {
|
|
||||||
let color = input => style(input, color.stack);
|
|
||||||
Reflect.setPrototypeOf(color, colors);
|
|
||||||
color.stack = this.stack ? this.stack.concat(fn.stack) : fn.stack;
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
colors.theme = custom => {
|
|
||||||
if (!isObject(custom)) throw new TypeError('Expected theme to be an object');
|
|
||||||
for (let name of Object.keys(custom)) {
|
|
||||||
colors.alias(name, custom[name]);
|
|
||||||
}
|
|
||||||
return colors;
|
|
||||||
};
|
|
||||||
|
|
||||||
colors.alias('unstyle', str => {
|
|
||||||
if (typeof str === 'string' && str !== '') {
|
|
||||||
colors.ansiRegex.lastIndex = 0;
|
|
||||||
return str.replace(colors.ansiRegex, '');
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
});
|
|
||||||
|
|
||||||
colors.alias('noop', str => str);
|
|
||||||
colors.none = colors.clear = colors.noop;
|
|
||||||
|
|
||||||
colors.stripColor = colors.unstyle;
|
|
||||||
colors.symbols = require('./symbols');
|
|
||||||
colors.define = define;
|
|
||||||
return colors;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = create();
|
|
||||||
module.exports.create = create;
|
|
|
@ -1,129 +0,0 @@
|
||||||
{
|
|
||||||
"name": "ansi-colors",
|
|
||||||
"description": "Easily add ANSI colors to your text and symbols in the terminal. A faster drop-in replacement for chalk, kleur and turbocolor (without the dependencies and rendering bugs).",
|
|
||||||
"version": "4.1.3",
|
|
||||||
"homepage": "https://github.com/doowb/ansi-colors",
|
|
||||||
"author": "Brian Woodward (https://github.com/doowb)",
|
|
||||||
"contributors": [
|
|
||||||
"Brian Woodward (https://twitter.com/doowb)",
|
|
||||||
"Jason Schilling (https://sourecode.de)",
|
|
||||||
"Jon Schlinkert (http://twitter.com/jonschlinkert)",
|
|
||||||
"Jordan (https://github.com/Silic0nS0ldier)"
|
|
||||||
],
|
|
||||||
"repository": "doowb/ansi-colors",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/doowb/ansi-colors/issues"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"files": [
|
|
||||||
"index.js",
|
|
||||||
"symbols.js",
|
|
||||||
"types/index.d.ts"
|
|
||||||
],
|
|
||||||
"main": "index.js",
|
|
||||||
"types": "./types/index.d.ts",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "mocha"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"decache": "^4.5.1",
|
|
||||||
"gulp-format-md": "^2.0.0",
|
|
||||||
"justified": "^1.0.1",
|
|
||||||
"mocha": "^6.1.4",
|
|
||||||
"text-table": "^0.2.0"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"256",
|
|
||||||
"ansi",
|
|
||||||
"bgblack",
|
|
||||||
"bgBlack",
|
|
||||||
"bgblue",
|
|
||||||
"bgBlue",
|
|
||||||
"bgcyan",
|
|
||||||
"bgCyan",
|
|
||||||
"bggreen",
|
|
||||||
"bgGreen",
|
|
||||||
"bgmagenta",
|
|
||||||
"bgMagenta",
|
|
||||||
"bgred",
|
|
||||||
"bgRed",
|
|
||||||
"bgwhite",
|
|
||||||
"bgWhite",
|
|
||||||
"bgyellow",
|
|
||||||
"bgYellow",
|
|
||||||
"black",
|
|
||||||
"blue",
|
|
||||||
"bold",
|
|
||||||
"cli",
|
|
||||||
"clorox",
|
|
||||||
"color",
|
|
||||||
"colors",
|
|
||||||
"colour",
|
|
||||||
"command line",
|
|
||||||
"command-line",
|
|
||||||
"console",
|
|
||||||
"cyan",
|
|
||||||
"dim",
|
|
||||||
"formatting",
|
|
||||||
"gray",
|
|
||||||
"green",
|
|
||||||
"grey",
|
|
||||||
"hidden",
|
|
||||||
"inverse",
|
|
||||||
"italic",
|
|
||||||
"kleur",
|
|
||||||
"log",
|
|
||||||
"logging",
|
|
||||||
"magenta",
|
|
||||||
"red",
|
|
||||||
"reset",
|
|
||||||
"rgb",
|
|
||||||
"shell",
|
|
||||||
"str",
|
|
||||||
"strikethrough",
|
|
||||||
"string",
|
|
||||||
"style",
|
|
||||||
"styles",
|
|
||||||
"terminal",
|
|
||||||
"text",
|
|
||||||
"tty",
|
|
||||||
"underline",
|
|
||||||
"white",
|
|
||||||
"xterm",
|
|
||||||
"yellow"
|
|
||||||
],
|
|
||||||
"verb": {
|
|
||||||
"toc": false,
|
|
||||||
"layout": "default",
|
|
||||||
"tasks": [
|
|
||||||
"readme"
|
|
||||||
],
|
|
||||||
"data": {
|
|
||||||
"author": {
|
|
||||||
"linkedin": "woodwardbrian",
|
|
||||||
"twitter": "doowb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"gulp-format-md"
|
|
||||||
],
|
|
||||||
"lint": {
|
|
||||||
"reflinks": true
|
|
||||||
},
|
|
||||||
"related": {
|
|
||||||
"list": [
|
|
||||||
"ansi-wrap",
|
|
||||||
"strip-color"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"reflinks": [
|
|
||||||
"chalk",
|
|
||||||
"colorette",
|
|
||||||
"colors",
|
|
||||||
"kleur"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const isHyper = typeof process !== 'undefined' && process.env.TERM_PROGRAM === 'Hyper';
|
|
||||||
const isWindows = typeof process !== 'undefined' && process.platform === 'win32';
|
|
||||||
const isLinux = typeof process !== 'undefined' && process.platform === 'linux';
|
|
||||||
|
|
||||||
const common = {
|
|
||||||
ballotDisabled: '☒',
|
|
||||||
ballotOff: '☐',
|
|
||||||
ballotOn: '☑',
|
|
||||||
bullet: '•',
|
|
||||||
bulletWhite: '◦',
|
|
||||||
fullBlock: '█',
|
|
||||||
heart: '❤',
|
|
||||||
identicalTo: '≡',
|
|
||||||
line: '─',
|
|
||||||
mark: '※',
|
|
||||||
middot: '·',
|
|
||||||
minus: '-',
|
|
||||||
multiplication: '×',
|
|
||||||
obelus: '÷',
|
|
||||||
pencilDownRight: '✎',
|
|
||||||
pencilRight: '✏',
|
|
||||||
pencilUpRight: '✐',
|
|
||||||
percent: '%',
|
|
||||||
pilcrow2: '❡',
|
|
||||||
pilcrow: '¶',
|
|
||||||
plusMinus: '±',
|
|
||||||
question: '?',
|
|
||||||
section: '§',
|
|
||||||
starsOff: '☆',
|
|
||||||
starsOn: '★',
|
|
||||||
upDownArrow: '↕'
|
|
||||||
};
|
|
||||||
|
|
||||||
const windows = Object.assign({}, common, {
|
|
||||||
check: '√',
|
|
||||||
cross: '×',
|
|
||||||
ellipsisLarge: '...',
|
|
||||||
ellipsis: '...',
|
|
||||||
info: 'i',
|
|
||||||
questionSmall: '?',
|
|
||||||
pointer: '>',
|
|
||||||
pointerSmall: '»',
|
|
||||||
radioOff: '( )',
|
|
||||||
radioOn: '(*)',
|
|
||||||
warning: '‼'
|
|
||||||
});
|
|
||||||
|
|
||||||
const other = Object.assign({}, common, {
|
|
||||||
ballotCross: '✘',
|
|
||||||
check: '✔',
|
|
||||||
cross: '✖',
|
|
||||||
ellipsisLarge: '⋯',
|
|
||||||
ellipsis: '…',
|
|
||||||
info: 'ℹ',
|
|
||||||
questionFull: '?',
|
|
||||||
questionSmall: '﹖',
|
|
||||||
pointer: isLinux ? '▸' : '❯',
|
|
||||||
pointerSmall: isLinux ? '‣' : '›',
|
|
||||||
radioOff: '◯',
|
|
||||||
radioOn: '◉',
|
|
||||||
warning: '⚠'
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = (isWindows && !isHyper) ? windows : other;
|
|
||||||
Reflect.defineProperty(module.exports, 'common', { enumerable: false, value: common });
|
|
||||||
Reflect.defineProperty(module.exports, 'windows', { enumerable: false, value: windows });
|
|
||||||
Reflect.defineProperty(module.exports, 'other', { enumerable: false, value: other });
|
|
|
@ -1,235 +0,0 @@
|
||||||
// Imported from DefinitelyTyped project.
|
|
||||||
// TypeScript definitions for ansi-colors
|
|
||||||
// Definitions by: Rogier Schouten <https://github.com/rogierschouten>
|
|
||||||
// Integrated by: Jordan Mele <https://github.com/Silic0nS0ldier>
|
|
||||||
|
|
||||||
interface SymbolsType {
|
|
||||||
/**
|
|
||||||
* `undefined` on windows, `✘` on other platforms.
|
|
||||||
*/
|
|
||||||
ballotCross?: "✘";
|
|
||||||
ballotDisabled: "☒";
|
|
||||||
ballotOff: "☐";
|
|
||||||
ballotOn: "☑";
|
|
||||||
bullet: "•";
|
|
||||||
bulletWhite: "◦";
|
|
||||||
/**
|
|
||||||
* `√` on windows, `✔` on other platforms.
|
|
||||||
*/
|
|
||||||
check: "√" | "✔";
|
|
||||||
/**
|
|
||||||
* `×` on windows, `✖` on other platforms.
|
|
||||||
*/
|
|
||||||
cross: "×" | "✖";
|
|
||||||
/**
|
|
||||||
* `...` on windows, `⋯` on other platforms.
|
|
||||||
*/
|
|
||||||
ellipsisLarge: "..." | "⋯";
|
|
||||||
/**
|
|
||||||
* `...` on windows, `…` on other platforms.
|
|
||||||
*/
|
|
||||||
ellipsis: "..." | "…";
|
|
||||||
fullBlock: "█";
|
|
||||||
heart: "❤";
|
|
||||||
identicalTo: "≡";
|
|
||||||
info: "i" | "ℹ";
|
|
||||||
line: "─";
|
|
||||||
mark: "※";
|
|
||||||
middot: "·";
|
|
||||||
minus: "-";
|
|
||||||
multiplication: "×";
|
|
||||||
obelus: "÷";
|
|
||||||
pencilDownRight: "✎";
|
|
||||||
pencilRight: "✏";
|
|
||||||
pencilUpRight: "✐";
|
|
||||||
percent: "%";
|
|
||||||
pilcrow2: "❡";
|
|
||||||
pilcrow: "¶";
|
|
||||||
plusMinus: "±";
|
|
||||||
/**
|
|
||||||
* `>` on windows, `▸` on linux, and `❯` on other platforms.
|
|
||||||
*/
|
|
||||||
pointer: ">" | "▸" | "❯";
|
|
||||||
/**
|
|
||||||
* `»` on windows, `‣` on linux, and `›` on other platforms.
|
|
||||||
*/
|
|
||||||
pointerSmall: "»" | "‣" | "›";
|
|
||||||
question: "?";
|
|
||||||
/**
|
|
||||||
* `undefined` on windows, `?` on other platforms.
|
|
||||||
*/
|
|
||||||
questionFull?: "?";
|
|
||||||
/**
|
|
||||||
* `?` on windows, `﹖` on other platforms.
|
|
||||||
*/
|
|
||||||
questionSmall: "?" | "﹖";
|
|
||||||
/**
|
|
||||||
* `( )` on windows, `◯` on other platforms.
|
|
||||||
*/
|
|
||||||
radioOff: "( )" | "◯";
|
|
||||||
/**
|
|
||||||
* `(*)` on windows, `◉` on other platforms.
|
|
||||||
*/
|
|
||||||
radioOn: "(*)" | "◉";
|
|
||||||
section: "§";
|
|
||||||
starsOff: "☆";
|
|
||||||
starsOn: "★";
|
|
||||||
upDownArrow: "↕";
|
|
||||||
/**
|
|
||||||
* `‼` on windows, `⚠` on other platforms.
|
|
||||||
*/
|
|
||||||
warning: "‼" | "⚠";
|
|
||||||
}
|
|
||||||
|
|
||||||
type StyleArrayStructure = [number, number];
|
|
||||||
interface StyleArrayProperties {
|
|
||||||
open: string;
|
|
||||||
close: string;
|
|
||||||
closeRe: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type StyleType = StyleArrayStructure & StyleArrayProperties;
|
|
||||||
|
|
||||||
|
|
||||||
interface StylesType<T> {
|
|
||||||
// modifiers
|
|
||||||
reset: T;
|
|
||||||
bold: T;
|
|
||||||
dim: T;
|
|
||||||
italic: T;
|
|
||||||
underline: T;
|
|
||||||
inverse: T;
|
|
||||||
hidden: T;
|
|
||||||
strikethrough: T;
|
|
||||||
|
|
||||||
// colors
|
|
||||||
black: T;
|
|
||||||
red: T;
|
|
||||||
green: T;
|
|
||||||
yellow: T;
|
|
||||||
blue: T;
|
|
||||||
magenta: T;
|
|
||||||
cyan: T;
|
|
||||||
white: T;
|
|
||||||
gray: T;
|
|
||||||
grey: T;
|
|
||||||
|
|
||||||
// bright colors
|
|
||||||
blackBright: T;
|
|
||||||
redBright: T;
|
|
||||||
greenBright: T;
|
|
||||||
yellowBright: T;
|
|
||||||
blueBright: T;
|
|
||||||
magentaBright: T;
|
|
||||||
cyanBright: T;
|
|
||||||
whiteBright: T;
|
|
||||||
|
|
||||||
// background colors
|
|
||||||
bgBlack: T;
|
|
||||||
bgRed: T;
|
|
||||||
bgGreen: T;
|
|
||||||
bgYellow: T;
|
|
||||||
bgBlue: T;
|
|
||||||
bgMagenta: T;
|
|
||||||
bgCyan: T;
|
|
||||||
bgWhite: T;
|
|
||||||
|
|
||||||
// bright background colors
|
|
||||||
bgBlackBright: T;
|
|
||||||
bgRedBright: T;
|
|
||||||
bgGreenBright: T;
|
|
||||||
bgYellowBright: T;
|
|
||||||
bgBlueBright: T;
|
|
||||||
bgMagentaBright: T;
|
|
||||||
bgCyanBright: T;
|
|
||||||
bgWhiteBright: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare namespace ansiColors {
|
|
||||||
interface StyleFunction extends StylesType<StyleFunction> {
|
|
||||||
(s: string): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// modifiers
|
|
||||||
const reset: StyleFunction;
|
|
||||||
const bold: StyleFunction;
|
|
||||||
const dim: StyleFunction;
|
|
||||||
const italic: StyleFunction;
|
|
||||||
const underline: StyleFunction;
|
|
||||||
const inverse: StyleFunction;
|
|
||||||
const hidden: StyleFunction;
|
|
||||||
const strikethrough: StyleFunction;
|
|
||||||
|
|
||||||
// colors
|
|
||||||
const black: StyleFunction;
|
|
||||||
const red: StyleFunction;
|
|
||||||
const green: StyleFunction;
|
|
||||||
const yellow: StyleFunction;
|
|
||||||
const blue: StyleFunction;
|
|
||||||
const magenta: StyleFunction;
|
|
||||||
const cyan: StyleFunction;
|
|
||||||
const white: StyleFunction;
|
|
||||||
const gray: StyleFunction;
|
|
||||||
const grey: StyleFunction;
|
|
||||||
|
|
||||||
// bright colors
|
|
||||||
const blackBright: StyleFunction;
|
|
||||||
const redBright: StyleFunction;
|
|
||||||
const greenBright: StyleFunction;
|
|
||||||
const yellowBright: StyleFunction;
|
|
||||||
const blueBright: StyleFunction;
|
|
||||||
const magentaBright: StyleFunction;
|
|
||||||
const cyanBright: StyleFunction;
|
|
||||||
const whiteBright: StyleFunction;
|
|
||||||
|
|
||||||
// background colors
|
|
||||||
const bgBlack: StyleFunction;
|
|
||||||
const bgRed: StyleFunction;
|
|
||||||
const bgGreen: StyleFunction;
|
|
||||||
const bgYellow: StyleFunction;
|
|
||||||
const bgBlue: StyleFunction;
|
|
||||||
const bgMagenta: StyleFunction;
|
|
||||||
const bgCyan: StyleFunction;
|
|
||||||
const bgWhite: StyleFunction;
|
|
||||||
|
|
||||||
// bright background colors
|
|
||||||
const bgBlackBright: StyleFunction;
|
|
||||||
const bgRedBright: StyleFunction;
|
|
||||||
const bgGreenBright: StyleFunction;
|
|
||||||
const bgYellowBright: StyleFunction;
|
|
||||||
const bgBlueBright: StyleFunction;
|
|
||||||
const bgMagentaBright: StyleFunction;
|
|
||||||
const bgCyanBright: StyleFunction;
|
|
||||||
const bgWhiteBright: StyleFunction;
|
|
||||||
|
|
||||||
let enabled: boolean;
|
|
||||||
let visible: boolean;
|
|
||||||
const ansiRegex: RegExp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove styles from string
|
|
||||||
*/
|
|
||||||
function stripColor(s: string): string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove styles from string
|
|
||||||
*/
|
|
||||||
function strip(s: string): string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove styles from string
|
|
||||||
*/
|
|
||||||
function unstyle(s: string): string;
|
|
||||||
|
|
||||||
const styles: StylesType<StyleType>;
|
|
||||||
const symbols: SymbolsType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs a string with check-symbol as prefix
|
|
||||||
*/
|
|
||||||
function ok(...args: string[]): string;
|
|
||||||
|
|
||||||
function create(): typeof ansiColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
export = ansiColors;
|
|
|
@ -1,185 +1,216 @@
|
||||||
1.0.10 / 2018-02-15
|
# Changelog
|
||||||
------------------
|
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
|
||||||
|
## [2.0.1] - 2020-08-29
|
||||||
|
### Fixed
|
||||||
|
- Fix issue with `process.argv` when used with interpreters (`coffee`, `ts-node`, etc.), #150.
|
||||||
|
|
||||||
|
|
||||||
|
## [2.0.0] - 2020-08-14
|
||||||
|
### Changed
|
||||||
|
- Full rewrite. Now port from python 3.9.0 & more precise following.
|
||||||
|
See [doc](./doc) for difference and migration info.
|
||||||
|
- node.js 10+ required
|
||||||
|
- Removed most of local docs in favour of original ones.
|
||||||
|
|
||||||
|
|
||||||
|
## [1.0.10] - 2018-02-15
|
||||||
|
### Fixed
|
||||||
- Use .concat instead of + for arrays, #122.
|
- Use .concat instead of + for arrays, #122.
|
||||||
|
|
||||||
|
|
||||||
1.0.9 / 2016-09-29
|
## [1.0.9] - 2016-09-29
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Rerelease after 1.0.8 - deps cleanup.
|
- Rerelease after 1.0.8 - deps cleanup.
|
||||||
|
|
||||||
|
|
||||||
1.0.8 / 2016-09-29
|
## [1.0.8] - 2016-09-29
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Maintenance (deps bump, fix node 6.5+ tests, coverage report).
|
- Maintenance (deps bump, fix node 6.5+ tests, coverage report).
|
||||||
|
|
||||||
|
|
||||||
1.0.7 / 2016-03-17
|
## [1.0.7] - 2016-03-17
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Teach `addArgument` to accept string arg names. #97, @tomxtobin.
|
- Teach `addArgument` to accept string arg names. #97, @tomxtobin.
|
||||||
|
|
||||||
|
|
||||||
1.0.6 / 2016-02-06
|
## [1.0.6] - 2016-02-06
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Maintenance: moved to eslint & updated CS.
|
- Maintenance: moved to eslint & updated CS.
|
||||||
|
|
||||||
|
|
||||||
1.0.5 / 2016-02-05
|
## [1.0.5] - 2016-02-05
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Removed lodash dependency to significantly reduce install size.
|
- Removed lodash dependency to significantly reduce install size.
|
||||||
Thanks to @mourner.
|
Thanks to @mourner.
|
||||||
|
|
||||||
|
|
||||||
1.0.4 / 2016-01-17
|
## [1.0.4] - 2016-01-17
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Maintenance: lodash update to 4.0.0.
|
- Maintenance: lodash update to 4.0.0.
|
||||||
|
|
||||||
|
|
||||||
1.0.3 / 2015-10-27
|
## [1.0.3] - 2015-10-27
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Fix parse `=` in args: `--examplepath="C:\myfolder\env=x64"`. #84, @CatWithApple.
|
- Fix parse `=` in args: `--examplepath="C:\myfolder\env=x64"`. #84, @CatWithApple.
|
||||||
|
|
||||||
|
|
||||||
1.0.2 / 2015-03-22
|
## [1.0.2] - 2015-03-22
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Relaxed lodash version dependency.
|
- Relaxed lodash version dependency.
|
||||||
|
|
||||||
|
|
||||||
1.0.1 / 2015-02-20
|
## [1.0.1] - 2015-02-20
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Changed dependencies to be compatible with ancient nodejs.
|
- Changed dependencies to be compatible with ancient nodejs.
|
||||||
|
|
||||||
|
|
||||||
1.0.0 / 2015-02-19
|
## [1.0.0] - 2015-02-19
|
||||||
------------------
|
### Changed
|
||||||
|
|
||||||
- Maintenance release.
|
- Maintenance release.
|
||||||
- Replaced `underscore` with `lodash`.
|
- Replaced `underscore` with `lodash`.
|
||||||
- Bumped version to 1.0.0 to better reflect semver meaning.
|
- Bumped version to 1.0.0 to better reflect semver meaning.
|
||||||
- HISTORY.md -> CHANGELOG.md
|
- HISTORY.md -> CHANGELOG.md
|
||||||
|
|
||||||
|
|
||||||
0.1.16 / 2013-12-01
|
## [0.1.16] - 2013-12-01
|
||||||
-------------------
|
### Changed
|
||||||
|
|
||||||
- Maintenance release. Updated dependencies and docs.
|
- Maintenance release. Updated dependencies and docs.
|
||||||
|
|
||||||
|
|
||||||
0.1.15 / 2013-05-13
|
## [0.1.15] - 2013-05-13
|
||||||
-------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed #55, @trebor89
|
- Fixed #55, @trebor89
|
||||||
|
|
||||||
|
|
||||||
0.1.14 / 2013-05-12
|
## [0.1.14] - 2013-05-12
|
||||||
-------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed #62, @maxtaco
|
- Fixed #62, @maxtaco
|
||||||
|
|
||||||
|
|
||||||
0.1.13 / 2013-04-08
|
## [0.1.13] - 2013-04-08
|
||||||
-------------------
|
### Changed
|
||||||
|
|
||||||
- Added `.npmignore` to reduce package size
|
- Added `.npmignore` to reduce package size
|
||||||
|
|
||||||
|
|
||||||
0.1.12 / 2013-02-10
|
## [0.1.12] - 2013-02-10
|
||||||
-------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed conflictHandler (#46), @hpaulj
|
- Fixed conflictHandler (#46), @hpaulj
|
||||||
|
|
||||||
|
|
||||||
0.1.11 / 2013-02-07
|
## [0.1.11] - 2013-02-07
|
||||||
-------------------
|
### Added
|
||||||
|
|
||||||
- Multiple bugfixes, @hpaulj
|
|
||||||
- Added 70+ tests (ported from python), @hpaulj
|
- Added 70+ tests (ported from python), @hpaulj
|
||||||
- Added conflictHandler, @applepicke
|
- Added conflictHandler, @applepicke
|
||||||
- Added fromfilePrefixChar, @hpaulj
|
- Added fromfilePrefixChar, @hpaulj
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Multiple bugfixes, @hpaulj
|
||||||
|
|
||||||
0.1.10 / 2012-12-30
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
|
## [0.1.10] - 2012-12-30
|
||||||
|
### Added
|
||||||
- Added [mutual exclusion](http://docs.python.org/dev/library/argparse.html#mutual-exclusion)
|
- Added [mutual exclusion](http://docs.python.org/dev/library/argparse.html#mutual-exclusion)
|
||||||
support, thanks to @hpaulj
|
support, thanks to @hpaulj
|
||||||
|
|
||||||
|
### Fixed
|
||||||
- Fixed options check for `storeConst` & `appendConst` actions, thanks to @hpaulj
|
- Fixed options check for `storeConst` & `appendConst` actions, thanks to @hpaulj
|
||||||
|
|
||||||
|
|
||||||
0.1.9 / 2012-12-27
|
## [0.1.9] - 2012-12-27
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed option dest interferens with other options (issue #23), thanks to @hpaulj
|
- Fixed option dest interferens with other options (issue #23), thanks to @hpaulj
|
||||||
- Fixed default value behavior with `*` positionals, thanks to @hpaulj
|
- Fixed default value behavior with `*` positionals, thanks to @hpaulj
|
||||||
- Improve `getDefault()` behavior, thanks to @hpaulj
|
- Improve `getDefault()` behavior, thanks to @hpaulj
|
||||||
- Imrove negative argument parsing, thanks to @hpaulj
|
- Improve negative argument parsing, thanks to @hpaulj
|
||||||
|
|
||||||
|
|
||||||
0.1.8 / 2012-12-01
|
## [0.1.8] - 2012-12-01
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed parser parents (issue #19), thanks to @hpaulj
|
- Fixed parser parents (issue #19), thanks to @hpaulj
|
||||||
- Fixed negative argument parse (issue #20), thanks to @hpaulj
|
- Fixed negative argument parse (issue #20), thanks to @hpaulj
|
||||||
|
|
||||||
|
|
||||||
0.1.7 / 2012-10-14
|
## [0.1.7] - 2012-10-14
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed 'choices' argument parse (issue #16)
|
- Fixed 'choices' argument parse (issue #16)
|
||||||
- Fixed stderr output (issue #15)
|
- Fixed stderr output (issue #15)
|
||||||
|
|
||||||
|
|
||||||
0.1.6 / 2012-09-09
|
## [0.1.6] - 2012-09-09
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed check for conflict of options (thanks to @tomxtobin)
|
- Fixed check for conflict of options (thanks to @tomxtobin)
|
||||||
|
|
||||||
|
|
||||||
0.1.5 / 2012-09-03
|
## [0.1.5] - 2012-09-03
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Fix parser #setDefaults method (thanks to @tomxtobin)
|
- Fix parser #setDefaults method (thanks to @tomxtobin)
|
||||||
|
|
||||||
|
|
||||||
0.1.4 / 2012-07-30
|
## [0.1.4] - 2012-07-30
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed pseudo-argument support (thanks to @CGamesPlay)
|
- Fixed pseudo-argument support (thanks to @CGamesPlay)
|
||||||
- Fixed addHelp default (should be true), if not set (thanks to @benblank)
|
- Fixed addHelp default (should be true), if not set (thanks to @benblank)
|
||||||
|
|
||||||
|
|
||||||
0.1.3 / 2012-06-27
|
## [0.1.3] - 2012-06-27
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Fixed formatter api name: Formatter -> HelpFormatter
|
- Fixed formatter api name: Formatter -> HelpFormatter
|
||||||
|
|
||||||
|
|
||||||
0.1.2 / 2012-05-29
|
## [0.1.2] - 2012-05-29
|
||||||
------------------
|
### Fixed
|
||||||
|
|
||||||
- Added basic tests
|
|
||||||
- Removed excess whitespace in help
|
- Removed excess whitespace in help
|
||||||
- Fixed error reporting, when parcer with subcommands
|
- Fixed error reporting, when parcer with subcommands
|
||||||
called with empty arguments
|
called with empty arguments
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added basic tests
|
||||||
|
|
||||||
0.1.1 / 2012-05-23
|
|
||||||
------------------
|
|
||||||
|
|
||||||
|
## [0.1.1] - 2012-05-23
|
||||||
|
### Fixed
|
||||||
- Fixed line wrapping in help formatter
|
- Fixed line wrapping in help formatter
|
||||||
- Added better error reporting on invalid arguments
|
- Added better error reporting on invalid arguments
|
||||||
|
|
||||||
|
|
||||||
0.1.0 / 2012-05-16
|
## [0.1.0] - 2012-05-16
|
||||||
------------------
|
### Added
|
||||||
|
|
||||||
- First release.
|
- First release.
|
||||||
|
|
||||||
|
|
||||||
|
[2.0.1]: https://github.com/nodeca/argparse/compare/2.0.0...2.0.1
|
||||||
|
[2.0.0]: https://github.com/nodeca/argparse/compare/1.0.10...2.0.0
|
||||||
|
[1.0.10]: https://github.com/nodeca/argparse/compare/1.0.9...1.0.10
|
||||||
|
[1.0.9]: https://github.com/nodeca/argparse/compare/1.0.8...1.0.9
|
||||||
|
[1.0.8]: https://github.com/nodeca/argparse/compare/1.0.7...1.0.8
|
||||||
|
[1.0.7]: https://github.com/nodeca/argparse/compare/1.0.6...1.0.7
|
||||||
|
[1.0.6]: https://github.com/nodeca/argparse/compare/1.0.5...1.0.6
|
||||||
|
[1.0.5]: https://github.com/nodeca/argparse/compare/1.0.4...1.0.5
|
||||||
|
[1.0.4]: https://github.com/nodeca/argparse/compare/1.0.3...1.0.4
|
||||||
|
[1.0.3]: https://github.com/nodeca/argparse/compare/1.0.2...1.0.3
|
||||||
|
[1.0.2]: https://github.com/nodeca/argparse/compare/1.0.1...1.0.2
|
||||||
|
[1.0.1]: https://github.com/nodeca/argparse/compare/1.0.0...1.0.1
|
||||||
|
[1.0.0]: https://github.com/nodeca/argparse/compare/0.1.16...1.0.0
|
||||||
|
[0.1.16]: https://github.com/nodeca/argparse/compare/0.1.15...0.1.16
|
||||||
|
[0.1.15]: https://github.com/nodeca/argparse/compare/0.1.14...0.1.15
|
||||||
|
[0.1.14]: https://github.com/nodeca/argparse/compare/0.1.13...0.1.14
|
||||||
|
[0.1.13]: https://github.com/nodeca/argparse/compare/0.1.12...0.1.13
|
||||||
|
[0.1.12]: https://github.com/nodeca/argparse/compare/0.1.11...0.1.12
|
||||||
|
[0.1.11]: https://github.com/nodeca/argparse/compare/0.1.10...0.1.11
|
||||||
|
[0.1.10]: https://github.com/nodeca/argparse/compare/0.1.9...0.1.10
|
||||||
|
[0.1.9]: https://github.com/nodeca/argparse/compare/0.1.8...0.1.9
|
||||||
|
[0.1.8]: https://github.com/nodeca/argparse/compare/0.1.7...0.1.8
|
||||||
|
[0.1.7]: https://github.com/nodeca/argparse/compare/0.1.6...0.1.7
|
||||||
|
[0.1.6]: https://github.com/nodeca/argparse/compare/0.1.5...0.1.6
|
||||||
|
[0.1.5]: https://github.com/nodeca/argparse/compare/0.1.4...0.1.5
|
||||||
|
[0.1.4]: https://github.com/nodeca/argparse/compare/0.1.3...0.1.4
|
||||||
|
[0.1.3]: https://github.com/nodeca/argparse/compare/0.1.2...0.1.3
|
||||||
|
[0.1.2]: https://github.com/nodeca/argparse/compare/0.1.1...0.1.2
|
||||||
|
[0.1.1]: https://github.com/nodeca/argparse/compare/0.1.0...0.1.1
|
||||||
|
[0.1.0]: https://github.com/nodeca/argparse/releases/tag/0.1.0
|
||||||
|
|
|
@ -1,21 +1,254 @@
|
||||||
(The MIT License)
|
A. HISTORY OF THE SOFTWARE
|
||||||
|
==========================
|
||||||
|
|
||||||
Copyright (C) 2012 by Vitaly Puzrin
|
Python was created in the early 1990s by Guido van Rossum at Stichting
|
||||||
|
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
|
||||||
|
as a successor of a language called ABC. Guido remains Python's
|
||||||
|
principal author, although it includes many contributions from others.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
In 1995, Guido continued his work on Python at the Corporation for
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
|
||||||
in the Software without restriction, including without limitation the rights
|
in Reston, Virginia where he released several versions of the
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
software.
|
||||||
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
|
In May 2000, Guido and the Python core development team moved to
|
||||||
all copies or substantial portions of the Software.
|
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
|
||||||
|
year, the PythonLabs team moved to Digital Creations, which became
|
||||||
|
Zope Corporation. In 2001, the Python Software Foundation (PSF, see
|
||||||
|
https://www.python.org/psf/) was formed, a non-profit organization
|
||||||
|
created specifically to own Python-related Intellectual Property.
|
||||||
|
Zope Corporation was a sponsoring member of the PSF.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
All Python releases are Open Source (see http://www.opensource.org for
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
the Open Source Definition). Historically, most, but not all, Python
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
releases have also been GPL-compatible; the table below summarizes
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
the various releases.
|
||||||
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
|
Release Derived Year Owner GPL-
|
||||||
THE SOFTWARE.
|
from compatible? (1)
|
||||||
|
|
||||||
|
0.9.0 thru 1.2 1991-1995 CWI yes
|
||||||
|
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
|
||||||
|
1.6 1.5.2 2000 CNRI no
|
||||||
|
2.0 1.6 2000 BeOpen.com no
|
||||||
|
1.6.1 1.6 2001 CNRI yes (2)
|
||||||
|
2.1 2.0+1.6.1 2001 PSF no
|
||||||
|
2.0.1 2.0+1.6.1 2001 PSF yes
|
||||||
|
2.1.1 2.1+2.0.1 2001 PSF yes
|
||||||
|
2.1.2 2.1.1 2002 PSF yes
|
||||||
|
2.1.3 2.1.2 2002 PSF yes
|
||||||
|
2.2 and above 2.1.1 2001-now PSF yes
|
||||||
|
|
||||||
|
Footnotes:
|
||||||
|
|
||||||
|
(1) GPL-compatible doesn't mean that we're distributing Python under
|
||||||
|
the GPL. All Python licenses, unlike the GPL, let you distribute
|
||||||
|
a modified version without making your changes open source. The
|
||||||
|
GPL-compatible licenses make it possible to combine Python with
|
||||||
|
other software that is released under the GPL; the others don't.
|
||||||
|
|
||||||
|
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
|
||||||
|
because its license has a choice of law clause. According to
|
||||||
|
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
|
||||||
|
is "not incompatible" with the GPL.
|
||||||
|
|
||||||
|
Thanks to the many outside volunteers who have worked under Guido's
|
||||||
|
direction to make these releases possible.
|
||||||
|
|
||||||
|
|
||||||
|
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
|
||||||
|
===============================================================
|
||||||
|
|
||||||
|
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||||
|
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||||
|
otherwise using this software ("Python") in source or binary form and
|
||||||
|
its associated documentation.
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||||
|
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||||
|
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||||
|
distribute, and otherwise use Python alone or in any derivative version,
|
||||||
|
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||||
|
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
|
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation;
|
||||||
|
All Rights Reserved" are retained in Python alone or in any derivative version
|
||||||
|
prepared by Licensee.
|
||||||
|
|
||||||
|
3. In the event Licensee prepares a derivative work that is based on
|
||||||
|
or incorporates Python or any part thereof, and wants to make
|
||||||
|
the derivative work available to others as provided herein, then
|
||||||
|
Licensee hereby agrees to include in any such work a brief summary of
|
||||||
|
the changes made to Python.
|
||||||
|
|
||||||
|
4. PSF is making Python available to Licensee on an "AS IS"
|
||||||
|
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||||
|
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||||
|
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||||
|
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||||
|
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||||
|
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||||
|
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||||
|
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
6. This License Agreement will automatically terminate upon a material
|
||||||
|
breach of its terms and conditions.
|
||||||
|
|
||||||
|
7. Nothing in this License Agreement shall be deemed to create any
|
||||||
|
relationship of agency, partnership, or joint venture between PSF and
|
||||||
|
Licensee. This License Agreement does not grant permission to use PSF
|
||||||
|
trademarks or trade name in a trademark sense to endorse or promote
|
||||||
|
products or services of Licensee, or any third party.
|
||||||
|
|
||||||
|
8. By copying, installing or otherwise using Python, Licensee
|
||||||
|
agrees to be bound by the terms and conditions of this License
|
||||||
|
Agreement.
|
||||||
|
|
||||||
|
|
||||||
|
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
|
||||||
|
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
|
||||||
|
Individual or Organization ("Licensee") accessing and otherwise using
|
||||||
|
this software in source or binary form and its associated
|
||||||
|
documentation ("the Software").
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this BeOpen Python License
|
||||||
|
Agreement, BeOpen hereby grants Licensee a non-exclusive,
|
||||||
|
royalty-free, world-wide license to reproduce, analyze, test, perform
|
||||||
|
and/or display publicly, prepare derivative works, distribute, and
|
||||||
|
otherwise use the Software alone or in any derivative version,
|
||||||
|
provided, however, that the BeOpen Python License is retained in the
|
||||||
|
Software, alone or in any derivative version prepared by Licensee.
|
||||||
|
|
||||||
|
3. BeOpen is making the Software available to Licensee on an "AS IS"
|
||||||
|
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||||
|
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
|
||||||
|
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||||
|
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
|
||||||
|
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
|
||||||
|
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
|
||||||
|
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
|
||||||
|
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
5. This License Agreement will automatically terminate upon a material
|
||||||
|
breach of its terms and conditions.
|
||||||
|
|
||||||
|
6. This License Agreement shall be governed by and interpreted in all
|
||||||
|
respects by the law of the State of California, excluding conflict of
|
||||||
|
law provisions. Nothing in this License Agreement shall be deemed to
|
||||||
|
create any relationship of agency, partnership, or joint venture
|
||||||
|
between BeOpen and Licensee. This License Agreement does not grant
|
||||||
|
permission to use BeOpen trademarks or trade names in a trademark
|
||||||
|
sense to endorse or promote products or services of Licensee, or any
|
||||||
|
third party. As an exception, the "BeOpen Python" logos available at
|
||||||
|
http://www.pythonlabs.com/logos.html may be used according to the
|
||||||
|
permissions granted on that web page.
|
||||||
|
|
||||||
|
7. By copying, installing or otherwise using the software, Licensee
|
||||||
|
agrees to be bound by the terms and conditions of this License
|
||||||
|
Agreement.
|
||||||
|
|
||||||
|
|
||||||
|
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between the Corporation for National
|
||||||
|
Research Initiatives, having an office at 1895 Preston White Drive,
|
||||||
|
Reston, VA 20191 ("CNRI"), and the Individual or Organization
|
||||||
|
("Licensee") accessing and otherwise using Python 1.6.1 software in
|
||||||
|
source or binary form and its associated documentation.
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this License Agreement, CNRI
|
||||||
|
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
||||||
|
license to reproduce, analyze, test, perform and/or display publicly,
|
||||||
|
prepare derivative works, distribute, and otherwise use Python 1.6.1
|
||||||
|
alone or in any derivative version, provided, however, that CNRI's
|
||||||
|
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
|
||||||
|
1995-2001 Corporation for National Research Initiatives; All Rights
|
||||||
|
Reserved" are retained in Python 1.6.1 alone or in any derivative
|
||||||
|
version prepared by Licensee. Alternately, in lieu of CNRI's License
|
||||||
|
Agreement, Licensee may substitute the following text (omitting the
|
||||||
|
quotes): "Python 1.6.1 is made available subject to the terms and
|
||||||
|
conditions in CNRI's License Agreement. This Agreement together with
|
||||||
|
Python 1.6.1 may be located on the Internet using the following
|
||||||
|
unique, persistent identifier (known as a handle): 1895.22/1013. This
|
||||||
|
Agreement may also be obtained from a proxy server on the Internet
|
||||||
|
using the following URL: http://hdl.handle.net/1895.22/1013".
|
||||||
|
|
||||||
|
3. In the event Licensee prepares a derivative work that is based on
|
||||||
|
or incorporates Python 1.6.1 or any part thereof, and wants to make
|
||||||
|
the derivative work available to others as provided herein, then
|
||||||
|
Licensee hereby agrees to include in any such work a brief summary of
|
||||||
|
the changes made to Python 1.6.1.
|
||||||
|
|
||||||
|
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
|
||||||
|
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||||
|
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
|
||||||
|
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||||
|
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
|
||||||
|
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||||
|
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||||
|
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
|
||||||
|
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
6. This License Agreement will automatically terminate upon a material
|
||||||
|
breach of its terms and conditions.
|
||||||
|
|
||||||
|
7. This License Agreement shall be governed by the federal
|
||||||
|
intellectual property law of the United States, including without
|
||||||
|
limitation the federal copyright law, and, to the extent such
|
||||||
|
U.S. federal law does not apply, by the law of the Commonwealth of
|
||||||
|
Virginia, excluding Virginia's conflict of law provisions.
|
||||||
|
Notwithstanding the foregoing, with regard to derivative works based
|
||||||
|
on Python 1.6.1 that incorporate non-separable material that was
|
||||||
|
previously distributed under the GNU General Public License (GPL), the
|
||||||
|
law of the Commonwealth of Virginia shall govern this License
|
||||||
|
Agreement only as to issues arising under or with respect to
|
||||||
|
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
|
||||||
|
License Agreement shall be deemed to create any relationship of
|
||||||
|
agency, partnership, or joint venture between CNRI and Licensee. This
|
||||||
|
License Agreement does not grant permission to use CNRI trademarks or
|
||||||
|
trade name in a trademark sense to endorse or promote products or
|
||||||
|
services of Licensee, or any third party.
|
||||||
|
|
||||||
|
8. By clicking on the "ACCEPT" button where indicated, or by copying,
|
||||||
|
installing or otherwise using Python 1.6.1, Licensee agrees to be
|
||||||
|
bound by the terms and conditions of this License Agreement.
|
||||||
|
|
||||||
|
ACCEPT
|
||||||
|
|
||||||
|
|
||||||
|
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
|
||||||
|
The Netherlands. All rights reserved.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software and its
|
||||||
|
documentation for any purpose and without fee is hereby granted,
|
||||||
|
provided that the above copyright notice appear in all copies and that
|
||||||
|
both that copyright notice and this permission notice appear in
|
||||||
|
supporting documentation, and that the name of Stichting Mathematisch
|
||||||
|
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||||
|
distribution of the software without specific, written prior
|
||||||
|
permission.
|
||||||
|
|
||||||
|
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||||
|
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
||||||
|
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||||
|
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
|
@ -4,69 +4,54 @@ argparse
|
||||||
[![Build Status](https://secure.travis-ci.org/nodeca/argparse.svg?branch=master)](http://travis-ci.org/nodeca/argparse)
|
[![Build Status](https://secure.travis-ci.org/nodeca/argparse.svg?branch=master)](http://travis-ci.org/nodeca/argparse)
|
||||||
[![NPM version](https://img.shields.io/npm/v/argparse.svg)](https://www.npmjs.org/package/argparse)
|
[![NPM version](https://img.shields.io/npm/v/argparse.svg)](https://www.npmjs.org/package/argparse)
|
||||||
|
|
||||||
CLI arguments parser for node.js. Javascript port of python's
|
CLI arguments parser for node.js, with [sub-commands](https://docs.python.org/3.9/library/argparse.html#sub-commands) support. Port of python's [argparse](http://docs.python.org/dev/library/argparse.html) (version [3.9.0](https://github.com/python/cpython/blob/v3.9.0rc1/Lib/argparse.py)).
|
||||||
[argparse](http://docs.python.org/dev/library/argparse.html) module
|
|
||||||
(original version 3.2). That's a full port, except some very rare options,
|
|
||||||
recorded in issue tracker.
|
|
||||||
|
|
||||||
**NB. Difference with original.**
|
**Difference with original.**
|
||||||
|
|
||||||
- Method names changed to camelCase. See [generated docs](http://nodeca.github.com/argparse/).
|
- JS has no keyword arguments support.
|
||||||
- Use `defaultValue` instead of `default`.
|
- Pass options instead: `new ArgumentParser({ description: 'example', add_help: true })`.
|
||||||
- Use `argparse.Const.REMAINDER` instead of `argparse.REMAINDER`, and
|
- JS has no python's types `int`, `float`, ...
|
||||||
similarly for constant values `OPTIONAL`, `ZERO_OR_MORE`, and `ONE_OR_MORE`
|
- Use string-typed names: `.add_argument('-b', { type: 'int', help: 'help' })`.
|
||||||
(aliases for `nargs` values `'?'`, `'*'`, `'+'`, respectively), and
|
- `%r` format specifier uses `require('util').inspect()`.
|
||||||
`SUPPRESS`.
|
|
||||||
|
More details in [doc](./doc).
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
=======
|
-------
|
||||||
|
|
||||||
test.js file:
|
`test.js` file:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
const { ArgumentParser } = require('argparse');
|
||||||
var parser = new ArgumentParser({
|
const { version } = require('./package.json');
|
||||||
version: '0.0.1',
|
|
||||||
addHelp:true,
|
const parser = new ArgumentParser({
|
||||||
description: 'Argparse example'
|
description: 'Argparse example'
|
||||||
});
|
});
|
||||||
parser.addArgument(
|
|
||||||
[ '-f', '--foo' ],
|
parser.add_argument('-v', '--version', { action: 'version', version });
|
||||||
{
|
parser.add_argument('-f', '--foo', { help: 'foo bar' });
|
||||||
help: 'foo bar'
|
parser.add_argument('-b', '--bar', { help: 'bar foo' });
|
||||||
}
|
parser.add_argument('--baz', { help: 'baz bar' });
|
||||||
);
|
|
||||||
parser.addArgument(
|
console.dir(parser.parse_args());
|
||||||
[ '-b', '--bar' ],
|
|
||||||
{
|
|
||||||
help: 'bar foo'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
parser.addArgument(
|
|
||||||
'--baz',
|
|
||||||
{
|
|
||||||
help: 'baz bar'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
var args = parser.parseArgs();
|
|
||||||
console.dir(args);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Display help:
|
Display help:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ./test.js -h
|
$ ./test.js -h
|
||||||
usage: example.js [-h] [-v] [-f FOO] [-b BAR] [--baz BAZ]
|
usage: test.js [-h] [-v] [-f FOO] [-b BAR] [--baz BAZ]
|
||||||
|
|
||||||
Argparse example
|
Argparse example
|
||||||
|
|
||||||
Optional arguments:
|
optional arguments:
|
||||||
-h, --help Show this help message and exit.
|
-h, --help show this help message and exit
|
||||||
-v, --version Show program's version number and exit.
|
-v, --version show program's version number and exit
|
||||||
-f FOO, --foo FOO foo bar
|
-f FOO, --foo FOO foo bar
|
||||||
-b BAR, --bar BAR bar foo
|
-b BAR, --bar BAR bar foo
|
||||||
--baz BAZ baz bar
|
--baz BAZ baz bar
|
||||||
|
@ -79,179 +64,21 @@ $ ./test.js -f=3 --bar=4 --baz 5
|
||||||
{ foo: '3', bar: '4', baz: '5' }
|
{ foo: '3', bar: '4', baz: '5' }
|
||||||
```
|
```
|
||||||
|
|
||||||
More [examples](https://github.com/nodeca/argparse/tree/master/examples).
|
|
||||||
|
API docs
|
||||||
|
--------
|
||||||
|
|
||||||
|
Since this is a port with minimal divergence, there's no separate documentation.
|
||||||
|
Use original one instead, with notes about difference.
|
||||||
|
|
||||||
|
1. [Original doc](https://docs.python.org/3.9/library/argparse.html).
|
||||||
|
2. [Original tutorial](https://docs.python.org/3.9/howto/argparse.html).
|
||||||
|
3. [Difference with python](./doc).
|
||||||
|
|
||||||
|
|
||||||
ArgumentParser objects
|
argparse for enterprise
|
||||||
======================
|
-----------------------
|
||||||
|
|
||||||
```
|
|
||||||
new ArgumentParser({parameters hash});
|
|
||||||
```
|
|
||||||
|
|
||||||
Creates a new ArgumentParser object.
|
|
||||||
|
|
||||||
**Supported params:**
|
|
||||||
|
|
||||||
- ```description``` - Text to display before the argument help.
|
|
||||||
- ```epilog``` - Text to display after the argument help.
|
|
||||||
- ```addHelp``` - Add a -h/–help option to the parser. (default: true)
|
|
||||||
- ```argumentDefault``` - Set the global default value for arguments. (default: null)
|
|
||||||
- ```parents``` - A list of ArgumentParser objects whose arguments should also be included.
|
|
||||||
- ```prefixChars``` - The set of characters that prefix optional arguments. (default: ‘-‘)
|
|
||||||
- ```formatterClass``` - A class for customizing the help output.
|
|
||||||
- ```prog``` - The name of the program (default: `path.basename(process.argv[1])`)
|
|
||||||
- ```usage``` - The string describing the program usage (default: generated)
|
|
||||||
- ```conflictHandler``` - Usually unnecessary, defines strategy for resolving conflicting optionals.
|
|
||||||
|
|
||||||
**Not supported yet**
|
|
||||||
|
|
||||||
- ```fromfilePrefixChars``` - The set of characters that prefix files from which additional arguments should be read.
|
|
||||||
|
|
||||||
|
|
||||||
Details in [original ArgumentParser guide](http://docs.python.org/dev/library/argparse.html#argumentparser-objects)
|
|
||||||
|
|
||||||
|
|
||||||
addArgument() method
|
|
||||||
====================
|
|
||||||
|
|
||||||
```
|
|
||||||
ArgumentParser.addArgument(name or flag or [name] or [flags...], {options})
|
|
||||||
```
|
|
||||||
|
|
||||||
Defines how a single command-line argument should be parsed.
|
|
||||||
|
|
||||||
- ```name or flag or [name] or [flags...]``` - Either a positional name
|
|
||||||
(e.g., `'foo'`), a single option (e.g., `'-f'` or `'--foo'`), an array
|
|
||||||
of a single positional name (e.g., `['foo']`), or an array of options
|
|
||||||
(e.g., `['-f', '--foo']`).
|
|
||||||
|
|
||||||
Options:
|
|
||||||
|
|
||||||
- ```action``` - The basic type of action to be taken when this argument is encountered at the command line.
|
|
||||||
- ```nargs```- The number of command-line arguments that should be consumed.
|
|
||||||
- ```constant``` - A constant value required by some action and nargs selections.
|
|
||||||
- ```defaultValue``` - The value produced if the argument is absent from the command line.
|
|
||||||
- ```type``` - The type to which the command-line argument should be converted.
|
|
||||||
- ```choices``` - A container of the allowable values for the argument.
|
|
||||||
- ```required``` - Whether or not the command-line option may be omitted (optionals only).
|
|
||||||
- ```help``` - A brief description of what the argument does.
|
|
||||||
- ```metavar``` - A name for the argument in usage messages.
|
|
||||||
- ```dest``` - The name of the attribute to be added to the object returned by parseArgs().
|
|
||||||
|
|
||||||
Details in [original add_argument guide](http://docs.python.org/dev/library/argparse.html#the-add-argument-method)
|
|
||||||
|
|
||||||
|
|
||||||
Action (some details)
|
|
||||||
================
|
|
||||||
|
|
||||||
ArgumentParser objects associate command-line arguments with actions.
|
|
||||||
These actions can do just about anything with the command-line arguments associated
|
|
||||||
with them, though most actions simply add an attribute to the object returned by
|
|
||||||
parseArgs(). The action keyword argument specifies how the command-line arguments
|
|
||||||
should be handled. The supported actions are:
|
|
||||||
|
|
||||||
- ```store``` - Just stores the argument’s value. This is the default action.
|
|
||||||
- ```storeConst``` - Stores value, specified by the const keyword argument.
|
|
||||||
(Note that the const keyword argument defaults to the rather unhelpful None.)
|
|
||||||
The 'storeConst' action is most commonly used with optional arguments, that
|
|
||||||
specify some sort of flag.
|
|
||||||
- ```storeTrue``` and ```storeFalse``` - Stores values True and False
|
|
||||||
respectively. These are special cases of 'storeConst'.
|
|
||||||
- ```append``` - Stores a list, and appends each argument value to the list.
|
|
||||||
This is useful to allow an option to be specified multiple times.
|
|
||||||
- ```appendConst``` - Stores a list, and appends value, specified by the
|
|
||||||
const keyword argument to the list. (Note, that the const keyword argument defaults
|
|
||||||
is None.) The 'appendConst' action is typically used when multiple arguments need
|
|
||||||
to store constants to the same list.
|
|
||||||
- ```count``` - Counts the number of times a keyword argument occurs. For example,
|
|
||||||
used for increasing verbosity levels.
|
|
||||||
- ```help``` - Prints a complete help message for all the options in the current
|
|
||||||
parser and then exits. By default a help action is automatically added to the parser.
|
|
||||||
See ArgumentParser for details of how the output is created.
|
|
||||||
- ```version``` - Prints version information and exit. Expects a `version=`
|
|
||||||
keyword argument in the addArgument() call.
|
|
||||||
|
|
||||||
Details in [original action guide](http://docs.python.org/dev/library/argparse.html#action)
|
|
||||||
|
|
||||||
|
|
||||||
Sub-commands
|
|
||||||
============
|
|
||||||
|
|
||||||
ArgumentParser.addSubparsers()
|
|
||||||
|
|
||||||
Many programs split their functionality into a number of sub-commands, for
|
|
||||||
example, the svn program can invoke sub-commands like `svn checkout`, `svn update`,
|
|
||||||
and `svn commit`. Splitting up functionality this way can be a particularly good
|
|
||||||
idea when a program performs several different functions which require different
|
|
||||||
kinds of command-line arguments. `ArgumentParser` supports creation of such
|
|
||||||
sub-commands with `addSubparsers()` method. The `addSubparsers()` method is
|
|
||||||
normally called with no arguments and returns an special action object.
|
|
||||||
This object has a single method `addParser()`, which takes a command name and
|
|
||||||
any `ArgumentParser` constructor arguments, and returns an `ArgumentParser` object
|
|
||||||
that can be modified as usual.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
sub_commands.js
|
|
||||||
```javascript
|
|
||||||
#!/usr/bin/env node
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
|
||||||
var parser = new ArgumentParser({
|
|
||||||
version: '0.0.1',
|
|
||||||
addHelp:true,
|
|
||||||
description: 'Argparse examples: sub-commands',
|
|
||||||
});
|
|
||||||
|
|
||||||
var subparsers = parser.addSubparsers({
|
|
||||||
title:'subcommands',
|
|
||||||
dest:"subcommand_name"
|
|
||||||
});
|
|
||||||
|
|
||||||
var bar = subparsers.addParser('c1', {addHelp:true});
|
|
||||||
bar.addArgument(
|
|
||||||
[ '-f', '--foo' ],
|
|
||||||
{
|
|
||||||
action: 'store',
|
|
||||||
help: 'foo3 bar3'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
var bar = subparsers.addParser(
|
|
||||||
'c2',
|
|
||||||
{aliases:['co'], addHelp:true}
|
|
||||||
);
|
|
||||||
bar.addArgument(
|
|
||||||
[ '-b', '--bar' ],
|
|
||||||
{
|
|
||||||
action: 'store',
|
|
||||||
type: 'int',
|
|
||||||
help: 'foo3 bar3'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
var args = parser.parseArgs();
|
|
||||||
console.dir(args);
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Details in [original sub-commands guide](http://docs.python.org/dev/library/argparse.html#sub-commands)
|
|
||||||
|
|
||||||
|
|
||||||
Contributors
|
|
||||||
============
|
|
||||||
|
|
||||||
- [Eugene Shkuropat](https://github.com/shkuropat)
|
|
||||||
- [Paul Jacobson](https://github.com/hpaulj)
|
|
||||||
|
|
||||||
[others](https://github.com/nodeca/argparse/graphs/contributors)
|
|
||||||
|
|
||||||
License
|
|
||||||
=======
|
|
||||||
|
|
||||||
Copyright (c) 2012 [Vitaly Puzrin](https://github.com/puzrin).
|
|
||||||
Released under the MIT license. See
|
|
||||||
[LICENSE](https://github.com/nodeca/argparse/blob/master/LICENSE) for details.
|
|
||||||
|
|
||||||
|
Available as part of the Tidelift Subscription
|
||||||
|
|
||||||
|
The maintainers of argparse and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-argparse?utm_source=npm-argparse&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
module.exports = require('./lib/argparse');
|
|
|
@ -1,146 +0,0 @@
|
||||||
/**
|
|
||||||
* class Action
|
|
||||||
*
|
|
||||||
* Base class for all actions
|
|
||||||
* Do not call in your code, use this class only for inherits your own action
|
|
||||||
*
|
|
||||||
* Information about how to convert command line strings to Javascript objects.
|
|
||||||
* Action objects are used by an ArgumentParser to represent the information
|
|
||||||
* needed to parse a single argument from one or more strings from the command
|
|
||||||
* line. The keyword arguments to the Action constructor are also all attributes
|
|
||||||
* of Action instances.
|
|
||||||
*
|
|
||||||
* ##### Allowed keywords:
|
|
||||||
*
|
|
||||||
* - `store`
|
|
||||||
* - `storeConstant`
|
|
||||||
* - `storeTrue`
|
|
||||||
* - `storeFalse`
|
|
||||||
* - `append`
|
|
||||||
* - `appendConstant`
|
|
||||||
* - `count`
|
|
||||||
* - `help`
|
|
||||||
* - `version`
|
|
||||||
*
|
|
||||||
* Information about action options see [[Action.new]]
|
|
||||||
*
|
|
||||||
* See also [original guide](http://docs.python.org/dev/library/argparse.html#action)
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
var c = require('./const');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* new Action(options)
|
|
||||||
*
|
|
||||||
* Base class for all actions. Used only for inherits
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* ##### Options:
|
|
||||||
*
|
|
||||||
* - `optionStrings` A list of command-line option strings for the action.
|
|
||||||
* - `dest` Attribute to hold the created object(s)
|
|
||||||
* - `nargs` The number of command-line arguments that should be consumed.
|
|
||||||
* By default, one argument will be consumed and a single value will be
|
|
||||||
* produced.
|
|
||||||
* - `constant` Default value for an action with no value.
|
|
||||||
* - `defaultValue` The value to be produced if the option is not specified.
|
|
||||||
* - `type` Cast to 'string'|'int'|'float'|'complex'|function (string). If
|
|
||||||
* None, 'string'.
|
|
||||||
* - `choices` The choices available.
|
|
||||||
* - `required` True if the action must always be specified at the command
|
|
||||||
* line.
|
|
||||||
* - `help` The help describing the argument.
|
|
||||||
* - `metavar` The name to be used for the option's argument with the help
|
|
||||||
* string. If None, the 'dest' value will be used as the name.
|
|
||||||
*
|
|
||||||
* ##### nargs supported values:
|
|
||||||
*
|
|
||||||
* - `N` (an integer) consumes N arguments (and produces a list)
|
|
||||||
* - `?` consumes zero or one arguments
|
|
||||||
* - `*` consumes zero or more arguments (and produces a list)
|
|
||||||
* - `+` consumes one or more arguments (and produces a list)
|
|
||||||
*
|
|
||||||
* Note: that the difference between the default and nargs=1 is that with the
|
|
||||||
* default, a single value will be produced, while with nargs=1, a list
|
|
||||||
* containing a single value will be produced.
|
|
||||||
**/
|
|
||||||
var Action = module.exports = function Action(options) {
|
|
||||||
options = options || {};
|
|
||||||
this.optionStrings = options.optionStrings || [];
|
|
||||||
this.dest = options.dest;
|
|
||||||
this.nargs = typeof options.nargs !== 'undefined' ? options.nargs : null;
|
|
||||||
this.constant = typeof options.constant !== 'undefined' ? options.constant : null;
|
|
||||||
this.defaultValue = options.defaultValue;
|
|
||||||
this.type = typeof options.type !== 'undefined' ? options.type : null;
|
|
||||||
this.choices = typeof options.choices !== 'undefined' ? options.choices : null;
|
|
||||||
this.required = typeof options.required !== 'undefined' ? options.required : false;
|
|
||||||
this.help = typeof options.help !== 'undefined' ? options.help : null;
|
|
||||||
this.metavar = typeof options.metavar !== 'undefined' ? options.metavar : null;
|
|
||||||
|
|
||||||
if (!(this.optionStrings instanceof Array)) {
|
|
||||||
throw new Error('optionStrings should be an array');
|
|
||||||
}
|
|
||||||
if (typeof this.required !== 'undefined' && typeof this.required !== 'boolean') {
|
|
||||||
throw new Error('required should be a boolean');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action#getName -> String
|
|
||||||
*
|
|
||||||
* Tells action name
|
|
||||||
**/
|
|
||||||
Action.prototype.getName = function () {
|
|
||||||
if (this.optionStrings.length > 0) {
|
|
||||||
return this.optionStrings.join('/');
|
|
||||||
} else if (this.metavar !== null && this.metavar !== c.SUPPRESS) {
|
|
||||||
return this.metavar;
|
|
||||||
} else if (typeof this.dest !== 'undefined' && this.dest !== c.SUPPRESS) {
|
|
||||||
return this.dest;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action#isOptional -> Boolean
|
|
||||||
*
|
|
||||||
* Return true if optional
|
|
||||||
**/
|
|
||||||
Action.prototype.isOptional = function () {
|
|
||||||
return !this.isPositional();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action#isPositional -> Boolean
|
|
||||||
*
|
|
||||||
* Return true if positional
|
|
||||||
**/
|
|
||||||
Action.prototype.isPositional = function () {
|
|
||||||
return (this.optionStrings.length === 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action#call(parser, namespace, values, optionString) -> Void
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Call the action. Should be implemented in inherited classes
|
|
||||||
*
|
|
||||||
* ##### Example
|
|
||||||
*
|
|
||||||
* ActionCount.prototype.call = function (parser, namespace, values, optionString) {
|
|
||||||
* namespace.set(this.dest, (namespace[this.dest] || 0) + 1);
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
Action.prototype.call = function () {
|
|
||||||
throw new Error('.call() not defined');// Not Implemented error
|
|
||||||
};
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionAppend
|
|
||||||
*
|
|
||||||
* This action stores a list, and appends each argument value to the list.
|
|
||||||
* This is useful to allow an option to be specified multiple times.
|
|
||||||
* This class inherided from [[Action]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var Action = require('../action');
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
var c = require('../const');
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionAppend(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
* Note: options.nargs should be optional for constants
|
|
||||||
* and more then zero for other
|
|
||||||
**/
|
|
||||||
var ActionAppend = module.exports = function ActionAppend(options) {
|
|
||||||
options = options || {};
|
|
||||||
if (this.nargs <= 0) {
|
|
||||||
throw new Error('nargs for append actions must be > 0; if arg ' +
|
|
||||||
'strings are not supplying the value to append, ' +
|
|
||||||
'the append const action may be more appropriate');
|
|
||||||
}
|
|
||||||
if (!!this.constant && this.nargs !== c.OPTIONAL) {
|
|
||||||
throw new Error('nargs must be OPTIONAL to supply const');
|
|
||||||
}
|
|
||||||
Action.call(this, options);
|
|
||||||
};
|
|
||||||
util.inherits(ActionAppend, Action);
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionAppend#call(parser, namespace, values, optionString) -> Void
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Call the action. Save result in namespace object
|
|
||||||
**/
|
|
||||||
ActionAppend.prototype.call = function (parser, namespace, values) {
|
|
||||||
var items = (namespace[this.dest] || []).slice();
|
|
||||||
items.push(values);
|
|
||||||
namespace.set(this.dest, items);
|
|
||||||
};
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionAppendConstant
|
|
||||||
*
|
|
||||||
* This stores a list, and appends the value specified by
|
|
||||||
* the const keyword argument to the list.
|
|
||||||
* (Note that the const keyword argument defaults to null.)
|
|
||||||
* The 'appendConst' action is typically useful when multiple
|
|
||||||
* arguments need to store constants to the same list.
|
|
||||||
*
|
|
||||||
* This class inherited from [[Action]]
|
|
||||||
**/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var Action = require('../../action');
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionAppendConstant(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
var ActionAppendConstant = module.exports = function ActionAppendConstant(options) {
|
|
||||||
options = options || {};
|
|
||||||
options.nargs = 0;
|
|
||||||
if (typeof options.constant === 'undefined') {
|
|
||||||
throw new Error('constant option is required for appendAction');
|
|
||||||
}
|
|
||||||
Action.call(this, options);
|
|
||||||
};
|
|
||||||
util.inherits(ActionAppendConstant, Action);
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionAppendConstant#call(parser, namespace, values, optionString) -> Void
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Call the action. Save result in namespace object
|
|
||||||
**/
|
|
||||||
ActionAppendConstant.prototype.call = function (parser, namespace) {
|
|
||||||
var items = [].concat(namespace[this.dest] || []);
|
|
||||||
items.push(this.constant);
|
|
||||||
namespace.set(this.dest, items);
|
|
||||||
};
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionCount
|
|
||||||
*
|
|
||||||
* This counts the number of times a keyword argument occurs.
|
|
||||||
* For example, this is useful for increasing verbosity levels
|
|
||||||
*
|
|
||||||
* This class inherided from [[Action]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var Action = require('../action');
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionCount(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
var ActionCount = module.exports = function ActionCount(options) {
|
|
||||||
options = options || {};
|
|
||||||
options.nargs = 0;
|
|
||||||
|
|
||||||
Action.call(this, options);
|
|
||||||
};
|
|
||||||
util.inherits(ActionCount, Action);
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionCount#call(parser, namespace, values, optionString) -> Void
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Call the action. Save result in namespace object
|
|
||||||
**/
|
|
||||||
ActionCount.prototype.call = function (parser, namespace) {
|
|
||||||
namespace.set(this.dest, (namespace[this.dest] || 0) + 1);
|
|
||||||
};
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionHelp
|
|
||||||
*
|
|
||||||
* Support action for printing help
|
|
||||||
* This class inherided from [[Action]]
|
|
||||||
**/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var Action = require('../action');
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
var c = require('../const');
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionHelp(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
var ActionHelp = module.exports = function ActionHelp(options) {
|
|
||||||
options = options || {};
|
|
||||||
if (options.defaultValue !== null) {
|
|
||||||
options.defaultValue = options.defaultValue;
|
|
||||||
} else {
|
|
||||||
options.defaultValue = c.SUPPRESS;
|
|
||||||
}
|
|
||||||
options.dest = (options.dest !== null ? options.dest : c.SUPPRESS);
|
|
||||||
options.nargs = 0;
|
|
||||||
Action.call(this, options);
|
|
||||||
|
|
||||||
};
|
|
||||||
util.inherits(ActionHelp, Action);
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionHelp#call(parser, namespace, values, optionString)
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Print help and exit
|
|
||||||
**/
|
|
||||||
ActionHelp.prototype.call = function (parser) {
|
|
||||||
parser.printHelp();
|
|
||||||
parser.exit();
|
|
||||||
};
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionStore
|
|
||||||
*
|
|
||||||
* This action just stores the argument’s value. This is the default action.
|
|
||||||
*
|
|
||||||
* This class inherited from [[Action]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var Action = require('../action');
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
var c = require('../const');
|
|
||||||
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionStore(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
var ActionStore = module.exports = function ActionStore(options) {
|
|
||||||
options = options || {};
|
|
||||||
if (this.nargs <= 0) {
|
|
||||||
throw new Error('nargs for store actions must be > 0; if you ' +
|
|
||||||
'have nothing to store, actions such as store ' +
|
|
||||||
'true or store const may be more appropriate');
|
|
||||||
|
|
||||||
}
|
|
||||||
if (typeof this.constant !== 'undefined' && this.nargs !== c.OPTIONAL) {
|
|
||||||
throw new Error('nargs must be OPTIONAL to supply const');
|
|
||||||
}
|
|
||||||
Action.call(this, options);
|
|
||||||
};
|
|
||||||
util.inherits(ActionStore, Action);
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionStore#call(parser, namespace, values, optionString) -> Void
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Call the action. Save result in namespace object
|
|
||||||
**/
|
|
||||||
ActionStore.prototype.call = function (parser, namespace, values) {
|
|
||||||
namespace.set(this.dest, values);
|
|
||||||
};
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionStoreConstant
|
|
||||||
*
|
|
||||||
* This action stores the value specified by the const keyword argument.
|
|
||||||
* (Note that the const keyword argument defaults to the rather unhelpful null.)
|
|
||||||
* The 'store_const' action is most commonly used with optional
|
|
||||||
* arguments that specify some sort of flag.
|
|
||||||
*
|
|
||||||
* This class inherited from [[Action]]
|
|
||||||
**/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var Action = require('../../action');
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionStoreConstant(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
var ActionStoreConstant = module.exports = function ActionStoreConstant(options) {
|
|
||||||
options = options || {};
|
|
||||||
options.nargs = 0;
|
|
||||||
if (typeof options.constant === 'undefined') {
|
|
||||||
throw new Error('constant option is required for storeAction');
|
|
||||||
}
|
|
||||||
Action.call(this, options);
|
|
||||||
};
|
|
||||||
util.inherits(ActionStoreConstant, Action);
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionStoreConstant#call(parser, namespace, values, optionString) -> Void
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Call the action. Save result in namespace object
|
|
||||||
**/
|
|
||||||
ActionStoreConstant.prototype.call = function (parser, namespace) {
|
|
||||||
namespace.set(this.dest, this.constant);
|
|
||||||
};
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionStoreFalse
|
|
||||||
*
|
|
||||||
* This action store the values False respectively.
|
|
||||||
* This is special cases of 'storeConst'
|
|
||||||
*
|
|
||||||
* This class inherited from [[Action]]
|
|
||||||
**/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var ActionStoreConstant = require('./constant');
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionStoreFalse(options)
|
|
||||||
* - options (object): hash of options see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
var ActionStoreFalse = module.exports = function ActionStoreFalse(options) {
|
|
||||||
options = options || {};
|
|
||||||
options.constant = false;
|
|
||||||
options.defaultValue = options.defaultValue !== null ? options.defaultValue : true;
|
|
||||||
ActionStoreConstant.call(this, options);
|
|
||||||
};
|
|
||||||
util.inherits(ActionStoreFalse, ActionStoreConstant);
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionStoreTrue
|
|
||||||
*
|
|
||||||
* This action store the values True respectively.
|
|
||||||
* This isspecial cases of 'storeConst'
|
|
||||||
*
|
|
||||||
* This class inherited from [[Action]]
|
|
||||||
**/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var ActionStoreConstant = require('./constant');
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionStoreTrue(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
var ActionStoreTrue = module.exports = function ActionStoreTrue(options) {
|
|
||||||
options = options || {};
|
|
||||||
options.constant = true;
|
|
||||||
options.defaultValue = options.defaultValue !== null ? options.defaultValue : false;
|
|
||||||
ActionStoreConstant.call(this, options);
|
|
||||||
};
|
|
||||||
util.inherits(ActionStoreTrue, ActionStoreConstant);
|
|
|
@ -1,149 +0,0 @@
|
||||||
/** internal
|
|
||||||
* class ActionSubparsers
|
|
||||||
*
|
|
||||||
* Support the creation of such sub-commands with the addSubparsers()
|
|
||||||
*
|
|
||||||
* This class inherited from [[Action]]
|
|
||||||
**/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
var format = require('util').format;
|
|
||||||
|
|
||||||
|
|
||||||
var Action = require('../action');
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
var c = require('../const');
|
|
||||||
|
|
||||||
// Errors
|
|
||||||
var argumentErrorHelper = require('../argument/error');
|
|
||||||
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ChoicesPseudoAction(name, help)
|
|
||||||
*
|
|
||||||
* Create pseudo action for correct help text
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
function ChoicesPseudoAction(name, help) {
|
|
||||||
var options = {
|
|
||||||
optionStrings: [],
|
|
||||||
dest: name,
|
|
||||||
help: help
|
|
||||||
};
|
|
||||||
|
|
||||||
Action.call(this, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
util.inherits(ChoicesPseudoAction, Action);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* new ActionSubparsers(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
function ActionSubparsers(options) {
|
|
||||||
options = options || {};
|
|
||||||
options.dest = options.dest || c.SUPPRESS;
|
|
||||||
options.nargs = c.PARSER;
|
|
||||||
|
|
||||||
this.debug = (options.debug === true);
|
|
||||||
|
|
||||||
this._progPrefix = options.prog;
|
|
||||||
this._parserClass = options.parserClass;
|
|
||||||
this._nameParserMap = {};
|
|
||||||
this._choicesActions = [];
|
|
||||||
|
|
||||||
options.choices = this._nameParserMap;
|
|
||||||
Action.call(this, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
util.inherits(ActionSubparsers, Action);
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionSubparsers#addParser(name, options) -> ArgumentParser
|
|
||||||
* - name (string): sub-command name
|
|
||||||
* - options (object): see [[ArgumentParser.new]]
|
|
||||||
*
|
|
||||||
* Note:
|
|
||||||
* addParser supports an additional aliases option,
|
|
||||||
* which allows multiple strings to refer to the same subparser.
|
|
||||||
* This example, like svn, aliases co as a shorthand for checkout
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
ActionSubparsers.prototype.addParser = function (name, options) {
|
|
||||||
var parser;
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
options.debug = (this.debug === true);
|
|
||||||
|
|
||||||
// set program from the existing prefix
|
|
||||||
if (!options.prog) {
|
|
||||||
options.prog = this._progPrefix + ' ' + name;
|
|
||||||
}
|
|
||||||
|
|
||||||
var aliases = options.aliases || [];
|
|
||||||
|
|
||||||
// create a pseudo-action to hold the choice help
|
|
||||||
if (!!options.help || typeof options.help === 'string') {
|
|
||||||
var help = options.help;
|
|
||||||
delete options.help;
|
|
||||||
|
|
||||||
var choiceAction = new ChoicesPseudoAction(name, help);
|
|
||||||
this._choicesActions.push(choiceAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the parser and add it to the map
|
|
||||||
parser = new this._parserClass(options);
|
|
||||||
this._nameParserMap[name] = parser;
|
|
||||||
|
|
||||||
// make parser available under aliases also
|
|
||||||
aliases.forEach(function (alias) {
|
|
||||||
self._nameParserMap[alias] = parser;
|
|
||||||
});
|
|
||||||
|
|
||||||
return parser;
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionSubparsers.prototype._getSubactions = function () {
|
|
||||||
return this._choicesActions;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionSubparsers#call(parser, namespace, values, optionString) -> Void
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Call the action. Parse input aguments
|
|
||||||
**/
|
|
||||||
ActionSubparsers.prototype.call = function (parser, namespace, values) {
|
|
||||||
var parserName = values[0];
|
|
||||||
var argStrings = values.slice(1);
|
|
||||||
|
|
||||||
// set the parser name if requested
|
|
||||||
if (this.dest !== c.SUPPRESS) {
|
|
||||||
namespace[this.dest] = parserName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// select the parser
|
|
||||||
if (this._nameParserMap[parserName]) {
|
|
||||||
parser = this._nameParserMap[parserName];
|
|
||||||
} else {
|
|
||||||
throw argumentErrorHelper(format(
|
|
||||||
'Unknown parser "%s" (choices: [%s]).',
|
|
||||||
parserName,
|
|
||||||
Object.keys(this._nameParserMap).join(', ')
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse all the remaining options into the namespace
|
|
||||||
parser.parseArgs(argStrings, namespace);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = ActionSubparsers;
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*:nodoc:*
|
|
||||||
* class ActionVersion
|
|
||||||
*
|
|
||||||
* Support action for printing program version
|
|
||||||
* This class inherited from [[Action]]
|
|
||||||
**/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var util = require('util');
|
|
||||||
|
|
||||||
var Action = require('../action');
|
|
||||||
|
|
||||||
//
|
|
||||||
// Constants
|
|
||||||
//
|
|
||||||
var c = require('../const');
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* new ActionVersion(options)
|
|
||||||
* - options (object): options hash see [[Action.new]]
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
var ActionVersion = module.exports = function ActionVersion(options) {
|
|
||||||
options = options || {};
|
|
||||||
options.defaultValue = (options.defaultValue ? options.defaultValue : c.SUPPRESS);
|
|
||||||
options.dest = (options.dest || c.SUPPRESS);
|
|
||||||
options.nargs = 0;
|
|
||||||
this.version = options.version;
|
|
||||||
Action.call(this, options);
|
|
||||||
};
|
|
||||||
util.inherits(ActionVersion, Action);
|
|
||||||
|
|
||||||
/*:nodoc:*
|
|
||||||
* ActionVersion#call(parser, namespace, values, optionString) -> Void
|
|
||||||
* - parser (ArgumentParser): current parser
|
|
||||||
* - namespace (Namespace): namespace for output data
|
|
||||||
* - values (Array): parsed values
|
|
||||||
* - optionString (Array): input option string(not parsed)
|
|
||||||
*
|
|
||||||
* Print version and exit
|
|
||||||
**/
|
|
||||||
ActionVersion.prototype.call = function (parser) {
|
|
||||||
var version = this.version || parser.version;
|
|
||||||
var formatter = parser._getFormatter();
|
|
||||||
formatter.addText(version);
|
|
||||||
parser.exit(0, formatter.formatHelp());
|
|
||||||
};
|
|
|
@ -1,482 +0,0 @@
|
||||||
/** internal
|
|
||||||
* class ActionContainer
|
|
||||||
*
|
|
||||||
* Action container. Parent for [[ArgumentParser]] and [[ArgumentGroup]]
|
|
||||||
**/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var format = require('util').format;
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
var c = require('./const');
|
|
||||||
|
|
||||||
var $$ = require('./utils');
|
|
||||||
|
|
||||||
//Actions
|
|
||||||
var ActionHelp = require('./action/help');
|
|
||||||
var ActionAppend = require('./action/append');
|
|
||||||
var ActionAppendConstant = require('./action/append/constant');
|
|
||||||
var ActionCount = require('./action/count');
|
|
||||||
var ActionStore = require('./action/store');
|
|
||||||
var ActionStoreConstant = require('./action/store/constant');
|
|
||||||
var ActionStoreTrue = require('./action/store/true');
|
|
||||||
var ActionStoreFalse = require('./action/store/false');
|
|
||||||
var ActionVersion = require('./action/version');
|
|
||||||
var ActionSubparsers = require('./action/subparsers');
|
|
||||||
|
|
||||||
// Errors
|
|
||||||
var argumentErrorHelper = require('./argument/error');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* new ActionContainer(options)
|
|
||||||
*
|
|
||||||
* Action container. Parent for [[ArgumentParser]] and [[ArgumentGroup]]
|
|
||||||
*
|
|
||||||
* ##### Options:
|
|
||||||
*
|
|
||||||
* - `description` -- A description of what the program does
|
|
||||||
* - `prefixChars` -- Characters that prefix optional arguments
|
|
||||||
* - `argumentDefault` -- The default value for all arguments
|
|
||||||
* - `conflictHandler` -- The conflict handler to use for duplicate arguments
|
|
||||||
**/
|
|
||||||
var ActionContainer = module.exports = function ActionContainer(options) {
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
this.description = options.description;
|
|
||||||
this.argumentDefault = options.argumentDefault;
|
|
||||||
this.prefixChars = options.prefixChars || '';
|
|
||||||
this.conflictHandler = options.conflictHandler;
|
|
||||||
|
|
||||||
// set up registries
|
|
||||||
this._registries = {};
|
|
||||||
|
|
||||||
// register actions
|
|
||||||
this.register('action', null, ActionStore);
|
|
||||||
this.register('action', 'store', ActionStore);
|
|
||||||
this.register('action', 'storeConst', ActionStoreConstant);
|
|
||||||
this.register('action', 'storeTrue', ActionStoreTrue);
|
|
||||||
this.register('action', 'storeFalse', ActionStoreFalse);
|
|
||||||
this.register('action', 'append', ActionAppend);
|
|
||||||
this.register('action', 'appendConst', ActionAppendConstant);
|
|
||||||
this.register('action', 'count', ActionCount);
|
|
||||||
this.register('action', 'help', ActionHelp);
|
|
||||||
this.register('action', 'version', ActionVersion);
|
|
||||||
this.register('action', 'parsers', ActionSubparsers);
|
|
||||||
|
|
||||||
// raise an exception if the conflict handler is invalid
|
|
||||||
this._getHandler();
|
|
||||||
|
|
||||||
// action storage
|
|
||||||
this._actions = [];
|
|
||||||
this._optionStringActions = {};
|
|
||||||
|
|
||||||
// groups
|
|
||||||
this._actionGroups = [];
|
|
||||||
this._mutuallyExclusiveGroups = [];
|
|
||||||
|
|
||||||
// defaults storage
|
|
||||||
this._defaults = {};
|
|
||||||
|
|
||||||
// determines whether an "option" looks like a negative number
|
|
||||||
// -1, -1.5 -5e+4
|
|
||||||
this._regexpNegativeNumber = new RegExp('^[-]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$');
|
|
||||||
|
|
||||||
// whether or not there are any optionals that look like negative
|
|
||||||
// numbers -- uses a list so it can be shared and edited
|
|
||||||
this._hasNegativeNumberOptionals = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
// Groups must be required, then ActionContainer already defined
|
|
||||||
var ArgumentGroup = require('./argument/group');
|
|
||||||
var MutuallyExclusiveGroup = require('./argument/exclusive');
|
|
||||||
|
|
||||||
//
|
|
||||||
// Registration methods
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ActionContainer#register(registryName, value, object) -> Void
|
|
||||||
* - registryName (String) : object type action|type
|
|
||||||
* - value (string) : keyword
|
|
||||||
* - object (Object|Function) : handler
|
|
||||||
*
|
|
||||||
* Register handlers
|
|
||||||
**/
|
|
||||||
ActionContainer.prototype.register = function (registryName, value, object) {
|
|
||||||
this._registries[registryName] = this._registries[registryName] || {};
|
|
||||||
this._registries[registryName][value] = object;
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._registryGet = function (registryName, value, defaultValue) {
|
|
||||||
if (arguments.length < 3) {
|
|
||||||
defaultValue = null;
|
|
||||||
}
|
|
||||||
return this._registries[registryName][value] || defaultValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Namespace default accessor methods
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ActionContainer#setDefaults(options) -> Void
|
|
||||||
* - options (object):hash of options see [[Action.new]]
|
|
||||||
*
|
|
||||||
* Set defaults
|
|
||||||
**/
|
|
||||||
ActionContainer.prototype.setDefaults = function (options) {
|
|
||||||
options = options || {};
|
|
||||||
for (var property in options) {
|
|
||||||
if ($$.has(options, property)) {
|
|
||||||
this._defaults[property] = options[property];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if these defaults match any existing arguments, replace the previous
|
|
||||||
// default on the object with the new one
|
|
||||||
this._actions.forEach(function (action) {
|
|
||||||
if ($$.has(options, action.dest)) {
|
|
||||||
action.defaultValue = options[action.dest];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ActionContainer#getDefault(dest) -> Mixed
|
|
||||||
* - dest (string): action destination
|
|
||||||
*
|
|
||||||
* Return action default value
|
|
||||||
**/
|
|
||||||
ActionContainer.prototype.getDefault = function (dest) {
|
|
||||||
var result = $$.has(this._defaults, dest) ? this._defaults[dest] : null;
|
|
||||||
|
|
||||||
this._actions.forEach(function (action) {
|
|
||||||
if (action.dest === dest && $$.has(action, 'defaultValue')) {
|
|
||||||
result = action.defaultValue;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
//
|
|
||||||
// Adding argument actions
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ActionContainer#addArgument(args, options) -> Object
|
|
||||||
* - args (String|Array): argument key, or array of argument keys
|
|
||||||
* - options (Object): action objects see [[Action.new]]
|
|
||||||
*
|
|
||||||
* #### Examples
|
|
||||||
* - addArgument([ '-f', '--foo' ], { action: 'store', defaultValue: 1, ... })
|
|
||||||
* - addArgument([ 'bar' ], { action: 'store', nargs: 1, ... })
|
|
||||||
* - addArgument('--baz', { action: 'store', nargs: 1, ... })
|
|
||||||
**/
|
|
||||||
ActionContainer.prototype.addArgument = function (args, options) {
|
|
||||||
args = args;
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
if (typeof args === 'string') {
|
|
||||||
args = [ args ];
|
|
||||||
}
|
|
||||||
if (!Array.isArray(args)) {
|
|
||||||
throw new TypeError('addArgument first argument should be a string or an array');
|
|
||||||
}
|
|
||||||
if (typeof options !== 'object' || Array.isArray(options)) {
|
|
||||||
throw new TypeError('addArgument second argument should be a hash');
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no positional args are supplied or only one is supplied and
|
|
||||||
// it doesn't look like an option string, parse a positional argument
|
|
||||||
if (!args || args.length === 1 && this.prefixChars.indexOf(args[0][0]) < 0) {
|
|
||||||
if (args && !!options.dest) {
|
|
||||||
throw new Error('dest supplied twice for positional argument');
|
|
||||||
}
|
|
||||||
options = this._getPositional(args, options);
|
|
||||||
|
|
||||||
// otherwise, we're adding an optional argument
|
|
||||||
} else {
|
|
||||||
options = this._getOptional(args, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no default was supplied, use the parser-level default
|
|
||||||
if (typeof options.defaultValue === 'undefined') {
|
|
||||||
var dest = options.dest;
|
|
||||||
if ($$.has(this._defaults, dest)) {
|
|
||||||
options.defaultValue = this._defaults[dest];
|
|
||||||
} else if (typeof this.argumentDefault !== 'undefined') {
|
|
||||||
options.defaultValue = this.argumentDefault;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the action object, and add it to the parser
|
|
||||||
var ActionClass = this._popActionClass(options);
|
|
||||||
if (typeof ActionClass !== 'function') {
|
|
||||||
throw new Error(format('Unknown action "%s".', ActionClass));
|
|
||||||
}
|
|
||||||
var action = new ActionClass(options);
|
|
||||||
|
|
||||||
// throw an error if the action type is not callable
|
|
||||||
var typeFunction = this._registryGet('type', action.type, action.type);
|
|
||||||
if (typeof typeFunction !== 'function') {
|
|
||||||
throw new Error(format('"%s" is not callable', typeFunction));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._addAction(action);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ActionContainer#addArgumentGroup(options) -> ArgumentGroup
|
|
||||||
* - options (Object): hash of options see [[ArgumentGroup.new]]
|
|
||||||
*
|
|
||||||
* Create new arguments groups
|
|
||||||
**/
|
|
||||||
ActionContainer.prototype.addArgumentGroup = function (options) {
|
|
||||||
var group = new ArgumentGroup(this, options);
|
|
||||||
this._actionGroups.push(group);
|
|
||||||
return group;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ActionContainer#addMutuallyExclusiveGroup(options) -> ArgumentGroup
|
|
||||||
* - options (Object): {required: false}
|
|
||||||
*
|
|
||||||
* Create new mutual exclusive groups
|
|
||||||
**/
|
|
||||||
ActionContainer.prototype.addMutuallyExclusiveGroup = function (options) {
|
|
||||||
var group = new MutuallyExclusiveGroup(this, options);
|
|
||||||
this._mutuallyExclusiveGroups.push(group);
|
|
||||||
return group;
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._addAction = function (action) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
// resolve any conflicts
|
|
||||||
this._checkConflict(action);
|
|
||||||
|
|
||||||
// add to actions list
|
|
||||||
this._actions.push(action);
|
|
||||||
action.container = this;
|
|
||||||
|
|
||||||
// index the action by any option strings it has
|
|
||||||
action.optionStrings.forEach(function (optionString) {
|
|
||||||
self._optionStringActions[optionString] = action;
|
|
||||||
});
|
|
||||||
|
|
||||||
// set the flag if any option strings look like negative numbers
|
|
||||||
action.optionStrings.forEach(function (optionString) {
|
|
||||||
if (optionString.match(self._regexpNegativeNumber)) {
|
|
||||||
if (!self._hasNegativeNumberOptionals.some(Boolean)) {
|
|
||||||
self._hasNegativeNumberOptionals.push(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// return the created action
|
|
||||||
return action;
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._removeAction = function (action) {
|
|
||||||
var actionIndex = this._actions.indexOf(action);
|
|
||||||
if (actionIndex >= 0) {
|
|
||||||
this._actions.splice(actionIndex, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._addContainerActions = function (container) {
|
|
||||||
// collect groups by titles
|
|
||||||
var titleGroupMap = {};
|
|
||||||
this._actionGroups.forEach(function (group) {
|
|
||||||
if (titleGroupMap[group.title]) {
|
|
||||||
throw new Error(format('Cannot merge actions - two groups are named "%s".', group.title));
|
|
||||||
}
|
|
||||||
titleGroupMap[group.title] = group;
|
|
||||||
});
|
|
||||||
|
|
||||||
// map each action to its group
|
|
||||||
var groupMap = {};
|
|
||||||
function actionHash(action) {
|
|
||||||
// unique (hopefully?) string suitable as dictionary key
|
|
||||||
return action.getName();
|
|
||||||
}
|
|
||||||
container._actionGroups.forEach(function (group) {
|
|
||||||
// if a group with the title exists, use that, otherwise
|
|
||||||
// create a new group matching the container's group
|
|
||||||
if (!titleGroupMap[group.title]) {
|
|
||||||
titleGroupMap[group.title] = this.addArgumentGroup({
|
|
||||||
title: group.title,
|
|
||||||
description: group.description
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// map the actions to their new group
|
|
||||||
group._groupActions.forEach(function (action) {
|
|
||||||
groupMap[actionHash(action)] = titleGroupMap[group.title];
|
|
||||||
});
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
// add container's mutually exclusive groups
|
|
||||||
// NOTE: if add_mutually_exclusive_group ever gains title= and
|
|
||||||
// description= then this code will need to be expanded as above
|
|
||||||
var mutexGroup;
|
|
||||||
container._mutuallyExclusiveGroups.forEach(function (group) {
|
|
||||||
mutexGroup = this.addMutuallyExclusiveGroup({
|
|
||||||
required: group.required
|
|
||||||
});
|
|
||||||
// map the actions to their new mutex group
|
|
||||||
group._groupActions.forEach(function (action) {
|
|
||||||
groupMap[actionHash(action)] = mutexGroup;
|
|
||||||
});
|
|
||||||
}, this); // forEach takes a 'this' argument
|
|
||||||
|
|
||||||
// add all actions to this container or their group
|
|
||||||
container._actions.forEach(function (action) {
|
|
||||||
var key = actionHash(action);
|
|
||||||
if (groupMap[key]) {
|
|
||||||
groupMap[key]._addAction(action);
|
|
||||||
} else {
|
|
||||||
this._addAction(action);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._getPositional = function (dest, options) {
|
|
||||||
if (Array.isArray(dest)) {
|
|
||||||
dest = dest[0];
|
|
||||||
}
|
|
||||||
// make sure required is not specified
|
|
||||||
if (options.required) {
|
|
||||||
throw new Error('"required" is an invalid argument for positionals.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark positional arguments as required if at least one is
|
|
||||||
// always required
|
|
||||||
if (options.nargs !== c.OPTIONAL && options.nargs !== c.ZERO_OR_MORE) {
|
|
||||||
options.required = true;
|
|
||||||
}
|
|
||||||
if (options.nargs === c.ZERO_OR_MORE && typeof options.defaultValue === 'undefined') {
|
|
||||||
options.required = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the keyword arguments with no option strings
|
|
||||||
options.dest = dest;
|
|
||||||
options.optionStrings = [];
|
|
||||||
return options;
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._getOptional = function (args, options) {
|
|
||||||
var prefixChars = this.prefixChars;
|
|
||||||
var optionStrings = [];
|
|
||||||
var optionStringsLong = [];
|
|
||||||
|
|
||||||
// determine short and long option strings
|
|
||||||
args.forEach(function (optionString) {
|
|
||||||
// error on strings that don't start with an appropriate prefix
|
|
||||||
if (prefixChars.indexOf(optionString[0]) < 0) {
|
|
||||||
throw new Error(format('Invalid option string "%s": must start with a "%s".',
|
|
||||||
optionString,
|
|
||||||
prefixChars
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// strings starting with two prefix characters are long options
|
|
||||||
optionStrings.push(optionString);
|
|
||||||
if (optionString.length > 1 && prefixChars.indexOf(optionString[1]) >= 0) {
|
|
||||||
optionStringsLong.push(optionString);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// infer dest, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
|
|
||||||
var dest = options.dest || null;
|
|
||||||
delete options.dest;
|
|
||||||
|
|
||||||
if (!dest) {
|
|
||||||
var optionStringDest = optionStringsLong.length ? optionStringsLong[0] : optionStrings[0];
|
|
||||||
dest = $$.trimChars(optionStringDest, this.prefixChars);
|
|
||||||
|
|
||||||
if (dest.length === 0) {
|
|
||||||
throw new Error(
|
|
||||||
format('dest= is required for options like "%s"', optionStrings.join(', '))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
dest = dest.replace(/-/g, '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the updated keyword arguments
|
|
||||||
options.dest = dest;
|
|
||||||
options.optionStrings = optionStrings;
|
|
||||||
|
|
||||||
return options;
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._popActionClass = function (options, defaultValue) {
|
|
||||||
defaultValue = defaultValue || null;
|
|
||||||
|
|
||||||
var action = (options.action || defaultValue);
|
|
||||||
delete options.action;
|
|
||||||
|
|
||||||
var actionClass = this._registryGet('action', action, action);
|
|
||||||
return actionClass;
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._getHandler = function () {
|
|
||||||
var handlerString = this.conflictHandler;
|
|
||||||
var handlerFuncName = '_handleConflict' + $$.capitalize(handlerString);
|
|
||||||
var func = this[handlerFuncName];
|
|
||||||
if (typeof func === 'undefined') {
|
|
||||||
var msg = 'invalid conflict resolution value: ' + handlerString;
|
|
||||||
throw new Error(msg);
|
|
||||||
} else {
|
|
||||||
return func;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._checkConflict = function (action) {
|
|
||||||
var optionStringActions = this._optionStringActions;
|
|
||||||
var conflictOptionals = [];
|
|
||||||
|
|
||||||
// find all options that conflict with this option
|
|
||||||
// collect pairs, the string, and an existing action that it conflicts with
|
|
||||||
action.optionStrings.forEach(function (optionString) {
|
|
||||||
var conflOptional = optionStringActions[optionString];
|
|
||||||
if (typeof conflOptional !== 'undefined') {
|
|
||||||
conflictOptionals.push([ optionString, conflOptional ]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (conflictOptionals.length > 0) {
|
|
||||||
var conflictHandler = this._getHandler();
|
|
||||||
conflictHandler.call(this, action, conflictOptionals);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._handleConflictError = function (action, conflOptionals) {
|
|
||||||
var conflicts = conflOptionals.map(function (pair) { return pair[0]; });
|
|
||||||
conflicts = conflicts.join(', ');
|
|
||||||
throw argumentErrorHelper(
|
|
||||||
action,
|
|
||||||
format('Conflicting option string(s): %s', conflicts)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionContainer.prototype._handleConflictResolve = function (action, conflOptionals) {
|
|
||||||
// remove all conflicting options
|
|
||||||
var self = this;
|
|
||||||
conflOptionals.forEach(function (pair) {
|
|
||||||
var optionString = pair[0];
|
|
||||||
var conflictingAction = pair[1];
|
|
||||||
// remove the conflicting option string
|
|
||||||
var i = conflictingAction.optionStrings.indexOf(optionString);
|
|
||||||
if (i >= 0) {
|
|
||||||
conflictingAction.optionStrings.splice(i, 1);
|
|
||||||
}
|
|
||||||
delete self._optionStringActions[optionString];
|
|
||||||
// if the option now has no option string, remove it from the
|
|
||||||
// container holding it
|
|
||||||
if (conflictingAction.optionStrings.length === 0) {
|
|
||||||
conflictingAction.container._removeAction(conflictingAction);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue