Skip to content

Commit 9fc2150

Browse files
committed
feat(ElasticApiParser): Improved source api filepath determination by version
1 parent fef17f0 commit 9fc2150

File tree

4 files changed

+126
-43
lines changed

4 files changed

+126
-43
lines changed

src/ElasticApiParser.js

Lines changed: 70 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,17 @@ import {
1313
GraphQLNonNull,
1414
} from 'graphql';
1515
import { GraphQLJSON, upperFirst, TypeComposer } from 'graphql-compose';
16+
import { reorderKeys } from './utils';
1617

1718
import type {
1819
GraphQLArgumentConfig,
1920
GraphQLFieldConfig,
21+
GraphQLFieldConfigMap,
2022
GraphQLFieldConfigArgumentMap,
2123
GraphQLFieldMap,
2224
GraphQLInputType,
2325
} from 'graphql/type/definition'; // eslint-disable-line
2426

25-
export type ElasticApiVersion =
26-
| '5_0'
27-
| '5_x'
28-
| '2_4'
29-
| '2_3'
30-
| '2_2'
31-
| '2_1'
32-
| '2_0'
33-
| '1_7'
34-
| '1_6'
35-
| '1_5'
36-
| '1_4'
37-
| '1_3'
38-
| '1_2'
39-
| '1_1'
40-
| '1_0'
41-
| '0_90';
42-
43-
export type ElasticApiParserOptsT = {
44-
elasticClient?: any, // Elastic client
45-
version?: ElasticApiVersion,
46-
prefix?: string,
47-
elasticApiFilePath?: string,
48-
};
49-
5027
export type ElasticParamConfigT = {
5128
type: string,
5229
name?: string,
@@ -84,22 +61,33 @@ export type ElasticParsedSourceT = {
8461
},
8562
};
8663

