Skip to content

Commit e4016d3

Browse files
authored
chore: remove duplications (#2207)
1 parent 1716a8e commit e4016d3

File tree

10 files changed

+78
-80
lines changed

10 files changed

+78
-80
lines changed

packages/cli/src/__tests__/commands/join.test.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
detectSpec,
55
getTotals,
66
loadConfig,
7-
BaseResolver,
87
type SpecVersion,
98
type Document,
109
} from '@redocly/openapi-core';
@@ -35,20 +34,35 @@ describe('handleJoin', () => {
3534
vi.mock('colorette');
3635
vi.mocked(yellow).mockImplementation((text) => text as string);
3736

38-
vi.mock('@redocly/openapi-core');
37+
vi.mock('@redocly/openapi-core', async () => {
38+
const actual = await vi.importActual<typeof import('@redocly/openapi-core')>(
39+
'@redocly/openapi-core'
40+
);
41+
class MockedBaseResolver extends actual.BaseResolver {
42+
resolveDocument = vi
43+
.fn()
44+
.mockImplementationOnce(() =>
45+
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: firstDocument } as Document)
46+
)
47+
.mockImplementationOnce(() =>
48+
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: secondDocument } as Document)
49+
)
50+
.mockImplementationOnce(() =>
51+
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: thirdDocument } as Document)
52+
);
53+
}
54+
return {
55+
...actual,
56+
bundleDocument: vi.fn(),
57+
detectSpec: vi.fn(),
58+
getTotals: vi.fn(),
59+
loadConfig: vi.fn(),
60+
BaseResolver: MockedBaseResolver,
61+
};
62+
});
3963
vi.mocked(bundleDocument).mockResolvedValue({ problems: [] } as any);
4064
vi.mocked(getTotals).mockReturnValue({ errors: 0, warnings: 0, ignored: 0 });
4165
vi.mocked(loadConfig).mockResolvedValue(configFixture);
42-
vi.mocked(BaseResolver.prototype.resolveDocument)
43-
.mockImplementationOnce(() =>
44-
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: firstDocument } as Document)
45-
)
46-
.mockImplementationOnce(() =>
47-
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: secondDocument } as Document)
48-
)
49-
.mockImplementationOnce(() =>
50-
Promise.resolve({ source: { absoluteRef: 'ref' }, parsed: thirdDocument } as Document)
51-
);
5266
});
5367

