diff --git a/.gitignore b/.gitignore index 7cdd4248..7dd3936a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,5 @@ -.idea +lib node_modules npm-debug.log -lib -test-js -coverage.html -example.html -example-compiled.apib +coverage +cache diff --git a/.npmignore b/.npmignore index 73d4e798..8f32cd36 100644 --- a/.npmignore +++ b/.npmignore @@ -1,8 +1,7 @@ -.DS_Store -.idea -.git +coverage +node_modules src test -node_modules npm-debug.log -example-compiled.apib +.travis.yml +cache diff --git a/.travis.yml b/.travis.yml index cb2cd599..256a33da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,12 @@ language: node_js sudo: false node_js: - - "0.10" - - "0.12" + - 0.10 + - 0.12 + - iojs - "3" - "4" - "5" - "6" -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-4.8 - - g++-4.8 -env: CXX="g++-4.8" CC="gcc-4.8" -before_install: - - npm install -g grunt-cli after_script: - - grunt coveralls + - npm run coveralls diff --git a/Changelog.md b/Changelog.md index daa10b57..bc70c287 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,150 +1,166 @@ -# 2.3.0 +# 1.6.3 - 2016-05-20 -* Switch to [Drafter](https://github.com/apiaryio/drafter-npm) for API Blueprint parsing. [#277](https://github.com/danielgtaylor/aglio/pull/277) -* Fix case when no arguments are supplied after `-o` [#262](https://github.com/danielgtaylor/aglio/pull/262) +* Fix for overlapping URI in Olio theme engine [#242](https://github.com/danielgtaylor/aglio/pull/242) +* Leave trailing slashes if specified in the URI template. This prevents showing an incorrect URI. [#254](https://github.com/danielgtaylor/aglio/pull/254) +* Improved rendering of URI templates [#200](https://github.com/danielgtaylor/aglio/pull/200) -# 2.2.1 - 2016-05-20 +# 1.6.2 - 2015-11-16 -* Bump protagonist version to 1.3.2 to support new features. [#256](https://github.com/danielgtaylor/aglio/pull/256) -* Update required default theme version to [1.6.3](https://github.com/danielgtaylor/aglio/blob/olio-theme/Changelog.md#163---2016-05-20). +* Use all element descriptions when available for JSON Schema generation. -# 2.2.0 - 2015-10-26 +# 1.6.1 - 2015-11-13 -* Support for Node.js 3.x and 4.x. [#183](https://github.com/danielgtaylor/aglio/issues/183) -* Upgraded to [Protagonist](https://github.com/apiaryio/protagonist) version 1.x, which has disabled the JSON Schema generation from MSON until some bugs can be worked out. +* Show sample values (if they exist) for named path parameters. [#193](https://github.com/danielgtaylor/aglio/issues/193) +* Properly handle MSON mixin property precedence. +* Properly handle MSON inheritance with overridden members. [#197](https://github.com/danielgtaylor/aglio/issues/197) -# 2.1.1 - 2015-09-14 +# 1.6.0 - 2015-11-11 -* Fix the default include path behavior when outputting a file to use the basename of the input file rather than `process.cwd()`. Also updates documentation to mention this behavior and option. [#166](https://github.com/danielgtaylor/aglio/issues/166) +* Allow disabling emoji support via `--no-theme-emoji`. [#194](https://github.com/danielgtaylor/aglio/issues/194) +* Support `One Of` mutually exclusive parameters in JSON Schema. +* Support `nullable` member attribute in JSON Schema. -# 2.1.0 - 2015-09-11 +# 1.5.0 - 2015-11-10 -* Add a `--include-path` option to set the path for relative includes. [#165](https://github.com/danielgtaylor/aglio/pull/165) +* Generate JSON examples internally rather than relying on Drafter. You can disable this feature by setting the `DRAFTEREXAMPLES` environment variable. For example: -# 2.0.4 - 2015-08-14 + ``` + DRAFTEREXAMPLES=1 aglio -i input.apib -o output.html + ``` -* Show theme name before loading when given `--verbose` option. -* Update required default theme version to [1.2.0](https://github.com/danielgtaylor/aglio/blob/olio-theme/Changelog.md#120---2015-08-14). +# 1.4.1 - 2015-11-10 -# 2.0.3 - 2015-08-12 +* Handle homogenous arrays with multiple samples better in the JSON Schema generator. +* Make navigation badge margin configurable. +* Permalink rendering fixes. +* Fix a looping bug in the JSON Schema generator. [#189](https://github.com/danielgtaylor/aglio/pull/189). +* Don't display `undefined` in URI example, and prevent including resource parameters when actions define their own URI template. [#190](https://github.com/danielgtaylor/aglio/pull/190) -* Update required default theme version to [1.1.0](https://github.com/danielgtaylor/aglio/blob/olio-theme/Changelog.md#110---2015-08-12). -* Readme and example updates. +# 1.4.0 - 2015-11-04 -# 2.0.2 - 2015-08-04 +* Tweaks to the `streak` theme. +* Add an extremely basic JSON Schema generator as a band-aid over missing functionality in Protagonist 1.x. -* Update required default theme version to support custom jade templates written for Aglio 1.x. -* Add a `--verbose` output option for errors that displays pretty stack traces. -* Provide more descriptive errors. +# 1.3.0 - 2015-10-30 -# 2.0.1 - 2015-08-03 +* Support built-in layout templates by name using `--theme-layout name`. +* Add a three-paned theme layout called `triple`. Use it with `--theme-layout triple`. All variable/color schemes are supported. [#161](https://github.com/danielgtaylor/aglio/issues/161) +* Show example URI for each action so that users with little URI template experience can quickly understand how URI parameters should work. [#138](https://github.com/danielgtaylor/aglio/issues/138) +* Add variables to better control font information, table styling, column sizing, hover effects, and more. This makes it even easier to modify existing themes to match your project's or company's style. +* Add a new simplified theme called `streak`. Use with `--theme-variables streak`. -* Add backward-compatible support for the `aglio` binary to specify a custom layout via the `-t` commandline option. Example: `aglio -i input.apib -t /path/to/my.jade -o output.html` -* Display default theme version when using `aglio --version`. +# 1.2.1 - 2015-09-01 -# 2.0.0 - 2015-07-16 -This is a new major version of Aglio, and as such has some breaking changes. -High-level changes in this release: +* Disable the auto-escaping of headers or navigation items to allow HTML. [#159](https://github.com/danielgtaylor/aglio/issues/159) [#160](https://github.com/danielgtaylor/aglio/issues/160) +* Use HTTPS links for Google Web Fonts. [#147](https://github.com/danielgtaylor/aglio/pull/147) -* Use [Drafter.js](https://github.com/apiaryio/drafter.js) to support [MSON](https://github.com/apiaryio/mson) via generated request/response bodies and schemas. -* Add support for [theme engines](https://github.com/danielgtaylor/aglio#using-custom-themes). -* Use [Olio](https://github.com/danielgtaylor/aglio/tree/olio-theme#readme) as the new default theme engine. -* API and resource group description headers are now included in the navigation bar. -* Server mode can now serve static files, which is useful if your documentation contains images. -* Fixes to how resource and action parameters are handled. +# 1.2.0 - 2015-08-14 -For more detailed information, see the beta releases below. +* Fix a minor template warning. +* Add extra output when the `--verbose` option is passed. This now shows information about the caches used and generated. +* Accept multiple `--theme-variables` and `--theme-style` arguments. When given + an array, each item is added to the final stylesheet in order. This means + that you can do something like this now: -Effort was taken to prevent backward-incompatible changes. Here is a list of -things that **will break** if you used them in 1.x. + ```sh + aglio -i input.apib -o output.html --theme-variables flatly --theme-variables ./my-customizations.less + ``` -Binary: -* It is no longer possible to list templates (`aglio -l`). You may use `npm list -g | grep aglio-theme` to list all installed theme engine packages instead. Refer to individual theme documentation for possible theme engine options. +* Cached assets are now stored via their key's SHA1 hash because of filename + length limits. +* Add auto-scrollbars to code blocks so that long lines can be seen. [#152](https://github.com/danielgtaylor/aglio/issues/152) -Library: -* The `aglio.getTemplates` function has been **removed**. +# 1.1.0 - 2015-08-12 -Templates: -* The multi-page layouts have been **removed**. Please open an issue if you would like to see them in the new theme engine. -* The collapsed navigation layouts have been **removed**. This is now in the default theme and handled automatically based on browser window height. +* Add the option of disabling CSS/template caching using `NOCACHE=1` environment variable. [#148](https://github.com/danielgtaylor/aglio/issues/148) +* Fix rendering of URI templates where some of the path components are removed. [#145](https://github.com/danielgtaylor/aglio/issues/145) +* Fix styling of `

