Comparing version 8.51.0 to 8.52.0
{ | ||
"types": [ | ||
{ "name": "problem", "displayName": "Possible Problems", "description": "These rules relate to possible logic errors in code:" }, | ||
{ "name": "suggestion", "displayName": "Suggestions", "description": "These rules suggest alternate ways of doing things:" }, | ||
{ "name": "layout", "displayName": "Layout & Formatting", "description": "These rules care about how the code looks rather than how it executes:" } | ||
], | ||
"deprecated": { | ||
"name": "Deprecated", | ||
"description": "These rules have been deprecated in accordance with the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a>, and replaced by newer rules:", | ||
"rules": [] | ||
"types": { | ||
"problem": [], | ||
"suggestion": [], | ||
"layout": [] | ||
}, | ||
"removed": { | ||
"name": "Removed", | ||
"description": "These rules from older versions of ESLint (before the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a> existed) have been replaced by newer rules:", | ||
"rules": [ | ||
{ "removed": "generator-star", "replacedBy": ["generator-star-spacing"] }, | ||
{ "removed": "global-strict", "replacedBy": ["strict"] }, | ||
{ "removed": "no-arrow-condition", "replacedBy": ["no-confusing-arrow", "no-constant-condition"] }, | ||
{ "removed": "no-comma-dangle", "replacedBy": ["comma-dangle"] }, | ||
{ "removed": "no-empty-class", "replacedBy": ["no-empty-character-class"] }, | ||
{ "removed": "no-empty-label", "replacedBy": ["no-labels"] }, | ||
{ "removed": "no-extra-strict", "replacedBy": ["strict"] }, | ||
{ "removed": "no-reserved-keys", "replacedBy": ["quote-props"] }, | ||
{ "removed": "no-space-before-semi", "replacedBy": ["semi-spacing"] }, | ||
{ "removed": "no-wrap-func", "replacedBy": ["no-extra-parens"] }, | ||
{ "removed": "space-after-function-name", "replacedBy": ["space-before-function-paren"] }, | ||
{ "removed": "space-after-keywords", "replacedBy": ["keyword-spacing"] }, | ||
{ "removed": "space-before-function-parentheses", "replacedBy": ["space-before-function-paren"] }, | ||
{ "removed": "space-before-keywords", "replacedBy": ["keyword-spacing"] }, | ||
{ "removed": "space-in-brackets", "replacedBy": ["object-curly-spacing", "array-bracket-spacing"] }, | ||
{ "removed": "space-return-throw-case", "replacedBy": ["keyword-spacing"] }, | ||
{ "removed": "space-unary-word-ops", "replacedBy": ["space-unary-ops"] }, | ||
{ "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] } | ||
] | ||
} | ||
"deprecated": [], | ||
"removed": [ | ||
{ "removed": "generator-star", "replacedBy": ["generator-star-spacing"] }, | ||
{ "removed": "global-strict", "replacedBy": ["strict"] }, | ||
{ "removed": "no-arrow-condition", "replacedBy": ["no-confusing-arrow", "no-constant-condition"] }, | ||
{ "removed": "no-comma-dangle", "replacedBy": ["comma-dangle"] }, | ||
{ "removed": "no-empty-class", "replacedBy": ["no-empty-character-class"] }, | ||
{ "removed": "no-empty-label", "replacedBy": ["no-labels"] }, | ||
{ "removed": "no-extra-strict", "replacedBy": ["strict"] }, | ||
{ "removed": "no-reserved-keys", "replacedBy": ["quote-props"] }, | ||
{ "removed": "no-space-before-semi", "replacedBy": ["semi-spacing"] }, | ||
{ "removed": "no-wrap-func", "replacedBy": ["no-extra-parens"] }, | ||
{ "removed": "space-after-function-name", "replacedBy": ["space-before-function-paren"] }, | ||
{ "removed": "space-after-keywords", "replacedBy": ["keyword-spacing"] }, | ||
{ "removed": "space-before-function-parentheses", "replacedBy": ["space-before-function-paren"] }, | ||
{ "removed": "space-before-keywords", "replacedBy": ["keyword-spacing"] }, | ||
{ "removed": "space-in-brackets", "replacedBy": ["object-curly-spacing", "array-bracket-spacing"] }, | ||
{ "removed": "space-return-throw-case", "replacedBy": ["keyword-spacing"] }, | ||
{ "removed": "space-unary-word-ops", "replacedBy": ["space-unary-ops"] }, | ||
{ "removed": "spaced-line-comment", "replacedBy": ["spaced-comment"] } | ||
] | ||
} |
@@ -321,3 +321,10 @@ /** | ||
debug("Error parsing CLI options:", error.message); | ||
log.error(error.message); | ||
let errorMessage = error.message; | ||
if (usingFlatConfig) { | ||
errorMessage += "\nYou're using eslint.config.js, some command line flags are no longer available. Please see https://eslint.org/docs/latest/use/command-line-interface for details."; | ||
} | ||
log.error(errorMessage); | ||
return 2; | ||
@@ -324,0 +331,0 @@ } |
@@ -9,2 +9,12 @@ /** | ||
//----------------------------------------------------------------------------- | ||
// Requirements | ||
//----------------------------------------------------------------------------- | ||
/* | ||
* Note: This can be removed in ESLint v9 because structuredClone is available globally | ||
* starting in Node.js v17. | ||
*/ | ||
const structuredClone = require("@ungap/structured-clone").default; | ||
//----------------------------------------------------------------------------- | ||
// Type Definitions | ||
@@ -123,3 +133,3 @@ //----------------------------------------------------------------------------- | ||
finalOptions[0] = ruleSeverities.get(finalOptions[0]); | ||
return finalOptions; | ||
return structuredClone(finalOptions); | ||
} | ||
@@ -383,44 +393,53 @@ | ||
for (const ruleId of Object.keys(result)) { | ||
// avoid hairy edge case | ||
if (ruleId === "__proto__") { | ||
try { | ||
/* eslint-disable-next-line no-proto -- Though deprecated, may still be present */ | ||
delete result.__proto__; | ||
continue; | ||
} | ||
// avoid hairy edge case | ||
if (ruleId === "__proto__") { | ||
result[ruleId] = normalizeRuleOptions(result[ruleId]); | ||
/* eslint-disable-next-line no-proto -- Though deprecated, may still be present */ | ||
delete result.__proto__; | ||
continue; | ||
} | ||
/* | ||
* If either rule config is missing, then the correct | ||
* config is already present and we just need to normalize | ||
* the severity. | ||
*/ | ||
if (!(ruleId in first) || !(ruleId in second)) { | ||
continue; | ||
} | ||
result[ruleId] = normalizeRuleOptions(result[ruleId]); | ||
const firstRuleOptions = normalizeRuleOptions(first[ruleId]); | ||
const secondRuleOptions = normalizeRuleOptions(second[ruleId]); | ||
/* | ||
* If either rule config is missing, then the correct | ||
* config is already present and we just need to normalize | ||
* the severity. | ||
*/ | ||
if (!(ruleId in first) || !(ruleId in second)) { | ||
continue; | ||
} | ||
/* | ||
* If the second rule config only has a severity (length of 1), | ||
* then use that severity and keep the rest of the options from | ||
* the first rule config. | ||
*/ | ||
if (secondRuleOptions.length === 1) { | ||
result[ruleId] = [secondRuleOptions[0], ...firstRuleOptions.slice(1)]; | ||
continue; | ||
const firstRuleOptions = normalizeRuleOptions(first[ruleId]); | ||
const secondRuleOptions = normalizeRuleOptions(second[ruleId]); | ||
/* | ||
* If the second rule config only has a severity (length of 1), | ||
* then use that severity and keep the rest of the options from | ||
* the first rule config. | ||
*/ | ||
if (secondRuleOptions.length === 1) { | ||
result[ruleId] = [secondRuleOptions[0], ...firstRuleOptions.slice(1)]; | ||
continue; | ||
} | ||
/* | ||
* In any other situation, then the second rule config takes | ||
* precedence. That means the value at `result[ruleId]` is | ||
* already correct and no further work is necessary. | ||
*/ | ||
} catch (ex) { | ||
throw new Error(`Key "${ruleId}": ${ex.message}`, { cause: ex }); | ||
} | ||
/* | ||
* In any other situation, then the second rule config takes | ||
* precedence. That means the value at `result[ruleId]` is | ||
* already correct and no further work is necessary. | ||
*/ | ||
} | ||
return result; | ||
}, | ||
@@ -427,0 +446,0 @@ |
@@ -33,3 +33,3 @@ /** | ||
* Groups a set of directives into sub-arrays by their parent comment. | ||
* @param {Directive[]} directives Unused directives to be removed. | ||
* @param {Iterable<Directive>} directives Unused directives to be removed. | ||
* @returns {Directive[][]} Directives grouped by their parent comment. | ||
@@ -181,6 +181,6 @@ */ | ||
* Parses details from directives to create output Problems. | ||
* @param {Directive[]} allDirectives Unused directives to be removed. | ||
* @param {Iterable<Directive>} allDirectives Unused directives to be removed. | ||
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems. | ||
*/ | ||
function processUnusedDisableDirectives(allDirectives) { | ||
function processUnusedDirectives(allDirectives) { | ||
const directiveGroups = groupByParentComment(allDirectives); | ||
@@ -205,2 +205,91 @@ | ||
/** | ||
* Collect eslint-enable comments that are removing suppressions by eslint-disable comments. | ||
* @param {Directive[]} directives The directives to check. | ||
* @returns {Set<Directive>} The used eslint-enable comments | ||
*/ | ||
function collectUsedEnableDirectives(directives) { | ||
/** | ||
* A Map of `eslint-enable` keyed by ruleIds that may be marked as used. | ||
* If `eslint-enable` does not have a ruleId, the key will be `null`. | ||
* @type {Map<string|null, Directive>} | ||
*/ | ||
const enabledRules = new Map(); | ||
/** | ||
* A Set of `eslint-enable` marked as used. | ||
* It is also the return value of `collectUsedEnableDirectives` function. | ||
* @type {Set<Directive>} | ||
*/ | ||
const usedEnableDirectives = new Set(); | ||
/* | ||
* Checks the directives backwards to see if the encountered `eslint-enable` is used by the previous `eslint-disable`, | ||
* and if so, stores the `eslint-enable` in `usedEnableDirectives`. | ||
*/ | ||
for (let index = directives.length - 1; index >= 0; index--) { | ||
const directive = directives[index]; | ||
if (directive.type === "disable") { | ||
if (enabledRules.size === 0) { | ||
continue; | ||
} | ||
if (directive.ruleId === null) { | ||
// If encounter `eslint-disable` without ruleId, | ||
// mark all `eslint-enable` currently held in enabledRules as used. | ||
// e.g. | ||
// /* eslint-disable */ <- current directive | ||
// /* eslint-enable rule-id1 */ <- used | ||
// /* eslint-enable rule-id2 */ <- used | ||
// /* eslint-enable */ <- used | ||
for (const enableDirective of enabledRules.values()) { | ||
usedEnableDirectives.add(enableDirective); | ||
} | ||
enabledRules.clear(); | ||
} else { | ||
const enableDirective = enabledRules.get(directive.ruleId); | ||
if (enableDirective) { | ||
// If encounter `eslint-disable` with ruleId, and there is an `eslint-enable` with the same ruleId in enabledRules, | ||
// mark `eslint-enable` with ruleId as used. | ||
// e.g. | ||
// /* eslint-disable rule-id */ <- current directive | ||
// /* eslint-enable rule-id */ <- used | ||
usedEnableDirectives.add(enableDirective); | ||
} else { | ||
const enabledDirectiveWithoutRuleId = enabledRules.get(null); | ||
if (enabledDirectiveWithoutRuleId) { | ||
// If encounter `eslint-disable` with ruleId, and there is no `eslint-enable` with the same ruleId in enabledRules, | ||
// mark `eslint-enable` without ruleId as used. | ||
// e.g. | ||
// /* eslint-disable rule-id */ <- current directive | ||
// /* eslint-enable */ <- used | ||
usedEnableDirectives.add(enabledDirectiveWithoutRuleId); | ||
} | ||
} | ||
} | ||
} else if (directive.type === "enable") { | ||
if (directive.ruleId === null) { | ||
// If encounter `eslint-enable` without ruleId, the `eslint-enable` that follows it are unused. | ||
// So clear enabledRules. | ||
// e.g. | ||
// /* eslint-enable */ <- current directive | ||
// /* eslint-enable rule-id *// <- unused | ||
// /* eslint-enable */ <- unused | ||
enabledRules.clear(); | ||
enabledRules.set(null, directive); | ||
} else { | ||
enabledRules.set(directive.ruleId, directive); | ||
} | ||
} | ||
} | ||
return usedEnableDirectives; | ||
} | ||
/** | ||
* This is the same as the exported function, except that it | ||
@@ -212,3 +301,3 @@ * doesn't handle disable-line and disable-next-line directives, and it always reports unused | ||
* (this function always reports unused disable directives). | ||
* @returns {{problems: LintMessage[], unusedDisableDirectives: LintMessage[]}} An object with a list | ||
* @returns {{problems: LintMessage[], unusedDirectives: LintMessage[]}} An object with a list | ||
* of problems (including suppressed ones) and unused eslint-disable directives | ||
@@ -265,13 +354,38 @@ */ | ||
const processed = processUnusedDisableDirectives(unusedDisableDirectivesToReport); | ||
const unusedDisableDirectives = processed | ||
const unusedEnableDirectivesToReport = new Set( | ||
options.directives.filter(directive => directive.unprocessedDirective.type === "enable") | ||
); | ||
/* | ||
* If directives has the eslint-enable directive, | ||
* check whether the eslint-enable comment is used. | ||
*/ | ||
if (unusedEnableDirectivesToReport.size > 0) { | ||
for (const directive of collectUsedEnableDirectives(options.directives)) { | ||
unusedEnableDirectivesToReport.delete(directive); | ||
} | ||
} | ||
const processed = processUnusedDirectives(unusedDisableDirectivesToReport) | ||
.concat(processUnusedDirectives(unusedEnableDirectivesToReport)); | ||
const unusedDirectives = processed | ||
.map(({ description, fix, unprocessedDirective }) => { | ||
const { parentComment, type, line, column } = unprocessedDirective; | ||
let message; | ||
if (type === "enable") { | ||
message = description | ||
? `Unused eslint-enable directive (no matching eslint-disable directives were found for ${description}).` | ||
: "Unused eslint-enable directive (no matching eslint-disable directives were found)."; | ||
} else { | ||
message = description | ||
? `Unused eslint-disable directive (no problems were reported from ${description}).` | ||
: "Unused eslint-disable directive (no problems were reported)."; | ||
} | ||
return { | ||
ruleId: null, | ||
message: description | ||
? `Unused eslint-disable directive (no problems were reported from ${description}).` | ||
: "Unused eslint-disable directive (no problems were reported).", | ||
message, | ||
line: type === "disable-next-line" ? parentComment.commentToken.loc.start.line : line, | ||
@@ -285,3 +399,3 @@ column: type === "disable-next-line" ? parentComment.commentToken.loc.start.column + 1 : column, | ||
return { problems, unusedDisableDirectives }; | ||
return { problems, unusedDirectives }; | ||
} | ||
@@ -353,6 +467,6 @@ | ||
? lineDirectivesResult.problems | ||
.concat(blockDirectivesResult.unusedDisableDirectives) | ||
.concat(lineDirectivesResult.unusedDisableDirectives) | ||
.concat(blockDirectivesResult.unusedDirectives) | ||
.concat(lineDirectivesResult.unusedDirectives) | ||
.sort(compareLocations) | ||
: lineDirectivesResult.problems; | ||
}; |
@@ -50,3 +50,3 @@ /** | ||
* @property {string} [printConfig] Print the configuration for the given file | ||
* @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable directives | ||
* @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable and eslint-enable directives | ||
* @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default | ||
@@ -308,3 +308,3 @@ * @property {Object} [rule] Specify rules | ||
default: void 0, | ||
description: "Adds reported errors for unused eslint-disable directives" | ||
description: "Adds reported errors for unused eslint-disable and eslint-enable directives" | ||
}, | ||
@@ -311,0 +311,0 @@ { |
@@ -12,3 +12,3 @@ /** | ||
const { getVariableByName, isArrowToken } = require("./utils/ast-utils"); | ||
const { getVariableByName, isArrowToken, isClosingBraceToken, isClosingParenToken } = require("./utils/ast-utils"); | ||
@@ -19,2 +19,41 @@ //------------------------------------------------------------------------------ | ||
const BREAK_OR_CONTINUE = new Set(["BreakStatement", "ContinueStatement"]); | ||
// Declaration types that must contain a string Literal node at the end. | ||
const DECLARATIONS = new Set(["ExportAllDeclaration", "ExportNamedDeclaration", "ImportDeclaration"]); | ||
const IDENTIFIER_OR_KEYWORD = new Set(["Identifier", "Keyword"]); | ||
// Keywords that can immediately precede an ExpressionStatement node, mapped to the their node types. | ||
const NODE_TYPES_BY_KEYWORD = { | ||
__proto__: null, | ||
break: "BreakStatement", | ||
continue: "ContinueStatement", | ||
debugger: "DebuggerStatement", | ||
do: "DoWhileStatement", | ||
else: "IfStatement", | ||
return: "ReturnStatement", | ||
yield: "YieldExpression" | ||
}; | ||
/* | ||
* Before an opening parenthesis, `>` (for JSX), and postfix `++` and `--` always trigger ASI; | ||
* the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement. | ||
*/ | ||
const PUNCTUATORS = new Set([":", ";", ">", "{", "=>", "++", "--"]); | ||
/* | ||
* Statements that can contain an `ExpressionStatement` after a closing parenthesis. | ||
* DoWhileStatement is an exception in that it always triggers ASI after the closing parenthesis. | ||
*/ | ||
const STATEMENTS = new Set([ | ||
"DoWhileStatement", | ||
"ForInStatement", | ||
"ForOfStatement", | ||
"ForStatement", | ||
"IfStatement", | ||
"WhileStatement", | ||
"WithStatement" | ||
]); | ||
/** | ||
@@ -58,3 +97,4 @@ * Tests if a node appears at the beginning of an ancestor ExpressionStatement node. | ||
preferLiteral: "The object literal notation {} is preferable.", | ||
useLiteral: "Replace with '{{replacement}}'." | ||
useLiteral: "Replace with '{{replacement}}'.", | ||
useLiteralAfterSemicolon: "Replace with '{{replacement}}', add preceding semicolon." | ||
} | ||
@@ -87,2 +127,46 @@ }, | ||
/** | ||
* Determines whether a parenthesized object literal that replaces a specified node needs to be preceded by a semicolon. | ||
* @param {ASTNode} node The node to be replaced. This node should be at the start of an `ExpressionStatement` or at the start of the body of an `ArrowFunctionExpression`. | ||
* @returns {boolean} Whether a semicolon is required before the parenthesized object literal. | ||
*/ | ||
function needsSemicolon(node) { | ||
const prevToken = sourceCode.getTokenBefore(node); | ||
if (!prevToken || prevToken.type === "Punctuator" && PUNCTUATORS.has(prevToken.value)) { | ||
return false; | ||
} | ||
const prevNode = sourceCode.getNodeByRangeIndex(prevToken.range[0]); | ||
if (isClosingParenToken(prevToken)) { | ||
return !STATEMENTS.has(prevNode.type); | ||
} | ||
if (isClosingBraceToken(prevToken)) { | ||
return ( | ||
prevNode.type === "BlockStatement" && prevNode.parent.type === "FunctionExpression" || | ||
prevNode.type === "ClassBody" && prevNode.parent.type === "ClassExpression" || | ||
prevNode.type === "ObjectExpression" | ||
); | ||
} | ||
if (IDENTIFIER_OR_KEYWORD.has(prevToken.type)) { | ||
if (BREAK_OR_CONTINUE.has(prevNode.parent.type)) { | ||
return false; | ||
} | ||
const keyword = prevToken.value; | ||
const nodeType = NODE_TYPES_BY_KEYWORD[keyword]; | ||
return prevNode.type !== nodeType; | ||
} | ||
if (prevToken.type === "String") { | ||
return !DECLARATIONS.has(prevNode.parent.type); | ||
} | ||
return true; | ||
} | ||
/** | ||
* Reports on nodes where the `Object` constructor is called without arguments. | ||
@@ -100,4 +184,18 @@ * @param {ASTNode} node The node to evaluate. | ||
if (variable && variable.identifiers.length === 0) { | ||
const replacement = needsParentheses(node) ? "({})" : "{}"; | ||
let replacement; | ||
let fixText; | ||
let messageId = "useLiteral"; | ||
if (needsParentheses(node)) { | ||
replacement = "({})"; | ||
if (needsSemicolon(node)) { | ||
fixText = ";({})"; | ||
messageId = "useLiteralAfterSemicolon"; | ||
} else { | ||
fixText = "({})"; | ||
} | ||
} else { | ||
replacement = fixText = "{}"; | ||
} | ||
context.report({ | ||
@@ -108,5 +206,5 @@ node, | ||
{ | ||
messageId: "useLiteral", | ||
messageId, | ||
data: { replacement }, | ||
fix: fixer => fixer.replaceText(node, replacement) | ||
fix: fixer => fixer.replaceText(node, fixText) | ||
} | ||
@@ -113,0 +211,0 @@ ] |
{ | ||
"name": "eslint", | ||
"version": "8.51.0", | ||
"version": "8.52.0", | ||
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>", | ||
@@ -66,6 +66,7 @@ "description": "An AST-based pattern checker for JavaScript.", | ||
"@eslint/eslintrc": "^2.1.2", | ||
"@eslint/js": "8.51.0", | ||
"@humanwhocodes/config-array": "^0.11.11", | ||
"@eslint/js": "8.52.0", | ||
"@humanwhocodes/config-array": "^0.11.13", | ||
"@humanwhocodes/module-importer": "^1.0.1", | ||
"@nodelib/fs.walk": "^1.2.8", | ||
"@ungap/structured-clone": "^1.2.0", | ||
"ajv": "^6.12.4", | ||
@@ -72,0 +73,0 @@ "chalk": "^4.0.0", |
@@ -257,2 +257,7 @@ [![npm version](https://img.shields.io/npm/v/eslint.svg)](https://www.npmjs.com/package/eslint) | ||
</a> | ||
</td><td align="center" valign="top" width="11%"> | ||
<a href="https://github.com/Tanujkanti4441"> | ||
<img src="https://github.com/Tanujkanti4441.png?s=75" width="75" height="75"><br /> | ||
Tanuj Kanti | ||
</a> | ||
</td></tr></tbody></table> | ||
@@ -292,3 +297,3 @@ | ||
<p><a href="https://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a></p><h3>Silver Sponsors</h3> | ||
<p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://opensource.siemens.com"><img src="https://avatars.githubusercontent.com/u/624020?v=4" alt="Siemens" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a></p><h3>Bronze Sponsors</h3> | ||
<p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a></p><h3>Bronze Sponsors</h3> | ||
<p><a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p> | ||
@@ -295,0 +300,0 @@ <!--sponsorsend--> |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3012122
71002
305
38
+ Added@eslint/js@8.52.0(transitive)
+ Added@ungap/structured-clone@1.2.0(transitive)
- Removed@eslint/js@8.51.0(transitive)
Updated@eslint/js@8.52.0