diff --git a/package.json b/package.json index a3141f9..30b4046 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "dependencies": { "coffee-script": "~1.7.1", "yargs": "~1.3.3", - "protagonist-experimental": "0.18.4", + "protagonist-experimental": "0.18.6", "boutique": "git+ssh://git@github.com:apiaryio/boutique.git" }, "devDependencies": { diff --git a/src/drafter.coffee b/src/drafter.coffee index 6b8e7bc..890fa52 100644 --- a/src/drafter.coffee +++ b/src/drafter.coffee @@ -7,6 +7,9 @@ fs = require 'fs' # class Drafter + # List of data structures + @dataStructures: {} + # Default configuration @defaultConfig: requireBlueprintName: false # Treat missing API name as error @@ -35,7 +38,86 @@ class Drafter # @param source [String] soruce API Bluerpint code # @param callback [(Error, ParseResult)] make: (source, callback) -> - protagonist.parse source, @config, callback + protagonist.parse source, @config, (error, result) => + callback error if error + + ruleList = ['mson-inheritance', 'mson-mixin', 'mson-member-type-name'] + rules = (require './rules/' + rule for rule in ruleList) + + @dataStructures = {} + delete result.ast.resourceGroups + + @expandNode result.ast, rules, 'blueprint' + @reconstructResourceGroups result.ast + + callback error, result + + # Expand a certain node with the given rules + # + # @param node [Object] A node of API Blueprint + # @param rules [Array] List of rules to apply + # @param elementTye [String] The element type of the node + expandNode: (node, rules, elementType) -> + elementType ?= node.element + + # On root node, Gather data structures first before applying rules to any of the children nodes + if elementType is 'blueprint' + for element in node.content + + if element.element is 'category' + for subElement in element.content + + switch subElement.element + 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 the gathered data structures + for rule in rules + rule.init.call rule, @dataStructures if rule.init + + # Apply rules to the current node + for rule in rules + rule[elementType].call rule, node if elementType in Object.keys(rule) + + # Recursively do the same for children nodes + switch elementType + when 'resource' + @expandNode action, rules, 'action' for action in node.actions + + when 'action' + @expandNode example, rules, 'transactionExample' for example in node.examples + + when 'transactionExample' + @expandNode request, rules, 'payload' for request in node.requests + @expandNode response, rules, 'payload' for response in node.responses + + if node.content and Array.isArray node.content + @expandNode element, rules for element in node.content + + # Reconstruct deprecated resource groups key from elements + # + # @param ast [Object] Blueprint ast + reconstructResourceGroups: (ast) -> + ast.resourceGroups = [] + + for element in ast.content + if element.element is 'category' + resources = [] + + for subElement in element.content + resources.push subElement if subElement.element is 'resource' + + if resources.length + description = element.content[0].content if element.content[0].element is 'copy' + + ast.resourceGroups.push + name: element.attributes?.name || '' + description: description || '' + resources: resources module.exports = Drafter module.exports.options = options diff --git a/src/rules/mson-inheritance.coffee b/src/rules/mson-inheritance.coffee new file mode 100644 index 0000000..3d8bd36 --- /dev/null +++ b/src/rules/mson-inheritance.coffee @@ -0,0 +1,88 @@ +rule = require './rule' + +module.exports = + + # Variables + expanded: {} + dataStructures: {} + + # Expand dataStructure element + dataStructure: (element) -> + superType = element.typeDefinition.name + typeName = element.name + + if not typeName + typeName = + literal: '' + + @expandInheritance typeName.literal, element + delete @expanded[''] + + # Given a data structure, expand its inheritance recursively + # + # @param name [String] Name of the data structure + # @param dataStructure [Object] Data structure + expandInheritance: (name, dataStructure) -> + return if @expanded[name] + + # Check for inheritance + superType = dataStructure.typeDefinition.typeSpecification.name + + if superType is null or typeof superType isnt 'object' or not superType?.literal + return @expanded[superType] = true + + # Expand the super type first + @expandInheritance superType.literal, @dataStructures[superType.literal] + + # If super type is not an object or array or enum + superTypeBaseName = @dataStructures[superType.literal].typeDefinition.typeSpecification.name + + if superTypeBaseName not in ['object', 'array', 'value'] + dataStructure.typeDefinition.typeSpecification.name = superTypeBaseName + memberTypeSection = + content: [] + + memberTypeSection['class'] = 'memberType' + rule.copyMembers @dataStructures[superType.literal], memberTypeSection + + dataStructure.sections.push memberTypeSection if memberTypeSection.content.length + return @expanded[name] = true + + # Find member type section of the current data structure + memberTypeSection = null + push = false + + for section in dataStructure.sections + memberTypeSection = section if section['class'] is 'memberType' + + # If no member type sections, create one + if not memberTypeSection + memberTypeSection = + content: [] + + memberTypeSection['class'] = 'memberType' + push = true + + # Copy super-type and all the member types to sub type + rule.copyMembers @dataStructures[superType.literal], memberTypeSection + dataStructure.typeDefinition.typeSpecification = + name: superTypeBaseName + nestedTypes: @dataStructures[superType.literal].typeDefinition.typeSpecification.nestedTypes + + # Push the created type section + dataStructure.sections.push memberTypeSection if push and memberTypeSection.content.length + + # Denote this type as expanded + @expanded[name] = true + + init: (dataStructures) -> + @expanded = {} + @dataStructures = dataStructures + + # Initiate flags + for name, dataStructure of @dataStructures + @expanded[name] = false + + # Actual expansion + for name, dataStructure of @dataStructures + @expandInheritance name, dataStructure diff --git a/src/rules/mson-member-type-name.coffee b/src/rules/mson-member-type-name.coffee new file mode 100644 index 0000000..b928a3c --- /dev/null +++ b/src/rules/mson-member-type-name.coffee @@ -0,0 +1,77 @@ +rule = require './rule' + +module.exports = + + # Variables + expanded: {} + dataStructures: {} + + # Expand dataStructure element + dataStructure: (element) -> + superType = element.typeDefinition.name + typeName = element.name + + if not typeName + typeName = + literal: '' + + @expandMember typeName.literal, element + delete @expanded[''] + + # Given a list of elements, recursively expand member type name contained + # in a group of elements inside the initial group of elements + # + # @param elements [Object] List of elements either from type section or a member type + diveIntoElements: (elements) -> + for member in elements + switch member['class'] + + when 'property', 'value' + superType = member.content.valueDefinition.typeDefinition.typeSpecification.name + + # If super type is a valid symbol + if typeof superType is 'object' and superType?.literal + @expandMember superType.literal, @dataStructures[superType.literal] + + superTypeBaseName = @dataStructures[superType.literal].typeDefinition.typeSpecification.name + member.content.valueDefinition.typeDefinition.typeSpecification.name = superTypeBaseName + + # If super type is not an object or array or enum + if superTypeBaseName in ['object', 'array', 'value'] + memberTypeSection = + content: [] + + memberTypeSection['class'] = 'memberType' + rule.copyMembers @dataStructures[superType.literal], memberTypeSection + member.content.sections.push memberTypeSection if memberTypeSection.content.length + + when 'oneOf', 'group' + @diveIntoElements member.content + + # Given a data structure, expand its member type recusrively + # + # @param name [String] Name of the data structure + # @param dataStructure [Object] Data structure + expandMember: (name, dataStructure) -> + return if @expanded[name] + + # Check for member type name + for section in dataStructure.sections + if section['class'] is 'memberType' + + @diveIntoElements section.content + + # Denote this type as expanded + @expanded[name] = true + + init: (dataStructures) -> + @expanded = {} + @dataStructures = dataStructures + + # Initiate flags + for name, dataStructure of @dataStructures + @expanded[name] = false + + # Actual expansion + for name, dataStructure of @dataStructures + @expandMember name, dataStructure diff --git a/src/rules/mson-mixin.coffee b/src/rules/mson-mixin.coffee new file mode 100644 index 0000000..942ec65 --- /dev/null +++ b/src/rules/mson-mixin.coffee @@ -0,0 +1,84 @@ +rule = require './rule' + +module.exports = + + # Variables + expanded: {} + dataStructures: {} + + # Expand dataStructure element + dataStructure: (element) -> + superType = element.typeDefinition.name + typeName = element.name + + if not typeName + typeName = + literal: '' + + @expandMixin typeName.literal, element + delete @expanded[''] + + # Given a list of elements, recursively expand mixins contained + # in a group of elements inside the initial group of elements + # + # @param elements [Object] List of elements either from type section or a member type + # @param sectionOrMember [Object] Type section or a member type + diveIntoElements: (elements, sectionOrMember) -> + for member in elements + switch member['class'] + + when 'mixin' + superType = member.content.typeSpecification.name + + # Expand the super type first + @expandMixin superType.literal, @dataStructures[superType.literal] + rule.copyMembers @dataStructures[superType.literal], sectionOrMember + + when 'oneOf', 'group' + memberType = + content: [] + + # Recursively dive into the elements + @diveIntoElements member.content, memberType + + # Replace the original member with out new member + member.content = memberType.content + sectionOrMember.content.push member + + else + sectionOrMember.content.push member + + # Given a data structure, expand its mixins recusrively + # + # @param name [String] Name of the data structure + # @param dataStructure [Object] Data structure + expandMixin: (name, dataStructure) -> + return if @expanded[name] + + # Check for mixin + for section in dataStructure.sections + if section['class'] is 'memberType' + + # New content for the section + memberTypeSection = + content: [] + + @diveIntoElements section.content, memberTypeSection + + # Replace section content with the new content + section.content = memberTypeSection.content + + # Denote this type as expanded + @expanded[name] = true + + init: (dataStructures) -> + @expanded = {} + @dataStructures = dataStructures + + # Initiate flags + for name, dataStructure of @dataStructures + @expanded[name] = false + + # Actual expansion + for name, dataStructure of @dataStructures + @expandMixin name, dataStructure diff --git a/src/rules/rule.coffee b/src/rules/rule.coffee new file mode 100644 index 0000000..38d4b22 --- /dev/null +++ b/src/rules/rule.coffee @@ -0,0 +1,14 @@ +module.exports = + + # Copy all member types from one data structure to another + # + # @param dataStructure [Object] The super type data structure + # @param memberTypeSection [Object] Member Type Section to be copied into + copyMembers: (dataStructure, memberTypeSection) -> + return if not dataStructure + + for section in dataStructure.sections + if section['class'] is 'memberType' + + for member in section.content + memberTypeSection.content.push member diff --git a/test/fixtures/dataStructures.apib b/test/fixtures/dataStructures.apib new file mode 100644 index 0000000..d40b401 --- /dev/null +++ b/test/fixtures/dataStructures.apib @@ -0,0 +1,97 @@ +FORMAT: 1A + +# Stripe +Inspired by stripe API + +# Group Coupons +Resource group description + +## Coupon [/coupons/{id}] +A coupon contains information about a percent-off or amount-off discount you might want to apply to a customer. + ++ Parameters + + id (string) + + The ID of the desired coupon. + ++ Attributes (Coupon Base) + + id: 250FF (string) + +### Retrieve a Coupon [GET] +Retrieves the coupon with the given ID. + ++ Response 200 (application/json) + + Attributes (Coupon) + +## Coupons [/coupons{?limit}] + ++ Attributes (array[Coupon]) + +### List all Coupons [GET] +Returns a list of your coupons. + ++ Parameters + + limit = `10` (optional, number) + + A limit on the number of objects to be returned. Limit can range between 1 and 100 items. + ++ Response 200 (application/json) + + Attributes (Coupons) + +### Create a Coupon [POST] +Creates a new Coupon. + ++ Attributes (Coupon Base) + ++ Request (application/json) + ++ Response 200 (application/json) + + Attributes (Coupon) + +# Data Structures + +## Timestamp (number) +Unix timestamp as an integer + +## Legacy Timestamps ++ created_at (Timestamp) ++ updated_at (Timestamp) + +## Timestamps (object) +This object contains the following unix timestamps + ++ created - Denoting the time when the object is created ++ modified - Denoting the time when the object has been recently updated + +### Properties ++ created (Timestamp) + +### Properties ++ modified (Timestamp) ++ Include Legacy Timestamps + +## Coupon Base (Timestamps) ++ percent_off: 25 (number) + + A positive integer between 1 and 100 that represents the discount the coupon will apply. + ++ redeem_by (number) - Date after which the coupon can no longer be redeemed + +## Coupon Base Clone (Coupon Base) +A clone of Coupon Base to be used for testing + +## Timestamp Clone (Timestamp) +A clone of timestamp to be used for testing + +## Coupon Clone (Coupon) +A clone of Coupon to be used for testing + +## Subscription ++ id: 1000 (number) ++ plan: `Startup` (string) - Subscription plan name ++ coupon (Coupon Base) - Coupon represting any existing discounts used by the customer during the subscription ++ One Of + + Include Timestamps + + Properties + + modified_at (Timestamp) + + Include (Legacy Timestamps) diff --git a/test/fixtures/dataStructures.ast.json b/test/fixtures/dataStructures.ast.json new file mode 100644 index 0000000..bc3e456 --- /dev/null +++ b/test/fixtures/dataStructures.ast.json @@ -0,0 +1,2825 @@ +{ + "_version": "2.1", + "metadata": [ + { + "name": "FORMAT", + "value": "1A" + } + ], + "name": "Stripe", + "description": "Inspired by stripe API\n\n", + "element": "category", + "content": [ + { + "element": "category", + "attributes": { + "name": "Coupons" + }, + "content": [ + { + "element": "copy", + "content": "Resource group description\n\n" + }, + { + "element": "resource", + "name": "Coupon", + "description": "A coupon contains information about a percent-off or amount-off discount you might want to apply to a customer.\n\n", + "uriTemplate": "/coupons/{id}", + "model": {}, + "parameters": [ + { + "name": "id", + "description": "The ID of the desired coupon.\n", + "type": "string", + "required": true, + "default": "", + "example": "", + "values": [] + } + ], + "actions": [ + { + "name": "Retrieve a Coupon", + "description": "Retrieves the coupon with the given ID.\n\n", + "method": "GET", + "parameters": [], + "content": [], + "examples": [ + { + "name": "", + "description": "", + "requests": [], + "responses": [ + { + "name": "200", + "description": "", + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "body": "", + "schema": "", + "content": [ + { + "element": "dataStructure", + "name": null, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "content": [ + { + "content": { + "name": { + "literal": "id" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "250FF", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "string", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + } + ] + } + ] + } + ] + } + ], + "content": [ + { + "element": "dataStructure", + "name": { + "literal": "Coupon", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "memberType", + "content": [ + { + "content": { + "name": { + "literal": "id" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "250FF", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "string", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "name": "Coupons", + "description": "", + "uriTemplate": "/coupons{?limit}", + "model": {}, + "parameters": [], + "actions": [ + { + "name": "List all Coupons", + "description": "Returns a list of your coupons.\n\n", + "method": "GET", + "parameters": [ + { + "name": "limit", + "description": "A limit on the number of objects to be returned. Limit can range between 1 and 100 items.\n", + "type": "number", + "required": false, + "default": "10", + "example": "", + "values": [] + } + ], + "content": [], + "examples": [ + { + "name": "", + "description": "", + "requests": [], + "responses": [ + { + "name": "200", + "description": "", + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "body": "", + "schema": "", + "content": [ + { + "element": "dataStructure", + "name": null, + "typeDefinition": { + "typeSpecification": { + "name": "array", + "nestedTypes": [ + { + "literal": "Coupon", + "variable": false + } + ] + }, + "attributes": [] + }, + "sections": [] + } + ] + } + ] + } + ] + }, + { + "name": "Create a Coupon", + "description": "Creates a new Coupon.\n\n", + "method": "POST", + "parameters": [], + "content": [ + { + "element": "dataStructure", + "name": null, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "content": [ + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + } + ], + "examples": [ + { + "name": "", + "description": "", + "requests": [ + { + "name": "", + "description": "", + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "body": "", + "schema": "", + "content": [] + } + ], + "responses": [ + { + "name": "200", + "description": "", + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "body": "", + "schema": "", + "content": [ + { + "element": "dataStructure", + "name": null, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "content": [ + { + "content": { + "name": { + "literal": "id" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "250FF", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "string", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + } + ] + } + ] + } + ] + } + ], + "content": [ + { + "element": "dataStructure", + "name": { + "literal": "Coupons", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "array", + "nestedTypes": [ + { + "literal": "Coupon", + "variable": false + } + ] + }, + "attributes": [] + }, + "sections": [] + } + ] + } + ] + }, + { + "element": "category", + "content": [ + { + "element": "dataStructure", + "name": { + "literal": "Timestamp", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "blockDescription", + "content": "Unix timestamp as an integer\n\n" + } + ] + }, + { + "element": "dataStructure", + "name": { + "literal": "Legacy Timestamps", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": null, + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "memberType", + "content": [ + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ] + } + ] + }, + { + "element": "dataStructure", + "name": { + "literal": "Timestamps", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "blockDescription", + "content": "This object contains the following unix timestamps\n\n+ created - Denoting the time when the object is created\n\n+ modified - Denoting the time when the object has been recently updated\n\n" + }, + { + "class": "memberType", + "content": [ + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ] + }, + { + "class": "memberType", + "content": [ + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ] + } + ] + }, + { + "element": "dataStructure", + "name": { + "literal": "Coupon Base", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "memberType", + "content": [ + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ] + } + ] + }, + { + "element": "dataStructure", + "name": { + "literal": "Coupon Base Clone", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "blockDescription", + "content": "A clone of Coupon Base to be used for testing\n\n" + }, + { + "content": [ + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + }, + { + "element": "dataStructure", + "name": { + "literal": "Timestamp Clone", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "blockDescription", + "content": "A clone of timestamp to be used for testing\n\n" + } + ] + }, + { + "element": "dataStructure", + "name": { + "literal": "Coupon Clone", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "blockDescription", + "content": "A clone of Coupon to be used for testing\n\n" + }, + { + "content": [ + { + "content": { + "name": { + "literal": "id" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "250FF", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "string", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + }, + { + "element": "dataStructure", + "name": { + "literal": "Subscription", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": null, + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "memberType", + "content": [ + { + "content": { + "name": { + "literal": "id" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "1000", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "plan" + }, + "description": "Subscription plan name", + "valueDefinition": { + "values": [ + { + "literal": "Startup", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "string", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "coupon" + }, + "description": "Coupon represting any existing discounts used by the customer during the subscription", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "content": [ + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + }, + "class": "property" + }, + { + "content": [ + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": [ + { + "content": { + "name": { + "literal": "modified_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "group" + } + ], + "class": "oneOf" + } + ] + } + ] + } + ] + } + ], + "resourceGroups": [ + { + "name": "Coupons", + "description": "Resource group description\n\n", + "resources": [ + { + "element": "resource", + "name": "Coupon", + "description": "A coupon contains information about a percent-off or amount-off discount you might want to apply to a customer.\n\n", + "uriTemplate": "/coupons/{id}", + "model": {}, + "parameters": [ + { + "name": "id", + "description": "The ID of the desired coupon.\n", + "type": "string", + "required": true, + "default": "", + "example": "", + "values": [] + } + ], + "actions": [ + { + "name": "Retrieve a Coupon", + "description": "Retrieves the coupon with the given ID.\n\n", + "method": "GET", + "parameters": [], + "content": [], + "examples": [ + { + "name": "", + "description": "", + "requests": [], + "responses": [ + { + "name": "200", + "description": "", + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "body": "", + "schema": "", + "content": [ + { + "element": "dataStructure", + "name": null, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "content": [ + { + "content": { + "name": { + "literal": "id" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "250FF", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "string", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + } + ] + } + ] + } + ] + } + ], + "content": [ + { + "element": "dataStructure", + "name": { + "literal": "Coupon", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "class": "memberType", + "content": [ + { + "content": { + "name": { + "literal": "id" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "250FF", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "string", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "name": "Coupons", + "description": "", + "uriTemplate": "/coupons{?limit}", + "model": {}, + "parameters": [], + "actions": [ + { + "name": "List all Coupons", + "description": "Returns a list of your coupons.\n\n", + "method": "GET", + "parameters": [ + { + "name": "limit", + "description": "A limit on the number of objects to be returned. Limit can range between 1 and 100 items.\n", + "type": "number", + "required": false, + "default": "10", + "example": "", + "values": [] + } + ], + "content": [], + "examples": [ + { + "name": "", + "description": "", + "requests": [], + "responses": [ + { + "name": "200", + "description": "", + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "body": "", + "schema": "", + "content": [ + { + "element": "dataStructure", + "name": null, + "typeDefinition": { + "typeSpecification": { + "name": "array", + "nestedTypes": [ + { + "literal": "Coupon", + "variable": false + } + ] + }, + "attributes": [] + }, + "sections": [] + } + ] + } + ] + } + ] + }, + { + "name": "Create a Coupon", + "description": "Creates a new Coupon.\n\n", + "method": "POST", + "parameters": [], + "content": [ + { + "element": "dataStructure", + "name": null, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "content": [ + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + } + ], + "examples": [ + { + "name": "", + "description": "", + "requests": [ + { + "name": "", + "description": "", + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "body": "", + "schema": "", + "content": [] + } + ], + "responses": [ + { + "name": "200", + "description": "", + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "body": "", + "schema": "", + "content": [ + { + "element": "dataStructure", + "name": null, + "typeDefinition": { + "typeSpecification": { + "name": "object", + "nestedTypes": [] + }, + "attributes": [] + }, + "sections": [ + { + "content": [ + { + "content": { + "name": { + "literal": "id" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "250FF", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "string", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "percent_off" + }, + "description": "", + "valueDefinition": { + "values": [ + { + "literal": "25", + "variable": false + } + ], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [ + { + "class": "blockDescription", + "content": "A positive integer between 1 and 100 that represents the discount the coupon will apply.\n" + } + ] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "redeem_by" + }, + "description": "Date after which the coupon can no longer be redeemed", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "modified" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "created_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + }, + { + "content": { + "name": { + "literal": "updated_at" + }, + "description": "", + "valueDefinition": { + "values": [], + "typeDefinition": { + "typeSpecification": { + "name": "number", + "nestedTypes": [] + }, + "attributes": [] + } + }, + "sections": [] + }, + "class": "property" + } + ], + "class": "memberType" + } + ] + } + ] + } + ] + } + ] + } + ], + "content": [ + { + "element": "dataStructure", + "name": { + "literal": "Coupons", + "variable": false + }, + "typeDefinition": { + "typeSpecification": { + "name": "array", + "nestedTypes": [ + { + "literal": "Coupon", + "variable": false + } + ] + }, + "attributes": [] + }, + "sections": [] + } + ] + } + ] + } + ] +} diff --git a/test/unit/drafter-test.coffee b/test/unit/drafter-test.coffee index 06b64f7..83fe9a9 100644 --- a/test/unit/drafter-test.coffee +++ b/test/unit/drafter-test.coffee @@ -1,4 +1,5 @@ {assert} = require 'chai' +fs = require 'fs' Drafter = require '../../src/drafter' @@ -11,3 +12,14 @@ describe 'Drafter Class', -> assert.isNull error assert.ok result.ast done() + + it 'parses and expands a blueprint', (done) -> + drafter = new Drafter + + drafter.make fs.readFileSync('./test/fixtures/dataStructures.apib', 'utf8'), (error, result) -> + assert.isNull error + assert.ok result.ast + + assert.deepEqual result.ast, require '../fixtures/dataStructures.ast.json' + + done()