Compare commits

..

6 Commits

Author SHA1 Message Date
RameshT 33e22a421c Your commit message 2024-08-21 12:04:30 +05:30
RameshT 4cbb962963 Your commit message 2024-08-13 15:22:21 +05:30
RameshT 3416f8a575 Your commit message 2024-08-13 15:16:26 +05:30
RameshT 1ff80f75e0 Your commit message 2024-08-13 15:10:34 +05:30
RameshT d37c197e5c Your commit message 2024-08-13 11:20:14 +05:30
RameshT 88a90e3aa3 Your commit message 2024-08-12 14:22:09 +05:30
1813 changed files with 75371 additions and 103268 deletions

View File

@ -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"
} }
} }

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

1
.husky/.gitignore vendored
View File

@ -0,0 +1 @@
_

View File

@ -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."

View File

@ -24,15 +24,18 @@ 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
if [ $ESLINT_ERRORS -ne 0 ]; then if [ $ESLINT_ERRORS -ne 0 ]; then

File diff suppressed because one or more lines are too long

49
.php-cs-fixer.php Normal file
View File

@ -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);

16
.prettier.rc.json Normal file
View File

@ -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"
}

View File

@ -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

View File

@ -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"
}

View File

@ -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);
}
});

View File

@ -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);
}
}

View File

@ -15,7 +15,9 @@ 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 // Retrieve form title from the forms table using form_id
$form_title = 'Untitled Form'; // Default title $form_title = 'Untitled Form'; // Default title

View File

@ -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]);
}
}

View File

@ -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);
}
}

86
assets/css/dummy.css Normal file
View File

@ -0,0 +1,86 @@
/* Basic Reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Container Styling */
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* Header Styling */
header {
background-color: #f8f9fa;
padding: 20px;
text-align: center;
border-bottom: 1px solid #dee2e6;
}
header h1 {
font-size: 2rem;
color: #343a40;
}
/* Navigation Styling */
nav {
margin-top: 10px;
}
nav ul {
list-style-type: none;
display: flex;
justify-content: center;
}
nav ul li {
margin: 0 15px;
}
nav ul li a {
text-decoration: none;
color: #007bff;
font-size: 1rem;
}
nav ul li a:hover {
text-decoration: underline;
}
/* Main Content Styling */
main {
padding: 20px;
}
article {
margin-bottom: 20px;
}
article h2 {
font-size: 1.5rem;
color: #495057;
}
article p {
line-height: 1.6;
color: #212529;
}
/* Footer Styling */
footer {
background-color: #f8f9fa;
padding: 10px;
text-align: center;
border-top: 1px solid #dee2e6;
}
footer p {
font-size: 0.875rem;
color: #6c757d;
}

View File

@ -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;

View File

@ -1,50 +1,56 @@
// src/index.js /**
* A simple function to calculate the sum of two numbers.
*
* @param {number} a - The first number.
* @param {number} b - The second number.
* @returns {number} The sum of the two numbers.
*/
// Example function to add two numbers
function add(a, b) { function add(a, b) {
return a + b return a + b;
} }
// Example usage of the add function /**
* Logs a greeting message to the console.
const result = add(5, 10) *
console.log('The result is:', result) * @param {string} name - The name to greet.
*/
// Example object with properties function greet(name) {
const person = { console.log(`Hello, ${name}!`);
name: 'John Doe',
age: 30,
greet: function () {
console.log(
`Hello, my name is ${this.name} and I am ${this.age} years old.`
)
},
} }
// Call the greet method // Example usage
person.greet() const result = add(5, 10);
// Example of an arrow function console.log(`The result is: ${result}`);
const multiply = (x, y) => x * y
console.log('The product is:', multiply(4, 5)) greet("Alice"); // Replaced 'Alice' with "Alice"
// Example of a variable declared with let /**
let count = 0 * An example class demonstrating basic TypeScript features in JavaScript.
for (let i = 0; i < 5; i++) { */
count += i class Person {
} /**
console.log('The count is:', count) * Creates an instance of Person.
*
* @param {string} name - The name of the person.
* @param {number} age - The age of the person.
*/
constructor(name, age) {
this.name = name;
this.age = age;
}
// Example of a variable declared with const /**
const message = 'This is a constant message.' * Introduces the person.
console.log(message) *
* @returns {string} A greeting message.
// Example of a function with default parameters */
function greet(name = 'Guest') { introduce() {
console.log(`Welcome, ${name}!`) return `Hi, I'm ${this.name} and I'm ${this.age} years old.`;
}
} }
// Call the function with and without arguments // Example usage of the Person class
greet('Alice') const person = new Person("Bob", 25); // Replaced 'Bob' with "Bob"
greet() console.log(person.introduce());

View File