` headings within action descriptions. +* Update `slug` function to handle inline HTML and consecutive `-` characters. +* Add support for informational notes and warnings, checkboxes and emoji. -The following are translated internally and will not break, but are suggested updates: +# 1.0.4 - 2015-08-04 -Binary: -* The `-t` option is now shorthand for `--theme` instead of `--template`. -* The `--full-width` and `--condense-nav` parameters are now `--theme-full-width` and `--theme-condense-nav` in the default theme engine. +* Support for Aglio 1.x Jade templates written without using `self`. +* Better error handling by exposing each error level via the error message. -Library: -* Passing a string as the options to `render` and `renderFile` will still work if it is a known variant: `default`, `flatly`, `slate`, `cyborg` or one of the collapsed versions of those. If it is a path and the file exists, then it will use it as a custom `themeLayout` option. Otherwise it will set the theme engine name. :dizzy_face: -* You should use `options.theme` instead of `options.template`. -* You should use `options.themeVariables = 'flatly'` to set the color variation. -* You should use `options.themeTemplate = '/path/to/layout.jade'` to set the layout template. +# 1.0.3 - 2015-08-03 -Thank you to all the contributors and testers for helping to make this an awesome release! :beers: +* Make cache directory writeable when installed via `sudo`. + [danielgtaylor/atom-api-blueprint-preview#40](https://github.com/danielgtaylor/atom-api-blueprint-preview/issues/40) -# 2.0.0-beta6 - 2015-07-14 -* Update to [olio theme](https://github.com/danielgtaylor/aglio/blob/olio-theme/Changelog.md) 0.0.9. +# 1.0.2 - 2015-07-28 -# 2.0.0-beta5 - 2015-07-10 -* Fix an issue with included paths when using `--server`. -* Update to [olio theme](https://github.com/danielgtaylor/aglio/blob/olio-theme/Changelog.md) 0.0.8. +* Fix margin around tables to ensure adequate space. [#141](https://github.com/danielgtaylor/aglio/issues/141) -# 2.0.0-beta4 - 2015-07-10 -* Update to [olio theme](https://github.com/danielgtaylor/aglio/blob/olio-theme/Changelog.md) 0.0.7. +# 1.0.1 - 2015-07-27 -# 2.0.0-beta3 - 2015-07-09 +* Fix the display of `%`-encoded parameter and attribute choices. +* Fix `%`-encoded value filtering in URI templates and support the `*` operator. + [#134](https://github.com/danielgtaylor/aglio/issues/134) +* Fix template URI font weight on some browsers. + +# 1.0.0 - 2015-07-16 + +* First stable release. + +# 0.0.9 - 2015-07-14 + +* Compliance with spec on parameter rendering. [#58](https://github.com/danielgtaylor/aglio/issues/58) +* Minor theme color tweaks. +* Make it possible to easily override padding and fonts. +* Fix minor styling issue on Internet Explorer 11. + +# 0.0.8 - 2015-07-13 + +* Better support of URL-encoded parameter names. +* Trim excess whitespace from code examples. +* Use action-specific name when available for resource nav items with a + single action. This ports over [#75](https://github.com/danielgtaylor/aglio/pull/75) + to the new Olio theme. +* Fix an issue with loading large blueprints. +* Include description headers for the API and resource groups in the navigation + menu. This is useful for describing authentication and other items. + +# 0.0.7 - 2015-07-10 + +* Implement a slug cache to stop name collisions. +* Prevent wrapping and overlapping navigation text. +* Add `slate` and `cyborg` color schemes. + +# 0.0.6 - 2015-07-09 + +* Implement navigation item auto-collapse based on window height. * Documentation updates. -* Server mode now serves static files if found. -* Add ability to output compiled API Blueprint file instead of HTML. -* Update to [olio theme](https://github.com/danielgtaylor/aglio/blob/olio-theme/Changelog.md) 0.0.6. - -# 2.0.0-beta2 - 2015-05-29 -* Live update fixes. -* Example fixes. - -# 2.0.0-beta1 - 2015-05-28 -* Implement theme engine support; depend on the default olio theme. -* Switch to using drafter.js instead of protagonist directly. - -# 1.18.0 - 2015-03-31 -* Upgrade to [Protagonist] 0.19.0, which adds support for Node.js 0.12.x - and iojs 1.x. - ([#77](https://github.com/danielgtaylor/aglio/issues/77)) - -# 1.17.1 - 2014-12-16 -* Switch to [Remarkable](https://github.com/jonschlinkert/remarkable) - Markdown parser, which is faster and supports the new CommonMark - specification. [GFM](https://help.github.com/articles/github-flavored-markdown/) - is supported. -* Fix live reload no longer working with some configurations - ([#74](https://github.com/danielgtaylor/aglio/issues/74)) -* Watch all included files for live reloading. - -# 1.17.0 - 2014-12-16 -* New logo -* Add support for [including files] - (https://github.com/danielgtaylor/aglio#including-files) -* Update dependencies (chokidar) - -# 1.16.2 - 2014-11-18 -* Update dependencies (chokidar, marked, protagonist, stylus) -* Fixes rendering description when headers are not present - ([#66](https://github.com/danielgtaylor/aglio/pull/66)) -* Fixes minor typo - ([#67](https://github.com/danielgtaylor/aglio/pull/67)) - -# 1.16.1 - 2014-08-29 -* Fixes template js bug related to live reloading. - ([179ea7e](https://github.com/danielgtaylor/aglio/commit/179ea7e5bf1b37e53b2b034be11eb134a506ffcf)) - -# 1.16.0 - 2014-08-29 -* Fix long choice lists not wrapping - ([#35](https://github.com/danielgtaylor/aglio/pull/35)) -* Fix long hostnames not wrapping - ([#55](https://github.com/danielgtaylor/aglio/pull/55)) -* Add support for live reloading the preview server - ([#57](https://github.com/danielgtaylor/aglio/pull/57)) -* Fix a bug when reading from stdin - ([#59](https://github.com/danielgtaylor/aglio/pull/59)) -* Update dependencies (coffee-script) -* Minor test fixes +* Update to latest Markdown renderer. + +# 0.0.5 - 2015-07-08 + +* Make navigation item groups collapsible. +* Fix backward compatibility for `--full-width` option. +* Add support for more HTTP verbs (e.g. `HEAD`, `PATCH`). +* Precompile and cache Jade templates. +* Precompile and cache LESS styles. +* Rename `colors` -> `variables`. + +# 0.0.4 - 2015-05-29 + +* Responsive theme adjustments/tweaks +* Fix buttons after live reload +* Prevent JSON parse errors for empty example bodies + +# 0.0.3 - 2015-05-28 + +* Prettify JSON example output of drafter.js. +* Test on more Node/iojs versions. + +# 0.0.2 - 2015-05-28 + +* Various theme fixes. +* Add a `flatly` color scheme. + +# 0.0.1 - 2015-02-26 + +* Use the `self` option with Jade, which significantly speeds up variable lookups. +* Speed request/response highlighting by limiting attempted languages. +* Remove inline `:stylus` in favor of converted CSS. +* Initial release of ported Aglio default theme. diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 0053db33..00000000 --- a/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -# Pull base image -FROM node:0.12.7 - -# Install Aglio -RUN npm install -g aglio@latest - - -ENTRYPOINT ["aglio"] diff --git a/Gruntfile.coffee b/Gruntfile.coffee deleted file mode 100644 index cf7fc31e..00000000 --- a/Gruntfile.coffee +++ /dev/null @@ -1,71 +0,0 @@ -async = require 'async' - -module.exports = (grunt) -> - grunt.initConfig - pkg: grunt.file.readJSON 'package.json' - coffeelint: - options: - indentation: - value: 4 - max_line_length: - value: 120 - level: 'warn' - src: - expand: true - src: ['src/**/*.coffee', 'test/**/*.coffee'] - coffee: - src: - expand: true - cwd: 'src' - src: ['**/*.coffee'] - dest: 'lib' - ext: '.js' - tests: - expand: true - cwd: 'test' - src: ['**/*.coffee'] - dest: 'test-js' - ext: '.js' - mochacov: - test: - options: - reporter: 'spec' - grep: grunt.option('grep') - src: 'test-js/**/*.js' - html: - options: - reporter: 'html-cov' - output: 'coverage.html' - src: 'test-js/**/*.js' - reportcoverage: - options: - coveralls: - serviceName: 'travis-ci' - src: 'test-js/**/*.js' - - grunt.loadNpmTasks 'grunt-coffeelint' - grunt.loadNpmTasks 'grunt-contrib-coffee' - grunt.loadNpmTasks 'grunt-mocha-cov' - - grunt.registerTask 'gen-examples', 'Generate an example for each theme', -> - done = @async() - - aglio = require './lib/main' - - render = (name, done) -> - console.log "Generating examples/#{name}.html" - aglio.renderFile 'example.apib', "examples/#{name}.html", themeVariables: name, (err) -> - if err then return done(err) - console.log "Generating examples/#{name}-triple.html" - aglio.renderFile 'example.apib', "examples/#{name}-triple.html", themeVariables: name, themeTemplate: 'triple', (err) -> - done(err) - - async.each ['default', 'flatly', 'slate', 'cyborg', 'streak'], render, done - - - grunt.registerTask 'compile', ['coffeelint', 'coffee'] - grunt.registerTask 'test', ['compile', 'mochacov:test'] - grunt.registerTask 'coverage', ['compile', 'mochacov:html'] - grunt.registerTask 'coveralls', ['compile', 'mochacov:reportcoverage'] - grunt.registerTask 'examples', ['compile', 'gen-examples'] - grunt.registerTask 'default', ['compile'] diff --git a/README.md b/README.md index 6578e411..df57a7b0 100644 --- a/README.md +++ b/README.md @@ -1,384 +1,54 @@ -![aglio](https://raw.github.com/danielgtaylor/aglio/master/images/aglio.png) +# Aglio Default Theme -[![Dependency Status](http://img.shields.io/david/danielgtaylor/aglio.svg?style=flat)](https://david-dm.org/danielgtaylor/aglio) [![Build Status](http://img.shields.io/travis/danielgtaylor/aglio/master.svg?style=flat)](https://travis-ci.org/danielgtaylor/aglio) [![Coverage Status](http://img.shields.io/coveralls/danielgtaylor/aglio.svg?style=flat)](https://coveralls.io/r/danielgtaylor/aglio) [![NPM version](http://img.shields.io/npm/v/aglio.svg?style=flat)](https://www.npmjs.org/package/aglio) [![License](http://img.shields.io/npm/l/aglio.svg?style=flat)](https://www.npmjs.org/package/aglio) [![Gitter](https://img.shields.io/badge/gitter-chat-orange.svg)](https://gitter.im/danielgtaylor/aglio?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![Dependency Status](https://img.shields.io/david/danielgtaylor/aglio/olio-theme.svg)](https://david-dm.org/danielgtaylor/aglio) [![Build Status](http://img.shields.io/travis/danielgtaylor/aglio/olio-theme.svg)](https://travis-ci.org/danielgtaylor/aglio) [![Coverage Status](http://img.shields.io/coveralls/danielgtaylor/aglio/olio-theme.svg)](https://coveralls.io/r/danielgtaylor/aglio) [![NPM version](http://img.shields.io/npm/v/aglio-theme-olio.svg)](https://www.npmjs.org/package/aglio-theme-olio) [![License](http://img.shields.io/npm/l/aglio-theme-olio.svg)](https://www.npmjs.org/package/aglio-theme-olio) -# Introduction - -An [API Blueprint](http://apiblueprint.org/) renderer that supports multiple themes and outputs static HTML that can be served by any web host. API Blueprint is a Markdown-based document format that lets you write API descriptions and documentation in a simple and straightforward way. Currently supported is [API Blueprint format 1A](https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md). - -**Note**: This project is mature and stable, but I don't have much time for it anymore. If you would like to join as a maintainer then please reach out to my GitHub username at Gmail. Thanks! - -## Features - - * Fast parsing thanks to [Protagonist](https://github.com/apiaryio/protagonist) - * Asyncronous processing - * Multiple templates/themes - * Support for custom colors, templates, and theme engines - * Include other documents in your blueprint - * Commandline executable `aglio -i service.apib -o api.html` - * Live-reloading preview server `aglio -i service.apib --server` - * Node.js library `require('aglio')` - * Excellent test coverage - * Tested on [BrowserStack](https://www.browserstack.com/) - -## Example Output -Example output is generated from the [example API Blueprint](https://raw.github.com/danielgtaylor/aglio/master/example.apib) using the default [Olio theme](https://github.com/danielgtaylor/aglio/tree/olio-theme#readme). - - * Default theme [two column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/default.html) or [three column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/default-triple.html) - * Streak theme [two column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/streak.html) or [three column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/streak-triple.html) - * Flatly theme [two column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/flatly.html) or [three column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/flatly-triple.html) - * Slate theme [two column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/slate.html) or [three column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/slate-triple.html) - * Cyborg theme [two column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/cyborg.html) or [three column](http://htmlpreview.github.io/?https://raw.githubusercontent.com/danielgtaylor/aglio/blob/master/examples/cyborg-triple.html) - -## Including Files -It is possible to include other files in your blueprint by using a special include directive with a path to the included file relative to the current file's directory. Included files can be written in API Blueprint, Markdown or HTML (or JSON for response examples). Included files can include other files, so be careful of circular references. - -```markdown - -``` - -For tools that do not support this include directive it will just render out as an HTML comment. API Blueprint may support its own mechanism of including files in the future, and this syntax was chosen to not interfere with the [external documents proposal](https://github.com/apiaryio/api-blueprint/issues/20) while allowing `aglio` users to include documents today. - - -# Installation & Usage -There are three ways to use aglio: as an executable, in a docker container or as a library for Node.js. - -## Executable -Install aglio via NPM. You need Node.js installed and you may need to use `sudo` to install globally: - -```bash -npm install -g aglio -``` - -Then, start generating HTML. - -```bash -# Default theme -aglio -i input.apib -o output.html - -# Use three-column layout -aglio -i input.apib --theme-template triple -o output.html - -# Built-in color scheme -aglio --theme-variables slate -i input.apib -o output.html - -# Customize a built-in style -aglio --theme-style default --theme-style ./my-style.less -i input.apib -o output.html - -# Custom layout template -aglio --theme-template /path/to/template.jade -i input.apib -o output.html - -# Custom theme engine -aglio -t my-engine -i input.apib -o output.html - -# Run a live preview server on http://localhost:3000/ -aglio -i input.apib -s - -# Print output to terminal (useful for piping) -aglio -i input.apib -o - - -# Disable condensing navigation links -aglio --no-theme-condense -i input.apib -o output.html - -# Render full-width page instead of fixed max width -aglio --theme-full-width -i input.apib -o output.html - -# Set an explicit file include path and read from stdin -aglio --include-path /path/to/includes -i - -o output.html - -# Output verbose error information with stack traces -aglio -i input.apib -o output.html --verbose -``` - -## With Docker -You can choose to use the provided `Dockerfile` to build yourself a repeatable and testable environment: - -1. Build the image with `docker build -t aglio .` -2. Run aglio inside a container with `docker run -t aglio` - You can use the `-v` switch to dynamically mount the folder that holds your API blueprint: - -```bash -docker run -v $(pwd):/tmp -t aglio -i /tmp/input.apib -o /tmp/output.html -``` - -## Node.js Library -You can also use aglio as a library. First, install and save it as a dependency: - -```bash -npm install --save aglio -``` - -Then, convert some API Blueprint to HTML: - -```javascript -var aglio = require('aglio'); - -// Render a blueprint with a template by name -var blueprint = '# Some API Blueprint string'; -var options = { - themeVariables: 'default' -}; - -aglio.render(blueprint, options, function (err, html, warnings) { - if (err) return console.log(err); - if (warnings) console.log(warnings); - - console.log(html); -}); - -// Render a blueprint with a custom template file -options = { - themeTemplate: '/path/to/my-template.jade' -}; -aglio.render(blueprint, options, function (err, html, warnings) { - if (err) return console.log(err); - if (warnings) console.log(warnings); - - console.log(html); -}); - - -// Pass custom locals along to the template, for example -// the following gives templates access to lodash and async -options = { - themeTemplate: '/path/to/my-template.jade', - locals: { - _: require('lodash'), - async: require('async') - } -}; -aglio.render(blueprint, options, function (err, html, warnings) { - if (err) return console.log(err); - if (warnings) console.log(warnings); - - console.log(html); -}); -``` - -### Reference -The following methods are available from the `aglio` library: - -#### aglio.collectPathsSync (blueprint, includePath) -Get a list of paths that are included in the blueprint. This list can be watched for changes to do things like live reload. The blueprint's own path is not included. - -```javascript -var blueprint = '# GET /foo\n<-- include(example.json -->\n'; -var watchPaths = aglio.collectPathsSync(blueprint, process.cwd()) -``` - -#### aglio.render (blueprint, options, callback) -Render an API Blueprint string and pass the generated HTML to the callback. The `options` can either be an object of options or a simple layout name or file path string. Available options are: - -| Option | Type | Default | Description | -| ----------- | ------ | ------------- | ------------------------------------- | -| filterInput | bool | `true` | Filter `\r` and `\t` from the input | -| includePath | string | process.cwd() | Base directory for relative includes | -| locals | object | `{}` | Extra locals to pass to templates | -| theme | string | `'default'` | Theme name to load for rendering | - -In addition, the [default theme](https://github.com/danielgtaylor/aglio/tree/olio-theme) provides the following options: - -| Option | Type | Default | Description | -| ---------------- | ------ | --------- | -------------------------------------------- | -| themeVariables | string | `default` | Built-in color scheme or path to LESS or CSS | -| themeCondenseNav | bool | `true` | Condense single-action navigation links | -| themeFullWidth | bool | `false` | Use the full page width | -| themeTemplate | string | | Layout name or path to custom layout file | -| themeStyle | string | `default` | Built-in style name or path to LESS or CSS | - - -```javascript -var blueprint = '...'; -var options = { - themeTemplate: 'default', - locals: { - myVariable: 125 - } -}; - -aglio.render(blueprint, options, function (err, html, warnings) { - if (err) return console.log(err); - - console.log(html); -}); -``` - -#### aglio.renderFile (inputFile, outputFile, options, callback) -Render an API Blueprint file and save the HTML to another file. The input/output file arguments are file paths. The options behaves the same as above for `aglio.render`, except that the `options.includePath` defaults to the basename of the input filename. - -```javascript -aglio.renderFile('/tmp/input.apib', '/tmp/output.html', options, function (err, warnings) { - if (err) return console.log(err); - if (warnings) console.log(warnings); -}); -``` - -# Development -Pull requests are encouraged! Feel free to fork and hack away, especially on new themes. The build system in use is Grunt, so make sure you have it installed: - -```bash -npm install -g grunt-cli -``` - -Then you can build the source and run the tests: - -```bash -# Lint/compile the Coffeescript -grunt - -# Run the test suite -grunt test - -# Generate an HTML test coverage report -grunt coverage - -# Render examples -grunt examples -``` - -## Customizing Output -Aglio is split into two components: a base that contains logic for loading API Blueprint, handling commandline arguments, etc and a theme engine that handles turning the API Blueprint AST into HTML. The default theme engine that ships with Aglio is called [olio](https://github.com/danielgtaylor/aglio/tree/olio-theme). Templates are written in Jade, with support for inline Coffeescript, LESS and Stylus via filters. The default stylesheets are written in LESS. - -While developing customizations, you may want to disable caching using the `NOCACHE` environment variable. +This is *Olio*, the default theme engine for [Aglio](https://github.com/danielgtaylor/aglio). It takes an [API Blueprint](http://apiblueprint.org/) AST and renders it into static HTML. Example use: ```bash -NOCACHE=1 aglio -i input.apib [customization options] +$ sudo npm install -g aglio +$ aglio -i blueprint.apib -o MyAPI.html ``` -### Custom Colors & Style -Aglio's default theme provides a way to easily override colors, fonts, padding, etc to match your company's style. This is done by providing your own LESS or CSS file(s) via the `--theme-variables` and `--theme-style` options. For example: +Theme engines for Aglio are described in more detail in the [Aglio documentation](https://github.com/danielgtaylor/aglio#customizing-output). -```bash -# Use my custom colors -aglio --theme-variables /path/to/my-colors.less -i input.apib -o output.html -``` +## Design Philosophy +Olio is designed from the ground up to be both **fast** and **extensible** while maintaining backward compatibility with most of the original Aglio theme. It uses the following technologies: -The `my-variables.less` file might contain a custom HTTP PUT color specification: +* [Less](http://lesscss.org/) to produce CSS +* [Markdown-it](https://github.com/markdown-it/markdown-it#readme) to render Markdown +* [Jade](http://jade-lang.com/) to produce HTML +* [Highlight.js](https://highlightjs.org/) to highlight code snippets -```less -/* HTTP PUT */ -@put-color: #f0ad4e; -@put-background-color: #fcf8e3; -@put-text-color: contrast(@put-background-color); -@put-border-color: darken(spin(@put-background-color, -10), 5%); -``` +For backward compatibility, Jade templates can continue to use inline Stylus and CoffeeScript. -See the [default variables](https://github.com/danielgtaylor/aglio/blob/olio-theme/styles/variables-default.less) file for examples of which variables can be set. +## Theme Options -The `--theme-style` option lets you override built-in styles with your own LESS or CSS definitions. It is processed **after** the variables have been defined, so the variables are available for your use. If you wish to modify a rule from an existing built-in style then you must copy the style. The order of loading roughly follows: +Olio comes with a handful of configurable theme options. These are set via the `--theme-XXX` parameter, where `XXX` is one of the following: -1. Default variables -2. Built-in **or** user-supplied variables -3. Built-in **or** user-supplied style +Name | Description +-------------- | ------------------ +`condense-nav` | Whether to condense nagivation for resources with only a single action (default is `true`). +`full-width` | Whether to use the full page width or a responsive layout (default is responsive). +`style` | LESS or CSS to control the layout and style of the document using the variables from below. Can be a path to your own file or one of the following presets: `default`. May be an array of paths and/or presets. +`template` | Jade template to render HTML. Can be a path to your own file or one of the following presets: `default`. +`variables` | LESS variables that control theme colors, fonts, and spacing. Can be a path to your own file or one of the following presets: `default`, `flatly`, `slate`, `cyborg`. May be an array of paths and/or presets. -Note that these options can be passed more than once, in which case they will be loaded in the order they were passed. This lets you, for example, load a variable preset like `flatly` and modify one of the colors with your own LESS file. Keep in mind that when you want to modify a built-in style you must explicitly list the style, e.g. `--theme-style default --theme-style my-style.less`. +**Note**: When using this theme programmatically, these options are cased like you would expect in Javascript: `--theme-full-width` becomes `options.themeFullWidth`. -#### Built-in Colors +## Benchmark -* `cyborg` -* `default` -* `flatly` -* `slate` - -#### Built-in Styles - -* `default` - -### Customizing Layout Templates -The `--theme-template` option allows you to provide a custom layout template that overrides the default. This is specified in the form of a [Jade](http://jade-lang.com/) template file. See the [default template](https://github.com/danielgtaylor/aglio/blob/olio-theme/templates/index.jade) file for an example. - -The locals available to templates look like the following: - -| Name | Description | -| ----------- | -------------------------------------------------------- | -| api | The API Blueprint AST from Protagonist | -| condenseNav | If true, you should condense the nav if possible | -| date | Date and time handling from Moment.js | -| fullWidth | If true, you should consume the entire page width | -| highlight | A function (`code`, `lang`) to highlight a piece of code | -| markdown | A function to convert Markdown strings to HTML | -| slug | A function to convert a string to a slug usable as an ID | -| hash | A function to return an hash (currently MD5) | - -#### Built-in Layout Templates - -* `default` - -### Using Custom Themes -While Aglio ships with a default theme, you have the option of installing and using third-party theme engines. They may use any technology and are not limited to Jade and LESS. Consult the theme's documentation to see which options are available and how to use and customize the theme. Common usage between all themes: - -```bash -# Install a custom theme engine globally -npm install -g aglio-theme- - -# Render using a custom theme engine -aglio -t -i input.apib -o output.html - -# Get a list of all options for a theme -aglio -t --help -``` - -### Writing a Theme Engine -Theme engines are simply Node.js modules that provide two public functions and follow a specific naming scheme (`aglio-theme-NAME`). Because they are their own npm package they can use whatever technologies the theme engine author wishes. The only hard requirement is to provide these two public functions: - -#### `getConfig()` -Returns configuration information about the theme, such as the API Blueprint format that is supported and any options the theme provides. - -#### `render(input, options, done)` -Render the given input API Blueprint AST with the given options. Calls `done(err, html)` when finished, either passing an error or the rendered HTML output as a string. - -#### Example Theme -The following is a very simple example theme. **Note**: it only returns a very simple string instead of rending out the API Blueprint AST. Normally you would invoke a template engine and output the resulting HTML that is generated. - -```javascript -// Get the theme's configuration options -exports.getConfig = function () { - return { - // This is a list of all supported API Blueprint format versions - formats: ['1A'], - // This is a list of all options your theme accepts. See - // here for more: https://github.com/bcoe/yargs#readme - // Note: These get prefixed with `theme` when you access - // them in the options object later! - options: [ - { - name: 'name', - description: 'Your name', - default: 'world' - } - ] - }; -} - -// Asyncronously render out a string -exports.render = function (input, options, done) { - // Normally you would use some template engine here. - // To keep this code really simple, we just print - // out a string and ignore the API Blueprint. - done(null, 'Hello, ' + options.themeName + '!'); -}; - -``` - -Example use: - -```bash -# Install the theme globally -npm install -g aglio-theme-hello - -# Render some output! -aglio -t hello -i example.apib -o - -=> 'Hello, world!' - -# Pass in the custom theme option! -aglio -t hello --theme-name Daniel -i example.apib -o - -=> 'Hello, Daniel!' -``` +Olio makes use of aggressive caching whenever it can, which means that rendering HTML can be blazing fast. Benchmark taken on a 2015 Macbook Pro via `BENCHMARK=1 aglio -i example.apib -o example.html`: -You are free to use whatever template system (Jade, EJS, Nunjucks, etc) and any supporting libraries (e.g. for CSS) you like. +Step | Cached | No cache +------------------- | ------:| --------: +Parse API Blueprint | 44ms | 44ms +Get CSS | 1ms | 49ms +Get template | 2ms | 102ms +Call template | 28ms | 32ms +**Total time** | 75ms | 227ms License ======= -Copyright (c) 2016 Daniel G. Taylor +Copyright © 2016 Daniel G. Taylor http://dgt.mit-license.org/ diff --git a/bin/aglio.js b/bin/aglio.js deleted file mode 100755 index 03e7d2ff..00000000 --- a/bin/aglio.js +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env node - -process.title = 'aglio'; - -require('../lib/bin').run(null, function(err){ - if(err){ - process.exit(1); - } -}); diff --git a/example-include.md b/example-include.md deleted file mode 100644 index 90d1c672..00000000 --- a/example-include.md +++ /dev/null @@ -1,4 +0,0 @@ -### Included File -This is content that was included from another file! It's easy, simply use `include(filename)` in an HTML comment (``). - -Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be *either* Markdown or HTML. diff --git a/example-schema.json b/example-schema.json deleted file mode 100644 index dc73aac3..00000000 --- a/example-schema.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "array", - "maxItems": 50, - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "image": { - "type": "string" - }, - "joined": { - "type": "string", - "pattern": "\\d{4}-\\d{2}-\\d{2}" - } - } - } -} diff --git a/example.apib b/example.apib deleted file mode 100644 index 44ff9692..00000000 --- a/example.apib +++ /dev/null @@ -1,320 +0,0 @@ -FORMAT: 1A -HOST: https://api.example.com - -# API Title -[Markdown](http://daringfireball.net/projects/markdown/syntax) **formatted** description. - -## Subtitle -Also Markdown *formatted*. This also includes automatic "smartypants" formatting -- hooray! - -> "A quote from another time and place" - -Another paragraph. Code sample: - -```http -Authorization: bearer 5262d64b892e8d4341000001 -``` - -And some code with no highlighting: - -```no-highlight -Foo bar baz -``` - -1. A list -2. Of items -3. Can be -4. Very useful - -Here is a table: - -ID | Name | Description ---:| ---- | ----------- - 1 | Foo | I am a foo. - 8 | Bar | I am a bar. -15 | Baz | I am a baz. - -::: note -## Extensions -Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain **formatting**. Features include: - -* Informational block fenced with `::: note` and `:::` -* Warning block fenced with `::: warning` and `:::` -* [x] GitHub-style checkboxes using `[x]` and `[ ]` -* Emoji support :smile: :ship: :cake: using `:smile:` ([cheat sheet](http://www.emoji-cheat-sheet.com/)) - -These extensions may change in the future as the [CommonMark specification](http://spec.commonmark.org/) defines a [standard extension syntax](https://github.com/jgm/CommonMark/wiki/Proposed-Extensions). -::: - - - -# Data Structures - -## NoteData -+ id: 1 (required, number) - Unique identifier -+ title: Grocery list (required) - Single line description -+ body: Buy milk - Full description of the note which supports Markdown. - -## NoteList (array) -+ (NoteData) - -# Group Notes -Group description (also with *Markdown*) - -## Important Info -Descriptions may also contain sub-headings and **more Markdown**. - -## Note List [/notes] -Note list description - -+ Even -+ More -+ Markdown - -### Get Notes [GET] -Get a list of notes. - -+ Response 200 (application/json) - - + Headers - - X-Request-ID: f72fc914 - X-Response-Time: 4ms - - + Attributes (NoteList) - -### Create New Note [POST] -Create a new note using a title and an optional content body. - -+ Request with body (application/json) - - + Body - - { - "title": "My new note", - "body": "This is the body" - } - -+ Response 201 - -+ Response 400 (application/json) - - + Body - - { - "error": "Invalid title" - } - -+ Request without body (application/json) - - + Body - - { - "title": "My new note" - } - -+ Response 201 - -+ Response 400 (application/json) - - + Body - - { - "error": "Invalid title" - } - -## Note [/notes/{id}{?body}] -Note description - -+ Parameters - - + id: `68a5sdf67` (required, string) - The note ID - -### Get Note [GET] -Get a single note. - -+ Parameters - - + body: `false` (boolean) - Set to `false` to exclude note body content. - -+ Response 200 (application/json) - - + Headers - - X-Request-ID: f72fc914 - X-Response-Time: 4ms - - + Attributes (NoteData) - -+ Response 404 (application/json) - - + Headers - - X-Request-ID: f72fc914 - X-Response-Time: 4ms - - + Body - - { - "error": "Note not found" - } - -### Update a Note [PUT] -Update a single note by setting the title and/or body. - -::: warning -#### Caution -If the value for `title` or `body` is `null` or `undefined`, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will **permanently overwrite** the original value. -::: - -+ Request (application/json) - - + Body - - { - "title": "Grocery List (Safeway)" - } - -+ Response 200 (application/json) - - + Headers - - X-Request-ID: f72fc914 - X-Response-Time: 4ms - - + Attributes (NoteData) - -+ Response 404 (application/json) - - + Headers - - X-Request-ID: f72fc914 - X-Response-Time: 4ms - - + Body - - { - "error": "Note not found" - } - -+ Request delete body (application/json) - - + Body - - { - "body": "" - } - -+ Response 200 (application/json) - - + Headers - - X-Request-ID: f72fc914 - X-Response-Time: 4ms - - + Attributes (NoteData) - -+ Response 404 (application/json) - - + Headers - - X-Request-ID: f72fc914 - X-Response-Time: 4ms - - + Body - - { - "error": "Note not found" - } - -### Delete a Note [DELETE] -Delete a single note - -+ Response 204 - -+ Response 404 (application/json) - - + Headers - - X-Request-ID: f72fc914 - X-Response-Time: 4ms - - + Body - - { - "error": "Note not found" - } - -# Group Users -Group description - -## User List [/users{?name,joinedBefore,joinedAfter,sort,limit}] -A list of users - -+ Parameters - - + name: `alice` (string, optional) - Search for a user by name - + joinedBefore: `2011-01-01` (string, optional) - Search by join date - + joinedAfter: `2011-01-01` (string, optional, ) - Search by join date - + sort: `joined` (string, optional) - Which field to sort by - + Default: `name` - + Members - + `name` - + `joined` - + `-joined` - + `age` - + `-age` - + `location` - + `-location` - + `plan` - + `-plan` - + limit: `25` (integer, optional) - The maximum number of users to return, up to `50` - + Default: `10` - -### Get users [GET] -Get a list of users. Example: - -```no-highlight -https://api.mywebsite.com/users?sort=joined&limit=5 -``` - -+ Response 200 (application/json) - - + Body - - [ - { - "name": "alice", - "image": "http://example.com/alice.jpg", - "joined": "2013-11-01" - }, - { - "name": "bob", - "image": "http://example.com/bob.jpg", - "joined": "2013-11-02" - } - ] - - + Schema - - - -# Group Tags and Tagging Long Title -Get or set tags on notes - -## GET /tags -Get a list of bars - -+ Response 200 (application/json) - - ["tag1", "tag2", "tag3"] - -## Get one tag [/tags/{id}] -Get a single tag - -+ Parameters - + id - Unique tag identifier - -### GET - -+ Response 200 diff --git a/examples/cyborg-triple.html b/examples/cyborg-triple.html deleted file mode 100644 index 2a9ca7be..00000000 --- a/examples/cyborg-triple.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-
GET https://api.example.com/notes
Responses200
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Get Notes
GET/notes

