Skip to content

Commit cb4fd6f

Browse files
Merge pull request #135 from luckymarmot/135-improve-paw-parser
135 improve paw parser
2 parents ec7f06e + d3d21fb commit cb4fd6f

File tree

4 files changed

+177
-8
lines changed

4 files changed

+177
-8
lines changed

src/parsers/paw/Parser.js

+40-7
Original file line numberDiff line numberDiff line change
@@ -354,17 +354,45 @@ methods.updateHostKeyWithLongestCommonPathname = ({ entries, lcPathname }, key)
354354
}
355355
}
356356

357+
/**
358+
* converts a PawRequest into an array of entries of size 1 where the key is the extracted origin of
359+
* the urlBase of the requests.
360+
* @param {Array<PawRequest>} request: the requests to group by host
361+
* @returns {Array<Entry<string, PawRequest>>} the corresponding sequence of entries.
362+
*/
363+
methods.convertSingleRequestIntoRequestEntry = (request) => {
364+
const baseUrl = request.getUrlBase()
365+
const numberOfSlashes = parse(baseUrl).slashes ? 3 : 1
366+
const origin = baseUrl.split('/').slice(0, numberOfSlashes).join('/')
367+
return [
368+
{ key: origin, value: request }
369+
]
370+
}
371+
372+
/**
373+
* converts an array of PawRequests into an array of entries where the keys are the urlBase of the
374+
* requests, except if there is only one request.
375+
* @param {Array<PawRequest>} requests: the requests to group by host
376+
* @returns {Array<Entry<string, PawRequest>>} the corresponding sequence of entries.
377+
*/
378+
methods.convertRequestsIntoRequestEntries = (requests) => {
379+
if (requests.length === 1) {
380+
return methods.convertSingleRequestIntoRequestEntry(requests[0])
381+
}
382+
383+
return requests.map(request => {
384+
return { key: request.getUrlBase(), value: request }
385+
})
386+
}
387+
357388
/**
358389
* extracts common hosts from a list of requests, and assigns each request to its corresponding host
359390
* @param {Array<PawRequest>} requests: the requests to group by host
360391
* @returns {Seq<Entry<string, *>>} the corresponding sequence of entries.
361392
*/
362393
methods.extractCommonHostsFromRequests = (requests) => {
363-
const hosts = requests
364-
.map((request) => {
365-
return { key: request.getUrlBase(), value: request }
366-
})
367-
.reduce(methods.addHostEntryToHostMap, {})
394+
const requestEntries = methods.convertRequestsIntoRequestEntries(requests)
395+
const hosts = requestEntries.reduce(methods.addHostEntryToHostMap, {})
368396

369397
return new OrderedMap(hosts).map(methods.updateHostKeyWithLongestCommonPathname).valueSeq()
370398
}
@@ -944,15 +972,20 @@ methods.convertRequestVariableDVIntoParameter = (
944972
}) }
945973
}
946974

947-
const { name, value, schema, type, description } = variable
975+
const { name, value, required, schema, type, description } = variable
976+
977+
const defaultValue = typeof (schema || {}).default !== 'undefined' ?
978+
schema.default :
979+
value.getEvaluatedString()
948980

949981
const param = new Parameter({
950982
in: location,
951983
key: name || paramName,
952984
name: name || paramName,
953985
type: type || 'string',
954986
description: description || null,
955-
default: value.getEvaluatedString(),
987+
required: required || false,
988+
default: defaultValue,
956989
constraints: List([
957990
new Constraint.JSONSchema(schema)
958991
]),

src/parsers/paw/__tests__/Parser.spec.js

+112
Original file line numberDiff line numberDiff line change
@@ -499,8 +499,52 @@ describe('parsers/paw/Parser.js', () => {
499499
})
500500
})
501501