64+
export type ElasticApiParserOptsT = {
65+
elasticClient?: any, // Elastic client
66+
apiVersion?: string,
67+
prefix?: string,
68+
elasticApiFilePath?: string,
69+
};
70+
8771
export default class ElasticApiParser {
8872
cachedEnums: {
8973
[fieldName: string]: { [valsStringified: string]: GraphQLEnumType },
9074
};
91-
version: string;
75+
apiVersion: string;
9276
prefix: string;
9377
elasticClient: any;
9478
parsedSource: ElasticParsedSourceT;
9579

9680
constructor(opts: ElasticApiParserOptsT = {}) {
97-
// derived from installed package `elasticsearch`
98-
// from ../../node_modules/elasticsearch/src/lib/apis/VERSION.js
99-
this.version = opts.version || '5_0';
81+
// avaliable varsions can be found in installed package `elasticsearch`
82+
// in file /node_modules/elasticsearch/src/lib/apis/index.js
83+
this.apiVersion = opts.apiVersion ||
84+
(opts.elasticClient &&
85+
opts.elasticClient.config &&
86+
opts.elasticClient.config.apiVersion) ||
87+
'_default';
10088
const apiFilePath = path.resolve(
10189
opts.elasticApiFilePath ||
102-
`./node_modules/elasticsearch/src/lib/apis/${this.version}.js`
90+
ElasticApiParser.findApiVersionFile(this.apiVersion)
10391
);
10492
const source = ElasticApiParser.loadApiFile(apiFilePath);
10593
this.parsedSource = ElasticApiParser.parseSource(source);
@@ -109,11 +97,48 @@ export default class ElasticApiParser {
10997
this.cachedEnums = {};
11098
}
11199

100+
static loadFile(absolutePath: string): string {
101+
return fs.readFileSync(absolutePath, 'utf8');
102+
}
103+
112104
static loadApiFile(absolutePath: string): string {
113-
const code = fs.readFileSync(absolutePath, 'utf8');
105+
let code;
106+
try {
107+
code = ElasticApiParser.loadFile(absolutePath);
108+
} catch (e) {
109+
throw new Error(
110+
`Cannot load Elastic API source file from ${absolutePath}`
111+
);
112+
}
114113
return ElasticApiParser.cleanUpSource(code);
115114
}
116115

116+
static loadApiListFile(absolutePath: string): string {
117+
let code;
118+
try {
119+
code = ElasticApiParser.loadFile(absolutePath);
120+
} catch (e) {
121+
throw new Error(
122+
`Cannot load Elastic API file with avaliable versions from ${absolutePath}`
123+
);
124+
}
125+
return code;
126+
}
127+
128+
static findApiVersionFile(version: string): string {
129+
const apiFolder = './node_modules/elasticsearch/src/lib/apis/';
130+
const apiListFile = path.resolve(apiFolder, 'index.js');
131+
const apiListCode = ElasticApiParser.loadApiListFile(apiListFile);
132+
const re = new RegExp(`\\'${version}\\':\\srequire\\(\\'(.+)\\'\\)`, 'gi');
133+
const match = re.exec(apiListCode);
134+
if (match && match[1]) {
135+
return path.resolve(apiFolder, `${match[1]}.js`);
136+
}
137+
throw new Error(
138+
`Can not found Elastic version '${version}' in ${apiListFile}`
139+
);
140+
}
141+
117142
static cleanUpSource(code: string): string {
118143
// remove invalid markup
119144
// {<<api-param-type-boolean,`Boolean`>>} converted to {Boolean}
@@ -229,12 +254,23 @@ export default class ElasticApiParser {
229254
return result;
230255
}
231256

232-
generateFieldMap(): GraphQLFieldMap<*, *> {
257+
generateFieldMap(): GraphQLFieldConfigMap<*, *> {
233258
const result = {};
234259
Object.keys(this.parsedSource).forEach(methodName => {
235260
result[methodName] = this.generateFieldConfig(methodName);
236261
});
237-
return this.reassembleNestedFields(result);
262+
263+
const fieldMap = this.reassembleNestedFields(result);
264+
return reorderKeys(fieldMap, [
265+
'cat',
266+
'cluster',
267+
'indices',
268+
'ingest',
269+
'nodes',
270+
'snapshot',
271+
'tasks',
272+
'search',
273+
]);
238274
}
239275

240276
generateFieldConfig(
@@ -433,7 +469,7 @@ export default class ElasticApiParser {
433469
if (!result[names[0]]) {
434470
result[names[0]] = {
435471
type: new GraphQLObjectType({
436-
name: `${this.prefix}Methods_${upperFirst(names[0])}`,
472+
name: `${this.prefix}_${upperFirst(names[0])}`,
437473
// $FlowFixMe
438474
fields: () => {},
439475
}),

src/__tests__/ElasticApiParser-test.js

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,13 @@ api.cat.prototype.allocation = ca({
5555
]
5656
});`;
5757

58-
// const elastic53 = fs.readFileSync(path.resolve(__dirname, '../../node_modules/elasticsearch/src/lib/apis/5_x.js'), 'utf8');
59-
// const t = fs.readFileSync(
60-
// path.resolve(__dirname, '__mocks__/apiPartial.js'),
61-
// 'utf8'
62-
// );
63-
// console.log(t);
64-
6558
describe('ElasticApiParser', () => {
6659
let parser;
6760

6861
beforeEach(() => {
69-
parser = new ElasticApiParser();
62+
parser = new ElasticApiParser({
63+
elasticApiFilePath: apiPartialPath,
64+
});
7065
});
7166

7267
describe('static methods', () => {
@@ -87,6 +82,46 @@ describe('ElasticApiParser', () => {
8782
});
8883
});
8984

85+
describe('findApiVersionFile()', () => {
86+
it('should find proper version', () => {
87+
const loadApiListFile = ElasticApiParser.loadApiListFile;
88+
// $FlowFixMe
89+
ElasticApiParser.loadApiListFile = () =>
90+
`
91+
module.exports = {
92+
'_default': require('./5_0'),
93+
'5.0': require('./5_0'),
94+
'2.4': require('./2_4'),
95+
'2.1': require('./2_1'),
96+
'1.7': require('./1_7'),
97+
'0.90': require('./0_90'),
98+
'5.x': require('./5_x'),
99+
'master': require('./master')
100+
};
101+
`;
102+
103+
expect(ElasticApiParser.findApiVersionFile('5.0')).toMatch(
104+
// $FlowFixMe
105+
'elasticsearch/src/lib/apis/5_0.js'
106+
);
107+
expect(ElasticApiParser.findApiVersionFile('2.4')).toMatch(
108+
// $FlowFixMe
109+
'elasticsearch/src/lib/apis/2_4.js'
110+
);
111+
expect(ElasticApiParser.findApiVersionFile('1.7')).toMatch(
112+
// $FlowFixMe
113+
'elasticsearch/src/lib/apis/1_7.js'
114+
);
115+
expect(ElasticApiParser.findApiVersionFile('_default')).toMatch(
116+
// $FlowFixMe
117+
'elasticsearch/src/lib/apis/5_0.js'
118+
);
119+
120+
// $FlowFixMe
121+
ElasticApiParser.loadApiListFile = loadApiListFile;
122+
});
123+
});
124+
90125
describe('cleanupDescription()', () => {
91126
it('should remove `- ` from start and trim', () => {
92127
expect(ElasticApiParser.cleanupDescription('- Some param ')).toEqual(

src/__tests__/__snapshots__/ElasticApiParser-test.js.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ exports[`ElasticApiParser generateFieldMap() should generate fieldMap 1`] = `
204204
Object {
205205
"cat": Object {
206206
"resolve": [Function],
207-
"type": "ElasticMethods_Cat",
207+
"type": "Elastic_Cat",
208208
},
209209
"search": Object {
210210
"args": Object {

src/utils.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,15 @@ export function getOrSetType<T>(
1919
export function desc(str: string): string {
2020
return str.replace(/\n\s+/ig, ' ').replace(/^\s+/, '');
2121
}
22+
23+
export function reorderKeys<T: Object>(obj: T, names: string[]): T {
24+
const orderedFields = {};
25+
const fields = { ...obj };
26+
names.forEach(name => {
27+
if (fields[name]) {
28+
orderedFields[name] = fields[name];
29+
delete fields[name];
30+
}
31+
});
32+
return { ...orderedFields, ...fields };
33+
}

0 commit comments

Comments
 (0)