1 | import { isEmpty } from 'ramda';
|
---|
2 | import * as url from "../util/url.mjs";
|
---|
3 | import File from "../util/File.mjs";
|
---|
4 | import * as plugins from "../util/plugins.mjs";
|
---|
5 | import ParseError from "../errors/ParseError.mjs";
|
---|
6 | import UnmatchedResolverError from "../errors/UnmatchedResolverError.mjs";
|
---|
7 | import { readFile } from "../resolve/util.mjs";
|
---|
8 | /**
|
---|
9 | * Parses the given file's contents, using the configured parser plugins.
|
---|
10 | */
|
---|
11 | const parseFile = async (file, options) => {
|
---|
12 | const optsBoundParsers = options.parse.parsers.map(parser => {
|
---|
13 | const clonedParser = Object.create(parser);
|
---|
14 | return Object.assign(clonedParser, options.parse.parserOpts);
|
---|
15 | });
|
---|
16 | const parsers = await plugins.filter('canParse', file, optsBoundParsers);
|
---|
17 |
|
---|
18 | // we couldn't find any parser for this File
|
---|
19 | if (isEmpty(parsers)) {
|
---|
20 | throw new UnmatchedResolverError(file.uri);
|
---|
21 | }
|
---|
22 | try {
|
---|
23 | const {
|
---|
24 | plugin,
|
---|
25 | result
|
---|
26 | } = await plugins.run('parse', [file], parsers);
|
---|
27 |
|
---|
28 | // empty files handling
|
---|
29 | if (!plugin.allowEmpty && result.isEmpty) {
|
---|
30 | return Promise.reject(new ParseError(`Error while parsing file "${file.uri}". File is empty.`));
|
---|
31 | }
|
---|
32 | return result;
|
---|
33 | } catch (error) {
|
---|
34 | throw new ParseError(`Error while parsing file "${file.uri}"`, {
|
---|
35 | cause: error
|
---|
36 | });
|
---|
37 | }
|
---|
38 | };
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * Parses a file into ApiDOM.
|
---|
42 | */
|
---|
43 | const parse = async (uri, options) => {
|
---|
44 | /**
|
---|
45 | * If the path is a filesystem path, then convert it to a URL.
|
---|
46 | *
|
---|
47 | * NOTE: According to the JSON Reference spec, these should already be URLs,
|
---|
48 | * but, in practice, many people use local filesystem paths instead.
|
---|
49 | * So we're being generous here and doing the conversion automatically.
|
---|
50 | * This is not intended to be a 100% bulletproof solution.
|
---|
51 | * If it doesn't work for your use-case, then use a URL instead.
|
---|
52 | */
|
---|
53 | const file = File({
|
---|
54 | uri: url.sanitize(url.stripHash(uri)),
|
---|
55 | mediaType: options.parse.mediaType
|
---|
56 | });
|
---|
57 | const data = await readFile(file, options);
|
---|
58 | return parseFile(File({
|
---|
59 | ...file,
|
---|
60 | data
|
---|
61 | }), options);
|
---|
62 | };
|
---|
63 | export default parse; |
---|