Get a list of notes.

-

POST https://api.example.com/notes
Requestswith bodywithout body
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Note

Note description

-
GET https://api.example.com/notes/id?body=false
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Get Note
GET/notes/{id}{?body}

Get a single note.

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-

PUT https://api.example.com/notes/id
Requestsexample 1delete body
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

DELETE https://api.example.com/notes/id
Responses204404
This response has no content.
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

Users

Group description

-

User List

A list of users

-
GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
Responses200
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET https://api.example.com/tags
Responses200
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

GET/tags

Get a list of bars

-

Get one tag

Get a single tag

-
GET https://api.example.com/tags/id
Responses200
This response has no content.

GET/tags/{id}

URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/cyborg.html b/examples/cyborg.html deleted file mode 100644 index 4c502455..00000000 --- a/examples/cyborg.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title  Back to top

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-

Get Notes
GET/notes

Get a list of notes.

-

Example URI

GET https://api.example.com/notes
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Example URI

POST https://api.example.com/notes
Request  with body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Request  without body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Note

Note description

-

Get Note
GET/notes/{id}{?body}

Get a single note.

-

Example URI

GET https://api.example.com/notes/id?body=false
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-

Example URI

PUT https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Request
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Request  delete body
HideShow
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-

Example URI

DELETE https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Response  204
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Users

Group description

-

User List

A list of users

-

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-

Example URI

GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET/tags

Get a list of bars

-

Example URI

GET https://api.example.com/tags
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

Get one tag

Get a single tag

-

GET/tags/{id}

Example URI

GET https://api.example.com/tags/id
URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-
Response  200

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/default-triple.html b/examples/default-triple.html deleted file mode 100644 index bc67045f..00000000 --- a/examples/default-triple.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-
GET https://api.example.com/notes
Responses200
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Get Notes
GET/notes

Get a list of notes.

-

POST https://api.example.com/notes
Requestswith bodywithout body
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Note

Note description

-
GET https://api.example.com/notes/id?body=false
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Get Note
GET/notes/{id}{?body}

Get a single note.

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-

PUT https://api.example.com/notes/id
Requestsexample 1delete body
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

DELETE https://api.example.com/notes/id
Responses204404
This response has no content.
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

Users

Group description

-

User List

A list of users

-
GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
Responses200
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET https://api.example.com/tags
Responses200
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

GET/tags

Get a list of bars

-

Get one tag

Get a single tag

-
GET https://api.example.com/tags/id
Responses200
This response has no content.

GET/tags/{id}

URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/default.html b/examples/default.html deleted file mode 100644 index 32b50dad..00000000 --- a/examples/default.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title  Back to top

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-

Get Notes
GET/notes

Get a list of notes.

-

Example URI

GET https://api.example.com/notes
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Example URI

POST https://api.example.com/notes
Request  with body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Request  without body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Note

Note description

-

Get Note
GET/notes/{id}{?body}

Get a single note.

-

Example URI

GET https://api.example.com/notes/id?body=false
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-

Example URI

PUT https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Request
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Request  delete body
HideShow
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-

Example URI

DELETE https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Response  204
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Users

Group description

-

User List

A list of users

-

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-

Example URI

GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET/tags

Get a list of bars

-

Example URI

GET https://api.example.com/tags
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

Get one tag

Get a single tag

-

GET/tags/{id}

Example URI

GET https://api.example.com/tags/id
URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-
Response  200

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/flatly-triple.html b/examples/flatly-triple.html deleted file mode 100644 index ca3330ef..00000000 --- a/examples/flatly-triple.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-
GET https://api.example.com/notes
Responses200
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Get Notes
GET/notes

Get a list of notes.

-

POST https://api.example.com/notes
Requestswith bodywithout body
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Note

Note description

-
GET https://api.example.com/notes/id?body=false
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Get Note
GET/notes/{id}{?body}

Get a single note.

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-

PUT https://api.example.com/notes/id
Requestsexample 1delete body
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

DELETE https://api.example.com/notes/id
Responses204404
This response has no content.
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

Users

Group description

-

User List

A list of users

-
GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
Responses200
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET https://api.example.com/tags
Responses200
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

GET/tags

Get a list of bars

-

Get one tag

Get a single tag

-
GET https://api.example.com/tags/id
Responses200
This response has no content.

GET/tags/{id}

URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/flatly.html b/examples/flatly.html deleted file mode 100644 index bd13ff80..00000000 --- a/examples/flatly.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title  Back to top

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-

Get Notes
GET/notes

Get a list of notes.

-

Example URI

GET https://api.example.com/notes
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Example URI

POST https://api.example.com/notes
Request  with body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Request  without body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Note

Note description

-

Get Note
GET/notes/{id}{?body}

Get a single note.

-

Example URI

GET https://api.example.com/notes/id?body=false
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-

Example URI

PUT https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Request
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Request  delete body
HideShow
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-

Example URI

DELETE https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Response  204
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Users

Group description

-

User List

A list of users

-

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-

Example URI

GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET/tags

Get a list of bars

-

Example URI

GET https://api.example.com/tags
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

Get one tag

Get a single tag

-

GET/tags/{id}

Example URI

GET https://api.example.com/tags/id
URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-
Response  200

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/slate-triple.html b/examples/slate-triple.html deleted file mode 100644 index 195ab2a8..00000000 --- a/examples/slate-triple.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-
GET https://api.example.com/notes
Responses200
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Get Notes
GET/notes

Get a list of notes.

-

POST https://api.example.com/notes
Requestswith bodywithout body
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Note

Note description

-
GET https://api.example.com/notes/id?body=false
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Get Note
GET/notes/{id}{?body}

Get a single note.

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-

PUT https://api.example.com/notes/id
Requestsexample 1delete body
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

DELETE https://api.example.com/notes/id
Responses204404
This response has no content.
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

Users

Group description

-

User List

A list of users

-
GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
Responses200
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET https://api.example.com/tags
Responses200
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

GET/tags

Get a list of bars

-

Get one tag

Get a single tag

-
GET https://api.example.com/tags/id
Responses200
This response has no content.

GET/tags/{id}

URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/slate.html b/examples/slate.html deleted file mode 100644 index ef8aef7c..00000000 --- a/examples/slate.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title  Back to top

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-

Get Notes
GET/notes

Get a list of notes.

-

Example URI

GET https://api.example.com/notes
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Example URI

POST https://api.example.com/notes
Request  with body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Request  without body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Note

Note description

-

Get Note
GET/notes/{id}{?body}

Get a single note.

-

Example URI

GET https://api.example.com/notes/id?body=false
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-

Example URI

PUT https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Request
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Request  delete body
HideShow
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-

Example URI

DELETE https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Response  204
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Users

Group description

-

User List

A list of users

-

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-

Example URI

GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET/tags

Get a list of bars

-

Example URI

GET https://api.example.com/tags
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

Get one tag

Get a single tag

-

GET/tags/{id}

Example URI

GET https://api.example.com/tags/id
URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-
Response  200

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/streak-triple.html b/examples/streak-triple.html deleted file mode 100644 index 9850802c..00000000 --- a/examples/streak-triple.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-
GET https://api.example.com/notes
Responses200
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Get Notes
GET/notes

Get a list of notes.

-

POST https://api.example.com/notes
Requestswith bodywithout body
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Responses201400
This response has no content.
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Note

Note description

-
GET https://api.example.com/notes/id?body=false
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Get Note
GET/notes/{id}{?body}

Get a single note.

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-

PUT https://api.example.com/notes/id
Requestsexample 1delete body
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Responses200404
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

DELETE https://api.example.com/notes/id
Responses204404
This response has no content.
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-

Users

Group description

-

User List

A list of users

-
GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
Responses200
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET https://api.example.com/tags
Responses200
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

GET/tags

Get a list of bars

-

Get one tag

Get a single tag

-
GET https://api.example.com/tags/id
Responses200
This response has no content.

GET/tags/{id}

URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/examples/streak.html b/examples/streak.html deleted file mode 100644 index 15640405..00000000 --- a/examples/streak.html +++ /dev/null @@ -1,498 +0,0 @@ -API Title  Back to top

API Title

Markdown formatted description.

-

Subtitle

-

Also Markdown formatted. This also includes automatic “smartypants” formatting – hooray!

-
-

“A quote from another time and place”

-
-

Another paragraph. Code sample:

-
Authorization: bearer 5262d64b892e8d4341000001
-

And some code with no highlighting:

-
Foo bar baz
-
    -
  1. -

    A list

    -
  2. -
  3. -

    Of items

    -
  4. -
  5. -

    Can be

    -
  6. -
  7. -

    Very useful

    -
  8. -
-

Here is a table:

- - - - - - - - - - - - - - - - - - - - - - - - - -
IDNameDescription
1FooI am a foo.
8BarI am a bar.
15BazI am a baz.
-
-

Extensions

-

Some non-standard Markdown extensions are also supported, such as this informational container, which can also contain formatting. Features include:

-
    -
  • -

    Informational block fenced with ::: note and :::

    -
  • -
  • -

    Warning block fenced with ::: warning and :::

    -
  • -
  • -

    [x] and [ ]

    -
  • -
  • -

    Emoji support 😀 🚀 🍰 using :smile: (cheat sheet)

    -
  • -
-

These extensions may change in the future as the CommonMark specification defines a standard extension syntax.

-
-

Included File

-

This is content that was included from another file! It’s easy, simply use include(filename) in an HTML comment (<!-- include... -->).

-

Included files can include other files as well, allowing you to structure your API documentation as you see fit. Since Markdown supports inline HTML, the files you include can be either Markdown or HTML.

-

Notes

Group description (also with Markdown)

-

Important Info

-

Descriptions may also contain sub-headings and more Markdown.

-

Note List

Note list description

-
    -
  • -

    Even

    -
  • -
  • -

    More

    -
  • -
  • -

    Markdown

    -
  • -
-

Get Notes
GET/notes

Get a list of notes.

-

Example URI

GET https://api.example.com/notes
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
[
-  {
-    "id": 1,
-    "title": "Grocery list",
-    "body": "Buy milk"
-  }
-]
Schema
{
-  "type": "array",
-  "items": {
-    "type": "object",
-    "properties": {
-      "id": {
-        "type": "number",
-        "description": "Unique identifier"
-      },
-      "title": {
-        "type": "string",
-        "description": "Single line description"
-      },
-      "body": {
-        "type": "string",
-        "description": "Full description of the note which supports Markdown."
-      }
-    },
-    "required": [
-      "id",
-      "title"
-    ]
-  },
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}

Create New Note
POST/notes

Create a new note using a title and an optional content body.

-

Example URI

POST https://api.example.com/notes
Request  with body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note",
-  "body": "This is the body"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}
Request  without body
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "My new note"
-}
Response  201
Response  400
HideShow
Headers
Content-Type: application/json
Body
{
-  "error": "Invalid title"
-}

Note

Note description

-

Get Note
GET/notes/{id}{?body}

Get a single note.

-

Example URI

GET https://api.example.com/notes/id?body=false
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
body
boolean (required) Example: false

Set to false to exclude note body content.

-
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Update a Note
PUT/notes/{id}

Update a single note by setting the title and/or body.

-
-

Caution

-

If the value for title or body is null or undefined, then the corresponding value is not modified on the server. However, if you send an empty string instead then it will permanently overwrite the original value.

-
-

Example URI

PUT https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Request
HideShow
Headers
Content-Type: application/json
Body
{
-  "title": "Grocery List (Safeway)"
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}
Request  delete body
HideShow
Headers
Content-Type: application/json
Body
{
-  "body": ""
-}
Response  200
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "id": 1,
-  "title": "Grocery list",
-  "body": "Buy milk"
-}
Schema
{
-  "type": "object",
-  "properties": {
-    "id": {
-      "type": "number",
-      "description": "Unique identifier"
-    },
-    "title": {
-      "type": "string",
-      "description": "Single line description"
-    },
-    "body": {
-      "type": "string",
-      "description": "Full description of the note which supports Markdown."
-    }
-  },
-  "required": [
-    "id",
-    "title"
-  ],
-  "$schema": "http://json-schema.org/draft-04/schema#"
-}
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Delete a Note
DELETE/notes/{id}

Delete a single note

-

Example URI

DELETE https://api.example.com/notes/id
URI Parameters
HideShow
id
string (required) Example: 68a5sdf67

The note ID

-
Response  204
Response  404
HideShow
Headers
Content-Type: application/json
X-Request-ID: f72fc914
X-Response-Time: 4ms
Body
{
-  "error": "Note not found"
-}

Users

Group description

-

User List

A list of users

-

Get users
GET/users{?name,joinedBefore,joinedAfter,sort,limit}

Get a list of users. Example:

-
https://api.mywebsite.com/users?sort=joined&limit=5
-

Example URI

GET https://api.example.com/users?name=alice&joinedBefore=2011-01-01&joinedAfter=2011-01-01&sort=joined&limit=25
URI Parameters
HideShow
name
string (optional) Example: alice

Search for a user by name

-
joinedBefore
string (optional) Example: 2011-01-01

Search by join date

-
joinedAfter
string (optional) Example: 2011-01-01

Search by join date

-
sort
string (optional) Default: name Example: joined

Which field to sort by

-

Choices: name joined -joined age -age location -location plan -plan

limit
integer (optional) Default: 10 Example: 25

The maximum number of users to return, up to 50

-
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  {
-    "name": "alice",
-    "image": "http://example.com/alice.jpg",
-    "joined": "2013-11-01"
-  },
-  {
-    "name": "bob",
-    "image": "http://example.com/bob.jpg",
-    "joined": "2013-11-02"
-  }
-]
Schema
{
-  "type": "array",
-  "maxItems": 50,
-  "items": {
-    "type": "object",
-    "properties": {
-      "name": {
-        "type": "string"
-      },
-      "image": {
-        "type": "string"
-      },
-      "joined": {
-        "type": "string",
-        "pattern": "\\d{4}-\\d{2}-\\d{2}"
-      }
-    }
-  }
-}

Tags and Tagging Long Title

Get or set tags on notes

-

Resource

GET/tags

Get a list of bars

-

Example URI

GET https://api.example.com/tags
Response  200
HideShow
Headers
Content-Type: application/json
Body
[
-  "tag1",
-  "tag2",
-  "tag3"
-]

Get one tag

Get a single tag

-

GET/tags/{id}

Example URI

GET https://api.example.com/tags/id
URI Parameters
HideShow
id
string (required) 

Unique tag identifier

-
Response  200

Generated by aglio on 11 Nov 2015