@ -1,12 +1,14 @@
$(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="form-section" data-type="">
<div class="header-row"> <div class="header-row">
<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>
<option value="paragraph">Paragraph</option> <option value="paragraph">Paragraph</option>
@ -15,119 +17,56 @@ $(document).ready(function () {
<option value="dropdown">Dropdown</option> <option value="dropdown">Dropdown</option>
</select> </select>
<label class="toggle-switch"> <label class="toggle-switch">
<input type="checkbox" class="required-toggle"> <input type="checkbox" class="required-toggle" />
<span class="slider"></span> <span class="slider"></span>
</label> </label>
<span class="delete-section-icon"><i class="fas fa-trash-alt"></i></span> <span class="delete-section-icon"><i class="fas fa-trash-alt"></i></span>
</div> </div>
<div class="options-container"></div> <div class="options-container"></div>
<button class="btn btn-secondary add-option-btn" style="display: none;">Add Option</button></div> <button class="btn btn-secondary add-option-btn" style="display: none;">
`; $('#form-container').append(sectionHtml); Add Option
}); </button>
</div>
// Add option button functionality ` $('#form-container').append(sectionHtml) }) // Add option button functionality
$(document).on('click', '.add-option-btn', function () { $(document).on('click', '.add-option-btn', function () { var optionHtml = `
var optionHtml = ` <div class="option">
<div class="option"> <input type="text" class="form-control option-label" placeholder="Option" />
<input type="text" class="form-control option-label" placeholder="Option">
<span class="delete-option-icon">&times;</span> <span class="delete-option-icon">&times;</span>
</div> </div>
`; ` $(this).siblings('.options-container').append(optionHtml) }) // Delete option
$(this).siblings('.options-container').append(optionHtml); functionality $(document).on('click', '.delete-option-icon', function () {
}); $(this).parent().remove() }) // Delete section functionality
$(document).on('click', '.delete-section-icon', function () {
// Delete option functionality $(this).closest('.form-section').remove() }) // Show/Hide "Add Option" button
$(document).on('click', '.delete-option-icon', function () { based on question type $(document) .on('change', '.custom-select', function () {
$(this).parent().remove(); var type = $(this).val() var $section = $(this).closest('.form-section') if (
}); type === 'multiple-choice' || type === 'checkboxes' || type === 'dropdown' ) {
$section.find('.add-option-btn').show() } else {
// Delete section functionality $section.find('.add-option-btn').hide() } }) .trigger('change') // Trigger
$(document).on('click', '.delete-section-icon', function () { change to apply to existing sections // Submit button functionality
$(this).closest('.form-section').remove(); $('#submit-btn').on('click', function () { var formData = collectFormData()
}); formData['form_id'] = /* eslint-disable */ <? php echo $form['id']; ?>; /*
eslint-enable */ let validation = validateFormData(formData) if
// Show/Hide "Add Option" button based on question type (!validation.isValid) { alert(validation.message) return } $.ajax({ url:
$(document).on('change', '.custom-select', function () { base_url + 'Form_controller/update_form', type: 'POST', data: { formData:
var type = $(this).val(); formData }, dataType: 'JSON', success: function (response) { if (response.status
var $section = $(this).closest('.form-section'); === 'success') { alert('Form updated successfully!') window.location.href =
if (type === 'multiple-choice' || type === 'checkboxes' || type === 'dropdown') { base_url + 'Form_controller/index_forms_draft' } else { alert(response.message)
$section.find('.add-option-btn').show(); } }, error: function (error) { alert('Error updating form!') console.log(error)
} else { }, }) }) // Collect form data function function collectFormData() { var formData
$section.find('.add-option-btn').hide(); = { title: $('#form-title').val(), description: $('#form-description').val(),
} questions: [], } $('.form-section').each(function () { var questionData = { id:
}).trigger('change'); // Trigger change to apply to existing sections $(this).data('index'), text: $(this).find('.untitled-question').val(), type:
$(this).find('.custom-select').val(), required:
// Submit button functionality $(this).find('.required-toggle').is(':checked') ? 1 : 0, // Correctly capture
$('#submit-btn').on('click', function () { the required value options: [], } $(this) .find('.option-label') .each(function
var formData = collectFormData(); () { questionData.options.push($(this).val()) })
formData['form_id'] = <? php echo $form['id']; ?>; formData.questions.push(questionData) }) return formData } function
validateFormData(formData) { for (let question of formData.questions) { if
let validation = validateFormData(formData); (!question.text.trim()) { return { isValid: false, message: 'All questions must
if (!validation.isValid) { have text.' } } if ( (question.type === 'multiple-choice' || question.type ===
alert(validation.message); 'checkboxes' || question.type === 'dropdown') && question.options.length === 0 )
return; { 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
$.ajax({ text.' } } } } return { isValid: true } } })
url: base_url + 'Form_controller/update_form',
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 };
}
});

View File

@ -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">&times;</span> <span class="delete-option-icon">&times;</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">&times;</span> <span class="delete-option-icon">&times;</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();
}) });

View File

@ -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"> <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">&times;</span> <span class="delete-option-icon">&times;</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">&times;</span> <span class="delete-option-icon">&times;</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>',
) );
} }
}) });
}) });

3
bootstrap.php Normal file
View File

@ -0,0 +1,3 @@
<?php
require_once __DIR__ . '/custom_sniffs/Sniffs/NamespaceMatchesDirectorySniff.php';
echo "Bootstrap file loaded.\n";

View File

@ -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/"
} }
} }
}

516
composer.lock generated
View File

@ -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"

View File

@ -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
node_modules/.bin/esparse generated vendored
View File

@ -1 +0,0 @@
../esprima/bin/esparse.js

1
node_modules/.bin/esvalidate generated vendored
View File

@ -1 +0,0 @@
../esprima/bin/esvalidate.js

1157
node_modules/.package-lock.json generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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.

View File

@ -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: {

View File

@ -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;

View File

@ -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: {

View File

@ -1,12 +0,0 @@
/**
* @fileoverview Stub eslint:all config
* @author Nicholas C. Zakas
*/
"use strict";
module.exports = {
settings: {
"eslint:all": true
}
};

View File

@ -1,12 +0,0 @@
/**
* @fileoverview Stub eslint:recommended config
* @author Nicholas C. Zakas
*/
"use strict";
module.exports = {
settings: {
"eslint:recommended": true
}
};

View File

@ -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 };

View File

@ -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 };

