Comparing version 5.22.3 to 5.23.0
@@ -24,3 +24,3 @@ import picocolors from 'picocolors'; | ||
try { | ||
const { report, issues, counters, rules, configurationHints } = await main({ | ||
const { report, issues, counters, rules, tagHints, configurationHints } = await main({ | ||
cwd, | ||
@@ -48,2 +48,3 @@ tsConfigFile: tsConfig, | ||
counters, | ||
tagHints, | ||
configurationHints, | ||
@@ -50,0 +51,0 @@ noConfigHints, |
@@ -9,3 +9,4 @@ import type { CommandLineOptions } from './types/cli.js'; | ||
rules: import("./types/issues.js").Rules; | ||
tagHints: Set<import("./types/issues.js").TagHint>; | ||
configurationHints: Set<import("./types/issues.js").ConfigurationHint>; | ||
}>; |
@@ -25,3 +25,3 @@ import { watch } from 'node:fs'; | ||
import { findMatch } from './util/regex.js'; | ||
import { getShouldIgnoreHandler } from './util/tag.js'; | ||
import { getShouldIgnoreHandler, getShouldIgnoreTagHandler } from './util/tag.js'; | ||
import { augmentWorkspace, getToSourcePathHandler } from './util/to-source-path.js'; | ||
@@ -289,8 +289,11 @@ import { createAndPrintTrace, printTrace } from './util/trace.js'; | ||
factory.deletePrincipal(principal); | ||
const shouldIgnore = getShouldIgnoreHandler(tags, isProduction); | ||
const shouldIgnore = getShouldIgnoreHandler(isProduction); | ||
const shouldIgnoreTags = getShouldIgnoreTagHandler(tags); | ||
const isIdentifierReferenced = getIsIdentifierReferencedHandler(graph, entryPaths); | ||
const isExportedItemReferenced = (exportedItem) => exportedItem.refs > 0 && | ||
(typeof chief.config.ignoreExportsUsedInFile === 'object' | ||
? exportedItem.type !== 'unknown' && !!chief.config.ignoreExportsUsedInFile[exportedItem.type] | ||
: chief.config.ignoreExportsUsedInFile); | ||
const ignoreExportsUsedInFile = chief.config.ignoreExportsUsedInFile; | ||
const isExportedItemReferenced = (exportedItem) => exportedItem.refs[1] || | ||
(exportedItem.refs[0] > 0 && | ||
(typeof ignoreExportsUsedInFile === 'object' | ||
? exportedItem.type !== 'unknown' && !!ignoreExportsUsedInFile[exportedItem.type] | ||
: ignoreExportsUsedInFile)); | ||
const findUnusedExports = async () => { | ||
@@ -318,3 +321,4 @@ if (isReportValues || isReportTypes) { | ||
continue; | ||
if (importsForExport) { | ||
const isIgnored = shouldIgnoreTags(exportedItem.jsDocTags); | ||
if (!isIgnored && importsForExport) { | ||
const { isReferenced, reExportingEntryFile, traceNode } = isIdentifierReferenced(filePath, identifier, isIncludeEntryExports); | ||
@@ -339,6 +343,9 @@ if (reExportingEntryFile) { | ||
continue; | ||
if (member.refs === 0) { | ||
if (member.refs[0] === 0) { | ||
const id = `${identifier}.${member.identifier}`; | ||
const { isReferenced } = isIdentifierReferenced(filePath, id); | ||
const isIgnored = shouldIgnoreTags(member.jsDocTags); | ||
if (!isReferenced) { | ||
if (isIgnored) | ||
continue; | ||
collector.addIssue({ | ||
@@ -355,2 +362,9 @@ type: 'enumMembers', | ||
} | ||
else if (isIgnored) { | ||
for (const tagName of exportedItem.jsDocTags) { | ||
if (tags[1].includes(tagName.replace(/^\@/, ''))) { | ||
collector.addTagHint({ type: 'tag', filePath, identifier: id, tagName }); | ||
} | ||
} | ||
} | ||
} | ||
@@ -362,2 +376,11 @@ } | ||
for (const member of principal.findUnusedMembers(filePath, members)) { | ||
if (shouldIgnoreTags(member.jsDocTags)) { | ||
const identifier = `${exportedItem.identifier}.${member.identifier}`; | ||
for (const tagName of exportedItem.jsDocTags) { | ||
if (tags[1].includes(tagName.replace(/^\@/, ''))) { | ||
collector.addTagHint({ type: 'tag', filePath, identifier, tagName }); | ||
} | ||
} | ||
continue; | ||
} | ||
collector.addIssue({ | ||
@@ -383,2 +406,4 @@ type: 'classMembers', | ||
if (!isExportedItemReferenced(exportedItem)) { | ||
if (isIgnored) | ||
continue; | ||
if (!isSkipLibs && principal?.hasExternalReferences(filePath, exportedItem)) | ||
@@ -405,2 +430,9 @@ continue; | ||
} | ||
else if (isIgnored) { | ||
for (const tagName of exportedItem.jsDocTags) { | ||
if (tags[1].includes(tagName.replace(/^\@/, ''))) { | ||
collector.addTagHint({ type: 'tag', filePath, identifier, tagName }); | ||
} | ||
} | ||
} | ||
} | ||
@@ -534,3 +566,3 @@ } | ||
await findUnusedExports(); | ||
const { issues, counters, configurationHints } = collector.getIssues(); | ||
const { issues, counters, tagHints, configurationHints } = collector.getIssues(); | ||
if (isFix) { | ||
@@ -543,3 +575,3 @@ await fixer.fixIssues(issues); | ||
streamer.clear(); | ||
return { report, issues, counters, rules, configurationHints }; | ||
return { report, issues, counters, rules, tagHints, configurationHints }; | ||
}; |
@@ -1,2 +0,2 @@ | ||
import type { ConfigurationHint, Issue, Rules } from './types/issues.js'; | ||
import type { ConfigurationHint, Issue, Rules, TagHint } from './types/issues.js'; | ||
type Filters = Partial<{ | ||
@@ -18,2 +18,3 @@ dir: string; | ||
private configurationHints; | ||
private tagHints; | ||
private ignorePatterns; | ||
@@ -30,2 +31,3 @@ private isMatch; | ||
addConfigurationHint(issue: ConfigurationHint): void; | ||
addTagHint(issue: TagHint): void; | ||
purge(): import("./types/issues.js").IssueSet; | ||
@@ -35,2 +37,3 @@ getIssues(): { | ||
counters: import("./types/issues.js").Counters; | ||
tagHints: Set<TagHint>; | ||
configurationHints: Set<ConfigurationHint>; | ||
@@ -37,0 +40,0 @@ }; |
@@ -5,3 +5,3 @@ import picomatch from 'picomatch'; | ||
import { relative } from './util/path.js'; | ||
const hasHint = (hints, hint) => Array.from(hints).some(item => item.identifier === hint.identifier && item.type === hint.type && item.workspaceName === hint.workspaceName); | ||
const hasConfigurationHint = (hints, hint) => Array.from(hints).some(item => item.identifier === hint.identifier && item.type === hint.type && item.workspaceName === hint.workspaceName); | ||
const isMatch = timerify(picomatch.isMatch, 'isMatch'); | ||
@@ -16,2 +16,3 @@ export class IssueCollector { | ||
configurationHints = new Set(); | ||
tagHints = new Set(); | ||
ignorePatterns = new Set(); | ||
@@ -64,6 +65,9 @@ isMatch; | ||
addConfigurationHint(issue) { | ||
if (!hasHint(this.configurationHints, issue)) { | ||
if (!hasConfigurationHint(this.configurationHints, issue)) { | ||
this.configurationHints.add(issue); | ||
} | ||
} | ||
addTagHint(issue) { | ||
this.tagHints.add(issue); | ||
} | ||
purge() { | ||
@@ -79,2 +83,3 @@ const unusedFiles = this.issues.files; | ||
counters: this.counters, | ||
tagHints: this.tagHints, | ||
configurationHints: this.configurationHints, | ||
@@ -81,0 +86,0 @@ }; |
declare const _default: { | ||
symbols: ({ report, issues, configurationHints, noConfigHints, isShowProgress }: import("../index.js").ReporterOptions) => void; | ||
symbols: ({ report, issues, tagHints, configurationHints, noConfigHints, isShowProgress }: import("../index.js").ReporterOptions) => void; | ||
compact: ({ report, issues, isShowProgress }: import("../index.js").ReporterOptions) => void; | ||
@@ -4,0 +4,0 @@ codeowners: ({ report, issues, isShowProgress, options }: import("../index.js").ReporterOptions) => void; |
import type { ReporterOptions } from '../types/issues.js'; | ||
declare const _default: ({ report, issues, configurationHints, noConfigHints, isShowProgress }: ReporterOptions) => void; | ||
declare const _default: ({ report, issues, tagHints, configurationHints, noConfigHints, isShowProgress }: ReporterOptions) => void; | ||
export default _default; |
@@ -23,3 +23,3 @@ import EasyTable from 'easy-table'; | ||
}; | ||
export default ({ report, issues, configurationHints, noConfigHints, isShowProgress }) => { | ||
export default ({ report, issues, tagHints, configurationHints, noConfigHints, isShowProgress }) => { | ||
const reportMultipleGroups = Object.values(report).filter(Boolean).length > 1; | ||
@@ -56,10 +56,20 @@ let totalIssues = 0; | ||
} | ||
if (!noConfigHints && configurationHints.size > 0) { | ||
logTitle('Configuration issues', configurationHints.size); | ||
for (const hint of configurationHints) { | ||
const { type, workspaceName, identifier } = hint; | ||
const message = `Unused item in ${type}`; | ||
const workspace = workspaceName && workspaceName !== ROOT_WORKSPACE_NAME ? ` (workspace: ${workspaceName})` : ''; | ||
console.warn(picocolors.gray(`${message}${workspace}:`), identifier); | ||
if (!noConfigHints) { | ||
if (configurationHints.size > 0) { | ||
logTitle('Configuration issues', configurationHints.size); | ||
for (const hint of configurationHints) { | ||
const { type, workspaceName, identifier } = hint; | ||
const message = `Unused item in ${type}`; | ||
const workspace = workspaceName && workspaceName !== ROOT_WORKSPACE_NAME ? ` (workspace: ${workspaceName})` : ''; | ||
console.warn(picocolors.gray(`${message}${workspace}:`), identifier); | ||
} | ||
} | ||
if (tagHints.size > 0) { | ||
logTitle('Tag issues', tagHints.size); | ||
for (const hint of tagHints) { | ||
const { filePath, identifier, tagName } = hint; | ||
const message = `Unused tag in ${toRelative(filePath)}:`; | ||
console.warn(picocolors.gray(message), `${identifier} → ${tagName}`); | ||
} | ||
} | ||
} | ||
@@ -66,0 +76,0 @@ if (totalIssues === 0 && isShowProgress) { |
@@ -36,3 +36,3 @@ import type ts from 'typescript'; | ||
jsDocTags: Tags; | ||
refs: number; | ||
refs: [number, boolean]; | ||
fixes: Fixes; | ||
@@ -48,3 +48,3 @@ symbol?: ts.Symbol; | ||
type: SymbolType; | ||
refs: number; | ||
refs: [number, boolean]; | ||
fix: Fix; | ||
@@ -51,0 +51,0 @@ symbol?: ts.Symbol; |
@@ -59,2 +59,3 @@ export declare enum SymbolType { | ||
counters: Counters; | ||
tagHints: TagHints; | ||
configurationHints: ConfigurationHints; | ||
@@ -78,1 +79,9 @@ noConfigHints: boolean; | ||
}; | ||
type TagHints = Set<TagHint>; | ||
export type TagHint = { | ||
type: 'tag'; | ||
filePath: string; | ||
identifier: string; | ||
tagName: string; | ||
}; | ||
export {}; |
@@ -26,1 +26,2 @@ import ts from 'typescript'; | ||
export declare const isImportSpecifier: (node: ts.Node) => boolean; | ||
export declare const isReferencedInExportedType: (node: ts.Node, symbol: ts.Symbol) => any; |
@@ -154,1 +154,10 @@ import ts from 'typescript'; | ||
ts.isNamespaceImport(node.parent); | ||
const isExported = (node) => { | ||
if (node.modifiers?.find(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) | ||
return true; | ||
return node.parent ? isExported(node.parent) : false; | ||
}; | ||
export const isReferencedInExportedType = (node, symbol) => symbol.exportSymbol && | ||
!(node.transformFlags & ts.TransformFlags.ContainsTypeScript) && | ||
Boolean(node.parent.transformFlags & ts.TransformFlags.ContainsTypeScript) && | ||
isExported(node.parent); |
@@ -8,4 +8,5 @@ import { isBuiltin } from 'node:module'; | ||
import { extname, isInNodeModules } from '../util/path.js'; | ||
import { isIdChar } from '../util/regex.js'; | ||
import { shouldIgnore } from '../util/tag.js'; | ||
import { getAccessMembers, getDestructuredIds, getJSDocTags, getLineAndCharacterOfPosition, getTypeName, isAccessExpression, isConsiderReferencedNS, isDestructuring, isImportSpecifier, } from './ast-helpers.js'; | ||
import { getAccessMembers, getDestructuredIds, getJSDocTags, getLineAndCharacterOfPosition, getTypeName, isAccessExpression, isConsiderReferencedNS, isDestructuring, isImportSpecifier, isReferencedInExportedType, } from './ast-helpers.js'; | ||
import getDynamicImportVisitors from './visitors/dynamic-imports/index.js'; | ||
@@ -32,8 +33,9 @@ import getExportVisitors from './visitors/exports/index.js'; | ||
fix: member.fix, | ||
refs: 0, | ||
refs: [0, false], | ||
jsDocTags: getJSDocTags(member.node), | ||
}; | ||
}; | ||
const isType = (item) => item.type === 'type' || item.type === 'interface' || item.type === 'member'; | ||
const getImportsAndExports = (sourceFile, resolveModule, typeChecker, options) => { | ||
const { skipTypeOnly, tags } = options; | ||
const { skipTypeOnly, tags, ignoreExportsUsedInFile } = options; | ||
const internalImports = new Map(); | ||
@@ -49,2 +51,3 @@ const externalImports = new Set(); | ||
const importedInternalSymbols = new Map(); | ||
const referencedSymbolsInExportedTypes = new Set(); | ||
const visitors = getVisitors(sourceFile); | ||
@@ -192,3 +195,3 @@ const addInternalImport = (options) => { | ||
fixes: fix ? [fix] : [], | ||
refs: 0, | ||
refs: [0, false], | ||
isReExport, | ||
@@ -289,2 +292,5 @@ }); | ||
} | ||
if (ignoreExportsUsedInFile && !isTopLevel && isReferencedInExportedType(node, symbol)) { | ||
referencedSymbolsInExportedTypes.add(symbol.exportSymbol); | ||
} | ||
} | ||
@@ -312,30 +318,36 @@ } | ||
let index = 0; | ||
while (index < sourceFile.text.length && (index = sourceFile.text.indexOf(item.identifier, index)) !== -1) { | ||
const isDeclaration = index === item.pos || index === item.pos + 1; | ||
if (!isDeclaration) { | ||
const symbol = typeChecker.getSymbolAtLocation(ts.getTokenAtPosition(sourceFile, index)); | ||
if (symbol) { | ||
if (item.symbol === symbol) { | ||
item.refs = 1; | ||
break; | ||
} | ||
const declaration = symbol.declarations?.[0]; | ||
if (declaration) { | ||
if (item.symbol === declaration.name?.flowNode?.node?.symbol) { | ||
item.refs = 1; | ||
break; | ||
const text = sourceFile.text; | ||
const id = item.identifier; | ||
while (index < text.length && (index = text.indexOf(id, index)) !== -1) { | ||
if (!isIdChar(text.charAt(index - 1)) && !isIdChar(text.charAt(index + id.length))) { | ||
const isDeclaration = index === item.pos || index === item.pos + 1; | ||
if (!isDeclaration) { | ||
const symbol = typeChecker.getSymbolAtLocation(ts.getTokenAtPosition(sourceFile, index)); | ||
if (symbol) { | ||
const isInExportedType = referencedSymbolsInExportedTypes.has(symbol); | ||
if (item.symbol === symbol) { | ||
item.refs = [1, isInExportedType]; | ||
if (isInExportedType || isType(item)) | ||
break; | ||
} | ||
if (ts.isImportSpecifier(declaration) && symbols.has(symbol)) { | ||
item.refs = 1; | ||
break; | ||
const declaration = symbol.declarations?.[0]; | ||
if (declaration) { | ||
if (item.symbol === declaration.name?.flowNode?.node?.symbol) { | ||
item.refs = [1, isInExportedType]; | ||
break; | ||
} | ||
if (ts.isImportSpecifier(declaration) && symbols.has(symbol)) { | ||
item.refs = [1, isInExportedType]; | ||
break; | ||
} | ||
} | ||
symbols.add(symbol); | ||
} | ||
symbols.add(symbol); | ||
} | ||
} | ||
index += item.identifier.length; | ||
index += id.length; | ||
} | ||
}; | ||
for (const item of exports.values()) { | ||
if (options.ignoreExportsUsedInFile) | ||
if (ignoreExportsUsedInFile) | ||
setRefs(item); | ||
@@ -342,0 +354,0 @@ for (const member of item.members) { |
export declare const toRegexOrString: (value: string | RegExp) => string | RegExp; | ||
export declare const findMatch: (haystack: undefined | (string | RegExp)[], needle: string) => string | RegExp | undefined; | ||
export declare const isIdChar: (text: string) => boolean; |
export const toRegexOrString = (value) => typeof value === 'string' && /[*+\\(|{^$]/.test(value) ? new RegExp(value) : value; | ||
export const findMatch = (haystack, needle) => haystack?.find(n => (typeof n === 'string' ? n === needle : n.test(needle))); | ||
const idCharMatch = /[a-zA-Z0-9$_]/; | ||
export const isIdChar = (text) => idCharMatch.test(text); |
import type { Tags } from '../types/cli.js'; | ||
export declare const splitTags: (rawTags: string[]) => Tags; | ||
export declare const shouldIgnore: (jsDocTags: Set<string>, tags: Tags) => boolean; | ||
export declare const getShouldIgnoreHandler: (tags: Tags, isProduction: boolean) => (jsDocTags: Set<string>) => boolean; | ||
export declare const getShouldIgnoreHandler: (isProduction: boolean) => (jsDocTags: Set<string>) => boolean; | ||
export declare const getShouldIgnoreTagHandler: (tags: Tags) => (jsDocTags: Set<string>) => boolean; |
@@ -19,6 +19,6 @@ export const splitTags = (rawTags) => { | ||
}; | ||
export const getShouldIgnoreHandler = (tags, isProduction) => (jsDocTags) => jsDocTags.has('@public') || | ||
export const getShouldIgnoreHandler = (isProduction) => (jsDocTags) => jsDocTags.has('@public') || | ||
jsDocTags.has('@beta') || | ||
jsDocTags.has('@alias') || | ||
shouldIgnore(jsDocTags, tags) || | ||
(isProduction && jsDocTags.has('@internal')); | ||
export const getShouldIgnoreTagHandler = (tags) => (jsDocTags) => shouldIgnore(jsDocTags, tags); |
@@ -1,1 +0,1 @@ | ||
export declare const version = "5.22.3"; | ||
export declare const version = "5.23.0"; |
@@ -1,1 +0,1 @@ | ||
export const version = '5.22.3'; | ||
export const version = '5.23.0'; |
@@ -35,3 +35,3 @@ import { CacheConsultant } from './CacheConsultant.js'; | ||
negatedWorkspacePatterns: string[]; | ||
enabledPluginsMap: Record<"angular" | "astro" | "ava" | "babel" | "capacitor" | "changesets" | "commitizen" | "commitlint" | "cspell" | "cucumber" | "cypress" | "drizzle" | "eleventy" | "eslint" | "gatsby" | "githubActions" | "graphqlCodegen" | "husky" | "jest" | "lefthook" | "linthtml" | "lintStaged" | "lockfileLint" | "lostPixel" | "markdownlint" | "mocha" | "moonrepo" | "msw" | "netlify" | "next" | "nodeTestRunner" | "npmPackageJsonLint" | "nx" | "nyc" | "oclif" | "playwright" | "playwrightCt" | "postcss" | "prettier" | "releaseIt" | "remark" | "remix" | "rollup" | "semanticRelease" | "sentry" | "simpleGitHooks" | "sizeLimit" | "storybook" | "stryker" | "stylelint" | "svelte" | "syncpack" | "tailwind" | "tsup" | "typedoc" | "typescript" | "unbuild" | "unocss" | "vercelOg" | "vite" | "vitest" | "vue" | "webdriverIo" | "webpack" | "wireit" | "wrangler" | "xo" | "yorkie", boolean>; | ||
enabledPluginsMap: Record<"astro" | "angular" | "ava" | "babel" | "capacitor" | "changesets" | "commitizen" | "commitlint" | "cspell" | "cucumber" | "cypress" | "eleventy" | "eslint" | "gatsby" | "husky" | "jest" | "lefthook" | "linthtml" | "markdownlint" | "mocha" | "moonrepo" | "msw" | "netlify" | "next" | "nx" | "nyc" | "oclif" | "playwright" | "postcss" | "prettier" | "remark" | "remix" | "rollup" | "sentry" | "storybook" | "stryker" | "stylelint" | "svelte" | "syncpack" | "tailwind" | "tsup" | "typedoc" | "typescript" | "unbuild" | "unocss" | "vue" | "vite" | "vitest" | "webpack" | "wireit" | "wrangler" | "xo" | "yorkie" | "drizzle" | "githubActions" | "graphqlCodegen" | "lintStaged" | "lockfileLint" | "lostPixel" | "nodeTestRunner" | "npmPackageJsonLint" | "playwrightCt" | "releaseIt" | "semanticRelease" | "simpleGitHooks" | "sizeLimit" | "vercelOg" | "webdriverIo", boolean>; | ||
enabledPlugins: PluginName[]; | ||
@@ -56,3 +56,3 @@ enabledPluginsInAncestors: string[]; | ||
referencedDependencies: ReferencedDependencies; | ||
enabledPlugins: ("angular" | "astro" | "ava" | "babel" | "capacitor" | "changesets" | "commitizen" | "commitlint" | "cspell" | "cucumber" | "cypress" | "drizzle" | "eleventy" | "eslint" | "gatsby" | "githubActions" | "graphqlCodegen" | "husky" | "jest" | "lefthook" | "linthtml" | "lintStaged" | "lockfileLint" | "lostPixel" | "markdownlint" | "mocha" | "moonrepo" | "msw" | "netlify" | "next" | "nodeTestRunner" | "npmPackageJsonLint" | "nx" | "nyc" | "oclif" | "playwright" | "playwrightCt" | "postcss" | "prettier" | "releaseIt" | "remark" | "remix" | "rollup" | "semanticRelease" | "sentry" | "simpleGitHooks" | "sizeLimit" | "storybook" | "stryker" | "stylelint" | "svelte" | "syncpack" | "tailwind" | "tsup" | "typedoc" | "typescript" | "unbuild" | "unocss" | "vercelOg" | "vite" | "vitest" | "vue" | "webdriverIo" | "webpack" | "wireit" | "wrangler" | "xo" | "yorkie")[]; | ||
enabledPlugins: ("astro" | "angular" | "ava" | "babel" | "capacitor" | "changesets" | "commitizen" | "commitlint" | "cspell" | "cucumber" | "cypress" | "eleventy" | "eslint" | "gatsby" | "husky" | "jest" | "lefthook" | "linthtml" | "markdownlint" | "mocha" | "moonrepo" | "msw" | "netlify" | "next" | "nx" | "nyc" | "oclif" | "playwright" | "postcss" | "prettier" | "remark" | "remix" | "rollup" | "sentry" | "storybook" | "stryker" | "stylelint" | "svelte" | "syncpack" | "tailwind" | "tsup" | "typedoc" | "typescript" | "unbuild" | "unocss" | "vue" | "vite" | "vitest" | "webpack" | "wireit" | "wrangler" | "xo" | "yorkie" | "drizzle" | "githubActions" | "graphqlCodegen" | "lintStaged" | "lockfileLint" | "lostPixel" | "nodeTestRunner" | "npmPackageJsonLint" | "playwrightCt" | "releaseIt" | "semanticRelease" | "simpleGitHooks" | "sizeLimit" | "vercelOg" | "webdriverIo")[]; | ||
}>; | ||
@@ -59,0 +59,0 @@ onDispose(): void; |
{ | ||
"name": "knip", | ||
"version": "5.22.3", | ||
"version": "5.23.0", | ||
"description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects", | ||
@@ -5,0 +5,0 @@ "homepage": "https://knip.dev", |
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
786507
17782