├── index.js
├── .eslintignore
├── .gitignore
├── _doc.scss
├── lib
├── nodejs
│ ├── swagger-to-html
│ │ ├── __tests__
│ │ │ ├── templates
│ │ │ │ ├── body.ejs
│ │ │ │ ├── head.ejs
│ │ │ │ ├── includes
│ │ │ │ │ ├── description.ejs
│ │ │ │ │ └── subtitle.ejs
│ │ │ │ ├── head-include-module.ejs
│ │ │ │ └── head-include-module-doesnt-exist.ejs
│ │ │ ├── index.test.js
│ │ │ ├── _petstore.yaml
│ │ │ └── core.test.js
│ │ ├── helpers
│ │ │ ├── parser
│ │ │ │ ├── index.js
│ │ │ │ ├── lib
│ │ │ │ │ ├── init.js
│ │ │ │ │ ├── processItems
│ │ │ │ │ │ ├── default.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── enum.js
│ │ │ │ │ │ ├── array.js
│ │ │ │ │ │ └── object.js
│ │ │ │ │ ├── parseBody.js
│ │ │ │ │ ├── parseResponse.js
│ │ │ │ │ ├── updateResult.js
│ │ │ │ │ └── traverse.js
│ │ │ │ └── __tests__
│ │ │ │ │ ├── index.test.js
│ │ │ │ │ └── lib
│ │ │ │ │ ├── processItems
│ │ │ │ │ ├── index.test.js
│ │ │ │ │ ├── default.test.js
│ │ │ │ │ ├── enum.test.js
│ │ │ │ │ ├── array.test.js
│ │ │ │ │ └── object.test.js
│ │ │ │ │ ├── init.test.js
│ │ │ │ │ ├── parseBody.test.js
│ │ │ │ │ ├── parseResponse.test.js
│ │ │ │ │ ├── updateResult.test.js
│ │ │ │ │ └── traverse.test.js
│ │ │ ├── index.js
│ │ │ └── utils.js
│ │ ├── modules
│ │ │ ├── templates
│ │ │ │ ├── operations.ejs
│ │ │ │ ├── responseSample.ejs
│ │ │ │ ├── requestSample.ejs
│ │ │ │ ├── head.ejs
│ │ │ │ ├── requestContent.ejs
│ │ │ │ ├── security.ejs
│ │ │ │ ├── securityRequirement.ejs
│ │ │ │ ├── responses.ejs
│ │ │ │ ├── response.ejs
│ │ │ │ ├── operation.ejs
│ │ │ │ ├── formData.ejs
│ │ │ │ ├── emptyResponse.ejs
│ │ │ │ ├── request.ejs
│ │ │ │ ├── header.ejs
│ │ │ │ ├── responseBody.ejs
│ │ │ │ ├── requestParams.ejs
│ │ │ │ ├── requestBody.ejs
│ │ │ │ └── securityDefinition.ejs
│ │ │ ├── controllers
│ │ │ │ ├── security.js
│ │ │ │ ├── responses.js
│ │ │ │ ├── requestBody.js
│ │ │ │ ├── operation.js
│ │ │ │ ├── __tests__
│ │ │ │ │ ├── responses.test.js
│ │ │ │ │ ├── security.test.js
│ │ │ │ │ ├── index.test.js
│ │ │ │ │ ├── requestBody.test.js
│ │ │ │ │ ├── response.test.js
│ │ │ │ │ ├── responseSample.test.js
│ │ │ │ │ ├── operation.test.js
│ │ │ │ │ ├── operations.test.js
│ │ │ │ │ ├── request.test.js
│ │ │ │ │ └── requestSample.test.js
│ │ │ │ ├── response.js
│ │ │ │ ├── responseSample.js
│ │ │ │ ├── index.js
│ │ │ │ ├── request.js
│ │ │ │ ├── operations.js
│ │ │ │ └── requestSample.js
│ │ │ └── index.js
│ │ └── index.js
│ ├── .eslintrc
│ ├── search
│ │ ├── child.js
│ │ ├── child-on-message.js
│ │ ├── __tests__
│ │ │ ├── mocks.js
│ │ │ ├── child-on-message.test.js
│ │ │ ├── build.test.js
│ │ │ ├── searcher.test.js
│ │ │ └── generator.test.js
│ │ ├── searcher.js
│ │ ├── generator.js
│ │ └── build.js
│ ├── swagger
│ │ ├── decorators
│ │ │ ├── index.js
│ │ │ ├── __tests__
│ │ │ │ ├── index.test.js
│ │ │ │ └── host.test.js
│ │ │ ├── docExclude
│ │ │ │ ├── filters
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── paths.js
│ │ │ │ │ ├── __tests__
│ │ │ │ │ │ ├── index.test.js
│ │ │ │ │ │ ├── paths.test.js
│ │ │ │ │ │ ├── operations.test.js
│ │ │ │ │ │ ├── parameters.test.js
│ │ │ │ │ │ └── security.test.js
│ │ │ │ │ ├── operations.js
│ │ │ │ │ ├── parameters.js
│ │ │ │ │ └── security.js
│ │ │ │ ├── index.js
│ │ │ │ ├── utils.js
│ │ │ │ └── __tests__
│ │ │ │ │ └── index.test.js
│ │ │ └── host.js
│ │ ├── index.js
│ │ └── __tests__
│ │ │ ├── index.test.js
│ │ │ ├── swagger-unmocked.test.js
│ │ │ └── swagger-mocks.js
│ ├── swagger-ui
│ │ ├── parse-schema-file-error.js
│ │ ├── partials
│ │ │ ├── v2
│ │ │ │ ├── libs.ejs
│ │ │ │ └── snippet.ejs
│ │ │ └── v3
│ │ │ │ ├── snippet.ejs
│ │ │ │ └── libs.ejs
│ │ ├── parse-schema-file.js
│ │ └── __tests__
│ │ │ ├── mocks.js
│ │ │ └── parse-schema-file.test.js
│ ├── support
│ │ ├── index.js
│ │ └── __tests__
│ │ │ └── index.test.js
│ ├── hexo-util.js
│ ├── __tests__
│ │ ├── hexo-util.test.js
│ │ └── swagger-store.test.js
│ ├── project-partial
│ │ ├── index.js
│ │ └── __tests__
│ │ │ └── index.test.js
│ └── swagger-store.js
└── browser
│ ├── polyfills.js
│ ├── search
│ ├── actions.js
│ ├── load.js
│ ├── __tests__
│ │ ├── load.test.js
│ │ ├── containers.test.jsx
│ │ └── components.test.jsx
│ ├── containers.jsx
│ └── components.jsx
│ ├── .eslintrc
│ ├── support
│ ├── containers.jsx
│ ├── components.jsx
│ └── __tests__
│ │ └── containers.test.jsx
│ ├── swagger-to-html.js
│ ├── index.js
│ ├── __tests__
│ └── utils.test.js
│ ├── utils.js
│ └── navigation
│ └── __tests__
│ └── components.test.js
├── mockup.png
├── MAINTAINERS
├── layout
├── _partial
│ ├── navigation.ejs
│ └── google_analytics.ejs
├── page.ejs
└── layout.ejs
├── source
├── fonts
│ ├── DressCodeIcons.eot
│ ├── DressCodeIcons.ttf
│ └── DressCodeIcons.woff
└── style
│ ├── _doc
│ ├── mixins.scss
│ ├── typography.scss
│ ├── support.scss
│ ├── index.scss
│ ├── content.scss
│ ├── search.scss
│ ├── layout.scss
│ ├── vars.scss
│ └── swagger-to-html.scss
│ └── _swagger
│ ├── swagger-ui-v3.scss
│ └── swagger-ui-v2.scss
├── jest.setup.js
├── plugins
├── support.js
├── favicon.js
├── project-partial.js
├── swagger-routes.js
├── swagger-ui.js
├── react-initial-state.js
├── search.js
├── react.js
└── swagger-to-html.js
├── ISSUE_TEMPLATE.md
├── .npmignore
├── .editorconfig
├── scripts
└── all.js
├── .zappr.yaml
├── jest.json
├── webpack.config.js
├── SECURITY.md
├── zappr.md
├── .eslintrc
├── banner.js
├── .travis.yml
├── CODE_OF_CONDUCT.md
└── package.json
/index.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/node_modules/**
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | target
3 |
--------------------------------------------------------------------------------
/_doc.scss:
--------------------------------------------------------------------------------
1 | @import "source/style/_doc/index"
2 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/templates/body.ejs:
--------------------------------------------------------------------------------
1 | <%= text %>
2 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/templates/head.ejs:
--------------------------------------------------------------------------------
1 | <%= title %>
2 |
--------------------------------------------------------------------------------
/mockup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando-incubator/hexo-theme-doc/HEAD/mockup.png
--------------------------------------------------------------------------------
/lib/nodejs/.eslintrc:
--------------------------------------------------------------------------------
1 | env:
2 | node: true
3 | parserOptions:
4 | ecmaVersion: 2017
5 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/templates/includes/description.ejs:
--------------------------------------------------------------------------------
1 | <%= description %>
2 |
--------------------------------------------------------------------------------
/MAINTAINERS:
--------------------------------------------------------------------------------
1 | Ruben Barilani
2 | Bhaskar Melkani
3 |
--------------------------------------------------------------------------------
/layout/_partial/navigation.ejs:
--------------------------------------------------------------------------------
1 | <%- react_component('Navigation', initial_state) %>
2 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/templates/head-include-module.ejs:
--------------------------------------------------------------------------------
1 | <%= title %>
2 |
3 | <%- include_module('subtitle') %>
4 |
--------------------------------------------------------------------------------
/source/fonts/DressCodeIcons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando-incubator/hexo-theme-doc/HEAD/source/fonts/DressCodeIcons.eot
--------------------------------------------------------------------------------
/source/fonts/DressCodeIcons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando-incubator/hexo-theme-doc/HEAD/source/fonts/DressCodeIcons.ttf
--------------------------------------------------------------------------------
/source/fonts/DressCodeIcons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zalando-incubator/hexo-theme-doc/HEAD/source/fonts/DressCodeIcons.woff
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/templates/head-include-module-doesnt-exist.ejs:
--------------------------------------------------------------------------------
1 | <%= title %>
2 |
3 | <%- include_module('doesnt-exist') %>
4 |
--------------------------------------------------------------------------------
/jest.setup.js:
--------------------------------------------------------------------------------
1 | const { configure } = require('enzyme');
2 | const Adapter = require('enzyme-adapter-react-16');
3 |
4 | configure({ adapter: new Adapter() });
5 |
--------------------------------------------------------------------------------
/lib/browser/polyfills.js:
--------------------------------------------------------------------------------
1 | require('whatwg-fetch');
2 | const Promise = require('promise-polyfill');
3 | if (window && !window.Promise) { window.Promise = Promise; }
4 |
--------------------------------------------------------------------------------
/lib/nodejs/search/child.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const childOnMessage = require('./child-on-message');
4 |
5 | process.on('message', childOnMessage({process}));
6 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/templates/includes/subtitle.ejs:
--------------------------------------------------------------------------------
1 | <%= subtitle %>
2 |
3 | <%= include_module('description', { description: 'description' }) %>
4 |
--------------------------------------------------------------------------------
/plugins/support.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {filter} = require('../lib/nodejs/support');
4 |
5 | module.exports = ({hexo}) => {
6 | hexo.extend.filter.register('template_locals', filter);
7 | };
8 |
--------------------------------------------------------------------------------
/source/style/_doc/mixins.scss:
--------------------------------------------------------------------------------
1 | // formatting
2 | // ----------
3 | @mixin doc-inline-code {
4 | background: $doc-color-lighter;
5 | font-size: 90%;
6 | padding: 1px 5px;
7 | border-radius: 2px;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const docExclude = require('./docExclude');
4 | const host = require('./host');
5 |
6 | module.exports = {
7 | docExclude,
8 | host
9 | };
10 |
--------------------------------------------------------------------------------
/lib/browser/search/actions.js:
--------------------------------------------------------------------------------
1 | const SHOW_SEARCH_RESULTS = 'SHOW_SEARCH_RESULTS';
2 | const HIDE_SEARCH_RESULTS = 'HIDE_SEARCH_RESULTS';
3 |
4 | module.exports = {
5 | SHOW_SEARCH_RESULTS,
6 | HIDE_SEARCH_RESULTS
7 | };
8 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const Swagger = require('./swagger');
5 | const decorators = require('./decorators');
6 |
7 |
8 | module.exports = {
9 | Swagger,
10 | decorators
11 | };
12 |
--------------------------------------------------------------------------------
/plugins/favicon.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('../lib/nodejs/hexo-util');
4 |
5 | module.exports = ({hexo}) => {
6 | const {themeConfig} = util({hexo});
7 |
8 | themeConfig({ favicon: '/favicon.ico' });
9 | };
10 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {parseBody} = require('./lib/parseBody.js');
4 | const {parseResponse} = require('./lib/parseResponse.js');
5 |
6 | module.exports = {
7 | parseBody,
8 | parseResponse
9 | };
10 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/init.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const {traverse} = require('./traverse');
5 |
6 | function init ({object}){
7 | return traverse({object, key: '', init: true});
8 | }
9 |
10 | module.exports = {
11 | init
12 | };
13 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Expected Behavior
2 |
3 |
4 | ## Actual Behavior
5 |
6 |
7 | ## Steps to Reproduce the Problem
8 |
9 | 1.
10 | 2.
11 | 3.
12 |
13 | ## Specifications
14 |
15 | - NodeJS Version:
16 | - NPM Version:
17 | - OS:
18 | - Hexo Version:
19 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/operations.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <% operations.forEach((operation) => {%>
4 | <%- include_module('operation', { operation, baseUrl, globalSecurity }) %>
5 | <% }) %>
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/responseSample.ejs:
--------------------------------------------------------------------------------
1 | <% if(sample){ %>
2 |
3 | <%- sample %>
4 |
5 |
6 | <% } %>
7 |
--------------------------------------------------------------------------------
/source/style/_doc/typography.scss:
--------------------------------------------------------------------------------
1 | a { @include dc-link }
2 | p { @extend .dc-p }
3 |
4 | h1 { @include dc-h1 }
5 | h2 { @include dc-h2 }
6 | h3 { @include dc-h3 }
7 | h4 { @include dc-h4 }
8 |
9 | hr {
10 | @include dc-divider;
11 | @include dc-divider--secondary;
12 | }
13 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/security.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const security = (ctx) => {
5 | const securityDefinitions = ctx.securityDefinitions;
6 |
7 | return {
8 | securityDefinitions
9 | };
10 | };
11 |
12 |
13 | module.exports = security;
14 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/requestSample.ejs:
--------------------------------------------------------------------------------
1 | <% if(curlString){ %>
2 |
3 | <%- curlString %>
4 |
5 |
6 | <% } %>
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # dotfiles
2 | .*
3 |
4 | # tests
5 | *__tests__
6 |
7 | # tools
8 | banner.js
9 | webpack.config.js
10 | jest*
11 | zappr.*
12 | .travis*
13 |
14 | # misc
15 | mockup*
16 | CONTRIBUTING.md
17 | ISSUE_TEMPLATE.md
18 | CODE_OF_CONDUCT.md
19 | *.log
20 | target
21 | public
22 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/responses.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const responses = (ctx) => {
5 | const operation = ctx.operation;
6 | const responses = operation['responses'];
7 |
8 | return {
9 | responses
10 | };
11 | };
12 |
13 |
14 | module.exports = responses;
15 |
--------------------------------------------------------------------------------
/source/style/_doc/support.scss:
--------------------------------------------------------------------------------
1 | .doc-support-footer {
2 | margin-top: 3.8rem;
3 | border-top: 2px solid $doc-support-footer-border-color;
4 | padding: 2.4rem 0;
5 |
6 | &__text {
7 | color: $doc-support-footer-color;
8 | }
9 |
10 | &__link {
11 | font-weight: 500;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { parseResponse, parseBody } = require('./parser');
5 | const { toSlug , deepMerge, highlight } = require('./utils');
6 |
7 | module.exports = {
8 | parseResponse,
9 | parseBody,
10 | toSlug,
11 | deepMerge,
12 | highlight
13 | };
14 |
15 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/processItems/default.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {updateResult} = require('../updateResult');
4 |
5 | const processDefault = ({object, key, isRequired, result}) => {
6 | updateResult({object, key, isRequired, result});
7 | return result;
8 | };
9 |
10 | module.exports = processDefault;
11 |
--------------------------------------------------------------------------------
/lib/browser/.eslintrc:
--------------------------------------------------------------------------------
1 | plugins:
2 | - react
3 | env:
4 | browser: true
5 | parserOptions:
6 | sourceType: module
7 | ecmaFeatures:
8 | experimentalObjectRestSpread: true
9 | jsx: true
10 | globals:
11 | module: true
12 | $: true
13 |
14 | rules:
15 | # React
16 | react/jsx-uses-react: 1
17 | react/jsx-uses-vars: 1
18 |
--------------------------------------------------------------------------------
/layout/page.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%- page.content %>
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/parseBody.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {init} = require('./init');
4 |
5 | const parseBody = (body) => {
6 |
7 | if (!body || !body.schema){
8 | return {};
9 | }
10 |
11 | const schema = body.schema;
12 |
13 | return init({ object: schema });
14 | };
15 |
16 | module.exports = {
17 | parseBody
18 | };
19 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('swagger.index', () => {
4 | it('should expose swagger and decorators', () => {
5 |
6 | const swagger = require('../index');
7 |
8 | expect(Object.keys(swagger).length).toBe(2);
9 | expect(swagger.Swagger).toBeDefined();
10 | expect(swagger.decorators).toBeDefined();
11 | });
12 |
13 | });
14 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/processItems/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const processEnum = require('./enum');
4 | const processArray = require('./array');
5 | const processObject = require('./object');
6 | const processDefault = require('./default');
7 |
8 | module.exports = {
9 | processEnum,
10 | processArray,
11 | processObject,
12 | processDefault
13 | };
14 |
--------------------------------------------------------------------------------
/plugins/project-partial.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {createHelper} = require('../lib/nodejs/project-partial');
4 |
5 | module.exports = ({hexo}) => {
6 |
7 | hexo.extend.helper.register('project_partial', createHelper({
8 | theme_config: hexo.config.theme_config,
9 | source_dir: hexo.source_dir,
10 | render: hexo.render,
11 | log: hexo.log
12 | }));
13 |
14 | };
15 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/head.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= info.title %>
5 |
6 |
7 | Version: <%= info.version %>
8 |
9 |
10 |
11 | <%= info.description %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('decocators.index', () => {
4 |
5 | it('should expost decocators', () => {
6 | const decorators = require('../index');
7 |
8 | expect(Object.keys(decorators).length).toBe(2);
9 |
10 | expect(decorators.docExclude).toBeDefined();
11 | expect(decorators.host).toBeDefined();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/processItems/enum.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {updateResult} = require('../updateResult');
4 |
5 | const processEnum = ({object, key, isRequired, result}) => {
6 | object.type = 'enum';
7 | object.values = object.enum;
8 | updateResult({object, key, isRequired, result});
9 | return result;
10 | };
11 |
12 | module.exports = processEnum;
13 |
14 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/requestBody.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { parseBody } = require('../../helpers');
5 |
6 |
7 | const requestBody = ( ctx ) => {
8 | const body = [];
9 |
10 | ctx['body'].forEach((item) => {
11 | body.push(parseBody(item));
12 | });
13 |
14 | return {
15 | body
16 | };
17 | };
18 |
19 |
20 | module.exports = requestBody;
21 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const filterOperations = require('./operations');
4 | const filterParameters = require('./parameters');
5 | const filterPaths = require('./paths');
6 | const filterSecurity = require('./security');
7 |
8 |
9 | module.exports = {
10 | filterOperations,
11 | filterParameters,
12 | filterPaths,
13 | filterSecurity
14 | };
15 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # /.editorconfig
2 | # EditorConfig helps developers define and maintain consistent
3 | # coding styles between different editors and IDEs
4 | # editorconfig.org
5 |
6 | root = true
7 | [*]
8 |
9 | indent_style = space
10 | indent_size = 2
11 |
12 | # We recommend you to keep these unchanged
13 | end_of_line = lf
14 | charset = utf-8
15 | trim_trailing_whitespace = true
16 | insert_final_newline = true
17 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-ui/parse-schema-file-error.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function ParseSchemaFileError ({message, filePath, referencePath}) {
4 | Error.captureStackTrace(this, this.constructor);
5 | this.name = this.constructor.name;
6 | this.message = message;
7 | this.filePath = filePath;
8 | this.referencePath = referencePath;
9 | };
10 |
11 | require('util').inherits(module.exports, Error);
12 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/operation.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { deepMerge } = require('../../helpers');
5 |
6 | const operation = (ctx) => {
7 | if (ctx.operation.security){
8 | deepMerge(ctx.operation.security, ctx.globalSecurity);
9 | } else {
10 | ctx.operation.security = ctx.globalSecurity;
11 | }
12 |
13 | return ctx;
14 | };
15 |
16 |
17 | module.exports = operation;
18 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/requestContent.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Request Body
4 |
5 | <% if(request.formData.length){ %>
6 | <%- include_module('formData', { params: request.formData }) %>
7 | <% } %>
8 | <% if(request.body.length){ %>
9 | <%- include_module('requestBody', { body: request.body }) %>
10 | <% } %>
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('parser.index', () => {
4 | const parser = require('../index');
5 |
6 | test('should export getBody, getResponse and filterResponses', () => {
7 | const {parseBody, parseResponse} = parser;
8 | expect(Object.keys(parser).length).toBe(2);
9 | expect(parseBody).toBeInstanceOf(Function);
10 | expect(parseResponse).toBeInstanceOf(Function);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/lib/browser/support/containers.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const SupportFooterComponent = require('./components.jsx').SupportFooter;
3 |
4 | class SupportFooter extends React.Component {
5 | constructor (props) {
6 | super(props);
7 | }
8 |
9 | render () {
10 | if (!this.props.page.support) { return null; }
11 |
12 | return ();
13 | }
14 | }
15 |
16 | module.exports = {SupportFooter};
17 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/processItems/array.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {traverse} = require('../traverse');
4 | const {updateResult} = require('../updateResult');
5 |
6 | const processArray = ({object, key, isRequired, result}) => {
7 | updateResult({object, key, isRequired, result});
8 | const items = object.items;
9 | return traverse({
10 | object: items,
11 | key: key + '[]'
12 | });
13 | };
14 |
15 | module.exports = processArray;
16 |
--------------------------------------------------------------------------------
/lib/browser/support/components.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | function SupportFooter ({support}) {
4 | return (
5 |
9 | );
10 | }
11 |
12 |
13 | module.exports = {SupportFooter};
14 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/parseResponse.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {init} = require('./init');
4 |
5 | const parseResponse = (response) => {
6 |
7 | if (!response){
8 | return {};
9 | }
10 |
11 | const schema = response.schema;
12 |
13 | if (schema){
14 | return init({ object: schema });
15 | } else {
16 | response.__noData = true;
17 | return response;
18 | }
19 | };
20 |
21 | module.exports = {
22 | parseResponse
23 | };
24 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { filterSecurity, filterParameters, filterPaths, filterOperations} = require('./filters');
4 |
5 | const docExclude = (swagger) => {
6 |
7 | swagger = filterSecurity(swagger);
8 |
9 | swagger = filterParameters(swagger);
10 |
11 | swagger = filterPaths(swagger);
12 |
13 | swagger = filterOperations(swagger);
14 |
15 | return swagger;
16 | };
17 |
18 |
19 | module.exports = docExclude;
20 |
--------------------------------------------------------------------------------
/scripts/all.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global hexo */
4 |
5 | require('../plugins/favicon')({hexo});
6 | require('../plugins/project-partial')({hexo});
7 | require('../plugins/search')({hexo});
8 | require('../plugins/swagger-to-html')({hexo});
9 | require('../plugins/swagger-ui')({hexo});
10 | require('../plugins/react')({hexo});
11 | require('../plugins/react-initial-state')({hexo});
12 | require('../plugins/support')({hexo});
13 | require('../plugins/swagger-routes')({hexo});
14 |
--------------------------------------------------------------------------------
/source/style/_doc/index.scss:
--------------------------------------------------------------------------------
1 | @import "dress-code/dist/sass/dress-code";
2 |
3 | @import "./vars";
4 | @import "./mixins";
5 |
6 | // include dc-* selectors after variables to allow customization
7 | @include dc-everything;
8 |
9 | // core
10 | @import "./typography";
11 | @import "./layout";
12 | @import "./navigation";
13 | @import "./content";
14 | @import "./formatting";
15 |
16 | // components
17 | @import "./search";
18 | @import "./swagger-to-html";
19 | @import "./support";
20 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/responses.test.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | const responsesController = require('../responses');
5 |
6 | describe('controllers.resposnes', () => {
7 | it('should transform context as expected', () => {
8 | const ctx = {
9 | operation: {
10 | responses: 'foo'
11 | }
12 | };
13 |
14 | const { responses } = responsesController(ctx);
15 |
16 | expect(responses).toBe('foo');
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { isExclude } = require('../utils');
4 |
5 |
6 | const filterPaths = (swagger) => {
7 |
8 | swagger.paths && Object
9 | .keys(swagger.paths)
10 | .forEach((key) => {
11 | const path = swagger.paths[key];
12 | if (isExclude(path)){
13 | delete swagger.paths[key];
14 | }
15 | });
16 |
17 | return swagger;
18 | };
19 |
20 |
21 | module.exports = filterPaths;
22 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/security.ejs:
--------------------------------------------------------------------------------
1 | <% if(securityDefinitions){ %>
2 |
3 |
Security Definitions
4 |
5 | <% Object.keys(securityDefinitions).forEach((key) => {
6 | const definition = securityDefinitions[key];
7 | %>
8 | <%- include_module('securityDefinition', { key, definition }) %>
9 | <% }) %>
10 |
11 |
12 | <% } %>
13 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const modules = require('./modules');
4 | const {createTransformer} = require('./core');
5 |
6 | module.exports = ({hexo}) => createTransformer({
7 | input: (api) => {
8 | const swaggerStore = require('../swagger-store')({hexo});
9 | return swaggerStore
10 | .getSwagger(api, true)
11 | .then(({swagger}) => {
12 | return Promise.resolve(swagger.swaggerObject);
13 | });
14 | },
15 | modules
16 | });
17 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/processItems/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('swagger-parser.lib.processItems.index', () => {
4 | test('should export processors', () => {
5 |
6 | const index = require('../../../lib/processItems/index');
7 |
8 | expect(index.processEnum).toBeDefined();
9 | expect(index.processArray).toBeDefined();
10 | expect(index.processObject).toBeDefined();
11 | expect(index.processDefault).toBeDefined();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/lib/nodejs/search/child-on-message.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const build = require('./build');
4 | const createLogger = require('hexo-log');
5 |
6 | module.exports = ({process}) => {
7 |
8 | return function (message) {
9 | const pages = message.pages ? Array.from(message.pages.data) : [];
10 | const logger = createLogger({ debug: message.debug });
11 | const rootPath = message.rootPath || '';
12 | const result = build({pages, logger, rootPath});
13 | process.send(result);
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('docExclude.index', () => {
4 | it('should expose filters', () => {
5 | const filters = require('../index');
6 |
7 | expect(Object.keys(filters).length).toBe(4);
8 | expect(filters.filterOperations).toBeDefined();
9 | expect(filters.filterParameters).toBeDefined();
10 | expect(filters.filterPaths).toBeDefined();
11 | expect(filters.filterSecurity).toBeDefined();
12 | });
13 | });
14 |
15 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/host.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const docKey = 'x-doc';
4 | const hostKey = 'host';
5 |
6 | const host = (swagger) => {
7 |
8 | let host;
9 |
10 | if (swagger && swagger[docKey] && swagger[docKey][hostKey]){
11 | host = swagger[docKey][hostKey];
12 | delete swagger[docKey][hostKey];
13 | }
14 | // Add more ways to provide host and order them in priority.
15 |
16 | if (host){
17 | swagger.host = host;
18 | }
19 |
20 | return swagger;
21 | };
22 |
23 |
24 | module.exports = host;
25 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/securityRequirement.ejs:
--------------------------------------------------------------------------------
1 | <% securityRequirement.forEach((security) => {
2 | Object.keys(security).forEach((key) => {
3 | %>
4 |
5 | <% if(key && security[key].length){ %>
6 | <%- security[key].join(', ').replace(/,([^,]*)$/, ' and$1') %> <% if(security[key].length > 1){ %>scopes are<%}else{ %>scope is<% } %> required for <%- key %>.
7 | <% } %>
8 |
9 | <% })}) %>
10 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/response.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { parseResponse} = require('../../helpers');
5 |
6 |
7 | const response = (ctx) => {
8 | const responseCode = ctx['responseCode'];
9 | const originalResponse = ctx['response'];
10 | const responseData = parseResponse(originalResponse);
11 | const response = {
12 | description: originalResponse.description,
13 | data: responseData
14 | };
15 |
16 | return {
17 | responseCode,
18 | response
19 | };
20 | };
21 |
22 |
23 | module.exports = response;
24 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/responseSample.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const { highlight } = require('../../helpers');
3 |
4 |
5 | const responseSample = (ctx) => {
6 | let sample = ctx.sample;
7 | if (sample && sample['application/json']){
8 | sample = sample['application/json'];
9 | }
10 | if (sample){
11 | const code = JSON.stringify(sample, null, 2);
12 | sample = highlight({
13 | code,
14 | lang: 'json'
15 | });
16 | }
17 |
18 | return {
19 | sample
20 | };
21 | };
22 |
23 |
24 | module.exports = responseSample;
25 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/init.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockTraverse = jest.fn();
4 |
5 | jest.mock('../../lib/traverse', () => ({
6 | traverse: mockTraverse
7 | }));
8 |
9 | const {init} = require('../../lib/init');
10 |
11 | describe('swagger-parser.lib.init', () => {
12 | test('should init traverse', () => {
13 | const object = {foo: 'bar'};
14 |
15 | init({object});
16 |
17 | expect(mockTraverse).toHaveBeenCalled();
18 | expect(mockTraverse).toHaveBeenCalledWith({object, key: '', init: true});
19 | });
20 |
21 | });
22 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/security.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const securityController = require('../security');
4 |
5 | describe('security.controller', () => {
6 | test('should return the context as expected', () => {
7 | const ctx = {
8 | securityDefinitions: 'securityDefinitions'
9 | };
10 |
11 | const updatedCtx = securityController(ctx);
12 | const {securityDefinitions} = updatedCtx;
13 |
14 | expect(Object.keys(updatedCtx).length).toBe(1);
15 | expect(securityDefinitions).toBe('securityDefinitions');
16 |
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/__tests__/host.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | describe('decorators.host', () => {
5 | it('should update host', () => {
6 | const hostDecorator = require('../host');
7 |
8 | const swagger = {
9 | host: 'ORIGINAL_HOST',
10 | 'x-doc': {
11 | host: 'UPDATED_HOST'
12 | }
13 | };
14 |
15 | const updatedSwagger = hostDecorator(swagger);
16 |
17 | const expectedSwagger = {
18 | host: 'UPDATED_HOST',
19 | 'x-doc': {}
20 | };
21 |
22 | expect(updatedSwagger).toEqual(expectedSwagger);
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/.zappr.yaml:
--------------------------------------------------------------------------------
1 | approvals:
2 | minimum: 2 # PR needs at least 2 approval for compliant reasons
3 | pattern: "^(:\\+1:|👍|approved)$" # write a comment to the PR with "approved" or ":+1"
4 | veto:
5 | pattern: "^(:\\-1:|👎|rejected)$" # write a comment to the PR with "rejected" or ":-1"
6 | from:
7 | collaborators: true
8 | commit:
9 | message:
10 | patterns:
11 | # Follow MC commit conventions.
12 | # CONTRIBUTING.md#-git-commit-guidelines
13 | - "^(feat|fix|docs|style|refactor|perf|test|chore)(|\\([a-zA-Z0-9-._]+\\)):.{3,}"
14 |
15 | X-Zalando-Type: code
16 |
--------------------------------------------------------------------------------
/jest.json:
--------------------------------------------------------------------------------
1 | {
2 | "verbose": true,
3 | "clearMocks": true,
4 | "testRegex": "(/__tests__/.*\\.(test|spec))\\.(js|jsx)$",
5 | "setupFiles": [
6 | "raf/polyfill",
7 | "./jest.setup.js"
8 | ],
9 | "collectCoverageFrom": [
10 | "!**/__tests__/*.{js,jsx}",
11 | "lib/browser/**/*.{js,jsx}",
12 | "lib/nodejs/**/*.js",
13 | "!lib/browser/sidebar/index.js"
14 | ],
15 | "testResultsProcessor": "./node_modules/jest-junit",
16 | "coverageDirectory": "target/coverage",
17 | "coverageReporters": [
18 | "json",
19 | "lcov",
20 | "html",
21 | "cobertura"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const path = require('path');
3 |
4 | module.exports = {
5 | externals: {
6 | jquery: '$',
7 | lunr: true,
8 | },
9 | entry: {
10 | 'doc': './lib/browser/index.js',
11 | },
12 | output: {
13 | path: path.resolve(__dirname, 'source/script'),
14 | filename: '[name].js'
15 | },
16 | module: {
17 | loaders: [
18 | {
19 | test: /.jsx?$/,
20 | loader: 'babel-loader',
21 | exclude: /node_modules/,
22 | query: {
23 | presets: ['es2015', 'react']
24 | }
25 | }
26 | ]
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | We acknowledge that every line of code that we write may potentially contain security issues.
2 | We are trying to deal with it responsibly and provide patches as quickly as possible.
3 |
4 | We host our bug bounty program on HackerOne, it is currently private, therefore if you would like to report a vulnerability and get rewarded for it, please ask to join our program by filling this form:
5 |
6 | https://corporate.zalando.com/en/services-and-contact#security-form
7 |
8 | You can also send your report via this form if you do not want to join our bug bounty program and just want to report a vulnerability or security issue.
9 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/operations.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { isExclude } = require('../utils');
4 |
5 |
6 | const filterOperations = (swagger) => {
7 |
8 | swagger.paths && Object
9 | .keys(swagger.paths)
10 | .forEach((key) => {
11 | const path = swagger.paths[key] ;
12 | path && Object
13 | .keys(path)
14 | .forEach((verb) => {
15 | const operation = path[verb];
16 | if (isExclude(operation)){
17 | delete path[verb];
18 | }
19 | });
20 | });
21 |
22 | return swagger;
23 | };
24 |
25 |
26 | module.exports = filterOperations;
27 |
--------------------------------------------------------------------------------
/layout/_partial/google_analytics.ejs:
--------------------------------------------------------------------------------
1 | <% if (config.theme_config.google_analytics){ %>
2 |
12 | <% } %>
13 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-ui/partials/v2/libs.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/plugins/swagger-routes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const getFilter = (hexo) => {
4 |
5 | const swaggerStore = require('../lib/nodejs/swagger-store')({hexo});
6 |
7 | return () => {
8 | const routes = swaggerStore.getRoutes();
9 | routes && Object
10 | .keys(routes)
11 | .forEach((route) => {
12 | const data = routes[route];
13 |
14 | if(data){
15 | hexo.route.set(route, data);
16 | }else{
17 | hexo.route.remove(route);
18 | }
19 | })
20 | }
21 | }
22 |
23 |
24 | module.exports = ({hexo}) => {
25 | const filter = getFilter(hexo);
26 | hexo.extend.filter.register('after_generate', filter);
27 | };
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const operation = require('./operation');
4 | const operations = require('./operations');
5 | const request = require('./request');
6 | const requestBody = require('./requestBody');
7 | const requestSample = require('./requestSample');
8 | const response = require('./response');
9 | const responses = require('./responses');
10 | const responseSample = require('./responseSample');
11 | const security = require('./security');
12 |
13 |
14 | module.exports = {
15 | operation,
16 | operations,
17 | request,
18 | requestBody,
19 | requestSample,
20 | response,
21 | responses,
22 | responseSample,
23 | security
24 | };
25 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Key for exclude flag.
5 | */
6 | const docKey = 'x-doc';
7 | const excludeKey = 'excluded';
8 |
9 | /**
10 | * Function to decide what objects to exclude from the schema.
11 | */
12 | const isExclude = (subject) => {
13 | if (subject.hasOwnProperty(docKey)){
14 | const isExcludable = !!(subject[docKey] && subject[docKey][excludeKey]);
15 | // Delete the key as its not a standard swagger key and will cause issues while rendering in SwaggerUI or Swagger-to-html
16 | delete subject[docKey];
17 | return isExcludable;
18 | }
19 | return false;
20 | };
21 |
22 | module.exports = {
23 | isExclude
24 | };
25 |
--------------------------------------------------------------------------------
/lib/browser/search/load.js:
--------------------------------------------------------------------------------
1 | const lunr = require('lunr');
2 | const searcher = require('../../nodejs/search/searcher');
3 |
4 | module.exports = function load (url) {
5 | return fetchIndex(url)
6 | .then((data) => {
7 | return searcher({
8 | index: data.index,
9 | store: data.store
10 | });
11 | });
12 | };
13 |
14 | function fetchIndex (url) {
15 | return fetch(url || '/lunr.json', { credentials: 'include' })
16 | .then(function (res) {
17 | return res.json();
18 | })
19 | .then(function (json) {
20 | const index = lunr.Index.load(json.index);
21 | const store = json.store;
22 | return { index: index, store: store };
23 | });
24 | }
25 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const index = require('../index');
4 |
5 | describe('controllers.index', () => {
6 | it('should return controllers', () => {
7 | expect(Object.keys(index).length).toBe(9);
8 | expect(index.operation).toBeDefined();
9 | expect(index.operations).toBeDefined();
10 | expect(index.request).toBeDefined();
11 | expect(index.requestBody).toBeDefined();
12 | expect(index.requestSample).toBeDefined();
13 | expect(index.response).toBeDefined();
14 | expect(index.responses).toBeDefined();
15 | expect(index.responseSample).toBeDefined();
16 | expect(index.security).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/__tests__/paths.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const pathsFilter = require('../paths');
4 |
5 | const dummySwagger = {
6 | paths: {
7 | '/pets': {
8 | 'get': {
9 | }
10 | },
11 | '/pets/id':{
12 | 'x-doc': {
13 | 'excluded': true
14 | }
15 | }
16 | }
17 | };
18 |
19 | const expectedSwagger = {
20 | paths: {
21 | '/pets': {
22 | 'get': {
23 | }
24 | }
25 | }
26 | };
27 |
28 | describe('docExclude.paths', () => {
29 | it('should filter paths', () => {
30 | const updatedSwagger = pathsFilter(dummySwagger);
31 |
32 | expect(updatedSwagger).toEqual(expectedSwagger);
33 | });
34 | });
35 |
36 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-ui/partials/v3/snippet.ejs:
--------------------------------------------------------------------------------
1 |
2 |
22 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/request.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const request = (ctx) => {
5 | const operation = ctx.operation;
6 | const parameters = operation.parameters;
7 | const baseUrl = ctx.baseUrl;
8 | const path = operation.path;
9 | const verb = operation.verb;
10 | const request = {
11 | header: [],
12 | path: [],
13 | query: [],
14 | formData: [],
15 | body: []
16 | };
17 |
18 | parameters && parameters.forEach((param) => {
19 | const paramType = param['in'];
20 | request[paramType] && request[paramType].push(param);
21 | });
22 |
23 | return {
24 | request,
25 | path,
26 | verb,
27 | baseUrl
28 | };
29 | };
30 |
31 |
32 | module.exports = request;
33 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/__tests__/operations.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const operationsFilter = require('../operations');
4 |
5 | const dummySwagger = {
6 | paths: {
7 | '/pets': {
8 | 'get': {
9 | 'x-doc':{
10 | 'excluded': true
11 | }
12 | },
13 | 'post':{
14 | }
15 | }
16 | }
17 | };
18 |
19 | const expectedSwagger = {
20 | paths: {
21 | '/pets': {
22 | 'post':{
23 | }
24 | }
25 | }
26 | };
27 |
28 | describe('docExclude.operations', () => {
29 | it('should filter operations', () => {
30 | const updatedSwagger = operationsFilter(dummySwagger);
31 |
32 | expect(updatedSwagger).toEqual(expectedSwagger);
33 | });
34 | });
35 |
36 |
--------------------------------------------------------------------------------
/source/style/_doc/content.scss:
--------------------------------------------------------------------------------
1 | //
2 | // content
3 | //
4 | .doc-content {
5 | position: relative;
6 | top: 0;
7 | right: 0;
8 | bottom: 0;
9 | left: 0;
10 | width: auto;
11 | height: auto;
12 | min-height: 100vh;
13 | padding-top: $doc-navbar-height;
14 | padding-bottom: 420px;
15 | z-index: 2;
16 | transition: 0.1s ease-in-out;
17 |
18 | transform: translateX($doc-sidebar-width);
19 | margin-right: $doc-sidebar-width;
20 |
21 | .dc-page {
22 | overflow: auto;
23 | padding-top: 0;
24 |
25 | @media screen and (max-width: $doc-breakpoint) {
26 | padding-top: 0.8rem;
27 | }
28 | }
29 |
30 | @media screen and (max-width: $doc-breakpoint) {
31 | transform: translateX(0);
32 | margin-right: 0;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/nodejs/search/__tests__/mocks.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockLogger = {
4 | info: () => {},
5 | error: () => {},
6 | debug: () => {}
7 | };
8 |
9 | const mockHexo = {
10 | env: {},
11 | config: {
12 | theme_config: {
13 | search: {
14 | route: 'testlunr.json'
15 | }
16 | }
17 | },
18 | route: {
19 | 'set': () => {}
20 | },
21 | log: mockLogger
22 | };
23 |
24 |
25 | const mockCb = () => {};
26 |
27 | const mockHexoUtil = () => {
28 | return {
29 | url_for: (path) => {
30 | return path;
31 | },
32 | themeConfig: () => {
33 | return mockHexo.theme_config;
34 | }
35 | };
36 | };
37 |
38 | module.exports = {
39 | mockHexo,
40 | mockLogger,
41 | mockCb,
42 | mockHexoUtil
43 | };
44 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/requestBody.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockParseBody = jest.fn(() => 'flatBody');
4 | const mockHelpers = {
5 | parseBody: mockParseBody
6 | };
7 |
8 | jest.mock('../../../helpers', () => mockHelpers);
9 |
10 |
11 | const requestBodyController = require('../requestBody');
12 |
13 | describe('controllers.requestBody', () => {
14 | it('should transform the context as expected', () => {
15 | const ctx = {
16 | request: {},
17 | body: [
18 | {},
19 | {}
20 | ]
21 | };
22 | const {body} = requestBodyController(ctx);
23 | expect(body).toBeInstanceOf(Array);
24 | expect(body.length).toBe(2);
25 | expect(body[0]).toBe('flatBody');
26 | });
27 | });
28 |
29 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/processItems/default.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockUpdateResult = jest.fn();
4 |
5 | jest.mock('../../../lib/updateResult', () => ({
6 | updateResult: mockUpdateResult
7 | }));
8 |
9 | const processDefault = require('../../../lib/processItems/default');
10 |
11 | describe('swagger-parser.lib.processItems.default', () => {
12 | test('should process default values', () => {
13 | const object = {};
14 | const key = 'key';
15 | const isRequired = true;
16 | const result = {};
17 |
18 | processDefault({object, key, isRequired, result});
19 |
20 | expect(mockUpdateResult).toHaveBeenCalled();
21 | expect(mockUpdateResult).toHaveBeenCalledWith({object, key, isRequired, result});
22 |
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/lib/browser/swagger-to-html.js:
--------------------------------------------------------------------------------
1 | const Clipboard = require('clipboard');
2 |
3 | const clipboard = new Clipboard('.doc-swagger-to-html .sample-snippet__copy-btn', {
4 | text: function (triggerElem) {
5 | const preBlock = triggerElem.parentNode.querySelector('pre') ;
6 | const textToCopy = preBlock.textContent;
7 | return textToCopy;
8 | }
9 | });
10 |
11 | // Show the tooltip;
12 | clipboard.on('success', function (event){
13 | const trigger = event.trigger;
14 | trigger.classList.add('dc--has-tooltip');
15 | trigger.classList.add('dc--has-tooltip--bottom');
16 |
17 | trigger.addEventListener('mouseleave', (event) => {
18 | event.stopPropagation();
19 | trigger.classList.remove('dc--has-tooltip');
20 | trigger.classList.remove('dc--has-tooltip--bottom');
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-ui/parse-schema-file.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const ParseSchemaFileError = require('./parse-schema-file-error.js');
4 |
5 | function parseSchemaFile (filePath, pageSource, hexo) {
6 |
7 | const swaggerStore = require('../swagger-store')({hexo});
8 | try {
9 | return swaggerStore
10 | .getSwagger(filePath)
11 | .then(({swagger, downloadRoute}) => {
12 | return {
13 | downloadRoute,
14 | pageSource,
15 | swagger: swagger.swaggerJson
16 | };
17 | });
18 | } catch (error){
19 | return Promise.reject(new ParseSchemaFileError({
20 | 'message': 'There is an error reading the file.',
21 | filePath,
22 | 'referencePath': pageSource
23 | }));
24 | }
25 | }
26 |
27 | module.exports = parseSchemaFile;
28 |
--------------------------------------------------------------------------------
/plugins/swagger-ui.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const createSwaggerUI = require('../lib/nodejs/swagger-ui/index');
4 | const util = require('../lib/nodejs/hexo-util');
5 |
6 | module.exports = ({hexo}) => {
7 | const {themeConfig} = util({hexo});
8 | const {swaggerUITag, swaggerUIProcessor} = createSwaggerUI({hexo});
9 |
10 | themeConfig({ swagger_ui: createSwaggerUI.DEFAULT_CONFIG });
11 |
12 | hexo.extend.tag.register('swagger_ui', swaggerUITag, {async: true});
13 | hexo.extend.tag.register('swagger_ui_advanced', swaggerUITag, {async: true, ends: true});
14 |
15 | /**
16 | * This funtion is called when any file is processed.
17 | * It is automatically hooked to the watch task and is called if any file is modified.
18 | * */
19 | hexo.extend.processor.register('*', swaggerUIProcessor);
20 | };
21 |
--------------------------------------------------------------------------------
/lib/nodejs/support/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const DEFAULT_CONFIG = {
4 | link_url: '',
5 | link_text: 'Contact Us',
6 | text: 'Didn\'t you find what are you looking for?
Try searching again on the left menu or',
7 | navigation: true,
8 | navigation_label: 'SUPPORT'
9 | };
10 |
11 | const filter = (locals) => {
12 | if (locals.page.support === false) {
13 | return locals;
14 | }
15 | if (locals.config.theme_config.support) {
16 | locals.config.theme_config.support = Object.assign({}, DEFAULT_CONFIG, locals.config.theme_config.support);
17 | locals.page.support = Object.assign(
18 | {},
19 | locals.config.theme_config.support,
20 | locals.page.support || {}
21 | );
22 | }
23 | return locals;
24 | };
25 |
26 | module.exports = {DEFAULT_CONFIG, filter};
27 |
--------------------------------------------------------------------------------
/zappr.md:
--------------------------------------------------------------------------------
1 | # Zappr
2 |
3 | We use [zappr](https://github.com/zalando/zappr) to enforce commit message patterns, PR specification correctness, etc.
4 |
5 |
6 | ## Zappr Template for Code Repositories
7 |
8 | ```yaml
9 | approvals:
10 | minimum: 2 # PR needs at least 2 approvals
11 | pattern: "^(:\\+1:|👍|approved)$" # write a comment to the PR with "approved" or ":+1"
12 | veto:
13 | pattern: "^(:\\-1:|👎|rejected)$" # write a comment to the PR with "rejected" or ":-1"
14 | from:
15 | orgs:
16 | - zalando-incubator
17 | - zalando
18 | collaborators: true
19 | commit:
20 | message:
21 | patterns:
22 | # follow commit guidelines CONTRIBUTING.md#git-commit-guidelines
23 | - "^(feat|fix|docs|style|refactor|perf|test|chore)(|\\([a-zA-Z0-9-._]+\\)):.{3,}"
24 | ```
25 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | extends:
2 | - eslint:recommended
3 | plugins:
4 | - jest
5 | env:
6 | es6: true
7 | jest: true
8 | node: true
9 | rules:
10 | semi: 2
11 | strict: 2
12 | indent:
13 | - error
14 | - 2
15 | quotes:
16 | - 1
17 | - single
18 | - avoid-escape
19 | space-before-function-paren:
20 | - 2
21 | - always
22 | keyword-spacing:
23 | - 2
24 | - before: true
25 | after: true
26 | space-infix-ops: 2
27 | spaced-comment:
28 | - 2
29 | - always
30 | arrow-spacing: 2
31 | no-console: 2
32 | no-empty: 2
33 | eqeqeq:
34 | - 2
35 | - always
36 | no-unused-vars: 2
37 | no-unsafe-negation: 2
38 | prefer-const: 2
39 | no-var: 2
40 |
41 | # Jest
42 | jest/no-disabled-tests: 1
43 | jest/no-focused-tests: 1
44 | jest/no-identical-title: 2
45 |
--------------------------------------------------------------------------------
/source/style/_swagger/swagger-ui-v3.scss:
--------------------------------------------------------------------------------
1 | .hexo-swagger-ui-v3 {
2 | // "namespace" required vendors
3 | @import "./swagger-ui-v3-vendors.scss";
4 |
5 | .swagger-ui {
6 |
7 | .wrapper {
8 | padding: 0;
9 | }
10 |
11 | .information-container .info {
12 | margin: 0;
13 | }
14 |
15 | .info .title {
16 | font-size: 24px;
17 | font-weight: bold;
18 | }
19 |
20 | .info a {
21 | font-weight: 600;
22 | }
23 |
24 | .info .title small {
25 | display: none;
26 | }
27 |
28 | .info .base-url {
29 | padding: 0;
30 | background: transparent;
31 | }
32 |
33 | .scheme-container {
34 | padding-right: 12px;
35 | padding-left: 12px;
36 | }
37 |
38 | .markdown p {
39 | margin-bottom: 0;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/browser/index.js:
--------------------------------------------------------------------------------
1 | require('./polyfills');
2 |
3 | const React = require('react');
4 | const ReactDOM = require('react-dom');
5 | const {Navigation} = require('./navigation/containers.jsx');
6 | const {SearchResults} = require('./search/containers.jsx');
7 | const {SupportFooter} = require('./support/containers.jsx');
8 | const PROPS = Object.assign({}, window.__INITIAL_STATE__, {log: console});
9 |
10 | require('./swagger-to-html');
11 |
12 | ReactDOM.hydrate(
13 | React.createFactory(Navigation)(PROPS),
14 | document.getElementById('react-navigation-root')
15 | );
16 |
17 | ReactDOM.render(
18 | React.createFactory(SearchResults)(PROPS),
19 | document.getElementById('react-search-results-root')
20 | );
21 |
22 | ReactDOM.render(
23 | React.createFactory(SupportFooter)(PROPS),
24 | document.getElementById('react-support-footer-root')
25 | );
26 |
--------------------------------------------------------------------------------
/lib/browser/support/__tests__/containers.test.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const {shallow} = require('enzyme');
3 |
4 | describe('browser.support.conatiners', () => {
5 | describe('SupportFooter', () => {
6 | const {SupportFooter} = require('../containers.jsx');
7 |
8 | it('should not render when page.support is falsy', () => {
9 | const page = {
10 | support: false
11 | };
12 | const supportFooter = shallow();
13 | expect(supportFooter.getElement()).toBe(null);
14 | });
15 |
16 | it('should render when page.support is not falsy', () => {
17 | const page = {
18 | support: true
19 | };
20 | const supportFooter = shallow();
21 | expect(supportFooter.getElement()).not.toBe(null);
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/responses.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Response
5 |
6 |
7 |
Sample Response
8 |
9 |
10 | <% Object.keys(responses).forEach((responseCode) => {
11 | const response = responses[responseCode];
12 | %>
13 |
14 |
15 | |
16 | <%- include_module('response', { responseCode, response }) %>
17 | |
18 |
19 | <%- include_module('responseSample', { sample: response['examples']}) %>
20 | |
21 |
22 |
23 | <% }) %>
24 |
25 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/processItems/enum.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockUpdateResult = jest.fn();
4 |
5 | jest.mock('../../../lib/updateResult', () => ({
6 | updateResult: mockUpdateResult
7 | }));
8 |
9 | const processEnum = require('../../../lib/processItems/enum');
10 |
11 | describe('swagger-parser.lib.processItems.enum', () => {
12 | test('should process enum', () => {
13 | const object = {
14 | enum: [1, 2]
15 | };
16 | const key = 'key';
17 | const isRequired = true;
18 | const result = {};
19 |
20 | processEnum({object, key, isRequired, result});
21 |
22 | object.type = 'enum';
23 | object.values = object.enum;
24 |
25 | expect(mockUpdateResult).toHaveBeenCalled();
26 | expect(mockUpdateResult).toHaveBeenCalledWith({object, key, isRequired, result});
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('swagger-to-html', () => {
4 |
5 | const mockGetSwagger = jest.fn()
6 | .mockImplementationOnce(() => {
7 | return Promise.resolve({
8 | swagger: {
9 | swaggerObject: 'SWAGGER_OBJECT'
10 | }
11 | });
12 | });
13 |
14 | jest.mock('../../swagger-store', () => {
15 | return () => ({
16 | getSwagger: mockGetSwagger
17 | });
18 | });
19 |
20 | jest.mock('../core', () => {
21 | return {
22 | createTransformer: ({input}) => {
23 | return input();
24 | }
25 | };
26 | });
27 | const hexo = {};
28 | const transformerPromise = require('../index')({hexo});
29 |
30 | it('shouldn\'t emit any error', async () => {
31 | await expect(transformerPromise).resolves.toEqual('SWAGGER_OBJECT');
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/response.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% if('default' === responseCode){ %>
5 | This is a default response for the request.
6 | <% }else{ %>
7 | Status Code: <%- responseCode %>
8 | <% } %>
9 |
10 |
11 | <% if(response.description){ %>
12 |
13 | <%- response.description %>
14 |
15 | <% } %>
16 |
17 |
18 |
19 | Reference
20 |
21 | <% if(response.data['__noData']){ %>
22 | <%- include_module('emptyResponse', { response: response.data }) %>
23 | <% } else { %>
24 | <%- include_module('responseBody', { response: response.data }) %>
25 | <% } %>
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/parseBody.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockInit = jest.fn(() => {});
4 |
5 | jest.mock('../../lib/init', () => ({
6 | init: mockInit
7 | }));
8 |
9 | describe('swagger-parser.lib.parseBody', () => {
10 | const {parseBody} = require('../../lib/parseBody');
11 |
12 | describe('if body or body.schema is not defined', () => {
13 | const parsedBody = parseBody();
14 | test('should return blank object', () => {
15 | expect(parsedBody).toEqual({});
16 | });
17 | });
18 |
19 | describe('if body is defined', () => {
20 | const body = {
21 | schema: 'mockSchema'
22 | };
23 |
24 | test('should traverse body.schema', () => {
25 | parseBody(body);
26 | expect(mockInit).toHaveBeenCalled();
27 | expect(mockInit).toHaveBeenCalledWith({object: body.schema});
28 | });
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/source/style/_swagger/swagger-ui-v2.scss:
--------------------------------------------------------------------------------
1 | .hexo-swagger-ui-v2 {
2 | // "namespace" required vendors
3 | @import "./swagger-ui-v2-vendors";
4 |
5 | $font-size-small: 14px;
6 | $font-weight-big: 800;
7 | $font-weight-small: 300;
8 |
9 | .swagger-wrap.bootstrap {
10 | font-size: $font-size-small;
11 | font-weight: $font-weight-small;
12 |
13 | .api-infos-contact-url, li a {
14 | font-weight: $font-weight-small;
15 | }
16 | .content {
17 | margin-left: initial;
18 | }
19 | .endpoint-actions a {
20 | font-weight: $font-weight-small;
21 | font-size: $font-size-small;
22 | }
23 | .endpoint-heading a {
24 | font-weight: $font-weight-big;
25 | }
26 |
27 | .endpoint-heading > li, .endpoint-actions > li {
28 | margin-bottom: 0;
29 | }
30 |
31 | .api-version .h4 {
32 | font-weight: $font-weight-big;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/response.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockParseResponse = jest.fn(() => 'flatResponse');
4 | const mockHelpers = {
5 | parseResponse: mockParseResponse
6 | };
7 |
8 | jest.mock('../../../helpers', () => mockHelpers);
9 |
10 |
11 | const responseController = require('../response');
12 |
13 | describe('controllers.resposne', () => {
14 | it('should transform context as expected', () => {
15 | const ctx = {
16 | 'responseCode': 200,
17 | 'response': {
18 | description: 'foo'
19 | }
20 | };
21 |
22 | const response = responseController(ctx);
23 | const expectedResponse = {
24 | description: 'foo',
25 | data: 'flatResponse'
26 | };
27 |
28 | expect(Object.keys(response).length).toBe(2);
29 | expect(response.responseCode).toBe(200);
30 | expect(response.response).toEqual(expectedResponse);
31 |
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/operation.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
<%= operation.title %>
4 |
5 |
<%= operation.description %>
6 |
7 |
8 |
9 | <%=operation.verb.toUpperCase()%>
10 |
11 |
12 | <%=operation.path%>
13 |
14 |
15 |
16 | <% if(operation.security){ %>
17 |
Security Requirement
18 | <%- include_module('securityRequirement', { securityRequirement: operation.security }) %>
19 | <% } %>
20 | <%- include_module('request', { operation, baseUrl }) %>
21 |
22 | <%- include_module('responses', { operation }) %>
23 |
24 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/processItems/object.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {traverse} = require('../traverse');
4 | const {updateResult} = require('../updateResult');
5 |
6 | const processObject = ({object, key, isRequired, result}) => {
7 | updateResult({object, key, isRequired, result});
8 |
9 | // Check for additional properteis
10 | if (object.additionalProperties){
11 | object = object.additionalProperties;
12 | }
13 |
14 | const properties = object.properties || {};
15 | const required = object.required || [] ;
16 |
17 | return Object.keys(properties).reduce((result, propertyName) => {
18 | const property = properties[propertyName];
19 | const childKey = key ? (key + '.' + propertyName) : propertyName;
20 | const isRequired = required.includes(propertyName);
21 |
22 | return traverse({
23 | object: property,
24 | key: childKey,
25 | isRequired
26 | });
27 |
28 | }, result);
29 | };
30 |
31 | module.exports = processObject;
32 |
--------------------------------------------------------------------------------
/banner.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const pkg = require('./package.json');
5 | const path = require('path');
6 |
7 | const banner = ` /*!
8 | * ${pkg.name} - ${pkg.version}
9 | * Copyright (c) see LICENSE at ${pkg.homepage}/blob/master/LICENSE
10 | */
11 | `;
12 |
13 | const files = [
14 | 'source/style/doc.css',
15 | 'source/style/swagger-ui-v2.css',
16 | 'source/style/swagger-ui-v3.css',
17 | 'source/script/doc.js'
18 | ];
19 |
20 | files.forEach(writeBanner(banner));
21 |
22 | function writeBanner (banner) {
23 | return function (filePath) {
24 | const fileExt = path.extname(filePath);
25 | const absFilePath = path.resolve(__dirname, filePath);
26 | let content = fs.readFileSync(absFilePath, 'utf8');
27 | content = banner + content;
28 | if (fileExt === '.css') {
29 | content = content.replace(/@charset "UTF-8";/g, '');
30 | content = '@charset "UTF-8";\n' + content;
31 | }
32 | fs.writeFileSync(absFilePath, content);
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/formData.ejs:
--------------------------------------------------------------------------------
1 | <% params.forEach((param) => {%>
2 |
3 |
4 |
5 | <%= param.name %>
6 |
7 |
8 | <%= param.type %> <% if(param.format){ %> (<%= param.format %>) <% } %>
9 |
10 | <% if ( param.required ) {%>
11 |
12 | required
13 |
14 | <% } %>
15 |
16 |
17 | <%= `Used in ${param.in}` %>
18 |
19 |
20 | <%= param.description %>
21 |
22 | <% if ( param.example ) { %>
23 |
24 | Eg: <%= param.example %>
25 |
26 | <% } %>
27 |
28 | <% }) %>
29 |
--------------------------------------------------------------------------------
/plugins/react-initial-state.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = ({hexo}) => {
4 | const allowedProperties = {
5 | config: [
6 | 'root',
7 | 'theme',
8 | 'theme_config',
9 | 'time_format',
10 | 'timezone'
11 | ],
12 | page: [
13 | 'path',
14 | 'title',
15 | 'support'
16 | ]
17 | };
18 |
19 | const filter = (source, allowedValues) => {
20 | return Object
21 | .keys(source)
22 | .filter(key => allowedValues.includes(key))
23 | .reduce((obj, key) => {
24 | obj[key] = source[key];
25 | return obj;
26 | }, {});
27 | };
28 |
29 | hexo.extend.filter.register('template_locals', function (locals){
30 |
31 | const data = locals.site.data;
32 |
33 | const page = filter(locals.page, allowedProperties.page);
34 |
35 | const config = filter(locals.config, allowedProperties.config);
36 |
37 | locals.initial_state = {
38 | page,
39 | data,
40 | config
41 | };
42 |
43 | return locals;
44 | }, 20);
45 | };
46 |
--------------------------------------------------------------------------------
/lib/nodejs/hexo-util.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {merge} = require('lodash');
4 |
5 | module.exports = ({hexo}) => {
6 | return {
7 | /**
8 | * url_for helper that you can normally use in templates
9 | * but for programmatic usage in hexo plugins
10 | *
11 | * @type {function}
12 | */
13 | url_for: hexo.extend.helper.get('url_for').bind({
14 | config: hexo.config,
15 | relative_url: hexo.extend.helper.get('relative_url')
16 | }),
17 | /**
18 | * Get or merge theme_config
19 | *
20 | * @param {Object} object - the object that you wanna merge
21 | * @return {Object} current theme_config
22 | */
23 | themeConfig: (object) => {
24 | if (!hexo.config.theme_config) {
25 | hexo.config.theme_config = {};
26 | }
27 |
28 | if (!object) {
29 | return hexo.config.theme_config;
30 | }
31 |
32 | hexo.config.theme_config = merge({}, object, hexo.config.theme_config);
33 |
34 | return hexo.config.theme_config;
35 | }
36 | };
37 | };
38 |
--------------------------------------------------------------------------------
/lib/nodejs/search/__tests__/child-on-message.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {mockLogger} = require('./mocks');
4 |
5 | describe('search.child-on-message', () => {
6 |
7 | jest.mock('../build', () => () => 'test');
8 | jest.mock('hexo-log', () => () => mockLogger);
9 |
10 | let childOnMessage, mockProcess;
11 |
12 | beforeEach(() => {
13 | mockProcess = {
14 | send: jest.fn()
15 | };
16 | childOnMessage = require('../child-on-message')({ process: mockProcess });
17 | });
18 |
19 | it('should send a message back to parent process', () => {
20 | const message = {
21 | pages: { data: [] },
22 | rootPath: '/'
23 | };
24 | childOnMessage(message);
25 |
26 | expect(mockProcess.send).toHaveBeenCalledWith('test');
27 | });
28 |
29 | it('should send a message back to parent process also when pages is undefined', () => {
30 | const message = {
31 | rootPath: '/'
32 | };
33 | childOnMessage(message);
34 |
35 | expect(mockProcess.send).toHaveBeenCalledWith('test');
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/lib/browser/__tests__/utils.test.js:
--------------------------------------------------------------------------------
1 | describe('browser.utils', () => {
2 | describe('url_for', () => {
3 | let url_for;
4 | beforeEach(() => {
5 | url_for = require('../utils').url_for({
6 | config: { root: '/root' }
7 | });
8 | });
9 |
10 | it('should create a function', () => {
11 | expect(typeof url_for).toBe('function');
12 | });
13 |
14 | it('should join configured root with the path passed as an argument', () => {
15 | expect(url_for('/index.html?query=hello#hash')).toBe('/root/index.html?query=hello#hash');
16 | });
17 |
18 | it('should remove eventual double slashes', () => {
19 | const url_for = require('../utils').url_for({
20 | config: { root: '/' }
21 | });
22 | expect(url_for('//index.html?query=hello#hash')).toBe('/index.html?query=hello#hash');
23 | });
24 |
25 | it('should return the untouched path if it\'s an absolute url ', () => {
26 | const path = 'https://www.google.com';
27 | expect(url_for(path)).toBe(path);
28 | });
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/source/style/_doc/search.scss:
--------------------------------------------------------------------------------
1 | .doc-search-form {
2 | max-width: 186px;
3 |
4 | &__input[type="search"] {
5 | width: 100%;
6 | box-sizing: border-box;
7 | }
8 |
9 | &__input:focus + &__btn {
10 | color: $dc-blue30;
11 | cursor: default;
12 | }
13 |
14 | &__btn {
15 | &:hover {
16 | color: $dc-gray40;
17 | cursor: default;
18 | }
19 | }
20 | }
21 |
22 | .doc-search-results {
23 | &__title {
24 | margin-top: 0;
25 | line-height: 3.4rem;
26 |
27 | &__query {
28 | font-weight: 500;
29 | }
30 | }
31 |
32 | &__list {
33 | list-style: none;
34 | padding: 0;
35 |
36 | &__item {
37 | display: block;
38 | }
39 |
40 | &__link {
41 | display: inline-block;
42 | font-weight: 500;
43 | }
44 |
45 | &__score-divider {
46 | display: inline-block;
47 | padding: 0 0.8rem;
48 | color: $dc-gray70;
49 | }
50 |
51 | &__score {
52 | color: $dc-gray50;
53 | }
54 | }
55 |
56 | .doc-highlight {
57 | font-weight: 500;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/updateResult.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const updateResult = ({object, key, isRequired, result}) => {
4 | if (!key){
5 | return false;
6 | }
7 |
8 | result[key] = result[key] || {};
9 |
10 | const _result = result[key];
11 |
12 | const description = object.description;
13 | const type = object.type;
14 | const values = object.values; // Used for enums
15 | const required = object.required || isRequired;
16 | const example = object.example;
17 | const format = object.format;
18 |
19 | if (description){
20 | _result.description = description;
21 | }
22 |
23 | if (type){
24 | _result.type = type;
25 | }
26 |
27 | if (values){
28 | _result.values = values;
29 | }
30 |
31 | if (typeof required === 'boolean' && required){
32 | _result.required = required;
33 | }
34 |
35 | if (example){
36 | _result.example = example;
37 | }
38 |
39 | if (format){
40 | _result.format = format;
41 | }
42 |
43 | return true;
44 | };
45 |
46 | module.exports = {updateResult};
47 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-ui/__tests__/mocks.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockFileContent = {
4 | '/path/to/swagger/petstore.json': '{"swagger":"2.0","info":{"version":"1.0.0","title":"Swagger Petstore","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://swagger.io/terms/","contact":{"name":"Swagger API Team"},"license":{"name":"MIT"}},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"consumes":["application/json"],"produces":["application/json"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","produces":["application/json"],"responses":{"200":{"description":"A list of pets.","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}}}}}},"definitions":{"Pet":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}',
5 | '/path/to/swagger/error.json': 'Invalid JSON'
6 | };
7 |
8 | module.exports = {
9 | mockFileContent
10 | };
11 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/processItems/array.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockTraverse = jest.fn();
4 | const mockUpdateResult = jest.fn();
5 |
6 |
7 | jest.mock('../../../lib/traverse', () => ({
8 | traverse: mockTraverse
9 | }));
10 |
11 | jest.mock('../../../lib/updateResult', () => ({
12 | updateResult: mockUpdateResult
13 | }));
14 |
15 | const processArray = require('../../../lib/processItems/array');
16 |
17 | describe('swagger-parser.lib.processItems.array', () => {
18 | test('should process array', () => {
19 | const object = {
20 | items: ['foo', 'bar']
21 | };
22 | const key = 'key';
23 | const isRequired = true;
24 | const result = {};
25 |
26 | processArray({object, key, isRequired, result});
27 |
28 | expect(mockUpdateResult).toHaveBeenCalled();
29 | expect(mockUpdateResult).toHaveBeenCalledWith({object, key, isRequired, result});
30 |
31 | expect(mockTraverse).toHaveBeenCalled();
32 | expect(mockTraverse).toHaveBeenCalledWith({object: object.items , key: key + '[]'});
33 |
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/responseSample.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockHighlight = jest.fn(() => 'EXPECTED_SAMPLE');
4 |
5 | jest.mock('../../../helpers', () => ({
6 | highlight: mockHighlight
7 | }));
8 |
9 | const responseSampleController = require('../responseSample');
10 |
11 | describe('controllers.responseSample', () => {
12 | it('should transform context as expected', () => {
13 | const responseData = {
14 | 'data': {
15 | },
16 | 'links': {
17 | }
18 | };
19 | const ctx = {
20 | sample: {
21 | 'application/json': responseData
22 | }
23 | };
24 |
25 | const {sample} = responseSampleController(ctx);
26 |
27 | const sampleStr = JSON.stringify(ctx.sample['application/json'], null, 2);
28 |
29 | const highlightArgs = {
30 | code: sampleStr,
31 | lang: 'json'
32 | };
33 |
34 | expect(mockHighlight).toHaveBeenCalled();
35 | expect(mockHighlight).toHaveBeenCalledWith(highlightArgs);
36 |
37 | expect(sample).toEqual('EXPECTED_SAMPLE');
38 |
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/operations.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const { toSlug } = require('../../helpers');
5 |
6 | const operations = (ctx) => {
7 | const paths = ctx.paths;
8 | const globalSecurity = ctx.security;
9 |
10 | ctx.schemes = ctx.schemes || [];
11 |
12 | let baseUrl = '';
13 | if (ctx.schemes.includes('https')){
14 | baseUrl += 'https://';
15 | } else {
16 | baseUrl += 'http://';
17 | }
18 | baseUrl += ctx.host + ctx.basePath;
19 |
20 | const operations = Object.keys(paths).reduce((acc, path_) => {
21 | const ops = Object.keys(paths[path_]).map((verb) => {
22 | const operation = paths[path_][verb];
23 | const title = operation.summary || operation.operationId || operation.description || '';
24 | return Object.assign({}, operation, {
25 | verb,
26 | path: path_,
27 | title: title,
28 | id: toSlug(title)
29 | });
30 | });
31 | return acc.concat(ops);
32 | }, []);
33 |
34 | return {
35 | operations,
36 | baseUrl,
37 | globalSecurity
38 | };
39 | };
40 |
41 |
42 | module.exports = operations;
43 |
--------------------------------------------------------------------------------
/plugins/search.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const generator = require('../lib/nodejs/search/generator');
4 | const util = require('../lib/nodejs/hexo-util');
5 |
6 | const DEFAULT_CONFIG = { route: '/lunr.json' };
7 |
8 | module.exports = ({hexo}) => {
9 | const {themeConfig} = util({hexo});
10 | hexo.extend.generator.register('search', createGeneratorFn({hexo, themeConfig}));
11 | };
12 |
13 | function createGeneratorFn ({hexo, themeConfig}) {
14 | const cmd = hexo.env.args._ && hexo.env.args._.length ? hexo.env.args._[0] : null;
15 |
16 | // hexo commands that should activate the generator
17 | const cmds = [
18 | 'generate',
19 | 'server',
20 | 'deploy',
21 | 'g',
22 | 's',
23 | 'd'
24 | ];
25 |
26 | // hexo commands that should activate the generator in background mode
27 | const bgCmds = [
28 | 'server',
29 | 's'
30 | ];
31 |
32 | const skip = cmds.indexOf(cmd) === -1 && typeof hexo.env.args._ !== 'undefined';
33 | const background = bgCmds.indexOf(cmd) > -1;
34 |
35 | themeConfig({ search: { skip, background, route: DEFAULT_CONFIG.route } });
36 |
37 | return generator({hexo});
38 | }
39 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/emptyResponse.ejs:
--------------------------------------------------------------------------------
1 | <% if(response.headers){ %>
2 | Headers
3 | <%
4 | const headers = response.headers;
5 | Object.keys(headers).forEach((key) => {
6 | const header = headers[key];
7 | header.name = key;
8 | %>
9 |
10 |
11 |
12 | <%= header.name %>
13 |
14 | <% if(header.type){ %>
15 |
16 | <%= header.type %> <% if(header.format){ %> (<%= header.format %>) <% } %>
17 |
18 | <% } %>
19 |
20 | <% if(header.description){ %>
21 |
22 | <%= header.description %>
23 |
24 | <% } %>
25 | <% if(header.format){ %>
26 |
27 | <%= header.format %>
28 |
29 | <% } %>
30 |
31 |
32 | <% }) %>
33 | <% } %>
34 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/parseResponse.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockInit = jest.fn(() => {});
4 |
5 | jest.mock('../../lib/init', () => ({
6 | init: mockInit
7 | }));
8 |
9 | describe('swagger-parser.lib.parseResponse', () => {
10 | const {parseResponse} = require('../../lib/parseResponse');
11 |
12 | describe('if response not defined', () => {
13 | const parsedResponse = parseResponse();
14 | test('should return blank object', () => {
15 | expect(parsedResponse).toEqual({});
16 | });
17 | });
18 |
19 | describe('if response is defined', () => {
20 | describe('if response have schema', () => {
21 | const response = {
22 | schema: 'mockSchema'
23 | };
24 | parseResponse(response);
25 | expect(mockInit).toHaveBeenCalled();
26 | expect(mockInit).toHaveBeenCalledWith({object: response.schema});
27 | });
28 |
29 | describe('if response does not have schema', () => {
30 | const response = {};
31 | const parsedResponse = parseResponse(response);
32 | expect(parsedResponse).toEqual({ '__noData': true});
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const stripIndent = require('strip-indent');
3 | const hexoUtil = require('hexo-util');
4 | const hexoHighlight = hexoUtil.highlight;
5 |
6 |
7 | const {mergeWith, isArray, uniq} = require('lodash');
8 |
9 | const arrayMergeCustomizer = (objValue, srcValue) => {
10 | if (isArray(objValue)) {
11 | return uniq(objValue.concat(srcValue));
12 | }
13 | };
14 |
15 | const deepMerge = (object, sources, customizer) => {
16 | const finalCustomizer = customizer || arrayMergeCustomizer;
17 | return mergeWith(object, sources, finalCustomizer);
18 | };
19 |
20 |
21 | const toSlug = (words) => {
22 | return encodeURIComponent(words.replace(/\s/g, '-').replace(/\./g, ''));
23 | };
24 |
25 | const highlight = ({code, lang}) => {
26 | const config = {
27 | gutter: false,
28 | firstLine: false
29 | };
30 |
31 | if (lang){
32 | config.lang = lang;
33 | } else {
34 | config.autoDetect = true;
35 | }
36 |
37 | code = stripIndent(code).trim();
38 | return hexoHighlight(code, config);
39 | };
40 |
41 | module.exports = {
42 | deepMerge,
43 | toSlug,
44 | highlight
45 | };
46 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/__tests__/swagger-unmocked.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 |
5 | describe('swager.Swagger.parser', () => {
6 | const specFile = 'lib/nodejs/swagger/__tests__/_petstore.yaml';
7 | const expectedSpec = 'lib/nodejs/swagger/__tests__/_petstore-parsed.yaml';
8 |
9 | const Swagger = require('../swagger');
10 | const decorators = require('../decorators');
11 | const swagger = new Swagger(specFile);
12 |
13 | it('should generate xml schema', () => {
14 | swagger
15 | .validate()
16 | .then(swagger => swagger.decorate(decorators.docExclude))
17 | .then(swagger => swagger.decorate(decorators.host))
18 | .then(swagger => {
19 | const readableStream = fs.createReadStream(expectedSpec);
20 | let data = '';
21 |
22 | readableStream
23 | .on('readable', () => {
24 | let chunk;
25 | while ((chunk = readableStream.read()) !== null) {
26 | data += chunk;
27 | }
28 | })
29 | .on('end', () => {
30 | expect(data).toEqual(swagger.swaggerYaml);
31 | });
32 | });
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-ui/partials/v2/snippet.ejs:
--------------------------------------------------------------------------------
1 |
3 |
12 | download="<%- options.download %>"
13 | <% } %>
14 | >
15 |
16 |
17 |
36 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | dist: trusty
3 | group: deprecated-2017Q4
4 |
5 | cache:
6 | directories:
7 | - node_modules
8 |
9 | language: node_js
10 |
11 | node_js:
12 | - '12'
13 |
14 | addons:
15 | chrome: stable
16 |
17 | before_script:
18 | - npm link
19 |
20 | # prepare e2e test environment
21 | - "export DISPLAY=:99.0"
22 | - "sh -e /etc/init.d/xvfb start" # the starting the virtual X frame buffer: Xvfb process
23 |
24 | - git clone --depth=50 --branch=gh-pages-source https://github.com/zalando-incubator/hexo-theme-doc ../hexo-theme-doc-site
25 | - cd ../hexo-theme-doc-site && npm install -q && npm link hexo-theme-doc
26 | - cd $TRAVIS_BUILD_DIR
27 |
28 | script:
29 | # quality checks, unit test and compiling fe artifacts
30 | - npm run lint -s
31 | - npm run lint:report -s
32 | - npm run test:coverage -s
33 | - npm run compile -s
34 |
35 | # run e2e tests
36 | - cd ../hexo-theme-doc-site && npm run generate
37 | - npm run serve &>/dev/null &
38 | - sleep 5 # give server some time to start
39 | - npm test
40 | - cd $TRAVIS_BUILD_DIR
41 |
42 | after_success:
43 | cat target/coverage/lcov.info | ./node_modules/.bin/codacy-coverage
44 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/request.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Request
5 |
6 |
7 |
Sample Request
8 |
9 |
10 |
11 |
12 | |
13 |
14 |
15 | <% if( request.header.length ) {%>
16 | <%- include_module('header', { header: request.header }) %>
17 | <% } %>
18 |
19 | <% if( request.path.length || request.query.length ) {%>
20 | <%- include_module('requestParams', { params: request.path.concat(request.query) }) %>
21 | <% } %>
22 |
23 | <% if( request.formData.length || request.body.length) {%>
24 | <%- include_module('requestContent', {request}) %>
25 | <% } %>
26 |
27 |
28 | |
29 |
30 | <%- include_module('requestSample', {request, path, verb, baseUrl}) %>
31 | |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockFilterSecurity = jest.fn(swagger => swagger + '-SECURITY');
4 | const mockFilterParameters = jest.fn(swagger => swagger + '-PARAMETERS');
5 | const mockFilterPaths = jest.fn(swagger => swagger + '-PATHS');
6 | const mockFilterOperations = jest.fn(swagger => swagger + '-OPERATIONS');
7 |
8 | jest.mock('../filters', () => ({
9 | filterSecurity: mockFilterSecurity,
10 | filterParameters: mockFilterParameters,
11 | filterPaths: mockFilterPaths,
12 | filterOperations: mockFilterOperations
13 | }));
14 |
15 | describe('docExclude.index', () => {
16 |
17 | it('should apply the filters', () => {
18 | const docExclude = require('../index');
19 |
20 | const swagger = 'SWAGGER';
21 |
22 | const updatedSwagger = docExclude(swagger);
23 |
24 | const expectedSwagger = 'SWAGGER-SECURITY-PARAMETERS-PATHS-OPERATIONS';
25 |
26 | expect(mockFilterSecurity).toBeCalled();
27 | expect(mockFilterParameters).toBeCalled();
28 | expect(mockFilterPaths).toBeCalled();
29 | expect(mockFilterOperations).toBeCalled();
30 |
31 | expect(updatedSwagger).toBe(expectedSwagger);
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/header.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Header
4 |
5 | <% header.forEach((param) => {%>
6 |
7 |
8 |
9 | <%= param.name %>
10 |
11 | <% if ( param.type ) {%>
12 |
13 | <%= param.type %> <% if(param.format){ %> (<%= param.format %>) <% } %>
14 |
15 | <% } %>
16 | <% if ( param.required ) {%>
17 |
18 | required
19 |
20 | <% } %>
21 |
22 | <% if ( param.description ) { %>
23 |
24 | <%= param.description %>
25 |
26 | <% } %>
27 | <% if ( param.example ) { %>
28 |
29 | Eg: <%= param.example %>
30 |
31 | <% } %>
32 |
33 | <% }) %>
34 |
35 |
36 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/operation.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const operationController = require('../operation');
4 |
5 | describe('controllers.operation', () => {
6 | test('should transform the context as expected', () => {
7 | const ctx = {
8 | operation: {
9 | security: {
10 | items: ['a']
11 | }
12 | },
13 | globalSecurity: {
14 | items: ['b'],
15 | foo: 'bar'
16 | }
17 | };
18 |
19 | const updatedCtx = operationController(ctx);
20 | const expectedSecurity = {
21 | foo: 'bar',
22 | items: ['a', 'b']
23 | };
24 |
25 | expect(updatedCtx.operation.security).toEqual(expectedSecurity);
26 | });
27 | test('should handle duplicates', () => {
28 | const ctx = {
29 | operation: {
30 | security: {
31 | items: ['a', 'b', 'c']
32 | }
33 | },
34 | globalSecurity: {
35 | items: ['b', 'd'],
36 | foo: 'bar'
37 | }
38 | };
39 |
40 | const updatedCtx = operationController(ctx);
41 | const expectedSecurity = {
42 | foo: 'bar',
43 | items: ['a', 'b', 'c', 'd']
44 | };
45 |
46 | expect(updatedCtx.operation.security).toEqual(expectedSecurity);
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/__tests__/parameters.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const parametersFilter = require('../parameters');
4 |
5 | const dummySwagger = {
6 | parameters: {
7 | 'foo':{
8 | 'name': 'foo'
9 | },
10 | 'bar':{
11 | 'name': 'bar',
12 | 'x-doc': {
13 | 'excluded': true
14 | }
15 | }
16 | },
17 | paths: {
18 | '/pets': {
19 | 'get': {
20 | parameters:[
21 | {
22 | name: 'param1'
23 | },
24 | {
25 | name: 'param2',
26 | 'x-doc':{
27 | 'excluded': true
28 | }
29 | }
30 | ]
31 | }
32 | }
33 | }
34 | };
35 |
36 | const expectedSwagger = {
37 | parameters: {
38 | 'foo':{
39 | 'name': 'foo'
40 | }
41 | },
42 | paths: {
43 | '/pets': {
44 | 'get': {
45 | parameters:[
46 | {
47 | 'name': 'param1'
48 | }
49 | ]
50 | }
51 | }
52 | }
53 | };
54 |
55 | describe('docExclude.parameters', () => {
56 | it('should filter parameters', () => {
57 | const updatedSwagger = parametersFilter(dummySwagger);
58 |
59 | expect(updatedSwagger).toEqual(expectedSwagger);
60 | });
61 | });
62 |
63 |
--------------------------------------------------------------------------------
/source/style/_doc/layout.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 16px;
3 | overflow-y: auto;
4 | overflow-x: hidden;
5 |
6 | &.doc-navigation--is-collapsed {
7 | @media screen and (min-width: $doc-breakpoint) {
8 | .doc-navbar {
9 | width: $doc-navbar-width-collapsed;
10 | overflow: hidden;
11 | border-bottom: 1px solid $doc-navbar-background-color;
12 | }
13 |
14 | .doc-sidebar {
15 | transform: translateX(-($doc-sidebar-width - $doc-navbar-width-collapsed));
16 | }
17 |
18 | .doc-content {
19 | transform: translateX($doc-sidebar-width-collapsed);
20 | margin-right: $doc-sidebar-width-collapsed;
21 | }
22 |
23 | .doc-navbar__logo__text,
24 | .doc-sidebar-content,
25 | .doc-navbar__sidebar-close {
26 | display: none;
27 | }
28 |
29 | .doc-sidebar__vertical-menu {
30 | display: block;
31 | }
32 | }
33 | }
34 |
35 | &.doc-sidebar--is-visible {
36 | @media screen and (max-width: $doc-breakpoint) {
37 | .doc-sidebar {
38 | transform: translateX(0);
39 | }
40 |
41 | .doc-content {
42 | transform: translateX($doc-sidebar-width);
43 | }
44 | }
45 | }
46 | }
47 |
48 | .doc-sidebar__vertical-menu {
49 | display: none;
50 | }
51 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/__tests__/security.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const securityFilter = require('../security');
4 |
5 | const dummySwagger = {
6 | securityDefinitions:{
7 | 'oauth':{
8 |
9 | },
10 | 'internalAuth':{
11 | 'x-doc': {
12 | 'excluded': true
13 | }
14 | },
15 | 'foo': {
16 | 'x-doc': {
17 | 'excluded': true
18 | }
19 | }
20 | },
21 | security: [
22 | {
23 | 'oauth':[]
24 | },
25 | {
26 | 'internalAuth': []
27 | }
28 | ],
29 | paths: {
30 | '/pets': {
31 | 'get': {
32 | },
33 | 'post': {
34 | security: [
35 | {
36 | 'foo': []
37 | }
38 | ]
39 | }
40 | }
41 | }
42 | };
43 |
44 | const expectedSwagger = {
45 | securityDefinitions:{
46 | 'oauth':{
47 |
48 | }
49 | },
50 | security: [
51 | {
52 | 'oauth':[]
53 | }
54 | ],
55 | paths: {
56 | '/pets': {
57 | 'get': {
58 | },
59 | 'post': {
60 | security: []
61 | }
62 | }
63 | }
64 | };
65 |
66 | describe('docExclude.parameters', () => {
67 | it('should filter parameters', () => {
68 | const updatedSwagger = securityFilter(dummySwagger);
69 |
70 | expect(updatedSwagger).toEqual(expectedSwagger);
71 | });
72 | });
73 |
74 |
--------------------------------------------------------------------------------
/plugins/react.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // NOTE: "node-jsx" package is deprecated but it's only one
4 | // that is working correctly without going crazy with presets and babel
5 | // the correct solution should be:
6 | //
7 | // ```
8 | // require('babel-register')({
9 | // 'presets': ['react', 'es2015']
10 | // });
11 | // ```
12 | //
13 | // But for "yet" unknown reasons it works just when you `npm link` the package but not when
14 | // you install it in a project with the usual `npm install`... ¯\_(ツ)_/¯
15 | //
16 |
17 |
18 | require('node-jsx').install();
19 |
20 | const React = require('react');
21 | const ReactDOM = require('react-dom/server');
22 | const {Navigation} = require('../lib/browser/navigation/containers.jsx');
23 | const components = {
24 | Navigation
25 | };
26 |
27 | module.exports = ({hexo}) => {
28 |
29 | /**
30 | * "Server-side render" a React component
31 | * @param {String} componentName - The componentName
32 | * @param {Object} [props={}] - injected props
33 | * @return {string}
34 | */
35 | function reactComponent (componentName, props = {}) {
36 | const Component = components[componentName];
37 | const componentFactory = React.createFactory(Component);
38 | return ReactDOM.renderToString(componentFactory(props));
39 | }
40 |
41 | hexo.extend.helper.register('react_component', reactComponent);
42 | };
43 |
--------------------------------------------------------------------------------
/lib/browser/search/__tests__/load.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @jest-environment jsdom
3 | */
4 |
5 | /* global global */
6 | const mockSearcher = () => {
7 | return () => {};
8 | };
9 |
10 | jest.mock('../../../nodejs/search/searcher', () => mockSearcher);
11 |
12 | const mockLunr = {
13 | Index: {
14 | load: (index) => index
15 | }
16 | };
17 |
18 | jest.mock('lunr', () => mockLunr);
19 |
20 | const mockResponse = () => {
21 | return {
22 | json: () => Promise.resolve({
23 | index: {},
24 | store: {}
25 | })
26 | };
27 | };
28 |
29 | const mockFetch = jest.fn().mockReturnValue(Promise.resolve(mockResponse()));
30 |
31 | global.fetch = mockFetch;
32 |
33 | describe('browser.search.load', () => {
34 | const load = require('../load');
35 |
36 | it('should fetch the expected json file and return a search function', () => {
37 | return load('/foo.json').then((search) => {
38 | expect(mockFetch).toHaveBeenCalledWith('/foo.json', { credentials: 'include'} );
39 | expect(typeof search).toBe('function');
40 | });
41 | });
42 |
43 | it('should fetch the default json file and return a search function', () => {
44 | return load().then((search) => {
45 | expect(mockFetch).toHaveBeenCalledWith('/lunr.json', { credentials: 'include'} );
46 | expect(typeof search).toBe('function');
47 | });
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/lib/traverse.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {merge} = require('lodash');
4 | let result;
5 |
6 | function traverse ({object, key, isRequired, init}){
7 |
8 | if (!object){
9 | return {};
10 | }
11 | // handle allOf property
12 | if (object.allOf){
13 | let mergedObj = {type: 'object'};
14 | for (const obj of object.allOf){
15 | mergedObj = merge(mergedObj, obj);
16 | }
17 | object = mergedObj;
18 |
19 | // delete allOf as its already used
20 | delete object.allOf;
21 | }
22 |
23 | // Check object type.
24 | const type = object.type;
25 | const hasProperties = !!object.properties;
26 |
27 | if (init){
28 | result = {};
29 | }
30 |
31 | if ('array' === type){
32 | return processArray({object, key, isRequired, result});
33 | }
34 |
35 | // Some schemas, object does not have a type but have properties
36 | if ('object' === type || hasProperties){
37 | return processObject({object, key, isRequired, result});
38 | }
39 |
40 | if (object.enum){
41 | return processEnum({object, key, isRequired, result}) ;
42 | }
43 |
44 | return processDefault({object, key, isRequired, result});
45 | }
46 |
47 |
48 |
49 | module.exports = {
50 | traverse
51 | };
52 |
53 | const {processArray, processObject, processEnum, processDefault} = require('./processItems') ;
54 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/responseBody.ejs:
--------------------------------------------------------------------------------
1 | <%
2 | Object.keys(response).forEach((key) => {
3 | const value = response[key];
4 | value.name = key;
5 | %>
6 |
7 |
8 |
9 | <%= value.name %>
10 |
11 | <% if(value.type){ %>
12 |
13 | <%= value.type %> <% if(value.format){ %> (<%= value.format %>) <% } %>
14 |
15 | <% } %>
16 | <% if ( value.required ) {%>
17 |
18 | required
19 |
20 | <% } %>
21 |
22 | <% if(value.description){ %>
23 |
24 | <%= value.description %>
25 |
26 | <% } %>
27 | <% if(value.values){ %>
28 |
29 | <%- 'Allowed values: ' + value.values.join(', ') + '.' %>
30 |
31 | <% } %>
32 | <% if(value.example){ %>
33 |
34 | Eg. <%= value.example %>
35 |
36 | <% } %>
37 |
38 | <% }); %>
39 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/requestParams.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | Path
4 |
5 | <% params.forEach((param) => {%>
6 |
7 |
8 |
9 | <%= param.name %>
10 |
11 | <% if ( param.type ) {%>
12 |
13 | <%= param.type %> <% if(param.format){ %> (<%= param.format %>) <% } %>
14 |
15 | <% } %>
16 | <% if ( param.required ) {%>
17 |
18 | required
19 |
20 | <% } %>
21 |
22 | <% if ( param.in ) { %>
23 |
24 | <%= `Used in ${param.in}` %>
25 |
26 | <% } %>
27 | <% if ( param.description ) { %>
28 |
29 | <%= param.description %>
30 |
31 | <% } %>
32 | <% if ( param.example ) { %>
33 |
34 | Eg: <%= param.example %>
35 |
36 | <% } %>
37 |
38 | <% }) %>
39 |
40 |
41 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/parameters.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { isExclude } = require('../utils');
4 | const { filter } = require('lodash');
5 |
6 |
7 | /**
8 | * Filter parameters.
9 | */
10 | const filterParameters = (swagger) => {
11 |
12 | const paramsToRemove = [];
13 | // Filter swager parameter definitions
14 | swagger.parameters && Object
15 | .keys(swagger.parameters)
16 | .forEach((key) => {
17 | const value = swagger.parameters[key];
18 | if (isExclude(value)){
19 | paramsToRemove.push(value.name);
20 | delete swagger.parameters[key];
21 | }
22 | });
23 |
24 |
25 | /**
26 | * Filter params for operations
27 | * */
28 | swagger.paths && Object
29 | .keys(swagger.paths)
30 | .forEach((key) => {
31 | const path = swagger.paths[key];
32 | path && Object
33 | .keys(path)
34 | .forEach((verb) => {
35 | const operation = path[verb];
36 | if ('object' !== typeof operation){
37 | return;
38 | }
39 |
40 | const parameters = operation.parameters;
41 | if (Array.isArray(parameters)){
42 | operation.parameters = filter(parameters, parameter => !paramsToRemove.includes(parameter.name) && !isExclude(parameter));
43 | }
44 | });
45 | });
46 |
47 | return swagger;
48 | };
49 |
50 |
51 | module.exports = filterParameters;
52 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/requestBody.ejs:
--------------------------------------------------------------------------------
1 | <% body.forEach((bodyObject) => {
2 | Object.keys(bodyObject).forEach((key) => {
3 | const value = bodyObject[key];
4 | value.name = key;
5 | %>
6 |
7 |
8 |
9 | <%= value.name %>
10 |
11 | <% if(value.type){ %>
12 |
13 | <%= value.type %> <% if(value.format){ %> (<%= value.format %>) <% } %>
14 |
15 | <% } %>
16 | <% if ( value.required ) {%>
17 |
18 | required
19 |
20 | <% } %>
21 |
22 | <% if(value.description){ %>
23 |
24 | <%= value.description %>
25 |
26 | <% } %>
27 | <% if(value.values){ %>
28 |
29 | <%- 'Allowed values: ' + value.values.join(', ') + '.' %>
30 |
31 | <% } %>
32 | <% if(value.example){ %>
33 |
34 | Eg. <%= value.example %>
35 |
36 | <% } %>
37 |
38 | <%
39 | });
40 | });
41 | %>
42 |
43 |
44 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/operations.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const operationsController = require('../operations');
4 |
5 | describe('controllers.operations', () => {
6 | it('should transform the context as expected', () => {
7 | const ctx = {
8 | paths: {
9 | '/foo/{fooId}': {
10 | 'get': {
11 | summary: 'Get Foo'
12 | },
13 | 'post': {
14 | summary: 'Post Foo'
15 | }
16 | },
17 | '/bar/{barId}': {
18 | 'get': {
19 | summary: 'Get Bar'
20 | }
21 | },
22 | },
23 | host: 'example.com',
24 | basePath: '/',
25 | schemes: ['https']
26 | };
27 |
28 | const {operations, baseUrl} = operationsController(ctx);
29 |
30 | expect(operations).toBeInstanceOf(Array);
31 | expect(operations.length).toBe(3);
32 |
33 | expect(operations[0].title).toBe('Get Foo');
34 | expect(operations[0].verb).toBe('get');
35 | expect(operations[0].path).toBe('/foo/{fooId}');
36 |
37 | expect(operations[1].title).toBe('Post Foo');
38 | expect(operations[1].verb).toBe('post');
39 | expect(operations[1].path).toBe('/foo/{fooId}');
40 |
41 | expect(operations[2].title).toBe('Get Bar');
42 | expect(operations[2].verb).toBe('get');
43 | expect(operations[2].path).toBe('/bar/{barId}');
44 |
45 | expect(baseUrl).toBe('https://example.com/');
46 |
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/layout/layout.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%- config.title %> | <%- page.title %>
7 |
8 |
9 |
10 | <%- project_partial('head_start') %>
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | <%- project_partial('head_end') %>
23 |
24 |
25 |
26 |
27 |
28 |
29 | <%- partial('_partial/navigation') -%>
30 | <%- body %>
31 | <%- partial('_partial/google_analytics') %>
32 |
33 | <%- project_partial('footer_start') %>
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | <%- project_partial('footer_end') %>
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/lib/browser/search/containers.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const $ = require('jquery');
3 | const {SHOW_SEARCH_RESULTS, HIDE_SEARCH_RESULTS} = require('./actions');
4 | const {subscribeOn} = require('../utils');
5 | const {SearchResultsTitle, SearchResultsList} = require('./components.jsx');
6 | const {SupportFooter} = require('../support/components.jsx');
7 |
8 | class SearchResults extends React.Component {
9 | constructor (props) {
10 | super(props);
11 | this.$page = $('#page-content');
12 | this.state = {
13 | query: null,
14 | visible: false,
15 | results: []
16 | };
17 | }
18 |
19 | componentDidMount () {
20 |
21 | subscribeOn(SHOW_SEARCH_RESULTS, (e) => {
22 | this.$page.hide();
23 | this.setState({
24 | query: e.query,
25 | visible: true,
26 | results: e.results
27 | });
28 | window.scrollTo(0,0);
29 | });
30 |
31 | subscribeOn(HIDE_SEARCH_RESULTS, () => {
32 | this.$page.show();
33 | this.setState({
34 | query: null,
35 | visible: false,
36 | results: []
37 | });
38 | });
39 | }
40 |
41 | render () {
42 | if (!this.state.visible) { return null; }
43 |
44 | const {theme_config} = this.props.config;
45 |
46 | return (
47 |
48 |
49 |
50 | { theme_config.support ? : null }
51 |
52 | );
53 | }
54 | }
55 |
56 | module.exports = {SearchResults};
57 |
--------------------------------------------------------------------------------
/lib/nodejs/support/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {merge} = require('lodash');
4 |
5 | describe('support', () => {
6 | const {filter, DEFAULT_CONFIG} = require('../index');
7 | describe('filter', () => {
8 | it('when font-matter page.support property is equal to false, it should leave untouched the locals object', () => {
9 | const locals = {
10 | page: { support: false }
11 | };
12 | const actual = filter(locals);
13 |
14 | expect(Object.keys(actual)).toEqual(Object.keys(locals));
15 | expect(actual.page.support).toEqual(locals.page.support);
16 | });
17 |
18 | it('when theme_config.support property is equal to a falsy value or undefined, it should leave untouched the locals object', () => {
19 | const locals = {
20 | page: { },
21 | config: {
22 | theme_config: { }
23 | }
24 | };
25 | const actual = filter(locals);
26 |
27 | expect(Object.keys(actual)).toEqual(Object.keys(locals));
28 | expect(actual.page.support).toEqual(locals.page.support);
29 | });
30 |
31 | it('should merge defaults to user provided support config', () => {
32 | const locals = {
33 | page: { },
34 | config: {
35 | theme_config: {
36 | support: {
37 | 'link_text': 'Hello'
38 | }
39 | }
40 | }
41 | };
42 | const actual = filter(locals);
43 | const expected = merge({}, DEFAULT_CONFIG, { link_text: 'Hello'});
44 |
45 | expect(actual.page.support).toEqual(expected);
46 | expect(actual.config.theme_config.support).toEqual(expected);
47 | });
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-ui/__tests__/parse-schema-file.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const ParseSchemaFileError = require('../parse-schema-file-error.js');
4 |
5 | describe('parse-schema-file', () => {
6 |
7 | const mockGetSwagger = jest.fn()
8 | .mockImplementationOnce(() => {
9 | return Promise.resolve({
10 | swagger: {
11 | swaggerJson: 'SWAGGER'
12 | }
13 | });
14 | })
15 | .mockImplementationOnce(() => {
16 | return Promise.reject(new ParseSchemaFileError({
17 | 'message': 'There is an error reading the file.',
18 | 'filePath': '/path/to/swagger/petstore.json',
19 | 'referencePath': 'path/to/md/file'
20 | }));
21 | });
22 |
23 | jest.mock('../../swagger-store', () => {
24 | return () => ({
25 | getSwagger: mockGetSwagger
26 | });
27 | });
28 |
29 | const parseSchemaFile = require('../parse-schema-file');
30 |
31 | test('should parse the schema file', async () => {
32 | const swaggerFilePath = '/path/to/swagger/petstore.json';
33 | const mdFilePath = 'path/to/md/file';
34 | const expectedOutput = {
35 | 'pageSource': mdFilePath,
36 | 'swagger': 'SWAGGER'
37 | };
38 | const hexo = {};
39 | await expect(parseSchemaFile(swaggerFilePath, mdFilePath, hexo)).resolves.toEqual(expectedOutput);
40 | expect(mockGetSwagger).toBeCalled();
41 | });
42 |
43 | test('should catch file read error for file read issues', async () => {
44 | const swaggerFilePath = '/path/to/swagger/petstore.json';
45 | const mdFilePath = 'path/to/md/file';
46 | await expect(parseSchemaFile(swaggerFilePath, mdFilePath)).rejects.toBeInstanceOf(ParseSchemaFileError);
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/lib/nodejs/__tests__/hexo-util.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Hexo = require('hexo');
4 | const hexo = new Hexo();
5 | const hexoUtil = require('../hexo-util');
6 | const mockRoute = 'mockRoute';
7 | const mockUrlFor = jest.fn().mockImplementation(route => '/' + route);
8 |
9 |
10 | hexo.config = {
11 | relative_link: 'relative_link'
12 | };
13 | hexo.extend.helper.store['url_for'] = mockUrlFor;
14 |
15 | describe('hexo-util', () => {
16 |
17 | const {url_for, themeConfig} = hexoUtil({hexo});
18 |
19 | describe('url_for', () => {
20 | const url = url_for(mockRoute);
21 | test('should call native url_for method', () => {
22 | expect(url).toEqual('/' + mockRoute);
23 | });
24 | });
25 |
26 | describe('themeConfig', () => {
27 |
28 | it('should initialize `theme_config` if undefined', () => {
29 | expect(hexo.config.theme_config).toBeUndefined();
30 | themeConfig();
31 | expect(hexo.config.theme_config).toBeDefined();
32 | });
33 |
34 | it('should return `theme_config` as the result of a deep merge with the object passed as an argument and the current `theme_config`', () => {
35 | hexo.config.theme_config = {
36 | foo: {
37 | bar: 'hello'
38 | },
39 | john: 'doe'
40 | };
41 | const defaults = {
42 | foo: {
43 | bar: 'world'
44 | },
45 | search: true
46 | };
47 |
48 | const actual = themeConfig(defaults);
49 | const expected = {
50 | foo: {
51 | bar: 'hello'
52 | },
53 | john: 'doe',
54 | search: true,
55 | };
56 |
57 | expect(actual).toEqual(expected);
58 | expect(hexo.config.theme_config).toEqual(expected);
59 | });
60 | });
61 | });
62 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/decorators/docExclude/filters/security.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { isExclude } = require('../utils');
4 |
5 |
6 | /**
7 | * Filteres securitDefinitions and security requirements.
8 | */
9 | const filterSecurity = (swagger) => {
10 |
11 | const securityToRemove = [];
12 |
13 | const securityDefinitions = swagger.securityDefinitions;
14 |
15 | const filterSecurityRequirements = (securityArr) => {
16 | return securityArr.reduce((acc, curr) => {
17 | const key = Object.keys(curr)[0];
18 | if (!securityToRemove.includes(key)){
19 | acc.push(curr);
20 | }
21 | return acc;
22 | },
23 | []);
24 | };
25 |
26 | // Remove security definitions
27 | securityDefinitions && Object
28 | .keys(securityDefinitions)
29 | .forEach((key) => {
30 | const value = securityDefinitions[key];
31 | if (isExclude(value)){
32 | securityToRemove.push(key);
33 | delete securityDefinitions[key];
34 | }
35 | });
36 |
37 | // Remove security requirements
38 | if (securityToRemove.length){
39 |
40 | // Global security
41 | if (swagger.security){
42 | swagger.security = filterSecurityRequirements(swagger.security);
43 | }
44 |
45 | // Local security
46 | swagger.paths && Object
47 | .keys(swagger.paths)
48 | .forEach((key) => {
49 | const path = swagger.paths[key];
50 | path && Object
51 | .keys(path)
52 | .forEach((verb) => {
53 | const operation = path[verb];
54 | if (operation.security){
55 | operation.security = filterSecurityRequirements(operation.security);
56 | }
57 | });
58 | });
59 | }
60 |
61 | return swagger;
62 | };
63 |
64 | module.exports = filterSecurity;
65 |
--------------------------------------------------------------------------------
/lib/browser/search/__tests__/containers.test.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const {shallow, mount} = require('enzyme');
3 | const {dispatch} = require('../../utils');
4 |
5 | const {HIDE_SEARCH_RESULTS, SHOW_SEARCH_RESULTS} = require('../actions');
6 |
7 | describe('browser.search.containers', () => {
8 |
9 | beforeEach(() => {
10 | document.documentElement.innerHTML = `
11 |
12 | `;
13 | });
14 |
15 | describe('SearchResults', () => {
16 | const {SearchResults} = require('../containers');
17 |
18 | it('in initial state it should not be visible', () => {
19 | const results = shallow();
20 | expect(results.getElement()).toBe(null);
21 | });
22 |
23 | it('when SHOW_SEARCH_RESULTS action is triggered, should be visible', () => {
24 | const results = mount();
25 | dispatch(SHOW_SEARCH_RESULTS, { results: [] });
26 | expect(results.getElement()).not.toBe(null);
27 | });
28 |
29 | it('when SHOW_SEARCH_RESULTS action is triggered, it should hide page content', () => {
30 | const results = mount();
31 | expect(results.instance().$page.css('display')).toBe('block');
32 | dispatch(SHOW_SEARCH_RESULTS, { results: [] });
33 | expect(results.instance().$page.css('display')).toBe('none');
34 | });
35 |
36 | it('when HIDE_SEARCH_RESULTS action is triggered, it should not be visible and the page content is visible', () => {
37 | const results = mount();
38 | dispatch(SHOW_SEARCH_RESULTS, { results: [] });
39 | expect(results.instance().$page.css('display')).toBe('none');
40 |
41 | dispatch(HIDE_SEARCH_RESULTS);
42 | expect(results.instance().$page.css('display')).toBe('block');
43 | expect(results.find('div').length).toBe(0);
44 | });
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/updateResult.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | describe('swagger-parser.lib.updateResult', () => {
5 |
6 | const {updateResult} = require('../../lib/updateResult');
7 |
8 | describe('for no key', () => {
9 | const result = {};
10 | const args = {};
11 |
12 | const output = updateResult(args);
13 |
14 | test('should do nothing and return false', () => {
15 | expect(output).toBe(false);
16 | expect(result).toEqual({});
17 | });
18 | });
19 |
20 | describe('when key is defined', () => {
21 | test('should update the result', () => {
22 | const result = {};
23 | const args = {
24 | object:{
25 | description: 'description',
26 | type: 'type',
27 | values: [1, 2],
28 | required: true,
29 | example: 'example',
30 | format: 'format'
31 | },
32 | key: 'key',
33 | result: result
34 | };
35 |
36 | updateResult(args);
37 |
38 | expect(result.key).toBeDefined();
39 |
40 | const _result = result.key;
41 |
42 | expect(_result.description).toBe('description');
43 | expect(_result.type).toBe('type');
44 | expect(_result.values).toEqual([1, 2]);
45 | expect(_result.required).toBe(true);
46 | expect(_result.example).toBe('example');
47 | expect(_result.format).toBe('format');
48 | });
49 | });
50 |
51 | describe('when isRequired is set', () => {
52 | test('should use it', () => {
53 | const result = {};
54 | const args = {
55 | object:{},
56 | key: 'key',
57 | result: result,
58 | isRequired: true
59 | };
60 |
61 | updateResult(args);
62 |
63 | expect(result.key).toBeDefined();
64 |
65 | const _result = result.key;
66 |
67 | expect(_result.required).toBe(true);
68 | });
69 | });
70 |
71 |
72 |
73 | });
74 |
--------------------------------------------------------------------------------
/lib/nodejs/search/__tests__/build.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const build = require('../build');
4 | const {mockLogger} = require('./mocks');
5 |
6 | describe('search.build', () => {
7 |
8 | it('should throw an error when `ctx.pages` is undefined', () => {
9 | expect(() => {
10 | build({logger: mockLogger});
11 | }).toThrow(new Error('Cannot find "pages" in the current context'));
12 | });
13 |
14 | it('should create the expected search index and expected store', () => {
15 | const result = build({
16 | logger: mockLogger,
17 | pages: [
18 | {title: 'foo', content: ' Foo
', path: '/foo', source: 'foo.md'},
19 | {title: 'bar', content: 'bar', path: '/bar', source: 'bar.md'}
20 | ]
21 | });
22 |
23 | expect(Object.keys(result.store).length).toBe(3);
24 | });
25 |
26 |
27 | it('should also use `ctx.pages.data` to support child process message', () => {
28 | const result = build({
29 | logger: mockLogger,
30 | pages: {
31 | data: [
32 | {title: 'foo', content: ' Foo
Body
Foo2
', path: '/foo', source: 'foo.md'},
33 | {title: 'bar', content: 'bar', path: '/bar', source: 'bar.md'}
34 | ]
35 | }
36 | });
37 |
38 | expect(Object.keys(result.store).length).toBe(4);
39 | });
40 |
41 | it('should process "mardown" files and skip the others', () => {
42 | const result = build({
43 | logger: mockLogger,
44 | pages: {
45 | data: [
46 | {title: 'foo', content: 'foo', path: '/foo', source: 'foo.md'},
47 | {title: 'bar', content: 'bar', path: '/bar', source: 'bar.markdown'},
48 | {title: 'john', content: 'john', path: '/john', source: 'john.mdown'},
49 | {title: 'exe', content: 'exe', path: '/exe', source: 'exe.exe'},
50 | ]
51 | }
52 | });
53 |
54 | expect(Object.keys(result.store).length).toBe(3);
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/templates/securityDefinition.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= key %>
4 |
5 | <% if(definition.description){ %>
6 |
7 | <%= definition.description %>
8 |
9 | <% } %>
10 | <% if(definition.type){ %>
11 |
12 | The type of security scheme is <%= definition.type %>.
13 |
14 | <% } %>
15 | <% if(definition.name){ %>
16 |
17 | The name of the <% if(definition.in === 'header'){ %>header<% }else{ %>query parameter<% } %> to be used is <%= definition.name %>.
18 |
19 | <% } %>
20 | <% if(definition.flow){ %>
21 |
22 | The flow used by the OAuth2 security scheme is <%= definition.flow %>.
23 |
24 | <% } %>
25 | <% if(definition.authorizationUrl){ %>
26 |
27 | The authorization URL to be used for this flow is <%= definition.authorizationUrl %>.
28 |
29 | <% } %>
30 | <% if(definition.tokenUrl){ %>
31 |
32 | The token URL to be used for this flow is <%= definition.tokenUrl %>.
33 |
34 | <% } %>
35 | <% if(definition.scopes){ %>
36 |
37 | The available scopes for the OAuth2 security scheme are as follows.
38 |
39 | <% Object.keys(definition.scopes).forEach((key) => { %>
40 |
41 | <%- key %>: <%-definition.scopes[key]%>
42 |
43 | <% }) %>
44 |
45 |
46 | <% } %>
47 |
48 |
--------------------------------------------------------------------------------
/source/style/_doc/vars.scss:
--------------------------------------------------------------------------------
1 | // breakpoints
2 | // -----------
3 | $doc-breakpoint: 800px !default;
4 | $doc-breakpoint-small: 480px !default;
5 |
6 | // colors
7 | // -------------
8 | $doc-color-primary: #fe6d05 !default;
9 | $doc-color-lightest: #fff !default;
10 | $doc-color-lighter: $dc-gray80 !default;
11 | $doc-color-light: #f3f3f3 !default;
12 | $doc-color-mediumlight: #eee !default;
13 | $doc-color-medium: #ccc !default;
14 | $doc-color-mediumdark: #999 !default;
15 | $doc-color-dark: #666 !default;
16 | $doc-color-darker: #444 !default;
17 | $doc-color-darkest: #333 !default;
18 |
19 | // navbar
20 | // -----
21 | $doc-navbar-height: 50px !default;
22 | $doc-navbar-background-color: $doc-color-lightest !default;
23 | $doc-navbar-border-color: #e1e1e1 !default;
24 | $doc-navbar-logo-text-color: $doc-color-primary !default;
25 | $doc-navbar-width-collapsed: $doc-navbar-height !default;
26 |
27 | // sidebar
28 | // ------
29 | $doc-sidebar-width: 230px !default;
30 | $doc-sidebar-width-collapsed: $doc-navbar-width-collapsed !default;
31 | $doc-sidebar-left-margin: 40px !default;
32 | $doc-sidebar-background-color: $doc-navbar-background-color !default;
33 | $doc-sidebar-color: $dc-gray30 !default;
34 | $doc-sidebar-label-color: $dc-gray20 !default;
35 | $doc-sidebar-current-color: $doc-color-primary !default;
36 | $doc-sidebar-item-border: 1px solid #ededed !default;
37 | $doc-sidebar-font-weight-normal: 300 !default;
38 | $doc-sidebar-font-weight-bold: 500 !default;
39 | $doc-sidebar-font-size-small: 12px !default;
40 | $doc-sidebar-font-size-normal: 14px !default;
41 |
42 | // support
43 | // -------
44 | $doc-support-footer-border-color: $dc-gray60 !default;
45 | $doc-support-footer-color: $dc-gray50 !default;
46 |
47 | // formatting
48 | // ----------
49 |
50 | // anchor
51 | $doc-anchor-color: $doc-color-medium !default;
52 | $doc-anchor-color-hover: $doc-color-primary !default;
53 |
54 | // blockquote
55 | $doc-blockquote-border-color: $doc-color-primary !default;
56 |
57 | // table
58 | $doc-table-border-color: $dc-gray60 !default;
59 | $doc-table-row-background-color: $dc-gray80 !default;
60 |
61 | // code
62 | $doc-inline-background-color: $dc-gray70 !default;
63 |
--------------------------------------------------------------------------------
/lib/nodejs/search/searcher.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const escapeStringRegexp = require('escape-string-regexp');
4 |
5 | module.exports = function searcher ({index, store}) {
6 | return function search (query) {
7 | let matches = index.search(query); // try search the exact keyword
8 |
9 | if (matches.length === 0) { // if no results, try with * "magic"
10 | matches = matches.concat(index.search(query + '*'));
11 | }
12 |
13 | return matches.reduce((results, match) => {
14 | // transform search match entries into actual results
15 | // by reconnecting them to store entry and enhance with useful properties
16 | // from search results
17 | if (store[match.ref]) {
18 | results.push(Object.assign({}, store[match.ref], {
19 | ref: match.ref,
20 | score: match.score,
21 | matchMetadata: match.matchData.metadata
22 | }));
23 | }
24 | return results;
25 | }, []).map((result) => {
26 | // enhance entry with highlight property representing
27 | // the actual matched tokens and the fields where those where found
28 | const highlight = Object.keys(result.matchMetadata).map((text) => {
29 | const fields = Object.keys(result.matchMetadata[text]);
30 | return { text, fields };
31 | });
32 | return Object.assign({}, result, { highlight });
33 |
34 | }).map((entry) => {
35 |
36 | // truncate `body` where "center" is the first matched text to highlight
37 | if (entry.body && entry.highlight.length) {
38 | const text = entry.highlight[0].text;
39 | const firstHighlightIndex = entry.body.indexOf(text);
40 | entry.body = '...' + entry.body.substring(firstHighlightIndex - 100, firstHighlightIndex + 200) + '...';
41 | }
42 |
43 | // add highlight markup
44 | entry.highlight.forEach((h) => {
45 | h.fields.forEach((f) => {
46 | if (f === 'body') {
47 | entry[f] = entry[f].replace(new RegExp(escapeStringRegexp(h.text), 'gi'), `${h.text}`);
48 | }
49 | });
50 | });
51 | return entry;
52 | });
53 | };
54 | };
55 |
--------------------------------------------------------------------------------
/lib/nodejs/search/generator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const { fork } = require('child_process');
5 | const build = require('./build');
6 | const hexoUtil = require('../hexo-util');
7 |
8 | /**
9 | * Return a function that represents the hexo generator.
10 | * When "hexo server" command is used we fork a child process to produce the search index in background since the task can be a time expensive operation.
11 | * When the child process it's done, it sends back a message containing the computed search index
12 | *
13 | * @param options.hexo - the hexo global instance
14 | * @return {Function} - hexo generator
15 | */
16 | module.exports = ({hexo}) => {
17 | const logger = hexo.log || console;
18 | const {url_for} = hexoUtil({hexo});
19 |
20 | function setRoute ({ hexo, result }) {
21 | const route = hexo.config.theme_config.search.route;
22 | const url = url_for(route);
23 | logger.debug(`New search index available at: ${url}`);
24 | hexo.route.set(route, JSON.stringify(result));
25 | }
26 |
27 | const {skip, background} = hexo.config.theme_config.search;
28 |
29 | if (skip) { return () => {}; }
30 |
31 | // build the index within the same process
32 | // wait for the task to complete
33 | if (!background) {
34 | return function (locals, cb) {
35 | logger.debug('Start building the search index');
36 | const result = build({pages: locals.pages, rootPath: hexo.config.root, logger});
37 | setRoute({hexo, result});
38 | cb();
39 | return result;
40 | };
41 | }
42 |
43 | if (background) {
44 | logger.debug('Open a background child process to build the search index');
45 | // use a child process to don't block the main process
46 | const child = fork(path.resolve(__dirname, './child.js'));
47 | child.on('message', (message) => {
48 | setRoute({ hexo, result: message });
49 | });
50 |
51 | return function (locals, cb) {
52 | logger.debug('Send a message to build the search index in background');
53 | child.send({
54 | pages: locals.pages,
55 | debug: hexo.env.debug,
56 | rootPath: hexo.config.root
57 | });
58 | cb();
59 | };
60 | }
61 | };
62 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/request.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const requestController = require('../request');
4 |
5 | describe('controllers.request', () => {
6 | it('should transform the context as expected', () => {
7 | const headerParam = {
8 | name: 'headerParam',
9 | in: 'header',
10 | description: 'description',
11 | required: 'true',
12 | type: 'string',
13 | format: 'format',
14 | };
15 | const pathParam = {
16 | name: 'pathParam',
17 | in: 'path',
18 | description: 'description',
19 | required: 'true',
20 | type: 'string',
21 | format: 'format',
22 | };
23 | const queryParam = {
24 | name: 'queryParam',
25 | in: 'query',
26 | description: 'description',
27 | required: 'true',
28 | type: 'string',
29 | format: 'format',
30 | };
31 | const formDataParam = {
32 | name: 'formDataParam',
33 | in: 'formData',
34 | description: 'description',
35 | required: 'true',
36 | type: 'string',
37 | format: 'format',
38 | };
39 | const bodyParam = {
40 | name: 'bodyParam',
41 | in: 'body',
42 | description: 'description',
43 | required: 'true',
44 | type: 'string',
45 | format: 'format',
46 | };
47 | const ctx = {
48 | operations: [ {} ],
49 | operation: {
50 | summary: 'A nice summary',
51 | description: 'A nice description',
52 | parameters: [
53 | headerParam,
54 | pathParam,
55 | queryParam,
56 | formDataParam,
57 | bodyParam
58 | ],
59 | tags: [],
60 | produces: [],
61 | responses: {},
62 | verb: 'get',
63 | path: '/path',
64 | title: 'title',
65 | }
66 | };
67 |
68 | const {request} = requestController(ctx);
69 |
70 | expect(request).toBeInstanceOf(Object);
71 | expect(Object.keys(request).length).toBe(5);
72 | expect(request.header[0]).toBe(headerParam);
73 | expect(request.path[0]).toBe(pathParam);
74 | expect(request.query[0]).toBe(queryParam);
75 | expect(request.formData[0]).toBe(formDataParam);
76 | expect(request.body[0]).toBe(bodyParam);
77 | });
78 | });
79 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/requestSample.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const { highlight } = require('../../helpers');
3 |
4 | const requestSample = (ctx) => {
5 | const sample = {
6 | header: {},
7 | formData: {},
8 | body: ''
9 | };
10 |
11 | const request = ctx.request;
12 | const baseUrl = ctx.baseUrl;
13 | let path = ctx.path;
14 | const verb = ctx.verb.toUpperCase();
15 |
16 | const pathParams = request.path;
17 | const queryParams = request.query;
18 |
19 | // Headers
20 | for (const header of request.header){
21 | sample.header[header.name] = header['x-example'];
22 | }
23 |
24 | // Form data
25 | for (const formData of request.formData){
26 | sample.formData[formData.name] = formData['x-example'];
27 | }
28 |
29 | // Update path with path params
30 | pathParams.forEach((param) => {
31 | if (param['x-example']){
32 | path = path.replace('{' + param.name + '}', param['x-example']);
33 | }
34 | });
35 |
36 | // Prepare query string
37 | const queryArray = [];
38 | queryParams.forEach((param) => {
39 | if (param['x-example']){
40 | queryArray.push(param.name + '=' + param['x-example']);
41 | }
42 | });
43 | const queryString = queryArray.join('&');
44 | if (queryString){
45 | path += '?' + queryString;
46 | }
47 |
48 | // Request body
49 | if (request.body.length){
50 | const _body = request.body[0]['x-examples'] && request.body[0]['x-examples']['default'];
51 | sample.body = JSON.stringify(_body, null, 2);
52 | }
53 |
54 |
55 | // Create CURL string
56 | let curlString = 'curl -v -X ' + verb + ' ' + baseUrl.replace(/\/$/, '') + path + ' \\\n';
57 |
58 | Object.keys(sample.header).forEach((header) => {
59 | if ('Authorization' === header){
60 | curlString += '-H "Authorization: Bearer " \\\n';
61 | } else {
62 | curlString += '-H "' + header + ': ' + sample.header[header] + '" \\\n';
63 | }
64 | });
65 |
66 | Object.keys(sample.formData).forEach((data) => {
67 | curlString += '-F "' + data + ': ' + sample.formData[data] + '" \\\n';
68 | });
69 |
70 | if (sample.body){
71 | curlString += sample.body;
72 | }
73 |
74 | curlString = curlString.replace(/\\\n$/, '');
75 | curlString = highlight({
76 | code: curlString,
77 | lang: 'bash'
78 | });
79 |
80 | return {
81 | curlString
82 | };
83 | };
84 |
85 |
86 | module.exports = requestSample;
87 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-ui/partials/v3/libs.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
37 |
--------------------------------------------------------------------------------
/lib/nodejs/search/__tests__/searcher.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const searcher = require('../searcher');
4 | const build = require('../build');
5 | const {mockLogger} = require('./mocks');
6 |
7 | describe('search.searcher', () => {
8 | let search;
9 |
10 | beforeAll(() => {
11 | const {index, store} = build({
12 | logger: mockLogger,
13 | pages: [
14 | {
15 | title: 'sed-cursus',
16 | content: 'Sed cursus nisl a interdum cursus. Sed consequat mi sit amet nulla molestie, vel cursus urna maximus. Etiam ac est ut libero condimentum eleifend quis feugiat urna. Vivamus consectetur odio diam, at faucibus lacus auctor sed. Nunc laoreet tellus id congue lobortis. Etiam et convallis velit. Donec a mauris quis ligula dignissim feugiat non in urna. In augue turpis, varius nec lacus sit amet, dictum sodales ante. Morbi volutpat eget libero ut porttitor.',
17 | path: 'sed',
18 | source: 'sed.md'
19 | },
20 | {
21 | title: 'lorem',
22 | content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed rhoncus elit libero, eget sollicitudin elit dignissim quis. Morbi ornare risus quis augue bibendum fringilla. Pellentesque pharetra pellentesque elit sed lobortis. Etiam dignissim, orci non convallis porta, erat nibh sodales nibh, et tempor leo diam ut lorem. Phasellus ullamcorper euismod dui, sit amet aliquam urna vestibulum accumsan. Integer ullamcorper cursus placerat. Aenean sodales, odio et efficitur mollis, sem nibh iaculis lacus, vel blandit nunc libero id risus. Ut ultrices diam ut magna porta, non molestie augue porttitor. Cras nec leo facilisis, lacinia risus quis, aliquet purus. In viverra et ligula eget ultrices. Integer ac tincidunt magna.',
23 | path: 'lorem',
24 | source: 'lorem.md'
25 | }
26 | ]
27 | });
28 | search = searcher({ index, store });
29 | });
30 |
31 | it('should return a `search` function', () => {
32 | expect(typeof search).toBe('function');
33 | });
34 |
35 | describe('search', () => {
36 | it('should return expected results in the right order', () => {
37 | const entries = search('sed');
38 | expect(entries.length).toBeGreaterThanOrEqual(2);
39 | expect(entries[0].ref).toBe('sed'); // has higher score since the search query was found also in the title
40 | expect(entries[1].ref).toBe('lorem');
41 | });
42 |
43 | it('should highlight and truncate the body according to the search query', () => {
44 | const entries = search('sed');
45 | expect(entries[0].body.indexOf('sed') > - 1).toBe(true);
46 | });
47 | });
48 |
49 | });
50 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/_petstore.yaml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | version: 1.0.0
4 | title: Swagger Petstore
5 | license:
6 | name: MIT
7 | host: petstore.swagger.io
8 | basePath: /v1
9 | schemes:
10 | - http
11 | consumes:
12 | - application/json
13 | produces:
14 | - application/json
15 | paths:
16 | /pets:
17 | get:
18 | summary: List all pets
19 | operationId: listPets
20 | tags:
21 | - pets
22 | parameters:
23 | - name: limit
24 | in: query
25 | description: How many items to return at one time (max 100)
26 | required: false
27 | type: integer
28 | format: int32
29 | responses:
30 | "200":
31 | description: An paged array of pets
32 | headers:
33 | x-next:
34 | type: string
35 | description: A link to the next page of responses
36 | schema:
37 | $ref: '#/definitions/Pets'
38 | default:
39 | description: unexpected error
40 | schema:
41 | $ref: '#/definitions/Error'
42 | post:
43 | summary: Create a pet
44 | operationId: createPets
45 | tags:
46 | - pets
47 | responses:
48 | "201":
49 | description: Null response
50 | default:
51 | description: unexpected error
52 | schema:
53 | $ref: '#/definitions/Error'
54 | /pets/{petId}:
55 | get:
56 | summary: Info for a specific pet
57 | operationId: showPetById
58 | tags:
59 | - pets
60 | parameters:
61 | - name: petId
62 | in: path
63 | required: true
64 | description: The id of the pet to retrieve
65 | type: string
66 | responses:
67 | "200":
68 | description: Expected response to a valid request
69 | schema:
70 | $ref: '#/definitions/Pets'
71 | default:
72 | description: unexpected error
73 | schema:
74 | $ref: '#/definitions/Error'
75 | definitions:
76 | Pet:
77 | required:
78 | - id
79 | - name
80 | properties:
81 | id:
82 | type: integer
83 | format: int64
84 | name:
85 | type: string
86 | tag:
87 | type: string
88 | Pets:
89 | type: array
90 | items:
91 | $ref: '#/definitions/Pet'
92 | Error:
93 | required:
94 | - code
95 | - message
96 | properties:
97 | code:
98 | type: integer
99 | format: int32
100 | message:
101 | type: string
102 |
--------------------------------------------------------------------------------
/lib/nodejs/project-partial/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | function createHelper ({theme_config, source_dir, render, log}) {
6 |
7 | let partials = null;
8 |
9 | function projectPartialHelper (area) {
10 |
11 | // Get and normalize "partials" configuration once and cache the result
12 | //
13 | // We do this operation inside the helper function because:
14 | //
15 | // - it means that `project_partial` template helper is really used in the layout
16 | // - the rendering process is involved (it will not be excuted if you run `hexo clean`, for example)
17 |
18 | if (!partials) {
19 | partials = getPartials({
20 | theme_config, source_dir, render, log
21 | });
22 | }
23 |
24 | if (!partials[area]) { return ''; }
25 |
26 | // in a hexo helper plugin function,
27 | // "this" represents the same context that hexo pass
28 | // when rendering theme's layout partials
29 | const locals = this;
30 | return partials[area]
31 | .map((p) => renderPartial(p, locals))
32 | .filter(h => h)
33 | .join('\n');
34 | }
35 |
36 | function renderPartial (partialPath, locals) {
37 | try {
38 | return render.renderSync({ path: partialPath }, locals);
39 | } catch (err) {
40 | log.error(`There was a problem while rendering partial "${partialPath}". skip rendering.`);
41 | log.error(`${err.message}`);
42 | log.debug(err);
43 | return '';
44 | }
45 | }
46 |
47 | return projectPartialHelper;
48 | }
49 |
50 | function getPartials ({theme_config, source_dir, render, log}) {
51 | const partials = Object.assign({
52 | head_start: [],
53 | head_end: [],
54 | footer_start: [],
55 | footer_end: []
56 | }, theme_config.partials);
57 |
58 | const isValidPartial = (p) => {
59 | return typeof p === 'string';
60 | };
61 |
62 | const isRenderablePartial = (p) => {
63 | if (!render.isRenderable(p) || render.getOutput(p) !== 'html') {
64 | log.warn(`partial "${p}" cannot be rendered or the output is not html.`);
65 | return false;
66 | }
67 | return true;
68 | };
69 |
70 | // "normalize" partials for each area:
71 | // - always use array type for each area
72 | // - exclude invalid partials or non renderable partials
73 | return Object.keys(partials).reduce((normalizedPartials, area) => {
74 |
75 | if (!Array.isArray(partials[area])) {
76 | partials[area] = [partials[area]];
77 | }
78 |
79 | normalizedPartials[area] = partials[area]
80 | .filter(isValidPartial)
81 | .map((p) => path.resolve(source_dir, p))
82 | .filter(isRenderablePartial);
83 |
84 | return normalizedPartials;
85 |
86 | }, {});
87 | }
88 |
89 | module.exports = { getPartials, createHelper };
90 |
--------------------------------------------------------------------------------
/plugins/swagger-to-html.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const { Promise } = require('bluebird');
6 | const validUrl = require('valid-url');
7 |
8 | module.exports = ({hexo}) => {
9 |
10 | const { url_for } = require('../lib/nodejs/hexo-util')({hexo});
11 | const {getRoute, getDigest, prepareRoute} = require('../lib/nodejs/swagger-store')({hexo});
12 |
13 | class SwaggerProcessor{
14 |
15 | /*
16 | * Default templating enging is 'html'.
17 | */
18 |
19 | constructor (engine = 'html'){
20 | const availableEngines = ['md', 'html'];
21 | this.engine = null;
22 |
23 | if (availableEngines.includes(engine)){
24 | this.engine = engine;
25 | } else {
26 | throw new TypeError(`Templating Engine(${engine}) is not supported.`);
27 | }
28 | }
29 |
30 | handleDownload (specPath){
31 | const downloadRoute = prepareRoute(specPath);
32 | const hexoRoute = url_for(downloadRoute);
33 | return hexoRoute;
34 | }
35 |
36 | get processor (){
37 |
38 | const transformer = require('../lib/nodejs/swagger-to-html')({hexo});
39 | const engine = this.engine;
40 | const that = this;
41 |
42 | return function (args){
43 | const ctx = this;
44 | let specPath = args[0];
45 |
46 | if(!validUrl.isUri(specPath)){
47 | specPath = path.resolve(path.dirname(ctx.full_source), specPath);
48 | }
49 |
50 | let output = '';
51 | const transformerPromise = new Promise((resolve, reject) => {
52 | const readableStream = transformer(specPath);
53 |
54 | readableStream.on('readable', () => {
55 | let chunk;
56 | while ((chunk = readableStream.read()) !== null) {
57 | output += chunk;
58 | }
59 | })
60 | .on('end', () => {
61 | resolve(output);
62 | })
63 | .on('error', (err) => {
64 | reject(err);
65 | });
66 | });
67 |
68 |
69 | return transformerPromise.then((output) => {
70 | const downloadRoute = that.handleDownload(specPath);
71 | return hexo.render.render({text: output.toString(), engine: engine })
72 | .then((html) =>
73 | ``
79 | );
80 | });
81 | };
82 | }
83 | }
84 |
85 | hexo.extend.tag.register('swagger_to_html', new SwaggerProcessor('html').processor, {async: true});
86 | };
87 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const controllers = require('./controllers');
5 |
6 |
7 | module.exports = {
8 | head: {
9 | order: 0,
10 | template: path.resolve(__dirname, './templates/head.ejs')
11 | },
12 | operations: {
13 | order: 2,
14 | template: path.resolve(__dirname, './templates/operations.ejs'),
15 | controller: controllers.operations
16 | },
17 | operation: {
18 | include: true,
19 | template: path.resolve(__dirname, './templates/operation.ejs'),
20 | controller: controllers.operation
21 | },
22 | header: {
23 | include: true,
24 | template: path.resolve(__dirname, './templates/header.ejs')
25 | },
26 | requestParams: {
27 | include: true,
28 | template: path.resolve(__dirname, './templates/requestParams.ejs')
29 | },
30 | requestBody: {
31 | include: true,
32 | template: path.resolve(__dirname, './templates/requestBody.ejs'),
33 | controller: controllers.requestBody
34 | },
35 | request: {
36 | include: true,
37 | template: path.resolve(__dirname, './templates/request.ejs'),
38 | controller: controllers.request
39 | },
40 | responses: {
41 | include: true,
42 | template: path.resolve(__dirname, './templates/responses.ejs'),
43 | controller: controllers.responses
44 | },
45 | response: {
46 | include: true,
47 | template: path.resolve(__dirname, './templates/response.ejs'),
48 | controller: controllers.response
49 | },
50 | emptyResponse: {
51 | include: true,
52 | template: path.resolve(__dirname, './templates/emptyResponse.ejs')
53 | },
54 | responseBody: {
55 | include: true,
56 | template: path.resolve(__dirname, './templates/responseBody.ejs')
57 | },
58 | requestSample: {
59 | include: true,
60 | template: path.resolve(__dirname, './templates/requestSample.ejs'),
61 | controller: controllers.requestSample
62 | },
63 | responseSample: {
64 | include: true,
65 | template: path.resolve(__dirname, './templates/responseSample.ejs'),
66 | controller: controllers.responseSample
67 | },
68 | security: {
69 | order: 1,
70 | template: path.resolve(__dirname, './templates/security.ejs'),
71 | controller: controllers.security
72 | },
73 | securityDefinition: {
74 | include: true,
75 | template: path.resolve(__dirname, './templates/securityDefinition.ejs')
76 | },
77 | securityRequirement: {
78 | include: true,
79 | template: path.resolve(__dirname, './templates/securityRequirement.ejs')
80 | },
81 | requestContent: {
82 | include: true,
83 | template: path.resolve(__dirname, './templates/requestContent.ejs')
84 | },
85 | formData: {
86 | include: true,
87 | template: path.resolve(__dirname, './templates/formData.ejs')
88 | }
89 | };
90 |
--------------------------------------------------------------------------------
/lib/browser/utils.js:
--------------------------------------------------------------------------------
1 | const urljoin = require('url-join');
2 | const $ = require('jquery');
3 |
4 | /**
5 | * Creates a function that mimic
6 | * url_for hexo helper function
7 | *
8 | * @param {Object} props - configuration properties
9 | * @return {Function} url_for function
10 | */
11 | function url_for (props) {
12 | return function (path) {
13 | if (/^(f|ht)tps?:\/\//i.test(path)) {
14 | return path;
15 | }
16 | const url = urljoin(
17 | props.config.root,
18 | path
19 | );
20 | return url.replace(/\/{2,}/g, '/'); // removes double slashes
21 | };
22 | }
23 |
24 | /**
25 | * Get heading html nodes in the current page
26 | * @return {jQuery} - a jQuery object
27 | */
28 | function getTOCHeaders () {
29 | return $('h2');
30 | }
31 |
32 | /**
33 | * dispatch an event
34 | * @param {string} eventType
35 | * @param {Object} [payload={}] - payload of the event
36 | * @return void
37 | */
38 | function dispatch (eventType, payload = {}) {
39 | const evt = new CustomEvent(eventType, { detail: payload });
40 | window.dispatchEvent(evt);
41 | }
42 |
43 | /**
44 | * subscribe to a specific event
45 | *
46 | * @param {string} eventType
47 | * @param {Function} cb - function called when the event is dispatched
48 | * @return {Function} - unsusscribe function
49 | */
50 | function subscribeOn (eventType, cb) {
51 | const handler = (e) => {
52 | cb(Object.assign({}, {type: e.type}, e.detail));
53 | };
54 |
55 | window.addEventListener(eventType, handler);
56 |
57 | return () => {
58 | window.removeEventListener(eventType, handler);
59 | };
60 | }
61 |
62 | /**
63 | * Reduce a map of [string]:boolean into a string,
64 | * concatenating the string keys when boolean value is true
65 | *
66 | * @exmaple
67 | *
68 | * // Button Component
69 | *
70 | * function Button(props) {
71 | * const className = classNames({
72 | * 'btn': true,
73 | * 'btn-disabled': props.disabled,
74 | * [props.classNames]: true // append classNames passed as props if any
75 | * });
76 | *
77 | * return (
78 | *
79 | * )
80 | * }
81 | *
82 | * // Usage
83 | *
84 | *
88 | *
89 | * // HTML
90 | *
91 | *
92 | *
93 | * @param {Object} [map={}]
94 | * @return {string}
95 | */
96 | function classNames (map = {}) {
97 | return Object.keys(map).reduce((acc, key) => {
98 | if (typeof key !== 'string' || key === 'undefined') { return acc; }
99 | if (map[key]) {
100 | return acc.concat(key);
101 | }
102 | return acc;
103 | }, []).join(' ');
104 | }
105 |
106 |
107 | module.exports = {url_for, getTOCHeaders, dispatch, subscribeOn, classNames};
108 |
--------------------------------------------------------------------------------
/lib/browser/search/components.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const {SHOW_SEARCH_RESULTS, HIDE_SEARCH_RESULTS} = require('./actions');
3 | const {dispatch} = require('../utils');
4 |
5 | class SearchForm extends React.Component {
6 |
7 | constructor (props) {
8 | super(props);
9 | }
10 |
11 | handleKeyUp (e) {
12 | const query = (e.target.value || '').trim();
13 |
14 | if (!query) {
15 | dispatch(HIDE_SEARCH_RESULTS);
16 | return;
17 | }
18 |
19 | if (query.length < 3) { return; }
20 |
21 | const results = this.props.search(query);
22 |
23 | dispatch(SHOW_SEARCH_RESULTS, {results, query});
24 |
25 | if (typeof this.props.onSearch === 'function') {
26 | this.props.onSearch();
27 | }
28 | }
29 |
30 | render () {
31 |
32 | if (!this.props.search) { return null; }
33 |
34 | return (
35 |
36 |
41 |
44 |
45 | );
46 | }
47 | }
48 |
49 | function SearchResultsTitle ({results, query}) {
50 | return (
51 |
52 |
53 | { results.length ? results.length : 'No' } results for "{query}"
54 |
55 |
56 | { !results.length ?
There are no results for "{query}". Why not try typing another keyword?
: null }
57 |
58 | );
59 | }
60 |
61 | function SearchResultsList ({results}) {
62 | if (!results.length) {
63 | return null;
64 | }
65 |
66 | const handleSearchResultLinkClick = () => dispatch(HIDE_SEARCH_RESULTS);
67 |
68 | const createMarkup = (html) => ({ __html: html });
69 |
70 | return (
71 |
72 | { results.map((result, i) => {
73 | return (
74 | -
75 |
79 | {result.title}
80 |
81 | |
82 | score: {result.score.toFixed(2)}
83 |
84 |
85 | );
86 | })}
87 |
88 | );
89 | }
90 |
91 | module.exports = {SearchForm, SearchResultsTitle, SearchResultsList};
92 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at oss-review@zalando.de. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/lib/nodejs/search/__tests__/generator.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | jest.mock('../../hexo-util', () => mockHexoUtil);
4 |
5 | const mockSend = jest.fn();
6 | const mockFork = jest.fn()
7 | .mockImplementation(() => ({
8 | on: () => {},
9 | send: mockSend
10 | }));
11 |
12 | jest.mock('child_process', () => ({
13 | fork: mockFork
14 | }));
15 |
16 | const {mockCb, mockHexo, mockHexoUtil} = require('./mocks');
17 | const generator = require('../generator');
18 |
19 | describe('search.generator', () => {
20 | let generate;
21 |
22 | beforeAll(() => {
23 | generate = generator({
24 | hexo: mockHexo
25 | });
26 | });
27 |
28 | it('should return a generate function', () => {
29 | expect(typeof generate).toBe('function');
30 | });
31 |
32 | describe('generate', () => {
33 | let result;
34 | beforeAll(() => {
35 | result = generate({
36 | pages: [
37 | {title: 'foo', content: '', path: '/foo', source: 'foo.md'},
38 | {title: 'bar', content: 'bar', path: '/bar', source: 'bar.md'}
39 | ]
40 | }, mockCb);
41 | });
42 |
43 | it('should return search `index` and `store` from pages', () => {
44 | expect(result.index).not.toBeUndefined();
45 | expect(result.store).not.toBeUndefined();
46 | });
47 |
48 | describe('index.search', () => {
49 | it('should return the expected results', () => {
50 | const results = result.index.search('b*');
51 | expect(results.length).toBeGreaterThan(0);
52 | });
53 | });
54 |
55 | it('store should contain only one specific entry, when "search:only" is used', () => {
56 | const result = generate({
57 | pages: [
58 | {title: 'foo', content: '', path: '/foo', source: 'foo.md'},
59 | {title: 'bar', content: 'bar', path: '/bar', source: 'bar.md', search: 'only'}
60 | ]
61 | }, () => {});
62 |
63 | expect(Object.keys(result.store).length).toBe(1);
64 | expect(result.store['/bar']).toBeDefined();
65 | });
66 |
67 | it('should throw an error when "pages" is not an array', () => {
68 | let error;
69 | try {
70 | generate({ pages: null }, () => {});
71 | } catch (err) {
72 | error = err;
73 | }
74 | expect(error instanceof Error).toBe(true);
75 | });
76 | });
77 |
78 | describe('when skip is true', () => {
79 | beforeAll(() => {
80 | mockHexo.config.theme_config.search = {
81 | skip: true
82 | };
83 | generate = generator({
84 | hexo: mockHexo
85 | });
86 | });
87 |
88 | test('should return an empty function', () => {
89 | const result = generate();
90 | expect(result).toBeUndefined();
91 | });
92 | });
93 |
94 | describe('when background is true', () => {
95 | beforeAll(() => {
96 | mockHexo.config.theme_config.search = {
97 | background: true
98 | };
99 | });
100 |
101 | test('should run task in background', () => {
102 | generate = generator({
103 | hexo: mockHexo
104 | });
105 |
106 | generate({pages: 'testPages'}, () => {});
107 | expect(mockSend).toHaveBeenCalled();
108 | expect(mockFork).toHaveBeenCalled();
109 | });
110 | });
111 | });
112 |
--------------------------------------------------------------------------------
/lib/nodejs/__tests__/swagger-store.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | /**
5 | * Mocking crypto.createHash('md5').update('...').digest('hex')
6 | */
7 | const mockCrypto = {
8 | createHash: jest.fn(() => {
9 | return mockCrypto;
10 | }),
11 | update: jest.fn(() => {
12 | return mockCrypto;
13 | }),
14 | digest: jest.fn(() => {
15 | return 'DIGEST';
16 | })
17 | };
18 |
19 | jest.mock('crypto',() => mockCrypto);
20 |
21 | function mockSwagger (){
22 | this.swaggerObject = '';
23 |
24 | this.validate = () => {
25 | this.swaggerObject += '-VALIDATED';
26 | return Promise.resolve(this);
27 | };
28 |
29 | this.merge = () => {
30 | this.swaggerObject += '-MERGED';
31 | return Promise.resolve(this);
32 | };
33 |
34 | this.unmerge = () => {
35 | this.swaggerObject += '-UNMERGED';
36 | return Promise.resolve(this);
37 | };
38 |
39 | this.decorate = mockSwagger.prototype.decorate = (x) => {
40 | this.swaggerObject += '-' + x();
41 | return Promise.resolve(this);
42 | };
43 | }
44 |
45 | jest.mock('../swagger', () => ({
46 | Swagger: mockSwagger,
47 | decorators: {
48 | docExclude: () => 'DOC_EXCLUDE' ,
49 | host: () => 'HOST'
50 | }
51 | }));
52 |
53 | describe('swagger-store', () => {
54 | const mockHexo = {
55 | config: {
56 | theme_config: {}
57 | }
58 | };
59 | const swaggerStore = require('../swagger-store')({hexo: mockHexo});
60 |
61 | it('should return swagger.helpers', () => {
62 | expect(Object.keys(swaggerStore).length).toBe(5);
63 | });
64 |
65 | it('should get digest', () => {
66 | const digest = swaggerStore.getDigest('/path/to/file');
67 | expect(digest).toEqual('DIGEST');
68 | expect(mockCrypto.createHash).toHaveBeenCalled();
69 | expect(mockCrypto.createHash).toHaveBeenCalledWith('md5');
70 | expect(mockCrypto.update).toHaveBeenCalled();
71 | expect(mockCrypto.update).toHaveBeenCalledWith('/path/to/file');
72 | expect(mockCrypto.digest).toHaveBeenCalled();
73 | expect(mockCrypto.digest).toHaveBeenCalledWith('hex');
74 | });
75 |
76 | it('should prepare routes', () => {
77 | const downloadRoute = swaggerStore.prepareRoute('/path/to/file.yaml');
78 | expect(downloadRoute).toBe('DIGEST/file.yaml');
79 | });
80 |
81 | it('should set and get route', () => {
82 | const result = swaggerStore.setRoute('ROUTE', 'DATA');
83 | const routeData = swaggerStore.getRoutes('ROUTE');
84 | expect(result).toBe(true);
85 | expect(routeData).toBe('DATA');
86 | });
87 |
88 | describe('when no route is passed in setRoute', () => {
89 | it('should no do anything', () => {
90 | const result = swaggerStore.setRoute();
91 | expect(result).toBe(false);
92 | });
93 | });
94 |
95 | describe('when no route is passed in getRoute', () => {
96 | it('should return all routes', () => {
97 | const routes = swaggerStore.getRoutes();
98 | expect(routes).toEqual({'ROUTE': 'DATA'});
99 | });
100 | });
101 |
102 | it('should get swagger', () => {
103 | return swaggerStore
104 | .getSwagger('/path/to/swagger')
105 | .then((swagger) => {
106 | expect(swagger.downloadRoute).toBe('DIGEST/swagger');
107 | expect(swagger.swagger.swaggerObject).toBe('-MERGED-DOC_EXCLUDE-HOST-UNMERGED');
108 | });
109 | });
110 | });
111 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/processItems/object.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockTraverse = jest.fn();
4 | const mockUpdateResult = jest.fn();
5 |
6 |
7 | jest.mock('../../../lib/traverse', () => ({
8 | traverse: mockTraverse
9 | }));
10 |
11 | jest.mock('../../../lib/updateResult', () => ({
12 | updateResult: mockUpdateResult
13 | }));
14 |
15 | const processObject = require('../../../lib/processItems/object');
16 |
17 | describe('swagger-parser.lib.processItems.object', () => {
18 | describe('when object is blank', () => {
19 | test('should use default values', () => {
20 | const object = {};
21 | const key = 'key';
22 | const isRequired = true;
23 | const result = {};
24 |
25 | processObject({object, key, isRequired, result});
26 |
27 | expect(mockTraverse).toHaveBeenCalledTimes(0);
28 |
29 | });
30 | });
31 |
32 | describe('when there is no key', () => {
33 | test('should use propertyName as key', () => {
34 | const object = {
35 | properties: {
36 | foo: {
37 | type: 'string'
38 | }
39 | },
40 | required: ['foo']
41 | };
42 | const key = '';
43 | const isRequired = true;
44 | const result = {};
45 |
46 | processObject({object, key, isRequired, result});
47 |
48 | expect(mockUpdateResult).toHaveBeenCalled();
49 | expect(mockUpdateResult).toHaveBeenCalledWith({object, key, isRequired, result});
50 |
51 | expect(mockTraverse).toHaveBeenCalledTimes(1);
52 | expect(mockTraverse).toHaveBeenCalledWith({object: {type: 'string'} , key: 'foo', isRequired: true});
53 |
54 | });
55 | });
56 |
57 | describe('if object have additionalProperties', () => {
58 | test('should handle them', () => {
59 | const object = {
60 | additionalProperties: {
61 | properties: {
62 | foo: {
63 | type: 'string'
64 | }
65 | },
66 | required: ['foo']
67 | }
68 | };
69 | const key = '';
70 | const isRequired = true;
71 | const result = {};
72 |
73 | processObject({object, key, isRequired, result});
74 |
75 | expect(mockUpdateResult).toHaveBeenCalled();
76 | expect(mockUpdateResult).toHaveBeenCalledWith({object, key, isRequired, result});
77 |
78 | expect(mockTraverse).toHaveBeenCalledTimes(1);
79 | expect(mockTraverse).toHaveBeenCalledWith({object: {type: 'string'} , key: 'foo', isRequired: true});
80 |
81 |
82 | });
83 | });
84 |
85 | test('should process object', () => {
86 | const object = {
87 | properties: {
88 | foo: {
89 | type: 'string'
90 | },
91 | bar: {
92 | type: 'object'
93 | }
94 | },
95 | required: ['foo']
96 | };
97 | const key = 'key';
98 | const isRequired = true;
99 | const result = {};
100 |
101 | processObject({object, key, isRequired, result});
102 |
103 | expect(mockUpdateResult).toHaveBeenCalled();
104 | expect(mockUpdateResult).toHaveBeenCalledWith({object, key, isRequired, result});
105 |
106 | expect(mockTraverse).toHaveBeenCalledTimes(2);
107 | expect(mockTraverse).toHaveBeenCalledWith({object: {type: 'string'} , key: key + '.foo', isRequired: true});
108 | expect(mockTraverse).toHaveBeenCalledWith({object: {type: 'object'} , key: key + '.bar', isRequired: false});
109 | });
110 | });
111 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-store.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {Swagger, decorators } = require('./swagger');
4 | const crypto = require('crypto');
5 | const path = require('path');
6 | const routeMap = Object.create(null);
7 | const validUrl = require('valid-url');
8 | const parseTemplateObject = require('@rbarilani/parse-template-object');
9 |
10 | module.exports = ({hexo}) => {
11 |
12 | let swaggerParserOptions = Object.assign({}, (hexo.config.theme_config.swagger_parser || {}));
13 | swaggerParserOptions = parseTemplateObject(swaggerParserOptions, {
14 | imports: {
15 | env: process.env
16 | }
17 | });
18 |
19 | const getDigest = (swaggerPath) => {
20 | return crypto
21 | .createHash('md5')
22 | .update(swaggerPath)
23 | .digest('hex');
24 | };
25 |
26 | const prepareRoute = function (specPath){
27 | const digest = getDigest(specPath);
28 | const basename = path.basename(specPath);
29 | const downloadRoute = digest + '/' + basename;
30 | return downloadRoute;
31 | };
32 |
33 |
34 | const handleRoute = (swagger, swaggerPath) => {
35 | const jsonSchema = swagger.swaggerJson;
36 | const yamlSchema = swagger.swaggerYaml;
37 | const extname = path.extname(swaggerPath);
38 | const downloadRoute = prepareRoute(swaggerPath);
39 |
40 | if (extname.match(/^\.json/)){
41 | setRoute(downloadRoute, jsonSchema);
42 | setRoute(downloadRoute.replace(/\.json/, '.yaml'), yamlSchema);
43 | } else {
44 | setRoute(downloadRoute, yamlSchema);
45 | setRoute(downloadRoute.replace(/\.yaml/, '.json'), jsonSchema);
46 | }
47 |
48 | /**
49 | * Hexo converts all the yaml file to json file.
50 | * removeLocalYamlRoute updates routeMap to remove that route.
51 | */
52 | if (!validUrl.isUri(swaggerPath)){
53 | removeLocalYamlRoute(swaggerPath);
54 | }
55 | return Promise.resolve(downloadRoute);
56 | };
57 |
58 |
59 | const removeLocalYamlRoute = (swaggerPath) => {
60 | const sourceDir = hexo.source_dir;
61 | const relativePath = swaggerPath
62 | .replace(sourceDir, '')
63 | .replace(/\.yaml$/, '.json')
64 | .replace(/\.yml$/, '.json');
65 | setRoute(relativePath, null);
66 | };
67 |
68 |
69 | const getSwagger = function (swaggerPath, dereferenced = false){
70 | const swagger = new Swagger(swaggerPath, swaggerParserOptions);
71 |
72 | return swagger
73 | .merge()
74 | .then(swagger => swagger.decorate(decorators.docExclude))
75 | .then(swagger => swagger.decorate(decorators.host))
76 | .then(swagger => swagger.unmerge(dereferenced))
77 | .then(swagger => {
78 | return handleRoute(swagger, swaggerPath);
79 | })
80 | .then(downloadRoute => {
81 | const result = {
82 | swagger,
83 | downloadRoute
84 | };
85 | return result;
86 | });
87 | };
88 |
89 | const setRoute = function (route, data){
90 | if (!route){
91 | return false;
92 | }
93 | routeMap[route] = data;
94 | return true;
95 | };
96 |
97 |
98 | const getRoutes = function (route){
99 | let routes = null;
100 |
101 | if (route){
102 | routes = routeMap[route];
103 | } else {
104 | routes = routeMap;
105 | }
106 | return routes;
107 | };
108 |
109 |
110 | return {
111 | getSwagger,
112 | getRoutes,
113 | setRoute,
114 | getDigest,
115 | prepareRoute
116 | };
117 |
118 | };
119 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger/__tests__/swagger-mocks.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const referencedSchema = {
4 | 'swagger': '2.0',
5 | 'parameters': {
6 | 'Auth': {
7 | 'name': 'Auth'
8 | }
9 | },
10 | 'paths': {
11 | '/pets': {
12 | 'get': {
13 | 'parameters': [
14 | {
15 | '$ref': '#/parameters/Auth'
16 | },
17 | {
18 | 'name': 'limit',
19 | 'in': 'query',
20 | 'description': 'Maximum number of results to return',
21 | 'required': false,
22 | 'type': 'integer',
23 | 'format': 'int32',
24 | 'x-example': 10
25 | }
26 | ],
27 | 'responses': {
28 | 'default': {
29 | 'schema': {
30 | '$ref': '#/definitions/Response'
31 | }
32 | }
33 | }
34 | }
35 | }
36 | },
37 | 'definitions': {
38 | 'Response': {
39 | 'type': 'object',
40 | 'properties': {
41 | 'name': {
42 | 'type': 'string'
43 | }
44 | }
45 | }
46 | }
47 | };
48 |
49 | const dereferencedSchema = {
50 | 'swagger': '2.0',
51 | 'parameters': {
52 | 'Auth': {
53 | 'name': 'Auth'
54 | }
55 | },
56 | 'paths': {
57 | '/pets': {
58 | 'get': {
59 | 'parameters': [
60 | {
61 | 'name': 'Auth'
62 | },
63 | {
64 | 'name': 'limit',
65 | 'in': 'query',
66 | 'description': 'Maximum number of results to return',
67 | 'required': false,
68 | 'type': 'integer',
69 | 'format': 'int32',
70 | 'x-example': 10
71 | }
72 | ],
73 | 'responses': {
74 | 'default': {
75 | 'schema': {
76 | 'type': 'object',
77 | 'properties': {
78 | 'name': {
79 | 'type': 'string'
80 | }
81 | }
82 | }
83 | }
84 | }
85 | }
86 | }
87 | },
88 | 'definitions': {
89 | 'Response': {
90 | 'type': 'object',
91 | 'properties': {
92 | 'name': {
93 | 'type': 'string'
94 | }
95 | }
96 | }
97 | }
98 | };
99 |
100 | const mergedSchema = {
101 | 'swagger': '2.0',
102 | 'parameters': {
103 | 'Auth': {
104 | 'name': 'Auth'
105 | }
106 | },
107 | 'paths': {
108 | '/pets': {
109 | 'get': {
110 | 'parameters': [
111 | {
112 | '$ref': '#/parameters/Auth',
113 | 'name': 'Auth'
114 | },
115 | {
116 | 'name': 'limit',
117 | 'in': 'query',
118 | 'description': 'Maximum number of results to return',
119 | 'required': false,
120 | 'type': 'integer',
121 | 'format': 'int32',
122 | 'x-example': 10
123 | }
124 | ],
125 | 'responses': {
126 | 'default': {
127 | 'schema': {
128 | '$ref': '#/definitions/Response',
129 | 'type': 'object',
130 | 'properties': {
131 | 'name': {
132 | 'type': 'string'
133 | }
134 | }
135 | }
136 | }
137 | }
138 | }
139 | }
140 | },
141 | 'definitions': {
142 | 'Response': {
143 | 'type': 'object',
144 | 'properties': {
145 | 'name': {
146 | 'type': 'string'
147 | }
148 | }
149 | }
150 | }
151 | };
152 |
153 | module.exports = {
154 | referencedSchema,
155 | dereferencedSchema,
156 | mergedSchema
157 | };
158 |
--------------------------------------------------------------------------------
/lib/nodejs/project-partial/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const {getPartials, createHelper} = require('../index');
4 | const {merge} = require('lodash');
5 |
6 | const mockLogger = {
7 | debug: jest.fn(),
8 | info () {},
9 | warn () {},
10 | error: jest.fn()
11 | };
12 |
13 | describe('project-partial.createHelper', () => {
14 | const defaultScenario = {
15 | source_dir: '/root',
16 | log: mockLogger,
17 | render: {
18 | isRenderable: () => true,
19 | getOutput: () => 'html',
20 | renderSync: jest.fn().mockReturnValue('foo')
21 | },
22 | theme_config: {
23 | partials: {
24 | head_start: './foo.ejs'
25 | }
26 | },
27 | area: 'head_start'
28 | };
29 |
30 | const scenarios = [{
31 | message: 'should render one partial for head_start area',
32 | expected: {
33 | helper_output: 'foo'
34 | }
35 | },
36 | {
37 | message: 'should render multiple partials for head_start area',
38 | theme_config: {
39 | partials: {
40 | head_start: ['./foo.ejs', './foo.ejs', './foo.ejs']
41 | }
42 | },
43 | expected: {
44 | helper_output: 'foo\nfoo\nfoo'
45 | }
46 | }, {
47 | message: 'should render empty string because error occured while rendering',
48 | render: {
49 | renderSync: () => { throw new Error('foo'); }
50 | },
51 | expected: {
52 | error: true,
53 | helper_output: ''
54 | }
55 | },{
56 | message: 'should render empty string because area doesn\'t exist',
57 | area: 'foo_bar',
58 | expected: {
59 | helper_output: ''
60 | }
61 | }];
62 |
63 | scenarios.map((scenario) => {
64 | const s = merge({}, defaultScenario, scenario);
65 | s.log.error.mockClear();
66 | const helper = createHelper(s);
67 |
68 | it(s.message, () => {
69 | expect(s.log.error).not.toHaveBeenCalled();
70 | expect(typeof helper).toEqual('function');
71 | expect(helper(s.area)).toEqual(s.expected.helper_output);
72 | expect(helper(s.area)).toEqual(s.expected.helper_output);
73 |
74 | if (s.expected.error) {
75 | expect(s.log.error).toHaveBeenCalled();
76 | }
77 | });
78 | });
79 | });
80 |
81 | describe('project-partial.getPartials', () => {
82 | const defaultScenario = {
83 | source_dir: '/root',
84 | log: mockLogger,
85 | };
86 |
87 | const scenarios = [{
88 | render: {
89 | isRenderable: () => true,
90 | getOutput: () => 'html'
91 | },
92 | theme_config: {
93 | partials: {
94 | head_start: './foo.ejs'
95 | }
96 | },
97 | expected: {
98 | head_start: ['/root/foo.ejs']
99 | }
100 | },
101 | {
102 | render: {
103 | isRenderable: () => true,
104 | getOutput: () => 'jpeg'
105 | },
106 | theme_config: {
107 | partials: {
108 | head_start: './foo.ejs'
109 | }
110 | },
111 | expected: {
112 | head_start: []
113 | }
114 | }];
115 |
116 | scenarios.map((scenario) => {
117 | const s = Object.assign({}, defaultScenario, scenario);
118 | const partials = getPartials(s);
119 |
120 | it('should return array for every area', () => {
121 | Object.keys(partials).forEach((area) => {
122 | const p = partials[area];
123 | expect(Array.isArray(p)).toBe(true);
124 | });
125 | });
126 |
127 | it('should transform a value into an array with one element', () => {
128 | expect(partials.head_start.length).toEqual(s.expected.head_start.length);
129 | });
130 |
131 | it('should resolve partials\' path relative to project source dir', () => {
132 | expect(partials.head_start).toEqual(s.expected.head_start);
133 | });
134 | });
135 | });
136 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hexo-theme-doc",
3 | "version": "1.0.0-rc.1",
4 | "main": "index.js",
5 | "description": "A documentation theme for Hexo",
6 | "keywords": [
7 | "hexo",
8 | "documentation",
9 | "theme",
10 | "swagger",
11 | "open-api"
12 | ],
13 | "license": "MIT",
14 | "homepage": "https://github.com/zalando-incubator/hexo-theme-doc",
15 | "author": "Bhaskar Melkani ",
16 | "contributors": [
17 | "Ruben Barilani "
18 | ],
19 | "scripts": {
20 | "test": "jest --config ./jest.json",
21 | "test:coverage": "NODE_ENV=test jest --coverage --no-cache --runInBand --config ./jest.json",
22 | "lint": "eslint lib packages scripts --ext .js,.jsx",
23 | "lint:report": "npm run lint -- -f checkstyle --output-file target/checkstyle.xml",
24 | "compile:sass": "npm run compile:sass:doc && npm run compile:sass:swagger-v2 && npm run compile:sass:swagger-v3",
25 | "compile:sass:doc": "node-sass _doc.scss source/style/doc.css --include-path node_modules --output-style='compressed'",
26 | "compile:sass:swagger-v2": "node-sass source/style/_swagger/swagger-ui-v2.scss source/style/swagger-ui-v2.css --output-style='compressed'",
27 | "compile:sass:swagger-v3": "node-sass source/style/_swagger/swagger-ui-v3.scss source/style/swagger-ui-v3.css --output-style='compressed'",
28 | "compile:js": "webpack -p",
29 | "compile": "npm run compile:sass && npm run compile:js && node banner.js",
30 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
31 | "prerelease": "npm run lint && npm run test && npm run compile && npm run changelog",
32 | "watch:sass": "nodemon -e scss -x 'npm run compile:sass'"
33 | },
34 | "repository": {
35 | "type": "git",
36 | "url": "git@github.com:zalando-incubator/hexo-theme-doc.git"
37 | },
38 | "dependencies": {
39 | "@rbarilani/parse-template-object": "^1.0.0",
40 | "babel-preset-es2015": "^6.24.1",
41 | "babel-preset-react": "^6.24.1",
42 | "babel-register": "^6.26.0",
43 | "cheerio": "^1.0.0-rc.1",
44 | "clipboard": "^1.7.1",
45 | "codacy-coverage": "^2.0.3",
46 | "consolidate": "^0.14.5",
47 | "dress-code": "~2.4.0",
48 | "ejs": "^2.5.7",
49 | "escape-string-regexp": "^1.0.5",
50 | "hexo-log": "^0.2.0",
51 | "is-plain-obj": "^1.1.0",
52 | "jquery": "^3.2.1",
53 | "js-crawler": "^0.3.19",
54 | "js-yaml": "^3.8.4",
55 | "jsx-loader": "^0.13.2",
56 | "lodash": "^4.17.4",
57 | "lunr": "2.1.0",
58 | "node-jsx": "^0.13.3",
59 | "react": "^16.0.0",
60 | "react-dom": "^16.0.0",
61 | "smooth-scroll": "^12.1.5",
62 | "strip-indent": "^2.0.0",
63 | "striptags": "^3.0.1",
64 | "swagger-parser": "^4.0.0",
65 | "touch": "^3.1.0",
66 | "url-join": "^2.0.2",
67 | "valid-url": "^1.0.9"
68 | },
69 | "devDependencies": {
70 | "babel-loader": "^7.1.2",
71 | "bootstrap-sass": "3.3.7",
72 | "conventional-changelog-cli": "^1.3.3",
73 | "enzyme": "^3.1.0",
74 | "enzyme-adapter-react-16": "^1.0.2",
75 | "eslint": "^4.1.1",
76 | "eslint-plugin-jest": "^20.0.3",
77 | "eslint-plugin-react": "^7.2.1",
78 | "hexo": "^3.3.7",
79 | "hexo-renderer-ejs": "^0.3.0",
80 | "jest": "^20.0.4",
81 | "jest-junit": "^2.1.0",
82 | "node-sass": "^4.5.3",
83 | "nodemon": "^1.12.1",
84 | "promise-polyfill": "^6.0.2",
85 | "raf": "^3.4.0",
86 | "react-test-renderer": "^16.0.0",
87 | "swagger-ui-dist": "^3.16.0",
88 | "webpack": "^3.0.0",
89 | "whatwg-fetch": "^2.0.3"
90 | },
91 | "jest-junit": {
92 | "output": "./target/junit.xml"
93 | },
94 | "babel": {
95 | "presets": [
96 | "react",
97 | "es2015"
98 | ]
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/modules/controllers/__tests__/requestSample.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 |
4 | const mockHighlight = jest.fn(() => 'CURL_STRING');
5 |
6 | jest.mock('../../../helpers', () => ({
7 | highlight: mockHighlight
8 | }));
9 |
10 | const requestSampleController = require('../requestSample');
11 |
12 | describe('controllers.requestSample', () => {
13 | it('should transform the context as expected', () => {
14 | const requestBody = {
15 | 'data': {
16 | 'type': 'Order',
17 | 'id': '123'
18 | }
19 | };
20 |
21 | const ctx = {
22 | 'request': {
23 | 'header': [
24 | {
25 | 'name': 'Authorization',
26 | 'in': 'header',
27 | 'description': 'JWT token',
28 | 'required': true,
29 | 'type': 'string',
30 | 'format': 'JWT token',
31 | 'x-example': 'ThisIsAnAuthToken'
32 | },
33 | {
34 | 'name': 'X-Flow-Id',
35 | 'in': 'header',
36 | 'description': 'For troubleshooting',
37 | 'required': false,
38 | 'type': 'string',
39 | 'format': 'uuid',
40 | 'x-example': 'ThisIsXFLOWID'
41 | }
42 | ],
43 | 'path': [
44 | {
45 | 'name': 'mid',
46 | 'in': 'path',
47 | 'description': 'To identify merchant this operation is carried out for',
48 | 'required': true,
49 | 'type': 'string',
50 | 'format': 'uuid',
51 | 'x-example': 'ThisIsMerchantId'
52 | },
53 | {
54 | 'name': 'oid',
55 | 'in': 'path',
56 | 'description': 'The ID of the order for which the items are being requested.',
57 | 'required': true,
58 | 'type': 'string',
59 | 'format': 'uuid',
60 | 'x-example': 'ThisIsAnOrderId'
61 | }
62 | ],
63 | 'query': [
64 | {
65 | 'name': 'include',
66 | 'in': 'query',
67 | 'description': 'Comma seperated field names to be included',
68 | 'required': false,
69 | 'type': 'string',
70 | 'x-example': 'ThisIsInclude'
71 | }
72 | ],
73 | 'formData': [
74 | {
75 | 'name': 'file',
76 | 'in': 'formData',
77 | 'description': "The merchant's document to create",
78 | 'required': true,
79 | 'type': 'file',
80 | 'x-example': 'ThisIsInclude'
81 | },
82 | {
83 | 'name': 'document-type',
84 | 'in': 'formData',
85 | 'description': "The merchant's document to create",
86 | 'required': true,
87 | 'type': 'string',
88 | 'x-example': 'ThisIsInclude'
89 | }
90 | ],
91 | 'body': [{
92 | 'in': 'body',
93 | 'name': 'order',
94 | 'description': 'Patch of order',
95 | 'required': true,
96 | 'schema': {},
97 | 'x-examples': {
98 | 'default': requestBody
99 | }
100 | }]
101 | },
102 | 'path': '/some/path/{mid}/{oid}',
103 | 'verb': 'get',
104 | 'baseUrl': 'https://example.com/'
105 | } ;
106 |
107 | let curlStr = 'curl -v -X GET https://example.com/some/path/ThisIsMerchantId/ThisIsAnOrderId?include=ThisIsInclude \\\n-H "Authorization: Bearer " \\\n-H "X-Flow-Id: ThisIsXFLOWID" \\\n-F "file: ThisIsInclude" \\\n-F "document-type: ThisIsInclude" \\\n';
108 |
109 | curlStr += JSON.stringify(requestBody, null, 2);
110 |
111 | const highlightArgs = {
112 | code: curlStr,
113 | lang: 'bash'
114 | };
115 |
116 | const {curlString} = requestSampleController(ctx);
117 |
118 | expect(mockHighlight).toHaveBeenCalled();
119 |
120 | expect(mockHighlight).toHaveBeenCalledWith(highlightArgs);
121 |
122 | expect(curlString).toBe('CURL_STRING');
123 |
124 | });
125 | });
126 |
127 |
--------------------------------------------------------------------------------
/lib/browser/search/__tests__/components.test.jsx:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const {shallow, mount} = require('enzyme');
3 |
4 | const {HIDE_SEARCH_RESULTS, SHOW_SEARCH_RESULTS} = require('../actions');
5 |
6 | describe('browser.search.components', () => {
7 |
8 | const mockDispatch = jest.fn();
9 |
10 | jest.mock('../../utils', () => ({ dispatch: mockDispatch }));
11 |
12 | afterEach(() => {
13 | mockDispatch.mockClear();
14 | });
15 |
16 | describe('SearchForm', () => {
17 | const {SearchForm} = require('../components.jsx');
18 |
19 | it('should not render anything if search props is null', () => {
20 | const searchForm = shallow();
21 | expect(searchForm.getElement()).toEqual(null);
22 | });
23 |
24 | it('should render the input if search props is a function', () => {
25 | const searchForm = shallow( {}} />);
26 | expect(searchForm.find('input').length).toEqual(1);
27 | });
28 |
29 | it('should hide search results if search query is empty', () => {
30 | const searchForm = shallow( {}} />);
31 | searchForm.find('input').simulate('keyup', { target: { value: '' } } );
32 | expect(mockDispatch).toHaveBeenCalledWith(HIDE_SEARCH_RESULTS);
33 | });
34 |
35 | it('should return immediately if query is too short', () => {
36 | const searchForm = shallow( []} />);
37 | searchForm.find('input').simulate('keyup', { target: { value: 'fo' } } );
38 | expect(mockDispatch).not.toHaveBeenCalled();
39 | });
40 |
41 | it('should show results if search query is not empty or too short', () => {
42 | const searchForm = shallow( []} />);
43 | searchForm.find('input').simulate('keyup', { target: { value: 'foobar' } } );
44 | expect(mockDispatch).toHaveBeenCalledWith(SHOW_SEARCH_RESULTS, expect.any(Object));
45 | });
46 |
47 |
48 | it('should call onSearch callback if it\'s a function', () => {
49 | const mockOnSearch = jest.fn();
50 | const searchForm = shallow( []} onSearch={mockOnSearch} />);
51 | searchForm.find('input').simulate('keyup', { target: { value: 'foobar' } } );
52 | expect(mockOnSearch).toHaveBeenCalled();
53 | });
54 | });
55 |
56 | describe('SearchResultsTitle', () => {
57 | const {SearchResultsTitle} = require('../components.jsx');
58 | it('should shallow render without any error', () => {
59 | const title = shallow();
60 | expect(title.length).toEqual(1);
61 | });
62 | });
63 |
64 | describe('SearchResultsList', () => {
65 | const {SearchResultsList} = require('../components.jsx');
66 |
67 | it('should not render anything if no results', () => {
68 | const list = shallow();
69 | expect(list.getElement()).toEqual(null);
70 | });
71 |
72 | it('should show the expected number of results', () => {
73 | const results = [{
74 | score: 0.4,
75 | title: 'foobar',
76 | body: 'foobar'
77 | }];
78 | const list = shallow();
79 | expect(list.find('ul').children('li').length).toBe(1);
80 | });
81 |
82 | it('should render result.body html value', () => {
83 | const results = [{
84 | score: 0.4,
85 | title: 'foobar',
86 | body: 'foobar
'
87 | }];
88 | const list = mount();
89 | expect(list.find('ul').children('li').find('p').html()).toBe('foobar
');
90 | });
91 |
92 | it('should hide results when a link is clicked', () => {
93 | const results = [{
94 | score: 0.4,
95 | title: 'foobar',
96 | body: 'foobar'
97 | }];
98 | const list = shallow();
99 |
100 | list.find('ul').children('li').find('a').last().simulate('click');
101 |
102 | expect(mockDispatch).toHaveBeenCalledWith(HIDE_SEARCH_RESULTS);
103 | });
104 | });
105 | });
106 |
--------------------------------------------------------------------------------
/lib/nodejs/search/build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const lunr = require('lunr');
4 | const striptags = require('striptags');
5 | const cheerio = require('cheerio');
6 | const path = require('path');
7 |
8 | /**
9 | * Build lunr search index and store
10 | *
11 | * Iterates over "registered" Indexers to get documents
12 | * to add to the search index and a store
13 | *
14 | * @param ctx - context
15 | * @return {{index, store}}
16 | */
17 | module.exports = function build (ctx) {
18 | const logger = ctx.logger;
19 | const hrstart = process.hrtime();
20 | const INDEXERS = [PagesIndexer];
21 |
22 | const { documents, store, items } = INDEXERS.reduce((acc, indexer) => {
23 | const { documents, store, items } = indexer.build(ctx);
24 | acc.store = Object.assign({}, acc.store, store);
25 | acc.documents = acc.documents.concat(documents);
26 | acc.items = acc.items.concat(items);
27 | return acc;
28 | }, {
29 | documents: [], // all documents that should be added to search index
30 | items: [], // all processed items
31 | store: {} // merged store
32 | });
33 |
34 | logger.debug(`Building search index and store for ${items.length} items, mapping to ${documents.length} documents`);
35 |
36 | const index = lunr(function () {
37 | this.ref('id');
38 | this.field('title');
39 | this.field('body');
40 | documents.forEach(function (doc) {
41 | this.add(doc);
42 | }, this);
43 | });
44 | const hrend = process.hrtime(hrstart);
45 | logger.debug(`Search index was built in ${hrend[0]}s, ${(hrend[1] / 1000000).toFixed()}ms`);
46 |
47 | return {
48 | index,
49 | store,
50 |
51 | };
52 | };
53 |
54 | function sanitize (html) {
55 | return striptags(html, [], ' ').trim() // strip html tags
56 | .replace(new RegExp('\n', 'g'), '') /* removes linebreaks */ // eslint-disable-line no-control-regex
57 | .replace(/ +(?= )/g,'') // removes double spaces
58 | .replace(/{|"|}|<|>/g, '');
59 | }
60 |
61 | function urlFor (rootPath, pagePath) {
62 | return path.join(rootPath || '/', pagePath);
63 | }
64 |
65 |
66 | /**
67 | * PagesIndexer
68 | *
69 | * @private
70 | * @type {{filter: Function, toData: Function}}
71 | */
72 | const PagesIndexer = {
73 | build: (ctx) => {
74 | const pages = Array.isArray(ctx.pages) ? ctx.pages : (ctx.pages && ctx.pages.data);
75 | const store = {};
76 |
77 | if (!Array.isArray(pages)) {
78 | throw new Error('Cannot find "pages" in the current context');
79 | }
80 |
81 | const items = pages.filter((page) => {
82 | const ext = page.source.split('.').pop().toLowerCase();
83 | return page.path
84 | && page.content
85 | && page.search !== 'exclude'
86 | && (ext === 'md' || ext === 'markdown' || ext === 'mdown');
87 | });
88 |
89 | const only = items.find((page) => {
90 | return page.search === 'only';
91 | });
92 |
93 | if (only) {
94 | items.length = 0;
95 | items.push(only);
96 | }
97 |
98 | const documents = items.reduce((acc, page) => {
99 | acc.push({
100 | id: page.path,
101 | title: page.title,
102 | body: sanitize(page.content),
103 | path: urlFor(ctx.rootPath, page.path)
104 | });
105 |
106 | const $ = cheerio.load(page.content);
107 | $('h1,h2').each(function () {
108 | const elem = $(this);
109 | const anchorPagePath = `${page.path}#${elem.attr('id')}`;
110 |
111 | let body = [];
112 |
113 | elem.nextUntil('h2').each(function () {
114 | body.push($(this).html());
115 | });
116 |
117 | body = body.join(' ');
118 |
119 | acc.push({
120 | id: `${page.path}#${elem.attr('id')}`,
121 | title: sanitize(elem.html()),
122 | body: sanitize(body),
123 | path: urlFor(ctx.rootPath, anchorPagePath)
124 | });
125 | });
126 | return acc;
127 | }, []);
128 |
129 | documents.forEach((doc) => {
130 | store[doc.id] = {
131 | title: doc.title,
132 | path: doc.path,
133 | body: doc.body
134 | };
135 | });
136 | return { documents, store, items };
137 | }
138 | };
139 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/helpers/parser/__tests__/lib/traverse.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mockProcessArray = jest.fn(() => {});
4 | const mockProcessObject = jest.fn(() => {});
5 | const mockProcessEnum = jest.fn(() => {});
6 | const mockProcessDefault = jest.fn(() => {});
7 |
8 | jest.mock('../../lib/processItems', () => ({
9 | processArray: mockProcessArray,
10 | processObject: mockProcessObject,
11 | processEnum: mockProcessEnum,
12 | processDefault: mockProcessDefault
13 | }));
14 |
15 | const {traverse} = require('../../lib/traverse');
16 |
17 | describe('swagger-parser.lib.traverse', () => {
18 | describe('if type is array', () => {
19 | const args = {
20 | object: {
21 | type: 'array'
22 | },
23 | key: 'mockKey',
24 | isRequired: 'isRequired'
25 | };
26 |
27 |
28 | test('should call processArray', () => {
29 |
30 | traverse(args);
31 |
32 | args['result'] = undefined;
33 |
34 | expect(mockProcessArray).toHaveBeenCalled();
35 | expect(mockProcessArray).toHaveBeenCalledWith(args);
36 | });
37 | });
38 |
39 | describe('if type is object', () => {
40 | const args = {
41 | object: {
42 | type: 'object'
43 | },
44 | key: 'mockKey',
45 | isRequired: 'isRequired'
46 | };
47 |
48 |
49 | test('should call processObject', () => {
50 |
51 | traverse(args);
52 |
53 | args['result'] = undefined;
54 |
55 | expect(mockProcessObject).toHaveBeenCalled();
56 | expect(mockProcessObject).toHaveBeenCalledWith(args);
57 | });
58 | });
59 |
60 | describe('if type is enum', () => {
61 | const args = {
62 | object: {
63 | enum: []
64 | },
65 | key: 'mockKey',
66 | isRequired: 'isRequired'
67 | };
68 |
69 |
70 | test('should call processEnum', () => {
71 |
72 | traverse(args);
73 |
74 | args['result'] = undefined;
75 |
76 | expect(mockProcessEnum).toHaveBeenCalled();
77 | expect(mockProcessEnum).toHaveBeenCalledWith(args);
78 | });
79 | });
80 |
81 | describe('for default case', () => {
82 | const args = {
83 | object: {
84 | type: 'string'
85 | },
86 | key: 'mockKey',
87 | isRequired: 'isRequired'
88 | };
89 |
90 |
91 | test('should call processEnum', () => {
92 |
93 | traverse(args);
94 |
95 | args['result'] = undefined;
96 |
97 | expect(mockProcessDefault).toHaveBeenCalled();
98 | expect(mockProcessDefault).toHaveBeenCalledWith(args);
99 | });
100 | });
101 |
102 | describe('when init is true', () => {
103 | const args = {
104 | object: {
105 | type: 'string'
106 | },
107 | key: 'mockKey',
108 | isRequired: 'isRequired',
109 | init: true
110 | };
111 |
112 |
113 | test('should set result to {}', () => {
114 |
115 | traverse(args);
116 |
117 | args['result'] = {};
118 |
119 | delete args['init'];
120 |
121 | expect(mockProcessDefault).toHaveBeenCalled();
122 | expect(mockProcessDefault).toHaveBeenCalledWith(args);
123 | });
124 | });
125 |
126 | describe('when allOf is present', () => {
127 | const args = {
128 | object: {
129 | type: 'object',
130 | allOf: [
131 | {
132 | type: 'object',
133 | properties: {
134 | name: {
135 | type: 'string'
136 | }
137 | }
138 | },
139 | {
140 | required: ['id'],
141 | properties: {
142 | id: {
143 | type: 'integer',
144 | format: 'int64'
145 | }
146 | }
147 | }
148 | ]
149 | },
150 | key: 'mockKey',
151 | isRequired: 'isRequired',
152 | init: true
153 | };
154 |
155 |
156 | test('should parse allOf', () => {
157 |
158 | traverse(args);
159 |
160 | const expectedArgs = {
161 | object: {
162 | type: 'object',
163 | required: ['id'],
164 | properties: {
165 | name: {
166 | type: 'string'
167 | },
168 | id: {
169 | type: 'integer',
170 | format: 'int64'
171 | }
172 | }
173 | },
174 | key: 'mockKey',
175 | isRequired: 'isRequired',
176 | result: {}
177 | };
178 |
179 | expect(mockProcessObject).toHaveBeenCalled();
180 | expect(mockProcessObject).toHaveBeenCalledWith(expectedArgs);
181 | });
182 | });
183 | });
184 |
--------------------------------------------------------------------------------
/lib/browser/navigation/__tests__/components.test.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const {mount, shallow} = require('enzyme');
3 |
4 | const itShouldAppendClasses = (Component) => {
5 | it('should append classes if any', () => {
6 | const className = 'custom-class';
7 | const component = shallow(React.createFactory(Component)({
8 | className
9 | }));
10 | expect(component.hasClass(className)).toBe(true);
11 | });
12 | };
13 |
14 | describe('browser.navigation.components', () => {
15 |
16 | describe('Navbar', () => {
17 | const {Navbar} = require('../components.jsx');
18 | it('should wrap children', () => {
19 | const navbar = mount(
20 |
21 |
22 |
23 | );
24 | expect(navbar.find('#foobar').length).toBe(1);
25 | });
26 | });
27 |
28 | describe('Logo', () => {
29 | const {Logo} = require('../components.jsx');
30 | it('should not render anything if props.navigation.logo is not set', () => {
31 | const logo = shallow();
32 | expect(logo.getElement()).toEqual(null);
33 | });
34 |
35 | it('should render if props.navigation.logo is set', () => {
36 | const logo = shallow( {}} navigation={{logo: {}}} />);
37 | expect(logo.find('a').length).toBe(1);
38 | });
39 | });
40 |
41 | describe('Sidebar', () => {
42 | const {Sidebar, SidebarItem} = require('../components.jsx');
43 | it('should render the expected number of items', () => {
44 | const sidebar = shallow();
48 | expect(sidebar.find(SidebarItem).length).toEqual(2);
49 | });
50 |
51 | it('should render the expected number of items when no items', () => {
52 | const sidebar = shallow();
53 | expect(sidebar.find(SidebarItem).length).toEqual(0);
54 | });
55 |
56 | it('should render the expected number of items when support navigation feature is on', () => {
57 | const support = {
58 | navigation: true,
59 | navigation_label: 'FOO',
60 | link_url: '/foo',
61 | link_text: 'foo'
62 | };
63 |
64 | const sidebar = shallow(
65 |
69 | );
70 | expect(sidebar.find(SidebarItem).length).toEqual(4);
71 | });
72 | });
73 |
74 | describe('SidebarItem', () => {
75 | const {SidebarItem} = require('../components.jsx');
76 |
77 | const createComponent = (props = {}) => {
78 | return React.createFactory(SidebarItem)(Object.assign({
79 | item: {
80 | path: '/bar',
81 | type: 'link'
82 | },
83 | page: {
84 | path: '/foo'
85 | },
86 | url_for: () => {},
87 | }, props));
88 | };
89 |
90 | it('shouldn\'t add TOC items if the item doesn\'t represent the current page', () => {
91 | const sidebarItem = mount(createComponent());
92 | expect(sidebarItem.find('.doc-sidebar-list__toc-list').length).toBe(0);
93 | });
94 |
95 | it('should add TOC items if the item represents the current page', () => {
96 | const sidebarItem = mount(createComponent({
97 | item: {
98 | path: '/foo',
99 | type: 'link',
100 | isCurrent: true
101 | },
102 | page: {
103 | path: '/foo'
104 | }
105 | }));
106 | expect(sidebarItem.find('.doc-sidebar-list__toc-list').length).toBe(1);
107 | });
108 |
109 | it('should render a label if the item type is "label"', () => {
110 | const sidebarItem = mount(createComponent({
111 | item: {
112 | type: 'label'
113 | }
114 | }));
115 | expect(sidebarItem.find('.doc-sidebar-list__item--label').length).toBe(1);
116 | });
117 | });
118 |
119 | describe('SidebarToggle', () => {
120 | const {SidebarToggle} = require('../components.jsx');
121 |
122 | it('should shallow render without any error', () => {
123 | const toggle = shallow();
124 | expect(toggle.length).toEqual(1);
125 | });
126 |
127 | itShouldAppendClasses(SidebarToggle);
128 | });
129 |
130 | describe('SidebarClose', () => {
131 | const {SidebarClose} = require('../components.jsx');
132 |
133 | it('should shallow render without any error', () => {
134 | const close = shallow();
135 | expect(close.length).toEqual(1);
136 | });
137 |
138 | itShouldAppendClasses(SidebarClose);
139 | });
140 | });
141 |
--------------------------------------------------------------------------------
/source/style/_doc/swagger-to-html.scss:
--------------------------------------------------------------------------------
1 | .doc-swagger-to-html{
2 |
3 | .inline-code{
4 | background: #f5f7fa;
5 | padding: 1px 5px;
6 | border-radius: 2px;
7 | border: 1px solid #e4e4e4;
8 | }
9 |
10 | .download-btn{
11 | overflow: hidden;
12 |
13 | &__link{
14 | float: right;
15 | font-weight: initial;
16 | }
17 | }
18 |
19 | .head{
20 |
21 | margin: 15px 0;
22 | overflow: hidden;
23 | $head-height: 34px;
24 |
25 | &__title{
26 | overflow: hidden;
27 |
28 | &__text{
29 | float: left;
30 | color: #4a4a4a;
31 | margin-top: 0px;
32 | margin-bottom: 5px;
33 | line-height: $head-height;
34 | }
35 | &__version{
36 | float: right;
37 | line-height: $head-height;
38 | margin-top: 0px;
39 | }
40 | }
41 |
42 | &__description{
43 | float: left;
44 | margin-top: 50px;
45 | }
46 | }
47 |
48 | .operation-info{
49 |
50 | &__title{
51 | border-bottom: 2px solid #d8d8d8;
52 | padding-bottom: 10px;
53 | position: relative;
54 | }
55 |
56 | &__verb{
57 | overflow: hidden;
58 | margin-top: 30px;
59 | }
60 |
61 | &__verb__name{
62 | font-size: 14px;
63 | font-weight: bold;
64 | float: left;
65 | color: #f7f7f7;
66 | padding: 10px 15px;
67 |
68 | &--get{
69 | $verb-color: #1fb3cb;
70 | background: $verb-color;
71 | border: 1px solid $verb-color;
72 | }
73 |
74 | &--post{
75 | $verb-color: #65cb1c;
76 | background: $verb-color;
77 | border: 1px solid $verb-color;
78 | }
79 |
80 | &--patch{
81 | $verb-color: #bb5cba;
82 | background: $verb-color;
83 | border: 1px solid $verb-color;
84 | }
85 |
86 | &--delete{
87 | $verb-color: #cc3a1d;
88 | background: $verb-color;
89 | border: 1px solid $verb-color;
90 | }
91 |
92 | &--put{
93 | $verb-color: #cc711d;
94 | background: $verb-color;
95 | border: 1px solid $verb-color;
96 | }
97 | }
98 |
99 | &__verb__path{
100 | font-size: 16px;
101 | color: #646464;
102 | padding: 10px 5px 10px 20px;
103 | border: solid 1px #d1d1d1;
104 | border-left: none;
105 | overflow: hidden;
106 | }
107 | }
108 |
109 | .request, .response{
110 | overflow: hidden;
111 |
112 | &__title{
113 | overflow: hidden;
114 |
115 | &__sample, &__reference{
116 | float: left;
117 | width: 50%;
118 | }
119 | }
120 |
121 | &__content{
122 | border: solid 1px #ededed;
123 | width: 100%;
124 | table-layout: fixed;
125 |
126 | &__sample, &__reference{
127 | width: 50%;
128 | padding: 15px;
129 | vertical-align: top;
130 | }
131 |
132 | &__sample{
133 | background: #ededed;
134 | }
135 | }
136 | }
137 |
138 | .reference-card{
139 |
140 | margin-top: 40px;
141 |
142 | &:first-of-type{
143 | margin-top: initial;
144 | }
145 |
146 | &__title{
147 | border-bottom: 2px solid #ededed;
148 | padding-bottom: 10px;
149 | color: #4a4a4a;
150 | }
151 |
152 | &__content{
153 | margin-top: 15px;
154 |
155 | &__info{
156 | overflow: hidden;
157 |
158 | &__name, &__type, &__required{
159 | float: left;
160 | border-left: 2px solid #ededed;
161 | font-size: 14px;
162 | padding: 0 15px;
163 |
164 | &:first-child{
165 | border-left: initial;
166 | }
167 | }
168 |
169 | &__name{
170 | font-weight: bold;
171 | font-size: 14px;
172 | padding-left: initial;
173 | }
174 |
175 | &__type{
176 | color: #b6b6b6;
177 | }
178 |
179 | &__required{
180 | color: #ff917d;
181 | }
182 | }
183 |
184 | &__description, &__example, &__usage, &__values{
185 | margin-top: 10px;
186 | }
187 | }
188 |
189 | }
190 |
191 | .sample-snippet{
192 |
193 | &__copy-btn{
194 | margin-top: 10px;
195 |
196 | &.dc--has-tooltip:after{
197 | text-transform: initial;
198 | }
199 | }
200 |
201 | .highlight{
202 | margin: 0;
203 | overflow: hidden;
204 |
205 | table{
206 | table-layout: fixed;
207 | width: 100%;
208 |
209 | .code{
210 | pre{
211 | background: initial;
212 | padding: initial;
213 | }
214 |
215 | .line{
216 | white-space: pre-wrap;
217 | }
218 | }
219 | }
220 | }
221 | }
222 |
223 | }
224 |
--------------------------------------------------------------------------------
/lib/nodejs/swagger-to-html/__tests__/core.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const {createTransformer} = require('../core');
5 |
6 | describe('swagger-processor.core', () => {
7 |
8 | describe('createTransformer', () => {
9 | const testTranformer = createTransformer({
10 | modules: {
11 | body: {
12 | order: 1,
13 | template: path.resolve(__dirname, './templates/body.ejs'),
14 | controller: (ctx) => {
15 | return { text: ctx.body_text };
16 | }
17 | },
18 | head: {
19 | order: 0,
20 | template: path.resolve(__dirname, './templates/head.ejs')
21 | }
22 | }
23 | });
24 |
25 | it('should be a function', () => {
26 | expect(typeof testTranformer).toEqual('function');
27 | });
28 |
29 | it('should transform the input in the expected output', (done) => {
30 | const data = [];
31 | testTranformer({
32 | title: 'title',
33 | body_text: 'body'
34 | }).on('data', (chunk) => {
35 | data.push(chunk.toString());
36 | }).on('error', done.fail)
37 | .on('end', () => {
38 | expect(data[0].trim()).toEqual('title');
39 | expect(data[1].trim()).toEqual('body');
40 | done();
41 | });
42 | });
43 |
44 | it('should transform the input in the expected output in the right order', (done) => {
45 | const delayedTransformer = createTransformer({
46 | render: (tpl) => {
47 | // "inject" a custom render function to emulate a delay
48 | const delay = tpl === 'a' ? 500 : 0;
49 | return new Promise((resolve) => {
50 | setTimeout(() => {
51 | resolve(tpl);
52 | }, delay);
53 | });
54 | },
55 | modules: {
56 | b: {
57 | order: 1,
58 | template: 'b'
59 | },
60 | a: {
61 | order: 0,
62 | template: 'a'
63 | }
64 | }
65 | });
66 |
67 | const data = [];
68 | delayedTransformer().on('data', (chunk) => {
69 | data.push(chunk.toString());
70 | }).on('error', done.fail)
71 | .on('end', () => {
72 | expect(data[0].trim()).toEqual('a');
73 | expect(data[1].trim()).toEqual('b');
74 | done();
75 | });
76 | });
77 |
78 | it('should emit error and close the stream when input function rejects', (done) => {
79 | const testError = new Error('test error');
80 | const failingTransformer = createTransformer({
81 | input: () => Promise.reject(testError),
82 | modules: {}
83 | });
84 | failingTransformer().on('error', (err) => {
85 | expect(err).toBe(testError);
86 | done();
87 | });
88 | });
89 |
90 | it('should emit error and close the stream when controller function throw an error', (done) => {
91 | const testError = new Error('test error');
92 | const failingTransformer = createTransformer({
93 | modules: {
94 | foo: {
95 | controller: () => { throw testError; }
96 | }
97 | }
98 | });
99 | failingTransformer().on('error', (err) => {
100 | expect(err).toBe(testError);
101 | done();
102 | });
103 | });
104 | });
105 |
106 | describe('include_module', () => {
107 | const includeModuleTestTransformer = createTransformer({
108 | modules: {
109 | head: {
110 | template: path.resolve(__dirname, './templates/head-include-module.ejs')
111 | },
112 | subtitle: {
113 | include: true,
114 | template: path.resolve(__dirname, './templates/includes/subtitle.ejs')
115 | },
116 | description: {
117 | include: true,
118 | template: path.resolve(__dirname, './templates/includes/description.ejs')
119 | }
120 | }
121 | });
122 |
123 | it('should transform the input using include_module template helper', (done) => {
124 | const data = [];
125 | includeModuleTestTransformer({
126 | title: 'title',
127 | subtitle: 'subtitle'
128 | }).on('data', (chunk) => {
129 | data.push(chunk.toString());
130 | }).on('error', done.fail).on('end', () => {
131 | expect(data[0].trim()).toEqual('title\n\nsubtitle\n\ndescription');
132 | done();
133 | });
134 | });
135 |
136 | it('should return an empty string for a non-existent module', (done) => {
137 | const data = [];
138 | const transformer = createTransformer({
139 | modules: {
140 | head: {
141 | template: path.resolve(__dirname, './templates/head-include-module-doesnt-exist.ejs')
142 | }
143 | }
144 | });
145 |
146 | transformer({
147 | title: 'title',
148 | }).on('data', (chunk) => {
149 | data.push(chunk.toString());
150 | }).on('error', done.fail).on('end', () => {
151 | expect(data[0].trim()).toEqual('title');
152 | done();
153 | });
154 | });
155 |
156 | });
157 | });
158 |
--------------------------------------------------------------------------------