View File

@ -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 = { /**
ConfigArray,
/**
* Get the used extracted configs. * Get the used extracted configs.
* CLIEngine will use this method to collect used deprecated rules. * CLIEngine will use this method to collect used deprecated rules.
* @param {ConfigArray} instance The config array object to get. * @param {ConfigArray} instance The config array object to get.
* @returns {ExtractedConfig[]} The used extracted configs. * @returns {ExtractedConfig[]} The used extracted configs.
* @private * @private
*/ */
getUsedExtractedConfigs(instance) { function getUsedExtractedConfigs(instance) {
const { cache } = internalSlotsMap.get(instance); const { cache } = internalSlotsMap.get(instance);
return Array.from(cache.values()); return Array.from(cache.values());
} }
};
module.exports = exportObject;
export {
ConfigArray,
getUsedExtractedConfigs
};

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -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,

View File

@ -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 };

View File

@ -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 };

View File

@ -2,36 +2,33 @@
* @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 = {
Legacy: {
ConfigArray, ConfigArray,
createConfigArrayFactoryContext, createConfigArrayFactoryContext,
CascadingConfigArrayFactory, CascadingConfigArrayFactory,
@ -41,13 +38,18 @@ module.exports = {
IgnorePattern, IgnorePattern,
OverrideTester, OverrideTester,
getUsedExtractedConfigs, getUsedExtractedConfigs,
environments,
// shared // shared
ConfigOps, ConfigOps,
ConfigValidator, ConfigValidator,
ModuleResolver, ModuleResolver,
naming naming
}, };
export {
Legacy,
FlatCompat FlatCompat

View File

@ -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,

View File

@ -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,9 +19,7 @@ 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 * Normalizes the severity value of a rule's configuration to a number
* @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally * @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), * received from the user. A valid config value is either 0, 1, 2, the string "off" (treated the same as 0),
@ -30,7 +27,7 @@ module.exports = {
* whose first element is one of the above values. Strings are matched case-insensitively. * 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. * @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.
*/ */
getRuleSeverity(ruleConfig) { function getRuleSeverity(ruleConfig) {
const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
if (severityValue === 0 || severityValue === 1 || severityValue === 2) { if (severityValue === 0 || severityValue === 1 || severityValue === 2) {
@ -42,16 +39,16 @@ module.exports = {
} }
return 0; return 0;
}, }
/** /**
* Converts old-style severity settings (0, 1, 2) into new-style * Converts old-style severity settings (0, 1, 2) into new-style
* severity settings (off, warn, error) for all rules. Assumption is that severity * severity settings (off, warn, error) for all rules. Assumption is that severity
* values have already been validated as correct. * values have already been validated as correct.
* @param {Object} config The config object to normalize. * @param {Object} config The config object to normalize.
* @returns {void} * @returns {void}
*/ */
normalizeToStrings(config) { function normalizeToStrings(config) {
if (config.rules) { if (config.rules) {
Object.keys(config.rules).forEach(ruleId => { Object.keys(config.rules).forEach(ruleId => {
@ -64,48 +61,48 @@ module.exports = {
} }
}); });
} }
}, }
/** /**
* Determines if the severity for the given rule configuration represents an error. * Determines if the severity for the given rule configuration represents an error.
* @param {int|string|Array} ruleConfig The configuration for an individual rule. * @param {int|string|Array} ruleConfig The configuration for an individual rule.
* @returns {boolean} True if the rule represents an error, false if not. * @returns {boolean} True if the rule represents an error, false if not.
*/ */
isErrorSeverity(ruleConfig) { function isErrorSeverity(ruleConfig) {
return module.exports.getRuleSeverity(ruleConfig) === 2; return getRuleSeverity(ruleConfig) === 2;
}, }
/** /**
* Checks whether a given config has valid severity or not. * Checks whether a given config has valid severity or not.
* @param {number|string|Array} ruleConfig The configuration for an individual rule. * @param {number|string|Array} ruleConfig The configuration for an individual rule.
* @returns {boolean} `true` if the configuration has valid severity. * @returns {boolean} `true` if the configuration has valid severity.
*/ */
isValidSeverity(ruleConfig) { function isValidSeverity(ruleConfig) {
let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig; let severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
if (typeof severity === "string") { if (typeof severity === "string") {
severity = severity.toLowerCase(); severity = severity.toLowerCase();
} }
return VALID_SEVERITIES.indexOf(severity) !== -1; return VALID_SEVERITIES.indexOf(severity) !== -1;
}, }
/** /**
* Checks whether every rule of a given config has valid severity or not. * Checks whether every rule of a given config has valid severity or not.
* @param {Object} config The configuration for rules. * @param {Object} config The configuration for rules.
* @returns {boolean} `true` if the configuration has valid severity. * @returns {boolean} `true` if the configuration has valid severity.
*/ */
isEverySeverityValid(config) { function isEverySeverityValid(config) {
return Object.keys(config).every(ruleId => this.isValidSeverity(config[ruleId])); return Object.keys(config).every(ruleId => isValidSeverity(config[ruleId]));
}, }
/** /**
* Normalizes a value for a global in a config * Normalizes a value for a global in a config
* @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in * @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
* a global directive comment * a global directive comment
* @returns {("readable"|"writeable"|"off")} The value normalized as a string * @returns {("readable"|"writeable"|"off")} The value normalized as a string
* @throws Error if global value is invalid * @throws Error if global value is invalid
*/ */
normalizeConfigGlobal(configuredValue) { function normalizeConfigGlobal(configuredValue) {
switch (configuredValue) { switch (configuredValue) {
case "off": case "off":
return "off"; return "off";
@ -126,5 +123,13 @@ module.exports = {
default: default:
throw new Error(`'${configuredValue}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`); throw new Error(`'${configuredValue}' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')`);
} }
} }
export {
getRuleSeverity,
normalizeToStrings,
isErrorSeverity,
isValidSeverity,
isEverySeverityValid,
normalizeConfigGlobal
}; };

View File

@ -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 {
} }
} }
}; }

