Skip to content

Commit

Permalink
feat(reference): change File from stamp to TypeScript class (#4096)
Browse files Browse the repository at this point in the history
Refs #3481

BREAKING CHANGE: File from apidom-reference package became a class
and requires to be instantiated with new operator.
  • Loading branch information
char0n committed May 14, 2024
1 parent 3bb7131 commit cb4b90b
Show file tree
Hide file tree
Showing 66 changed files with 519 additions and 507 deletions.
3 changes: 1 addition & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions packages/apidom-converter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@
"@swagger-api/apidom-core": "*",
"@swagger-api/apidom-ns-openapi-3-0": "*",
"@swagger-api/apidom-ns-openapi-3-1": "*",
"@swagger-api/apidom-reference": "*",
"stampit": "^4.3.2"
"@swagger-api/apidom-reference": "*"
},
"files": [
"cjs/",
Expand Down
2 changes: 1 addition & 1 deletion packages/apidom-converter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export { ConvertError, UnmatchedConvertStrategyError };
*/
export const convertApiDOM = async (element: ParseResultElement, options = {}) => {
const mergedOptions = mergeOptions(defaultOptions, options || {}) as ConverterOptions;
const file = File({
const file = new File({
uri: mergedOptions.resolve.baseURI,
parseResult: element,
mediaType: mergedOptions.convert.sourceMediaType || mergedOptions.parse.mediaType,
Expand Down
8 changes: 2 additions & 6 deletions packages/apidom-converter/src/strategies/ConvertStrategy.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import stampit from 'stampit';
import { ParseResultElement } from '@swagger-api/apidom-core';
import { File } from '@swagger-api/apidom-reference';

import type { ConverterOptions } from '../options';

type ExtractGenericType<T> = T extends stampit.Stamp<infer U> ? U : never;
export type IFile = ExtractGenericType<typeof File>;

export interface ConvertStrategyOptions {
readonly name: string;
}
Expand All @@ -18,9 +14,9 @@ abstract class ConvertStrategy {
this.name = name;
}

abstract canConvert(file: IFile, options: ConverterOptions): boolean;
abstract canConvert(file: File, options: ConverterOptions): boolean;

abstract convert(file: IFile, options: ConverterOptions): Promise<ParseResultElement>;
abstract convert(file: File, options: ConverterOptions): Promise<ParseResultElement>;
}

export default ConvertStrategy;
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import {
cloneDeep,
dispatchRefractorPlugins as dispatchPlugins,
} from '@swagger-api/apidom-core';
import { File } from '@swagger-api/apidom-reference';

import ConvertStrategy, { IFile } from '../ConvertStrategy';
import ConvertStrategy from '../ConvertStrategy';
import openAPIVersionRefractorPlugin from './refractor-plugins/openapi-version';
import webhooksRefractorPlugin from './refractor-plugins/webhooks';
import securitySchemeTypeRefractorPlugin from './refractor-plugins/security-scheme-type';
Expand All @@ -42,7 +43,7 @@ class OpenAPI31ToOpenAPI30ConvertStrategy extends ConvertStrategy {
super({ name: 'openapi-3-1-to-openapi-3-0-3' });
}

canConvert(file: IFile, options: ConverterOptions): boolean {
canConvert(file: File, options: ConverterOptions): boolean {
let hasRecognizedSourceMediaType = false;
const hasRecognizedTargetMediaType = openAPI3_0_3MediaTypes.includes(
options.convert.targetMediaType,
Expand All @@ -60,10 +61,10 @@ class OpenAPI31ToOpenAPI30ConvertStrategy extends ConvertStrategy {
return hasRecognizedSourceMediaType && hasRecognizedTargetMediaType;
}

async convert(file: IFile): Promise<ParseResultElement> {
async convert(file: File): Promise<ParseResultElement> {
const annotations: AnnotationElement[] = [];
const parseResultElement: ParseResultElement = await dispatchPluginsAsync(
cloneDeep(file.parseResult),
cloneDeep(file.parseResult!),
[
openAPIVersionRefractorPlugin(),
webhooksRefractorPlugin({ annotations }),
Expand Down
59 changes: 59 additions & 0 deletions packages/apidom-reference/src/File.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { type } from 'ramda';
import { isString } from 'ramda-adjunct';
import { ParseResultElement } from '@swagger-api/apidom-core';

import * as url from './util/url';

/**
* This class represents a File object with url and data.
*/

export interface FileOptions {
readonly uri: string;
readonly mediaType?: string;
readonly data?: Buffer | DataView | ArrayBuffer | string;
readonly parseResult?: ParseResultElement;
}

class File {
public uri: string;

public mediaType: string;

public data?: Buffer | DataView | ArrayBuffer | string;

public parseResult?: ParseResultElement;

constructor({ uri, mediaType = 'text/plain', data, parseResult }: FileOptions) {
this.uri = uri;
this.mediaType = mediaType;
this.data = data;
this.parseResult = parseResult;
}

get extension(): string {
if (isString(this.uri)) {
return url.getExtension(this.uri);
}
return '';
}

toString(): string {
if (typeof this.data === 'string') {
return this.data;
}

if (
this.data instanceof ArrayBuffer ||
['ArrayBuffer'].includes(type(this.data)) ||
ArrayBuffer.isView(this.data)
) {
const textDecoder = new TextDecoder('utf-8');
return textDecoder.decode(this.data as Buffer | DataView | ArrayBuffer);
}

return String(this.data);
}
}

export default File;
4 changes: 2 additions & 2 deletions packages/apidom-reference/src/bundle/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { isEmpty, propEq } from 'ramda';
import { ParseResultElement } from '@swagger-api/apidom-core';

import File from '../util/File';
import File from '../File';
import * as plugins from '../util/plugins';
import UnmatchedBundleStrategyError from '../errors/UnmatchedBundleStrategyError';
import BundleError from '../errors/BundleError';
Expand All @@ -27,7 +27,7 @@ const bundle = async (uri: string, options: IReferenceOptions): Promise<ParseRes
parseResult = await parse(uri, mergedOptions);
}

const file = File({
const file = new File({
uri: mergedOptions.resolve.baseURI,
parseResult,
mediaType: mergedOptions.parse.mediaType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import stampit from 'stampit';
import { ParseResultElement } from '@swagger-api/apidom-core';
import { mediaTypes, isOpenApi3_1Element } from '@swagger-api/apidom-ns-openapi-3-1';

import File from '../../../File';
import BundleStrategy from '../BundleStrategy';
import { BundleStrategy as IBundleStrategy, File as IFile } from '../../../types';
import { BundleStrategy as IBundleStrategy } from '../../../types';

// eslint-disable-next-line @typescript-eslint/naming-convention
const OpenApi3_1BundleStrategy: stampit.Stamp<IBundleStrategy> = stampit(BundleStrategy, {
init() {
this.name = 'openapi-3-1';
},
methods: {
canBundle(file: IFile): boolean {
canBundle(file: File): boolean {
// assert by media type
if (file.mediaType !== 'text/plain') {
return mediaTypes.includes(file.mediaType);
Expand All @@ -21,8 +22,8 @@ const OpenApi3_1BundleStrategy: stampit.Stamp<IBundleStrategy> = stampit(BundleS
return isOpenApi3_1Element(file.parseResult?.result);
},

async bundle(file: IFile): Promise<ParseResultElement> {
return file.parseResult;
async bundle(file: File): Promise<ParseResultElement> {
return file.parseResult!;
},
},
});
Expand Down
4 changes: 2 additions & 2 deletions packages/apidom-reference/src/dereference/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
cloneShallow,
} from '@swagger-api/apidom-core';

import File from '../util/File';
import File from '../File';
import * as plugins from '../util/plugins';
import UnmatchedDereferenceStrategyError from '../errors/UnmatchedDereferenceStrategyError';
import DereferenceError from '../errors/DereferenceError';
Expand Down Expand Up @@ -34,7 +34,7 @@ export const dereferenceApiDOM = async <T extends Element>(
surrogateWrapping = true;
}

const file = File({
const file = new File({
uri: options.resolve.baseURI,
parseResult,
mediaType: options.parse.mediaType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { Element, isElement, cloneDeep, visit } from '@swagger-api/apidom-core';
import DereferenceStrategy from '../DereferenceStrategy';
import {
DereferenceStrategy as IDereferenceStrategy,
File as IFile,
ReferenceOptions as IReferenceOptions,
} from '../../../types';
import File from '../../../File';
import Reference from '../../../Reference';
import ReferenceSet from '../../../ReferenceSet';
import ApiDOMDereferenceVisitor from './visitor';
Expand All @@ -21,13 +21,13 @@ const ApiDOMDereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stampit(
this.name = 'apidom';
},
methods: {
canDereference(file: IFile) {
canDereference(file: File) {
return (
file.mediaType.startsWith('application/vnd.apidom') && isElement(file.parseResult?.result)
);
},

async dereference(file: IFile, options: IReferenceOptions): Promise<Element> {
async dereference(file: File, options: IReferenceOptions): Promise<Element> {
const immutableRefSet = options.dereference.refSet ?? ReferenceSet();
const mutableRefsSet = ReferenceSet();
let refSet = immutableRefSet;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import asyncApi2Namespace, {
import DereferenceStrategy from '../DereferenceStrategy';
import {
DereferenceStrategy as IDereferenceStrategy,
File as IFile,
ReferenceOptions as IReferenceOptions,
} from '../../../types';
import File from '../../../File';
import Reference from '../../../Reference';
import ReferenceSet from '../../../ReferenceSet';
import AsyncApi2DereferenceVisitor from './visitor';
Expand All @@ -27,7 +27,7 @@ const AsyncApi2DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stampi
this.name = 'asyncapi-2';
},
methods: {
canDereference(file: IFile): boolean {
canDereference(file: File): boolean {
// assert by media type
if (file.mediaType !== 'text/plain') {
return mediaTypes.includes(file.mediaType);
Expand All @@ -37,7 +37,7 @@ const AsyncApi2DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stampi
return isAsyncApi2Element(file.parseResult?.api);
},

async dereference(file: IFile, options: IReferenceOptions): Promise<Element> {
async dereference(file: File, options: IReferenceOptions): Promise<Element> {
const namespace = createNamespace(asyncApi2Namespace);
const immutableRefSet = options.dereference.refSet ?? ReferenceSet();
const mutableRefsSet = ReferenceSet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import openApi2Namespace, {
import DereferenceStrategy from '../DereferenceStrategy';
import {
DereferenceStrategy as IDereferenceStrategy,
File as IFile,
ReferenceOptions as IReferenceOptions,
} from '../../../types';
import File from '../../../File';
import Reference from '../../../Reference';
import ReferenceSet from '../../../ReferenceSet';
import OpenApi2DereferenceVisitor from './visitor';
Expand All @@ -27,7 +27,7 @@ const OpenApi2DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stampit
this.name = 'openapi-2';
},
methods: {
canDereference(file: IFile): boolean {
canDereference(file: File): boolean {
// assert by media type
if (file.mediaType !== 'text/plain') {
return mediaTypes.includes(file.mediaType);
Expand All @@ -37,7 +37,7 @@ const OpenApi2DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stampit
return isSwaggerElement(file.parseResult?.api);
},

async dereference(file: IFile, options: IReferenceOptions): Promise<Element> {
async dereference(file: File, options: IReferenceOptions): Promise<Element> {
const namespace = createNamespace(openApi2Namespace);
const immutableRefSet = options.dereference.refSet ?? ReferenceSet();
const mutableRefsSet = ReferenceSet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import openApi3_0Namespace, {
import DereferenceStrategy from '../DereferenceStrategy';
import {
DereferenceStrategy as IDereferenceStrategy,
File as IFile,
ReferenceOptions as IReferenceOptions,
} from '../../../types';
import File from '../../../File';
import Reference from '../../../Reference';
import ReferenceSet from '../../../ReferenceSet';
import OpenApi3_0DereferenceVisitor from './visitor';
Expand All @@ -28,7 +28,7 @@ const OpenApi3_0DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stamp
this.name = 'openapi-3-0';
},
methods: {
canDereference(file: IFile): boolean {
canDereference(file: File): boolean {
// assert by media type
if (file.mediaType !== 'text/plain') {
return mediaTypes.includes(file.mediaType);
Expand All @@ -38,7 +38,7 @@ const OpenApi3_0DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stamp
return isOpenApi3_0Element(file.parseResult?.api);
},

async dereference(file: IFile, options: IReferenceOptions): Promise<Element> {
async dereference(file: File, options: IReferenceOptions): Promise<Element> {
const namespace = createNamespace(openApi3_0Namespace);
const immutableRefSet = options.dereference.refSet ?? ReferenceSet();
const mutableRefsSet = ReferenceSet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import openApi3_1Namespace, {
import DereferenceStrategy from '../DereferenceStrategy';
import {
DereferenceStrategy as IDereferenceStrategy,
File as IFile,
ReferenceOptions as IReferenceOptions,
} from '../../../types';
import File from '../../../File';
import Reference from '../../../Reference';
import ReferenceSet from '../../../ReferenceSet';
import OpenApi3_1DereferenceVisitor from './visitor';
Expand All @@ -29,7 +29,7 @@ const OpenApi3_1DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stamp
this.name = 'openapi-3-1';
},
methods: {
canDereference(file: IFile): boolean {
canDereference(file: File): boolean {
// assert by media type
if (file.mediaType !== 'text/plain') {
return mediaTypes.includes(file.mediaType);
Expand All @@ -39,7 +39,7 @@ const OpenApi3_1DereferenceStrategy: stampit.Stamp<IDereferenceStrategy> = stamp
return isOpenApi3_1Element(file.parseResult?.result);
},

async dereference(file: IFile, options: IReferenceOptions): Promise<Element> {
async dereference(file: File, options: IReferenceOptions): Promise<Element> {
const namespace = createNamespace(openApi3_1Namespace);
const immutableRefSet = options.dereference.refSet ?? ReferenceSet();
const mutableRefsSet = ReferenceSet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import MaximumResolveDepthError from '../../../errors/MaximumResolveDepthError';
import * as url from '../../../util/url';
import parse from '../../../parse';
import Reference from '../../../Reference';
import File from '../../../util/File';
import File from '../../../File';
import { resolveSchema$refField, maybeRefractToSchemaElement } from './util';
import { AncestorLineage } from '../../util';
import EvaluationJsonSchemaUriError from '../../../errors/EvaluationJsonSchemaUriError';
Expand Down Expand Up @@ -697,7 +697,7 @@ const OpenApi3_1DereferenceVisitor = stampit({
let { uri: retrievalURI } = reference;
const $refBaseURI = resolveSchema$refField(retrievalURI, referencingElement)!;
const $refBaseURIStrippedHash = url.stripHash($refBaseURI);
const file = File({ uri: $refBaseURIStrippedHash });
const file = new File({ uri: $refBaseURIStrippedHash });
const isUnknownURI = none((r: IResolver) => r.canRead(file), this.options.resolve.resolvers);
const isURL = !isUnknownURI;
let isInternalReference = url.stripHash(this.reference.uri) === $refBaseURI;
Expand Down
4 changes: 2 additions & 2 deletions packages/apidom-reference/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ParseResultElement, Element } from '@swagger-api/apidom-core';

import File from './util/File';
import File from './File';
import * as url from './util/url';
import { ReferenceSet as IReferenceSet } from './types';
import defaultOptions from './options';
Expand Down Expand Up @@ -53,7 +53,7 @@ export { default as UnmatchedResolverError } from './errors/UnmatchedResolverErr

export const readFile = async (uri: string, options = {}): Promise<Buffer> => {
const mergedOptions = mergeOptions(defaultOptions, options);
const file = File({ uri: url.sanitize(uri) });
const file = new File({ uri: url.sanitize(uri) });

return readFileFn(file, mergedOptions);
};
Expand Down

0 comments on commit cb4b90b

Please sign in to comment.