├── .nvmrc
├── .gitattributes
├── test
├── indexof
│ └── object1.raml
├── world-music-api
│ ├── schemas
│ │ ├── idea.raml
│ │ └── songs.xsd
│ ├── examples
│ │ └── songs.xml
│ ├── secured
│ │ └── accessToken.raml
│ └── libraries
│ │ ├── songs-library.raml
│ │ └── api-library.raml
├── indexof.raml
├── oom.js
├── consistent-headers.raml
├── typeexample.raml
├── typeexample.flatObject.raml
├── examples-not-polluted.raml
├── zeropointeight.spec.js
├── array-of-strings.raml
├── array-of-foo.raml
├── output-json.js
├── outofmemory.raml
├── resourceexample.raml
├── typeexample.spec.js
├── consistent-headers.spec.js
├── inheritance.raml
├── array-of-strings.spec.js
├── indexof.spec.js
├── array-of-foo.spec.js
├── examples-not-polluted.spec.js
├── zeropointeight.raml
├── helloworld.raml
├── resourceexample.spec.js
├── secured-by.raml
├── consistent-headers.json
├── typeexample.flatObject.spec.js
├── indexof.json
├── inheritance.spec.js
├── parameters.raml
├── consistent-examples.raml
├── secured-by.spec.js
├── consistent-examples.spec.js
├── helloworld.spec.js
├── helloworld-as-buffer.spec.js
├── helloworld-as-string.spec.js
├── helloworld.json
├── array-of-strings.json
├── worldmusic.raml
├── typeexample.json
├── secured-by.json
├── parameters.spec.js
├── typeexample.flatObject.json
├── worldmusic.spec.js
├── array-of-foo.json
├── resourceexample.json
├── parameters.json
└── inheritance.json
├── .gitignore
├── .editorconfig
├── .eslintrc.js
├── .github
└── workflows
│ └── tests.yml
├── CONTRIBUTING.md
├── LICENSE
├── package.json
├── README.md
├── arrays-objects-helpers.js
├── consistency-helpers.js
├── changelog.md
└── index.js
/.nvmrc:
--------------------------------------------------------------------------------
1 | 4.7.0
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js text eol=lf
2 | *.raml text eol=lf
--------------------------------------------------------------------------------
/test/indexof/object1.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0 DataType
2 |
3 | type: object
4 | properties:
5 | o1a: string
6 |
--------------------------------------------------------------------------------
/test/world-music-api/schemas/idea.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0 DataType
2 |
3 | properties:
4 | comment: string
5 |
--------------------------------------------------------------------------------
/test/world-music-api/examples/songs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | str1234
4 | str1234
5 |
6 |
--------------------------------------------------------------------------------
/test/indexof.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Test
3 | version: v1
4 | mediaType: application/json
5 | /test:
6 | get:
7 | body:
8 | type: !include indexof/object1.raml
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | pids
11 | logs
12 | results
13 |
14 | npm-debug.log
15 | node_modules
16 | .vscode
17 |
--------------------------------------------------------------------------------
/test/oom.js:
--------------------------------------------------------------------------------
1 | const raml2obj = require('..');
2 |
3 | raml2obj.parse('outofmemory.raml').then(
4 | () => {
5 | console.log('DONE');
6 | },
7 | error => {
8 | console.log('error', error);
9 | }
10 | );
11 |
--------------------------------------------------------------------------------
/test/world-music-api/secured/accessToken.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0 Trait
2 |
3 | usage: |
4 | This trait can be used to apply an access token query parameter
5 | to any resources or HTTP methods.
6 | queryParameters:
7 | access_token: string
8 |
--------------------------------------------------------------------------------
/test/consistent-headers.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Consistent Headers
3 |
4 |
5 | /A:
6 | get:
7 | headers:
8 | X-Some-Header: string
9 | responses:
10 | 200:
11 | headers:
12 | X-Some-Other-Header: string
--------------------------------------------------------------------------------
/test/typeexample.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Test
3 | types:
4 | objectid:
5 | description: A valid MongoDB object id.
6 | example:
7 | value: 576bca8b70fddb149c4a9e92
8 | /company:
9 | uriParameters:
10 | id:
11 | type: objectid
12 | get:
13 | description: bla
14 |
--------------------------------------------------------------------------------
/test/typeexample.flatObject.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Test
3 | types:
4 | objectid:
5 | description: A valid MongoDB object id.
6 | example:
7 | value: 576bca8b70fddb149c4a9e92
8 | objectType:
9 | description: a type with properties.
10 | properties:
11 | first:
12 | type: string
13 | second:
14 | type: number
15 | /company:
16 | uriParameters:
17 | id:
18 | type: objectid
19 | get:
20 | description: bla
21 |
--------------------------------------------------------------------------------
/test/examples-not-polluted.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Test examples are not polluted with previous usages
3 | types:
4 | TypeId:
5 | description: The request identifier.
6 | type: integer
7 | example: 123
8 |
9 | /a/{aId}:
10 | uriParameters:
11 | aId:
12 | type: TypeId
13 | example: 456
14 | get:
15 | description: bla
16 |
17 | /b/{bId}:
18 | uriParameters:
19 | bId:
20 | type: TypeId
21 | example: 789
22 | get:
23 | description: bla
--------------------------------------------------------------------------------
/test/world-music-api/schemas/songs.xsd:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/zeropointeight.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | it('should not support 0.8 files at all', done => {
10 | raml2obj.parse('test/zeropointeight.raml').then(null, error => {
11 | assert.strictEqual(
12 | error.message,
13 | '_sourceToRamlObj: only RAML 1.0 is supported!'
14 | );
15 | done();
16 | });
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: [
3 | 'eslint:recommended',
4 | ],
5 | plugins: [
6 | 'prettier',
7 | ],
8 | env: {
9 | es6: true,
10 | browser: false,
11 | node: true,
12 | commonjs: true,
13 | },
14 | parserOptions: {
15 | ecmaVersion: 7,
16 | },
17 | rules: {
18 | 'prettier/prettier': ['error', {trailingComma: 'es5', singleQuote: true}],
19 | 'no-console': 'off',
20 | 'prefer-const': 'error',
21 | 'eqeqeq': 'error',
22 | 'no-useless-return': 'error',
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/test/array-of-strings.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: API used to test broken features
3 | version: v1
4 | baseUri: http://api.samplehost.com/broken/{version}
5 | mediaType: application/json
6 | protocols: [HTTP, HTTPS]
7 |
8 | /:
9 | get:
10 | responses:
11 | 200:
12 | body:
13 | type: string[]
14 | example: ["somevalue","anothervalue"]
15 | post:
16 | responses:
17 | 200:
18 | body:
19 | type: array
20 | items: string
21 | example: ["somevalue","anothervalue"]
22 |
--------------------------------------------------------------------------------
/test/world-music-api/libraries/songs-library.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0 Library
2 |
3 | types:
4 | Song:
5 | properties:
6 | title: string
7 | length: number
8 | examples:
9 | song1:
10 | strict: false
11 | value:
12 | title: "My Song"
13 | length: 12
14 | song2:
15 | title: "Last"
16 | length: 3
17 | Album:
18 | properties:
19 | title: string
20 | songs: Song[]
21 | Musician:
22 | properties:
23 | name: string
24 | discography: (Song | Album)[]
25 |
--------------------------------------------------------------------------------
/test/array-of-foo.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Test
3 | description: Test of array support
4 | version: v1
5 | baseUri:
6 | value: https://exmaple.com/{version}
7 | protocols: HTTPS
8 | mediaType: application/json
9 |
10 | types:
11 | Foo:
12 | properties:
13 | id: string
14 | Foos: Foo[]
15 |
16 | /foos:
17 | get:
18 | responses:
19 | 200:
20 | body: Foos
21 | post:
22 | responses:
23 | 200:
24 | body:
25 | type: array
26 | items: Foo
27 | minItems: 1
28 | maxItems: 200
29 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on:
4 | push:
5 | branches: [ develop ]
6 | pull_request:
7 | branches: [ '*' ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [10.x, 12.x, 14.x, 15.x]
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Use Node.js ${{ matrix.node-version }}
20 | uses: actions/setup-node@v1
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 |
24 | - run: npm ci
25 | - run: npm test
26 |
--------------------------------------------------------------------------------
/test/output-json.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const raml2obj = require('..');
5 | const glob = require('glob');
6 |
7 | process.chdir(__dirname);
8 |
9 | const ramlFiles = glob
10 | .sync('*.raml')
11 | .filter(
12 | ramlFile =>
13 | ramlFile !== 'zeropointeight.raml' && ramlFile !== 'outofmemory.raml'
14 | );
15 |
16 | ramlFiles.forEach(ramlFile => {
17 | console.log(ramlFile);
18 | raml2obj.parse(ramlFile).then(
19 | result => {
20 | const jsonString = JSON.stringify(result, null, 4);
21 | const filename = ramlFile.replace('.raml', '.json');
22 | fs.writeFileSync(filename, jsonString);
23 | },
24 | error => {
25 | console.log(ramlFile, error);
26 | }
27 | );
28 | });
29 |
--------------------------------------------------------------------------------
/test/outofmemory.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: some API
3 | baseUri: https://someserver.com/api
4 | mediaType: application/json
5 |
6 | types:
7 | SomeProfile:
8 | type: object
9 | properties:
10 | attr1: string?
11 | attr2: string?
12 | attr3: string?
13 | attr4: string?
14 | attr5: string?
15 | attr6: string?
16 | attr7: string?
17 | attr8: string?
18 | attr9: string?
19 | attr10: string?
20 | attr11: string?
21 | attr12: string?
22 | attr13: string?
23 | attr14: string?
24 | attr15: string?
25 |
26 | ManyProfiles:
27 | type: object
28 | properties:
29 | profiles?: SomeProfile
30 |
31 | /api:
32 | get:
33 | responses:
34 | 200:
35 | body:
36 | type: ManyProfiles
37 |
--------------------------------------------------------------------------------
/test/resourceexample.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: resource example
3 |
4 | types:
5 | ResourceExampleType:
6 | type: object
7 | properties:
8 | content: string
9 | additionalProperties: false
10 | examples:
11 | typeExample1: { "content": "typeExample1" }
12 | typeExample2: { "content": "typeExample2" }
13 |
14 |
15 |
16 | /example:
17 | get:
18 | responses:
19 | 200:
20 | body:
21 | application/json:
22 | type: ResourceExampleType
23 | 202:
24 | body:
25 | application/json:
26 | type: ResourceExampleType
27 | examples:
28 | resourceExample1: { "content": "resourceExample1" }
29 | resourceExample2: { "content": "resourceExample2" }
30 |
31 |
--------------------------------------------------------------------------------
/test/typeexample.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('typeexample.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/typeexample.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should test the array items', () => {
25 | const uriParameter = obj.resources[0].uriParameters[0];
26 | assert.strictEqual(
27 | uriParameter.description,
28 | 'A valid MongoDB object id.'
29 | );
30 | assert.strictEqual(
31 | uriParameter.examples[0].value,
32 | '576bca8b70fddb149c4a9e92'
33 | );
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/consistent-headers.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('consistent-headers.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/consistent-headers.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should have keys on both request and response headers', () => {
25 | assert.strictEqual(
26 | obj.resources[0].methods[0].headers[0].key,
27 | 'X-Some-Header'
28 | );
29 | assert.strictEqual(
30 | obj.resources[0].methods[0].responses[0].headers[0].key,
31 | 'X-Some-Other-Header'
32 | );
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/test/inheritance.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Inheritance Test
3 |
4 | types:
5 | Email:
6 | type: string
7 | pattern: ^.+@.+\..+$
8 | Account:
9 | description: A basic account in the inheritance test
10 | properties:
11 | name: string
12 | email: Email
13 | gender:
14 | type: string
15 | enum: [ "male", "female" ]
16 | required: false
17 | PasswordProtectedAccount:
18 | description: An account which is password protected.
19 | type: Account
20 | properties:
21 | password: string
22 | BannableAccount:
23 | type: PasswordProtectedAccount
24 | properties:
25 | banned: boolean
26 |
27 | /account:
28 | displayName: ACCOUNT
29 |
30 | post:
31 | description: |
32 | Creates a new account
33 | body:
34 | application/json:
35 | type: PasswordProtectedAccount
36 | put:
37 | body:
38 | application/json:
39 | type: BannableAccount
40 |
--------------------------------------------------------------------------------
/test/array-of-strings.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('array-of-strings.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/array-of-strings.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should test the array items', () => {
25 | let body;
26 |
27 | body = obj.resources[0].methods[0].responses[0].body[0];
28 | assert.strictEqual(body.type, 'array');
29 | assert.strictEqual(body.items, 'string');
30 |
31 | body = obj.resources[0].methods[1].responses[0].body[0];
32 | assert.strictEqual(body.type, 'array');
33 | assert.strictEqual(body.items, 'string');
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/indexof.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('indexof.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/indexof.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should test the basic properties of the raml object', () => {
25 | assert.strictEqual(obj.title, 'Test');
26 | assert.strictEqual(obj.resources.length, 1);
27 | });
28 |
29 | it('should test the GET /test method', () => {
30 | const GET = obj.resources[0].methods[0];
31 | const body = GET.body[0];
32 | assert.strictEqual(body.type.displayName, 'type');
33 | assert.strictEqual(body.type.properties[0].name, 'o1a');
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/array-of-foo.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('array-of-foo.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/array-of-foo.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should test the array items', () => {
25 | let body;
26 |
27 | body = obj.resources[0].methods[0].responses[0].body[0];
28 | assert.strictEqual(body.type, 'array');
29 | assert.strictEqual(body.items.displayName, 'Foo');
30 |
31 | body = obj.resources[0].methods[1].responses[0].body[0];
32 | assert.strictEqual(body.type, 'array');
33 | assert.strictEqual(body.items.displayName, 'Foo');
34 | assert.strictEqual(body.minItems, 1);
35 | assert.strictEqual(body.maxItems, 200);
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 | raml2obj is an open source project and your contribution is very much appreciated. Since raml2obj is
3 | maintained by a very limited number of people, we ask you to please keep these rules in mind.
4 |
5 | ## Questions
6 | If you have a question, please use [StackOverflow](http://stackoverflow.com/).
7 |
8 | ## Bugs
9 | If you found a bug, instead of creating a new issue, please create a failing unit test and send in a pull request.
10 | It would be even better if you could include the fix as well :)
11 |
12 | ## Workflow
13 | 1. Fork the repository on Github and make your changes on the **develop** branch (or branch off of it).
14 | 3. Add unit tests, run them with `npm run test`
15 | 3. Run `npm run lint` before committing to check for common problems and auto format all code.
16 | 4. Send a pull request (with the develop branch as the target).
17 |
18 | ## Thanks
19 | A big thank you goes out to everyone who helped with the project, the [contributors](https://github.com/raml2html/raml2obj/graphs/contributors)
20 | and everyone who took the time to report issues and give feedback.
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Kevin Renskers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/test/examples-not-polluted.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('examples-not-polluted.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/examples-not-polluted.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('examples should not be polluted with previous usages', () => {
25 | // Take the first value example to verify is not in the type examples
26 | const [ramlExample] = obj.resources.map(
27 | rsc => rsc.methods[0].allUriParameters[0].examples[0].value
28 | );
29 | // Take all type examples
30 | const typeExamples = obj.types.TypeId.examples.map(
31 | example => example.value
32 | );
33 | typeExamples.forEach(typeExample => {
34 | assert.notStrictEqual(ramlExample, typeExample);
35 | });
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/test/zeropointeight.raml:
--------------------------------------------------------------------------------
1 | #%RAML 0.8
2 | title: Hello world # required title
3 | version: 1
4 | documentation:
5 | - title: Welcome
6 | content: |
7 | Welcome to the Example Documentation. The Example API allows you
8 | to do stuff. See also [example.com](https://www.example.com).
9 | - title: Chapter two
10 | content: |
11 | More content here. Including **bold** text!
12 |
13 | /helloworld: # optional resource
14 | get: # HTTP method declaration
15 | responses: # declare a response
16 | 200: # HTTP status code
17 | body: # declare content of response
18 | application/json: # media type
19 | schema: | # structural definition of a response (schema or type)
20 | {
21 | "title": "Hello world Response",
22 | "type": "object",
23 | "properties": {
24 | "message": {
25 | "type": "string"
26 | }
27 | }
28 | }
29 | example: | # example how a response looks like
30 | {
31 | "message": "Hello world"
32 | }
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "raml2obj",
3 | "description": "RAML to object",
4 | "version": "6.8.1",
5 | "author": {
6 | "name": "Kevin Renskers",
7 | "email": "kevin@loopwerk.io"
8 | },
9 | "bugs": {
10 | "url": "https://github.com/raml2html/raml2obj/issues"
11 | },
12 | "dependencies": {
13 | "datatype-expansion": "^0.4.1",
14 | "raml-1-parser": "^1.1.67"
15 | },
16 | "devDependencies": {
17 | "eslint": "^6.8.0",
18 | "eslint-plugin-prettier": "^3.1.4",
19 | "glob": "^7.1.6",
20 | "mocha": "^6.2.3",
21 | "prettier": "^1.19.1"
22 | },
23 | "homepage": "https://github.com/raml2html/raml2obj",
24 | "keywords": [
25 | "RAML"
26 | ],
27 | "license": "MIT",
28 | "main": "index.js",
29 | "repository": {
30 | "type": "git",
31 | "url": "git://github.com/raml2html/raml2obj.git"
32 | },
33 | "preferGlobal": false,
34 | "scripts": {
35 | "json": "node test/output-json.js",
36 | "lint": "eslint . --fix",
37 | "test": "mocha 'test/*.spec.js' --reporter progress"
38 | },
39 | "files": [
40 | "index.js",
41 | "arrays-objects-helpers.js",
42 | "consistency-helpers.js"
43 | ],
44 | "engines": {
45 | "node": ">=4"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/test/helloworld.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Hello world # required title
3 | version: 1
4 | baseUri: http://example.com/{version}
5 | documentation:
6 | - title: Welcome
7 | content: |
8 | Welcome to the Example Documentation. The Example API allows you
9 | to do stuff. See also [example.com](https://www.example.com).
10 | - title: Chapter two
11 | content: |
12 | More content here. Including **bold** text!
13 |
14 | /helloworld: # optional resource
15 | description: This is the top level description for /helloworld.
16 |
17 | get: # HTTP method declaration
18 | responses: # declare a response
19 | 200: # HTTP status code
20 | body: # declare content of response
21 | application/json: # media type
22 | type: | # structural definition of a response (schema or type)
23 | {
24 | "title": "Hello world Response",
25 | "type": "object",
26 | "properties": {
27 | "message": {
28 | "type": "string"
29 | }
30 | }
31 | }
32 | example: # example how a response looks like
33 | {
34 | "message": "Hello world"
35 | }
36 | /test:
37 | displayName: TEST
38 | get:
39 | description: a sub resource
40 |
--------------------------------------------------------------------------------
/test/resourceexample.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('resourceexample.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/resourceexample.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should have examples from types when no examples in resource', () => {
25 | const method = obj.resources[0].methods[0];
26 | const response = method.responses[0];
27 | const examples = response.body[0].examples;
28 | assert.strictEqual(response.code, '200');
29 | assert.strictEqual(examples.length, 2);
30 | assert.deepEqual(examples[0].structuredValue, {
31 | content: 'typeExample1',
32 | });
33 | assert.deepEqual(examples[1].structuredValue, {
34 | content: 'typeExample2',
35 | });
36 | });
37 |
38 | it('should have examples from resources when given', () => {
39 | const method = obj.resources[0].methods[0];
40 | const response = method.responses[1];
41 | const examples = response.body[0].examples;
42 | assert.strictEqual(response.code, '202');
43 | assert.strictEqual(examples.length, 2);
44 | assert.deepEqual(examples[0].structuredValue, {
45 | content: 'resourceExample1',
46 | });
47 | assert.deepEqual(examples[1].structuredValue, {
48 | content: 'resourceExample2',
49 | });
50 | });
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/test/secured-by.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Secured By Null
3 |
4 | securitySchemes:
5 | oauth_2_0:
6 | type: OAuth 2.0
7 | describedBy:
8 | headers:
9 | Authorization: string
10 | responses:
11 | 401:
12 | description: Invalid or expired token.
13 | settings:
14 | accessTokenUri: /token
15 | authorizationGrants: [ client_credentials ]
16 | oauth_2_0_withscopes:
17 | type: OAuth 2.0
18 | describedBy:
19 | headers:
20 | Authorization: string
21 | responses:
22 | 401:
23 | description: Invalid or expired token.
24 | settings:
25 | accessTokenUri: /token
26 | authorizationGrants: [ client_credentials ]
27 | scopes: [ add-a, remove-a, add-b, remove-b, read-c ]
28 | custom_scheme:
29 | description: |
30 | A custom security scheme for authenticating requests.
31 | type: x-custom
32 | describedBy:
33 | headers:
34 | SpecialToken:
35 | description: |
36 | Used to send a custom token.
37 | type: string
38 | responses:
39 | 401:
40 | description: |
41 | Bad token.
42 | 403:
43 |
44 | /A:
45 | get:
46 | post:
47 | securedBy: [ ]
48 | put:
49 | securedBy: [ null ]
50 | delete:
51 | securedBy: [ null, null, null ]
52 |
53 | /B:
54 | get:
55 | securedBy: [ oauth_2_0 ]
56 | post:
57 | securedBy: [ oauth_2_0, null ]
58 | delete:
59 | securedBy: [ oauth_2_0_withscopes: { scopes: [ remove-b ] }, null ]
60 |
61 | /C:
62 | get:
63 | securedBy: [ oauth_2_0_withscopes: { scopes: [ read-c ] }, custom_scheme ]
64 |
--------------------------------------------------------------------------------
/test/world-music-api/libraries/api-library.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0 Library
2 |
3 | types:
4 | RamlDataType:
5 | type: object
6 | properties:
7 | propString: string
8 | propStringArray1: string[]
9 | ideas:
10 | type: array
11 | items: !include ../schemas/idea.raml
12 | extIdeas:
13 | type: !include ../schemas/idea.raml
14 | properties:
15 | createdBy: string
16 | feedback:
17 | type: string
18 | default: "very nice"
19 | example: "very well made"
20 | minLength: 1
21 | maxLength: 255
22 | pattern: "[a-zA-Z\\s]*"
23 | propNumber:
24 | type: number
25 | minimum: 0
26 | maximum: 32
27 | format: int32
28 | multipleOf: 2
29 | propInteger:
30 | type: integer
31 | minimum: 3
32 | maximum: 5
33 | format: int8
34 | multipleOf: 1
35 | propBoolean: boolean
36 | propDate:
37 | type: date-only
38 | example: 2015-05-23
39 | userPicture:
40 | type: file
41 | fileTypes: ['image/jpeg', 'image/png']
42 | maxLength: 307200
43 | NilValue:
44 | type: object
45 | properties:
46 | name:
47 | comment: string?
48 | CatOrDog: Cat | Dog
49 | CatAndDog: [ Cat, Dog ]
50 | PossibleMeetingDate:
51 | type: CustomDate
52 | noHolidays: true
53 | Cat:
54 | type: object
55 | properties:
56 | name: string
57 | color: string
58 | Dog:
59 | type: object
60 | properties:
61 | name: string
62 | fangs: string
63 | CustomDate:
64 | type: date-only
65 | facets:
66 | onlyFutureDates?: boolean # optional in `PossibleMeetingDate`
67 | noHolidays: boolean # required in `PossibleMeetingDate`
68 |
--------------------------------------------------------------------------------
/test/consistent-headers.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Consistent Headers",
3 | "resources": [
4 | {
5 | "methods": [
6 | {
7 | "headers": [
8 | {
9 | "name": "X-Some-Header",
10 | "displayName": "X-Some-Header",
11 | "typePropertyKind": "TYPE_EXPRESSION",
12 | "type": "string",
13 | "required": true,
14 | "key": "X-Some-Header"
15 | }
16 | ],
17 | "responses": [
18 | {
19 | "code": "200",
20 | "headers": [
21 | {
22 | "name": "X-Some-Other-Header",
23 | "displayName": "X-Some-Other-Header",
24 | "typePropertyKind": "TYPE_EXPRESSION",
25 | "type": "string",
26 | "required": true,
27 | "key": "X-Some-Other-Header"
28 | }
29 | ],
30 | "key": "200"
31 | }
32 | ],
33 | "method": "get",
34 | "allUriParameters": []
35 | }
36 | ],
37 | "relativeUri": "/A",
38 | "displayName": "/A",
39 | "relativeUriPathSegments": [
40 | "A"
41 | ],
42 | "absoluteUri": "/A",
43 | "parentUrl": "",
44 | "uniqueId": "a",
45 | "allUriParameters": []
46 | }
47 | ]
48 | }
--------------------------------------------------------------------------------
/test/typeexample.flatObject.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('typeexample.flatObject.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj
14 | .parse('test/typeexample.flatObject.raml', {
15 | collectionFormat: 'arrays',
16 | })
17 | .then(
18 | result => {
19 | obj = result;
20 | done();
21 | },
22 | error => {
23 | console.log('error', error);
24 | }
25 | );
26 | });
27 |
28 | it('should test the structure if the option "arraysToObjects" is set to "flatObjects"', () => {
29 | assert.strictEqual(
30 | // check that it's really an array without keys
31 | Object.prototype.toString.call(obj.types),
32 | '[object Array]'
33 | );
34 | assert.strictEqual(
35 | // check that it's really an Object
36 | Object(obj),
37 | obj
38 | );
39 | assert.strictEqual(
40 | // check that we can directly access a property inside the object (this is the actual difference the flag makes)
41 | obj.types[0].name,
42 | 'objectid'
43 | );
44 | assert.strictEqual(
45 | // check that the type key is in a property inside the object
46 | obj.types[0].key,
47 | 'objectid'
48 | );
49 | assert.strictEqual(
50 | // check that the second type is still the second
51 | obj.types[1].key,
52 | 'objectType'
53 | );
54 | assert.strictEqual(
55 | // check that the second type's second property is still the second
56 | obj.types[1].properties[1].key,
57 | 'second'
58 | );
59 | });
60 | });
61 | });
62 |
--------------------------------------------------------------------------------
/test/indexof.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Test",
3 | "version": "v1",
4 | "mediaType": "application/json",
5 | "resources": [
6 | {
7 | "methods": [
8 | {
9 | "body": [
10 | {
11 | "name": "application/json",
12 | "displayName": "application/json",
13 | "typePropertyKind": "INPLACE",
14 | "type": {
15 | "name": "type",
16 | "displayName": "type",
17 | "typePropertyKind": "TYPE_EXPRESSION",
18 | "type": "object",
19 | "properties": [
20 | {
21 | "name": "o1a",
22 | "displayName": "o1a",
23 | "typePropertyKind": "TYPE_EXPRESSION",
24 | "type": "string",
25 | "required": true,
26 | "key": "o1a"
27 | }
28 | ]
29 | },
30 | "key": "application/json"
31 | }
32 | ],
33 | "method": "get",
34 | "allUriParameters": []
35 | }
36 | ],
37 | "relativeUri": "/test",
38 | "displayName": "/test",
39 | "relativeUriPathSegments": [
40 | "test"
41 | ],
42 | "absoluteUri": "/test",
43 | "parentUrl": "",
44 | "uniqueId": "test",
45 | "allUriParameters": []
46 | }
47 | ]
48 | }
--------------------------------------------------------------------------------
/test/inheritance.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('inheritance.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/inheritance.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should test the basic properties of the raml object', () => {
25 | assert.strictEqual(obj.title, 'Inheritance Test');
26 | assert.strictEqual(obj.resources.length, 1);
27 | });
28 |
29 | it('should test type inheritance', () => {
30 | const properties = obj.resources[0].methods[0].body[0].properties;
31 |
32 | assert.strictEqual(properties.length, 4);
33 | assert.strictEqual(properties[0].displayName, 'name');
34 | assert.strictEqual(properties[0].type, 'string');
35 |
36 | assert.strictEqual(properties[1].displayName, 'email');
37 | assert.strictEqual(properties[1].type, 'string');
38 | assert.strictEqual(properties[1].pattern, '^.+@.+\\..+$');
39 |
40 | assert.strictEqual(properties[2].displayName, 'gender');
41 | assert.strictEqual(properties[2].type, 'string');
42 | assert.strictEqual(properties[2].enum.length, 2);
43 |
44 | assert.strictEqual(properties[3].displayName, 'password');
45 | assert.strictEqual(properties[3].type, 'string');
46 | });
47 |
48 | it('should test description of descendants', () => {
49 | const methods = obj.resources[0].methods;
50 |
51 | assert.strictEqual(
52 | methods[0].body[0].description,
53 | 'An account which is password protected.'
54 | );
55 | assert.strictEqual(
56 | methods[1].body[0].description,
57 | 'An account which is password protected.'
58 | );
59 | });
60 | });
61 | });
62 |
--------------------------------------------------------------------------------
/test/parameters.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Lots of parameters
3 |
4 | /account:
5 | post:
6 | body:
7 | application/json:
8 | examples:
9 | example1:
10 | value:
11 | {
12 | "email": "john@example.com",
13 | "password": "super_secret",
14 | "name": "John Doe"
15 | }
16 | responses:
17 | 200:
18 | description: Account was created and user is now logged in
19 |
20 | /find:
21 | get:
22 | queryParameters:
23 | name:
24 | description: name on account
25 | required: true
26 | example: Naruto Uzumaki
27 | gender:
28 | enum: ["male", "female"]
29 | required: true
30 | number:
31 | type: integer
32 | default: 42
33 |
34 | /{id}:
35 | uriParameters:
36 | id:
37 | type: string
38 | description: account identifier
39 | minLength: 1
40 | maxLength: 10
41 |
42 | get:
43 | headers:
44 | Authorization:
45 | type: string
46 | description: Basic authentication header
47 | example: |
48 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
49 |
50 | put:
51 | body:
52 | application/x-www-form-urlencoded:
53 | properties:
54 | name:
55 | description: name on account
56 | type: string
57 | examples:
58 | example1: Naruto Uzumaki
59 | example2:
60 | value: Kevin Renskers
61 | gender:
62 | enum: ["male", "female"]
63 |
64 | delete:
65 | description: Delete the account
66 |
67 | /{id}:
68 | uriParameters:
69 | id:
70 | type: string
71 | description: sub account identifier
72 | minLength: 1
73 | maxLength: 10
74 | get:
75 | responses:
76 | 401:
77 | description: Not authorized
78 | headers:
79 | WWW-Authenticate:
80 | type: string
81 | description: user was not authorized
82 | example: |
83 | WWW-Authenticate: Basic realm="raml2html"
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RAML to object
2 |
3 | [](https://www.npmjs.org/package/raml2obj)
4 | [](https://github.com/prettier/prettier)
5 |
6 | A thin wrapper around [raml-js-parser-2](https://github.com/raml-org/raml-js-parser-2), adding extra properties to the resulting
7 | object for use in [raml2html](https://www.npmjs.org/package/raml2html) and [raml2md](https://www.npmjs.org/package/raml2md).
8 |
9 | Versions 4.0.0 and up only support RAML 1.x files. If you still have RAML 0.8 source files, please stick with raml2obj 3.
10 |
11 | ## Install
12 | ```
13 | npm i raml2obj --save
14 | ```
15 |
16 | ## Usage
17 | ```js
18 | var raml2obj = require('raml2obj');
19 |
20 | // source can either be a filename, url, or parsed RAML object.
21 | // Returns a promise.
22 | raml2obj.parse(source).then(function(ramlObj) {
23 | // Do something with the resulting ramlObj :)
24 | });
25 | ```
26 |
27 | ## Options
28 | The `parse()` function can be called with options to customize the result.
29 | Defaults are compatible with `raml2html`.
30 |
31 | ```js
32 | raml2obj.parse(source, {
33 | validate: true,
34 | extensionsAndOverlays : [],
35 | collectionFormat: 'arrays',
36 | }).then(function(ramlObj) {
37 | // Do something with the resulting ramlObj :)
38 | });
39 | ```
40 | * `validate`: triggers the `rejectOnErrors` flag of the underlying parser. defaults to `false`
41 | * `extensionsAndOverlays`: Defaults to `[]`. See parser documentation.
42 | * `collectionFormat`: choose what data structure the double-nested `[{name1: {..}}, {name2: {..}}]` patterns of the `raml-1-parser` are transformed to in the output object:
43 |
44 | | `collectionFormat` value | output |
45 | | --- | --- |
46 | |`objects` (*default*)|`{name1: { orderHint: 0, ..}, name2: { orderHint: 1, ..}}` (eases e.g. property access). *Applies to top-level collections only, nested are arrays except type properties.*|
47 | |`arrays`|`[ {key: "name1", ..}, {key: "name2", ..}]` (eases e.g. representation in a database). *Applies recursively everywhere.* |
48 |
49 |
50 | ## Questions & Support
51 | Do you have a question? Have you found a bug or would you like to request a feature? Please check out [`CONTRIBUTING.md`](CONTRIBUTING.md).
52 |
53 |
54 | ## License
55 | raml2obj is available under the MIT license. See the LICENSE file for more info.
56 |
--------------------------------------------------------------------------------
/arrays-objects-helpers.js:
--------------------------------------------------------------------------------
1 | function _isObject(obj) {
2 | return obj === Object(obj);
3 | }
4 |
5 | // EXAMPLE INPUT:
6 | // {
7 | // foo: {
8 | // name: "foo!"
9 | // },
10 | // bar: {
11 | // name: "bar"
12 | // }
13 | // }
14 | //
15 | // EXAMPLE OUTPUT:
16 | // [ { name: "foo!", key: "foo" }, { name: "bar", key: "bar" } ]
17 | function _objectToArray(obj) {
18 | if (Array.isArray(obj)) {
19 | return obj;
20 | }
21 |
22 | return Object.keys(obj).map(key => {
23 | if (_isObject(obj[key])) {
24 | obj[key].key = key;
25 | }
26 | return obj[key];
27 | });
28 | }
29 |
30 | // EXAMPLE INPUT:
31 | // [
32 | // { foo: { ... } },
33 | // { bar: { ... } },
34 | // ]
35 | //
36 | // EXAMPLE OUTPUT:
37 | // { foo: { orderHint: 0, ... }, bar: { orderHint: 1, ... } }
38 | function _arrayToObject(arr) {
39 | return arr.reduce((acc, cur, idx) => {
40 | Object.keys(cur).forEach(key => {
41 | acc[key] = cur[key];
42 | acc[key].orderHint = idx;
43 | });
44 | return acc;
45 | }, {});
46 | }
47 |
48 | // PUBLIC
49 |
50 | function recursiveObjectToArray(obj) {
51 | if (_isObject(obj)) {
52 | Object.keys(obj).forEach(key => {
53 | const value = obj[key];
54 | if (
55 | _isObject(obj) &&
56 | [
57 | 'responses',
58 | 'body',
59 | 'queryParameters',
60 | 'headers',
61 | 'properties',
62 | 'baseUriParameters',
63 | 'annotations',
64 | 'uriParameters',
65 | ].indexOf(key) !== -1
66 | ) {
67 | obj[key] = _objectToArray(value);
68 | }
69 |
70 | recursiveObjectToArray(value);
71 | });
72 | } else if (Array.isArray(obj)) {
73 | obj.forEach(value => {
74 | recursiveObjectToArray(value);
75 | });
76 | }
77 |
78 | return obj;
79 | }
80 |
81 | // Transform some TOP LEVEL properties from objects to simple arrays
82 | function objectsToArrays(ramlObj) {
83 | [
84 | 'types',
85 | 'traits',
86 | 'resourceTypes',
87 | 'annotationTypes',
88 | 'securitySchemes',
89 | ].forEach(key => {
90 | if (ramlObj[key]) {
91 | ramlObj[key] = _objectToArray(ramlObj[key]);
92 | ramlObj[key].sort((first, second) => {
93 | first.orderHint - second.orderHint;
94 | });
95 | }
96 | });
97 |
98 | return ramlObj;
99 | }
100 |
101 | // Transform some TOP LEVEL properties from arrays to simple objects
102 | function arraysToObjects(ramlObj) {
103 | [
104 | 'types',
105 | 'traits',
106 | 'resourceTypes',
107 | 'annotationTypes',
108 | 'securitySchemes',
109 | ].forEach(key => {
110 | if (ramlObj[key]) {
111 | ramlObj[key] = _arrayToObject(ramlObj[key]);
112 | }
113 | });
114 |
115 | return ramlObj;
116 | }
117 |
118 | module.exports = {
119 | arraysToObjects,
120 | recursiveObjectToArray,
121 | objectsToArrays,
122 | };
123 |
--------------------------------------------------------------------------------
/test/consistent-examples.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: Consistent Examples
3 |
4 | types:
5 | HasFullExamples:
6 | properties:
7 | SomeField: string
8 | examples:
9 | firstExample:
10 | displayName: First Example!
11 | description: It's the first example
12 | value:
13 | SomeField: Uno
14 | secondExample:
15 | displayName: Second Example!
16 | description: It's the second example
17 | value:
18 | SomeField: Duo
19 |
20 | HasJsonExample:
21 | properties:
22 | TestField: string
23 | example: |
24 | {
25 | "TestField": "This example is defined in JSON."
26 | }
27 |
28 | NestedExample:
29 | properties:
30 | ChildObject:
31 | type: Nestee
32 | Message:
33 | type: string
34 | example: I'm layered, bro
35 |
36 | Nestee:
37 | properties:
38 | HereIsANumber:
39 | type: number
40 | HereIsAString:
41 | type: string
42 | example:
43 | displayName: Sneaky nested example
44 | description: It's sneaky!
45 | value:
46 | HereIsANumber: 42
47 | HereIsAString: Strange strong string
48 |
49 |
50 | /FullExamples:
51 | get:
52 | responses:
53 | 200:
54 | body:
55 | application/json:
56 | type: HasFullExamples
57 |
58 | /JsonExample:
59 | get:
60 | responses:
61 | 200:
62 | body:
63 | application/json:
64 | type: HasJsonExample
65 |
66 | /HeaderExample:
67 | get:
68 | headers:
69 | X-MyImportantHeader:
70 | type: string
71 | example: Very Important
72 | X-MyDescriptiveHeader:
73 | type: string
74 | example:
75 | displayName: Baloon Assertion
76 | description: This descriptive header example
77 | value: Red baloons are known to be the colour red.
78 |
79 | /UriExample/{Id}/{Mood}:
80 | uriParameters:
81 | Id:
82 | type: string
83 | example: ABC123
84 | Mood:
85 | type: string
86 | example:
87 | displayName: How are ya
88 | description: ARE YOU ANGRY
89 | value: Serene.
90 | get:
91 |
92 | /QueryParamsExample:
93 | get:
94 | queryParameters:
95 | Temperature:
96 | type: number
97 | description: In celsius you savages
98 | example:
99 | displayName: Comfortable
100 | description: Best combined with a sunny day
101 | value: 24
102 |
103 | /NestedExample:
104 | get:
105 | responses:
106 | 200:
107 | body:
108 | application/json:
109 | type: NestedExample
--------------------------------------------------------------------------------
/test/secured-by.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('secured-by.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/secured-by.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should remove securedBy', () => {
25 | const A = obj.resources[0];
26 | const get = A.methods[0];
27 | const post = A.methods[1];
28 | const put = A.methods[2];
29 | const del = A.methods[3];
30 |
31 | assert.strictEqual(get.securedBy, undefined);
32 | assert.strictEqual(post.securedBy, undefined);
33 | assert.strictEqual(put.securedBy, undefined);
34 | assert.strictEqual(del.securedBy, undefined);
35 | });
36 |
37 | it('should make securedBy consistent', () => {
38 | const B = obj.resources[1];
39 |
40 | assert.strictEqual(B.methods[0].securedBy.constructor, Array);
41 | assert.strictEqual(B.methods[0].securedBy.length, 1);
42 | assert.strictEqual(
43 | B.methods[0].securedBy[0],
44 | Object(B.methods[0].securedBy[0])
45 | );
46 | assert.strictEqual(B.methods[0].securedBy[0].schemeName, 'oauth_2_0');
47 |
48 | assert.strictEqual(B.methods[1].securedBy.constructor, Array);
49 | assert.strictEqual(B.methods[1].securedBy.length, 2);
50 | assert.strictEqual(
51 | B.methods[1].securedBy[0],
52 | Object(B.methods[1].securedBy[0])
53 | );
54 | assert.strictEqual(B.methods[1].securedBy[0].schemeName, 'oauth_2_0');
55 | assert.strictEqual(B.methods[1].securedBy[1], null);
56 |
57 | assert.strictEqual(B.methods[2].securedBy.constructor, Array);
58 | assert.strictEqual(B.methods[2].securedBy.length, 2);
59 | assert.strictEqual(
60 | B.methods[2].securedBy[0],
61 | Object(B.methods[2].securedBy[0])
62 | );
63 | assert.strictEqual(
64 | B.methods[2].securedBy[0].schemeName,
65 | 'oauth_2_0_withscopes'
66 | );
67 | assert.strictEqual(B.methods[2].securedBy[0].scopes.constructor, Array);
68 | assert.strictEqual(B.methods[2].securedBy[0].scopes.length, 1);
69 | assert.strictEqual(B.methods[2].securedBy[0].scopes[0], 'remove-b');
70 | assert.strictEqual(B.methods[2].securedBy[1], null);
71 |
72 | const C = obj.resources[2];
73 |
74 | assert.strictEqual(C.methods[0].securedBy.constructor, Array);
75 | assert.strictEqual(C.methods[0].securedBy.length, 2);
76 | assert.strictEqual(
77 | C.methods[0].securedBy[0],
78 | Object(C.methods[0].securedBy[0])
79 | );
80 | assert.strictEqual(
81 | C.methods[0].securedBy[0].schemeName,
82 | 'oauth_2_0_withscopes'
83 | );
84 | assert.strictEqual(C.methods[0].securedBy[0].scopes.constructor, Array);
85 | assert.strictEqual(C.methods[0].securedBy[0].scopes.length, 1);
86 | assert.strictEqual(C.methods[0].securedBy[0].scopes[0], 'read-c');
87 | assert.strictEqual(
88 | C.methods[0].securedBy[1],
89 | Object(C.methods[0].securedBy[1])
90 | );
91 | assert.strictEqual(C.methods[0].securedBy[1].schemeName, 'custom_scheme');
92 | });
93 | });
94 | });
95 |
--------------------------------------------------------------------------------
/test/consistent-examples.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('consistent-examples.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/consistent-examples.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('all examples should have consistent representations', () => {
25 | let parent;
26 | let example;
27 | let value;
28 |
29 | assert.strictEqual(obj.resources[0].relativeUri, '/FullExamples');
30 | parent = obj.resources[0].methods[0].responses[0].body[0];
31 | example = parent.examples[0];
32 |
33 | assert.strictEqual(example.displayName, 'First Example!');
34 | assert.strictEqual(example.description, "It's the first example");
35 | assert.strictEqual(JSON.parse(example.value).SomeField, 'Uno');
36 |
37 | example = parent.examples[1];
38 |
39 | assert.strictEqual(example.displayName, 'Second Example!');
40 | assert.strictEqual(example.description, "It's the second example");
41 | assert.strictEqual(JSON.parse(example.value).SomeField, 'Duo');
42 |
43 | assert.strictEqual(obj.resources[1].relativeUri, '/JsonExample');
44 | parent = obj.resources[1].methods[0].responses[0].body[0];
45 | example = parent.examples[0];
46 | value = JSON.parse(example.value);
47 | assert.strictEqual(value.TestField, 'This example is defined in JSON.');
48 |
49 | assert.strictEqual(obj.resources[2].relativeUri, '/HeaderExample');
50 | parent = obj.resources[2].methods[0];
51 | example = parent.headers[0].examples[0];
52 | assert.strictEqual(example.value, 'Very Important');
53 |
54 | example = parent.headers[1].examples[0];
55 | assert.strictEqual(example.displayName, 'Baloon Assertion');
56 | assert.strictEqual(
57 | example.description,
58 | 'This descriptive header example'
59 | );
60 | assert.strictEqual(
61 | example.value,
62 | 'Red baloons are known to be the colour red.'
63 | );
64 |
65 | assert.strictEqual(
66 | obj.resources[3].relativeUri,
67 | '/UriExample/{Id}/{Mood}'
68 | );
69 | parent = obj.resources[3];
70 | example = parent.uriParameters[0].examples[0];
71 | assert.strictEqual(example.value, 'ABC123');
72 |
73 | example = parent.uriParameters[1].examples[0];
74 | assert.strictEqual(example.displayName, 'How are ya');
75 | assert.strictEqual(example.description, 'ARE YOU ANGRY');
76 | assert.strictEqual(example.value, 'Serene.');
77 |
78 | assert.strictEqual(obj.resources[4].relativeUri, '/QueryParamsExample');
79 | parent = obj.resources[4].methods[0];
80 | example = parent.queryParameters[0].examples[0];
81 | assert.strictEqual(example.displayName, 'Comfortable');
82 | assert.strictEqual(example.description, 'Best combined with a sunny day');
83 | assert.strictEqual(example.value, '24');
84 |
85 | assert.strictEqual(obj.resources[5].relativeUri, '/NestedExample');
86 | parent = obj.resources[5].methods[0].responses[0].body[0];
87 | example = parent.properties[0].examples[0];
88 | value = JSON.parse(example.value);
89 | assert.strictEqual(example.displayName, 'Sneaky nested example');
90 | assert.strictEqual(example.description, "It's sneaky!");
91 | assert.strictEqual(value.HereIsANumber, 42);
92 | assert.strictEqual(value.HereIsAString, 'Strange strong string');
93 |
94 | example = parent.properties[1].examples[0];
95 | assert.strictEqual(example.value, "I'm layered, bro");
96 | });
97 | });
98 | });
99 |
--------------------------------------------------------------------------------
/test/helloworld.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('helloworld.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/helloworld.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should test the basic properties of the raml object', () => {
25 | assert.strictEqual(obj.title, 'Hello world');
26 | assert.strictEqual(obj.version, '1');
27 | assert.strictEqual(obj.baseUri, 'http://example.com/{version}');
28 | assert.strictEqual(obj.resources.length, 1);
29 | });
30 |
31 | it('should test the documentation', () => {
32 | assert.strictEqual(obj.documentation.length, 2);
33 |
34 | const first = obj.documentation[0];
35 | const second = obj.documentation[1];
36 |
37 | assert.strictEqual(first.title, 'Welcome');
38 | assert.strictEqual(
39 | first.content,
40 | 'Welcome to the Example Documentation. The Example API allows you\nto do stuff. See also [example.com](https://www.example.com).\n'
41 | );
42 | assert.strictEqual(first.uniqueId, 'welcome');
43 |
44 | assert.strictEqual(second.title, 'Chapter two');
45 | assert.strictEqual(
46 | second.content,
47 | 'More content here. Including **bold** text!\n'
48 | );
49 | assert.strictEqual(second.uniqueId, 'chapter_two');
50 | });
51 |
52 | it('should test the top level /helloworld resource', () => {
53 | const resource = obj.resources[0];
54 |
55 | assert.strictEqual(resource.relativeUri, '/helloworld');
56 | assert.strictEqual(resource.displayName, '/helloworld');
57 | assert.strictEqual(
58 | resource.description,
59 | 'This is the top level description for /helloworld.'
60 | );
61 | assert.strictEqual(resource.parentUrl, '');
62 | assert.strictEqual(resource.uniqueId, 'helloworld');
63 | assert.deepEqual(resource.allUriParameters, []);
64 | });
65 |
66 | it('should test the /helloworld methods', () => {
67 | const methods = obj.resources[0].methods;
68 |
69 | assert.strictEqual(methods.length, 1);
70 |
71 | const method = methods[0];
72 |
73 | assert.strictEqual(method.method, 'get');
74 | assert.deepEqual(method.allUriParameters, []);
75 | assert.deepEqual(method.responses.length, 1);
76 |
77 | const response = method.responses[0];
78 |
79 | assert.strictEqual(response.code, '200');
80 | assert.strictEqual(response.body.length, 1);
81 | assert.strictEqual(response.body[0].name, 'application/json');
82 | assert.strictEqual(response.body[0].displayName, 'application/json');
83 | assert.strictEqual(
84 | response.body[0].type,
85 | '{\n "title": "Hello world Response",\n "type": "object",\n "properties": {\n "message": {\n "type": "string"\n }\n }\n}\n'
86 | );
87 | assert.strictEqual(
88 | response.body[0].examples[0].value,
89 | '{\n "message": "Hello world"\n}'
90 | );
91 | });
92 |
93 | it('should test the sub-resource', () => {
94 | const topTesource = obj.resources[0];
95 | assert.strictEqual(topTesource.resources.length, 1);
96 |
97 | const resource = obj.resources[0].resources[0];
98 | assert.strictEqual(resource.relativeUri, '/test');
99 | assert.strictEqual(resource.displayName, 'TEST');
100 | assert.strictEqual(resource.parentUrl, '/helloworld');
101 | assert.strictEqual(resource.uniqueId, 'helloworld_test');
102 | assert.deepEqual(resource.allUriParameters, []);
103 | });
104 | });
105 | });
106 |
--------------------------------------------------------------------------------
/test/helloworld-as-buffer.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 | const fs = require('fs');
8 |
9 | describe('raml2obj', () => {
10 | describe('helloworld.raml as Buffer', () => {
11 | let obj;
12 |
13 | before(done => {
14 | const strContent = fs.readFileSync('test/helloworld.raml');
15 | raml2obj.parse(strContent).then(
16 | result => {
17 | obj = result;
18 | done();
19 | },
20 | error => {
21 | console.log('error', error);
22 | }
23 | );
24 | });
25 |
26 | it('should test the basic properties of the raml object', () => {
27 | assert.strictEqual(obj.title, 'Hello world');
28 | assert.strictEqual(obj.version, '1');
29 | assert.strictEqual(obj.baseUri, 'http://example.com/{version}');
30 | assert.strictEqual(obj.resources.length, 1);
31 | });
32 |
33 | it('should test the documentation', () => {
34 | assert.strictEqual(obj.documentation.length, 2);
35 |
36 | const first = obj.documentation[0];
37 | const second = obj.documentation[1];
38 |
39 | assert.strictEqual(first.title, 'Welcome');
40 | assert.strictEqual(
41 | first.content,
42 | 'Welcome to the Example Documentation. The Example API allows you\nto do stuff. See also [example.com](https://www.example.com).\n'
43 | );
44 | assert.strictEqual(first.uniqueId, 'welcome');
45 |
46 | assert.strictEqual(second.title, 'Chapter two');
47 | assert.strictEqual(
48 | second.content,
49 | 'More content here. Including **bold** text!\n'
50 | );
51 | assert.strictEqual(second.uniqueId, 'chapter_two');
52 | });
53 |
54 | it('should test the top level /helloworld resource', () => {
55 | const resource = obj.resources[0];
56 |
57 | assert.strictEqual(resource.relativeUri, '/helloworld');
58 | assert.strictEqual(resource.displayName, '/helloworld');
59 | assert.strictEqual(
60 | resource.description,
61 | 'This is the top level description for /helloworld.'
62 | );
63 | assert.strictEqual(resource.parentUrl, '');
64 | assert.strictEqual(resource.uniqueId, 'helloworld');
65 | assert.deepEqual(resource.allUriParameters, []);
66 | });
67 |
68 | it('should test the /helloworld methods', () => {
69 | const methods = obj.resources[0].methods;
70 |
71 | assert.strictEqual(methods.length, 1);
72 |
73 | const method = methods[0];
74 |
75 | assert.strictEqual(method.method, 'get');
76 | assert.deepEqual(method.allUriParameters, []);
77 | assert.deepEqual(method.responses.length, 1);
78 |
79 | const response = method.responses[0];
80 |
81 | assert.strictEqual(response.code, '200');
82 | assert.strictEqual(response.body.length, 1);
83 | assert.strictEqual(response.body[0].name, 'application/json');
84 | assert.strictEqual(response.body[0].displayName, 'application/json');
85 | assert.strictEqual(
86 | response.body[0].type,
87 | '{\n "title": "Hello world Response",\n "type": "object",\n "properties": {\n "message": {\n "type": "string"\n }\n }\n}\n'
88 | );
89 | assert.strictEqual(
90 | response.body[0].examples[0].value,
91 | '{\n "message": "Hello world"\n}'
92 | );
93 | });
94 |
95 | it('should test the sub-resource', () => {
96 | const topTesource = obj.resources[0];
97 | assert.strictEqual(topTesource.resources.length, 1);
98 |
99 | const resource = obj.resources[0].resources[0];
100 | assert.strictEqual(resource.relativeUri, '/test');
101 | assert.strictEqual(resource.displayName, 'TEST');
102 | assert.strictEqual(resource.parentUrl, '/helloworld');
103 | assert.strictEqual(resource.uniqueId, 'helloworld_test');
104 | assert.deepEqual(resource.allUriParameters, []);
105 | });
106 | });
107 | });
108 |
--------------------------------------------------------------------------------
/test/helloworld-as-string.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 | const fs = require('fs');
8 |
9 | describe('raml2obj', () => {
10 | describe('helloworld.raml as string', () => {
11 | let obj;
12 |
13 | before(done => {
14 | const strContent = fs.readFileSync('test/helloworld.raml').toString();
15 | raml2obj.parse(strContent).then(
16 | result => {
17 | obj = result;
18 | done();
19 | },
20 | error => {
21 | console.log('error', error);
22 | }
23 | );
24 | });
25 |
26 | it('should test the basic properties of the raml object', () => {
27 | assert.strictEqual(obj.title, 'Hello world');
28 | assert.strictEqual(obj.version, '1');
29 | assert.strictEqual(obj.baseUri, 'http://example.com/{version}');
30 | assert.strictEqual(obj.resources.length, 1);
31 | });
32 |
33 | it('should test the documentation', () => {
34 | assert.strictEqual(obj.documentation.length, 2);
35 |
36 | const first = obj.documentation[0];
37 | const second = obj.documentation[1];
38 |
39 | assert.strictEqual(first.title, 'Welcome');
40 | assert.strictEqual(
41 | first.content,
42 | 'Welcome to the Example Documentation. The Example API allows you\nto do stuff. See also [example.com](https://www.example.com).\n'
43 | );
44 | assert.strictEqual(first.uniqueId, 'welcome');
45 |
46 | assert.strictEqual(second.title, 'Chapter two');
47 | assert.strictEqual(
48 | second.content,
49 | 'More content here. Including **bold** text!\n'
50 | );
51 | assert.strictEqual(second.uniqueId, 'chapter_two');
52 | });
53 |
54 | it('should test the top level /helloworld resource', () => {
55 | const resource = obj.resources[0];
56 |
57 | assert.strictEqual(resource.relativeUri, '/helloworld');
58 | assert.strictEqual(resource.displayName, '/helloworld');
59 | assert.strictEqual(
60 | resource.description,
61 | 'This is the top level description for /helloworld.'
62 | );
63 | assert.strictEqual(resource.parentUrl, '');
64 | assert.strictEqual(resource.uniqueId, 'helloworld');
65 | assert.deepEqual(resource.allUriParameters, []);
66 | });
67 |
68 | it('should test the /helloworld methods', () => {
69 | const methods = obj.resources[0].methods;
70 |
71 | assert.strictEqual(methods.length, 1);
72 |
73 | const method = methods[0];
74 |
75 | assert.strictEqual(method.method, 'get');
76 | assert.deepEqual(method.allUriParameters, []);
77 | assert.deepEqual(method.responses.length, 1);
78 |
79 | const response = method.responses[0];
80 |
81 | assert.strictEqual(response.code, '200');
82 | assert.strictEqual(response.body.length, 1);
83 | assert.strictEqual(response.body[0].name, 'application/json');
84 | assert.strictEqual(response.body[0].displayName, 'application/json');
85 | assert.strictEqual(
86 | response.body[0].type,
87 | '{\n "title": "Hello world Response",\n "type": "object",\n "properties": {\n "message": {\n "type": "string"\n }\n }\n}\n'
88 | );
89 | assert.strictEqual(
90 | response.body[0].examples[0].value,
91 | '{\n "message": "Hello world"\n}'
92 | );
93 | });
94 |
95 | it('should test the sub-resource', () => {
96 | const topTesource = obj.resources[0];
97 | assert.strictEqual(topTesource.resources.length, 1);
98 |
99 | const resource = obj.resources[0].resources[0];
100 | assert.strictEqual(resource.relativeUri, '/test');
101 | assert.strictEqual(resource.displayName, 'TEST');
102 | assert.strictEqual(resource.parentUrl, '/helloworld');
103 | assert.strictEqual(resource.uniqueId, 'helloworld_test');
104 | assert.deepEqual(resource.allUriParameters, []);
105 | });
106 | });
107 | });
108 |
--------------------------------------------------------------------------------
/test/helloworld.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Hello world",
3 | "version": "1",
4 | "baseUri": "http://example.com/{version}",
5 | "baseUriParameters": [
6 | {
7 | "name": "version",
8 | "displayName": "version",
9 | "typePropertyKind": "TYPE_EXPRESSION",
10 | "type": "string",
11 | "required": true,
12 | "enum": [
13 | "1"
14 | ],
15 | "key": "version"
16 | }
17 | ],
18 | "protocols": [
19 | "HTTP"
20 | ],
21 | "resources": [
22 | {
23 | "methods": [
24 | {
25 | "responses": [
26 | {
27 | "code": "200",
28 | "body": [
29 | {
30 | "name": "application/json",
31 | "displayName": "application/json",
32 | "typePropertyKind": "JSON",
33 | "type": "{\n \"title\": \"Hello world Response\",\n \"type\": \"object\",\n \"properties\": {\n \"message\": {\n \"type\": \"string\"\n }\n }\n}\n",
34 | "examples": [
35 | {
36 | "value": "{\n \"message\": \"Hello world\"\n}",
37 | "strict": true,
38 | "name": null,
39 | "structuredValue": {
40 | "message": "Hello world"
41 | }
42 | }
43 | ],
44 | "key": "application/json"
45 | }
46 | ],
47 | "key": "200"
48 | }
49 | ],
50 | "protocols": [
51 | "HTTP"
52 | ],
53 | "method": "get",
54 | "allUriParameters": []
55 | }
56 | ],
57 | "description": "This is the top level description for /helloworld.",
58 | "relativeUri": "/helloworld",
59 | "displayName": "/helloworld",
60 | "resources": [
61 | {
62 | "methods": [
63 | {
64 | "protocols": [
65 | "HTTP"
66 | ],
67 | "description": "a sub resource",
68 | "method": "get",
69 | "allUriParameters": []
70 | }
71 | ],
72 | "relativeUri": "/test",
73 | "displayName": "TEST",
74 | "relativeUriPathSegments": [
75 | "test"
76 | ],
77 | "absoluteUri": "http://example.com/{version}/helloworld/test",
78 | "parentUrl": "/helloworld",
79 | "uniqueId": "helloworld_test",
80 | "allUriParameters": []
81 | }
82 | ],
83 | "relativeUriPathSegments": [
84 | "helloworld"
85 | ],
86 | "absoluteUri": "http://example.com/{version}/helloworld",
87 | "parentUrl": "",
88 | "uniqueId": "helloworld",
89 | "allUriParameters": []
90 | }
91 | ],
92 | "documentation": [
93 | {
94 | "title": "Welcome",
95 | "content": "Welcome to the Example Documentation. The Example API allows you\nto do stuff. See also [example.com](https://www.example.com).\n",
96 | "uniqueId": "welcome"
97 | },
98 | {
99 | "title": "Chapter two",
100 | "content": "More content here. Including **bold** text!\n",
101 | "uniqueId": "chapter_two"
102 | }
103 | ]
104 | }
--------------------------------------------------------------------------------
/test/array-of-strings.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "API used to test broken features",
3 | "version": "v1",
4 | "baseUri": "http://api.samplehost.com/broken/{version}",
5 | "baseUriParameters": [
6 | {
7 | "name": "version",
8 | "displayName": "version",
9 | "typePropertyKind": "TYPE_EXPRESSION",
10 | "type": "string",
11 | "required": true,
12 | "enum": [
13 | "v1"
14 | ],
15 | "key": "version"
16 | }
17 | ],
18 | "protocols": [
19 | "HTTP",
20 | "HTTPS"
21 | ],
22 | "mediaType": "application/json",
23 | "resources": [
24 | {
25 | "methods": [
26 | {
27 | "responses": [
28 | {
29 | "code": "200",
30 | "body": [
31 | {
32 | "name": "application/json",
33 | "displayName": "application/json",
34 | "typePropertyKind": "TYPE_EXPRESSION",
35 | "type": "array",
36 | "items": "string",
37 | "examples": [
38 | {
39 | "value": "[\n \"somevalue\",\n \"anothervalue\"\n]",
40 | "strict": true,
41 | "name": null,
42 | "structuredValue": [
43 | "somevalue",
44 | "anothervalue"
45 | ]
46 | }
47 | ],
48 | "key": "application/json"
49 | }
50 | ],
51 | "key": "200"
52 | }
53 | ],
54 | "protocols": [
55 | "HTTP"
56 | ],
57 | "method": "get",
58 | "allUriParameters": []
59 | },
60 | {
61 | "responses": [
62 | {
63 | "code": "200",
64 | "body": [
65 | {
66 | "name": "application/json",
67 | "displayName": "application/json",
68 | "typePropertyKind": "TYPE_EXPRESSION",
69 | "type": "array",
70 | "items": "string",
71 | "examples": [
72 | {
73 | "value": "[\n \"somevalue\",\n \"anothervalue\"\n]",
74 | "strict": true,
75 | "name": null,
76 | "structuredValue": [
77 | "somevalue",
78 | "anothervalue"
79 | ]
80 | }
81 | ],
82 | "key": "application/json"
83 | }
84 | ],
85 | "key": "200"
86 | }
87 | ],
88 | "protocols": [
89 | "HTTP"
90 | ],
91 | "method": "post",
92 | "allUriParameters": []
93 | }
94 | ],
95 | "relativeUri": "/",
96 | "displayName": "/",
97 | "relativeUriPathSegments": [],
98 | "absoluteUri": "http://api.samplehost.com/broken/{version}/",
99 | "parentUrl": "",
100 | "uniqueId": "",
101 | "allUriParameters": []
102 | }
103 | ]
104 | }
--------------------------------------------------------------------------------
/consistency-helpers.js:
--------------------------------------------------------------------------------
1 | function _isObject(obj) {
2 | return obj === Object(obj);
3 | }
4 |
5 | function _objectToArray(obj) {
6 | if (Array.isArray(obj)) {
7 | return obj;
8 | }
9 |
10 | return Object.keys(obj).map(key => {
11 | if (_isObject(obj[key])) {
12 | obj[key].key = key;
13 | }
14 | return obj[key];
15 | });
16 | }
17 |
18 | function makeConsistent(obj, types) {
19 | if (_isObject(obj)) {
20 | const ignoredKeys = { rawType: true };
21 | if (obj.type) {
22 | if (Array.isArray(obj.type)) {
23 | obj.type = obj.type[0];
24 | }
25 |
26 | if (
27 | obj.type === 'array' &&
28 | Array.isArray(obj.items) &&
29 | obj.items.length === 1
30 | ) {
31 | obj.items = obj.items[0];
32 | }
33 |
34 | if (types && types[obj.type]) {
35 | const mergedObj = Object.assign({}, obj, types[obj.type]);
36 |
37 | // Every exception of inheritance should be deleted from mergedObj
38 | if (obj.description && types[obj.type].description) {
39 | delete mergedObj.description;
40 | }
41 |
42 | if (obj.examples) {
43 | mergedObj.examples = _objectToArray(obj.examples);
44 | } else if (obj.example) {
45 | mergedObj.examples = [];
46 | } else if (Array.isArray(types[obj.type].examples)) {
47 | mergedObj.examples = [...types[obj.type].examples];
48 | } else if (_isObject(types[obj.type].examples)) {
49 | mergedObj.examples = _objectToArray(types[obj.type].examples);
50 | }
51 |
52 | Object.assign(obj, mergedObj);
53 | ignoredKeys.type = true;
54 | }
55 | }
56 |
57 | if (obj.items && types && types[obj.items]) {
58 | obj.items = types[obj.items];
59 | ignoredKeys.items = true;
60 | }
61 |
62 | if (obj.structuredExample) {
63 | if (typeof obj.examples === 'undefined') {
64 | obj.examples = [];
65 | }
66 |
67 | obj.examples.push(obj.structuredExample);
68 | delete obj.example;
69 | delete obj.structuredExample;
70 | }
71 |
72 | if (obj.examples && obj.examples.length) {
73 | obj.examples = obj.examples.map(example => {
74 | if (!example.value) {
75 | return { value: example };
76 | }
77 | if (!example.displayName && example.name) {
78 | example.displayName = example.name;
79 | }
80 | return example;
81 | });
82 | }
83 |
84 | // Give each security scheme a displayName if it isn't already set
85 | if (obj.securitySchemes) {
86 | Object.keys(obj.securitySchemes).forEach(schemeName => {
87 | const scheme = obj.securitySchemes[schemeName];
88 | scheme.displayName = scheme.displayName || scheme.name;
89 | });
90 | }
91 |
92 | if (Array.isArray(obj.securedBy)) {
93 | if (
94 | obj.securedBy.length === 0 ||
95 | obj.securedBy.every(scheme => scheme === null)
96 | ) {
97 | // The RAML 1.0 spec allows that:
98 | // "A securedBy node containing null as the array component indicates
99 | // the method can be called without applying any security scheme."
100 | delete obj.securedBy;
101 | } else {
102 | // Guarantee that all elements of the securedBy array are either null or
103 | // objects containing a schemeName property (and an optional scopes property)
104 | obj.securedBy = obj.securedBy.map(scheme => {
105 | if (scheme === null) {
106 | return null;
107 | }
108 | if (typeof scheme === 'string') {
109 | return { schemeName: scheme };
110 | }
111 | const schemeName = Object.keys(scheme)[0];
112 | return Object.assign({ schemeName }, scheme[schemeName] || {});
113 | });
114 | }
115 | }
116 |
117 | // Fix inconsistency between request headers and response headers from raml-1-parser.
118 | // https://github.com/raml-org/raml-js-parser-2/issues/582
119 | // TODO this issue is fixed since 26 Sep 2017, i.e. v1.1.32, could be removed
120 | if (Array.isArray(obj.headers)) {
121 | obj.headers.forEach(hdr => {
122 | if (typeof hdr.key === 'undefined' && hdr.name) {
123 | hdr.key = hdr.name;
124 | }
125 | });
126 | }
127 |
128 | Object.keys(obj).forEach(key => {
129 | // Don't recurse into types, which have already been canonicalized.
130 | if (!(key in ignoredKeys)) {
131 | makeConsistent(obj[key], types);
132 | }
133 | });
134 | } else if (Array.isArray(obj)) {
135 | obj.forEach(value => {
136 | makeConsistent(value, types);
137 | });
138 | }
139 |
140 | return obj;
141 | }
142 |
143 | module.exports = makeConsistent;
144 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | 6.8.1 - Jun 28, 2021
2 | - Removed `#!/usr/bin/env node` from index.js
3 |
4 | 6.7.0 - Jul 16, 2020
5 | - Updated dependencies
6 |
7 | 6.6.0 - Oct 30, 2019
8 | - Updated dependencies
9 |
10 | 6.5.0 - June 13, 2019
11 | - Allow for 'parse' to accept raw input (e.g. string or Buffer)
12 |
13 | 6.4.0 - May 29, 2019
14 | - Array output format and orderHints in object output (via options flag)
15 |
16 | 6.3.0 - May 29, 2019
17 | - Add support for RAML parser resolvers options
18 |
19 | 6.2.0 - April 2, 2019
20 | - Updated dependencies
21 |
22 | 6.1.0 - September 7, 2018
23 | - Added options.extensionsAndOverlays
24 | - Updated dependencies
25 |
26 | 6.0.0 - February 19, 2018
27 | - Updated datatype-expansion to 0.3.x, which fixes invalid hoisting of unions outside of array items, as well as several other issues
28 | - Enabled tracking of original type in datatype-expansion, so that themes can reference base types
29 | - Tracking rawType of canonicalized types, so that themes can distinguish between declared annotations and inherited annotations
30 |
31 | 5.9.0 - January 9, 2018
32 | - Updated raml-1-parser to 1.1.36, plus devDependencies like eslint, prettier, and mocha
33 |
34 | 5.8.0 - December 6, 2017
35 | - Updated datatype-expansion dependency to 0.2.6
36 |
37 | 5.7.0 - November 3, 2017
38 | - Updated datatype-expansion dependency to 0.2.4
39 | - Updated raml-1-parser to 1.1.36
40 |
41 | 5.6.0 - September 27, 2017
42 | - Updated raml-1-parser
43 |
44 | 5.5.0 - June 5, 2017
45 | - Prefer taking examples from higher level items instead of types (#41)
46 | - Update raml-1-parser dependency
47 |
48 | 5.4.0 - May 3, 2017
49 | - Updated third party dependencies
50 |
51 | 5.3.0 - April 25, 2017
52 | - Updated third party dependencies
53 | - By default we're no longer using raml-1-parser's rejectOnErrors option since it's very slow (raml2html/raml2html#345)
54 |
55 | 5.2.1 - April 14, 2017
56 | - Updated third party dependencies
57 |
58 | 5.2.0 - March 24, 2017
59 | - Updated raml-1-parser dependency
60 |
61 | 5.1.0 - March 1, 2017
62 | - Updated raml-1-parser dependency
63 |
64 | 5.0.0 - February 15, 2017
65 | - Breaking change: updated mapping of securitySchemes and securedBy
66 | - Fixed an issue with some array type declarations having inconsistent item type definitions (raml2html/raml2html#323) (#29)
67 |
68 | 4.1.0 - January 27, 2017
69 | - Added extra properties to examples (#22)
70 | - Updated raml-js-parser-2 dependancy (#25)
71 | - Fixed types' parent overriding behaviour (#26)
72 |
73 | 4.0.4 - January 10, 2017
74 | - Fix response headers inconsistency (#23)
75 |
76 | 4.0.3 - December 29, 2016
77 | - Made securedBy: [ null] consistent with no security
78 |
79 | 4.0.2 - December 8, 2016
80 | - Fixed more Node 4 problems, now actually tested via NVM
81 |
82 | 4.0.1 - December 7, 2016
83 | - Fixed Node 4 support
84 |
85 | 4.0.0 - December 1, 2016
86 | - After almost 4 months of development, it's done: 4.0.0 with RAML 1 support, and a much more consistent output. And a whole lot of unit tests!
87 | - Breaking change: removed support for RAML 0.8 files
88 | - Breaking change: the output of raml2obj has changed
89 |
90 | 4.0.0-beta16 - November 30, 2016
91 | - Updated raml-1-parser to 1.1.9 (#18)
92 |
93 | 4.0.0-beta15 - November 21, 2016
94 | - Downgraded datatype-expansion library
95 | - Making all the types consistent ourselves now, always an array
96 |
97 | 4.0.0-beta14 - November 21, 2016
98 | - Updated datatype-expansion library
99 |
100 | 4.0.0-beta13 - November 2, 2016
101 | - Correctly expanding types within uriParameters
102 | - Updated datatype-expansion and raml-1-parser
103 |
104 | 4.0.0-beta12 - November 1, 2016
105 | - Handling `array` types with `items` by expanding the items into a type object
106 |
107 | 4.0.0-beta11 - November 1, 2016
108 | - Updated datatype-expansion to 0.0.14
109 |
110 | 4.0.0-beta10 - October 31, 2016
111 | - Updated raml-1-parser to 1.1.6
112 |
113 | 4.0.0-beta9 - October 14, 2016
114 | - Types are just a string instead of an array
115 |
116 | 4.0.0-beta8 - October 14, 2016
117 | - Updated raml-1-parser to 1.1.5
118 | - Fixed handling of type inheritance (#15)
119 |
120 | 4.0.0-beta7 - October 4, 2016
121 | - Fixed JS error when `body` is used as a property (#14)
122 | - Removed all the empty examples arrays
123 | - Fixed `key` properties that were sometimes integers
124 |
125 | 4.0.0-beta6 - September 29, 2016
126 | - Fixed examples array
127 |
128 | 4.0.0-beta5 - September 29, 2016
129 | - Always return an `examples` array containing simple strings
130 |
131 | 4.0.0-beta4 - September 29, 2016
132 | - Expanding types where possible
133 | - Added more unit tests
134 |
135 | 4.0.0-beta3 - September 23, 2016
136 | - Limit the `files` that are sent to NPM
137 |
138 | 4.0.0-beta2 - September 22, 2016
139 | - Updated raml-1-parser to 1.1.3
140 | - Added a bunch of unit tests
141 | - Breaking change: removed support for RAML 0.8 files
142 | - Breaking change: the output of raml2obj has changed
143 |
144 | 4.0.0-beta1 - August 10, 2016
145 | - Using the new raml-1-parser which support RAML 1.0 as well as 0.8
146 | - Breaking change: raml-1-parser doesn't support string or buffer sources anymore
147 |
148 | 3.0.0 - August 10, 2016
149 | - Released without further changes
150 |
151 | 3.0.0-beta2 - August 8, 2016
152 | - Fix JS error
153 |
154 | 3.0.0-beta1 - August 7, 2016
155 | - Updated code to use ES6 syntax
156 | - The securitySchemeWithName helper function is now part of raml2obj
157 | - Breaking change: Node 4 or higher is now required!
158 |
159 | 2.2.0 - July 16, 2015
160 | - Update third party dependencies
161 |
162 | 2.1.0 - May 22, 2015
163 | - Renamed raml2obj.js to index.js
164 | - Trim the left underscore from the uniqueId's
165 |
166 | 2.0.0 - March 13, 2015
167 | - Using a promise based API, please see README for updated usage example
168 |
169 | 1.0.0 - January 26, 2015
170 | - Finalized API, the parse method is all we need
171 | - Removed FileReader export
172 |
173 | 0.5.0 - January 21, 2015
174 | - Copy resource allUriParameters to its methods
175 |
176 | 0.4.0 - January 14, 2015
177 | - Export FileReader object
178 |
179 | 0.3.0 - September 25, 2014
180 | - Allow remote urls to be loaded
181 |
182 | 0.2.1 - July 8, 2014
183 | - Critical bugfix
184 |
185 | 0.2.0 - July 8, 2014
186 | - Adding the unique id's to top level documentation chapters has been moved from raml2html to raml2obj
187 |
188 | 0.1.0 - June 12, 2014
189 | - Initial release of standalone raml2obj
190 |
--------------------------------------------------------------------------------
/test/worldmusic.raml:
--------------------------------------------------------------------------------
1 | #%RAML 1.0
2 | title: World Music API
3 | description: This is an example of a music API.
4 | version: v1
5 | baseUri:
6 | value: http://{environment}.musicapi.com/{version}
7 | (rediractable): true
8 | baseUriParameters:
9 | environment:
10 | type: string
11 | enum: [ "stg", "dev", "test", "prod" ]
12 | protocols: [ HTTP, HTTPS ]
13 | mediaType: [ application/json ]
14 | documentation:
15 | - title: Getting Started
16 | content: |
17 | This is a getting started guide for the World Music API.
18 | - title: Legal
19 | content: See http://legal.musicapi.com
20 |
21 | types:
22 | Comment:
23 | type: object
24 | properties:
25 | author:
26 | type: string
27 | required: true
28 | body:
29 | type: string
30 | required: true
31 | date:
32 | type: integer
33 | required: true
34 | editAuthor:
35 | type: string
36 | required: false
37 | edited:
38 | type: integer
39 | required: false
40 | Entry: |
41 | {
42 | "type": "array",
43 | "items": {
44 | "$ref": "#/definitions/song"
45 | },
46 | "definitions": {
47 | "song": {
48 | "type": "object",
49 | "properties": {
50 | "title": {
51 | "type": "string"
52 | },
53 | "artist": {
54 | "type": "string"
55 | }
56 | }
57 | }
58 | }
59 | }
60 | AnotherEntry:
61 | type: Entry
62 | description: |
63 | This is just another entry to simulate that you can add facets also on JSON
64 | schema defined types. Although you can only add documentation-based facets.
65 | User:
66 | properties:
67 | firstname: string
68 | lastname:
69 | type: string
70 | example: Doe
71 | required: false
72 | example:
73 | firstname: John
74 |
75 | traits:
76 | secured: !include world-music-api/secured/accessToken.raml
77 |
78 | resourceTypes:
79 | collection:
80 | get:
81 | description: returns a list of <>
82 | responses:
83 | 200:
84 | body:
85 | application/json:
86 | schema: <>
87 |
88 |
89 | annotationTypes:
90 | deprecated:
91 | properties:
92 | date: datetime
93 | deprecatedBy: User
94 | comment: nil | string
95 | monitoringInterval:
96 | type: integer
97 | description: interval in seconds
98 | example: 2
99 | ready:
100 | type: nil
101 | description: markes a resource as ready
102 | allowedTargets: Resource
103 | info:
104 | properties:
105 | license:
106 | type: string
107 | enum: [ "MIT", "Apache 2.0" ]
108 | allowedTargets: API
109 | rediractable: boolean
110 |
111 | (info):
112 | license: MIT
113 |
114 | securitySchemes:
115 | oauth_1_0:
116 | description: |
117 | OAuth 1.0 continues to be supported for all API requests, but OAuth 2.0 is now preferred.
118 | type: OAuth 1.0
119 | settings:
120 | requestTokenUri: https://api.mysampleapi.com/1/oauth/request_token
121 | authorizationUri: https://api.mysampleapi.com/1/oauth/authorize
122 | tokenCredentialsUri: https://api.mysampleapi.com/1/oauth/access_token
123 | signatures: [ 'HMAC-SHA1', 'PLAINTEXT' ]
124 | oauth_2_0:
125 | description: |
126 | Dropbox supports OAuth 2.0 for authenticating all API requests.
127 | type: OAuth 2.0
128 | describedBy:
129 | headers:
130 | Authorization:
131 | description: |
132 | Used to send a valid OAuth 2 access token. Do not use
133 | with the "access_token" query string parameter.
134 | type: string
135 | queryParameters:
136 | access_token:
137 | description: |
138 | Used to send a valid OAuth 2 access token. Do not use with
139 | the "Authorization" header.
140 | type: string
141 | responses:
142 | 401:
143 | description: |
144 | Bad or expired token. This can happen if the user or Dropbox
145 | revoked or expired an access token. To fix, re-authenticate
146 | the user.
147 | 403:
148 | description: |
149 | Bad OAuth request (wrong consumer key, bad nonce, expired
150 | timestamp...). Unfortunately, re-authenticating the user won't help here.
151 | settings:
152 | authorizationUri: https://www.dropbox.com/1/oauth2/authorize
153 | accessTokenUri: https://api.dropbox.com/1/oauth2/token
154 | authorizationGrants: [ authorization_code, implicit, 'urn:ietf:params:oauth:grant-type:saml2-bearer' ]
155 | custom_scheme:
156 | description: |
157 | A custom security scheme for authenticating requests.
158 | type: x-custom
159 | describedBy:
160 | headers:
161 | SpecialToken:
162 | description: |
163 | Used to send a custom token.
164 | type: string
165 | responses:
166 | 401:
167 | description: |
168 | Bad token.
169 | 403:
170 |
171 | securedBy: custom_scheme
172 |
173 | uses:
174 | SongsLib: world-music-api/libraries/songs-library.raml
175 | ApiLib: world-music-api/libraries/api-library.raml
176 |
177 | /api:
178 | get:
179 | queryString:
180 | properties:
181 | start?: number
182 | page-size?: number
183 | post:
184 | body:
185 | application/json:
186 | type: ApiLib.RamlDataType
187 | /entry:
188 | type: collection
189 | post:
190 | responses:
191 | 200:
192 | body: AnotherEntry
193 | /songs:
194 | displayName: Songs
195 | description: Access to all songs inside the music world library.
196 | (ready):
197 | is: [ secured ]
198 | get:
199 | securedBy: [ oauth_2_0, null ]
200 | (monitoringInterval): 30
201 | queryParameters:
202 | genre:
203 | description: filter the songs by genre
204 | post:
205 | /{songId}:
206 | get:
207 | (deprecated):
208 | date: 2016-02-28T16:41:41.090Z
209 | deprecatedBy:
210 | firstname: Christian
211 | comment: no comment
212 | responses:
213 | 200:
214 | body:
215 | application/json:
216 | type: SongsLib.Song
217 | application/xml:
218 | type: !include world-music-api/schemas/songs.xsd
219 | example: !include world-music-api/examples/songs.xml
220 |
--------------------------------------------------------------------------------
/test/typeexample.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Test",
3 | "resources": [
4 | {
5 | "methods": [
6 | {
7 | "description": "bla",
8 | "method": "get",
9 | "allUriParameters": [
10 | {
11 | "name": "objectid",
12 | "displayName": "objectid",
13 | "typePropertyKind": "TYPE_EXPRESSION",
14 | "type": "string",
15 | "required": true,
16 | "description": "A valid MongoDB object id.",
17 | "rawType": {
18 | "name": "objectid",
19 | "displayName": "objectid",
20 | "typePropertyKind": "TYPE_EXPRESSION",
21 | "type": [
22 | "string"
23 | ],
24 | "example": "576bca8b70fddb149c4a9e92",
25 | "description": "A valid MongoDB object id.",
26 | "structuredExample": {
27 | "value": "576bca8b70fddb149c4a9e92",
28 | "strict": true,
29 | "name": null,
30 | "structuredValue": "576bca8b70fddb149c4a9e92"
31 | }
32 | },
33 | "examples": [
34 | {
35 | "value": "576bca8b70fddb149c4a9e92",
36 | "strict": true,
37 | "name": null,
38 | "structuredValue": "576bca8b70fddb149c4a9e92"
39 | }
40 | ],
41 | "key": "id"
42 | }
43 | ]
44 | }
45 | ],
46 | "uriParameters": [
47 | {
48 | "name": "objectid",
49 | "displayName": "objectid",
50 | "typePropertyKind": "TYPE_EXPRESSION",
51 | "type": "string",
52 | "required": true,
53 | "description": "A valid MongoDB object id.",
54 | "rawType": {
55 | "name": "objectid",
56 | "displayName": "objectid",
57 | "typePropertyKind": "TYPE_EXPRESSION",
58 | "type": [
59 | "string"
60 | ],
61 | "example": "576bca8b70fddb149c4a9e92",
62 | "description": "A valid MongoDB object id.",
63 | "structuredExample": {
64 | "value": "576bca8b70fddb149c4a9e92",
65 | "strict": true,
66 | "name": null,
67 | "structuredValue": "576bca8b70fddb149c4a9e92"
68 | }
69 | },
70 | "examples": [
71 | {
72 | "value": "576bca8b70fddb149c4a9e92",
73 | "strict": true,
74 | "name": null,
75 | "structuredValue": "576bca8b70fddb149c4a9e92"
76 | }
77 | ],
78 | "key": "id"
79 | }
80 | ],
81 | "relativeUri": "/company",
82 | "displayName": "/company",
83 | "relativeUriPathSegments": [
84 | "company"
85 | ],
86 | "absoluteUri": "/company",
87 | "parentUrl": "",
88 | "uniqueId": "company",
89 | "allUriParameters": [
90 | {
91 | "name": "objectid",
92 | "displayName": "objectid",
93 | "typePropertyKind": "TYPE_EXPRESSION",
94 | "type": "string",
95 | "required": true,
96 | "description": "A valid MongoDB object id.",
97 | "rawType": {
98 | "name": "objectid",
99 | "displayName": "objectid",
100 | "typePropertyKind": "TYPE_EXPRESSION",
101 | "type": [
102 | "string"
103 | ],
104 | "example": "576bca8b70fddb149c4a9e92",
105 | "description": "A valid MongoDB object id.",
106 | "structuredExample": {
107 | "value": "576bca8b70fddb149c4a9e92",
108 | "strict": true,
109 | "name": null,
110 | "structuredValue": "576bca8b70fddb149c4a9e92"
111 | }
112 | },
113 | "examples": [
114 | {
115 | "value": "576bca8b70fddb149c4a9e92",
116 | "strict": true,
117 | "name": null,
118 | "structuredValue": "576bca8b70fddb149c4a9e92"
119 | }
120 | ],
121 | "key": "id"
122 | }
123 | ]
124 | }
125 | ],
126 | "types": {
127 | "objectid": {
128 | "type": "string",
129 | "name": "objectid",
130 | "displayName": "objectid",
131 | "typePropertyKind": "TYPE_EXPRESSION",
132 | "description": "A valid MongoDB object id.",
133 | "rawType": {
134 | "name": "objectid",
135 | "displayName": "objectid",
136 | "typePropertyKind": "TYPE_EXPRESSION",
137 | "type": [
138 | "string"
139 | ],
140 | "example": "576bca8b70fddb149c4a9e92",
141 | "description": "A valid MongoDB object id.",
142 | "structuredExample": {
143 | "value": "576bca8b70fddb149c4a9e92",
144 | "strict": true,
145 | "name": null,
146 | "structuredValue": "576bca8b70fddb149c4a9e92"
147 | }
148 | },
149 | "examples": [
150 | {
151 | "value": "576bca8b70fddb149c4a9e92",
152 | "strict": true,
153 | "name": null,
154 | "structuredValue": "576bca8b70fddb149c4a9e92"
155 | }
156 | ]
157 | }
158 | }
159 | }
--------------------------------------------------------------------------------
/test/secured-by.json:
--------------------------------------------------------------------------------
1 | {
2 | "securitySchemes": {
3 | "oauth_2_0": {
4 | "name": "oauth_2_0",
5 | "type": "OAuth 2.0",
6 | "describedBy": {
7 | "headers": [
8 | {
9 | "name": "Authorization",
10 | "displayName": "Authorization",
11 | "typePropertyKind": "TYPE_EXPRESSION",
12 | "type": "string",
13 | "required": true,
14 | "key": "Authorization"
15 | }
16 | ],
17 | "responses": [
18 | {
19 | "code": "401",
20 | "description": "Invalid or expired token."
21 | }
22 | ]
23 | },
24 | "settings": {
25 | "accessTokenUri": "/token",
26 | "authorizationGrants": [
27 | "client_credentials"
28 | ]
29 | },
30 | "displayName": "oauth_2_0"
31 | },
32 | "oauth_2_0_withscopes": {
33 | "name": "oauth_2_0_withscopes",
34 | "type": "OAuth 2.0",
35 | "describedBy": {
36 | "headers": [
37 | {
38 | "name": "Authorization",
39 | "displayName": "Authorization",
40 | "typePropertyKind": "TYPE_EXPRESSION",
41 | "type": "string",
42 | "required": true,
43 | "key": "Authorization"
44 | }
45 | ],
46 | "responses": [
47 | {
48 | "code": "401",
49 | "description": "Invalid or expired token."
50 | }
51 | ]
52 | },
53 | "settings": {
54 | "accessTokenUri": "/token",
55 | "authorizationGrants": [
56 | "client_credentials"
57 | ],
58 | "scopes": [
59 | "add-a",
60 | "remove-a",
61 | "add-b",
62 | "remove-b",
63 | "read-c"
64 | ]
65 | },
66 | "displayName": "oauth_2_0_withscopes"
67 | },
68 | "custom_scheme": {
69 | "name": "custom_scheme",
70 | "type": "x-custom",
71 | "description": "A custom security scheme for authenticating requests.\n",
72 | "describedBy": {
73 | "headers": [
74 | {
75 | "name": "SpecialToken",
76 | "displayName": "SpecialToken",
77 | "typePropertyKind": "TYPE_EXPRESSION",
78 | "type": "string",
79 | "required": true,
80 | "description": "Used to send a custom token.\n",
81 | "key": "SpecialToken"
82 | }
83 | ],
84 | "responses": [
85 | {
86 | "code": "401",
87 | "description": "Bad token.\n"
88 | },
89 | {
90 | "code": "403"
91 | }
92 | ]
93 | },
94 | "displayName": "custom_scheme"
95 | }
96 | },
97 | "title": "Secured By Null",
98 | "resources": [
99 | {
100 | "methods": [
101 | {
102 | "method": "get",
103 | "allUriParameters": []
104 | },
105 | {
106 | "method": "post",
107 | "allUriParameters": []
108 | },
109 | {
110 | "method": "put",
111 | "allUriParameters": []
112 | },
113 | {
114 | "method": "delete",
115 | "allUriParameters": []
116 | }
117 | ],
118 | "relativeUri": "/A",
119 | "displayName": "/A",
120 | "relativeUriPathSegments": [
121 | "A"
122 | ],
123 | "absoluteUri": "/A",
124 | "parentUrl": "",
125 | "uniqueId": "a",
126 | "allUriParameters": []
127 | },
128 | {
129 | "methods": [
130 | {
131 | "securedBy": [
132 | {
133 | "schemeName": "oauth_2_0"
134 | }
135 | ],
136 | "method": "get",
137 | "allUriParameters": []
138 | },
139 | {
140 | "securedBy": [
141 | {
142 | "schemeName": "oauth_2_0"
143 | },
144 | null
145 | ],
146 | "method": "post",
147 | "allUriParameters": []
148 | },
149 | {
150 | "securedBy": [
151 | {
152 | "schemeName": "oauth_2_0_withscopes",
153 | "scopes": [
154 | "remove-b"
155 | ]
156 | },
157 | null
158 | ],
159 | "method": "delete",
160 | "allUriParameters": []
161 | }
162 | ],
163 | "relativeUri": "/B",
164 | "displayName": "/B",
165 | "relativeUriPathSegments": [
166 | "B"
167 | ],
168 | "absoluteUri": "/B",
169 | "parentUrl": "",
170 | "uniqueId": "b",
171 | "allUriParameters": []
172 | },
173 | {
174 | "methods": [
175 | {
176 | "securedBy": [
177 | {
178 | "schemeName": "oauth_2_0_withscopes",
179 | "scopes": [
180 | "read-c"
181 | ]
182 | },
183 | {
184 | "schemeName": "custom_scheme"
185 | }
186 | ],
187 | "method": "get",
188 | "allUriParameters": []
189 | }
190 | ],
191 | "relativeUri": "/C",
192 | "displayName": "/C",
193 | "relativeUriPathSegments": [
194 | "C"
195 | ],
196 | "absoluteUri": "/C",
197 | "parentUrl": "",
198 | "uniqueId": "c",
199 | "allUriParameters": []
200 | }
201 | ]
202 | }
--------------------------------------------------------------------------------
/test/parameters.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('parameters.raml', () => {
10 | let obj;
11 |
12 | before(done => {
13 | raml2obj.parse('test/parameters.raml').then(
14 | result => {
15 | obj = result;
16 | done();
17 | },
18 | error => {
19 | console.log('error', error);
20 | }
21 | );
22 | });
23 |
24 | it('should test the basic properties of the raml object', () => {
25 | assert.strictEqual(obj.title, 'Lots of parameters');
26 | assert.strictEqual(obj.resources.length, 1);
27 | });
28 |
29 | it('should test the /account resource', () => {
30 | const resource = obj.resources[0];
31 |
32 | assert.strictEqual(resource.relativeUri, '/account');
33 | assert.strictEqual(resource.displayName, '/account');
34 | assert.strictEqual(resource.parentUrl, '');
35 | assert.strictEqual(resource.allUriParameters.length, 0);
36 | assert.strictEqual(resource.methods.length, 1);
37 |
38 | const method = resource.methods[0];
39 |
40 | assert.strictEqual(method.allUriParameters.length, 0);
41 | assert.strictEqual(method.method, 'post');
42 | assert.strictEqual(method.body.length, 1);
43 | assert.strictEqual(method.body[0].name, 'application/json');
44 | assert.strictEqual(method.body[0].type, 'any');
45 | assert.strictEqual(
46 | method.body[0].examples[0].value,
47 | '{\n "email": "john@example.com",\n "password": "super_secret",\n "name": "John Doe"\n}'
48 | );
49 | assert.strictEqual(method.responses.length, 1);
50 | assert.strictEqual(method.responses[0].code, '200');
51 | assert.strictEqual(
52 | method.responses[0].description,
53 | 'Account was created and user is now logged in'
54 | );
55 | });
56 |
57 | it('should test the /account/find resource', () => {
58 | const resource = obj.resources[0].resources[0];
59 |
60 | assert.strictEqual(resource.relativeUri, '/find');
61 | assert.strictEqual(resource.displayName, '/find');
62 | assert.strictEqual(resource.parentUrl, '/account');
63 | assert.deepEqual(resource.allUriParameters, []);
64 | assert.strictEqual(resource.methods.length, 1);
65 |
66 | const method = resource.methods[0];
67 |
68 | assert.strictEqual(method.allUriParameters.length, 0);
69 | assert.strictEqual(method.method, 'get');
70 |
71 | assert.strictEqual(method.queryParameters.length, 3);
72 | assert.strictEqual(method.queryParameters[0].name, 'name');
73 | assert.strictEqual(method.queryParameters[0].displayName, 'name');
74 | assert.strictEqual(method.queryParameters[0].type, 'string');
75 | assert.strictEqual(
76 | method.queryParameters[0].examples[0].value,
77 | 'Naruto Uzumaki'
78 | );
79 | assert.strictEqual(method.queryParameters[0].required, true);
80 | assert.strictEqual(
81 | method.queryParameters[0].description,
82 | 'name on account'
83 | );
84 |
85 | assert.strictEqual(method.queryParameters[1].name, 'gender');
86 | assert.strictEqual(method.queryParameters[1].displayName, 'gender');
87 | assert.strictEqual(method.queryParameters[1].type, 'string');
88 | assert.strictEqual(method.queryParameters[1].required, true);
89 | assert.deepEqual(method.queryParameters[1].enum, ['male', 'female']);
90 |
91 | assert.strictEqual(method.queryParameters[2].name, 'number');
92 | assert.strictEqual(method.queryParameters[2].displayName, 'number');
93 | assert.strictEqual(method.queryParameters[2].type, 'integer');
94 | assert.strictEqual(method.queryParameters[2].required, true);
95 | assert.strictEqual(method.queryParameters[2].default, 42);
96 | });
97 |
98 | it('should test the /account/{id} resource', () => {
99 | const resource = obj.resources[0].resources[1];
100 |
101 | assert.strictEqual(resource.relativeUri, '/{id}');
102 | assert.strictEqual(resource.displayName, '/{id}');
103 | assert.strictEqual(resource.parentUrl, '/account');
104 | assert.strictEqual(resource.methods.length, 3);
105 |
106 | assert.strictEqual(resource.uriParameters.length, 1);
107 | assert.strictEqual(resource.uriParameters[0].name, 'id');
108 | assert.strictEqual(resource.uriParameters[0].displayName, 'id');
109 | assert.strictEqual(resource.uriParameters[0].type, 'string');
110 | assert.strictEqual(resource.uriParameters[0].required, true);
111 | assert.strictEqual(
112 | resource.uriParameters[0].description,
113 | 'account identifier'
114 | );
115 | assert.strictEqual(resource.uriParameters[0].minLength, 1);
116 | assert.strictEqual(resource.uriParameters[0].maxLength, 10);
117 |
118 | assert.deepEqual(resource.allUriParameters, resource.uriParameters);
119 |
120 | const get = resource.methods[0];
121 |
122 | assert.strictEqual(get.method, 'get');
123 | assert.strictEqual(get.allUriParameters.length, 1);
124 | assert.strictEqual(get.allUriParameters[0].name, 'id');
125 | assert.strictEqual(get.headers.length, 1);
126 | assert.strictEqual(get.headers[0].name, 'Authorization');
127 | assert.strictEqual(get.headers[0].displayName, 'Authorization');
128 | assert.strictEqual(get.headers[0].type, 'string');
129 | assert.strictEqual(
130 | get.headers[0].examples[0].value,
131 | 'Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n'
132 | );
133 | assert.strictEqual(get.headers[0].required, true);
134 | assert.strictEqual(
135 | get.headers[0].description,
136 | 'Basic authentication header'
137 | );
138 |
139 | const put = resource.methods[1];
140 |
141 | assert.strictEqual(put.method, 'put');
142 | assert.strictEqual(put.allUriParameters.length, 1);
143 | assert.strictEqual(put.allUriParameters[0].name, 'id');
144 | assert.strictEqual(put.body.length, 1);
145 | assert.strictEqual(put.body[0].name, 'application/x-www-form-urlencoded');
146 | assert.strictEqual(put.body[0].type, 'object');
147 | assert.strictEqual(put.body[0].properties.length, 2);
148 | assert.strictEqual(put.body[0].properties[0].name, 'name');
149 | assert.strictEqual(put.body[0].properties[0].examples.length, 2);
150 | assert.strictEqual(
151 | put.body[0].properties[0].examples[0].value,
152 | 'Naruto Uzumaki'
153 | );
154 | assert.strictEqual(
155 | put.body[0].properties[0].examples[1].value,
156 | 'Kevin Renskers'
157 | );
158 | assert.strictEqual(put.body[0].properties[1].name, 'gender');
159 | });
160 |
161 | it('should test the /account/{id}/{id} resource', () => {
162 | const resource = obj.resources[0].resources[1].resources[0];
163 |
164 | assert.strictEqual(resource.relativeUri, '/{id}');
165 | assert.strictEqual(resource.displayName, '/{id}');
166 | assert.strictEqual(resource.parentUrl, '/account/{id}');
167 |
168 | assert.strictEqual(resource.uriParameters.length, 1);
169 | assert.strictEqual(resource.uriParameters[0].name, 'id');
170 |
171 | assert.strictEqual(resource.allUriParameters.length, 2);
172 | assert.strictEqual(resource.allUriParameters[0].name, 'id');
173 | assert.strictEqual(resource.allUriParameters[1].name, 'id');
174 |
175 | const get = resource.methods[0];
176 | assert.strictEqual(get.responses.length, 1);
177 | assert.strictEqual(get.responses[0].headers.length, 1);
178 | assert.strictEqual(get.responses[0].headers[0].name, 'WWW-Authenticate');
179 | assert.strictEqual(
180 | get.responses[0].headers[0].description,
181 | 'user was not authorized'
182 | );
183 | });
184 | });
185 | });
186 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const raml = require('raml-1-parser');
4 | const tools = require('datatype-expansion');
5 | const fs = require('fs');
6 | const makeExamplesAndTypesConsistent = require('./consistency-helpers');
7 | const helpers = require('./arrays-objects-helpers');
8 |
9 | function _makeUniqueId(string) {
10 | const stringWithSpacesReplaced = string.replace(/\W/g, '_');
11 | const stringWithLeadingUnderscoreRemoved = stringWithSpacesReplaced.replace(
12 | new RegExp('^_+'),
13 | ''
14 | );
15 | return stringWithLeadingUnderscoreRemoved.toLowerCase();
16 | }
17 |
18 | // Add unique id's and parent URL's plus parent URI parameters to resources
19 | function _addRaml2htmlProperties(ramlObj, parentUrl, allUriParameters) {
20 | // Add unique id's to top level documentation chapters
21 | if (ramlObj.documentation) {
22 | ramlObj.documentation.forEach(docSection => {
23 | docSection.uniqueId = _makeUniqueId(docSection.title);
24 | });
25 | }
26 |
27 | if (!ramlObj.resources) {
28 | return ramlObj;
29 | }
30 |
31 | ramlObj.resources.forEach(resource => {
32 | resource.parentUrl = parentUrl || '';
33 | resource.uniqueId = _makeUniqueId(
34 | resource.parentUrl + resource.relativeUri
35 | );
36 | resource.allUriParameters = [];
37 |
38 | if (allUriParameters) {
39 | resource.allUriParameters.push.apply(
40 | resource.allUriParameters,
41 | allUriParameters
42 | );
43 | }
44 |
45 | if (resource.uriParameters) {
46 | resource.uriParameters.forEach(uriParameter => {
47 | resource.allUriParameters.push(uriParameter);
48 | });
49 | }
50 |
51 | // Copy the RESOURCE uri parameters to the METHOD, because that's where they will be rendered.
52 | if (resource.methods) {
53 | resource.methods.forEach(method => {
54 | method.allUriParameters = resource.allUriParameters;
55 | });
56 | }
57 |
58 | _addRaml2htmlProperties(
59 | resource,
60 | resource.parentUrl + resource.relativeUri,
61 | resource.allUriParameters
62 | );
63 | });
64 |
65 | return ramlObj;
66 | }
67 |
68 | // This uses the datatype-expansion library to expand all the root type to their canonical expanded form
69 | function _expandRootTypes(types) {
70 | if (!types) {
71 | return types;
72 | }
73 |
74 | Object.keys(types).forEach(key => {
75 | try {
76 | const original = types[key];
77 | const expanded = tools.expandedForm(original, types, {
78 | trackOriginalType: true,
79 | });
80 | const canonical = tools.canonicalForm(expanded, { hoistUnions: false });
81 | // Save a reference to the type as defined in the RAML, so we can differentiate between declared
82 | // and inherited facets, particularly annotations.
83 | canonical.rawType = original;
84 | types[key] = canonical;
85 | } catch (err) {
86 | // Dump the error to stderr and continue with the non-canonical form
87 | console.error(
88 | 'Warning: Unable to canonicalize type "' + key + '": ' + err.message
89 | );
90 | }
91 | });
92 |
93 | return types;
94 | }
95 |
96 | function _enhanceRamlObj(ramlObj, options) {
97 | // Override default options
98 | options = Object.assign(
99 | {
100 | collectionFormat: 'objects',
101 | },
102 | options
103 | );
104 |
105 | // Some of the structures (like `types`) are an array that hold key/value pairs, which is very annoying to work with.
106 | // Let's make them into a simple object, this makes it easy to use them for direct lookups.
107 | //
108 | // EXAMPLE of these structures:
109 | // [
110 | // { foo: { ... } },
111 | // { bar: { ... } },
112 | // ]
113 | //
114 | // EXAMPLE of what we want (default option "objects")
115 | // { foo: { ... }, bar: { ... } }
116 | //
117 | // EXAMPLE of what we want (option "arrays")
118 | // [ { key: "foo", ... }, { key: "bar", ... } ]
119 | // the "arrays" option will be evalulated at the very end to so the conversion and cleanup code
120 | // does not have to handle different data structures.
121 | ramlObj = helpers.arraysToObjects(ramlObj);
122 |
123 | // We want to expand inherited root types, so that later on when we copy type properties into an object,
124 | // we get the full graph.
125 | const types = makeExamplesAndTypesConsistent(_expandRootTypes(ramlObj.types));
126 | // Delete the types from the ramlObj so it's not processed again later on.
127 | delete ramlObj.types;
128 |
129 | // Recursively go over the entire object and make all examples and types consistent.
130 | ramlObj = makeExamplesAndTypesConsistent(ramlObj, types);
131 |
132 | // Other structures (like `responses`) are an object that hold other wrapped objects.
133 | // Flatten this to simple (non-wrapped) objects in an array instead,
134 | // this makes it easy to loop over them in raml2html / raml2md.
135 | //
136 | // EXAMPLE of these structures:
137 | // {
138 | // foo: {
139 | // name: "foo!"
140 | // },
141 | // bar: {
142 | // name: "bar"
143 | // }
144 | // }
145 | //
146 | // EXAMPLE of what we want:
147 | // [ { name: "foo!", key: "foo" }, { name: "bar", key: "bar" } ]
148 | ramlObj = helpers.recursiveObjectToArray(ramlObj);
149 |
150 | // Now add all the properties and things that we need for raml2html, stuff like the uniqueId, parentUrl,
151 | // and allUriParameters.
152 | ramlObj = _addRaml2htmlProperties(ramlObj);
153 |
154 | if (types) {
155 | ramlObj.types = types;
156 | }
157 |
158 | // convert to optional variations in the output structure:
159 | if (options.collectionFormat === 'arrays') {
160 | // repeat recursive to also clean up the types:
161 | ramlObj = helpers.recursiveObjectToArray(ramlObj);
162 | // modify the top-level collections to be arrays
163 | ramlObj = helpers.objectsToArrays(ramlObj);
164 | }
165 |
166 | return ramlObj;
167 | }
168 |
169 | function _validateLoadedRaml(ramlObj) {
170 | if (ramlObj._node._universe._typedVersion === '0.8') {
171 | throw new Error('_sourceToRamlObj: only RAML 1.0 is supported!');
172 | }
173 |
174 | if (ramlObj.expand) {
175 | return ramlObj.expand(true).toJSON({ serializeMetadata: false });
176 | }
177 |
178 | return new Promise((resolve, reject) => {
179 | reject(
180 | new Error(
181 | '_sourceToRamlObj: source could not be parsed. Is it a root RAML file?'
182 | )
183 | );
184 | });
185 | }
186 |
187 | function _sourceToRamlObj(source, options = {}) {
188 | // "options" was originally a validation flag
189 | if (typeof options === 'boolean') {
190 | options = { validate: options };
191 | }
192 | if (typeof source === 'string') {
193 | if (fs.existsSync(source) || source.indexOf('http') === 0) {
194 | // Parse as file or url
195 | return raml
196 | .loadApi(source, options.extensionsAndOverlays || [], {
197 | rejectOnErrors: !!options.validate,
198 | httpResolver: options.httpResolver,
199 | fsResolver: options.fsResolver,
200 | })
201 | .then(_validateLoadedRaml);
202 | } else if (source) {
203 | return raml
204 | .parseRAML(source, {
205 | rejectOnErrors: !!options.validate,
206 | httpResolver: options.httpResolver,
207 | fsResolver: options.fsResolver,
208 | })
209 | .then(_validateLoadedRaml);
210 | }
211 |
212 | return new Promise((resolve, reject) => {
213 | reject(
214 | new Error(
215 | '_sourceToRamlObj: source does not exist or cannot be parsed.'
216 | )
217 | );
218 | });
219 | } else if (source instanceof Buffer) {
220 | return raml
221 | .parseRAML(source.toString(), {
222 | rejectOnErrors: !!options.validate,
223 | httpResolver: options.httpResolver,
224 | fsResolver: options.fsResolver,
225 | })
226 | .then(_validateLoadedRaml);
227 | } else if (typeof source === 'object') {
228 | // Parse RAML object directly
229 | return new Promise(resolve => {
230 | resolve(source);
231 | });
232 | }
233 |
234 | return new Promise((resolve, reject) => {
235 | reject(
236 | new Error(
237 | '_sourceToRamlObj: You must supply either file, url or object as source.'
238 | )
239 | );
240 | });
241 | }
242 |
243 | module.exports.parse = function(source, options) {
244 | return _sourceToRamlObj(source, options).then(ramlObj =>
245 | _enhanceRamlObj(ramlObj, options)
246 | );
247 | };
248 |
--------------------------------------------------------------------------------
/test/typeexample.flatObject.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Test",
3 | "resources": [
4 | {
5 | "methods": [
6 | {
7 | "description": "bla",
8 | "method": "get",
9 | "allUriParameters": [
10 | {
11 | "name": "objectid",
12 | "displayName": "objectid",
13 | "typePropertyKind": "TYPE_EXPRESSION",
14 | "type": "string",
15 | "required": true,
16 | "description": "A valid MongoDB object id.",
17 | "orderHint": 0,
18 | "rawType": {
19 | "name": "objectid",
20 | "displayName": "objectid",
21 | "typePropertyKind": "TYPE_EXPRESSION",
22 | "type": [
23 | "string"
24 | ],
25 | "example": "576bca8b70fddb149c4a9e92",
26 | "description": "A valid MongoDB object id.",
27 | "structuredExample": {
28 | "value": "576bca8b70fddb149c4a9e92",
29 | "strict": true,
30 | "name": null,
31 | "structuredValue": "576bca8b70fddb149c4a9e92"
32 | },
33 | "orderHint": 0
34 | },
35 | "examples": [
36 | {
37 | "value": "576bca8b70fddb149c4a9e92",
38 | "strict": true,
39 | "name": null,
40 | "structuredValue": "576bca8b70fddb149c4a9e92"
41 | }
42 | ],
43 | "key": "id"
44 | }
45 | ]
46 | }
47 | ],
48 | "uriParameters": [
49 | {
50 | "name": "objectid",
51 | "displayName": "objectid",
52 | "typePropertyKind": "TYPE_EXPRESSION",
53 | "type": "string",
54 | "required": true,
55 | "description": "A valid MongoDB object id.",
56 | "orderHint": 0,
57 | "rawType": {
58 | "name": "objectid",
59 | "displayName": "objectid",
60 | "typePropertyKind": "TYPE_EXPRESSION",
61 | "type": [
62 | "string"
63 | ],
64 | "example": "576bca8b70fddb149c4a9e92",
65 | "description": "A valid MongoDB object id.",
66 | "structuredExample": {
67 | "value": "576bca8b70fddb149c4a9e92",
68 | "strict": true,
69 | "name": null,
70 | "structuredValue": "576bca8b70fddb149c4a9e92"
71 | },
72 | "orderHint": 0
73 | },
74 | "examples": [
75 | {
76 | "value": "576bca8b70fddb149c4a9e92",
77 | "strict": true,
78 | "name": null,
79 | "structuredValue": "576bca8b70fddb149c4a9e92"
80 | }
81 | ],
82 | "key": "id"
83 | }
84 | ],
85 | "relativeUri": "/company",
86 | "displayName": "/company",
87 | "relativeUriPathSegments": [
88 | "company"
89 | ],
90 | "absoluteUri": "/company",
91 | "parentUrl": "",
92 | "uniqueId": "company",
93 | "allUriParameters": [
94 | {
95 | "name": "objectid",
96 | "displayName": "objectid",
97 | "typePropertyKind": "TYPE_EXPRESSION",
98 | "type": "string",
99 | "required": true,
100 | "description": "A valid MongoDB object id.",
101 | "orderHint": 0,
102 | "rawType": {
103 | "name": "objectid",
104 | "displayName": "objectid",
105 | "typePropertyKind": "TYPE_EXPRESSION",
106 | "type": [
107 | "string"
108 | ],
109 | "example": "576bca8b70fddb149c4a9e92",
110 | "description": "A valid MongoDB object id.",
111 | "structuredExample": {
112 | "value": "576bca8b70fddb149c4a9e92",
113 | "strict": true,
114 | "name": null,
115 | "structuredValue": "576bca8b70fddb149c4a9e92"
116 | },
117 | "orderHint": 0
118 | },
119 | "examples": [
120 | {
121 | "value": "576bca8b70fddb149c4a9e92",
122 | "strict": true,
123 | "name": null,
124 | "structuredValue": "576bca8b70fddb149c4a9e92"
125 | }
126 | ],
127 | "key": "id"
128 | }
129 | ]
130 | }
131 | ],
132 | "types": [
133 | {
134 | "type": "string",
135 | "name": "objectid",
136 | "displayName": "objectid",
137 | "typePropertyKind": "TYPE_EXPRESSION",
138 | "description": "A valid MongoDB object id.",
139 | "orderHint": 0,
140 | "rawType": {
141 | "name": "objectid",
142 | "displayName": "objectid",
143 | "typePropertyKind": "TYPE_EXPRESSION",
144 | "type": [
145 | "string"
146 | ],
147 | "example": "576bca8b70fddb149c4a9e92",
148 | "description": "A valid MongoDB object id.",
149 | "structuredExample": {
150 | "value": "576bca8b70fddb149c4a9e92",
151 | "strict": true,
152 | "name": null,
153 | "structuredValue": "576bca8b70fddb149c4a9e92"
154 | },
155 | "orderHint": 0
156 | },
157 | "examples": [
158 | {
159 | "value": "576bca8b70fddb149c4a9e92",
160 | "strict": true,
161 | "name": null,
162 | "structuredValue": "576bca8b70fddb149c4a9e92"
163 | }
164 | ],
165 | "key": "objectid"
166 | },
167 | {
168 | "type": "object",
169 | "properties": [
170 | {
171 | "type": "string",
172 | "name": "first",
173 | "displayName": "first",
174 | "typePropertyKind": "TYPE_EXPRESSION",
175 | "required": true,
176 | "key": "first"
177 | },
178 | {
179 | "type": "number",
180 | "name": "second",
181 | "displayName": "second",
182 | "typePropertyKind": "TYPE_EXPRESSION",
183 | "required": true,
184 | "key": "second"
185 | }
186 | ],
187 | "name": "objectType",
188 | "displayName": "objectType",
189 | "typePropertyKind": "TYPE_EXPRESSION",
190 | "description": "a type with properties.",
191 | "orderHint": 1,
192 | "additionalProperties": true,
193 | "rawType": {
194 | "name": "objectType",
195 | "displayName": "objectType",
196 | "typePropertyKind": "TYPE_EXPRESSION",
197 | "type": [
198 | "object"
199 | ],
200 | "description": "a type with properties.",
201 | "properties": [
202 | {
203 | "name": "first",
204 | "displayName": "first",
205 | "typePropertyKind": "TYPE_EXPRESSION",
206 | "type": [
207 | "string"
208 | ],
209 | "required": true,
210 | "key": "first"
211 | },
212 | {
213 | "name": "second",
214 | "displayName": "second",
215 | "typePropertyKind": "TYPE_EXPRESSION",
216 | "type": [
217 | "number"
218 | ],
219 | "required": true,
220 | "key": "second"
221 | }
222 | ],
223 | "orderHint": 1
224 | },
225 | "key": "objectType"
226 | }
227 | ]
228 | }
--------------------------------------------------------------------------------
/test/worldmusic.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node, mocha */
2 |
3 | 'use strict';
4 |
5 | const raml2obj = require('..');
6 | const assert = require('assert');
7 |
8 | describe('raml2obj', () => {
9 | describe('worldmusic.raml', function() {
10 | this.timeout(10000);
11 |
12 | let obj;
13 |
14 | before(done => {
15 | raml2obj.parse('test/worldmusic.raml').then(
16 | result => {
17 | obj = result;
18 | done();
19 | },
20 | error => {
21 | console.log(JSON.stringify(error));
22 | }
23 | );
24 | });
25 |
26 | it('should test the basic properties of the raml object', () => {
27 | assert.strictEqual(obj.title, 'World Music API');
28 | assert.strictEqual(obj.version, 'v1');
29 | assert.strictEqual(
30 | obj.baseUri,
31 | 'http://{environment}.musicapi.com/{version}'
32 | );
33 | assert.strictEqual(obj.resources.length, 3); // /api, /entry, /songs
34 | });
35 |
36 | it('should test baseUriParameters', () => {
37 | assert.strictEqual(obj.baseUriParameters.length, 2);
38 |
39 | assert.strictEqual(obj.baseUriParameters[0].name, 'environment');
40 | assert.strictEqual(obj.baseUriParameters[0].type, 'string');
41 | assert.strictEqual(obj.baseUriParameters[0].required, true);
42 | assert.deepEqual(obj.baseUriParameters[0].enum, [
43 | 'stg',
44 | 'dev',
45 | 'test',
46 | 'prod',
47 | ]);
48 |
49 | assert.strictEqual(obj.baseUriParameters[1].name, 'version');
50 | assert.strictEqual(obj.baseUriParameters[1].type, 'string');
51 | assert.strictEqual(obj.baseUriParameters[1].required, true);
52 | assert.deepEqual(obj.baseUriParameters[1].enum, ['v1']);
53 | });
54 |
55 | it('should test the documentation', () => {
56 | assert.strictEqual(obj.documentation.length, 2);
57 |
58 | const first = obj.documentation[0];
59 | const second = obj.documentation[1];
60 |
61 | assert.strictEqual(first.title, 'Getting Started');
62 | assert.strictEqual(
63 | first.content,
64 | 'This is a getting started guide for the World Music API.\n'
65 | );
66 | assert.strictEqual(first.uniqueId, 'getting_started');
67 |
68 | assert.strictEqual(second.title, 'Legal');
69 | assert.strictEqual(second.content, 'See http://legal.musicapi.com');
70 | assert.strictEqual(second.uniqueId, 'legal');
71 | });
72 |
73 | it('should test the /api resource', () => {
74 | const resource = obj.resources[0];
75 |
76 | assert.strictEqual(resource.relativeUri, '/api');
77 | assert.strictEqual(resource.displayName, '/api');
78 | assert.strictEqual(resource.parentUrl, '');
79 | assert.strictEqual(resource.uniqueId, 'api');
80 | assert.deepEqual(resource.securedBy, [{ schemeName: 'custom_scheme' }]);
81 | assert.strictEqual(resource.allUriParameters.length, 0);
82 | });
83 |
84 | it('should test the /api methods', () => {
85 | const methods = obj.resources[0].methods;
86 |
87 | assert.strictEqual(methods.length, 2);
88 |
89 | const get = methods[0];
90 |
91 | assert.strictEqual(get.method, 'get');
92 | assert.strictEqual(get.allUriParameters.length, 0);
93 | assert.deepEqual(get.securedBy, [{ schemeName: 'custom_scheme' }]);
94 |
95 | assert.strictEqual(get.queryString.name, 'queryString');
96 | assert.strictEqual(get.queryString.type, 'object');
97 | assert.strictEqual(get.queryString.properties.length, 2);
98 | assert.strictEqual(get.queryString.properties[0].name, 'start');
99 | assert.strictEqual(get.queryString.properties[0].required, false);
100 | assert.strictEqual(get.queryString.properties[0].type, 'number');
101 |
102 | assert.strictEqual(get.queryString.properties[1].name, 'page-size');
103 | assert.strictEqual(get.queryString.properties[1].required, false);
104 | assert.strictEqual(get.queryString.properties[1].type, 'number');
105 |
106 | const post = methods[1];
107 |
108 | assert.strictEqual(post.method, 'post');
109 | assert.strictEqual(post.allUriParameters.length, 0);
110 | assert.deepEqual(post.securedBy, [{ schemeName: 'custom_scheme' }]);
111 | assert.strictEqual(post.body.length, 1);
112 | assert.strictEqual(post.body[0].name, 'RamlDataType');
113 | assert.strictEqual(post.body[0].key, 'application/json');
114 | assert.strictEqual(post.body[0].type, 'object');
115 | assert.strictEqual(post.body[0].properties.length, 14);
116 | assert.strictEqual(
117 | post.body[0].properties[4].examples[0].value,
118 | 'very well made'
119 | );
120 | assert.strictEqual(post.body[0].properties[10].key, 'NilValue');
121 | assert.strictEqual(
122 | post.body[0].properties[10].properties[1].name,
123 | 'comment'
124 | );
125 | assert.strictEqual(
126 | post.body[0].properties[10].properties[1].type,
127 | 'union'
128 | );
129 | assert.strictEqual(
130 | post.body[0].properties[10].properties[1].anyOf[0].type,
131 | 'string'
132 | );
133 | assert.strictEqual(
134 | post.body[0].properties[10].properties[1].anyOf[1].type,
135 | 'nil'
136 | );
137 | assert.strictEqual(post.body[0].properties[11].key, 'CatOrDog');
138 | assert.strictEqual(post.body[0].properties[11].type, 'union');
139 | assert.strictEqual(post.body[0].properties[11].anyOf[0].type, 'object');
140 | assert.strictEqual(
141 | post.body[0].properties[11].anyOf[0].originalType,
142 | 'ApiLib.Cat'
143 | );
144 | assert.strictEqual(post.body[0].properties[11].anyOf[1].type, 'object');
145 | assert.strictEqual(
146 | post.body[0].properties[11].anyOf[1].originalType,
147 | 'ApiLib.Dog'
148 | );
149 | });
150 |
151 | it('should test the /entry resource', () => {
152 | const resource = obj.resources[1];
153 |
154 | assert.strictEqual(resource.relativeUri, '/entry');
155 | assert.strictEqual(resource.displayName, '/entry');
156 | assert.strictEqual(resource.parentUrl, '');
157 | assert.strictEqual(resource.uniqueId, 'entry');
158 | assert.strictEqual(resource.type, 'collection');
159 | assert.deepEqual(resource.securedBy, [{ schemeName: 'custom_scheme' }]);
160 | assert.strictEqual(resource.allUriParameters.length, 0);
161 | });
162 |
163 | it('should test the /entry methods', () => {
164 | const methods = obj.resources[1].methods;
165 |
166 | assert.strictEqual(methods.length, 2);
167 |
168 | const post = methods[0];
169 |
170 | assert.strictEqual(post.method, 'post');
171 | assert.strictEqual(post.allUriParameters.length, 0);
172 | assert.deepEqual(post.securedBy, [{ schemeName: 'custom_scheme' }]);
173 | assert.strictEqual(post.responses.length, 1);
174 | assert.strictEqual(post.responses[0].code, '200');
175 | assert.strictEqual(post.responses[0].body.length, 1);
176 | assert.strictEqual(post.responses[0].body[0].name, 'AnotherEntry');
177 | assert.strictEqual(post.responses[0].body[0].key, 'application/json');
178 | assert.strictEqual(post.responses[0].body[0].type, 'json');
179 | assert.strictEqual(
180 | post.responses[0].body[0].content.indexOf('{\n "type": "array"'),
181 | 0
182 | );
183 |
184 | const get = methods[1];
185 |
186 | assert.strictEqual(get.method, 'get');
187 | assert.strictEqual(get.description, 'returns a list of entry');
188 | assert.strictEqual(get.allUriParameters.length, 0);
189 | assert.deepEqual(get.securedBy, [{ schemeName: 'custom_scheme' }]);
190 | assert.strictEqual(get.responses.length, 1);
191 | assert.strictEqual(get.responses[0].code, '200');
192 | assert.strictEqual(get.responses[0].body.length, 1);
193 | assert.strictEqual(get.responses[0].body[0].name, 'application/json');
194 | assert.deepEqual(get.responses[0].body[0].schema, ['Entry']);
195 | });
196 |
197 | it('should test the /songs resource', () => {
198 | const resource = obj.resources[2];
199 |
200 | assert.strictEqual(resource.relativeUri, '/songs');
201 | assert.strictEqual(resource.displayName, 'Songs');
202 | assert.strictEqual(
203 | resource.description,
204 | 'Access to all songs inside the music world library.'
205 | );
206 | assert.strictEqual(resource.parentUrl, '');
207 | assert.strictEqual(resource.uniqueId, 'songs');
208 | assert.deepEqual(resource.securedBy, [{ schemeName: 'custom_scheme' }]);
209 | assert.strictEqual(resource.allUriParameters.length, 0);
210 | assert.strictEqual(resource.annotations.length, 1);
211 | assert.strictEqual(resource.annotations[0].name, 'ready');
212 | assert.deepEqual(resource.is, ['secured']);
213 | assert.strictEqual(resource.resources.length, 1);
214 | });
215 |
216 | it('should test the /songs methods', () => {
217 | const methods = obj.resources[2].methods;
218 |
219 | assert.strictEqual(methods.length, 2);
220 |
221 | const get = methods[0];
222 |
223 | assert.strictEqual(get.method, 'get');
224 | assert.strictEqual(get.allUriParameters.length, 0);
225 | assert.deepEqual(get.securedBy, [{ schemeName: 'oauth_2_0' }, null]);
226 |
227 | assert.strictEqual(get.annotations.length, 1);
228 | assert.strictEqual(get.annotations[0].name, 'monitoringInterval');
229 | assert.strictEqual(get.annotations[0].structuredValue, 30);
230 |
231 | assert.strictEqual(get.queryParameters.length, 2);
232 |
233 | const post = methods[1];
234 |
235 | assert.strictEqual(post.method, 'post');
236 | assert.deepEqual(post.securedBy, [{ schemeName: 'custom_scheme' }]);
237 | assert.strictEqual(post.queryParameters.length, 1);
238 | });
239 |
240 | it('should test the /songs/{songId} resource', () => {
241 | const resource = obj.resources[2].resources[0];
242 |
243 | assert.strictEqual(resource.relativeUri, '/{songId}');
244 | assert.strictEqual(resource.displayName, '/{songId}');
245 | assert.strictEqual(resource.parentUrl, '/songs');
246 | assert.strictEqual(resource.uniqueId, 'songs__songid_');
247 | assert.deepEqual(resource.securedBy, [{ schemeName: 'custom_scheme' }]);
248 | assert.strictEqual(resource.allUriParameters.length, 1);
249 | });
250 |
251 | it('should test the /songs/{songId} methods', () => {
252 | const methods = obj.resources[2].resources[0].methods;
253 |
254 | assert.strictEqual(methods.length, 1);
255 |
256 | const get = methods[0];
257 |
258 | assert.strictEqual(get.method, 'get');
259 | assert.strictEqual(get.allUriParameters.length, 1);
260 | assert.strictEqual(get.annotations.length, 1);
261 | assert.strictEqual(get.responses.length, 1);
262 | assert.deepEqual(get.securedBy, [{ schemeName: 'custom_scheme' }]);
263 |
264 | assert.strictEqual(get.responses[0].body.length, 2);
265 | assert.strictEqual(get.responses[0].body[0].displayName, 'Song');
266 | assert.strictEqual(get.responses[0].body[0].key, 'application/json');
267 | assert.strictEqual(get.responses[0].body[0].examples.length, 2);
268 | assert.strictEqual(get.responses[0].body[0].type, 'object');
269 |
270 | assert.strictEqual(
271 | get.responses[0].body[1].type.indexOf(
272 | ''
273 | ),
274 | 0
275 | );
276 | });
277 | });
278 | });
279 |
--------------------------------------------------------------------------------
/test/array-of-foo.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Test",
3 | "description": "Test of array support",
4 | "version": "v1",
5 | "baseUri": "https://exmaple.com/{version}",
6 | "baseUriParameters": [
7 | {
8 | "name": "version",
9 | "displayName": "version",
10 | "typePropertyKind": "TYPE_EXPRESSION",
11 | "type": "string",
12 | "required": true,
13 | "enum": [
14 | "v1"
15 | ],
16 | "key": "version"
17 | }
18 | ],
19 | "protocols": [
20 | "HTTPS"
21 | ],
22 | "mediaType": "application/json",
23 | "resources": [
24 | {
25 | "methods": [
26 | {
27 | "responses": [
28 | {
29 | "code": "200",
30 | "body": [
31 | {
32 | "name": "Foos",
33 | "displayName": "Foos",
34 | "typePropertyKind": "TYPE_EXPRESSION",
35 | "type": "array",
36 | "items": {
37 | "type": "object",
38 | "properties": [
39 | {
40 | "type": "string",
41 | "name": "id",
42 | "displayName": "id",
43 | "typePropertyKind": "TYPE_EXPRESSION",
44 | "required": true,
45 | "key": "id"
46 | }
47 | ],
48 | "name": "Foo",
49 | "displayName": "Foo",
50 | "typePropertyKind": "TYPE_EXPRESSION",
51 | "additionalProperties": true,
52 | "rawType": {
53 | "name": "Foo",
54 | "displayName": "Foo",
55 | "typePropertyKind": "TYPE_EXPRESSION",
56 | "type": [
57 | "object"
58 | ],
59 | "properties": [
60 | {
61 | "name": "id",
62 | "displayName": "id",
63 | "typePropertyKind": "TYPE_EXPRESSION",
64 | "type": [
65 | "string"
66 | ],
67 | "required": true,
68 | "key": "id"
69 | }
70 | ]
71 | },
72 | "originalType": "Foo"
73 | },
74 | "rawType": {
75 | "name": "Foos",
76 | "displayName": "Foos",
77 | "typePropertyKind": "TYPE_EXPRESSION",
78 | "type": [
79 | "array"
80 | ],
81 | "items": "Foo"
82 | },
83 | "key": "application/json"
84 | }
85 | ],
86 | "key": "200"
87 | }
88 | ],
89 | "protocols": [
90 | "HTTPS"
91 | ],
92 | "method": "get",
93 | "allUriParameters": []
94 | },
95 | {
96 | "responses": [
97 | {
98 | "code": "200",
99 | "body": [
100 | {
101 | "name": "application/json",
102 | "displayName": "application/json",
103 | "typePropertyKind": "TYPE_EXPRESSION",
104 | "type": "array",
105 | "items": {
106 | "type": "object",
107 | "properties": [
108 | {
109 | "type": "string",
110 | "name": "id",
111 | "displayName": "id",
112 | "typePropertyKind": "TYPE_EXPRESSION",
113 | "required": true,
114 | "key": "id"
115 | }
116 | ],
117 | "name": "Foo",
118 | "displayName": "Foo",
119 | "typePropertyKind": "TYPE_EXPRESSION",
120 | "additionalProperties": true,
121 | "rawType": {
122 | "name": "Foo",
123 | "displayName": "Foo",
124 | "typePropertyKind": "TYPE_EXPRESSION",
125 | "type": [
126 | "object"
127 | ],
128 | "properties": [
129 | {
130 | "name": "id",
131 | "displayName": "id",
132 | "typePropertyKind": "TYPE_EXPRESSION",
133 | "type": [
134 | "string"
135 | ],
136 | "required": true,
137 | "key": "id"
138 | }
139 | ]
140 | }
141 | },
142 | "minItems": 1,
143 | "maxItems": 200,
144 | "key": "application/json"
145 | }
146 | ],
147 | "key": "200"
148 | }
149 | ],
150 | "protocols": [
151 | "HTTPS"
152 | ],
153 | "method": "post",
154 | "allUriParameters": []
155 | }
156 | ],
157 | "relativeUri": "/foos",
158 | "displayName": "/foos",
159 | "relativeUriPathSegments": [
160 | "foos"
161 | ],
162 | "absoluteUri": "https://exmaple.com/{version}/foos",
163 | "parentUrl": "",
164 | "uniqueId": "foos",
165 | "allUriParameters": []
166 | }
167 | ],
168 | "types": {
169 | "Foo": {
170 | "type": "object",
171 | "properties": [
172 | {
173 | "type": "string",
174 | "name": "id",
175 | "displayName": "id",
176 | "typePropertyKind": "TYPE_EXPRESSION",
177 | "required": true,
178 | "key": "id"
179 | }
180 | ],
181 | "name": "Foo",
182 | "displayName": "Foo",
183 | "typePropertyKind": "TYPE_EXPRESSION",
184 | "additionalProperties": true,
185 | "rawType": {
186 | "name": "Foo",
187 | "displayName": "Foo",
188 | "typePropertyKind": "TYPE_EXPRESSION",
189 | "type": [
190 | "object"
191 | ],
192 | "properties": [
193 | {
194 | "name": "id",
195 | "displayName": "id",
196 | "typePropertyKind": "TYPE_EXPRESSION",
197 | "type": [
198 | "string"
199 | ],
200 | "required": true,
201 | "key": "id"
202 | }
203 | ]
204 | }
205 | },
206 | "Foos": {
207 | "type": "array",
208 | "items": {
209 | "type": "object",
210 | "properties": [
211 | {
212 | "type": "string",
213 | "name": "id",
214 | "displayName": "id",
215 | "typePropertyKind": "TYPE_EXPRESSION",
216 | "required": true,
217 | "key": "id"
218 | }
219 | ],
220 | "name": "Foo",
221 | "displayName": "Foo",
222 | "typePropertyKind": "TYPE_EXPRESSION",
223 | "additionalProperties": true,
224 | "rawType": {
225 | "name": "Foo",
226 | "displayName": "Foo",
227 | "typePropertyKind": "TYPE_EXPRESSION",
228 | "type": [
229 | "object"
230 | ],
231 | "properties": [
232 | {
233 | "name": "id",
234 | "displayName": "id",
235 | "typePropertyKind": "TYPE_EXPRESSION",
236 | "type": [
237 | "string"
238 | ],
239 | "required": true,
240 | "key": "id"
241 | }
242 | ]
243 | },
244 | "originalType": "Foo"
245 | },
246 | "name": "Foos",
247 | "displayName": "Foos",
248 | "typePropertyKind": "TYPE_EXPRESSION",
249 | "rawType": {
250 | "name": "Foos",
251 | "displayName": "Foos",
252 | "typePropertyKind": "TYPE_EXPRESSION",
253 | "type": [
254 | "array"
255 | ],
256 | "items": "Foo"
257 | }
258 | }
259 | }
260 | }
--------------------------------------------------------------------------------
/test/resourceexample.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "resource example",
3 | "resources": [
4 | {
5 | "methods": [
6 | {
7 | "responses": [
8 | {
9 | "code": "200",
10 | "body": [
11 | {
12 | "name": "ResourceExampleType",
13 | "displayName": "ResourceExampleType",
14 | "typePropertyKind": "TYPE_EXPRESSION",
15 | "type": "object",
16 | "properties": [
17 | {
18 | "type": "string",
19 | "name": "content",
20 | "displayName": "content",
21 | "typePropertyKind": "TYPE_EXPRESSION",
22 | "required": true,
23 | "key": "content"
24 | }
25 | ],
26 | "examples": [
27 | {
28 | "value": "{\n \"content\": \"typeExample1\"\n}",
29 | "strict": true,
30 | "name": "typeExample1",
31 | "structuredValue": {
32 | "content": "typeExample1"
33 | },
34 | "displayName": "typeExample1"
35 | },
36 | {
37 | "value": "{\n \"content\": \"typeExample2\"\n}",
38 | "strict": true,
39 | "name": "typeExample2",
40 | "structuredValue": {
41 | "content": "typeExample2"
42 | },
43 | "displayName": "typeExample2"
44 | }
45 | ],
46 | "additionalProperties": false,
47 | "rawType": {
48 | "name": "ResourceExampleType",
49 | "displayName": "ResourceExampleType",
50 | "typePropertyKind": "TYPE_EXPRESSION",
51 | "type": [
52 | "object"
53 | ],
54 | "examples": [
55 | {
56 | "value": "{\n \"content\": \"typeExample1\"\n}",
57 | "strict": true,
58 | "name": "typeExample1",
59 | "structuredValue": {
60 | "content": "typeExample1"
61 | }
62 | },
63 | {
64 | "value": "{\n \"content\": \"typeExample2\"\n}",
65 | "strict": true,
66 | "name": "typeExample2",
67 | "structuredValue": {
68 | "content": "typeExample2"
69 | }
70 | }
71 | ],
72 | "properties": [
73 | {
74 | "name": "content",
75 | "displayName": "content",
76 | "typePropertyKind": "TYPE_EXPRESSION",
77 | "type": [
78 | "string"
79 | ],
80 | "required": true,
81 | "key": "content"
82 | }
83 | ],
84 | "additionalProperties": false
85 | },
86 | "key": "application/json"
87 | }
88 | ],
89 | "key": "200"
90 | },
91 | {
92 | "code": "202",
93 | "body": [
94 | {
95 | "name": "ResourceExampleType",
96 | "displayName": "ResourceExampleType",
97 | "typePropertyKind": "TYPE_EXPRESSION",
98 | "type": "object",
99 | "examples": [
100 | {
101 | "value": "{\n \"content\": \"resourceExample1\"\n}",
102 | "strict": true,
103 | "name": "resourceExample1",
104 | "structuredValue": {
105 | "content": "resourceExample1"
106 | },
107 | "displayName": "resourceExample1"
108 | },
109 | {
110 | "value": "{\n \"content\": \"resourceExample2\"\n}",
111 | "strict": true,
112 | "name": "resourceExample2",
113 | "structuredValue": {
114 | "content": "resourceExample2"
115 | },
116 | "displayName": "resourceExample2"
117 | }
118 | ],
119 | "properties": [
120 | {
121 | "type": "string",
122 | "name": "content",
123 | "displayName": "content",
124 | "typePropertyKind": "TYPE_EXPRESSION",
125 | "required": true,
126 | "key": "content"
127 | }
128 | ],
129 | "additionalProperties": false,
130 | "rawType": {
131 | "name": "ResourceExampleType",
132 | "displayName": "ResourceExampleType",
133 | "typePropertyKind": "TYPE_EXPRESSION",
134 | "type": [
135 | "object"
136 | ],
137 | "examples": [
138 | {
139 | "value": "{\n \"content\": \"typeExample1\"\n}",
140 | "strict": true,
141 | "name": "typeExample1",
142 | "structuredValue": {
143 | "content": "typeExample1"
144 | }
145 | },
146 | {
147 | "value": "{\n \"content\": \"typeExample2\"\n}",
148 | "strict": true,
149 | "name": "typeExample2",
150 | "structuredValue": {
151 | "content": "typeExample2"
152 | }
153 | }
154 | ],
155 | "properties": [
156 | {
157 | "name": "content",
158 | "displayName": "content",
159 | "typePropertyKind": "TYPE_EXPRESSION",
160 | "type": [
161 | "string"
162 | ],
163 | "required": true,
164 | "key": "content"
165 | }
166 | ],
167 | "additionalProperties": false
168 | },
169 | "key": "application/json"
170 | }
171 | ],
172 | "key": "202"
173 | }
174 | ],
175 | "method": "get",
176 | "allUriParameters": []
177 | }
178 | ],
179 | "relativeUri": "/example",
180 | "displayName": "/example",
181 | "relativeUriPathSegments": [
182 | "example"
183 | ],
184 | "absoluteUri": "/example",
185 | "parentUrl": "",
186 | "uniqueId": "example",
187 | "allUriParameters": []
188 | }
189 | ],
190 | "types": {
191 | "ResourceExampleType": {
192 | "type": "object",
193 | "properties": {
194 | "content": {
195 | "type": "string",
196 | "name": "content",
197 | "displayName": "content",
198 | "typePropertyKind": "TYPE_EXPRESSION",
199 | "required": true,
200 | "key": "content"
201 | }
202 | },
203 | "name": "ResourceExampleType",
204 | "displayName": "ResourceExampleType",
205 | "typePropertyKind": "TYPE_EXPRESSION",
206 | "examples": [
207 | {
208 | "value": "{\n \"content\": \"typeExample1\"\n}",
209 | "strict": true,
210 | "name": "typeExample1",
211 | "structuredValue": {
212 | "content": "typeExample1"
213 | },
214 | "displayName": "typeExample1"
215 | },
216 | {
217 | "value": "{\n \"content\": \"typeExample2\"\n}",
218 | "strict": true,
219 | "name": "typeExample2",
220 | "structuredValue": {
221 | "content": "typeExample2"
222 | },
223 | "displayName": "typeExample2"
224 | }
225 | ],
226 | "additionalProperties": false,
227 | "rawType": {
228 | "name": "ResourceExampleType",
229 | "displayName": "ResourceExampleType",
230 | "typePropertyKind": "TYPE_EXPRESSION",
231 | "type": [
232 | "object"
233 | ],
234 | "examples": [
235 | {
236 | "value": "{\n \"content\": \"typeExample1\"\n}",
237 | "strict": true,
238 | "name": "typeExample1",
239 | "structuredValue": {
240 | "content": "typeExample1"
241 | }
242 | },
243 | {
244 | "value": "{\n \"content\": \"typeExample2\"\n}",
245 | "strict": true,
246 | "name": "typeExample2",
247 | "structuredValue": {
248 | "content": "typeExample2"
249 | }
250 | }
251 | ],
252 | "properties": [
253 | {
254 | "name": "content",
255 | "displayName": "content",
256 | "typePropertyKind": "TYPE_EXPRESSION",
257 | "type": [
258 | "string"
259 | ],
260 | "required": true,
261 | "key": "content"
262 | }
263 | ],
264 | "additionalProperties": false
265 | }
266 | }
267 | }
268 | }
--------------------------------------------------------------------------------
/test/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Lots of parameters",
3 | "resources": [
4 | {
5 | "methods": [
6 | {
7 | "responses": [
8 | {
9 | "code": "200",
10 | "description": "Account was created and user is now logged in",
11 | "key": "200"
12 | }
13 | ],
14 | "body": [
15 | {
16 | "name": "application/json",
17 | "displayName": "application/json",
18 | "typePropertyKind": "TYPE_EXPRESSION",
19 | "type": "any",
20 | "examples": [
21 | {
22 | "value": "{\n \"email\": \"john@example.com\",\n \"password\": \"super_secret\",\n \"name\": \"John Doe\"\n}",
23 | "strict": true,
24 | "name": "example1",
25 | "structuredValue": {
26 | "email": "john@example.com",
27 | "password": "super_secret",
28 | "name": "John Doe"
29 | },
30 | "displayName": "example1"
31 | }
32 | ],
33 | "key": "application/json"
34 | }
35 | ],
36 | "method": "post",
37 | "allUriParameters": []
38 | }
39 | ],
40 | "relativeUri": "/account",
41 | "displayName": "/account",
42 | "resources": [
43 | {
44 | "methods": [
45 | {
46 | "queryParameters": [
47 | {
48 | "name": "name",
49 | "displayName": "name",
50 | "typePropertyKind": "TYPE_EXPRESSION",
51 | "type": "string",
52 | "required": true,
53 | "description": "name on account",
54 | "examples": [
55 | {
56 | "value": "Naruto Uzumaki",
57 | "strict": true,
58 | "name": null,
59 | "structuredValue": "Naruto Uzumaki"
60 | }
61 | ],
62 | "key": "name"
63 | },
64 | {
65 | "name": "gender",
66 | "displayName": "gender",
67 | "typePropertyKind": "TYPE_EXPRESSION",
68 | "type": "string",
69 | "required": true,
70 | "enum": [
71 | "male",
72 | "female"
73 | ],
74 | "key": "gender"
75 | },
76 | {
77 | "name": "number",
78 | "displayName": "number",
79 | "typePropertyKind": "TYPE_EXPRESSION",
80 | "type": "integer",
81 | "default": 42,
82 | "required": true,
83 | "key": "number"
84 | }
85 | ],
86 | "method": "get",
87 | "allUriParameters": []
88 | }
89 | ],
90 | "relativeUri": "/find",
91 | "displayName": "/find",
92 | "relativeUriPathSegments": [
93 | "find"
94 | ],
95 | "absoluteUri": "/account/find",
96 | "parentUrl": "/account",
97 | "uniqueId": "account_find",
98 | "allUriParameters": []
99 | },
100 | {
101 | "methods": [
102 | {
103 | "headers": [
104 | {
105 | "name": "Authorization",
106 | "displayName": "Authorization",
107 | "typePropertyKind": "TYPE_EXPRESSION",
108 | "type": "string",
109 | "required": true,
110 | "description": "Basic authentication header",
111 | "examples": [
112 | {
113 | "value": "Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n",
114 | "strict": true,
115 | "name": null,
116 | "structuredValue": "Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n"
117 | }
118 | ],
119 | "key": "Authorization"
120 | }
121 | ],
122 | "method": "get",
123 | "allUriParameters": [
124 | {
125 | "name": "id",
126 | "displayName": "id",
127 | "typePropertyKind": "TYPE_EXPRESSION",
128 | "type": "string",
129 | "required": true,
130 | "description": "account identifier",
131 | "minLength": 1,
132 | "maxLength": 10,
133 | "key": "id"
134 | }
135 | ]
136 | },
137 | {
138 | "body": [
139 | {
140 | "name": "application/x-www-form-urlencoded",
141 | "displayName": "application/x-www-form-urlencoded",
142 | "typePropertyKind": "TYPE_EXPRESSION",
143 | "type": "object",
144 | "properties": [
145 | {
146 | "name": "name",
147 | "displayName": "name",
148 | "typePropertyKind": "TYPE_EXPRESSION",
149 | "type": "string",
150 | "examples": [
151 | {
152 | "value": "Naruto Uzumaki",
153 | "strict": true,
154 | "name": "example1",
155 | "structuredValue": "Naruto Uzumaki",
156 | "displayName": "example1"
157 | },
158 | {
159 | "value": "Kevin Renskers",
160 | "strict": true,
161 | "name": "example2",
162 | "structuredValue": "Kevin Renskers",
163 | "displayName": "example2"
164 | }
165 | ],
166 | "required": true,
167 | "description": "name on account",
168 | "key": "name"
169 | },
170 | {
171 | "name": "gender",
172 | "displayName": "gender",
173 | "typePropertyKind": "TYPE_EXPRESSION",
174 | "type": "string",
175 | "required": true,
176 | "enum": [
177 | "male",
178 | "female"
179 | ],
180 | "key": "gender"
181 | }
182 | ],
183 | "key": "application/x-www-form-urlencoded"
184 | }
185 | ],
186 | "method": "put",
187 | "allUriParameters": [
188 | {
189 | "name": "id",
190 | "displayName": "id",
191 | "typePropertyKind": "TYPE_EXPRESSION",
192 | "type": "string",
193 | "required": true,
194 | "description": "account identifier",
195 | "minLength": 1,
196 | "maxLength": 10,
197 | "key": "id"
198 | }
199 | ]
200 | },
201 | {
202 | "description": "Delete the account",
203 | "method": "delete",
204 | "allUriParameters": [
205 | {
206 | "name": "id",
207 | "displayName": "id",
208 | "typePropertyKind": "TYPE_EXPRESSION",
209 | "type": "string",
210 | "required": true,
211 | "description": "account identifier",
212 | "minLength": 1,
213 | "maxLength": 10,
214 | "key": "id"
215 | }
216 | ]
217 | }
218 | ],
219 | "uriParameters": [
220 | {
221 | "name": "id",
222 | "displayName": "id",
223 | "typePropertyKind": "TYPE_EXPRESSION",
224 | "type": "string",
225 | "required": true,
226 | "description": "account identifier",
227 | "minLength": 1,
228 | "maxLength": 10,
229 | "key": "id"
230 | }
231 | ],
232 | "relativeUri": "/{id}",
233 | "displayName": "/{id}",
234 | "resources": [
235 | {
236 | "methods": [
237 | {
238 | "responses": [
239 | {
240 | "code": "401",
241 | "headers": [
242 | {
243 | "name": "WWW-Authenticate",
244 | "displayName": "WWW-Authenticate",
245 | "typePropertyKind": "TYPE_EXPRESSION",
246 | "type": "string",
247 | "required": true,
248 | "description": "user was not authorized",
249 | "examples": [
250 | {
251 | "value": "WWW-Authenticate: Basic realm=\"raml2html\"\n",
252 | "strict": true,
253 | "name": null,
254 | "structuredValue": "WWW-Authenticate: Basic realm=\"raml2html\"\n"
255 | }
256 | ],
257 | "key": "WWW-Authenticate"
258 | }
259 | ],
260 | "description": "Not authorized",
261 | "key": "401"
262 | }
263 | ],
264 | "method": "get",
265 | "allUriParameters": [
266 | {
267 | "name": "id",
268 | "displayName": "id",
269 | "typePropertyKind": "TYPE_EXPRESSION",
270 | "type": "string",
271 | "required": true,
272 | "description": "account identifier",
273 | "minLength": 1,
274 | "maxLength": 10,
275 | "key": "id"
276 | },
277 | {
278 | "name": "id",
279 | "displayName": "id",
280 | "typePropertyKind": "TYPE_EXPRESSION",
281 | "type": "string",
282 | "required": true,
283 | "description": "sub account identifier",
284 | "minLength": 1,
285 | "maxLength": 10,
286 | "key": "id"
287 | }
288 | ]
289 | }
290 | ],
291 | "uriParameters": [
292 | {
293 | "name": "id",
294 | "displayName": "id",
295 | "typePropertyKind": "TYPE_EXPRESSION",
296 | "type": "string",
297 | "required": true,
298 | "description": "sub account identifier",
299 | "minLength": 1,
300 | "maxLength": 10,
301 | "key": "id"
302 | }
303 | ],
304 | "relativeUri": "/{id}",
305 | "displayName": "/{id}",
306 | "relativeUriPathSegments": [
307 | "{id}"
308 | ],
309 | "absoluteUri": "/account/{id}/{id}",
310 | "parentUrl": "/account/{id}",
311 | "uniqueId": "account__id___id_",
312 | "allUriParameters": [
313 | {
314 | "name": "id",
315 | "displayName": "id",
316 | "typePropertyKind": "TYPE_EXPRESSION",
317 | "type": "string",
318 | "required": true,
319 | "description": "account identifier",
320 | "minLength": 1,
321 | "maxLength": 10,
322 | "key": "id"
323 | },
324 | {
325 | "name": "id",
326 | "displayName": "id",
327 | "typePropertyKind": "TYPE_EXPRESSION",
328 | "type": "string",
329 | "required": true,
330 | "description": "sub account identifier",
331 | "minLength": 1,
332 | "maxLength": 10,
333 | "key": "id"
334 | }
335 | ]
336 | }
337 | ],
338 | "relativeUriPathSegments": [
339 | "{id}"
340 | ],
341 | "absoluteUri": "/account/{id}",
342 | "parentUrl": "/account",
343 | "uniqueId": "account__id_",
344 | "allUriParameters": [
345 | {
346 | "name": "id",
347 | "displayName": "id",
348 | "typePropertyKind": "TYPE_EXPRESSION",
349 | "type": "string",
350 | "required": true,
351 | "description": "account identifier",
352 | "minLength": 1,
353 | "maxLength": 10,
354 | "key": "id"
355 | }
356 | ]
357 | }
358 | ],
359 | "relativeUriPathSegments": [
360 | "account"
361 | ],
362 | "absoluteUri": "/account",
363 | "parentUrl": "",
364 | "uniqueId": "account",
365 | "allUriParameters": []
366 | }
367 | ]
368 | }
--------------------------------------------------------------------------------
/test/inheritance.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Inheritance Test",
3 | "resources": [
4 | {
5 | "methods": [
6 | {
7 | "body": [
8 | {
9 | "name": "PasswordProtectedAccount",
10 | "displayName": "PasswordProtectedAccount",
11 | "typePropertyKind": "TYPE_EXPRESSION",
12 | "type": "object",
13 | "properties": [
14 | {
15 | "type": "string",
16 | "name": "name",
17 | "displayName": "name",
18 | "typePropertyKind": "TYPE_EXPRESSION",
19 | "required": true,
20 | "key": "name"
21 | },
22 | {
23 | "type": "string",
24 | "name": "email",
25 | "displayName": "email",
26 | "typePropertyKind": "TYPE_EXPRESSION",
27 | "pattern": "^.+@.+\\..+$",
28 | "rawType": {
29 | "name": "Email",
30 | "displayName": "Email",
31 | "typePropertyKind": "TYPE_EXPRESSION",
32 | "type": [
33 | "string"
34 | ],
35 | "pattern": "^.+@.+\\..+$"
36 | },
37 | "originalType": "Email",
38 | "required": true,
39 | "key": "email"
40 | },
41 | {
42 | "type": "string",
43 | "name": "gender",
44 | "displayName": "gender",
45 | "typePropertyKind": "TYPE_EXPRESSION",
46 | "required": false,
47 | "enum": [
48 | "male",
49 | "female"
50 | ],
51 | "key": "gender"
52 | },
53 | {
54 | "type": "string",
55 | "name": "password",
56 | "displayName": "password",
57 | "typePropertyKind": "TYPE_EXPRESSION",
58 | "required": true,
59 | "key": "password"
60 | }
61 | ],
62 | "description": "An account which is password protected.",
63 | "additionalProperties": true,
64 | "rawType": {
65 | "name": "PasswordProtectedAccount",
66 | "displayName": "PasswordProtectedAccount",
67 | "typePropertyKind": "TYPE_EXPRESSION",
68 | "type": [
69 | "Account"
70 | ],
71 | "description": "An account which is password protected.",
72 | "properties": [
73 | {
74 | "name": "password",
75 | "displayName": "password",
76 | "typePropertyKind": "TYPE_EXPRESSION",
77 | "type": [
78 | "string"
79 | ],
80 | "required": true,
81 | "key": "password"
82 | }
83 | ]
84 | },
85 | "originalType": "Account",
86 | "key": "application/json"
87 | }
88 | ],
89 | "description": "Creates a new account\n",
90 | "method": "post",
91 | "allUriParameters": []
92 | },
93 | {
94 | "body": [
95 | {
96 | "name": "BannableAccount",
97 | "displayName": "BannableAccount",
98 | "typePropertyKind": "TYPE_EXPRESSION",
99 | "type": "object",
100 | "properties": [
101 | {
102 | "type": "string",
103 | "name": "name",
104 | "displayName": "name",
105 | "typePropertyKind": "TYPE_EXPRESSION",
106 | "required": true,
107 | "key": "name"
108 | },
109 | {
110 | "type": "string",
111 | "name": "email",
112 | "displayName": "email",
113 | "typePropertyKind": "TYPE_EXPRESSION",
114 | "pattern": "^.+@.+\\..+$",
115 | "rawType": {
116 | "name": "Email",
117 | "displayName": "Email",
118 | "typePropertyKind": "TYPE_EXPRESSION",
119 | "type": [
120 | "string"
121 | ],
122 | "pattern": "^.+@.+\\..+$"
123 | },
124 | "originalType": "Email",
125 | "required": true,
126 | "key": "email"
127 | },
128 | {
129 | "type": "string",
130 | "name": "gender",
131 | "displayName": "gender",
132 | "typePropertyKind": "TYPE_EXPRESSION",
133 | "required": false,
134 | "enum": [
135 | "male",
136 | "female"
137 | ],
138 | "key": "gender"
139 | },
140 | {
141 | "type": "string",
142 | "name": "password",
143 | "displayName": "password",
144 | "typePropertyKind": "TYPE_EXPRESSION",
145 | "required": true,
146 | "key": "password"
147 | },
148 | {
149 | "type": "boolean",
150 | "name": "banned",
151 | "displayName": "banned",
152 | "typePropertyKind": "TYPE_EXPRESSION",
153 | "required": true,
154 | "key": "banned"
155 | }
156 | ],
157 | "description": "An account which is password protected.",
158 | "additionalProperties": true,
159 | "rawType": {
160 | "name": "BannableAccount",
161 | "displayName": "BannableAccount",
162 | "typePropertyKind": "TYPE_EXPRESSION",
163 | "type": [
164 | "PasswordProtectedAccount"
165 | ],
166 | "properties": [
167 | {
168 | "name": "banned",
169 | "displayName": "banned",
170 | "typePropertyKind": "TYPE_EXPRESSION",
171 | "type": [
172 | "boolean"
173 | ],
174 | "required": true,
175 | "key": "banned"
176 | }
177 | ]
178 | },
179 | "originalType": "PasswordProtectedAccount",
180 | "key": "application/json"
181 | }
182 | ],
183 | "method": "put",
184 | "allUriParameters": []
185 | }
186 | ],
187 | "relativeUri": "/account",
188 | "displayName": "ACCOUNT",
189 | "relativeUriPathSegments": [
190 | "account"
191 | ],
192 | "absoluteUri": "/account",
193 | "parentUrl": "",
194 | "uniqueId": "account",
195 | "allUriParameters": []
196 | }
197 | ],
198 | "types": {
199 | "Email": {
200 | "type": "string",
201 | "name": "Email",
202 | "displayName": "Email",
203 | "typePropertyKind": "TYPE_EXPRESSION",
204 | "pattern": "^.+@.+\\..+$",
205 | "rawType": {
206 | "name": "Email",
207 | "displayName": "Email",
208 | "typePropertyKind": "TYPE_EXPRESSION",
209 | "type": [
210 | "string"
211 | ],
212 | "pattern": "^.+@.+\\..+$"
213 | }
214 | },
215 | "Account": {
216 | "type": "object",
217 | "properties": {
218 | "name": {
219 | "type": "string",
220 | "name": "name",
221 | "displayName": "name",
222 | "typePropertyKind": "TYPE_EXPRESSION",
223 | "required": true
224 | },
225 | "email": {
226 | "type": "string",
227 | "name": "email",
228 | "displayName": "email",
229 | "typePropertyKind": "TYPE_EXPRESSION",
230 | "pattern": "^.+@.+\\..+$",
231 | "rawType": {
232 | "name": "Email",
233 | "displayName": "Email",
234 | "typePropertyKind": "TYPE_EXPRESSION",
235 | "type": [
236 | "string"
237 | ],
238 | "pattern": "^.+@.+\\..+$"
239 | },
240 | "originalType": "Email",
241 | "required": true
242 | },
243 | "gender": {
244 | "type": "string",
245 | "name": "gender",
246 | "displayName": "gender",
247 | "typePropertyKind": "TYPE_EXPRESSION",
248 | "required": false,
249 | "enum": [
250 | "male",
251 | "female"
252 | ]
253 | }
254 | },
255 | "name": "Account",
256 | "displayName": "Account",
257 | "typePropertyKind": "TYPE_EXPRESSION",
258 | "description": "A basic account in the inheritance test",
259 | "additionalProperties": true,
260 | "rawType": {
261 | "name": "Account",
262 | "displayName": "Account",
263 | "typePropertyKind": "TYPE_EXPRESSION",
264 | "type": [
265 | "object"
266 | ],
267 | "description": "A basic account in the inheritance test",
268 | "properties": {
269 | "name": {
270 | "name": "name",
271 | "displayName": "name",
272 | "typePropertyKind": "TYPE_EXPRESSION",
273 | "type": [
274 | "string"
275 | ],
276 | "required": true
277 | },
278 | "email": {
279 | "name": "email",
280 | "displayName": "email",
281 | "typePropertyKind": "TYPE_EXPRESSION",
282 | "type": [
283 | "Email"
284 | ],
285 | "required": true
286 | },
287 | "gender": {
288 | "name": "gender",
289 | "displayName": "gender",
290 | "typePropertyKind": "TYPE_EXPRESSION",
291 | "type": [
292 | "string"
293 | ],
294 | "required": false,
295 | "enum": [
296 | "male",
297 | "female"
298 | ]
299 | }
300 | }
301 | }
302 | },
303 | "PasswordProtectedAccount": {
304 | "type": "object",
305 | "properties": {
306 | "name": {
307 | "type": "string",
308 | "name": "name",
309 | "displayName": "name",
310 | "typePropertyKind": "TYPE_EXPRESSION",
311 | "required": true,
312 | "key": "name"
313 | },
314 | "email": {
315 | "type": "string",
316 | "name": "email",
317 | "displayName": "email",
318 | "typePropertyKind": "TYPE_EXPRESSION",
319 | "pattern": "^.+@.+\\..+$",
320 | "rawType": {
321 | "name": "Email",
322 | "displayName": "Email",
323 | "typePropertyKind": "TYPE_EXPRESSION",
324 | "type": [
325 | "string"
326 | ],
327 | "pattern": "^.+@.+\\..+$"
328 | },
329 | "originalType": "Email",
330 | "required": true,
331 | "key": "email"
332 | },
333 | "gender": {
334 | "type": "string",
335 | "name": "gender",
336 | "displayName": "gender",
337 | "typePropertyKind": "TYPE_EXPRESSION",
338 | "required": false,
339 | "enum": [
340 | "male",
341 | "female"
342 | ],
343 | "key": "gender"
344 | },
345 | "password": {
346 | "type": "string",
347 | "name": "password",
348 | "displayName": "password",
349 | "typePropertyKind": "TYPE_EXPRESSION",
350 | "required": true,
351 | "key": "password"
352 | }
353 | },
354 | "name": "PasswordProtectedAccount",
355 | "displayName": "PasswordProtectedAccount",
356 | "typePropertyKind": "TYPE_EXPRESSION",
357 | "description": "An account which is password protected.",
358 | "additionalProperties": true,
359 | "rawType": {
360 | "name": "PasswordProtectedAccount",
361 | "displayName": "PasswordProtectedAccount",
362 | "typePropertyKind": "TYPE_EXPRESSION",
363 | "type": [
364 | "Account"
365 | ],
366 | "description": "An account which is password protected.",
367 | "properties": [
368 | {
369 | "name": "password",
370 | "displayName": "password",
371 | "typePropertyKind": "TYPE_EXPRESSION",
372 | "type": [
373 | "string"
374 | ],
375 | "required": true,
376 | "key": "password"
377 | }
378 | ]
379 | },
380 | "originalType": "Account"
381 | },
382 | "BannableAccount": {
383 | "type": "object",
384 | "properties": {
385 | "name": {
386 | "type": "string",
387 | "name": "name",
388 | "displayName": "name",
389 | "typePropertyKind": "TYPE_EXPRESSION",
390 | "required": true,
391 | "key": "name"
392 | },
393 | "email": {
394 | "type": "string",
395 | "name": "email",
396 | "displayName": "email",
397 | "typePropertyKind": "TYPE_EXPRESSION",
398 | "pattern": "^.+@.+\\..+$",
399 | "rawType": {
400 | "name": "Email",
401 | "displayName": "Email",
402 | "typePropertyKind": "TYPE_EXPRESSION",
403 | "type": [
404 | "string"
405 | ],
406 | "pattern": "^.+@.+\\..+$"
407 | },
408 | "originalType": "Email",
409 | "required": true,
410 | "key": "email"
411 | },
412 | "gender": {
413 | "type": "string",
414 | "name": "gender",
415 | "displayName": "gender",
416 | "typePropertyKind": "TYPE_EXPRESSION",
417 | "required": false,
418 | "enum": [
419 | "male",
420 | "female"
421 | ],
422 | "key": "gender"
423 | },
424 | "password": {
425 | "type": "string",
426 | "name": "password",
427 | "displayName": "password",
428 | "typePropertyKind": "TYPE_EXPRESSION",
429 | "required": true,
430 | "key": "password"
431 | },
432 | "banned": {
433 | "type": "boolean",
434 | "name": "banned",
435 | "displayName": "banned",
436 | "typePropertyKind": "TYPE_EXPRESSION",
437 | "required": true,
438 | "key": "banned"
439 | }
440 | },
441 | "name": "BannableAccount",
442 | "displayName": "BannableAccount",
443 | "typePropertyKind": "TYPE_EXPRESSION",
444 | "description": "An account which is password protected.",
445 | "additionalProperties": true,
446 | "rawType": {
447 | "name": "BannableAccount",
448 | "displayName": "BannableAccount",
449 | "typePropertyKind": "TYPE_EXPRESSION",
450 | "type": [
451 | "PasswordProtectedAccount"
452 | ],
453 | "properties": [
454 | {
455 | "name": "banned",
456 | "displayName": "banned",
457 | "typePropertyKind": "TYPE_EXPRESSION",
458 | "type": [
459 | "boolean"
460 | ],
461 | "required": true,
462 | "key": "banned"
463 | }
464 | ]
465 | },
466 | "originalType": "PasswordProtectedAccount"
467 | }
468 | }
469 | }
--------------------------------------------------------------------------------