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": {
"browser": true,
"jquery": true
},
"parser": "@babel/eslint-parser",
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module"
},
"plugins": [
"prettier"
"prettier",
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"prettier"
"plugin:prettier/recommended",
"prettier",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"prettier/prettier": "error",
@ -27,6 +26,4 @@
"window": "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
. "$(dirname "$0")/_/husky.sh"
# Run JS/CSS checks
.husky/pre-commit-js-css
if [ $? -ne 0 ]; then
echo "JS/CSS checks failed"
exit 1
fi
# Get the list of staged PHP files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.php$')
@ -41,26 +43,38 @@ if [ $SYNTAX_ERRORS -ne 0 ]; then
exit 1
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
echo "Running PHP CS Fixer..."
for FILE in $STAGED_FILES; do
/home/aissel/.config/composer/vendor/bin/php-cs-fixer fix "$FILE"
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..."
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
# 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
for FILE in $STAGED_FILES; do
git add "$FILE"
done
echo "Pre-commit checks completed."

View File

@ -24,15 +24,18 @@ for FILE in $STAGED_FILES; do
npx prettier --write "$FILE"
done
# Run ESLint
# Run ESLint for JS/TS files only
echo "Running ESLint..."
ESLINT_ERRORS=0
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)
if [ $? -ne 0 ]; then
display_errors "$ESLINT_OUTPUT"
ESLINT_ERRORS=1
fi
fi
done
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/
# Ignore build directory
build/
# Ignore all minified JavaScript files
node_modules
dist
build
*.min.js
# 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
*.min.css

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'
| 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
redirect('users/login');
}
$user_id = $this->session->userdata('user_id');
$user_id = $this->session->userdata('user_id')
// Retrieve form title from the forms table using form_id
$form_title = 'Untitled Form'; // Default title

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-description {
.form- description {
border: none;
border-bottom: 1px solid #ccc;
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) {
return a + b
return a + b;
}
// Example usage of the add function
const result = add(5, 10)
console.log('The result is:', result)
// Example object with properties
const person = {
name: 'John Doe',
age: 30,
greet: function () {
console.log(
`Hello, my name is ${this.name} and I am ${this.age} years old.`
)
},
/**
* Logs a greeting message to the console.
*
* @param {string} name - The name to greet.
*/
function greet(name) {
console.log(`Hello, ${name}!`);
}
// Call the greet method
person.greet()
// Example usage
const result = add(5, 10);
// Example of an arrow function
const multiply = (x, y) => x * y
console.log(`The result is: ${result}`);
console.log('The product is:', multiply(4, 5))
greet("Alice"); // Replaced 'Alice' with "Alice"
// Example of a variable declared with let
let count = 0
for (let i = 0; i < 5; i++) {
count += i
}
console.log('The count is:', count)
/**
* An example class demonstrating basic TypeScript features in JavaScript.
*/
class Person {
/**
* 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.'
console.log(message)
// Example of a function with default parameters
function greet(name = 'Guest') {
console.log(`Welcome, ${name}!`)
/**
* Introduces the person.
*
* @returns {string} A greeting message.
*/
introduce() {
return `Hi, I'm ${this.name} and I'm ${this.age} years old.`;
}
}
// Call the function with and without arguments
greet('Alice')
greet()
// Example usage of the Person class
const person = new Person("Bob", 25); // Replaced 'Bob' with "Bob"
console.log(person.introduce());

View File

@ -1,12 +1,14 @@
$(document).ready(function () {
var base_url = '<?php echo base_url(); ?>';
// Add section button functionality
$('#add-section-btn').on('click', function () {
var sectionHtml = `
<div class="form-section" data-type="">
$(document).ready(function () { var base_url = '<?php echo base_url(); ?>' //
// Add section button functionality
$('#add-section-btn').on('click', function () {
var sectionHtml = `
<div class="form-section" data-type="">
<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">
<option value="short-answer">Short Answer</option>
<option value="paragraph">Paragraph</option>
@ -15,119 +17,56 @@ $(document).ready(function () {
<option value="dropdown">Dropdown</option>
</select>
<label class="toggle-switch">
<input type="checkbox" class="required-toggle">
<input type="checkbox" class="required-toggle" />
<span class="slider"></span>
</label>
<span class="delete-section-icon"><i class="fas fa-trash-alt"></i></span>
</div>
<div class="options-container"></div>
<button class="btn btn-secondary add-option-btn" style="display: none;">Add Option</button></div>
`; $('#form-container').append(sectionHtml);
});
// Add option button functionality
$(document).on('click', '.add-option-btn', function () {
var optionHtml = `
<div class="option">
<input type="text" class="form-control option-label" placeholder="Option">
<button class="btn btn-secondary add-option-btn" style="display: none;">
Add Option
</button>
</div>
` $('#form-container').append(sectionHtml) }) // Add option button functionality
$(document).on('click', '.add-option-btn', function () { var optionHtml = `
<div class="option">
<input type="text" class="form-control option-label" placeholder="Option" />
<span class="delete-option-icon">&times;</span>
</div>
`;
$(this).siblings('.options-container').append(optionHtml);
});
// Delete option functionality
$(document).on('click', '.delete-option-icon', function () {
$(this).parent().remove();
});
// Delete section functionality
$(document).on('click', '.delete-section-icon', function () {
$(this).closest('.form-section').remove();
});
// Show/Hide "Add Option" button based on question type
$(document).on('change', '.custom-select', function () {
var type = $(this).val();
var $section = $(this).closest('.form-section');
if (type === 'multiple-choice' || type === 'checkboxes' || type === 'dropdown') {
$section.find('.add-option-btn').show();
} else {
$section.find('.add-option-btn').hide();
}
}).trigger('change'); // Trigger change to apply to existing sections
// Submit button functionality
$('#submit-btn').on('click', function () {
var formData = collectFormData();
formData['form_id'] = <? php echo $form['id']; ?>;
let validation = validateFormData(formData);
if (!validation.isValid) {
alert(validation.message);
return;
}
$.ajax({
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 };
}
});
</div>
` $(this).siblings('.options-container').append(optionHtml) }) // Delete option
functionality $(document).on('click', '.delete-option-icon', function () {
$(this).parent().remove() }) // Delete section functionality
$(document).on('click', '.delete-section-icon', function () {
$(this).closest('.form-section').remove() }) // Show/Hide "Add Option" button
based on question type $(document) .on('change', '.custom-select', function () {
var type = $(this).val() var $section = $(this).closest('.form-section') if (
type === 'multiple-choice' || type === 'checkboxes' || type === 'dropdown' ) {
$section.find('.add-option-btn').show() } else {
$section.find('.add-option-btn').hide() } }) .trigger('change') // Trigger
change to apply to existing sections // Submit button functionality
$('#submit-btn').on('click', function () { var formData = collectFormData()
formData['form_id'] = /* eslint-disable */ <? php echo $form['id']; ?>; /*
eslint-enable */ let validation = validateFormData(formData) if
(!validation.isValid) { alert(validation.message) return } $.ajax({ 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 () {
let index = 1
let activeSection = null
let index = 1;
let activeSection = null;
function addOption(type, container) {
// let optionIndex = container.children().length + 1;
let optionHtml
if (type === 'multiple-choice' || type === 'checkboxes') {
let optionHtml;
if (type === "multiple-choice" || type === "checkboxes") {
optionHtml = `
<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" >
<span class="delete-option-icon">&times;</span>
</div>
`
} else if (type === 'dropdown') {
`;
} else if (type === "dropdown") {
optionHtml = `
<div class="option">
<input type="text" class="form-control option-label">
<span class="delete-option-icon">&times;</span>
</div>
`
`;
}
container.append(optionHtml)
container.append(optionHtml);
}
function createFormSection() {
let newSection = `
<div class="form-section" data-index="${index}">
<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">
<option value="short-answer">Short Answer</option>
<option value="paragraph">Paragraph</option>
@ -44,100 +44,100 @@ $(document).ready(function () {
</div>
<div class="options-container"></div>
</div>
`
$('#form-container').append(newSection)
index++
positionAddSectionButton()
`;
$("#form-container").append(newSection);
index++;
positionAddSectionButton();
}
function positionAddSectionButton() {
if (activeSection) {
let position = activeSection.position()
let buttonWidth = $('#add-section-btn').outerWidth()
let buttonHeight = $('#add-section-btn').outerHeight()
let position = activeSection.position();
let buttonWidth = $("#add-section-btn").outerWidth();
let buttonHeight = $("#add-section-btn").outerHeight();
$('#add-section-btn').css({
position: 'absolute',
left: position.left - buttonWidth - 47 + 'px',
$("#add-section-btn").css({
position: "absolute",
left: position.left - buttonWidth - 47 + "px",
top:
position.top + activeSection.height() / 2 - buttonHeight / 2 + 'px',
})
position.top + activeSection.height() / 2 - buttonHeight / 2 + "px",
});
}
}
$('#add-section-btn').on('click', function () {
createFormSection()
$('.form-section').removeClass('active')
activeSection = $('.form-section').last()
activeSection.addClass('active')
positionAddSectionButton()
})
$("#add-section-btn").on("click", function () {
createFormSection();
$(".form-section").removeClass("active");
activeSection = $(".form-section").last();
activeSection.addClass("active");
positionAddSectionButton();
});
$(document).on('change', '.custom-select', function () {
let type = $(this).val()
let container = $(this).closest('.form-section').find('.options-container')
container.empty()
$(this).closest('.form-section').find('.add-option-btn').remove()
$(document).on("change", ".custom-select", function () {
let type = $(this).val();
let container = $(this).closest(".form-section").find(".options-container");
container.empty();
$(this).closest(".form-section").find(".add-option-btn").remove();
if (type === 'short-answer') {
if (type === "short-answer") {
container.append(
'<input type="text" class="form-control" disabled placeholder="Short answer text">'
)
} else if (type === 'paragraph') {
'<input type="text" class="form-control" disabled placeholder="Short answer text">',
);
} else if (type === "paragraph") {
container.append(
'<textarea class="form-control" disabled placeholder="Paragraph text"></textarea>'
)
'<textarea class="form-control" disabled placeholder="Paragraph text"></textarea>',
);
} else {
addOption(type, container)
addOption(type, container);
$(this)
.closest('.form-section')
.closest(".form-section")
.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 () {
let type = $(this).closest('.form-section').find('.custom-select').val()
let container = $(this).closest('.form-section').find('.options-container')
addOption(type, container)
})
$(document).on("click", ".add-option-btn", function () {
let type = $(this).closest(".form-section").find(".custom-select").val();
let container = $(this).closest(".form-section").find(".options-container");
addOption(type, container);
});
$(document).on('click', '.delete-section-icon', function () {
let section = $(this).closest('.form-section')
let prevSection = section.prev('.form-section')
let nextSection = section.next('.form-section')
section.remove()
if (section.hasClass('active')) {
activeSection = null
$(document).on("click", ".delete-section-icon", function () {
let section = $(this).closest(".form-section");
let prevSection = section.prev(".form-section");
let nextSection = section.next(".form-section");
section.remove();
if (section.hasClass("active")) {
activeSection = null;
}
if (prevSection.length > 0) {
prevSection
.find('.delete-section-icon')
.appendTo(prevSection.find('.form-section'))
activeSection = prevSection
row
.find(".delete-section-icon")
.appendTo(prevSection.find(".form-section"));
activeSection = prevSection;
row;
} else if (nextSection.length > 0) {
nextSection
.find('.delete-section-icon')
.appendTo(nextSection.find('.form-header'))
activeSection = nextSection
.find(".delete-section-icon")
.appendTo(nextSection.find(".form-header"));
activeSection = nextSection;
}
positionAddSectionButton()
})
positionAddSectionButton();
});
$(document).on('click', '.delete-option-icon', function () {
let option = $(this).closest('.option')
let container = option.closest('.options-container')
option.remove()
})
$(document).on("click", ".delete-option-icon", function () {
let option = $(this).closest(".option");
let container = option.closest(".options-container");
option.remove();
});
$(document).on('click', '.required-toggle', function () {
$(this).closest('.form-section').toggleClass('required')
})
$(document).on("click", ".required-toggle", function () {
$(this).closest(".form-section").toggleClass("required");
});
$('#preview-btn').on('click', function () {
let previewWindow = window.open('', '_blank')
$("#preview-btn").on("click", function () {
let previewWindow = window.open("", "_blank");
let previewContent = `
<html>
<head>
@ -157,189 +157,189 @@ $(document).ready(function () {
<div class="form-header">
<h3>Form Preview</h3>
</div>
`
$('.form-section').each(function () {
previewContent += '<div class="form-section">'
previewContent += '<div class="question-section">'
`;
$(".form-section").each(function () {
previewContent += '<div class="form-section">';
previewContent += '<div class="question-section">';
previewContent +=
'<div class="question-label">' +
$(this).find('.untitled-question').val() +
'</div>'
previewContent += '</div>'
let type = $(this).find('.custom-select').val()
let optionsContainer = $(this).find('.options-container')
$(this).find(".untitled-question").val() +
"</div>";
previewContent += "</div>";
let type = $(this).find(".custom-select").val();
let optionsContainer = $(this).find(".options-container");
if (type === 'multiple-choice') {
optionsContainer.find('.option').each(function () {
if (type === "multiple-choice") {
optionsContainer.find(".option").each(function () {
previewContent += `
<div class="option">
<input type="radio" name="option-${index}">
<label>${$(this).find('.option-label').val()}</label>
<label>${$(this).find(".option-label").val()}</label>
</div>
`
})
} else if (type === 'checkboxes') {
optionsContainer.find('.option').each(function () {
`;
});
} else if (type === "checkboxes") {
optionsContainer.find(".option").each(function () {
previewContent += `
<div class="option">
<input type="checkbox">
<label>${$(this).find('.option-label').val()}</label>
<label>${$(this).find(".option-label").val()}</label>
</div>
`
})
} else if (type === 'short-answer') {
`;
});
} else if (type === "short-answer") {
previewContent +=
'<input type="text" class="form-control" placeholder="Short answer text">'
} else if (type === 'paragraph') {
'<input type="text" class="form-control" placeholder="Short answer text">';
} else if (type === "paragraph") {
previewContent +=
'<textarea class="form-control" placeholder="Paragraph text"></textarea>'
} else if (type === 'dropdown') {
let dropdownHtml = '<select class="form-control">'
optionsContainer.find('.option .option-label').each(function () {
dropdownHtml += `<option>${$(this).val()}</option>`
})
dropdownHtml += '</select>'
previewContent += dropdownHtml
'<textarea class="form-control" placeholder="Paragraph text"></textarea>';
} else if (type === "dropdown") {
let dropdownHtml = '<select class="form-control">';
optionsContainer.find(".option .option-label").each(function () {
dropdownHtml += `<option>${$(this).val()}</option>`;
});
dropdownHtml += "</select>";
previewContent += dropdownHtml;
}
previewContent += '</div>'
})
previewContent += "</div>";
});
previewContent += `
</div>
</body>
</html>
`
previewWindow.document.write(previewContent)
previewWindow.document.close()
})
`;
previewWindow.document.write(previewContent);
previewWindow.document.close();
});
$(document).on('click', '.form-section', function () {
$('.form-section').removeClass('active')
$(this).addClass('active')
activeSection = $(this)
positionAddSectionButton()
})
$(document).on("click", ".form-section", function () {
$(".form-section").removeClass("active");
$(this).addClass("active");
activeSection = $(this);
positionAddSectionButton();
});
$('#form-container').sortable({
placeholder: 'ui-state-highlight',
$("#form-container").sortable({
placeholder: "ui-state-highlight",
start: function (event, ui) {
ui.placeholder.height(ui.item.height())
ui.placeholder.height(ui.item.height());
},
stop: function (event, ui) {
positionAddSectionButton()
positionAddSectionButton();
},
})
});
function collectFormData() {
var formData = {
questions: [],
}
};
$('.form-section').each(function () {
var questionType = $(this).find('.custom-select').val()
$(".form-section").each(function () {
var questionType = $(this).find(".custom-select").val();
var questionData = {
text: $(this).find('.untitled-question').val(),
text: $(this).find(".untitled-question").val(),
type: questionType,
is_required: $(this).find('.required-toggle').is(':checked'),
is_required: $(this).find(".required-toggle").is(":checked"),
options: [],
}
};
// Only add options if the question type supports them
if (
questionType === 'multiple-choice' ||
questionType === 'checkboxes' ||
questionType === 'dropdown'
questionType === "multiple-choice" ||
questionType === "checkboxes" ||
questionType === "dropdown"
) {
$(this)
.find('.option-label')
.find(".option-label")
.each(function () {
questionData.options.push($(this).val())
})
questionData.options.push($(this).val());
});
}
formData.questions.push(questionData)
})
formData.questions.push(questionData);
});
console.log(formData)
return formData
console.log(formData);
return formData;
}
function validateFormData(formData) {
for (let question of formData.questions) {
if (!question.text.trim()) {
return { isValid: false, message: 'All questions must have text.' }
return { isValid: false, message: "All questions must have text." };
}
if (
(question.type === 'multiple-choice' ||
question.type === 'checkboxes' ||
question.type === 'dropdown') &&
(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.',
}
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: false, message: "All options must have text." };
}
}
}
return { isValid: true }
return { isValid: true };
}
$('#submit-btn').on('click', function () {
let formData = collectFormData()
console.log(formData)
$("#submit-btn").on("click", function () {
let formData = collectFormData();
console.log(formData);
let validation = validateFormData(formData)
let validation = validateFormData(formData);
if (!validation.isValid) {
alert(validation.message)
return
alert(validation.message);
return;
}
$.ajax({
url: base_url + 'New_form_controller/submit_form',
type: 'POST',
url: base_url + "New_form_controller/submit_form",
type: "POST",
data: { formData: formData },
dataType: 'JSON',
dataType: "JSON",
success: function (response) {
if (response.status === 'success') {
if (response.status === "success") {
Swal.fire({
title: 'Success!',
text: 'Form submitted successfully!',
icon: 'success',
confirmButtonText: 'OK',
title: "Success!",
text: "Form submitted successfully!",
icon: "success",
confirmButtonText: "OK",
}).then((result) => {
window.location.href = base_url
})
window.location.href = base_url;
});
} else {
Swal.fire({
title: 'Error!',
title: "Error!",
text: response.message,
icon: 'error',
confirmButtonText: 'OK',
})
console.log(response)
icon: "error",
confirmButtonText: "OK",
});
console.log(response);
}
},
error: function (error) {
Swal.fire({
title: 'Error!',
text: 'Error submitting form!',
icon: 'error',
confirmButtonText: 'OK',
width: '400px',
height: '300px',
padding: 'auto',
title: "Error!",
text: "Error submitting form!",
icon: "error",
confirmButtonText: "OK",
width: "400px",
height: "300px",
padding: "auto",
}).then((result) => {
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 () {
let index = 1
let activeSection = null
let index = 1;
let activeSection = null;
function addOption(type, container) {
let optionHtml
let optionHtml;
if (type === 'multiple-choice' || type === 'checkboxes') {
if (type === "multiple-choice" || type === "checkboxes") {
optionHtml = `
<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">
<span class="delete-option-icon">&times;</span>
</div>
`
} else if (type === 'dropdown') {
`;
} else if (type === "dropdown") {
optionHtml = `
<div class="option">
<input type="text" class="form-control option-label">
<span class="delete-option-icon">&times;</span>
</div>
`
`;
}
container.append(optionHtml)
container.append(optionHtml);
}
function createFormSection() {
let newSection = `
<div class="form-section" data-index="${index}">
<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>
<select class="custom-select">
<option value="short-answer">Short Answer</option>
@ -46,58 +47,58 @@ $(document).ready(function () {
</div>
<div class="options-container"></div>
</div>
`
$('#form-container').append(newSection)
index++
`;
$("#form-container").append(newSection);
index++;
positionAddSectionButton()
positionAddSectionButton();
}
function positionAddSectionButton() {
if (activeSection) {
let position = activeSection.position()
let buttonWidth = $('#add-section-btn').outerWidth()
let buttonHeight = $('#add-section-btn').outerHeight()
let position = activeSection.position();
let buttonWidth = $("#add-section-btn").outerWidth();
let buttonHeight = $("#add-section-btn").outerHeight();
$('#add-section-btn').css({
position: 'absolute',
left: position.left - buttonWidth - 47 + 'px',
$("#add-section-btn").css({
position: "absolute",
left: position.left - buttonWidth - 47 + "px",
top:
position.top + activeSection.height() / 2 - buttonHeight / 2 + 'px',
})
position.top + activeSection.height() / 2 - buttonHeight / 2 + "px",
});
}
}
$('#add-section-btn').on('click', function () {
createFormSection()
$('.form-section').removeClass('active')
activeSection = $('.form-section').last()
activeSection.addClass('active')
positionAddSectionButton()
})
$("#add-section-btn").on("click", function () {
createFormSection();
$(".form-section").removeClass("active");
activeSection = $(".form-section").last();
activeSection.addClass("active");
positionAddSectionButton();
});
$(document).on('change', '.custom-select', function () {
let type = $(this).val()
let container = $(this).closest('.form-section').find('.options-container')
container.empty()
$(document).on("change", ".custom-select", function () {
let type = $(this).val();
let container = $(this).closest(".form-section").find(".options-container");
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(
'<input type="text" class="form-control" disabled placeholder="Short answer text">'
)
} else if (type === 'paragraph') {
'<input type="text" class="form-control" disabled placeholder="Short answer text">',
);
} else if (type === "paragraph") {
container.append(
'<textarea class="form-control" disabled placeholder="Paragraph text"></textarea>'
)
'<textarea class="form-control" disabled placeholder="Paragraph text"></textarea>',
);
} else {
addOption(type, container)
addOption(type, container);
$(this)
.closest('.form-section')
.closest(".form-section")
.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",
"source": "https://github.com/bcit-ci/CodeIgniter"
},
"require": {
"php": ">=5.3.7"
},
"require": {
"php": ">=7.4"
},
"suggest": {
"paragonie/random_compat": "Provides better randomness in PHP 5.x"
},
@ -31,6 +31,19 @@
"require-dev": {
"mikey179/vfsstream": "1.6.*",
"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",
"This file is @generated automatically"
],
"content-hash": "e56478c624f38d66a8457b936ab02732",
"content-hash": "3aa20e9993bebd9d273b0335f238881f",
"packages": [],
"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",
"version": "1.5.0",
@ -41,7 +119,9 @@
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["MIT"],
"license": [
"MIT"
],
"authors": [
{
"name": "Marco Pivetta",
@ -51,7 +131,10 @@
],
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
"keywords": ["constructor", "instantiate"],
"keywords": [
"constructor",
"instantiate"
],
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
"source": "https://github.com/doctrine/instantiator/tree/1.5.0"
@ -104,7 +187,9 @@
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Frank Kleine",
@ -150,15 +235,25 @@
},
"type": "library",
"autoload": {
"files": ["src/DeepCopy/deep_copy.php"],
"files": [
"src/DeepCopy/deep_copy.php"
],
"psr-4": {
"DeepCopy\\": "src/DeepCopy/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["MIT"],
"license": [
"MIT"
],
"description": "Create deep copies (clones) of your objects",
"keywords": ["clone", "copy", "duplicate", "object", "object graph"],
"keywords": [
"clone",
"copy",
"duplicate",
"object",
"object graph"
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
@ -195,7 +290,9 @@
"ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^9.0"
},
"bin": ["bin/php-parse"],
"bin": [
"bin/php-parse"
],
"type": "library",
"extra": {
"branch-alias": {
@ -208,14 +305,19 @@
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov"
}
],
"description": "A PHP parser written in PHP",
"keywords": ["parser", "php"],
"keywords": [
"parser",
"php"
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0"
@ -251,10 +353,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
@ -304,10 +410,14 @@
},
"type": "library",
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
@ -332,6 +442,53 @@
},
"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",
"version": "9.2.31",
@ -375,10 +532,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -388,7 +549,11 @@
],
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
"keywords": ["coverage", "testing", "xunit"],
"keywords": [
"coverage",
"testing",
"xunit"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
@ -429,10 +594,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -442,7 +611,10 @@
],
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
"keywords": ["filesystem", "iterator"],
"keywords": [
"filesystem",
"iterator"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
@ -486,10 +658,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -499,7 +675,9 @@
],
"description": "Invoke callables with a timeout",
"homepage": "https://github.com/sebastianbergmann/php-invoker/",
"keywords": ["process"],
"keywords": [
"process"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-invoker/issues",
"source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
@ -539,10 +717,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -552,7 +734,9 @@
],
"description": "Simple template engine.",
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
"keywords": ["template"],
"keywords": [
"template"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
@ -592,10 +776,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -605,7 +793,9 @@
],
"description": "Utility class for timing",
"homepage": "https://github.com/sebastianbergmann/php-timer/",
"keywords": ["timer"],
"keywords": [
"timer"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
"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-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
},
"bin": ["phpunit"],
"bin": [
"phpunit"
],
"type": "library",
"extra": {
"branch-alias": {
@ -673,11 +865,17 @@
}
},
"autoload": {
"files": ["src/Framework/Assert/Functions.php"],
"classmap": ["src/"]
"files": [
"src/Framework/Assert/Functions.php"
],
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -687,7 +885,11 @@
],
"description": "The PHP Unit Testing framework.",
"homepage": "https://phpunit.de/",
"keywords": ["phpunit", "testing", "xunit"],
"keywords": [
"phpunit",
"testing",
"xunit"
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
@ -736,10 +938,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -788,10 +994,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -840,10 +1050,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -893,10 +1107,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -917,7 +1135,11 @@
],
"description": "Provides the functionality to compare PHP values for equality",
"homepage": "https://github.com/sebastianbergmann/comparator",
"keywords": ["comparator", "compare", "equality"],
"keywords": [
"comparator",
"compare",
"equality"
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
@ -958,10 +1180,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1011,10 +1237,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1027,7 +1257,12 @@
],
"description": "Diff implementation",
"homepage": "https://github.com/sebastianbergmann/diff",
"keywords": ["diff", "udiff", "unidiff", "unified diff"],
"keywords": [
"diff",
"udiff",
"unidiff",
"unified diff"
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
@ -1070,10 +1305,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1082,7 +1321,11 @@
],
"description": "Provides functionality to handle HHVM/PHP environments",
"homepage": "http://www.github.com/sebastianbergmann/environment",
"keywords": ["Xdebug", "environment", "hhvm"],
"keywords": [
"Xdebug",
"environment",
"hhvm"
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
@ -1124,10 +1367,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1152,7 +1399,10 @@
],
"description": "Provides the functionality to export PHP variables for visualization",
"homepage": "https://www.github.com/sebastianbergmann/exporter",
"keywords": ["export", "exporter"],
"keywords": [
"export",
"exporter"
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
@ -1198,10 +1448,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1210,7 +1464,9 @@
],
"description": "Snapshotting of global state",
"homepage": "http://www.github.com/sebastianbergmann/global-state",
"keywords": ["global state"],
"keywords": [
"global state"
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
@ -1251,10 +1507,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1305,10 +1565,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1356,10 +1620,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1407,10 +1675,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1466,10 +1738,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1516,10 +1792,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1565,10 +1845,14 @@
}
},
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
@ -1590,6 +1874,71 @@
],
"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",
"version": "3.10.2",
@ -1613,7 +1962,10 @@
"require-dev": {
"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",
"extra": {
"branch-alias": {
@ -1621,7 +1973,9 @@
}
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"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.",
"homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
"keywords": ["phpcs", "standards", "static analysis"],
"keywords": [
"phpcs",
"standards",
"static analysis"
],
"support": {
"issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
"security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
@ -1683,10 +2041,14 @@
},
"type": "library",
"autoload": {
"classmap": ["src/"]
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": ["BSD-3-Clause"],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Arne Blankerts",
@ -1714,7 +2076,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.3.7"
"php": ">=7.4"
},
"platform-dev": [],
"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 (c) 2020 ESLint
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
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
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 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.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,8 +1,8 @@
# 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
@ -16,33 +16,87 @@ npm install @eslint/eslintrc --save-dev
yarn add @eslint/eslintrc -D
```
## Future Usage
**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.
## Usage (ESM)
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
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 [
// mimic ESLintRC-style extends
compat.extends("standard", "example"),
...compat.extends("standard", "example"),
// mimic environments
compat.env({
...compat.env({
es2020: true,
node: true
}),
// mimic plugins
compat.plugins("airbnb", "react"),
...compat.plugins("airbnb", "react"),
// 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"],
extends: "standard",
env: {

View File

@ -3,8 +3,6 @@
* @author Sylvan Mably
*/
"use strict";
const baseConfigProperties = {
$schema: { type: "string" },
env: { type: "object" },
@ -78,4 +76,4 @@ const configSchema = {
$ref: "#/definitions/objectConfig"
};
module.exports = configSchema;
export default configSchema;

View File

@ -2,13 +2,12 @@
* @fileoverview Defines environment settings and globals.
* @author Elan Shanker
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const globals = require("globals");
import globals from "globals";
//------------------------------------------------------------------------------
// Helpers
@ -55,7 +54,7 @@ const newGlobals2021 = {
//------------------------------------------------------------------------------
/** @type {Map<string, import("../lib/shared/types").Environment>} */
module.exports = new Map(Object.entries({
export default new Map(Object.entries({
// Language
builtin: {
@ -73,12 +72,30 @@ module.exports = new Map(Object.entries({
ecmaVersion: 6
}
},
es2016: {
globals: newGlobals2015,
parserOptions: {
ecmaVersion: 7
}
},
es2017: {
globals: { ...newGlobals2015, ...newGlobals2017 },
parserOptions: {
ecmaVersion: 8
}
},
es2018: {
globals: { ...newGlobals2015, ...newGlobals2017 },
parserOptions: {
ecmaVersion: 9
}
},
es2019: {
globals: { ...newGlobals2015, ...newGlobals2017 },
parserOptions: {
ecmaVersion: 10
}
},
es2020: {
globals: { ...newGlobals2015, ...newGlobals2017, ...newGlobals2020 },
parserOptions: {
@ -91,6 +108,24 @@ module.exports = new Map(Object.entries({
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
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>
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const os = require("os");
const path = require("path");
const ConfigValidator = require("./shared/config-validator");
const { emitDeprecationWarning } = require("./shared/deprecation-warnings");
const { ConfigArrayFactory } = require("./config-array-factory");
const { ConfigArray, ConfigDependency, IgnorePattern } = require("./config-array");
const debug = require("debug")("eslintrc:cascading-config-array-factory");
import debugOrig from "debug";
import os from "os";
import path from "path";
import { ConfigArrayFactory } from "./config-array-factory.js";
import {
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
@ -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 {Object} [resolver=ModuleResolver] The module resolver object.
* @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 {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 {Object} [resolver=ModuleResolver] The module resolver object.
* @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 {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
*/
/** @type {WeakMap<CascadingConfigArrayFactory, CascadingConfigArrayFactoryInternalSlots>} */
@ -218,7 +228,9 @@ class CascadingConfigArrayFactory {
loadRules,
resolver,
eslintRecommendedPath,
eslintAllPath
getEslintRecommendedConfig,
eslintAllPath,
getEslintAllConfig
} = {}) {
const configArrayFactory = new ConfigArrayFactory({
additionalPluginPool,
@ -227,7 +239,9 @@ class CascadingConfigArrayFactory {
builtInRules,
resolver,
eslintRecommendedPath,
eslintAllPath
getEslintRecommendedConfig,
eslintAllPath,
getEslintAllConfig
});
internalSlotsMap.set(this, {
@ -236,8 +250,7 @@ class CascadingConfigArrayFactory {
configArrayFactory,
cwd,
rulePaths,
loadRules,
resolver
loadRules
}),
baseConfigData,
cliConfigArray: createCLIConfigArray({
@ -516,4 +529,4 @@ class CascadingConfigArrayFactory {
// Public Interface
//------------------------------------------------------------------------------
module.exports = { CascadingConfigArrayFactory };
export { CascadingConfigArrayFactory };

View File

@ -33,26 +33,31 @@
*
* @author Toru Nagashima <https://github.com/mysticatea>
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const fs = require("fs");
const path = require("path");
const importFresh = require("import-fresh");
const stripComments = require("strip-json-comments");
const ConfigValidator = require("./shared/config-validator");
const naming = require("./shared/naming");
const ModuleResolver = require("./shared/relative-module-resolver");
const {
import debugOrig from "debug";
import fs from "fs";
import importFresh from "import-fresh";
import { createRequire } from "module";
import path from "path";
import stripComments from "strip-json-comments";
import {
ConfigArray,
ConfigDependency,
IgnorePattern,
OverrideTester
} = require("./config-array");
const debug = require("debug")("eslintrc:config-array-factory");
} from "./config-array/index.js";
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
@ -86,7 +91,9 @@ const configFilenames = [
* @property {Map<string,Rule>} builtInRules The rules that are built in to ESLint.
* @property {Object} [resolver=ModuleResolver] The module resolver object.
* @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 {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 {Object} [resolver=ModuleResolver] The module resolver object.
* @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 {Function} getEslintRecommendedConfig Returns the config data for eslint:recommended.
*/
/**
@ -120,6 +129,9 @@ const configFilenames = [
/** @type {WeakMap<ConfigArrayFactory, ConfigArrayFactoryInternalSlots>} */
const internalSlotsMap = new WeakMap();
/** @type {WeakMap<object, Plugin>} */
const normalizedPlugins = new WeakMap();
/**
* Check if a given string is a file path.
* @param {string} nameOrPath A module name or file path.
@ -158,7 +170,7 @@ function loadYAMLConfigFile(filePath) {
try {
// empty YAML file can be null, so always use
return yaml.safeLoad(readFile(filePath)) || {};
return yaml.load(readFile(filePath)) || {};
} catch (e) {
debug(`Error reading YAML file: ${filePath}`);
e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
@ -204,7 +216,7 @@ function loadLegacyConfigFile(filePath) {
const yaml = require("js-yaml");
try {
return yaml.safeLoad(stripComments(readFile(filePath))) || /* istanbul ignore next */ {};
return yaml.load(stripComments(readFile(filePath))) || /* istanbul ignore next */ {};
} catch (e) {
debug("Error reading YAML file: %s\n%o", filePath, e);
e.message = `Cannot read config file: ${filePath}\nError: ${e.message}`;
@ -396,12 +408,25 @@ function createContext(
* @returns {Plugin} The normalized plugin.
*/
function normalizePlugin(plugin) {
return {
// first check the cache
let normalizedPlugin = normalizedPlugins.get(plugin);
if (normalizedPlugin) {
return normalizedPlugin;
}
normalizedPlugin = {
configs: plugin.configs || {},
environments: plugin.environments || {},
processors: plugin.processors || {},
rules: plugin.rules || {}
};
// save the reference for later
normalizedPlugins.set(plugin, normalizedPlugin);
return normalizedPlugin;
}
//------------------------------------------------------------------------------
@ -424,7 +449,9 @@ class ConfigArrayFactory {
builtInRules,
resolver = ModuleResolver,
eslintAllPath,
eslintRecommendedPath
getEslintAllConfig,
eslintRecommendedPath,
getEslintRecommendedConfig
} = {}) {
internalSlotsMap.set(this, {
additionalPluginPool,
@ -435,7 +462,9 @@ class ConfigArrayFactory {
builtInRules,
resolver,
eslintAllPath,
eslintRecommendedPath
getEslintAllConfig,
eslintRecommendedPath,
getEslintRecommendedConfig
});
}
@ -793,20 +822,41 @@ class ConfigArrayFactory {
* @private
*/
_loadExtendedBuiltInConfig(extendName, ctx) {
const { eslintAllPath, eslintRecommendedPath } = internalSlotsMap.get(this);
const {
eslintAllPath,
getEslintAllConfig,
eslintRecommendedPath,
getEslintRecommendedConfig
} = internalSlotsMap.get(this);
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({
...ctx,
filePath: eslintRecommendedPath,
name: `${ctx.name} » ${extendName}`
name,
filePath: eslintRecommendedPath
});
}
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({
...ctx,
filePath: eslintAllPath,
name: `${ctx.name} » ${extendName}`
name,
filePath: eslintAllPath
});
}
@ -922,11 +972,11 @@ class ConfigArrayFactory {
_loadParser(nameOrPath, ctx) {
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");
try {
const filePath = ModuleResolver.resolve(nameOrPath, relativeTo);
const filePath = resolver.resolve(nameOrPath, relativeTo);
writeDebugLogForLoading(nameOrPath, relativeTo, filePath);
@ -973,7 +1023,7 @@ class ConfigArrayFactory {
_loadPlugin(name, ctx) {
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 id = naming.getShorthandName(request, "eslint-plugin");
const relativeTo = path.join(ctx.pluginBasePath, "__placeholder__.js");
@ -1003,6 +1053,7 @@ class ConfigArrayFactory {
if (plugin) {
return new ConfigDependency({
definition: normalizePlugin(plugin),
original: plugin,
filePath: "", // It's unknown where the plugin came from.
id,
importerName: ctx.name,
@ -1014,7 +1065,7 @@ class ConfigArrayFactory {
let error;
try {
filePath = ModuleResolver.resolve(request, relativeTo);
filePath = resolver.resolve(request, relativeTo);
} catch (resolveError) {
error = resolveError;
/* istanbul ignore else */
@ -1039,6 +1090,7 @@ class ConfigArrayFactory {
return new ConfigDependency({
definition: normalizePlugin(pluginDefinition),
original: pluginDefinition,
filePath,
id,
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>
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const { ExtractedConfig } = require("./extracted-config");
const { IgnorePattern } = require("./ignore-pattern");
import { ExtractedConfig } from "./extracted-config.js";
import { IgnorePattern } from "./ignore-pattern.js";
//------------------------------------------------------------------------------
// Helpers
@ -504,21 +503,21 @@ class ConfigArray extends Array {
}
}
const exportObject = {
ConfigArray,
/**
/**
* Get the used extracted configs.
* CLIEngine will use this method to collect used deprecated rules.
* @param {ConfigArray} instance The config array object to get.
* @returns {ExtractedConfig[]} The used extracted configs.
* @private
*/
getUsedExtractedConfigs(instance) {
function getUsedExtractedConfigs(instance) {
const { cache } = internalSlotsMap.get(instance);
return Array.from(cache.values());
}
};
}
module.exports = exportObject;
export {
ConfigArray,
getUsedExtractedConfigs
};

View File

@ -14,9 +14,8 @@
*
* @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.
@ -29,6 +28,7 @@ class ConfigDependency {
* Initialize this instance.
* @param {Object} data The dependency data.
* @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 {string} [data.filePath] The actual path to the dependency if the loading succeeded.
* @param {string} data.id The ID of this dependency.
@ -37,6 +37,7 @@ class ConfigDependency {
*/
constructor({
definition = null,
original = null,
error = null,
filePath = null,
id,
@ -50,6 +51,12 @@ class ConfigDependency {
*/
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.
* @type {Error|null}
@ -102,7 +109,8 @@ class ConfigDependency {
*/
[util.inspect.custom]() {
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
} = this;
@ -113,4 +121,4 @@ class ConfigDependency {
/** @typedef {ConfigDependency<import("../../shared/types").Parser>} DependentParser */
/** @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>
*/
"use strict";
const { IgnorePattern } = require("./ignore-pattern");
import { IgnorePattern } from "./ignore-pattern.js";
// For VSCode intellisense
/** @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>
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const assert = require("assert");
const path = require("path");
const ignore = require("ignore");
const debug = require("debug")("eslintrc:ignore-pattern");
import assert from "assert";
import path from "path";
import ignore from "ignore";
import debugOrig from "debug";
const debug = debugOrig("eslintrc:ignore-pattern");
/** @typedef {ReturnType<import("ignore").default>} Ignore */
@ -155,8 +156,8 @@ class IgnorePattern {
const patterns = [].concat(
...ignorePatterns.map(p => p.getPatternsRelativeTo(basePath))
);
const ig = ignore().add([...DotPatterns, ...patterns]);
const dotIg = ignore().add(patterns);
const ig = ignore({ allowRelativePaths: true }).add([...DotPatterns, ...patterns]);
const dotIg = ignore({ allowRelativePaths: true }).add(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.
* @author Toru Nagashima <https://github.com/mysticatea>
*/
"use strict";
const { ConfigArray, getUsedExtractedConfigs } = require("./config-array");
const { ConfigDependency } = require("./config-dependency");
const { ExtractedConfig } = require("./extracted-config");
const { IgnorePattern } = require("./ignore-pattern");
const { OverrideTester } = require("./override-tester");
import { ConfigArray, getUsedExtractedConfigs } from "./config-array.js";
import { ConfigDependency } from "./config-dependency.js";
import { ExtractedConfig } from "./extracted-config.js";
import { IgnorePattern } from "./ignore-pattern.js";
import { OverrideTester } from "./override-tester.js";
module.exports = {
export {
ConfigArray,
ConfigDependency,
ExtractedConfig,

View File

@ -16,12 +16,14 @@
*
* @author Toru Nagashima <https://github.com/mysticatea>
*/
"use strict";
const assert = require("assert");
const path = require("path");
const util = require("util");
const { Minimatch } = require("minimatch");
import assert from "assert";
import path from "path";
import util from "util";
import minimatch from "minimatch";
const { Minimatch } = minimatch;
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
*/
"use strict";
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
const path = require("path");
const environments = require("../conf/environments");
const createDebug = require("debug");
const { ConfigArrayFactory } = require("./config-array-factory");
import createDebug from "debug";
import path from "path";
import environments from "../conf/environments.js";
import { ConfigArrayFactory } from "./config-array-factory.js";
//-----------------------------------------------------------------------------
// Helpers
@ -54,17 +53,6 @@ function translateESLintRC(eslintrcConfig, {
const languageOptionsKeysToCopy = ["globals", "parser", "parserOptions"];
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
for (const key of keysToCopy) {
if (key in eslintrcConfig && typeof eslintrcConfig[key] !== "undefined") {
@ -144,7 +132,7 @@ function translateESLintRC(eslintrcConfig, {
debug(`Translating plugin: ${pluginName}`);
debug(`Resolving plugin '${pluginName} relative to ${resolvePluginsRelativeTo}`);
const { definition: plugin, error } = eslintrcConfig.plugins[pluginName];
const { original: plugin, error } = eslintrcConfig.plugins[pluginName];
if (error) {
throw error;
@ -180,14 +168,20 @@ function translateESLintRC(eslintrcConfig, {
if (environments.has(envName)) {
// built-in environments should be defined first
configs.unshift(...translateESLintRC(environments.get(envName), {
configs.unshift(...translateESLintRC({
criteria: eslintrcConfig.criteria,
...environments.get(envName)
}, {
resolveConfigRelativeTo,
resolvePluginsRelativeTo
}));
} else if (pluginEnvironments.has(envName)) {
// 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,
resolvePluginsRelativeTo
}));
@ -216,15 +210,31 @@ class FlatCompat {
constructor({
baseDirectory = process.cwd(),
resolvePluginsRelativeTo = baseDirectory
resolvePluginsRelativeTo = baseDirectory,
recommendedConfig,
allConfig
} = {}) {
this.baseDirectory = baseDirectory;
this.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
this[cafactory] = new ConfigArrayFactory({
cwd: baseDirectory,
resolvePluginsRelativeTo,
eslintAllPath: path.resolve(__dirname, "../conf/eslint-all.js"),
eslintRecommendedPath: path.resolve(__dirname, "../conf/eslint-recommended.js")
getEslintAllConfig: () => {
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.
* @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) {
return this.config({
@ -285,7 +295,7 @@ class FlatCompat {
/**
* Translates the `extends` section of an ESLintRC-style config.
* @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) {
return this.config({
@ -296,7 +306,7 @@ class FlatCompat {
/**
* Translates the `plugins` section of an ESLintRC-style config.
* @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) {
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
* @author Nicholas C. Zakas
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const {
import {
ConfigArrayFactory,
createContext: createConfigArrayFactoryContext
} = require("./config-array-factory");
createContext as createConfigArrayFactoryContext
} from "./config-array-factory.js";
const { CascadingConfigArrayFactory } = require("./cascading-config-array-factory");
const ModuleResolver = require("./shared/relative-module-resolver");
const { ConfigArray, getUsedExtractedConfigs } = require("./config-array");
const { ConfigDependency } = require("./config-array/config-dependency");
const { ExtractedConfig } = require("./config-array/extracted-config");
const { IgnorePattern } = require("./config-array/ignore-pattern");
const { OverrideTester } = require("./config-array/override-tester");
const ConfigOps = require("./shared/config-ops");
const ConfigValidator = require("./shared/config-validator");
const naming = require("./shared/naming");
const { FlatCompat } = require("./flat-compat");
import { CascadingConfigArrayFactory } from "./cascading-config-array-factory.js";
import * as ModuleResolver from "./shared/relative-module-resolver.js";
import { ConfigArray, getUsedExtractedConfigs } from "./config-array/index.js";
import { ConfigDependency } from "./config-array/config-dependency.js";
import { ExtractedConfig } from "./config-array/extracted-config.js";
import { IgnorePattern } from "./config-array/ignore-pattern.js";
import { OverrideTester } from "./config-array/override-tester.js";
import * as ConfigOps from "./shared/config-ops.js";
import ConfigValidator from "./shared/config-validator.js";
import * as naming from "./shared/naming.js";
import { FlatCompat } from "./flat-compat.js";
import environments from "../conf/environments.js";
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
module.exports = {
Legacy: {
const Legacy = {
ConfigArray,
createConfigArrayFactoryContext,
CascadingConfigArrayFactory,
@ -41,13 +38,18 @@ module.exports = {
IgnorePattern,
OverrideTester,
getUsedExtractedConfigs,
environments,
// shared
ConfigOps,
ConfigValidator,
ModuleResolver,
naming
},
};
export {
Legacy,
FlatCompat

View File

@ -2,20 +2,177 @@
* @fileoverview The instance of Ajv validator.
* @author Evgeny Poberezkin
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const Ajv = require("ajv"),
metaSchema = require("ajv/lib/refs/json-schema-draft-04.json");
import Ajv from "ajv";
//-----------------------------------------------------------------------------
// 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
//------------------------------------------------------------------------------
module.exports = (additionalOptions = {}) => {
export default (additionalOptions = {}) => {
const ajv = new Ajv({
meta: false,
useDefaults: true,

View File

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

View File

@ -3,22 +3,21 @@
* @author Brandon Mills
*/
"use strict";
/* eslint class-methods-use-this: "off" */
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const
util = require("util"),
configSchema = require("../../conf/config-schema"),
BuiltInEnvironments = require("../../conf/environments"),
ConfigOps = require("./config-ops"),
{ emitDeprecationWarning } = require("./deprecation-warnings");
import util from "util";
import * as ConfigOps from "./config-ops.js";
import { emitDeprecationWarning } from "./deprecation-warnings.js";
import ajvOrig from "./ajv.js";
import configSchema from "../../conf/config-schema.js";
import BuiltInEnvironments from "../../conf/environments.js";
const ajv = ajvOrig();
const ajv = require("./ajv")();
const ruleValidators = new WeakMap();
const noop = Function.prototype;
@ -38,7 +37,7 @@ const validated = new WeakSet();
// Exports
//-----------------------------------------------------------------------------
module.exports = class ConfigValidator {
export default class ConfigValidator {
constructor({ builtInRules = new Map() } = {}) {
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.
* @author Toru Nagashima <http://github.com/mysticatea>
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const path = require("path");
import path from "path";
//------------------------------------------------------------------------------
// Private
@ -59,6 +58,6 @@ function emitDeprecationWarning(source, errorCode) {
// Public Interface
//------------------------------------------------------------------------------
module.exports = {
export {
emitDeprecationWarning
};

View File

@ -1,7 +1,6 @@
/**
* @fileoverview Common helpers for naming of plugins, formatters and configs
*/
"use strict";
const NAMESPACE_REGEX = /^@.*\//iu;
@ -90,7 +89,7 @@ function getNamespaceFromTerm(term) {
// Public Interface
//------------------------------------------------------------------------------
module.exports = {
export {
normalizePackageName,
getShorthandName,
getNamespaceFromTerm

View File

@ -3,27 +3,22 @@
* @author Teddy Katz
*/
"use strict";
const Module = require("module");
import Module from "module";
/*
* `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.
*/
// eslint-disable-next-line node/no-unsupported-features/node-builtins, node/no-deprecated-api
const createRequire = Module.createRequire || Module.createRequireFromPath;
const createRequire = Module.createRequire;
module.exports = {
/**
/**
* Resolves a Node module relative to another module
* @param {string} moduleName The name of a Node module, or a path to a Node module.
* @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
* a file rather than a directory, but the file need not actually exist.
* @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
*/
resolve(moduleName, relativeToPath) {
function resolve(moduleName, relativeToPath) {
try {
return createRequire(relativeToPath).resolve(moduleName);
} catch (error) {
@ -40,5 +35,8 @@ module.exports = {
}
throw error;
}
}
}
export {
resolve
};

View File

@ -2,10 +2,9 @@
* @fileoverview Define common types for input completion.
* @author Toru Nagashima <https://github.com/mysticatea>
*/
"use strict";
/** @type {any} */
module.exports = {};
export default {};
/** @typedef {boolean | "off" | "readable" | "readonly" | "writable" | "writeable"} GlobalConf */
/** @typedef {0 | 1 | 2 | "off" | "warn" | "error"} SeverityConf */

View File

@ -1,27 +1,44 @@
{
"name": "@eslint/eslintrc",
"version": "0.4.3",
"version": "2.1.4",
"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": [
"lib",
"conf",
"LICENSE"
"LICENSE",
"dist",
"universal.js"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "rollup -c",
"lint": "eslint . --report-unused-disable-directives",
"fix": "npm run lint -- --fix",
"test": "mocha -R progress -c 'tests/lib/**/*.js'",
"generate-release": "eslint-generate-release",
"generate-alpharelease": "eslint-generate-prerelease alpha",
"generate-betarelease": "eslint-generate-prerelease beta",
"generate-rcrelease": "eslint-generate-prerelease rc",
"publish-release": "eslint-publish-release"
"lint:fix": "npm run lint -- --fix",
"prepare": "npm run build",
"release:generate:latest": "eslint-generate-release",
"release:generate:alpha": "eslint-generate-prerelease alpha",
"release:generate:beta": "eslint-generate-prerelease beta",
"release:generate:rc": "eslint-generate-prerelease rc",
"release:publish": "eslint-publish-release",
"test": "mocha -R progress -c 'tests/lib/*.cjs' && c8 mocha -R progress -c 'tests/lib/**/*.js'"
},
"repository": "eslint/eslintrc",
"funding": "https://opencollective.com/eslint",
"keywords": [
"ESLint",
"ESLintRC",
@ -34,30 +51,32 @@
},
"homepage": "https://github.com/eslint/eslintrc#readme",
"devDependencies": {
"chai": "^4.2.0",
"eslint": "^7.21.0",
"c8": "^7.7.3",
"chai": "^4.3.4",
"eslint": "^7.31.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-release": "^3.1.2",
"fs-teardown": "0.1.1",
"mocha": "^8.1.1",
"eslint-release": "^3.2.0",
"fs-teardown": "^0.1.3",
"mocha": "^9.0.3",
"rollup": "^2.70.1",
"shelljs": "^0.8.4",
"sinon": "^9.2.0",
"sinon": "^11.1.2",
"temp-dir": "^2.0.0"
},
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.1.1",
"espree": "^7.3.0",
"globals": "^13.9.0",
"ignore": "^4.0.6",
"debug": "^4.3.2",
"espree": "^9.6.0",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^3.13.1",
"minimatch": "^3.0.4",
"js-yaml": "^4.1.0",
"minimatch": "^3.1.2",
"strip-json-comments": "^3.1.1"
},
"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",
"version": "9.8.0",
"version": "9.9.0",
"description": "ESLint JavaScript language implementation",
"main": "./src/index.js",
"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
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
const configFilename = path.resolve(process.cwd(), "my.config.js");
@ -106,14 +106,17 @@ const configs = new ConfigArray(rawConfigs, {
// the path to match filenames from
basePath: process.cwd(),
// additional items in each config
schema: mySchema
// additional item schemas in each config
schema: mySchema,
// additional config types supported (default: [])
extraConfigTypes: ["array", "function"];
});
```
### 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
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 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 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
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.
**Note:** Config functions cannot be async. This will be added in a future version.
**Note:** Config functions can also be async.
### 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.
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.
### 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.
* 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.
* 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

View File

@ -1,12 +1,8 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var path = _interopDefault(require('path'));
var minimatch = _interopDefault(require('minimatch'));
var createDebug = _interopDefault(require('debug'));
var path = require('path');
var minimatch = require('minimatch');
var createDebug = require('debug');
var objectSchema = require('@humanwhocodes/object-schema');
/**
@ -18,31 +14,13 @@ var objectSchema = require('@humanwhocodes/object-schema');
// Helpers
//------------------------------------------------------------------------------
/**
* Assets 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.');
}
}
/**
* 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.');
}
}
const NOOP_STRATEGY = {
required: false,
merge() {
return undefined;
},
validate() { }
};
//------------------------------------------------------------------------------
// 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: {
required: false,
merge() {
@ -72,7 +110,7 @@ const baseSchema = Object.freeze({
validate(value) {
// first check if it's an array
assertIsArray(value);
assertIsNonEmptyArray(value);
// then check each member
value.forEach(item => {
@ -99,16 +137,25 @@ const baseSchema = Object.freeze({
* @author Nicholas C. Zakas
*/
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const Minimatch = minimatch.Minimatch;
const minimatchCache = new Map();
const negatedMinimatchCache = new Map();
const debug = createDebug('@hwc/config-array');
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.
* @param {any} value The value to check.
@ -118,27 +165,143 @@ function isString(value) {
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
* that are found inside.
* @param {Array} items The items in a `ConfigArray`.
* @param {Object} context The context object to pass into any function
* 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.
*/
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) {
if (typeof item === 'function') {
if (!allowFunctions) {
throw new TypeError('Unexpected function.');
}
item = item(context);
if (item.then) {
item = await 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') {
throw new TypeError('A config function can only return an object or array.');
} else {
@ -150,43 +313,111 @@ async function normalize(items, context) {
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
* 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
* `ignores`.
* @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 pathMatches(filePath, basePath, config) {
// a config without a `files` field always matches
if (!config.files) {
return true;
}
// 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.');
}
/*
* 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);
// match both strings and functions
const match = pattern => {
if (isString(pattern)) {
return minimatch(relativeFilePath, pattern, MINIMATCH_OPTIONS);
return doMatch(relativeFilePath, pattern);
}
if (typeof pattern === 'function') {
return pattern(filePath);
}
throw new TypeError(`Unexpected matcher type ${pattern}.`);
};
// check for all matches to config.files
let matches = config.files.some(pattern => {
let filePathMatchesPattern = config.files.some(pattern => {
if (Array.isArray(pattern)) {
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 there are any files to ignore.
*/
if (matches && config.ignores) {
matches = !config.ignores.some(pattern => {
return minimatch(filePath, pattern, MINIMATCH_OPTIONS);
});
if (filePathMatchesPattern && config.ignores) {
filePathMatchesPattern = !shouldIgnorePath(config.ignores, filePath, relativeFilePath);
}
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
//------------------------------------------------------------------------------
@ -232,6 +479,9 @@ const ConfigArraySymbol = {
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
* those config objects.
@ -247,8 +497,15 @@ class ConfigArray extends Array {
* configs have already been normalized.
* @param {Object} [options.schema] The additional 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();
/**
@ -265,10 +522,9 @@ class ConfigArray extends Array {
* @type ObjectSchema
* @private
*/
this[ConfigArraySymbol.schema] = new objectSchema.ObjectSchema({
...customSchema,
...baseSchema
});
this[ConfigArraySymbol.schema] = new objectSchema.ObjectSchema(
Object.assign({}, customSchema, baseSchema)
);
/**
* The path of the config file that this array was loaded from.
@ -278,6 +534,15 @@ class ConfigArray extends Array {
*/
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.
* @property configCache
@ -286,6 +551,14 @@ class ConfigArray extends Array {
*/
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
if (Array.isArray(configs)) {
this.push(...configs);
@ -308,54 +581,79 @@ class ConfigArray extends 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
* config array or to use as a glob pattern when no patterns are provided
* for a command line interface.
* @returns {string[]} An array of string patterns.
* @returns {Array<string|Function>} An array of matchers.
*/
get files() {
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 = [];
for (const config of this) {
if (config.files) {
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);
}
});
}
}
// store result
cache.files = result;
dataCache.set(this, cache);
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 behavior of things like .gitignore and .eslintignore, allowing a
* 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() {
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 = [];
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;
}
@ -371,14 +669,37 @@ class ConfigArray extends Array {
* Normalizes a config array by flattening embedded arrays and executing
* 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 = {}) {
if (!this.isNormalized()) {
const normalizedConfigs = await normalize(this, context);
const normalizedConfigs = await normalize(this, context, this.extraConfigTypes);
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;
// prevent further changes
@ -411,6 +732,56 @@ class ConfigArray extends Array {
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.
* @param {string} filePath The complete path of a file to get a config for.
@ -420,37 +791,239 @@ class ConfigArray extends Array {
assertNormalized(this);
// first check the cache to avoid duplicate work
let finalConfig = this[ConfigArraySymbol.configCache].get(filePath);
const cache = this[ConfigArraySymbol.configCache];
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;
}
// 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)) {
debug(`Matching config found for ${filePath}`);
matchingConfigs.push(config);
} else {
debug(`No matching config found for ${filePath}`);
}
matchingConfigIndices.push(index);
matchFound = true;
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);
finalConfig = this[ConfigArraySymbol.finalizeConfig](finalConfig);
this[ConfigArraySymbol.configCache].set(filePath, finalConfig);
cache.set(filePath, finalConfig);
cache.set(matchingConfigIndices.toString(), 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;

View File

@ -1,6 +1,6 @@
{
"name": "@humanwhocodes/config-array",
"version": "0.5.0",
"version": "0.11.14",
"description": "Glob-based configuration matching.",
"author": "Nicholas C. Zakas",
"main": "api.js",
@ -19,6 +19,7 @@
"build": "rollup -c",
"format": "nitpik",
"lint": "eslint *.config.js src/*.js tests/*.js",
"lint:fix": "eslint --fix *.config.js src/*.js tests/*.js",
"prepublish": "npm run build",
"test:coverage": "nyc --include src/*.js npm run test",
"test": "mocha -r esm tests/ --recursive"
@ -28,7 +29,6 @@
},
"lint-staged": {
"*.js": [
"nitpik",
"eslint --fix --ignore-pattern '!.eslintrc.js'"
]
},
@ -42,20 +42,20 @@
"node": ">=10.10.0"
},
"dependencies": {
"@humanwhocodes/object-schema": "^1.2.0",
"debug": "^4.1.1",
"minimatch": "^3.0.4"
"@humanwhocodes/object-schema": "^2.0.2",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
"devDependencies": {
"@nitpik/javascript": "^0.3.3",
"@nitpik/javascript": "0.4.0",
"@nitpik/node": "0.0.5",
"chai": "^4.2.0",
"eslint": "^6.7.1",
"esm": "^3.2.25",
"lint-staged": "^10.2.8",
"mocha": "^6.1.4",
"nyc": "^14.1.1",
"rollup": "^1.12.3",
"yorkie": "^2.0.0"
"chai": "4.3.10",
"eslint": "8.52.0",
"esm": "3.2.25",
"lint-staged": "15.0.2",
"mocha": "6.2.3",
"nyc": "15.1.0",
"rollup": "3.28.1",
"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
## [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)

View File

@ -1,8 +1,13 @@
{
"name": "@humanwhocodes/object-schema",
"version": "1.2.1",
"version": "2.0.3",
"description": "An object schema merger/validator",
"main": "src/index.js",
"files": [
"src",
"LICENSE",
"README.md"
],
"directories": {
"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
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"))) {
throw new Error("All arguments must be objects.");
throw new TypeError("All arguments must be objects.");
}
return objects.reduce((result, object) => {
@ -179,8 +247,7 @@ class ObjectSchema {
}
}
} catch (ex) {
ex.message = `Key "${key}": ` + ex.message;
throw ex;
throw new WrapperError(key, ex);
}
}
return result;
@ -200,7 +267,7 @@ class ObjectSchema {
// check to see if the key is defined
if (!this.hasKey(key)) {
throw new Error(`Unexpected key "${key}" found.`);
throw new UnexpectedKeyError(key);
}
// validate existing keys
@ -209,7 +276,7 @@ class ObjectSchema {
// first check to see if any other keys are required
if (Array.isArray(strategy.requires)) {
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 {
strategy.validate.call(strategy, object[key]);
} catch (ex) {
ex.message = `Key "${key}": ` + ex.message;
throw ex;
throw new WrapperError(key, ex);
}
}
// ensure required keys aren't missing
for (const [key] of this[requiredKeys]) {
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)
### New features

2
node_modules/acorn/LICENSE generated vendored
View File

@ -1,6 +1,6 @@
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
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
[report bugs](https://github.com/acornjs/acorn/issues) or create pull
requests on [github](https://github.com/acornjs/acorn). For questions
and discussion, please use the
[Tern discussion forum](https://discuss.ternjs.net).
requests on [github](https://github.com/acornjs/acorn).
## Installation
@ -32,14 +30,14 @@ npm install
## Interface
**parse**`(input, options)` is the main interface to the library. The
`input` parameter is a string, `options` can be undefined or an object
setting some of the options listed below. The return value will be an
abstract syntax tree object as specified by the [ESTree
`input` parameter is a string, `options` must be an object setting
some of the options listed below. The return value will be an abstract
syntax tree object as specified by the [ESTree
spec](https://github.com/estree/estree).
```javascript
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
@ -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}`
object referring to that same position.
Options can be provided by passing a second argument, which should be
an object containing any of these fields:
Options are provided by in a second argument, which should be an
object containing any of these fields (only `ecmaVersion` is
required):
- **ecmaVersion**: Indicates the ECMAScript version to parse. Must be
either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), 10 (2019) or 11
(2020, partial support). This influences support for strict mode,
the set of reserved words, and support for new syntax features.
Default is 10.
- **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.
**NOTE**: Only 'stage 4' (finalized) ECMAScript features are being
implemented by Acorn. Other proposed new features can be implemented
through plugins.
implemented by Acorn. Other proposed new features must be
implemented through plugins.
- **sourceType**: Indicate the mode the code should be parsed in. Can be
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`
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
only appear inside `async` functions. Setting this option to
`true` allows to have top-level `await` expressions. They are
still not allowed in non-`async` functions, though.
- **allowAwaitOutsideFunction**: If `false`, `await` expressions can
only appear inside `async` functions. Defaults to `true` in modules
for `ecmaVersion` 2022 and later, `false` for lower versions.
Setting this option to `true` allows to have top-level `await`
expressions. They are still not allowed in non-`async` functions,
though.
- **allowHashBang**: When this is enabled (off by default), if the
code starts with the characters `#!` (as in a shellscript), the
first line will be treated as a comment.
- **allowSuperOutsideMethod**: By default, `super` outside a method
raises an error. Set this to `true` to accept such code.
- **allowHashBang**: When this is enabled, if the code starts with the
characters `#!` (as in a shellscript), the first line will be
treated as a comment. Defaults to true when `ecmaVersion` >= 2023.
- **checkPrivateFields**: By default, the parser will verify that
private properties are only used in places where they are valid and
have been declared. Set this to false to turn such checks off.
- **locations**: When `true`, each node has a `loc` object attached
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
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
protocol-compliant iterable:
@ -224,7 +241,7 @@ you can use its static `extend` method.
var acorn = require("acorn");
var jsx = require("acorn-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
@ -249,6 +266,9 @@ options:
- `--allow-hash-bang`: If the code starts with the characters #! (as
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.
- `--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
- [`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
'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 = acorn
export interface Node {
start: number
end: number
type: string
range?: [number, number]
loc?: SourceLocation | null
}
declare namespace acorn {
function parse(input: string, options?: Options): Node
export interface SourceLocation {
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
[Symbol.iterator](): Iterator<Token>
}
}
interface Options {
ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020
sourceType?: 'script' | 'module'
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"
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
/**
* 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
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
/**
* 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
/**
* 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
/**
* 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
/**
* 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
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?: ((
isBlock: boolean, text: string, start: number, end: number, startLoc?: Position,
endLoc?: Position
) => void) | Comment[]
ranges?: boolean
program?: Node
sourceFile?: string
directSourceFile?: string
preserveParens?: boolean
}
class Parser {
constructor(options: Options, input: string, startPos?: number)
parse(this: Parser): Node
static parse(this: typeof Parser, input: string, options?: Options): Node
static parseExpressionAt(this: typeof Parser, input: string, pos: number, options?: Options): Node
static tokenizer(this: typeof Parser, input: string, options?: Options): {
/**
* Nodes have their start and end characters offsets recorded in
* `start` and `end` properties (directly on the node, rather than
* the `loc` object, which holds line/column data. To also add a
* [semi-standardized][range] `range` property holding a `[start,
* 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
[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
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 {
export class TokenType {
label: string
keyword: string
beforeExpr: boolean
startsExpr: boolean
isLoop: boolean
isAssign: boolean
prefix: boolean
postfix: boolean
binop: number
updateContext?: (prevType: TokenType) => void
constructor(label: string, conf?: any)
}
keyword: string | undefined
}
const tokTypes: {
export const tokTypes: {
num: TokenType
regexp: TokenType
string: TokenType
name: TokenType
privateId: TokenType
eof: TokenType
bracketL: TokenType
bracketR: TokenType
braceL: TokenType
@ -100,11 +772,14 @@ declare namespace acorn {
colon: TokenType
dot: TokenType
question: TokenType
questionDot: TokenType
arrow: TokenType
template: TokenType
invalidTemplate: TokenType
ellipsis: TokenType
backQuote: TokenType
dollarBraceL: TokenType
eq: TokenType
assign: TokenType
incDec: TokenType
@ -122,6 +797,8 @@ declare namespace acorn {
star: TokenType
slash: TokenType
starstar: TokenType
coalesce: TokenType
_break: TokenType
_case: TokenType
_catch: TokenType
@ -157,53 +834,23 @@ declare namespace acorn {
_typeof: TokenType
_void: TokenType
_delete: TokenType
}
}
class TokContext {
constructor(token: string, isExpr: boolean, preserveSpace: boolean, override?: (p: Parser) => void)
}
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
export interface Comment {
type: "Line" | "Block"
value: string
start: number
end: number
loc?: SourceLocation
range?: [number, number]
}
}
class Token {
export class Token {
type: TokenType
value: any
start: number
end: number
loc?: SourceLocation
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 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 = {};
function help(status) {
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(" [--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);
}
for (var i = 2; i < process.argv.length; ++i) {
var arg = process.argv[i];
if ((arg === "-" || arg[0] !== "-") && !infile) { infile = arg; }
else if (arg === "--" && !infile && i + 2 === process.argv.length) { forceFile = infile = process.argv[++i]; }
else if (arg === "--locations") { options.locations = true; }
if (arg[0] !== "-" || arg === "-") { inputFilePaths.push(arg); }
else if (arg === "--") {
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-await-outside-function") { options.allowAwaitOutsideFunction = true; }
else if (arg === "--silent") { silent = true; }
else if (arg === "--compact") { compact = true; }
else if (arg === "--help") { help(0); }
@ -34,31 +57,34 @@ for (var i = 2; i < process.argv.length; ++i) {
}
}
function run(code) {
var result;
function run(codeList) {
var result = [], fileIdx = 0;
try {
codeList.forEach(function (code, idx) {
fileIdx = idx;
if (!tokenize) {
result = acorn.parse(code, options);
result = acorn__namespace.parse(code, options);
options.program = result;
} else {
result = [];
var tokenizer = acorn.tokenizer(code, options), token;
var tokenizer = acorn__namespace.tokenizer(code, options), token;
do {
token = tokenizer.getToken();
result.push(token);
} while (token.type !== acorn.tokTypes.eof)
} while (token.type !== acorn__namespace.tokTypes.eof)
}
});
} 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);
}
if (!silent) { console.log(JSON.stringify(result, null, compact ? null : 2)); }
}
if (forceFile || infile && infile !== "-") {
run(fs.readFileSync(infile, "utf8"));
if (fileMode = inputFilePaths.length && (forceFileName || !inputFilePaths.includes("-") || inputFilePaths.length !== 1)) {
run(inputFilePaths.map(function (path) { return fs.readFileSync(path, "utf8"); }));
} else {
var code = "";
process.stdin.resume();
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",
"types": "dist/acorn.d.ts",
"module": "dist/acorn.mjs",
"version": "7.4.1",
"engines": {"node": ">=0.4.0"},
"exports": {
".": [
{
"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": [
{
"name": "Marijn Haverbeke",
@ -25,11 +38,13 @@
],
"repository": {
"type": "git",
"url": "https://github.com/acornjs/acorn.git"
"url": "git+https://github.com/acornjs/acorn.git"
},
"license": "MIT",
"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.
1.0.9 / 2016-09-29
------------------
## [1.0.9] - 2016-09-29
### Changed
- 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).
1.0.7 / 2016-03-17
------------------
## [1.0.7] - 2016-03-17
### Changed
- 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.
1.0.5 / 2016-02-05
------------------
## [1.0.5] - 2016-02-05
### Changed
- Removed lodash dependency to significantly reduce install size.
Thanks to @mourner.
1.0.4 / 2016-01-17
------------------
## [1.0.4] - 2016-01-17
### Changed
- 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.
1.0.2 / 2015-03-22
------------------
## [1.0.2] - 2015-03-22
### Changed
- 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.
1.0.0 / 2015-02-19
------------------
## [1.0.0] - 2015-02-19
### Changed
- Maintenance release.
- Replaced `underscore` with `lodash`.
- Bumped version to 1.0.0 to better reflect semver meaning.
- HISTORY.md -> CHANGELOG.md
0.1.16 / 2013-12-01
-------------------
## [0.1.16] - 2013-12-01
### Changed
- Maintenance release. Updated dependencies and docs.
0.1.15 / 2013-05-13
-------------------
## [0.1.15] - 2013-05-13
### Fixed
- Fixed #55, @trebor89
0.1.14 / 2013-05-12
-------------------
## [0.1.14] - 2013-05-12
### Fixed
- Fixed #62, @maxtaco
0.1.13 / 2013-04-08
-------------------
## [0.1.13] - 2013-04-08
### Changed
- Added `.npmignore` to reduce package size
0.1.12 / 2013-02-10
-------------------
## [0.1.12] - 2013-02-10
### Fixed
- Fixed conflictHandler (#46), @hpaulj
0.1.11 / 2013-02-07
-------------------
- Multiple bugfixes, @hpaulj
## [0.1.11] - 2013-02-07
### Added
- Added 70+ tests (ported from python), @hpaulj
- Added conflictHandler, @applepicke
- 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)
support, thanks to @hpaulj
### Fixed
- 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 default value behavior with `*` positionals, 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 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 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)
0.1.5 / 2012-09-03
------------------
## [0.1.5] - 2012-09-03
### Fixed
- 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 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
0.1.2 / 2012-05-29
------------------
- Added basic tests
## [0.1.2] - 2012-05-29
### Fixed
- Removed excess whitespace in help
- Fixed error reporting, when parcer with subcommands
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
- Added better error reporting on invalid arguments
0.1.0 / 2012-05-16
------------------
## [0.1.0] - 2012-05-16
### Added
- 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
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:
In 1995, Guido continued his work on Python at the Corporation for
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
in Reston, Virginia where he released several versions of the
software.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
In May 2000, Guido and the Python core development team moved to
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
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.
All Python releases are Open Source (see http://www.opensource.org for
the Open Source Definition). Historically, most, but not all, Python
releases have also been GPL-compatible; the table below summarizes
the various releases.
Release Derived Year Owner GPL-
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)
[![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
[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.
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)).
**NB. Difference with original.**
**Difference with original.**
- Method names changed to camelCase. See [generated docs](http://nodeca.github.com/argparse/).
- Use `defaultValue` instead of `default`.
- Use `argparse.Const.REMAINDER` instead of `argparse.REMAINDER`, and
similarly for constant values `OPTIONAL`, `ZERO_OR_MORE`, and `ONE_OR_MORE`
(aliases for `nargs` values `'?'`, `'*'`, `'+'`, respectively), and
`SUPPRESS`.
- JS has no keyword arguments support.
- Pass options instead: `new ArgumentParser({ description: 'example', add_help: true })`.
- JS has no python's types `int`, `float`, ...
- Use string-typed names: `.add_argument('-b', { type: 'int', help: 'help' })`.
- `%r` format specifier uses `require('util').inspect()`.
More details in [doc](./doc).
Example
=======
-------
test.js file:
`test.js` file:
```javascript
#!/usr/bin/env node
'use strict';
var ArgumentParser = require('../lib/argparse').ArgumentParser;
var parser = new ArgumentParser({
version: '0.0.1',
addHelp:true,
const { ArgumentParser } = require('argparse');
const { version } = require('./package.json');
const parser = new ArgumentParser({
description: 'Argparse example'
});
parser.addArgument(
[ '-f', '--foo' ],
{
help: 'foo bar'
}
);
parser.addArgument(
[ '-b', '--bar' ],
{
help: 'bar foo'
}
);
parser.addArgument(
'--baz',
{
help: 'baz bar'
}
);
var args = parser.parseArgs();
console.dir(args);
parser.add_argument('-v', '--version', { action: 'version', version });
parser.add_argument('-f', '--foo', { help: 'foo bar' });
parser.add_argument('-b', '--bar', { help: 'bar foo' });
parser.add_argument('--baz', { help: 'baz bar' });
console.dir(parser.parse_args());
```
Display help:
```
$ ./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
Optional arguments:
-h, --help Show this help message and exit.
-v, --version Show program's version number and exit.
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-f FOO, --foo FOO foo bar
-b BAR, --bar BAR bar foo
--baz BAZ baz bar
@ -79,179 +64,21 @@ $ ./test.js -f=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
======================
```
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.
argparse for enterprise
-----------------------
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