View File

@ -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
}; };

View File

@ -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

View File

@ -3,27 +3,22 @@
* @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 * 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} 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 * @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. * 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` * @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
*/ */
resolve(moduleName, relativeToPath) { function resolve(moduleName, relativeToPath) {
try { try {
return createRequire(relativeToPath).resolve(moduleName); return createRequire(relativeToPath).resolve(moduleName);
} catch (error) { } catch (error) {
@ -40,5 +35,8 @@ module.exports = {
} }
throw error; throw error;
} }
} }
export {
resolve
}; };

View File

@ -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 */

View File

@ -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"
} }
} }

View File

@ -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": {},

View File

@ -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

View File

@ -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.filter(pattern => {
return isString(pattern) && !pattern.startsWith('!');
}));
} else if (isString(filePattern) && !filePattern.startsWith('!')) {
result.push(filePattern); 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
cache.set(filePath, finalConfig);
return finalConfig;
}
// filePath isn't automatically ignored, so try to construct 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)) { if (pathMatches(filePath, this.basePath, config)) {
debug(`Matching config found for ${filePath}`); debug(`Matching config found for ${filePath}`);
matchingConfigs.push(config); matchingConfigIndices.push(index);
} else { matchFound = true;
debug(`No matching config found for ${filePath}`); return;
}
} }
finalConfig = matchingConfigs.reduce((result, config) => { });
return this[ConfigArraySymbol.schema].merge(result, config);
// 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;

View File

@ -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"
} }
} }

View File

@ -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"
]
}
};

View File

@ -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

View File

@ -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 }}

View File

@ -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)

View File

@ -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"
}, },

View File

@ -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);
} }
} }

View File

@ -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
});
});
});
});

View File

@ -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"
}
});
});
});
});

View File

@ -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/);
});
});
});

290
node_modules/acorn/CHANGELOG.md generated vendored
View File

@ -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

2
node_modules/acorn/LICENSE generated vendored
View File

@ -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

77
node_modules/acorn/README.md generated vendored
View File

@ -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
(when `sourceType` is not `"module"`).
- **allowAwaitOutsideFunction**: By default, `await` expressions can - **allowAwaitOutsideFunction**: If `false`, `await` expressions can
only appear inside `async` functions. Setting this option to only appear inside `async` functions. Defaults to `true` in modules
`true` allows to have top-level `await` expressions. They are for `ecmaVersion` 2022 and later, `false` for lower versions.
still not allowed in non-`async` functions, though. 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 - **allowSuperOutsideMethod**: By default, `super` outside a method
code starts with the characters `#!` (as in a shellscript), the raises an error. Set this to `true` to accept such code.
first line will be treated as a comment.
- **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

4
node_modules/acorn/bin/acorn generated vendored
View File

@ -1,4 +1,4 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict'; "use strict"
require('../dist/bin.js'); require("../dist/bin.js")

841
node_modules/acorn/dist/acorn.d.ts generated vendored
View File