\ No newline at end of file diff --git a/images/aglio-logo-bw.svg b/images/aglio-logo-bw.svg deleted file mode 100644 index fc8dd022..00000000 --- a/images/aglio-logo-bw.svg +++ /dev/null @@ -1,1057 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/aglio-logo.svg b/images/aglio-logo.svg deleted file mode 100644 index 6487390d..00000000 --- a/images/aglio-logo.svg +++ /dev/null @@ -1,1866 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/aglio.png b/images/aglio.png deleted file mode 100644 index 5c3ba233..00000000 Binary files a/images/aglio.png and /dev/null differ diff --git a/package.json b/package.json index 4ad3ad5a..ef452c66 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,23 @@ { - "name": "aglio", - "version": "2.3.0", - "description": "An API Blueprint renderer with theme support", + "name": "aglio-theme-olio", + "version": "1.6.3", + "description": "Default theme for the Aglio API Blueprint renderer", "main": "lib/main.js", - "bin": { - "aglio": "./bin/aglio.js" - }, "scripts": { - "test": "grunt test", - "prepublish": "grunt compile", - "blanket": { - "pattern": [ - "aglio/lib" - ], - "data-cover-never": "node_modules" - } + "build": "coffeelint src/*.coffee && coffee -o lib -c src", + "precoverage": "npm run build", + "coverage": "istanbul cover -x cache/*.js _mocha -- --compilers coffee:coffee-script/register -R spec", + "precoveralls": "npm run coverage", + "coveralls": "coveralls - inputLines = input.split('\n') - context = inputLines.slice(lineNo - 5, lineNo + 5) - context.map (line, index) -> - if index == 4 - cWarn(">>>> #{line}") - else - " #{line}" - -# Get a line number from an error if possible -getLineNo = (input, err) -> - if err.location and err.location.length - input.substr(0, err.location[0].index).split('\n').length - -# Output warning info -logWarnings = (warnings) -> - for warning in warnings or [] - lineNo = getLineNo(warnings.input, warning) or 0 - errContext = getErrContext(warnings.input, lineNo) - console.error cWarn(">> Line #{lineNo}:") + " #{warning.message} (warning code #{warning.code})" - console.error cWarn(">> Context") - console.error " ...\n #{errContext.join('\n')} \n ..." - -# Output an error message -logError = (err, verbose) -> - if verbose - pe = new PrettyError() - pe.setMaxItems 5 - console.error pe.render(err) - else - console.error cErr('>>'), err - -exports.run = (argv=parser.argv, done=->) -> - _html = null - getHtml = (cb) -> - if _html - cb and cb(null, _html) - else - fs.readFile argv.i, "utf-8", (err, blueprint) -> - console.log "Rendering " + argv.i - aglio.render blueprint, argv, (err, html, warnings) -> - logWarnings warnings - if err - logError err, argv.verbose - cb and cb(err) - else - _html = html - cb and cb(null, _html) - - if argv.version - console.log("aglio #{require('../package.json').version}") - console.log("olio #{require('aglio-theme-olio/package.json').version}") - return done() - - # The option used to be called `template` - if argv.template then argv.theme = argv.template - - # Backward-compatible support for -t /path/to/layout.jade - if fs.existsSync(argv.theme) - argv.themeTemplate = argv.theme - argv.theme = 'default' - - # Add theme options to the help output - if argv.verbose then console.log "Loading theme #{argv.theme}" - try - theme = aglio.getTheme(argv.theme) - catch err - err.message = "Could not load theme: #{err.message}" - logError err, argv.verbose - return done(err) - - config = theme.getConfig() - for entry in config.options - parser.options("theme-#{entry.name}", entry) - - if argv.s - if not argv.i - parser.showHelp() - return done 'Invalid arguments' - - argv.locals = - livePreview: true - - # Set where to include files from before generating HTML - if argv.i isnt '-' - argv.includePath = path.dirname(argv.i) - - getHtml() - server = http.createServer((req, res) -> - if req.url isnt '/' - serve = serveStatic(path.dirname(argv.i)) - return serve(req, res, () -> res.end()) - - getHtml (err, html) -> - res.writeHead 200, - "Content-Type": "text/html" - - res.end (if err then err.toString() else html) - - ).listen argv.p, argv.h, -> - console.log "Server started on http://#{argv.h}:#{argv.p}/" - - sendHtml = (socket) -> - getHtml (err, html) -> - unless err - console.log "Refresh web page in browser" - re = /[^]*<\/body>/gi - html = html.match(re)[0] - socket.emit "refresh", html - - io = require("socket.io")(server) - io.on "connection", (socket) -> - console.log "Socket connected" - socket.on 'request-refresh', -> - sendHtml socket - - paths = aglio.collectPathsSync fs.readFileSync(argv.i, 'utf-8'), path.dirname(argv.i) - - watcher = chokidar.watch [argv.i].concat(paths) - watcher.on "change", (path) -> - console.log "Updated " + path - _html = null - sendHtml io - - done() - else - # Render or Compile API Blueprint, requires input/output files - if not argv.i or not argv.o - parser.showHelp() - return done 'Invalid arguments' - - if argv.c or (typeof argv.o is 'string' and (argv.o.match /\.apib$/ or argv.o.match /\.md$/)) - aglio.compileFile argv.i, argv.o, (err) -> - if (err) - logError err, argv.verbose - - done() - else - aglio.renderFile argv.i, argv.o, argv, (err, warnings) -> - if err - lineNo = getLineNo err.input, err - if lineNo? - console.error cErr(">> Line #{lineNo}:") + " #{err.message} (error code #{err.code})" - else - logError err, argv.verbose - - return done err - - logWarnings warnings - - done() diff --git a/src/example.coffee b/src/example.coffee new file mode 100644 index 00000000..0b8acc08 --- /dev/null +++ b/src/example.coffee @@ -0,0 +1,49 @@ +# This is an extremely simple example generator given refracted MSON input. +# It handles the following: +# +# * Simple types, enums, arrays, objects +# * Property descriptions +# * References +# * Mixins (Includes) +# * Arrays with members of different types +# * One Of properties (the first is always selected) +# +# It is missing support for many advanced features. +inherit = require './inherit' + +defaultValue = (type) -> + switch type + when 'boolean' then true + when 'number' then 1 + when 'string' then 'Hello, world!' + +module.exports = renderExample = (root, dataStructures) -> + switch root.element + when 'boolean', 'string', 'number' + if root.content? then root.content else defaultValue(root.element) + when 'enum' then renderExample root.content[0], dataStructures + when 'array' + for item in root.content or [] + renderExample(item, dataStructures) + when 'object' + obj = {} + properties = root.content.slice(0) + i = 0 + while i < properties.length + member = properties[i] + i++ + if member.element == 'ref' + ref = dataStructures[member.content.href] + i-- + properties.splice.apply properties, [i, 1].concat(ref.content) + continue + else if member.element == 'select' + # Note: we *always* select the first choice! + member = member.content[0].content[0] + key = member.content.key.content + obj[key] = renderExample(member.content.value, dataStructures) + obj + else + ref = dataStructures[root.element] + if ref + renderExample(inherit(ref, root), dataStructures) diff --git a/src/inherit.coffee b/src/inherit.coffee new file mode 100644 index 00000000..84f9881a --- /dev/null +++ b/src/inherit.coffee @@ -0,0 +1,55 @@ +# Handle MSON inheritance. This is interesting because certain attributes, +# items, members, etc can be overridden. For example, the `id` property is +# overridden to be any valid `string` below: +# +# # My Type +# + id (number) +# + name (string) +# +# # Another Type (My Type) +# + id (string) + +# Make sure all members are unique, removing all duplicates before the last +# occurence of the member key name. +uniqueMembers = (content) -> + known = [] + i = content.length - 1 + while i >= 0 + if content[i].element is 'member' + key = content[i].content.key.content + if known.indexOf(key) isnt -1 + content.splice(i, 1) + continue + known.push key + i-- + +# Have `element` inherit from `base`. +module.exports = (base, element) -> + # First, we do a deep copy of the base (parent) element + combined = JSON.parse(JSON.stringify(base)) + + # Next, we copy or overwrite any metadata and attributes + if element.meta + combined.meta ?= {} + combined.meta[key] = value for own key, value of element.meta + if element.attributes + combined.attributes ?= {} + combined.attributes[key] = value for own key, value of element.attributes + + # Lastly, we combine the content if we can. For simple types, this means + # overwriting the content. For arrays it adds to the content list and for + # objects is adds *or* overwrites (if an existing key already exists). + if element.content + if combined.content?.push or element.content?.push + # This could be an object or array + combined.content ?= [] + for item in element.content + combined.content.push item + + if combined.content.length and combined.content[0].element is 'member' + # This is probably an object - remove duplicate keys! + uniqueMembers combined.content + else + # Not an array or object, just overwrite the content + combine.content = element.content + combined diff --git a/src/main.coffee b/src/main.coffee index adada1e1..e2c0bf04 100644 --- a/src/main.coffee +++ b/src/main.coffee @@ -1,14 +1,20 @@ +crypto = require 'crypto' fs = require 'fs' +hljs = require 'highlight.js' +jade = require 'jade' +less = require 'less' +markdownIt = require 'markdown-it' +moment = require 'moment' path = require 'path' -drafter = require 'drafter' +querystring = require 'querystring' -INCLUDE = /( *)/gmi +renderExample = require './example' +renderSchema = require './schema' + +# The root directory of this project ROOT = path.dirname __dirname -# Legacy template names -LEGACY_TEMPLATES = [ - 'default', 'default-collapsed', 'flatly', 'flatly-collapsed', 'slate', - 'slate-collapsed', 'cyborg', 'cyborg-collapsed'] +cache = {} # Utility for benchmarking benchmark = @@ -17,153 +23,544 @@ benchmark = # Extend an error's message. Returns the modified error. errMsg = (message, err) -> - err.message = "#{message}: #{err.message}" - return err - -# Replace the include directive with the contents of the included -# file in the input. -includeReplace = (includePath, match, spaces, filename) -> - fullPath = path.join includePath, filename - lines = fs.readFileSync(fullPath, 'utf-8').replace(/\r\n?/g, '\n').split('\n') - content = spaces + lines.join "\n#{spaces}" - - # The content can itself include other files, so check those - # as well! Beware of circular includes! - includeDirective path.dirname(fullPath), content - -# Handle the include directive, which inserts the contents of one -# file into another. We find the directive using a regular expression -# and replace it using the method above. -includeDirective = (includePath, input) -> - input.replace INCLUDE, includeReplace.bind(this, includePath) - -# Get a list of all paths from included files. This *excludes* the -# input path itself. -exports.collectPathsSync = (input, includePath) -> - paths = [] - input.replace INCLUDE, (match, spaces, filename) -> - fullPath = path.join(includePath, filename) - paths.push fullPath - - content = fs.readFileSync fullPath, 'utf-8' - paths = paths.concat exports.collectPathsSync(content, path.dirname(fullPath)) - paths - -# Get the theme module for a given theme name -exports.getTheme = (name) -> - name = 'olio' if not name or name in LEGACY_TEMPLATES - require "aglio-theme-#{name}" - -# Render an API Blueprint string using a given template -exports.render = (input, options, done) -> - # Support a template name as the options argument - if typeof options is 'string' or options instanceof String - options = - theme: options - - # Defaults - options.filterInput ?= true - options.includePath ?= process.cwd() - options.theme ?= 'default' - - # For backward compatibility - if options.template then options.theme = options.template - - if fs.existsSync options.theme - console.log "Setting theme to olio and layout to #{options.theme}" - options.themeLayout = options.theme - options.theme = 'olio' - else if options.theme isnt 'default' and options.theme in LEGACY_TEMPLATES - variables = options.theme.split('-')[0] - console.log "Setting theme to olio and variables to #{variables}" - options.themeVariables = variables - options.theme = 'olio' - - # Handle custom directive(s) - input = includeDirective options.includePath, input - - # Drafter does not support \r ot \t in the input, so - # try to intelligently massage the input so that it works. - # This is required to process files created on Windows. - filteredInput = if not options.filterInput then input else - input - .replace(/\r\n?/g, '\n') - .replace(/\t/g, ' ') - - benchmark.start 'parse' - drafter.parse filteredInput, type: 'ast', (err, res) -> - benchmark.end 'parse' - if err - err.input = input - return done(errMsg 'Error parsing input', err) - - try - theme = exports.getTheme options.theme - catch err - return done(errMsg 'Error getting theme', err) - - # Setup default options if needed - for option in theme.getConfig().options or [] - # Convert `foo-bar` into `themeFooBar` - words = (f[0].toUpperCase() + f.slice(1) for f in option.name.split('-')) - name = "theme#{words.join('')}" - options[name] ?= option.default - - benchmark.start 'render-total' - theme.render res.ast, options, (err, html) -> - benchmark.end 'render-total' - if err then return done(err) - - # Add filtered input to warnings since we have no - # error to return - res.warnings.input = filteredInput - - done null, html, res.warnings - -# Render from/to files -exports.renderFile = (inputFile, outputFile, options, done) -> - render = (input) -> - exports.render input, options, (err, html, warnings) -> - if err then return done(err) - - if outputFile isnt '-' - fs.writeFile outputFile, html, (err) -> - done err, warnings - else - console.log html - done null, warnings - - if inputFile isnt '-' - options.includePath ?= path.dirname inputFile - fs.readFile inputFile, encoding: 'utf-8', (err, input) -> - if err then return done(errMsg 'Error reading input', err) - render input.toString() + err.message = "#{message}: #{err.message}" + return err + +# Generate a SHA1 hash +sha1 = (value) -> + crypto.createHash('sha1').update(value.toString()).digest('hex') + +# A function to create ID-safe slugs. If `unique` is passed, then +# unique slugs are returned for the same input. The cache is just +# a plain object where the keys are the sluggified name. +slug = (cache={}, value='', unique=false) -> + sluggified = value.toLowerCase() + .replace(/[ \t\n\\<>"'=:/]/g, '-') + .replace(/-+/g, '-') + .replace(/^-/, '') + + if unique + while cache[sluggified] + # Already exists, so let's try to make it unique. + if sluggified.match /\d+$/ + sluggified = sluggified.replace /\d+$/, (value) -> + parseInt(value) + 1 + else + sluggified = sluggified + '-1' + + cache[sluggified] = true + + return sluggified + +# A function to highlight snippets of code. lang is optional and +# if given, is used to set the code language. If lang is no-highlight +# then no highlighting is performed. +highlight = (code, lang, subset) -> + benchmark.start "highlight #{lang}" + response = switch lang + when 'no-highlight' then code + when undefined, null, '' + hljs.highlightAuto(code, subset).value + else hljs.highlight(lang, code).value + benchmark.end "highlight #{lang}" + return response.trim() + +getCached = (key, compiledPath, sources, load, done) -> + # Disable the template/css caching? + if process.env.NOCACHE then return done null + + # Already loaded? Just return it! + if cache[key] then return done null, cache[key] + + # Next, try to check if the compiled path exists and is newer than all of + # the sources. If so, load the compiled path into the in-memory cache. + try + if fs.existsSync compiledPath + compiledStats = fs.statSync compiledPath + + for source in sources + sourceStats = fs.statSync source + if sourceStats.mtime > compiledStats.mtime + # There is a newer source file, so we ignore the compiled + # version on disk. It'll be regenerated later. + return done null + + try + load compiledPath, (err, item) -> + if err then return done(errMsg 'Error loading cached resource', err) + + cache[key] = item + done null, cache[key] + catch loadErr + return done(errMsg 'Error loading cached resource', loadErr) else - process.stdin.setEncoding 'utf-8' - process.stdin.on 'readable', -> - chunk = process.stdin.read() - if chunk? - render chunk - -# Compile markdown from/to files -exports.compileFile = (inputFile, outputFile, done) -> - compile = (input) -> - compiled = includeDirective path.dirname(inputFile), input - - if outputFile isnt '-' - fs.writeFile outputFile, compiled, (err) -> - done err - else - console.log compiled - done null - - if inputFile isnt '-' - fs.readFile inputFile, encoding: 'utf-8', (err, input) -> - if err then return done(errMsg 'Error writing output', err) - compile input.toString() + done null + catch err + done err + +getCss = (variables, styles, verbose, done) -> + # Get the CSS for the given variables and style. This method caches + # its output, so subsequent calls will be extremely fast but will + # not reload potentially changed data from disk. + # The CSS is generated via a dummy LESS file with imports to the + # default variables, any custom override variables, and the given + # layout style. Both variables and style support special values, + # for example `flatly` might load `styles/variables-flatly.less`. + # See the `styles` directory for available options. + key = "css-#{variables}-#{styles}" + if cache[key] then return done null, cache[key] + + # Not cached in memory, but maybe it's already compiled on disk? + compiledPath = path.join ROOT, 'cache', + "#{sha1 key}.css" + + defaultVariablePath = path.join ROOT, 'styles', 'variables-default.less' + sources = [defaultVariablePath] + + if not Array.isArray(variables) then variables = [variables] + if not Array.isArray(styles) then styles = [styles] + + variablePaths = [defaultVariablePath] + for item in variables + if item isnt 'default' + customPath = path.join ROOT, 'styles', "variables-#{item}.less" + if not fs.existsSync customPath + customPath = item + if not fs.existsSync customPath + return done new Error "#{customPath} does not exist!" + variablePaths.push customPath + sources.push customPath + + stylePaths = [] + for item in styles + customPath = path.join ROOT, 'styles', "layout-#{item}.less" + if not fs.existsSync customPath + customPath = item + if not fs.existsSync customPath + return done new Error "#{customPath} does not exist!" + stylePaths.push customPath + sources.push customPath + + load = (filename, loadDone) -> + fs.readFile filename, 'utf-8', loadDone + + if verbose + console.log "Using variables #{variablePaths}" + console.log "Using styles #{stylePaths}" + console.log "Checking cache #{compiledPath}" + + getCached key, compiledPath, sources, load, (err, css) -> + if err then return done err + if css + if verbose then console.log 'Cached version loaded' + return done null, css + + # Not cached, so let's create the file. + if verbose + console.log 'Not cached or out of date. Generating CSS...' + + tmp = '' + + for customPath in variablePaths + tmp += "@import \"#{customPath}\";\n" + + for customPath in stylePaths + tmp += "@import \"#{customPath}\";\n" + + benchmark.start 'less-compile' + less.render tmp, compress: true, (err, result) -> + if err then return done(msgErr 'Error processing LESS -> CSS', err) + + try + css = result.css + fs.writeFileSync compiledPath, css, 'utf-8' + catch writeErr + return done(errMsg 'Error writing cached CSS to file', writeErr) + + benchmark.end 'less-compile' + + cache[key] = css + done null, cache[key] + +compileTemplate = (filename, options) -> + compiled = """ + var jade = require('jade/runtime'); + #{jade.compileFileClient filename, options} + module.exports = compiledFunc; + """ + +getTemplate = (name, verbose, done) -> + # Check if this is a built-in template name + builtin = path.join(ROOT, 'templates', "#{name}.jade") + if not fs.existsSync(name) and fs.existsSync(builtin) + name = builtin + + # Get the template function for the given path. This will load and + # compile the template if necessary, and cache it for future use. + key = "template-#{name}" + + # Check if it is cached in memory. If not, then we'll check the disk. + if cache[key] then return done null, cache[key] + + # Check if it is compiled on disk and not older than the template file. + # If not present or outdated, then we'll need to compile it. + compiledPath = path.join ROOT, 'cache', "#{sha1 key}.js" + + load = (filename, loadDone) -> + try + loaded = require(filename) + catch loadErr + return loadDone(errMsg 'Unable to load template', loadErr) + + loadDone null, require(filename) + + if verbose + console.log "Using template #{name}" + console.log "Checking cache #{compiledPath}" + + getCached key, compiledPath, [name], load, (err, template) -> + if err then return done err + if template + if verbose then console.log 'Cached version loaded' + return done null, template + + if verbose + console.log 'Not cached or out of date. Generating template JS...' + + # We need to compile the template, then cache it. This is interesting + # because we are compiling to a client-side template, then adding some + # module-specific code to make it work here. This allows us to save time + # in the future by just loading the generated javascript function. + benchmark.start 'jade-compile' + compileOptions = + filename: name + name: 'compiledFunc' + self: true + compileDebug: false + + try + compiled = compileTemplate name, compileOptions + catch compileErr + return done(errMsg 'Error compiling template', compileErr) + + if compiled.indexOf('self.') is -1 + # Not using self, so we probably need to recompile into compatibility + # mode. This is slower, but keeps things working with Jade files + # designed for Aglio 1.x. + compileOptions.self = false + + try + compiled = compileTemplate name, compileOptions + catch compileErr + return done(errMsg 'Error compiling template', compileErr) + + try + fs.writeFileSync compiledPath, compiled, 'utf-8' + catch writeErr + return done(errMsg 'Error writing cached template file', writeErr) + + benchmark.end 'jade-compile' + + cache[key] = require(compiledPath) + done null, cache[key] + +modifyUriTemplate = (templateUri, parameters, colorize) -> + # Modify a URI template to only include the parameter names from + # the given parameters. For example: + # URI template: /pages/{id}{?verbose} + # Parameters contains a single `id` parameter + # Output: /pages/{id} + parameterValidator = (b) -> + # Compare the names, removing the special `*` operator + parameterNames.indexOf( + querystring.unescape b.replace(/^\*|\*$/, '')) isnt -1 + parameterNames = (param.name for param in parameters) + parameterBlocks = [] + lastIndex = index = 0 + while (index = templateUri.indexOf("{", index)) isnt - 1 + parameterBlocks.push templateUri.substring(lastIndex, index) + block = {} + closeIndex = templateUri.indexOf("}", index) + block.querySet = templateUri.indexOf("{?", index) is index + block.formSet = templateUri.indexOf("{&", index) is index + block.reservedSet = templateUri.indexOf("{+", index) is index + lastIndex = closeIndex + 1 + index++ + index++ if block.querySet or block.formSet or block.reservedSet + parameterSet = templateUri.substring(index, closeIndex) + block.parameters = parameterSet.split(",").filter(parameterValidator) + parameterBlocks.push block if block.parameters.length + parameterBlocks.push templateUri.substring(lastIndex, templateUri.length) + parameterBlocks.reduce((uri, v) -> + if typeof v is "string" + uri.push v else - process.stdin.setEncoding 'utf-8' - process.stdin.on 'readable', -> - chunk = process.stdin.read() - if chunk? - compile chunk + segment = if not colorize then ["{"] else [] + segment.push "?" if v.querySet + segment.push "&" if v.formSet + segment.push "+" if v.reservedSet and not colorize + segment.push v.parameters.map((name) -> + if not colorize then name else + # TODO: handle errors here? + name = name.replace(/^\*|\*$/, '') + param = parameters[parameterNames.indexOf(querystring.unescape name)] + if v.querySet or v.formSet + "#{name}=" + + "#{param.example || ''}" + else + "#{ + param.example || name}" + ).join(if colorize then '&' else ',') + if not colorize + segment.push "}" + uri.push segment.join("") + uri + , []).join('').replace(/\/+/g, '/') + +decorate = (api, md, slugCache, verbose) -> + # Decorate an API Blueprint AST with various pieces of information that + # will be useful for the theme. Anything that would significantly + # complicate the Jade template should probably live here instead! + + # Use the slug caching mechanism + slugify = slug.bind slug, slugCache + + # Find data structures. This is a temporary workaround until Drafter is + # updated to support JSON Schema again. + # TODO: Remove me when Drafter is released. + dataStructures = {} + for category in api.content or [] + for item in category.content or [] + if item.element is 'dataStructure' + dataStructure = item.content[0] + dataStructures[dataStructure.meta.id] = dataStructure + if verbose + console.log "Known data structures: #{Object.keys(dataStructures)}" + + # API overview description + if api.description + api.descriptionHtml = md.render api.description + api.navItems = slugCache._nav + slugCache._nav = [] + + for meta in api.metadata or [] + if meta.name is 'HOST' + api.host = meta.value + + for resourceGroup in api.resourceGroups or [] + # Element ID and link + resourceGroup.elementId = slugify resourceGroup.name, true + resourceGroup.elementLink = "##{resourceGroup.elementId}" + + # Description + if resourceGroup.description + resourceGroup.descriptionHtml = md.render resourceGroup.description + resourceGroup.navItems = slugCache._nav + slugCache._nav = [] + + for resource in resourceGroup.resources or [] + # Element ID and link + resource.elementId = slugify( + "#{resourceGroup.name}-#{resource.name}", true) + resource.elementLink = "##{resource.elementId}" + + for action in resource.actions or [] + # Element ID and link + action.elementId = slugify( + "#{resourceGroup.name}-#{resource.name}-#{action.method}", true) + action.elementLink = "##{action.elementId}" + + # Lowercase HTTP method name + action.methodLower = action.method.toLowerCase() + + # Parameters may be defined on the action or on the + # parent resource. Resource parameters should be concatenated + # to the action-specific parameters if set. + if not (action.attributes or {}).uriTemplate + if not action.parameters or not action.parameters.length + action.parameters = resource.parameters + else if resource.parameters + action.parameters = resource.parameters.concat(action.parameters) + + # Remove any duplicates! This gives precedence to the parameters + # defined on the action. + knownParams = {} + newParams = [] + reversed = (action.parameters or []).concat([]).reverse() + for param in reversed + if knownParams[param.name] then continue + knownParams[param.name] = true + newParams.push param + + action.parameters = newParams.reverse() + + # Set up the action's template URI + action.uriTemplate = modifyUriTemplate( + (action.attributes or {}).uriTemplate or resource.uriTemplate or '', + action.parameters) + + action.colorizedUriTemplate = modifyUriTemplate( + (action.attributes or {}).uriTemplate or resource.uriTemplate or '', + action.parameters, true) + + # Examples have a content section only if they have a + # description, headers, body, or schema. + action.hasRequest = false + for example in action.examples or [] + for name in ['requests', 'responses'] + for item in example[name] or [] + if name is 'requests' and not action.hasRequest + action.hasRequest = true + + # If there is no schema, but there are MSON attributes, then try + # to generate the schema. This will fail sometimes. + # TODO: Remove me when Drafter is released. + if not item.schema and item.content + for dataStructure in item.content + if dataStructure.element is 'dataStructure' + try + schema = renderSchema( + dataStructure.content[0], dataStructures) + schema['$schema'] = + 'http://json-schema.org/draft-04/schema#' + item.schema = JSON.stringify(schema, null, 2) + catch err + if verbose + console.log( + JSON.stringify dataStructure.content[0], null, 2) + console.log(err) + + if item.content and not process.env.DRAFTER_EXAMPLES + for dataStructure in item.content + if dataStructure.element is 'dataStructure' + try + item.body = JSON.stringify(renderExample( + dataStructure.content[0], dataStructures), null, 2) + catch err + if verbose + console.log( + JSON.stringify dataStructure.content[0], null, 2) + console.log(err) + + item.hasContent = item.description or \ + Object.keys(item.headers).length or \ + item.body or \ + item.schema + + # If possible, make the body/schema pretty + try + if item.body + item.body = JSON.stringify(JSON.parse(item.body), null, 2) + if item.schema + item.schema = JSON.stringify(JSON.parse(item.schema), null, 2) + catch err + false + +# Get the theme's configuration, used by Aglio to present available +# options and confirm that the input blueprint is a supported +# version. +exports.getConfig = -> + formats: ['1A'] + options: [ + {name: 'variables', + description: 'Color scheme name or path to custom variables', + default: 'default'}, + {name: 'condense-nav', description: 'Condense navigation links', + boolean: true, default: true}, + {name: 'full-width', description: 'Use full window width', + boolean: true, default: false}, + {name: 'template', description: 'Template name or path to custom template', + default: 'default'}, + {name: 'style', + description: 'Layout style name or path to custom stylesheet'}, + {name: 'emoji', description: 'Enable support for emoticons', + boolean: true, default: true} + ] + +# Render the blueprint with the given options using Jade and LESS +exports.render = (input, options, done) -> + if not done? + done = options + options = {} + + # Disable the template/css caching? + if process.env.NOCACHE then cache = {} + + # This is purely for backward-compatibility + if options.condenseNav then options.themeCondenseNav = options.condenseNav + if options.fullWidth then options.themeFullWidth = options.fullWidth + + # Setup defaults + options.themeVariables ?= 'default' + options.themeStyle ?= 'default' + options.themeTemplate ?= 'default' + options.themeCondenseNav ?= true + options.themeFullWidth ?= false + + # Transform built-in layout names to paths + if options.themeTemplate is 'default' + options.themeTemplate = path.join ROOT, 'templates', 'index.jade' + + # Setup markdown with code highlighting and smartypants. This also enables + # automatically inserting permalinks for headers. + slugCache = + _nav: [] + md = markdownIt( + html: true + linkify: true + typographer: true + highlight: highlight + ).use(require('markdown-it-anchor'), + slugify: (value) -> + output = "header-#{slug(slugCache, value, true)}" + slugCache._nav.push [value, "##{output}"] + return output + permalink: true + permalinkClass: 'permalink' + ).use(require('markdown-it-checkbox') + ).use(require('markdown-it-container'), 'note' + ).use(require('markdown-it-container'), 'warning') + + if options.themeEmoji then md.use require('markdown-it-emoji') + + # Enable code highlighting for unfenced code blocks + md.renderer.rules.code_block = md.renderer.rules.fence + + benchmark.start 'decorate' + decorate input, md, slugCache, options.verbose + benchmark.end 'decorate' + + benchmark.start 'css-total' + {themeVariables, themeStyle, verbose} = options + getCss themeVariables, themeStyle, verbose, (err, css) -> + if err then return done(errMsg 'Could not get CSS', err) + benchmark.end 'css-total' + + locals = + api: input + condenseNav: options.themeCondenseNav + css: css + fullWidth: options.themeFullWidth + date: moment + hash: (value) -> + crypto.createHash('md5').update(value.toString()).digest('hex') + highlight: highlight + markdown: (content) -> md.render content + slug: slug.bind(slug, slugCache) + urldec: (value) -> querystring.unescape(value) + + for key, value of options.locals or {} + locals[key] = value + + benchmark.start 'get-template' + getTemplate options.themeTemplate, verbose, (getTemplateErr, renderer) -> + if getTemplateErr + return done(errMsg 'Could not get template', getTemplateErr) + benchmark.end 'get-template' + + benchmark.start 'call-template' + try html = renderer locals + catch err + return done(errMsg 'Error calling template during rendering', err) + benchmark.end 'call-template' + done null, html diff --git a/src/schema.coffee b/src/schema.coffee new file mode 100644 index 00000000..787e9906 --- /dev/null +++ b/src/schema.coffee @@ -0,0 +1,88 @@ +# This is an extremely simple JSON Schema generator given refracted MSON input. +# It handles the following: +# +# * Simple types, enums, arrays, objects +# * Property descriptions +# * Required, default, nullable properties +# * References +# * Mixins (Includes) +# * Arrays with members of different types +# * One Of (mutually exclusive) properties +# +# It is missing support for many advanced features. +{deepEqual} = require 'assert' +inherit = require './inherit' + +module.exports = renderSchema = (root, dataStructures) -> + schema = {} + switch root.element + when 'boolean', 'string', 'number' + schema.type = root.element + if root.attributes?.default? + schema.default = root.attributes.default + when 'enum' + schema.enum = [] + for item in root.content or [] + schema.enum.push item.content + when 'array' + schema.type = 'array' + items = [] + for item in root.content or [] + items.push renderSchema(item, dataStructures) + if items.length is 1 + schema.items = items[0] + else if items.length > 1 + try + schema.items = items.reduce (l, r) -> deepEqual(l, r) or r + catch + schema.items = 'anyOf': items + when 'object', 'option' + schema.type = 'object' + schema.properties = {} + required = [] + properties = root.content.slice(0) + i = 0 + while i < properties.length + member = properties[i] + i++ + if member.element == 'ref' + ref = dataStructures[member.content.href] + i-- + properties.splice.apply properties, [i, 1].concat(ref.content) + continue + else if member.element == 'select' + exclusive = [] + for option in member.content + optionSchema = renderSchema(option, dataStructures) + for key, prop of optionSchema.properties + exclusive.push key + schema.properties[key] = prop + if not schema.allOf then schema.allOf = [] + schema.allOf.push not: required: exclusive + continue + key = member.content.key.content + schema.properties[key] = renderSchema( + member.content.value, dataStructures) + if member.meta?.description? + schema.properties[key].description = member.meta.description + if member.attributes?.typeAttributes + typeAttr = member.attributes.typeAttributes + if typeAttr.indexOf('required') isnt -1 + if required.indexOf(key) is -1 then required.push key + if typeAttr.indexOf('nullable') isnt -1 + schema.properties[key].type = [schema.properties[key].type, 'null'] + if required.length + schema.required = required + else + ref = dataStructures[root.element] + if ref + schema = renderSchema(inherit(ref, root), dataStructures) + + if root.meta?.description? + schema.description = root.meta.description + + if root.attributes?.typeAttributes + typeAttr = root.attributes.typeAttributes + if typeAttr.indexOf('nullable') isnt -1 + schema.type = [schema.type, 'null'] + schema diff --git a/styles/layout-default.less b/styles/layout-default.less new file mode 100644 index 00000000..1d957a70 --- /dev/null +++ b/styles/layout-default.less @@ -0,0 +1,863 @@ +/* Element styles */ +body { + color: @text-color; + background: @background-color; + font: @base-font; +} + +header { + border-bottom: 1px solid @group-title-background-color; + margin-bottom: @padding; +} + +h1, h2, h3, h4, h5 { + color: @heading-text-color; + margin: @padding 0; + + & .permalink { + margin-left: 0; + opacity: 0; + transition: opacity 0.25s ease; + } + + &:hover .permalink { + opacity: 1; + } + + // Chrome makes the *text* disappear after hover rather than the permalink + // itself... weird bug so we're disabling the fading for now. The key + // to the issue is the `position: relative` on the `.triple .content` + // container (disabling that rule fixes the problem, hence why it works + // in the two-column theme). + .triple & .permalink { + opacity: 0.15; + } + + .triple &:hover .permalink { + opacity: 0.15; + } +} + +h1 { + font: @title-font; + font-size: 36px; +} + +h2 { + font: @title-font; + font-size: 30px; +} + +h3 { + font-size: 100%; + text-transform: uppercase; +} + +h5 { + font-size: 100%; + font-weight: normal; +} + +p { + margin: 0 0 10px; + + &.choices { + line-height: 1.6; + } +} + +a { + color: @link-color; + text-decoration: none; +} + +li { + p { + margin: 0; + } +} + +hr.split { + border: 0; + height: 1px; + width: 100%; + padding-left: @padding / 2; + margin: @padding auto; + background-image: linear-gradient(to right, fade(@text-color, 0%) 20%, fade(@text-color, 20%) 100% - @right-panel-background-width, fade(@right-text-color, 20%) 100% - @right-panel-background-width, fade(@right-text-color, 0%) 80%); +} + +dl { + dt { + float: left; + width: 130px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 700; + } + + dd { + margin-left: 150px; + } +} + +blockquote { + color: fadeout(@text-color, 50%); + font-size: 15.5px; + padding: 10px 20px; + margin: @padding 0; + border-left: 5px solid @quote-border-color; + + p:last-child { + margin-bottom: 0; + } +} + +pre { + background-color: @code-block-background-color; + padding: @padding; + border: 1px solid @code-block-border-color; + border-radius: @border-radius; + overflow: auto; + + code { + color: @code-block-text-color; + background-color: transparent; + padding: 0; + border: none; + } +} + +code { + color: @inline-code-text-color; + background-color: @inline-code-background-color; + font: @code-font; + padding: 1px 4px; + border: 1px solid @code-block-border-color; + border-radius: 3px; +} + +ul, ol { + padding-left: 2em; +} + +table { + border-collapse: collapse; + border-spacing: 0; + margin-bottom: @padding; + + tr:nth-child(2n) { + background-color: @table-row-background-color; + } + + th, td { + padding: @padding/2 @padding; + border: 1px solid @table-border-color; + } +} + +.text-muted { + opacity: 0.5; +} + +.note, .warning { + padding: 0.3em 1em; + margin: 1em 0; + border-radius: 2px; + font-size: 90%; + + h1, h2, h3, h4, h5, h6 { + font-family: @title-font; + font-size: 135%; + font-weight: 500; + } + + p { + margin: 0.5em 0; + } +} + +.note { + color: @note-text-color; + background-color: @note-background-color; + border-left: 4px solid @note-border-color; + + h1, h2, h3, h4, h5, h6 { + color: @note-title-text-color; + } +} + +.warning { + color: @warning-text-color; + background-color: @warning-background-color; + border-left: 4px solid @warning-border-color; + + h1, h2, h3, h4, h5, h6 { + color: @warning-title-text-color; + } +} + +header { + margin-top: @padding * 2; +} + +nav { + position: fixed; + top: @padding * 2; + bottom: 0; + overflow-y: auto; + + .resource-group { + padding: 0; + + .heading { + position: relative; + + .chevron { + position: absolute; + top: @padding; + right: @padding; + opacity: 0.5; + } + + a { + display: block; + color: @text-color; + opacity: 0.7; + border-left: 2px solid transparent; + margin: 0; + + &:hover { + text-decoration: @nav-hover-text-decoration; + background-color: @nav-hover-background-color; + border-left: 2px solid @nav-hover-border-color; + } + } + } + } + + ul { + list-style-type: none; + padding-left: 0; + + a { + display: block; + font-size: 13 * @font-size / 14; + color: fade(@text-color, 70%); + padding: (2 * @padding / 3) @padding; + border-top: 1px solid @group-border-color; + border-left: 2px solid transparent; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + &:hover { + text-decoration: @nav-hover-text-decoration; + background-color: @nav-hover-background-color; + border-left: 2px solid @nav-hover-border-color; + } + } + + /* Spacing for first level items */ + & > li { + margin: 0; + + &:first-child { + margin-top: -@padding; + } + + &:last-child { + margin-bottom: -@padding; + } + } + + /* Adjust spacing for nested lists */ + ul { + a { + padding-left: @padding * 2; + } + + li { + margin: 0; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + } + } + } + + /* Remove the top border from the first item in each group */ + & > div > div > ul > li:first-child > a { + border-top: none; + } +} + +/* Generic classes */ +.preload * { + transition: none !important; +} + +.pull-left { + float: left; +} + +.pull-right { + float: right; +} + +.badge { + display: inline-block; + float: right; + min-width: 10px; + min-height: @font-size; + padding: 3px 7px; + font-size: 12px; + color: @group-text-color; + background-color: @group-title-background-color; + border-radius: 10px; + margin: @badge-margin; + + &.get { + color: @get-badge-text-color; + background-color: @get-background-color; + } + + &.head { + color: @head-badge-text-color; + background-color: @head-background-color; + } + + &.options { + color: @options-badge-text-color; + background-color: @options-background-color; + } + + &.put { + color: @put-badge-text-color; + background-color: @put-background-color; + } + + &.patch { + color: @patch-badge-text-color; + background-color: @patch-background-color; + } + + &.post { + color: @post-badge-text-color; + background-color: @post-background-color; + } + + &.delete { + color: @delete-badge-text-color; + background-color: @delete-background-color; + } +} + +.collapse-button { + float: right; + + .close { + display: none; + color: @link-color; + cursor: pointer; + } + + .open { + color: @link-color; + cursor: pointer; + } + + &.show { + .close { + display: inline; + } + + .open { + display: none; + } + } +} + +.collapse-content { + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease-in-out; +} + +/* Layout classes */ +nav { + width: @nav-width; +} + +.container { + max-width: 940px; + margin-left: auto; + margin-right: auto; + + .row { + .content { + margin-left: @nav-width + (@padding * 2); + width: 720px - (@padding * 2); + } + + &:after { + content: ''; + display: block; + clear: both; + } + } +} + +.container-fluid { + nav { + width: 22%; + } + + .row { + .content { + margin-left: 24%; + } + } + + &.triple { + nav { + width: @nav-triple-width; + padding-right: 1px; + } + + .row .content { + position: relative; + margin-left: @nav-triple-width; + padding-left: @padding * 2; + } + } +} + +.middle:before, .middle:after { + content: ''; + display: table; +} + +.middle:after { + clear: both; +} + +.middle { + box-sizing: border-box; + width: 100% - @right-panel-width; + padding-right: @padding; +} + +.right { + box-sizing: border-box; + float: right; + width: @right-panel-width; + padding-left: @padding; + + a { + color: @right-link-color; + } + + h1, h2, h3, h4, h5, p, div { + color: @right-text-color; + } + + pre { + background-color: @right-code-block-background-color; + border: 1px solid @right-code-block-border-color; + + code { + color: @right-code-block-text-color; + } + } + + .description { + margin-top: @padding; + } +} + +.triple .resource-heading { + font-size: 125%; +} + +.definition { + margin-top: @padding; + margin-bottom: @padding; + + .method { + font-weight: bold; + + &.get { + color: hsl(hue(@get-background-color), 60%, 45%); + } + + &.head { + color: hsl(hue(@head-background-color), 60%, 45%); + } + + &.options { + color: hsl(hue(@options-background-color), 60%, 45%); + } + + &.post { + color: hsl(hue(@post-background-color), 60%, 45%); + } + + &.put { + color: hsl(hue(@put-background-color), 60%, 45%); + } + + &.patch { + color: hsl(hue(@patch-background-color), 60%, 45%); + } + + &.delete { + color: hsl(hue(@delete-background-color), 60%, 45%); + } + } + + .uri { + word-break: break-all; + word-wrap: break-word; + } + + .hostname { + opacity: 0.5; + } +} + +.example-names { + background-color: @tabs-background-color; + padding: @padding; + border-radius: @border-radius; + + .tab-button { + cursor: pointer; + color: @text-color; + border: 1px solid @tabs-border-color; + padding: @padding / 2; + margin-left: @padding; + + &.active { + background-color: @tabs-active-background-color; + } + } +} + +.right .example-names { + background-color: @right-tabs-background-color; + + .tab-button { + color: @right-text-color; + border: 1px solid @right-tabs-border-color; + border-radius: @border-radius; + + &.active { + background-color: @right-tabs-active-background-color; + } + } +} + +#nav-background { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: @nav-triple-width; + padding-right: @padding * 1.2; + background-color: @nav-background-color; + border-right: 1px solid @nav-border-color; + z-index: -1; +} + +#right-panel-background { + position: absolute; + right: -@padding; + top: -@padding; + bottom: -@padding; + width: @right-panel-background-width; + background-color: @right-background-color; + z-index: -1; +} + +@media (max-width: 1200px) { + nav { + width: @nav-width * 0.9; + } + + .container { + max-width: 840px; + + .row { + .content { + margin-left: 200px + (@padding * 2); + width: 630px - (@padding * 2); + } + } + } +} + +@media (max-width: 992px) { + nav { + width: @nav-width * 0.77; + } + + .container { + max-width: 720px; + + .row { + .content { + margin-left: 170px + (@padding * 2); + width: 550px - (@padding * 2); + } + } + } +} + +@media (max-width: 768px) { + nav { + display: none; + } + + .container { + width: 95%; + max-width: none; + } + + .container .row, .container-fluid .row, .container-fluid.triple .row { + .content { + margin-left: auto; + margin-right: auto; + width: 95%; + } + } + + #nav-background { + display: none; + } + + #right-panel-background { + width: @right-panel-background-width; + } +} + +/* Context-specific and API color classes */ +.back-to-top { + position: fixed; + z-index: 1; + bottom: 0px; + right: 24px; + padding: 4px 8px; + color: fadeout(@text-color, 50%); + background-color: @group-title-background-color; + text-decoration: none !important; + border-top: 1px solid @group-border-color; + border-left: 1px solid @group-border-color; + border-right: 1px solid @group-border-color; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +.resource-group { + padding: @group-padding; + margin-bottom: @padding; + background-color: @group-background-color; + border: 1px solid @group-border-color; + border-radius: @border-radius; + + h2.group-heading, .heading a { + padding: @group-padding; + margin: @group-header-margin; + background-color: @group-title-background-color; + border-bottom: 1px solid @group-border-color; + border-top-left-radius: @border-radius; + border-top-right-radius: @border-radius; + + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } +} + +.triple .content .resource-group { + padding: 0; + border: none; + + h2.group-heading, .heading a { + margin: 0 0 @padding 0; + border: 1px solid @group-border-color; + } +} + +nav .resource-group{ + .heading a { + padding: @padding; + margin-bottom: 0; + } + + .collapse-content { + padding: 0; + } +} + +.action { + margin-bottom: @padding; + padding: @padding @padding 0 @padding; + overflow: hidden; + border: 1px solid transparent; + border-radius: @border-radius; + + h4.action-heading { + padding: @padding / 2 @padding; + margin: -@padding -@padding @padding -@padding; + border-bottom: 1px solid transparent; + border-top-left-radius: @border-radius; + border-top-right-radius: @border-radius; + overflow: hidden; + + .name { + float: right; + font-weight: normal; + padding: @padding / 2 0; + } + + .method { + padding: @padding / 2 @padding; + margin-right: @padding; + border-radius: ceil(@border-radius / 2); + display: inline-block; + + &.get { + color: contrast(@get-color); + background-color: @get-color; + } + + &.head { + color: contrast(@head-color); + background-color: @head-color; + } + + &.options { + color: contrast(@options-color); + background-color: @options-color; + } + + &.put { + color: contrast(@put-color); + background-color: @put-color; + } + + &.patch { + color: contrast(@patch-color); + background-color: @patch-color; + } + + &.post { + color: contrast(@post-color); + background-color: @post-color; + } + + &.delete { + color: contrast(@delete-color); + background-color: @delete-color; + } + } + + code { + color: @title-code-text-color; + background-color: @title-code-background-color; + border-color: @title-code-border-color; + font-weight: normal; + word-break: break-all; + display: inline-block; + margin-top: 2px; + } + } + + dl.inner { + padding-bottom: 2px; + } + + .title { + border-bottom: 1px solid @group-background-color; + margin: 0 -@padding -1px -@padding; + padding: @padding; + } + + &.get { + border-color: @get-border-color; + + h4.action-heading { + color: @get-color; + background: @get-background-color; + border-bottom-color: @get-border-color; + } + } + + &.head { + border-color: @head-border-color; + + h4.action-heading { + color: @head-color; + background: @head-background-color; + border-bottom-color: @head-border-color; + } + } + + &.options { + border-color: @options-border-color; + + h4.action-heading { + color: @options-color; + background: @options-background-color; + border-bottom-color: @options-border-color; + } + } + + &.post { + border-color: @post-border-color; + + h4.action-heading { + color: @post-color; + background: @post-background-color; + border-bottom-color: @post-border-color; + } + } + + &.put { + border-color: @put-border-color; + + h4.action-heading { + color: @put-color; + background: @put-background-color; + border-bottom-color: @put-border-color; + } + } + + &.patch { + border-color: @patch-border-color; + + h4.action-heading { + color: @patch-color; + background: @patch-background-color; + border-bottom-color: @patch-border-color; + } + } + + &.delete { + border-color: @delete-border-color; + + h4.action-heading { + color: @delete-color; + background: @delete-background-color; + border-bottom-color: @delete-border-color; + } + } +} diff --git a/styles/variables-cyborg.less b/styles/variables-cyborg.less new file mode 100644 index 00000000..793d2d94 --- /dev/null +++ b/styles/variables-cyborg.less @@ -0,0 +1,118 @@ +/* Basic page-wide colors */ +@background-color: #060606; +@text-color: #888; + +@link-color: #2a9fd6; +@right-link-color: @link-color; + +@heading-text-color: white; + +/* Nav and right panel */ +@nav-hover-border-color: @text-color; +@nav-background-color: #060606; +@nav-border-color: #060606; +@right-background-color: #1a1a1a; +@right-text-color: @text-color; + +/* Tabs */ +@tabs-background-color: #eee; +@tabs-active-background-color: darken(@tabs-background-color, 15%); +@tabs-border-color: #ddd; +@right-tabs-background-color: lighten(@background-color, 4%); +@right-tabs-active-background-color: lighten(@right-tabs-background-color, 10%); +@right-tabs-border-color: @background-color; + +/* Notes and warnings */ +@note-text-color: @text-color; +@note-title-text-color: #77b300; +@note-background-color: mix(@note-title-text-color, #111, 8%); +@note-border-color: @note-title-text-color; + +@warning-text-color: @text-color; +@warning-title-text-color: darken(#c00, 10%); +@warning-background-color: mix(@warning-title-text-color, #111, 7%); +@warning-border-color: @warning-title-text-color; + +/* HTTP method-specific colors */ +@group-background-color: #222; +@group-title-background-color: #3c3c3c; +@group-border-color: lighten(@group-background-color, 3%); +@group-text-color: contrast(@group-background-color); + +/* HTTP GET */ +@get-background-color: #9933cc; +@get-color: darken(@get-background-color, 20%); +@get-text-color: contrast(@get-background-color); +@get-badge-text-color: white; +@get-border-color: darken(@get-background-color, 10%); + +/* HTTP HEAD */ +@head-color: @get-color; +@head-background-color: @get-background-color; +@head-text-color: @get-text-color; +@head-badge-text-color: @get-badge-text-color; +@head-border-color: @get-border-color; + +/* HTTP OPTIONS */ +@options-color: @get-color; +@options-background-color: @get-background-color; +@options-text-color: @get-text-color; +@options-badge-text-color: @get-badge-text-color; +@options-border-color: @get-border-color; + +/* HTTP PUT */ +@put-background-color: #ff8800; +@put-color: darken(@put-background-color, 20%); +@put-text-color: contrast(@put-background-color); +@put-badge-text-color: white; +@put-border-color: darken(@put-background-color, 10%); + +/* HTTP PATCH */ +@patch-color: @put-color; +@patch-background-color: @put-background-color; +@patch-text-color: @put-text-color; +@patch-badge-text-color: @put-badge-text-color; +@patch-border-color: @put-border-color; + +/* HTTP POST */ +@post-background-color: #77b300; +@post-color: darken(@post-background-color, 20%); +@post-text-color: contrast(@post-background-color); +@post-badge-text-color: white; +@post-border-color: darken(@post-background-color, 10%); + +/* HTTP DELETE */ +@delete-background-color: #cc0000; +@delete-color: darken(@delete-background-color, 20%); +@delete-text-color: contrast(@delete-background-color); +@delete-badge-text-color: white; +@delete-border-color: darken(@delete-background-color, 10%); + +/* Code colors */ +@inline-code-background-color: #444; +@inline-code-text-color: #ddd; + +@code-block-background-color: #1b1b1b; +@code-block-border-color: contrast(@code-block-background-color, + darken(@code-block-background-color, 5%), + lighten(@code-block-background-color, 5%)); + +@right-code-block-text-color: #888; +@right-code-block-background-color: #222; +@right-code-block-border-color: @right-code-block-background-color; + +@title-code-background-color: darken(@inline-code-background-color, 10%); +@title-code-text-color: @inline-code-text-color; +@title-code-border-color: transparent; + +@quote-border-color: contrast(@code-block-background-color, + darken(@code-block-background-color, 5%), + lighten(@code-block-background-color, 5%)); + +/* Highlight.js Theme Ateleir Plateau Dark */ +.hljs-comment,.hljs-quote{color:#7e7777}.hljs-attribute,.hljs-link,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ca4949}.hljs-built_in,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#b45a3c}.hljs-bullet,.hljs-string,.hljs-symbol{color:#4b8b8b}.hljs-section,.hljs-title{color:#7272ca}.hljs-keyword,.hljs-selector-tag{color:#8464c4}.hljs-addition,.hljs-deletion{color:#1b1818;display:inline-block;width:100%}.hljs-deletion{background-color:#ca4949}.hljs-addition{background-color:#4b8b8b}.hljs{display:block;overflow-x:auto;background:#1b1818;color:#8a8585;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} + +/* Highlight.js Theme Ateleir Plateau Dark */ +.right { + .hljs-comment,.hljs-quote{color:#7e7777}.hljs-attribute,.hljs-link,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ca4949}.hljs-built_in,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#b45a3c}.hljs-bullet,.hljs-string,.hljs-symbol{color:#4b8b8b}.hljs-section,.hljs-title{color:#7272ca}.hljs-keyword,.hljs-selector-tag{color:#8464c4}.hljs-addition,.hljs-deletion{color:#1b1818;display:inline-block;width:100%}.hljs-deletion{background-color:#ca4949}.hljs-addition{background-color:#4b8b8b}.hljs{display:block;overflow-x:auto;background:#1b1818;color:#8a8585;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} +} diff --git a/styles/variables-default.less b/styles/variables-default.less new file mode 100644 index 00000000..0c323367 --- /dev/null +++ b/styles/variables-default.less @@ -0,0 +1,148 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:400,700|Inconsolata|Raleway:200'); + +/* Page-wide variables */ +@padding: 12px; +@border-radius: 6px; +@font-size: 14px; +@nav-width: 220px; +@nav-triple-width: 16.5%; +@right-panel-width: 48.5%; +@right-panel-background-width: 48.6%; + +@base-font: 400 14px ~"/" 1.42 'Roboto', Helvetica, sans-serif; +@title-font: 200 36px 'Raleway', Helvetica, sans-serif; +@code-font: 'Inconsolata', monospace; + +/* Basic page-wide colors */ +@background-color: white; +@text-color: black; + +@link-color: #428bca; +@right-link-color: @link-color; + +@heading-text-color: @text-color; + +@table-row-background-color: darken(@background-color, 2%); +@table-border-color: darken(@background-color, 10%); + +/* Nav and right panel */ +@nav-hover-border-color: @text-color; +@nav-hover-background-color: bad-color; +@nav-hover-text-decoration: none; +@nav-background-color: #fbfbfb; +@nav-border-color: #f0f0f0; +@right-background-color: #333; +@right-text-color: @background-color; +@badge-margin: -2px 0; + +/* Tabs */ +@tabs-background-color: #eee; +@tabs-active-background-color: darken(@tabs-background-color, 10%); +@tabs-border-color: #ddd; +@right-tabs-background-color: #444; +@right-tabs-active-background-color: lighten(@right-tabs-background-color, 10%); +@right-tabs-border-color: #666; + +/* Notes and warnings */ +@note-text-color: @text-color; +@note-title-text-color: @link-color; +@note-background-color: mix(@link-color, @background-color, 8%); +@note-border-color: @note-title-text-color; + +@warning-text-color: @text-color; +@warning-title-text-color: darken(#d9534f, 10%); +@warning-background-color: mix(@warning-title-text-color, @background-color, 7%); +@warning-border-color: @warning-title-text-color; + +/* Resource groups */ +@group-padding: @padding; +@group-header-margin: -@padding -@padding @padding -@padding; +@group-background-color: @background-color; +@group-title-background-color: contrast(@background-color, + darken(@background-color, 5%), + lighten(@background-color, 5%)); +@group-border-color: contrast(@background-color, + darken(@background-color, 15%), + lighten(@background-color, 15%)); +@group-text-color: contrast(@group-background-color); + +/* HTTP method-specific colors */ + +/* HTTP GET */ +@get-color: darken(@link-color, 6.5%); +@get-background-color: #d9edf7; +@get-text-color: contrast(@get-background-color); +@get-badge-text-color: darken(@get-background-color, 25%); +@get-border-color: darken(spin(@get-background-color, -10), 7%); + +/* HTTP HEAD */ +@head-color: @get-color; +@head-background-color: @get-background-color; +@head-text-color: @get-text-color; +@head-badge-text-color: @get-badge-text-color; +@head-border-color: @get-border-color; + +/* HTTP OPTIONS */ +@options-color: @get-color; +@options-background-color: @get-background-color; +@options-text-color: @get-text-color; +@options-badge-text-color: @get-badge-text-color; +@options-border-color: @get-border-color; + +/* HTTP PUT */ +@put-color: darken(#f0ad4e, 8%); +@put-background-color: #fcf8e3; +@put-text-color: contrast(@put-background-color); +@put-badge-text-color: darken(@put-background-color, 25%); +@put-border-color: darken(spin(@put-background-color, -10), 5%); + +/* HTTP PATCH */ +@patch-color: @put-color; +@patch-background-color: @put-background-color; +@patch-text-color: @put-text-color; +@patch-badge-text-color: @put-badge-text-color; +@patch-border-color: @put-border-color; + +/* HTTP POST */ +@post-color: #5cb85c; +@post-background-color: #dff0d8; +@post-text-color: contrast(@post-background-color); +@post-badge-text-color: darken(@post-background-color, 25%); +@post-border-color: darken(spin(@post-background-color, -10), 5%); + +/* HTTP DELETE */ +@delete-color: #d9534f; +@delete-background-color: #f2dede; +@delete-text-color: contrast(@delete-background-color); +@delete-badge-text-color: darken(@delete-background-color, 25%); +@delete-border-color: darken(spin(@delete-background-color, -10), 5%); + +/* Code colors */ +@inline-code-background-color: #f5f5f5; +@inline-code-text-color: #444; + +@code-block-text-color: @text-color; +@code-block-background-color: #f5f5f5; +@code-block-border-color: contrast(@code-block-background-color, + darken(@code-block-background-color, 15%), + lighten(@code-block-background-color, 15%)); + +@right-code-block-text-color: #c5c8c6; +@right-code-block-background-color: #1d1f21; +@right-code-block-border-color: @right-code-block-background-color; + +@title-code-background-color: @inline-code-background-color; +@title-code-text-color: @inline-code-text-color; +@title-code-border-color: @code-block-border-color; + +@quote-border-color: contrast(@code-block-background-color, + darken(@code-block-background-color, 5%), + lighten(@code-block-background-color, 5%)); + +/* Highlight.js Theme Tomorrow */ +.hljs-comment,.hljs-title{color:#8e908c}.hljs-variable,.hljs-attribute,.hljs-tag,.hljs-regexp,.ruby .hljs-constant,.xml .hljs-tag .hljs-title,.xml .hljs-pi,.xml .hljs-doctype,.html .hljs-doctype,.css .hljs-id,.css .hljs-class,.css .hljs-pseudo{color:#c82829}.hljs-number,.hljs-preprocessor,.hljs-pragma,.hljs-built_in,.hljs-literal,.hljs-params,.hljs-constant{color:#f5871f}.ruby .hljs-class .hljs-title,.css .hljs-rules .hljs-attribute{color:#eab700}.hljs-string,.hljs-value,.hljs-inheritance,.hljs-header,.ruby .hljs-symbol,.xml .hljs-cdata{color:#718c00}.css .hljs-hexcolor{color:#3e999f}.hljs-function,.python .hljs-decorator,.python .hljs-title,.ruby .hljs-function .hljs-title,.ruby .hljs-title .hljs-keyword,.perl .hljs-sub,.javascript .hljs-title,.coffeescript .hljs-title{color:#4271ae}.hljs-keyword,.javascript .hljs-function{color:#8959a8}.hljs{display:block;background:white;color:#4d4d4c;padding:.5em}.coffeescript .javascript,.javascript .xml,.tex .hljs-formula,.xml .javascript,.xml .vbscript,.xml .css,.xml .hljs-cdata{opacity:.5} + +/* Highlight.js Theme Tomorrow Night */ +.right { + .hljs-comment{color:#969896}.css .hljs-class,.css .hljs-id,.css .hljs-pseudo,.hljs-attribute,.hljs-regexp,.hljs-tag,.hljs-variable,.html .hljs-doctype,.ruby .hljs-constant,.xml .hljs-doctype,.xml .hljs-pi,.xml .hljs-tag .hljs-title{color:#c66}.hljs-built_in,.hljs-constant,.hljs-literal,.hljs-number,.hljs-params,.hljs-pragma,.hljs-preprocessor{color:#de935f}.css .hljs-rule .hljs-attribute,.ruby .hljs-class .hljs-title{color:#f0c674}.hljs-header,.hljs-inheritance,.hljs-name,.hljs-string,.hljs-value,.ruby .hljs-symbol,.xml .hljs-cdata{color:#b5bd68}.css .hljs-hexcolor,.hljs-title{color:#8abeb7}.coffeescript .hljs-title,.hljs-function,.javascript .hljs-title,.perl .hljs-sub,.python .hljs-decorator,.python .hljs-title,.ruby .hljs-function .hljs-title,.ruby .hljs-title .hljs-keyword{color:#81a2be}.hljs-keyword,.javascript .hljs-function{color:#b294bb}.hljs{display:block;overflow-x:auto;background:#1d1f21;color:#c5c8c6;padding:.5em;-webkit-text-size-adjust:none}.coffeescript .javascript,.javascript .xml,.tex .hljs-formula,.xml .css,.xml .hljs-cdata,.xml .javascript,.xml .vbscript{opacity:.5} +} diff --git a/styles/variables-flatly.less b/styles/variables-flatly.less new file mode 100644 index 00000000..9d406f9b --- /dev/null +++ b/styles/variables-flatly.less @@ -0,0 +1,80 @@ +/* Basic page-wide colors */ +@background-color: white; +@text-color: black; + +@link-color: #18bc9c; +@right-link-color: @link-color; + +/* Notes and warnings */ +@note-text-color: @text-color; +@note-title-text-color: #3498db; +@note-background-color: mix(@note-title-text-color, @background-color, 8%); +@note-border-color: @note-title-text-color; + +@warning-text-color: @text-color; +@warning-title-text-color: darken(#e74c3c, 10%); +@warning-background-color: mix(@warning-title-text-color, @background-color, 7%); +@warning-border-color: @warning-title-text-color; + +/* HTTP method-specific colors */ +@group-background-color: @background-color; +@group-title-background-color: contrast(@background-color, + darken(@background-color, 7%), + lighten(@background-color, 7%)); +@group-border-color: contrast(@background-color, + darken(@background-color, 7%), + lighten(@background-color, 7%)); +@group-text-color: contrast(@group-background-color); + +/* HTTP GET */ +@get-color: white; +@get-background-color: #3498db; +@get-text-color: contrast(@get-background-color); +@get-badge-text-color: white; +@get-border-color: @get-background-color; + +/* HTTP HEAD */ +@head-color: @get-color; +@head-background-color: @get-background-color; +@head-text-color: @get-text-color; +@head-badge-text-color: @get-badge-text-color; +@head-border-color: @get-border-color; + +/* HTTP OPTIONS */ +@options-color: @get-color; +@options-background-color: @get-background-color; +@options-text-color: @get-text-color; +@options-badge-text-color: @get-badge-text-color; +@options-border-color: @get-border-color; + +/* HTTP PUT */ +@put-color: white; +@put-background-color: #f39c12; +@put-text-color: contrast(@put-background-color); +@put-badge-text-color: white; +@put-border-color: @put-background-color; + +/* HTTP PATCH */ +@patch-color: @put-color; +@patch-background-color: @put-background-color; +@patch-text-color: @put-text-color; +@patch-badge-text-color: @put-badge-text-color; +@patch-border-color: @put-border-color; + +/* HTTP POST */ +@post-color: white; +@post-background-color: #18bc9c; +@post-text-color: contrast(@post-background-color); +@post-badge-text-color: white; +@post-border-color: @post-background-color; + +/* HTTP DELETE */ +@delete-color: white; +@delete-background-color: #e74c3c; +@delete-text-color: contrast(@delete-background-color); +@delete-badge-text-color: white; +@delete-border-color: @delete-background-color; + +/* Code colors */ +@title-code-background-color: rgba(255, 255, 255, 0.7); +@title-code-border-color: transparent; diff --git a/styles/variables-slate.less b/styles/variables-slate.less new file mode 100644 index 00000000..d9367633 --- /dev/null +++ b/styles/variables-slate.less @@ -0,0 +1,117 @@ +/* Basic page-wide colors */ +@background-color: #272b30; +@text-color: #c8c8c8; + +@link-color: white; +@right-link-color: #666; + +@heading-text-color: @text-color; + +/* Nav and right panel */ +@nav-hover-border-color: @text-color; +@nav-background-color: #272b30; +@nav-border-color: #272b30; +@right-background-color: #d8d4cf; +@right-text-color: @background-color; + +/* Tabs */ +@right-tabs-background-color: #adaaa6; +@right-tabs-active-background-color: darken(@right-tabs-background-color, 10%); +@right-tabs-border-color: @right-background-color; + +/* Notes and warnings */ +@note-text-color: @text-color; +@note-title-text-color: #5bc0de; +@note-background-color: mix(@note-title-text-color, @background-color, 8%); +@note-border-color: @note-title-text-color; + +@warning-text-color: @text-color; +@warning-title-text-color: darken(#ee5f5b, 10%); +@warning-background-color: mix(@warning-title-text-color, @background-color, 7%); +@warning-border-color: @warning-title-text-color; + +/* HTTP method-specific colors */ +@group-background-color: @background-color; +@group-title-background-color: contrast(@background-color, + darken(@background-color, 7%), + lighten(@background-color, 7%)); +@group-border-color: #202020; +@group-text-color: contrast(@group-background-color); + +/* HTTP GET */ +@get-background-color: #5bc0de; +@get-color: darken(@get-background-color, 20%); +@get-text-color: contrast(@get-background-color); +@get-badge-text-color: white; +@get-border-color: #202020; + +/* HTTP HEAD */ +@head-color: @get-color; +@head-background-color: @get-background-color; +@head-text-color: @get-text-color; +@head-badge-text-color: @get-badge-text-color; +@head-border-color: #202020; + +/* HTTP OPTIONS */ +@options-color: @get-color; +@options-background-color: @get-background-color; +@options-text-color: @get-text-color; +@options-badge-text-color: @get-badge-text-color; +@options-border-color: #202020; + +/* HTTP PUT */ +@put-background-color: #f89406; +@put-color: darken(@put-background-color, 20%); +@put-text-color: contrast(@put-background-color); +@put-badge-text-color: white; +@put-border-color: #202020; + +/* HTTP PATCH */ +@patch-color: @put-color; +@patch-background-color: @put-background-color; +@patch-text-color: @put-text-color; +@patch-badge-text-color: @put-badge-text-color; +@patch-border-color: #202020; + +/* HTTP POST */ +@post-background-color: #62c462; +@post-color: darken(@post-background-color, 20%); +@post-text-color: contrast(@post-background-color); +@post-badge-text-color: white; +@post-border-color: #202020; + +/* HTTP DELETE */ +@delete-background-color: #ee5f5b; +@delete-color: darken(@delete-background-color, 20%); +@delete-text-color: contrast(@delete-background-color); +@delete-badge-text-color: white; +@delete-border-color: #202020; + +/* Code colors */ +@inline-code-background-color: #373b40; +@inline-code-text-color: #ddd; + +@code-block-background-color: #202529; +@code-block-border-color: contrast(@code-block-background-color, + darken(@code-block-background-color, 15%), + lighten(@code-block-background-color, 15%)); + +@right-code-block-text-color: #333; +@right-code-block-background-color: #f7f6f5; +@right-code-block-border-color: @right-code-block-background-color; + +@title-code-background-color: rgba(255, 255, 255, 0.7); +@title-code-text-color: black; +@title-code-border-color: transparent; + +@quote-border-color: contrast(@code-block-background-color, + darken(@code-block-background-color, 5%), + lighten(@code-block-background-color, 5%)); + +/* Highlight.js Theme Atelier Heath Dark */ +.hljs-comment,.hljs-quote{color:#9e8f9e}.hljs-attribute,.hljs-link,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ca402b}.hljs-built_in,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#a65926}.hljs-bullet,.hljs-string,.hljs-symbol{color:#918b3b}.hljs-section,.hljs-title{color:#516aec}.hljs-keyword,.hljs-selector-tag{color:#7b59c0}.hljs{display:block;overflow-x:auto;background:#1b181b;color:#ab9bab;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} + +/* Highlight.js Theme Atelier Heath Light */ +.right { + .hljs-comment,.hljs-quote{color:#776977}.hljs-attribute,.hljs-link,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#ca402b}.hljs-built_in,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#a65926}.hljs-bullet,.hljs-string,.hljs-symbol{color:#918b3b}.hljs-section,.hljs-title{color:#516aec}.hljs-keyword,.hljs-selector-tag{color:#7b59c0}.hljs{display:block;overflow-x:auto;background:#f7f3f7;color:#695d69;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} +} diff --git a/styles/variables-streak.less b/styles/variables-streak.less new file mode 100644 index 00000000..103774b2 --- /dev/null +++ b/styles/variables-streak.less @@ -0,0 +1,137 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:100,400,700|Source+Code+Pro'); + +/* Page-wide variables */ +@border-radius: 3px; +@nav-triple-width: 15%; +@right-panel-width: 52%; +@right-panel-background-width: 52%; + +@base-font: 400 14px ~"/" 1.42 'Roboto', Helvetica, sans-serif; +@title-font: 100 36px 'Roboto', Helvetica, sans-serif; +@code-font: 13px ~"/" 19.5px 'Source Code Pro', Menlo, monospace; + +/* Basic page-wide colors */ +@text-color: #4c555a; + +@link-color: #0099e5; +@right-link-color: @link-color; + +@heading-text-color: #292e31; + +/* Nav and right panel */ +@nav-hover-border-color: transparent; +@nav-hover-background-color: transparent; +@nav-hover-text-decoration: underline; +@nav-background-color: #fafcfc; +@nav-border-color: #f0f4f7; +@right-background-color: #2d3134; +@right-text-color: #dde4e8; +@badge-margin: -2px -@padding/3*2 -2px 0; + +/* Tabs */ +@tabs-background-color: #eee; +@tabs-active-background-color: darken(@tabs-background-color, 10%); +@tabs-border-color: #ddd; +@right-tabs-background-color: #424648; +@right-tabs-active-background-color: lighten(@right-tabs-background-color, 10%); +@right-tabs-border-color: #6C6F71; + +/* Notes and warnings */ +@note-text-color: @text-color; +@note-title-text-color: @link-color; +@note-background-color: mix(@link-color, @background-color, 8%); +@note-border-color: @note-title-text-color; + +@warning-text-color: @text-color; +@warning-title-text-color: #B82E5F; +@warning-background-color: mix(@warning-title-text-color, @background-color, 7%); +@warning-border-color: @warning-title-text-color; + +/* Resource groups */ +@group-padding: @padding @padding @padding 0; +@group-header-margin: 0 0 @padding 0; +@group-background-color: transparent; +@group-title-background-color: @group-background-color; +@group-border-color: @group-background-color; +@group-text-color: black; + +/* HTTP method-specific colors */ + +/* HTTP GET */ +@get-color: multiply(@link-color, #fff); +@get-background-color: screen(@link-color, #ddd); +@get-text-color: contrast(@get-background-color); +@get-badge-text-color: lighten(@get-background-color, 25%); +@get-border-color: @get-background-color; + +/* HTTP HEAD */ +@head-color: @get-color; +@head-background-color: @get-background-color; +@head-text-color: @get-text-color; +@head-badge-text-color: @get-badge-text-color; +@head-border-color: @get-border-color; + +/* HTTP OPTIONS */ +@options-color: @get-color; +@options-background-color: @get-background-color; +@options-text-color: @get-text-color; +@options-badge-text-color: @get-badge-text-color; +@options-border-color: @get-border-color; + +/* HTTP PUT */ +@put-color: multiply(#ebde68, #c0c0c0); +@put-background-color: screen(#ebde68, #999); +@put-text-color: contrast(@put-background-color); +@put-badge-text-color: lighten(@put-background-color, 25%); +@put-border-color: @put-background-color; + +/* HTTP PATCH */ +@patch-color: @put-color; +@patch-background-color: @put-background-color; +@patch-text-color: @put-text-color; +@patch-badge-text-color: @put-badge-text-color; +@patch-border-color: @put-border-color; + +/* HTTP POST */ +@post-color: multiply(#c1ef65, #b0b0b0); +@post-background-color: desaturate(screen(#c1ef65, #999), 20%); +@post-text-color: contrast(@post-background-color); +@post-badge-text-color: lighten(@post-background-color, 25%); +@post-border-color: @post-background-color; + +/* HTTP DELETE */ +@delete-color: screen(#b82e5f, #222); +@delete-background-color: screen(#b82e5f, #cfcfcf); +@delete-text-color: contrast(@delete-background-color); +@delete-badge-text-color: lighten(@delete-background-color, 25%); +@delete-border-color: @delete-background-color; + +/* Code colors */ +@inline-code-background-color: #f5f5f5; +@inline-code-text-color: #b93d6a; + +@code-block-text-color: @text-color; +@code-block-background-color: #f5f5f5; +@code-block-border-color: contrast(@code-block-background-color, + darken(@code-block-background-color, 15%), + lighten(@code-block-background-color, 15%)); + +@right-code-block-text-color: #D0D0D0; +@right-code-block-background-color: #272B2D; +@right-code-block-border-color: @right-code-block-background-color; + +@title-code-background-color: @inline-code-background-color; +@title-code-text-color: #444; +@title-code-border-color: @code-block-border-color; + +@quote-border-color: contrast(@code-block-background-color, + darken(@code-block-background-color, 5%), + lighten(@code-block-background-color, 5%)); + +/* Highlight.js Theme Streak */ +.hljs-comment{color:#969896}.css .hljs-class,.css .hljs-id,.css .hljs-pseudo,.hljs-attribute,.hljs-regexp,.hljs-tag,.hljs-variable,.html .hljs-doctype,.ruby .hljs-constant,.xml .hljs-doctype,.xml .hljs-pi,.xml .hljs-tag .hljs-title{color:#77A619}.hljs-literal{color:#A69819}.hljs-built_in,.hljs-constant,.hljs-number,.hljs-params,.hljs-pragma,.hljs-preprocessor{color:#1B88B3}.css .hljs-rule .hljs-attribute,.ruby .hljs-class .hljs-title{color:#A37518}.hljs-header,.hljs-inheritance,.hljs-name,.hljs-string,.hljs-value,.ruby .hljs-symbol,.xml .hljs-cdata{color:inherit}.coffeescript .hljs-title,.css .hljs-hexcolor,.hljs-function,.hljs-title,.javascript .hljs-title,.perl .hljs-sub,.python .hljs-decorator,.python .hljs-title,.ruby .hljs-function .hljs-title,.ruby .hljs-title .hljs-keyword{color:#A63A4A}.hljs-keyword,.javascript .hljs-function{color:#A69819}.hljs{display:block;overflow-x:auto;background:#1d1f21;color:#c5c8c6;padding:.5em;-webkit-text-size-adjust:none}.coffeescript .javascript,.javascript .xml,.tex .hljs-formula,.xml .css,.xml .hljs-cdata,.xml .javascript,.xml .vbscript{opacity:.5} + +/* Highlight.js Theme Streak Night */ +.right { + .hljs-comment{color:#969896}.css .hljs-class,.css .hljs-id,.css .hljs-pseudo,.hljs-attribute,.hljs-regexp,.hljs-tag,.hljs-variable,.html .hljs-doctype,.ruby .hljs-constant,.xml .hljs-doctype,.xml .hljs-pi,.xml .hljs-tag .hljs-title{color:#C1EF65}.hljs-literal{color:#EBDE68}.hljs-built_in,.hljs-constant,.hljs-number,.hljs-params,.hljs-pragma,.hljs-preprocessor{color:#77BCD7}.css .hljs-rule .hljs-attribute,.ruby .hljs-class .hljs-title{color:#f0c674}.hljs-header,.hljs-inheritance,.hljs-name,.hljs-string,.hljs-value,.ruby .hljs-symbol,.xml .hljs-cdata{color:inherit}.coffeescript .hljs-title,.css .hljs-hexcolor,.hljs-function,.hljs-title,.javascript .hljs-title,.perl .hljs-sub,.python .hljs-decorator,.python .hljs-title,.ruby .hljs-function .hljs-title,.ruby .hljs-title .hljs-keyword{color:#f099a6}.hljs-keyword,.javascript .hljs-function{color:#EBDE68}.hljs{display:block;overflow-x:auto;background:#1d1f21;color:#c5c8c6;padding:.5em;-webkit-text-size-adjust:none}.coffeescript .javascript,.javascript .xml,.tex .hljs-formula,.xml .css,.xml .hljs-cdata,.xml .javascript,.xml .vbscript{opacity:.5} +} diff --git a/templates/index.jade b/templates/index.jade new file mode 100644 index 00000000..b6c2fe9f --- /dev/null +++ b/templates/index.jade @@ -0,0 +1,38 @@ +doctype + +include mixins.jade + +html + head + meta(charset="utf-8") + title= self.api.name || 'API Documentation' + link(rel="stylesheet", href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css") + style!= self.css + body.preload + a.text-muted.back-to-top(href='#top') + i.fa.fa-toggle-up + |  Back to top + div(class=self.fullWidth ? 'container-fluid' : 'container') + .row + block nav + +Nav(false) + + .content + block content + +Content('primary', false) + + p.text-muted(style="text-align: center;") + | Generated by  + a.aglio(href="/danielgtaylor/aglio") aglio + |  on #{self.date().format('DD MMM YYYY')} + + script: include scripts.js + + if self.livePreview + script(src="/socket.io/socket.io.js") + script. + var socket = io(); + socket.on('refresh', refresh); + socket.on('reconnect', function () { + socket.emit('request-refresh'); + }); diff --git a/templates/mixins.jade b/templates/mixins.jade new file mode 100644 index 00000000..888811a9 --- /dev/null +++ b/templates/mixins.jade @@ -0,0 +1,293 @@ + +mixin Badge(method) + //- Draw a badge for a given HTTP method + case method + when 'GET' + span.badge.get: i.fa.fa-arrow-down + when 'HEAD' + span.badge.head: i.fa.fa-info-circle + when 'OPTIONS' + span.badge.options: i.fa.fa-dot-circle-o + when 'POST' + span.badge.post: i.fa.fa-plus + when 'PUT' + span.badge.put: i.fa.fa-pencil + when 'PATCH' + span.badge.patch: i.fa.fa-pencil + when 'DELETE' + span.badge.delete: i.fa.fa-times + default + span.badge: i.fa.fa-dot-circle-o + +mixin Nav() + //- Draw a navigation bar, which includes links to individual + //- resources and actions. + nav + if self.api.navItems && self.api.navItems.length + .resource-group + .heading + .chevron + i.open.fa.fa-angle-down + a(href='#top') Overview + .collapse-content + ul: each item in self.api.navItems + li + a(href=item[1])!= item[0] + each resourceGroup in self.api.resourceGroups || [] + .resource-group + .heading + .chevron + i.open.fa.fa-angle-down + a(href=resourceGroup.elementLink)!= resourceGroup.name || 'Resource Group' + .collapse-content + ul + each item in resourceGroup.navItems || [] + li + a(href=item[1])!= item[0] + each resource in resourceGroup.resources || [] + li + if !self.condenseNav || (resource.actions.length != 1) + a(href=resource.elementLink)!= resource.name || 'Resource' + ul: each action in resource.actions || [] + li: a(href=action.elementLink) + +Badge(action.method) + != action.name || action.method + ' ' + (action.attributes && action.attributes.uriTemplate || resource.uriTemplate) + else + - var action = resource.actions[0] + a(href=action.elementLink) + +Badge(action.method) + != action.name || resource.name || action.method + ' ' + (action.attributes && action.attributes.uriTemplate || resource.uriTemplate) + //- Link to the API hostname, e.g. api.yourcompany.com + each meta in self.api.metadata || {} + if meta.name == 'HOST' + p(style="text-align: center; word-wrap: break-word;") + a(href=meta.value)= meta.value + +mixin Parameters(params) + //- Draw a definition list of parameter names, types, defaults, + //- examples and descriptions. + .title + strong URI Parameters + .collapse-button.show + span.close Hide + span.open Show + .collapse-content + dl.inner: each param in params || [] + dt= self.urldec(param.name) + dd + code= param.type || 'string' + |   + if param.required + span.required (required) + else + span (optional) + |   + if param.default + span.text-info.default + strong Default:  + span= param.default + |   + if param.example + span.text-muted.example + strong Example:  + span= param.example + != self.markdown(param.description) + if param.values.length + p.choices + strong Choices:  + each value in param.values + code= self.urldec(value.value) + = ' ' + +mixin RequestResponse(title, request, collapse) + .title + strong + = title + if request.name + |    + code= request.name + if collapse && request.hasContent + .collapse-button + span.close Hide + span.open Show + +RequestResponseBody(request, collapse) + +mixin RequestResponseBody(request, collapse, showBlank) + if request.hasContent || showBlank + div(class=collapse ? 'collapse-content' : ''): .inner + if request.description + .description!= self.markdown(request.description) + + if Object.keys(request.headers).length + h5 Headers + pre: code + each item, index in request.headers + != self.highlight(item.name + ': ' + item.value, 'http') + if index < request.headers.length - 1 + br + div(style="height: 1px;") + if request.body + h5 Body + pre: code + != self.highlight(request.body, null, ['json', 'yaml', 'xml', 'javascript']) + div(style="height: 1px;") + if request.schema + h5 Schema + pre: code + != self.highlight(request.schema, null, ['json', 'yaml', 'xml']) + div(style="height: 1px;") + if !request.hasContent + .description.text-muted This response has no content. + div(style="height: 1px;") + +mixin Examples(resourceGroup, resource, action) + each example in action.examples + each request in example.requests + +RequestResponse('Request', request, true) + each response in example.responses + +RequestResponse('Response', response, true) + +mixin Content() + //- Page header and API description + header + h1#top!= self.api.name || 'API Documentation' + + if self.api.descriptionHtml + != self.api.descriptionHtml + + //- Loop through and display information about all the resource + //- groups, resources, and actions. + each resourceGroup in self.api.resourceGroups || [] + section.resource-group(id=resourceGroup.elementId) + h2.group-heading + != resourceGroup.name || 'Resource Group' + = " " + a.permalink(href=resourceGroup.elementLink) ¶ + if resourceGroup.descriptionHtml + != resourceGroup.descriptionHtml + + each resource in resourceGroup.resources || [] + .resource(id=resource.elementId) + h3.resource-heading + != resource.name || ((resource.actions[0] != null) && resource.actions[0].name) || 'Resource' + = " " + a.permalink(href=resource.elementLink)  ¶ + if resource.description + != self.markdown(resource.description) + + each action in resource.actions || [] + .action(class=action.methodLower, id=action.elementId) + h4.action-heading + .name!= action.name + a.method(class=action.methodLower, href=action.elementLink) + = action.method + code.uri= self.urldec(action.uriTemplate) + if action.description + != self.markdown(action.description) + + h4 Example URI + .definition + span.method(class=action.methodLower)= action.method + |   + span.uri + span.hostname= self.api.host + != action.colorizedUriTemplate + + //- A list of sub-sections for parameters, requests + //- and responses. + if action.parameters.length + +Parameters(action.parameters) + if action.examples + +Examples(resourceGroup, resource, action) + +mixin ContentTriple() + .middle + //- Page header and API description + header + h1#top!= self.api.name || 'API Documentation' + + .right + h5 API Endpoint + a(href=self.api.host)= self.api.host + .middle + if self.api.descriptionHtml + != self.api.descriptionHtml + + //- Loop through and display information about all the resource + //- groups, resources, and actions. + each resourceGroup in self.api.resourceGroups || [] + .middle + section.resource-group(id=resourceGroup.elementId) + h2.group-heading + != resourceGroup.name || 'Resource Group' + = " " + a.permalink(href=resourceGroup.elementLink) ¶ + if resourceGroup.descriptionHtml + != resourceGroup.descriptionHtml + + each resource in resourceGroup.resources || [] + .middle + .resource(id=resource.elementId) + h3.resource-heading + != resource.name || ((resource.actions[0] != null) && resource.actions[0].name) || 'Resource' + = " " + a.permalink(href=resource.elementLink) ¶ + if resource.description + != self.markdown(resource.description) + + each action in resource.actions || [] + if action.examples + .right + .definition + span.method(class=action.methodLower)= action.method + |   + span.uri + span.hostname= self.api.host + != action.colorizedUriTemplate + .tabs + if action.hasRequest + .example-names + span Requests + - var requestCount = 0 + each example in action.examples + each request in example.requests + - requestCount++ + span.tab-button= request.name || 'example ' + requestCount + each example in action.examples + each request in example.requests + .tab + +RequestResponseBody(request, false, true) + .tabs + .example-names + span Responses + each response in example.responses + span.tab-button= response.name + each response in example.responses + .tab + +RequestResponseBody(response, false, true) + else + each example in action.examples + .tabs + .example-names + span Responses + each response in example.responses + span.tab-button= response.name + each response in example.responses + .tab + +RequestResponseBody(response, false, true) + .middle + .action(class=action.methodLower, id=action.elementId) + h4.action-heading + .name!= action.name + a.method(class=action.methodLower, href=action.elementLink) + = action.method + code.uri= self.urldec(action.uriTemplate) + if action.description + != self.markdown(action.description) + + //- A list of sub-sections for parameters, requests + //- and responses. + if action.parameters.length + +Parameters(action.parameters) + + hr.split diff --git a/templates/scripts.js b/templates/scripts.js new file mode 100644 index 00000000..d105df6c --- /dev/null +++ b/templates/scripts.js @@ -0,0 +1,223 @@ +/* eslint-env browser */ +/* eslint quotes: [2, "single"] */ +'use strict'; + +/* + Determine if a string ends with another string. +*/ +function endsWith(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; +} + +/* + Get a list of direct child elements by class name. +*/ +function childrenByClass(element, name) { + var filtered = []; + + for (var i = 0; i < element.children.length; i++) { + var child = element.children[i]; + var classNames = child.className.split(' '); + if (classNames.indexOf(name) !== -1) { + filtered.push(child); + } + } + + return filtered; +} + +/* + Get an array [width, height] of the window. +*/ +function getWindowDimensions() { + var w = window, + d = document, + e = d.documentElement, + g = d.body, + x = w.innerWidth || e.clientWidth || g.clientWidth, + y = w.innerHeight || e.clientHeight || g.clientHeight; + + return [x, y]; +} + +/* + Collapse or show a request/response example. +*/ +function toggleCollapseButton(event) { + var button = event.target.parentNode; + var content = button.parentNode.nextSibling; + var inner = content.children[0]; + + if (button.className.indexOf('collapse-button') === -1) { + // Clicked without hitting the right element? + return; + } + + if (content.style.maxHeight && content.style.maxHeight !== '0px') { + // Currently showing, so let's hide it + button.className = 'collapse-button'; + content.style.maxHeight = '0px'; + } else { + // Currently hidden, so let's show it + button.className = 'collapse-button show'; + content.style.maxHeight = inner.offsetHeight + 12 + 'px'; + } +} + +function toggleTabButton(event) { + var i, index; + var button = event.target; + + // Get index of the current button. + var buttons = childrenByClass(button.parentNode, 'tab-button'); + for (i = 0; i < buttons.length; i++) { + if (buttons[i] === button) { + index = i; + button.className = 'tab-button active'; + } else { + buttons[i].className = 'tab-button'; + } + } + + // Hide other tabs and show this one. + var tabs = childrenByClass(button.parentNode.parentNode, 'tab'); + for (i = 0; i < tabs.length; i++) { + if (i === index) { + tabs[i].style.display = 'block'; + } else { + tabs[i].style.display = 'none'; + } + } +} + +/* + Collapse or show a navigation menu. It will not be hidden unless it + is currently selected or `force` has been passed. +*/ +function toggleCollapseNav(event, force) { + var heading = event.target.parentNode; + var content = heading.nextSibling; + var inner = content.children[0]; + + if (heading.className.indexOf('heading') === -1) { + // Clicked without hitting the right element? + return; + } + + if (content.style.maxHeight && content.style.maxHeight !== '0px') { + // Currently showing, so let's hide it, but only if this nav item + // is already selected. This prevents newly selected items from + // collapsing in an annoying fashion. + if (force || window.location.hash && endsWith(event.target.href, window.location.hash)) { + content.style.maxHeight = '0px'; + } + } else { + // Currently hidden, so let's show it + content.style.maxHeight = inner.offsetHeight + 12 + 'px'; + } +} + +/* + Refresh the page after a live update from the server. This only + works in live preview mode (using the `--server` parameter). +*/ +function refresh(body) { + document.querySelector('body').className = 'preload'; + document.body.innerHTML = body; + + // Re-initialize the page + init(); + autoCollapse(); + + document.querySelector('body').className = ''; +} + +/* + Determine which navigation items should be auto-collapsed to show as many + as possible on the screen, based on the current window height. This also + collapses them. +*/ +function autoCollapse() { + var windowHeight = getWindowDimensions()[1]; + var itemsHeight = 64; /* Account for some padding */ + var itemsArray = Array.prototype.slice.call( + document.querySelectorAll('nav .resource-group .heading')); + + // Get the total height of the navigation items + itemsArray.forEach(function (item) { + itemsHeight += item.parentNode.offsetHeight; + }); + + // Should we auto-collapse any nav items? Try to find the smallest item + // that can be collapsed to show all items on the screen. If not possible, + // then collapse the largest item and do it again. First, sort the items + // by height from smallest to largest. + var sortedItems = itemsArray.sort(function (a, b) { + return a.parentNode.offsetHeight - b.parentNode.offsetHeight; + }); + + while (sortedItems.length && itemsHeight > windowHeight) { + for (var i = 0; i < sortedItems.length; i++) { + // Will collapsing this item help? + var itemHeight = sortedItems[i].nextSibling.offsetHeight; + if ((itemsHeight - itemHeight <= windowHeight) || i === sortedItems.length - 1) { + // It will, so let's collapse it, remove its content height from + // our total and then remove it from our list of candidates + // that can be collapsed. + itemsHeight -= itemHeight; + toggleCollapseNav({target: sortedItems[i].children[0]}, true); + sortedItems.splice(i, 1); + break; + } + } + } +} + +/* + Initialize the interactive functionality of the page. +*/ +function init() { + var i, j; + + // Make collapse buttons clickable + var buttons = document.querySelectorAll('.collapse-button'); + for (i = 0; i < buttons.length; i++) { + buttons[i].onclick = toggleCollapseButton; + + // Show by default? Then toggle now. + if (buttons[i].className.indexOf('show') !== -1) { + toggleCollapseButton({target: buttons[i].children[0]}); + } + } + + var responseCodes = document.querySelectorAll('.example-names'); + for (i = 0; i < responseCodes.length; i++) { + var tabButtons = childrenByClass(responseCodes[i], 'tab-button'); + for (j = 0; j < tabButtons.length; j++) { + tabButtons[j].onclick = toggleTabButton; + + // Show by default? + if (j === 0) { + toggleTabButton({target: tabButtons[j]}); + } + } + } + + // Make nav items clickable to collapse/expand their content. + var navItems = document.querySelectorAll('nav .resource-group .heading'); + for (i = 0; i < navItems.length; i++) { + navItems[i].onclick = toggleCollapseNav; + + // Show all by default + toggleCollapseNav({target: navItems[i].children[0]}); + } +} + +// Initial call to set up buttons +init(); + +window.onload = function () { + autoCollapse(); + // Remove the `preload` class to enable animations + document.querySelector('body').className = ''; +}; diff --git a/templates/triple.jade b/templates/triple.jade new file mode 100644 index 00000000..862990a9 --- /dev/null +++ b/templates/triple.jade @@ -0,0 +1,39 @@ +doctype + +include mixins.jade + +html + head + meta(charset="utf-8") + title= self.api.name || 'API Documentation' + link(rel="stylesheet", href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css") + style!= self.css + body.preload + #nav-background + div.container-fluid.triple + .row + block nav + +Nav() + + .content + #right-panel-background + + block content + +ContentTriple() + + .middle + p.text-muted(style="text-align: center;") + | Generated by  + a.aglio(href="/danielgtaylor/aglio") aglio + |  on #{self.date().format('DD MMM YYYY')} + + script: include scripts.js + + if self.livePreview + script(src="/socket.io/socket.io.js") + script. + var socket = io(); + socket.on('refresh', refresh); + socket.on('reconnect', function () { + socket.emit('request-refresh'); + }); diff --git a/test/basic.coffee b/test/basic.coffee deleted file mode 100644 index ec5406f9..00000000 --- a/test/basic.coffee +++ /dev/null @@ -1,336 +0,0 @@ -aglio = require '../lib/main' -assert = require 'assert' -bin = require '../lib/bin' -fs = require 'fs' -http = require 'http' -path = require 'path' -drafter = require 'drafter' -sinon = require 'sinon' - -root = path.dirname(__dirname) - -blueprint = fs.readFileSync path.join(root, 'example.apib'), 'utf-8' - -describe 'API Blueprint Renderer', -> - it 'Should load the default theme', -> - theme = aglio.getTheme 'default' - - assert.ok theme - - it 'Should get a list of included files', -> - sinon.stub fs, 'readFileSync', -> 'I am a test file' - - input = ''' - # Title - - Some content... - - More content... - ''' - - paths = aglio.collectPathsSync input, '.' - - fs.readFileSync.restore() - - assert.equal paths.length, 2 - assert 'test1.apib' in paths - assert 'test2.apib' in paths - - it 'Should render blank string', (done) -> - aglio.render '', template: 'default', locals: {foo: 1}, (err, html) -> - if err then return done(err) - - assert html - - done() - - it 'Should render a complex document', (done) -> - aglio.render blueprint, 'default', (err, html) -> - if err then return done(err) - - assert html - - # Ensure include works - assert html.indexOf 'This is content that was included' - - done() - - it 'Should render mixed line endings and tabs properly', (done) -> - temp = '# GET /message\r\n+ Response 200 (text/plain)\r\r\t\tHello!\n' - aglio.render temp, 'default', done - - it 'Should render a custom template by filename', (done) -> - template = path.join(root, 'test', 'test.jade') - aglio.render '# Blueprint', template, (err, html) -> - if err then return done(err) - - assert html - - done() - - it 'Should return warnings with filtered input', (done) -> - temp = '# GET /message\r\n+ Response 200 (text/plain)\r\r\t\tHello!\n' - filteredTemp = temp.replace(/\r\n?/g, '\n').replace(/\t/g, ' ') - - aglio.render temp, 'default', (err, html, warnings) -> - if err then return done(err) - - assert.equal filteredTemp, warnings.input - - done() - - it 'Should render from/to files', (done) -> - src = path.join root, 'example.apib' - dest = path.join root, 'example.html' - aglio.renderFile src, dest, {}, done - - it 'Should render from stdin', (done) -> - sinon.stub process.stdin, 'read', -> '# Hello\n' - - setTimeout -> process.stdin.emit 'readable', 1 - - aglio.renderFile '-', 'example.html', 'default', (err) -> - if err then return done(err) - - assert process.stdin.read.called - process.stdin.read.restore() - process.stdin.removeAllListeners() - - done() - - it 'Should render to stdout', (done) -> - sinon.stub console, 'log' - - aglio.renderFile path.join(root, 'example.apib'), '-', 'default', (err) -> - if err - console.log.restore() - return done(err) - - assert console.log.called - console.log.restore() - - done() - - it 'Should compile from/to files', (done) -> - src = path.join root, 'example.apib' - dest = path.join root, 'example-compiled.apib' - aglio.compileFile src, dest, done - - it 'Should compile from stdin', (done) -> - sinon.stub process.stdin, 'read', -> '# Hello\n' - - setTimeout -> process.stdin.emit 'readable', 1 - - aglio.compileFile '-', 'example-compiled.apib', (err) -> - if err then return done(err) - - assert process.stdin.read.called - process.stdin.read.restore() - process.stdin.removeAllListeners() - - done() - - it 'Should compile to stdout', (done) -> - sinon.stub console, 'log' - - aglio.compileFile path.join(root, 'example.apib'), '-', (err) -> - if err then return done(err) - - assert console.log.called - console.log.restore() - - done() - - it 'Should support legacy theme names', (done) -> - aglio.render '', template: 'flatly', (err, html) -> - if err then return done(err) - - assert html - - done() - - it 'Should error on missing input file', (done) -> - aglio.renderFile 'missing', 'output.html', 'default', (err, html) -> - assert err - - aglio.compileFile 'missing', 'output.apib', (err) -> - assert err - done() - - it 'Should error on bad template', (done) -> - aglio.render blueprint, 'bad', (err, html) -> - assert err - - done() - - it 'Should error on drafter failure', (done) -> - sinon.stub drafter, 'parse', (content, options, callback) -> - callback 'error' - - aglio.render blueprint, 'default', (err, html) -> - assert err - - drafter.parse.restore() - - done() - - it 'Should error on file read failure', (done) -> - sinon.stub fs, 'readFile', (filename, options, callback) -> - callback 'error' - - aglio.renderFile 'foo', 'bar', 'default', (err, html) -> - assert err - - fs.readFile.restore() - - done() - - it 'Should error on file write failure', (done) -> - sinon.stub fs, 'writeFile', (filename, data, callback) -> - callback 'error' - - aglio.renderFile 'foo', 'bar', 'default', (err, html) -> - assert err - - fs.writeFile.restore() - - done() - - it 'Should error on non-file failure', (done) -> - sinon.stub aglio, 'render', (content, template, callback) -> - callback 'error' - - aglio.renderFile path.join(root, 'example.apib'), 'bar', 'default', (err, html) -> - assert err - - aglio.render.restore() - - done() - -describe 'Executable', -> - it 'Should print a version', (done) -> - sinon.stub console, 'log' - - bin.run version: true, (err) -> - assert console.log.args[0][0].match /aglio \d+/ - assert console.log.args[1][0].match /olio \d+/ - console.log.restore() - done(err) - - it 'Should render a file', (done) -> - sinon.stub console, 'error' - - sinon.stub aglio, 'renderFile', (i, o, t, callback) -> - warnings = [ - { - code: 1 - message: 'Test message' - location: [ - { - index: 0 - length: 1 - } - ] - } - ] - warnings.input = 'test' - callback null, warnings - - bin.run {}, (err) -> - assert err - - bin.run i: path.join(root, 'example.apib'), o: '-', -> - console.error.restore() - aglio.renderFile.restore() - done() - - it 'Should compile a file', (done) -> - sinon.stub aglio, 'compileFile', (i, o, callback) -> - callback null - - bin.run c: 1, i: path.join(root, 'example.apib'), o: '-', -> - aglio.compileFile.restore() - done() - - it 'Should start a live preview server', (done) -> - @timeout 5000 - - sinon.stub aglio, 'render', (i, t, callback) -> - callback null, 'foo' - - sinon.stub http, 'createServer', (handler) -> - listen: (port, host, cb) -> - console.log 'calling listen' - # Simulate requests - req = - url: '/favicon.ico' - res = - end: (data) -> - assert not data - handler req, res - - req = - url: '/' - res = - writeHead: (status, headers) -> false - end: (data) -> - aglio.render.restore() - cb() - file = fs.readFileSync 'example.apib', 'utf8' - setTimeout -> - fs.writeFileSync 'example.apib', file, 'utf8' - setTimeout -> - console.log.restore() - done() - , 500 - , 500 - handler req, res - - sinon.stub console, 'log' - sinon.stub console, 'error' - - bin.run s: true, (err) -> - console.error.restore() - assert err - - bin.run i: path.join(root, 'example.apib'), s: true, p: 3000, h: 'localhost', (err) -> - assert.equal err, null - http.createServer.restore() - - it 'Should support custom Jade template shortcut', (done) -> - sinon.stub console, 'log' - - bin.run i: path.join(root, 'example.apib'), t: 'test.jade', o: '-', (err) -> - console.log.restore() - done(err) - - it 'Should handle theme load errors', (done) -> - sinon.stub console, 'error' - sinon.stub aglio, 'getTheme', -> - throw new Error('Could not load theme') - - bin.run template: 'invalid', (err) -> - console.error.restore() - aglio.getTheme.restore() - assert err - done() - - it 'Should handle rendering errors', (done) -> - sinon.stub aglio, 'renderFile', (i, o, t, callback) -> - callback - code: 1 - message: 'foo' - input: 'foo bar baz' - location: [ - { index: 1, length: 1 } - ] - - sinon.stub console, 'error' - - bin.run i: path.join(root, 'example.apib'), o: '-', -> - assert console.error.called - - console.error.restore() - aglio.renderFile.restore() - - done() diff --git a/test/layout.coffee b/test/layout.coffee new file mode 100644 index 00000000..9bf7da3a --- /dev/null +++ b/test/layout.coffee @@ -0,0 +1,151 @@ +{assert} = require 'chai' +theme = require '../lib/main' + +describe 'Layout', -> + it 'Should include API title & description', (done) -> + ast = + name: 'Test API' + description: 'I am a [test](http://test.com/) API.' + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, 'Test API' + assert.include html, 'I am a test API.' + done() + + it 'Should render custom code in markdown', (done) -> + ast = + description: 'Test\n\n```coffee\na = 1\n```\n' + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, 'a = 1' + done() + + it 'Should highlight unfenced code blocks', (done) -> + ast = + description: 'Test\n\n var a = 1;\n' + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, '1' + done() + + it 'Should auto-link headings in markdown', (done) -> + ast = + description: '# Custom Heading' + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, '

+ ast = + description: '# Custom heading\n## Custom heading\n## Custom heading\n' + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, '"header-custom-heading"' + assert.include html, '"header-custom-heading-1"' + assert.include html, '"header-custom-heading-2"' + done() + + it 'Should include API hostname', (done) -> + ast = + metadata: [ + {name: 'HOST', value: 'http://foo.com/'} + ] + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, 'http://foo.com/' + done() + + it 'Should include resource group name & description', (done) -> + ast = + resourceGroups: [ + name: 'Frobs' + description: 'A list of *Frobs*' + resources: [] + ] + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, 'Frobs' + assert.include html, 'A list of Frobs' + done() + + it 'Should include resource information', (done) -> + ast = + resourceGroups: [ + name: 'Frobs' + resources: [ + name: 'Test Resource' + description: 'Test *description*' + actions: [] + ] + ] + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, 'Test Resource' + assert.include html, 'Test description' + done() + + it 'Should include action information', (done) -> + ast = + resourceGroups: [ + name: 'TestGroup' + resources: [ + name: 'TestResource' + uriTemplate: '/resource/{idParam}{?param%2Dname*,param2Name}' + parameters: [ + name: 'idParam' + description: 'Id parameter description' + values: [] + ] + actions: [ + name: 'Test Action', + description: 'Test *description*' + method: 'GET' + parameters: [ + name: 'param-name' + description: 'Param *description*' + type: 'bool' + required: true + values: [ + {value: 'test%2Dchoice'} + ] + ] + examples: [ + name: '' + description: '' + requests: [ + name: '200' + headers: [] + body: '{"error": true}' + schema: '' + ] + responses: [] + ] + ] + ] + ] + + theme.render ast, (err, html) -> + if err then return done err + assert.include html, 'Test Action' + assert.include html, 'Test description' + assert.include html, 'GET' + assert.include html, '/resource/{idParam}{?param-name*}' + assert.include html, 'idParam' + assert.include html, 'Id parameter description' + assert.include html, 'param-name' + assert.include html, 'Param description' + assert.include html, 'bool' + assert.include html, 'required' + assert.include html, 'true' + assert.include html, 'test-choice' + done() diff --git a/test/library.coffee b/test/library.coffee new file mode 100644 index 00000000..3419f175 --- /dev/null +++ b/test/library.coffee @@ -0,0 +1,76 @@ +{assert} = require 'chai' +jade = require 'jade' +rimraf = require 'rimraf' +theme = require '../lib/main' + +# Clear cache before test. This helps make sure the cache builds properly! +rimraf.sync 'cache/*' + +describe 'Library', -> + describe 'Config', -> + it 'Should allow getting config', -> + config = theme.getConfig() + assert.ok config + + it 'Should contain supported format version', -> + config = theme.getConfig() + assert.ok config.formats + + it 'Should contain option information', -> + config = theme.getConfig() + assert.ok config.options + + assert.ok config.options.length > 1 + option = config.options[0] + + assert.ok option.name + assert.ok option.description + + describe 'Render', -> + it 'Should not require options', (done) -> + theme.render {}, (err, html) -> + done err + + it 'Should accept options', (done) -> + theme.render {}, {}, (err, html) -> + done err + + it 'Should accept custom variables', (done) -> + theme.render {}, themeVariables: 'styles/variables-default.less', done + + it 'Should accept array of custom variables', (done) -> + theme.render {}, themeVariables: [ + 'styles/variables-default.less', + 'styles/variables-flatly.less' + ], done + + it 'Should error on missing variables', (done) -> + theme.render {}, themeVariables: '/bad/path.less', (err, html) -> + assert.ok err + done() + + it 'Should accept a custom style', (done) -> + theme.render {}, themeStyle: 'styles/layout-default.less', done + + it 'Should accept an array of custom styles', (done) -> + theme.render {}, themeStyle: [ + 'styles/layout-default.less', + 'styles/layout-default.less' + ], done + + it 'Should error on missing style', (done) -> + theme.render {}, themeStyle: '/bad/style.less', (err, html) -> + assert.ok err + done() + + it 'Should error on missing template', (done) -> + theme.render {}, themeTemplate: '/bad/path.jade', (err, html) -> + assert.ok err + done() + + it 'Should benchmark', (done) -> + old = process.env.BENCHMARK + process.env.BENCHMARK = true + theme.render {}, (err, html) -> + process.env.BENCHMARK = old + done err diff --git a/test/test.jade b/test/test.jade deleted file mode 100644 index 0e58661c..00000000 --- a/test/test.jade +++ /dev/null @@ -1,8 +0,0 @@ -doctype - -html - head - meta(charset="utf-8") - title= self.api.name || 'API Documentation' - body - p Test layout page for a custom API diff --git a/test/uri.coffee b/test/uri.coffee new file mode 100644 index 00000000..115b4e80 --- /dev/null +++ b/test/uri.coffee @@ -0,0 +1,187 @@ +{assert} = require 'chai' +theme = require '../lib/main' + +examples = [ + { + uriTemplate: '/resource/{path}' + parameters: [ + { + name: 'path' + } + ] + exampleURI: [ + '/resource/' + {attribute: 'path'} + ] + } + + { + uriTemplate: '/resource/{+reserved}' + parameters: [ + { + name: 'reserved' + example: 'this/that' + } + ] + exampleURI: [ + '/resource/' + {attribute: 'this/that', title: 'reserved'} + ] + } + + { + uriTemplate: '/resource{?greeting,name*}' + parameters: [ + { + name: 'greeting' + example: 'hello' + } + { + name: 'name' + example: 'world' + } + ] + exampleURI: [ + '/resource' + {operator: '?', attribute: 'greeting', literal: 'hello'} + {operator: '&', attribute: 'name', literal: 'world'} + ] + } + + { + uriTemplate: '/resource{?greeting}{&name}' + parameters: [ + { + name: 'greeting' + example: 'hello' + } + { + name: 'name' + example: 'world' + } + ] + exampleURI: [ + '/resource' + {operator: '?', attribute: 'greeting', literal: 'hello'} + {operator: '&', attribute: 'name', literal: 'world'} + ] + } + + { + uriTemplate: '/resource{?greeting}{+something}' + parameters: [ + { + name: 'greeting' + example: 'hello' + } + { + name: 'something' + example: 'with/slash' + } + ] + exampleURI: [ + '/resource' + {operator: '?', attribute: 'greeting', literal: 'hello'} + {title: 'something', attribute: 'with/slash'} + ] + } + + { + uriTemplate: '/resource/' + parameters: [] + exampleURI: [ + '/resource/' + ] + } + + { + uriTemplate: '/resource/{path}/' + parameters: [ + { + name: 'path' + } + ] + exampleURI: [ + '/resource/' + {attribute: 'path'} + '/' + ] + } + + { + uriTemplate: '/resource' + parameters: [] + exampleURI: [ + '/resource' + ] + } + +] + +addParameterDefaults = (example) -> + example.parameters = for parameter in example.parameters + { + name: parameter.name + description: parameter.description or '' + type: parameter.type or 'string' + required: parameter.required or false + values: parameter.values or [] + example: parameter.example or '' + defaultValue: parameter.defaultValue or '' + } + +generateAST = (example) -> + example.ast = + resourceGroups: [ + name: 'TestGroup' + resources: [ + name: 'TestResource' + uriTemplate: example.uriTemplate + parameters: example.parameters + actions: [ + name: 'Test Action', + description: 'Test *description*' + method: 'GET' + parameters: [] + examples: [ + name: '' + description: '' + requests: [ + name: '200' + headers: [] + body: '' + schema: '' + ] + responses: [] + ] + ] + ] + ] + +createExampleURI = (example) -> + exampleURI = '' + for segment in example.exampleURI + if typeof segment is 'string' + exampleURI += segment + else + if segment.operator + exampleURI += segment.operator + if segment.literal + exampleURI += "#{segment.attribute}=#{segment.literal}" + else + exampleURI += "#{segment.attribute}" + example.exampleURI = exampleURI + + +describe 'URI Rendering', -> + examples.forEach (example) -> + addParameterDefaults example + generateAST example + createExampleURI example + + it "Should render #{example.uriTemplate}", (done) -> + theme.render example.ast, (err, html) -> + if err then return done err + assert.include html, example.uriTemplate.replace /&/g, '&' + assert.include html, example.exampleURI + done()