Skip to content

Commit e3d195d

Browse files
committed
feat(reference): change parsers from stamps to TypeScript classes (#4102)
Refs #3481 BREAKING CHANGE: parsers from apidom-reference package became a class and requires to be instantiated with new operator.
1 parent 468259e commit e3d195d

File tree

40 files changed

+1110
-981
lines changed

40 files changed

+1110
-981
lines changed

packages/apidom-reference/src/configuration/saturated.ts

+31-31
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@ import OpenApi3_0ResolveStrategy from '../resolve/strategies/openapi-3-0';
55
import OpenApi3_1ResolveStrategy from '../resolve/strategies/openapi-3-1';
66
import AsyncApi2ResolveStrategy from '../resolve/strategies/asyncapi-2';
77
import ApiDOMResolveStrategy from '../resolve/strategies/apidom';
8-
import ApiDesignSystemsJsonParser from '../parse/parsers/api-design-systems-json';
9-
import ApiDesignSystemsYamlParser from '../parse/parsers/api-design-systems-yaml';
10-
import OpenApiJson2Parser from '../parse/parsers/openapi-json-2';
11-
import OpenApiYaml2Parser from '../parse/parsers/openapi-yaml-2';
12-
import OpenApiJson3_0Parser from '../parse/parsers/openapi-json-3-0';
13-
import OpenApiYaml3_0Parser from '../parse/parsers/openapi-yaml-3-0';
14-
import OpenApiJson3_1Parser from '../parse/parsers/openapi-json-3-1';
15-
import OpenApiYaml3_1Parser from '../parse/parsers/openapi-yaml-3-1';
16-
import AsyncApiJson2Parser from '../parse/parsers/asyncapi-json-2';
17-
import AsyncApiYaml2Parser from '../parse/parsers/asyncapi-yaml-2';
18-
import WorkflowsJson1Parser from '../parse/parsers/workflows-json-1';
19-
import WorkflowsYaml1Parser from '../parse/parsers/workflows-yaml-1';
20-
import ApiDOMJsonParser from '../parse/parsers/apidom-json';
21-
import JsonParser from '../parse/parsers/json';
22-
import YamlParser from '../parse/parsers/yaml-1-2';
8+
import APIDesignSystemsJSONParser from '../parse/parsers/api-design-systems-json';
9+
import APIDesignSystemsYAMLParser from '../parse/parsers/api-design-systems-yaml';
10+
import OpenAPIJSON2Parser from '../parse/parsers/openapi-json-2';
11+
import OpenAPIYAML2Parser from '../parse/parsers/openapi-yaml-2';
12+
import OpenAPIJSON3_0Parser from '../parse/parsers/openapi-json-3-0';
13+
import OpenAPIYAML3_0Parser from '../parse/parsers/openapi-yaml-3-0';
14+
import OpenAPIJSON3_1Parser from '../parse/parsers/openapi-json-3-1';
15+
import OpenAPIYAML3_1Parser from '../parse/parsers/openapi-yaml-3-1';
16+
import AsyncAPIJSON2Parser from '../parse/parsers/asyncapi-json-2';
17+
import AsyncAPIYAML2Parser from '../parse/parsers/asyncapi-yaml-2';
18+
import WorkflowsJSON1Parser from '../parse/parsers/workflows-json-1';
19+
import WorkflowsYAML1Parser from '../parse/parsers/workflows-yaml-1';
20+
import APIDOMJSONParser from '../parse/parsers/apidom-json';
21+
import JSONParser from '../parse/parsers/json';
22+
import YAMLParser from '../parse/parsers/yaml-1-2';
2323
import BinaryParser from '../parse/parsers/binary/index-node';
2424
import ApiDOMDereferenceStrategy from '../dereference/strategies/apidom';
2525
import OpenApi2DereferenceStrategy from '../dereference/strategies/openapi-2';
@@ -30,22 +30,22 @@ import OpenApi3_1BundleStrategy from '../bundle/strategies/openapi-3-1';
3030
import { options } from '../index';
3131

3232
options.parse.parsers = [
33-
OpenApiJson2Parser({ allowEmpty: true, sourceMap: false }),
34-
OpenApiYaml2Parser({ allowEmpty: true, sourceMap: false }),
35-
OpenApiJson3_0Parser({ allowEmpty: true, sourceMap: false }),
36-
OpenApiYaml3_0Parser({ allowEmpty: true, sourceMap: false }),
37-
OpenApiJson3_1Parser({ allowEmpty: true, sourceMap: false }),
38-
OpenApiYaml3_1Parser({ allowEmpty: true, sourceMap: false }),
39-
AsyncApiJson2Parser({ allowEmpty: true, sourceMap: false }),
40-
AsyncApiYaml2Parser({ allowEmpty: true, sourceMap: false }),
41-
WorkflowsJson1Parser({ allowEmpty: true, sourceMap: false }),
42-
WorkflowsYaml1Parser({ allowEmpty: true, sourceMap: false }),
43-
ApiDesignSystemsJsonParser({ allowEmpty: true, sourceMap: false }),
44-
ApiDesignSystemsYamlParser({ allowEmpty: true, sourceMap: false }),
45-
ApiDOMJsonParser({ allowEmpty: true, sourceMap: false }),
46-
JsonParser({ allowEmpty: true, sourceMap: false }),
47-
YamlParser({ allowEmpty: true, sourceMap: false }),
48-
BinaryParser({ allowEmpty: true }),
33+
new OpenAPIJSON2Parser({ allowEmpty: true, sourceMap: false }),
34+
new OpenAPIYAML2Parser({ allowEmpty: true, sourceMap: false }),
35+
new OpenAPIJSON3_0Parser({ allowEmpty: true, sourceMap: false }),
36+
new OpenAPIYAML3_0Parser({ allowEmpty: true, sourceMap: false }),
37+
new OpenAPIJSON3_1Parser({ allowEmpty: true, sourceMap: false }),
38+
new OpenAPIYAML3_1Parser({ allowEmpty: true, sourceMap: false }),
39+
new AsyncAPIJSON2Parser({ allowEmpty: true, sourceMap: false }),
40+
new AsyncAPIYAML2Parser({ allowEmpty: true, sourceMap: false }),
41+
new WorkflowsJSON1Parser({ allowEmpty: true, sourceMap: false }),
42+
new WorkflowsYAML1Parser({ allowEmpty: true, sourceMap: false }),
43+
new APIDesignSystemsJSONParser({ allowEmpty: true, sourceMap: false }),
44+
new APIDesignSystemsYAMLParser({ allowEmpty: true, sourceMap: false }),
45+
new APIDOMJSONParser({ allowEmpty: true, sourceMap: false }),
46+
new JSONParser({ allowEmpty: true, sourceMap: false }),
47+
new YAMLParser({ allowEmpty: true, sourceMap: false }),
48+
new BinaryParser({ allowEmpty: true }),
4949
];
5050

5151
options.resolve.resolvers = [

packages/apidom-reference/src/parse/index.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { ParseResultElement } from '@swagger-api/apidom-core';
44
import * as url from '../util/url';
55
import File from '../File';
66
import * as plugins from '../util/plugins';
7-
import { ReferenceOptions as IReferenceOptions, Parser as IParser } from '../types';
7+
import { ReferenceOptions as IReferenceOptions } from '../types';
8+
import Parser from './parsers/Parser';
89
import ParseError from '../errors/ParseError';
910
import UnmatchedResolverError from '../errors/UnmatchedResolverError';
1011
import { readFile } from '../resolve/util';
@@ -18,7 +19,7 @@ const parseFile = async (file: File, options: IReferenceOptions): Promise<ParseR
1819
return Object.assign(clonedParser, options.parse.parserOpts);
1920
});
2021

