Compare commits

..

63 Commits

Author SHA1 Message Date
ShubhamRwt
504bdb8e6c fixed gh pages 2022-03-01 12:44:13 +05:30
ShubhamRwt
0b6f4fb7e6 Fixing the docmentation for 1.3.4 2022-02-25 16:37:16 +05:30
ShubhamRwt
8748254d5a fixes for releasing 1.3.4 2022-02-22 14:56:21 +05:30
ShubhamRwt
7917565654 fixes for releasing 1.3.4 2022-02-22 14:22:38 +05:30
ShubhamRwt
30b41b0d70 Releasing 1.3.4 2022-02-22 13:49:22 +05:30
ShubhamRwt
a421b6d83a Releasing 1.3.4 2022-02-22 13:40:35 +05:30
ShubhamRwt
a8665290a0 Releasing 1.3.4 2022-02-21 15:25:20 +05:30
ShubhamRwt
61af76927e Release notes for 1.3.4 2022-02-21 15:14:33 +05:30
Shubham Rawat
2ffe3d5b8e Merge pull request #432 from Swagger2Markup/revert-431-signing
Revert "Added signing"
2022-02-18 22:03:47 +05:30
Shubham Rawat
03b5c42696 Revert "Added signing" 2022-02-18 22:03:27 +05:30
Shubham Rawat
f9b812a58d Merge pull request #431 from ShubhamRwt/signing
Added signing
2022-02-18 22:00:21 +05:30
ShubhamRwt
16cd99aece changes 2022-02-18 21:51:07 +05:30
ShubhamRwt
368bed514e github action file changes 2022-02-18 17:10:50 +05:30
Shubham Rawat
1492c40fc2 Merge pull request #430 from ShubhamRwt/github
github action file
2022-02-17 16:20:52 +05:30
Shubham Rawat
dafa73832e Update gradle-build.yml 2022-02-17 16:18:03 +05:30
Shubham Rawat
702a2cb180 Update gradle-build.yml 2022-02-17 15:38:54 +05:30
ShubhamRwt
89dbbc284b github action file 2022-02-17 15:30:04 +05:30
Shubham Rawat
6023d015b6 Merge pull request #429 from ShubhamRwt/1.3.x
Changing the build.gradle file
2022-02-17 15:22:55 +05:30
ShubhamRwt
ea2e61cfd9 Changing the build.gradle 2022-02-17 15:22:06 +05:30
ShubhamRwt
bdcbd0069c Changing the build.gradle 2022-02-17 15:15:54 +05:30
austek
859312b7d2 Remove OpenApi2Markup for 1.3.x release 2020-11-11 06:00:16 +00:00
Stefan Larsson
9de5ad0157 Fix Javadoc, added missing parameters and replaced with valid html (#415) 2020-11-05 08:45:30 +01:00
Aaron Watry
61df613cd2 tests: Update swagger petstore URLs from http to https to fix failing tests (#411)
Accessing the http URLs was doing a 302 redirect to https.

Co-authored-by: Aaron Watry <aaron.watry@advarra.com>
2020-10-02 09:57:43 +02:00
Sergei Khramkov
b70d6ca9ca Fixed the description of getMax in PropertyAdapter (#412)
Co-authored-by: Sergey.Khramkov <Sergey.Khramkov@nexign-systems.com>
2020-10-02 09:57:25 +02:00
Robert Winkler
0e15676cb7 Fixed failing test. 2020-06-16 11:36:27 +02:00
Robert Winkler
5f419a0d02 Removed SwaggerPageBreakLocations for backward compability. 2020-06-16 11:27:38 +02:00
Robert Winkler
a0efe7dd26 Removed SwaggerPageBreakLocations for backward compability. 2020-06-16 11:23:57 +02:00
Robert Winkler
21afb5adcd Removed SwaggerPageBreakLocations for backward compability. 2020-06-16 11:19:37 +02:00
Robert Winkler
7d0d73cd51 Moved classes for backward compability. 2020-06-16 11:07:28 +02:00
Robert Winkler
e8a51345a8 Delimiters should use the system line separator by default 2020-06-16 09:40:31 +02:00
Robert Winkler
f471774da9 Updated release notes. 2020-06-16 09:39:23 +02:00
Robert Winkler
0facccf009 Moved Swagger2MarkupConfig back into the main package for backward compability. 2020-06-16 09:35:09 +02:00
Robert Winkler
835c8fec03 Moved Swagger2MarkupConfig back into the main package for backward compability. 2020-06-16 09:18:04 +02:00
Robert Winkler
eea093acd4 Merge remote-tracking branch 'origin/master' 2020-06-15 13:07:14 +02:00
Robert Winkler
b32bfb3e54 Moved Swagger2MarkupConfig back into the main package for backward compability. 2020-06-15 12:25:19 +02:00
Robert Winkler
65f330baae Updated to 2.0.0-SNAPSHOT 2020-06-15 11:24:26 +02:00
Klaus Schwartz
b43a677744 Issue #248: Added a curl request example (#408)
* Issue #248 Add a curl request example

added configurable 3 kinds of request examples:

- basic (default, no source highlight)
- curl (bash source highlight)
- Invoke-WebRequest (powershell source highlight)

* updated default.properties to support curl example request feature

Issue #248 Add a curl request example

added configurable 3 kinds of request examples:

- basic (default, no source highlight)
- curl (bash source highlight)
- Invoke-WebRequest (powershell source highlight)

* added few tests, fixed extra space before query "?" delimiter, added builder configuration methods

Issue #248 Add a curl request example

* fix missig headers in example, fix Content-Type header name spelling

Issue #248 Add a curl request example
2020-06-10 15:42:27 +02:00
Paolo Patierno
4b69d6a150 Added support for MIME types with structured syntax suffixes (#410) 2020-06-08 15:47:44 +02:00
Robert Winkler
4a3ee6c5ca Feature/open api v3 support (#405) 2020-03-06 08:31:21 +01:00
Ali Ustek
69baeb6339 Merge pull request #400 from kolbdaniel1/patch-1
renamed jCenter() repository to jcenter()
2020-01-29 19:00:36 +00:00
Daniel
f7fe2b0cca renamed jCenter() repository to jcenter() 2020-01-29 14:39:45 +01:00
Ali Ustek
f853550748 Migrated markup document builder (#374)
* Initial commit

* Updated documentation

* Test travis CI

* Added library to bintray

* Updated documentation

* Updated documentation

* Updated documentation

* Published Version 1.1 to Maven Central

* Updated Bintray Badge

* Updated Bintray Badge

* Fixed maven pom issue

* Fixed issue: Comma should be escapes when constructing table in csv format in asciidoc
Fixed issue: logback.xml on the classpath

* New version number

* New version number

* Added Apache2 Copyright Header

* Updated documentation

* Updated documentation

* Updates documentation

* Fix Markdown level 3 title

* Fixed SECTION_TITLE_LEVEL3 in Markdown enum

* Added twitter batch

* Updated documentation

* Added method sectionTitleLevel4

* Added Artifactory Gradle Plugin in order to deploy snapshots to oss.jfrog.org

* Added artifactoryPublish task to TravisCI to publish SNAPSHOTS to OSS Artifactory

* Fixed coveralls badge

* Introduced new commands : anchor(anchor), crossReference(anchor, text)
Refactored writeToFile for robustness
Cleanups and fixes

* Enhanced support for tables

* Introduce inline commands : inlineAnchor, inlineCrossReference for easier markup composition

* More tests

* Renamed inline* to *AsString

* Implemented anchors and crossReferences for Markdown (GFM style)

* Updated readme

* Fixed anchor normalization

* Cleanups

* Cleanups

* Fixed replacing error

* Renamed TableColumnSpec to MarkupTableColumn

* Travis Secure Environment variables must be escaped

* Fixed travis.yml

* Fixed travis.yml

* fixed anchor normalization (again). Asciidoc anchor normalization differs between title and custom anchors => introducted crossReferenceTitle

* fixed tests compilation

* Update dependency-management-plugin to work with Gradle versions newer than 2.5

* Update Gradle wrapper to 2.10

* Fixed inter-document cross-references

* renamed crossReference -> crossReferenceAnchor and crossReferenceTitle -> crossReference as it's the default behavior
introduced addFilenameExtension (e.g. needed for inter-document cross-references)
fixed anchor normalization (support for ASCII characters in AsciiDoc)
Several workarounds with inter-document cross-references
Removed documentTitleWithAttributes as it's no use as-is

* Support for inter-document cross-references in Markdown

* fixed #9 Refactor anchor and cross-reference interface and implementation

* Updated asciidoctor-gradle-plugin: and asciidoctorj-pdf Gradle plugins to newer versions.

* [Bug] The document title must not have a anchor in front of it.

* Ignore punctuation in normalizeAnchor
Added new functions to create sections with a custom anchor not directly derived from the title

* Use paragrah local hardbreaks instead of global attribute

* fixed normalization and provided tests for normalization (finally) !

* missing Mockito in Gradle
fixed tests

* anchor normalization better manages beginning and ending escape characters, and intermediate punctuation

* introduce text, italicText, boldText
remove *AsString builders, use a new MarkupDocBuilder with toString() method instead

* Create a builder instance from another builder instance, for easier composition

* introduce forceLineBreak on all *Line methods

* Introduce new sectionTitleWithAnchor* to allow users to create titles without anchor, with a custom anchor (will be normalized anyway), or with an auto-generated anchor.

* sectionTitleWithAnchor* consistency fix when anchor == null => auto-generate anchor

* Introduce global builder configuration .withAnchorPrefix
Introduce copy() method to easily duplicate builders with configuration

* Introduce Markup-dependent specifiers on tables

* Added public interface complete documentation

* Added 2 newlines at the end of generated output when output are files. This protect the final AsciiDoc when you later include these files.

* MarkupTableColumn documentation enhancements

* Added importMarkup(markupText, levelOffset)

* Check for levelOffset < 0 in importMarkup(markupText, levelOffset)

* Support for levelOffset < 0 in importMarkup

* Use Reader in importMarkup instead of a String

* MAX_TITLE_LEVEL = 4 -> 5

* Added new interface methods to support java.nio.file.Path parameters

* Added new block methods (supporting title and admonitions)
Refactored listing() and method() methods
Does not flush buffer anymore when writeToFile

* Renamed addfileExtension to addFileExtension

* logging fix

* Support level 5 titles.
Added sectionTitleLevel(int level, String title) for convenience.

* Line separators (Mac, Windows, Linux) of input data are replaced by the system line separator.

* Removed source folder mainpjava.

* Fixed AbstractMarkupDocBuilderTest on windows machines by setting newLine to a fixed value.

* Added validation that input values are not null and empty.

* Added the functionality to provide a custom line separator which should be used.

* Added Mac line separator.

* Removed io.spring.gradle:dependency-management-plugin

* Added default line separator if provided lineSeparator is null.

* Updated versions of commons-collection, commons-lang3, commons-codec and slf4j-api.

* Removed Guava library.

* New lines in Table headers are replaced by a whitespace
New lines in Table cells are replaced by the configured line separator.

* Opens MarkupDocBuilders for additional/external markup builders (includes an example for Confluence wiki markup)

* Make changes Java 1.7 compatible.

* Adds a markup builder for Atlassian's Jira/Confluence wiki markup.

* Updated README.

* Renamed ATLASSIAN to ATLASSIAN_WIKI

* Updated publishing and coverage gradle scripts.

* Updated publishing gradle script.

* Moved source code which does not belong to the external API into an internal package.

* Copy newLine in copy() method + non regression test

* simplify empty constructors
added missing copyright headers

* factored importMarkupStyle1/2 + Style2 tests
removed deprecated tableWithHeaderRow
refactored ConfluenceMarkupBuilder

* copy with optional copyBuffer

* Added assertj-diff.

* fixing ConfluenceMarkupBuilder
fixed MarkdownBuilder with null block styles

* remove FILE_EXTENSION from Markups, use MarkupLanguage::getFileNameExtensions instead

* fixed documentTitle level for ConfluenceMarkupBuilder

* fixed LINE_BREAK for ConfluenceMarkupBuilder

* fixed empty cells for ConfluenceMarkupBuilder

* fixed crossReferences for ConfluenceMarkupBuilder

* cleanups

* removed deprecated writeToFile*

* Support column headers style generically in MarkupTableColumn

* Use DiffAssertions to check generated markup result in tests

* Introduce MarkupLanguage conversion in importMarkup. Currently support Markdown -> AsciiDoc.

* remove unnecessary newlines when importMarkup text is blank

* removed hardbreaks from AsciiDoc paragraph()

* fixed tests after removing hardbreaks

* better cell formatting : content trimming and newLines management

* fixed pipe escaping management in ConfluenceMarkup cell formatter (does not escape pipe in links in cells)
fixed corner cases in Regexp replacements (quoting)

* added OpenOption parameter in writeToFile()

* Fixed MarkupDocBuilderTests on windows by fixing line separator to LineSeparator.UNIX

* Adapted group id, versioning and root package to other swagger2markup projects

* introduced paragraph(text, hardbreaks), force line breaks on each line for Markdown and ConfluenceMarkup

* ImportMarkup, writeToFile and writeToFileWithoutExtension don't throw IOExceptions anymore, but RuntimeExceptions.

* Upgrade to Java8

* Fixed JavaDoc

* Fixed JavaDoc
Removed commons-collection by using Java8 Streams

* Updated readme

* Updated readme

* reintroduce literalTextLine(text)
rename listing -> listingBlock

* Support <> in cross-reference texts in AsciiDoc

* fixed sectionTitleWithAnchor and auto-generated anchor (and fixed tests)
fixed ConfluenceBuilder : missing replaceNewLinesWithWhiteSpace on title/anchor, removed extra newLine

* supports for blank value for text and textLine only to support adding simple spaces to document

* Released v1.0.0

* Updated readme

* Updated readme

* Updated readme

* Updated readme

* Updated readme

* Changed bold to ** and italic to __ so that special chars in the text are possible

* Updated version to 1.1.0-SNAPSHOT

* Release v1.0.0

* Updated bintray badge

* Updated docs

* Add support for page breaks

* Add page breaks to unit tests

* Updated version from 1.1.0 to 1.1.1-SNAPSHOT

* Released v1.1.1

* Updated README

* Improve code blocks in markdown (#28)

* Prepare release 1.1.2

* Update AbstractMarkupDocBuilder.java (#29)

Support relative file names both of "filename" and "./filename" while `writeToFileWithoutExtension`

* Issue #21: AsciidocBuilder should enable option to set pegdown timeout (#31)

* Upgraded gradle (#33)

* upgrade to gradle 5.6.3

* update dependencies versions

* Moved markup-document-builder files and folders into swagger2markup-builder/

* Fix merge problems from markup-document-builder

* correct expected file for instagram/overview.adoc

* fix paths to examples files in documentation files
2019-10-30 08:13:52 +01:00
Ali Ustek
75fa8f788c Moved docs to documentation module (#373) 2019-10-29 12:49:09 +01:00
Ali Ustek
7a86fdaba3 Updated version numbers and turn on strict conflict resolution (#371) 2019-10-29 12:48:43 +01:00
Ali Ustek
1566b22489 Convert project to be multi-module (#372) 2019-10-29 08:15:17 +01:00
Ali Ustek
ed026f3587 Upgraded to gradle 5.6.3 (#370) 2019-10-24 10:02:22 +02:00
Robert Winkler
6e8e4ce780 Updated READE 2019-06-27 13:02:46 +02:00
mona
60b7d90ad2 get label for operation.deprecated (#363) 2019-06-03 22:54:51 +02:00
guangp
da83465f19 add hostname in uri section of every operation, it is configurable. (#356)
* add hostname in uri section of every operation, it is configurable.

* modify java docs

* test hostname conf
2019-03-21 15:41:58 +01:00
alexmartinsrj
7ae0b64d8e Update labels_pt_BR.properties (#359)
translate of some untraslated words.
2019-03-21 15:41:24 +01:00
Sridhar Jonnalagadda
f8cbf7801d Issue #21: AsciidocBuilder should enable option to set pegdown timeout (#353) 2018-11-21 13:04:22 +01:00
Maciej Swiderski
7fbd49c5ea Issue #349 - Add support for generating example for request data based on media type (#350) 2018-11-05 10:43:03 +01:00
Valy Diarrassouba
8717e26f76 Allow to define freeform with additionalProperties: {} (#346) (#347) 2018-10-22 12:48:02 +02:00
aspekt23
483d6c3d17 Issue 291 support for title property in definitions (#348)
* Implemented preference for definition title if it is present

* Fixed failing test data
2018-10-22 12:43:09 +02:00
parrrot
03fb52fb8e Bugfix/issue336 (#345)
* added if branches for "header" parameter for examples and generated proper format

* modified expected test files to include new format of request header
2018-10-18 09:21:28 +02:00
MarosPataky
e574f0e65f Added support for minItems, maxItems property in parameters section o… (#341)
* Added support for minItems, maxItems property in parameters section of specification

* Added values for min/max items for all languages (for now, no translations are provided)

* Fixed issues with NPE and failing tests

* Added translations for min_items and max_items
2018-10-15 10:14:03 +02:00
MarosPataky
e9b04c712d Added support for enums with Integer type (#342)
* Added support for enums for Integer type, changed enums test data to reflect the change

* Fixed test failures that were caused by missing "format" part of integer type description
2018-10-15 10:13:24 +02:00
Martin Waßmann
b4c7c8860c Better generated examples for strings (#329)
* Generate examples based on string format

The following static examples are generated:
* byte: Ynl0ZQ== (base64 of byte)
* date: 1970-01-01
* date-time: 1970-01-01T00:00:00Z
* email: email@example.com
* password: secret
* uuid: f81d4fae-7dec-11d0-a765-00a0c91e6bf6

* Use first enum value as example

* Also generate string examples for path and query parameter

* Test example generation for custom string format
2018-08-06 12:50:07 +02:00
Bennet Schulz
815c161b7e fix typo in documentation (#330) 2018-08-06 10:31:18 +02:00
Łukasz Kolek
ecaaaeb049 fix: polish translation corrected from UTF-8 to encoded properites (#324) 2018-07-12 15:24:56 +02:00
Barry Ostroff
647846762d Generate examples for inline responses (#314)
* Handle untyped inlines - swagger parser no longer defaults untyped to object types
* Handle object inlines - generates a name based on method and response code
* Handle object inlines with titles - generates a name from the title
2018-05-01 21:35:43 +02:00
Michał Dul
655a15c722 Polish language translation (#311)
* Polish language translation

* language builder adjusted
2018-04-29 11:42:18 +02:00
Robert Winkler
6297b859dd Use old gitHubPages plugin 2018-04-27 13:42:29 +02:00
475 changed files with 17706 additions and 1304 deletions

82
.github/workflows/gradle-build.yml vendored Normal file
View File

@@ -0,0 +1,82 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Build
on:
push:
branches: [ 1.3.x ]
pull_request:
branches: [ 1.3.x ]
jobs:
validation:
name: "Gradle wrapper validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.5
- uses: gradle/wrapper-validation-action@v1.0.4
build:
name: "Build and publish"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.5
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'temurin'
- name: Cache SonarCloud packages
uses: actions/cache@v2.1.6
if: env.SONAR_TOKEN != null && env.SONAR_TOKEN != ''
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Build
id: gradle
uses: eskatos/gradle-command-action@v1
with:
arguments: check
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
- name: "Comment build scan url"
uses: actions/github-script@v5
if: github.event_name == 'pull_request' && failure()
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '❌ ${{ github.workflow }} failed: ${{ steps.gradle.outputs.build-scan-url }}'
})
- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action/composite@v1
if: always()
with:
files: '**/test-results/**/*.xml'
- name: Analyze with SonarCloud
continue-on-error: true
if: env.SONAR_TOKEN != null && env.SONAR_TOKEN != ''
uses: eskatos/gradle-command-action@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
arguments: sonarqube -Psonar.organization=swagger2markup
dependencies-cache-enabled: true
configuration-cache-enabled: true
- name: Publish to Sonatype
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/1.3.x' }}
uses: eskatos/gradle-command-action@v1
env:
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USER }}
ORG_GRADLE_PROJECT_sonatypePassword : ${{ secrets.SONATYPE_PASSWORD }}
with:
arguments: publishToSonatype
dependencies-cache-enabled: true
configuration-cache-enabled: true

View File

@@ -1,6 +1,6 @@
language: java
jdk:
- oraclejdk8
- openjdk8
before_install:
- chmod +x gradlew
after_success:

View File

@@ -7,6 +7,17 @@ image:https://travis-ci.org/Swagger2Markup/swagger2markup.svg?branch=master["Bui
== Overview
NOTE: Dear community,
unfortunately I can't maintain Swagger2Markup alone anymore. There are many interesting new topics:
1) Swagger v3 support
2) Fixing bugs
2) Merge Swagger2Markup repositories and create a new multi-module repository.
Any help is welcome.
Kind regards,
Robert
The primary goal of this project is to *simplify the generation of an up-to-date RESTful API documentation by combining documentation that's been hand-written with auto-generated API documentation* produced by https://github.com/swagger-api[Swagger]. The result is intended to be an *up-to-date, easy-to-read, on- and offline user guide*, comparable to https://developer.github.com/v3/[GitHub's API documentation]. The output of Swagger2Markup can be used as an alternative to https://github.com/swagger-api/swagger-ui[swagger-ui] and can be served as static content.
NOTE: The Swagger Specification has been donated to to the https://openapis.org/[Open API Initiative (OAI)] and has been renamed to the https://github.com/OAI/OpenAPI-Specification[OpenAPI Specification].
@@ -22,12 +33,12 @@ The project requires at least JDK 8.
== Example
image::src/docs/asciidoc/images/Swagger2Markup.PNG[]
image::swagger2markup-documentation/src/docs/asciidoc/images/Swagger2Markup.PNG[]
image::src/docs/asciidoc/images/Swagger2Markup_definitions.PNG[]
image::swagger2markup-documentation/src/docs/asciidoc/images/Swagger2Markup_definitions.PNG[]
== Reference documentation
- http://swagger2markup.github.io/swagger2markup/1.3.1/[Reference Documentation]
- http://swagger2markup.github.io/swagger2markup/1.3.4/[Reference Documentation]
- https://github.com/Swagger2Markup/swagger2markup/blob/master/RELEASENOTES.adoc[Release notes]
- https://github.com/Swagger2Markup/spring-swagger2markup-demo[Demo using Swagger2Markup, Spring Boot, Springfox and spring-restdocs]

View File

@@ -3,6 +3,21 @@
== Version 0.1.0
* Initial version with support for AsciiDoc and Markdown
=== Version 0.1.1
* Signed jar files
=== Version 0.1.2
* Removed logback from compile dependency
=== Version 0.1.3
* Removed commons.io from compile dependency
=== Version 0.1.4
* Fixed SECTION_TITLE_LEVEL3 in Markdown enum
=== Version 0.1.5
* Added SECTION_TITLE_LEVEL4
== Version 0.2.0
* This version is not downward compatible. This version supports includes of example files and JSON/XML Schema files. See documentation.
@@ -102,6 +117,7 @@
* PR #190: Add support for Spanish language
* PR #192: Updated min/max value to format correctly based on the data type
* PR #193: Added support for exclusiveMin and exclusiveMax
* Changed bold to ** and italic to __ so that special chars in the text are possible
=== Version 1.1.1
* Issue #194: Added a config parameter which allows to prepend the basePath to all paths.
@@ -115,6 +131,10 @@
* Issue #198: Chinese chinese language encoding
* Issue #207: Properties that start with an underscore are displayed correctly now
* Refactored Swagger2Markup to use a Component-Based design. A document can be composed of components and components can be composed of other components.
* Added a method to add page breaks.
== Version 1.1.2
* Improve code blocks in markdown
== Version 1.2.0
* Issue #214: Add page break locations
@@ -143,4 +163,10 @@
* PR #294: Examples always start with a newline if there is other content in the same cell
* PR 307: Include required parameters in example request
=== Version 1.3.4
* Moved from bintray to Sonatype
* Introduced Github actions
* Certain bug fixes
* Added support for MIME types with structured syntax suffixes (#410)

View File

@@ -1,68 +1,117 @@
buildscript {
plugins {
id "org.sonarqube" version "2.7"
id "me.champeau.gradle.jmh" version "0.4.8"
id 'org.asciidoctor.convert' version '1.6.0'
id "org.ajoberstar.github-pages" version "1.7.2"
id "io.github.gradle-nexus.publish-plugin" version "1.1.0"
}
apply plugin: 'idea'
apply from: "${rootDir}/libraries.gradle"
ext {
releaseVersion = '1.3.4'
}
allprojects {
apply plugin: 'jacoco'
apply plugin: 'me.champeau.gradle.jmh'
version = '1.3.4'
group 'io.github.swagger2markup'
description = 'swagger2markup Build'
repositories {
jcenter()
}
dependencies {
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.6'
classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.16'
classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.0.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6'
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.0.0"
classpath "org.ajoberstar:gradle-git-publish:0.3.1"
mavenCentral()
}
}
description = 'swagger2markup Build'
version = '1.3.3'
ext.releaseVersion = '1.3.3'
group = 'io.github.swagger2markup'
//artifactoryPublish.skip = true // apply to all projects except the root
apply plugin: 'java'
apply plugin: 'eclipse'
apply from: 'gradle/publishing.gradle'
apply from: 'gradle/coverage.gradle'
apply from: 'gradle/documentation.gradle'
tasks.withType(JavaCompile) {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
options.deprecation = true
options.encoding = 'UTF-8'
options.compilerArgs << "-Xlint:unchecked"
}
repositories {
maven {
url "https://oss.jfrog.org/artifactory/oss-snapshot-local"
ext {
coreProjects = subprojects.findAll {
p -> !p.name.endsWith("-bom")
}
jcenter()
//mavenLocal()
}
dependencies {
compile 'io.github.swagger2markup:markup-document-builder:1.1.2'
compile 'io.swagger:swagger-compat-spec-parser:1.0.35'
compile 'org.apache.commons:commons-configuration2:2.1'
compile 'commons-beanutils:commons-beanutils:1.9.2'
compile 'org.apache.commons:commons-collections4:4.1'
compile 'io.vavr:vavr:0.9.1'
compile 'ch.netzwerg:paleo-core:0.11.0'
testCompile 'junit:junit:4.12'
testCompile 'org.asciidoctor:asciidoctorj:1.5.6'
testCompile 'ch.qos.logback:logback-classic:1.1.2'
testCompile 'org.assertj:assertj-core:3.8.0'
testCompile 'io.github.robwin:assertj-diff:0.1.1'
configure(project.coreProjects) {
apply plugin: 'signing'
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'maven-publish'
apply from: "${rootDir}/publishing.gradle"
apply plugin: 'jacoco'
tasks.withType(JavaCompile) {
sourceCompatibility = "11"
targetCompatibility = "11"
options.deprecation = true
options.encoding = 'UTF-8'
options.compilerArgs += ["-Xlint:unchecked", "-parameters"]
}
tasks.withType(Javadoc){
options.encoding = 'UTF-8'
}
jmh {
duplicateClassesStrategy = 'warn'
}
configurations.all {
resolutionStrategy {
failOnVersionConflict()
}
}
}
nexusPublishing {
repositories {
sonatype()
}
}
sonarqube {
properties {
property "sonar.host.url", "https://sonarcloud.io"
property "sonar.organization", "swagger2markup"
property "sonar.projectName", "swagger2markup"
property "sonar.projectKey", "Swagger2Markup_swagger2markup"
property "sonar.links.homepage", "https://github.com/Swagger2Markup/swagger2markup"
property "sonar.links.ci", "https://travis-ci.org/Swagger2Markup/swagger2markup"
property "sonar.links.scm", "https://github.com/Swagger2Markup/swagger2markup"
property "sonar.links.issue", "https://github.com/Swagger2Markup/swagger2markup/issues"
property "sonar.language", "java"
}
}
def allTestCoverageFile = "$buildDir/jacoco/allTestCoverage.exec"
task jacocoMergeTest(type: JacocoMerge) {
destinationFile = file(allTestCoverageFile)
executionData = project.fileTree(dir: '.', include: '**/build/jacoco/test.exec')
}
task jacocoMerge(dependsOn: ['jacocoMergeTest']) {
// used to run the other merge tasks
}
subprojects {
sonarqube {
properties {
property "sonar.jacoco.reportPaths", allTestCoverageFile
}
}
afterEvaluate {
// exclude subprojects that don't produce a jar file or by design.
if (!project.name.equals('swagger2markup-bom') && !project.name.equals('swagger2markup-documentation')) {
jar {
inputs.property('moduleName', moduleName)
manifest.attributes(
'Automatic-Module-Name': moduleName
)
}
}
}
}
tasks.check.dependsOn tasks.jacocoTestReport
test {
if (System.properties['http.proxyHost']) {
systemProperty 'http.proxyHost', System.properties['http.proxyHost']
systemProperty 'http.proxyPort', System.properties['http.proxyPort']
systemProperty 'http.nonProxyHosts', System.properties['http.nonProxyHosts']
}
systemProperty 'file.encoding', 'UTF-8'
}
task wrapper(type: Wrapper) {
gradleVersion = '4.3.1'
dependsOn(subprojects.test) // required by cobertura to aggregate report
}

View File

@@ -1,13 +0,0 @@
apply plugin: 'jacoco'
apply plugin: 'com.github.kt3k.coveralls'
jacocoTestReport {
reports {
xml.enabled = true // coveralls plugin depends on xml format report
html.enabled = true
}
}
tasks.coveralls {
dependsOn 'check'
}

View File

@@ -1,41 +0,0 @@
apply plugin: 'org.asciidoctor.convert'
apply plugin: 'org.ajoberstar.git-publish'
asciidoctor {
sources {
include 'index.adoc'
}
backends = ['html5', 'pdf']
attributes = [
doctype: 'book',
toc: 'left',
toclevels: '3',
numbered: '',
sectlinks: '',
sectanchors: '',
hardbreaks: '',
'release-version': project.releaseVersion
]
}
gitPublishCommit.dependsOn asciidoctor
gitPublish {
repoUri = 'git@github.com:Swagger2Markup/swagger2markup.git'
branch = 'gh-pages'
// use ENV GRGIT_USER
// use ENV GRGIT_PASS
// or org.ajoberstar.grgit.auth.username system property
// org.ajoberstar.grgit.auth.password system property
// see http://ajoberstar.org/grgit/grgit-authentication.html for details
// credentials {
// username = project.hasProperty('githubUser') ? project.githubUser : System.getenv('GITHUB_USER')
// password = project.hasProperty('githubPassword') ? project.githubPassword : System.getenv('GITHUB_PASSWORD')
// }
contents {
from file(asciidoctor.outputDir.path + '/html5')
into project.releaseVersion
}
}

View File

@@ -1,151 +0,0 @@
import java.text.SimpleDateFormat
apply plugin: 'maven-publish'
apply plugin: 'com.jfrog.bintray'
apply plugin: "com.jfrog.artifactory"
Date buildTimeAndDate = new Date()
ext {
buildDate = new SimpleDateFormat('yyyy-MM-dd').format(buildTimeAndDate)
buildTime = new SimpleDateFormat('HH:mm:ss.SSSZ').format(buildTimeAndDate)
projectUrl = 'https://github.com/Swagger2Markup/swagger2markup'
licenseUrl = 'https://github.com/Swagger2Markup/swagger2markup/blob/master/LICENSE.txt'
scmUrl = 'https://github.com/Swagger2Markup/swagger2markup.git'
issuesUrl = 'https://github.com/Swagger2Markup/swagger2markup/issues'
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives sourcesJar
archives javadocJar
}
jar {
manifest {
attributes(
'Created-By': System.properties['java.version'] + " (" + System.properties['java.vendor'] + " " + System.properties['java.vm.version'] + ")",
'Built-With': "gradle-${project.getGradle().getGradleVersion()}, groovy-${GroovySystem.getVersion()}",
'Build-Time': "${new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")}",
'Specification-Title': "${project.name}",
'Specification-Version': project.version.toString(),
'Implementation-Title': "${project.name}",
'Implementation-Version': project.version.toString()
)
}
}
if (!project.hasProperty('bintrayUsername')) ext.bintrayUsername = ''
if (!project.hasProperty('bintrayApiKey')) ext.bintrayApiKey = ''
if (!project.hasProperty('gpgPassphrase')) ext.gpgPassphrase = ''
if (!project.hasProperty('ossUser')) ext.ossUser = ''
if (!project.hasProperty('ossPassword')) ext.ossPassword = ''
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom.withXml {
def devs = ['RobWin': 'Robert Winkler']
def root = asNode()
root.dependencies.'*'.findAll() {
it.scope.text() == 'runtime' && project.configurations.compile.allDependencies.find { dep ->
dep.name == it.artifactId.text()
}
}.each() {
it.scope*.value = 'compile'
}
root.appendNode('name', project.name)
root.appendNode('packaging', 'jar')
root.appendNode('url', projectUrl)
root.appendNode('description', project.description)
def license = root.appendNode('licenses').appendNode('license')
license.appendNode('name', 'Apache-2.0')
license.appendNode('url', licenseUrl)
license.appendNode('distribution', 'repo')
root.appendNode('scm').appendNode('url', scmUrl)
def developers = root.appendNode('developers')
devs.each {
def d = developers.appendNode('developer')
d.appendNode('id', it.key)
d.appendNode('name', it.value)
}
}
artifact sourcesJar
artifact javadocJar
}
}
}
bintray {
user = project.bintrayUsername
key = project.bintrayApiKey
dryRun = false //Whether to run this as dry-run, without deploying
publish = true //If version should be auto published after an upload
publications = ['mavenJava']
pkg {
repo = 'Maven'
name = 'swagger2markup'
userOrg = 'swagger2markup'
websiteUrl = projectUrl
issueTrackerUrl = issuesUrl
vcsUrl = scmUrl
desc = rootProject.description
licenses = ['Apache-2.0']
version {
vcsTag = rootProject.version
gpg {
sign = true //Determines whether to GPG sign the files. The default is false
passphrase = project.gpgPassphrase //Optional. The passphrase for GPG signing'
}
mavenCentralSync {
sync = true //Optional (true by default). Determines whether to sync the version to Maven Central.
user = ossUser //OSS user token
password = ossPassword //OSS user password
}
}
}
}
artifactory {
contextUrl = 'https://oss.jfrog.org'
resolve {
repository {
repoKey = 'libs-release'
}
}
publish {
repository {
repoKey = 'oss-snapshot-local' //The Artifactory repository key to publish to
//when using oss.jfrog.org the credentials are from Bintray. For local build we expect them to be found in
//~/.gradle/gradle.properties, otherwise to be set in the build server
username = project.hasProperty('bintrayUsername') ? project.bintrayUsername : System.getenv('BINTRAY_USER')
password = project.hasProperty('bintrayApiKey') ? project.bintrayApiKey : System.getenv('BINTRAY_KEY')
}
defaults {
publications('mavenJava')
}
}
if (System.properties['https.proxyHost']) {
clientConfig.proxy.host = System.properties['https.proxyHost']
clientConfig.proxy.port = System.properties['https.proxyPort'].toInteger()
}
}
tasks.artifactoryPublish {
dependsOn 'check'
}

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#Mon Dec 04 10:24:38 CET 2017
#Mon Oct 21 16:35:38 BST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.3-all.zip

6
gradlew vendored
View File

@@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
warn () {
echo "$*"
}
die ( ) {
die () {
echo
echo "$*"
echo
@@ -155,7 +155,7 @@ if $cygwin ; then
fi
# Escape application args
save ( ) {
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}

52
libraries.gradle Normal file
View File

@@ -0,0 +1,52 @@
// Allows centralized definition of the version of artifacts to
// use. In that respect it serves a role similar to <dependencyManagement> in Maven
ext {
implLibraries = [:]
testLibraries = [:]
dependencyOverrides = [:]
}
implLibraries = [
asciiDocJApi : "org.asciidoctor:asciidoctorj-api:2.2.0",
commonsBeanUtils : "commons-beanutils:commons-beanutils:1.9.4",
commonsCodec : "commons-codec:commons-codec:1.13",
commonsCollections4: "org.apache.commons:commons-collections4:4.4",
commonsConf2 : "org.apache.commons:commons-configuration2:2.6",
commonsLang3 : "org.apache.commons:commons-lang3:3.9",
commonsIO : "commons-io:commons-io:2.6",
commonsText : "org.apache.commons:commons-text:1.8",
guava : 'com.google.guava:guava:27.0.1-android',
jacksonDatabind : 'com.fasterxml.jackson.core:jackson-databind:2.9.10',
mark2Ascii : "nl.jworks.markdown_to_asciidoc:markdown_to_asciidoc:1.1",
paleo : "ch.netzwerg:paleo-core:0.14.0",
pegdown : "org.pegdown:pegdown:1.6.0",
slf4j : "org.slf4j:slf4j-api:1.7.28",
swaggerV2 : "io.swagger:swagger-parser:1.0.47",
swaggerV2Converter : "io.swagger.parser.v3:swagger-parser-v2-converter:2.0.15",
swaggerV3 : "io.swagger.parser.v3:swagger-parser:2.0.15",
vavr : "io.vavr:vavr:0.10.2"
]
testLibraries = [
asciiDocJ : "org.asciidoctor:asciidoctorj:2.2.0",
assertj : "org.assertj:assertj-core:3.13.2",
assertjDiff: "io.github.robwin:assertj-diff:0.1.1",
junit : "junit:junit:4.12",
logback : "ch.qos.logback:logback-classic:1.2.3",
mockito : "org.mockito:mockito-core:3.1.0"
]
dependencyOverrides = [
assertj : testLibraries.assertj,
commonsCodec : implLibraries.commonsCodec,
commonsIO : implLibraries.commonsIO,
commonsLang3 : implLibraries.commonsLang3,
findBugs : 'com.google.code.findbugs:jsr305:3.0.2',
guava : implLibraries.guava,
jaksonCore : 'com.github.fge:jackson-coreutils:1.8',
jacksonDatabind: implLibraries.jacksonDatabind,
jnrConstants : 'com.github.jnr:jnr-constants:0.9.12',
jnrEnxio : 'com.github.jnr:jnr-enxio:0.19',
jnrPosix : 'com.github.jnr:jnr-posix:3.0.49',
jodaTime : 'joda-time:joda-time:2.9.9',
slf4j : implLibraries.slf4j,
]

91
publishing.gradle Normal file
View File

@@ -0,0 +1,91 @@
import java.text.SimpleDateFormat
Date buildTimeAndDate = new Date()
ext {
buildDate = new SimpleDateFormat('yyyy-MM-dd').format(buildTimeAndDate)
buildTime = new SimpleDateFormat('HH:mm:ss.SSSZ').format(buildTimeAndDate)
licenseUrl = 'https://github.com/Swagger2Markup/swagger2markup/blob/master/LICENSE.txt'
scmUrl = 'https://github.com/Swagger2Markup/swagger2markup.git'
}
def projectArtifactId = 'swagger2markup'
def projectUrl = 'https://github.com/Swagger2Markup/swagger2markup'
def licenseUrl = 'https://github.com/Swagger2Markup/swagger2markup/blob/master/LICENSE.txt'
def scmUrl = 'https://github.com/Swagger2Markup/swagger2markup.git'
def issuesUrl = 'https://github.com/Swagger2Markup/swagger2markup/issues'
jar {
manifest {
attributes(
'Built-By': 'Robert Winkler',
'Created-By': System.properties['java.version'] + " (" + System.properties['java.vendor'] + " " + System.properties['java.vm.version'] + ")",
'Build-Date': project.buildDate,
'Build-Time': project.buildTime,
'Specification-Title': projectArtifactId,
'Specification-Version': project.version,
'Implementation-Title': projectArtifactId,
'Implementation-Version': project.version
)
}
}
task sourcesJar(type: Jar) {
from sourceSets.main.allJava
archiveClassifier = 'sources'
}
task javadocJar(type: Jar) {
from javadoc
archiveClassifier = 'javadoc'
}
artifacts {
archives sourcesJar
archives javadocJar
}
signing {
sign publishing.publications
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom.withXml {
def devs = ['RobWin': 'Robert Winkler',
'austek': 'Ali Ustek']
def root = asNode()
root.dependencies.'*'.findAll() {
it.scope.text() == 'runtime' && project.configurations.compile.allDependencies.find { dep ->
dep.name == it.artifactId.text()
}
}.each() {
it.scope*.value = 'compile'
}
root.appendNode('name', projectArtifactId)
root.appendNode('packaging', 'jar')
root.appendNode('url', projectUrl)
root.appendNode('description', project.description)
def license = root.appendNode('licenses').appendNode('license')
license.appendNode('name', 'Apache-2.0')
license.appendNode('url', licenseUrl)
license.appendNode('distribution', 'repo')
root.appendNode('scm').appendNode('url', scmUrl)
def developers = root.appendNode('developers')
devs.each {
def d = developers.appendNode('developer')
d.appendNode('id', it.key)
d.appendNode('name', it.value)
}
}
artifact sourcesJar
artifact javadocJar
}
}
}

View File

@@ -1 +1,9 @@
rootProject.name = 'swagger2markup'
rootProject.name = 'swagger2markup'
include 'swagger2markup-asciidoc'
include 'swagger2markup-bom'
include 'swagger2markup-builder'
include 'swagger2markup-documentation'
include 'swagger2markup'
include 'swagger2markup-core'

View File

@@ -1,80 +0,0 @@
/*
* Copyright 2017 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.swagger2markup.model;
import io.swagger.models.HttpMethod;
import io.swagger.models.Operation;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class PathOperation {
private HttpMethod method;
private String path;
private Operation operation;
public PathOperation(HttpMethod method, String path, Operation operation) {
this.method = method;
this.path = path;
this.operation = operation;
}
public HttpMethod getMethod() {
return method;
}
public String getPath() {
return path;
}
/**
* Returns the display title for an operation
*
* @return the operation title
*/
public String getTitle() {
String operationName = operation.getSummary();
if (isBlank(operationName)) {
operationName = getMethod().toString() + " " + getPath();
}
return operationName;
}
/**
* Returns an unique id for the operation.<br>
* Use {@code <operation id>}, then {@code <operation path> lowercase(<operation method>)} if operation id is not set.
*
* @return operation unique id
*/
public String getId() {
String id = operation.getOperationId();
if (id == null)
id = getPath() + " " + getMethod().toString().toLowerCase();
return id;
}
public Operation getOperation() {
return operation;
}
@Override
public String toString() {
return getId();
}
}

View File

@@ -0,0 +1,25 @@
ext.moduleName="io.github.swagger2markup.asciidoc"
dependencies {
configurations.all {
// resolutionStrategy.force dependencyOverrides.commonsCodec
// resolutionStrategy.force dependencyOverrides.commonsIO
// resolutionStrategy.force dependencyOverrides.commonsLang3
resolutionStrategy.force dependencyOverrides.jnrConstants
resolutionStrategy.force dependencyOverrides.jnrEnxio
resolutionStrategy.force dependencyOverrides.jnrPosix
// resolutionStrategy.force dependencyOverrides.jodaTime
resolutionStrategy.force dependencyOverrides.slf4j
// resolutionStrategy.force dependencyOverrides.jacksonDatabind
// resolutionStrategy.force dependencyOverrides.guava
// resolutionStrategy.force dependencyOverrides.findBugs
// resolutionStrategy.force dependencyOverrides.jaksonCore
}
implementation implLibraries.asciiDocJApi
implementation implLibraries.commonsText
implementation implLibraries.slf4j
testImplementation implLibraries.commonsIO
testImplementation testLibraries.asciiDocJ
testImplementation testLibraries.junit
testImplementation testLibraries.logback
}

View File

@@ -0,0 +1,887 @@
package io.github.swagger2markup.adoc;
import io.github.swagger2markup.adoc.converter.internal.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.asciidoctor.ast.List;
import org.asciidoctor.ast.*;
import org.asciidoctor.converter.ConverterFor;
import org.asciidoctor.converter.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import static io.github.swagger2markup.adoc.converter.internal.Delimiters.*;
@ConverterFor(AsciidocConverter.NAME)
public class AsciidocConverter extends StringConverter {
private Logger logger = LoggerFactory.getLogger(getClass());
public static final String NAME = "adoc";
private final Pattern emptyLineOrStartWith = Pattern.compile("(?m)^\\s*(?:\\r?\\n)|(?m)^\\s+");
private final Pattern coListItemIdPattern = Pattern.compile(".*-(\\d+)");
private final Pattern tableColumnsStylePattern = Pattern.compile("((\\d+)\\*)?([<^>])?(\\.[<^>])?(\\d+)?([adehlmsv])?");
private static final java.util.List<String> attributeToExclude = Arrays.asList(
"localtime",
"filetype",
"asciidoctor-version",
"doctime",
"localyear",
"docdate",
"localdate",
"localdatetime",
"docdatetime",
"backend",
"basebackend",
"doctitle",
"docyear"
);
private static final String[] supportedUrlSchemes = new String[]{
"http",
"https",
"ftp",
"irc",
"mailto"
};
public AsciidocConverter(String backend, Map<String, Object> opts) {
super(backend, opts);
}
/**
* Converts an {@link ContentNode} using the specified transform along
* with additional options. If a transform is not specified, implementations
* typically derive one from the {@link ContentNode#getNodeName()} property.
*
* <p>Implementations are free to decide how to carry out the conversion. In
* the case of the built-in converters, the tranform value is used to
* dispatch to a handler method. The TemplateConverter uses the value of
* the transform to select a template to render.
*
* @param node The concrete instance of FlowNode to convert
* @param transform An optional String transform that hints at which transformation
* should be applied to this node. If a transform is not specified,
* the transform is typically derived from the value of the
* node's node_name property. (optional, default: null)
* @param opts An optional map of options that provide additional hints about
* how to convert the node. (optional, default: empty map)
* @return the converted result
*/
@Override
public String convert(ContentNode node, String transform, Map<Object, Object> opts) {
if (null == transform) {
transform = node.getNodeName();
}
switch (transform) {
case "inline_quoted":
return convertInlineQuoted((PhraseNode) node);
case "paragraph":
return convertParagraph((StructuralNode) node);
case "inline_anchor":
return convertInlineAnchor((PhraseNode) node);
case "section":
return convertSection((Section) node);
case "listing":
return convertListing((Block) node);
case "literal":
return convertLiteral((StructuralNode) node);
case "ulist":
return convertUList((List) node);
case "olist":
return convertOList((List) node);
case "dlist":
return convertDescriptionList((DescriptionList) node);
case "admonition":
return convertAdmonition((Block) node);
case "colist":
return convertCoList((List) node);
case "embedded":
case "document":
return convertEmbedded((Document) node);
case "example":
return convertExample((Block) node);
case "floating_title":
return convertFloatingTitle((StructuralNode) node);
case "image":
return convertImage((StructuralNode) node);
case "inline_break":
return convertInlineBreak(node);
case "inline_button":
return convertInlineButton(node);
case "inline_callout":
return convertInlineCallout(node);
case "inline_footnote":
return convertInlineFootnote(node);
case "inline_image":
return convertInlineImage((PhraseNode) node);
case "inline_indexterm":
return convertInlineIndexTerm(node);
case "inline_kbd":
return convertInlineKbd(node);
case "inline_menu":
return convertInlineMenu(node);
case "open":
return convertOpen((StructuralNode) node);
case "page_break":
return convertPageBreak(node);
case "preamble":
return convertPreamble((StructuralNode) node);
case "quote":
return convertQuote((StructuralNode) node);
case "sidebar":
return convertSidebar((StructuralNode) node);
case "stem":
return convertStem(node);
case "table":
return convertTable((Table) node);
case "thematic_break":
return convertThematicBreak(node);
case "verse":
return convertVerse((StructuralNode) node);
case "video":
return convertVideo(node);
case "toc":
return convertToc(node);
case "pass":
return convertPass(node);
case "audio":
return convertAudio(node);
// didn't exist on html converter
case "list":
return convertList((List) node);
case "list_item":
return convertListItem((ListItem) node);
default:
logger.debug("Don't know how to convert transform: [" + transform + "] Node: " + node);
return null;
}
}
String convertEmbedded(Document node) {
logger.debug("convertEmbedded");
StringBuilder sb = new StringBuilder();
appendId(node, sb);
if (StringUtils.isNotBlank(node.getDoctitle())) {
sb.append(repeat(node.getLevel() + 1,DOCUMENT_TITLE)).append(' ').append(StringEscapeUtils.unescapeHtml4(node.getDoctitle())).append(LINE_SEPARATOR);
}
Map<String, Object> attributes = node.getAttributes();
appendAuthors(sb, attributes);
appendRevisionDetails(sb, attributes);
appendDocumentAttributes(sb, attributes);
appendTrailingNewLine(sb);
appendChildBlocks(node, sb);
return sb.toString();
}
private void appendAuthors(StringBuilder sb, Map<String, Object> attributes) {
Long authorCount = (Long) attributes.getOrDefault("authorcount", 0L);
if (authorCount == 1) {
String author = getAuthorDetail(attributes, "author", "email");
if (StringUtils.isNotBlank(author)) {
sb.append(author).append(LINE_SEPARATOR);
}
} else if (authorCount > 1) {
String authors = LongStream.rangeClosed(1, authorCount)
.mapToObj(i -> getAuthorDetail(attributes, "author_" + i, "email_" + i))
.collect(Collectors.joining("; "));
if (StringUtils.isNotBlank(authors)) {
sb.append(authors).append(LINE_SEPARATOR);
}
}
}
private void appendDocumentAttributes(StringBuilder sb, Map<String, Object> attributes) {
attributes.forEach((k, v) -> {
if (!attributeToExclude.contains(k) && v != null && !v.toString().isEmpty())
sb.append(COLON).append(k).append(COLON).append(" ").append(v).append(LINE_SEPARATOR);
});
}
private void appendRevisionDetails(StringBuilder sb, Map<String, Object> attributes) {
String revDetails = Stream.of(attributes.get("revnumber"), attributes.get("revdate")).filter(Objects::nonNull)
.filter(o -> !o.toString().isEmpty()).map(Object::toString)
.collect(Collectors.joining(", "));
if (!revDetails.isEmpty()) {
sb.append("v").append(revDetails).append(LINE_SEPARATOR);
}
}
private String getAuthorDetail(Map<String, Object> attributes, String authorKey, String emailKey) {
String author = attributes.getOrDefault(authorKey, "").toString();
String email = attributes.getOrDefault(emailKey, "").toString();
if (StringUtils.isNotBlank(email)) {
email = " <" + email + ">";
}
return (author + email).trim();
}
private String convertInlineAnchor(PhraseNode node) {
logger.debug("convertInlineAnchor");
String type = node.getType();
switch (type) {
case "xref": {
String attrs;
String text;
String path = Optional.ofNullable(node.getAttributes().get("path")).orElse("").toString();
if (StringUtils.isNotBlank(path)) {
ArrayList<String> list = new ArrayList<>();
if (StringUtils.isNotBlank(node.getRole())) {
list.add(" class=\"#{node.role}\"");
}
append_link_constraint_attrs(node, list);
attrs = String.join(" ", list);
text = StringUtils.isNotBlank(node.getText()) ? node.getText() : path;
} else {
attrs = StringUtils.isNotBlank(node.getRole()) ? " class=\"" + node.getRole() + "\"" : "";
text = node.getText();
if (StringUtils.isNotBlank(text)) {
text = node.getAttributes().get("refid").toString();
}
}
return node.getTarget() + ATTRIBUTES_BEGIN + text + (StringUtils.isNotBlank(attrs) ? "," + attrs : "") + ATTRIBUTES_END;
}
case "ref":
return node.getId();
case "link": {
ArrayList<String> attrs = new ArrayList<>();
String target = node.getTarget();
String includePrefix = !StringUtils.startsWithAny(target, supportedUrlSchemes) ? "include::" : "";
String text = node.getText();
if (!target.equals(text)) {
attrs.add(text);
}
if (StringUtils.isNotBlank(node.getId())) {
attrs.add("id=\"" + node.getId() + "\"");
}
String role = node.getRole();
if (StringUtils.isNotBlank(role) && !role.equals("bare")) {
attrs.add("role=\"" + role + "\"");
}
String title = node.getAttribute("title", "").toString();
if (StringUtils.isNotBlank(title)) {
attrs.add("title=\"" + title + "\"");
}
return includePrefix + target + ATTRIBUTES_BEGIN + String.join(",", attrs) + ATTRIBUTES_END;
}
case "bibref":
return node.getId() + ATTRIBUTES_BEGIN + (StringUtils.isNotBlank(node.getReftext()) ? node.getReftext() : node.getId()) + ATTRIBUTES_END;
default:
logger.warn("unknown anchor type: " + node.getType());
return null;
}
}
private String convertAdmonition(Block node) {
logger.debug("convertAdmonition");
StringBuilder sb = new StringBuilder();
java.util.List<StructuralNode> blocks = node.getBlocks();
if (blocks.isEmpty()) {
sb.append(node.getStyle()).append(": ").append(node.getSource());
} else {
appendTitle(node, sb);
sb.append(ATTRIBUTES_BEGIN).append(node.getStyle()).append(ATTRIBUTES_END)
.append(LINE_SEPARATOR).append(DELIMITER_EXAMPLE).append(LINE_SEPARATOR);
appendChildBlocks(node, sb);
sb.append(DELIMITER_EXAMPLE).append(LINE_SEPARATOR);
}
return sb.toString();
}
private String convertInlineQuoted(PhraseNode node) {
logger.debug("convertInlineQuoted");
StringBuilder sb = new StringBuilder();
String marker = "";
switch (node.getType()) {
case "monospaced":
marker = "`";
break;
case "emphasis":
marker = "_";
break;
case "strong":
marker = "*";
break;
case "superscript":
marker = "^";
break;
case "subscript":
marker = "~";
break;
case "double":
case "single":
case "mark":
case "asciimath":
case "latexmath":
marker = "";
break;
}
sb.append(marker).append(node.getText()).append(marker);
return sb.toString();
}
private String convertFloatingTitle(StructuralNode node) {
logger.debug("convertFloatingTitle");
return ATTRIBUTES_BEGIN + "discrete" + ATTRIBUTES_END + LINE_SEPARATOR +
repeat(node.getLevel() + 1, TITLE) + ' ' + node.getTitle() + LINE_SEPARATOR;
}
private String convertExample(Block node) {
logger.debug("convertExample");
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
sb.append(DELIMITER_EXAMPLE).append(LINE_SEPARATOR);
appendChildBlocks(node, sb);
sb.append(DELIMITER_EXAMPLE).append(LINE_SEPARATOR);
return sb.toString();
}
private String convertInlineButton(ContentNode node) {
logger.debug("convertInlineButton: name" + node.getNodeName());
return "convertInlineButton";
}
private String convertInlineCallout(ContentNode node) {
logger.debug("convertInlineCallout: name" + node.getNodeName());
return "convertInlineCallout";
}
private String convertInlineBreak(ContentNode node) {
logger.debug("convertInlineBreak: name" + node.getNodeName());
return "convertInlineBreak";
}
private String convertInlineFootnote(ContentNode node) {
logger.debug("convertInlineFootnote: name" + node.getNodeName());
return "convertInlineFootnote";
}
private String convertInlineImage(PhraseNode node) {
logger.debug("convertInlineImage");
if (node.getType().equals("icon")) {
return (new IconNode(node)).toAsciiDocContent();
} else {
return (new BlockImageNode(node)).toAsciiDocContent();
}
}
private String convertInlineIndexTerm(ContentNode node) {
logger.debug("convertInlineIndexTerm: name" + node.getNodeName());
return "convertInlineIndexTerm";
}
private String convertInlineKbd(ContentNode node) {
logger.debug("convertInlineKbd: name" + node.getNodeName());
return "convertInlineKbd";
}
private String convertInlineMenu(ContentNode node) {
logger.debug("convertInlineMenu: name" + node.getNodeName());
return "convertInlineMenu";
}
private String convertOpen(StructuralNode node) {
logger.debug("convertOpen");
StringBuilder sb = new StringBuilder();
switch (node.getStyle()) {
case "abstract":
sb.append(ATTRIBUTES_BEGIN).append("abstract").append(ATTRIBUTES_END).append(LINE_SEPARATOR);
break;
case "open":
sb.append(DELIMITER_OPEN_BLOCK).append(LINE_SEPARATOR);
}
sb.append(Optional.ofNullable(((Block) node).getSource()).orElse(""));
appendChildBlocks(node, sb);
if ("open".equals(node.getStyle())) {
sb.append(DELIMITER_OPEN_BLOCK).append(LINE_SEPARATOR);
}
return sb.toString();
}
private String convertPageBreak(ContentNode node) {
logger.debug("convertPageBreak: name" + node.getNodeName());
return DELIMITER_PAGE_BREAK + LINE_SEPARATOR;
}
private String convertQuote(StructuralNode node) {
logger.debug("convertQuote");
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
sb.append(ATTRIBUTES_BEGIN);
java.util.List<String> attrs = new ArrayList<>();
if (StringUtils.isNotBlank(node.getStyle())) {
attrs.add("quote");
}
appendAttributeTo(node, attrs, "attribution");
appendAttributeTo(node, attrs, "citetitle");
sb.append(String.join(",", attrs)).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
java.util.List<StructuralNode> blocks = node.getBlocks();
if (!blocks.isEmpty()) {
sb.append("____").append(LINE_SEPARATOR);
appendChildBlocks(node, sb);
sb.append("____").append(LINE_SEPARATOR);
} else {
sb.append(((Block) node).getSource());
}
return sb.toString();
}
private String convertSidebar(StructuralNode node) {
logger.debug("convertSidebar");
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
appendChildBlocks(node, sb);
return sb.toString();
}
private String convertStem(ContentNode node) {
logger.debug("convertStem: name" + node.getNodeName());
return "convertStem";
}
private String convertThematicBreak(ContentNode node) {
logger.debug("convertThematicBreak: name" + node.getNodeName());
return DELIMITER_THEMATIC_BREAK + LINE_SEPARATOR;
}
private String convertVerse(StructuralNode node) {
logger.debug("convertVerse");
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
sb.append(ATTRIBUTES_BEGIN);
java.util.List<String> attrs = new ArrayList<>();
if (StringUtils.isNotBlank(node.getStyle())) {
attrs.add("verse");
}
appendAttributeTo(node, attrs, "attribution");
appendAttributeTo(node, attrs, "citetitle");
sb.append(String.join(",", attrs)).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
String source = ((Block) node).getSource();
boolean matches = emptyLineOrStartWith.matcher(source).find();
if (matches) {
sb.append(DELIMITER_VERSE).append(LINE_SEPARATOR);
}
sb.append(source);
if (matches) {
sb.append(LINE_SEPARATOR).append(DELIMITER_VERSE);
}
appendTrailingNewLine(sb);
return sb.toString();
}
private String convertVideo(ContentNode node) {
logger.debug("convertVideo: name" + node.getNodeName());
return "convertVideo";
}
private String convertToc(ContentNode node) {
logger.debug("convertToc: name" + node.getNodeName());
return "convertToc";
}
private String convertPass(ContentNode node) {
logger.debug("convertPass: name" + node.getNodeName());
return "convertPass";
}
private String convertAudio(ContentNode node) {
logger.debug("convertAudio: name" + node.getNodeName());
return "convertAudio";
}
private String convertCell(Cell node) {
logger.debug("convertCell");
StringBuilder sb = new StringBuilder();
String source = node.getSource();
if (StringUtils.isNotBlank(source)) {
sb.append(source);
}
Document innerDocument = node.getInnerDocument();
if (null != innerDocument) {
appendChildBlocks(innerDocument, sb, false);
}
return sb.toString().replaceAll(LINE_SEPARATOR + LINE_SEPARATOR + "+", LINE_SEPARATOR + LINE_SEPARATOR);
}
private String convertRow(Row node, java.util.List<TableCellStyle> columnStyles, String delimiterTableCell) {
logger.debug("convertRow");
StringBuilder sb = new StringBuilder();
node.getCells().forEach(cell -> {
boolean addNewLine = false;
int colspan = cell.getColspan();
if (colspan != 0) {
addNewLine = true;
sb.append(colspan).append('+');
}
int rowspan = cell.getRowspan();
if (rowspan != 0) {
addNewLine = true;
sb.append('.').append(rowspan).append('+');
}
int index = cell.getColumn().getColumnNumber() - 1;
TableCellStyle tableCellStyle = (columnStyles.size() > index) ? columnStyles.get(index) : null;
boolean hAlignmentAdded = false;
TableCellHorizontalAlignment hAlignment = TableCellHorizontalAlignment.fromName(cell.getHorizontalAlignment().name());
if ((null != hAlignment) && (null == tableCellStyle || hAlignment != tableCellStyle.horizontalAlignment)) {
hAlignmentAdded = true;
addNewLine = true;
sb.append(hAlignment.getDelimiter());
}
TableCellVerticalAlignment vAlignment = TableCellVerticalAlignment.fromName(cell.getVerticalAlignment().name());
if ((null != vAlignment) && (null == tableCellStyle || hAlignmentAdded || vAlignment != tableCellStyle.verticalAlignment)) {
addNewLine = true;
sb.append(vAlignment.getDelimiter());
}
Style style = Style.fromName(cell.getAttribute("style", "").toString());
if (null != style && (null == tableCellStyle || style != tableCellStyle.style)) {
addNewLine = true;
sb.append(style.getShortHand());
}
sb.append(delimiterTableCell).append(convertCell(cell));
if (addNewLine) {
sb.append(LINE_SEPARATOR);
} else {
sb.append(' ');
}
});
return sb.toString();
}
private String convertTable(Table node) {
logger.debug("convertTable");
java.util.List<TableCellStyle> columnStyles = new ArrayList<>();
for (String col : node.getAttribute("cols", "").toString().split(",")) {
Matcher matcher = tableColumnsStylePattern.matcher(col);
if (matcher.find()) {
int multiplier = 1;
String multiplierGroup = matcher.group(2);
if (null != multiplierGroup) {
try {
multiplier = Integer.parseInt(multiplierGroup);
} catch (NumberFormatException ignored) {
}
}
int width = 0;
try {
width = Integer.parseInt(matcher.group(5));
} catch (NumberFormatException ignored) {
}
TableCellStyle tableCellStyle = new TableCellStyle(
TableCellHorizontalAlignment.fromString(matcher.group(3)),
TableCellVerticalAlignment.fromString(matcher.group(4)),
Style.fromString(matcher.group(6)),
width
);
for (int i = 0; i < multiplier; i++) {
columnStyles.add(tableCellStyle);
}
}
}
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
sb.append(new TableNode(node).toAsciiDocContent());
boolean innerTable = isInnerTable(node);
String tableDelimiter = innerTable ? DELIMITER_INNER_TABLE : DELIMITER_TABLE;
String cellDelimiter = innerTable ? DELIMITER_INNER_TABLE_CELL : DELIMITER_TABLE_CELL;
sb.append(tableDelimiter).append(LINE_SEPARATOR);
appendRows(node.getHeader(), sb, columnStyles, cellDelimiter);
appendRows(node.getBody(), sb, columnStyles, cellDelimiter);
appendRows(node.getFooter(), sb, columnStyles, cellDelimiter);
sb.append(tableDelimiter).append(LINE_SEPARATOR);
return sb.toString();
}
private boolean isInnerTable(ContentNode node) {
if(null != node) {
ContentNode parent = node.getParent();
if (null != parent) {
return parent instanceof Table || isInnerTable(parent);
}
}
return false;
}
private void appendRows(java.util.List<Row> rows, StringBuilder sb, java.util.List<TableCellStyle> columnStyles, String delimiterTableCell) {
rows.forEach(row -> sb.append(convertRow(row, columnStyles, delimiterTableCell)).append(LINE_SEPARATOR));
}
private String convertDescriptionList(DescriptionList node) {
logger.debug("convertDescriptionList");
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
String style = Optional.ofNullable(node.getStyle()).orElse("");
switch (style) {
case STYLE_HORIZONTAL:
sb.append(ATTRIBUTES_BEGIN).append(STYLE_HORIZONTAL).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
node.getItems().forEach(item -> sb.append(convertDescriptionListEntry(item, node.getLevel(), false)));
break;
case STYLE_Q_AND_A:
sb.append(ATTRIBUTES_BEGIN).append(STYLE_Q_AND_A).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
default:
node.getItems().forEach(item -> sb.append(convertDescriptionListEntry(item, node.getLevel(), true)));
break;
}
appendTrailingNewLine(sb);
return sb.toString();
}
private String convertDescriptionListEntry(DescriptionListEntry node, int level, Boolean descriptionOnNewLine) {
logger.debug("convertDescriptionListEntry");
StringBuilder sb = new StringBuilder();
String delimiter = repeat(level + 1, MARKER_D_LIST_ITEM);
String entryTerms = node.getTerms().stream()
.map(term -> Optional.ofNullable(term.getSource()).orElse(""))
.collect(Collectors.joining(delimiter + LINE_SEPARATOR, "", delimiter));
sb.append(entryTerms);
ListItem description = node.getDescription();
if (null != description) {
if (descriptionOnNewLine) {
sb.append(LINE_SEPARATOR);
}
String desc = Optional.ofNullable(description.getSource()).orElse("");
if (StringUtils.isNotBlank(desc)) {
sb.append(desc).append(LINE_SEPARATOR);
}
appendChildBlocks(description, sb);
}
return sb.toString();
}
private String convertListing(Block node) {
logger.debug("convertListing");
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
if (STYLE_SOURCE.equals(node.getStyle())) {
sb.append(new SourceNode(node).toAsciiDocContent());
} else {
sb.append(new BlockListingNode(node).toAsciiDocContent());
}
return sb.toString();
}
private String convertUList(List node) {
logger.debug("convertUList");
StringBuilder sb = new StringBuilder();
appendStyle(node, sb);
appendTitle(node, sb);
appendChildBlocks(node, sb);
appendTrailingNewLine(sb);
return sb.toString();
}
private String convertOList(List node) {
logger.debug("convertOList");
StringBuilder sb = new StringBuilder();
java.util.List<String> attrs = new ArrayList<>();
String start = node.getAttribute("start", "").toString();
if (StringUtils.isNotBlank(start)) {
attrs.add("start=" + start);
}
if (node.isOption("reversed")) {
attrs.add("%reversed");
}
if (!attrs.isEmpty()) {
sb.append(ATTRIBUTES_BEGIN).append(String.join(",", attrs)).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
}
appendTitle(node, sb);
appendChildBlocks(node, sb);
appendTrailingNewLine(sb);
return sb.toString();
}
private String convertCoList(List node) {
logger.debug("convertCoList");
StringBuilder result = new StringBuilder();
appendChildBlocks(node, result);
return result.toString();
}
private String convertListItem(ListItem node) {
logger.debug("convertListItem");
StringBuilder sb = new StringBuilder();
String marker = Optional.ofNullable(node.getMarker()).orElse(repeat(node.getLevel(), MARKER_LIST_ITEM));
String coids = node.getAttribute("coids", "").toString();
Matcher matcher = coListItemIdPattern.matcher(coids);
if (matcher.find()) {
marker = marker.replaceAll("\\d+", matcher.group(1));
}
sb.append(marker).append(" ");
if (node.hasAttribute("checkbox")) {
sb.append('[');
if (node.hasAttribute("checked")) {
sb.append('x');
} else {
sb.append(' ');
}
sb.append(']').append(' ');
}
sb.append(Optional.ofNullable(node.getSource()).orElse(""));
appendTrailingNewLine(sb);
appendChildBlocks(node, sb);
return sb.toString();
}
private String convertList(List node) {
logger.debug("convertList");
return node.getContent().toString();
}
private String convertPreamble(StructuralNode node) {
logger.debug("convertPreamble");
return node.getContent().toString();
}
private String convertImage(StructuralNode node) {
logger.debug("convertImage");
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
appendRoles(node, sb);
sb.append(new BlockImageNode(node).toAsciiDocContent());
return sb.toString();
}
private String convertLiteral(StructuralNode node) {
logger.debug("convertLiteral");
return ATTRIBUTES_BEGIN + node.getContext() + ATTRIBUTES_END + LINE_SEPARATOR +
StringEscapeUtils.unescapeHtml4(node.getContent().toString()) + LINE_SEPARATOR;
}
private String convertParagraph(StructuralNode node) {
logger.debug("convertParagraph");
StringBuilder sb = new StringBuilder();
appendTitle(node, sb);
sb.append(new ParagraphAttributes(node).toAsciiDocContent());
appendSource((Block) node, sb);
appendTrailingNewLine(sb);
return sb.toString();
}
private String convertSection(Section node) {
logger.debug("convertSection");
StringBuilder sb = new StringBuilder();
appendId(node, sb);
sb.append(new DelimitedBlockNode(node).toAsciiDocContent()).append(StringUtils.repeat(TITLE, node.getLevel() + 1))
.append(" ").append(StringEscapeUtils.unescapeHtml4(node.getTitle())).append(LINE_SEPARATOR);
appendChildBlocks(node, sb);
appendTrailingNewLine(sb);
return sb.toString();
}
private void append_link_constraint_attrs(ContentNode node, java.util.List<String> attrs) {
String rel = node.getAttribute("nofollow-option").toString();
String window = node.getAttributes().get("window").toString();
if (StringUtils.isNotBlank(window)) {
attrs.add("target = \"#{window}\"");
if (window.equals("_blank") || (node.getAttributes().containsKey("option-noopener"))) {
if (StringUtils.isNotBlank(rel)) {
attrs.add("rel = \"" + rel + "noopener\"");
} else {
attrs.add(" rel=\"noopener\"");
}
}
} else if (StringUtils.isNotBlank(rel)) {
attrs.add("rel = " + rel + "\"");
}
}
private String repeat(int count, String with) {
return new String(new char[count]).replace("\0", with);
}
private void appendChildBlocks(StructuralNode parentNode, StringBuilder sb) {
appendChildBlocks(parentNode, sb, true);
}
private void appendChildBlocks(StructuralNode parentNode, StringBuilder sb, boolean addTrailingLineSeparator) {
final boolean isParentAListItem = parentNode instanceof ListItem || parentNode instanceof DescriptionListEntry;
parentNode.getBlocks().forEach(childNode -> {
String childNodeValue = childNode.convert();
if (StringUtils.isNotBlank(childNodeValue)) {
if (isParentAListItem && (sb.toString().contains("+" + LINE_SEPARATOR) || !(childNode instanceof List || childNode instanceof DescriptionList))) {
sb.append('+').append(LINE_SEPARATOR);
}
sb.append(childNodeValue);
if (addTrailingLineSeparator && !StringUtils.endsWith(childNodeValue, LINE_SEPARATOR)) {
sb.append(LINE_SEPARATOR);
}
}
});
}
private void appendTrailingNewLine(StringBuilder sb) {
if (!sb.toString().endsWith(LINE_SEPARATOR + LINE_SEPARATOR)) {
sb.append(LINE_SEPARATOR);
}
}
private void appendId(StructuralNode node, StringBuilder sb) {
String id = node.getId();
if (StringUtils.isNotBlank(id)) {
sb.append("[[").append(id).append("]]").append(LINE_SEPARATOR);
}
}
private void appendSource(Block node, StringBuilder sb) {
String source = node.getSource();
if (StringUtils.isNotBlank(source)) {
sb.append(source).append(LINE_SEPARATOR);
}
}
private void appendTitle(StructuralNode node, StringBuilder sb) {
String title = node.getTitle();
if (StringUtils.isNotBlank(title)) {
sb.append(".").append(StringEscapeUtils.unescapeHtml4(title)).append(LINE_SEPARATOR);
}
}
private void appendStyle(StructuralNode node, StringBuilder sb) {
String style = node.getStyle();
if (StringUtils.isNotBlank(style)) {
sb.append(ATTRIBUTES_BEGIN).append(style).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
}
}
private void appendRoles(StructuralNode node, StringBuilder sb) {
java.util.List<String> roles = node.getRoles();
if (!roles.isEmpty()) {
sb.append(ATTRIBUTES_BEGIN).append(".").append(String.join(".", roles))
.append(ATTRIBUTES_END).append(LINE_SEPARATOR);
}
}
private void appendAttributeTo(StructuralNode node, java.util.List<String> attrs, String name) {
String attribution = node.getAttribute(name, "").toString();
if (StringUtils.isNotBlank(attribution)) {
attrs.add(attribution);
}
}
}

View File

@@ -0,0 +1,70 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.Block;
import org.asciidoctor.ast.StructuralNode;
import java.util.*;
public class BlockImpl extends StructuralNodeImpl implements Block {
private List<String> lines;
public BlockImpl(StructuralNode parent, String context) {
this(parent, context, "");
}
public BlockImpl(StructuralNode parent, String context, Object content) {
this(parent, context, new HashMap<>(), content);
}
public BlockImpl(StructuralNode parent, String context, Map<String, Object> attributes) {
this(parent, context, attributes, "");
}
public BlockImpl(StructuralNode parent, String context, Map<String, Object> attributes, Object content) {
this(parent, context, attributes, new ArrayList<>(), content, new ArrayList<>(), "", new ArrayList<>());
}
public BlockImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, String contentModel, List<String> subs) {
this(parent, context, attributes, roles, content, blocks, calculateLevel(parent), contentModel, subs);
}
public BlockImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level, String contentModel, List<String> subs) {
super(parent, context, attributes, roles, content, blocks, level, contentModel, subs);
this.lines = new ArrayList<>();
}
@Override
@Deprecated
public List<String> lines() {
return getLines();
}
@Override
public List<String> getLines() {
return lines;
}
@Override
public void setLines(List<String> lines) {
this.lines = lines;
}
@Override
@Deprecated
public String source() {
return getSource();
}
@Override
public String getSource() {
return String.join("\n", lines);
}
@Override
public void setSource(String source) {
setLines(Arrays.asList(source.split("\n")));
}
}

View File

@@ -0,0 +1,112 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.Cell;
import org.asciidoctor.ast.Column;
import org.asciidoctor.ast.Document;
import org.asciidoctor.ast.Table;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CellImpl extends ContentNodeImpl implements Cell {
private final int colspan;
private final int rowspan;
private String text;
private String style;
private Document innerDocument;
public CellImpl(Column parent, String text) {
this(parent, "table_cell", new HashMap<>(), new ArrayList<>(), 0, 0);
this.text = text;
}
public CellImpl(Column parent, Document innerDocument) {
this(parent, "table_cell", new HashMap<>(), new ArrayList<>(), 0, 0);
this.innerDocument = innerDocument;
}
public CellImpl(Column parent, String context, Map<String, Object> attributes, List<String> roles, int colspan, int rowspan) {
super(parent, context, attributes, roles);
this.colspan = colspan;
this.rowspan = rowspan;
}
@Override
public Column getColumn() {
return (Column) getParent();
}
@Override
public int getColspan() {
return colspan;
}
@Override
public int getRowspan() {
return rowspan;
}
@Override
public String getText() {
return text;
}
@Override
public String getSource() {
return text;
}
@Override
public void setSource(String source) {
this.text = source;
}
@Override
public Object getContent() {
return text;
}
@Override
public String getStyle() {
return style;
}
@Override
public void setStyle(String style) {
this.style = style;
}
@Override
public Table.HorizontalAlignment getHorizontalAlignment() {
return Table.HorizontalAlignment.valueOf(((String) getAttribute("halign", "left")).toUpperCase());
}
@Override
public void setHorizontalAlignment(Table.HorizontalAlignment halign) {
setAttribute("halign", halign.name().toLowerCase(), true);
}
@Override
public Table.VerticalAlignment getVerticalAlignment() {
return Table.VerticalAlignment.valueOf(((String) getAttribute("valign", "top")).toUpperCase());
}
@Override
public void setVerticalAlignment(Table.VerticalAlignment valign) {
setAttribute("valign", valign.name().toLowerCase(), true);
}
@Override
public Document getInnerDocument() {
return innerDocument;
}
@Override
public void setInnerDocument(Document document) {
this.innerDocument = document;
}
}

View File

@@ -0,0 +1,81 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.Column;
import org.asciidoctor.ast.Table;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ColumnImpl extends ContentNodeImpl implements Column {
private String style;
private Number columnNumber = -1;
private Number width = 0;
public ColumnImpl(Table parent) {
this(parent, "table_column", new HashMap<>(), new ArrayList<>());
}
public ColumnImpl(Table parent, String context, Map<String, Object> attributes, List<String> roles) {
super(parent, context, attributes, roles);
}
@Override
public String getStyle() {
return style;
}
@Override
public void setStyle(String style) {
this.style = style;
}
@Override
public Table getTable() {
return (Table) getParent();
}
@Override
public int getColumnNumber() {
return columnNumber.intValue();
}
public void setColumnNumber(Integer columnNumber) {
setAttribute("colnumber", columnNumber, true);
this.columnNumber = columnNumber;
}
@Override
public int getWidth() {
return width.intValue();
}
@Override
public void setWidth(int width) {
setAttribute("width", width, true);
this.width = width;
}
@Override
public Table.HorizontalAlignment getHorizontalAlignment() {
return Table.HorizontalAlignment.valueOf(((String) getAttribute("halign", "left")).toUpperCase());
}
@Override
public void setHorizontalAlignment(Table.HorizontalAlignment halign) {
setAttribute("halign", halign.name().toLowerCase(), true);
}
@Override
public Table.VerticalAlignment getVerticalAlignment() {
return Table.VerticalAlignment.valueOf(((String) getAttribute("valign", "top")).toUpperCase());
}
@Override
public void setVerticalAlignment(Table.VerticalAlignment valign) {
setAttribute("valign", valign.name().toLowerCase(), true);
}
}

View File

@@ -0,0 +1,309 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.ContentNode;
import org.asciidoctor.ast.Document;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SuppressWarnings("SuspiciousMethodCalls")
public abstract class ContentNodeImpl implements ContentNode {
private String id;
private final String context;
private final Map<String, Object> attributes;
private final List<String> roles;
private final ContentNode parent;
public ContentNodeImpl(ContentNode parent, String context) {
this(parent, context, new HashMap<>(), new ArrayList<>());
}
public ContentNodeImpl(ContentNode parent, String context, Map<String, Object> attributes, List<String> roles) {
this.parent = parent;
this.context = context;
this.attributes = attributes;
this.roles = roles;
}
@Override
@Deprecated
public String id() {
return getId();
}
@Override
public String getId() {
return id;
}
@Override
public void setId(String id) {
this.id = id.toLowerCase().replaceAll("\\s+", "_");
}
@Override
@Deprecated
public String context() {
return getContext();
}
@Override
public String getContext() {
return context;
}
@Override
@Deprecated
public ContentNode parent() {
return getParent();
}
@Override
public ContentNode getParent() {
return parent;
}
@Override
@Deprecated
public Document document() {
return getDocument();
}
@Override
public Document getDocument() {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String getNodeName() {
return getContext();
}
@Override
public boolean isInline() {
return false;
}
@Override
public boolean isBlock() {
return false;
}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
@Override
@Deprecated
public Object getAttr(Object name, Object defaultValue, boolean inherit) {
return getAttribute(name, defaultValue, inherit);
}
@Override
@Deprecated
public Object getAttr(Object name, Object defaultValue) {
return getAttribute(name, defaultValue);
}
@Override
@Deprecated
public Object getAttr(Object name) {
return getAttribute(name);
}
@Override
public Object getAttribute(Object name, Object defaultValue, boolean inherit) {
return getAttribute(name, defaultValue);
}
@Override
public Object getAttribute(Object name, Object defaultValue) {
return attributes.getOrDefault(name, defaultValue);
}
@Override
public Object getAttribute(Object name) {
return attributes.get(name);
}
@Override
@Deprecated
public boolean isAttr(Object name, Object expected, boolean inherit) {
return isAttribute(name, expected, inherit);
}
@Override
@Deprecated
public boolean isAttr(Object name, Object expected) {
return isAttribute(name, expected);
}
@Override
public boolean isAttribute(Object name, Object expected, boolean inherit) {
return isAttribute(name, expected);
}
@Override
public boolean isAttribute(Object name, Object expected) {
try {
if (attributes.containsKey(name)) {
return attributes.get(name).equals(expected);
} else return false;
} catch (Exception e) {
return false;
}
}
@Override
@Deprecated
public boolean hasAttr(Object name) {
return hasAttribute(name);
}
@Override
@Deprecated
public boolean hasAttr(Object name, boolean inherited) {
return hasAttribute(name, inherited);
}
@Override
public boolean hasAttribute(Object name) {
return attributes.containsKey(name);
}
@Override
public boolean hasAttribute(Object name, boolean inherited) {
return hasAttribute(name);
}
@Override
@Deprecated
public boolean setAttr(Object name, Object value, boolean overwrite) {
return setAttribute(name, value, overwrite);
}
@Override
public boolean setAttribute(Object name, Object value, boolean overwrite) {
return setAttribute((String)name, value, overwrite);
}
public boolean setAttribute(String name, Object value, boolean overwrite) {
try {
if (overwrite) {
attributes.put(name, value);
} else {
attributes.putIfAbsent(name, value);
}
return true;
} catch (Exception e) {
return false;
}
}
public Object removeAttribute(String name){
return attributes.remove(name);
}
public boolean removeAttribute(String name, Object value){
return attributes.remove(name, value);
}
@Override
public boolean isOption(Object name) {
try {
Object o = attributes.get(name + "-option");
return null != o && o.toString().equals("");
}catch (Exception ignored){
return false;
}
}
public boolean setOption(String name){
return setAttribute(name + "-option", "", true);
}
public Object removeOption(String name){
return removeAttribute(name + "-option");
}
@Override
public boolean isRole() {
return false;
}
@Override
public String getRole() {
return String.join(",", roles);
}
@Override
@Deprecated
public String role() {
return getRole();
}
@Override
public List<String> getRoles() {
return roles;
}
@Override
public boolean hasRole(String role) {
return roles.contains(role);
}
@Override
public void addRole(String role) {
roles.add(role);
}
@Override
public void removeRole(String role) {
roles.remove(role);
}
@Override
public boolean isReftext() {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String getReftext() {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String iconUri(String name) {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String mediaUri(String target) {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String imageUri(String targetImage) {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String imageUri(String targetImage, String assetDirKey) {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String readAsset(String path, Map<Object, Object> opts) {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String normalizeWebPath(String path, String start, boolean preserveUriTarget) {
throw new UnsupportedOperationException("Not implemented, yet");
}
}

View File

@@ -0,0 +1,36 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.Cursor;
public class CursorImpl implements Cursor {
private int lineno;
public CursorImpl() {
}
@Override
public int getLineNumber() {
return lineno;
}
@Override
public String getPath() {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String getDir() {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String getFile() {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public String toString() {
throw new UnsupportedOperationException("Not implemented, yet");
}
}

View File

@@ -0,0 +1,66 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.DescriptionListEntry;
import org.asciidoctor.ast.ListItem;
import org.asciidoctor.ast.StructuralNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DescriptionListEntryImpl extends StructuralNodeImpl implements DescriptionListEntry {
private final List<ListItem> terms;
private ListItem description;
public DescriptionListEntryImpl(StructuralNode parent) {
this(parent, new ArrayList<>());
}
public DescriptionListEntryImpl(StructuralNode parent, List<ListItem> terms) {
this(parent, terms, null);
}
public DescriptionListEntryImpl(StructuralNode parent, List<ListItem> terms, ListItem description) {
this(parent, null, terms, description);
}
public DescriptionListEntryImpl(StructuralNode parent, Object content, List<ListItem> terms, ListItem description) {
this(parent, new HashMap<>(), new ArrayList<>(), content, new ArrayList<>(), "", new ArrayList<>(), terms, description);
}
public DescriptionListEntryImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, String contentModel, List<String> subs,
List<ListItem> terms, ListItem description) {
this(parent, attributes, roles, content, blocks, null != parent ? parent.getLevel() : 1, contentModel, subs, terms, description);
}
public DescriptionListEntryImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level, String contentModel,
List<String> subs, List<ListItem> terms, ListItem description) {
super(parent, "dlist_item", attributes, roles, content, blocks, level, contentModel, subs);
this.terms = terms;
this.description = description;
}
@Override
public List<ListItem> getTerms() {
return terms;
}
public boolean addTerm(ListItem term) {
return terms.add(term);
}
@Override
public ListItem getDescription() {
return description;
}
public void setDescription(final ListItem description) {
this.description = description;
}
}

View File

@@ -0,0 +1,72 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.DescriptionList;
import org.asciidoctor.ast.DescriptionListEntry;
import org.asciidoctor.ast.StructuralNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DescriptionListImpl extends StructuralNodeImpl implements DescriptionList {
public static final String CONTEXT = "dlist";
private List<DescriptionListEntry> items;
public DescriptionListImpl(StructuralNode parent) {
this(parent, new ArrayList<>());
}
public DescriptionListImpl(StructuralNode parent, List<DescriptionListEntry> items) {
this(parent, null, items);
}
public DescriptionListImpl(StructuralNode parent, Object content, List<DescriptionListEntry> items) {
this(parent, new HashMap<>(), new ArrayList<>(), content, new ArrayList<>(), "", new ArrayList<>(), items);
}
public DescriptionListImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, String contentModel,
List<String> subs, List<DescriptionListEntry> items) {
this(parent, attributes, roles, content, blocks, calculateLevel(parent), contentModel, subs, items);
}
public DescriptionListImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level,
String contentModel, List<String> subs, List<DescriptionListEntry> items) {
super(parent, CONTEXT, attributes, roles, content, blocks, level, contentModel, subs);
this.items = items;
}
@Override
public List<DescriptionListEntry> getItems() {
return items;
}
public void setItems(List<DescriptionListEntry> items) {
this.items = items;
}
public void addEntry(DescriptionListEntry entry) {
this.items.add(entry);
}
@Override
public boolean hasItems() {
return !items.isEmpty();
}
@Override
@Deprecated
public String render() {
return convert();
}
protected static Integer calculateLevel(StructuralNode parent) {
int level = 1;
if (parent instanceof DescriptionList)
level = parent.getLevel() + 1;
return level;
}
}

View File

@@ -0,0 +1,89 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.Document;
import org.asciidoctor.ast.StructuralNode;
import org.asciidoctor.ast.Title;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DocumentImpl extends StructuralNodeImpl implements Document {
public DocumentImpl() {
this(null);
}
public DocumentImpl(StructuralNode parent) {
this(parent, "document", "");
}
public DocumentImpl(StructuralNode parent, String context, Object content) {
this(parent, context, new HashMap<>(), new ArrayList<>(), content, new ArrayList<>(), "", new ArrayList<>());
}
public DocumentImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, String contentModel,
List<String> subs) {
this(parent, context, attributes, roles, content, blocks, null != parent ? parent.getLevel() + 1 : 0, contentModel, subs);
}
public DocumentImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level, String contentModel,
List<String> subs) {
super(parent, context, attributes, roles, content, blocks, level, contentModel, subs);
}
@Override
public boolean isBasebackend(String backend) {
return isAttribute("basebackend", backend);
}
@Override
@Deprecated
public boolean basebackend(String backend) {
return isBasebackend(backend);
}
@Override
public Map<Object, Object> getOptions() {
return null;
}
@Override
public Title getStructuredDoctitle() {
return (Title) getOptions().get("doctitle");
}
@Override
public String getDoctitle() {
return getTitle();
}
@Override
@Deprecated
public String doctitle() {
return getDoctitle();
}
@Override
public int getAndIncrementCounter(String name) {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public int getAndIncrementCounter(String name, int initialValue) {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public boolean isSourcemap() {
throw new UnsupportedOperationException("Not implemented, yet");
}
@Override
public void setSourcemap(boolean state) {
throw new UnsupportedOperationException("Not implemented, yet");
}
}

View File

@@ -0,0 +1,56 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.List;
import org.asciidoctor.ast.StructuralNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class ListImpl extends StructuralNodeImpl implements List {
private final java.util.List<StructuralNode> items;
public ListImpl(StructuralNode parent, String context) {
this(parent, context, new ArrayList<>());
}
public ListImpl(StructuralNode parent, String context, java.util.List<StructuralNode> items) {
this(parent, context, null, items);
}
public ListImpl(StructuralNode parent, String context, Object content, java.util.List<StructuralNode> items) {
this(parent, context, new HashMap<>(), new ArrayList<>(), content, new ArrayList<>(), "", new ArrayList<>(), items);
}
public ListImpl(StructuralNode parent, String context, Map<String, Object> attributes, java.util.List<String> roles,
Object content, java.util.List<StructuralNode> blocks,
String contentModel, java.util.List<String> subs, java.util.List<StructuralNode> items) {
this(parent, context, attributes, roles, content, blocks, null != parent ? parent.getLevel() + 1 : 0, contentModel, subs, items);
}
public ListImpl(StructuralNode parent, String context, Map<String, Object> attributes, java.util.List<String> roles,
Object content, java.util.List<StructuralNode> blocks,
Integer level, String contentModel, java.util.List<String> subs, java.util.List<StructuralNode> items) {
super(parent, context, attributes, roles, content, blocks, level, contentModel, subs);
this.items = items;
}
@Override
public java.util.List<StructuralNode> getItems() {
return items;
}
@Override
public boolean hasItems() {
return !items.isEmpty();
}
@Override
@Deprecated
public String render() {
return convert();
}
}

View File

@@ -0,0 +1,63 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.apache.commons.lang3.StringUtils;
import org.asciidoctor.ast.ListItem;
import org.asciidoctor.ast.StructuralNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ListItemImpl extends StructuralNodeImpl implements ListItem {
private final String marker;
private String text;
public ListItemImpl(StructuralNode parent, String text) {
this(parent, "list_item", null, "*", text);
}
public ListItemImpl(StructuralNode parent, String context, Object content, String marker, String text) {
this(parent, context, new HashMap<>(), new ArrayList<>(), content, new ArrayList<>(), "", new ArrayList<>(), marker, text);
}
public ListItemImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, String contentModel,
List<String> subs, String marker, String text) {
this(parent, context, attributes, roles, content, blocks, null != parent ? parent.getLevel() : 1, contentModel, subs, marker, text);
}
public ListItemImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level,
String contentModel, List<String> subs, String marker, String text) {
super(parent, context, attributes, roles, content, blocks, level, contentModel, subs);
this.marker = marker;
this.text = text;
}
@Override
public String getMarker() {
return marker;
}
@Override
public String getText() {
return text;
}
@Override
public String getSource() {
return text;
}
@Override
public void setSource(String source) {
this.text = source;
}
@Override
public boolean hasText() {
return StringUtils.isNotBlank(text);
}
}

View File

@@ -0,0 +1,38 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.StructuralNode;
import java.util.List;
import java.util.Map;
public class ParagraphBlockImpl extends BlockImpl {
public static final String CONTEXT = "paragraph";
public ParagraphBlockImpl(StructuralNode parent) {
super(parent, CONTEXT);
}
public ParagraphBlockImpl(StructuralNode parent, Object content) {
super(parent, CONTEXT, content);
}
public ParagraphBlockImpl(StructuralNode parent, Map<String, Object> attributes) {
super(parent, CONTEXT, attributes);
}
public ParagraphBlockImpl(StructuralNode parent, Map<String, Object> attributes, Object content) {
super(parent, CONTEXT, attributes, content);
}
public ParagraphBlockImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, String contentModel, List<String> subs) {
super(parent, CONTEXT, attributes, roles, content, blocks, contentModel, subs);
}
public ParagraphBlockImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level, String contentModel,
List<String> subs) {
super(parent, CONTEXT, attributes, roles, content, blocks, level, contentModel, subs);
}
}

View File

@@ -0,0 +1,50 @@
package io.github.swagger2markup.adoc.ast.impl;
import io.github.swagger2markup.adoc.AsciidocConverter;
import org.asciidoctor.ast.ContentNode;
import org.asciidoctor.ast.PhraseNode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PhraseNodeImpl extends ContentNodeImpl implements PhraseNode {
private final String type;
private final String text;
private final String target;
private final AsciidocConverter converter = new AsciidocConverter(AsciidocConverter.NAME, new HashMap<>());
public PhraseNodeImpl(ContentNode parent, String context, Map<String, Object> attributes, List<String> roles, String type, String text, String target) {
super(parent, context, attributes, roles);
this.type = type;
this.text = text;
this.target = target;
}
@Override
@Deprecated
public String render() {
return convert();
}
@Override
public String convert() {
return converter.convert(this, null, new HashMap<>());
}
@Override
public String getType() {
return type;
}
@Override
public String getText() {
return text;
}
@Override
public String getTarget() {
return target;
}
}

View File

@@ -0,0 +1,21 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.Cell;
import org.asciidoctor.ast.Row;
import java.util.List;
public class RowImpl implements Row {
private final List<Cell> cells;
public RowImpl(List<Cell> cells) {
this.cells = cells;
}
@Override
public List<Cell> getCells() {
return cells;
}
}

View File

@@ -0,0 +1,118 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.Section;
import org.asciidoctor.ast.StructuralNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SectionImpl extends StructuralNodeImpl implements Section {
private final Integer index;
private final Integer number;
private final String numeral;
private final String sectionName;
private final boolean special;
private final boolean numbered;
public SectionImpl(StructuralNode parent) {
this(parent, new HashMap<>());
}
public SectionImpl(StructuralNode parent, Map<String, Object> attributes) {
this(parent, "section", null, "");
}
public SectionImpl(StructuralNode parent, String context, Object content, String sectionName) {
this(parent, context, content, null, null, "", sectionName, false, false);
}
public SectionImpl(StructuralNode parent, String context, Object content, Integer index, Integer number, String numeral,
String sectionName, boolean special, boolean numbered) {
this(parent, context, new HashMap<>(), new ArrayList<>(), content, new ArrayList<>(),
"", new ArrayList<>(), index, number, numeral, sectionName, special, numbered);
}
public SectionImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, String contentModel, List<String> subs,
Integer index, Integer number, String numeral, String sectionName, boolean special, boolean numbered) {
this(parent, context, attributes, roles, content, blocks, calculateLevel(parent), contentModel, subs, index, number, numeral, sectionName, special, numbered);
}
public SectionImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level, String contentModel, List<String> subs,
Integer index, Integer number, String numeral, String sectionName, boolean special, boolean numbered) {
super(parent, context, attributes, roles, content, blocks, level, contentModel, subs);
this.index = index;
this.number = number;
this.numeral = numeral;
this.sectionName = sectionName;
this.special = special;
this.numbered = numbered;
}
@Override
@Deprecated
public int index() {
return getIndex();
}
@Override
public int getIndex() {
return index;
}
@Override
@Deprecated
public int number() {
return getNumber();
}
@Override
@Deprecated
public int getNumber() {
return number;
}
@Override
public String getNumeral() {
return numeral;
}
@Override
@Deprecated
public String sectname() {
return getSectionName();
}
@Override
public String getSectionName() {
return sectionName;
}
@Override
@Deprecated
public boolean special() {
return isSpecial();
}
@Override
public boolean isSpecial() {
return special;
}
@Override
@Deprecated
public boolean numbered() {
return isNumbered();
}
@Override
public boolean isNumbered() {
return numbered;
}
}

View File

@@ -0,0 +1,179 @@
package io.github.swagger2markup.adoc.ast.impl;
import io.github.swagger2markup.adoc.AsciidocConverter;
import org.asciidoctor.ast.Cursor;
import org.asciidoctor.ast.StructuralNode;
import java.util.*;
public class StructuralNodeImpl extends ContentNodeImpl implements StructuralNode {
private String title;
private String caption;
private String style;
private final Object content;
private final List<StructuralNode> blocks;
private Integer level;
private final String contentModel;
private List<String> subs;
private final AsciidocConverter converter = new AsciidocConverter(AsciidocConverter.NAME, new HashMap<>());
public StructuralNodeImpl(StructuralNode parent, String context) {
this(parent, context, new HashMap<>());
}
public StructuralNodeImpl(StructuralNode parent, String context, Map<String, Object> attributes) {
this(parent, context, attributes, null);
}
public StructuralNodeImpl(StructuralNode parent, String context, Object content) {
this(parent, context, new HashMap<>(), content);
}
public StructuralNodeImpl(StructuralNode parent, String context, Map<String, Object> attributes, Object content) {
this(parent, context, attributes, new ArrayList<>(), content, new ArrayList<>(), "", new ArrayList<>());
}
public StructuralNodeImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, String contentModel, List<String> subs) {
this(parent, context, attributes, roles, content, blocks, calculateLevel(parent), contentModel, subs);
}
public StructuralNodeImpl(StructuralNode parent, String context, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level, String contentModel, List<String> subs) {
super(parent, context, attributes, roles);
this.content = content;
this.blocks = blocks;
this.level = level;
this.contentModel = contentModel;
this.subs = subs;
}
@Override
@Deprecated
public String title() {
return getTitle();
}
@Override
public String getTitle() {
return title;
}
@Override
public void setTitle(String title) {
this.title = title;
}
@Override
public String getCaption() {
return caption;
}
@Override
public void setCaption(String caption) {
this.caption = caption;
}
@Override
@Deprecated
public String style() {
return getStyle();
}
@Override
public String getStyle() {
return style;
}
@Override
public void setStyle(String style) {
this.style = style;
}
@Override
@Deprecated
public List<StructuralNode> blocks() {
return getBlocks();
}
@Override
public List<StructuralNode> getBlocks() {
return blocks;
}
@Override
public void append(StructuralNode block) {
blocks.add(block);
}
@Override
@Deprecated
public Object content() {
return getContent();
}
@Override
public Object getContent() {
return content;
}
@Override
public String convert() {
return converter.convert(this, null, new HashMap<>());
}
@Override
public int getLevel() {
return level;
}
@Override
public Cursor getSourceLocation() {
return new CursorImpl();
}
@Override
public String getContentModel() {
return contentModel;
}
@Override
public List<String> getSubstitutions() {
return subs;
}
@Override
public boolean isSubstitutionEnabled(String substitution) {
return subs.contains(substitution);
}
@Override
public void removeSubstitution(String substitution) {
subs.remove(substitution);
}
@Override
public void addSubstitution(String substitution) {
subs.add(substitution);
}
@Override
public void prependSubstitution(String substitution) {
}
@Override
public void setSubstitutions(String... substitutions) {
subs = Arrays.asList(substitutions);
}
@Override
public List<StructuralNode> findBy(Map<Object, Object> selector) {
throw new UnsupportedOperationException("Not implemented, yet");
}
protected static Integer calculateLevel(StructuralNode parent) {
return null != parent ? parent.getLevel() + 1 : 0;
}
}

View File

@@ -0,0 +1,306 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.*;
public class TableImpl extends StructuralNodeImpl implements Table {
public static final String OPTION_UNBREAKABLE = "unbreakable";
public static final String OPTION_BREAKABLE = "breakable";
private Logger logger = LoggerFactory.getLogger(getClass());
public static final String CONTEXT = "table";
private static final String FRAME_ATTR = "frame";
private static final String GRID_ATTR = "grid";
private RowList headerRows;
private RowList bodyRows;
private RowList footerRows;
private List<Column> columns = new ArrayList<>();
public TableImpl(StructuralNode parent) {
this(parent, new HashMap<>(), new ArrayList<>());
}
public TableImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles) {
this(parent, attributes, roles, calculateLevel(parent));
}
public TableImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles, Integer level) {
this(parent, attributes, roles, null, new ArrayList<>(), level, "", new ArrayList<>());
}
public TableImpl(StructuralNode parent, Map<String, Object> attributes, List<String> roles,
Object content, List<StructuralNode> blocks, Integer level, String contentModel, List<String> subs) {
super(parent, CONTEXT, attributes, roles, content, blocks, level, contentModel, subs);
this.headerRows = new RowList(new ArrayList<>());
this.bodyRows = new RowList(new ArrayList<>());
this.footerRows = new RowList(new ArrayList<>());
}
@Override
public boolean hasHeaderOption() {
return isOption("header");
}
@Override
public String getFrame() {
return (String) getAttribute(FRAME_ATTR, "all");
}
@Override
public void setFrame(String frame) {
setAttribute(FRAME_ATTR, frame, true);
}
@Override
public String getGrid() {
return (String) getAttribute(GRID_ATTR, "all");
}
@Override
public void setGrid(String grid) {
setAttribute(GRID_ATTR, grid, true);
}
@Override
public List<Column> getColumns() {
return columns;
}
@Override
public List<Row> getHeader() {
return headerRows;
}
public void setHeaderRow(Row row) {
headerRows.clear();
headerRows.add(row);
scanRowForColumns(row);
}
public void setHeaderRow(List<Cell> cells) {
setHeaderRow(new RowImpl(cells));
}
public void setHeaderRow(String... documentContents) {
headerRows.clear();
headerRows.add(generateRow(documentContents));
}
public RowImpl generateRow(Document... innerDocs) {
List<Cell> cells = new ArrayList<>();
for (int i = 0; i < innerDocs.length; i++) {
Column column = null;
try {
column = columns.get(i);
} catch (Exception ignored) {
}
if (null == column) {
ColumnImpl newColumn = new ColumnImpl(this);
newColumn.setColumnNumber(i + 1);
column = newColumn;
addColumnAt(column, i);
}
cells.add(new CellImpl(column, innerDocs[i]));
}
return new RowImpl(cells);
}
public RowImpl generateRow(String... documentContents) {
Document[] documents = Arrays.stream(documentContents).map(documentContent -> {
Document innerDoc = new DocumentImpl();
Block paragraph = new ParagraphBlockImpl(innerDoc);
paragraph.setSource(documentContent);
innerDoc.append(paragraph);
return innerDoc;
}).toArray(Document[]::new);
return generateRow(documents);
}
@Override
public List<Row> getBody() {
return bodyRows;
}
public void setBodyRows(List<Row> rows) {
bodyRows.clear();
bodyRows.addAll(rows);
bodyRows.forEach(this::scanRowForColumns);
}
public void addRow(Row row) {
bodyRows.add(row);
scanRowForColumns(row);
}
public void addRow(List<Cell> cells) {
bodyRows.add(new RowImpl(cells));
}
public RowImpl addRow(Document... documentContents) {
RowImpl row = generateRow(documentContents);
bodyRows.add(row);
return row;
}
public RowImpl addRow(String... documentContents) {
RowImpl row = generateRow(documentContents);
bodyRows.add(row);
return row;
}
@Override
public List<Row> getFooter() {
return footerRows;
}
public void setFooterRow(Row row) {
footerRows.clear();
footerRows.add(row);
scanRowForColumns(row);
}
public void setFooterRow(String... documentContents) {
footerRows.clear();
footerRows.add(generateRow(documentContents));
}
private void scanRowForColumns(Row row) {
row.getCells().forEach(cell -> {
Column column = cell.getColumn();
int i = column.getColumnNumber() - 1;
addColumnAt(column, i);
});
}
private void addColumnAt(Column column, int i) {
if (columns.size() >= i) {
columns.add(i, column);
} else {
while (columns.size() < i) {
columns.add(columns.size(), null);
}
columns.add(column);
}
}
public void setFooterRow(List<Cell> cells) {
setFooterRow(new RowImpl(cells));
}
class RowList extends AbstractList<Row> {
private final List<Row> rubyArray;
private RowList(List<Row> rubyArray) {
this.rubyArray = rubyArray;
}
@Override
public int size() {
return rubyArray.size();
}
@Override
public boolean isEmpty() {
return rubyArray.isEmpty();
}
@Override
public boolean contains(Object o) {
return rubyArray.contains(o);
}
@Override
public boolean add(Row row) {
boolean changed = false;
try {
changed = rubyArray.add(row);
setAttribute("rowcount", size(), true);
} catch (Exception e) {
logger.debug("Couldn't add row", e);
}
return changed;
}
@Override
public boolean remove(Object o) {
if (!(o instanceof RowImpl)) {
return false;
}
try {
boolean changed = rubyArray.remove(o);
setAttribute("rowcount", size(), true);
return changed;
} catch (Exception e) {
logger.debug("Couldn't add row", e);
return false;
}
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
rubyArray.clear();
setAttribute("rowcount", size(), true);
}
@Override
public Row get(int index) {
return rubyArray.get(index);
}
@Override
public Row set(int index, Row element) {
Row oldRow = get(index);
rubyArray.set(index, element);
return oldRow;
}
@Override
public void add(int index, Row element) {
rubyArray.add(index, element);
setAttribute("rowcount", size(), true);
}
@Override
public Row remove(int index) {
Row removed = rubyArray.remove(index);
setAttribute("rowcount", size(), true);
return removed;
}
@Override
public int indexOf(Object o) {
if (!(o instanceof RowImpl)) {
return -1;
}
return rubyArray.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
if (!(o instanceof RowImpl)) {
return -1;
}
return rubyArray.lastIndexOf(o);
}
}
protected static Integer calculateLevel(StructuralNode parent) {
int level = 1;
if (parent instanceof Table)
level = parent.getLevel() + 1;
return level;
}
}

View File

@@ -0,0 +1,34 @@
package io.github.swagger2markup.adoc.ast.impl;
import org.asciidoctor.ast.Title;
public class TitleImpl implements Title {
private final String main;
private final String subtitle;
public TitleImpl(String main, String subtitle) {
this.main = main;
this.subtitle = subtitle;
}
@Override
public String getMain() {
return main;
}
@Override
public String getSubtitle() {
return subtitle;
}
@Override
public String getCombined() {
return main + ": " + subtitle;
}
@Override
public boolean isSanitized() {
return false;
}
}

View File

@@ -0,0 +1,50 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.apache.commons.lang3.StringUtils;
import org.asciidoctor.ast.ContentNode;
public class BlockImageNode extends NodeAttributes {
final private String target;
public BlockImageNode(ContentNode node) {
super(node.getAttributes());
target = pop("target").replaceAll("\\s", "{sp}");
}
public String getTarget() {
return target;
}
@Override
public void processPositionalAttributes() {
String attr1 = pop("1", "alt");
if (StringUtils.isNotBlank(attr1)) {
attrs.add(attr1);
}
String attr2 = pop("2", "width");
if (StringUtils.isNotBlank(attr2)) {
attrs.add(attr2);
}
String attr3 = pop("3", "height");
if (StringUtils.isNotBlank(attr3)) {
attrs.add(attr3);
}
}
@Override
void processAttributes() {
attributes.forEach((k, v) -> {
if (!k.equals("role") && null != v) {
attrs.add(k + "=" + v);
}
});
}
@Override
public String processAsciiDocContent() {
return "image::" + target + '[' + String.join(",", attrs) + ']';
}
}

View File

@@ -0,0 +1,31 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.asciidoctor.ast.Block;
import java.util.List;
import static io.github.swagger2markup.adoc.converter.internal.Delimiters.*;
public class BlockListingNode extends ParagraphAttributes {
final private Block node;
public BlockListingNode(Block node) {
super(node);
this.node = node;
}
@Override
public String processAsciiDocContent() {
StringBuilder sb = new StringBuilder();
attrsToString(sb, attrs);
sb.append(LINE_SEPARATOR).append(DELIMITER_BLOCK).append(LINE_SEPARATOR).append(node.getSource()).append(LINE_SEPARATOR).append(DELIMITER_BLOCK).append(LINE_SEPARATOR);
return sb.toString();
}
void attrsToString(StringBuilder sb, List<String> list) {
if (!list.isEmpty()) {
sb.append(ATTRIBUTES_BEGIN).append(String.join(",", list)).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
}
}
}

View File

@@ -0,0 +1,45 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.apache.commons.lang3.StringUtils;
import org.asciidoctor.ast.StructuralNode;
import java.util.ArrayList;
import java.util.List;
import static io.github.swagger2markup.adoc.converter.internal.Delimiters.*;
public class DelimitedBlockNode extends ParagraphAttributes {
public DelimitedBlockNode(StructuralNode node) {
super(node);
}
@Override
public void processPositionalAttributes() {
String source = pop("1", "style");
StringBuilder options = new StringBuilder();
List<String> toRemove = new ArrayList<>();
attributes.forEach((k, v) -> {
if (k.endsWith(OPTION_SUFFIX)) {
toRemove.add(k);
options.append('%').append(k.replace(OPTION_SUFFIX, ""));
}
});
toRemove.forEach(attributes::remove);
source += options.toString();
if (StringUtils.isNotBlank(source)) {
attrs.add(source);
}
super.processPositionalAttributes();
}
@Override
public String processAsciiDocContent() {
StringBuilder sb = new StringBuilder();
if (!attrs.isEmpty()) {
sb.append(ATTRIBUTES_BEGIN).append(String.join(",", attrs)).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,26 @@
package io.github.swagger2markup.adoc.converter.internal;
public class Delimiters {
public static final String ATTRIBUTES_BEGIN = "[";
public static final String ATTRIBUTES_END = "]";
public static final String COLON = ":";
public static final String DELIMITER_BLOCK = "----";
public static final String DELIMITER_EXAMPLE = "====";
public static final String DELIMITER_INNER_TABLE_CELL = "!";
public static final String DELIMITER_INNER_TABLE = "!===";
public static final String DELIMITER_PAGE_BREAK = "<<<";
public static final String DELIMITER_OPEN_BLOCK = "--";
public static final String DELIMITER_SIDEBAR = "****";
public static final String DELIMITER_TABLE = "|===";
public static final String DELIMITER_TABLE_CELL = "|";
public static final String DELIMITER_THEMATIC_BREAK = "'''";
public static final String DELIMITER_VERSE = "____";
public static final String DOCUMENT_TITLE = "=";
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final String MARKER_LIST_ITEM = "*";
public static final String MARKER_D_LIST_ITEM = ":";
public static final String STYLE_HORIZONTAL = "horizontal";
public static final String STYLE_Q_AND_A = "qanda";
public static final String STYLE_SOURCE = "source";
public static final String TITLE = "=";
}

View File

@@ -0,0 +1,38 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.apache.commons.lang3.StringUtils;
import org.asciidoctor.ast.ContentNode;
public class IconNode extends NodeAttributes {
final private String alt;
public IconNode(ContentNode node) {
super(node.getAttributes());
alt = pop("alt", "default-alt");
}
public String getAlt() {
return alt;
}
@Override
void processPositionalAttributes() {
String attr1 = pop("1", "size");
if (StringUtils.isNotBlank(attr1)) {
attrs.add(attr1);
}
}
@Override
void processAttributes() {
attributes.forEach((k, v) -> {
attrs.add(k + "=" + v);
});
}
@Override
String processAsciiDocContent() {
return "icon:" + alt + '[' + String.join(",", attrs) + ']';
}
}

View File

@@ -0,0 +1,64 @@
package io.github.swagger2markup.adoc.converter.internal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
import static io.github.swagger2markup.adoc.converter.internal.Delimiters.*;
abstract class NodeAttributes {
public static final String TITLE = "title";
final Map<String, Object> attributes;
List<String> attrs = new ArrayList<>();
NodeAttributes(Map<String, Object> attributes) {
this.attributes = attributes;
}
public String pop(String... keys) {
AtomicReference<String> value = new AtomicReference<>("");
Stream.of(keys).forEach(key -> {
try {
String tmpValue = attributes.remove(key).toString();
if (null != tmpValue && !tmpValue.isEmpty() && value.get().isEmpty()) {
value.set(tmpValue);
}
} catch (NullPointerException ignored) {
}
});
return value.get();
}
String pop(String key) {
try {
String value = attributes.remove(key).toString();
if (null == value) {
value = "";
}
return value;
} catch (NullPointerException ignored) {
return "";
}
}
final public String toAsciiDocContent() {
processPositionalAttributes();
processAttributes();
return processAsciiDocContent();
}
abstract void processPositionalAttributes();
abstract void processAttributes();
String processAsciiDocContent() {
StringBuilder sb = new StringBuilder();
if (!attrs.isEmpty()) {
sb.append(ATTRIBUTES_BEGIN).append(String.join(",", attrs)).append(ATTRIBUTES_END).append(LINE_SEPARATOR);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,63 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.apache.commons.lang3.StringUtils;
import org.asciidoctor.ast.StructuralNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public class ParagraphAttributes extends NodeAttributes {
public static final String OPTION_SUFFIX = "-option";
private Logger logger = LoggerFactory.getLogger(getClass());
public ParagraphAttributes(StructuralNode node) {
super(node.getAttributes());
}
@Override
public void processPositionalAttributes() {
String attr1 = pop("1", "style");
if (StringUtils.isNotBlank(attr1)) {
attrs.add(attr1);
}
}
@Override
void processAttributes() {
String id = pop("id");
if (StringUtils.isNotBlank(id)) {
id = "#" + id;
}
String roles = String.join(".", pop("role").split(" "));
if (StringUtils.isNotBlank(roles)) {
roles = "." + roles;
}
StringBuilder options = new StringBuilder();
List<String> namedAttributes = new ArrayList<>();
attributes.forEach((k, v) -> {
if (k.equals(TITLE)) {
logger.debug("Skipping attribute: " + TITLE);
} else if (k.endsWith(OPTION_SUFFIX)) {
options.append('%').append(k.replace(OPTION_SUFFIX, ""));
} else if (null != v) {
if(v.toString().contains(" ") || v.toString().contains(",")) {
namedAttributes.add(k + "=\"" + v +"\"");
} else {
namedAttributes.add(k + "=" + v);
}
} else {
logger.warn("Don't know how to handle key: " + k);
}
});
String nonNamedAttributes = id + roles + options.toString();
if (StringUtils.isNotBlank(nonNamedAttributes)) {
attrs.add(nonNamedAttributes);
}
attrs.addAll(namedAttributes);
}
}

View File

@@ -0,0 +1,53 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.apache.commons.lang3.StringUtils;
import org.asciidoctor.ast.Block;
import java.util.ArrayList;
import java.util.List;
import static io.github.swagger2markup.adoc.converter.internal.Delimiters.*;
public class SourceNode extends BlockListingNode {
private List<String> sourceAttrs = new ArrayList<>();
private final Block node;
public SourceNode(Block node) {
super(node);
this.node = node;
}
@Override
public void processPositionalAttributes() {
String source = pop("1", "style");
String language = pop("2", "language");
StringBuilder options = new StringBuilder();
List<String> toRemove = new ArrayList<>();
attributes.forEach((k, v) -> {
if (k.endsWith(OPTION_SUFFIX)) {
toRemove.add(k);
options.append('%').append(k.replace(OPTION_SUFFIX, ""));
}
});
toRemove.forEach(attributes::remove);
source += options.toString();
if (StringUtils.isNotBlank(source)) {
sourceAttrs.add(source);
}
if (StringUtils.isNotBlank(language)) {
sourceAttrs.add(language);
}
super.processPositionalAttributes();
}
@Override
public String processAsciiDocContent() {
StringBuilder sb = new StringBuilder();
attrsToString(sb, attrs);
attrsToString(sb, sourceAttrs);
sb.append(LINE_SEPARATOR).append(DELIMITER_BLOCK).append(LINE_SEPARATOR).append(node.getSource()).append(LINE_SEPARATOR).append(DELIMITER_BLOCK).append(LINE_SEPARATOR);
return sb.toString();
}
}

View File

@@ -0,0 +1,35 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.apache.commons.lang3.StringUtils;
public enum Style {
ASCIIDOC("a"), EMPHASIS("e"), HEADER("h"), LITERAL("l"), MONOSPACED("m"), NONE("d"), STRONG("s"), VERSE("v");
String shortHand;
Style(String h) {
this.shortHand = h;
}
public static Style fromString(String text) {
if(StringUtils.isNotBlank(text)) {
for (Style s : Style.values()) {
if (s.shortHand.equalsIgnoreCase(text)) {
return s;
}
}
}
return null;
}
public static Style fromName(String text) {
if(StringUtils.isNotBlank(text)) {
return valueOf(text.toUpperCase());
}
return null;
}
public String getShortHand() {
return shortHand;
}
}

View File

@@ -0,0 +1,35 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.apache.commons.lang3.StringUtils;
public enum TableCellHorizontalAlignment {
LEFT("<"), CENTER("^"), RIGHT(">");
String delimiter;
TableCellHorizontalAlignment(String s) {
this.delimiter = s;
}
public static TableCellHorizontalAlignment fromString(String text) {
if(StringUtils.isNotBlank(text)) {
for (TableCellHorizontalAlignment a : TableCellHorizontalAlignment.values()) {
if (a.delimiter.equalsIgnoreCase(text)) {
return a;
}
}
}
return null;
}
public static TableCellHorizontalAlignment fromName(String text) {
if(StringUtils.isNotBlank(text)) {
return valueOf(text.toUpperCase());
}
return null;
}
public String getDelimiter() {
return delimiter;
}
}

View File

@@ -0,0 +1,15 @@
package io.github.swagger2markup.adoc.converter.internal;
public class TableCellStyle {
public final TableCellHorizontalAlignment horizontalAlignment;
public final TableCellVerticalAlignment verticalAlignment;
public final Style style;
public final int width;
public TableCellStyle(TableCellHorizontalAlignment horizontalAlignment, TableCellVerticalAlignment verticalAlignment, Style style, int width) {
this.horizontalAlignment = horizontalAlignment;
this.verticalAlignment = verticalAlignment;
this.style = style;
this.width = width;
}
}

View File

@@ -0,0 +1,35 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.apache.commons.lang3.StringUtils;
public enum TableCellVerticalAlignment {
TOP(".<"), MIDDLE(".^"), BOTTOM(".>");
String delimiter;
TableCellVerticalAlignment(String s) {
this.delimiter = s;
}
public static TableCellVerticalAlignment fromString(String text) {
if(StringUtils.isNotBlank(text)) {
for (TableCellVerticalAlignment a : TableCellVerticalAlignment.values()) {
if (a.delimiter.equalsIgnoreCase(text)) {
return a;
}
}
}
return null;
}
public static TableCellVerticalAlignment fromName(String text) {
if(StringUtils.isNotBlank(text)) {
return valueOf(text.toUpperCase());
}
return null;
}
public String getDelimiter() {
return delimiter;
}
}

View File

@@ -0,0 +1,15 @@
package io.github.swagger2markup.adoc.converter.internal;
import org.asciidoctor.ast.Table;
public class TableNode extends DelimitedBlockNode {
public TableNode(Table table) {
super(table);
}
@Override
void processAttributes() {
pop("colcount", "rowcount", "tablepcwidth");
super.processAttributes();
}
}

View File

@@ -0,0 +1 @@
io.github.swagger2markup.adoc.AsciiDocConverterRegistry

View File

@@ -0,0 +1,50 @@
package io.github.swagger2markup.adoc;
import org.apache.commons.io.IOUtils;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.OptionsBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import static org.junit.Assert.*;
@RunWith(Parameterized.class)
public class AsciidocConverterTest {
private Asciidoctor asciidoctor = Asciidoctor.Factory.create();
@Parameterized.Parameters(name = "Run {index}: file={0}")
public static Iterable<?> data() {
return Arrays.asList(
"simple.adoc",
"arrows-and-boxes-example.ad",
"brokeninclude.asciidoc",
"changeattribute.adoc",
"chronicles-example.adoc",
"document-with-arrays.adoc"
);
}
@Parameterized.Parameter
public String asciidocFile;
@Test
public void converts_asciidoc_to_asciidoc() throws IOException {
//Given
String originalAsciiDoc = IOUtils.toString(getClass().getResourceAsStream("/asciidoc/original/" + asciidocFile), StandardCharsets.UTF_8);
String expectedAsciiDoc = IOUtils.toString(getClass().getResourceAsStream("/asciidoc/expected/" + asciidocFile), StandardCharsets.UTF_8);
//When
asciidoctor.javaConverterRegistry().register(AsciidocConverter.class, AsciidocConverter.NAME);
String result = asciidoctor.convert(originalAsciiDoc, OptionsBuilder.options().backend(AsciidocConverter.NAME).headerFooter(false).asMap());
//Then
assertEquals(expectedAsciiDoc, result);
}
}

View File

@@ -0,0 +1,34 @@
= Document Title
:tip-caption: Tip
:appendix-caption: Appendix
:appendix-refsig: Appendix
:toc-title: Table of Contents
:iconsdir: ./images/icons
:warning-caption: Warning
:figure-caption: Figure
:attribute-missing: skip
:section-refsig: Section
:toc-placement: auto
:important-caption: Important
:note-caption: Note
:stylesdir: .
:untitled-label: Untitled
:max-include-depth: 64
:caution-caption: Caution
:user-home: .
:max-attribute-value-size: 4096
:safe-mode-level: 20
:safe-mode-name: secure
:table-caption: Table
:part-refsig: Part
:authorcount: 0
:example-caption: Example
:version-label: Version
:last-update-label: Last updated
:doctype: article
:chapter-refsig: Chapter
:attribute-undefined: drop-line
[arrowsAndBoxes]
(User) > (Admin)

View File

@@ -0,0 +1,33 @@
= Title
:tip-caption: Tip
:appendix-caption: Appendix
:appendix-refsig: Appendix
:toc-title: Table of Contents
:iconsdir: ./images/icons
:warning-caption: Warning
:figure-caption: Figure
:attribute-missing: skip
:section-refsig: Section
:toc-placement: auto
:important-caption: Important
:note-caption: Note
:stylesdir: .
:untitled-label: Untitled
:max-include-depth: 64
:caution-caption: Caution
:user-home: .
:max-attribute-value-size: 4096
:safe-mode-level: 20
:safe-mode-name: secure
:table-caption: Table
:part-refsig: Part
:authorcount: 0
:example-caption: Example
:version-label: Version
:last-update-label: Last updated
:doctype: article
:chapter-refsig: Chapter
:attribute-undefined: drop-line
link:b.adoc[]

View File

@@ -0,0 +1,33 @@
= Document Title
:tip-caption: Tip
:appendix-caption: Appendix
:appendix-refsig: Appendix
:toc-title: Table of Contents
:iconsdir: ./images/icons
:warning-caption: Warning
:figure-caption: Figure
:attribute-missing: skip
:section-refsig: Section
:toc-placement: auto
:important-caption: Important
:note-caption: Note
:stylesdir: .
:untitled-label: Untitled
:max-include-depth: 64
:caution-caption: Caution
:user-home: .
:max-attribute-value-size: 4096
:safe-mode-level: 20
:safe-mode-name: secure
:table-caption: Table
:part-refsig: Part
:authorcount: 0
:example-caption: Example
:version-label: Version
:last-update-label: Last updated
:doctype: article
:chapter-refsig: Chapter
:attribute-undefined: drop-line
sample {content}

View File

@@ -0,0 +1,535 @@
= The Dangerous & _Thrilling_ Documentation Chronicles: Based on True Events
Kismet Caméléon; Lazarus het Draeke
v1.0, 2014-01-01
:tip-caption: Tip
:appendix-caption: Appendix
:toclevels: 3
:appendix-refsig: Appendix
:author_2: Lazarus het Draeke
:uri-stbernardusabt12: http://www.sintbernardus.be/stbernardusabt12.php?l=en
:authorinitials: KC
:author_1: Kismet Caméléon
:toc-title: Table of Contents
:iconsdir: ./images/icons
:author: Kismet Caméléon
:warning-caption: Warning
:figure-caption: Figure
:lastname: Caméléon
:attribute-missing: skip
:lastname_1: Caméléon
:section-refsig: Section
:uri-devoxx: https://devoxx.be
:lastname_2: het Draeke
:toc-placement: auto
:important-caption: Important
:authors: Kismet Caméléon, Lazarus het Draeke
:note-caption: Note
:firstname: Kismet
:stylesdir: .
:uri-devoxx-top-talks: https://www.youtube.com/watch?v=1OpAgZvYXLQ&amp;list=PLRsbF2sD7JVq7fv1GZGORShSUIae1ZAPy&amp;index=1
:untitled-label: Untitled
:description: This story chronicles the inexplicable hazards and vicious beasts a team must conquer and vanquish on their journey to discovering the true power of Open Source.
:max-include-depth: 64
:caution-caption: Caution
:listing-caption: Listing
:user-home: .
:max-attribute-value-size: 4096
:safe-mode-level: 20
:safe-mode-name: secure
:table-caption: Table
:part-refsig: Part
:firstname_1: Kismet
:authorcount: 2
:revdate: 2014-01-01
:example-caption: Example
:firstname_2: Lazarus
:version-label: Version
:revnumber: 1.0
:last-update-label: Last updated
:doctype: book
:chapter-refsig: Chapter
:uri-wolpertinger: http://en.wikipedia.org/wiki/Wolpertinger
:organization: Company Name
:authorinitials_1: KC
:authorinitials_2: Lh
:attribute-undefined: drop-line
[abstract]
{description}
[[_its_a_city_under_siege]]
== Its a City Under Siege
This journey begins one late Monday afternoon at {uri-devoxx}[((Devoxx))].
Our team needs coffee, _desperately_, but none of us dare open the theater doors...
During the {uri-devoxx-top-talks}[opening university session], a script-happy warlock inadvertently released a legion of Wolpertingers!
To leave now would mean *code dismemberment and certain death*.
Behold -> the horror!
.Wolpertinger, stuffed
[.left.thumb]
image::wolpertinger.jpg[Wolpertinger,link=http://en.wikipedia.org/wiki/Wolpertinger,pdfwidth=50%]
(((Wolpertinger)))
(((Ravenous Beast,Wolpertinger)))
You may not be familiar with these {uri-wolpertinger}[ravenous beasts].
Trust us, they'll eat your shorts and suck loops from your code.
In light of this danger, we've searched high and wide for the security crew's defensive operations manual.
We can't find it and the DefOps{empty}footnote:defops[DefOps is a portmanteau of "`defensive`" and "`operations`".] werewolves haven't returned from their rendezvous at Bier Central.
They've either eaten each other or fallen victim to the Wolpertingers roaming the streets of ((Antwerp)).
Quick, hit kbd:[Ctrl,Alt,Backspace] or select menu:File[Quit] and let's bail out of here!
WARNING: Working with DefOps{empty}footnote:defops[] werewolves leads to howling and trying to train aggressive regular expressions with Pavlovian reinforcement.
_Weak light from the hallway trickled across the theater, chased by a distant scream._
[[_rendezvous_point]]
=== Rendezvous Point
Come on, [[bier-central,Bier Central]]_Bier Central_, of course!
Did you have to ask?
If you beat me there, order me a {uri-stbernardusabt12}[St. Bernardus Abt 12].
Here's some &#x20ac;.
[[ravages]]
[#ravages]
== The Ravages of Writing
Crystalline XML tags relentlessly bombarded the theater.
.XML tags
[source,xml]
----
<author id="1">
<personname>
<firstname>Lazarus</firstname>
<surname>het Draeke</surname>
</personname>
</author>
----
Despite the assault, we continued our pursuit to draft a DefOps{empty}footnote:defops[] plan.
.DefOps Plan
====
Click btn:[Download Zip] to download the defensive operation plan bundle.
OMG!
Somebody please save us now!
I want my mum -- and an extra-large double macchiato, please.
====
Unfortunately, Lazarus and I had both come to the conclusion that we weren't going to get out of this without corrupted hardrives if we didn't locate caffeine within the next few hours.
[[_a_recipe_for_potion_that_will_ensure_you_win_the_hearts_of_developers]]
=== A Recipe for Potion That Will Ensure You Win the Hearts of Developers
This potion for a sample document contains the following ingredients, which are listed in a very random, chaotically nested order.
.Ingredients for Potion that Demystifies Documents
* all the headings
** syntax highlighted source code
*** non-syntax highlighted source code or just a listing block
* quote block
** verse block
*** table with some cell formatting
**** sequential paragraphs
***** admonition blocks, but use them sparingly
*** bullet list with nesting
** numbered list with nesting
** definition list
*** sidebar
* example block
** block image (no inline images)
*** inline formatting in a paragraph
**** two fresh Burdockian leaves
***** They must be harvested by the light of the teal moons.
Are you square?
[square]
* one
* two
* three
What is there to do?
* [x] Done
* [ ] Next
* Who's counting?
[[_searching_for_burdockian]]
==== Searching for Burdockian
.Steps for finding and preparing Burdockian leaves
. Locate dusty botany
.. Sneeze
... Sneeze some more
. Find section on Burdockian
.. Review its characteristics
... Take a picture of the diagram of its leaves
.... Don't rip out the picture like a troglodyte
..... Don't do it, I'm watching you
. Put on your hiking boots
. Freeze your butt off on the side of a mountain at midnight
Let's skip a few steps and start counting from 10.
[start=10]
. arabic (10)
.. loweralpha (a)
... lowerroman (i)
... lowerroman (ii)
... lowerroman (iii)
... lowerroman (iv)
.... upperalpha (A)
. arabic (11)
It's time for a top 5 list, made using the `reversed` option on an ordered list!
[%reversed]
. Stone Imperial Russian Stout
. Pliny the Elder
. Chimay Grande Réserve (Blue)
. St. Bernardus Abt 12
. Westvleteren 12 (XII)
How about a list with some terms?
* Fruits
Apple::::
The round fruit of a tree of the rose family, which typically has thin red or green skin and crisp flesh.
Yes, I said _flesh_.
Pear::::
A yellowish- or brownish-green edible fruit that is typically narrow at the stalk and wider toward the base, with sweet, slightly gritty flesh.
More flesh.
Mmmmm.
* Vegetables
Carrot::::
An orange-colored root eaten as a vegetable.
Beware, it's a favorite of the Wolpertinger.
[[_are_you_still_here]]
===== Are You Still Here?
.Move, move, move!
[CAUTION]
====
The Wolpertingers can smell your procrastination.
It's not their fault you can't find your boots.
====
[[_sigh]]
====== Sigh…
TIP: Your boots are in your closet.
[[_dawn_on_the_plateau]]
== Dawn on the Plateau
Lazarus was hanging from the bottom limb of a Burdockian tree, licking the bark.
[quote,Mark Tobey]
On pavements and the bark of trees I have found whole worlds.
"`If there are whole worlds on that bark, he just swallowed them,`" Kizmet replied.
[verse,The documentation attorneys]
____
No bark was harmed in the making of this potion.
We're not so sure about a couple ants though.
Nor those worlds...
Crap, I smell an injunction.
____
We'd retrieved the leaves, but we'd obviously lost our minds in the process.
[verse]
Roses are +++<span style="color: #FF0000">red</span>+++.
Violets are +++<span style="color: #0000FF">blue</span>+++__-ish__.
[[_words_seasoned_with_power]]
== Words Seasoned with Power
To _tame_ the [.wild]#wild# wolpertingers, we needed to build a *charm*.
But **ul**timate victory could only be won if we divined the *_true name_* of the __war__lock.
"`What kind of charm?`" Lazarus asked. "`An odoriferous one or a mineral one?`"
Kizmet shrugged. "`The note from Olaf's desk says '`wormwood and licorice,`' but these could be normal groceries for werewolves.`"
"`Well the H~2~O written on the security whiteboard could be part of a shopping list, but I don't think the local bodega also sells e = mc^2^,`" Lazarus replied.
"`Wait!`" Indigo plucked a small vial from her desk's top drawer and held it toward us.
The vial's label read '```e = mc^2^ *_the scent of science_* _smells like a genius_```'.
[[_can_i_get_some_code]]
=== Can I Get Some `Code`?
[%hardbreaks]
Sure.
Have a listing block.
[listing]
----
This is an example of a listing block.
The content inside is rendered as <pre> text.
----
But I'm not giving you any highlighting shazam just yet.
.What is a listing block?
Like literal blocks, the content in listing blocks is displayed exactly as you entered it.
Listing block content is rendered as `<pre>` text.
The `listing` style is applied to an element, such as a paragraph, by setting the `listing` attribute on that element.
Let's get our #((highlighting))# on!
<<<
Install Prawn:
[literal]
$ gem install prawn
Then create your first PDF document in Ruby!
.Generates a basic PDF document using Prawn
[source,ruby]
----
require 'prawn' # <1>
Prawn::Document.generate 'output.pdf' do # <3>
text 'Hello, World!' # <2>
end
----
<1> Imports Prawn library
<3> Adds text “Hello, World!” to first page
<2> Writes PDF to [file]_output.pdf_ after executing all statements
How about some source code that styles code? So meta!
[source,css]
----
code {
padding: 2px 4px;
font-size: 90%;
font-weight: normal;
color: #c7254e;
white-space: nowrap !important;
background-color: #f9f2f4;
border-radius: 4px;
}
----
Where could we go without some Java(TM)?
Naturally, some autosizing is necessary.
[source%autofit,java]
----
package org.javaee7.cdi.events;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.event.Observes;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.ws.rs.*;
/**
* This session-scoped bean receives greeting strings from the event bus
* and provides access to the collection of these greetings via a REST API.
*
* @author The Duke
* @since 1.0
*/
@SessionScoped
public class GreetingReceiver implements EventReceiver, Serializable {
private List<String> greetings;
@PostConstruct
void init() {
this.greetings = new ArrayList<String>();
}
void receive(@Observes String greet) {
this.greetings.add(greet);
}
@GET
@Produces("application/json")
public List<String> listAll(@QueryParam("start") Integer start, @QueryParam("max") Integer max) {
int numGreetings = this.greetings.size();
if (numGreetings == 0 || max == 0) {
return Collections.<String>emptyList();
}
if (start == null) {
start = 0;
}
if (max == null) {
max = numGreetings;
}
return this.greetings.subList(start, Math.min(max + start, numGreetings));
}
}
----
We already showed you an XML example in <<ravages>>, a language we often rant about over beers at <<bier-central>>.
I'll trade you a little table for some of that bark.
[table%header,grid=rows,cols=4,frame=topbot]
|===
<.<|Column 1
<.<|Column 2
<.<|Column 3
<.<|Column 4
^.<m|Prefix `{vbar}` with `{caret}` to center content horizontally within the cell.
<.>|Prefix `{vbar}` with a `.` and `>` to align content to the bottom of the cell.
^.^|Prefix `{vbar}` with a `^`, `.`, and `^` to place content in the middle of the cell.
>.<|Prefix `{vbar}` with `>` to align content to the right horizontally within the cell.
4+^.<e|This content spans all four columns (`4{plus}`) and is centered horizontally (`{caret}`) within the cell.
|===
Wait.
What?
Where is this story going?
`<span>`:::
an html tag that makes me crazy
align:::
something I never get going in the right direction.
Also has to do with my poor verbal communication skills
float:::
style:::
don't make me laugh
Does anyone have the time?
Tg lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborumj.
[[_keeping_it_together]]
== Keeping It Together
On this page we have nested "`keep together`" logic.
The combined block will be shifted to the next page if there isn't room available on this one.
[verse]
First,
we
need
to
waste
several
lines
using
a
verse
to
push
the
next
block
to
its
breaking
point.
.What happens if there is both a field and a method with the same name?
[NOTE]
====
Back to the previous example, suppose that we have both a field and a method with the same name, as in:
.Java class with a field and method that share the same name
[source,java]
----
public class Foo {
public String bar;
public String bar() {
return bar;
}
}
----
*Golo resolves methods first, fields last.*
Hence, the following Golo code will resolve the `bar()` method, not the `bar` field:
.Golo picks the method over the field with the same name
[source,golo]
----
let foo = Foo()
foo: bar("baz") # <1>
println(foo: bar()) # <2>
----
<1> Writes the field
<2> Calls the `bar()` method
====
<<<
Here's a preview of how each heading level is rendered.
[discrete]
= Heading 1 (Level 0)
filler content
[discrete]
== Heading 2 (Level 1)
filler content
[discrete]
=== Heading 3 (Level 2)
filler content
[discrete]
==== Heading 4 (Level 3)
filler content
[discrete]
===== Heading 5 (Level 4)
filler content
[discrete]
====== Heading 6 (Level 5)
filler content
'''
--
Here's some content inside an open block.
--
[[_credits]]
[appendix]
== Credits
.Brought to you with icon:heart[set=fas,role=love] by OpenDevise
[table%footer%header,grid=rows,width=75%,cols="2,2s,^4",frame=topbot]
|===
<.<|Name
<.<|Title
.<|Alias
<.<|Sarah White
<.<|President
.<|http://twitter.com/carbonfray[@carbonfray]
<.<|Dan Allen
<.<|Vice President
.<|http://twitter.com/mojavelinux[@mojavelinux]
3+^.<e|Powered by Open Source
|===
[[_index]]
[index]
== Index

View File

@@ -0,0 +1,48 @@
= Asciidoctor Changelog
:tip-caption: Tip
:appendix-caption: Appendix
:appendix-refsig: Appendix
:toc-title: Table of Contents
:iconsdir: ./images/icons
:warning-caption: Warning
:figure-caption: Figure
:attribute-missing: skip
:section-refsig: Section
:toc-placement: auto
:important-caption: Important
:note-caption: Note
:stylesdir: .
:untitled-label: Untitled
:max-include-depth: 64
:caution-caption: Caution
:user-home: .
:max-attribute-value-size: 4096
:safe-mode-level: 20
:safe-mode-name: secure
:table-caption: Table
:part-refsig: Part
:authorcount: 0
:example-caption: Example
:version-label: Version
:last-update-label: Last updated
:doctype: article
:chapter-refsig: Chapter
:attribute-undefined: drop-line
http://asciidoctor.org[Asciidoctor] is an open source text processor and publishing toolchain for converting http://asciidoctor.org[AsciiDoc] markup into HTML, DocBook and custom formats.
This document provides a high-level view of the changes introduced in Asciidoctor by release.
For a detailed view of what has changed, refer to the https://github.com/asciidoctor/asciidoctor/commits/master[commit history] on GitHub.
[[_0_1_4_2013_09_05_mojavelinux]]
== 0.1.4 (2013-09-05) - @mojavelinux
Performance::
* 15% increase in speed compared to 0.1.3
Enhancements::
* updated xref inline macro to support inter-document references (#417)
Bug Fixes::
* lowercase attribute names passed to API (#508)

View File

@@ -0,0 +1,77 @@
= Simple Inventory API
You <you@your-company.com>
v1.0.0
:tip-caption: Tip
:appendix-caption: Appendix
:appendix-refsig: Appendix
:authorinitials: Y
:toc-title: Table of Contents
:iconsdir: ./images/icons
:author: You
:warning-caption: Warning
:figure-caption: Figure
:attribute-missing: skip
:section-refsig: Section
:toc-placement: auto
:important-caption: Important
:authors: You
:note-caption: Note
:firstname: You
:stylesdir: .
:untitled-label: Untitled
:max-include-depth: 64
:caution-caption: Caution
:user-home: .
:max-attribute-value-size: 4096
:safe-mode-level: 20
:safe-mode-name: secure
:table-caption: Table
:part-refsig: Part
:authorcount: 1
:example-caption: Example
:email: you@your-company.com
:version-label: Version
:revnumber: 1.0.0
:last-update-label: Last updated
:doctype: article
:chapter-refsig: Chapter
:attribute-undefined: drop-line
[[_overview]]
== Overview
This is a simple API
[[_license]]
=== License
[%hardbreaks]
http://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0]
[[_servers]]
== Servers
* https://{username}.gigantic-server.com:{port}/{basePath}
+
The production API server
+
.Variables
username::
*this* __value__ is assigned by the service provider, in this example `gigantic-server.com`
Possible Values::
Any
Default::
demo
port::
Possible Values::
- 8443
- 443
Default::
8443
basePath::
Possible Values::
Any
Default::
v2

View File

@@ -0,0 +1,4 @@
= Document Title
[arrowsAndBoxes]
(User) > (Admin)

View File

@@ -0,0 +1,3 @@
= Title
include::b.adoc[]

View File

@@ -0,0 +1,4 @@
= Document Title
sample {content}

View File

@@ -0,0 +1,529 @@
= The Dangerous & _Thrilling_ Documentation Chronicles: Based on True Events
Kismet Caméléon; Lazarus het_Draeke
v1.0, 2014-01-01
:description: This story chronicles the inexplicable hazards and vicious beasts a \
team must conquer and vanquish on their journey to discovering the true power of \
Open Source.
:organization: Company Name
:doctype: book
// Settings:
:experimental:
:reproducible:
:icons: font
:listing-caption: Listing
:sectnums:
:toc:
:toclevels: 3
ifeval::["{asciidoctor-version}" < "1.5.7"]
:legacy-footnoteref:
endif::[]
ifdef::backend-pdf[]
:pdf-theme: chronicles
:pdf-themesdir: {docdir}
:title-logo-image: image:sample-banner.svg[pdfwidth=4.25in,align=center]
:source-highlighter: rouge
//:rouge-style: github
endif::[]
// URIs:
:uri-devoxx: https://devoxx.be
:uri-devoxx-top-talks: https://www.youtube.com/watch?v=1OpAgZvYXLQ&list=PLRsbF2sD7JVq7fv1GZGORShSUIae1ZAPy&index=1
:uri-stbernardusabt12: http://www.sintbernardus.be/stbernardusabt12.php?l=en
:uri-wolpertinger: http://en.wikipedia.org/wiki/Wolpertinger
[abstract]
{description}
== It's a City Under Siege
This journey begins one late Monday afternoon at {uri-devoxx}[((Devoxx))].
Our team needs coffee, _desperately_, but none of us dare open the theater doors...
During the {uri-devoxx-top-talks}[opening university session], a script-happy warlock inadvertently released a legion of Wolpertingers!
To leave now would mean *code dismemberment and certain death*.
Behold -> the horror!
.Wolpertinger, stuffed
[.left.thumb]
image::wolpertinger.jpg[Wolpertinger,pdfwidth=50%,link={uri-wolpertinger}]
(((Wolpertinger)))
(((Ravenous Beast,Wolpertinger)))
You may not be familiar with these {uri-wolpertinger}[ravenous beasts].
Trust us, they'll eat your shorts and suck loops from your code.
In light of this danger, we've searched high and wide for the security crew's defensive operations manual.
ifndef::legacy-footnoteref[]
We can't find it and the DefOps{empty}footnote:defops[DefOps is a portmanteau of "`defensive`" and "`operations`".] werewolves haven't returned from their rendezvous at Bier Central.
endif::[]
ifdef::legacy-footnoteref[]
We can't find it and the DefOps{empty}footnoteref:[defops,DefOps is a portmanteau of "`defensive`" and "`operations`".] werewolves haven't returned from their rendezvous at Bier Central.
endif::[]
They've either eaten each other or fallen victim to the Wolpertingers roaming the streets of ((Antwerp)).
Quick, hit kbd:[Ctrl,Alt,Backspace] or select menu:File[Quit] and let's bail out of here!
ifndef::legacy-footnoteref[]
WARNING: Working with DefOps{empty}footnote:defops[] werewolves leads to howling and trying to train aggressive regular expressions with Pavlovian reinforcement.
endif::[]
ifdef::legacy-footnoteref[]
WARNING: Working with DefOps{empty}footnoteref:[defops] werewolves leads to howling and trying to train aggressive regular expressions with Pavlovian reinforcement.
endif::[]
_Weak light from the hallway trickled across the theater, chased by a distant scream._
=== Rendezvous Point
Come on, [[bier-central,Bier Central]]_Bier Central_, of course!
Did you have to ask?
If you beat me there, order me a {uri-stbernardusabt12}[St. Bernardus Abt 12].
Here's some &#x20ac;.
[#ravages]
== The Ravages of Writing
Crystalline XML tags relentlessly bombarded the theater.
.XML tags
[source,xml]
----
<author id="1">
<personname>
<firstname>Lazarus</firstname>
<surname>het Draeke</surname>
</personname>
</author>
----
ifndef::legacy-footnoteref[]
Despite the assault, we continued our pursuit to draft a DefOps{empty}footnote:defops[] plan.
endif::[]
ifdef::legacy-footnoteref[]
Despite the assault, we continued our pursuit to draft a DefOps{empty}footnoteref:[defops] plan.
endif::[]
.DefOps Plan
====
Click btn:[Download Zip] to download the defensive operation plan bundle.
OMG!
Somebody please save us now!
I want my mum -- and an extra-large double macchiato, please.
====
Unfortunately, Lazarus and I had both come to the conclusion that we weren't going to get out of this without corrupted hardrives if we didn't locate caffeine within the next few hours.
=== A Recipe for Potion That Will Ensure You Win the Hearts of Developers
This potion for a sample document contains the following ingredients, which are listed in a very random, chaotically nested order.
.Ingredients for Potion that Demystifies Documents
* all the headings
** syntax highlighted source code
*** non-syntax highlighted source code or just a listing block
* quote block
** verse block
*** table with some cell formatting
**** sequential paragraphs
***** admonition blocks, but use them sparingly
*** bullet list with nesting
** numbered list with nesting
** definition list
*** sidebar
* example block
** block image (no inline images)
*** inline formatting in a paragraph
**** two fresh Burdockian leaves
***** They must be harvested by the light of the teal moons.
Are you square?
[square]
* one
* two
* three
What is there to do?
* [x] Done
* [ ] Next
* Who's counting?
==== Searching for Burdockian
.Steps for finding and preparing Burdockian leaves
. Locate dusty botany
.. Sneeze
... Sneeze some more
. Find section on Burdockian
.. Review its characteristics
... Take a picture of the diagram of its leaves
.... Don't rip out the picture like a troglodyte
..... Don't do it, I'm watching you
. Put on your hiking boots
. Freeze your butt off on the side of a mountain at midnight
Let's skip a few steps and start counting from 10.
[start=10]
. arabic (10)
.. loweralpha (a)
... lowerroman (i)
... lowerroman (ii)
... lowerroman (iii)
... lowerroman (iv)
.... upperalpha (A)
. arabic (11)
It's time for a top 5 list, made using the `reversed` option on an ordered list!
[%reversed]
. Stone Imperial Russian Stout
. Pliny the Elder
. Chimay Grande Réserve (Blue)
. St. Bernardus Abt 12
. Westvleteren 12 (XII)
How about a list with some terms?
* Fruits
Apple::
The round fruit of a tree of the rose family, which typically has thin red or green skin and crisp flesh.
Yes, I said _flesh_.
Pear::
A yellowish- or brownish-green edible fruit that is typically narrow at the stalk and wider toward the base, with sweet, slightly gritty flesh.
More flesh.
Mmmmm.
* Vegetables
Carrot::
An orange-colored root eaten as a vegetable.
Beware, it's a favorite of the Wolpertinger.
===== Are You Still Here?
.Move, move, move!
[CAUTION]
====
The Wolpertingers can smell your procrastination.
It's not their fault you can't find your boots.
====
====== Sigh...
TIP: Your boots are in your closet.
== Dawn on the Plateau
Lazarus was hanging from the bottom limb of a Burdockian tree, licking the bark.
[quote,Mark Tobey]
On pavements and the bark of trees I have found whole worlds.
"`If there are whole worlds on that bark, he just swallowed them,`" Kizmet replied.
[verse,The documentation attorneys]
____
No bark was harmed in the making of this potion.
We're not so sure about a couple ants though.
Nor those worlds...
Crap, I smell an injunction.
____
We'd retrieved the leaves, but we'd obviously lost our minds in the process.
[verse]
Roses are +++<span style="color: #FF0000">red</span>+++.
Violets are +++<span style="color: #0000FF">blue</span>+++__-ish__.
== Words Seasoned with Power
To _tame_ the [.wild]#wild# wolpertingers, we needed to build a *charm*.
But **ul**timate victory could only be won if we divined the *_true name_* of the __war__lock.
"`What kind of charm?`" Lazarus asked. "`An odoriferous one or a mineral one?`"
Kizmet shrugged. "`The note from Olaf's desk says '`wormwood and licorice,`' but these could be normal groceries for werewolves.`"
"`Well the H~2~O written on the security whiteboard could be part of a shopping list, but I don't think the local bodega also sells e = mc^2^,`" Lazarus replied.
"`Wait!`" Indigo plucked a small vial from her desk's top drawer and held it toward us.
The vial's label read '```e = mc^2^ *_the scent of science_* _smells like a genius_```'.
=== Can I Get Some `Code`?
[%hardbreaks]
Sure.
Have a listing block.
----
This is an example of a listing block.
The content inside is rendered as <pre> text.
----
But I'm not giving you any highlighting shazam just yet.
.What is a listing block?
****
Like literal blocks, the content in listing blocks is displayed exactly as you entered it.
Listing block content is rendered as `<pre>` text.
The `listing` style is applied to an element, such as a paragraph, by setting the `listing` attribute on that element.
****
Let's get our #((highlighting))# on!
<<<
Install Prawn:
$ gem install prawn
Then create your first PDF document in Ruby!
.Generates a basic PDF document using Prawn
[source,ruby]
----
require 'prawn' # <1>
Prawn::Document.generate 'output.pdf' do # <3>
text 'Hello, World!' # <2>
end
----
<1> Imports Prawn library
<2> Adds text “Hello, World!” to first page
<3> Writes PDF to [file]_output.pdf_ after executing all statements
How about some source code that styles code? So meta!
[source,css]
----
code {
padding: 2px 4px;
font-size: 90%;
font-weight: normal;
color: #c7254e;
white-space: nowrap !important;
background-color: #f9f2f4;
border-radius: 4px;
}
----
Where could we go without some Java(TM)?
Naturally, some autosizing is necessary.
[source%autofit,java]
----
package org.javaee7.cdi.events;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.event.Observes;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.ws.rs.*;
/**
* This session-scoped bean receives greeting strings from the event bus
* and provides access to the collection of these greetings via a REST API.
*
* @author The Duke
* @since 1.0
*/
@SessionScoped
public class GreetingReceiver implements EventReceiver, Serializable {
private List<String> greetings;
@PostConstruct
void init() {
this.greetings = new ArrayList<String>();
}
void receive(@Observes String greet) {
this.greetings.add(greet);
}
@GET
@Produces("application/json")
public List<String> listAll(@QueryParam("start") Integer start, @QueryParam("max") Integer max) {
int numGreetings = this.greetings.size();
if (numGreetings == 0 || max == 0) {
return Collections.<String>emptyList();
}
if (start == null) {
start = 0;
}
if (max == null) {
max = numGreetings;
}
return this.greetings.subList(start, Math.min(max + start, numGreetings));
}
}
----
We already showed you an XML example in <<ravages>>, a language we often rant about over beers at <<bier-central>>.
I'll trade you a little table for some of that bark.
[cols=4,frame=topbot,grid=rows]
|===
|Column 1 |Column 2 |Column 3 |Column 4
^m|Prefix `{vbar}` with `{caret}` to center content horizontally within the cell.
.>|Prefix `{vbar}` with a `.` and `>` to align content to the bottom of the cell.
^.^|Prefix `{vbar}` with a `^`, `.`, and `^` to place content in the middle of the cell.
>|Prefix `{vbar}` with `>` to align content to the right horizontally within the cell.
4+^e|This content spans all four columns (`4{plus}`) and is centered horizontally (`{caret}`) within the cell.
|===
Wait.
What?
Where is this story going?
`<span>`:: an html tag that makes me crazy
align:: something I never get going in the right direction.
Also has to do with my poor verbal communication skills
float::
style::
don't make me laugh
Does anyone have the time?
Tg lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborumj.
== Keeping It Together
On this page we have nested "`keep together`" logic.
The combined block will be shifted to the next page if there isn't room available on this one.
[verse]
First,
we
need
to
waste
several
lines
using
a
verse
to
push
the
next
block
to
its
breaking
point.
[NOTE]
.What happens if there is both a field and a method with the same name?
====
Back to the previous example, suppose that we have both a field and a method with the same name, as in:
.Java class with a field and method that share the same name
[source,java]
----
public class Foo {
public String bar;
public String bar() {
return bar;
}
}
----
*Golo resolves methods first, fields last.*
Hence, the following Golo code will resolve the `bar()` method, not the `bar` field:
.Golo picks the method over the field with the same name
[source,golo]
----
let foo = Foo()
foo: bar("baz") # <1>
println(foo: bar()) # <2>
----
<1> Writes the field
<2> Calls the `bar()` method
====
<<<
Here's a preview of how each heading level is rendered.
[discrete]
= Heading 1 (Level 0)
filler content
[discrete]
== Heading 2 (Level 1)
filler content
[discrete]
=== Heading 3 (Level 2)
filler content
[discrete]
==== Heading 4 (Level 3)
filler content
[discrete]
===== Heading 5 (Level 4)
filler content
[discrete]
====== Heading 6 (Level 5)
filler content
---
--
Here's some content inside an open block.
--
[appendix]
== Credits
.Brought to you with icon:heart[set=fas,role=love] by OpenDevise
[%header%footer,cols="2,2s,^4",grid=rows,frame=topbot,width=75%,caption=]
|===
|Name |Title |Alias
|Sarah White
|President
|http://twitter.com/carbonfray[@carbonfray]
|Dan Allen
|Vice President
|http://twitter.com/mojavelinux[@mojavelinux]
3+^.e|Powered by Open Source
|===
[index]
== Index

View File

@@ -0,0 +1,21 @@
= Asciidoctor Changelog
http://asciidoctor.org[Asciidoctor] is an open source text processor and publishing toolchain for converting http://asciidoctor.org[AsciiDoc] markup into HTML, DocBook and custom formats.
This document provides a high-level view of the changes introduced in Asciidoctor by release.
For a detailed view of what has changed, refer to the https://github.com/asciidoctor/asciidoctor/commits/master[commit history] on GitHub.
== 0.1.4 (2013-09-05) - @mojavelinux
Performance::
* 15% increase in speed compared to 0.1.3
Enhancements::
* updated xref inline macro to support inter-document references (#417)
Bug Fixes::
* lowercase attribute names passed to API (#508)

View File

@@ -0,0 +1,28 @@
= Simple Inventory API
You <you@your-company.com>
v1.0.0
== Overview
This is a simple API
=== License
[%hardbreaks]
http://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0]
== Servers
* https://{username}.gigantic-server.com:{port}/{basePath}
+
The production API server
+
.Variables
username:: *this* __value__ is assigned by the service provider, in this example `gigantic-server.com`
Possible Values::: Any
Default::: demo
port::
Possible Values:::
- 8443
- 443
Default::: 8443
basePath::
Possible Values::: Any
Default::: v2

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="io.github.swagger2markup" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

View File

@@ -0,0 +1,40 @@
= swagger2markup-bom
generates BOM (Bill Of Materials) to control used version of swagger2markup projects in a single place.
.Maven's example:
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Swagger2Markup -->
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup-bom</artifactId>
<version>0.14.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
.Gradle example:
[source,groovy]
----
dependencies {
implementation 'io.github.swagger2markup:swagger2markup-bom:0.14.0'
implementation 'io.github.swagger2markup:swagger2markup-core'
}
----
== License
Copyright {docyear} Alexey Shirmanov
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

View File

@@ -0,0 +1,53 @@
description = "swagger2markup bom"
apply plugin: 'maven-publish'
apply plugin: 'signing'
def projectArtifactId = 'swagger2markup'
def url = 'https://github.com/Swagger2Markup/swagger2markup'
signing {
sign publishing.publications
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
pom.withXml {
def devs = ['RobWin': 'Robert Winkler',
'austek': 'Ali Ustek']
asNode().appendNode('packaging', 'pom')
def license = asNode().appendNode('licenses').appendNode('license')
license.appendNode('name', 'Apache-2.0')
license.appendNode('url', 'https://github.com/Swagger2Markup/swagger2markup/blob/master/LICENSE.txt')
license.appendNode('distribution', 'repo')
def root = asNode()
root.appendNode('name', "${projectArtifactId}")
root.appendNode('url', "${url}")
root.appendNode('description', project.description)
asNode().appendNode('scm').appendNode('url', 'https://github.com/Swagger2Markup/swagger2markup.git')
Node deps = asNode().appendNode('dependencyManagement').appendNode('dependencies')
coreProjects.each {
Node dep = deps.appendNode('dependency')
dep.appendNode('groupId').value = it.group
dep.appendNode('artifactId').value = it.name
dep.appendNode('version').value = it.version
}
def developers = root.appendNode('developers')
devs.each {
def d = developers.appendNode('developer')
d.appendNode('id', it.key)
d.appendNode('name', it.value)
}
}
}
}
}

View File

@@ -0,0 +1,122 @@
= MarkupDocBuilder
:author: Robert Winkler
:version: 1.1.1
:hardbreaks:
== Overview
This project is a Markup document builder (AsciiDoc, Markdown and ConfluenceWiki). The primary goal of this project is to simplify the creation of Markup documents. The builder is used by https://github.com/RobWin/swagger2markup[swagger2markup].
The project requires at least JDK 7.
=== Usage
=== Adding MarkupDocBuilder to your project
The project is published in JCenter and Maven Central.
==== Maven
[source,xml, subs="specialcharacters,attributes"]
----
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>bintray</name>
<url>http://jcenter.bintray.com</url>
</repository>
</repositories>
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>markup-document-builder</artifactId>
<version>{version}</version>
</dependency>
----
==== Gradle
[source,groovy, subs="attributes"]
----
repositories {
jcenter()
}
compile "io.github.swagger2markup:markup-document-builder:{version}"
----
=== Using MarkupDocBuilder
The MarkupDocBuilder allows to build an AsciiDoc or Markdown document via the Builder pattern.
[source,java]
----
public class MarkupDocBuilderTest {
List<String> tableRowsInPSV;
@Before
public void setUp(){
tableRowsInPSV = new ArrayList<>();
tableRowsInPSV.add("Header 1 | Header 2 | Header2");
tableRowsInPSV.add("Row 1, Column 1 | Row 1, Column 2 | Row 1, Column 3");
tableRowsInPSV.add("Row 2, Column 1 | Row 2, Column 2 | Row 2, Column 3");
}
@Test
public void testToAsciiDocFile() throws IOException {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC);
builder.documentTitle("Test title")
.sectionTitleLevel1("Section Level 1a")
.sectionTitleLevel2("Section Level 2a")
.sectionTitleLevel3("Section Level 3a")
.paragraph("Paragraph with long text bla bla bla bla bla")
.listing("Source code listing")
.source("MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC)", "java")
.tableWithHeaderRow(tableRowsInPSV)
.sectionTitleLevel1("Section Level 1b")
.sectionTitleLevel2("Section Level 2b")
.boldTextLine("Bold text line b")
.italicTextLine("Italic text line b")
.unorderedList(Arrays.asList("Entry1", "Entry2", "Entry 2"))
.writeToFile("build/tmp", "test", StandardCharsets.UTF_8);
}
@Test
public void testToMarkdownDocFile() throws IOException {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder.documentTitle("Test title")
.sectionTitleLevel1("Section Level 1a")
.sectionTitleLevel2("Section Level 2a")
.sectionTitleLevel3("Section Level 3a")
.paragraph("Paragraph with long text bla bla bla bla bla")
.listing("Source code listing")
.source("MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN)", "java")
.tableWithHeaderRow(tableRowsInPSV)
.sectionTitleLevel1("Section Level 1b")
.sectionTitleLevel2("Section Level 2b")
.boldTextLine("Bold text line b")
.italicTextLine("Italic text line b")
.unorderedList(Arrays.asList("Entry1", "Entry2", "Entry 2"))
.writeToFile("build/tmp", "test", StandardCharsets.UTF_8);
}
}
----
=== Generated HTML using AsciidoctorJ
You can generate your PDF or HTML documentation via https://github.com/asciidoctor/asciidoctorj[asciidoctorj] or even better via the https://github.com/asciidoctor/asciidoctor-gradle-plugin[asciidoctor-gradle-plugin] or https://github.com/aalmiray/markdown-gradle-plugin[markdown-gradle-plugin].
image::images/asciidoc_html.jpg[asciidoc_html]
== License
Copyright {docyear} Robert Winkler
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

View File

@@ -0,0 +1,18 @@
ext.moduleName='io.github.swagger2markup.markup-document-builder'
dependencies {
configurations.all {
resolutionStrategy.force dependencyOverrides.commonsIO
resolutionStrategy.force dependencyOverrides.slf4j
}
implementation implLibraries.commonsCodec
implementation implLibraries.commonsLang3
implementation implLibraries.commonsIO
implementation implLibraries.mark2Ascii
implementation implLibraries.slf4j
implementation implLibraries.pegdown
testImplementation testLibraries.assertjDiff
testImplementation testLibraries.junit
testImplementation testLibraries.logback
testImplementation testLibraries.mockito
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -0,0 +1,45 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder;
public enum LineSeparator {
/**
* Line separator for Unix systems (<code>\n</code>).
*/
UNIX("\n"),
/**
* Line separator for Windows systems (<code>\r\n</code>).
*/
WINDOWS("\r\n"),
/**
* Line separator for Macintosh systems (<code>\r</code>).
*/
MAC("\r");
private String lineSeparator;
LineSeparator(String lineSeparator) {
this.lineSeparator = lineSeparator;
}
@Override
public String toString() {
return lineSeparator;
}
}

View File

@@ -0,0 +1,9 @@
package io.github.swagger2markup.markup.builder;
public enum MarkupAdmonition {
NOTE,
TIP,
IMPORTANT,
CAUTION,
WARNING
}

View File

@@ -0,0 +1,9 @@
package io.github.swagger2markup.markup.builder;
public enum MarkupBlockStyle {
SIDEBAR,
EXAMPLE,
LITERAL,
LISTING,
PASSTHROUGH
}

View File

@@ -0,0 +1,599 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.util.List;
/**
* @author Robert Winkler
*/
public interface MarkupDocBuilder {
/**
* Builds a document section {@code title}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder documentTitle(String title);
/**
* Builds a section {@code title}.
*
* @param title title
* @param level section title level [1, 5]
* @return this builder
*/
MarkupDocBuilder sectionTitleLevel(int level, String title);
/**
* Builds a section {@code title} with a custom {@code anchor} for later reference.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param title title
* @param level section title level [1, 5]
* @param anchor custom anchor. If null, auto-generate the anchor from the normalized title.
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel(int level, String title, String anchor);
/**
* Builds a section {@code title} with an auto-generated anchor from the normalized title, for later reference.<br>
* This is an alias for {@link #sectionTitleWithAnchorLevel(int, String, String) sectionTitleWithAnchorLevel(level, title, null)}.
*
* @param title title
* @param level section title level [1, 5]
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel(int level, String title);
/**
* Builds a level 1 section {@code title}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleLevel1(String title);
/**
* Builds a level 1 section {@code title} with a custom {@code anchor} for later reference.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param title title
* @param anchor custom anchor. If null, auto-generate the anchor from the normalized title.
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel1(String title, String anchor);
/**
* Builds a level 1 section {@code title} with an auto-generated anchor from the normalized title, for later reference.<br>
* This is an alias for {@link #sectionTitleWithAnchorLevel1(String, String) sectionTitleWithAnchorLevel1(title, null)}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel1(String title);
/**
* Builds a level 2 section {@code title}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleLevel2(String title);
/**
* Builds a level 2 section {@code title} with a custom {@code anchor} for later reference.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param title title
* @param anchor custom anchor. If null, auto-generate the anchor from the normalized title.
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel2(String title, String anchor);
/**
* Builds a level 2 section {@code title} with an auto-generated anchor from the normalized title, for later reference.<br>
* This is an alias for {@link #sectionTitleWithAnchorLevel2(String, String) sectionTitleWithAnchorLevel2(title, null)}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel2(String title);
/**
* Builds a level 3 section {@code title}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleLevel3(String title);
/**
* Builds a level 3 section {@code title} with a custom {@code anchor} for later reference.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param title title
* @param anchor custom anchor. If null, auto-generate the anchor from the normalized title.
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel3(String title, String anchor);
/**
* Builds a level 3 section {@code title} with an auto-generated anchor from the normalized title, for later reference.<br>
* This is an alias for {@link #sectionTitleWithAnchorLevel3(String, String) sectionTitleWithAnchorLevel3(title, null)}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel3(String title);
/**
* Builds a level 4 section {@code title}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleLevel4(String title);
/**
* Builds a level 4 section {@code title} with a custom {@code anchor} for later reference.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param title title
* @param anchor custom anchor. If null, auto-generate the anchor from the normalized title.
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel4(String title, String anchor);
/**
* Builds a level 4 section {@code title} with an auto-generated anchor from the normalized title, for later reference.<br>
* This is an alias for {@link #sectionTitleWithAnchorLevel4(String, String) sectionTitleWithAnchorLevel4(title, null)}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel4(String title);
/**
* Builds a level 5 section {@code title}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleLevel5(String title);
/**
* Builds a level 5 section {@code title} with a custom {@code anchor} for later reference.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param title title
* @param anchor custom anchor. If null, auto-generate the anchor from the normalized title.
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel5(String title, String anchor);
/**
* Builds a level 5 section {@code title} with an auto-generated anchor from the normalized title, for later reference.<br>
* This is an alias for {@link #sectionTitleWithAnchorLevel5(String, String) sectionTitleWithAnchorLevel5(title, null)}.
*
* @param title title
* @return this builder
*/
MarkupDocBuilder sectionTitleWithAnchorLevel5(String title);
/**
* Builds a regular text line.<br>
* This is an alias for {@link #textLine(String, boolean) textLine(text, false)}.
*
* @param text text
* @return this builder
*/
MarkupDocBuilder textLine(String text);
/**
* Builds a regular text line.
*
* @param text text
* @param forceLineBreak add an explicit line break if true.
* @return this builder
*/
MarkupDocBuilder textLine(String text, boolean forceLineBreak);
/**
* Builds a regular text.
*
* @param text text
* @return this builder
*/
MarkupDocBuilder text(String text);
/**
* Builds a text paragraph.<br>
*
* @param text multi-line text
* @param hardbreaks force hardbreaks on all lines
* @return this builder
*/
MarkupDocBuilder paragraph(String text, boolean hardbreaks);
/**
* Builds a text paragraph.<br>
* This is an alias for {@link #paragraph(String, boolean) paragraph(text, false)}.
*
* @param text multi-line text
* @return this builder
*/
MarkupDocBuilder paragraph(String text);
/**
* Insert a page break
*
* @return this builder
*/
MarkupDocBuilder pageBreak();
/**
* Builds a block of {@code text} with specified {@code style}.
*
* @param text text
* @param style block style
* @param title an optional title for the block. No title if null.
* @param admonition an optional admonition for the block. No admonition if null.
* @return this builder
*/
MarkupDocBuilder block(String text, MarkupBlockStyle style, String title, MarkupAdmonition admonition);
/**
* Builds a block of {@code text} with specified {@code style}.<br>
* This is an alias for {@link #block(String, MarkupBlockStyle, String, MarkupAdmonition) block(String, MarkupBlockStyle, null, null)}.
*
* @param text text
* @param style block style
* @return this builder
*/
MarkupDocBuilder block(String text, MarkupBlockStyle style);
/**
* Builds a source code block using the specified {@code language}.<br>
* Line breaks are respected.
*
* @param text multi-line text
* @param language source code language. Simple listing if {@code language} == null.
* @return this builder
*/
MarkupDocBuilder listingBlock(String text, String language);
/**
* Builds a listing text block.<br>
* This is an alias for {@link #listingBlock(String, String) listingBlock(String, null)}.
*
* @param text multi-line text
* @return this builder
*/
MarkupDocBuilder listingBlock(String text);
/**
* Builds a literal text line.<br>
* This is an alias for {@link #literalTextLine(String, boolean) literalTextLine(text, false)}.
*
* @param text text
* @return this builder
*/
MarkupDocBuilder literalTextLine(String text);
/**
* Builds a literal text line.
*
* @param text text
* @param forceLineBreak add an explicit line break if true.
* @return this builder
*/
MarkupDocBuilder literalTextLine(String text, boolean forceLineBreak);
/**
* Builds a literal text.
*
* @param text text
* @return this builder
*/
MarkupDocBuilder literalText(String text);
/**
* Builds a bold text line.<br>
* This is an alias for {@link #boldTextLine(String, boolean) boldTextLine(text, false)}.
*
* @param text text
* @return this builder
*/
MarkupDocBuilder boldTextLine(String text);
/**
* Builds a bold text line.
*
* @param text text
* @param forceLineBreak add an explicit line break if true.
* @return this builder
*/
MarkupDocBuilder boldTextLine(String text, boolean forceLineBreak);
/**
* Builds a bold text.
*
* @param text text
* @return this builder
*/
MarkupDocBuilder boldText(String text);
/**
* Builds an italic text line.<br>
* This is an alias for {@link #italicTextLine(String, boolean) italicTextLine(text, false)}.
*
* @param text text
* @return this builder
*/
MarkupDocBuilder italicTextLine(String text);
/**
* Builds an italic text line.
*
* @param text text
* @param forceLineBreak add an explicit line break if true.
* @return this builder
*/
MarkupDocBuilder italicTextLine(String text, boolean forceLineBreak);
/**
* Builds an italic text.
*
* @param text text
* @return this builder
*/
MarkupDocBuilder italicText(String text);
/**
* Builds an unordered item list
*
* @param list list of items
* @return this builder
*/
MarkupDocBuilder unorderedList(List<String> list);
/**
* Builds a single list item
*
* @param item item
* @return this builder
*/
MarkupDocBuilder unorderedListItem(String item);
/**
* Builds a table without column specifiers, using specified cell values.<br>
* This is an alias for {@link #tableWithColumnSpecs(List, List) tableWithColumnSpecs(null, cells)}.<br>
* Limited support : Markdown does not support table without headers.
*
* @param cells cell values
* @return this builder
*/
MarkupDocBuilder table(List<List<String>> cells);
/**
* Builds a table with column specifiers, using specified cell values.
*
* @param columnSpecs list of column specifiers. Ignored if null.
* @param cells cell values
* @return this builder
*/
MarkupDocBuilder tableWithColumnSpecs(List<MarkupTableColumn> columnSpecs, List<List<String>> cells);
/**
* Builds a custom {@code anchor} for later reference.<br>
* Specified {@code anchor} will be normalized anyway.<br>
* Limited support : Markdown does not support default text for anchors, and will ignore {@code text}.
*
* @param anchor custom anchor
* @param text default text to display when a cross-reference does not have text itself. Ignored if null.
* @return this builder
*/
MarkupDocBuilder anchor(String anchor, String text);
/**
* Builds a custom {@code anchor} for later reference.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param anchor custom anchor
* @return this builder
*/
MarkupDocBuilder anchor(String anchor);
/**
* Builds an inter-document cross-reference to {@code document}#{@code anchor} with specified {@code text}.<br>
* This is the "raw anchor" version. Use the preferred method {@link #crossReference(String, String, String)} instead.<br>
* Specified {@code anchor} is built as-is, without any normalization.
*
* @param document document to point to. Reference becomes a simple cross-reference if null.
* @param anchor anchor to point to
* @param text display text
* @return this builder
*/
MarkupDocBuilder crossReferenceRaw(String document, String anchor, String text);
/**
* Builds an cross-reference to local document {@code anchor} with specified {@code text}.<br>
* This is the "raw anchor" version. Use the preferred method {@link #crossReference(String, String)} instead.<br>
* Specified {@code anchor} is built as-is, without any normalization.
*
* @param anchor anchor to point to
* @param text display text
* @return this builder
*/
MarkupDocBuilder crossReferenceRaw(String anchor, String text);
/**
* Builds an cross-reference to local document {@code anchor}.<br>
* This is the "raw anchor" version. Use the preferred method {@link #crossReference(String)} instead.<br>
* Specified {@code anchor} is built as-is, without any normalization.
*
* @param anchor anchor to point to
* @return this builder
*/
MarkupDocBuilder crossReferenceRaw(String anchor);
/**
* Builds an inter-document cross-reference to {@code document}#{@code anchor} with specified {@code text}.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param document document to point to. Reference becomes a simple cross-reference if null.
* @param anchor anchor to point to
* @param text display text
* @return this builder
*/
MarkupDocBuilder crossReference(String document, String anchor, String text);
/**
* Builds an cross-reference to local document {@code anchor} with specified {@code text}.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param anchor anchor to point to
* @param text display text
* @return this builder
*/
MarkupDocBuilder crossReference(String anchor, String text);
/**
* Builds an cross-reference to local document {@code anchor}.<br>
* Specified {@code anchor} will be normalized anyway.
*
* @param anchor anchor to point to
* @return this builder
*/
MarkupDocBuilder crossReference(String anchor);
/**
* Builds a newline using {@code System.getProperty("line.separator")}.<br>
* This is an alias for {@link #newLine(boolean) newLine(false)}.
*
* @return this builder
*/
MarkupDocBuilder newLine();
/**
* Builds a newline using {@code System.getProperty("line.separator")}.
*
* @param forceLineBreak add an explicit line break if true.
* @return this builder
*/
MarkupDocBuilder newLine(boolean forceLineBreak);
/**
* Import some markup text into this builder.<br>
* This is an alias for {@link #importMarkup(Reader, MarkupLanguage, int) importMarkup(markupText, markupLanguage, 0)}.
*
* @param markupText markup reader to read data from
* @param markupLanguage identify the imported markup language
* @return this builder
*/
MarkupDocBuilder importMarkup(Reader markupText, MarkupLanguage markupLanguage);
/**
* Import some markup text into this builder.<br>
* If {@code markupLanguage} is different from current builder language, markupText is converted when supported, or conversion is just ignored.<br>
* Currently supported conversions :
* <ul>
* <li> Markdown -&gt; AsciiDoc </li>
* </ul>
* Newlines are normalized in the process.
*
* @param markupText markup reader to read data from
* @param markupLanguage identify the imported markup language
* @param levelOffset adapt section leveling by adding {@code levelOffset} [-5, 5]
* @return this builder
* @throws IllegalArgumentException if levelOffset is too high for the imported markup
*/
MarkupDocBuilder importMarkup(Reader markupText, MarkupLanguage markupLanguage, int levelOffset);
/**
* Returns a string representation of the document.
*/
String toString();
/**
* Configure this builder to prefix all generated anchors with {@code prefix}.
*
* @param prefix anchor prefix
* @return this builder
*/
MarkupDocBuilder withAnchorPrefix(String prefix);
/**
* @return anchor prefix configuration
*/
String getAnchorPrefix();
/**
* Builds a new instance of this builder with a state copy.
*
* @param copyBuffer copy current buffer into the new instance
* @return new builder instance with a state copy
*/
MarkupDocBuilder copy(boolean copyBuffer);
/**
* Add an extension to fileName depending on markup language.
*
* @param fileName without extension
* @return fileName with an extension
*/
String addFileExtension(String fileName);
/**
* Add an extension to file depending on markup language.
*
* @param file without extension
* @return file with an extension
*/
Path addFileExtension(Path file);
/**
* Writes the content of the builder to a file.<br>
* An extension will be dynamically added to fileName depending on the markup language.
*
* @param file the generated file without extension
* @param charset the the charset to use for encoding
* @param options the file open options
*/
void writeToFile(Path file, Charset charset, OpenOption... options);
/**
* Writes the content of the builder to a file.
*
* @param file the generated file
* @param charset the the charset to use for encoding
* @param options the file open options
*/
void writeToFileWithoutExtension(Path file, Charset charset, OpenOption... options);
}

View File

@@ -0,0 +1,115 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder;
import io.github.swagger2markup.markup.builder.internal.asciidoc.AsciiDocBuilder;
import io.github.swagger2markup.markup.builder.internal.confluenceMarkup.ConfluenceMarkupBuilder;
import io.github.swagger2markup.markup.builder.internal.markdown.MarkdownBuilder;
/**
* @author Robert Winkler
*/
public final class MarkupDocBuilders {
private MarkupDocBuilders() {
}
/**
* Creates a MarkupDocBuilder which uses the system line separator.
*
* @param markupLanguage the markup language which is used to generate the files
* @return a MarkupDocBuilder
*/
public static MarkupDocBuilder documentBuilder(MarkupLanguage markupLanguage) {
switch (markupLanguage) {
case MARKDOWN:
return new MarkdownBuilder();
case ASCIIDOC:
return new AsciiDocBuilder();
case CONFLUENCE_MARKUP:
return new ConfluenceMarkupBuilder();
default:
throw new IllegalArgumentException(String.format("Unsupported markup language %s", markupLanguage));
}
}
/**
* Creates a MarkupDocBuilder which uses a custom line separator.
* If the custom line separator is null, it uses the system line separator.
*
* @param markupLanguage the markup language which is used to generate the files
* @param lineSeparator the line separator which should be used
* @return a MarkupDocBuilder
*/
public static MarkupDocBuilder documentBuilder(MarkupLanguage markupLanguage, LineSeparator lineSeparator) {
switch (markupLanguage) {
case MARKDOWN:
if (lineSeparator == null)
return new MarkdownBuilder();
else
return new MarkdownBuilder(lineSeparator.toString());
case ASCIIDOC:
if (lineSeparator == null)
return new AsciiDocBuilder();
else
return new AsciiDocBuilder(lineSeparator.toString());
case CONFLUENCE_MARKUP:
if (lineSeparator == null)
return new ConfluenceMarkupBuilder();
else
return new ConfluenceMarkupBuilder(lineSeparator.toString());
default:
throw new IllegalArgumentException(String.format("Unsupported markup language %s", markupLanguage));
}
}
/**
* Creates a MarkupDocBuilder which uses a custom line separator.
* If the custom line separator is null, it uses the system line separator.
* There is a possibility asciidoc generator pegdown (<a href="https://github.com/sirthias/pegdown#parsing-timeouts">optional</a>) can
* take more time. The default is set to two seconds. To override pass value greater than two seconds.
*
* @param markupLanguage the markup language which is used to generate the files
* @param lineSeparator the line separator which should be used
* @param asciidocPegdownTimeoutMillis asciidoc generator timeout
* @return a MarkupDocBuilder
*/
public static MarkupDocBuilder documentBuilder(MarkupLanguage markupLanguage, LineSeparator lineSeparator, int asciidocPegdownTimeoutMillis) {
switch (markupLanguage) {
case MARKDOWN:
if (lineSeparator == null)
return new MarkdownBuilder();
else
return new MarkdownBuilder(lineSeparator.toString());
case ASCIIDOC:
if (lineSeparator == null)
return new AsciiDocBuilder(asciidocPegdownTimeoutMillis);
else
return new AsciiDocBuilder(lineSeparator.toString(), asciidocPegdownTimeoutMillis);
case CONFLUENCE_MARKUP:
if (lineSeparator == null)
return new ConfluenceMarkupBuilder();
else
return new ConfluenceMarkupBuilder(lineSeparator.toString());
default:
throw new IllegalArgumentException(String.format("Unsupported markup language %s", markupLanguage));
}
}
}

View File

@@ -0,0 +1,45 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder;
import java.util.Arrays;
import java.util.List;
/**
* @author Robert Winkler
*/
public enum MarkupLanguage {
ASCIIDOC(".adoc,.asciidoc"),
MARKDOWN(".md,.markdown"),
CONFLUENCE_MARKUP(".txt");
private final String fileNameExtensions;
/**
* @param fileNameExtensions file name suffix
*/
private MarkupLanguage(final String fileNameExtensions) {
this.fileNameExtensions = fileNameExtensions;
}
public List<String> getFileNameExtensions() {
return Arrays.asList(fileNameExtensions.split(","));
}
}

View File

@@ -0,0 +1,87 @@
package io.github.swagger2markup.markup.builder;
import java.util.HashMap;
import java.util.Map;
public class MarkupTableColumn {
public String header;
public boolean headerColumn = false;
public Integer widthRatio = 0;
public Map<MarkupLanguage, String> markupSpecifiers = new HashMap<>();
/**
* Empty constructor
*/
public MarkupTableColumn() {
}
/**
* Header constructor.
*
* @param header header name
*/
public MarkupTableColumn(String header) {
this.header = header;
}
/**
* Header and specifiers constructor.
*
* @param header header
* @param headerColumn set column as an header column.
* @param widthRatio width ratio
*/
public MarkupTableColumn(String header, boolean headerColumn, Integer widthRatio) {
this.header = header;
this.headerColumn = headerColumn;
this.widthRatio = widthRatio;
}
/**
* Set header name for this column.
*
* @param header header name
* @return this builder
*/
public MarkupTableColumn withHeader(String header) {
this.header = header;
return this;
}
/**
* Set column as an header column.<br>
* Limited support : Markdown does not support header column and will ignore it.
*
* @param headerColumn configuration value
* @return this builder
*/
public MarkupTableColumn withHeaderColumn(boolean headerColumn) {
this.headerColumn = headerColumn;
return this;
}
/**
* Set column width ratio for this column.<br>
* Limited support : Markdown does not support column width specifiers and will ignore {@code widthRatio}.
*
* @param widthRatio width ratio integer value [0-100]. Accept relative width specifiers (e.g.: 1, 2, 3, .. with sum of width ratios for all columns != 100).
* @return this builder
*/
public MarkupTableColumn withWidthRatio(Integer widthRatio) {
this.widthRatio = widthRatio;
return this;
}
/**
* Overrides all other specifiers for the specified {@code language} with this language-dependent {@code specifiers} string.<br>
* This method should be used as a last resort.
*
* @param language apply the {@code specifiers} to this language only
* @param specifiers RAW language-dependent specifiers string for the column
* @return this builder
*/
public MarkupTableColumn withMarkupSpecifiers(MarkupLanguage language, String specifiers) {
this.markupSpecifiers.put(language, specifiers);
return this;
}
}

View File

@@ -0,0 +1,558 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.internal;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.text.Normalizer;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.github.swagger2markup.markup.builder.MarkupBlockStyle;
import io.github.swagger2markup.markup.builder.MarkupDocBuilder;
import io.github.swagger2markup.markup.builder.MarkupLanguage;
import io.github.swagger2markup.markup.builder.internal.asciidoc.AsciiDocConverterExtension;
import static org.apache.commons.lang3.StringUtils.defaultString;
/**
* @author Robert Winkler
*/
public abstract class AbstractMarkupDocBuilder implements MarkupDocBuilder {
/**
* Explicit line break default behavior for line returns, when not specified. Please, change documentation accordingly.
*/
protected static final boolean LINE_BREAK_DEFAULT = false;
protected static final Pattern ANCHOR_UNIGNORABLE_PATTERN = Pattern.compile("[^0-9a-zA-Z-_]+");
protected static final Pattern ANCHOR_IGNORABLE_PATTERN = Pattern.compile("[\\s@#&(){}\\[\\]!$*%+=/:.;,?\\\\<>|]+");
protected static final String ANCHOR_SEPARATION_CHARACTERS = "_-";
protected static final int MAX_TITLE_LEVEL = 5;
protected static final String NEW_LINES = "\\r\\n|\\r|\\n";
protected static final String WHITESPACE = " ";
protected static final int ASCIIDOC_PEGDOWN_DEFUALT_MILLIS = 2000;
protected StringBuilder documentBuilder = new StringBuilder();
protected String newLine;
protected int asciidocPegdownTimeoutMillis;
protected Logger logger = LoggerFactory.getLogger(getClass());
protected String anchorPrefix = null;
public AbstractMarkupDocBuilder() {
this(System.getProperty("line.separator"), ASCIIDOC_PEGDOWN_DEFUALT_MILLIS);
}
public AbstractMarkupDocBuilder(String newLine) {
this(newLine, ASCIIDOC_PEGDOWN_DEFUALT_MILLIS);
}
public AbstractMarkupDocBuilder(String newLine, int asciidocPegdownTimeoutMillis) {
this.newLine = newLine;
this.asciidocPegdownTimeoutMillis = asciidocPegdownTimeoutMillis;
}
protected abstract MarkupLanguage getMarkupLanguage();
@Override
public MarkupDocBuilder withAnchorPrefix(String prefix) {
this.anchorPrefix = prefix;
return this;
}
@Override
public String getAnchorPrefix() {
return this.anchorPrefix;
}
protected void documentTitle(Markup markup, String title) {
Validate.notBlank(title, "title must not be blank");
documentBuilder.append(markup).append(replaceNewLinesWithWhiteSpace(title)).append(newLine).append(newLine);
}
protected void sectionTitleLevel(Markup markup, int level, String title) {
Validate.notBlank(title, "title must not be blank");
Validate.inclusiveBetween(1, MAX_TITLE_LEVEL, level);
documentBuilder.append(newLine);
documentBuilder.append(StringUtils.repeat(markup.toString(), level + 1)).append(" ").append(replaceNewLinesWithWhiteSpace(title)).append(newLine);
}
protected void sectionTitleWithAnchorLevel(Markup markup, int level, String title, String anchor) {
Validate.notBlank(title, "title must not be blank");
Validate.inclusiveBetween(1, MAX_TITLE_LEVEL, level);
documentBuilder.append(newLine);
if (anchor == null)
anchor = title;
anchor(replaceNewLinesWithWhiteSpace(anchor)).newLine();
documentBuilder.append(StringUtils.repeat(markup.toString(), level + 1)).append(" ").append(replaceNewLinesWithWhiteSpace(title)).append(newLine);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel(int level, String title) {
return sectionTitleWithAnchorLevel(level, title, null);
}
@Override
public MarkupDocBuilder sectionTitleLevel1(String title) {
return sectionTitleLevel(1, title);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel1(String title, String anchor) {
return sectionTitleWithAnchorLevel(1, title, anchor);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel1(String title) {
return sectionTitleWithAnchorLevel1(title, null);
}
@Override
public MarkupDocBuilder sectionTitleLevel2(String title) {
return sectionTitleLevel(2, title);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel2(String title, String anchor) {
return sectionTitleWithAnchorLevel(2, title, anchor);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel2(String title) {
return sectionTitleWithAnchorLevel2(title, null);
}
@Override
public MarkupDocBuilder sectionTitleLevel3(String title) {
return sectionTitleLevel(3, title);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel3(String title, String anchor) {
return sectionTitleWithAnchorLevel(3, title, anchor);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel3(String title) {
return sectionTitleWithAnchorLevel3(title, null);
}
@Override
public MarkupDocBuilder sectionTitleLevel4(String title) {
return sectionTitleLevel(4, title);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel4(String title, String anchor) {
return sectionTitleWithAnchorLevel(4, title, anchor);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel4(String title) {
return sectionTitleWithAnchorLevel4(title, null);
}
@Override
public MarkupDocBuilder sectionTitleLevel5(String title) {
return sectionTitleLevel(5, title);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel5(String title, String anchor) {
return sectionTitleWithAnchorLevel(5, title, anchor);
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel5(String title) {
return sectionTitleWithAnchorLevel5(title, null);
}
@Override
public MarkupDocBuilder textLine(String text, boolean forceLineBreak) {
Validate.notNull(text, "text must not be null");
text(replaceNewLines(text));
newLine(forceLineBreak);
return this;
}
@Override
public MarkupDocBuilder textLine(String text) {
textLine(text, LINE_BREAK_DEFAULT);
return this;
}
@Override
public MarkupDocBuilder text(String text) {
Validate.notNull(text, "text must not be null");
documentBuilder.append(replaceNewLines(text));
return this;
}
@Override
public MarkupDocBuilder paragraph(String text) {
return paragraph(text, false);
}
@Override
public MarkupDocBuilder block(String text, MarkupBlockStyle style) {
Validate.notBlank(text, "text must not be blank");
return block(replaceNewLines(text), style, null, null);
}
@Override
public MarkupDocBuilder listingBlock(String text) {
Validate.notBlank(text, "text must not be blank");
return listingBlock(replaceNewLines(text), null);
}
protected void delimitedBlockText(Markup begin, String text, Markup end, boolean skipLeadingNewline) {
Validate.notBlank(text, "text must not be blank");
if (!StringUtils.isBlank(begin.toString()))
documentBuilder.append(begin);
if (!skipLeadingNewline)
documentBuilder.append(newLine);
documentBuilder.append(replaceNewLines(text)).append(newLine);
if (!StringUtils.isBlank(end.toString()))
documentBuilder.append(end).append(newLine);
documentBuilder.append(newLine);
}
protected void delimitedBlockText(Markup begin, String text, Markup end) {
Validate.notBlank(text, "text must not be blank");
if (!StringUtils.isBlank(begin.toString()))
documentBuilder.append(begin).append(newLine);
documentBuilder.append(replaceNewLines(text)).append(newLine);
if (!StringUtils.isBlank(end.toString()))
documentBuilder.append(end).append(newLine);
documentBuilder.append(newLine);
}
protected void delimitedTextWithoutLineBreaks(Markup begin, String text, Markup end) {
Validate.notBlank(text, "text must not be blank");
if (!StringUtils.isBlank(begin.toString()))
documentBuilder.append(begin);
documentBuilder.append(replaceNewLines(text));
if (!StringUtils.isBlank(end.toString()))
documentBuilder.append(end);
}
protected void delimitedBlockText(Markup markup, String text) {
delimitedBlockText(markup, text, markup);
}
protected void delimitedTextWithoutLineBreaks(Markup markup, String text) {
delimitedTextWithoutLineBreaks(markup, text, markup);
}
protected void literalText(Markup markup, String text) {
delimitedTextWithoutLineBreaks(markup, text);
}
@Override
public MarkupDocBuilder literalTextLine(String text, boolean forceLineBreak) {
Validate.notBlank(text, "text must not be blank");
literalText(replaceNewLines(text));
newLine(forceLineBreak);
return this;
}
@Override
public MarkupDocBuilder literalTextLine(String text) {
return literalTextLine(text, LINE_BREAK_DEFAULT);
}
protected void boldText(Markup markup, String text) {
delimitedTextWithoutLineBreaks(markup, text);
}
@Override
public MarkupDocBuilder boldTextLine(String text, boolean forceLineBreak) {
Validate.notBlank(text, "text must not be blank");
boldText(replaceNewLines(text));
newLine(forceLineBreak);
return this;
}
@Override
public MarkupDocBuilder boldTextLine(String text) {
return boldTextLine(text, LINE_BREAK_DEFAULT);
}
protected void italicText(Markup markup, String text) {
delimitedTextWithoutLineBreaks(markup, text);
}
@Override
public MarkupDocBuilder italicTextLine(String text, boolean forceLineBreak) {
italicText(text);
newLine(forceLineBreak);
return this;
}
@Override
public MarkupDocBuilder italicTextLine(String text) {
return italicTextLine(text, LINE_BREAK_DEFAULT);
}
protected void unorderedList(Markup markup, List<String> list) {
Validate.notEmpty(list, "list must not be empty");
documentBuilder.append(newLine);
for (String listEntry : list) {
unorderedListItem(markup, listEntry);
}
documentBuilder.append(newLine);
}
protected void unorderedListItem(Markup markup, String item) {
Validate.notBlank(item, "item must not be blank");
documentBuilder.append(markup).append(item).append(newLine);
}
@Override
public MarkupDocBuilder anchor(String anchor) {
Validate.notBlank(anchor, "anchor must not be blank");
return anchor(anchor, null);
}
/*
* Generic normalization algorithm for all markups (less common denominator character set).
* Key points :
* - Anchor is normalized (Normalized.Form.NFD)
* - Punctuations (excluding [-_]) and spaces are replaced with escape character (depends on markup : Markup.E)
* - Beginning, ending separation characters [-_] are ignored, repeating separation characters are simplified (keep first one)
* - Anchor is trimmed and lower cased
* - If the anchor still contains forbidden characters (non-ASCII, ...), replace the whole anchor with an hash (MD5).
* - Add the anchor prefix if configured
*/
protected String normalizeAnchor(Markup spaceEscape, String anchor) {
String normalizedAnchor = defaultString(anchorPrefix) + anchor.trim();
normalizedAnchor = Normalizer.normalize(normalizedAnchor, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
normalizedAnchor = ANCHOR_IGNORABLE_PATTERN.matcher(normalizedAnchor).replaceAll(spaceEscape.toString());
normalizedAnchor = normalizedAnchor.replaceAll(String.format("([%1$s])([%1$s]+)", ANCHOR_SEPARATION_CHARACTERS), "$1");
normalizedAnchor = StringUtils.strip(normalizedAnchor, ANCHOR_SEPARATION_CHARACTERS);
normalizedAnchor = normalizedAnchor.trim().toLowerCase();
String validAnchor = ANCHOR_UNIGNORABLE_PATTERN.matcher(normalizedAnchor).replaceAll("");
if (validAnchor.length() != normalizedAnchor.length())
normalizedAnchor = DigestUtils.md5Hex(normalizedAnchor);
else
normalizedAnchor = validAnchor;
return normalizedAnchor;
}
@Override
public MarkupDocBuilder crossReferenceRaw(String anchor, String text) {
return crossReferenceRaw(null, anchor, text);
}
@Override
public MarkupDocBuilder crossReferenceRaw(String anchor) {
return crossReferenceRaw(null, anchor, null);
}
@Override
public MarkupDocBuilder crossReference(String anchor, String text) {
return crossReference(null, anchor, text);
}
@Override
public MarkupDocBuilder crossReference(String anchor) {
return crossReference(null, anchor, null);
}
protected void newLine(Markup markup, boolean forceLineBreak) {
if (forceLineBreak)
documentBuilder.append(markup);
documentBuilder.append(newLine);
}
@Override
public MarkupDocBuilder newLine() {
newLine(LINE_BREAK_DEFAULT);
return this;
}
@Override
public MarkupDocBuilder importMarkup(Reader markupText, MarkupLanguage markupLanguage) {
Validate.notNull(markupText, "markupText must not be null");
Validate.notNull(markupLanguage, "markupLanguage must not be null");
return importMarkup(markupText, markupLanguage, 0);
}
protected String convert(String markupText, MarkupLanguage markupLanguage) {
if (markupLanguage == getMarkupLanguage())
return markupText;
else {
if (markupLanguage == MarkupLanguage.MARKDOWN && getMarkupLanguage() == MarkupLanguage.ASCIIDOC) {
return AsciiDocConverterExtension.convertMarkdownToAsciiDoc(markupText, asciidocPegdownTimeoutMillis) + newLine;
} else {
return markupText;
}
}
}
protected void importMarkupStyle1(Pattern titlePattern, Markup titlePrefix, Reader markupText, MarkupLanguage markupLanguage, int levelOffset) {
Validate.isTrue(levelOffset <= MAX_TITLE_LEVEL, String.format("Specified levelOffset (%d) > max levelOffset (%d)", levelOffset, MAX_TITLE_LEVEL));
Validate.isTrue(levelOffset >= -MAX_TITLE_LEVEL, String.format("Specified levelOffset (%d) < min levelOffset (%d)", levelOffset, -MAX_TITLE_LEVEL));
StringBuffer leveledText = new StringBuffer();
try (BufferedReader bufferedReader = new BufferedReader(markupText)) {
String readLine;
while ((readLine = bufferedReader.readLine()) != null) {
Matcher titleMatcher = titlePattern.matcher(readLine);
while (titleMatcher.find()) {
int titleLevel = titleMatcher.group(1).length() - 1;
String title = titleMatcher.group(2);
if (titleLevel + levelOffset > MAX_TITLE_LEVEL)
throw new IllegalArgumentException(String.format("Specified levelOffset (%d) set title '%s' level (%d) > max title level (%d)", levelOffset, title, titleLevel, MAX_TITLE_LEVEL));
if (titleLevel + levelOffset < 0)
throw new IllegalArgumentException(String.format("Specified levelOffset (%d) set title '%s' level (%d) < 0", levelOffset, title, titleLevel));
else
titleMatcher.appendReplacement(leveledText, Matcher.quoteReplacement(String.format("%s %s", StringUtils.repeat(titlePrefix.toString(), 1 + titleLevel + levelOffset), title)));
}
titleMatcher.appendTail(leveledText);
leveledText.append(newLine);
}
} catch (IOException e) {
throw new RuntimeException("Failed to import Markup", e);
}
if (!StringUtils.isBlank(leveledText)) {
documentBuilder.append(newLine);
documentBuilder.append(convert(leveledText.toString(), markupLanguage));
documentBuilder.append(newLine);
}
}
protected void importMarkupStyle2(Pattern titlePattern, String titleFormat, boolean startFrom0, Reader markupText, MarkupLanguage markupLanguage, int levelOffset) {
Validate.isTrue(levelOffset <= MAX_TITLE_LEVEL, String.format("Specified levelOffset (%d) > max levelOffset (%d)", levelOffset, MAX_TITLE_LEVEL));
Validate.isTrue(levelOffset >= -MAX_TITLE_LEVEL, String.format("Specified levelOffset (%d) < min levelOffset (%d)", levelOffset, -MAX_TITLE_LEVEL));
StringBuffer leveledText = new StringBuffer();
try (BufferedReader bufferedReader = new BufferedReader(markupText)) {
String readLine;
while ((readLine = bufferedReader.readLine()) != null) {
Matcher titleMatcher = titlePattern.matcher(readLine);
while (titleMatcher.find()) {
int titleLevel = Integer.valueOf(titleMatcher.group(1)) - (startFrom0 ? 0 : 1);
String title = titleMatcher.group(2);
if (titleLevel + levelOffset > MAX_TITLE_LEVEL)
throw new IllegalArgumentException(String.format("Specified levelOffset (%d) set title '%s' level (%d) > max title level (%d)", levelOffset, title, titleLevel, MAX_TITLE_LEVEL));
if (titleLevel + levelOffset < 0)
throw new IllegalArgumentException(String.format("Specified levelOffset (%d) set title '%s' level (%d) < 0", levelOffset, title, titleLevel));
else
titleMatcher.appendReplacement(leveledText, Matcher.quoteReplacement(String.format(titleFormat, (startFrom0 ? 0 : 1) + titleLevel + levelOffset, title)));
}
titleMatcher.appendTail(leveledText);
leveledText.append(newLine);
}
} catch (IOException e) {
throw new RuntimeException("Failed to import Markup", e);
}
if (!StringUtils.isBlank(leveledText)) {
documentBuilder.append(newLine);
documentBuilder.append(convert(leveledText.toString(), markupLanguage));
documentBuilder.append(newLine);
}
}
@Override
public MarkupDocBuilder table(List<List<String>> cells) {
Validate.notEmpty(cells, "cells must not be null");
return tableWithColumnSpecs(null, cells);
}
@Override
public String toString() {
return documentBuilder.toString();
}
@Override
public Path addFileExtension(Path file) {
return file.resolveSibling(addFileExtension(file.getFileName().toString()));
}
/**
* 2 newLines are needed at the end of file for file to be included without protection.
*/
@Override
public void writeToFileWithoutExtension(Path file, Charset charset, OpenOption... options) {
// Support relative file names both of "filename" and "./filename"
if (file.getParent() != null) {
try {
Files.createDirectories(file.getParent());
} catch (IOException e) {
throw new RuntimeException("Failed create directory", e);
}
}
try (BufferedWriter writer = Files.newBufferedWriter(file, charset, options)) {
writer.write(toString());
writer.write(newLine);
writer.write(newLine);
} catch (IOException e) {
throw new RuntimeException("Failed to write file", e);
}
if (logger.isInfoEnabled()) {
logger.info("Markup document written to: {}", file);
}
}
public String replaceNewLines(String content, String replacement) {
return content.replaceAll(NEW_LINES, Matcher.quoteReplacement(replacement));
}
public String replaceNewLines(String content) {
return replaceNewLines(content, newLine);
}
public String replaceNewLinesWithWhiteSpace(String content) {
return replaceNewLines(content, WHITESPACE);
}
@Override
public void writeToFile(Path file, Charset charset, OpenOption... options) {
writeToFileWithoutExtension(file.resolveSibling(addFileExtension(file.getFileName().toString())), charset, options);
}
}

View File

@@ -0,0 +1,26 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.internal;
/**
* @author Robert Winkler
*/
public interface Markup {
String toString();
}

View File

@@ -0,0 +1,60 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.internal.asciidoc;
import io.github.swagger2markup.markup.builder.internal.Markup;
/**
* @author Robert Winkler
*/
public enum AsciiDoc implements Markup {
ATTRIBUTE(":"),
TABLE("|==="),
TABLE_COLUMN_DELIMITER("|"),
TITLE("="),
DOCUMENT_TITLE("= "),
LITERAL("`"),
BOLD("**"),
ITALIC("__"),
LIST_ENTRY("* "),
CROSS_REFERENCE_START("<<"),
CROSS_REFERENCE_END(">>"),
ANCHOR_START("[["),
ANCHOR_END("]]"),
SPACE_ESCAPE("_"),
LINE_BREAK(" +");
private final String markup;
/**
* @param markup AsciiDoc markup
*/
AsciiDoc(final String markup) {
this.markup = markup;
}
/* (non-Javadoc)
* @see java.lang.Enum#toString()
*/
@Override
public String toString() {
return markup;
}
}

View File

@@ -0,0 +1,274 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.internal.asciidoc;
import io.github.swagger2markup.markup.builder.*;
import io.github.swagger2markup.markup.builder.internal.AbstractMarkupDocBuilder;
import io.github.swagger2markup.markup.builder.internal.Markup;
import org.apache.commons.lang3.Validate;
import java.io.File;
import java.io.Reader;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.*;
/**
* @author Robert Winkler
*/
public class AsciiDocBuilder extends AbstractMarkupDocBuilder {
private static final Pattern TITLE_PATTERN = Pattern.compile(String.format("^(%s{1,%d})\\s+(.*)$", AsciiDoc.TITLE, MAX_TITLE_LEVEL + 1));
private static final Map<MarkupBlockStyle, String> BLOCK_STYLE = new HashMap<MarkupBlockStyle, String>() {{
put(MarkupBlockStyle.EXAMPLE, "====");
put(MarkupBlockStyle.LISTING, "----");
put(MarkupBlockStyle.LITERAL, "....");
put(MarkupBlockStyle.PASSTHROUGH, "++++");
put(MarkupBlockStyle.SIDEBAR, "****");
}};
public AsciiDocBuilder() {
super();
}
public AsciiDocBuilder(int asciidocPegdownTimeoutMillis) {
super(System.getProperty("line.separator"), asciidocPegdownTimeoutMillis);
}
public AsciiDocBuilder(String newLine) {
super(newLine);
}
public AsciiDocBuilder(String newLine, int asciidocPegdownTimeoutMillis) {
super(newLine, asciidocPegdownTimeoutMillis);
}
protected MarkupLanguage getMarkupLanguage() {
return MarkupLanguage.ASCIIDOC;
}
@Override
public MarkupDocBuilder copy(boolean copyBuffer) {
AsciiDocBuilder builder = new AsciiDocBuilder(newLine, asciidocPegdownTimeoutMillis);
if (copyBuffer)
builder.documentBuilder = new StringBuilder(this.documentBuilder);
return builder.withAnchorPrefix(anchorPrefix);
}
@Override
public MarkupDocBuilder documentTitle(String title) {
documentTitle(AsciiDoc.DOCUMENT_TITLE, title);
return this;
}
@Override
public MarkupDocBuilder sectionTitleLevel(int level, String title) {
sectionTitleLevel(AsciiDoc.TITLE, level, title);
return this;
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel(int level, String title, String anchor) {
sectionTitleWithAnchorLevel(AsciiDoc.TITLE, level, title, anchor);
return this;
}
@Override
public MarkupDocBuilder paragraph(String text, boolean hardbreaks) {
Validate.notBlank(text, "text must not be blank");
if (hardbreaks)
documentBuilder.append("[%hardbreaks]").append(newLine);
text = text.trim();
documentBuilder.append(replaceNewLines(text)).append(newLine).append(newLine);
return this;
}
@Override
public MarkupDocBuilder pageBreak() {
documentBuilder.append(newLine).append("<<<").append(newLine);
return this;
}
@Override
public MarkupDocBuilder block(String text, final MarkupBlockStyle style, String title, MarkupAdmonition admonition) {
if (admonition != null)
documentBuilder.append("[").append(admonition).append("]").append(newLine);
if (title != null)
documentBuilder.append(".").append(title).append(newLine);
delimitedBlockText(new Markup() {
public String toString() {
return BLOCK_STYLE.get(style);
}
}, text);
return this;
}
@Override
public MarkupDocBuilder literalText(String text) {
boldText(AsciiDoc.LITERAL, text);
return this;
}
@Override
public MarkupDocBuilder boldText(String text) {
boldText(AsciiDoc.BOLD, text);
return this;
}
@Override
public MarkupDocBuilder italicText(String text) {
italicText(AsciiDoc.ITALIC, text);
return this;
}
@Override
public MarkupDocBuilder unorderedList(List<String> list) {
unorderedList(AsciiDoc.LIST_ENTRY, list);
return this;
}
@Override
public MarkupDocBuilder unorderedListItem(String item) {
unorderedListItem(AsciiDoc.LIST_ENTRY, item);
return this;
}
@Override
public MarkupDocBuilder listingBlock(String text, String language) {
if (language != null)
documentBuilder.append(String.format("[source,%s]", language)).append(newLine);
block(text, MarkupBlockStyle.LISTING);
return this;
}
private String normalizeAnchor(String anchor) {
String normalizedAnchor = "_" + normalizeAnchor(AsciiDoc.SPACE_ESCAPE, anchor);
if (normalizedAnchor.endsWith("-"))
normalizedAnchor += "_";
return normalizedAnchor;
}
/**
* Partial workaround for https://github.com/asciidoctor/asciidoctor/issues/844
*/
private String normalizeDocument(String document) {
if (document == null)
return null;
return new File(document).toPath().normalize().toString();
}
@Override
public MarkupDocBuilder anchor(String anchor, String text) {
documentBuilder.append(AsciiDoc.ANCHOR_START).append(normalizeAnchor(anchor));
if (text != null)
documentBuilder.append(",").append(text);
documentBuilder.append(AsciiDoc.ANCHOR_END);
return this;
}
@Override
public MarkupDocBuilder crossReferenceRaw(String document, String anchor, String text) {
documentBuilder.append(AsciiDoc.CROSS_REFERENCE_START);
if (document != null)
documentBuilder.append(document).append("#");
documentBuilder.append(anchor);
if (text != null) {
documentBuilder.append(",").append(text);
if (text.endsWith(">"))
documentBuilder.append(" ");
}
documentBuilder.append(AsciiDoc.CROSS_REFERENCE_END);
return this;
}
@Override
public MarkupDocBuilder crossReference(String document, String anchor, String text) {
return crossReferenceRaw(normalizeDocument(document), normalizeAnchor(anchor), text);
}
private String formatTableCell(String cell) {
cell = replaceNewLines(cell.trim());
return cell.replace(AsciiDoc.TABLE_COLUMN_DELIMITER.toString(), "\\" + AsciiDoc.TABLE_COLUMN_DELIMITER.toString());
}
@Override
public MarkupDocBuilder tableWithColumnSpecs(List<MarkupTableColumn> columnSpecs, List<List<String>> cells) {
Validate.notEmpty(cells, "cells must not be null");
Boolean hasHeader = false;
List<String> options = new ArrayList<>();
List<String> cols = new ArrayList<>();
if (columnSpecs != null && !columnSpecs.isEmpty()) {
for (MarkupTableColumn col : columnSpecs) {
if (!hasHeader && isNotBlank(col.header)) {
options.add("header");
hasHeader = true;
}
String languageStyle = col.markupSpecifiers.get(MarkupLanguage.ASCIIDOC);
if (languageStyle != null && isNoneBlank(languageStyle)) {
cols.add(languageStyle);
} else {
cols.add(String.valueOf(col.widthRatio) + (col.headerColumn ? "h" : ""));
}
}
}
newLine();
documentBuilder.append("[options=\"").append(join(options, ",")).append("\", cols=\"").append(join(cols, ",")).append("\"]").append(newLine);
documentBuilder.append(AsciiDoc.TABLE).append(newLine);
if (hasHeader) {
Collection<String> headerList = columnSpecs.stream().map(header -> formatTableCell(defaultString(header.header))).collect(Collectors.toList());
documentBuilder.append(AsciiDoc.TABLE_COLUMN_DELIMITER).append(join(headerList, AsciiDoc.TABLE_COLUMN_DELIMITER.toString())).append(newLine);
}
for (List<String> row : cells) {
Collection<String> cellList = row.stream().map(cell -> formatTableCell(defaultString(cell))).collect(Collectors.toList());
documentBuilder.append(AsciiDoc.TABLE_COLUMN_DELIMITER).append(join(cellList, AsciiDoc.TABLE_COLUMN_DELIMITER.toString())).append(newLine);
}
documentBuilder.append(AsciiDoc.TABLE).append(newLine);
newLine();
return this;
}
@Override
public MarkupDocBuilder newLine(boolean forceLineBreak) {
newLine(AsciiDoc.LINE_BREAK, forceLineBreak);
return this;
}
@Override
public MarkupDocBuilder importMarkup(Reader markupText, MarkupLanguage markupLanguage, int levelOffset) {
importMarkupStyle1(TITLE_PATTERN, AsciiDoc.TITLE, markupText, markupLanguage, levelOffset);
return this;
}
@Override
public String addFileExtension(String fileName) {
return fileName + MarkupLanguage.ASCIIDOC.getFileNameExtensions().get(0);
}
}

View File

@@ -0,0 +1,29 @@
package io.github.swagger2markup.markup.builder.internal.asciidoc;
import org.pegdown.Extensions;
import org.pegdown.PegDownProcessor;
import org.pegdown.ast.RootNode;
import nl.jworks.markdown_to_asciidoc.Converter;
import nl.jworks.markdown_to_asciidoc.ToAsciiDocSerializer;
public class AsciiDocConverterExtension extends Converter {
/**
* Converts markdown to asciidoc.
*
* @param markdown the markdown source to convert
* @param timeoutMills parsing timeout
* @return asciidoc format
*/
public static String convertMarkdownToAsciiDoc(String markdown, long timeoutMills) {
PegDownProcessor processor = new PegDownProcessor(Extensions.ALL, timeoutMills);
// insert blank line before fenced code block if necessary
if (markdown.contains("```")) {
markdown = markdown.replaceAll("(?m)(?<!\n\n)(\\s*)```(\\w*\n)((?:\\1[^\n]*\n)+)\\1```", "\n$1```$2$3$1```");
}
char[] markDown = markdown.toCharArray();
RootNode rootNode = processor.parseMarkdown(markDown);
return new ToAsciiDocSerializer(rootNode, markdown).toAsciiDoc();
}
}

View File

@@ -0,0 +1,54 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.internal.confluenceMarkup;
import io.github.swagger2markup.markup.builder.internal.Markup;
/**
* @author Robert Winkler
*/
public enum ConfluenceMarkup implements Markup {
TABLE_COLUMN_DELIMITER("|"),
LITERAL("{noformat}"),
BOLD("*"),
ITALIC("_"),
LIST_ENTRY("* "),
ANCHOR_START("{anchor:"),
ANCHOR_END("}"),
SPACE_ESCAPE("_"),
LINE_BREAK("\\\\ ");
private final String markup;
/**
* @param markup AsciiDoc markup
*/
ConfluenceMarkup(final String markup) {
this.markup = markup;
}
/* (non-Javadoc)
* @see java.lang.Enum#toString()
*/
@Override
public String toString() {
return markup;
}
}

View File

@@ -0,0 +1,345 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.internal.confluenceMarkup;
import io.github.swagger2markup.markup.builder.*;
import io.github.swagger2markup.markup.builder.internal.AbstractMarkupDocBuilder;
import io.github.swagger2markup.markup.builder.internal.Markup;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringUtils.*;
public final class ConfluenceMarkupBuilder extends AbstractMarkupDocBuilder {
private static final Pattern TITLE_PATTERN = Pattern.compile("^h([0-9])\\.\\s+(.*)$");
private static final String TITLE_FORMAT = "h%d. %s";
private static final Pattern ESCAPE_CELL_PIPE_PATTERN = Pattern.compile("((\\[.*?(?<!\\\\)\\])|(.))");
/**
* Associate macro name to block style.<br>
* ending ':' means the macro supports title attribute.<br>
* '>ADMONITION_BLOCK' means value should refer to {@link #ADMONITION_BLOCK_STYLE}.
*/
private static final Map<MarkupBlockStyle, String> BLOCK_STYLE = new HashMap<MarkupBlockStyle, String>() {{
put(MarkupBlockStyle.EXAMPLE, ">ADMONITION_BLOCK");
put(MarkupBlockStyle.LISTING, "code:");
put(MarkupBlockStyle.LITERAL, "noformat");
put(MarkupBlockStyle.PASSTHROUGH, "html");
put(MarkupBlockStyle.SIDEBAR, ">ADMONITION_BLOCK");
}};
private static final Map<MarkupAdmonition, String> ADMONITION_BLOCK_STYLE = new HashMap<MarkupAdmonition, String>() {{
put(null, "panel:");
put(MarkupAdmonition.CAUTION, "note:");
put(MarkupAdmonition.IMPORTANT, "alert:");
put(MarkupAdmonition.NOTE, "info:");
put(MarkupAdmonition.TIP, "tip:");
put(MarkupAdmonition.WARNING, "warning:");
}};
public ConfluenceMarkupBuilder() {
super();
}
public ConfluenceMarkupBuilder(String newLine) {
super(newLine);
}
protected MarkupLanguage getMarkupLanguage() {
return MarkupLanguage.CONFLUENCE_MARKUP;
}
@Override
public MarkupDocBuilder copy(boolean copyBuffer) {
ConfluenceMarkupBuilder builder = new ConfluenceMarkupBuilder(newLine);
if (copyBuffer)
builder.documentBuilder = new StringBuilder(this.documentBuilder);
return builder.withAnchorPrefix(anchorPrefix);
}
@Override
public MarkupDocBuilder documentTitle(String title) {
Validate.notBlank(title, "title must not be blank");
documentBuilder.append(String.format(TITLE_FORMAT, 1, title));
documentBuilder.append(newLine).append(newLine);
return this;
}
@Override
public MarkupDocBuilder sectionTitleLevel(int level, String title) {
Validate.notBlank(title, "title must not be blank");
Validate.inclusiveBetween(1, MAX_TITLE_LEVEL, level);
documentBuilder.append(newLine);
documentBuilder.append(String.format(TITLE_FORMAT, level + 1, replaceNewLinesWithWhiteSpace(title)));
documentBuilder.append(newLine);
return this;
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel(int level, String title, String anchor) {
Validate.notBlank(title, "title must not be blank");
Validate.inclusiveBetween(1, MAX_TITLE_LEVEL, level);
documentBuilder.append(newLine);
documentBuilder.append(String.format(TITLE_FORMAT, level + 1, replaceNewLinesWithWhiteSpace(title)));
if (isBlank(anchor))
anchor = title;
documentBuilder.append(" ");
anchor(replaceNewLinesWithWhiteSpace(anchor));
documentBuilder.append(newLine);
return this;
}
@Override
public MarkupDocBuilder paragraph(String text, boolean hardbreaks) {
Validate.notBlank(text, "text must not be blank");
text = text.trim();
if (hardbreaks)
text = replaceNewLines(text, ConfluenceMarkup.LINE_BREAK + newLine);
else
text = replaceNewLines(text);
documentBuilder.append(text).append(newLine).append(newLine);
return this;
}
@Override
public MarkupDocBuilder pageBreak() {
documentBuilder.append(newLine).append("<div style='page-break-before:always;'></div>").append(newLine);
return this;
}
@Override
public MarkupDocBuilder block(String text, final MarkupBlockStyle style, String title, MarkupAdmonition admonition) {
String block = BLOCK_STYLE.get(style);
boolean admonitionBlock = block.equals(">ADMONITION_BLOCK");
if (admonitionBlock) {
block = ADMONITION_BLOCK_STYLE.get(admonition);
}
boolean supportTitle = false;
if (block.endsWith(":")) {
supportTitle = true;
block = StringUtils.stripEnd(block, ":");
}
String titleString = null;
if (admonition != null && !admonitionBlock) {
titleString = StringUtils.capitalize(admonition.name().toLowerCase());
}
if (title != null) {
titleString = (titleString == null ? "" : titleString + " | ") + title;
}
final String finalBlock = block;
Markup blockMarkup = new Markup() {
@Override
public String toString() {
return String.format("{%s}", finalBlock);
}
};
if (!supportTitle) {
if (titleString != null)
documentBuilder.append(titleString).append(" : ").append(newLine);
delimitedBlockText(blockMarkup, text);
} else {
final String finalTitleString = titleString;
delimitedBlockText(new Markup() {
@Override
public String toString() {
if (finalTitleString == null)
return String.format("{%s}", finalBlock);
else
return String.format("{%s:title=%s}", finalBlock, finalTitleString);
}
}, text, blockMarkup);
}
return this;
}
@Override
public MarkupDocBuilder listingBlock(String text, final String language) {
Markup blockMarkup = new Markup() {
@Override
public String toString() {
return String.format("{%s}", "code");
}
};
if (language != null) {
delimitedBlockText(new Markup() {
@Override
public String toString() {
return String.format("{code:language=%s}", language);
}
}, text, blockMarkup);
} else {
delimitedBlockText(blockMarkup, text);
}
return this;
}
@Override
public MarkupDocBuilder literalText(String text) {
boldText(ConfluenceMarkup.LITERAL, text);
return this;
}
@Override
public MarkupDocBuilder boldText(String text) {
boldText(ConfluenceMarkup.BOLD, text);
return this;
}
@Override
public MarkupDocBuilder italicText(String text) {
italicText(ConfluenceMarkup.ITALIC, text);
return this;
}
@Override
public MarkupDocBuilder unorderedList(List<String> list) {
unorderedList(ConfluenceMarkup.LIST_ENTRY, list);
return this;
}
@Override
public MarkupDocBuilder unorderedListItem(String item) {
unorderedListItem(ConfluenceMarkup.LIST_ENTRY, item);
return this;
}
@Override
public MarkupDocBuilder tableWithColumnSpecs(List<MarkupTableColumn> columnSpecs, List<List<String>> cells) {
Validate.notEmpty(cells, "cells must not be null");
documentBuilder.append(newLine);
if (columnSpecs != null && !columnSpecs.isEmpty()) {
documentBuilder.append("||");
for (MarkupTableColumn column : columnSpecs) {
documentBuilder.append(formatCellContent(defaultString(column.header))).append("||");
}
documentBuilder.append(newLine);
}
for (List<String> row : cells) {
documentBuilder.append(ConfluenceMarkup.TABLE_COLUMN_DELIMITER);
ListIterator<String> cellIterator = row.listIterator();
while (cellIterator.hasNext()) {
int cellIndex = cellIterator.nextIndex();
if (columnSpecs != null && columnSpecs.size() > cellIndex && columnSpecs.get(cellIndex).headerColumn)
documentBuilder.append(ConfluenceMarkup.TABLE_COLUMN_DELIMITER);
documentBuilder.append(formatCellContent(cellIterator.next())).append(ConfluenceMarkup.TABLE_COLUMN_DELIMITER);
}
documentBuilder.append(newLine);
}
documentBuilder.append(newLine);
return this;
}
private String formatCellContent(String cell) {
cell = replaceNewLines(cell.trim(), ConfluenceMarkup.LINE_BREAK.toString());
if (isBlank(cell)) {
return " ";
}
return escapeCellPipes(cell);
}
private String escapeCellPipes(String cell) {
Matcher m = ESCAPE_CELL_PIPE_PATTERN.matcher(cell);
StringBuffer res = new StringBuffer();
while (m.find()) {
String repl = m.group(1);
if (repl.equals(ConfluenceMarkup.TABLE_COLUMN_DELIMITER.toString()))
repl = "\\" + ConfluenceMarkup.TABLE_COLUMN_DELIMITER.toString();
m.appendReplacement(res, Matcher.quoteReplacement(repl));
}
m.appendTail(res);
return res.toString();
}
private String normalizeAnchor(String anchor) {
return normalizeAnchor(ConfluenceMarkup.SPACE_ESCAPE, anchor);
}
@Override
public MarkupDocBuilder anchor(String anchor, String text) {
documentBuilder.append(ConfluenceMarkup.ANCHOR_START).append(normalizeAnchor(anchor)).append(ConfluenceMarkup.ANCHOR_END);
return this;
}
@Override
public MarkupDocBuilder crossReference(String document, String anchor, String text) {
crossReferenceRaw(document, normalizeAnchor(anchor), text);
return this;
}
@Override
public MarkupDocBuilder crossReferenceRaw(String document, String anchor, String text) {
documentBuilder.append("[");
if (isNotBlank(text)) {
documentBuilder.append(text).append("|");
}
if (isNotBlank(document)) {
documentBuilder.append(document);
}
documentBuilder.append("#").append(anchor);
documentBuilder.append("]");
return this;
}
@Override
public MarkupDocBuilder newLine(boolean forceLineBreak) {
newLine(ConfluenceMarkup.LINE_BREAK, forceLineBreak);
return this;
}
@Override
public MarkupDocBuilder importMarkup(Reader markupText, MarkupLanguage markupLanguage, int levelOffset) {
importMarkupStyle2(TITLE_PATTERN, TITLE_FORMAT, false, markupText, markupLanguage, levelOffset);
return this;
}
@Override
public String addFileExtension(String fileName) {
return fileName + MarkupLanguage.CONFLUENCE_MARKUP.getFileNameExtensions().get(0);
}
}

View File

@@ -0,0 +1,55 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.internal.markdown;
import io.github.swagger2markup.markup.builder.internal.Markup;
/**
* @author Robert Winkler
*/
public enum Markdown implements Markup {
TABLE_COLUMN_DELIMITER("|"),
TABLE_ROW("-"),
LISTING("```"),
TITLE("#"),
DOCUMENT_TITLE("# "),
LITERAL("`"),
BOLD("**"),
ITALIC("*"),
LIST_ENTRY("* "),
SPACE_ESCAPE("-"),
LINE_BREAK(" ");
private final String markup;
/**
* @param markup AsciiDoc markup
*/
private Markdown(final String markup) {
this.markup = markup;
}
/* (non-Javadoc)
* @see java.lang.Enum#toString()
*/
@Override
public String toString() {
return markup;
}
}

View File

@@ -0,0 +1,254 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.internal.markdown;
import io.github.swagger2markup.markup.builder.*;
import io.github.swagger2markup.markup.builder.internal.AbstractMarkupDocBuilder;
import io.github.swagger2markup.markup.builder.internal.Markup;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import java.io.Reader;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.join;
/**
* @author Robert Winkler
*/
public class MarkdownBuilder extends AbstractMarkupDocBuilder {
private static final Pattern TITLE_PATTERN = Pattern.compile(String.format("^(%s{1,%d})\\s+(.*)$", Markdown.TITLE, MAX_TITLE_LEVEL + 1));
private static final Map<MarkupBlockStyle, String> BLOCK_STYLE = new HashMap<MarkupBlockStyle, String>() {{
put(MarkupBlockStyle.EXAMPLE, "");
put(MarkupBlockStyle.LISTING, Markdown.LISTING.toString());
put(MarkupBlockStyle.LITERAL, Markdown.LISTING.toString());
put(MarkupBlockStyle.PASSTHROUGH, "");
put(MarkupBlockStyle.SIDEBAR, "");
}};
public MarkdownBuilder() {
super();
}
public MarkdownBuilder(String newLine) {
super(newLine);
}
protected MarkupLanguage getMarkupLanguage() {
return MarkupLanguage.MARKDOWN;
}
@Override
public MarkupDocBuilder copy(boolean copyBuffer) {
MarkdownBuilder builder = new MarkdownBuilder(newLine);
if (copyBuffer)
builder.documentBuilder = new StringBuilder(this.documentBuilder);
return builder.withAnchorPrefix(anchorPrefix);
}
@Override
public MarkupDocBuilder documentTitle(String title) {
documentTitle(Markdown.DOCUMENT_TITLE, title);
return this;
}
@Override
public MarkupDocBuilder sectionTitleLevel(int level, String title) {
sectionTitleLevel(Markdown.TITLE, level, title);
return this;
}
@Override
public MarkupDocBuilder sectionTitleWithAnchorLevel(int level, String title, String anchor) {
sectionTitleWithAnchorLevel(Markdown.TITLE, level, title, anchor);
return this;
}
@Override
public MarkupDocBuilder paragraph(String text, boolean hardbreaks) {
Validate.notBlank(text, "text must not be blank");
text = text.trim();
if (hardbreaks)
text = replaceNewLines(text, Markdown.LINE_BREAK + newLine);
else
text = replaceNewLines(text);
documentBuilder.append(text).append(newLine).append(newLine);
return this;
}
@Override
public MarkupDocBuilder pageBreak() {
documentBuilder.append(newLine).append("***").append(newLine);
return this;
}
@Override
public MarkupDocBuilder block(String text, final MarkupBlockStyle style, String title, MarkupAdmonition admonition) {
boolean multiline = text.contains(newLine);
if (admonition != null)
documentBuilder.append(StringUtils.capitalize(admonition.name().toLowerCase()));
if (title != null) {
if (admonition != null)
documentBuilder.append(" | ");
documentBuilder.append(title);
}
if (admonition != null || title != null)
documentBuilder.append(" : ").append(newLine);
Markup m = new Markup() {
public String toString() {
return BLOCK_STYLE.get(style);
}
};
if (style == MarkupBlockStyle.LISTING && multiline) {
delimitedBlockText(m, text, m, true);
} else {
delimitedBlockText(m, text, m);
}
return this;
}
@Override
public MarkupDocBuilder listingBlock(String text, String language) {
text = newLine + text;
if (language != null) {
text = language + text;
}
block(text, MarkupBlockStyle.LISTING);
return this;
}
@Override
public MarkupDocBuilder literalText(String text) {
boldText(Markdown.LITERAL, text);
return this;
}
@Override
public MarkupDocBuilder boldText(String text) {
boldText(Markdown.BOLD, text);
return this;
}
@Override
public MarkupDocBuilder italicText(String text) {
italicText(Markdown.ITALIC, text);
return this;
}
@Override
public MarkupDocBuilder unorderedList(List<String> list) {
unorderedList(Markdown.LIST_ENTRY, list);
return this;
}
@Override
public MarkupDocBuilder unorderedListItem(String item) {
unorderedListItem(Markdown.LIST_ENTRY, item);
return this;
}
private String normalizeAnchor(String anchor) {
return normalizeAnchor(Markdown.SPACE_ESCAPE, anchor);
}
@Override
public MarkupDocBuilder anchor(String anchor, String text) {
documentBuilder.append("<a name=\"").append(normalizeAnchor(anchor)).append("\"></a>");
return this;
}
@Override
public MarkupDocBuilder crossReferenceRaw(String document, String anchor, String text) {
if (text == null)
text = anchor.trim();
documentBuilder.append("[").append(text).append("]").append("(");
if (document != null)
documentBuilder.append(document);
documentBuilder.append("#").append(anchor).append(")");
return this;
}
@Override
public MarkupDocBuilder crossReference(String document, String anchor, String text) {
return crossReferenceRaw(document, normalizeAnchor(anchor), text);
}
private String formatTableCell(String cell) {
cell = replaceNewLines(cell.trim(), "<br>");
return cell.replace(Markdown.TABLE_COLUMN_DELIMITER.toString(), "\\" + Markdown.TABLE_COLUMN_DELIMITER.toString());
}
@Override
public MarkupDocBuilder tableWithColumnSpecs(List<MarkupTableColumn> columnSpecs, List<List<String>> cells) {
Validate.notEmpty(cells, "cells must not be null");
newLine();
if (columnSpecs != null && !columnSpecs.isEmpty()) {
Collection<String> headerList = columnSpecs.stream().map(header -> formatTableCell(defaultString(header.header))).collect(Collectors.toList());
documentBuilder.append(Markdown.TABLE_COLUMN_DELIMITER).append(join(headerList, Markdown.TABLE_COLUMN_DELIMITER.toString())).append(Markdown.TABLE_COLUMN_DELIMITER).append(newLine);
documentBuilder.append(Markdown.TABLE_COLUMN_DELIMITER);
columnSpecs.forEach(col -> {
documentBuilder.append(StringUtils.repeat(Markdown.TABLE_ROW.toString(), 3));
documentBuilder.append(Markdown.TABLE_COLUMN_DELIMITER);
});
documentBuilder.append(newLine);
}
for (List<String> row : cells) {
Collection<String> cellList = row.stream().map(cell -> formatTableCell(defaultString(cell))).collect(Collectors.toList());
documentBuilder.append(Markdown.TABLE_COLUMN_DELIMITER).append(join(cellList, Markdown.TABLE_COLUMN_DELIMITER.toString())).append(Markdown.TABLE_COLUMN_DELIMITER).append(newLine);
}
newLine();
return this;
}
@Override
public MarkupDocBuilder newLine(boolean forceLineBreak) {
newLine(Markdown.LINE_BREAK, forceLineBreak);
return this;
}
@Override
public MarkupDocBuilder importMarkup(Reader markupText, MarkupLanguage markupLanguage, int levelOffset) {
importMarkupStyle1(TITLE_PATTERN, Markdown.TITLE, markupText, markupLanguage, levelOffset);
return this;
}
@Override
public String addFileExtension(String fileName) {
return fileName + MarkupLanguage.MARKDOWN.getFileNameExtensions().get(0);
}
}

View File

@@ -0,0 +1,538 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder;
import io.github.swagger2markup.markup.builder.assertions.DiffUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.StringReader;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static junit.framework.TestCase.assertEquals;
import static org.junit.Assert.fail;
/**
* @author Robert Winkler
*/
public class MarkupDocBuilderTest {
private final String newLine = System.getProperty("line.separator");
private List<MarkupTableColumn> tableColumns;
private List<List<String>> tableCells;
@Before
public void setUp() {
tableColumns = Arrays.asList(
new MarkupTableColumn().withHeader("Header1"),
new MarkupTableColumn().withWidthRatio(2),
new MarkupTableColumn().withHeader("Header3").withWidthRatio(1).withHeaderColumn(true));
tableCells = new ArrayList<>();
tableCells.add(Arrays.asList("Row 1 | Column 1", "Row 1 | Column 2", "Row 1 | Column 3"));
tableCells.add(Arrays.asList("Row 2 | Column 1", "Row 2 | Column 2", "Row 2 | Column 3"));
}
@Test
public void testAsciiDoc() throws IOException, URISyntaxException {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC);
builder = builder.documentTitle("Test title")
.sectionTitleLevel(1, "Section Level 1a")
.sectionTitleWithAnchorLevel(1, "Section with anchor Level 1a", "level-1a")
.sectionTitleWithAnchorLevel(1, "Section with anchor Level 1a")
.sectionTitleLevel(2, "Section Level 2a")
.sectionTitleWithAnchorLevel(2, "Section with anchor Level 2a", "level-2a")
.sectionTitleWithAnchorLevel(2, "Section with anchor Level 2a")
.sectionTitleLevel(3, "Section Level 3a")
.sectionTitleWithAnchorLevel(3, "Section with anchor Level 3a", "level-3a")
.sectionTitleWithAnchorLevel(3, "Section with anchor Level 3a")
.sectionTitleLevel(4, "Section Level 4a")
.sectionTitleWithAnchorLevel(4, "Section with anchor Level 4a", "level-4a")
.sectionTitleWithAnchorLevel(4, "Section with anchor Level 4a")
.sectionTitleLevel(5, "Section Level 5a")
.sectionTitleWithAnchorLevel(5, "Section with anchor Level 5a", "level-5a")
.sectionTitleWithAnchorLevel(5, "Section with anchor Level 5a")
.paragraph("Paragraph with long text bla bla bla bla bla")
.paragraph("\rLine1\nLine2\r\n", false)
.paragraph("\rLine1\nLine2\r\n", true)
.listingBlock("Source code listing")
.listingBlock("MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN)", "java")
.block("Example", MarkupBlockStyle.EXAMPLE)
.block("Example", MarkupBlockStyle.EXAMPLE, "Example", null)
.block("Example", MarkupBlockStyle.EXAMPLE, null, MarkupAdmonition.IMPORTANT)
.block("Listing", MarkupBlockStyle.LISTING, null, MarkupAdmonition.CAUTION)
.block("Literal", MarkupBlockStyle.LITERAL, null, MarkupAdmonition.NOTE)
.block("Sidebar", MarkupBlockStyle.SIDEBAR, null, MarkupAdmonition.TIP)
.block("Passthrough", MarkupBlockStyle.PASSTHROUGH, null, MarkupAdmonition.WARNING)
.pageBreak()
.table(tableCells)
.tableWithColumnSpecs(tableColumns, tableCells)
.sectionTitleLevel1("Section Level 1b")
.sectionTitleLevel2("Section Level 2b")
.textLine("text line", true)
.literalTextLine("Literal text line", true)
.boldTextLine("Bold text line", true)
.italicTextLine("Italic text line", true)
.boldText("bold").italicText("italic").text("regular").newLine(true)
.unorderedList(Arrays.asList("Entry1", "Entry2", "Entry 2"))
.anchor("anchor", "text").newLine()
.anchor(" Simple anchor").newLine()
.anchor(" \u0240 µ&|ù This .:/-_# ").newLine()
.crossReferenceRaw("./document.adoc", "anchor", "text").newLine(true)
.crossReferenceRaw(" \u0240 µ&|ù This .:/-_ ").newLine(true)
.crossReference("./document.adoc", "anchor", "text").newLine(true)
.crossReference(" \u0240 µ&|ù This .:/-_ ").newLine(true);
Path outputFile = Paths.get("build/test/asciidoc/test");
builder.writeToFileWithoutExtension(builder.addFileExtension(outputFile), StandardCharsets.UTF_8);
builder.writeToFile(outputFile, StandardCharsets.UTF_8);
Path expectedFile = Paths.get(MarkupDocBuilderTest.class.getResource("/expected/asciidoc/test.adoc").toURI());
DiffUtils.assertThatFileIsEqual(expectedFile, builder.addFileExtension(outputFile), "testAsciiDoc.html");
}
@Test
public void testAsciiDocWithAnchorPrefix() {
MarkupDocBuilder builderWithConfig = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC).withAnchorPrefix(" mdb test- ");
String prefixMarkup = builderWithConfig.anchor("anchor", "text")
.crossReference("anchor", "text")
.toString();
assertEquals("[[_mdb_test-anchor,text]]<<_mdb_test-anchor,text>>", prefixMarkup);
}
@Test
public void testMarkdownCodeBlock() throws IOException, URISyntaxException {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder = builder.listingBlock("$o = new Thing();", "php");
Path outputFile = Paths.get("build/test/markdown/test2");
builder.writeToFileWithoutExtension(builder.addFileExtension(outputFile), StandardCharsets.UTF_8);
builder.writeToFile(outputFile, StandardCharsets.UTF_8);
Path expectedFile = Paths.get(MarkupDocBuilderTest.class.getResource("/expected/markdown/test2.md").toURI());
DiffUtils.assertThatFileIsEqual(expectedFile, builder.addFileExtension(outputFile), "testMarkdown2.html");
}
@Test
public void testMarkdown() throws IOException, URISyntaxException {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder = builder.documentTitle("Test title")
.sectionTitleLevel(1, "Section Level 1a")
.sectionTitleWithAnchorLevel(1, "Section with anchor Level 1a", "level-1a")
.sectionTitleWithAnchorLevel(1, "Section with anchor Level 1a")
.sectionTitleLevel(2, "Section Level 2a")
.sectionTitleWithAnchorLevel(2, "Section with anchor Level 2a", "level-2a")
.sectionTitleWithAnchorLevel(2, "Section with anchor Level 2a")
.sectionTitleLevel(3, "Section Level 3a")
.sectionTitleWithAnchorLevel(3, "Section with anchor Level 3a", "level-3a")
.sectionTitleWithAnchorLevel(3, "Section with anchor Level 3a")
.sectionTitleLevel(4, "Section Level 4a")
.sectionTitleWithAnchorLevel(4, "Section with anchor Level 4a", "level-4a")
.sectionTitleWithAnchorLevel(4, "Section with anchor Level 4a")
.sectionTitleLevel(5, "Section Level 5a")
.sectionTitleWithAnchorLevel(5, "Section with anchor Level 5a", "level-5a")
.sectionTitleWithAnchorLevel(5, "Section with anchor Level 5a")
.paragraph("Paragraph with long text bla bla bla bla bla")
.paragraph("\rLine1\nLine2\r\n", false)
.paragraph("\rLine1\nLine2\r\n", true)
.listingBlock("Source code listing")
.listingBlock("MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN)", "java")
.block("Example", MarkupBlockStyle.EXAMPLE)
.block("Example", MarkupBlockStyle.EXAMPLE, "Example", null)
.block("Example", MarkupBlockStyle.EXAMPLE, null, MarkupAdmonition.IMPORTANT)
.block("Listing", MarkupBlockStyle.LISTING, null, MarkupAdmonition.CAUTION)
.block("Literal", MarkupBlockStyle.LITERAL, null, MarkupAdmonition.NOTE)
.block("Sidebar", MarkupBlockStyle.SIDEBAR, null, MarkupAdmonition.TIP)
.block("Passthrough", MarkupBlockStyle.PASSTHROUGH, null, MarkupAdmonition.WARNING)
.pageBreak()
//.table(tableCells)
.tableWithColumnSpecs(tableColumns, tableCells)
.sectionTitleLevel1("Section Level 1b")
.sectionTitleLevel2("Section Level 2b")
.textLine("text line", true)
.literalTextLine("Literal text line", true)
.boldTextLine("Bold text line", true)
.italicTextLine("Italic text line", true)
.boldText("bold").italicText("italic").text("regular").newLine(true)
.unorderedList(Arrays.asList("Entry1", "Entry2", "Entry 2"))
.anchor("anchor", "text").newLine()
.anchor(" Simple anchor").newLine()
.anchor(" \u0240 µ&|ù This .:/-_# ").newLine()
.crossReferenceRaw("./document.md", "anchor", "text").newLine(true)
.crossReferenceRaw(" \u0240 µ&|ù This .:/-_ ").newLine(true)
.crossReference("./document.md", "anchor", "text").newLine(true)
.crossReference(" \u0240 µ&|ù This .:/-_ ").newLine(true);
Path outputFile = Paths.get("build/test/markdown/test");
builder.writeToFileWithoutExtension(builder.addFileExtension(outputFile), StandardCharsets.UTF_8);
builder.writeToFile(outputFile, StandardCharsets.UTF_8);
Path expectedFile = Paths.get(MarkupDocBuilderTest.class.getResource("/expected/markdown/test.md").toURI());
DiffUtils.assertThatFileIsEqual(expectedFile, builder.addFileExtension(outputFile), "testMarkdown.html");
}
@Test
public void testMarkdownWithAnchorPrefix() {
MarkupDocBuilder builderWithConfig = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN).withAnchorPrefix(" mdb test- ");
String prefixMarkup = builderWithConfig.anchor("anchor", "text")
.crossReference("anchor", "text")
.toString();
assertEquals("<a name=\"mdb-test-anchor\"></a>[text](#mdb-test-anchor)", prefixMarkup);
}
@Test
public void testConfluenceMarkup() throws IOException, URISyntaxException {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.CONFLUENCE_MARKUP);
builder = builder.documentTitle("Test title")
.sectionTitleLevel(1, "Section Level 1a")
.sectionTitleWithAnchorLevel(1, "Section with anchor Level 1a", "level-1a")
.sectionTitleWithAnchorLevel(1, "Section with anchor Level 1a")
.sectionTitleLevel(2, "Section Level 2a")
.sectionTitleWithAnchorLevel(2, "Section with anchor Level 2a", "level-2a")
.sectionTitleWithAnchorLevel(2, "Section with anchor Level 2a")
.sectionTitleLevel(3, "Section Level 3a")
.sectionTitleWithAnchorLevel(3, "Section with anchor Level 3a", "level-3a")
.sectionTitleWithAnchorLevel(3, "Section with anchor Level 3a")
.sectionTitleLevel(4, "Section Level 4a")
.sectionTitleWithAnchorLevel(4, "Section with anchor Level 4a", "level-4a")
.sectionTitleWithAnchorLevel(4, "Section with anchor Level 4a")
.sectionTitleLevel(5, "Section Level 5a")
.sectionTitleWithAnchorLevel(5, "Section with anchor Level 5a", "level-5a")
.sectionTitleWithAnchorLevel(5, "Section with anchor Level 5a")
.paragraph("Paragraph with long text bla bla bla bla bla")
.paragraph("\rLine1\nLine2\r\n", false)
.paragraph("\rLine1\nLine2\r\n", true)
.listingBlock("Source code listing")
.listingBlock("MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.CONFLUENCE_MARKUP)", "java")
.block("Example", MarkupBlockStyle.EXAMPLE)
.block("Example", MarkupBlockStyle.EXAMPLE, "Example", null)
.block("Example", MarkupBlockStyle.EXAMPLE, null, MarkupAdmonition.IMPORTANT)
.block("Listing", MarkupBlockStyle.LISTING, null, MarkupAdmonition.CAUTION)
.block("Literal", MarkupBlockStyle.LITERAL, null, MarkupAdmonition.NOTE)
.block("Sidebar", MarkupBlockStyle.SIDEBAR, null, MarkupAdmonition.TIP)
.block("Passthrough", MarkupBlockStyle.PASSTHROUGH, null, MarkupAdmonition.WARNING)
.pageBreak()
.table(tableCells)
.tableWithColumnSpecs(tableColumns, tableCells)
.sectionTitleLevel1("Section Level 1b")
.sectionTitleLevel2("Section Level 2b")
.textLine("text line", true)
.literalTextLine("Literal text line", true)
.boldTextLine("Bold text line", true)
.italicTextLine("Italic text line", true)
.boldText("bold").italicText("italic").text("regular").newLine(true)
.unorderedList(Arrays.asList("Entry1", "Entry2", "Entry 2"))
.anchor("anchor", "text").newLine()
.anchor(" Simple anchor").newLine()
.anchor(" \u0240 µ&|ù This .:/-_# ").newLine()
.crossReferenceRaw("./document.txt", "anchor", "text").newLine(true)
.crossReferenceRaw(" \u0240 µ&|ù This .:/-_ ").newLine(true)
.crossReference("./document.txt", "anchor", "text").newLine(true)
.crossReference(" \u0240 µ&|ù This .:/-_ ").newLine(true);
Path outputFile = Paths.get("build/test/confluenceMarkup/test");
builder.writeToFileWithoutExtension(builder.addFileExtension(outputFile), StandardCharsets.UTF_8);
builder.writeToFile(outputFile, StandardCharsets.UTF_8);
Path expectedFile = Paths.get(MarkupDocBuilderTest.class.getResource("/expected/confluenceMarkup/test.txt").toURI());
DiffUtils.assertThatFileIsEqual(expectedFile, builder.addFileExtension(outputFile), "testConfluenceMarkup.html");
}
@Test
public void testConfluenceMarkupWithAnchorPrefix() {
MarkupDocBuilder builderWithConfig = MarkupDocBuilders.documentBuilder(MarkupLanguage.CONFLUENCE_MARKUP).withAnchorPrefix(" mdb test- ");
String prefixMarkup = builderWithConfig.anchor("anchor", "text")
.crossReference("anchor", "text")
.toString();
assertEquals("{anchor:mdb_test-anchor}[text|#mdb_test-anchor]", prefixMarkup);
}
@Test
public void shouldReplaceNewLinesWithSystemNewLine() {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder.paragraph("Long text \n bla bla \r bla \r\n bla");
Assert.assertEquals("Long text " + newLine + " bla bla " + newLine + " bla " + newLine + " bla" + newLine + newLine, builder.toString());
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder.text("Long text \n bla bla \r bla \r\n bla");
Assert.assertEquals("Long text " + newLine + " bla bla " + newLine + " bla " + newLine + " bla", builder.toString());
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder.textLine("Long text \n bla bla \r bla \r\n bla");
Assert.assertEquals("Long text " + newLine + " bla bla " + newLine + " bla " + newLine + " bla" + newLine, builder.toString());
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder.italicText("Long text \n bla bla \r bla \r\n bla");
Assert.assertEquals("*Long text " + newLine + " bla bla " + newLine + " bla " + newLine + " bla*", builder.toString());
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder.italicTextLine("Long text \n bla bla \r bla \r\n bla");
Assert.assertEquals("*Long text " + newLine + " bla bla " + newLine + " bla " + newLine + " bla*" + newLine, builder.toString());
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder.boldText("Long text \n bla bla \r bla \r\n bla");
Assert.assertEquals("**Long text " + newLine + " bla bla " + newLine + " bla " + newLine + " bla**", builder.toString());
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
builder.boldTextLine("Long text \n bla bla \r bla \r\n bla");
Assert.assertEquals("**Long text " + newLine + " bla bla " + newLine + " bla " + newLine + " bla**" + newLine, builder.toString());
}
@Test
public void shouldReplaceTitleNewLinesWithWhiteSpace() {
String whitespace = " ";
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC);
builder.documentTitle("Long title \n bla bla \r bla \r\n bla");
Assert.assertEquals("= Long title " + whitespace + " bla bla " + whitespace + " bla " + whitespace + " bla" + newLine + newLine, builder.toString());
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC);
builder.sectionTitleLevel1("Long title \n bla bla \r bla \r\n bla");
Assert.assertEquals(newLine + "== Long title " + whitespace + " bla bla " + whitespace + " bla " + whitespace + " bla" + newLine, builder.toString());
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC);
builder.sectionTitleLevel2("Long title \n bla bla \r bla \r\n bla");
Assert.assertEquals(newLine + "=== Long title " + whitespace + " bla bla " + whitespace + " bla " + whitespace + " bla" + newLine, builder.toString());
}
@Test
public void shouldUseProvidedLineSeparator() {
String lineSeparator = LineSeparator.UNIX.toString();
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN, LineSeparator.UNIX);
builder.paragraph("Long text \n bla bla \r bla \r\n bla");
Assert.assertEquals("Long text " + lineSeparator + " bla bla " + lineSeparator + " bla " + lineSeparator + " bla" + lineSeparator + lineSeparator, builder.toString());
}
private void assertImportMarkup(String expected, String text, MarkupLanguage markupLanguage, int levelOffset) {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(markupLanguage, LineSeparator.UNIX);
builder.importMarkup(new StringReader(text), markupLanguage, levelOffset);
Assert.assertEquals(expected, builder.toString());
}
private void assertImportMarkupException(String expected, String text, MarkupLanguage markupLanguage, int levelOffset) {
try {
assertImportMarkup(expected, text, markupLanguage, levelOffset);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
Assert.assertEquals(expected, e.getMessage());
}
}
@Test
public void testImportMarkupAsciiDoc() {
assertImportMarkup("", "", MarkupLanguage.ASCIIDOC, 0);
assertImportMarkup("", "", MarkupLanguage.ASCIIDOC, 4);
assertImportMarkupException("Specified levelOffset (6) > max levelOffset (5)", "", MarkupLanguage.ASCIIDOC, 6);
assertImportMarkup("", "", MarkupLanguage.ASCIIDOC, -4);
assertImportMarkupException("Specified levelOffset (-6) < min levelOffset (-5)", "", MarkupLanguage.ASCIIDOC, -6);
assertImportMarkup("\n= title\nline 1\nline 2\n\n", "= title\r\nline 1\r\nline 2", MarkupLanguage.ASCIIDOC, 0);
assertImportMarkup("\nline 1\nline 2\n\n", "line 1\nline 2", MarkupLanguage.ASCIIDOC, 0);
assertImportMarkup("\nline 1\nline 2\n\n", "line 1\nline 2", MarkupLanguage.ASCIIDOC, 4);
assertImportMarkup("\n= title\nline 1\nline 2\n= title 2\nline 3\n\n", "= title\nline 1\nline 2\n= title 2\nline 3", MarkupLanguage.ASCIIDOC, 0);
assertImportMarkup("\n===== title\nline 1\nline 2\n\n", "= title\nline 1\nline 2", MarkupLanguage.ASCIIDOC, 4);
assertImportMarkup("\n= title\nline 1\nline 2\n\n", "===== title\nline 1\nline 2", MarkupLanguage.ASCIIDOC, -4);
assertImportMarkupException("Specified levelOffset (5) set title 'title' level (1) > max title level (5)", "== title\nline 1\nline 2", MarkupLanguage.ASCIIDOC, 5);
assertImportMarkupException("Specified levelOffset (-1) set title 'title' level (0) < 0", "= title\nline 1\nline 2", MarkupLanguage.ASCIIDOC, -1);
assertImportMarkupException("Specified levelOffset (-3) set title 'title' level (1) < 0", "== title\nline 1\nline 2", MarkupLanguage.ASCIIDOC, -3);
}
@Test
public void testImportMarkupMarkdown() {
assertImportMarkup("", "", MarkupLanguage.MARKDOWN, 0);
assertImportMarkup("", "", MarkupLanguage.MARKDOWN, 4);
assertImportMarkup("", "", MarkupLanguage.MARKDOWN, -4);
assertImportMarkupException("Specified levelOffset (6) > max levelOffset (5)", "", MarkupLanguage.MARKDOWN, 6);
assertImportMarkupException("Specified levelOffset (-6) < min levelOffset (-5)", "", MarkupLanguage.MARKDOWN, -6);
assertImportMarkup("\n# title\nline 1\nline 2\n\n", "# title\r\nline 1\r\nline 2", MarkupLanguage.MARKDOWN, 0);
assertImportMarkup("\nline 1\nline 2\n\n", "line 1\nline 2", MarkupLanguage.MARKDOWN, 0);
assertImportMarkup("\nline 1\nline 2\n\n", "line 1\nline 2", MarkupLanguage.MARKDOWN, 4);
assertImportMarkup("\n# title\nline 1\nline 2\n# title 2\nline 3\n\n", "# title\nline 1\nline 2\n# title 2\nline 3", MarkupLanguage.MARKDOWN, 0);
assertImportMarkup("\n##### title\nline 1\nline 2\n\n", "# title\nline 1\nline 2", MarkupLanguage.MARKDOWN, 4);
assertImportMarkup("\n# title\nline 1\nline 2\n\n", "##### title\nline 1\nline 2", MarkupLanguage.MARKDOWN, -4);
assertImportMarkupException("Specified levelOffset (5) set title 'title' level (1) > max title level (5)", "## title\nline 1\nline 2", MarkupLanguage.MARKDOWN, 5);
assertImportMarkupException("Specified levelOffset (-1) set title 'title' level (0) < 0", "# title\nline 1\nline 2", MarkupLanguage.MARKDOWN, -1);
assertImportMarkupException("Specified levelOffset (-3) set title 'title' level (1) < 0", "## title\nline 1\nline 2", MarkupLanguage.MARKDOWN, -3);
}
@Test
public void testImportMarkupConfluenceMarkup() {
assertImportMarkup("", "", MarkupLanguage.CONFLUENCE_MARKUP, 0);
assertImportMarkup("", "", MarkupLanguage.CONFLUENCE_MARKUP, 4);
assertImportMarkup("", "", MarkupLanguage.CONFLUENCE_MARKUP, -4);
assertImportMarkupException("Specified levelOffset (6) > max levelOffset (5)", "", MarkupLanguage.CONFLUENCE_MARKUP, 6);
assertImportMarkupException("Specified levelOffset (-6) < min levelOffset (-5)", "", MarkupLanguage.CONFLUENCE_MARKUP, -6);
assertImportMarkup("\nh1. title\nline 1\nline 2\n\n", "h1. title\r\nline 1\r\nline 2", MarkupLanguage.CONFLUENCE_MARKUP, 0);
assertImportMarkup("\nline 1\nline 2\n\n", "line 1\nline 2", MarkupLanguage.CONFLUENCE_MARKUP, 0);
assertImportMarkup("\nline 1\nline 2\n\n", "line 1\nline 2", MarkupLanguage.CONFLUENCE_MARKUP, 4);
assertImportMarkup("\nh1. title\nline 1\nline 2\nh1. title 2\nline 3\n\n", "h1. title\nline 1\nline 2\nh1. title 2\nline 3", MarkupLanguage.CONFLUENCE_MARKUP, 0);
assertImportMarkup("\nh5. title\nline 1\nline 2\n\n", "h1. title\nline 1\nline 2", MarkupLanguage.CONFLUENCE_MARKUP, 4);
assertImportMarkup("\nh1. title\nline 1\nline 2\n\n", "h5. title\nline 1\nline 2", MarkupLanguage.CONFLUENCE_MARKUP, -4);
assertImportMarkupException("Specified levelOffset (5) set title 'title' level (1) > max title level (5)", "h2. title\nline 1\nline 2", MarkupLanguage.CONFLUENCE_MARKUP, 5);
assertImportMarkupException("Specified levelOffset (-1) set title 'title' level (0) < 0", "h1. title\nline 1\nline 2", MarkupLanguage.CONFLUENCE_MARKUP, -1);
assertImportMarkupException("Specified levelOffset (-3) set title 'title' level (1) < 0", "h2. title\nline 1\nline 2", MarkupLanguage.CONFLUENCE_MARKUP, -3);
}
@Test
public void importMarkupConversion() {
// ASCIIDOC -> ASCIIDOC
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC, LineSeparator.UNIX);
builder.importMarkup(new StringReader("= Title"), MarkupLanguage.ASCIIDOC);
Assert.assertEquals("\n= Title\n\n", builder.toString());
// ASCIIDOC -> MARKDOWN
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN, LineSeparator.UNIX);
builder.importMarkup(new StringReader("= Title"), MarkupLanguage.ASCIIDOC);
// Assert.assertEquals("\n# Title\n\n", builder.toString()); // Unsupported
Assert.assertEquals("\n= Title\n\n", builder.toString());
// ASCIIDOC -> CONFLUENCE_MARKUP
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.CONFLUENCE_MARKUP, LineSeparator.UNIX);
builder.importMarkup(new StringReader("= Title"), MarkupLanguage.ASCIIDOC);
// Assert.assertEquals("\nh1. Title\n\n", builder.toString()); // Unsupported
Assert.assertEquals("\n= Title\n\n", builder.toString());
// MARKDOWN -> ASCIIDOC
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC, LineSeparator.UNIX);
builder.importMarkup(new StringReader("# Title"), MarkupLanguage.MARKDOWN);
Assert.assertEquals("\n= Title\n\n", builder.toString());
// MARKDOWN -> MARKDOWN
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN, LineSeparator.UNIX);
builder.importMarkup(new StringReader("# Title"), MarkupLanguage.MARKDOWN);
Assert.assertEquals("\n# Title\n\n", builder.toString());
// MARKDOWN -> CONFLUENCE_MARKUP
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.CONFLUENCE_MARKUP, LineSeparator.UNIX);
builder.importMarkup(new StringReader("# Title"), MarkupLanguage.MARKDOWN);
// Assert.assertEquals("\nh1. Title\n\n", builder.toString()); // Unsupported
Assert.assertEquals("\n# Title\n\n", builder.toString());
// CONFLUENCE_MARKUP -> ASCIIDOC
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC, LineSeparator.UNIX);
builder.importMarkup(new StringReader("h1. Title"), MarkupLanguage.CONFLUENCE_MARKUP);
// Assert.assertEquals("\n= Title\n\n", builder.toString()); // Unsupported
Assert.assertEquals("\nh1. Title\n\n", builder.toString());
// CONFLUENCE_MARKUP -> MARKDOWN
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN, LineSeparator.UNIX);
builder.importMarkup(new StringReader("h1. Title"), MarkupLanguage.CONFLUENCE_MARKUP);
// Assert.assertEquals("\n# Title\n\n", builder.toString()); // Unsupported
Assert.assertEquals("\nh1. Title\n\n", builder.toString());
// CONFLUENCE_MARKUP -> CONFLUENCE_MARKUP
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.CONFLUENCE_MARKUP, LineSeparator.UNIX);
builder.importMarkup(new StringReader("h1. Title"), MarkupLanguage.CONFLUENCE_MARKUP);
Assert.assertEquals("\nh1. Title\n\n", builder.toString());
}
@Test
public void tableFormatAsciiDoc() throws URISyntaxException, IOException {
Path outputFile = Paths.get("build/test/asciidoc/tableFormat.adoc");
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC);
List<MarkupTableColumn> cols = Arrays.asList(
new MarkupTableColumn().withHeader("Header1\nfirst one"),
new MarkupTableColumn().withWidthRatio(2),
new MarkupTableColumn().withHeader("Header3").withWidthRatio(1).withHeaderColumn(true));
List<List<String>> cells = new ArrayList<>();
cells.add(Arrays.asList("\nRow 2 \\| Column \r\n1\r", "Row 2 || Column 2", "Row 2 | | Column 3"));
builder = builder.tableWithColumnSpecs(cols, cells);
builder.writeToFileWithoutExtension(outputFile, StandardCharsets.UTF_8);
DiffUtils.assertThatFileIsEqual(Paths.get(MarkupDocBuilderTest.class.getResource("/expected/asciidoc/tableFormat.adoc").toURI()), outputFile, "tableFormatAsciiDoc.html");
}
@Test
public void tableFormatMarkdown() throws URISyntaxException, IOException {
Path outputFile = Paths.get("build/test/markdown/tableFormat.md");
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN);
List<MarkupTableColumn> cols = Arrays.asList(
new MarkupTableColumn().withHeader("Header1\nfirst one"),
new MarkupTableColumn().withWidthRatio(2),
new MarkupTableColumn().withHeader("Header3").withWidthRatio(1).withHeaderColumn(true));
List<List<String>> cells = new ArrayList<>();
cells.add(Arrays.asList("\nRow 2 \\| Column \r\n1\r", "Row 2 || Column 2", "Row 2 | | Column 3"));
builder = builder.tableWithColumnSpecs(cols, cells);
builder.writeToFileWithoutExtension(outputFile, StandardCharsets.UTF_8);
DiffUtils.assertThatFileIsEqual(Paths.get(MarkupDocBuilderTest.class.getResource("/expected/markdown/tableFormat.md").toURI()), outputFile, "tableFormatMarkdown.html");
}
@Test
public void tableFormatConfluenceMarkup() throws URISyntaxException, IOException {
Path outputFile = Paths.get("build/test/confluenceMarkup/tableFormat.txt");
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.CONFLUENCE_MARKUP);
List<MarkupTableColumn> cols = Arrays.asList(
new MarkupTableColumn().withHeader("Header1\nfirst one"),
new MarkupTableColumn().withWidthRatio(2),
new MarkupTableColumn().withHeader("Header3").withWidthRatio(1).withHeaderColumn(true));
List<List<String>> cells = new ArrayList<>();
cells.add(Arrays.asList("Row 1 [Title|Page#Anchor] | Column 1", "Row 1 [Title1|Page#Anchor][Title2|Page#Anchor] [Title3|Page#Anchor] | Column [Title|Page#Anchor] 2", "Row 1 [Ti\\|t\\]\\[le|Page#Anchor] | Column 3"));
cells.add(Arrays.asList("[Title|Page#Anchor]Row 1 | Column 1[Title|Page#Anchor]", "|[Title1|Page#Anchor]Row1 Column2|[Title1|Page#Anchor]", "|Row 1 Column 3|"));
cells.add(Arrays.asList("\nRow 2 \\| Column \r\n1\r", "Row 2 || Column 2", "Row 2 | | Column 3"));
builder = builder.tableWithColumnSpecs(cols, cells);
builder.writeToFileWithoutExtension(outputFile, StandardCharsets.UTF_8);
DiffUtils.assertThatFileIsEqual(Paths.get(MarkupDocBuilderTest.class.getResource("/expected/confluenceMarkup/tableFormat.txt").toURI()), outputFile, "tableFormatConfluenceMarkup.html");
}
}

View File

@@ -0,0 +1,55 @@
/*
*
* Copyright 2016 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup.markup.builder.assertions;
import io.github.robwin.diff.DiffAssertions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class DiffUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(DiffUtils.class);
public static void assertThatAllFilesAreEqual(Path expectedDirectory, Path actualDirectory, String reportName) {
Path reportPath = Paths.get("build/diff-report/", reportName);
try {
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(expectedDirectory)) {
for (Path expectedFile : directoryStream) {
Path actualFile = actualDirectory.resolve(expectedFile.getFileName());
LOGGER.info("Diffing file {} with {}", actualFile, expectedFile);
DiffAssertions.assertThat(actualFile).isEqualTo(expectedFile, reportPath);
}
}
} catch (IOException e) {
throw new RuntimeException("Failed to assert that all files are equal", e);
}
}
public static void assertThatFileIsEqual(Path expectedFile, Path actualFile, String reportName) {
Path reportPath = Paths.get("build/diff-report/", reportName);
LOGGER.info("Diffing file {} with {}", actualFile, expectedFile);
DiffAssertions.assertThat(actualFile).isEqualTo(expectedFile, reportPath);
}
}

View File

@@ -0,0 +1,104 @@
package io.github.swagger2markup.markup.builder.internal;
import io.github.swagger2markup.markup.builder.LineSeparator;
import io.github.swagger2markup.markup.builder.MarkupDocBuilder;
import io.github.swagger2markup.markup.builder.MarkupDocBuilders;
import io.github.swagger2markup.markup.builder.MarkupLanguage;
import io.github.swagger2markup.markup.builder.internal.asciidoc.AsciiDoc;
import io.github.swagger2markup.markup.builder.internal.markdown.Markdown;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
public class AbstractMarkupDocBuilderTest {
AbstractMarkupDocBuilder builder;
@Before
public void setUp() {
builder = mock(AbstractMarkupDocBuilder.class, Mockito.CALLS_REAL_METHODS);
builder.newLine = "\n";
builder.documentBuilder = new StringBuilder();
}
private String normalize(Markup markup, String anchor) {
return builder.normalizeAnchor(markup, anchor);
}
private void assertNormalization(Markup markup, String result, String anchor) {
assertEquals(result, normalize(markup, anchor));
}
@Test
public void testNormalizeAnchorAsciiDoc() throws Exception {
assertNormalization(AsciiDoc.SPACE_ESCAPE, "", "");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "anchor", "anchor");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "anchor", "aNcHoR");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "anchor", "_ anchor _");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "anchor", "- anchor -");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "a_n-c_h_o-r", "_-a _ - n-_-_-c_-_-_h___o---r_-");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "classic-simple_anchor", "classic-simple_anchor");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "an_chor", " an chor ");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "anchor", "# anchor &");
assertNormalization(AsciiDoc.SPACE_ESCAPE, DigestUtils.md5Hex("\u0240"), "\u0240");
assertNormalization(AsciiDoc.SPACE_ESCAPE, normalize(AsciiDoc.SPACE_ESCAPE, "\u0240"), " \u0240 ");
assertNormalization(AsciiDoc.SPACE_ESCAPE, DigestUtils.md5Hex("µ_u_\u0240this"), " µ&|ù \u0240This .:/-_# ");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "this_is_a_really_funky_string", "Tĥïŝ ĩš â really fůňķŷ Šťŕĭńġ");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "", " @#&(){}[]!$*%+=/:.;,?\\<>| ");
assertNormalization(AsciiDoc.SPACE_ESCAPE, "sub_action_html_query_value", " /sub/action.html/?query=value ");
}
@Test
public void testNormalizeAnchorMarkdown() throws Exception {
assertNormalization(Markdown.SPACE_ESCAPE, "", "");
assertNormalization(Markdown.SPACE_ESCAPE, "anchor", "anchor");
assertNormalization(Markdown.SPACE_ESCAPE, "anchor", "aNcHoR");
assertNormalization(Markdown.SPACE_ESCAPE, "anchor", "_ anchor _");
assertNormalization(Markdown.SPACE_ESCAPE, "anchor", "- anchor -");
assertNormalization(Markdown.SPACE_ESCAPE, "a-n-c_h_o-r", "_-a _ - n-_-_-c_-_-_h___o---r_-");
assertNormalization(Markdown.SPACE_ESCAPE, "classic-simple_anchor", "classic-simple_anchor");
assertNormalization(Markdown.SPACE_ESCAPE, "an-chor", " an chor ");
assertNormalization(Markdown.SPACE_ESCAPE, "anchor", "# anchor &");
assertNormalization(Markdown.SPACE_ESCAPE, DigestUtils.md5Hex("\u0240"), "\u0240");
assertNormalization(Markdown.SPACE_ESCAPE, normalize(Markdown.SPACE_ESCAPE, "\u0240"), " \u0240 ");
assertNormalization(Markdown.SPACE_ESCAPE, DigestUtils.md5Hex("µ-u-\u0240this"), " µ&|ù \u0240This .:/-_# ");
assertNormalization(Markdown.SPACE_ESCAPE, "this-is-a-really-funky-string", "Tĥïŝ ĩš â really fůňķŷ Šťŕĭńġ");
assertNormalization(Markdown.SPACE_ESCAPE, "", " @#&(){}[]!$*%+=/:.;,?\\<>| ");
assertNormalization(Markdown.SPACE_ESCAPE, "sub-action-html-query-value", " /sub/action.html/?query=value ");
}
@Test
public void testCopy() {
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC, LineSeparator.UNIX).withAnchorPrefix("anchor-");
MarkupDocBuilder copy = builder.copy(false);
Assert.assertTrue(copy instanceof AbstractMarkupDocBuilder);
AbstractMarkupDocBuilder internalCopy = (AbstractMarkupDocBuilder) copy;
Assert.assertEquals(LineSeparator.UNIX.toString(), internalCopy.newLine);
Assert.assertEquals("anchor-", internalCopy.anchorPrefix);
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC, LineSeparator.WINDOWS);
copy = builder.copy(false);
Assert.assertTrue(copy instanceof AbstractMarkupDocBuilder);
internalCopy = (AbstractMarkupDocBuilder) copy;
Assert.assertEquals(LineSeparator.WINDOWS.toString(), internalCopy.newLine);
Assert.assertNull(internalCopy.anchorPrefix);
builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.ASCIIDOC, LineSeparator.UNIX);
builder.text("This is text");
copy = builder.copy(true);
Assert.assertTrue(copy instanceof AbstractMarkupDocBuilder);
internalCopy = (AbstractMarkupDocBuilder) copy;
Assert.assertEquals(LineSeparator.UNIX.toString(), internalCopy.newLine);
Assert.assertNull(internalCopy.anchorPrefix);
Assert.assertEquals("This is text", internalCopy.documentBuilder.toString());
}
}

View File

@@ -0,0 +1,11 @@
[options="header", cols="0,2,1h"]
|===
|Header1
first one||Header3
|Row 2 \\| Column
1|Row 2 \|\| Column 2|Row 2 \| \| Column 3
|===

View File

@@ -0,0 +1,134 @@
= Test title
== Section Level 1a
[[_level-1a]]
== Section with anchor Level 1a
[[_section_with_anchor_level_1a]]
== Section with anchor Level 1a
=== Section Level 2a
[[_level-2a]]
=== Section with anchor Level 2a
[[_section_with_anchor_level_2a]]
=== Section with anchor Level 2a
==== Section Level 3a
[[_level-3a]]
==== Section with anchor Level 3a
[[_section_with_anchor_level_3a]]
==== Section with anchor Level 3a
===== Section Level 4a
[[_level-4a]]
===== Section with anchor Level 4a
[[_section_with_anchor_level_4a]]
===== Section with anchor Level 4a
====== Section Level 5a
[[_level-5a]]
====== Section with anchor Level 5a
[[_section_with_anchor_level_5a]]
====== Section with anchor Level 5a
Paragraph with long text bla bla bla bla bla
Line1
Line2
[%hardbreaks]
Line1
Line2
----
Source code listing
----
[source,java]
----
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN)
----
====
Example
====
.Example
====
Example
====
[IMPORTANT]
====
Example
====
[CAUTION]
----
Listing
----
[NOTE]
....
Literal
....
[TIP]
****
Sidebar
****
[WARNING]
++++
Passthrough
++++
<<<
[options="", cols=""]
|===
|Row 1 \| Column 1|Row 1 \| Column 2|Row 1 \| Column 3
|Row 2 \| Column 1|Row 2 \| Column 2|Row 2 \| Column 3
|===
[options="header", cols="0,2,1h"]
|===
|Header1||Header3
|Row 1 \| Column 1|Row 1 \| Column 2|Row 1 \| Column 3
|Row 2 \| Column 1|Row 2 \| Column 2|Row 2 \| Column 3
|===
== Section Level 1b
=== Section Level 2b
text line +
`Literal text line` +
**Bold text line** +
__Italic text line__ +
**bold**__italic__regular +
* Entry1
* Entry2
* Entry 2
[[_anchor,text]]
[[_simple_anchor]]
[[_8be261a9de7ce958fe46548a62609aeb]]
<<./document.adoc#anchor,text>> +
<< ɀ µ&|ù This .:/-_ >> +
<<document.adoc#_anchor,text>> +
<<_8be261a9de7ce958fe46548a62609aeb>> +

View File

@@ -0,0 +1,8 @@
||Header1\\ first one|| ||Header3||
|Row 1 [Title|Page#Anchor] \| Column 1|Row 1 [Title1|Page#Anchor][Title2|Page#Anchor] [Title3|Page#Anchor] \| Column [Title|Page#Anchor] 2||Row 1 [Ti\|t\]\[le|Page#Anchor] \| Column 3|
|[Title|Page#Anchor]Row 1 \| Column 1[Title|Page#Anchor]|\|[Title1|Page#Anchor]Row1 Column2\|[Title1|Page#Anchor]||\|Row 1 Column 3\||
|Row 2 \\| Column \\ 1|Row 2 \|\| Column 2||Row 2 \| \| Column 3|

View File

@@ -0,0 +1,112 @@
h1. Test title
h2. Section Level 1a
h2. Section with anchor Level 1a {anchor:level-1a}
h2. Section with anchor Level 1a {anchor:section_with_anchor_level_1a}
h3. Section Level 2a
h3. Section with anchor Level 2a {anchor:level-2a}
h3. Section with anchor Level 2a {anchor:section_with_anchor_level_2a}
h4. Section Level 3a
h4. Section with anchor Level 3a {anchor:level-3a}
h4. Section with anchor Level 3a {anchor:section_with_anchor_level_3a}
h5. Section Level 4a
h5. Section with anchor Level 4a {anchor:level-4a}
h5. Section with anchor Level 4a {anchor:section_with_anchor_level_4a}
h6. Section Level 5a
h6. Section with anchor Level 5a {anchor:level-5a}
h6. Section with anchor Level 5a {anchor:section_with_anchor_level_5a}
Paragraph with long text bla bla bla bla bla
Line1
Line2
Line1\\
Line2
{code}
Source code listing
{code}
{code:language=java}
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.CONFLUENCE_MARKUP)
{code}
{panel}
Example
{panel}
{panel:title=Example}
Example
{panel}
{alert}
Example
{alert}
{code:title=Caution}
Listing
{code}
Note :
{noformat}
Literal
{noformat}
{tip}
Sidebar
{tip}
Warning :
{html}
Passthrough
{html}
<div style='page-break-before:always;'></div>
|Row 1 \| Column 1|Row 1 \| Column 2|Row 1 \| Column 3|
|Row 2 \| Column 1|Row 2 \| Column 2|Row 2 \| Column 3|
||Header1|| ||Header3||
|Row 1 \| Column 1|Row 1 \| Column 2||Row 1 \| Column 3|
|Row 2 \| Column 1|Row 2 \| Column 2||Row 2 \| Column 3|
h2. Section Level 1b
h3. Section Level 2b
text line\\
{noformat}Literal text line{noformat}\\
*Bold text line*\\
_Italic text line_\\
*bold*_italic_regular\\
* Entry1
* Entry2
* Entry 2
{anchor:anchor}
{anchor:simple_anchor}
{anchor:8be261a9de7ce958fe46548a62609aeb}
[text|./document.txt#anchor]\\
[# ɀ µ&|ù This .:/-_ ]\\
[text|./document.txt#anchor]\\
[#8be261a9de7ce958fe46548a62609aeb]\\

View File

@@ -0,0 +1,7 @@
|Header1<br>first one||Header3|
|---|---|---|
|Row 2 \\| Column <br>1|Row 2 \|\| Column 2|Row 2 \| \| Column 3|

View File

@@ -0,0 +1,113 @@
# Test title
## Section Level 1a
<a name="level-1a"></a>
## Section with anchor Level 1a
<a name="section-with-anchor-level-1a"></a>
## Section with anchor Level 1a
### Section Level 2a
<a name="level-2a"></a>
### Section with anchor Level 2a
<a name="section-with-anchor-level-2a"></a>
### Section with anchor Level 2a
#### Section Level 3a
<a name="level-3a"></a>
#### Section with anchor Level 3a
<a name="section-with-anchor-level-3a"></a>
#### Section with anchor Level 3a
##### Section Level 4a
<a name="level-4a"></a>
##### Section with anchor Level 4a
<a name="section-with-anchor-level-4a"></a>
##### Section with anchor Level 4a
###### Section Level 5a
<a name="level-5a"></a>
###### Section with anchor Level 5a
<a name="section-with-anchor-level-5a"></a>
###### Section with anchor Level 5a
Paragraph with long text bla bla bla bla bla
Line1
Line2
Line1
Line2
```
Source code listing
```
```java
MarkupDocBuilder builder = MarkupDocBuilders.documentBuilder(MarkupLanguage.MARKDOWN)
```
Example
Example :
Example
Important :
Example
Caution :
```
Listing
```
Note :
```
Literal
```
Tip :
Sidebar
Warning :
Passthrough
***
|Header1||Header3|
|---|---|---|
|Row 1 \| Column 1|Row 1 \| Column 2|Row 1 \| Column 3|
|Row 2 \| Column 1|Row 2 \| Column 2|Row 2 \| Column 3|
## Section Level 1b
### Section Level 2b
text line
`Literal text line`
**Bold text line**
*Italic text line*
**bold***italic*regular
* Entry1
* Entry2
* Entry 2
<a name="anchor"></a>
<a name="simple-anchor"></a>
<a name="313af8b99da5a524603837deb119d273"></a>
[text](./document.md#anchor)
[ɀ µ&|ù This .:/-_](# ɀ µ&|ù This .:/-_ )
[text](./document.md#anchor)
[313af8b99da5a524603837deb119d273](#313af8b99da5a524603837deb119d273)

View File

@@ -0,0 +1,6 @@
```php
$o = new Thing();
```

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

View File

@@ -0,0 +1,25 @@
ext.moduleName="io.github.swagger2markup.core"
dependencies {
configurations.all {
resolutionStrategy.force dependencyOverrides.commonsCodec
resolutionStrategy.force dependencyOverrides.commonsIO
resolutionStrategy.force dependencyOverrides.commonsLang3
resolutionStrategy.force dependencyOverrides.jnrConstants
resolutionStrategy.force dependencyOverrides.jnrEnxio
resolutionStrategy.force dependencyOverrides.jnrPosix
resolutionStrategy.force dependencyOverrides.jodaTime
resolutionStrategy.force dependencyOverrides.slf4j
resolutionStrategy.force dependencyOverrides.jacksonDatabind
resolutionStrategy.force dependencyOverrides.guava
resolutionStrategy.force dependencyOverrides.findBugs
resolutionStrategy.force dependencyOverrides.jaksonCore
}
implementation implLibraries.commonsText
implementation implLibraries.slf4j
implementation implLibraries.commonsCollections4
implementation implLibraries.commonsConf2
implementation implLibraries.guava
testImplementation testLibraries.junit
testImplementation testLibraries.logback
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2017 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.swagger2markup;
import io.github.swagger2markup.config.Schema2MarkupConfig;
import io.github.swagger2markup.extension.Schema2MarkupExtensionRegistry;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* Abstract implementation of Schema2Markup converter
*
* @author Balaji V
*/
public abstract class AbstractSchema2MarkupConverter<T> {
protected Logger logger = LoggerFactory.getLogger(getClass());
private final Context<T> context;
public AbstractSchema2MarkupConverter(Context<T> context) {
this.context = context;
}
/**
* Returns the global Context
*
* @return the global Context
*/
public Context<T> getContext() {
return context;
}
/**
* Converts the Swagger specification into the {@code outputPath} which can be either a directory (e.g /tmp) or a file without extension (e.g /tmp/swagger).
* Internally the method invokes either {@code toFolder} or {@code toFile}. If the {@code outputPath} is a directory, the directory must exist.
* Otherwise it cannot be determined if the {@code outputPath} is a directory or not.
*
* @param outputPath the output path
*/
public void toPath(Path outputPath) {
Validate.notNull(outputPath, "outputPath must not be null");
if (Files.isDirectory(outputPath)) {
toFolder(outputPath);
} else {
toFile(outputPath);
}
}
/**
* Converts the Swagger specification into the given {@code outputDirectory}.
*
* @param outputDirectory the output directory path
*/
public abstract void toFolder(Path outputDirectory);
/**
* Converts the Swagger specification the given {@code outputFile}.<br>
* An extension identifying the markup language will be automatically added to file name.
*
* @param outputFile the output file
*/
public abstract void toFile(Path outputFile);
/**
* Converts the Swagger specification the given {@code outputFile}.
*
* @param outputFile the output file
*/
public abstract void toFileWithoutExtension(Path outputFile);
/**
* Builds the document returns it as a String.
*
* @return the document as a String
*/
public abstract String toString();
public abstract static class Context<T> {
private final Schema2MarkupConfig config;
private final T schema;
private final URI swaggerLocation;
private final Schema2MarkupExtensionRegistry extensionRegistry;
private final Labels labels;
private Path outputPath;
public Context(Schema2MarkupConfig config,
Schema2MarkupExtensionRegistry extensionRegistry,
T schema,
URI swaggerLocation,
Labels labels) {
this.config = config;
this.extensionRegistry = extensionRegistry;
this.schema = schema;
this.swaggerLocation = swaggerLocation;
this.labels = labels;
}
public Schema2MarkupConfig getConfig() {
return config;
}
public T getSchema() {
return schema;
}
public URI getSwaggerLocation() {
return swaggerLocation;
}
public Schema2MarkupExtensionRegistry getExtensionRegistry() {
return extensionRegistry;
}
public Labels getLabels() {
return labels;
}
public Path getOutputPath() {
return outputPath;
}
public void setOutputPath(Path outputPath) {
this.outputPath = outputPath;
}
}
}

View File

@@ -15,6 +15,9 @@
*/
package io.github.swagger2markup;
/**
* GroupBy enum for ordering
*/
public enum GroupBy {
AS_IS,
TAGS,

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2017 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.swagger2markup;
import java.util.ResourceBundle;
public class Labels {
private ResourceBundle resourceBundle;
public Labels(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
}
/**
* Gets a label for the given key from this resource bundle.
*
* @param key the key for the desired label
* @return the label for the given key
*/
public String getLabel(String key) {
return resourceBundle.getString(key);
}
}

View File

@@ -30,7 +30,8 @@ public enum Language {
ZH(Locale.CHINESE),
ES(new Locale("es")),
BR(new Locale("pt", "BR")),
JA(Locale.JAPANESE);
JA(Locale.JAPANESE),
PL(new Locale("pl"));
private final Locale lang;

View File

@@ -0,0 +1,45 @@
/*
*
* Copyright 2015 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/
package io.github.swagger2markup;
import java.util.Arrays;
import java.util.List;
/**
* @author Robert Winkler
*/
public enum MarkupLanguage {
ASCIIDOC(".adoc,.asciidoc"),
MARKDOWN(".md,.markdown"),
CONFLUENCE_MARKUP(".txt");
private final String fileNameExtensions;
/**
* @param fileNameExtensions file name suffix
*/
private MarkupLanguage(final String fileNameExtensions) {
this.fileNameExtensions = fileNameExtensions;
}
public List<String> getFileNameExtensions() {
return Arrays.asList(fileNameExtensions.split(","));
}
}

Some files were not shown because too many files have changed in this diff Show More