5468
it('should call exitWithError because only one entrypoint', async () => {

packages/cli/src/commands/bundle.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ import {
1515
} from '../utils/miscellaneous.js';
1616
import { AbortFlowError } from '../utils/error.js';
1717

18-
import type { OutputExtensions, Totals, VerifyConfigOptions } from '../types.js';
18+
import type { OutputExtension, Totals, VerifyConfigOptions } from '../types.js';
1919
import type { CommandArgs } from '../wrapper.js';
2020

2121
export type BundleArgv = {
2222
apis?: string[];
2323
extends?: string[];
2424
output?: string;
25-
ext?: OutputExtensions;
25+
ext?: OutputExtension;
2626
dereferenced?: boolean;
2727
force?: boolean;
2828
metafile?: string;

packages/cli/src/commands/join.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import {
1111
isRef,
1212
dequal,
1313
logger,
14+
isString,
15+
isPlainObject,
16+
keysOf,
1417
} from '@redocly/openapi-core';
1518
import {
1619
getFallbackApisOrExit,
@@ -20,7 +23,6 @@ import {
2023
writeToFileByExtension,
2124
} from '../utils/miscellaneous.js';
2225
import { exitWithError } from '../utils/error.js';
23-
import { isObject, isString, keysOf } from '../utils/js-utils.js';
2426
import { COMPONENTS, OPENAPI3_METHOD } from './split/types.js';
2527
import { crawl, startsWithComponents } from './split/index.js';
2628

@@ -769,10 +771,10 @@ function getInfoPrefix(info: any, prefixArg: string | undefined, type: string) {
769771

770772
function replace$Refs(obj: unknown, componentsPrefix: string) {
771773
crawl(obj, (node: Record<string, unknown>) => {
772-
if (node.$ref && typeof node.$ref === 'string' && startsWithComponents(node.$ref)) {
774+
if (isRef(node) && startsWithComponents(node.$ref)) {
773775
const name = path.basename(node.$ref);
774776
node.$ref = node.$ref.replace(name, componentsPrefix + '_' + name);
775-
} else if (isObject(node.discriminator) && isObject(node.discriminator.mapping)) {
777+
} else if (isPlainObject(node.discriminator) && isPlainObject(node.discriminator.mapping)) {
776778
const { mapping } = node.discriminator;
777779
for (const name of Object.keys(mapping)) {
778780
const mappingPointer = mapping[name];

packages/cli/src/commands/split/index.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import { red, blue, green } from 'colorette';
22
import * as fs from 'node:fs';
3-
import { parseYaml, slash, isRef, isTruthy, dequal, logger } from '@redocly/openapi-core';
3+
import {
4+
parseYaml,
5+
slash,
6+
isRef,
7+
isTruthy,
8+
dequal,
9+
logger,
10+
isEmptyObject,
11+
isPlainObject,
12+
} from '@redocly/openapi-core';
413
import * as path from 'node:path';
514
import { performance } from 'perf_hooks';
615
import {
@@ -12,7 +21,6 @@ import {
1221
writeToFileByExtension,
1322
getAndValidateFileExtension,
1423
} from '../../utils/miscellaneous.js';
15-
import { isObject, isEmptyObject } from '../../utils/js-utils.js';
1624
import { exitWithError } from '../../utils/error.js';
1725
import {
1826
OPENAPI3_COMPONENT,
@@ -148,19 +156,23 @@ function traverseDirectoryDeepCallback(
148156
}
149157

150158
export function crawl(object: unknown, visitor: (node: Record<string, unknown>) => void) {
151-
if (!isObject(object)) return;
152-
153-
visitor(object);
154-
for (const key of Object.keys(object)) {
155-
crawl(object[key], visitor);
159+
if (isPlainObject(object)) {
160+
visitor(object);
161+
for (const key of Object.keys(object)) {
162+
crawl(object[key], visitor);
163+
}
164+
} else if (Array.isArray(object)) {
165+
for (const item of object) {
166+
crawl(item, visitor);
167+
}
156168
}
157169
}
158170

159171
function replace$Refs(obj: unknown, relativeFrom: string, componentFiles = {} as ComponentsFiles) {
160172
crawl(obj, (node: Record<string, unknown>) => {
161-
if (node.$ref && typeof node.$ref === 'string' && startsWithComponents(node.$ref)) {
173+
if (isRef(node) && startsWithComponents(node.$ref)) {
162174
replace(node as RefObject, '$ref');
163-
} else if (isObject(node.discriminator) && isObject(node.discriminator.mapping)) {
175+
} else if (isPlainObject(node.discriminator) && isPlainObject(node.discriminator.mapping)) {
164176
const { mapping } = node.discriminator;
165177
for (const name of Object.keys(mapping)) {
166178
const mappingPointer = mapping[name];

packages/cli/src/reunite/commands/push-status.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import * as colors from 'colorette';
22
import { logger } from '@redocly/openapi-core';
3-
import { printExecutionTime } from '../../utils/miscellaneous.js';
3+
import { printExecutionTime, capitalize } from '../../utils/miscellaneous.js';
44
import { Spinner } from '../../utils/spinner.js';
55
import { DeploymentError } from '../utils.js';
66
import { ReuniteApi, getApiKeys, getDomain } from '../api/index.js';
7-
import { capitalize } from '../../utils/js-utils.js';
87
import { handleReuniteError, retryUntilConditionMet } from './utils.js';
98

109
import type { OutputFormat } from '@redocly/openapi-core';

packages/cli/src/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { GenerateArazzoCommandArgv } from './commands/generate-arazzo.js';
2-
import type { BundleOutputFormat, RuleSeverity } from '@redocly/openapi-core';
2+
import type { RuleSeverity } from '@redocly/openapi-core';
33
import type { RespectArgv } from './commands/respect/index.js';
44
import type { LintArgv } from './commands/lint.js';
55
import type { BundleArgv } from './commands/bundle.js';
@@ -24,8 +24,8 @@ export type Entrypoint = {
2424
alias?: string;
2525
output?: string;
2626
};
27-
export const outputExtensions = ['json', 'yaml', 'yml'] as ReadonlyArray<BundleOutputFormat>; // FIXME: use one source of truth (2.0)
28-
export type OutputExtensions = 'json' | 'yaml' | 'yml' | undefined; // FIXME: use one source of truth (2.0)
27+
export const outputExtensions = ['json', 'yaml', 'yml'] as const;
28+
export type OutputExtension = typeof outputExtensions[number];
2929
export type CommandArgv =
3030
| StatsArgv
3131
| SplitArgv

packages/cli/src/utils/js-utils.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

packages/cli/src/utils/miscellaneous.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,8 @@ import { outputExtensions } from '../types.js';
2828
import { exitWithError } from './error.js';
2929
import { handleLintConfig } from '../commands/lint.js';
3030

31-
import type {
32-
Config,
33-
BundleOutputFormat,
34-
Oas3Definition,
35-
Oas2Definition,
36-
Exact,
37-
} from '@redocly/openapi-core';
38-
import type { Totals, Entrypoint, OutputExtensions, CommandArgv } from '../types.js';
31+
import type { Config, Oas3Definition, Oas2Definition, Exact } from '@redocly/openapi-core';
32+
import type { Totals, Entrypoint, OutputExtension, CommandArgv } from '../types.js';
3933

4034
const globPromise = promisify(glob.glob);
4135

@@ -185,7 +179,7 @@ export class CircularJSONNotSupportedError extends Error {
185179
}
186180
}
187181

188-
export function dumpBundle(obj: any, format: BundleOutputFormat, dereference?: boolean): string {
182+
export function dumpBundle(obj: any, format: OutputExtension, dereference?: boolean): string {
189183
if (format === 'json') {
190184
try {
191185
return JSON.stringify(obj, null, 2);
@@ -277,12 +271,10 @@ export function writeJson(data: unknown, filename: string) {
277271
fs.writeFileSync(filename, content);
278272
}
279273

280-
export function getAndValidateFileExtension(fileName: string): NonNullable<OutputExtensions> {
274+
export function getAndValidateFileExtension(fileName: string): NonNullable<OutputExtension> {
281275
const ext = fileName.split('.').pop();
282-
283-
if (['yaml', 'yml', 'json'].includes(ext!)) {
284-
// FIXME: ^ use one source of truth (2.0)
285-
return ext as NonNullable<OutputExtensions>;
276+
if (outputExtensions.includes(ext as OutputExtension)) {
277+
return ext as OutputExtension;
286278
}
287279
logger.warn(`Unsupported file extension: ${ext}. Using yaml.\n`);
288280
return 'yaml';
@@ -377,7 +369,7 @@ export function getOutputFileName({
377369
entrypoint: string;
378370
output?: string;
379371
argvOutput?: string;
380-
ext?: BundleOutputFormat;
372+
ext?: OutputExtension;
381373
entries: number;
382374
}) {
383375
let outputFile = output || argvOutput;
@@ -386,16 +378,16 @@ export function getOutputFileName({
386378
}
387379

388380
if (entries > 1 && argvOutput) {
389-
ext = ext || (extname(entrypoint).substring(1) as BundleOutputFormat);
381+
ext = ext || (extname(entrypoint).substring(1) as OutputExtension);
390382
if (!outputExtensions.includes(ext)) {
391383
throw new Error(`Invalid file extension: ${ext}.`);
392384
}
393385
outputFile = join(argvOutput, basename(entrypoint, extname(entrypoint))) + '.' + ext;
394386
} else {
395387
ext =
396388
ext ||
397-
(extname(outputFile).substring(1) as BundleOutputFormat) ||
398-
(extname(entrypoint).substring(1) as BundleOutputFormat);
389+
(extname(outputFile).substring(1) as OutputExtension) ||
390+
(extname(entrypoint).substring(1) as OutputExtension);
399391
if (!outputExtensions.includes(ext)) {
400392
throw new Error(`Invalid file extension: ${ext}.`);
401393
}
@@ -556,3 +548,10 @@ export function formatPath(path: string) {
556548
}
557549
return relative(process.cwd(), path);
558550
}
551+
552+
export function capitalize(s: string) {
553+
if (s?.length > 0) {
554+
return s[0].toUpperCase() + s.slice(1);
555+
}
556+
return s;
557+
}

packages/core/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
export {
2-
type BundleOutputFormat,
32
type CollectFn,
43
type Exact,
4+
keysOf,
55
readFileFromUrl,
66
slash,
77
doesYamlFileExist,
88
isTruthy,
99
pause,
1010
isPlainObject,
11+
isString,
1112
dequal,
1213
pluralize,
1314
isEmptyObject,
@@ -68,7 +69,7 @@ export {
6869
type ResolvedApiConfig,
6970
type Plugin,
7071
type RuleConfig,
71-
Config, // FIXME: only export as a type in v2
72+
Config, // FIXME: export it as a type
7273
IGNORE_FILE,
7374
loadConfig,
7475
findConfig,

packages/core/src/utils.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ export function popStack<T, P extends Stack<T>>(head: P) {
3232
return head?.prev ?? null;
3333
}
3434

35-
export type BundleOutputFormat = 'json' | 'yml' | 'yaml'; // FIXME: use one source of truth (2.0)
36-
3735
export async function loadYaml<T>(filename: string): Promise<T> {
3836
const contents = await fs.promises.readFile(filename, 'utf-8');
3937
return parseYaml(contents) as T;
@@ -168,7 +166,6 @@ export function slash(path: string): string {
168166
return path.replace(/\\/g, '/');
169167
}
170168

171-
// TODO: use it everywhere
172169
export function isString(value: unknown): value is string {
173170
return typeof value === 'string';
174171
}

0 commit comments

Comments
 (0)