@ -1,94 +1,766 @@
export as namespace acorn export interface Node {
export = acorn start: number
end: number
type: string
range?: [number, number]
loc?: SourceLocation | null
}
declare namespace acorn { export interface SourceLocation {
function parse(input: string, options?: Options): Node source?: string | null
start: Position
end: Position
}
function parseExpressionAt(input: string, pos?: number, options?: Options): Node export interface Position {
/** 1-based */
line: number
/** 0-based */
column: number
}
function tokenizer(input: string, options?: Options): { export interface Identifier extends Node {
type: "Identifier"
name: string
}
export interface Literal extends Node {
type: "Literal"
value?: string | boolean | null | number | RegExp | bigint
raw?: string
regex?: {
pattern: string
flags: string
}
bigint?: string
}
export interface Program extends Node {
type: "Program"
body: Array<Statement | ModuleDeclaration>
sourceType: "script" | "module"
}
export interface Function extends Node {
id?: Identifier | null
params: Array<Pattern>
body: BlockStatement | Expression
generator: boolean
expression: boolean
async: boolean
}
export interface ExpressionStatement extends Node {
type: "ExpressionStatement"
expression: Expression | Literal
directive?: string
}
export interface BlockStatement extends Node {
type: "BlockStatement"
body: Array<Statement>
}
export interface EmptyStatement extends Node {
type: "EmptyStatement"
}
export interface DebuggerStatement extends Node {
type: "DebuggerStatement"
}
export interface WithStatement extends Node {
type: "WithStatement"
object: Expression
body: Statement
}
export interface ReturnStatement extends Node {
type: "ReturnStatement"
argument?: Expression | null
}
export interface LabeledStatement extends Node {
type: "LabeledStatement"
label: Identifier
body: Statement
}
export interface BreakStatement extends Node {
type: "BreakStatement"
label?: Identifier | null
}
export interface ContinueStatement extends Node {
type: "ContinueStatement"
label?: Identifier | null
}
export interface IfStatement extends Node {
type: "IfStatement"
test: Expression
consequent: Statement
alternate?: Statement | null
}
export interface SwitchStatement extends Node {
type: "SwitchStatement"
discriminant: Expression
cases: Array<SwitchCase>
}
export interface SwitchCase extends Node {
type: "SwitchCase"
test?: Expression | null
consequent: Array<Statement>
}
export interface ThrowStatement extends Node {
type: "ThrowStatement"
argument: Expression
}
export interface TryStatement extends Node {
type: "TryStatement"
block: BlockStatement
handler?: CatchClause | null
finalizer?: BlockStatement | null
}
export interface CatchClause extends Node {
type: "CatchClause"
param?: Pattern | null
body: BlockStatement
}
export interface WhileStatement extends Node {
type: "WhileStatement"
test: Expression
body: Statement
}
export interface DoWhileStatement extends Node {
type: "DoWhileStatement"
body: Statement
test: Expression
}
export interface ForStatement extends Node {
type: "ForStatement"
init?: VariableDeclaration | Expression | null
test?: Expression | null
update?: Expression | null
body: Statement
}
export interface ForInStatement extends Node {
type: "ForInStatement"
left: VariableDeclaration | Pattern
right: Expression
body: Statement
}
export interface FunctionDeclaration extends Function {
type: "FunctionDeclaration"
id: Identifier
body: BlockStatement
}
export interface VariableDeclaration extends Node {
type: "VariableDeclaration"
declarations: Array<VariableDeclarator>
kind: "var" | "let" | "const"
}
export interface VariableDeclarator extends Node {
type: "VariableDeclarator"
id: Pattern
init?: Expression | null
}
export interface ThisExpression extends Node {
type: "ThisExpression"
}
export interface ArrayExpression extends Node {
type: "ArrayExpression"
elements: Array<Expression | SpreadElement | null>
}
export interface ObjectExpression extends Node {
type: "ObjectExpression"
properties: Array<Property | SpreadElement>
}
export interface Property extends Node {
type: "Property"
key: Expression
value: Expression
kind: "init" | "get" | "set"
method: boolean
shorthand: boolean
computed: boolean
}
export interface FunctionExpression extends Function {
type: "FunctionExpression"
body: BlockStatement
}
export interface UnaryExpression extends Node {
type: "UnaryExpression"
operator: UnaryOperator
prefix: boolean
argument: Expression
}
export type UnaryOperator = "-" | "+" | "!" | "~" | "typeof" | "void" | "delete"
export interface UpdateExpression extends Node {
type: "UpdateExpression"
operator: UpdateOperator
argument: Expression
prefix: boolean
}
export type UpdateOperator = "++" | "--"
export interface BinaryExpression extends Node {
type: "BinaryExpression"
operator: BinaryOperator
left: Expression | PrivateIdentifier
right: Expression
}
export type BinaryOperator = "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "|" | "^" | "&" | "in" | "instanceof" | "**"
export interface AssignmentExpression extends Node {
type: "AssignmentExpression"
operator: AssignmentOperator
left: Pattern
right: Expression
}
export type AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" | "**=" | "||=" | "&&=" | "??="
export interface LogicalExpression extends Node {
type: "LogicalExpression"
operator: LogicalOperator
left: Expression
right: Expression
}
export type LogicalOperator = "||" | "&&" | "??"
export interface MemberExpression extends Node {
type: "MemberExpression"
object: Expression | Super
property: Expression | PrivateIdentifier
computed: boolean
optional: boolean
}
export interface ConditionalExpression extends Node {
type: "ConditionalExpression"
test: Expression
alternate: Expression
consequent: Expression
}
export interface CallExpression extends Node {
type: "CallExpression"
callee: Expression | Super
arguments: Array<Expression | SpreadElement>
optional: boolean
}
export interface NewExpression extends Node {
type: "NewExpression"
callee: Expression
arguments: Array<Expression | SpreadElement>
}
export interface SequenceExpression extends Node {
type: "SequenceExpression"
expressions: Array<Expression>
}
export interface ForOfStatement extends Node {
type: "ForOfStatement"
left: VariableDeclaration | Pattern
right: Expression
body: Statement
await: boolean
}
export interface Super extends Node {
type: "Super"
}
export interface SpreadElement extends Node {
type: "SpreadElement"
argument: Expression
}
export interface ArrowFunctionExpression extends Function {
type: "ArrowFunctionExpression"
}
export interface YieldExpression extends Node {
type: "YieldExpression"
argument?: Expression | null
delegate: boolean
}
export interface TemplateLiteral extends Node {
type: "TemplateLiteral"
quasis: Array<TemplateElement>
expressions: Array<Expression>
}
export interface TaggedTemplateExpression extends Node {
type: "TaggedTemplateExpression"
tag: Expression
quasi: TemplateLiteral
}
export interface TemplateElement extends Node {
type: "TemplateElement"
tail: boolean
value: {
cooked?: string | null
raw: string
}
}
export interface AssignmentProperty extends Node {
type: "Property"
key: Expression
value: Pattern
kind: "init"
method: false
shorthand: boolean
computed: boolean
}
export interface ObjectPattern extends Node {
type: "ObjectPattern"
properties: Array<AssignmentProperty | RestElement>
}
export interface ArrayPattern extends Node {
type: "ArrayPattern"
elements: Array<Pattern | null>
}
export interface RestElement extends Node {
type: "RestElement"
argument: Pattern
}
export interface AssignmentPattern extends Node {
type: "AssignmentPattern"
left: Pattern
right: Expression
}
export interface Class extends Node {
id?: Identifier | null
superClass?: Expression | null
body: ClassBody
}
export interface ClassBody extends Node {
type: "ClassBody"
body: Array<MethodDefinition | PropertyDefinition | StaticBlock>
}
export interface MethodDefinition extends Node {
type: "MethodDefinition"
key: Expression | PrivateIdentifier
value: FunctionExpression
kind: "constructor" | "method" | "get" | "set"
computed: boolean
static: boolean
}
export interface ClassDeclaration extends Class {
type: "ClassDeclaration"
id: Identifier
}
export interface ClassExpression extends Class {
type: "ClassExpression"
}
export interface MetaProperty extends Node {
type: "MetaProperty"
meta: Identifier
property: Identifier
}
export interface ImportDeclaration extends Node {
type: "ImportDeclaration"
specifiers: Array<ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier>
source: Literal
}
export interface ImportSpecifier extends Node {
type: "ImportSpecifier"
imported: Identifier | Literal
local: Identifier
}
export interface ImportDefaultSpecifier extends Node {
type: "ImportDefaultSpecifier"
local: Identifier
}
export interface ImportNamespaceSpecifier extends Node {
type: "ImportNamespaceSpecifier"
local: Identifier
}
export interface ExportNamedDeclaration extends Node {
type: "ExportNamedDeclaration"
declaration?: Declaration | null
specifiers: Array<ExportSpecifier>
source?: Literal | null
}
export interface ExportSpecifier extends Node {
type: "ExportSpecifier"
exported: Identifier | Literal
local: Identifier | Literal
}
export interface AnonymousFunctionDeclaration extends Function {
type: "FunctionDeclaration"
id: null
body: BlockStatement
}
export interface AnonymousClassDeclaration extends Class {
type: "ClassDeclaration"
id: null
}
export interface ExportDefaultDeclaration extends Node {
type: "ExportDefaultDeclaration"
declaration: AnonymousFunctionDeclaration | FunctionDeclaration | AnonymousClassDeclaration | ClassDeclaration | Expression
}
export interface ExportAllDeclaration extends Node {
type: "ExportAllDeclaration"
source: Literal
exported?: Identifier | Literal | null
}
export interface AwaitExpression extends Node {
type: "AwaitExpression"
argument: Expression
}
export interface ChainExpression extends Node {
type: "ChainExpression"
expression: MemberExpression | CallExpression
}
export interface ImportExpression extends Node {
type: "ImportExpression"
source: Expression
}
export interface ParenthesizedExpression extends Node {
type: "ParenthesizedExpression"
expression: Expression
}
export interface PropertyDefinition extends Node {
type: "PropertyDefinition"
key: Expression | PrivateIdentifier
value?: Expression | null
computed: boolean
static: boolean
}
export interface PrivateIdentifier extends Node {
type: "PrivateIdentifier"
name: string
}
export interface StaticBlock extends Node {
type: "StaticBlock"
body: Array<Statement>
}
export type Statement =
| ExpressionStatement
| BlockStatement
| EmptyStatement
| DebuggerStatement
| WithStatement
| ReturnStatement
| LabeledStatement
| BreakStatement
| ContinueStatement
| IfStatement
| SwitchStatement
| ThrowStatement
| TryStatement
| WhileStatement
| DoWhileStatement
| ForStatement
| ForInStatement
| ForOfStatement
| Declaration
export type Declaration =
| FunctionDeclaration
| VariableDeclaration
| ClassDeclaration
export type Expression =
| Identifier
| Literal
| ThisExpression
| ArrayExpression
| ObjectExpression
| FunctionExpression
| UnaryExpression
| UpdateExpression
| BinaryExpression
| AssignmentExpression
| LogicalExpression
| MemberExpression
| ConditionalExpression
| CallExpression
| NewExpression
| SequenceExpression
| ArrowFunctionExpression
| YieldExpression
| TemplateLiteral
| TaggedTemplateExpression
| ClassExpression
| MetaProperty
| AwaitExpression
| ChainExpression
| ImportExpression
| ParenthesizedExpression
export type Pattern =
| Identifier
| MemberExpression
| ObjectPattern
| ArrayPattern
| RestElement
| AssignmentPattern
export type ModuleDeclaration =
| ImportDeclaration
| ExportNamedDeclaration
| ExportDefaultDeclaration
| ExportAllDeclaration
export type AnyNode = Statement | Expression | Declaration | ModuleDeclaration | Literal | Program | SwitchCase | CatchClause | Property | Super | SpreadElement | TemplateElement | AssignmentProperty | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | ClassBody | MethodDefinition | MetaProperty | ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier | ExportSpecifier | AnonymousFunctionDeclaration | AnonymousClassDeclaration | PropertyDefinition | PrivateIdentifier | StaticBlock | VariableDeclarator
export function parse(input: string, options: Options): Program
export function parseExpressionAt(input: string, pos: number, options: Options): Expression
export function tokenizer(input: string, options: Options): {
getToken(): Token getToken(): Token
[Symbol.iterator](): Iterator<Token> [Symbol.iterator](): Iterator<Token>
} }
interface Options { export type ecmaVersion = 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | "latest"
ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020
sourceType?: 'script' | 'module' export interface Options {
/**
* `ecmaVersion` indicates the ECMAScript version to parse. Can be a
* number, either in year (`2022`) or plain version number (`6`) form,
* or `"latest"` (the latest the library supports). This influences
* support for strict mode, the set of reserved words, and support for
* new syntax features.
*/
ecmaVersion: ecmaVersion
/**
* `sourceType` indicates the mode the code should be parsed in.
* Can be either `"script"` or `"module"`. This influences global
* strict mode and parsing of `import` and `export` declarations.
*/
sourceType?: "script" | "module"
/**
* a callback that will be called when a semicolon is automatically inserted.
* @param lastTokEnd the position of the comma as an offset
* @param lastTokEndLoc location if {@link locations} is enabled
*/
onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void
/**
* similar to `onInsertedSemicolon`, but for trailing commas
* @param lastTokEnd the position of the comma as an offset
* @param lastTokEndLoc location if `locations` is enabled
*/
onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void
allowReserved?: boolean | 'never'
/**
* By default, reserved words are only enforced if ecmaVersion >= 5.
* Set `allowReserved` to a boolean value to explicitly turn this on
* an off. When this option has the value "never", reserved words
* and keywords can also not be used as property names.
*/
allowReserved?: boolean | "never"
/**
* When enabled, a return at the top level is not considered an error.
*/
allowReturnOutsideFunction?: boolean allowReturnOutsideFunction?: boolean
/**
* When enabled, import/export statements are not constrained to
* appearing at the top of the program, and an import.meta expression
* in a script isn't considered an error.
*/
allowImportExportEverywhere?: boolean allowImportExportEverywhere?: boolean
/**
* By default, `await` identifiers are allowed to appear at the top-level scope only if {@link ecmaVersion} >= 2022.
* When enabled, await identifiers are allowed to appear at the top-level scope,
* but they are still not allowed in non-async functions.
*/
allowAwaitOutsideFunction?: boolean allowAwaitOutsideFunction?: boolean
/**
* When enabled, super identifiers are not constrained to
* appearing in methods and do not raise an error when they appear elsewhere.
*/
allowSuperOutsideMethod?: boolean
/**
* When enabled, hashbang directive in the beginning of file is
* allowed and treated as a line comment. Enabled by default when
* {@link ecmaVersion} >= 2023.
*/
allowHashBang?: boolean allowHashBang?: boolean
/**
* 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.
*/
checkPrivateFields?: boolean
/**
* When `locations` is on, `loc` properties holding objects with
* `start` and `end` properties as {@link Position} objects will be attached to the
* nodes.
*/
locations?: boolean locations?: boolean
onToken?: ((token: Token) => any) | Token[]
/**
* a callback that will cause Acorn to call that export function with object in the same
* format as tokens returned from `tokenizer().getToken()`. Note
* that you are not allowed to call the parser from the
* callbackthat will corrupt its internal state.
*/
onToken?: ((token: Token) => void) | Token[]
/**
* This takes a export function or an array.
*
* When a export function is passed, Acorn will call that export function with `(block, text, start,
* end)` parameters whenever a comment is skipped. `block` is a
* boolean indicating whether this is a block (`/* *\/`) comment,
* `text` is the content of the comment, and `start` and `end` are
* character offsets that denote the start and end of the comment.
* When the {@link locations} option is on, two more parameters are
* passed, the full locations of {@link Position} export type of the start and
* end of the comments.
*
* When a array is passed, each found comment of {@link Comment} export type is pushed to the array.
*
* Note that you are not allowed to call the
* parser from the callbackthat will corrupt its internal state.
*/
onComment?: (( onComment?: ((
isBlock: boolean, text: string, start: number, end: number, startLoc?: Position, isBlock: boolean, text: string, start: number, end: number, startLoc?: Position,
endLoc?: Position endLoc?: Position
) => void) | Comment[] ) => void) | Comment[]
ranges?: boolean
program?: Node
sourceFile?: string
directSourceFile?: string
preserveParens?: boolean
}
class Parser { /**
constructor(options: Options, input: string, startPos?: number) * Nodes have their start and end characters offsets recorded in
parse(this: Parser): Node * `start` and `end` properties (directly on the node, rather than
static parse(this: typeof Parser, input: string, options?: Options): Node * the `loc` object, which holds line/column data. To also add a
static parseExpressionAt(this: typeof Parser, input: string, pos: number, options?: Options): Node * [semi-standardized][range] `range` property holding a `[start,
static tokenizer(this: typeof Parser, input: string, options?: Options): { * end]` array with the same numbers, set the `ranges` option to
* `true`.
*/
ranges?: boolean
/**
* It is possible to parse multiple files into a single AST by
* passing the tree produced by parsing the first file as
* `program` option in subsequent parses. This will add the
* toplevel forms of the parsed file to the `Program` (top) node
* of an existing parse tree.
*/
program?: Node
/**
* When {@link locations} is on, you can pass this to record the source
* file in every node's `loc` object.
*/
sourceFile?: string
/**
* This value, if given, is stored in every node, whether {@link locations} is on or off.
*/
directSourceFile?: string
/**
* When enabled, parenthesized expressions are represented by
* (non-standard) ParenthesizedExpression nodes
*/
preserveParens?: boolean
}
export class Parser {
options: Options
input: string
protected constructor(options: Options, input: string, startPos?: number)
parse(): Program
static parse(input: string, options: Options): Program
static parseExpressionAt(input: string, pos: number, options: Options): Expression
static tokenizer(input: string, options: Options): {
getToken(): Token getToken(): Token
[Symbol.iterator](): Iterator<Token> [Symbol.iterator](): Iterator<Token>
} }
static extend(this: typeof Parser, ...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser static extend(...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser
} }
interface Position { line: number; column: number; offset: number } export const defaultOptions: Options
const defaultOptions: Options export function getLineInfo(input: string, offset: number): Position
function getLineInfo(input: string, offset: number): Position export class TokenType {
class SourceLocation {
start: Position
end: Position
source?: string | null
constructor(p: Parser, start: Position, end: Position)
}
class Node {
type: string
start: number
end: number
loc?: SourceLocation
sourceFile?: string
range?: [number, number]
constructor(parser: Parser, pos: number, loc?: SourceLocation)
}
class TokenType {
label: string label: string
keyword: string keyword: string | undefined
beforeExpr: boolean }
startsExpr: boolean
isLoop: boolean
isAssign: boolean
prefix: boolean
postfix: boolean
binop: number
updateContext?: (prevType: TokenType) => void
constructor(label: string, conf?: any)
}
const tokTypes: { export const tokTypes: {
num: TokenType num: TokenType
regexp: TokenType regexp: TokenType
string: TokenType string: TokenType
name: TokenType name: TokenType
privateId: TokenType
eof: TokenType eof: TokenType
bracketL: TokenType bracketL: TokenType
bracketR: TokenType bracketR: TokenType
braceL: TokenType braceL: TokenType
@ -100,11 +772,14 @@ declare namespace acorn {
colon: TokenType colon: TokenType
dot: TokenType dot: TokenType
question: TokenType question: TokenType
questionDot: TokenType
arrow: TokenType arrow: TokenType
template: TokenType template: TokenType
invalidTemplate: TokenType
ellipsis: TokenType ellipsis: TokenType
backQuote: TokenType backQuote: TokenType
dollarBraceL: TokenType dollarBraceL: TokenType
eq: TokenType eq: TokenType
assign: TokenType assign: TokenType
incDec: TokenType incDec: TokenType
@ -122,6 +797,8 @@ declare namespace acorn {
star: TokenType star: TokenType
slash: TokenType slash: TokenType
starstar: TokenType starstar: TokenType
coalesce: TokenType
_break: TokenType _break: TokenType
_case: TokenType _case: TokenType
_catch: TokenType _catch: TokenType
@ -157,53 +834,23 @@ declare namespace acorn {
_typeof: TokenType _typeof: TokenType
_void: TokenType _void: TokenType
_delete: TokenType _delete: TokenType
} }
class TokContext { export interface Comment {
constructor(token: string, isExpr: boolean, preserveSpace: boolean, override?: (p: Parser) => void) type: "Line" | "Block"
}
const tokContexts: {
b_stat: TokContext
b_expr: TokContext
b_tmpl: TokContext
p_stat: TokContext
p_expr: TokContext
q_tmpl: TokContext
f_expr: TokContext
}
function isIdentifierStart(code: number, astral?: boolean): boolean
function isIdentifierChar(code: number, astral?: boolean): boolean
interface AbstractToken {
}
interface Comment extends AbstractToken {
type: string
value: string value: string
start: number start: number
end: number end: number
loc?: SourceLocation loc?: SourceLocation
range?: [number, number] range?: [number, number]
} }
class Token { export class Token {
type: TokenType type: TokenType
value: any
start: number start: number
end: number end: number
loc?: SourceLocation loc?: SourceLocation
range?: [number, number] range?: [number, number]
constructor(p: Parser)
}
function isNewLine(code: number): boolean
const lineBreak: RegExp
const lineBreakG: RegExp
const version: string
} }
export const version: string

2915
node_modules/acorn/dist/acorn.js generated vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2915
node_modules/acorn/dist/acorn.mjs generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
import * as acorn from "./acorn";
export = acorn;

File diff suppressed because one or more lines are too long

56
node_modules/acorn/dist/bin.js generated vendored
View File

@ -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 {
codeList.forEach(function (code, idx) {
fileIdx = idx;
if (!tokenize) { if (!tokenize) {
result = acorn.parse(code, options); result = acorn__namespace.parse(code, options);
options.program = result;
} else { } else {
result = []; var tokenizer = acorn__namespace.tokenizer(code, options), token;
var tokenizer = acorn.tokenizer(code, options), token;
do { do {
token = tokenizer.getToken(); token = tokenizer.getToken();
result.push(token); result.push(token);
} while (token.type !== acorn.tokTypes.eof) } 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]); });
} }

25
node_modules/acorn/package.json generated vendored
View File

@ -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"
}
} }

21
node_modules/ansi-colors/LICENSE generated vendored
View File

@ -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.

315
node_modules/ansi-colors/README.md generated vendored
View File

@ -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._

184
node_modules/ansi-colors/index.js generated vendored
View File

@ -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;

129
node_modules/ansi-colors/package.json generated vendored
View File

@ -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"
]
}
}

69
node_modules/ansi-colors/symbols.js generated vendored
View File

@ -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 });

View File

@ -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;

199
node_modules/argparse/CHANGELOG.md generated vendored
View File

@ -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

267
node_modules/argparse/LICENSE generated vendored
View File

@ -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.

253
node_modules/argparse/README.md generated vendored
View File

@ -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 arguments 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)

3
node_modules/argparse/index.js generated vendored
View File

@ -1,3 +0,0 @@
'use strict';
module.exports = require('./lib/argparse');

146
node_modules/argparse/lib/action.js generated vendored
View File

@ -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
};

View File

@ -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);
};

View File

@ -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);
};

View File

@ -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);
};

View File

@ -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();
};

View File

@ -1,50 +0,0 @@
/*:nodoc:*
* class ActionStore
*
* This action just stores the arguments 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);
};

View File

@ -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);
};

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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());
};

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