21-
const parsers: IParser[] = await plugins.filter('canParse', [file, options], optsBoundParsers);
22+
const parsers: Parser[] = await plugins.filter('canParse', [file, options], optsBoundParsers);
2223

2324
// we couldn't find any parser for this File
2425
if (isEmpty(parsers)) {
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,54 @@
1-
import stampit from 'stampit';
21
import { ParseResultElement } from '@swagger-api/apidom-core';
3-
import { NotImplementedError } from '@swagger-api/apidom-error';
4-
5-
import { Parser as IParser } from '../../types';
6-
7-
const Parser: stampit.Stamp<IParser> = stampit({
8-
props: {
9-
name: '',
10-
/**
11-
* Whether to allow "empty" files. This includes zero-byte files.
12-
*/
13-
allowEmpty: true,
14-
15-
/**
16-
* Whether to generate source map during parsing.
17-
*/
18-
sourceMap: false,
19-
/**
20-
* List of supported file extensions.
21-
*/
22-
fileExtensions: [],
23-
/**
24-
* List of supported media types.
25-
*/
26-
mediaTypes: [],
27-
},
28-
init(
29-
this: IParser,
30-
{
31-
allowEmpty = this.allowEmpty,
32-
sourceMap = this.sourceMap,
33-
fileExtensions = this.fileExtensions,
34-
mediaTypes = this.mediaTypes,
35-
} = {},
36-
) {
2+
3+
import File from '../../File';
4+
5+
export interface ParserOptions {
6+
readonly name: string;
7+
readonly allowEmpty?: boolean;
8+
readonly sourceMap?: boolean;
9+
readonly fileExtensions?: string[];
10+
readonly mediaTypes?: string[];
11+
}
12+
13+
abstract class Parser {
14+
public readonly name: string;
15+
16+
/**
17+
* Whether to allow "empty" files. This includes zero-byte files.
18+
*/
19+
public allowEmpty: boolean;
20+
21+
/**
22+
* Whether to generate source map during parsing.
23+
*/
24+
public sourceMap: boolean;
25+
26+
/**
27+
* List of supported file extensions.
28+
*/
29+
public fileExtensions: string[];
30+
31+
/**
32+
* List of supported media types.
33+
*/
34+
public mediaTypes: string[];
35+
36+
constructor({
37+
name,
38+
allowEmpty = true,
39+
sourceMap = false,
40+
fileExtensions = [],
41+
mediaTypes = [],
42+
}: ParserOptions) {
43+
this.name = name;
3744
this.allowEmpty = allowEmpty;
3845
this.sourceMap = sourceMap;
3946
this.fileExtensions = fileExtensions;
4047
this.mediaTypes = mediaTypes;
41-
},
42-
methods: {
43-
async canParse(): Promise<boolean> {
44-
throw new NotImplementedError('canParse method in Parser stamp is not yet implemented.');
45-
},
46-
async parse(): Promise<ParseResultElement> {
47-
throw new NotImplementedError('parse method in Parser stamp is not yet implemented.');
48-
},
49-
},
50-
});
48+
}
49+
50+
abstract canParse(file: File): boolean | Promise<boolean>;
51+
abstract parse(file: File): ParseResultElement | Promise<ParseResultElement>;
52+
}
5153

5254
export default Parser;
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,51 @@
1-
import stampit from 'stampit';
21
import { pick } from 'ramda';
32
import { ParseResultElement } from '@swagger-api/apidom-core';
43
import {
54
parse,
6-
mediaTypes,
5+
mediaTypes as ADSMediaTypes,
76
detect,
87
} from '@swagger-api/apidom-parser-adapter-api-design-systems-json';
98

109
import ParserError from '../../../errors/ParserError';
11-
import { Parser as IParser } from '../../../types';
12-
import Parser from '../Parser';
10+
import Parser, { ParserOptions } from '../Parser';
1311
import File from '../../../File';
1412

15-
const ApiDesignSystemsJsonParser: stampit.Stamp<IParser> = stampit(Parser, {
16-
props: {
17-
name: 'api-design-systems-json',
18-
fileExtensions: ['.json'],
19-
mediaTypes,
20-
},
21-
methods: {
22-
async canParse(file: File): Promise<boolean> {
23-
const hasSupportedFileExtension =
24-
this.fileExtensions.length === 0 ? true : this.fileExtensions.includes(file.extension);
25-
const hasSupportedMediaType = this.mediaTypes.includes(file.mediaType);
26-
27-
if (!hasSupportedFileExtension) return false;
28-
if (hasSupportedMediaType) return true;
29-
if (!hasSupportedMediaType) {
30-
return detect(file.toString());
31-
}
32-
return false;
33-
},
34-
async parse(file: File): Promise<ParseResultElement> {
35-
const source = file.toString();
36-
37-
try {
38-
const parserOpts = pick(['sourceMap', 'syntacticAnalysis', 'refractorOpts'], this);
39-
return await parse(source, parserOpts);
40-
} catch (error: any) {
41-
throw new ParserError(`Error parsing "${file.uri}"`, { cause: error });
42-
}
43-
},
44-
},
45-
});
46-
47-
export default ApiDesignSystemsJsonParser;
13+
export interface APIDesignSystemsJSONParserOptions extends Omit<ParserOptions, 'name'> {}
14+
15+
class APIDesignSystemsJSONParser extends Parser {
16+
public syntacticAnalysis?: 'direct' | 'indirect';
17+
18+
public refractorOpts!: object;
19+
20+
constructor(options?: APIDesignSystemsJSONParserOptions) {
21+
const { fileExtensions = ['.json'], mediaTypes = ADSMediaTypes, ...rest } = options ?? {};
22+
23+
super({ ...rest, name: 'api-design-systems-json', fileExtensions, mediaTypes });
24+
}
25+
26+
async canParse(file: File): Promise<boolean> {
27+
const hasSupportedFileExtension =
28+
this.fileExtensions.length === 0 ? true : this.fileExtensions.includes(file.extension);
29+
const hasSupportedMediaType = this.mediaTypes.includes(file.mediaType);
30+
31+
if (!hasSupportedFileExtension) return false;
32+
if (hasSupportedMediaType) return true;
33+
if (!hasSupportedMediaType) {
34+
return detect(file.toString());
35+
}
36+
return false;
37+
}
38+
39+
async parse(file: File): Promise<ParseResultElement> {
40+
const source = file.toString();
41+
42+
try {
43+
const parserOpts = pick(['sourceMap', 'syntacticAnalysis', 'refractorOpts'], this);
44+
return await parse(source, parserOpts);
45+
} catch (error: unknown) {
46+
throw new ParserError(`Error parsing "${file.uri}"`, { cause: error });
47+
}
48+
}
49+
}
50+
51+
export default APIDesignSystemsJSONParser;
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,53 @@
1-
import stampit from 'stampit';
21
import { pick } from 'ramda';
32
import { ParseResultElement } from '@swagger-api/apidom-core';
43
import {
54
parse,
6-
mediaTypes,
5+
mediaTypes as ADSMediaTypes,
76
detect,
87
} from '@swagger-api/apidom-parser-adapter-api-design-systems-yaml';
98

109
import ParserError from '../../../errors/ParserError';
11-
import { Parser as IParser } from '../../../types';
12-
import Parser from '../Parser';
10+
import Parser, { ParserOptions } from '../Parser';
1311
import File from '../../../File';
1412

15-
const ApiDesignSystemsYamlParser: stampit.Stamp<IParser> = stampit(Parser, {
16-
props: {
17-
name: 'api-design-systems-yaml',
18-
fileExtensions: ['.yaml', '.yml'],
19-
mediaTypes,
20-
},
21-
methods: {
22-
async canParse(file: File): Promise<boolean> {
23-
const hasSupportedFileExtension =
24-
this.fileExtensions.length === 0 ? true : this.fileExtensions.includes(file.extension);
25-
const hasSupportedMediaType = this.mediaTypes.includes(file.mediaType);
26-
27-
if (!hasSupportedFileExtension) return false;
28-
if (hasSupportedMediaType) return true;
29-
if (!hasSupportedMediaType) {
30-
return detect(file.toString());
31-
}
32-
return false;
33-
},
34-
async parse(file: File): Promise<ParseResultElement> {
35-
const source = file.toString();
36-
37-
try {
38-
const parserOpts = pick(['sourceMap', 'refractorOpts'], this);
39-
return await parse(source, parserOpts);
40-
} catch (error: any) {
41-
throw new ParserError(`Error parsing "${file.uri}"`, { cause: error });
42-
}
43-
},
44-
},
45-
});
46-
47-
export default ApiDesignSystemsYamlParser;
13+
export interface APIDesignSystemsYAMLParserOptions extends Omit<ParserOptions, 'name'> {}
14+
15+
class APIDesignSystemsYAMLParser extends Parser {
16+
public refractorOpts!: object;
17+
18+
constructor(options?: APIDesignSystemsYAMLParserOptions) {
19+
const {
20+
fileExtensions = ['.yaml', '.yml'],
21+
mediaTypes = ADSMediaTypes,
22+
...rest
23+
} = options ?? {};
24+
25+
super({ ...rest, name: 'api-design-systems-yaml', fileExtensions, mediaTypes });
26+
}
27+
28+
async canParse(file: File): Promise<boolean> {
29+
const hasSupportedFileExtension =
30+
this.fileExtensions.length === 0 ? true : this.fileExtensions.includes(file.extension);
31+
const hasSupportedMediaType = this.mediaTypes.includes(file.mediaType);
32+
33+
if (!hasSupportedFileExtension) return false;
34+
if (hasSupportedMediaType) return true;
35+
if (!hasSupportedMediaType) {
36+
return detect(file.toString());
37+
}
38+
return false;
39+
}
40+
41+
async parse(file: File): Promise<ParseResultElement> {
42+
const source = file.toString();
43+
44+
try {
45+
const parserOpts = pick(['sourceMap', 'refractorOpts'], this);
46+
return await parse(source, parserOpts);
47+
} catch (error: unknown) {
48+
throw new ParserError(`Error parsing "${file.uri}"`, { cause: error });
49+
}
50+
}
51+
}
52+
53+
export default APIDesignSystemsYAMLParser;

0 commit comments

Comments
 (0)