Skip to content
This repository has been archived by the owner on Nov 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #7 from apiaryio/pksunkara/boutique
Browse files Browse the repository at this point in the history
Integrate boutique
  • Loading branch information
zdne committed Feb 17, 2015
2 parents c9387b6 + 0ed3de9 commit 3547e34
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 6 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,40 @@ EOF
$ drafter blueprint.apib
```

## Resolved Named Types

Named Types (and anonymous named types) are expanded in-place in the AST. The three rules for when MSON AST is expanded are:

* If a named type is a sub-type of another named type
* If a named types includes a mixin
* If a value member or property member is referencing a named type

## Resolved Assets

The resolved assets for a *payload body example* and *payload body schema* are added to the array in the `content` key of the **Payload Object** with their element name set to `resolvedAsset` and `role` in `attributes` set as `bodyExample` and `bodySchema` respectively.

```json
{
// This is the payload object
"content": [
{
"element": "resolvedAsset",
"attributes": {
"role": "bodyExample"
},
"content": "{\"id\":\"250FF\",\"percent_off\":25,\"redeem_by\":null}"
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodySchema"
},
"content": "{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"string\"},\"percent_off\":{\"type\":\"number\"},\"redeem_by\":{\"type\":\"number\",\"description\":\"Date after which the coupon can no longer be redeemed\"}},\"$schema\":\"http://json-schema.org/draft-04/schema#\"}"
}
]
}
```

## Test
In order to run CI tests you need to have access to both Drafter and Boutique repositories and you need to give CircleCI some extended permissions over all your repositories to enable testing on their machines.

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"coffee-script": "~1.7.1",
"yargs": "~1.3.3",
"protagonist-experimental": "0.18.6",
"async": "~0.9.0",
"boutique": "git+ssh://[email protected]:apiaryio/boutique.git"
},
"devDependencies": {
Expand Down
106 changes: 102 additions & 4 deletions src/drafter.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,82 @@
protagonist = require 'protagonist-experimental'
boutique = require 'boutique'
options = require './options'
fs = require 'fs'
async = require 'async'

# Gather all payloads from the given parse result
#
# @param result [Object] Parse Result
gatherPayloads = (result) ->
payloads = []

for element in result.ast.content
if element.element is 'category'

for subElement in element.content
if subElement.element is 'resource'

for action in subElement.actions
attributes = null

for actionElement in action.content
attributes = actionElement if actionElement.element is 'dataStructure'

for example in action.examples
payloads.push {payload: request, actionAttributes: attributes} for request in example.requests
payloads.push {payload: response, actionAttributes: attributes} for response in example.responses

return payloads

# Generate payload body if MSON is provided and no body
#
# @param payload [Object] Payload object
# @param attributes [Object] Payload attributes object
# @param contentType [Object] Payload content type
generateBody = (payload, attributes, contentType, callback) ->
if not attributes? or not contentType? or payload.body
return callback null, payload, attributes, contentType

boutique.represent
ast: attributes,
contentType: contentType
, (error, body) ->
if not error? and body
resolved =
element: 'resolvedAsset'
attributes:
role: 'bodyExample'
content: body

payload.content.push resolved

# For waterfall
callback null, payload, attributes, contentType

# Generate payload schema if MSON is provided and no schema and ContentType is json
#
# @param payload [Object] Payload object
# @param attributes [Object] Payload attributes object
# @param contentType [Object] Payload content type
generateSchema = (payload, attributes, contentType, callback) ->
if not attributes? or payload.schema or contentType.indexOf('json') is -1
return callback null, payload, attributes, contentType

boutique.represent
ast: attributes,
contentType: 'application/schema+json'
, (error, body) ->
if not error? and body
resolved =
element: 'resolvedAsset'
attributes:
role: 'bodySchema'
content: body

payload.content.push resolved

# For waterfall
callback null, payload, attributes, contentType

#
# Drafter
Expand Down Expand Up @@ -39,7 +115,7 @@ class Drafter
# @param callback [(Error, ParseResult)]
make: (source, callback) ->
protagonist.parse source, @config, (error, result) =>
callback error if error
return callback error if error

ruleList = ['mson-inheritance', 'mson-mixin', 'mson-member-type-name']
rules = (require './rules/' + rule for rule in ruleList)
Expand All @@ -48,9 +124,32 @@ class Drafter
delete result.ast.resourceGroups

@expandNode result.ast, rules, 'blueprint'
@reconstructResourceGroups result.ast
payloads = gatherPayloads result

async.each payloads, @resolvePayload, (error) =>
@reconstructResourceGroups result.ast
callback error or null, result

# Resolve assets of a payload
resolvePayload: ({payload, actionAttributes}, callback) ->
attributes = null
contentType = ''

callback error, result
for header in payload.headers
contentType = header.value if header.name is 'Content-Type'

for element in payload.content
attributes = element if element.element is 'dataStructure'

attributes ?= actionAttributes

async.waterfall [
(cb) ->
cb null, payload, attributes, contentType
, generateBody
, generateSchema
], (error) ->
callback error or null

# Expand a certain node with the given rules
#
Expand All @@ -71,7 +170,6 @@ class Drafter
when 'dataStructure'
@dataStructures[subElement.name.literal] = subElement
when 'resource'

for resourceSubElement in subElement.content
@dataStructures[resourceSubElement.name.literal] = resourceSubElement if resourceSubElement.element is 'dataStructure'

Expand Down
90 changes: 88 additions & 2 deletions test/fixtures/dataStructures.ast.json
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,20 @@
"class": "memberType"
}
]
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodyExample"
},
"content": "{\"id\":\"250FF\",\"percent_off\":25,\"redeem_by\":null,\"created\":null,\"modified\":null,\"created_at\":null,\"updated_at\":null}"
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodySchema"
},
"content": "{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"string\"},\"percent_off\":{\"type\":\"number\"},\"redeem_by\":{\"type\":\"number\",\"description\":\"Date after which the coupon can no longer be redeemed\"},\"created\":{\"type\":\"number\"},\"modified\":{\"type\":\"number\"},\"created_at\":{\"type\":\"number\"},\"updated_at\":{\"type\":\"number\"}},\"$schema\":\"http://json-schema.org/draft-04/schema#\"}"
}
]
}
Expand Down Expand Up @@ -657,7 +671,22 @@
],
"body": "",
"schema": "",
"content": []
"content": [
{
"element": "resolvedAsset",
"attributes": {
"role": "bodyExample"
},
"content": "{\"percent_off\":25,\"redeem_by\":null,\"created\":null,\"modified\":null,\"created_at\":null,\"updated_at\":null}"
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodySchema"
},
"content": "{\"type\":\"object\",\"properties\":{\"percent_off\":{\"type\":\"number\"},\"redeem_by\":{\"type\":\"number\",\"description\":\"Date after which the coupon can no longer be redeemed\"},\"created\":{\"type\":\"number\"},\"modified\":{\"type\":\"number\"},\"created_at\":{\"type\":\"number\"},\"updated_at\":{\"type\":\"number\"}},\"$schema\":\"http://json-schema.org/draft-04/schema#\"}"
}
]
}
],
"responses": [
Expand Down Expand Up @@ -845,6 +874,20 @@
"class": "memberType"
}
]
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodyExample"
},
"content": "{\"id\":\"250FF\",\"percent_off\":25,\"redeem_by\":null,\"created\":null,\"modified\":null,\"created_at\":null,\"updated_at\":null}"
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodySchema"
},
"content": "{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"string\"},\"percent_off\":{\"type\":\"number\"},\"redeem_by\":{\"type\":\"number\",\"description\":\"Date after which the coupon can no longer be redeemed\"},\"created\":{\"type\":\"number\"},\"modified\":{\"type\":\"number\"},\"created_at\":{\"type\":\"number\"},\"updated_at\":{\"type\":\"number\"}},\"$schema\":\"http://json-schema.org/draft-04/schema#\"}"
}
]
}
Expand Down Expand Up @@ -2177,6 +2220,20 @@
"class": "memberType"
}
]
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodyExample"
},
"content": "{\"id\":\"250FF\",\"percent_off\":25,\"redeem_by\":null,\"created\":null,\"modified\":null,\"created_at\":null,\"updated_at\":null}"
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodySchema"
},
"content": "{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"string\"},\"percent_off\":{\"type\":\"number\"},\"redeem_by\":{\"type\":\"number\",\"description\":\"Date after which the coupon can no longer be redeemed\"},\"created\":{\"type\":\"number\"},\"modified\":{\"type\":\"number\"},\"created_at\":{\"type\":\"number\"},\"updated_at\":{\"type\":\"number\"}},\"$schema\":\"http://json-schema.org/draft-04/schema#\"}"
}
]
}
Expand Down Expand Up @@ -2600,7 +2657,22 @@
],
"body": "",
"schema": "",
"content": []
"content": [
{
"element": "resolvedAsset",
"attributes": {
"role": "bodyExample"
},
"content": "{\"percent_off\":25,\"redeem_by\":null,\"created\":null,\"modified\":null,\"created_at\":null,\"updated_at\":null}"
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodySchema"
},
"content": "{\"type\":\"object\",\"properties\":{\"percent_off\":{\"type\":\"number\"},\"redeem_by\":{\"type\":\"number\",\"description\":\"Date after which the coupon can no longer be redeemed\"},\"created\":{\"type\":\"number\"},\"modified\":{\"type\":\"number\"},\"created_at\":{\"type\":\"number\"},\"updated_at\":{\"type\":\"number\"}},\"$schema\":\"http://json-schema.org/draft-04/schema#\"}"
}
]
}
],
"responses": [
Expand Down Expand Up @@ -2788,6 +2860,20 @@
"class": "memberType"
}
]
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodyExample"
},
"content": "{\"id\":\"250FF\",\"percent_off\":25,\"redeem_by\":null,\"created\":null,\"modified\":null,\"created_at\":null,\"updated_at\":null}"
},
{
"element": "resolvedAsset",
"attributes": {
"role": "bodySchema"
},
"content": "{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"string\"},\"percent_off\":{\"type\":\"number\"},\"redeem_by\":{\"type\":\"number\",\"description\":\"Date after which the coupon can no longer be redeemed\"},\"created\":{\"type\":\"number\"},\"modified\":{\"type\":\"number\"},\"created_at\":{\"type\":\"number\"},\"updated_at\":{\"type\":\"number\"}},\"$schema\":\"http://json-schema.org/draft-04/schema#\"}"
}
]
}
Expand Down

0 comments on commit 3547e34

Please sign in to comment.