diff --git a/packages/core/src/bundle/bundle-visitor.ts b/packages/core/src/bundle/bundle-visitor.ts index 8569007ab0..cf07f59afb 100644 --- a/packages/core/src/bundle/bundle-visitor.ts +++ b/packages/core/src/bundle/bundle-visitor.ts @@ -124,7 +124,7 @@ export function makeBundleVisitor({ keepUrlRefs: boolean; componentRenamingConflicts?: RuleSeverity; }) { - let components: Record>; + let components: Record>; let rootLocation: Location; const visitor: Oas3Visitor | Oas2Visitor = { diff --git a/packages/core/src/decorators/common/filters/filter-helper.ts b/packages/core/src/decorators/common/filters/filter-helper.ts index 13444959d7..d587d7b345 100644 --- a/packages/core/src/decorators/common/filters/filter-helper.ts +++ b/packages/core/src/decorators/common/filters/filter-helper.ts @@ -4,7 +4,7 @@ import { isEmptyObject } from '../../../utils/is-empty-object.js'; import { isPlainObject } from '../../../utils/is-plain-object.js'; import type { UserContext } from '../../../walk.js'; -export function filter(node: any, ctx: UserContext, criteria: (item: any) => boolean) { +export function filter(node: unknown, ctx: UserContext, criteria: (item: unknown) => boolean) { const { parent, key } = ctx; let didDelete = false; if (Array.isArray(node)) { @@ -25,7 +25,6 @@ export function filter(node: any, ctx: UserContext, criteria: (item: any) => boo } } else if (isPlainObject(node)) { for (const key of Object.keys(node)) { - node = node as any; if (isRef(node[key])) { const resolved = ctx.resolve(node[key]); if (criteria(resolved.node)) { diff --git a/packages/core/src/env.ts b/packages/core/src/env.ts index 0e94c25e52..bbf7eac223 100644 --- a/packages/core/src/env.ts +++ b/packages/core/src/env.ts @@ -1,5 +1,5 @@ export const isBrowser = typeof window !== 'undefined' || typeof process === 'undefined' || - (process?.platform as any) === 'browser'; // main and worker thread + (process?.platform as string) === 'browser'; // main and worker thread export const env = isBrowser ? {} : process.env || {}; diff --git a/packages/core/src/format/format.ts b/packages/core/src/format/format.ts index 41b3a9f4c7..7d4d44388d 100644 --- a/packages/core/src/format/format.ts +++ b/packages/core/src/format/format.ts @@ -230,9 +230,9 @@ export function formatProblems( totals, version, problems: problems.map((p) => { - const problem = { + const problem: Record = { ...p, - location: p.location.map((location: any) => ({ + location: p.location.map((location: LocationObject) => ({ ...location, source: { ref: isAbsoluteUrl(location.source.absoluteRef) @@ -255,7 +255,7 @@ export function formatProblems( if (env.FORMAT_JSON_WITH_CODEFRAMES) { const location = p.location[0]; // TODO: support multiple locations const loc = getLineColLocation(location); - (problem as any).codeframe = getCodeframe(loc, color); + problem.codeframe = getCodeframe(loc, color); } return problem; }), @@ -458,14 +458,14 @@ function outputForGithubActions(problems: NormalizedProblem[], cwd: string): voi } } - function formatProperties(props: Record): string { + function formatProperties(props: Record): string { return Object.entries(props) .filter(([, v]) => v !== null && v !== undefined) .map(([k, v]) => `${k}=${escapeProperty(v)}`) .join(','); } - function toString(v: any): string { + function toString(v: unknown): string { if (v === null || v === undefined) { return ''; } else if (typeof v === 'string' || v instanceof String) { @@ -474,10 +474,10 @@ function outputForGithubActions(problems: NormalizedProblem[], cwd: string): voi return JSON.stringify(v); } - function escapeMessage(v: any): string { + function escapeMessage(v: unknown): string { return toString(v).replace(/%/g, '%25').replace(/\r/g, '%0D').replace(/\n/g, '%0A'); } - function escapeProperty(v: any): string { + function escapeProperty(v: unknown): string { return toString(v) .replace(/%/g, '%25') .replace(/\r/g, '%0D') diff --git a/packages/core/src/logger.ts b/packages/core/src/logger.ts index f7d22d109e..4d48325213 100644 --- a/packages/core/src/logger.ts +++ b/packages/core/src/logger.ts @@ -13,6 +13,7 @@ export const colorize = new Proxy(colorette, { return identity; } + // oxlint-disable-next-line typescript/no-explicit-any return (target as any)[prop]; }, }); diff --git a/packages/core/src/resolve.ts b/packages/core/src/resolve.ts index 3a9f25e106..aba78f00ca 100644 --- a/packages/core/src/resolve.ts +++ b/packages/core/src/resolve.ts @@ -17,6 +17,7 @@ import { import { isNamedType, SpecExtension, type NormalizedNodeType } from './types/index.js'; import type { OasRef } from './typings/openapi.js'; import { getOwn } from './utils/get-own.js'; +import { isPlainObject } from './utils/is-plain-object.js'; import { makeRefId } from './utils/make-ref-id.js'; import { nextTick } from './utils/next-tick.js'; import { readFileFromUrl } from './utils/read-file-from-url.js'; @@ -193,17 +194,17 @@ export type ResolvedRefMap = Map; type RefFrame = { prev: RefFrame | null; - node: any; + node: unknown; }; -function pushRef(head: RefFrame, node: any): RefFrame { +function pushRef(head: RefFrame, node: unknown): RefFrame { return { prev: head, node, }; } -function hasRef(head: RefFrame | null, node: any): boolean { +function hasRef(head: RefFrame | null, node: unknown): boolean { while (head) { if (head.node === node) { return true; @@ -236,18 +237,18 @@ export async function resolveDocument(opts: { return resolvedRefMap; function resolveRefsInParallel( - rootNode: any, + rootNode: unknown, rootNodeDocument: Document, rootNodePointer: string, - type: any + type: NormalizedNodeType ) { const rootNodeDocAbsoluteRef = rootNodeDocument.source.absoluteRef; - const anchorRefsMap: Map = new Map(); + const anchorRefsMap: Map = new Map(); walk(rootNode, type, rootNodeDocAbsoluteRef + rootNodePointer); - function walk(node: any, type: NormalizedNodeType, nodeAbsoluteRef: string) { - if (typeof node !== 'object' || node === null) { + function walk(node: unknown, type: NormalizedNodeType, nodeAbsoluteRef: string) { + if (!isPlainObject(node) && !Array.isArray(node)) { return; } @@ -258,11 +259,6 @@ export async function resolveDocument(opts: { seenNodes.add(nodeId); - const [_, anchor] = Object.entries(node).find(([key]) => key === '$anchor') || []; - if (anchor) { - anchorRefsMap.set(`#${anchor}`, node); - } - if (Array.isArray(node)) { const itemsType = type.items; // we continue resolving unknown types, but stop early on known scalars @@ -291,6 +287,11 @@ export async function resolveDocument(opts: { return; } + const [_, anchor] = Object.entries(node).find(([key]) => key === '$anchor') || []; + if (anchor) { + anchorRefsMap.set(`#${anchor}`, node); + } + for (const propName of Object.keys(node)) { let propValue = node[propName]; let propType = getOwn(type.properties, propName); @@ -342,7 +343,7 @@ export async function resolveDocument(opts: { if (isExternalValue(node)) { const promise = followRef( rootNodeDocument, - { $ref: node.externalValue }, + { $ref: node.externalValue as string }, { prev: null, node, @@ -352,7 +353,7 @@ export async function resolveDocument(opts: { resolveRefsInParallel( resolvedRef.node, resolvedRef.document, - resolvedRef.nodePointer!, + resolvedRef.nodePointer, type ); } @@ -420,33 +421,42 @@ export async function resolveDocument(opts: { nodePointer: '#/', }; - let target = targetDoc.parsed as any; + let target = targetDoc.parsed; const segments = pointer; for (const segment of segments) { - if (typeof target !== 'object') { - target = undefined; - break; - } else if (target[segment] !== undefined) { + if (isPlainObject(target) && target[segment] !== undefined) { target = target[segment]; resolvedRef.nodePointer = joinPointer( resolvedRef.nodePointer!, escapePointerFragment(segment) ); + } else if (Array.isArray(target) && target[+segment] !== undefined) { + target = target[+segment]; + resolvedRef.nodePointer = joinPointer( + resolvedRef.nodePointer!, + escapePointerFragment(segment) + ); } else if (isRef(target)) { resolvedRef = await followRef(targetDoc, target, pushRef(refStack, target)); targetDoc = resolvedRef.document || targetDoc; - if (typeof resolvedRef.node !== 'object') { + if (isPlainObject(resolvedRef.node)) { + target = resolvedRef.node[segment]; + resolvedRef.nodePointer = joinPointer( + resolvedRef.nodePointer!, + escapePointerFragment(segment) + ); + } else if (Array.isArray(resolvedRef.node)) { + target = resolvedRef.node[+segment]; + resolvedRef.nodePointer = joinPointer( + resolvedRef.nodePointer!, + escapePointerFragment(segment) + ); + } else { target = undefined; break; } - - target = resolvedRef.node[segment]; - resolvedRef.nodePointer = joinPointer( - resolvedRef.nodePointer!, - escapePointerFragment(segment) - ); } else { target = undefined; break; diff --git a/packages/core/src/rules/ajv.ts b/packages/core/src/rules/ajv.ts index 57df09f00e..bd774e47b7 100644 --- a/packages/core/src/rules/ajv.ts +++ b/packages/core/src/rules/ajv.ts @@ -61,6 +61,7 @@ function getAjv(resolve: ResolveFn, dialect: AjvDialect): AnyAjv { ajvInstances[dialect] = dialect === '2020' ? new Ajv2020(options) : new AjvDraft4(options); + // oxlint-disable-next-line typescript/no-explicit-any addFormats(ajvInstances[dialect] as any); } return ajvInstances[dialect]; @@ -126,9 +127,10 @@ export function validateJsonSchema( function beatifyErrorMessage(error: ErrorObject) { let message = error.message; - const suggest = error.keyword === 'enum' ? error.params.allowedValues : undefined; + const suggest: string[] | undefined = + error.keyword === 'enum' ? error.params.allowedValues : undefined; if (suggest) { - message += ` ${suggest.map((e: any) => `"${e}"`).join(', ')}`; + message += ` ${suggest.map((e) => `"${e}"`).join(', ')}`; } if (error.keyword === 'type') { diff --git a/packages/core/src/rules/async2/no-channel-trailing-slash.ts b/packages/core/src/rules/async2/no-channel-trailing-slash.ts index 3e7b8b08f2..dc0feb3172 100644 --- a/packages/core/src/rules/async2/no-channel-trailing-slash.ts +++ b/packages/core/src/rules/async2/no-channel-trailing-slash.ts @@ -3,7 +3,7 @@ import type { UserContext } from '../../walk.js'; export const NoChannelTrailingSlash: Async2Rule = () => { return { - Channel(_channel: any, { report, key, location }: UserContext) { + Channel(_channel: unknown, { report, key, location }: UserContext) { if ((key as string).endsWith('/') && key !== '/') { report({ message: `\`${key}\` should not have a trailing slash.`, diff --git a/packages/core/src/rules/catalog-entity/entity-key-valid.ts b/packages/core/src/rules/catalog-entity/entity-key-valid.ts index 66e710dfb9..a7520bec07 100644 --- a/packages/core/src/rules/catalog-entity/entity-key-valid.ts +++ b/packages/core/src/rules/catalog-entity/entity-key-valid.ts @@ -8,7 +8,7 @@ const MAX_KEY_LENGTH = 150; export const EntityKeyValid: CatalogEntityRule = () => { return { - any(node: any, { report, location }: UserContext) { + any(node: unknown, { report, location }: UserContext) { if (isPlainObject(node) && 'key' in node) { const key = node.key; diff --git a/packages/core/src/rules/common/no-invalid-parameter-examples.ts b/packages/core/src/rules/common/no-invalid-parameter-examples.ts index 1f6140c09d..6434618853 100644 --- a/packages/core/src/rules/common/no-invalid-parameter-examples.ts +++ b/packages/core/src/rules/common/no-invalid-parameter-examples.ts @@ -1,10 +1,11 @@ import type { Oas3Parameter } from '../../typings/openapi.js'; import { isDefined } from '../../utils/is-defined.js'; import { isPlainObject } from '../../utils/is-plain-object.js'; +import type { Oas2Rule, Oas3Rule } from '../../visitors.js'; import type { UserContext } from '../../walk.js'; import { validateExample } from '../utils.js'; -export const NoInvalidParameterExamples: any = (opts: any) => { +export const NoInvalidParameterExamples: Oas3Rule | Oas2Rule = (opts) => { return { Parameter: { leave(parameter: Oas3Parameter, ctx: UserContext) { diff --git a/packages/core/src/rules/common/no-invalid-schema-examples.ts b/packages/core/src/rules/common/no-invalid-schema-examples.ts index c95a0b7bca..6d431c3992 100644 --- a/packages/core/src/rules/common/no-invalid-schema-examples.ts +++ b/packages/core/src/rules/common/no-invalid-schema-examples.ts @@ -4,7 +4,7 @@ import type { Oas2Rule, Oas3Rule } from '../../visitors.js'; import type { UserContext } from '../../walk.js'; import { validateExample } from '../utils.js'; -export const NoInvalidSchemaExamples: Oas3Rule | Oas2Rule = (opts: any) => { +export const NoInvalidSchemaExamples: Oas3Rule | Oas2Rule = (opts) => { return { Schema: { leave(schema: Oas3_1Schema | Oas3Schema, ctx: UserContext) { diff --git a/packages/core/src/rules/common/no-path-trailing-slash.ts b/packages/core/src/rules/common/no-path-trailing-slash.ts index cb7ef89f73..e00147e31f 100644 --- a/packages/core/src/rules/common/no-path-trailing-slash.ts +++ b/packages/core/src/rules/common/no-path-trailing-slash.ts @@ -3,7 +3,7 @@ import type { UserContext } from '../../walk.js'; export const NoPathTrailingSlash: Oas3Rule | Oas2Rule = () => { return { - PathItem(_path: any, { report, key, rawLocation }: UserContext) { + PathItem(_path: unknown, { report, key, rawLocation }: UserContext) { if ((key as string).endsWith('/') && key !== '/') { report({ message: `\`${key}\` should not have a trailing slash.`, diff --git a/packages/core/src/rules/common/path-http-verbs-order.ts b/packages/core/src/rules/common/path-http-verbs-order.ts index b0514079c2..fdf8c22d0b 100644 --- a/packages/core/src/rules/common/path-http-verbs-order.ts +++ b/packages/core/src/rules/common/path-http-verbs-order.ts @@ -5,7 +5,7 @@ import type { UserContext } from '../../walk.js'; const defaultOrder = ['get', 'head', 'post', 'put', 'patch', 'delete', 'options', 'query', 'trace']; -export const PathHttpVerbsOrder: Oas3Rule | Oas2Rule = (opts: any) => { +export const PathHttpVerbsOrder: Oas3Rule | Oas2Rule = (opts) => { const order: string[] = (opts && opts.order) || defaultOrder; if (!Array.isArray(order)) { throw new Error('path-http-verbs-order `order` option must be an array'); diff --git a/packages/core/src/rules/common/path-segment-plural.ts b/packages/core/src/rules/common/path-segment-plural.ts index 4703d32530..7974e07d79 100644 --- a/packages/core/src/rules/common/path-segment-plural.ts +++ b/packages/core/src/rules/common/path-segment-plural.ts @@ -8,7 +8,7 @@ export const PathSegmentPlural: Oas3Rule | Oas2Rule = (opts) => { const { ignoreLastPathSegment, exceptions } = opts; return { PathItem: { - leave(_path: any, { report, key, location }: UserContext) { + leave(_path: unknown, { report, key, location }: UserContext) { const pathKey = key.toString(); if (pathKey.startsWith('/')) { const pathSegments = pathKey.split('/'); diff --git a/packages/core/src/rules/oas2/index.ts b/packages/core/src/rules/oas2/index.ts index 59c7ed5df1..3e6d20bbab 100644 --- a/packages/core/src/rules/oas2/index.ts +++ b/packages/core/src/rules/oas2/index.ts @@ -48,7 +48,7 @@ import { ResponseMimeType } from './response-mime-type.js'; export const rules: Oas2RuleSet<'built-in'> = { struct: Struct as Oas2Rule, 'no-invalid-schema-examples': NoInvalidSchemaExamples as Oas2Rule, - 'no-invalid-parameter-examples': NoInvalidParameterExamples, + 'no-invalid-parameter-examples': NoInvalidParameterExamples as Oas2Rule, 'info-contact': InfoContact as Oas2Rule, 'info-license': InfoLicense as Oas2Rule, 'info-license-strict': InfoLicenseStrict as Oas2Rule, diff --git a/packages/core/src/rules/oas3/index.ts b/packages/core/src/rules/oas3/index.ts index d106a182c9..2518307aea 100644 --- a/packages/core/src/rules/oas3/index.ts +++ b/packages/core/src/rules/oas3/index.ts @@ -111,7 +111,7 @@ export const rules: Oas3RuleSet<'built-in'> = { 'response-mime-type': ResponseMimeType, 'path-segment-plural': PathSegmentPlural as Oas3Rule, 'no-invalid-schema-examples': NoInvalidSchemaExamples as Oas3Rule, - 'no-invalid-parameter-examples': NoInvalidParameterExamples, + 'no-invalid-parameter-examples': NoInvalidParameterExamples as Oas3Rule, 'response-contains-header': ResponseContainsHeader as Oas3Rule, 'response-contains-property': ResponseContainsProperty, 'scalar-property-missing-example': ScalarPropertyMissingExample as Oas3Rule, diff --git a/packages/core/src/rules/other/stats.ts b/packages/core/src/rules/other/stats.ts index ffd1b666c0..23f17d94f2 100644 --- a/packages/core/src/rules/other/stats.ts +++ b/packages/core/src/rules/other/stats.ts @@ -1,5 +1,12 @@ import type { OASStatsAccumulator, AsyncAPIStatsAccumulator } from '../../typings/common.js'; -import type { Oas3Parameter, OasRef, Oas3Tag, Oas3_2Tag } from '../../typings/openapi.js'; +import type { + Oas3Link, + Oas3Operation, + Oas3Parameter, + Oas3Tag, + Oas3_2Tag, + OasRef, +} from '../../typings/openapi.js'; import type { Oas2Parameter } from '../../typings/swagger.js'; export const StatsOAS = (statsAccumulator: OASStatsAccumulator) => { @@ -20,13 +27,13 @@ export const StatsOAS = (statsAccumulator: OASStatsAccumulator) => { }, }, Link: { - leave(link: any) { - statsAccumulator.links.items!.add(link.operationId); + leave(link: Oas3Link) { + statsAccumulator.links.items!.add(link.operationId!); }, }, WebhooksMap: { Operation: { - leave(operation: any) { + leave(operation: Oas3Operation) { statsAccumulator.webhooks.total++; if (operation.tags) { for (const tag of operation.tags) { @@ -42,7 +49,7 @@ export const StatsOAS = (statsAccumulator: OASStatsAccumulator) => { statsAccumulator.pathItems.total++; }, Operation: { - leave(operation: any) { + leave(operation: Oas3Operation) { statsAccumulator.operations.total++; if (operation.tags) { for (const tag of operation.tags) { @@ -89,7 +96,7 @@ export const StatsAsync2 = (statsAccumulator: AsyncAPIStatsAccumulator) => { }, }, Tag: { - leave(tag: Oas3Tag | Oas3_2Tag) { + leave(tag: Oas3Tag) { statsAccumulator.tags.items!.add(tag.name); }, }, @@ -147,7 +154,7 @@ export const StatsAsync3 = (statsAccumulator: AsyncAPIStatsAccumulator) => { }, }, Tag: { - leave(tag: Oas3Tag | Oas3_2Tag) { + leave(tag: Oas3Tag) { statsAccumulator.tags.items!.add(tag.name); }, },