502+
describe('@convertSingleRequestIntoRequestEntry', () => {
503+
it('should work', () => {
504+
const inputs = [
505+
{ getUrlBase: () => '' },
506+
{ getUrlBase: () => 'http://paw.cloud/base/users' },
507+
{ getUrlBase: () => 'file:///base/users' },
508+
{ getUrlBase: () => 'urn:paw.cloud/base/users' }
509+
]
510+
const expected = [
511+
[ { key: '', value: { getUrlBase: () => null } } ],
512+
[ { key: 'http://paw.cloud', value: { getUrlBase: () => 'http://paw.cloud/base/users' } } ],
513+
[ { key: 'file://', value: { getUrlBase: () => 'file:///base/users' } } ],
514+
[ { key: 'urn:paw.cloud', value: { getUrlBase: () => 'urn:paw.cloud/base/users' } } ]
515+
]
516+
const actual = inputs.map(input => __internals__.convertSingleRequestIntoRequestEntry(input))
517+
expect(JSON.stringify(actual, null, 2)).toEqual(JSON.stringify(expected, null, 2))
518+
})
519+
})
520+
521+
describe('@convertRequestsIntoRequestEntries', () => {
522+
it('should work', () => {
523+
spyOn(__internals__, 'convertSingleRequestIntoRequestEntry').andCall(r => {
524+
return [ { key: r.getUrlBase() * 2, value: r } ]
525+
})
526+
527+
const inputs = [
528+
[],
529+
[ { getUrlBase: () => 123 } ],
530+
[ { getUrlBase: () => 123 }, { getUrlBase: () => 234 } ]
531+
]
532+
const expected = [
533+
[],
534+
[ { key: 123 * 2, value: { getUrlBase: () => 123 } } ],
535+
[
536+
{ key: 123, value: { getUrlBase: () => 123 } },
537+
{ key: 234, value: { getUrlBase: () => 234 } }
538+
]
539+
]
540+
const actual = inputs.map(input => __internals__.convertRequestsIntoRequestEntries(input))
541+
expect(JSON.stringify(actual, null, 2)).toEqual(JSON.stringify(expected, null, 2))
542+
})
543+
})
544+
502545
describe('@extractCommonHostsFromRequests', () => {
503546
it('should work if underlying methods are correct', () => {
547+
spyOn(__internals__, 'convertRequestsIntoRequestEntries').andCall(v => v)
504548
spyOn(__internals__, 'addHostEntryToHostMap').andReturn({ a: 321, b: 321, c: 321 })
505549
spyOn(__internals__, 'updateHostKeyWithLongestCommonPathname').andReturn(123)
506550
const req1 = { getUrlBase: () => {} }
@@ -1313,6 +1357,74 @@ describe('parsers/paw/Parser.js', () => {
13131357
)
13141358
expect(actual).toEqual(expected)
13151359
})
1360+
1361+
it('should prefer schema default over value', () => {
1362+
const variable = {
1363+
name: 'userId',
1364+
value: { getEvaluatedString: () => 123 },
1365+
schema: { default: '' },
1366+
type: 345
1367+
}
1368+
const request = { getVariableById: () => variable }
1369+
const location = 'queries'
1370+
const contexts = List([ 567, 567 ])
1371+
const paramName = 'UserId'
1372+
const input = { variableUUID: 678 }
1373+
const expected = {
1374+
key: 'UserId',
1375+
value: new Parameter({
1376+
in: 'queries',
1377+
key: 'userId',
1378+
name: 'userId',
1379+
type: 345,
1380+
description: null,
1381+
default: '',
1382+
constraints: List([
1383+
new Constraint.JSONSchema({ default: '' })
1384+
]),
1385+
applicableContexts: List([ 567, 567 ])
1386+
})
1387+
}
1388+
1389+
const actual = __internals__.convertRequestVariableDVIntoParameter(
1390+
request, location, contexts, input, paramName
1391+
)
1392+
expect(actual).toEqual(expected)
1393+
})
1394+
1395+
it('should work if no schema', () => {
1396+
const variable = {
1397+
name: 'userId',
1398+
value: { getEvaluatedString: () => 123 },
1399+
schema: null,
1400+
type: 345
1401+
}
1402+
const request = { getVariableById: () => variable }
1403+
const location = 'queries'
1404+
const contexts = List([ 567, 567 ])
1405+
const paramName = 'UserId'
1406+
const input = { variableUUID: 678 }
1407+
const expected = {
1408+
key: 'UserId',
1409+
value: new Parameter({
1410+
in: 'queries',
1411+
key: 'userId',
1412+
name: 'userId',
1413+
type: 345,
1414+
description: null,
1415+
default: 123,
1416+
constraints: List([
1417+
new Constraint.JSONSchema(null)
1418+
]),
1419+
applicableContexts: List([ 567, 567 ])
1420+
})
1421+
}
1422+
1423+
const actual = __internals__.convertRequestVariableDVIntoParameter(
1424+
request, location, contexts, input, paramName
1425+
)
1426+
expect(actual).toEqual(expected)
1427+
})
13161428
})
13171429

13181430
describe('@convertRequestVariableDSIntoParameter', () => {

src/serializers/swagger/v2.0/Serializer.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,11 @@ methods.getTagDefinitions = (api) => {
918918
*/
919919
methods.getPathFromResource = (resource) => {
920920
const path = resource.get('path').toURLObject(List([ '{', '}' ])).pathname
921+
922+
if (path[0] !== '/') {
923+
return '/' + path
924+
}
925+
921926
return path
922927
}
923928

@@ -1329,7 +1334,7 @@ methods.convertRequestToOperationObject = (store, { consumes, produces }, reques
13291334
}
13301335

13311336
const value = operation
1332-
return { key, value }
1337+
return { key: key.toLowerCase(), value }
13331338
}
13341339
/* eslint-enable max-statements */
13351340

src/serializers/swagger/v2.0/__tests__/Serializer.spec.js

+19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Reference from '../../../../models/Reference'
1010
import Parameter from '../../../../models/Parameter'
1111
import Resource from '../../../../models/Resource'
1212
import URL from '../../../../models/URL'
13+
import URLComponent from '../../../../models/URLComponent'
1314
import Store from '../../../../models/Store'
1415
import Constraint from '../../../../models/Constraint'
1516
import ParameterContainer from '../../../../models/ParameterContainer'
@@ -1650,6 +1651,24 @@ describe('serializers/swagger/v2.0/Serializer.js', () => {
16501651

16511652
expect(actual).toEqual(expected)
16521653
})
1654+
1655+
it('should work even if path not starting with /', () => {
1656+
const input = new Resource({
1657+
path: new URL().set(
1658+
'pathname',
1659+
new URLComponent({
1660+
componentName: 'pathname',
1661+
string: 'my/path/{pathId}',
1662+
variableDelimiters: List([ '{', '}' ])
1663+
})
1664+
)
1665+
})
1666+
1667+
const expected = '/my/path/{pathId}'
1668+
const actual = __internals__.getPathFromResource(input)
1669+
1670+
expect(actual).toEqual(expected)
1671+
})
16531672
})
16541673

16551674
describe('@convertInterfaceToTagString', () => {

0 commit comments

Comments
 (0)