diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..77a9976 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +[*.js] +indent_style = space +indent_size = 2 +continuation_indent_size = 2 +insert_final_newline = true +quote_type = single +space_after_anonymous_functions = true +space_after_control_statements = true +spaces_around_operators = true +trim_trailing_whitespace = true +spaces_in_brackets = false +curly_bracket_next_line = true +indent_brace_style = 1TBS +end_of_line = lf +charset = utf-8 diff --git a/.gitattributes b/.gitattributes index 7e29a2c..6821512 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,10 @@ /test export-ignore +.editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore -/perlMarkdown export-ignore -/example export-ignore -grunt.js export-ignore - +.jscs.json export-ignore +.jshintignore export-ignore +.jshintrc +.travis.yml export-ignore +bower.json +Gruntfile.js export-ignore diff --git a/.gitignore b/.gitignore index 0c3454b..56ba81a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +.idea/ +.build/ .DS_Store node_modules -npm-debug.log \ No newline at end of file +npm-debug.log +/*.test.* diff --git a/.jscs.json b/.jscs.json new file mode 100644 index 0000000..f3d0acb --- /dev/null +++ b/.jscs.json @@ -0,0 +1,90 @@ +{ + "validateIndentation": 2, + "requireCurlyBraces": [ + "if", + "else", + "for", + "while", + "do", + "try", + "catch" + ], + "requireOperatorBeforeLineBreak": true, + "requireCamelCaseOrUpperCaseIdentifiers": true, + "validateIndentation": 2, + "validateQuoteMarks": "'", + "disallowMultipleLineStrings": true, + "disallowMixedSpacesAndTabs": true, + "disallowTrailingWhitespace": true, + "disallowSpaceAfterPrefixUnaryOperators": true, + "requireMultipleVarDecl": true, + "disallowKeywordsOnNewLine": ["else"], + "requireSpaceAfterKeywords": [ + "if", + "else", + "for", + "while", + "do", + "switch", + "return", + "try", + "catch" + ], + "requireSpaceBeforeBinaryOperators": [ + "=", + "+=", + "-=", + "*=", + "/=", + "%=", + "<<=", + ">>=", + ">>>=", + "&=", + "|=", + "^=", + "+=", + "+", + "-", + "*", + "/", + "%", + "<<", + ">>", + ">>>", + "&", + "|", + "^", + "&&", + "||", + "===", + "==", + ">=", + "<=", + "<", + ">", + "!=", + "!==" + ], + "requireSpaceAfterBinaryOperators": true, + "requireSpacesInConditionalExpression": true, + "requireSpaceBeforeBlockStatements": true, + "requireSpacesInForStatement": true, + "requireLineFeedAtFileEnd": true, + "requireSpacesInFunctionExpression": { + "beforeOpeningCurlyBrace": true + }, + "requireSpacesInAnonymousFunctionExpression": { + "beforeOpeningRoundBrace": true, + "beforeOpeningCurlyBrace": true + }, + "disallowSpacesInsideObjectBrackets": "all", + "disallowSpacesInsideArrayBrackets": "all", + "disallowSpacesInsideParentheses": true, + "validateJSDoc": { + "checkParamNames": true, + "requireParamTypes": true + }, + "disallowMultipleLineBreaks": true, + "disallowNewlineBeforeBlockStatements": true +} diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 0000000..54c5705 --- /dev/null +++ b/.jshintignore @@ -0,0 +1,5 @@ +Gruntfile.js +dist/**/*.js +build/**/*.js +src/options.js +bin/* diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..0dfea06 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,28 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": "nofunc", + "newcap": true, + "noarg": true, + "quotmark": "single", + "undef": false, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "onevar": true, + "globals": { + "angular": true, + "module": true, + "define": true, + "window": true, + "showdown": true + } +} diff --git a/.travis.yml b/.travis.yml index 8111245..6110552 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,25 @@ language: node_js node_js: - - 0.6 - - 0.8 \ No newline at end of file + - "0.8" + - "0.10" + - "0.12" + +before_install: + - '[ "${TRAVIS_NODE_VERSION}" != "0.8" ] || npm install -g npm@1.4.28' + - npm install -g npm@latest + - npm install -g grunt-cli + +#travis build speed up +sudo: false +cache: + directories: + - node_modules + +# hooks +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/e369617839852624aa69 + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..027302f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,162 @@ + +### 1.2.2 (2015-08-02) + + +#### Bug Fixes + +* **lists:** fix github code blocks not being parsed inside lists ([7720c88b](http://github.com/showdownjs/showdown/commit/7720c88b), closes [#142](http://github.com/showdownjs/showdown/issues/142), [#183](http://github.com/showdownjs/showdown/issues/183), [#184](http://github.com/showdownjs/showdown/issues/184)) + + + +### 1.2.1 (2015-07-22) + + +#### Features + +* **smoothLivePreview:** fix weird effects due to parsing incomplete input ([62ba3733](http://github.com/showdownjs/showdown/commit/62ba3733)) +* **subParsers/githubCodeBlock:** add extra language class to conform to html5 spec ([b7f5e32](http://github.com/showdownjs/showdown/commit/b7f5e32)) + + +#### Bug Fixes + +* **tables:** + + * fix undefined error in malformed tables ([6176977](http://github.com/showdownjs/showdown/commit/6176977)) + + Cannot read property 'trim' of undefined happens when the parser is fed a malformed table. + This happens in live previews (for instance, when using Angularjs). + + * add support for md span elements in table headers ([789dc18](http://github.com/showdownjs/showdown/commit/789dc18)) + + Closes #179 + +* **italicsAndBold:** + + * fix broken em/strong tags when used with literalMidWordUnderscores ([7ee2017](http://github.com/showdownjs/showdown/commit/7ee2017)) + + When literalMidWordUnderscoresis set to true, em and strong tags that start or end a paragraph don't get parsed as such. + This fixes this issue. + + Closes #174 + + * fix underscores not being correctly parsed when used in conjunction with literalMidWordsUnderscores option ([c9e85f1](http://github.com/showdownjs/showdown/commit/c9e85f1)) + +* **codeSpans:** Fix issue with code html tags not being correctly escaped ([5f043ca](http://github.com/showdownjs/showdown/commit/5f043ca)) + +* **images:** fix alt attribute not being escaped correctly ([542194e](http://github.com/showdownjs/showdown/commit/542194e)) + + + +## 1.2.0 (2015-07-13) + +This release moves some of the most popular extensions (such as table-extension and github-extension) to core. +Also introduces a simple cli tool that you can use to quickly convert markdown files into html. + + +#### Bug Fixes + +* **headerLevelStart:** fix for NaN error when specifying a non number as headerLevelStart param ([be72b487](http://github.com/showdownjs/showdown/commit/be72b487)) + + +#### Features + +* **CLI:** simple cli tool (ALPHA) ([f6a33e40](http://github.com/showdownjs/showdown/commit/f6a33e40)) +* **flavours:** add markdown presets/flavors ([7e55bceb](http://github.com/showdownjs/showdown/commit/7e55bceb), closes [#164](http://github.com/showdownjs/showdown/issues/164)) +* **ghCodeBlocks:** add option to disable GH codeblocks ([c33f9888](http://github.com/showdownjs/showdown/commit/c33f9888)) +* **literalMidWordUnderscores:** add support for GFM literal midword underscores ([0c0cd7db](http://github.com/showdownjs/showdown/commit/0c0cd7db)) +* **simplifiedAutoLink:** add support for GFM autolinks ([cff02372](http://github.com/showdownjs/showdown/commit/cff02372)) +* **strikethrough:** add support for GFM strikethrough ([43e9448d](http://github.com/showdownjs/showdown/commit/43e9448d)) +* **tables:** add support for GFM tables ([3a924e3c](http://github.com/showdownjs/showdown/commit/3a924e3c)) +* **tasklists:** add support for GFM tasklists ([dc72403a](http://github.com/showdownjs/showdown/commit/dc72403a)) + + + +## 1.1.0 (2015-06-18) + + +#### Bug Fixes + +* **converter.js:** add error if the passed constructor argument is not an object ([d86ed450](http://github.com/showdownjs/showdown/commit/d86ed450)) +* **output modifiers:** fix for output modifiers running twice ([dcbdc61e](http://github.com/showdownjs/showdown/commit/dcbdc61e)) + + +#### Features + +* **headerLevelStart:** add support for setting the header starting level ([b84ac67d](http://github.com/showdownjs/showdown/commit/b84ac67d), closes [#69](http://github.com/showdownjs/showdown/issues/69)) +* **image dimensions:** add support for setting image dimensions within markdown syntax ([af82c2b6](http://github.com/showdownjs/showdown/commit/af82c2b6), closes [#143](http://github.com/showdownjs/showdown/issues/143)) +* **noHeaderId:** add option to suppress automatic generation of ids in headers ([7ac893e9](http://github.com/showdownjs/showdown/commit/7ac893e9)) +* **showdown.getDefaultOptions:** add method to retrieve default global options keypairs ([2de53a7d](http://github.com/showdownjs/showdown/commit/2de53a7d)) + + +#### Breaking Changes + +* Deprecates `showdown.extensions` property. To migrate, extensions should use the new method `showdown.extension(, )` to register. + For more information on the new extension loading mechanism, please check the wiki pages. + ([4ebd0caa](http://github.com/showdownjs/showdown/commit/4ebd0caa)) + + + +### 1.0.2 (2015-05-28) + +#### Bug Fixes + +* **Gruntfile.js** add missing comma in footer. This bug prevented concatenating other js scripts and libraries + with showdown([5315508](http://github.com/showdownjs/showdown/commit/5315508). Credits to Alexandre Courtiol. + + + +### 1.0.1 (2015-05-27) + + +#### Bug Fixes + +* **bower.json:** update bower.json main attribute to point to dist directory ([bc3a092f](http://github.com/showdownjs/showdown/commit/bc3a092f)) + + + +## 1.0.0 (2015-05-27) + +#### Release Information +This is a major code refactor with some big changes such as: + - showdown.js file was split in several files, called sub-parsers. This should improve code maintainability. + - angular integration was removed from core and move to its own repository, similar to what was done with extensions + - A new extension registering system is on the "cooks" that should reduce errors when using extensions. The old mechanism + is kept so old extensions should be compatible. + +#### Bug Fixes + +* **extensions:** support for old extension loading mechanism ([95ed7c68](http://github.com/showdownjs/showdown/commit/95ed7c68)) +* **helpers:** fix wrong function call 'escapeCharacters' due to old strayed code ([18ba4e75](http://github.com/showdownjs/showdown/commit/18ba4e75)) +* **showdown.js:** + - fix showdown extension loader ([a38c76d2](http://github.com/showdownjs/showdown/commit/a38c76d2)), + closes [#50](http://github.com/showdownjs/showdown/issues/50),[#56](http://github.com/showdownjs/showdown/issues/56), + [#104](http://github.com/showdownjs/showdown/issues/104), [#108](http://github.com/showdownjs/showdown/issues/108), + [#109](http://github.com/showdownjs/showdown/issues/109), [#111](http://github.com/showdownjs/showdown/issues/111), + [#118](http://github.com/showdownjs/showdown/issues/118), [#122](http://github.com/showdownjs/showdown/issues/122) + - add unique id prefix and suffix to headers ([c367a4b9](http://github.com/showdownjs/showdown/commit/c367a4b9), closes [#81](http://github.com/showdownjs/showdown/issues/81), [#82](http://github.com/showdownjs/showdown/issues/82)) +* **options.omitExtraWLInCodeBlocks:** fix for options.omitExtraWLInCodeBlocks only applying in gitHub flavoured code b ([e6f40e19](http://github.com/showdownjs/showdown/commit/e6f40e19)) +* **showdown:** fix for options merging into globalOptions ([ddd6011d](http://github.com/showdownjs/showdown/commit/ddd6011d), closes [#153](http://github.com/showdownjs/showdown/issues/153)) + +#### Features + +* **registerExtension():** new extension loading mechanism. Now extensions can be registered using this function. + The system, however, is not final and will probably be changed until the final version([0fd10cb] (http://github.com/showdownjs/showdown/commit/0fd10cb)) +* **allowBlockIndents:** indented inline block elements can now be parsed as markdown ([f6326b84](http://github.com/showdownjs/showdown/commit/f6326b84)) +* **omitExtraWLInCodeBlocks:** add option to omit extra newline at the end of codeblocks ([141e3f5](http://github.com/showdownjs/showdown/commit/141e3f5)) +* **prefixHeaderId:** add options to prefix header ids to prevent id clash ([141e3f5](http://github.com/showdownjs/showdown/commit/141e3f5)) +* **Converter.options:** add getOption(), setOption() and getOptions() to Converter object ([db6f79b0](http://github.com/showdownjs/showdown/commit/db6f79b0)) + +#### Breaking Changes +* **NAMESPACE:** showdown's namespace changed. + + To migrate your code you should update all references to `Showdown` with `showdown`. + +* **Converter:** converter reference changed from `converter` to `Converter`. + + To migrate you should update all references to `Showdown.converter` with `showdown.Converter` + +* **angular:** angular integration was removed from core and now lives in it's own [repository](http://github.com/showdownjs/angular/). + + If you're using angular integration, you should install ng-showdown. Ex: `bower install ng-showdown` + +* **extensions:** showdown extensions were removed from core package and now live in their own repository. See the [project's github page](https://github.com/showdownjs) for available extensions diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8c14afa --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,48 @@ +Contributing +============ + +If you wish to contribute please read the following quick guide. + +# Want a Feature? +You can request a new feature by submitting an issue. If you would like to implement a new feature feel free to issue a +Pull Request. + + +# Pull requests (PRs) +PRs are awesome. However, before you submit your pull request consider the following guidelines: + + - Search GitHub for an open or closed Pull Request that relates to your submission. You don't want to duplicate effort. + - When issuing PRs that change code, make your changes in a new git branch based on master: + + ```bash + git checkout -b my-fix-branch master + ``` + + - Documentation (i.e: README.md) changes can be made directly against master. + - Run the full test suite before submitting and make sure all tests pass (obviously =P). + - Try to follow our [**coding style rules**](https://github.com/showdownjs/code-style/blob/master/README.md). + Breaking them prevents the PR to pass the tests. + - Refrain from fixing multiple issues in the same pull request. It's preferable to open multiple small PRs instead of one + hard to review big one. Also, don't reuse old forks (or PRs) to fix new issues. + - If the PR introduces a new feature or fixes an issue, please add the appropriate test case. + - We use commit notes to generate the changelog. It's extremely helpful if your commit messages adhere to the + [**AngularJS Git Commit Guidelines**](https://github.com/showdownjs/code-style/blob/master/README.md#commit-message-convention). + - If we suggest changes then: + - Make the required updates. + - Re-run the Angular test suite to ensure tests are still passing. + - Rebase your branch and force push to your GitHub repository (this will update your Pull Request): + + ```bash + git rebase master -i + git push origin my-fix-branch -f + ``` + - After your pull request is merged, you can safely delete your branch. + +If you have time to contribute to this project, we feel obliged that you get credit for it. +These rules enable us to review your PR faster and will give you appropriate credit in your GitHub profile. +We thank you in advance for your contribution! + + +# Joining the team +We're looking for members to help maintaining Showdown. +Please see [this issue](https://github.com/showdownjs/showdown/issues/114) to express interest or comment on this note. diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 0000000..191761f --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,48 @@ +Credits +======= + - Showdown v1 + * [Estevão Santos](https://github.com/tivie) + * [Pascal Deschênes](https://github.com/pdeschen) + + - Showdown v0 + * [Corey Innis](http://github.com/coreyti):
+ Original GitHub project maintainer + * [Remy Sharp](https://github.com/remy/):
+ CommonJS-compatibility and more + * [Konstantin Käfer](https://github.com/kkaefer/):
+ CommonJS packaging + * [Roger Braun](https://github.com/rogerbraun):
+ Github-style code blocks + * [Dominic Tarr](https://github.com/dominictarr):
+ Documentation + * [Cat Chen](https://github.com/CatChen):
+ Export fix + * [Titus Stone](https://github.com/tstone):
+ Mocha tests, extension mechanism, and bug fixes + * [Rob Sutherland](https://github.com/roberocity):
+ The idea that lead to extensions + * [Pavel Lang](https://github.com/langpavel):
+ Code cleanup + * [Ben Combee](https://github.com/unwiredben):
+ Regex optimization + * [Adam Backstrom](https://github.com/abackstrom):
+ WebKit bugfix + * [Pascal Deschênes](https://github.com/pdeschen):
+ Grunt support, extension fixes + additions, packaging improvements, documentation + * [Estevão Santos](https://github.com/tivie)
+ Bug fixing and late maintainer + * [Hannah Wolfe](https://github.com/ErisDS)
+ Bug fixes + * [Alexandre Courtiol](https://github.com/acourtiol)
+ Bug fixes and build optimization + * [Karthik Balakrishnan](https://github.com/torcellite)
+ Support for table alignment + * [rheber](https://github.com/rheber)
+ Cli + + + - Original Project + * [John Gruber](http://daringfireball.net/projects/markdown/)
+ Author of Markdown + * [John Fraser](http://attacklab.net/)
+ Author of Showdown diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..1a69f73 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,170 @@ +/** + * Created by Tivie on 12-11-2014. + */ + +module.exports = function (grunt) { + + if (grunt.option('q') || grunt.option('quiet')) { + require('quiet-grunt'); + } + + // Project configuration. + var config = { + pkg: grunt.file.readJSON('package.json'), + + concat: { + options: { + sourceMap: true, + banner: ';/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n(function(){\n', + footer: '}).call(this);' + }, + dist: { + src: [ + 'src/options.js', + 'src/showdown.js', + 'src/helpers.js', + 'src/converter.js', + 'src/subParsers/*.js', + 'src/loader.js' + ], + dest: 'dist/<%= pkg.name %>.js' + }, + test: { + src: '<%= concat.dist.src %>', + dest: '.build/<%= pkg.name %>.js', + options: { + sourceMap: false + } + } + }, + + clean: ['.build/'], + + uglify: { + options: { + sourceMap: true, + banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n' + }, + dist: { + files: { + 'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>'] + } + } + }, + + jshint: { + options: { + jshintrc: '.jshintrc' + }, + files: [ + 'Gruntfile.js', + 'src/**/*.js', + 'test/**/*.js' + ] + }, + + jscs: { + options: { + config: '.jscs.json' + }, + files: { + src: [ + 'Gruntfile.js', + 'src/**/*.js', + 'test/**/*.js' + ] + } + }, + + changelog: { + options: { + repository: 'http://github.com/showdownjs/showdown', + dest: 'CHANGELOG.md' + } + }, + + simplemocha: { + node: { + src: 'test/node/**/*.js', + options: { + globals: ['should'], + timeout: 3000, + ignoreLeaks: true, + reporter: 'spec' + } + }, + karlcow: { + src: 'test/node/testsuite.karlcow.js', + options: { + globals: ['should'], + timeout: 3000, + ignoreLeaks: false, + reporter: 'spec' + } + }, + issues: { + src: 'test/node/testsuite.issues.js', + options: { + globals: ['should'], + timeout: 3000, + ignoreLeaks: false, + reporter: 'spec' + } + }, + standard: { + src: 'test/node/testsuite.standard.js', + options: { + globals: ['should'], + timeout: 3000, + ignoreLeaks: false, + reporter: 'spec' + } + }, + features: { + src: 'test/node/testsuite.features.js', + options: { + globals: ['should'], + timeout: 3000, + ignoreLeaks: false, + reporter: 'spec' + } + }, + single: { + src: 'test/node/**/*.js', + options: { + globals: ['should'], + timeout: 3000, + ignoreLeaks: false, + reporter: 'spec' + } + } + } + }; + + grunt.initConfig(config); + + require('load-grunt-tasks')(grunt); + + grunt.registerTask('single-test', function (grep) { + 'use strict'; + grunt.config.merge({ + simplemocha: { + single: { + options: { + grep: grep + } + } + } + }); + + grunt.task.run(['lint', 'concat:test', 'simplemocha:single', 'clean']); + }); + + grunt.registerTask('lint', ['jshint', 'jscs']); + grunt.registerTask('test', ['clean', 'lint', 'concat:test', 'simplemocha:node', 'clean']); + grunt.registerTask('build', ['test', 'concat:dist', 'uglify']); + grunt.registerTask('prep-release', ['build', 'changelog']); + + // Default task(s). + grunt.registerTask('default', ['test']); +}; diff --git a/README.md b/README.md index a198541..980d298 100644 --- a/README.md +++ b/README.md @@ -1,327 +1,374 @@ -# Showdown [![build status](https://secure.travis-ci.org/coreyti/showdown.png)](http://travis-ci.org/coreyti/showdown) - -A JavaScript port of Markdown - -## Note - - > **Please note** that I, [Corey](https://github.com/coreyti), am not the author - > of Showdown. Rather, I found it some time back at - > (website removed, see: ) - > and wanted to see it available on GitHub. - > - > All credit and praise for authoring this library should go to John Fraser. - > - > Oh, and John Gruber of course. - > - > That said, Showdown *is* evolving. See below for a list of contributors and an - > overview of their contributions to the project. - > - > Apologies for any confusion or perceived misinformation. - > - > Cheers,
- > Corey - - -## Original Attributions - -Showdown Copyright (c) 2007 John Fraser. - - -Original Markdown Copyright (c) 2004-2005 John Gruber - - -Redistributable under a BSD-style open source license. -See license.txt for more information. - -## Quick Example - -```js -var Showdown = require('showdown'); -var converter = new Showdown.converter(); - -converter.makeHtml('#hello markdown!'); - -//

hello, markdown

-``` - -## What's it for? - -Developers can use Showdown to: - - * Add in-browser preview to existing Markdown apps - - Showdown's output is (almost always) identical to - markdown.pl's, so the server can reproduce exactly - the output that the user saw. (See below for - exceptions.) - - * Add Markdown input to programs that don't support it - - Any app that accepts HTML input can now be made to speak - Markdown by modifying the input pages's HTML. If your - application lets users edit documents again later, - then they won't have access to the original Markdown - text. But this should be good enough for many - uses -- and you can do it with just a two-line - `onsubmit` function! - - * Add Markdown input to closed-source web apps - - You can write bookmarklets or userscripts to extend - any standard textarea on the web so that it accepts - Markdown instead of HTML. With a little more hacking, - the same can probably be done with many rich edit - controls. - - * Build new web apps from scratch - - A Showdown front-end can send back text in Markdown, - HTML or both, so you can trade bandwidth for server - load to reduce your cost of operation. If your app - requires JavaScript, you won't need to do any - Markdown processing on the server at all. (For most - uses, you'll still need to sanitize the HTML before - showing it to other users -- but you'd need to do - that anyway if you're allowing raw HTML in your - Markdown.) - - -## Browser Compatibility - -Showdown has been tested successfully with: - - * Firefox 1.5 and 2.0 - * Internet Explorer 6 and 7 - * Safari 2.0.4 - * Opera 8.54 and 9.10 - * Netscape 8.1.2 - * Konqueror 3.5.4 - -In theory, Showdown will work in any browser that supports ECMA 262 3rd Edition (JavaScript 1.5). The converter itself might even work in things that aren't web browsers, like Acrobat. No promises. - - -## Extensions - -Showdown allows additional functionality to be loaded via extensions. - -### Client-side Extension Usage - -```js - - - - - - - - - -
-
- Input -
- -
- -
-
- -
- - - -
- - - - - - - - - - - - - - -
- - - - - - \ No newline at end of file diff --git a/example/showdown-gui.js b/example/showdown-gui.js deleted file mode 100644 index 5f3519f..0000000 --- a/example/showdown-gui.js +++ /dev/null @@ -1,349 +0,0 @@ -// -// showdown-gui.js -// -// A sample application for Showdown, a javascript port -// of Markdown. -// -// Copyright (c) 2007 John Fraser. -// -// Redistributable under a BSD-style open source license. -// See license.txt for more information. -// -// The full source distribution is at: -// -// A A L -// T C A -// T K B -// -// -// - -// -// The Showdown converter itself is in showdown.js, which must be -// included by the HTML before this file is. -// -// showdown-gui.js assumes the id and class definitions in -// showdown.html. It isn't dependent on the CSS, but it does -// manually hide, display, and resize the individual panes -- -// overriding the stylesheets. -// -// This sample application only interacts with showdown.js in -// two places: -// -// In startGui(): -// -// converter = new Showdown.converter(); -// -// In convertText(): -// -// text = converter.makeHtml(text); -// -// The rest of this file is user interface stuff. -// - - -// -// Register for onload -// -window.onload = startGui; - - -// -// Globals -// - -var converter; -var convertTextTimer,processingTime; -var lastText,lastOutput,lastRoomLeft; -var convertTextSetting, convertTextButton, paneSetting; -var inputPane,previewPane,outputPane,syntaxPane; -var maxDelay = 3000; // longest update pause (in ms) - - -// -// Initialization -// - -function startGui() { - // find elements - convertTextSetting = document.getElementById("convertTextSetting"); - convertTextButton = document.getElementById("convertTextButton"); - paneSetting = document.getElementById("paneSetting"); - - inputPane = document.getElementById("inputPane"); - previewPane = document.getElementById("previewPane"); - outputPane = document.getElementById("outputPane"); - syntaxPane = document.getElementById("syntaxPane"); - - // set event handlers - convertTextSetting.onchange = onConvertTextSettingChanged; - convertTextButton.onclick = onConvertTextButtonClicked; - paneSetting.onchange = onPaneSettingChanged; - window.onresize = setPaneHeights; - - // First, try registering for keyup events - // (There's no harm in calling onInput() repeatedly) - window.onkeyup = inputPane.onkeyup = onInput; - - // In case we can't capture paste events, poll for them - var pollingFallback = window.setInterval(function(){ - if(inputPane.value != lastText) - onInput(); - },1000); - - // Try registering for paste events - inputPane.onpaste = function() { - // It worked! Cancel paste polling. - if (pollingFallback!=undefined) { - window.clearInterval(pollingFallback); - pollingFallback = undefined; - } - onInput(); - } - - // Try registering for input events (the best solution) - if (inputPane.addEventListener) { - // Let's assume input also fires on paste. - // No need to cancel our keyup handlers; - // they're basically free. - inputPane.addEventListener("input",inputPane.onpaste,false); - } - - // poll for changes in font size - // this is cheap; do it often - window.setInterval(setPaneHeights,250); - - // start with blank page? - if (top.document.location.href.match(/\?blank=1$/)) - inputPane.value = ""; - - // refresh panes to avoid a hiccup - onPaneSettingChanged(); - - // build the converter - converter = new Showdown.converter(); - - // do an initial conversion to avoid a hiccup - convertText(); - - // give the input pane focus - inputPane.focus(); - - // start the other panes at the top - // (our smart scrolling moved them to the bottom) - previewPane.scrollTop = 0; - outputPane.scrollTop = 0; -} - - -// -// Conversion -// - -function convertText() { - // get input text - var text = inputPane.value; - - // if there's no change to input, cancel conversion - if (text && text == lastText) { - return; - } else { - lastText = text; - } - - var startTime = new Date().getTime(); - - // Do the conversion - text = converter.makeHtml(text); - - // display processing time - var endTime = new Date().getTime(); - processingTime = endTime - startTime; - document.getElementById("processingTime").innerHTML = processingTime+" ms"; - - // save proportional scroll positions - saveScrollPositions(); - - // update right pane - if (paneSetting.value == "outputPane") { - // the output pane is selected - outputPane.value = text; - } else if (paneSetting.value == "previewPane") { - // the preview pane is selected - previewPane.innerHTML = text; - } - - lastOutput = text; - - // restore proportional scroll positions - restoreScrollPositions(); -}; - - -// -// Event handlers -// - -function onConvertTextSettingChanged() { - // If the user just enabled automatic - // updates, we'll do one now. - onInput(); -} - -function onConvertTextButtonClicked() { - // hack: force the converter to run - lastText = ""; - - convertText(); - inputPane.focus(); -} - -function onPaneSettingChanged() { - previewPane.style.display = "none"; - outputPane.style.display = "none"; - syntaxPane.style.display = "none"; - - // now make the selected one visible - top[paneSetting.value].style.display = "block"; - - lastRoomLeft = 0; // hack: force resize of new pane - setPaneHeights(); - - if (paneSetting.value == "outputPane") { - // Update output pane - outputPane.value = lastOutput; - } else if (paneSetting.value == "previewPane") { - // Update preview pane - previewPane.innerHTML = lastOutput; - } -} - -function onInput() { -// In "delayed" mode, we do the conversion at pauses in input. -// The pause is equal to the last runtime, so that slow -// updates happen less frequently. -// -// Use a timer to schedule updates. Each keystroke -// resets the timer. - - // if we already have convertText scheduled, cancel it - if (convertTextTimer) { - window.clearTimeout(convertTextTimer); - convertTextTimer = undefined; - } - - if (convertTextSetting.value != "manual") { - var timeUntilConvertText = 0; - if (convertTextSetting.value == "delayed") { - // make timer adaptive - timeUntilConvertText = processingTime; - } - - if (timeUntilConvertText > maxDelay) - timeUntilConvertText = maxDelay; - - // Schedule convertText(). - // Even if we're updating every keystroke, use a timer at 0. - // This gives the browser time to handle other events. - convertTextTimer = window.setTimeout(convertText,timeUntilConvertText); - } -} - - -// -// Smart scrollbar adjustment -// -// We need to make sure the user can't type off the bottom -// of the preview and output pages. We'll do this by saving -// the proportional scroll positions before the update, and -// restoring them afterwards. -// - -var previewScrollPos; -var outputScrollPos; - -function getScrollPos(element) { - // favor the bottom when the text first overflows the window - if (element.scrollHeight <= element.clientHeight) - return 1.0; - return element.scrollTop/(element.scrollHeight-element.clientHeight); -} - -function setScrollPos(element,pos) { - element.scrollTop = (element.scrollHeight - element.clientHeight) * pos; -} - -function saveScrollPositions() { - previewScrollPos = getScrollPos(previewPane); - outputScrollPos = getScrollPos(outputPane); -} - -function restoreScrollPositions() { - // hack for IE: setting scrollTop ensures scrollHeight - // has been updated after a change in contents - previewPane.scrollTop = previewPane.scrollTop; - - setScrollPos(previewPane,previewScrollPos); - setScrollPos(outputPane,outputScrollPos); -} - -// -// Textarea resizing -// -// Some browsers (i.e. IE) refuse to set textarea -// percentage heights in standards mode. (But other units? -// No problem. Percentage widths? No problem.) -// -// So we'll do it in javascript. If IE's behavior ever -// changes, we should remove this crap and do 100% textarea -// heights in CSS, because it makes resizing much smoother -// on other browsers. -// - -function getTop(element) { - var sum = element.offsetTop; - while(element = element.offsetParent) - sum += element.offsetTop; - return sum; -} - -function getElementHeight(element) { - var height = element.clientHeight; - if (!height) height = element.scrollHeight; - return height; -} - -function getWindowHeight(element) { - if (window.innerHeight) - return window.innerHeight; - else if (document.documentElement && document.documentElement.clientHeight) - return document.documentElement.clientHeight; - else if (document.body) - return document.body.clientHeight; -} - -function setPaneHeights() { - var textarea = inputPane; - var footer = document.getElementById("footer"); - - var windowHeight = getWindowHeight(); - var footerHeight = getElementHeight(footer); - var textareaTop = getTop(textarea); - - // figure out how much room the panes should fill - var roomLeft = windowHeight - footerHeight - textareaTop; - - if (roomLeft < 0) roomLeft = 0; - - // if it hasn't changed, return - if (roomLeft == lastRoomLeft) { - return; - } - lastRoomLeft = roomLeft; - - // resize all panes - inputPane.style.height = roomLeft + "px"; - previewPane.style.height = roomLeft + "px"; - outputPane.style.height = roomLeft + "px"; - syntaxPane.style.height = roomLeft + "px"; -} \ No newline at end of file diff --git a/example/showdown.js b/example/showdown.js deleted file mode 120000 index e165c71..0000000 --- a/example/showdown.js +++ /dev/null @@ -1 +0,0 @@ -../src/showdown.js \ No newline at end of file diff --git a/grunt.js b/grunt.js deleted file mode 100644 index 4ad9b32..0000000 --- a/grunt.js +++ /dev/null @@ -1,30 +0,0 @@ - -module.exports = function(grunt) { - - // Project configuration. - grunt.initConfig({ - lint: { - all: ['src/**/*.js', 'test/**/*.js'] - }, - jshint: { - options: { - browser: true - } - }, - simplemocha: { - all: { - src: 'test/run.js', - options: { - globals: ['should'], - timeout: 3000, - ignoreLeaks: false, - ui: 'bdd' - } - } - } - }); - - grunt.loadNpmTasks('grunt-simple-mocha'); - - grunt.registerTask('default', ['simplemocha', 'lint']); -}; diff --git a/license.txt b/license.txt index a6096c8..bb98b86 100644 --- a/license.txt +++ b/license.txt @@ -1,9 +1,9 @@ -Copyright (c) 2007, John Fraser - +Showdown Copyright (c) 2007, John Fraser + All rights reserved. -Original Markdown copyright (c) 2004, John Gruber - +Original Markdown copyright (c) 2004, John Gruber + All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/package.json b/package.json index af24c2b..07327fd 100644 --- a/package.json +++ b/package.json @@ -1,41 +1,61 @@ { - "name": "showdown", - "version": "0.3.1", - "author": "John Fraser", - "scripts": { - "test": "mocha ./test/run.js" - }, - "contributors": [ - "John Gruber", - "John Fraser", - "Corey Innis", - "Remy Sharp", - "Konstantin Käfer", - "Roger Braun", - "Dominic Tarr", - "Cat Chen", - "Titus Stone", - "Rob Sutherland", - "Pavel Lang", - "Ben Combee", - "Adam Backstrom", - "Pascal Deschênes" - ], - "repository": { - "type": "git", - "url": "https://github.com/coreyti/showdown.git", - "web": "https://github.com/coreyti/showdown" - }, - "devDependencies": { - "mocha": "1.3.0", - "grunt": "0.3.17", - "grunt-simple-mocha": "*", - "grunt-mocha": "*", - "should": "1.2.0" - }, - "licenses": [{ - "type": "BSD", - "url": "https://github.com/coreyti/showdown/raw/master/license.txt" - }], - "main": "./src/showdown" + "name": "showdown", + "version": "1.2.2", + "description": "A Markdown to HTML converter written in Javascript", + "author": "Estevão Santos", + "homepage": "http://showdownjs.github.io/showdown/", + "keywords": [ + "markdown", + "converter" + ], + "contributors": [ + "John Gruber", + "John Fraser", + "Corey Innis", + "Remy Sharp", + "Konstantin Käfer", + "Roger Braun", + "Dominic Tarr", + "Cat Chen", + "Titus Stone", + "Rob Sutherland", + "Pavel Lang", + "Ben Combee", + "Adam Backstrom", + "Pascal Deschênes", + "Estevão Santos" + ], + "repository": { + "type": "git", + "url": "https://github.com/showdownjs/showdown.git", + "web": "https://github.com/showdownjs/showdown" + }, + "license": "BSD-2-Clause", + "main": "./dist/showdown.js", + "scripts": { + "test": "grunt test" + }, + "bin": { + "showdown": "bin/showdown.js" + }, + "devDependencies": { + "chai": "^1.10.0", + "grunt": "^0.4.5", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-concat": "^0.5.0", + "grunt-contrib-jshint": "^0.10.0", + "grunt-contrib-uglify": "^0.6.0", + "grunt-conventional-changelog": "^1.1.0", + "grunt-jscs": "^1.2.0", + "grunt-simple-mocha": "^0.4.0", + "js-beautify": "^1.5.6", + "load-grunt-tasks": "^3.2.0", + "quiet-grunt": "^0.2.3", + "semver": "^5.0.0", + "sinon": "^1.14.1", + "source-map-support": "^0.2.9" + }, + "dependencies": { + "yargs": "^3.15.0" + } } diff --git a/perlMarkdown/Markdown License.txt b/perlMarkdown/Markdown License.txt deleted file mode 100644 index 6d76506..0000000 --- a/perlMarkdown/Markdown License.txt +++ /dev/null @@ -1,30 +0,0 @@ -Copyright (c) 2004, John Gruber - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name "Markdown" nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as -is" and any express or implied warranties, including, but not limited -to, the implied warranties of merchantability and fitness for a -particular purpose are disclaimed. In no event shall the copyright owner -or contributors be liable for any direct, indirect, incidental, special, -exemplary, or consequential damages (including, but not limited to, -procurement of substitute goods or services; loss of use, data, or -profits; or business interruption) however caused and on any theory of -liability, whether in contract, strict liability, or tort (including -negligence or otherwise) arising in any way out of the use of this -software, even if advised of the possibility of such damage. diff --git a/perlMarkdown/Markdown-1.0.2b2.pl b/perlMarkdown/Markdown-1.0.2b2.pl deleted file mode 100644 index 5c78edd..0000000 --- a/perlMarkdown/Markdown-1.0.2b2.pl +++ /dev/null @@ -1,1509 +0,0 @@ -#!/usr/bin/perl - -# -# Markdown -- A text-to-HTML conversion tool for web writers -# -# Copyright (c) 2004-2005 John Gruber -# -# - - -package Markdown; -require 5.006_000; -use strict; -use warnings; - -use Digest::MD5 qw(md5_hex); -use vars qw($VERSION); -$VERSION = '1.0.2b2'; -# Sat 26 Mar 2005 - -## Disabled; causes problems under Perl 5.6.1: -# use utf8; -# binmode( STDOUT, ":utf8" ); # c.f.: http://acis.openlib.org/dev/perl-unicode-struggle.html - - -# -# Global default settings: -# -my $g_empty_element_suffix = " />"; # Change to ">" for HTML output -my $g_tab_width = 4; - - -# -# Globals: -# - -# Regex to match balanced [brackets]. See Friedl's -# "Mastering Regular Expressions", 2nd Ed., pp. 328-331. -my $g_nested_brackets; -$g_nested_brackets = qr{ - (?> # Atomic matching - [^\[\]]+ # Anything other than brackets - | - \[ - (??{ $g_nested_brackets }) # Recursive set of nested brackets - \] - )* -}x; - - -# Table of hash values for escaped characters: -my %g_escape_table; -foreach my $char (split //, '\\`*_{}[]()>#+-.!') { - $g_escape_table{$char} = md5_hex($char); -} - - -# Global hashes, used by various utility routines -my %g_urls; -my %g_titles; -my %g_html_blocks; - -# Used to track when we're inside an ordered or unordered list -# (see _ProcessListItems() for details): -my $g_list_level = 0; - - -#### Blosxom plug-in interface ########################################## - -# Set $g_blosxom_use_meta to 1 to use Blosxom's meta plug-in to determine -# which posts Markdown should process, using a "meta-markup: markdown" -# header. If it's set to 0 (the default), Markdown will process all -# entries. -my $g_blosxom_use_meta = 0; - -sub start { 1; } -sub story { - my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_; - - if ( (! $g_blosxom_use_meta) or - (defined($meta::markup) and ($meta::markup =~ /^\s*markdown\s*$/i)) - ){ - $$body_ref = Markdown($$body_ref); - } - 1; -} - - -#### Movable Type plug-in interface ##################################### -eval {require MT}; # Test to see if we're running in MT. -unless ($@) { - require MT; - import MT; - require MT::Template::Context; - import MT::Template::Context; - - eval {require MT::Plugin}; # Test to see if we're running >= MT 3.0. - unless ($@) { - require MT::Plugin; - import MT::Plugin; - my $plugin = new MT::Plugin({ - name => "Markdown", - description => "A plain-text-to-HTML formatting plugin. (Version: $VERSION)", - doc_link => 'http://daringfireball.net/projects/markdown/' - }); - MT->add_plugin( $plugin ); - } - - MT::Template::Context->add_container_tag(MarkdownOptions => sub { - my $ctx = shift; - my $args = shift; - my $builder = $ctx->stash('builder'); - my $tokens = $ctx->stash('tokens'); - - if (defined ($args->{'output'}) ) { - $ctx->stash('markdown_output', lc $args->{'output'}); - } - - defined (my $str = $builder->build($ctx, $tokens) ) - or return $ctx->error($builder->errstr); - $str; # return value - }); - - MT->add_text_filter('markdown' => { - label => 'Markdown', - docs => 'http://daringfireball.net/projects/markdown/', - on_format => sub { - my $text = shift; - my $ctx = shift; - my $raw = 0; - if (defined $ctx) { - my $output = $ctx->stash('markdown_output'); - if (defined $output && $output =~ m/^html/i) { - $g_empty_element_suffix = ">"; - $ctx->stash('markdown_output', ''); - } - elsif (defined $output && $output eq 'raw') { - $raw = 1; - $ctx->stash('markdown_output', ''); - } - else { - $raw = 0; - $g_empty_element_suffix = " />"; - } - } - $text = $raw ? $text : Markdown($text); - $text; - }, - }); - - # If SmartyPants is loaded, add a combo Markdown/SmartyPants text filter: - my $smartypants; - - { - no warnings "once"; - $smartypants = $MT::Template::Context::Global_filters{'smarty_pants'}; - } - - if ($smartypants) { - MT->add_text_filter('markdown_with_smartypants' => { - label => 'Markdown With SmartyPants', - docs => 'http://daringfireball.net/projects/markdown/', - on_format => sub { - my $text = shift; - my $ctx = shift; - if (defined $ctx) { - my $output = $ctx->stash('markdown_output'); - if (defined $output && $output eq 'html') { - $g_empty_element_suffix = ">"; - } - else { - $g_empty_element_suffix = " />"; - } - } - $text = Markdown($text); - $text = $smartypants->($text, '1'); - }, - }); - } -} -else { -#### BBEdit/command-line text filter interface ########################## -# Needs to be hidden from MT (and Blosxom when running in static mode). - - # We're only using $blosxom::version once; tell Perl not to warn us: - no warnings 'once'; - unless ( defined($blosxom::version) ) { - use warnings; - - #### Check for command-line switches: ################# - my %cli_opts; - use Getopt::Long; - Getopt::Long::Configure('pass_through'); - GetOptions(\%cli_opts, - 'version', - 'shortversion', - 'html4tags', - ); - if ($cli_opts{'version'}) { # Version info - print "\nThis is Markdown, version $VERSION.\n"; - print "Copyright 2004 John Gruber\n"; - print "http://daringfireball.net/projects/markdown/\n\n"; - exit 0; - } - if ($cli_opts{'shortversion'}) { # Just the version number string. - print $VERSION; - exit 0; - } - if ($cli_opts{'html4tags'}) { # Use HTML tag style instead of XHTML - $g_empty_element_suffix = ">"; - } - - - #### Process incoming text: ########################### - my $text; - { - local $/; # Slurp the whole file - $text = <>; - } - print Markdown($text); - } -} - - - -sub Markdown { -# -# Main function. The order in which other subs are called here is -# essential. Link and image substitutions need to happen before -# _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the -# and tags get encoded. -# - my $text = shift; - - # Clear the global hashes. If we don't clear these, you get conflicts - # from other articles when generating a page which contains more than - # one article (e.g. an index page that shows the N most recent - # articles): - %g_urls = (); - %g_titles = (); - %g_html_blocks = (); - - - # Standardize line endings: - $text =~ s{\r\n}{\n}g; # DOS to Unix - $text =~ s{\r}{\n}g; # Mac to Unix - - # Make sure $text ends with a couple of newlines: - $text .= "\n\n"; - - # Convert all tabs to spaces. - $text = _Detab($text); - - # Strip any lines consisting only of spaces and tabs. - # This makes subsequent regexen easier to write, because we can - # match consecutive blank lines with /\n+/ instead of something - # contorted like /[ \t]*\n+/ . - $text =~ s/^[ \t]+$//mg; - - # Turn block-level HTML blocks into hash entries - $text = _HashHTMLBlocks($text); - - # Strip link definitions, store in hashes. - $text = _StripLinkDefinitions($text); - - $text = _RunBlockGamut($text); - - $text = _UnescapeSpecialChars($text); - - return $text . "\n"; -} - - -sub _StripLinkDefinitions { -# -# Strips link definitions from text, stores the URLs and titles in -# hash references. -# - my $text = shift; - my $less_than_tab = $g_tab_width - 1; - - # Link defs are in the form: ^[id]: url "optional title" - while ($text =~ s{ - ^[ ]{0,$less_than_tab}\[(.+)\]: # id = $1 - [ \t]* - \n? # maybe *one* newline - [ \t]* - ? # url = $2 - [ \t]* - \n? # maybe one newline - [ \t]* - (?: - (?<=\s) # lookbehind for whitespace - ["(] - (.+?) # title = $3 - [")] - [ \t]* - )? # title is optional - (?:\n+|\Z) - } - {}mx) { - $g_urls{lc $1} = _EncodeAmpsAndAngles( $2 ); # Link IDs are case-insensitive - if ($3) { - $g_titles{lc $1} = $3; - $g_titles{lc $1} =~ s/"/"/g; - } - } - - return $text; -} - - -sub _HashHTMLBlocks { - my $text = shift; - my $less_than_tab = $g_tab_width - 1; - - # Hashify HTML blocks: - # We only want to do this for block-level HTML tags, such as headers, - # lists, and tables. That's because we still want to wrap

s around - # "paragraphs" that are wrapped in non-block-level tags, such as anchors, - # phrase emphasis, and spans. The list of tags we're looking for is - # hard-coded: - my $block_tags_a = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del/; - my $block_tags_b = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math/; - - # First, look for nested blocks, e.g.: - #

- #
- # tags for inner block must be indented. - #
- #
- # - # The outermost tags must start at the left margin for this to match, and - # the inner nested divs must be indented. - # We need to do this before the next, more liberal match, because the next - # match will start at the first `
` and stop at the first `
`. - $text =~ s{ - ( # save in $1 - ^ # start of line (with /m) - <($block_tags_a) # start tag = $2 - \b # word break - (.*\n)*? # any number of lines, minimally matching - # the matching end tag - [ \t]* # trailing spaces/tabs - (?=\n+|\Z) # followed by a newline or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egmx; - - - # - # Now match more liberally, simply from `\n` to `\n` - # - $text =~ s{ - ( # save in $1 - ^ # start of line (with /m) - <($block_tags_b) # start tag = $2 - \b # word break - (.*\n)*? # any number of lines, minimally matching - .* # the matching end tag - [ \t]* # trailing spaces/tabs - (?=\n+|\Z) # followed by a newline or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egmx; - # Special case just for
. It was easier to make a special case than - # to make the other regex more complicated. - $text =~ s{ - (?: - (?<=\n\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - [ ]{0,$less_than_tab} - <(hr) # start tag = $2 - \b # word break - ([^<>])*? # - /?> # the matching end tag - [ \t]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egx; - - # Special case for standalone HTML comments: - $text =~ s{ - (?: - (?<=\n\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - [ ]{0,$less_than_tab} - (?s: - - ) - [ \t]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egx; - - - return $text; -} - - -sub _RunBlockGamut { -# -# These are all the transformations that form block-level -# tags like paragraphs, headers, and list items. -# - my $text = shift; - - $text = _DoHeaders($text); - - # Do Horizontal Rules: - $text =~ s{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}{\n tags around block-level tags. - $text = _HashHTMLBlocks($text); - $text = _FormParagraphs($text); - - return $text; -} - - -sub _RunSpanGamut { -# -# These are all the transformations that occur *within* block-level -# tags like paragraphs, headers, and list items. -# - my $text = shift; - - $text = _EscapeSpecialCharsWithinTagAttributes($text); - $text = _DoCodeSpans($text); - $text = _EncodeBackslashEscapes($text); - - # Process anchor and image tags. Images must come first, - # because ![foo][f] looks like an anchor. - $text = _DoImages($text); - $text = _DoAnchors($text); - - # Make links out of things like `` - # Must come after _DoAnchors(), because you can use < and > - # delimiters in inline links like [this](). - $text = _DoAutoLinks($text); - $text = _EncodeAmpsAndAngles($text); - $text = _DoItalicsAndBold($text); - - # Do hard breaks: - $text =~ s/ {2,}\n/ -- encode [\ ` * _] so they -# don't conflict with their use in Markdown for code, italics and strong. -# We're replacing each such character with its corresponding MD5 checksum -# value; this is likely overkill, but it should prevent us from colliding -# with the escape values by accident. -# - my $text = shift; - my $tokens ||= _TokenizeHTML($text); - $text = ''; # rebuild $text from the tokens - - foreach my $cur_token (@$tokens) { - if ($cur_token->[0] eq "tag") { - $cur_token->[1] =~ s! \\ !$g_escape_table{'\\'}!gx; - $cur_token->[1] =~ s! ` !$g_escape_table{'`'}!gx; - $cur_token->[1] =~ s! \* !$g_escape_table{'*'}!gx; - $cur_token->[1] =~ s! _ !$g_escape_table{'_'}!gx; - } - $text .= $cur_token->[1]; - } - return $text; -} - - -sub _DoAnchors { -# -# Turn Markdown link shortcuts into XHTML
tags. -# - my $text = shift; - - # - # First, handle reference-style links: [link text] [id] - # - $text =~ s{ - ( # wrap whole match in $1 - \[ - ($g_nested_brackets) # link text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - ) - }{ - my $result; - my $whole_match = $1; - my $link_text = $2; - my $link_id = lc $3; - - if ($link_id eq "") { - $link_id = lc $link_text; # for shortcut links like [this][]. - } - - if (defined $g_urls{$link_id}) { - my $url = $g_urls{$link_id}; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "? # href = $3 - [ \t]* - ( # $4 - (['"]) # quote char = $5 - (.*?) # Title = $6 - \5 # matching quote - )? # title is optional - \) - ) - }{ - my $result; - my $whole_match = $1; - my $link_text = $2; - my $url = $3; - my $title = $6; - - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = " tags. -# - my $text = shift; - - # - # First, handle reference-style labeled images: ![alt text][id] - # - $text =~ s{ - ( # wrap whole match in $1 - !\[ - (.*?) # alt text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - - ) - }{ - my $result; - my $whole_match = $1; - my $alt_text = $2; - my $link_id = lc $3; - - if ($link_id eq "") { - $link_id = lc $alt_text; # for shortcut links like ![this][]. - } - - $alt_text =~ s/"/"/g; - if (defined $g_urls{$link_id}) { - my $url = $g_urls{$link_id}; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "\"$alt_text\"";? # src url = $3 - [ \t]* - ( # $4 - (['"]) # quote char = $5 - (.*?) # title = $6 - \5 # matching quote - [ \t]* - )? # title is optional - \) - ) - }{ - my $result; - my $whole_match = $1; - my $alt_text = $2; - my $url = $3; - my $title = ''; - if (defined($6)) { - $title = $6; - } - - $alt_text =~ s/"/"/g; - $title =~ s/"/"/g; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "\"$alt_text\"";" . _RunSpanGamut($1) . "\n\n"; - }egmx; - - $text =~ s{ ^(.+)[ \t]*\n-+[ \t]*\n+ }{ - "

" . _RunSpanGamut($1) . "

\n\n"; - }egmx; - - - # atx-style headers: - # # Header 1 - # ## Header 2 - # ## Header 2 with closing hashes ## - # ... - # ###### Header 6 - # - $text =~ s{ - ^(\#{1,6}) # $1 = string of #'s - [ \t]* - (.+?) # $2 = Header text - [ \t]* - \#* # optional closing #'s (not counted) - \n+ - }{ - my $h_level = length($1); - "" . _RunSpanGamut($2) . "\n\n"; - }egmx; - - return $text; -} - - -sub _DoLists { -# -# Form HTML ordered (numbered) and unordered (bulleted) lists. -# - my $text = shift; - my $less_than_tab = $g_tab_width - 1; - - # Re-usable patterns to match list item bullets and number markers: - my $marker_ul = qr/[*+-]/; - my $marker_ol = qr/\d+[.]/; - my $marker_any = qr/(?:$marker_ul|$marker_ol)/; - - # Re-usable pattern to match any entirel ul or ol list: - my $whole_list = qr{ - ( # $1 = whole list - ( # $2 - [ ]{0,$less_than_tab} - (${marker_any}) # $3 = first list item marker - [ \t]+ - ) - (?s:.+?) - ( # $4 - \z - | - \n{2,} - (?=\S) - (?! # Negative lookahead for another list item marker - [ \t]* - ${marker_any}[ \t]+ - ) - ) - ) - }mx; - - # We use a different prefix before nested lists than top-level lists. - # See extended comment in _ProcessListItems(). - # - # Note: There's a bit of duplication here. My original implementation - # created a scalar regex pattern as the conditional result of the test on - # $g_list_level, and then only ran the $text =~ s{...}{...}egmx - # substitution once, using the scalar as the pattern. This worked, - # everywhere except when running under MT on my hosting account at Pair - # Networks. There, this caused all rebuilds to be killed by the reaper (or - # perhaps they crashed, but that seems incredibly unlikely given that the - # same script on the same server ran fine *except* under MT. I've spent - # more time trying to figure out why this is happening than I'd like to - # admit. My only guess, backed up by the fact that this workaround works, - # is that Perl optimizes the substition when it can figure out that the - # pattern will never change, and when this optimization isn't on, we run - # afoul of the reaper. Thus, the slightly redundant code that uses two - # static s/// patterns rather than one conditional pattern. - - if ($g_list_level) { - $text =~ s{ - ^ - $whole_list - }{ - my $list = $1; - my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol"; - - # Turn double returns into triple returns, so that we can make a - # paragraph for the last item in a list, if necessary: - $list =~ s/\n{2,}/\n\n\n/g; - my $result = _ProcessListItems($list, $marker_any); - - # Trim any trailing whitespace, to put the closing `` - # up on the preceding line, to get it past the current stupid - # HTML block parser. This is a hack to work around the terrible - # hack that is the HTML block parser. - $result =~ s{\s+$}{}; - $result = "<$list_type>" . $result . "\n"; - $result; - }egmx; - } - else { - $text =~ s{ - (?:(?<=\n\n)|\A\n?) - $whole_list - }{ - my $list = $1; - my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol"; - # Turn double returns into triple returns, so that we can make a - # paragraph for the last item in a list, if necessary: - $list =~ s/\n{2,}/\n\n\n/g; - my $result = _ProcessListItems($list, $marker_any); - $result = "<$list_type>\n" . $result . "\n"; - $result; - }egmx; - } - - - return $text; -} - - -sub _ProcessListItems { -# -# Process the contents of a single ordered or unordered list, splitting it -# into individual list items. -# - - my $list_str = shift; - my $marker_any = shift; - - - # The $g_list_level global keeps track of when we're inside a list. - # Each time we enter a list, we increment it; when we leave a list, - # we decrement. If it's zero, we're not in a list anymore. - # - # We do this because when we're not inside a list, we want to treat - # something like this: - # - # I recommend upgrading to version - # 8. Oops, now this line is treated - # as a sub-list. - # - # As a single paragraph, despite the fact that the second line starts - # with a digit-period-space sequence. - # - # Whereas when we're inside a list (or sub-list), that line will be - # treated as the start of a sub-list. What a kludge, huh? This is - # an aspect of Markdown's syntax that's hard to parse perfectly - # without resorting to mind-reading. Perhaps the solution is to - # change the syntax rules such that sub-lists must start with a - # starting cardinal number; e.g. "1." or "a.". - - $g_list_level++; - - # trim trailing blank lines: - $list_str =~ s/\n{2,}\z/\n/; - - - $list_str =~ s{ - (\n)? # leading line = $1 - (^[ \t]*) # leading whitespace = $2 - ($marker_any) [ \t]+ # list marker = $3 - ((?s:.+?) # list item text = $4 - (\n{1,2})) - (?= \n* (\z | \2 ($marker_any) [ \t]+)) - }{ - my $item = $4; - my $leading_line = $1; - my $leading_space = $2; - - if ($leading_line or ($item =~ m/\n{2,}/)) { - $item = _RunBlockGamut(_Outdent($item)); - } - else { - # Recursion for sub-lists: - $item = _DoLists(_Outdent($item)); - chomp $item; - $item = _RunSpanGamut($item); - } - - "
  • " . $item . "
  • \n"; - }egmx; - - $g_list_level--; - return $list_str; -} - - - -sub _DoCodeBlocks { -# -# Process Markdown `
    ` blocks.
    -#  
    -
    -  my $text = shift;
    -
    -  $text =~ s{
    -      (?:\n\n|\A)
    -      (              # $1 = the code block -- one or more lines, starting with a space/tab
    -        (?:
    -          (?:[ ]{$g_tab_width} | \t)  # Lines must start with a tab or a tab-width of spaces
    -          .*\n+
    -        )+
    -      )
    -      ((?=^[ ]{0,$g_tab_width}\S)|\Z)  # Lookahead for non-space at line-start, or end of doc
    -    }{
    -      my $codeblock = $1;
    -      my $result; # return value
    -
    -      $codeblock = _EncodeCode(_Outdent($codeblock));
    -      $codeblock = _Detab($codeblock);
    -      $codeblock =~ s/\A\n+//; # trim leading newlines
    -      $codeblock =~ s/\s+\z//; # trim trailing whitespace
    -
    -      $result = "\n\n
    " . $codeblock . "\n
    \n\n"; - - $result; - }egmx; - - return $text; -} - - -sub _DoCodeSpans { -# -# * Backtick quotes are used for spans. -# -# * You can use multiple backticks as the delimiters if you want to -# include literal backticks in the code span. So, this input: -# -# Just type ``foo `bar` baz`` at the prompt. -# -# Will translate to: -# -#

    Just type foo `bar` baz at the prompt.

    -# -# There's no arbitrary limit to the number of backticks you -# can use as delimters. If you need three consecutive backticks -# in your code, use four for delimiters, etc. -# -# * You can use spaces to get literal backticks at the edges: -# -# ... type `` `bar` `` ... -# -# Turns to: -# -# ... type `bar` ... -# - - my $text = shift; - - $text =~ s@ - (?$c
    "; - @egsx; - - return $text; -} - - -sub _EncodeCode { -# -# Encode/escape certain characters inside Markdown code runs. -# The point is that in code, these characters are literals, -# and lose their special Markdown meanings. -# - local $_ = shift; - - # Encode all ampersands; HTML entities are not - # entities within a Markdown code span. - s/&/&/g; - - # Encode $'s, but only if we're running under Blosxom. - # (Blosxom interpolates Perl variables in article bodies.) - { - no warnings 'once'; - if (defined($blosxom::version)) { - s/\$/$/g; - } - } - - - # Do the angle bracket song and dance: - s! < !<!gx; - s! > !>!gx; - - # Now, escape characters that are magic in Markdown: - s! \* !$g_escape_table{'*'}!gx; - s! _ !$g_escape_table{'_'}!gx; - s! { !$g_escape_table{'{'}!gx; - s! } !$g_escape_table{'}'}!gx; - s! \[ !$g_escape_table{'['}!gx; - s! \] !$g_escape_table{']'}!gx; - s! \\ !$g_escape_table{'\\'}!gx; - - return $_; -} - - -sub _DoItalicsAndBold { - my $text = shift; - - # must go first: - $text =~ s{ (\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1 } - {$2}gsx; - - $text =~ s{ (\*|_) (?=\S) (.+?) (?<=\S) \1 } - {$2}gsx; - - return $text; -} - - -sub _DoBlockQuotes { - my $text = shift; - - $text =~ s{ - ( # Wrap whole match in $1 - ( - ^[ \t]*>[ \t]? # '>' at the start of a line - .+\n # rest of the first line - (.+\n)* # subsequent consecutive lines - \n* # blanks - )+ - ) - }{ - my $bq = $1; - $bq =~ s/^[ \t]*>[ \t]?//gm; # trim one level of quoting - $bq =~ s/^[ \t]+$//mg; # trim whitespace-only lines - $bq = _RunBlockGamut($bq); # recurse - - $bq =~ s/^/ /g; - # These leading spaces screw with
     content, so we need to fix that:
    -      $bq =~ s{
    -          (\s*
    .+?
    ) - }{ - my $pre = $1; - $pre =~ s/^ //mg; - $pre; - }egsx; - - "
    \n$bq\n
    \n\n"; - }egmx; - - - return $text; -} - - -sub _FormParagraphs { -# -# Params: -# $text - string to process with html

    tags -# - my $text = shift; - - # Strip leading and trailing lines: - $text =~ s/\A\n+//; - $text =~ s/\n+\z//; - - my @grafs = split(/\n{2,}/, $text); - - # - # Wrap

    tags. - # - foreach (@grafs) { - unless (defined( $g_html_blocks{$_} )) { - $_ = _RunSpanGamut($_); - s/^([ \t]*)/

    /; - $_ .= "

    "; - } - } - - # - # Unhashify HTML blocks - # - foreach (@grafs) { - if (defined( $g_html_blocks{$_} )) { - $_ = $g_html_blocks{$_}; - } - } - - return join "\n\n", @grafs; -} - - -sub _EncodeAmpsAndAngles { -# Smart processing for ampersands and angle brackets that need to be encoded. - - my $text = shift; - - # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: - # http://bumppo.net/projects/amputator/ - $text =~ s/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/&/g; - - # Encode naked <'s - $text =~ s{<(?![a-z/?\$!])}{<}gi; - - return $text; -} - - -sub _EncodeBackslashEscapes { -# -# Parameter: String. -# Returns: The string, with after processing the following backslash -# escape sequences. -# - local $_ = shift; - - s! \\\\ !$g_escape_table{'\\'}!gx; # Must process escaped backslashes first. - s! \\` !$g_escape_table{'`'}!gx; - s! \\\* !$g_escape_table{'*'}!gx; - s! \\_ !$g_escape_table{'_'}!gx; - s! \\\{ !$g_escape_table{'{'}!gx; - s! \\\} !$g_escape_table{'}'}!gx; - s! \\\[ !$g_escape_table{'['}!gx; - s! \\\] !$g_escape_table{']'}!gx; - s! \\\( !$g_escape_table{'('}!gx; - s! \\\) !$g_escape_table{')'}!gx; - s! \\> !$g_escape_table{'>'}!gx; - s! \\\# !$g_escape_table{'#'}!gx; - s! \\\+ !$g_escape_table{'+'}!gx; - s! \\\- !$g_escape_table{'-'}!gx; - s! \\\. !$g_escape_table{'.'}!gx; - s{ \\! }{$g_escape_table{'!'}}gx; - - return $_; -} - - -sub _DoAutoLinks { - my $text = shift; - - $text =~ s{<((https?|ftp):[^'">\s]+)>}{
    $1}gi; - - # Email addresses: - $text =~ s{ - < - (?:mailto:)? - ( - [-.\w]+ - \@ - [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ - ) - > - }{ - _EncodeEmailAddress( _UnescapeSpecialChars($1) ); - }egix; - - return $text; -} - - -sub _EncodeEmailAddress { -# -# Input: an email address, e.g. "foo@example.com" -# -# Output: the email address as a mailto link, with each character -# of the address encoded as either a decimal or hex entity, in -# the hopes of foiling most address harvesting spam bots. E.g.: -# -# foo -# @example.com -# -# Based on a filter by Matthew Wickline, posted to the BBEdit-Talk -# mailing list: -# - - my $addr = shift; - - srand; - my @encode = ( - sub { '&#' . ord(shift) . ';' }, - sub { '&#x' . sprintf( "%X", ord(shift) ) . ';' }, - sub { shift }, - ); - - $addr = "mailto:" . $addr; - - $addr =~ s{(.)}{ - my $char = $1; - if ( $char eq '@' ) { - # this *must* be encoded. I insist. - $char = $encode[int rand 1]->($char); - } elsif ( $char ne ':' ) { - # leave ':' alone (to spot mailto: later) - my $r = rand; - # roughly 10% raw, 45% hex, 45% dec - $char = ( - $r > .9 ? $encode[2]->($char) : - $r < .45 ? $encode[1]->($char) : - $encode[0]->($char) - ); - } - $char; - }gex; - - $addr = qq{$addr}; - $addr =~ s{">.+?:}{">}; # strip the mailto: from the visible part - - return $addr; -} - - -sub _UnescapeSpecialChars { -# -# Swap back in all the special characters we've hidden. -# - my $text = shift; - - while( my($char, $hash) = each(%g_escape_table) ) { - $text =~ s/$hash/$char/g; - } - return $text; -} - - -sub _TokenizeHTML { -# -# Parameter: String containing HTML markup. -# Returns: Reference to an array of the tokens comprising the input -# string. Each token is either a tag (possibly with nested, -# tags contained therein, such as , or a -# run of text between tags. Each element of the array is a -# two-element array; the first is either 'tag' or 'text'; -# the second is the actual value. -# -# -# Derived from the _tokenize() subroutine from Brad Choate's MTRegex plugin. -# -# - - my $str = shift; - my $pos = 0; - my $len = length $str; - my @tokens; - - my $depth = 6; - my $nested_tags = join('|', ('(?:<[a-z/!$](?:[^<>]') x $depth) . (')*>)' x $depth); - my $match = qr/(?s: ) | # comment - (?s: <\? .*? \?> ) | # processing instruction - $nested_tags/ix; # nested tags - - while ($str =~ m/($match)/g) { - my $whole_tag = $1; - my $sec_start = pos $str; - my $tag_start = $sec_start - length $whole_tag; - if ($pos < $tag_start) { - push @tokens, ['text', substr($str, $pos, $tag_start - $pos)]; - } - push @tokens, ['tag', $whole_tag]; - $pos = pos $str; - } - push @tokens, ['text', substr($str, $pos, $len - $pos)] if $pos < $len; - \@tokens; -} - - -sub _Outdent { -# -# Remove one level of line-leading tabs or spaces -# - my $text = shift; - - $text =~ s/^(\t|[ ]{1,$g_tab_width})//gm; - return $text; -} - - -sub _Detab { -# -# Cribbed from a post by Bart Lateur: -# -# - my $text = shift; - - $text =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge; - return $text; -} - - -1; - -__END__ - - -=pod - -=head1 NAME - -B - - -=head1 SYNOPSIS - -B [ B<--html4tags> ] [ B<--version> ] [ B<-shortversion> ] - [ I ... ] - - -=head1 DESCRIPTION - -Markdown is a text-to-HTML filter; it translates an easy-to-read / -easy-to-write structured text format into HTML. Markdown's text format -is most similar to that of plain text email, and supports features such -as headers, *emphasis*, code blocks, blockquotes, and links. - -Markdown's syntax is designed not as a generic markup language, but -specifically to serve as a front-end to (X)HTML. You can use span-level -HTML tags anywhere in a Markdown document, and you can use block level -HTML tags (like
    and as well). - -For more information about Markdown's syntax, see: - - http://daringfireball.net/projects/markdown/ - - -=head1 OPTIONS - -Use "--" to end switch parsing. For example, to open a file named "-z", use: - - Markdown.pl -- -z - -=over 4 - - -=item B<--html4tags> - -Use HTML 4 style for empty element tags, e.g.: - -
    - -instead of Markdown's default XHTML style tags, e.g.: - -
    - - -=item B<-v>, B<--version> - -Display Markdown's version number and copyright information. - - -=item B<-s>, B<--shortversion> - -Display the short-form version number. - - -=back - - - -=head1 BUGS - -To file bug reports or feature requests (other than topics listed in the -Caveats section above) please send email to: - - support@daringfireball.net - -Please include with your report: (1) the example input; (2) the output -you expected; (3) the output Markdown actually produced. - - -=head1 VERSION HISTORY - -See the readme file for detailed release notes for this version. - -1.0.2b2 - 20 Mar 2005 - - + Fix for nested sub-lists in list-paragraph mode. Previously we got - a spurious extra level of `

    ` tags for something like this: - - * this - - * sub - - that - - + Experimental support for [this] as a synonym for [this][]. - (Note to self: No test yet for this.) - Be sure to test, e.g.: [permutations of this sort of [thing][].] - - -1.0.2b1 - 28 Feb 2005 - - + Fix for backticks within HTML tag: like this - - + Fix for escaped backticks still triggering code spans: - - There are two raw backticks here: \` and here: \`, not a code span - -1.0.1 - 14 Dec 2004 - -1.0 - 28 Aug 2004 - - -=head1 AUTHOR - - John Gruber - http://daringfireball.net - - PHP port and other contributions by Michel Fortin - http://michelf.com - - -=head1 COPYRIGHT AND LICENSE - -Copyright (c) 2003-2005 John Gruber - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name "Markdown" nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as -is" and any express or implied warranties, including, but not limited -to, the implied warranties of merchantability and fitness for a -particular purpose are disclaimed. In no event shall the copyright owner -or contributors be liable for any direct, indirect, incidental, special, -exemplary, or consequential damages (including, but not limited to, -procurement of substitute goods or services; loss of use, data, or -profits; or business interruption) however caused and on any theory of -liability, whether in contract, strict liability, or tort (including -negligence or otherwise) arising in any way out of the use of this -software, even if advised of the possibility of such damage. - -=cut diff --git a/perlMarkdown/Markdown-1.0.2b7.pl b/perlMarkdown/Markdown-1.0.2b7.pl deleted file mode 100644 index c3b351f..0000000 --- a/perlMarkdown/Markdown-1.0.2b7.pl +++ /dev/null @@ -1,1642 +0,0 @@ -#!/usr/bin/env perl - -# -# Markdown -- A text-to-HTML conversion tool for web writers -# -# Copyright (c) 2004-2005 John Gruber -# -# - - -package Markdown; -require 5.006_000; -use strict; -use warnings; - -use Digest::MD5 qw(md5_hex); -use vars qw($VERSION); -$VERSION = '1.0.2b7'; -# Tue 29 Aug 2006 - -## Disabled; causes problems under Perl 5.6.1: -# use utf8; -# binmode( STDOUT, ":utf8" ); # c.f.: http://acis.openlib.org/dev/perl-unicode-struggle.html - -# -# Global default settings: -# -my $g_empty_element_suffix = " />"; # Change to ">" for HTML output -my $g_tab_width = 4; - - -# -# Globals: -# - -# Regex to match balanced [brackets]. See Friedl's -# "Mastering Regular Expressions", 2nd Ed., pp. 328-331. -my $g_nested_brackets; -$g_nested_brackets = qr{ - (?> # Atomic matching - [^\[\]]+ # Anything other than brackets - | - \[ - (??{ $g_nested_brackets }) # Recursive set of nested brackets - \] - )* -}x; - - -# Table of hash values for escaped characters: -my %g_escape_table; -foreach my $char (split //, '\\`*_{}[]()>#+-.!') { - $g_escape_table{$char} = md5_hex($char); -} - - -# Global hashes, used by various utility routines -my %g_urls; -my %g_titles; -my %g_html_blocks; - -# Used to track when we're inside an ordered or unordered list -# (see _ProcessListItems() for details): -my $g_list_level = 0; - - -#### Blosxom plug-in interface ########################################## - -# Set $g_blosxom_use_meta to 1 to use Blosxom's meta plug-in to determine -# which posts Markdown should process, using a "meta-markup: markdown" -# header. If it's set to 0 (the default), Markdown will process all -# entries. -my $g_blosxom_use_meta = 0; - -sub start { 1; } -sub story { - my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_; - - if ( (! $g_blosxom_use_meta) or - (defined($meta::markup) and ($meta::markup =~ /^\s*markdown\s*$/i)) - ){ - $$body_ref = Markdown($$body_ref); - } - 1; -} - - -#### Movable Type plug-in interface ##################################### -eval {require MT}; # Test to see if we're running in MT. -unless ($@) { - require MT; - import MT; - require MT::Template::Context; - import MT::Template::Context; - - eval {require MT::Plugin}; # Test to see if we're running >= MT 3.0. - unless ($@) { - require MT::Plugin; - import MT::Plugin; - my $plugin = new MT::Plugin({ - name => "Markdown", - description => "A plain-text-to-HTML formatting plugin. (Version: $VERSION)", - doc_link => 'http://daringfireball.net/projects/markdown/' - }); - MT->add_plugin( $plugin ); - } - - MT::Template::Context->add_container_tag(MarkdownOptions => sub { - my $ctx = shift; - my $args = shift; - my $builder = $ctx->stash('builder'); - my $tokens = $ctx->stash('tokens'); - - if (defined ($args->{'output'}) ) { - $ctx->stash('markdown_output', lc $args->{'output'}); - } - - defined (my $str = $builder->build($ctx, $tokens) ) - or return $ctx->error($builder->errstr); - $str; # return value - }); - - MT->add_text_filter('markdown' => { - label => 'Markdown', - docs => 'http://daringfireball.net/projects/markdown/', - on_format => sub { - my $text = shift; - my $ctx = shift; - my $raw = 0; - if (defined $ctx) { - my $output = $ctx->stash('markdown_output'); - if (defined $output && $output =~ m/^html/i) { - $g_empty_element_suffix = ">"; - $ctx->stash('markdown_output', ''); - } - elsif (defined $output && $output eq 'raw') { - $raw = 1; - $ctx->stash('markdown_output', ''); - } - else { - $raw = 0; - $g_empty_element_suffix = " />"; - } - } - $text = $raw ? $text : Markdown($text); - $text; - }, - }); - - # If SmartyPants is loaded, add a combo Markdown/SmartyPants text filter: - my $smartypants; - - { - no warnings "once"; - $smartypants = $MT::Template::Context::Global_filters{'smarty_pants'}; - } - - if ($smartypants) { - MT->add_text_filter('markdown_with_smartypants' => { - label => 'Markdown With SmartyPants', - docs => 'http://daringfireball.net/projects/markdown/', - on_format => sub { - my $text = shift; - my $ctx = shift; - if (defined $ctx) { - my $output = $ctx->stash('markdown_output'); - if (defined $output && $output eq 'html') { - $g_empty_element_suffix = ">"; - } - else { - $g_empty_element_suffix = " />"; - } - } - $text = Markdown($text); - $text = $smartypants->($text, '1'); - }, - }); - } -} -else { -#### BBEdit/command-line text filter interface ########################## -# Needs to be hidden from MT (and Blosxom when running in static mode). - - # We're only using $blosxom::version once; tell Perl not to warn us: - no warnings 'once'; - unless ( defined($blosxom::version) ) { - use warnings; - - #### Check for command-line switches: ################# - my %cli_opts; - use Getopt::Long; - Getopt::Long::Configure('pass_through'); - GetOptions(\%cli_opts, - 'version', - 'shortversion', - 'html4tags', - ); - if ($cli_opts{'version'}) { # Version info - print "\nThis is Markdown, version $VERSION.\n"; - print "Copyright 2004 John Gruber\n"; - print "http://daringfireball.net/projects/markdown/\n\n"; - exit 0; - } - if ($cli_opts{'shortversion'}) { # Just the version number string. - print $VERSION; - exit 0; - } - if ($cli_opts{'html4tags'}) { # Use HTML tag style instead of XHTML - $g_empty_element_suffix = ">"; - } - - - #### Process incoming text: ########################### - my $text; - { - local $/; # Slurp the whole file - $text = <>; - } - print Markdown($text); - } -} - - - -sub Markdown { -# -# Main function. The order in which other subs are called here is -# essential. Link and image substitutions need to happen before -# _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the -# and tags get encoded. -# - my $text = shift; - - # Clear the global hashes. If we don't clear these, you get conflicts - # from other articles when generating a page which contains more than - # one article (e.g. an index page that shows the N most recent - # articles): - %g_urls = (); - %g_titles = (); - %g_html_blocks = (); - - - # Standardize line endings: - $text =~ s{\r\n}{\n}g; # DOS to Unix - $text =~ s{\r}{\n}g; # Mac to Unix - - # Make sure $text ends with a couple of newlines: - $text .= "\n\n"; - - # Convert all tabs to spaces. - $text = _Detab($text); - - # Strip any lines consisting only of spaces and tabs. - # This makes subsequent regexen easier to write, because we can - # match consecutive blank lines with /\n+/ instead of something - # contorted like /[ \t]*\n+/ . - $text =~ s/^[ \t]+$//mg; - - # Turn block-level HTML blocks into hash entries - $text = _HashHTMLBlocks($text); - - # Strip link definitions, store in hashes. - $text = _StripLinkDefinitions($text); - - $text = _RunBlockGamut($text); - - $text = _UnescapeSpecialChars($text); - - return $text . "\n"; -} - - -sub _StripLinkDefinitions { -# -# Strips link definitions from text, stores the URLs and titles in -# hash references. -# - my $text = shift; - my $less_than_tab = $g_tab_width - 1; - - # Link defs are in the form: ^[id]: url "optional title" - while ($text =~ s{ - ^[ ]{0,$less_than_tab}\[(.+)\]: # id = $1 - [ \t]* - \n? # maybe *one* newline - [ \t]* - ? # url = $2 - [ \t]* - \n? # maybe one newline - [ \t]* - (?: - (?<=\s) # lookbehind for whitespace - ["(] - (.+?) # title = $3 - [")] - [ \t]* - )? # title is optional - (?:\n+|\Z) - } - {}mx) { - $g_urls{lc $1} = _EncodeAmpsAndAngles( $2 ); # Link IDs are case-insensitive - if ($3) { - $g_titles{lc $1} = $3; - $g_titles{lc $1} =~ s/"/"/g; - } - } - - return $text; -} - - -sub _HashHTMLBlocks { - my $text = shift; - my $less_than_tab = $g_tab_width - 1; - - # Hashify HTML blocks: - # We only want to do this for block-level HTML tags, such as headers, - # lists, and tables. That's because we still want to wrap

    s around - # "paragraphs" that are wrapped in non-block-level tags, such as anchors, - # phrase emphasis, and spans. The list of tags we're looking for is - # hard-coded: - my $block_tags = qr{ - (?: - p | div | h[1-6] | blockquote | pre | table | - dl | ol | ul | script | noscript | form | - fieldset | iframe | math | ins | del - ) - }x; - - my $tag_attrs = qr{ - (?: # Match one attr name/value pair - \s+ # There needs to be at least some whitespace - # before each attribute name. - [\w.:_-]+ # Attribute name - \s*=\s* - (["']) # Attribute quoter - .+? # Attribute value - \1 # Closing quoter - )* # Zero or more - }x; - - my $empty_tag = qr{< \w+ $tag_attrs \s* />}xms; - my $open_tag = qr{< $block_tags $tag_attrs \s* >}xms; - my $close_tag = undef; # let Text::Balanced handle this - - use Text::Balanced qw(gen_extract_tagged); - my $extract_block = gen_extract_tagged($open_tag, $close_tag, undef, { ignore => [$empty_tag] }); - - my @chunks; - ## TO-DO: the 0,3 on the next line ought to respect the - ## tabwidth, or else, we should mandate 4-space tabwidth and - ## be done with it: - while ($text =~ s{^(([ ]{0,3}<)?.*\n)}{}m) { - my $cur_line = $1; - if (defined $2) { - # current line could be start of code block - - my ($tag, $remainder) = $extract_block->($cur_line . $text); - if ($tag) { - my $key = md5_hex($tag); - $g_html_blocks{$key} = $tag; - push @chunks, "\n\n" . $key . "\n\n"; - $text = $remainder; - } - else { - # No tag match, so toss $cur_line into @chunks - push @chunks, $cur_line; - } - } - else { - # current line could NOT be start of code block - push @chunks, $cur_line; - } - - } - push @chunks, $text; # Whatever is left. - - $text = join '', @chunks; - - - - # Special case just for


    . It was easier to make a special case than - # to make the other regex more complicated. - $text =~ s{ - (?: - (?<=\n\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - [ ]{0,$less_than_tab} - <(hr) # start tag = $2 - \b # word break - ([^<>])*? # - /?> # the matching end tag - [ \t]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egx; - - # Special case for standalone HTML comments: - $text =~ s{ - (?: - (?<=\n\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - [ ]{0,$less_than_tab} - (?s: - - ) - [ \t]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egx; - - # PHP and ASP-style processor instructions ( and <%…%>) - $text =~ s{ - (?: - (?<=\n\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - [ ]{0,$less_than_tab} - (?s: - <([?%]) # $2 - .*? - \2> - ) - [ \t]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egx; - - - return $text; -} - - -sub _RunBlockGamut { -# -# These are all the transformations that form block-level -# tags like paragraphs, headers, and list items. -# - my $text = shift; - - $text = _DoHeaders($text); - - # Do Horizontal Rules: - $text =~ s{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}{\n tags around block-level tags. - $text = _HashHTMLBlocks($text); - $text = _FormParagraphs($text); - - return $text; -} - - -sub _RunSpanGamut { -# -# These are all the transformations that occur *within* block-level -# tags like paragraphs, headers, and list items. -# - my $text = shift; - - $text = _DoCodeSpans($text); - $text = _EscapeSpecialCharsWithinTagAttributes($text); - $text = _EncodeBackslashEscapes($text); - - # Process anchor and image tags. Images must come first, - # because ![foo][f] looks like an anchor. - $text = _DoImages($text); - $text = _DoAnchors($text); - - # Make links out of things like `` - # Must come after _DoAnchors(), because you can use < and > - # delimiters in inline links like [this](). - $text = _DoAutoLinks($text); - $text = _EncodeAmpsAndAngles($text); - $text = _DoItalicsAndBold($text); - - # Do hard breaks: - $text =~ s/ {2,}\n/ -- encode [\ ` * _] so they -# don't conflict with their use in Markdown for code, italics and strong. -# We're replacing each such character with its corresponding MD5 checksum -# value; this is likely overkill, but it should prevent us from colliding -# with the escape values by accident. -# - my $text = shift; - my $tokens ||= _TokenizeHTML($text); - $text = ''; # rebuild $text from the tokens - - foreach my $cur_token (@$tokens) { - if ($cur_token->[0] eq "tag") { - $cur_token->[1] =~ s! \\ !$g_escape_table{'\\'}!gx; - $cur_token->[1] =~ s{ (?<=.)(?=.) }{$g_escape_table{'`'}}gx; - $cur_token->[1] =~ s! \* !$g_escape_table{'*'}!gx; - $cur_token->[1] =~ s! _ !$g_escape_table{'_'}!gx; - } - $text .= $cur_token->[1]; - } - return $text; -} - - -sub _DoAnchors { -# -# Turn Markdown link shortcuts into XHTML tags. -# - my $text = shift; - - # - # First, handle reference-style links: [link text] [id] - # - $text =~ s{ - ( # wrap whole match in $1 - \[ - ($g_nested_brackets) # link text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - ) - }{ - my $result; - my $whole_match = $1; - my $link_text = $2; - my $link_id = lc $3; - - if ($link_id eq "") { - $link_id = lc $link_text; # for shortcut links like [this][]. - } - - if (defined $g_urls{$link_id}) { - my $url = $g_urls{$link_id}; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "? # href = $3 - [ \t]* - ( # $4 - (['"]) # quote char = $5 - (.*?) # Title = $6 - \5 # matching quote - [ \t]* # ignore any spaces/tabs between closing quote and ) - )? # title is optional - \) - ) - }{ - my $result; - my $whole_match = $1; - my $link_text = $2; - my $url = $3; - my $title = $6; - - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = " tags. -# - my $text = shift; - - # - # First, handle reference-style labeled images: ![alt text][id] - # - $text =~ s{ - ( # wrap whole match in $1 - !\[ - (.*?) # alt text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - - ) - }{ - my $result; - my $whole_match = $1; - my $alt_text = $2; - my $link_id = lc $3; - - if ($link_id eq "") { - $link_id = lc $alt_text; # for shortcut links like ![this][]. - } - - $alt_text =~ s/"/"/g; - if (defined $g_urls{$link_id}) { - my $url = $g_urls{$link_id}; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "\"$alt_text\"";? # src url = $3 - [ \t]* - ( # $4 - (['"]) # quote char = $5 - (.*?) # title = $6 - \5 # matching quote - [ \t]* - )? # title is optional - \) - ) - }{ - my $result; - my $whole_match = $1; - my $alt_text = $2; - my $url = $3; - my $title = ''; - if (defined($6)) { - $title = $6; - } - - $alt_text =~ s/"/"/g; - $title =~ s/"/"/g; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "\"$alt_text\"";" . _RunSpanGamut($1) . "\n\n"; - }egmx; - - $text =~ s{ ^(.+)[ \t]*\n-+[ \t]*\n+ }{ - "

    " . _RunSpanGamut($1) . "

    \n\n"; - }egmx; - - - # atx-style headers: - # # Header 1 - # ## Header 2 - # ## Header 2 with closing hashes ## - # ... - # ###### Header 6 - # - $text =~ s{ - ^(\#{1,6}) # $1 = string of #'s - [ \t]* - (.+?) # $2 = Header text - [ \t]* - \#* # optional closing #'s (not counted) - \n+ - }{ - my $h_level = length($1); - "" . _RunSpanGamut($2) . "\n\n"; - }egmx; - - return $text; -} - - -sub _DoLists { -# -# Form HTML ordered (numbered) and unordered (bulleted) lists. -# - my $text = shift; - my $less_than_tab = $g_tab_width - 1; - - # Re-usable patterns to match list item bullets and number markers: - my $marker_ul = qr/[*+-]/; - my $marker_ol = qr/\d+[.]/; - my $marker_any = qr/(?:$marker_ul|$marker_ol)/; - - # Re-usable pattern to match any entirel ul or ol list: - my $whole_list = qr{ - ( # $1 = whole list - ( # $2 - [ ]{0,$less_than_tab} - (${marker_any}) # $3 = first list item marker - [ \t]+ - ) - (?s:.+?) - ( # $4 - \z - | - \n{2,} - (?=\S) - (?! # Negative lookahead for another list item marker - [ \t]* - ${marker_any}[ \t]+ - ) - ) - ) - }mx; - - # We use a different prefix before nested lists than top-level lists. - # See extended comment in _ProcessListItems(). - # - # Note: There's a bit of duplication here. My original implementation - # created a scalar regex pattern as the conditional result of the test on - # $g_list_level, and then only ran the $text =~ s{...}{...}egmx - # substitution once, using the scalar as the pattern. This worked, - # everywhere except when running under MT on my hosting account at Pair - # Networks. There, this caused all rebuilds to be killed by the reaper (or - # perhaps they crashed, but that seems incredibly unlikely given that the - # same script on the same server ran fine *except* under MT. I've spent - # more time trying to figure out why this is happening than I'd like to - # admit. My only guess, backed up by the fact that this workaround works, - # is that Perl optimizes the substition when it can figure out that the - # pattern will never change, and when this optimization isn't on, we run - # afoul of the reaper. Thus, the slightly redundant code that uses two - # static s/// patterns rather than one conditional pattern. - - if ($g_list_level) { - $text =~ s{ - ^ - $whole_list - }{ - my $list = $1; - my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol"; - - # Turn double returns into triple returns, so that we can make a - # paragraph for the last item in a list, if necessary: - $list =~ s/\n{2,}/\n\n\n/g; - my $result = _ProcessListItems($list, $marker_any); - - # Trim any trailing whitespace, to put the closing `` - # up on the preceding line, to get it past the current stupid - # HTML block parser. This is a hack to work around the terrible - # hack that is the HTML block parser. - $result =~ s{\s+$}{}; - $result = "<$list_type>" . $result . "\n"; - $result; - }egmx; - } - else { - $text =~ s{ - (?:(?<=\n\n)|\A\n?) - $whole_list - }{ - my $list = $1; - my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol"; - # Turn double returns into triple returns, so that we can make a - # paragraph for the last item in a list, if necessary: - $list =~ s/\n{2,}/\n\n\n/g; - my $result = _ProcessListItems($list, $marker_any); - $result = "<$list_type>\n" . $result . "\n"; - $result; - }egmx; - } - - - return $text; -} - - -sub _ProcessListItems { -# -# Process the contents of a single ordered or unordered list, splitting it -# into individual list items. -# - - my $list_str = shift; - my $marker_any = shift; - - - # The $g_list_level global keeps track of when we're inside a list. - # Each time we enter a list, we increment it; when we leave a list, - # we decrement. If it's zero, we're not in a list anymore. - # - # We do this because when we're not inside a list, we want to treat - # something like this: - # - # I recommend upgrading to version - # 8. Oops, now this line is treated - # as a sub-list. - # - # As a single paragraph, despite the fact that the second line starts - # with a digit-period-space sequence. - # - # Whereas when we're inside a list (or sub-list), that line will be - # treated as the start of a sub-list. What a kludge, huh? This is - # an aspect of Markdown's syntax that's hard to parse perfectly - # without resorting to mind-reading. Perhaps the solution is to - # change the syntax rules such that sub-lists must start with a - # starting cardinal number; e.g. "1." or "a.". - - $g_list_level++; - - # trim trailing blank lines: - $list_str =~ s/\n{2,}\z/\n/; - - - $list_str =~ s{ - (\n)? # leading line = $1 - (^[ \t]*) # leading whitespace = $2 - ($marker_any) [ \t]+ # list marker = $3 - ((?s:.+?) # list item text = $4 - (\n{1,2})) - (?= \n* (\z | \2 ($marker_any) [ \t]+)) - }{ - my $item = $4; - my $leading_line = $1; - my $leading_space = $2; - - if ($leading_line or ($item =~ m/\n{2,}/)) { - $item = _RunBlockGamut(_Outdent($item)); - } - else { - # Recursion for sub-lists: - $item = _DoLists(_Outdent($item)); - chomp $item; - $item = _RunSpanGamut($item); - } - - "
  • " . $item . "
  • \n"; - }egmx; - - $g_list_level--; - return $list_str; -} - - - -sub _DoCodeBlocks { -# -# Process Markdown `
    ` blocks.
    -#	
    -
    -	my $text = shift;
    -
    -	$text =~ s{
    -			(?:\n\n|\A)
    -			(	            # $1 = the code block -- one or more lines, starting with a space/tab
    -			  (?:
    -			    (?:[ ]{$g_tab_width} | \t)  # Lines must start with a tab or a tab-width of spaces
    -			    .*\n+
    -			  )+
    -			)
    -			((?=^[ ]{0,$g_tab_width}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
    -		}{
    -			my $codeblock = $1;
    -			my $result; # return value
    -
    -			$codeblock = _EncodeCode(_Outdent($codeblock));
    -			$codeblock = _Detab($codeblock);
    -			$codeblock =~ s/\A\n+//; # trim leading newlines
    -			$codeblock =~ s/\n+\z//; # trim trailing newlines
    -
    -			$result = "\n\n
    " . $codeblock . "\n
    \n\n"; - - $result; - }egmx; - - return $text; -} - - -sub _DoCodeSpans { -# -# * Backtick quotes are used for spans. -# -# * You can use multiple backticks as the delimiters if you want to -# include literal backticks in the code span. So, this input: -# -# Just type ``foo `bar` baz`` at the prompt. -# -# Will translate to: -# -#

    Just type foo `bar` baz at the prompt.

    -# -# There's no arbitrary limit to the number of backticks you -# can use as delimters. If you need three consecutive backticks -# in your code, use four for delimiters, etc. -# -# * You can use spaces to get literal backticks at the edges: -# -# ... type `` `bar` `` ... -# -# Turns to: -# -# ... type `bar` ... -# - - my $text = shift; - - $text =~ s@ - (?$c
    "; - @egsx; - - return $text; -} - - -sub _EncodeCode { -# -# Encode/escape certain characters inside Markdown code runs. -# The point is that in code, these characters are literals, -# and lose their special Markdown meanings. -# - local $_ = shift; - - # Encode all ampersands; HTML entities are not - # entities within a Markdown code span. - s/&/&/g; - - # Encode $'s, but only if we're running under Blosxom. - # (Blosxom interpolates Perl variables in article bodies.) - { - no warnings 'once'; - if (defined($blosxom::version)) { - s/\$/$/g; - } - } - - - # Do the angle bracket song and dance: - s! < !<!gx; - s! > !>!gx; - - # Now, escape characters that are magic in Markdown: - s! \* !$g_escape_table{'*'}!gx; - s! _ !$g_escape_table{'_'}!gx; - s! { !$g_escape_table{'{'}!gx; - s! } !$g_escape_table{'}'}!gx; - s! \[ !$g_escape_table{'['}!gx; - s! \] !$g_escape_table{']'}!gx; - s! \\ !$g_escape_table{'\\'}!gx; - - return $_; -} - - -sub _DoItalicsAndBold { - my $text = shift; - - # must go first: - $text =~ s{ (\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1 } - {$2}gsx; - - $text =~ s{ (\*|_) (?=\S) (.+?) (?<=\S) \1 } - {$2}gsx; - - return $text; -} - - -sub _DoBlockQuotes { - my $text = shift; - - $text =~ s{ - ( # Wrap whole match in $1 - ( - ^[ \t]*>[ \t]? # '>' at the start of a line - .+\n # rest of the first line - (.+\n)* # subsequent consecutive lines - \n* # blanks - )+ - ) - }{ - my $bq = $1; - $bq =~ s/^[ \t]*>[ \t]?//gm; # trim one level of quoting - $bq =~ s/^[ \t]+$//mg; # trim whitespace-only lines - $bq = _RunBlockGamut($bq); # recurse - - $bq =~ s/^/ /g; - # These leading spaces screw with
     content, so we need to fix that:
    -			$bq =~ s{
    -					(\s*
    .+?
    ) - }{ - my $pre = $1; - $pre =~ s/^ //mg; - $pre; - }egsx; - - "
    \n$bq\n
    \n\n"; - }egmx; - - - return $text; -} - - -sub _FormParagraphs { -# -# Params: -# $text - string to process with html

    tags -# - my $text = shift; - - # Strip leading and trailing lines: - $text =~ s/\A\n+//; - $text =~ s/\n+\z//; - - my @grafs = split(/\n{2,}/, $text); - - # - # Wrap

    tags. - # - foreach (@grafs) { - unless (defined( $g_html_blocks{$_} )) { - $_ = _RunSpanGamut($_); - s/^([ \t]*)/

    /; - $_ .= "

    "; - } - } - - # - # Unhashify HTML blocks - # -# foreach my $graf (@grafs) { -# my $block = $g_html_blocks{$graf}; -# if (defined $block) { -# $graf = $block; -# } -# } - - foreach my $graf (@grafs) { - # Modify elements of @grafs in-place... - my $block = $g_html_blocks{$graf}; - if (defined $block) { - $graf = $block; - if ($block =~ m{ - \A - ( # $1 =
    tag -
    ]* - \b - markdown\s*=\s* (['"]) # $2 = attr quote char - 1 - \2 - [^>]* - > - ) - ( # $3 = contents - .* - ) - (
    ) # $4 = closing tag - \z - - }xms - ) { - my ($div_open, $div_content, $div_close) = ($1, $3, $4); - - # We can't call Markdown(), because that resets the hash; - # that initialization code should be pulled into its own sub, though. - $div_content = _HashHTMLBlocks($div_content); - $div_content = _StripLinkDefinitions($div_content); - $div_content = _RunBlockGamut($div_content); - $div_content = _UnescapeSpecialChars($div_content); - - $div_open =~ s{\smarkdown\s*=\s*(['"]).+?\1}{}ms; - - $graf = $div_open . "\n" . $div_content . "\n" . $div_close; - } - } - } - - - return join "\n\n", @grafs; -} - - -sub _EncodeAmpsAndAngles { -# Smart processing for ampersands and angle brackets that need to be encoded. - - my $text = shift; - - # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: - # http://bumppo.net/projects/amputator/ - $text =~ s/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/&/g; - - # Encode naked <'s - $text =~ s{<(?![a-z/?\$!])}{<}gi; - - return $text; -} - - -sub _EncodeBackslashEscapes { -# -# Parameter: String. -# Returns: The string, with after processing the following backslash -# escape sequences. -# - local $_ = shift; - - s! \\\\ !$g_escape_table{'\\'}!gx; # Must process escaped backslashes first. - s! \\` !$g_escape_table{'`'}!gx; - s! \\\* !$g_escape_table{'*'}!gx; - s! \\_ !$g_escape_table{'_'}!gx; - s! \\\{ !$g_escape_table{'{'}!gx; - s! \\\} !$g_escape_table{'}'}!gx; - s! \\\[ !$g_escape_table{'['}!gx; - s! \\\] !$g_escape_table{']'}!gx; - s! \\\( !$g_escape_table{'('}!gx; - s! \\\) !$g_escape_table{')'}!gx; - s! \\> !$g_escape_table{'>'}!gx; - s! \\\# !$g_escape_table{'#'}!gx; - s! \\\+ !$g_escape_table{'+'}!gx; - s! \\\- !$g_escape_table{'-'}!gx; - s! \\\. !$g_escape_table{'.'}!gx; - s{ \\! }{$g_escape_table{'!'}}gx; - - return $_; -} - - -sub _DoAutoLinks { - my $text = shift; - - $text =~ s{<((https?|ftp|dict):[^'">\s]+)>}{
    $1}gi; - - # Email addresses: - $text =~ s{ - < - (?:mailto:)? - ( - [-.\w]+ - \@ - [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ - ) - > - }{ - _EncodeEmailAddress( _UnescapeSpecialChars($1) ); - }egix; - - return $text; -} - - -sub _EncodeEmailAddress { -# -# Input: an email address, e.g. "foo@example.com" -# -# Output: the email address as a mailto link, with each character -# of the address encoded as either a decimal or hex entity, in -# the hopes of foiling most address harvesting spam bots. E.g.: -# -# foo -# @example.com -# -# Based on a filter by Matthew Wickline, posted to the BBEdit-Talk -# mailing list: -# - - my $addr = shift; - - srand; - my @encode = ( - sub { '&#' . ord(shift) . ';' }, - sub { '&#x' . sprintf( "%X", ord(shift) ) . ';' }, - sub { shift }, - ); - - $addr = "mailto:" . $addr; - - $addr =~ s{(.)}{ - my $char = $1; - if ( $char eq '@' ) { - # this *must* be encoded. I insist. - $char = $encode[int rand 1]->($char); - } elsif ( $char ne ':' ) { - # leave ':' alone (to spot mailto: later) - my $r = rand; - # roughly 10% raw, 45% hex, 45% dec - $char = ( - $r > .9 ? $encode[2]->($char) : - $r < .45 ? $encode[1]->($char) : - $encode[0]->($char) - ); - } - $char; - }gex; - - $addr = qq{$addr}; - $addr =~ s{">.+?:}{">}; # strip the mailto: from the visible part - - return $addr; -} - - -sub _UnescapeSpecialChars { -# -# Swap back in all the special characters we've hidden. -# - my $text = shift; - - while( my($char, $hash) = each(%g_escape_table) ) { - $text =~ s/$hash/$char/g; - } - return $text; -} - - -sub _TokenizeHTML { -# -# Parameter: String containing HTML markup. -# Returns: Reference to an array of the tokens comprising the input -# string. Each token is either a tag (possibly with nested, -# tags contained therein, such as , or a -# run of text between tags. Each element of the array is a -# two-element array; the first is either 'tag' or 'text'; -# the second is the actual value. -# -# -# Derived from the _tokenize() subroutine from Brad Choate's MTRegex plugin. -# -# - - my $str = shift; - my $pos = 0; - my $len = length $str; - my @tokens; - - my $depth = 6; - my $nested_tags = join('|', ('(?:<[a-z/!$](?:[^<>]') x $depth) . (')*>)' x $depth); - my $match = qr/(?s: ) | # comment - (?s: <\? .*? \?> ) | # processing instruction - $nested_tags/ix; # nested tags - - while ($str =~ m/($match)/g) { - my $whole_tag = $1; - my $sec_start = pos $str; - my $tag_start = $sec_start - length $whole_tag; - if ($pos < $tag_start) { - push @tokens, ['text', substr($str, $pos, $tag_start - $pos)]; - } - push @tokens, ['tag', $whole_tag]; - $pos = pos $str; - } - push @tokens, ['text', substr($str, $pos, $len - $pos)] if $pos < $len; - - return \@tokens; -} - - -sub _Outdent { -# -# Remove one level of line-leading tabs or spaces -# - my $text = shift; - - $text =~ s/^(\t|[ ]{1,$g_tab_width})//gm; - return $text; -} - - -sub _Detab { -# -# Cribbed from a post by Bart Lateur: -# -# - my $text = shift; - - $text =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge; - return $text; -} - - -1; - -__END__ - - -=pod - -=head1 NAME - -B - - -=head1 SYNOPSIS - -B [ B<--html4tags> ] [ B<--version> ] [ B<-shortversion> ] - [ I ... ] - - -=head1 DESCRIPTION - -Markdown is a text-to-HTML filter; it translates an easy-to-read / -easy-to-write structured text format into HTML. Markdown's text format -is most similar to that of plain text email, and supports features such -as headers, *emphasis*, code blocks, blockquotes, and links. - -Markdown's syntax is designed not as a generic markup language, but -specifically to serve as a front-end to (X)HTML. You can use span-level -HTML tags anywhere in a Markdown document, and you can use block level -HTML tags (like
    and
    as well). - -For more information about Markdown's syntax, see: - - http://daringfireball.net/projects/markdown/ - - -=head1 OPTIONS - -Use "--" to end switch parsing. For example, to open a file named "-z", use: - - Markdown.pl -- -z - -=over 4 - - -=item B<--html4tags> - -Use HTML 4 style for empty element tags, e.g.: - -
    - -instead of Markdown's default XHTML style tags, e.g.: - -
    - - -=item B<-v>, B<--version> - -Display Markdown's version number and copyright information. - - -=item B<-s>, B<--shortversion> - -Display the short-form version number. - - -=back - - - -=head1 BUGS - -To file bug reports or feature requests (other than topics listed in the -Caveats section above) please send email to: - - support@daringfireball.net - -Please include with your report: (1) the example input; (2) the output -you expected; (3) the output Markdown actually produced. - - -=head1 VERSION HISTORY - -See the readme file for detailed release notes for this version. - -1.0.2b7 - - + Changed shebang line from "/usr/bin/perl" to "/usr/bin/env perl" - - + Now only trim trailing newlines from code blocks, instead of trimming - all trailing whitespace characters. - - -1.0.2b6 - Mon 03 Apr 2006 - - + Fixed bad performance bug in new `Text::Balanced`-based block-level parser. - - -1.0.2b5 - Thu 08 Dec 2005 - - + Fixed bug where this: - - [text](http://m.com "title" ) - - wasn't working as expected, because the parser wasn't allowing for spaces - before the closing paren. - - -1.0.2b4 - Thu 08 Sep 2005 - - + Filthy hack to support markdown='1' in div tags, because I need it - to write today's fireball. - - + First crack at a new, smarter, block-level HTML parser. - -1.0.2b3 - Thu 28 Apr 2005 - - + _DoAutoLinks() now supports the 'dict://' URL scheme. - - + PHP- and ASP-style processor instructions are now protected as - raw HTML blocks. - - - <% ... %> - - + Workarounds for regressions introduced with fix for "backticks within - tags" bug in 1.0.2b1. The fix is to allow `...` to be turned into - ... within an HTML tag attribute, and then to turn - these spurious `` tags back into literal backtick characters - in _EscapeSpecialCharsWithinTagAttributes(). - - The regression was caused because in the fix, we moved - _EscapeSpecialCharsWithinTagAttributes() ahead of _DoCodeSpans() - in _RunSpanGamut(), but that's no good. We need to process code - spans first, otherwise we can get tripped up by something like this: - - `` - - -1.0.2b2 - 20 Mar 2005 - - + Fix for nested sub-lists in list-paragraph mode. Previously we got - a spurious extra level of `

    ` tags for something like this: - - * this - - * sub - - that - - + Experimental support for [this] as a synonym for [this][]. - (Note to self: No test yet for this.) - Be sure to test, e.g.: [permutations of this sort of [thing][].] - - -1.0.2b1 - 28 Feb 2005 - - + Fix for backticks within HTML tag: like this - - + Fix for escaped backticks still triggering code spans: - - There are two raw backticks here: \` and here: \`, not a code span - -1.0.1 - 14 Dec 2004 - -1.0 - 28 Aug 2004 - - -=head1 AUTHOR - - John Gruber - http://daringfireball.net - - PHP port and other contributions by Michel Fortin - http://michelf.com - - -=head1 COPYRIGHT AND LICENSE - -Copyright (c) 2003-2005 John Gruber - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name "Markdown" nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as -is" and any express or implied warranties, including, but not limited -to, the implied warranties of merchantability and fitness for a -particular purpose are disclaimed. In no event shall the copyright owner -or contributors be liable for any direct, indirect, incidental, special, -exemplary, or consequential damages (including, but not limited to, -procurement of substitute goods or services; loss of use, data, or -profits; or business interruption) however caused and on any theory of -liability, whether in contract, strict liability, or tort (including -negligence or otherwise) arising in any way out of the use of this -software, even if advised of the possibility of such damage. - -=cut diff --git a/perlMarkdown/readme.txt b/perlMarkdown/readme.txt deleted file mode 100644 index 9e73e56..0000000 --- a/perlMarkdown/readme.txt +++ /dev/null @@ -1,13 +0,0 @@ -Reference Implementation ------------------------- - -This directory contains John Gruber's original Perl implementation of Markdown. Smart diff programs like Araxis Merge will be able to match up this file with markdown.pl. - -A little tweaking helps. In markdown.pl: - - - replace `#` with `//` - - replace `$text` with `text` - -Be sure to ignore whitespace and line endings. - -Note: This release of Showdown is based on `markdown1.0.2b7.pl`, but uses the HTML parser from `markdown1.0.2b2.pl`. diff --git a/src/cli/cli.js b/src/cli/cli.js new file mode 100644 index 0000000..7cd8dc4 --- /dev/null +++ b/src/cli/cli.js @@ -0,0 +1,30 @@ +'use strict'; + +var version = require('../../package.json').version, + yargs = require('yargs'); + +yargs + .version(version, 'v') + .alias('v', 'version') + .option('h', { + alias: 'help', + description: 'Show help' + }) + .usage('Usage: showdown [options]') + .demand(1, 'You must provide a valid command') + .command('makehtml', 'Converts markdown into html') + .example('showdown makehtml -i foo.md -o bar.html', 'Converts \'foo.md\' to \'bar.html\'') + .wrap(yargs.terminalWidth()); + +var argv = yargs.argv, + command = argv._[0]; +if (command === 'makehtml') { + require('./makehtml.cmd.js').run(); +} else { + yargs.showHelp(); +} + +if (argv.help) { + yargs.showHelp(); +} +process.exit(0); diff --git a/src/cli/errorexit.js b/src/cli/errorexit.js new file mode 100644 index 0000000..ea25eff --- /dev/null +++ b/src/cli/errorexit.js @@ -0,0 +1,6 @@ +module.exports = exports = function errorExit(e) { + 'use strict'; + console.error('ERROR: ' + e.message); + console.error('Run \'showdown -h\' for help'); + process.exit(1); +}; diff --git a/src/cli/makehtml.cmd.js b/src/cli/makehtml.cmd.js new file mode 100644 index 0000000..acaf359 --- /dev/null +++ b/src/cli/makehtml.cmd.js @@ -0,0 +1,123 @@ +var yargs = require('yargs'), + fs = require('fs'), + errorExit = require('./errorexit.js'), + showdown = require('../../dist/showdown'); + +yargs.reset() + .usage('Usage: showdown makehtml [options]') + .example('showdown makehtml -i', 'Reads from stdin and outputs to stdout') + .example('showdown makehtml -i foo.md -o bar.html', 'Reads \'foo.md\' and writes to \'bar.html\'') + //.demand(['i']) + .option('i', { + alias : 'input', + describe: 'Input source. Usually a md file. If omitted or empty, reads from stdin', + type: 'string' + }) + .option('o', { + alias : 'output', + describe: 'Output target. Usually a html file. If omitted or empty, writes to stdout', + type: 'string', + default: false + }) + .option('u', { + alias : 'encoding', + describe: 'Input encoding', + type: 'string' + }) + .option('a', { + alias : 'append', + describe: 'Append data to output instead of overwriting', + type: 'string' + }) + .option('e', { + alias : 'extensions', + describe: 'Load the specified extensions. Should be valid paths to node compatible extensions', + type: 'array' + }) + .config('c') + .alias('c', 'config') + .help('h') + .alias('h', 'help'); + +yargs.options(showdown.getDefaultOptions(false)); +argv = yargs.argv; + +function run() { + 'use strict'; + var input = '', + enc = 'utf8', + output; + + if (argv.encoding) { + enc = argv.encoding; + } + + // to avoid passing extensions to converter + delete argv.extensions; + var converter = new showdown.Converter(argv); + + // Load extensions + if (argv.e) { + for (var i = 0; i < argv.e.length; ++i) { + loadExtension(argv.e[i], converter); + } + } + + if (!argv.i || argv.i === '') { + // 'i' is undefined or empty, read from stdin + try { + var size = fs.fstatSync(process.stdin.fd).size; + input = size > 0 ? fs.readSync(process.stdin.fd, size)[0] : ''; + } catch (e) { + var err = new Error('Could not read from stdin, reason: ' + e.message); + errorExit(err); + } + } else { + // 'i' has a value, read from file + try { + input = fs.readFileSync(argv.i, enc); + } catch (err) { + errorExit(err); + } + } + + // parse and convert file + output = converter.makeHtml(input); + + // Write output + if (!argv.o || argv.o === '') { + // o is undefined or empty, write to stdout + process.stdout.write(output); + // we won't print anything since it would conspurcate stdout and, + // consequently, the outputted file + } else { + // o is has a value, presumably a file, write to it. + + // If a flag is passed, it means we should append instead of overwriting. + // Only works with files, obviously + var write = (argv.a) ? fs.appendFileSync : fs.writeFileSync; + + try { + write(argv.o, output); + } catch (err) { + errorExit(err); + } + console.error('DONE!'); + } +} + +function loadExtension(path, converter) { + 'use strict'; + var ext; + try { + ext = require(path); + converter.addExtension(ext, path); + } catch (e) { + console.error('Could not load extension ' + path + '. Reason:'); + console.error(e.message); + } +} + +module.exports = exports = { + run: run +}; diff --git a/src/converter.js b/src/converter.js new file mode 100644 index 0000000..55ecb44 --- /dev/null +++ b/src/converter.js @@ -0,0 +1,344 @@ +/** + * Created by Estevao on 31-05-2015. + */ + +/** + * Showdown Converter class + * @class + * @param {object} [converterOptions] + * @returns { + * {makeHtml: Function}, + * {setOption: Function}, + * {getOption: Function}, + * {getOptions: Function} + * } + */ +showdown.Converter = function (converterOptions) { + 'use strict'; + + var + /** + * Options used by this converter + * @private + * @type {{}} + */ + options = {}, + + /** + * Language extensions used by this converter + * @private + * @type {Array} + */ + langExtensions = [], + + /** + * Output modifiers extensions used by this converter + * @private + * @type {Array} + */ + outputModifiers = [], + + /** + * The parser Order + * @private + * @type {string[]} + */ + parserOrder = [ + 'githubCodeBlocks', + 'hashHTMLBlocks', + 'stripLinkDefinitions', + 'blockGamut', + 'unescapeSpecialChars' + ]; + + _constructor(); + + /** + * Converter constructor + * @private + */ + function _constructor() { + converterOptions = converterOptions || {}; + + for (var gOpt in globalOptions) { + if (globalOptions.hasOwnProperty(gOpt)) { + options[gOpt] = globalOptions[gOpt]; + } + } + + // Merge options + if (typeof converterOptions === 'object') { + for (var opt in converterOptions) { + if (converterOptions.hasOwnProperty(opt)) { + options[opt] = converterOptions[opt]; + } + } + } else { + throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions + + ' was passed instead.'); + } + + if (options.extensions) { + showdown.helper.forEach(options.extensions, _parseExtension); + } + } + + /** + * Parse extension + * @param {*} ext + * @param {string} [name=''] + * @private + */ + function _parseExtension(ext, name) { + + name = name || null; + // If it's a string, the extension was previously loaded + if (showdown.helper.isString(ext)) { + ext = showdown.helper.stdExtName(ext); + name = ext; + + // LEGACY_SUPPORT CODE + if (showdown.extensions[ext]) { + console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' + + 'Please inform the developer that the extension should be updated!'); + legacyExtensionLoading(showdown.extensions[ext], ext); + return; + // END LEGACY SUPPORT CODE + + } else if (!showdown.helper.isUndefined(extensions[ext])) { + ext = extensions[ext]; + + } else { + throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.'); + } + } + + if (typeof ext === 'function') { + ext = ext(); + } + + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } + + var validExt = validate(ext, name); + if (!validExt.valid) { + throw Error(validExt.error); + } + + for (var i = 0; i < ext.length; ++i) { + switch (ext[i].type) { + case 'lang': + langExtensions.push(ext[i]); + break; + + case 'output': + outputModifiers.push(ext[i]); + break; + + default: + // should never reach here + throw Error('Extension loader error: Type unrecognized!!!'); + } + } + } + + /** + * LEGACY_SUPPORT + * @param {*} ext + * @param {string} name + */ + function legacyExtensionLoading(ext, name) { + if (typeof ext === 'function') { + ext = ext(new showdown.Converter()); + } + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } + var valid = validate(ext, name); + + if (!valid.valid) { + throw Error(valid.error); + } + + for (var i = 0; i < ext.length; ++i) { + switch (ext[i].type) { + case 'lang': + langExtensions.push(ext[i]); + break; + case 'output': + outputModifiers.push(ext[i]); + break; + default:// should never reach here + throw Error('Extension loader error: Type unrecognized!!!'); + } + } + } + + /** + * Converts a markdown string into HTML + * @param {string} text + * @returns {*} + */ + this.makeHtml = function (text) { + //check if text is not falsy + if (!text) { + return text; + } + + var globals = { + gHtmlBlocks: [], + gUrls: {}, + gTitles: {}, + gDimensions: {}, + gListLevel: 0, + hashLinkCounts: {}, + langExtensions: langExtensions, + outputModifiers: outputModifiers, + converter: this + }; + + // attacklab: Replace ~ with ~T + // This lets us use tilde as an escape char to avoid md5 hashes + // The choice of character is arbitrary; anything that isn't + // magic in Markdown will work. + text = text.replace(/~/g, '~T'); + + // attacklab: Replace $ with ~D + // RegExp interprets $ as a special character + // when it's in a replacement string + text = text.replace(/\$/g, '~D'); + + // Standardize line endings + text = text.replace(/\r\n/g, '\n'); // DOS to Unix + text = text.replace(/\r/g, '\n'); // Mac to Unix + + // Make sure text begins and ends with a couple of newlines: + text = '\n\n' + text + '\n\n'; + + // detab + text = showdown.subParser('detab')(text, options, globals); + + // stripBlankLines + text = showdown.subParser('stripBlankLines')(text, options, globals); + + //run languageExtensions + showdown.helper.forEach(langExtensions, function (ext) { + text = showdown.subParser('runExtension')(ext, text, options, globals); + }); + + // Run all registered parsers + for (var i = 0; i < parserOrder.length; ++i) { + var name = parserOrder[i]; + text = parsers[name](text, options, globals); + } + + // attacklab: Restore dollar signs + text = text.replace(/~D/g, '$$'); + + // attacklab: Restore tildes + text = text.replace(/~T/g, '~'); + + // Run output modifiers + showdown.helper.forEach(outputModifiers, function (ext) { + text = showdown.subParser('runExtension')(ext, text, options, globals); + }); + + return text; + }; + + /** + * Set an option of this Converter instance + * @param {string} key + * @param {*} value + */ + this.setOption = function (key, value) { + options[key] = value; + }; + + /** + * Get the option of this Converter instance + * @param {string} key + * @returns {*} + */ + this.getOption = function (key) { + return options[key]; + }; + + /** + * Get the options of this Converter instance + * @returns {{}} + */ + this.getOptions = function () { + return options; + }; + + /** + * Add extension to THIS converter + * @param {{}} extension + * @param {string} [name=null] + */ + this.addExtension = function (extension, name) { + name = name || null; + _parseExtension(extension, name); + }; + + /** + * Use a global registered extension with THIS converter + * @param {string} extensionName Name of the previously registered extension + */ + this.useExtension = function (extensionName) { + _parseExtension(extensionName); + }; + + /** + * Set the flavor THIS converter should use + * @param {string} name + */ + this.setFlavor = function (name) { + if (flavor.hasOwnProperty(name)) { + var preset = flavor[name]; + for (var option in preset) { + if (preset.hasOwnProperty(option)) { + options[option] = preset[option]; + } + } + } + }; + + /** + * Remove an extension from THIS converter. + * Note: This is a costly operation. It's better to initialize a new converter + * and specify the extensions you wish to use + * @param {Array} extension + */ + this.removeExtension = function (extension) { + if (!showdown.helper.isArray(extension)) { + extension = [extension]; + } + for (var a = 0; a < extension.length; ++a) { + var ext = extension[a]; + for (var i = 0; i < langExtensions.length; ++i) { + if (langExtensions[i] === ext) { + langExtensions[i].splice(i, 1); + } + } + for (var ii = 0; ii < outputModifiers.length; ++i) { + if (outputModifiers[ii] === ext) { + outputModifiers[ii].splice(i, 1); + } + } + } + }; + + /** + * Get all extension of THIS converter + * @returns {{language: Array, output: Array}} + */ + this.getAllExtensions = function () { + return { + language: langExtensions, + output: outputModifiers + }; + }; +}; diff --git a/src/extensions/github.js b/src/extensions/github.js deleted file mode 100644 index c4f8682..0000000 --- a/src/extensions/github.js +++ /dev/null @@ -1,25 +0,0 @@ -// -// Github Extension (WIP) -// ~~strike-through~~ -> strike-through -// - -(function(){ - var github = function(converter) { - return [ - { - // strike-through - // NOTE: showdown already replaced "~" with "~T", so we need to adjust accordingly. - type : 'lang', - regex : '(~T){2}([^~]+)(~T){2}', - replace : function(match, prefix, content, suffix) { - return '' + content + ''; - } - } - ]; - }; - - // Client-side export - if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.github = github; } - // Server-side export - if (typeof module !== 'undefined') module.exports = github; -}()); diff --git a/src/extensions/prettify.js b/src/extensions/prettify.js deleted file mode 100644 index 4b3a70b..0000000 --- a/src/extensions/prettify.js +++ /dev/null @@ -1,29 +0,0 @@ -// -// Google Prettify -// A showdown extension to add Google Prettify (http://code.google.com/p/google-code-prettify/) -// hints to showdown's HTML output. -// - -(function(){ - - var prettify = function(converter) { - return [ - { type: 'output', filter: function(source){ - - return source.replace(/(

    )?/gi, function(match, pre) {
    -                    if (pre) {
    -                        return '
    ';
    -                    } else {
    -                        return '';
    -                    }
    -                });
    -            }}
    -        ];
    -    };
    -
    -    // Client-side export
    -    if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.prettify = prettify; }
    -    // Server-side export
    -    if (typeof module !== 'undefined') module.exports = prettify;
    -
    -}());
    diff --git a/src/extensions/table.js b/src/extensions/table.js
    deleted file mode 100644
    index 7bf1954..0000000
    --- a/src/extensions/table.js
    +++ /dev/null
    @@ -1,105 +0,0 @@
    -/*global module:true*/
    -/*
    - * Basic table support with re-entrant parsing, where cell content
    - * can also specify markdown.
    - *
    - * Tables
    - * ======
    - *
    - * | Col 1   | Col 2                                              |
    - * |======== |====================================================|
    - * |**bold** | ![Valid XHTML] (http://w3.org/Icons/valid-xhtml10) |
    - * | Plain   | Value                                              |
    - *
    - */
    -
    -(function(){
    -  var table = function(converter) {
    -    var tables = {}, style = 'text-align:left;', filter; 
    -    tables.th = function(header){
    -      if (header.trim() === "") { return "";}
    -      var id = header.trim().replace(/ /g, '_').toLowerCase();
    -      return '
    '; - }; - tables.td = function(cell) { - return ''; - }; - tables.ths = function(){ - var out = "", i = 0, hs = [].slice.apply(arguments); - for (i;i']; - hs = line.substring(1, line.length -1).split('|'); - tbl.push(tables.thead.apply(this, hs)); - line = lines[++i]; - if (!line.trim().match(/^[|]{1}[-=| ]+[|]{1}$/)) { - // not a table rolling back - line = lines[--i]; - } - else { - line = lines[++i]; - tbl.push(''); - while (line.trim().match(/^[|]{1}.*[|]{1}$/)) { - line = line.trim(); - tbl.push(tables.tr.apply(this, line.substring(1, line.length -1).split('|'))); - line = lines[++i]; - } - tbl.push(''); - tbl.push('
    ' + header + '' + converter.makeHtml(cell) + '
    '); - // we are done with this table and we move along - out.push(tbl.join('\n')); - continue; - } - } - out.push(line); - } - return out.join('\n'); - }; - return [ - { - type: 'lang', - filter: filter - } - ]; - }; - - // Client-side export - if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.table = table; } - // Server-side export - if (typeof module !== 'undefined') { - module.exports = table; - } -}()); diff --git a/src/extensions/twitter.js b/src/extensions/twitter.js deleted file mode 100644 index cde3379..0000000 --- a/src/extensions/twitter.js +++ /dev/null @@ -1,42 +0,0 @@ -// -// Twitter Extension -// @username -> @username -// #hashtag -> #hashtag -// - -(function(){ - - var twitter = function(converter) { - return [ - - // @username syntax - { type: 'lang', regex: '\\B(\\\\)?@([\\S]+)\\b', replace: function(match, leadingSlash, username) { - // Check if we matched the leading \ and return nothing changed if so - if (leadingSlash === '\\') { - return match; - } else { - return '@' + username + ''; - } - }}, - - // #hashtag syntax - { type: 'lang', regex: '\\B(\\\\)?#([\\S]+)\\b', replace: function(match, leadingSlash, tag) { - // Check if we matched the leading \ and return nothing changed if so - if (leadingSlash === '\\') { - return match; - } else { - return '#' + tag + ''; - } - }}, - - // Escaped @'s - { type: 'lang', regex: '\\\\@', replace: '@' } - ]; - }; - - // Client-side export - if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.twitter = twitter; } - // Server-side export - if (typeof module !== 'undefined') module.exports = twitter; - -}()); diff --git a/src/helpers.js b/src/helpers.js new file mode 100644 index 0000000..eb2a6ff --- /dev/null +++ b/src/helpers.js @@ -0,0 +1,123 @@ +/** + * showdownjs helper functions + */ + +if (!showdown.hasOwnProperty('helper')) { + showdown.helper = {}; +} + +/** + * Check if var is string + * @static + * @param {string} a + * @returns {boolean} + */ +showdown.helper.isString = function isString(a) { + 'use strict'; + return (typeof a === 'string' || a instanceof String); +}; + +/** + * ForEach helper function + * @static + * @param {*} obj + * @param {function} callback + */ +showdown.helper.forEach = function forEach(obj, callback) { + 'use strict'; + if (typeof obj.forEach === 'function') { + obj.forEach(callback); + } else { + for (var i = 0; i < obj.length; i++) { + callback(obj[i], i, obj); + } + } +}; + +/** + * isArray helper function + * @static + * @param {*} a + * @returns {boolean} + */ +showdown.helper.isArray = function isArray(a) { + 'use strict'; + return a.constructor === Array; +}; + +/** + * Check if value is undefined + * @static + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + */ +showdown.helper.isUndefined = function isUndefined(value) { + 'use strict'; + return typeof value === 'undefined'; +}; + +/** + * Standardidize extension name + * @static + * @param {string} s extension name + * @returns {string} + */ +showdown.helper.stdExtName = function (s) { + 'use strict'; + return s.replace(/[_-]||\s/g, '').toLowerCase(); +}; + +function escapeCharactersCallback(wholeMatch, m1) { + 'use strict'; + var charCodeToEscape = m1.charCodeAt(0); + return '~E' + charCodeToEscape + 'E'; +} + +/** + * Callback used to escape characters when passing through String.replace + * @static + * @param {string} wholeMatch + * @param {string} m1 + * @returns {string} + */ +showdown.helper.escapeCharactersCallback = escapeCharactersCallback; + +/** + * Escape characters in a string + * @static + * @param {string} text + * @param {string} charsToEscape + * @param {boolean} afterBackslash + * @returns {XML|string|void|*} + */ +showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape, afterBackslash) { + 'use strict'; + // First we have to escape the escape characters so that + // we can build a character class out of them + var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])'; + + if (afterBackslash) { + regexString = '\\\\' + regexString; + } + + var regex = new RegExp(regexString, 'g'); + text = text.replace(regex, escapeCharactersCallback); + + return text; +}; + +/** + * POLYFILLS + */ +if (showdown.helper.isUndefined(console)) { + console = { + warn: function (msg) { + 'use strict'; + alert(msg); + }, + log: function (msg) { + 'use strict'; + alert(msg); + } + }; +} diff --git a/src/loader.js b/src/loader.js new file mode 100644 index 0000000..255ed92 --- /dev/null +++ b/src/loader.js @@ -0,0 +1,17 @@ +var root = this; + +// CommonJS/nodeJS Loader +if (typeof module !== 'undefined' && module.exports) { + module.exports = showdown; + +// AMD Loader +} else if (typeof define === 'function' && define.amd) { + define('showdown', function () { + 'use strict'; + return showdown; + }); + +// Regular Browser loader +} else { + root.showdown = showdown; +} diff --git a/src/options.js b/src/options.js new file mode 100644 index 0000000..9364938 --- /dev/null +++ b/src/options.js @@ -0,0 +1,85 @@ +/** + * Created by Tivie on 13-07-2015. + */ + +function getDefaultOpts(simple) { + 'use strict'; + + var defaultOptions = { + omitExtraWLInCodeBlocks: { + default: false, + describe: 'Omit the default extra whiteline added to code blocks', + type: 'boolean' + }, + noHeaderId: { + default: false, + describe: 'Turn on/off generated header id', + type: 'boolean' + }, + prefixHeaderId: { + default: false, + describe: 'Specify a prefix to generated header ids', + type: 'string' + }, + headerLevelStart: { + default: false, + describe: 'The header blocks level start', + type: 'integer' + }, + parseImgDimensions: { + default: false, + describe: 'Turn on/off image dimension parsing', + type: 'boolean' + }, + simplifiedAutoLink: { + default: false, + describe: 'Turn on/off GFM autolink style', + type: 'boolean' + }, + literalMidWordUnderscores: { + default: false, + describe: 'Parse midword underscores as literal underscores', + type: 'boolean' + }, + strikethrough: { + default: false, + describe: 'Turn on/off strikethrough support', + type: 'boolean' + }, + tables: { + default: false, + describe: 'Turn on/off tables support', + type: 'boolean' + }, + tablesHeaderId: { + default: false, + describe: 'Add an id to table headers', + type: 'boolean' + }, + ghCodeBlocks: { + default: true, + describe: 'Turn on/off GFM fenced code blocks support', + type: 'boolean' + }, + tasklists: { + default: false, + describe: 'Turn on/off GFM tasklist support', + type: 'boolean' + }, + smoothLivePreview: { + default: false, + describe: 'Prevents weird effects in live previews due to incomplete input', + type: 'boolean' + } + }; + if (simple === false) { + return JSON.parse(JSON.stringify(defaultOptions)); + } + var ret = {}; + for (var opt in defaultOptions) { + if (defaultOptions.hasOwnProperty(opt)) { + ret[opt] = defaultOptions[opt].default; + } + } + return ret; +} diff --git a/src/showdown.js b/src/showdown.js index b488bad..1ee2ee0 100644 --- a/src/showdown.js +++ b/src/showdown.js @@ -1,1454 +1,306 @@ -// -// showdown.js -- A javascript port of Markdown. -// -// Copyright (c) 2007 John Fraser. -// -// Original Markdown Copyright (c) 2004-2005 John Gruber -// -// -// Redistributable under a BSD-style open source license. -// See license.txt for more information. -// -// The full source distribution is at: -// -// A A L -// T C A -// T K B -// -// -// +/** + * Created by Tivie on 06-01-2015. + */ -// -// Wherever possible, Showdown is a straight, line-by-line port -// of the Perl version of Markdown. -// -// This is not a normal parser design; it's basically just a -// series of string substitutions. It's hard to read and -// maintain this way, but keeping Showdown close to the original -// design makes it easier to port new features. -// -// More importantly, Showdown behaves like markdown.pl in most -// edge cases. So web applications can do client-side preview -// in Javascript, and then build identical HTML on the server. -// -// This port needs the new RegExp functionality of ECMA 262, -// 3rd Edition (i.e. Javascript 1.5). Most modern web browsers -// should do fine. Even with the new regular expression features, -// We do a lot of work to emulate Perl's regex functionality. -// The tricky changes in this file mostly have the "attacklab:" -// label. Major or self-explanatory changes don't. -// -// Smart diff tools like Araxis Merge will be able to match up -// this file with markdown.pl in a useful way. A little tweaking -// helps: in a copy of markdown.pl, replace "#" with "//" and -// replace "$text" with "text". Be sure to ignore whitespace -// and line endings. -// +// Private properties +var showdown = {}, + parsers = {}, + extensions = {}, + globalOptions = getDefaultOpts(true), + flavor = { + github: { + omitExtraWLInCodeBlocks: true, + prefixHeaderId: 'user-content-', + simplifiedAutoLink: true, + literalMidWordUnderscores: true, + strikethrough: true, + tables: true, + tablesHeaderId: true, + ghCodeBlocks: true, + tasklists: true + }, + vanilla: getDefaultOpts(true) + }; +/** + * helper namespace + * @type {{}} + */ +showdown.helper = {}; -// -// Showdown usage: -// -// var text = "Markdown *rocks*."; -// -// var converter = new Showdown.converter(); -// var html = converter.makeHtml(text); -// -// alert(html); -// -// Note: move the sample code to the bottom of this -// file before uncommenting it. -// +/** + * TODO LEGACY SUPPORT CODE + * @type {{}} + */ +showdown.extensions = {}; - -// -// Showdown namespace -// -var Showdown = { extensions: {} }; - -// -// forEach -// -var forEach = Showdown.forEach = function(obj, callback) { - if (typeof obj.forEach === 'function') { - obj.forEach(callback); - } else { - var i, len = obj.length; - for (i = 0; i < len; i++) { - callback(obj[i], i, obj); - } - } +/** + * Set a global option + * @static + * @param {string} key + * @param {*} value + * @returns {showdown} + */ +showdown.setOption = function (key, value) { + 'use strict'; + globalOptions[key] = value; + return this; }; -// -// Standard extension naming -// -var stdExtName = function(s) { - return s.replace(/[_-]||\s/g, '').toLowerCase(); +/** + * Get a global option + * @static + * @param {string} key + * @returns {*} + */ +showdown.getOption = function (key) { + 'use strict'; + return globalOptions[key]; }; -// -// converter -// -// Wraps all "globals" so that the only thing -// exposed is makeHtml(). -// -Showdown.converter = function(converter_options) { - -// -// Globals: -// - -// Global hashes, used by various utility routines -var g_urls; -var g_titles; -var g_html_blocks; - -// Used to track when we're inside an ordered or unordered list -// (see _ProcessListItems() for details): -var g_list_level = 0; - -// Global extensions -var g_lang_extensions = []; -var g_output_modifiers = []; - - -// -// Automatic Extension Loading (node only): -// - -if (typeof module !== 'undefind' && typeof exports !== 'undefined' && typeof require !== 'undefind') { - var fs = require('fs'); - - if (fs) { - // Search extensions folder - var extensions = fs.readdirSync((__dirname || '.')+'/extensions').filter(function(file){ - return ~file.indexOf('.js'); - }).map(function(file){ - return file.replace(/\.js$/, ''); - }); - // Load extensions into Showdown namespace - Showdown.forEach(extensions, function(ext){ - var name = stdExtName(ext); - Showdown.extensions[name] = require('./extensions/' + ext); - }); - } -} - -this.makeHtml = function(text) { -// -// Main function. The order in which other subs are called here is -// essential. Link and image substitutions need to happen before -// _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the -// and tags get encoded. -// - - // Clear the global hashes. If we don't clear these, you get conflicts - // from other articles when generating a page which contains more than - // one article (e.g. an index page that shows the N most recent - // articles): - g_urls = {}; - g_titles = {}; - g_html_blocks = []; - - // attacklab: Replace ~ with ~T - // This lets us use tilde as an escape char to avoid md5 hashes - // The choice of character is arbitray; anything that isn't - // magic in Markdown will work. - text = text.replace(/~/g,"~T"); - - // attacklab: Replace $ with ~D - // RegExp interprets $ as a special character - // when it's in a replacement string - text = text.replace(/\$/g,"~D"); - - // Standardize line endings - text = text.replace(/\r\n/g,"\n"); // DOS to Unix - text = text.replace(/\r/g,"\n"); // Mac to Unix - - // Make sure text begins and ends with a couple of newlines: - text = "\n\n" + text + "\n\n"; - - // Convert all tabs to spaces. - text = _Detab(text); - - // Strip any lines consisting only of spaces and tabs. - // This makes subsequent regexen easier to write, because we can - // match consecutive blank lines with /\n+/ instead of something - // contorted like /[ \t]*\n+/ . - text = text.replace(/^[ \t]+$/mg,""); - - // Run language extensions - Showdown.forEach(g_lang_extensions, function(x){ - text = _ExecuteExtension(x, text); - }); - - // Handle github codeblocks prior to running HashHTML so that - // HTML contained within the codeblock gets escaped propertly - text = _DoGithubCodeBlocks(text); - - // Turn block-level HTML blocks into hash entries - text = _HashHTMLBlocks(text); - - // Strip link definitions, store in hashes. - text = _StripLinkDefinitions(text); - - text = _RunBlockGamut(text); - - text = _UnescapeSpecialChars(text); - - // attacklab: Restore dollar signs - text = text.replace(/~D/g,"$$"); - - // attacklab: Restore tildes - text = text.replace(/~T/g,"~"); - - // Run output modifiers - Showdown.forEach(g_output_modifiers, function(x){ - text = _ExecuteExtension(x, text); - }); - - return text; -}; -// -// Options: -// - -// Parse extensions options into separate arrays -if (converter_options && converter_options.extensions) { - - var self = this; - - // Iterate over each plugin - Showdown.forEach(converter_options.extensions, function(plugin){ - - // Assume it's a bundled plugin if a string is given - if (typeof plugin === 'string') { - plugin = Showdown.extensions[stdExtName(plugin)]; - } - - if (typeof plugin === 'function') { - // Iterate over each extension within that plugin - Showdown.forEach(plugin(self), function(ext){ - // Sort extensions by type - if (ext.type) { - if (ext.type === 'language' || ext.type === 'lang') { - g_lang_extensions.push(ext); - } else if (ext.type === 'output' || ext.type === 'html') { - g_output_modifiers.push(ext); - } - } else { - // Assume language extension - g_output_modifiers.push(ext); - } - }); - } else { - throw "Extension '" + plugin + "' could not be loaded. It was either not found or is not a valid extension."; - } - }); -} - - -var _ExecuteExtension = function(ext, text) { - if (ext.regex) { - var re = new RegExp(ext.regex, 'g'); - return text.replace(re, ext.replace); - } else if (ext.filter) { - return ext.filter(text); - } +/** + * Get the global options + * @static + * @returns {{}} + */ +showdown.getOptions = function () { + 'use strict'; + return globalOptions; }; -var _StripLinkDefinitions = function(text) { -// -// Strips link definitions from text, stores the URLs and titles in -// hash references. -// - - // Link defs are in the form: ^[id]: url "optional title" - - /* - var text = text.replace(/ - ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1 - [ \t]* - \n? // maybe *one* newline - [ \t]* - ? // url = $2 - [ \t]* - \n? // maybe one newline - [ \t]* - (?: - (\n*) // any lines skipped = $3 attacklab: lookbehind removed - ["(] - (.+?) // title = $4 - [")] - [ \t]* - )? // title is optional - (?:\n+|$) - /gm, - function(){...}); - */ - - // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug - text += "~0"; - - text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|(?=~0))/gm, - function (wholeMatch,m1,m2,m3,m4) { - m1 = m1.toLowerCase(); - g_urls[m1] = _EncodeAmpsAndAngles(m2); // Link IDs are case-insensitive - if (m3) { - // Oops, found blank lines, so it's not a title. - // Put back the parenthetical statement we stole. - return m3+m4; - } else if (m4) { - g_titles[m1] = m4.replace(/"/g,"""); - } - - // Completely remove the definition from the text - return ""; - } - ); - - // attacklab: strip sentinel - text = text.replace(/~0/,""); - - return text; -} - - -var _HashHTMLBlocks = function(text) { - // attacklab: Double up blank lines to reduce lookaround - text = text.replace(/\n/g,"\n\n"); - - // Hashify HTML blocks: - // We only want to do this for block-level HTML tags, such as headers, - // lists, and tables. That's because we still want to wrap

    s around - // "paragraphs" that are wrapped in non-block-level tags, such as anchors, - // phrase emphasis, and spans. The list of tags we're looking for is - // hard-coded: - var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del|style|section|header|footer|nav|article|aside"; - var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside"; - - // First, look for nested blocks, e.g.: - //

    - //
    - // tags for inner block must be indented. - //
    - //
    - // - // The outermost tags must start at the left margin for this to match, and - // the inner nested divs must be indented. - // We need to do this before the next, more liberal match, because the next - // match will start at the first `
    ` and stop at the first `
    `. - - // attacklab: This regex can be expensive when it fails. - /* - var text = text.replace(/ - ( // save in $1 - ^ // start of line (with /m) - <($block_tags_a) // start tag = $2 - \b // word break - // attacklab: hack around khtml/pcre bug... - [^\r]*?\n // any number of lines, minimally matching - // the matching end tag - [ \t]* // trailing spaces/tabs - (?=\n+) // followed by a newline - ) // attacklab: there are sentinel newlines at end of document - /gm,function(){...}}; - */ - text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,hashElement); - - // - // Now match more liberally, simply from `\n` to `\n` - // - - /* - var text = text.replace(/ - ( // save in $1 - ^ // start of line (with /m) - <($block_tags_b) // start tag = $2 - \b // word break - // attacklab: hack around khtml/pcre bug... - [^\r]*? // any number of lines, minimally matching - // the matching end tag - [ \t]* // trailing spaces/tabs - (?=\n+) // followed by a newline - ) // attacklab: there are sentinel newlines at end of document - /gm,function(){...}}; - */ - text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside)\b[^\r]*?<\/\2>[ \t]*(?=\n+)\n)/gm,hashElement); - - // Special case just for
    . It was easier to make a special case than - // to make the other regex more complicated. - - /* - text = text.replace(/ - ( // save in $1 - \n\n // Starting after a blank line - [ ]{0,3} - (<(hr) // start tag = $2 - \b // word break - ([^<>])*? // - \/?>) // the matching end tag - [ \t]* - (?=\n{2,}) // followed by a blank line - ) - /g,hashElement); - */ - text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement); - - // Special case for standalone HTML comments: - - /* - text = text.replace(/ - ( // save in $1 - \n\n // Starting after a blank line - [ ]{0,3} // attacklab: g_tab_width - 1 - - [ \t]* - (?=\n{2,}) // followed by a blank line - ) - /g,hashElement); - */ - text = text.replace(/(\n\n[ ]{0,3}[ \t]*(?=\n{2,}))/g,hashElement); - - // PHP and ASP-style processor instructions ( and <%...%>) - - /* - text = text.replace(/ - (?: - \n\n // Starting after a blank line - ) - ( // save in $1 - [ ]{0,3} // attacklab: g_tab_width - 1 - (?: - <([?%]) // $2 - [^\r]*? - \2> - ) - [ \t]* - (?=\n{2,}) // followed by a blank line - ) - /g,hashElement); - */ - text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement); - - // attacklab: Undo double lines (see comment at top of this function) - text = text.replace(/\n\n/g,"\n"); - return text; -} - -var hashElement = function(wholeMatch,m1) { - var blockText = m1; - - // Undo double lines - blockText = blockText.replace(/\n\n/g,"\n"); - blockText = blockText.replace(/^\n/,""); - - // strip trailing blank lines - blockText = blockText.replace(/\n+$/g,""); - - // Replace the element text with a marker ("~KxK" where x is its key) - blockText = "\n\n~K" + (g_html_blocks.push(blockText)-1) + "K\n\n"; - - return blockText; +/** + * Reset global options to the default values + * @static + */ +showdown.resetOptions = function () { + 'use strict'; + globalOptions = getDefaultOpts(true); }; -var _RunBlockGamut = function(text) { -// -// These are all the transformations that form block-level -// tags like paragraphs, headers, and list items. -// - text = _DoHeaders(text); - - // Do Horizontal Rules: - var key = hashBlock("
    "); - text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key); - text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key); - text = text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key); - - text = _DoLists(text); - text = _DoCodeBlocks(text); - text = _DoBlockQuotes(text); - - // We already ran _HashHTMLBlocks() before, in Markdown(), but that - // was to escape raw HTML in the original Markdown source. This time, - // we're escaping the markup we've just created, so that we don't wrap - //

    tags around block-level tags. - text = _HashHTMLBlocks(text); - text = _FormParagraphs(text); - - return text; +/** + * Set the flavor showdown should use as default + * @param {string} name + */ +showdown.setFlavor = function (name) { + 'use strict'; + if (flavor.hasOwnProperty(name)) { + var preset = flavor[name]; + for (var option in preset) { + if (preset.hasOwnProperty(option)) { + globalOptions[option] = preset[option]; + } + } + } }; - -var _RunSpanGamut = function(text) { -// -// These are all the transformations that occur *within* block-level -// tags like paragraphs, headers, and list items. -// - - text = _DoCodeSpans(text); - text = _EscapeSpecialCharsWithinTagAttributes(text); - text = _EncodeBackslashEscapes(text); - - // Process anchor and image tags. Images must come first, - // because ![foo][f] looks like an anchor. - text = _DoImages(text); - text = _DoAnchors(text); - - // Make links out of things like `` - // Must come after _DoAnchors(), because you can use < and > - // delimiters in inline links like [this](). - text = _DoAutoLinks(text); - text = _EncodeAmpsAndAngles(text); - text = _DoItalicsAndBold(text); - - // Do hard breaks: - text = text.replace(/ +\n/g,"
    \n"); - - return text; -} - -var _EscapeSpecialCharsWithinTagAttributes = function(text) { -// -// Within tags -- meaning between < and > -- encode [\ ` * _] so they -// don't conflict with their use in Markdown for code, italics and strong. -// - - // Build a regex to find HTML tags and comments. See Friedl's - // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. - var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi; - - text = text.replace(regex, function(wholeMatch) { - var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`"); - tag = escapeCharacters(tag,"\\`*_"); - return tag; - }); - - return text; -} - -var _DoAnchors = function(text) { -// -// Turn Markdown link shortcuts into XHTML
    tags. -// - // - // First, handle reference-style links: [link text] [id] - // - - /* - text = text.replace(/ - ( // wrap whole match in $1 - \[ - ( - (?: - \[[^\]]*\] // allow brackets nested one level - | - [^\[] // or anything else - )* - ) - \] - - [ ]? // one optional space - (?:\n[ ]*)? // one optional newline followed by spaces - - \[ - (.*?) // id = $3 - \] - )()()()() // pad remaining backreferences - /g,_DoAnchors_callback); - */ - text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag); - - // - // Next, inline-style links: [link text](url "optional title") - // - - /* - text = text.replace(/ - ( // wrap whole match in $1 - \[ - ( - (?: - \[[^\]]*\] // allow brackets nested one level - | - [^\[\]] // or anything else - ) - ) - \] - \( // literal paren - [ \t]* - () // no id, so leave $3 empty - ? // href = $4 - [ \t]* - ( // $5 - (['"]) // quote char = $6 - (.*?) // Title = $7 - \6 // matching quote - [ \t]* // ignore any spaces/tabs between closing quote and ) - )? // title is optional - \) - ) - /g,writeAnchorTag); - */ - text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag); - - // - // Last, handle reference-style shortcuts: [link text] - // These must come last in case you've also got [link test][1] - // or [link test](/foo) - // - - /* - text = text.replace(/ - ( // wrap whole match in $1 - \[ - ([^\[\]]+) // link text = $2; can't contain '[' or ']' - \] - )()()()()() // pad rest of backreferences - /g, writeAnchorTag); - */ - text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag); - - return text; -} - -var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) { - if (m7 == undefined) m7 = ""; - var whole_match = m1; - var link_text = m2; - var link_id = m3.toLowerCase(); - var url = m4; - var title = m7; - - if (url == "") { - if (link_id == "") { - // lower-case and turn embedded newlines into spaces - link_id = link_text.toLowerCase().replace(/ ?\n/g," "); - } - url = "#"+link_id; - - if (g_urls[link_id] != undefined) { - url = g_urls[link_id]; - if (g_titles[link_id] != undefined) { - title = g_titles[link_id]; - } - } - else { - if (whole_match.search(/\(\s*\)$/m)>-1) { - // Special case for explicit empty url - url = ""; - } else { - return whole_match; - } - } - } - - url = escapeCharacters(url,"*_"); - var result = ""; - - return result; -} - - -var _DoImages = function(text) { -// -// Turn Markdown image shortcuts into tags. -// - - // - // First, handle reference-style labeled images: ![alt text][id] - // - - /* - text = text.replace(/ - ( // wrap whole match in $1 - !\[ - (.*?) // alt text = $2 - \] - - [ ]? // one optional space - (?:\n[ ]*)? // one optional newline followed by spaces - - \[ - (.*?) // id = $3 - \] - )()()()() // pad rest of backreferences - /g,writeImageTag); - */ - text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag); - - // - // Next, handle inline images: ![alt text](url "optional title") - // Don't forget: encode * and _ - - /* - text = text.replace(/ - ( // wrap whole match in $1 - !\[ - (.*?) // alt text = $2 - \] - \s? // One optional whitespace character - \( // literal paren - [ \t]* - () // no id, so leave $3 empty - ? // src url = $4 - [ \t]* - ( // $5 - (['"]) // quote char = $6 - (.*?) // title = $7 - \6 // matching quote - [ \t]* - )? // title is optional - \) - ) - /g,writeImageTag); - */ - text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag); - - return text; -} - -var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) { - var whole_match = m1; - var alt_text = m2; - var link_id = m3.toLowerCase(); - var url = m4; - var title = m7; - - if (!title) title = ""; - - if (url == "") { - if (link_id == "") { - // lower-case and turn embedded newlines into spaces - link_id = alt_text.toLowerCase().replace(/ ?\n/g," "); - } - url = "#"+link_id; - - if (g_urls[link_id] != undefined) { - url = g_urls[link_id]; - if (g_titles[link_id] != undefined) { - title = g_titles[link_id]; - } - } - else { - return whole_match; - } - } - - alt_text = alt_text.replace(/"/g,"""); - url = escapeCharacters(url,"*_"); - var result = "\""' + _RunSpanGamut(m1) + "");}); - - text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm, - function(matchFound,m1){return hashBlock('

    ' + _RunSpanGamut(m1) + "

    ");}); - - // atx-style headers: - // # Header 1 - // ## Header 2 - // ## Header 2 with closing hashes ## - // ... - // ###### Header 6 - // - - /* - text = text.replace(/ - ^(\#{1,6}) // $1 = string of #'s - [ \t]* - (.+?) // $2 = Header text - [ \t]* - \#* // optional closing #'s (not counted) - \n+ - /gm, function() {...}); - */ - - text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm, - function(wholeMatch,m1,m2) { - var h_level = m1.length; - return hashBlock("' + _RunSpanGamut(m2) + ""); - }); - - function headerId(m) { - return m.replace(/[^\w]/g, '').toLowerCase(); - } - return text; -} - -// This declaration keeps Dojo compressor from outputting garbage: -var _ProcessListItems; - -var _DoLists = function(text) { -// -// Form HTML ordered (numbered) and unordered (bulleted) lists. -// - - // attacklab: add sentinel to hack around khtml/safari bug: - // http://bugs.webkit.org/show_bug.cgi?id=11231 - text += "~0"; - - // Re-usable pattern to match any entirel ul or ol list: - - /* - var whole_list = / - ( // $1 = whole list - ( // $2 - [ ]{0,3} // attacklab: g_tab_width - 1 - ([*+-]|\d+[.]) // $3 = first list item marker - [ \t]+ - ) - [^\r]+? - ( // $4 - ~0 // sentinel for workaround; should be $ - | - \n{2,} - (?=\S) - (?! // Negative lookahead for another list item marker - [ \t]* - (?:[*+-]|\d+[.])[ \t]+ - ) - ) - )/g - */ - var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm; - - if (g_list_level) { - text = text.replace(whole_list,function(wholeMatch,m1,m2) { - var list = m1; - var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol"; - - // Turn double returns into triple returns, so that we can make a - // paragraph for the last item in a list, if necessary: - list = list.replace(/\n{2,}/g,"\n\n\n");; - var result = _ProcessListItems(list); - - // Trim any trailing whitespace, to put the closing `` - // up on the preceding line, to get it past the current stupid - // HTML block parser. This is a hack to work around the terrible - // hack that is the HTML block parser. - result = result.replace(/\s+$/,""); - result = "<"+list_type+">" + result + "\n"; - return result; - }); - } else { - whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g; - text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) { - var runup = m1; - var list = m2; - - var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol"; - // Turn double returns into triple returns, so that we can make a - // paragraph for the last item in a list, if necessary: - var list = list.replace(/\n{2,}/g,"\n\n\n");; - var result = _ProcessListItems(list); - result = runup + "<"+list_type+">\n" + result + "\n"; - return result; - }); - } - - // attacklab: strip sentinel - text = text.replace(/~0/,""); - - return text; -} - -_ProcessListItems = function(list_str) { -// -// Process the contents of a single ordered or unordered list, splitting it -// into individual list items. -// - // The $g_list_level global keeps track of when we're inside a list. - // Each time we enter a list, we increment it; when we leave a list, - // we decrement. If it's zero, we're not in a list anymore. - // - // We do this because when we're not inside a list, we want to treat - // something like this: - // - // I recommend upgrading to version - // 8. Oops, now this line is treated - // as a sub-list. - // - // As a single paragraph, despite the fact that the second line starts - // with a digit-period-space sequence. - // - // Whereas when we're inside a list (or sub-list), that line will be - // treated as the start of a sub-list. What a kludge, huh? This is - // an aspect of Markdown's syntax that's hard to parse perfectly - // without resorting to mind-reading. Perhaps the solution is to - // change the syntax rules such that sub-lists must start with a - // starting cardinal number; e.g. "1." or "a.". - - g_list_level++; - - // trim trailing blank lines: - list_str = list_str.replace(/\n{2,}$/,"\n"); - - // attacklab: add sentinel to emulate \z - list_str += "~0"; - - /* - list_str = list_str.replace(/ - (\n)? // leading line = $1 - (^[ \t]*) // leading whitespace = $2 - ([*+-]|\d+[.]) [ \t]+ // list marker = $3 - ([^\r]+? // list item text = $4 - (\n{1,2})) - (?= \n* (~0 | \2 ([*+-]|\d+[.]) [ \t]+)) - /gm, function(){...}); - */ - list_str = list_str.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm, - function(wholeMatch,m1,m2,m3,m4){ - var item = m4; - var leading_line = m1; - var leading_space = m2; - - if (leading_line || (item.search(/\n{2,}/)>-1)) { - item = _RunBlockGamut(_Outdent(item)); - } - else { - // Recursion for sub-lists: - item = _DoLists(_Outdent(item)); - item = item.replace(/\n$/,""); // chomp(item) - item = _RunSpanGamut(item); - } - - return "
  • " + item + "
  • \n"; - } - ); - - // attacklab: strip sentinel - list_str = list_str.replace(/~0/g,""); - - g_list_level--; - return list_str; -} - - -var _DoCodeBlocks = function(text) { -// -// Process Markdown `
    ` blocks.
    -//
    -
    -	/*
    -		text = text.replace(text,
    -			/(?:\n\n|^)
    -			(								// $1 = the code block -- one or more lines, starting with a space/tab
    -				(?:
    -					(?:[ ]{4}|\t)			// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
    -					.*\n+
    -				)+
    -			)
    -			(\n*[ ]{0,3}[^ \t\n]|(?=~0))	// attacklab: g_tab_width
    -		/g,function(){...});
    -	*/
    -
    -	// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
    -	text += "~0";
    -
    -	text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
    -		function(wholeMatch,m1,m2) {
    -			var codeblock = m1;
    -			var nextChar = m2;
    -
    -			codeblock = _EncodeCode( _Outdent(codeblock));
    -			codeblock = _Detab(codeblock);
    -			codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
    -			codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
    -
    -			codeblock = "
    " + codeblock + "\n
    "; - - return hashBlock(codeblock) + nextChar; - } - ); - - // attacklab: strip sentinel - text = text.replace(/~0/,""); - - return text; +/** + * Get the default options + * @static + * @param {boolean} [simple=true] + * @returns {{}} + */ +showdown.getDefaultOptions = function (simple) { + 'use strict'; + return getDefaultOpts(simple); }; -var _DoGithubCodeBlocks = function(text) { -// -// Process Github-style code blocks -// Example: -// ```ruby -// def hello_world(x) -// puts "Hello, #{x}" -// end -// ``` -// +/** + * Get or set a subParser + * + * subParser(name) - Get a registered subParser + * subParser(name, func) - Register a subParser + * @static + * @param {string} name + * @param {function} [func] + * @returns {*} + */ +showdown.subParser = function (name, func) { + 'use strict'; + if (showdown.helper.isString(name)) { + if (typeof func !== 'undefined') { + parsers[name] = func; + } else { + if (parsers.hasOwnProperty(name)) { + return parsers[name]; + } else { + throw Error('SubParser named ' + name + ' not registered!'); + } + } + } +}; +/** + * Gets or registers an extension + * @static + * @param {string} name + * @param {object|function=} ext + * @returns {*} + */ +showdown.extension = function (name, ext) { + 'use strict'; - // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug - text += "~0"; + if (!showdown.helper.isString(name)) { + throw Error('Extension \'name\' must be a string'); + } - text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, - function(wholeMatch,m1,m2) { - var language = m1; - var codeblock = m2; + name = showdown.helper.stdExtName(name); - codeblock = _EncodeCode(codeblock); - codeblock = _Detab(codeblock); - codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines - codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace + // Getter + if (showdown.helper.isUndefined(ext)) { + if (!extensions.hasOwnProperty(name)) { + throw Error('Extension named ' + name + ' is not registered!'); + } + return extensions[name]; - codeblock = "
    " + codeblock + "\n
    "; + // Setter + } else { + // Expand extension if it's wrapped in a function + if (typeof ext === 'function') { + ext = ext(); + } - return hashBlock(codeblock); - } - ); + // Ensure extension is an array + if (!showdown.helper.isArray(ext)) { + ext = [ext]; + } - // attacklab: strip sentinel - text = text.replace(/~0/,""); + var validExtension = validate(ext, name); - return text; + if (validExtension.valid) { + extensions[name] = ext; + } else { + throw Error(validExtension.error); + } + } +}; + +/** + * Gets all extensions registered + * @returns {{}} + */ +showdown.getAllExtensions = function () { + 'use strict'; + return extensions; +}; + +/** + * Remove an extension + * @param {string} name + */ +showdown.removeExtension = function (name) { + 'use strict'; + delete extensions[name]; +}; + +/** + * Removes all extensions + */ +showdown.resetExtensions = function () { + 'use strict'; + extensions = {}; +}; + +/** + * Validate extension + * @param {array} extension + * @param {string} name + * @returns {{valid: boolean, error: string}} + */ +function validate(extension, name) { + 'use strict'; + + var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension', + ret = { + valid: true, + error: '' + }; + + if (!showdown.helper.isArray(extension)) { + extension = [extension]; + } + + for (var i = 0; i < extension.length; ++i) { + var baseMsg = errMsg + ' sub-extension ' + i + ': ', + ext = extension[i]; + if (typeof ext !== 'object') { + ret.valid = false; + ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given'; + return ret; + } + + if (!showdown.helper.isString(ext.type)) { + ret.valid = false; + ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given'; + return ret; + } + + var type = ext.type = ext.type.toLowerCase(); + + // normalize extension type + if (type === 'language') { + type = ext.type = 'lang'; + } + + if (type === 'html') { + type = ext.type = 'output'; + } + + if (type !== 'lang' && type !== 'output') { + ret.valid = false; + ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang" or "output"'; + return ret; + } + + if (ext.filter) { + if (typeof ext.filter !== 'function') { + ret.valid = false; + ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given'; + return ret; + } + + } else if (ext.regex) { + if (showdown.helper.isString(ext.regex)) { + ext.regex = new RegExp(ext.regex, 'g'); + } + if (!ext.regex instanceof RegExp) { + ret.valid = false; + ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + + typeof ext.regex + ' given'; + return ret; + } + if (showdown.helper.isUndefined(ext.replace)) { + ret.valid = false; + ret.error = baseMsg + '"regex" extensions must implement a replace string or function'; + return ret; + } + + } else { + ret.valid = false; + ret.error = baseMsg + 'extensions must define either a "regex" property or a "filter" method'; + return ret; + } + + if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) { + ret.valid = false; + ret.error = baseMsg + 'output extensions must define a filter property'; + return ret; + } + } + return ret; } -var hashBlock = function(text) { - text = text.replace(/(^\n+|\n+$)/g,""); - return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n"; -} - -var _DoCodeSpans = function(text) { -// -// * Backtick quotes are used for spans. -// -// * You can use multiple backticks as the delimiters if you want to -// include literal backticks in the code span. So, this input: -// -// Just type ``foo `bar` baz`` at the prompt. -// -// Will translate to: -// -//

    Just type foo `bar` baz at the prompt.

    -// -// There's no arbitrary limit to the number of backticks you -// can use as delimters. If you need three consecutive backticks -// in your code, use four for delimiters, etc. -// -// * You can use spaces to get literal backticks at the edges: -// -// ... type `` `bar` `` ... -// -// Turns to: -// -// ... type `bar` ... -// - - /* - text = text.replace(/ - (^|[^\\]) // Character before opening ` can't be a backslash - (`+) // $2 = Opening run of ` - ( // $3 = The code block - [^\r]*? - [^`] // attacklab: work around lack of lookbehind - ) - \2 // Matching closer - (?!`) - /gm, function(){...}); - */ - - text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, - function(wholeMatch,m1,m2,m3,m4) { - var c = m3; - c = c.replace(/^([ \t]*)/g,""); // leading whitespace - c = c.replace(/[ \t]*$/g,""); // trailing whitespace - c = _EncodeCode(c); - return m1+""+c+""; - }); - - return text; -} - -var _EncodeCode = function(text) { -// -// Encode/escape certain characters inside Markdown code runs. -// The point is that in code, these characters are literals, -// and lose their special Markdown meanings. -// - // Encode all ampersands; HTML entities are not - // entities within a Markdown code span. - text = text.replace(/&/g,"&"); - - // Do the angle bracket song and dance: - text = text.replace(//g,">"); - - // Now, escape characters that are magic in Markdown: - text = escapeCharacters(text,"\*_{}[]\\",false); - -// jj the line above breaks this: -//--- - -//* Item - -// 1. Subitem - -// special char: * -//--- - - return text; -} - - -var _DoItalicsAndBold = function(text) { - - // must go first: - text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, - "$2"); - - text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, - "$2"); - - return text; -} - - -var _DoBlockQuotes = function(text) { - - /* - text = text.replace(/ - ( // Wrap whole match in $1 - ( - ^[ \t]*>[ \t]? // '>' at the start of a line - .+\n // rest of the first line - (.+\n)* // subsequent consecutive lines - \n* // blanks - )+ - ) - /gm, function(){...}); - */ - - text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm, - function(wholeMatch,m1) { - var bq = m1; - - // attacklab: hack around Konqueror 3.5.4 bug: - // "----------bug".replace(/^-/g,"") == "bug" - - bq = bq.replace(/^[ \t]*>[ \t]?/gm,"~0"); // trim one level of quoting - - // attacklab: clean up hack - bq = bq.replace(/~0/g,""); - - bq = bq.replace(/^[ \t]+$/gm,""); // trim whitespace-only lines - bq = _RunBlockGamut(bq); // recurse - - bq = bq.replace(/(^|\n)/g,"$1 "); - // These leading spaces screw with
     content, so we need to fix that:
    -			bq = bq.replace(
    -					/(\s*
    [^\r]+?<\/pre>)/gm,
    -				function(wholeMatch,m1) {
    -					var pre = m1;
    -					// attacklab: hack around Konqueror 3.5.4 bug:
    -					pre = pre.replace(/^  /mg,"~0");
    -					pre = pre.replace(/~0/g,"");
    -					return pre;
    -				});
    -
    -			return hashBlock("
    \n" + bq + "\n
    "); - }); - return text; -} - - -var _FormParagraphs = function(text) { -// -// Params: -// $text - string to process with html

    tags -// - - // Strip leading and trailing lines: - text = text.replace(/^\n+/g,""); - text = text.replace(/\n+$/g,""); - - var grafs = text.split(/\n{2,}/g); - var grafsOut = []; - - // - // Wrap

    tags. - // - var end = grafs.length; - for (var i=0; i= 0) { - grafsOut.push(str); - } - else if (str.search(/\S/) >= 0) { - str = _RunSpanGamut(str); - str = str.replace(/^([ \t]*)/g,"

    "); - str += "

    " - grafsOut.push(str); - } - - } - - // - // Unhashify HTML blocks - // - end = grafsOut.length; - for (var i=0; i= 0) { - var blockText = g_html_blocks[RegExp.$1]; - blockText = blockText.replace(/\$/g,"$$$$"); // Escape any dollar signs - grafsOut[i] = grafsOut[i].replace(/~K\d+K/,blockText); - } - } - - return grafsOut.join("\n\n"); -} - - -var _EncodeAmpsAndAngles = function(text) { -// Smart processing for ampersands and angle brackets that need to be encoded. - - // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: - // http://bumppo.net/projects/amputator/ - text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&"); - - // Encode naked <'s - text = text.replace(/<(?![a-z\/?\$!])/gi,"<"); - - return text; -} - - -var _EncodeBackslashEscapes = function(text) { -// -// Parameter: String. -// Returns: The string, with after processing the following backslash -// escape sequences. -// - - // attacklab: The polite way to do this is with the new - // escapeCharacters() function: - // - // text = escapeCharacters(text,"\\",true); - // text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); - // - // ...but we're sidestepping its use of the (slow) RegExp constructor - // as an optimization for Firefox. This function gets called a LOT. - - text = text.replace(/\\(\\)/g,escapeCharacters_callback); - text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g,escapeCharacters_callback); - return text; -} - - -var _DoAutoLinks = function(text) { - - text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"
    $1"); - - // Email addresses: - - /* - text = text.replace(/ - < - (?:mailto:)? - ( - [-.\w]+ - \@ - [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ - ) - > - /gi, _DoAutoLinks_callback()); - */ - text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi, - function(wholeMatch,m1) { - return _EncodeEmailAddress( _UnescapeSpecialChars(m1) ); - } - ); - - return text; -} - - -var _EncodeEmailAddress = function(addr) { -// -// Input: an email address, e.g. "foo@example.com" -// -// Output: the email address as a mailto link, with each character -// of the address encoded as either a decimal or hex entity, in -// the hopes of foiling most address harvesting spam bots. E.g.: -// -// foo -// @example.com -// -// Based on a filter by Matthew Wickline, posted to the BBEdit-Talk -// mailing list: -// - - var encode = [ - function(ch){return "&#"+ch.charCodeAt(0)+";";}, - function(ch){return "&#x"+ch.charCodeAt(0).toString(16)+";";}, - function(ch){return ch;} - ]; - - addr = "mailto:" + addr; - - addr = addr.replace(/./g, function(ch) { - if (ch == "@") { - // this *must* be encoded. I insist. - ch = encode[Math.floor(Math.random()*2)](ch); - } else if (ch !=":") { - // leave ':' alone (to spot mailto: later) - var r = Math.random(); - // roughly 10% raw, 45% hex, 45% dec - ch = ( - r > .9 ? encode[2](ch) : - r > .45 ? encode[1](ch) : - encode[0](ch) - ); - } - return ch; - }); - - addr = "" + addr + ""; - addr = addr.replace(/">.+:/g,"\">"); // strip the mailto: from the visible part - - return addr; -} - - -var _UnescapeSpecialChars = function(text) { -// -// Swap back in all the special characters we've hidden. -// - text = text.replace(/~E(\d+)E/g, - function(wholeMatch,m1) { - var charCodeToReplace = parseInt(m1); - return String.fromCharCode(charCodeToReplace); - } - ); - return text; -} - - -var _Outdent = function(text) { -// -// Remove one level of line-leading tabs or spaces -// - - // attacklab: hack around Konqueror 3.5.4 bug: - // "----------bug".replace(/^-/g,"") == "bug" - - text = text.replace(/^(\t|[ ]{1,4})/gm,"~0"); // attacklab: g_tab_width - - // attacklab: clean up hack - text = text.replace(/~0/g,"") - - return text; -} - -var _Detab = function(text) { -// attacklab: Detab's completely rewritten for speed. -// In perl we could fix it by anchoring the regexp with \G. -// In javascript we're less fortunate. - - // expand first n-1 tabs - text = text.replace(/\t(?=\t)/g," "); // attacklab: g_tab_width - - // replace the nth with two sentinels - text = text.replace(/\t/g,"~A~B"); - - // use the sentinel to anchor our regex so it doesn't explode - text = text.replace(/~B(.+?)~A/g, - function(wholeMatch,m1,m2) { - var leadingText = m1; - var numSpaces = 4 - leadingText.length % 4; // attacklab: g_tab_width - - // there *must* be a better way to do this: - for (var i=0; i tags. + */ +showdown.subParser('anchors', function (text, config, globals) { + 'use strict'; + + var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) { + if (showdown.helper.isUndefined(m7)) { + m7 = ''; + } + wholeMatch = m1; + var linkText = m2, + linkId = m3.toLowerCase(), + url = m4, + title = m7; + + if (!url) { + if (!linkId) { + // lower-case and turn embedded newlines into spaces + linkId = linkText.toLowerCase().replace(/ ?\n/g, ' '); + } + url = '#' + linkId; + + if (!showdown.helper.isUndefined(globals.gUrls[linkId])) { + url = globals.gUrls[linkId]; + if (!showdown.helper.isUndefined(globals.gTitles[linkId])) { + title = globals.gTitles[linkId]; + } + } else { + if (wholeMatch.search(/\(\s*\)$/m) > -1) { + // Special case for explicit empty url + url = ''; + } else { + return wholeMatch; + } + } + } + + url = showdown.helper.escapeCharacters(url, '*_', false); + var result = ''; + + return result; + }; + + // First, handle reference-style links: [link text] [id] + /* + text = text.replace(/ + ( // wrap whole match in $1 + \[ + ( + (?: + \[[^\]]*\] // allow brackets nested one level + | + [^\[] // or anything else + )* + ) + \] + + [ ]? // one optional space + (?:\n[ ]*)? // one optional newline followed by spaces + + \[ + (.*?) // id = $3 + \] + )()()()() // pad remaining backreferences + /g,_DoAnchors_callback); + */ + text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeAnchorTag); + + // + // Next, inline-style links: [link text](url "optional title") + // + + /* + text = text.replace(/ + ( // wrap whole match in $1 + \[ + ( + (?: + \[[^\]]*\] // allow brackets nested one level + | + [^\[\]] // or anything else + ) + ) + \] + \( // literal paren + [ \t]* + () // no id, so leave $3 empty + ? // href = $4 + [ \t]* + ( // $5 + (['"]) // quote char = $6 + (.*?) // Title = $7 + \6 // matching quote + [ \t]* // ignore any spaces/tabs between closing quote and ) + )? // title is optional + \) + ) + /g,writeAnchorTag); + */ + text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, + writeAnchorTag); + + // + // Last, handle reference-style shortcuts: [link text] + // These must come last in case you've also got [link test][1] + // or [link test](/foo) + // + + /* + text = text.replace(/ + ( // wrap whole match in $1 + \[ + ([^\[\]]+) // link text = $2; can't contain '[' or ']' + \] + )()()()()() // pad rest of backreferences + /g, writeAnchorTag); + */ + text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag); + + return text; + +}); diff --git a/src/subParsers/autoLinks.js b/src/subParsers/autoLinks.js new file mode 100644 index 0000000..04b0e2f --- /dev/null +++ b/src/subParsers/autoLinks.js @@ -0,0 +1,27 @@ +showdown.subParser('autoLinks', function (text, options) { + 'use strict'; + + //simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi, + + var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi, + delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi, + simpleMailRegex = /\b(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)\b/gi, + delimMailRegex = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi; + + text = text.replace(delimUrlRegex, '$1'); + text = text.replace(delimMailRegex, replaceMail); + //simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi, + // Email addresses: + + if (options.simplifiedAutoLink) { + text = text.replace(simpleURLRegex, '$1'); + text = text.replace(simpleMailRegex, replaceMail); + } + + function replaceMail(wholeMatch, m1) { + var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1); + return showdown.subParser('encodeEmailAddress')(unescapedStr); + } + + return text; +}); diff --git a/src/subParsers/blockGamut.js b/src/subParsers/blockGamut.js new file mode 100644 index 0000000..e2c24a6 --- /dev/null +++ b/src/subParsers/blockGamut.js @@ -0,0 +1,30 @@ +/** + * These are all the transformations that form block-level + * tags like paragraphs, headers, and list items. + */ +showdown.subParser('blockGamut', function (text, options, globals) { + 'use strict'; + + text = showdown.subParser('headers')(text, options, globals); + + // Do Horizontal Rules: + var key = showdown.subParser('hashBlock')('
    ', options, globals); + text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key); + text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key); + text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key); + + text = showdown.subParser('tables')(text, options, globals); + text = showdown.subParser('lists')(text, options, globals); + text = showdown.subParser('codeBlocks')(text, options, globals); + text = showdown.subParser('blockQuotes')(text, options, globals); + + // We already ran _HashHTMLBlocks() before, in Markdown(), but that + // was to escape raw HTML in the original Markdown source. This time, + // we're escaping the markup we've just created, so that we don't wrap + //

    tags around block-level tags. + text = showdown.subParser('hashHTMLBlocks')(text, options, globals); + text = showdown.subParser('paragraphs')(text, options, globals); + + return text; + +}); diff --git a/src/subParsers/blockQuotes.js b/src/subParsers/blockQuotes.js new file mode 100644 index 0000000..4b1782f --- /dev/null +++ b/src/subParsers/blockQuotes.js @@ -0,0 +1,43 @@ +showdown.subParser('blockQuotes', function (text, options, globals) { + 'use strict'; + + /* + text = text.replace(/ + ( // Wrap whole match in $1 + ( + ^[ \t]*>[ \t]? // '>' at the start of a line + .+\n // rest of the first line + (.+\n)* // subsequent consecutive lines + \n* // blanks + )+ + ) + /gm, function(){...}); + */ + + text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) { + var bq = m1; + + // attacklab: hack around Konqueror 3.5.4 bug: + // "----------bug".replace(/^-/g,"") == "bug" + bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting + + // attacklab: clean up hack + bq = bq.replace(/~0/g, ''); + + bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines + bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse + + bq = bq.replace(/(^|\n)/g, '$1 '); + // These leading spaces screw with

     content, so we need to fix that:
    +    bq = bq.replace(/(\s*
    [^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
    +      var pre = m1;
    +      // attacklab: hack around Konqueror 3.5.4 bug:
    +      pre = pre.replace(/^  /mg, '~0');
    +      pre = pre.replace(/~0/g, '');
    +      return pre;
    +    });
    +
    +    return showdown.subParser('hashBlock')('
    \n' + bq + '\n
    ', options, globals); + }); + return text; +}); diff --git a/src/subParsers/codeBlocks.js b/src/subParsers/codeBlocks.js new file mode 100644 index 0000000..6005939 --- /dev/null +++ b/src/subParsers/codeBlocks.js @@ -0,0 +1,48 @@ +/** + * Process Markdown `
    ` blocks.
    + */
    +showdown.subParser('codeBlocks', function (text, options, globals) {
    +  'use strict';
    +
    +  /*
    +   text = text.replace(text,
    +   /(?:\n\n|^)
    +   (								// $1 = the code block -- one or more lines, starting with a space/tab
    +   (?:
    +   (?:[ ]{4}|\t)			// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
    +   .*\n+
    +   )+
    +   )
    +   (\n*[ ]{0,3}[^ \t\n]|(?=~0))	// attacklab: g_tab_width
    +   /g,function(){...});
    +   */
    +
    +  // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
    +  text += '~0';
    +
    +  var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;
    +  text = text.replace(pattern, function (wholeMatch, m1, m2) {
    +    var codeblock = m1,
    +        nextChar = m2,
    +        end = '\n';
    +
    +    codeblock = showdown.subParser('outdent')(codeblock);
    +    codeblock = showdown.subParser('encodeCode')(codeblock);
    +    codeblock = showdown.subParser('detab')(codeblock);
    +    codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
    +    codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
    +
    +    if (options.omitExtraWLInCodeBlocks) {
    +      end = '';
    +    }
    +
    +    codeblock = '
    ' + codeblock + end + '
    '; + + return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar; + }); + + // attacklab: strip sentinel + text = text.replace(/~0/, ''); + + return text; +}); diff --git a/src/subParsers/codeSpans.js b/src/subParsers/codeSpans.js new file mode 100644 index 0000000..b0ec1dd --- /dev/null +++ b/src/subParsers/codeSpans.js @@ -0,0 +1,60 @@ +/** + * + * * Backtick quotes are used for spans. + * + * * You can use multiple backticks as the delimiters if you want to + * include literal backticks in the code span. So, this input: + * + * Just type ``foo `bar` baz`` at the prompt. + * + * Will translate to: + * + *

    Just type foo `bar` baz at the prompt.

    + * + * There's no arbitrary limit to the number of backticks you + * can use as delimters. If you need three consecutive backticks + * in your code, use four for delimiters, etc. + * + * * You can use spaces to get literal backticks at the edges: + * + * ... type `` `bar` `` ... + * + * Turns to: + * + * ... type `bar` ... + */ +showdown.subParser('codeSpans', function (text) { + 'use strict'; + + //special case -> literal html code tag + text = text.replace(/(<]*?>)([^]*?)<\/code>/g, function (wholeMatch, tag, c) { + c = c.replace(/^([ \t]*)/g, ''); // leading whitespace + c = c.replace(/[ \t]*$/g, ''); // trailing whitespace + c = showdown.subParser('encodeCode')(c); + return tag + c + '
    '; + }); + + /* + text = text.replace(/ + (^|[^\\]) // Character before opening ` can't be a backslash + (`+) // $2 = Opening run of ` + ( // $3 = The code block + [^\r]*? + [^`] // attacklab: work around lack of lookbehind + ) + \2 // Matching closer + (?!`) + /gm, function(){...}); + */ + text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, + function (wholeMatch, m1, m2, m3) { + var c = m3; + c = c.replace(/^([ \t]*)/g, ''); // leading whitespace + c = c.replace(/[ \t]*$/g, ''); // trailing whitespace + c = showdown.subParser('encodeCode')(c); + return m1 + '' + c + ''; + } + ); + + return text; +}); diff --git a/src/subParsers/detab.js b/src/subParsers/detab.js new file mode 100644 index 0000000..b3c6d65 --- /dev/null +++ b/src/subParsers/detab.js @@ -0,0 +1,32 @@ +/** + * Convert all tabs to spaces + */ +showdown.subParser('detab', function (text) { + 'use strict'; + + // expand first n-1 tabs + text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width + + // replace the nth with two sentinels + text = text.replace(/\t/g, '~A~B'); + + // use the sentinel to anchor our regex so it doesn't explode + text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) { + var leadingText = m1, + numSpaces = 4 - leadingText.length % 4; // g_tab_width + + // there *must* be a better way to do this: + for (var i = 0; i < numSpaces; i++) { + leadingText += ' '; + } + + return leadingText; + }); + + // clean up sentinels + text = text.replace(/~A/g, ' '); // g_tab_width + text = text.replace(/~B/g, ''); + + return text; + +}); diff --git a/src/subParsers/encodeAmpsAndAngles.js b/src/subParsers/encodeAmpsAndAngles.js new file mode 100644 index 0000000..984cd2e --- /dev/null +++ b/src/subParsers/encodeAmpsAndAngles.js @@ -0,0 +1,14 @@ +/** + * Smart processing for ampersands and angle brackets that need to be encoded. + */ +showdown.subParser('encodeAmpsAndAngles', function (text) { + 'use strict'; + // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: + // http://bumppo.net/projects/amputator/ + text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&'); + + // Encode naked <'s + text = text.replace(/<(?![a-z\/?\$!])/gi, '<'); + + return text; +}); diff --git a/src/subParsers/encodeBackslashEscapes.js b/src/subParsers/encodeBackslashEscapes.js new file mode 100644 index 0000000..ee2cce2 --- /dev/null +++ b/src/subParsers/encodeBackslashEscapes.js @@ -0,0 +1,17 @@ +/** + * Returns the string, with after processing the following backslash escape sequences. + * + * attacklab: The polite way to do this is with the new escapeCharacters() function: + * + * text = escapeCharacters(text,"\\",true); + * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); + * + * ...but we're sidestepping its use of the (slow) RegExp constructor + * as an optimization for Firefox. This function gets called a LOT. + */ +showdown.subParser('encodeBackslashEscapes', function (text) { + 'use strict'; + text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback); + text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback); + return text; +}); diff --git a/src/subParsers/encodeCode.js b/src/subParsers/encodeCode.js new file mode 100644 index 0000000..0ae9645 --- /dev/null +++ b/src/subParsers/encodeCode.js @@ -0,0 +1,28 @@ +/** + * Encode/escape certain characters inside Markdown code runs. + * The point is that in code, these characters are literals, + * and lose their special Markdown meanings. + */ +showdown.subParser('encodeCode', function (text) { + 'use strict'; + + // Encode all ampersands; HTML entities are not + // entities within a Markdown code span. + text = text.replace(/&/g, '&'); + + // Do the angle bracket song and dance: + text = text.replace(//g, '>'); + + // Now, escape characters that are magic in Markdown: + text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false); + + // jj the line above breaks this: + //--- + //* Item + // 1. Subitem + // special char: * + // --- + + return text; +}); diff --git a/src/subParsers/encodeEmailAddress.js b/src/subParsers/encodeEmailAddress.js new file mode 100644 index 0000000..925b3cc --- /dev/null +++ b/src/subParsers/encodeEmailAddress.js @@ -0,0 +1,52 @@ +/** + * Input: an email address, e.g. "foo@example.com" + * + * Output: the email address as a mailto link, with each character + * of the address encoded as either a decimal or hex entity, in + * the hopes of foiling most address harvesting spam bots. E.g.: + * + * foo + * @example.com + * + * Based on a filter by Matthew Wickline, posted to the BBEdit-Talk + * mailing list: + * + */ +showdown.subParser('encodeEmailAddress', function (addr) { + 'use strict'; + + var encode = [ + function (ch) { + return '&#' + ch.charCodeAt(0) + ';'; + }, + function (ch) { + return '&#x' + ch.charCodeAt(0).toString(16) + ';'; + }, + function (ch) { + return ch; + } + ]; + + addr = 'mailto:' + addr; + + addr = addr.replace(/./g, function (ch) { + if (ch === '@') { + // this *must* be encoded. I insist. + ch = encode[Math.floor(Math.random() * 2)](ch); + } else if (ch !== ':') { + // leave ':' alone (to spot mailto: later) + var r = Math.random(); + // roughly 10% raw, 45% hex, 45% dec + ch = ( + r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch) + ); + } + return ch; + }); + + addr = '' + addr + ''; + addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part + + return addr; +}); diff --git a/src/subParsers/escapeSpecialCharsWithinTagAttributes.js b/src/subParsers/escapeSpecialCharsWithinTagAttributes.js new file mode 100644 index 0000000..a363f19 --- /dev/null +++ b/src/subParsers/escapeSpecialCharsWithinTagAttributes.js @@ -0,0 +1,19 @@ +/** + * Within tags -- meaning between < and > -- encode [\ ` * _] so they + * don't conflict with their use in Markdown for code, italics and strong. + */ +showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) { + 'use strict'; + + // Build a regex to find HTML tags and comments. See Friedl's + // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. + var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi; + + text = text.replace(regex, function (wholeMatch) { + var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`'); + tag = showdown.helper.escapeCharacters(tag, '\\`*_', false); + return tag; + }); + + return text; +}); diff --git a/src/subParsers/githubCodeBlocks.js b/src/subParsers/githubCodeBlocks.js new file mode 100644 index 0000000..35987ae --- /dev/null +++ b/src/subParsers/githubCodeBlocks.js @@ -0,0 +1,39 @@ +/** + * Handle github codeblocks prior to running HashHTML so that + * HTML contained within the codeblock gets escaped properly + * Example: + * ```ruby + * def hello_world(x) + * puts "Hello, #{x}" + * end + * ``` + */ +showdown.subParser('githubCodeBlocks', function (text, options, globals) { + 'use strict'; + + // early exit if option is not enabled + if (!options.ghCodeBlocks) { + return text; + } + + text += '~0'; + + text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) { + var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n'; + + codeblock = showdown.subParser('encodeCode')(codeblock); + codeblock = showdown.subParser('detab')(codeblock); + codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines + codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace + + codeblock = '
    ' + codeblock + end + '
    '; + + return showdown.subParser('hashBlock')(codeblock, options, globals); + }); + + // attacklab: strip sentinel + text = text.replace(/~0/, ''); + + return text; + +}); diff --git a/src/subParsers/hashBlock.js b/src/subParsers/hashBlock.js new file mode 100644 index 0000000..3196f1d --- /dev/null +++ b/src/subParsers/hashBlock.js @@ -0,0 +1,5 @@ +showdown.subParser('hashBlock', function (text, options, globals) { + 'use strict'; + text = text.replace(/(^\n+|\n+$)/g, ''); + return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n'; +}); diff --git a/src/subParsers/hashElement.js b/src/subParsers/hashElement.js new file mode 100644 index 0000000..7bf1291 --- /dev/null +++ b/src/subParsers/hashElement.js @@ -0,0 +1,19 @@ +showdown.subParser('hashElement', function (text, options, globals) { + 'use strict'; + + return function (wholeMatch, m1) { + var blockText = m1; + + // Undo double lines + blockText = blockText.replace(/\n\n/g, '\n'); + blockText = blockText.replace(/^\n/, ''); + + // strip trailing blank lines + blockText = blockText.replace(/\n+$/g, ''); + + // Replace the element text with a marker ("~KxK" where x is its key) + blockText = '\n\n~K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n'; + + return blockText; + }; +}); diff --git a/src/subParsers/hashHTMLBlocks.js b/src/subParsers/hashHTMLBlocks.js new file mode 100644 index 0000000..de640a4 --- /dev/null +++ b/src/subParsers/hashHTMLBlocks.js @@ -0,0 +1,133 @@ +showdown.subParser('hashHTMLBlocks', function (text, options, globals) { + 'use strict'; + + // attacklab: Double up blank lines to reduce lookaround + text = text.replace(/\n/g, '\n\n'); + + // Hashify HTML blocks: + // We only want to do this for block-level HTML tags, such as headers, + // lists, and tables. That's because we still want to wrap

    s around + // "paragraphs" that are wrapped in non-block-level tags, such as anchors, + // phrase emphasis, and spans. The list of tags we're looking for is + // hard-coded: + //var block_tags_a = + // 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del|style|section|header|footer|nav|article|aside'; + // var block_tags_b = + // 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside'; + + // First, look for nested blocks, e.g.: + //

    + //
    + // tags for inner block must be indented. + //
    + //
    + // + // The outermost tags must start at the left margin for this to match, and + // the inner nested divs must be indented. + // We need to do this before the next, more liberal match, because the next + // match will start at the first `
    ` and stop at the first `
    `. + + // attacklab: This regex can be expensive when it fails. + /* + var text = text.replace(/ + ( // save in $1 + ^ // start of line (with /m) + <($block_tags_a) // start tag = $2 + \b // word break + // attacklab: hack around khtml/pcre bug... + [^\r]*?\n // any number of lines, minimally matching + // the matching end tag + [ \t]* // trailing spaces/tabs + (?=\n+) // followed by a newline + ) // attacklab: there are sentinel newlines at end of document + /gm,function(){...}}; + */ + text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm, + showdown.subParser('hashElement')(text, options, globals)); + + // + // Now match more liberally, simply from `\n` to `\n` + // + + /* + var text = text.replace(/ + ( // save in $1 + ^ // start of line (with /m) + <($block_tags_b) // start tag = $2 + \b // word break + // attacklab: hack around khtml/pcre bug... + [^\r]*? // any number of lines, minimally matching + // the matching end tag + [ \t]* // trailing spaces/tabs + (?=\n+) // followed by a newline + ) // attacklab: there are sentinel newlines at end of document + /gm,function(){...}}; + */ + text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside|address|audio|canvas|figure|hgroup|output|video)\b[^\r]*?<\/\2>[ \t]*(?=\n+)\n)/gm, + showdown.subParser('hashElement')(text, options, globals)); + + // Special case just for
    . It was easier to make a special case than + // to make the other regex more complicated. + + /* + text = text.replace(/ + ( // save in $1 + \n\n // Starting after a blank line + [ ]{0,3} + (<(hr) // start tag = $2 + \b // word break + ([^<>])*? // + \/?>) // the matching end tag + [ \t]* + (?=\n{2,}) // followed by a blank line + ) + /g,showdown.subParser('hashElement')(text, options, globals)); + */ + text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, + showdown.subParser('hashElement')(text, options, globals)); + + // Special case for standalone HTML comments: + + /* + text = text.replace(/ + ( // save in $1 + \n\n // Starting after a blank line + [ ]{0,3} // attacklab: g_tab_width - 1 + + [ \t]* + (?=\n{2,}) // followed by a blank line + ) + /g,showdown.subParser('hashElement')(text, options, globals)); + */ + text = text.replace(/(\n\n[ ]{0,3}[ \t]*(?=\n{2,}))/g, + showdown.subParser('hashElement')(text, options, globals)); + + // PHP and ASP-style processor instructions ( and <%...%>) + + /* + text = text.replace(/ + (?: + \n\n // Starting after a blank line + ) + ( // save in $1 + [ ]{0,3} // attacklab: g_tab_width - 1 + (?: + <([?%]) // $2 + [^\r]*? + \2> + ) + [ \t]* + (?=\n{2,}) // followed by a blank line + ) + /g,showdown.subParser('hashElement')(text, options, globals)); + */ + text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, + showdown.subParser('hashElement')(text, options, globals)); + + // attacklab: Undo double lines (see comment at top of this function) + text = text.replace(/\n\n/g, '\n'); + return text; + +}); diff --git a/src/subParsers/headers.js b/src/subParsers/headers.js new file mode 100644 index 0000000..ea9d862 --- /dev/null +++ b/src/subParsers/headers.js @@ -0,0 +1,72 @@ +showdown.subParser('headers', function (text, options, globals) { + 'use strict'; + + var prefixHeader = options.prefixHeaderId, + headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart), + + // Set text-style headers: + // Header 1 + // ======== + // + // Header 2 + // -------- + // + setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm, + setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm; + + text = text.replace(setextRegexH1, function (wholeMatch, m1) { + + var spanGamut = showdown.subParser('spanGamut')(m1, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"', + hLevel = headerLevelStart, + hashBlock = '' + spanGamut + ''; + return showdown.subParser('hashBlock')(hashBlock, options, globals); + }); + + text = text.replace(setextRegexH2, function (matchFound, m1) { + var spanGamut = showdown.subParser('spanGamut')(m1, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"', + hLevel = headerLevelStart + 1, + hashBlock = '' + spanGamut + ''; + return showdown.subParser('hashBlock')(hashBlock, options, globals); + }); + + // atx-style headers: + // # Header 1 + // ## Header 2 + // ## Header 2 with closing hashes ## + // ... + // ###### Header 6 + // + text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) { + var span = showdown.subParser('spanGamut')(m2, options, globals), + hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"', + hLevel = headerLevelStart - 1 + m1.length, + header = '' + span + ''; + + return showdown.subParser('hashBlock')(header, options, globals); + }); + + function headerId(m) { + var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase(); + + if (globals.hashLinkCounts[escapedId]) { + title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++); + } else { + title = escapedId; + globals.hashLinkCounts[escapedId] = 1; + } + + // Prefix id to prevent causing inadvertent pre-existing style matches. + if (prefixHeader === true) { + prefixHeader = 'section'; + } + + if (showdown.helper.isString(prefixHeader)) { + return prefixHeader + title; + } + return title; + } + + return text; +}); diff --git a/src/subParsers/images.js b/src/subParsers/images.js new file mode 100644 index 0000000..8dde87b --- /dev/null +++ b/src/subParsers/images.js @@ -0,0 +1,74 @@ +/** + * Turn Markdown image shortcuts into tags. + */ +showdown.subParser('images', function (text, options, globals) { + 'use strict'; + + var inlineRegExp = /!\[(.*?)]\s?\([ \t]*()?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g, + referenceRegExp = /!\[(.*?)][ ]?(?:\n[ ]*)?\[(.*?)]()()()()()/g; + + function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) { + + var gUrls = globals.gUrls, + gTitles = globals.gTitles, + gDims = globals.gDimensions; + + linkId = linkId.toLowerCase(); + + if (!title) { + title = ''; + } + + if (url === '' || url === null) { + if (linkId === '' || linkId === null) { + // lower-case and turn embedded newlines into spaces + linkId = altText.toLowerCase().replace(/ ?\n/g, ' '); + } + url = '#' + linkId; + + if (!showdown.helper.isUndefined(gUrls[linkId])) { + url = gUrls[linkId]; + if (!showdown.helper.isUndefined(gTitles[linkId])) { + title = gTitles[linkId]; + } + if (!showdown.helper.isUndefined(gDims[linkId])) { + width = gDims[linkId].width; + height = gDims[linkId].height; + } + } else { + return wholeMatch; + } + } + + altText = altText.replace(/"/g, '"'); + altText = showdown.helper.escapeCharacters(altText, '*_', false); + url = showdown.helper.escapeCharacters(url, '*_', false); + var result = '' + altText + 'x "optional title") + text = text.replace(inlineRegExp, writeImageTag); + + return text; +}); diff --git a/src/subParsers/italicsAndBold.js b/src/subParsers/italicsAndBold.js new file mode 100644 index 0000000..4a2fa4d --- /dev/null +++ b/src/subParsers/italicsAndBold.js @@ -0,0 +1,19 @@ +showdown.subParser('italicsAndBold', function (text, options) { + 'use strict'; + + if (options.literalMidWordUnderscores) { + //underscores + // Since we are consuming a \s character, we need to add it + text = text.replace(/(^|\s|>|\b)__(?=\S)([^]+?)__(?=\b|<|\s|$)/gm, '$1$2'); + text = text.replace(/(^|\s|>|\b)_(?=\S)([^]+?)_(?=\b|<|\s|$)/gm, '$1$2'); + //asterisks + text = text.replace(/\*\*(?=\S)([^]+?)\*\*/g, '$1'); + text = text.replace(/\*(?=\S)([^]+?)\*/g, '$1'); + + } else { + // must go first: + text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '$2'); + text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '$2'); + } + return text; +}); diff --git a/src/subParsers/lists.js b/src/subParsers/lists.js new file mode 100644 index 0000000..1a4f43d --- /dev/null +++ b/src/subParsers/lists.js @@ -0,0 +1,160 @@ +/** + * Form HTML ordered (numbered) and unordered (bulleted) lists. + */ +showdown.subParser('lists', function (text, options, globals) { + 'use strict'; + + /** + * Process the contents of a single ordered or unordered list, splitting it + * into individual list items. + * @param {string} listStr + * @returns {string} + */ + function processListItems (listStr, trimTrailing) { + // The $g_list_level global keeps track of when we're inside a list. + // Each time we enter a list, we increment it; when we leave a list, + // we decrement. If it's zero, we're not in a list anymore. + // + // We do this because when we're not inside a list, we want to treat + // something like this: + // + // I recommend upgrading to version + // 8. Oops, now this line is treated + // as a sub-list. + // + // As a single paragraph, despite the fact that the second line starts + // with a digit-period-space sequence. + // + // Whereas when we're inside a list (or sub-list), that line will be + // treated as the start of a sub-list. What a kludge, huh? This is + // an aspect of Markdown's syntax that's hard to parse perfectly + // without resorting to mind-reading. Perhaps the solution is to + // change the syntax rules such that sub-lists must start with a + // starting cardinal number; e.g. "1." or "a.". + globals.gListLevel++; + + // trim trailing blank lines: + listStr = listStr.replace(/\n{2,}$/, '\n'); + + // attacklab: add sentinel to emulate \z + listStr += '~0'; + + var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm, + isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr)); + + listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) { + checked = (checked && checked.trim() !== ''); + var item = showdown.subParser('outdent')(m4, options, globals), + bulletStyle = ''; + + // Support for github tasklists + if (taskbtn && options.tasklists) { + bulletStyle = ' class="task-list-item" style="list-style-type: none;"'; + item = item.replace(/^[ \t]*\[(x| )?]/m, function () { + var otp = ' -1)) { + item = showdown.subParser('githubCodeBlocks')(item, options, globals); + item = showdown.subParser('blockGamut')(item, options, globals); + } else { + // Recursion for sub-lists: + item = showdown.subParser('lists')(item, options, globals); + item = item.replace(/\n$/, ''); // chomp(item) + if (isParagraphed) { + item = showdown.subParser('paragraphs')(item, options, globals); + } else { + item = showdown.subParser('spanGamut')(item, options, globals); + } + } + item = '\n' + item + '\n'; + return item; + }); + + // attacklab: strip sentinel + listStr = listStr.replace(/~0/g, ''); + + globals.gListLevel--; + + if (trimTrailing) { + listStr = listStr.replace(/\s+$/, ''); + } + + return listStr; + } + + /** + * Check and parse consecutive lists (better fix for issue #142) + * @param {string} list + * @param {string} listType + * @returns {string} + */ + function parseConsecutiveLists(list, listType, trimTrailing) { + // check if we caught 2 or more consecutive lists by mistake + // we use the counterRgx, meaning if listType is UL we look for UL and vice versa + var counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm, + subLists = [], + result = ''; + + if (list.search(counterRxg) !== -1) { + (function parseCL(txt) { + var pos = txt.search(counterRxg); + if (pos !== -1) { + // slice + result += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '\n\n'; + + // invert counterType and listType + listType = (listType === 'ul') ? 'ol' : 'ul'; + counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm; + + //recurse + parseCL(txt.slice(pos)); + } else { + result += '\n\n<' + listType + '>' + processListItems(txt, !!trimTrailing) + '\n\n'; + } + })(list); + for (var i = 0; i < subLists.length; ++i) { + + } + } else { + result = '\n\n<' + listType + '>' + processListItems(list, !!trimTrailing) + '\n\n'; + } + + return result; + } + + // attacklab: add sentinel to hack around khtml/safari bug: + // http://bugs.webkit.org/show_bug.cgi?id=11231 + text += '~0'; + + // Re-usable pattern to match any entire ul or ol list: + var wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm; + + if (globals.gListLevel) { + text = text.replace(wholeList, function (wholeMatch, list, m2) { + var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; + return parseConsecutiveLists(list, listType, true); + }); + } else { + wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm; + //wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g; + text = text.replace(wholeList, function (wholeMatch, m1, list, m3) { + + var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol'; + return parseConsecutiveLists(list, listType); + }); + } + + // attacklab: strip sentinel + text = text.replace(/~0/, ''); + + return text; +}); diff --git a/src/subParsers/outdent.js b/src/subParsers/outdent.js new file mode 100644 index 0000000..d27db2e --- /dev/null +++ b/src/subParsers/outdent.js @@ -0,0 +1,15 @@ +/** + * Remove one level of line-leading tabs or spaces + */ +showdown.subParser('outdent', function (text) { + 'use strict'; + + // attacklab: hack around Konqueror 3.5.4 bug: + // "----------bug".replace(/^-/g,"") == "bug" + text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width + + // attacklab: clean up hack + text = text.replace(/~0/g, ''); + + return text; +}); diff --git a/src/subParsers/paragraphs.js b/src/subParsers/paragraphs.js new file mode 100644 index 0000000..2fb1f42 --- /dev/null +++ b/src/subParsers/paragraphs.js @@ -0,0 +1,41 @@ +/** + * + */ +showdown.subParser('paragraphs', function (text, options, globals) { + 'use strict'; + + // Strip leading and trailing lines: + text = text.replace(/^\n+/g, ''); + text = text.replace(/\n+$/g, ''); + + var grafs = text.split(/\n{2,}/g), + grafsOut = [], + end = grafs.length; // Wrap

    tags + + for (var i = 0; i < end; i++) { + var str = grafs[i]; + + // if this is an HTML marker, copy it + if (str.search(/~K(\d+)K/g) >= 0) { + grafsOut.push(str); + } else if (str.search(/\S/) >= 0) { + str = showdown.subParser('spanGamut')(str, options, globals); + str = str.replace(/^([ \t]*)/g, '

    '); + str += '

    '; + grafsOut.push(str); + } + } + + /** Unhashify HTML blocks */ + end = grafsOut.length; + for (i = 0; i < end; i++) { + // if this is a marker for an html block... + while (grafsOut[i].search(/~K(\d+)K/) >= 0) { + var blockText = globals.gHtmlBlocks[RegExp.$1]; + blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs + grafsOut[i] = grafsOut[i].replace(/~K\d+K/, blockText); + } + } + + return grafsOut.join('\n\n'); +}); diff --git a/src/subParsers/runExtension.js b/src/subParsers/runExtension.js new file mode 100644 index 0000000..de741ec --- /dev/null +++ b/src/subParsers/runExtension.js @@ -0,0 +1,20 @@ +/** + * Run extension + */ +showdown.subParser('runExtension', function (ext, text, options, globals) { + 'use strict'; + + if (ext.filter) { + text = ext.filter(text, globals.converter, options); + + } else if (ext.regex) { + // TODO remove this when old extension loading mechanism is deprecated + var re = ext.regex; + if (!re instanceof RegExp) { + re = new RegExp(re, 'g'); + } + text = text.replace(re, ext.replace); + } + + return text; +}); diff --git a/src/subParsers/spanGamut.js b/src/subParsers/spanGamut.js new file mode 100644 index 0000000..e2568da --- /dev/null +++ b/src/subParsers/spanGamut.js @@ -0,0 +1,30 @@ +/** + * These are all the transformations that occur *within* block-level + * tags like paragraphs, headers, and list items. + */ +showdown.subParser('spanGamut', function (text, options, globals) { + 'use strict'; + + text = showdown.subParser('codeSpans')(text, options, globals); + text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals); + text = showdown.subParser('encodeBackslashEscapes')(text, options, globals); + + // Process anchor and image tags. Images must come first, + // because ![foo][f] looks like an anchor. + text = showdown.subParser('images')(text, options, globals); + text = showdown.subParser('anchors')(text, options, globals); + + // Make links out of things like `` + // Must come after _DoAnchors(), because you can use < and > + // delimiters in inline links like [this](). + text = showdown.subParser('autoLinks')(text, options, globals); + text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals); + text = showdown.subParser('italicsAndBold')(text, options, globals); + text = showdown.subParser('strikethrough')(text, options, globals); + + // Do hard breaks: + text = text.replace(/ +\n/g, '
    \n'); + + return text; + +}); diff --git a/src/subParsers/strikethrough.js b/src/subParsers/strikethrough.js new file mode 100644 index 0000000..b84ab39 --- /dev/null +++ b/src/subParsers/strikethrough.js @@ -0,0 +1,9 @@ +showdown.subParser('strikethrough', function (text, options) { + 'use strict'; + + if (options.strikethrough) { + text = text.replace(/(?:~T){2}([^~]+)(?:~T){2}/g, '$1'); + } + + return text; +}); diff --git a/src/subParsers/stripBlankLines.js b/src/subParsers/stripBlankLines.js new file mode 100644 index 0000000..c507d5a --- /dev/null +++ b/src/subParsers/stripBlankLines.js @@ -0,0 +1,10 @@ +/** + * Strip any lines consisting only of spaces and tabs. + * This makes subsequent regexs easier to write, because we can + * match consecutive blank lines with /\n+/ instead of something + * contorted like /[ \t]*\n+/ + */ +showdown.subParser('stripBlankLines', function (text) { + 'use strict'; + return text.replace(/^[ \t]+$/mg, ''); +}); diff --git a/src/subParsers/stripLinkDefinitions.js b/src/subParsers/stripLinkDefinitions.js new file mode 100644 index 0000000..792cafe --- /dev/null +++ b/src/subParsers/stripLinkDefinitions.js @@ -0,0 +1,62 @@ +/** + * Strips link definitions from text, stores the URLs and titles in + * hash references. + * Link defs are in the form: ^[id]: url "optional title" + * + * ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1 + * [ \t]* + * \n? // maybe *one* newline + * [ \t]* + * ? // url = $2 + * [ \t]* + * \n? // maybe one newline + * [ \t]* + * (?: + * (\n*) // any lines skipped = $3 attacklab: lookbehind removed + * ["(] + * (.+?) // title = $4 + * [")] + * [ \t]* + * )? // title is optional + * (?:\n+|$) + * /gm, + * function(){...}); + * + */ +showdown.subParser('stripLinkDefinitions', function (text, options, globals) { + 'use strict'; + + var regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=~0))/gm; + + // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug + text += '~0'; + + text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) { + linkId = linkId.toLowerCase(); + globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url); // Link IDs are case-insensitive + + if (blankLines) { + // Oops, found blank lines, so it's not a title. + // Put back the parenthetical statement we stole. + return blankLines + title; + + } else { + if (title) { + globals.gTitles[linkId] = title.replace(/"|'/g, '"'); + } + if (options.parseImgDimensions && width && height) { + globals.gDimensions[linkId] = { + width: width, + height: height + }; + } + } + // Completely remove the definition from the text + return ''; + }); + + // attacklab: strip sentinel + text = text.replace(/~0/, ''); + + return text; +}); diff --git a/src/subParsers/tables.js b/src/subParsers/tables.js new file mode 100644 index 0000000..104db35 --- /dev/null +++ b/src/subParsers/tables.js @@ -0,0 +1,162 @@ +showdown.subParser('tables', function (text, options, globals) { + 'use strict'; + + var table = function () { + + var tables = {}, + filter; + + tables.th = function (header, style) { + var id = ''; + header = header.trim(); + if (header === '') { + return ''; + } + if (options.tableHeaderId) { + id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"'; + } + header = showdown.subParser('spanGamut')(header, options, globals); + if (!style || style.trim() === '') { + style = ''; + } else { + style = ' style="' + style + '"'; + } + return '' + header + ''; + }; + + tables.td = function (cell, style) { + var subText = showdown.subParser('spanGamut')(cell.trim(), options, globals); + if (!style || style.trim() === '') { + style = ''; + } else { + style = ' style="' + style + '"'; + } + return '' + subText + ''; + }; + + tables.ths = function () { + var out = '', + i = 0, + hs = [].slice.apply(arguments[0]), + style = [].slice.apply(arguments[1]); + + for (i; i < hs.length; i += 1) { + out += tables.th(hs[i], style[i]) + '\n'; + } + + return out; + }; + + tables.tds = function () { + var out = '', + i = 0, + ds = [].slice.apply(arguments[0]), + style = [].slice.apply(arguments[1]); + + for (i; i < ds.length; i += 1) { + out += tables.td(ds[i], style[i]) + '\n'; + } + return out; + }; + + tables.thead = function () { + var out, + hs = [].slice.apply(arguments[0]), + style = [].slice.apply(arguments[1]); + + out = '\n'; + out += '\n'; + out += tables.ths.apply(this, [hs, style]); + out += '\n'; + out += '\n'; + return out; + }; + + tables.tr = function () { + var out, + cs = [].slice.apply(arguments[0]), + style = [].slice.apply(arguments[1]); + + out = '\n'; + out += tables.tds.apply(this, [cs, style]); + out += '\n'; + return out; + }; + + filter = function (text) { + var i = 0, + lines = text.split('\n'), + line, + hs, + out = []; + + for (i; i < lines.length; i += 1) { + line = lines[i]; + // looks like a table heading + if (line.trim().match(/^[|].*[|]$/)) { + line = line.trim(); + + var tbl = [], + align = lines[i + 1].trim(), + styles = [], + j = 0; + + if (align.match(/^[|][-=|: ]+[|]$/)) { + styles = align.substring(1, align.length - 1).split('|'); + for (j = 0; j < styles.length; ++j) { + styles[j] = styles[j].trim(); + if (styles[j].match(/^[:][-=| ]+[:]$/)) { + styles[j] = 'text-align:center;'; + + } else if (styles[j].match(/^[-=| ]+[:]$/)) { + styles[j] = 'text-align:right;'; + + } else if (styles[j].match(/^[:][-=| ]+$/)) { + styles[j] = 'text-align:left;'; + } else { + styles[j] = ''; + } + } + } + tbl.push(''); + hs = line.substring(1, line.length - 1).split('|'); + + if (styles.length === 0) { + for (j = 0; j < hs.length; ++j) { + styles.push('text-align:left'); + } + } + tbl.push(tables.thead.apply(this, [hs, styles])); + line = lines[++i]; + if (!line.trim().match(/^[|][-=|: ]+[|]$/)) { + // not a table rolling back + line = lines[--i]; + } else { + line = lines[++i]; + tbl.push(''); + while (line.trim().match(/^[|].*[|]$/)) { + line = line.trim(); + tbl.push(tables.tr.apply(this, [line.substring(1, line.length - 1).split('|'), styles])); + line = lines[++i]; + } + tbl.push(''); + tbl.push('
    '); + // we are done with this table and we move along + out.push(tbl.join('\n')); + continue; + } + } + out.push(line); + } + return out.join('\n'); + }; + return {parse: filter}; + }; + + if (options.tables) { + var tableParser = table(); + return tableParser.parse(text); + } else { + return text; + } +}); diff --git a/src/subParsers/unescapeSpecialChars.js b/src/subParsers/unescapeSpecialChars.js new file mode 100644 index 0000000..1873f43 --- /dev/null +++ b/src/subParsers/unescapeSpecialChars.js @@ -0,0 +1,12 @@ +/** + * Swap back in all the special characters we've hidden. + */ +showdown.subParser('unescapeSpecialChars', function (text) { + 'use strict'; + + text = text.replace(/~E(\d+)E/g, function (wholeMatch, m1) { + var charCodeToReplace = parseInt(m1); + return String.fromCharCode(charCodeToReplace); + }); + return text; +}); diff --git a/test/bootstrap.js b/test/bootstrap.js new file mode 100644 index 0000000..fc9b11d --- /dev/null +++ b/test/bootstrap.js @@ -0,0 +1,98 @@ +/** + * Created by Estevao on 08-06-2015. + */ + +//jscs:disable requireCamelCaseOrUpperCaseIdentifiers +(function () { + 'use strict'; + + require('source-map-support').install(); + require('chai').should(); + var fs = require('fs'), + os = require('os'), + /*jshint -W106 */ + beautify = require('js-beautify').html_beautify, + beauOptions = { + eol: os.EOL, + indent_size: 2, + preserve_newlines: false + }; + /*jshint +W106 */ + + function getTestSuite(dir) { + return fs.readdirSync(dir) + .filter(filter()) + .map(map(dir)); + } + + function filter() { + return function (file) { + var ext = file.slice(-3); + return (ext === '.md'); + }; + } + + function map(dir) { + return function (file) { + var name = file.replace('.md', ''), + htmlPath = dir + name + '.html', + html = fs.readFileSync(htmlPath, 'utf8'), + mdPath = dir + name + '.md', + md = fs.readFileSync(mdPath, 'utf8'); + + return { + name: name, + input: md, + expected: html + }; + }; + } + + function assertion(testCase, converter) { + return function () { + testCase.actual = converter.makeHtml(testCase.input); + testCase = normalize(testCase); + + // Compare + testCase.actual.should.equal(testCase.expected); + }; + } + + //Normalize input/output + function normalize(testCase) { + + // Normalize line returns + testCase.expected = testCase.expected.replace(/(\r\n)|\n|\r/g, '\n'); + testCase.actual = testCase.actual.replace(/(\r\n)|\n|\r/g, '\n'); + + // Ignore all leading/trailing whitespace + testCase.expected = testCase.expected.split('\n').map(function (x) { + return x.trim(); + }).join('\n'); + testCase.actual = testCase.actual.split('\n').map(function (x) { + return x.trim(); + }).join('\n'); + + // Remove extra lines + testCase.expected = testCase.expected.trim(); + testCase.actual = testCase.actual.trim(); + + //Beautify + testCase.expected = beautify(testCase.expected, beauOptions); + testCase.actual = beautify(testCase.actual, beauOptions); + + // Normalize line returns + testCase.expected = testCase.expected.replace(/(\r\n)|\n|\r/g, '\n'); + testCase.actual = testCase.actual.replace(/(\r\n)|\n|\r/g, '\n'); + + return testCase; + } + + module.exports = { + getTestSuite: getTestSuite, + assertion: assertion, + normalize: normalize, + showdown: require('../.build/showdown.js') + }; +})(); + diff --git a/test/cases/anchors-by-reference.html b/test/cases/anchors-by-reference.html index 9265274..1bba333 100644 --- a/test/cases/anchors-by-reference.html +++ b/test/cases/anchors-by-reference.html @@ -1,5 +1,4 @@ -

    This is an example reference-style link. -This is another reference-style link. -This is a third reference-style link. -This is a fourth reference-style link.

    \ No newline at end of file + This is another reference-style link. + This is a third reference-style link. + This is a fourth reference-style link.

    diff --git a/test/cases/automatic-anchors.html b/test/cases/automatic-anchors.html index 8d32215..6de71a9 100644 --- a/test/cases/automatic-anchors.html +++ b/test/cases/automatic-anchors.html @@ -1,2 +1 @@ - -

    http://example.com/

    \ No newline at end of file +

    http://example.com/

    diff --git a/test/cases/blockquote-nested-markdown.html b/test/cases/blockquote-nested-markdown.html index 25800d7..5022edc 100644 --- a/test/cases/blockquote-nested-markdown.html +++ b/test/cases/blockquote-nested-markdown.html @@ -1,12 +1,12 @@
    -

    This is a header.

    +

    This is a header.

    -
      -
    1. This is the first list item.
    2. -
    3. This is the second list item.
    4. -
    +
      +
    1. This is the first list item.
    2. +
    3. This is the second list item.
    4. +
    -

    Here's some example code:

    +

    Here's some example code:

    return shell_exec("echo $input | $markdown_script");
         
    diff --git a/test/cases/blockquote.html b/test/cases/blockquote.html index c31f284..c74d3f6 100644 --- a/test/cases/blockquote.html +++ b/test/cases/blockquote.html @@ -1,5 +1,5 @@
    -

    This is a multi line blockquote test

    +

    This is a multi line blockquote test

    -

    With more than one line.

    -
    \ No newline at end of file +

    With more than one line.

    +
    diff --git a/test/cases/code-block-html-escape.html b/test/cases/code-block-html-escape.html index 123e4f3..028f874 100644 --- a/test/cases/code-block-html-escape.html +++ b/test/cases/code-block-html-escape.html @@ -1,5 +1,4 @@ -

    This is some HTML:

    <h1>Heading</h1>
    -
    \ No newline at end of file +
    diff --git a/test/cases/code-block.html b/test/cases/code-block.html index bdb50b4..3e56099 100644 --- a/test/cases/code-block.html +++ b/test/cases/code-block.html @@ -1,5 +1,4 @@ -

    This is a normal paragraph:

    This is a code block.
    -
    \ No newline at end of file +
    diff --git a/test/cases/doubline-list.html b/test/cases/doubline-list.html index da41237..a2fe204 100644 --- a/test/cases/doubline-list.html +++ b/test/cases/doubline-list.html @@ -1,5 +1,4 @@ -
      -
    • Bird

    • -
    • Magic

    • -
    \ No newline at end of file +
  • Bird

  • +
  • Magic

  • + diff --git a/test/cases/emphasis.html b/test/cases/emphasis.html index 056fdea..e33c510 100644 --- a/test/cases/emphasis.html +++ b/test/cases/emphasis.html @@ -1,8 +1,66 @@ +

    single asterisks

    -

    important

    +

    single underscores

    -

    important

    +

    double asterisks

    -

    this midimportantsentence

    +

    double underscores

    -

    *not important*

    \ No newline at end of file +

    text with italic sentence in middle

    + +

    text with bold sentence in middle

    + +

    text with bold text that + spans across multiple lines

    + +

    underscored_word

    + +

    doubleunderscore__word

    + +

    asterix*word

    + +

    doubleasterix**word

    + +

    line with_underscored word

    + +

    line with__doubleunderscored word

    + +

    line with*asterixed word

    + +

    line with**doubleasterixed word

    + +

    some linewithinner underscores

    + +

    some linewithinner double underscores

    + +

    some linewithinner asterixs

    + +

    some linewithinner double asterixs

    + +

    another line with just _one underscore

    + +

    another line with just __one double underscore

    + +

    another line with just *one asterix

    + +

    another line with just **one double asterix

    + +

    a sentence withunderscore and anotherunderscore

    + +

    a sentence withdoubleunderscore and anotherdoubleunderscore

    + +

    a sentence withasterix and anotherasterix

    + +

    a sentence withdoubleasterix and anotherdoubleasterix

    + +

    escaped word_with_underscores

    + +

    escaped word__with__double underscores

    + +

    escaped word_with_single italic underscore

    + +

    escaped word*with*asterixs

    + +

    escaped word**with**asterixs

    + +

    escaped word*with*bold asterixs

    diff --git a/test/cases/emphasis.md b/test/cases/emphasis.md index 0e70802..dc7901f 100644 --- a/test/cases/emphasis.md +++ b/test/cases/emphasis.md @@ -1,8 +1,66 @@ +*single asterisks* -*important* +_single underscores_ -_important_ +**double asterisks** -this mid*important*sentence +__double underscores__ -\*not important\* \ No newline at end of file +text *with italic sentence* in middle + +text __with bold sentence__ in middle + +text with __bold text that +spans across multiple__ lines + +underscored_word + +doubleunderscore__word + +asterix*word + +doubleasterix**word + +line with_underscored word + +line with__doubleunderscored word + +line with*asterixed word + +line with**doubleasterixed word + +some line_with_inner underscores + +some line__with__inner double underscores + +some line*with*inner asterixs + +some line**with**inner double asterixs + +another line with just _one underscore + +another line with just __one double underscore + +another line with just *one asterix + +another line with just **one double asterix + +a sentence with_underscore and another_underscore + +a sentence with__doubleunderscore and another__doubleunderscore + +a sentence with*asterix and another*asterix + +a sentence with**doubleasterix and another**doubleasterix + +escaped word\_with\_underscores + +escaped word\_\_with\_\_double underscores + +escaped word_\_with\__single italic underscore + +escaped word\*with*asterixs + +escaped word\*\*with\*\*asterixs + +escaped word**\*with\***bold asterixs diff --git a/test/cases/escaped-number-period.html b/test/cases/escaped-number-period.html index f773d21..42f286d 100644 --- a/test/cases/escaped-number-period.html +++ b/test/cases/escaped-number-period.html @@ -1 +1 @@ -

    It happened in 1986. What a great season.

    \ No newline at end of file +

    It happened in 1986. What a great season.

    diff --git a/test/cases/escaped-number-period.md b/test/cases/escaped-number-period.md index d321a38..654761b 100644 --- a/test/cases/escaped-number-period.md +++ b/test/cases/escaped-number-period.md @@ -1 +1 @@ -It happened in 1986\. What a great season. \ No newline at end of file +It happened in 1986\. What a great season. diff --git a/test/cases/escaping.html b/test/cases/escaping.html index 671a2a6..1ac6a29 100644 --- a/test/cases/escaping.html +++ b/test/cases/escaping.html @@ -1,4 +1,3 @@ -

    These should all be escaped:

    \

    @@ -29,4 +28,4 @@

    .

    -

    !

    \ No newline at end of file +

    !

    diff --git a/test/cases/github-style-at-start.html b/test/cases/github-style-at-start.html index 8f5dd94..5cfec09 100644 --- a/test/cases/github-style-at-start.html +++ b/test/cases/github-style-at-start.html @@ -1,7 +1,6 @@ -
    function MyFunc(a) {
    -    // ...
    -}
    +  // ...
    +  }
     
    -

    That is some code!

    \ No newline at end of file +

    That is some code!

    diff --git a/test/cases/github-style-codeblock.html b/test/cases/github-style-codeblock.html index fc4187e..8d593ae 100644 --- a/test/cases/github-style-codeblock.html +++ b/test/cases/github-style-codeblock.html @@ -1,13 +1,11 @@ - -

    Define a function in javascript:

    function MyFunc(a) {
    -    var s = '`';
    -}
    +  var s = '`';
    +  }
     

    And some HTML

    -
    <div>HTML!</div>
    -
    \ No newline at end of file +
    <div>HTML!</div>
    +
    diff --git a/test/cases/github-style-linebreaks.html b/test/cases/github-style-linebreaks.html index d8210a4..e92a482 100644 --- a/test/cases/github-style-linebreaks.html +++ b/test/cases/github-style-linebreaks.html @@ -1,4 +1,3 @@ -
    code can go here
    -this is rendered on a second line
    -
    \ No newline at end of file + this is rendered on a second line +
    diff --git a/test/cases/h1-with-double-hash.html b/test/cases/h1-with-double-hash.html index 2cecc38..ab5b555 100644 --- a/test/cases/h1-with-double-hash.html +++ b/test/cases/h1-with-double-hash.html @@ -1 +1 @@ -

    This is an H1

    \ No newline at end of file +

    This is an H1

    diff --git a/test/cases/h1-with-equals.html b/test/cases/h1-with-equals.html index 2cecc38..ab5b555 100644 --- a/test/cases/h1-with-equals.html +++ b/test/cases/h1-with-equals.html @@ -1 +1 @@ -

    This is an H1

    \ No newline at end of file +

    This is an H1

    diff --git a/test/cases/h1-with-single-hash.html b/test/cases/h1-with-single-hash.html index 2cecc38..ab5b555 100644 --- a/test/cases/h1-with-single-hash.html +++ b/test/cases/h1-with-single-hash.html @@ -1 +1 @@ -

    This is an H1

    \ No newline at end of file +

    This is an H1

    diff --git a/test/cases/h2-with-dashes.html b/test/cases/h2-with-dashes.html index d040d75..375a0d0 100644 --- a/test/cases/h2-with-dashes.html +++ b/test/cases/h2-with-dashes.html @@ -1 +1 @@ -

    This is an H2

    \ No newline at end of file +

    This is an H2

    diff --git a/test/cases/h2-with-double-hash.html b/test/cases/h2-with-double-hash.html index d040d75..375a0d0 100644 --- a/test/cases/h2-with-double-hash.html +++ b/test/cases/h2-with-double-hash.html @@ -1 +1 @@ -

    This is an H2

    \ No newline at end of file +

    This is an H2

    diff --git a/test/cases/h2-with-single-hash.html b/test/cases/h2-with-single-hash.html index d040d75..375a0d0 100644 --- a/test/cases/h2-with-single-hash.html +++ b/test/cases/h2-with-single-hash.html @@ -1 +1 @@ -

    This is an H2

    \ No newline at end of file +

    This is an H2

    diff --git a/test/cases/h3-with-double-hash.html b/test/cases/h3-with-double-hash.html index 082318e..13f8c9e 100644 --- a/test/cases/h3-with-double-hash.html +++ b/test/cases/h3-with-double-hash.html @@ -1 +1 @@ -

    This is an H3

    \ No newline at end of file +

    This is an H3

    diff --git a/test/cases/h3-with-single-hash.html b/test/cases/h3-with-single-hash.html index 082318e..13f8c9e 100644 --- a/test/cases/h3-with-single-hash.html +++ b/test/cases/h3-with-single-hash.html @@ -1 +1 @@ -

    This is an H3

    \ No newline at end of file +

    This is an H3

    diff --git a/test/cases/h4-with-single-hash.html b/test/cases/h4-with-single-hash.html index cc32aa1..165b4ef 100644 --- a/test/cases/h4-with-single-hash.html +++ b/test/cases/h4-with-single-hash.html @@ -1 +1 @@ -

    This is an H4

    \ No newline at end of file +

    This is an H4

    diff --git a/test/cases/h5-with-single-hash.html b/test/cases/h5-with-single-hash.html index 96dca78..28eac14 100644 --- a/test/cases/h5-with-single-hash.html +++ b/test/cases/h5-with-single-hash.html @@ -1 +1 @@ -
    This is an H5
    \ No newline at end of file +
    This is an H5
    diff --git a/test/cases/h6-with-single-hash.html b/test/cases/h6-with-single-hash.html index 10de690..47574cc 100644 --- a/test/cases/h6-with-single-hash.html +++ b/test/cases/h6-with-single-hash.html @@ -1 +1 @@ -
    This is an H6
    \ No newline at end of file +
    This is an H6
    diff --git a/test/cases/horizontal-rules.html b/test/cases/horizontal-rules.html index 88eb5de..aaef23e 100644 --- a/test/cases/horizontal-rules.html +++ b/test/cases/horizontal-rules.html @@ -1,4 +1,3 @@ -

    @@ -7,4 +6,4 @@
    -
    \ No newline at end of file +
    diff --git a/test/cases/html5-strutural-tags.html b/test/cases/html5-strutural-tags.html index 98698e8..5b351d3 100644 --- a/test/cases/html5-strutural-tags.html +++ b/test/cases/html5-strutural-tags.html @@ -1,4 +1,3 @@ -

    These HTML5 tags should pass through just fine.

    hello
    @@ -14,10 +13,63 @@
    read -me
    + me -

    the end

    \ No newline at end of file +

    the end

    + + + + + + + + +
    Foo
    Bar
    + + + + + + + + + + + + + + + +
    Foo
    Bar
    Bar
    + + + + + +
    My street
    + + + Sorry, your browser doesn't support the <canvas> element. + + +
    + An awesome picture +
    Caption for the awesome picture
    +
    + +
    +

    Main title

    +

    Secondary title

    +
    + + diff --git a/test/cases/html5-strutural-tags.md b/test/cases/html5-strutural-tags.md index 5b27728..c326836 100644 --- a/test/cases/html5-strutural-tags.md +++ b/test/cases/html5-strutural-tags.md @@ -13,4 +13,57 @@ me ignore me -the end \ No newline at end of file +the end + + + + + + + + +
    Foo
    Bar
    + + + + + + + + + + + + + + + +
    Foo
    Bar
    Bar
    + + + + + +
    My street
    + + + Sorry, your browser doesn't support the <canvas> element. + + +
    + An awesome picture +
    Caption for the awesome picture
    +
    + +
    +

    Main title

    +

    Secondary title

    +
    + + \ No newline at end of file diff --git a/test/cases/images.html b/test/cases/images.html index f214ba1..d1e0cb3 100644 --- a/test/cases/images.html +++ b/test/cases/images.html @@ -1,6 +1,5 @@ - -

    Alt text

    +

    Alt text

    Alt text

    -

    Alt text

    \ No newline at end of file +

    Alt text

    diff --git a/test/cases/implicit-anchors.html b/test/cases/implicit-anchors.html index 8bb39ff..01e62d9 100644 --- a/test/cases/implicit-anchors.html +++ b/test/cases/implicit-anchors.html @@ -1,2 +1 @@ - -

    Search the web at Google or Daring Fireball.

    \ No newline at end of file +

    Search the web at Google or Daring Fireball.

    diff --git a/test/cases/inline-anchors.html b/test/cases/inline-anchors.html index 7be05ef..52f90ed 100644 --- a/test/cases/inline-anchors.html +++ b/test/cases/inline-anchors.html @@ -1,4 +1,3 @@ -

    This is an example inline link.

    -

    This link has no title attribute.

    \ No newline at end of file +

    This link has no title attribute.

    diff --git a/test/cases/inline-code.html b/test/cases/inline-code.html index e1809e6..ebb7fdc 100644 --- a/test/cases/inline-code.html +++ b/test/cases/inline-code.html @@ -1,4 +1,3 @@ -

    Create a new function.

    Use the backtick in MySQL syntax SELECT `column` FROM whatever.

    @@ -9,4 +8,4 @@

    Please don't use any <blink> tags.

    -

    &#8212; is the decimal-encoded equivalent of &mdash;.

    \ No newline at end of file +

    &#8212; is the decimal-encoded equivalent of &mdash;.

    diff --git a/test/cases/inline-escaped-chars.html b/test/cases/inline-escaped-chars.html index ff9226c..5ee58e6 100644 --- a/test/cases/inline-escaped-chars.html +++ b/test/cases/inline-escaped-chars.html @@ -1,3 +1,2 @@ -

    Hello.this_is_a_variable -and.this.is.another_one

    \ No newline at end of file + and.this.is.another_one

    diff --git a/test/cases/inline-style-tag.html b/test/cases/inline-style-tag.html index 9a6540b..d51b485 100644 --- a/test/cases/inline-style-tag.html +++ b/test/cases/inline-style-tag.html @@ -1,6 +1,5 @@ - -

    An exciting sentence.

    \ No newline at end of file +

    An exciting sentence.

    diff --git a/test/cases/lazy-blockquote.html b/test/cases/lazy-blockquote.html index c31f284..c74d3f6 100644 --- a/test/cases/lazy-blockquote.html +++ b/test/cases/lazy-blockquote.html @@ -1,5 +1,5 @@
    -

    This is a multi line blockquote test

    +

    This is a multi line blockquote test

    -

    With more than one line.

    -
    \ No newline at end of file +

    With more than one line.

    + diff --git a/test/cases/list-followed-by-blockquote.html b/test/cases/list-followed-by-blockquote.html new file mode 100644 index 0000000..e1f2aca --- /dev/null +++ b/test/cases/list-followed-by-blockquote.html @@ -0,0 +1,15 @@ +

    some title

    + +
      +
    1. list item 1
    2. +
    3. list item 2
    4. +
    + +
    +

    some text in a blockquote

    +
    + +
      +
    • another list item 1
    • +
    • another list item 2
    • +
    diff --git a/test/cases/list-followed-by-blockquote.md b/test/cases/list-followed-by-blockquote.md new file mode 100644 index 0000000..e2dd15f --- /dev/null +++ b/test/cases/list-followed-by-blockquote.md @@ -0,0 +1,9 @@ +# some title + +1. list item 1 +2. list item 2 + +> some text in a blockquote + +* another list item 1 +* another list item 2 \ No newline at end of file diff --git a/test/cases/list-followed-by-ghcode.html b/test/cases/list-followed-by-ghcode.html new file mode 100644 index 0000000..4117942 --- /dev/null +++ b/test/cases/list-followed-by-ghcode.html @@ -0,0 +1,16 @@ +

    some title

    + +
      +
    1. list item 1
    2. +
    3. list item 2
    4. +
    + +
    some code
    +
    +    and some other line of code
    +
    + +
      +
    • another list item 1
    • +
    • another list item 2
    • +
    diff --git a/test/cases/list-followed-by-ghcode.md b/test/cases/list-followed-by-ghcode.md new file mode 100644 index 0000000..b640e43 --- /dev/null +++ b/test/cases/list-followed-by-ghcode.md @@ -0,0 +1,13 @@ +# some title + +1. list item 1 +2. list item 2 + +``` +some code + +and some other line of code +``` + +* another list item 1 +* another list item 2 \ No newline at end of file diff --git a/test/cases/list-with-blockquote.html b/test/cases/list-with-blockquote.html index e33c04f..67a0a96 100644 --- a/test/cases/list-with-blockquote.html +++ b/test/cases/list-with-blockquote.html @@ -1,8 +1,8 @@
      -
    • A list item with a blockquote:

      +
    • A list item with a blockquote:

      -

      This is a blockquote +

      This is a blockquote inside a list item.

    • -
    \ No newline at end of file + diff --git a/test/cases/list-with-code.html b/test/cases/list-with-code.html index 753a269..4fb69c5 100644 --- a/test/cases/list-with-code.html +++ b/test/cases/list-with-code.html @@ -1,6 +1,6 @@
      -
    • A list item with code:

      +
    • A list item with code:

      alert('Hello world!');
           
    • -
    \ No newline at end of file + diff --git a/test/cases/multi-paragraph-list.html b/test/cases/multi-paragraph-list.html index 1afca57..b5b2946 100644 --- a/test/cases/multi-paragraph-list.html +++ b/test/cases/multi-paragraph-list.html @@ -1,6 +1,6 @@
      -
    1. This is a major bullet point.

      +
    2. This is a major bullet point.

      That contains multiple paragraphs.

    3. -
    4. And another line

    5. -
    \ No newline at end of file +
  • And another line

  • + diff --git a/test/cases/multiline-unordered-list.html b/test/cases/multiline-unordered-list.html index bb6c06a..6af8aac 100644 --- a/test/cases/multiline-unordered-list.html +++ b/test/cases/multiline-unordered-list.html @@ -1,5 +1,5 @@
      -
    • This line spans - more than one line and is lazy
    • -
    • Similar to this line
    • -
    \ No newline at end of file +
  • This line spans + more than one line and is lazy
  • +
  • Similar to this line
  • + diff --git a/test/cases/nested-blockquote.html b/test/cases/nested-blockquote.html index 97ca7d7..b91c9d9 100644 --- a/test/cases/nested-blockquote.html +++ b/test/cases/nested-blockquote.html @@ -1,9 +1,9 @@
    -

    This is a multi line blockquote test

    +

    This is a multi line blockquote test

    -
    -

    And nesting!

    -
    +
    +

    And nesting!

    +
    -

    With more than one line.

    -
    \ No newline at end of file +

    With more than one line.

    + diff --git a/test/cases/ordered-list-same-number.html b/test/cases/ordered-list-same-number.html index 726f66c..a48b0b7 100644 --- a/test/cases/ordered-list-same-number.html +++ b/test/cases/ordered-list-same-number.html @@ -1,5 +1,5 @@
      -
    1. Red
    2. -
    3. Green
    4. -
    5. Blue
    6. -
    \ No newline at end of file +
  • Red
  • +
  • Green
  • +
  • Blue
  • + diff --git a/test/cases/ordered-list-wrong-numbers.html b/test/cases/ordered-list-wrong-numbers.html index 726f66c..a48b0b7 100644 --- a/test/cases/ordered-list-wrong-numbers.html +++ b/test/cases/ordered-list-wrong-numbers.html @@ -1,5 +1,5 @@
      -
    1. Red
    2. -
    3. Green
    4. -
    5. Blue
    6. -
    \ No newline at end of file +
  • Red
  • +
  • Green
  • +
  • Blue
  • + diff --git a/test/cases/ordered-list.html b/test/cases/ordered-list.html index 726f66c..a48b0b7 100644 --- a/test/cases/ordered-list.html +++ b/test/cases/ordered-list.html @@ -1,5 +1,5 @@
      -
    1. Red
    2. -
    3. Green
    4. -
    5. Blue
    6. -
    \ No newline at end of file +
  • Red
  • +
  • Green
  • +
  • Blue
  • + diff --git a/test/cases/paragraphed-list-with-sublists.html b/test/cases/paragraphed-list-with-sublists.html new file mode 100644 index 0000000..d118571 --- /dev/null +++ b/test/cases/paragraphed-list-with-sublists.html @@ -0,0 +1,15 @@ +
      +
    • foo

      +
        +
      • bazinga

      • +
      • yeah

      • +
      +
    • +
    • bar

      +
        +
      1. damn

      2. +
      3. so many paragraphs

      4. +
      +
    • +
    • baz

    • +
    diff --git a/test/cases/paragraphed-list-with-sublists.md b/test/cases/paragraphed-list-with-sublists.md new file mode 100644 index 0000000..e93c855 --- /dev/null +++ b/test/cases/paragraphed-list-with-sublists.md @@ -0,0 +1,13 @@ + - foo + + - bazinga + + - yeah + + - bar + + 1. damn + + 2. so many paragraphs + + - baz diff --git a/test/cases/relative-anchors.html b/test/cases/relative-anchors.html index a412083..6db73dc 100644 --- a/test/cases/relative-anchors.html +++ b/test/cases/relative-anchors.html @@ -1,2 +1 @@ - -

    See my About page for details.

    \ No newline at end of file +

    See my About page for details.

    diff --git a/test/cases/repeated-headers.html b/test/cases/repeated-headers.html new file mode 100644 index 0000000..97acc54 --- /dev/null +++ b/test/cases/repeated-headers.html @@ -0,0 +1,5 @@ +

    Same Title

    + +

    some text

    + +

    Same Title

    diff --git a/test/cases/repeated-headers.md b/test/cases/repeated-headers.md new file mode 100644 index 0000000..4369318 --- /dev/null +++ b/test/cases/repeated-headers.md @@ -0,0 +1,5 @@ +# Same Title + +some text + +# Same Title diff --git a/test/cases/simple-paragraph.html b/test/cases/simple-paragraph.html index 1f19a39..7ce5354 100644 --- a/test/cases/simple-paragraph.html +++ b/test/cases/simple-paragraph.html @@ -1 +1 @@ -

    Hello, world!

    \ No newline at end of file +

    Hello, world!

    diff --git a/test/cases/strong.html b/test/cases/strong.html index 4938794..5bcc675 100644 --- a/test/cases/strong.html +++ b/test/cases/strong.html @@ -1,6 +1,5 @@ -

    important

    important

    -

    really freakingstrong

    \ No newline at end of file +

    really freakingstrong

    diff --git a/test/cases/unordered-list-asterisk.html b/test/cases/unordered-list-asterisk.html index ddc422c..62dba34 100644 --- a/test/cases/unordered-list-asterisk.html +++ b/test/cases/unordered-list-asterisk.html @@ -1,5 +1,5 @@
      -
    • Red
    • -
    • Green
    • -
    • Blue
    • -
    \ No newline at end of file +
  • Red
  • +
  • Green
  • +
  • Blue
  • + diff --git a/test/cases/unordered-list-minus.html b/test/cases/unordered-list-minus.html index ddc422c..62dba34 100644 --- a/test/cases/unordered-list-minus.html +++ b/test/cases/unordered-list-minus.html @@ -1,5 +1,5 @@
      -
    • Red
    • -
    • Green
    • -
    • Blue
    • -
    \ No newline at end of file +
  • Red
  • +
  • Green
  • +
  • Blue
  • + diff --git a/test/cases/unordered-list-plus.html b/test/cases/unordered-list-plus.html index ddc422c..62dba34 100644 --- a/test/cases/unordered-list-plus.html +++ b/test/cases/unordered-list-plus.html @@ -1,5 +1,5 @@
      -
    • Red
    • -
    • Green
    • -
    • Blue
    • -
    \ No newline at end of file +
  • Red
  • +
  • Green
  • +
  • Blue
  • + diff --git a/test/cases/url-with-parenthesis.html b/test/cases/url-with-parenthesis.html index d42cee8..9e1e7cc 100644 --- a/test/cases/url-with-parenthesis.html +++ b/test/cases/url-with-parenthesis.html @@ -1,2 +1 @@ - -

    There's an episode of Star Trek: The Next Generation

    \ No newline at end of file +

    There's an episode of Star Trek: The Next Generation

    diff --git a/test/cases/url-with-parenthesis.md b/test/cases/url-with-parenthesis.md index f271d26..d1777ab 100644 --- a/test/cases/url-with-parenthesis.md +++ b/test/cases/url-with-parenthesis.md @@ -1,2 +1 @@ - -There's an [episode](http://en.memory-alpha.org/wiki/Darmok_(episode)) of Star Trek: The Next Generation \ No newline at end of file +There's an [episode](http://en.memory-alpha.org/wiki/Darmok_(episode)) of Star Trek: The Next Generation diff --git a/test/cli/basic.html b/test/cli/basic.html new file mode 100644 index 0000000..a014504 --- /dev/null +++ b/test/cli/basic.html @@ -0,0 +1,3 @@ +

    some title

    + +

    Test bold and italic

    diff --git a/test/cli/basic.md b/test/cli/basic.md new file mode 100644 index 0000000..a5256ad --- /dev/null +++ b/test/cli/basic.md @@ -0,0 +1,3 @@ +# some title + +Test **bold** and _italic_ diff --git a/test/extensions/github/basic.html b/test/extensions/github/basic.html deleted file mode 100644 index af2b069..0000000 --- a/test/extensions/github/basic.html +++ /dev/null @@ -1,5 +0,0 @@ -

    github-flavored markdown adds support for:

    - -
      -
    • strike-through text
    • -
    \ No newline at end of file diff --git a/test/extensions/github/basic.md b/test/extensions/github/basic.md deleted file mode 100644 index 0ef04a3..0000000 --- a/test/extensions/github/basic.md +++ /dev/null @@ -1,3 +0,0 @@ -[github-flavored markdown](http://github.github.com/github-flavored-markdown/) adds support for: - - * ~~strike-through text~~ diff --git a/test/extensions/prettify/basic.html b/test/extensions/prettify/basic.html deleted file mode 100644 index 13c7f40..0000000 --- a/test/extensions/prettify/basic.html +++ /dev/null @@ -1,7 +0,0 @@ - -

    Here's a simple hello world in javascript:

    - -
    alert('Hello World!');
    -
    - -

    The alert function is a build-in global from window.

    \ No newline at end of file diff --git a/test/extensions/prettify/basic.md b/test/extensions/prettify/basic.md deleted file mode 100644 index fba19fa..0000000 --- a/test/extensions/prettify/basic.md +++ /dev/null @@ -1,6 +0,0 @@ - -Here's a simple hello world in javascript: - - alert('Hello World!'); - -The `alert` function is a build-in global from `window`. \ No newline at end of file diff --git a/test/extensions/table/basic.html b/test/extensions/table/basic.html deleted file mode 100644 index d909e65..0000000 --- a/test/extensions/table/basic.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
    First Header Second Header

    Row 1 Cell 1

    Row 1 Cell 2

    Row 2 Cell 1

    Row 2 Cell 2

    diff --git a/test/extensions/table/large.html b/test/extensions/table/large.html deleted file mode 100644 index 332bdab..0000000 --- a/test/extensions/table/large.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    First Header Second Header Third Header Fourth Header

    Row 1 Cell 1

    Row 1 Cell 2

    Row 1 Cell 3

    Row 1 Cell 4

    Row 2 Cell 1

    Row 2 Cell 2

    Row 2 Cell 3

    Row 2 Cell 4

    Row 3 Cell 1

    Row 3 Cell 2

    Row 3 Cell 3

    Row 3 Cell 4

    Row 4 Cell 1

    Row 4 Cell 2

    Row 4 Cell 3

    Row 4 Cell 4

    Row 5 Cell 1

    Row 5 Cell 2

    Row 5 Cell 3

    Row 5 Cell 4

    diff --git a/test/extensions/table/with-equals.html b/test/extensions/table/with-equals.html deleted file mode 100644 index d909e65..0000000 --- a/test/extensions/table/with-equals.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
    First Header Second Header

    Row 1 Cell 1

    Row 1 Cell 2

    Row 2 Cell 1

    Row 2 Cell 2

    diff --git a/test/extensions/table/without-body.html b/test/extensions/table/without-body.html deleted file mode 100644 index 5b37e4a..0000000 --- a/test/extensions/table/without-body.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - -
    First Header Second Header
    diff --git a/test/extensions/twitter/basic.html b/test/extensions/twitter/basic.html deleted file mode 100644 index 4e9b316..0000000 --- a/test/extensions/twitter/basic.html +++ /dev/null @@ -1,5 +0,0 @@ -

    Testing of the twitter extension.

    - -

    Ping @andstuff to find out more about #extensions with showdown

    - -

    And @something shouldn't render as a twitter link

    \ No newline at end of file diff --git a/test/extensions/twitter/basic.md b/test/extensions/twitter/basic.md deleted file mode 100644 index 6269c9d..0000000 --- a/test/extensions/twitter/basic.md +++ /dev/null @@ -1,5 +0,0 @@ -Testing of the twitter extension. - -Ping @andstuff to find out more about #extensions with showdown - -And \@something shouldn't render as a twitter link \ No newline at end of file diff --git a/test/features/#143.support_image_dimensions.html b/test/features/#143.support_image_dimensions.html new file mode 100644 index 0000000..5288494 --- /dev/null +++ b/test/features/#143.support_image_dimensions.html @@ -0,0 +1,2 @@ +

    my image

    +

    my image2

    \ No newline at end of file diff --git a/test/features/#143.support_image_dimensions.md b/test/features/#143.support_image_dimensions.md new file mode 100644 index 0000000..ecbd02f --- /dev/null +++ b/test/features/#143.support_image_dimensions.md @@ -0,0 +1,5 @@ +![my image](./pic/pic1_50.png =100pxx20px) + +![my image2][1] + +[1]: ./pic/pic1_50.png =100pxx20px diff --git a/test/features/#164.1.simple_autolink.html b/test/features/#164.1.simple_autolink.html new file mode 100644 index 0000000..909ae2c --- /dev/null +++ b/test/features/#164.1.simple_autolink.html @@ -0,0 +1,11 @@ +

    foo.bar

    + +

    www.foobar

    + +

    www.foobar.com

    + +

    http://foobar.com

    + +

    https://www.foobar.com/baz?bazinga=nhecos;

    + +

    http://www.google.com

    diff --git a/test/features/#164.1.simple_autolink.md b/test/features/#164.1.simple_autolink.md new file mode 100644 index 0000000..25b9f86 --- /dev/null +++ b/test/features/#164.1.simple_autolink.md @@ -0,0 +1,11 @@ +foo.bar + +www.foobar + +www.foobar.com + +http://foobar.com + +https://www.foobar.com/baz?bazinga=nhecos; + +http://www.google.com diff --git a/test/features/#164.2.disallow_underscore_emphasis_mid_word.html b/test/features/#164.2.disallow_underscore_emphasis_mid_word.html new file mode 100644 index 0000000..e728b10 --- /dev/null +++ b/test/features/#164.2.disallow_underscore_emphasis_mid_word.html @@ -0,0 +1,18 @@ +

    this is a sentence_with_mid underscores

    + +

    this is a sentence with just_one underscore

    + +

    this should be parsed as emphasis

    + +

    this is double__underscore__mid word

    + +

    this has just__one double underscore

    + +

    this should be parsed as bold

    + +

    emphasis at end of sentence

    + +

    emphasis at line start

    + +

    multi line emphasis +yeah it is yeah

    diff --git a/test/features/#164.2.disallow_underscore_emphasis_mid_word.md b/test/features/#164.2.disallow_underscore_emphasis_mid_word.md new file mode 100644 index 0000000..1e2cd9c --- /dev/null +++ b/test/features/#164.2.disallow_underscore_emphasis_mid_word.md @@ -0,0 +1,18 @@ +this is a sentence_with_mid underscores + +this is a sentence with just_one underscore + +this _should be parsed_ as emphasis + +this is double__underscore__mid word + +this has just__one double underscore + +this __should be parsed__ as bold + +emphasis at _end of sentence_ + +_emphasis at_ line start + +multi _line emphasis +yeah it is_ yeah diff --git a/test/features/#164.3.strikethrough.html b/test/features/#164.3.strikethrough.html new file mode 100644 index 0000000..68139e4 --- /dev/null +++ b/test/features/#164.3.strikethrough.html @@ -0,0 +1,5 @@ +

    a strikethrough word

    + +

    this should~~not be parsed

    + +

    strike-through text

    diff --git a/test/features/#164.3.strikethrough.md b/test/features/#164.3.strikethrough.md new file mode 100644 index 0000000..3498b1a --- /dev/null +++ b/test/features/#164.3.strikethrough.md @@ -0,0 +1,5 @@ +a ~~strikethrough~~ word + +this should~~not be parsed + +~~strike-through text~~ diff --git a/test/features/#164.4.tasklists.html b/test/features/#164.4.tasklists.html new file mode 100644 index 0000000..6c5a6df --- /dev/null +++ b/test/features/#164.4.tasklists.html @@ -0,0 +1,10 @@ +

    my things

    + +
      +
    • foo
    • +
    • bar
    • +
    • baz
    • +
    • bazinga
    • +
    + +

    otherthings

    diff --git a/test/features/#164.4.tasklists.md b/test/features/#164.4.tasklists.md new file mode 100644 index 0000000..0054490 --- /dev/null +++ b/test/features/#164.4.tasklists.md @@ -0,0 +1,8 @@ +# my things + + - foo + - [] bar + - [ ] baz + - [x] bazinga + +otherthings diff --git a/test/features/#69.header_level_start.html b/test/features/#69.header_level_start.html new file mode 100644 index 0000000..4bf4104 --- /dev/null +++ b/test/features/#69.header_level_start.html @@ -0,0 +1,9 @@ +

    Given

    + +

    When

    + +

    Then

    + +

    foo

    + +

    bar

    diff --git a/test/features/#69.header_level_start.md b/test/features/#69.header_level_start.md new file mode 100644 index 0000000..e7d12c6 --- /dev/null +++ b/test/features/#69.header_level_start.md @@ -0,0 +1,11 @@ +#Given + +#When + +#Then + +foo +=== + +bar +--- diff --git a/test/features/autolink_and_disallow_underscores.html b/test/features/autolink_and_disallow_underscores.html new file mode 100644 index 0000000..69efe76 --- /dev/null +++ b/test/features/autolink_and_disallow_underscores.html @@ -0,0 +1 @@ +

    http://en.wikipedia.org/wiki/Tourism_in_Germany

    \ No newline at end of file diff --git a/test/features/autolink_and_disallow_underscores.md b/test/features/autolink_and_disallow_underscores.md new file mode 100644 index 0000000..799cdcf --- /dev/null +++ b/test/features/autolink_and_disallow_underscores.md @@ -0,0 +1 @@ +http://en.wikipedia.org/wiki/Tourism_in_Germany \ No newline at end of file diff --git a/test/features/disable_gh_codeblocks.html b/test/features/disable_gh_codeblocks.html new file mode 100644 index 0000000..35dc1c2 --- /dev/null +++ b/test/features/disable_gh_codeblocks.html @@ -0,0 +1,9 @@ +

    this is some text

    + +

    php +function thisThing() { +echo "some weird formatted code!"; +} +

    + +

    some other text

    diff --git a/test/features/disable_gh_codeblocks.md b/test/features/disable_gh_codeblocks.md new file mode 100644 index 0000000..8d307ff --- /dev/null +++ b/test/features/disable_gh_codeblocks.md @@ -0,0 +1,9 @@ +this is some text + +```php +function thisThing() { + echo "some weird formatted code!"; +} +``` + +some other text \ No newline at end of file diff --git a/test/features/tables/#179.parse_md_in_table_ths.html b/test/features/tables/#179.parse_md_in_table_ths.html new file mode 100644 index 0000000..e641c3a --- /dev/null +++ b/test/features/tables/#179.parse_md_in_table_ths.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + +
    foobarbaz
    100blablaaaa
    diff --git a/test/features/tables/#179.parse_md_in_table_ths.md b/test/features/tables/#179.parse_md_in_table_ths.md new file mode 100644 index 0000000..42f88d8 --- /dev/null +++ b/test/features/tables/#179.parse_md_in_table_ths.md @@ -0,0 +1,3 @@ +| *foo* | **bar** | ~~baz~~ | +|-------|---------|---------| +| 100 | blabla | aaa | diff --git a/test/features/tables/basic-alignment.html b/test/features/tables/basic-alignment.html new file mode 100644 index 0000000..6fa12e9 --- /dev/null +++ b/test/features/tables/basic-alignment.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +
    First HeaderSecond Header
    Row 1 Cell 1Row 1 Cell 2
    Row 2 Cell 1Row 2 Cell 2
    diff --git a/test/features/tables/basic-alignment.md b/test/features/tables/basic-alignment.md new file mode 100644 index 0000000..5aa9082 --- /dev/null +++ b/test/features/tables/basic-alignment.md @@ -0,0 +1,4 @@ +| First Header | Second Header | +| :------------ | :------------ | +| Row 1 Cell 1 | Row 1 Cell 2 | +| Row 2 Cell 1 | Row 2 Cell 2 | diff --git a/test/features/tables/basic.html b/test/features/tables/basic.html new file mode 100644 index 0000000..fe198b8 --- /dev/null +++ b/test/features/tables/basic.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +
    First HeaderSecond Header
    Row 1 Cell 1Row 1 Cell 2
    Row 2 Cell 1Row 2 Cell 2
    diff --git a/test/extensions/table/basic.md b/test/features/tables/basic.md similarity index 100% rename from test/extensions/table/basic.md rename to test/features/tables/basic.md diff --git a/test/features/tables/basic_with_header_ids.html b/test/features/tables/basic_with_header_ids.html new file mode 100644 index 0000000..a5c61e0 --- /dev/null +++ b/test/features/tables/basic_with_header_ids.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +
    First HeaderSecond Header
    Row 1 Cell 1Row 1 Cell 2
    Row 2 Cell 1Row 2 Cell 2
    diff --git a/test/features/tables/basic_with_header_ids.md b/test/features/tables/basic_with_header_ids.md new file mode 100644 index 0000000..f3af2ff --- /dev/null +++ b/test/features/tables/basic_with_header_ids.md @@ -0,0 +1,4 @@ +| First Header | Second Header | +| ------------- | ------------- | +| Row 1 Cell 1 | Row 1 Cell 2 | +| Row 2 Cell 1 | Row 2 Cell 2 | \ No newline at end of file diff --git a/test/features/tables/large-table-with-allignments.html b/test/features/tables/large-table-with-allignments.html new file mode 100644 index 0000000..8b758b6 --- /dev/null +++ b/test/features/tables/large-table-with-allignments.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First HeaderSecond HeaderThird HeaderFourth Header
    Row 1 Cell 1Row 1 Cell 2Row 1 Cell 3Row 1 Cell 4
    Row 2 Cell 1Row 2 Cell 2Row 2 Cell 3Row 2 Cell 4
    Row 3 Cell 1Row 3 Cell 2Row 3 Cell 3Row 3 Cell 4
    Row 4 Cell 1Row 4 Cell 2Row 4 Cell 3Row 4 Cell 4
    Row 5 Cell 1Row 5 Cell 2Row 5 Cell 3Row 5 Cell 4
    diff --git a/test/features/tables/large-table-with-allignments.md b/test/features/tables/large-table-with-allignments.md new file mode 100644 index 0000000..b3fe137 --- /dev/null +++ b/test/features/tables/large-table-with-allignments.md @@ -0,0 +1,7 @@ +| First Header | Second Header | Third Header | Fourth Header | +| :------------ |: ----------- :| ------------ :| ------------- | +| Row 1 Cell 1 | Row 1 Cell 2 | Row 1 Cell 3 | Row 1 Cell 4 | +| Row 2 Cell 1 | Row 2 Cell 2 | Row 2 Cell 3 | Row 2 Cell 4 | +| Row 3 Cell 1 | Row 3 Cell 2 | Row 3 Cell 3 | Row 3 Cell 4 | +| Row 4 Cell 1 | Row 4 Cell 2 | Row 4 Cell 3 | Row 4 Cell 4 | +| Row 5 Cell 1 | Row 5 Cell 2 | Row 5 Cell 3 | Row 5 Cell 4 | diff --git a/test/features/tables/large.html b/test/features/tables/large.html new file mode 100644 index 0000000..bfa4557 --- /dev/null +++ b/test/features/tables/large.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    First HeaderSecond HeaderThird HeaderFourth Header
    Row 1 Cell 1Row 1 Cell 2Row 1 Cell 3Row 1 Cell 4
    Row 2 Cell 1Row 2 Cell 2Row 2 Cell 3Row 2 Cell 4
    Row 3 Cell 1Row 3 Cell 2Row 3 Cell 3Row 3 Cell 4
    Row 4 Cell 1Row 4 Cell 2Row 4 Cell 3Row 4 Cell 4
    Row 5 Cell 1Row 5 Cell 2Row 5 Cell 3Row 5 Cell 4
    diff --git a/test/extensions/table/large.md b/test/features/tables/large.md similarity index 100% rename from test/extensions/table/large.md rename to test/features/tables/large.md diff --git a/test/features/tables/mixed-alignment.html b/test/features/tables/mixed-alignment.html new file mode 100644 index 0000000..bb400c4 --- /dev/null +++ b/test/features/tables/mixed-alignment.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Left-AlignedCenter-AlignedRight-Aligned
    col 3 issome wordy paragraph$1600
    col 2 iscentered$12
    zebra stripesare neat$1
    diff --git a/test/features/tables/mixed-alignment.md b/test/features/tables/mixed-alignment.md new file mode 100644 index 0000000..6504a00 --- /dev/null +++ b/test/features/tables/mixed-alignment.md @@ -0,0 +1,5 @@ +| Left-Aligned | Center-Aligned | Right-Aligned | +| :------------ |:--------------------:| -------------:| +| col 3 is | some wordy paragraph | $1600 | +| col 2 is | centered | $12 | +| zebra stripes | are neat | $1 | \ No newline at end of file diff --git a/test/features/tables/multiple-tables.html b/test/features/tables/multiple-tables.html new file mode 100644 index 0000000..7f955d1 --- /dev/null +++ b/test/features/tables/multiple-tables.html @@ -0,0 +1,43 @@ +

    Table Test

    + +

    section 1

    + + + + + + + + + + + + + + + + + + +
    header1header2header3
    Value1Value2Value3
    + +

    section 2

    + + + + + + + + + + + + + + + + + + +
    headerAheaderBheaderC
    ValueAValueBValueC
    \ No newline at end of file diff --git a/test/features/tables/multiple-tables.md b/test/features/tables/multiple-tables.md new file mode 100644 index 0000000..25bc09e --- /dev/null +++ b/test/features/tables/multiple-tables.md @@ -0,0 +1,17 @@ +Table Test +============ + +section 1 +------------ + +|header1 |header2 |header3| +|-----------|-----------|---------| +|Value1 |Value2 |Value3 | + + +section 2 +----------- + +|headerA |headerB |headerC| +|-----------|-----------|---------| +|ValueA |ValueB |ValueC | diff --git a/test/features/tables/with-equals.html b/test/features/tables/with-equals.html new file mode 100644 index 0000000..fe198b8 --- /dev/null +++ b/test/features/tables/with-equals.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +
    First HeaderSecond Header
    Row 1 Cell 1Row 1 Cell 2
    Row 2 Cell 1Row 2 Cell 2
    diff --git a/test/extensions/table/with-equals.md b/test/features/tables/with-equals.md similarity index 100% rename from test/extensions/table/with-equals.md rename to test/features/tables/with-equals.md diff --git a/test/features/tables/with-span-elements.html b/test/features/tables/with-span-elements.html new file mode 100644 index 0000000..1b4a4d1 --- /dev/null +++ b/test/features/tables/with-span-elements.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
    First HeaderSecond Header
    boldimg
    italiclink
    some codegoogle
    www.foo.comnormal
    \ No newline at end of file diff --git a/test/features/tables/with-span-elements.md b/test/features/tables/with-span-elements.md new file mode 100644 index 0000000..6a918e6 --- /dev/null +++ b/test/features/tables/with-span-elements.md @@ -0,0 +1,9 @@ +| First Header | Second Header | +| ------------- | ----------------- | +| **bold** | ![img](foo.jpg) | +| _italic_ | [link](bla.html) | +| `some code` | [google][1] | +| | normal | + + + [1]: www.google.com diff --git a/test/extensions/table/with-surroundings.html b/test/features/tables/with-surroundings.html similarity index 69% rename from test/extensions/table/with-surroundings.html rename to test/features/tables/with-surroundings.html index a8957c3..d99c181 100644 --- a/test/extensions/table/with-surroundings.html +++ b/test/features/tables/with-surroundings.html @@ -6,20 +6,20 @@ vulputate dictum. Vestibulum consequat ultricies nibh, sed tempus nisl mattis a. - - + + - - + + - - + + diff --git a/test/extensions/table/with-surroundings.md b/test/features/tables/with-surroundings.md similarity index 100% rename from test/extensions/table/with-surroundings.md rename to test/features/tables/with-surroundings.md diff --git a/test/features/tables/without-body.html b/test/features/tables/without-body.html new file mode 100644 index 0000000..4379949 --- /dev/null +++ b/test/features/tables/without-body.html @@ -0,0 +1,11 @@ +
    First Header Second Header First HeaderSecond Header

    Row 1 Cell 1

    Row 1 Cell 2

    Row 1 Cell 1Row 1 Cell 2

    Row 2 Cell 1

    Row 2 Cell 2

    Row 2 Cell 1Row 2 Cell 2
    + + + + + + + + + +
    First HeaderSecond Header
    diff --git a/test/extensions/table/without-body.md b/test/features/tables/without-body.md similarity index 100% rename from test/extensions/table/without-body.md rename to test/features/tables/without-body.md diff --git a/test/extensions/table/without-header-delimiter.html b/test/features/tables/without-header-delimiter.html similarity index 100% rename from test/extensions/table/without-header-delimiter.html rename to test/features/tables/without-header-delimiter.html diff --git a/test/extensions/table/without-header-delimiter.md b/test/features/tables/without-header-delimiter.md similarity index 100% rename from test/extensions/table/without-header-delimiter.md rename to test/features/tables/without-header-delimiter.md diff --git a/test/ghost/markdown-magic.html b/test/ghost/markdown-magic.html new file mode 100644 index 0000000..d7e74e5 --- /dev/null +++ b/test/ghost/markdown-magic.html @@ -0,0 +1,40 @@ + + +
    https://ghost.org
    +
    + +

    https://ghost.org

    + +

    Markdown Footnotes

    + +
    The quick brown fox[^1] jumped over the lazy dog[^2].
    +
    +    [^1]: Foxes are red
    +    [^2]: Dogs are usually not red
    +
    + +

    The quick brown fox[^1] jumped over the lazy dog[^2].

    + +

    Syntax Highlighting

    + +
    ```language-javascript
    +    [...]
    +    ```
    +
    + +

    Combined with Prism.js in the Ghost theme:

    + +
    // # Notifications API
    +// RESTful API for creating notifications
    +var Promise            = require('bluebird'),
    +_                  = require('lodash'),
    +canThis            = require('../permissions').canThis,
    +errors             = require('../errors'),
    +utils              = require('./utils'),
    +
    +// Holds the persistent notifications
    +notificationsStore = [],
    +// Holds the last used id
    +notificationCounter = 0,
    +notifications;
    +
    \ No newline at end of file diff --git a/test/ghost/markdown-magic.md b/test/ghost/markdown-magic.md new file mode 100644 index 0000000..59153db --- /dev/null +++ b/test/ghost/markdown-magic.md @@ -0,0 +1,43 @@ +### Automatic Links + +``` +https://ghost.org +``` + +https://ghost.org + +### Markdown Footnotes + +``` +The quick brown fox[^1] jumped over the lazy dog[^2]. + +[^1]: Foxes are red +[^2]: Dogs are usually not red +``` + +The quick brown fox[^1] jumped over the lazy dog[^2]. + + +### Syntax Highlighting + + ```language-javascript + [...] + ``` + +Combined with [Prism.js](http://prismjs.com/) in the Ghost theme: + +```language-javascript +// # Notifications API +// RESTful API for creating notifications +var Promise = require('bluebird'), + _ = require('lodash'), + canThis = require('../permissions').canThis, + errors = require('../errors'), + utils = require('./utils'), + + // Holds the persistent notifications + notificationsStore = [], + // Holds the last used id + notificationCounter = 0, + notifications; +``` \ No newline at end of file diff --git a/test/ghost/underscore.html b/test/ghost/underscore.html new file mode 100644 index 0000000..27c071b --- /dev/null +++ b/test/ghost/underscore.html @@ -0,0 +1,78 @@ +

    foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo

    + +

    baz_bar_foo

    + +

    baz_bar_foo

    + +

    baz_bar_foo

    + +

    baz bar foo baz_bar_foo foo bar baz and foo

    + +

    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo

    + +

    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo

    + +
    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo
    +
    + +
    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo
    +
    + +
    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo
    + +
    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo
    + +
    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo
    + + + +

    foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo

    + +

    foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo

    + +

    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo

    + +

    foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo

    + +

    foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo

    + +
      +
    1. foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo
    2. +
    3. foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo
    4. +
    + +
    +

    blockquote foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo

    +
    + +
      +
    • foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo
    • +
    • foo_bar_baz foo_bar_baz_bar_foo foo_bar baz_bar baz_foo
    • +
    + +
    + +

    http://en.wikipedia.org/wiki/Tourism_in_Germany

    + +

    an example

    + +

    Another example of a link

    + +

    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo

    + + + +

    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo

    + +

    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo

    + +

    http://myurl.com/foo_bar_baz_bar_foo

    + +

    http://myurl.com/foo_bar_baz_bar_foo

    + +

    italics.

    + +

    italics .

    diff --git a/test/ghost/underscore.md b/test/ghost/underscore.md new file mode 100644 index 0000000..23d0b38 --- /dev/null +++ b/test/ghost/underscore.md @@ -0,0 +1,76 @@ +foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + +_baz_bar_foo_ + +__baz_bar_foo__ + +___baz_bar_foo___ + +baz bar foo _baz_bar_foo foo bar baz_ and foo + +foo\_bar\_baz foo\_bar\_baz\_bar\_foo \_foo\_bar baz\_bar\_ baz\_foo + +`foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo` + + + foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + + +```html +foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo +``` + +
    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo
    + +
    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo
    + +
    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo
    + + + +[foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo](http://myurl.com/foo_bar_baz_bar_foo) + +foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + +foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + +foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo +----- + +### foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + +1. foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo +2. foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + +> blockquote foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + +* foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo +* foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + +------- + +http://en.wikipedia.org/wiki/Tourism_in_Germany + +[an example] [wiki] + +Another [example][wiki] of a link + +[wiki]: http://en.wikipedia.org/wiki/Tourism_in_Germany + +

    foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo

    + + +foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo + +![foo_bar_baz foo_bar_baz_bar_foo _foo_bar baz_bar_ baz_foo](http://myurl.com/foo_bar_baz_bar_foo) + +http://myurl.com/foo_bar_baz_bar_foo + + + +_italics_. + +_italics_ . diff --git a/test/issues/#107.inner_underscore_parse_to_block.html b/test/issues/#107.inner_underscore_parse_to_block.html new file mode 100644 index 0000000..b47ea95 --- /dev/null +++ b/test/issues/#107.inner_underscore_parse_to_block.html @@ -0,0 +1,11 @@ +

    escaped word_with_underscores

    + +

    escaped word__with__double underscores

    + +

    escaped word_with_single italic underscore

    + +

    escaped word*with*asterixs

    + +

    escaped word**with**asterixs

    + +

    escaped word*with*bold asterixs

    diff --git a/test/issues/#107.inner_underscore_parse_to_block.md b/test/issues/#107.inner_underscore_parse_to_block.md new file mode 100644 index 0000000..8d22521 --- /dev/null +++ b/test/issues/#107.inner_underscore_parse_to_block.md @@ -0,0 +1,11 @@ +escaped word\_with\_underscores + +escaped word\_\_with\_\_double underscores + +escaped word_\_with\__single italic underscore + +escaped word\*with*asterixs + +escaped word\*\*with\*\*asterixs + +escaped word**\*with\***bold asterixs diff --git a/test/issues/#142.odd_behaviour_for_multiple_consecutive_lists.html b/test/issues/#142.odd_behaviour_for_multiple_consecutive_lists.html new file mode 100644 index 0000000..49c9ca4 --- /dev/null +++ b/test/issues/#142.odd_behaviour_for_multiple_consecutive_lists.html @@ -0,0 +1,12 @@ +
      +
    • Item 1
    • +
    • Item 2
    • +
    +
      +
    1. Item 1
    2. +
    3. Item 2
    4. +
    +
      +
    • Item 1
    • +
    • Item 2
    • +
    diff --git a/test/issues/#142.odd_behaviour_for_multiple_consecutive_lists.md b/test/issues/#142.odd_behaviour_for_multiple_consecutive_lists.md new file mode 100644 index 0000000..4621a36 --- /dev/null +++ b/test/issues/#142.odd_behaviour_for_multiple_consecutive_lists.md @@ -0,0 +1,8 @@ +* Item 1 +* Item 2 + +1. Item 1 +2. Item 2 + +- Item 1 +- Item 2 diff --git a/test/issues/#150.hyphens are getting removed.html b/test/issues/#150.hyphens are getting removed.html new file mode 100644 index 0000000..8f9d2e5 --- /dev/null +++ b/test/issues/#150.hyphens are getting removed.html @@ -0,0 +1 @@ +

    2015-10-04

    \ No newline at end of file diff --git a/test/issues/#150.hyphens are getting removed.md b/test/issues/#150.hyphens are getting removed.md new file mode 100644 index 0000000..d0d6dda --- /dev/null +++ b/test/issues/#150.hyphens are getting removed.md @@ -0,0 +1 @@ +2015-10-04 diff --git a/test/issues/#183.gh_code_blocks_within_lists_do_not_render_properly.html b/test/issues/#183.gh_code_blocks_within_lists_do_not_render_properly.html new file mode 100644 index 0000000..d3141bc --- /dev/null +++ b/test/issues/#183.gh_code_blocks_within_lists_do_not_render_properly.html @@ -0,0 +1,16 @@ +
      +
    1. +

      Hi, I am a thing

      + +
      $ git clone thing.git
      +
      +dfgdfg
      +
    2. +
    3. +

      I am another thing!

      + +
      $ git clone other-thing.git
      +
      +foobar
      +
    4. +
    \ No newline at end of file diff --git a/test/issues/#183.gh_code_blocks_within_lists_do_not_render_properly.md b/test/issues/#183.gh_code_blocks_within_lists_do_not_render_properly.md new file mode 100644 index 0000000..7c7e0b9 --- /dev/null +++ b/test/issues/#183.gh_code_blocks_within_lists_do_not_render_properly.md @@ -0,0 +1,17 @@ +1. Hi, I am a thing + + ```sh + + $ git clone thing.git + + dfgdfg + ``` + +1. I am another thing! + + ```sh + + $ git clone other-thing.git + + foobar + ``` diff --git a/test/issues/#83.parsed_text_links_with_underscores.html b/test/issues/#83.parsed_text_links_with_underscores.html new file mode 100644 index 0000000..892e412 --- /dev/null +++ b/test/issues/#83.parsed_text_links_with_underscores.html @@ -0,0 +1,5 @@ +

    plain text link http://test.com/this_has/one.html with underscores

    + +

    legit·word_with·1·underscore

    + +

    a wordwith2underscores (gets em)

    diff --git a/test/issues/#83.parsed_text_links_with_underscores.md b/test/issues/#83.parsed_text_links_with_underscores.md new file mode 100644 index 0000000..e2118ed --- /dev/null +++ b/test/issues/#83.parsed_text_links_with_underscores.md @@ -0,0 +1,5 @@ +plain text link http://test.com/this_has/one.html with underscores + +legit·word_with·1·underscore + +a word_with_2underscores (gets em) diff --git a/test/issues/#96.Underscores_in_links.html b/test/issues/#96.Underscores_in_links.html new file mode 100644 index 0000000..273dcb9 --- /dev/null +++ b/test/issues/#96.Underscores_in_links.html @@ -0,0 +1,3 @@ +

    this is a underscore_test my cat

    + +

    another my cat underscore_test bla

    diff --git a/test/issues/#96.Underscores_in_links.md b/test/issues/#96.Underscores_in_links.md new file mode 100644 index 0000000..9b4ba0d --- /dev/null +++ b/test/issues/#96.Underscores_in_links.md @@ -0,0 +1,3 @@ +this is a underscore_test ![my cat](http://myserver.com/my_kitty.jpg) + +another ![my cat](http://myserver.com/my_kitty.jpg) underscore_test bla diff --git a/test/karlcow/2-paragraphs-hard-return-spaces.html b/test/karlcow/2-paragraphs-hard-return-spaces.html new file mode 100644 index 0000000..ed211e1 --- /dev/null +++ b/test/karlcow/2-paragraphs-hard-return-spaces.html @@ -0,0 +1,5 @@ +

    This is a first paragraph, +on multiple lines.

    + +

    This is a second paragraph. +There are spaces in between the two.

    \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-hard-return-spaces.md b/test/karlcow/2-paragraphs-hard-return-spaces.md new file mode 100644 index 0000000..77ecf1e --- /dev/null +++ b/test/karlcow/2-paragraphs-hard-return-spaces.md @@ -0,0 +1,5 @@ +This is a first paragraph, +on multiple lines. + +This is a second paragraph. +There are spaces in between the two. \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-hard-return.html b/test/karlcow/2-paragraphs-hard-return.html new file mode 100644 index 0000000..5da1c69 --- /dev/null +++ b/test/karlcow/2-paragraphs-hard-return.html @@ -0,0 +1,5 @@ +

    This is a first paragraph, +on multiple lines.

    + +

    This is a second paragraph +which has multiple lines too.

    \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-hard-return.md b/test/karlcow/2-paragraphs-hard-return.md new file mode 100644 index 0000000..7e103ad --- /dev/null +++ b/test/karlcow/2-paragraphs-hard-return.md @@ -0,0 +1,5 @@ +This is a first paragraph, +on multiple lines. + +This is a second paragraph +which has multiple lines too. \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-line-returns.html b/test/karlcow/2-paragraphs-line-returns.html new file mode 100644 index 0000000..89f0e94 --- /dev/null +++ b/test/karlcow/2-paragraphs-line-returns.html @@ -0,0 +1,3 @@ +

    A first paragraph.

    + +

    A second paragraph after 3 CR (carriage return).

    \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-line-returns.md b/test/karlcow/2-paragraphs-line-returns.md new file mode 100644 index 0000000..6eefed1 --- /dev/null +++ b/test/karlcow/2-paragraphs-line-returns.md @@ -0,0 +1,5 @@ +A first paragraph. + + + +A second paragraph after 3 CR (carriage return). \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-line-spaces.html b/test/karlcow/2-paragraphs-line-spaces.html new file mode 100644 index 0000000..39270cc --- /dev/null +++ b/test/karlcow/2-paragraphs-line-spaces.html @@ -0,0 +1,3 @@ +

    This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph on 1 line.

    + +

    A few spaces and a new long long long long long long long long long long long long long long long long paragraph on 1 line.

    \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-line-spaces.md b/test/karlcow/2-paragraphs-line-spaces.md new file mode 100644 index 0000000..59b9c3c --- /dev/null +++ b/test/karlcow/2-paragraphs-line-spaces.md @@ -0,0 +1,3 @@ +This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph on 1 line. + +A few spaces and a new long long long long long long long long long long long long long long long long paragraph on 1 line. \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-line-tab.html b/test/karlcow/2-paragraphs-line-tab.html new file mode 100644 index 0000000..6ba5a11 --- /dev/null +++ b/test/karlcow/2-paragraphs-line-tab.html @@ -0,0 +1,3 @@ +

    This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph on 1 line.

    + +

    1 tab to separate them and a new long long long long long long long long long long long long long long long long paragraph on 1 line.

    \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-line-tab.md b/test/karlcow/2-paragraphs-line-tab.md new file mode 100644 index 0000000..9dcc229 --- /dev/null +++ b/test/karlcow/2-paragraphs-line-tab.md @@ -0,0 +1,3 @@ +This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph on 1 line. + +1 tab to separate them and a new long long long long long long long long long long long long long long long long paragraph on 1 line. \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-line.html b/test/karlcow/2-paragraphs-line.html new file mode 100644 index 0000000..8812518 --- /dev/null +++ b/test/karlcow/2-paragraphs-line.html @@ -0,0 +1,3 @@ +

    This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph on 1 line.

    + +

    A new long long long long long long long long long long long long long long long long paragraph on 1 line.

    \ No newline at end of file diff --git a/test/karlcow/2-paragraphs-line.md b/test/karlcow/2-paragraphs-line.md new file mode 100644 index 0000000..4cff3ed --- /dev/null +++ b/test/karlcow/2-paragraphs-line.md @@ -0,0 +1,3 @@ +This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph on 1 line. + +A new long long long long long long long long long long long long long long long long paragraph on 1 line. \ No newline at end of file diff --git a/test/karlcow/EOL-CR+LF.html b/test/karlcow/EOL-CR+LF.html new file mode 100644 index 0000000..c236b1d --- /dev/null +++ b/test/karlcow/EOL-CR+LF.html @@ -0,0 +1,5 @@ +

    These lines all end with end of line (EOL) sequences.

    + +

    Seriously, they really do.

    + +

    If you don't believe me: HEX EDIT!

    \ No newline at end of file diff --git a/test/karlcow/EOL-CR+LF.md b/test/karlcow/EOL-CR+LF.md new file mode 100644 index 0000000..15cb86e --- /dev/null +++ b/test/karlcow/EOL-CR+LF.md @@ -0,0 +1,6 @@ +These lines all end with end of line (EOL) sequences. + +Seriously, they really do. + +If you don't believe me: HEX EDIT! + diff --git a/test/karlcow/EOL-CR.html b/test/karlcow/EOL-CR.html new file mode 100644 index 0000000..36a489b --- /dev/null +++ b/test/karlcow/EOL-CR.html @@ -0,0 +1 @@ +

    These lines all end with end of line (EOL) sequences.

    Seriously, they really do.

    If you don't believe me: HEX EDIT!

    \ No newline at end of file diff --git a/test/karlcow/EOL-CR.md b/test/karlcow/EOL-CR.md new file mode 100644 index 0000000..f0a17c8 --- /dev/null +++ b/test/karlcow/EOL-CR.md @@ -0,0 +1 @@ +These lines all end with end of line (EOL) sequences. Seriously, they really do. If you don't believe me: HEX EDIT! \ No newline at end of file diff --git a/test/karlcow/EOL-LF.html b/test/karlcow/EOL-LF.html new file mode 100644 index 0000000..c236b1d --- /dev/null +++ b/test/karlcow/EOL-LF.html @@ -0,0 +1,5 @@ +

    These lines all end with end of line (EOL) sequences.

    + +

    Seriously, they really do.

    + +

    If you don't believe me: HEX EDIT!

    \ No newline at end of file diff --git a/test/karlcow/EOL-LF.md b/test/karlcow/EOL-LF.md new file mode 100644 index 0000000..15cb86e --- /dev/null +++ b/test/karlcow/EOL-LF.md @@ -0,0 +1,6 @@ +These lines all end with end of line (EOL) sequences. + +Seriously, they really do. + +If you don't believe me: HEX EDIT! + diff --git a/test/karlcow/ampersand-text-flow.html b/test/karlcow/ampersand-text-flow.html new file mode 100644 index 0000000..0f2eaf3 --- /dev/null +++ b/test/karlcow/ampersand-text-flow.html @@ -0,0 +1 @@ +

    An ampersand & in the text flow is escaped as an html entity.

    \ No newline at end of file diff --git a/test/karlcow/ampersand-text-flow.md b/test/karlcow/ampersand-text-flow.md new file mode 100644 index 0000000..fb83563 --- /dev/null +++ b/test/karlcow/ampersand-text-flow.md @@ -0,0 +1 @@ +An ampersand & in the text flow is escaped as an html entity. \ No newline at end of file diff --git a/test/karlcow/ampersand-uri.html b/test/karlcow/ampersand-uri.html new file mode 100644 index 0000000..de4b210 --- /dev/null +++ b/test/karlcow/ampersand-uri.html @@ -0,0 +1 @@ +

    There is an ampersand in the URI.

    \ No newline at end of file diff --git a/test/karlcow/ampersand-uri.md b/test/karlcow/ampersand-uri.md new file mode 100644 index 0000000..499635e --- /dev/null +++ b/test/karlcow/ampersand-uri.md @@ -0,0 +1 @@ +There is an [ampersand](http://validator.w3.org/check?uri=http://www.w3.org/&verbose=1) in the URI. \ No newline at end of file diff --git a/test/karlcow/asterisk-near-text.html b/test/karlcow/asterisk-near-text.html new file mode 100644 index 0000000..aa442c3 --- /dev/null +++ b/test/karlcow/asterisk-near-text.html @@ -0,0 +1 @@ +

    This is *an asterisk which should stay as is.

    \ No newline at end of file diff --git a/test/karlcow/asterisk-near-text.md b/test/karlcow/asterisk-near-text.md new file mode 100644 index 0000000..b27634d --- /dev/null +++ b/test/karlcow/asterisk-near-text.md @@ -0,0 +1 @@ +This is \*an asterisk which should stay as is. \ No newline at end of file diff --git a/test/karlcow/asterisk.html b/test/karlcow/asterisk.html new file mode 100644 index 0000000..b6c93a8 --- /dev/null +++ b/test/karlcow/asterisk.html @@ -0,0 +1 @@ +

    This is * an asterisk which should stay as is.

    \ No newline at end of file diff --git a/test/karlcow/asterisk.md b/test/karlcow/asterisk.md new file mode 100644 index 0000000..ccbbc23 --- /dev/null +++ b/test/karlcow/asterisk.md @@ -0,0 +1 @@ +This is * an asterisk which should stay as is. \ No newline at end of file diff --git a/test/karlcow/backslash-escape.html b/test/karlcow/backslash-escape.html new file mode 100644 index 0000000..d69d385 --- /dev/null +++ b/test/karlcow/backslash-escape.html @@ -0,0 +1,12 @@ +

    \ backslash +` backtick +* asterisk +_ underscore +{} curly braces +[] square brackets +() parentheses +# hash mark ++ plus sign +- minus sign (hyphen) +. dot +! exclamation mark

    \ No newline at end of file diff --git a/test/karlcow/backslash-escape.md b/test/karlcow/backslash-escape.md new file mode 100644 index 0000000..306aca2 --- /dev/null +++ b/test/karlcow/backslash-escape.md @@ -0,0 +1,12 @@ +\\ backslash +\` backtick +\* asterisk +\_ underscore +\{\} curly braces +\[\] square brackets +\(\) parentheses +\# hash mark +\+ plus sign +\- minus sign (hyphen) +\. dot +\! exclamation mark \ No newline at end of file diff --git a/test/karlcow/blockquote-added-markup.html b/test/karlcow/blockquote-added-markup.html new file mode 100644 index 0000000..375dbe8 --- /dev/null +++ b/test/karlcow/blockquote-added-markup.html @@ -0,0 +1,5 @@ +
    +

    heading level 1

    + +

    paragraph

    +
    diff --git a/test/karlcow/blockquote-added-markup.md b/test/karlcow/blockquote-added-markup.md new file mode 100644 index 0000000..b60a049 --- /dev/null +++ b/test/karlcow/blockquote-added-markup.md @@ -0,0 +1,3 @@ +> # heading level 1 +> +> paragraph \ No newline at end of file diff --git a/test/karlcow/blockquote-line-2-paragraphs.html b/test/karlcow/blockquote-line-2-paragraphs.html new file mode 100644 index 0000000..9cb7059 --- /dev/null +++ b/test/karlcow/blockquote-line-2-paragraphs.html @@ -0,0 +1,5 @@ +
    +

    A blockquote with a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long line.

    + +

    and a second very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long line.

    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-line-2-paragraphs.md b/test/karlcow/blockquote-line-2-paragraphs.md new file mode 100644 index 0000000..46358c0 --- /dev/null +++ b/test/karlcow/blockquote-line-2-paragraphs.md @@ -0,0 +1,3 @@ +>A blockquote with a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long line. + +>and a second very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long line. \ No newline at end of file diff --git a/test/karlcow/blockquote-line.html b/test/karlcow/blockquote-line.html new file mode 100644 index 0000000..41451af --- /dev/null +++ b/test/karlcow/blockquote-line.html @@ -0,0 +1,3 @@ +
    +

    This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph in a blockquote.

    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-line.md b/test/karlcow/blockquote-line.md new file mode 100644 index 0000000..23990a3 --- /dev/null +++ b/test/karlcow/blockquote-line.md @@ -0,0 +1 @@ +>This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph in a blockquote. \ No newline at end of file diff --git a/test/karlcow/blockquote-multiline-1-space-begin.html b/test/karlcow/blockquote-multiline-1-space-begin.html new file mode 100644 index 0000000..6282d21 --- /dev/null +++ b/test/karlcow/blockquote-multiline-1-space-begin.html @@ -0,0 +1,5 @@ +
    +

    A blockquote +on multiple lines +like this.

    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-multiline-1-space-begin.md b/test/karlcow/blockquote-multiline-1-space-begin.md new file mode 100644 index 0000000..eafd549 --- /dev/null +++ b/test/karlcow/blockquote-multiline-1-space-begin.md @@ -0,0 +1,3 @@ +> A blockquote +> on multiple lines +> like this. \ No newline at end of file diff --git a/test/karlcow/blockquote-multiline-1-space-end.html b/test/karlcow/blockquote-multiline-1-space-end.html new file mode 100644 index 0000000..82907e2 --- /dev/null +++ b/test/karlcow/blockquote-multiline-1-space-end.html @@ -0,0 +1,5 @@ +
    +

    A blockquote +on multiple lines +like this.

    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-multiline-1-space-end.md b/test/karlcow/blockquote-multiline-1-space-end.md new file mode 100644 index 0000000..014617a --- /dev/null +++ b/test/karlcow/blockquote-multiline-1-space-end.md @@ -0,0 +1,3 @@ +>A blockquote +>on multiple lines +>like this. \ No newline at end of file diff --git a/test/karlcow/blockquote-multiline-2-paragraphs.html b/test/karlcow/blockquote-multiline-2-paragraphs.html new file mode 100644 index 0000000..1339eee --- /dev/null +++ b/test/karlcow/blockquote-multiline-2-paragraphs.html @@ -0,0 +1,8 @@ +
    +

    A blockquote +on multiple lines +like this.

    + +

    But it has +two paragraphs.

    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-multiline-2-paragraphs.md b/test/karlcow/blockquote-multiline-2-paragraphs.md new file mode 100644 index 0000000..0af137d --- /dev/null +++ b/test/karlcow/blockquote-multiline-2-paragraphs.md @@ -0,0 +1,6 @@ +>A blockquote +>on multiple lines +>like this. +> +>But it has +>two paragraphs. \ No newline at end of file diff --git a/test/karlcow/blockquote-multiline.html b/test/karlcow/blockquote-multiline.html new file mode 100644 index 0000000..18126d4 --- /dev/null +++ b/test/karlcow/blockquote-multiline.html @@ -0,0 +1,5 @@ +
    +

    A blockquote +on multiple lines +like this

    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-multiline.md b/test/karlcow/blockquote-multiline.md new file mode 100644 index 0000000..283f95d --- /dev/null +++ b/test/karlcow/blockquote-multiline.md @@ -0,0 +1,3 @@ +>A blockquote +>on multiple lines +>like this \ No newline at end of file diff --git a/test/karlcow/blockquote-nested-multiplereturn-level1.html b/test/karlcow/blockquote-nested-multiplereturn-level1.html new file mode 100644 index 0000000..37d039d --- /dev/null +++ b/test/karlcow/blockquote-nested-multiplereturn-level1.html @@ -0,0 +1,9 @@ +
    +

    This is the first level of quoting.

    + +
    +

    This is nested blockquote.

    +
    + +

    Back to the first level.

    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-nested-multiplereturn-level1.md b/test/karlcow/blockquote-nested-multiplereturn-level1.md new file mode 100644 index 0000000..8b2530f --- /dev/null +++ b/test/karlcow/blockquote-nested-multiplereturn-level1.md @@ -0,0 +1,5 @@ +> This is the first level of quoting. +> +> > This is nested blockquote. +> +> Back to the first level. diff --git a/test/karlcow/blockquote-nested-multiplereturn.html b/test/karlcow/blockquote-nested-multiplereturn.html new file mode 100644 index 0000000..5b0d801 --- /dev/null +++ b/test/karlcow/blockquote-nested-multiplereturn.html @@ -0,0 +1,7 @@ +
    +

    This is the first level of quoting.

    + +
    +

    This is nested blockquote.

    +
    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-nested-multiplereturn.md b/test/karlcow/blockquote-nested-multiplereturn.md new file mode 100644 index 0000000..4a8202d --- /dev/null +++ b/test/karlcow/blockquote-nested-multiplereturn.md @@ -0,0 +1,3 @@ +> This is the first level of quoting. +> +> > This is nested blockquote. \ No newline at end of file diff --git a/test/karlcow/blockquote-nested-return-level1.html b/test/karlcow/blockquote-nested-return-level1.html new file mode 100644 index 0000000..d37d55f --- /dev/null +++ b/test/karlcow/blockquote-nested-return-level1.html @@ -0,0 +1,8 @@ +
    +

    This is the first level of quoting.

    + +
    +

    This is nested blockquote. +Back to the first level.

    +
    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-nested-return-level1.md b/test/karlcow/blockquote-nested-return-level1.md new file mode 100644 index 0000000..e01158b --- /dev/null +++ b/test/karlcow/blockquote-nested-return-level1.md @@ -0,0 +1,3 @@ +> This is the first level of quoting. +> > This is nested blockquote. +> Back to the first level. diff --git a/test/karlcow/blockquote-nested.html b/test/karlcow/blockquote-nested.html new file mode 100644 index 0000000..5b0d801 --- /dev/null +++ b/test/karlcow/blockquote-nested.html @@ -0,0 +1,7 @@ +
    +

    This is the first level of quoting.

    + +
    +

    This is nested blockquote.

    +
    +
    \ No newline at end of file diff --git a/test/karlcow/blockquote-nested.md b/test/karlcow/blockquote-nested.md new file mode 100644 index 0000000..739ac21 --- /dev/null +++ b/test/karlcow/blockquote-nested.md @@ -0,0 +1,2 @@ +> This is the first level of quoting. +> > This is nested blockquote. diff --git a/test/karlcow/code-1-tab.html b/test/karlcow/code-1-tab.html new file mode 100644 index 0000000..9b8bb7a --- /dev/null +++ b/test/karlcow/code-1-tab.html @@ -0,0 +1,3 @@ +
    10 PRINT HELLO INFINITE
    +20 GOTO 10
    +
    \ No newline at end of file diff --git a/test/karlcow/code-1-tab.md b/test/karlcow/code-1-tab.md new file mode 100644 index 0000000..a314307 --- /dev/null +++ b/test/karlcow/code-1-tab.md @@ -0,0 +1,2 @@ + 10 PRINT HELLO INFINITE + 20 GOTO 10 \ No newline at end of file diff --git a/test/karlcow/code-4-spaces-escaping.html b/test/karlcow/code-4-spaces-escaping.html new file mode 100644 index 0000000..6d9fa87 --- /dev/null +++ b/test/karlcow/code-4-spaces-escaping.html @@ -0,0 +1,3 @@ +
    10 PRINT < > &
    +20 GOTO 10
    +
    \ No newline at end of file diff --git a/test/karlcow/code-4-spaces-escaping.md b/test/karlcow/code-4-spaces-escaping.md new file mode 100644 index 0000000..2edbd4e --- /dev/null +++ b/test/karlcow/code-4-spaces-escaping.md @@ -0,0 +1,2 @@ + 10 PRINT < > & + 20 GOTO 10 \ No newline at end of file diff --git a/test/karlcow/code-4-spaces.html b/test/karlcow/code-4-spaces.html new file mode 100644 index 0000000..9b8bb7a --- /dev/null +++ b/test/karlcow/code-4-spaces.html @@ -0,0 +1,3 @@ +
    10 PRINT HELLO INFINITE
    +20 GOTO 10
    +
    \ No newline at end of file diff --git a/test/karlcow/code-4-spaces.md b/test/karlcow/code-4-spaces.md new file mode 100644 index 0000000..e3b6e6d --- /dev/null +++ b/test/karlcow/code-4-spaces.md @@ -0,0 +1,2 @@ + 10 PRINT HELLO INFINITE + 20 GOTO 10 \ No newline at end of file diff --git a/test/karlcow/em-middle-word.html b/test/karlcow/em-middle-word.html new file mode 100644 index 0000000..74f7f90 --- /dev/null +++ b/test/karlcow/em-middle-word.html @@ -0,0 +1 @@ +

    asterisks

    \ No newline at end of file diff --git a/test/karlcow/em-middle-word.md b/test/karlcow/em-middle-word.md new file mode 100644 index 0000000..0935359 --- /dev/null +++ b/test/karlcow/em-middle-word.md @@ -0,0 +1 @@ +as*te*risks \ No newline at end of file diff --git a/test/karlcow/em-star.html b/test/karlcow/em-star.html new file mode 100644 index 0000000..d35dd53 --- /dev/null +++ b/test/karlcow/em-star.html @@ -0,0 +1 @@ +

    single asterisks

    \ No newline at end of file diff --git a/test/karlcow/em-star.md b/test/karlcow/em-star.md new file mode 100644 index 0000000..ddd8676 --- /dev/null +++ b/test/karlcow/em-star.md @@ -0,0 +1 @@ +*single asterisks* \ No newline at end of file diff --git a/test/karlcow/em-underscore.html b/test/karlcow/em-underscore.html new file mode 100644 index 0000000..2627bde --- /dev/null +++ b/test/karlcow/em-underscore.html @@ -0,0 +1 @@ +

    single underscores

    \ No newline at end of file diff --git a/test/karlcow/em-underscore.md b/test/karlcow/em-underscore.md new file mode 100644 index 0000000..155bb0e --- /dev/null +++ b/test/karlcow/em-underscore.md @@ -0,0 +1 @@ +_single underscores_ \ No newline at end of file diff --git a/test/karlcow/entities-text-flow.html b/test/karlcow/entities-text-flow.html new file mode 100644 index 0000000..6924fea --- /dev/null +++ b/test/karlcow/entities-text-flow.html @@ -0,0 +1 @@ +

    HTML entities are written using ampersand notation: ©

    \ No newline at end of file diff --git a/test/karlcow/entities-text-flow.md b/test/karlcow/entities-text-flow.md new file mode 100644 index 0000000..7e685ea --- /dev/null +++ b/test/karlcow/entities-text-flow.md @@ -0,0 +1 @@ +HTML entities are written using ampersand notation: © \ No newline at end of file diff --git a/test/karlcow/header-level1-equal-underlined.html b/test/karlcow/header-level1-equal-underlined.html new file mode 100644 index 0000000..af0c276 --- /dev/null +++ b/test/karlcow/header-level1-equal-underlined.html @@ -0,0 +1 @@ +

    This is an H1

    \ No newline at end of file diff --git a/test/karlcow/header-level1-equal-underlined.md b/test/karlcow/header-level1-equal-underlined.md new file mode 100644 index 0000000..f18b949 --- /dev/null +++ b/test/karlcow/header-level1-equal-underlined.md @@ -0,0 +1,2 @@ +This is an H1 +============= \ No newline at end of file diff --git a/test/karlcow/header-level1-hash-sign-closed.html b/test/karlcow/header-level1-hash-sign-closed.html new file mode 100644 index 0000000..af0c276 --- /dev/null +++ b/test/karlcow/header-level1-hash-sign-closed.html @@ -0,0 +1 @@ +

    This is an H1

    \ No newline at end of file diff --git a/test/karlcow/header-level1-hash-sign-closed.md b/test/karlcow/header-level1-hash-sign-closed.md new file mode 100644 index 0000000..147d59b --- /dev/null +++ b/test/karlcow/header-level1-hash-sign-closed.md @@ -0,0 +1 @@ +# This is an H1 # \ No newline at end of file diff --git a/test/karlcow/header-level1-hash-sign-trailing-1-space.html b/test/karlcow/header-level1-hash-sign-trailing-1-space.html new file mode 100644 index 0000000..1b48fc2 --- /dev/null +++ b/test/karlcow/header-level1-hash-sign-trailing-1-space.html @@ -0,0 +1 @@ +

    # This is an H1

    \ No newline at end of file diff --git a/test/karlcow/header-level1-hash-sign-trailing-1-space.md b/test/karlcow/header-level1-hash-sign-trailing-1-space.md new file mode 100644 index 0000000..b999b38 --- /dev/null +++ b/test/karlcow/header-level1-hash-sign-trailing-1-space.md @@ -0,0 +1 @@ + # This is an H1 \ No newline at end of file diff --git a/test/karlcow/header-level1-hash-sign-trailing-2-spaces.html b/test/karlcow/header-level1-hash-sign-trailing-2-spaces.html new file mode 100644 index 0000000..797d31c --- /dev/null +++ b/test/karlcow/header-level1-hash-sign-trailing-2-spaces.html @@ -0,0 +1,3 @@ +

    this is an h1 with two trailing spaces

    + +

    A new paragraph.

    \ No newline at end of file diff --git a/test/karlcow/header-level1-hash-sign-trailing-2-spaces.md b/test/karlcow/header-level1-hash-sign-trailing-2-spaces.md new file mode 100644 index 0000000..9cdcedf --- /dev/null +++ b/test/karlcow/header-level1-hash-sign-trailing-2-spaces.md @@ -0,0 +1,2 @@ +# this is an h1 with two trailing spaces +A new paragraph. \ No newline at end of file diff --git a/test/karlcow/header-level1-hash-sign.html b/test/karlcow/header-level1-hash-sign.html new file mode 100644 index 0000000..af0c276 --- /dev/null +++ b/test/karlcow/header-level1-hash-sign.html @@ -0,0 +1 @@ +

    This is an H1

    \ No newline at end of file diff --git a/test/karlcow/header-level1-hash-sign.md b/test/karlcow/header-level1-hash-sign.md new file mode 100644 index 0000000..f6a39e1 --- /dev/null +++ b/test/karlcow/header-level1-hash-sign.md @@ -0,0 +1 @@ +# This is an H1 \ No newline at end of file diff --git a/test/karlcow/header-level2-dash-underlined.html b/test/karlcow/header-level2-dash-underlined.html new file mode 100644 index 0000000..2f4138b --- /dev/null +++ b/test/karlcow/header-level2-dash-underlined.html @@ -0,0 +1 @@ +

    This is an H2

    \ No newline at end of file diff --git a/test/karlcow/header-level2-dash-underlined.md b/test/karlcow/header-level2-dash-underlined.md new file mode 100644 index 0000000..4564336 --- /dev/null +++ b/test/karlcow/header-level2-dash-underlined.md @@ -0,0 +1,2 @@ +This is an H2 +------------- \ No newline at end of file diff --git a/test/karlcow/header-level2-hash-sign-closed.html b/test/karlcow/header-level2-hash-sign-closed.html new file mode 100644 index 0000000..2f4138b --- /dev/null +++ b/test/karlcow/header-level2-hash-sign-closed.html @@ -0,0 +1 @@ +

    This is an H2

    \ No newline at end of file diff --git a/test/karlcow/header-level2-hash-sign-closed.md b/test/karlcow/header-level2-hash-sign-closed.md new file mode 100644 index 0000000..b84a1de --- /dev/null +++ b/test/karlcow/header-level2-hash-sign-closed.md @@ -0,0 +1 @@ +## This is an H2 ## \ No newline at end of file diff --git a/test/karlcow/header-level2-hash-sign.html b/test/karlcow/header-level2-hash-sign.html new file mode 100644 index 0000000..2f4138b --- /dev/null +++ b/test/karlcow/header-level2-hash-sign.html @@ -0,0 +1 @@ +

    This is an H2

    \ No newline at end of file diff --git a/test/karlcow/header-level2-hash-sign.md b/test/karlcow/header-level2-hash-sign.md new file mode 100644 index 0000000..6a93c6b --- /dev/null +++ b/test/karlcow/header-level2-hash-sign.md @@ -0,0 +1 @@ +## This is an H2 \ No newline at end of file diff --git a/test/karlcow/header-level3-hash-sign-closed.html b/test/karlcow/header-level3-hash-sign-closed.html new file mode 100644 index 0000000..a9d3ba9 --- /dev/null +++ b/test/karlcow/header-level3-hash-sign-closed.html @@ -0,0 +1 @@ +

    This is an H3

    \ No newline at end of file diff --git a/test/karlcow/header-level3-hash-sign-closed.md b/test/karlcow/header-level3-hash-sign-closed.md new file mode 100644 index 0000000..7d790cf --- /dev/null +++ b/test/karlcow/header-level3-hash-sign-closed.md @@ -0,0 +1 @@ +### This is an H3 ### \ No newline at end of file diff --git a/test/karlcow/header-level3-hash-sign.html b/test/karlcow/header-level3-hash-sign.html new file mode 100644 index 0000000..a9d3ba9 --- /dev/null +++ b/test/karlcow/header-level3-hash-sign.html @@ -0,0 +1 @@ +

    This is an H3

    \ No newline at end of file diff --git a/test/karlcow/header-level3-hash-sign.md b/test/karlcow/header-level3-hash-sign.md new file mode 100644 index 0000000..70c6d10 --- /dev/null +++ b/test/karlcow/header-level3-hash-sign.md @@ -0,0 +1 @@ +### This is an H3 \ No newline at end of file diff --git a/test/karlcow/header-level4-hash-sign-closed.html b/test/karlcow/header-level4-hash-sign-closed.html new file mode 100644 index 0000000..1c0f3d6 --- /dev/null +++ b/test/karlcow/header-level4-hash-sign-closed.html @@ -0,0 +1 @@ +

    This is an H4

    \ No newline at end of file diff --git a/test/karlcow/header-level4-hash-sign-closed.md b/test/karlcow/header-level4-hash-sign-closed.md new file mode 100644 index 0000000..716cf64 --- /dev/null +++ b/test/karlcow/header-level4-hash-sign-closed.md @@ -0,0 +1 @@ +#### This is an H4 #### \ No newline at end of file diff --git a/test/karlcow/header-level4-hash-sign.html b/test/karlcow/header-level4-hash-sign.html new file mode 100644 index 0000000..1c0f3d6 --- /dev/null +++ b/test/karlcow/header-level4-hash-sign.html @@ -0,0 +1 @@ +

    This is an H4

    \ No newline at end of file diff --git a/test/karlcow/header-level4-hash-sign.md b/test/karlcow/header-level4-hash-sign.md new file mode 100644 index 0000000..8283f11 --- /dev/null +++ b/test/karlcow/header-level4-hash-sign.md @@ -0,0 +1 @@ +#### This is an H4 \ No newline at end of file diff --git a/test/karlcow/header-level5-hash-sign-closed.html b/test/karlcow/header-level5-hash-sign-closed.html new file mode 100644 index 0000000..aa43910 --- /dev/null +++ b/test/karlcow/header-level5-hash-sign-closed.html @@ -0,0 +1 @@ +
    This is an H5
    \ No newline at end of file diff --git a/test/karlcow/header-level5-hash-sign-closed.md b/test/karlcow/header-level5-hash-sign-closed.md new file mode 100644 index 0000000..4294de6 --- /dev/null +++ b/test/karlcow/header-level5-hash-sign-closed.md @@ -0,0 +1 @@ +##### This is an H5 ##### \ No newline at end of file diff --git a/test/karlcow/header-level5-hash-sign.html b/test/karlcow/header-level5-hash-sign.html new file mode 100644 index 0000000..aa43910 --- /dev/null +++ b/test/karlcow/header-level5-hash-sign.html @@ -0,0 +1 @@ +
    This is an H5
    \ No newline at end of file diff --git a/test/karlcow/header-level5-hash-sign.md b/test/karlcow/header-level5-hash-sign.md new file mode 100644 index 0000000..abcdd91 --- /dev/null +++ b/test/karlcow/header-level5-hash-sign.md @@ -0,0 +1 @@ +##### This is an H5 \ No newline at end of file diff --git a/test/karlcow/header-level6-hash-sign-closed.html b/test/karlcow/header-level6-hash-sign-closed.html new file mode 100644 index 0000000..2cbc7b1 --- /dev/null +++ b/test/karlcow/header-level6-hash-sign-closed.html @@ -0,0 +1 @@ +
    This is an H6
    \ No newline at end of file diff --git a/test/karlcow/header-level6-hash-sign-closed.md b/test/karlcow/header-level6-hash-sign-closed.md new file mode 100644 index 0000000..dca50d6 --- /dev/null +++ b/test/karlcow/header-level6-hash-sign-closed.md @@ -0,0 +1 @@ +###### This is an H6 ###### \ No newline at end of file diff --git a/test/karlcow/header-level6-hash-sign.html b/test/karlcow/header-level6-hash-sign.html new file mode 100644 index 0000000..2cbc7b1 --- /dev/null +++ b/test/karlcow/header-level6-hash-sign.html @@ -0,0 +1 @@ +
    This is an H6
    \ No newline at end of file diff --git a/test/karlcow/header-level6-hash-sign.md b/test/karlcow/header-level6-hash-sign.md new file mode 100644 index 0000000..df2ff4c --- /dev/null +++ b/test/karlcow/header-level6-hash-sign.md @@ -0,0 +1 @@ +###### This is an H6 \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-3-dashes-spaces.html b/test/karlcow/horizontal-rule-3-dashes-spaces.html new file mode 100644 index 0000000..1d6667d --- /dev/null +++ b/test/karlcow/horizontal-rule-3-dashes-spaces.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-3-dashes-spaces.md b/test/karlcow/horizontal-rule-3-dashes-spaces.md new file mode 100644 index 0000000..4587849 --- /dev/null +++ b/test/karlcow/horizontal-rule-3-dashes-spaces.md @@ -0,0 +1 @@ +- - - \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-3-dashes.html b/test/karlcow/horizontal-rule-3-dashes.html new file mode 100644 index 0000000..1d6667d --- /dev/null +++ b/test/karlcow/horizontal-rule-3-dashes.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-3-dashes.md b/test/karlcow/horizontal-rule-3-dashes.md new file mode 100644 index 0000000..73b314f --- /dev/null +++ b/test/karlcow/horizontal-rule-3-dashes.md @@ -0,0 +1 @@ +--- \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-3-stars.html b/test/karlcow/horizontal-rule-3-stars.html new file mode 100644 index 0000000..1d6667d --- /dev/null +++ b/test/karlcow/horizontal-rule-3-stars.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-3-stars.md b/test/karlcow/horizontal-rule-3-stars.md new file mode 100644 index 0000000..93a5273 --- /dev/null +++ b/test/karlcow/horizontal-rule-3-stars.md @@ -0,0 +1 @@ +*** \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-3-underscores.html b/test/karlcow/horizontal-rule-3-underscores.html new file mode 100644 index 0000000..1d6667d --- /dev/null +++ b/test/karlcow/horizontal-rule-3-underscores.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-3-underscores.md b/test/karlcow/horizontal-rule-3-underscores.md new file mode 100644 index 0000000..da706a0 --- /dev/null +++ b/test/karlcow/horizontal-rule-3-underscores.md @@ -0,0 +1 @@ +___ \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-7-dashes.html b/test/karlcow/horizontal-rule-7-dashes.html new file mode 100644 index 0000000..1d6667d --- /dev/null +++ b/test/karlcow/horizontal-rule-7-dashes.html @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/test/karlcow/horizontal-rule-7-dashes.md b/test/karlcow/horizontal-rule-7-dashes.md new file mode 100644 index 0000000..f88adb6 --- /dev/null +++ b/test/karlcow/horizontal-rule-7-dashes.md @@ -0,0 +1 @@ +------- \ No newline at end of file diff --git a/test/karlcow/img-idref-title.html b/test/karlcow/img-idref-title.html new file mode 100644 index 0000000..f9b1715 --- /dev/null +++ b/test/karlcow/img-idref-title.html @@ -0,0 +1 @@ +

    HTML5

    \ No newline at end of file diff --git a/test/karlcow/img-idref-title.md b/test/karlcow/img-idref-title.md new file mode 100644 index 0000000..151b1e8 --- /dev/null +++ b/test/karlcow/img-idref-title.md @@ -0,0 +1,3 @@ +![HTML5][h5] + +[h5]: http://www.w3.org/html/logo/img/mark-word-icon.png "HTML5 for everyone" \ No newline at end of file diff --git a/test/karlcow/img-idref.html b/test/karlcow/img-idref.html new file mode 100644 index 0000000..79103a8 --- /dev/null +++ b/test/karlcow/img-idref.html @@ -0,0 +1 @@ +

    HTML5

    \ No newline at end of file diff --git a/test/karlcow/img-idref.md b/test/karlcow/img-idref.md new file mode 100644 index 0000000..4db1bcc --- /dev/null +++ b/test/karlcow/img-idref.md @@ -0,0 +1,3 @@ +![HTML5][h5] + +[h5]: http://www.w3.org/html/logo/img/mark-word-icon.png \ No newline at end of file diff --git a/test/karlcow/img-title.html b/test/karlcow/img-title.html new file mode 100644 index 0000000..cc0e195 --- /dev/null +++ b/test/karlcow/img-title.html @@ -0,0 +1 @@ +

    HTML5

    \ No newline at end of file diff --git a/test/karlcow/img-title.md b/test/karlcow/img-title.md new file mode 100644 index 0000000..2c8e6ff --- /dev/null +++ b/test/karlcow/img-title.md @@ -0,0 +1 @@ +![HTML5](http://www.w3.org/html/logo/img/mark-word-icon.png "HTML5 logo for everyone") \ No newline at end of file diff --git a/test/karlcow/img.html b/test/karlcow/img.html new file mode 100644 index 0000000..79103a8 --- /dev/null +++ b/test/karlcow/img.html @@ -0,0 +1 @@ +

    HTML5

    \ No newline at end of file diff --git a/test/karlcow/img.md b/test/karlcow/img.md new file mode 100644 index 0000000..3b3ca15 --- /dev/null +++ b/test/karlcow/img.md @@ -0,0 +1 @@ +![HTML5](http://www.w3.org/html/logo/img/mark-word-icon.png) \ No newline at end of file diff --git a/test/karlcow/inline-code-escaping-entities.html b/test/karlcow/inline-code-escaping-entities.html new file mode 100644 index 0000000..726e8a8 --- /dev/null +++ b/test/karlcow/inline-code-escaping-entities.html @@ -0,0 +1 @@ +

    We love <code> and & for everything

    \ No newline at end of file diff --git a/test/karlcow/inline-code-escaping-entities.md b/test/karlcow/inline-code-escaping-entities.md new file mode 100644 index 0000000..3821a9b --- /dev/null +++ b/test/karlcow/inline-code-escaping-entities.md @@ -0,0 +1 @@ +We love ` and &` for everything \ No newline at end of file diff --git a/test/karlcow/inline-code-with-visible-backtick.html b/test/karlcow/inline-code-with-visible-backtick.html new file mode 100644 index 0000000..bc92165 --- /dev/null +++ b/test/karlcow/inline-code-with-visible-backtick.html @@ -0,0 +1 @@ +

    We love `code` for everything

    \ No newline at end of file diff --git a/test/karlcow/inline-code-with-visible-backtick.md b/test/karlcow/inline-code-with-visible-backtick.md new file mode 100644 index 0000000..ecc9408 --- /dev/null +++ b/test/karlcow/inline-code-with-visible-backtick.md @@ -0,0 +1 @@ +``We love `code` for everything`` \ No newline at end of file diff --git a/test/karlcow/inline-code.html b/test/karlcow/inline-code.html new file mode 100644 index 0000000..bc92165 --- /dev/null +++ b/test/karlcow/inline-code.html @@ -0,0 +1 @@ +

    We love `code` for everything

    \ No newline at end of file diff --git a/test/karlcow/inline-code.md b/test/karlcow/inline-code.md new file mode 100644 index 0000000..ecc9408 --- /dev/null +++ b/test/karlcow/inline-code.md @@ -0,0 +1 @@ +``We love `code` for everything`` \ No newline at end of file diff --git a/test/karlcow/line-break-2-spaces.html b/test/karlcow/line-break-2-spaces.html new file mode 100644 index 0000000..cb75f09 --- /dev/null +++ b/test/karlcow/line-break-2-spaces.html @@ -0,0 +1,2 @@ +

    A first sentence
    +and a line break.

    \ No newline at end of file diff --git a/test/karlcow/line-break-2-spaces.md b/test/karlcow/line-break-2-spaces.md new file mode 100644 index 0000000..2b330a5 --- /dev/null +++ b/test/karlcow/line-break-2-spaces.md @@ -0,0 +1,2 @@ +A first sentence +and a line break. \ No newline at end of file diff --git a/test/karlcow/line-break-5-spaces.html b/test/karlcow/line-break-5-spaces.html new file mode 100644 index 0000000..cb75f09 --- /dev/null +++ b/test/karlcow/line-break-5-spaces.html @@ -0,0 +1,2 @@ +

    A first sentence
    +and a line break.

    \ No newline at end of file diff --git a/test/karlcow/line-break-5-spaces.md b/test/karlcow/line-break-5-spaces.md new file mode 100644 index 0000000..f2e3e37 --- /dev/null +++ b/test/karlcow/line-break-5-spaces.md @@ -0,0 +1,2 @@ +A first sentence +and a line break. \ No newline at end of file diff --git a/test/karlcow/link-automatic.html b/test/karlcow/link-automatic.html new file mode 100644 index 0000000..604cbdc --- /dev/null +++ b/test/karlcow/link-automatic.html @@ -0,0 +1 @@ +

    This is an automatic link http://www.w3.org/

    \ No newline at end of file diff --git a/test/karlcow/link-automatic.md b/test/karlcow/link-automatic.md new file mode 100644 index 0000000..bf5987d --- /dev/null +++ b/test/karlcow/link-automatic.md @@ -0,0 +1 @@ +This is an automatic link \ No newline at end of file diff --git a/test/karlcow/link-bracket-paranthesis-title.html b/test/karlcow/link-bracket-paranthesis-title.html new file mode 100644 index 0000000..5e568ba --- /dev/null +++ b/test/karlcow/link-bracket-paranthesis-title.html @@ -0,0 +1 @@ +

    W3C

    \ No newline at end of file diff --git a/test/karlcow/link-bracket-paranthesis-title.md b/test/karlcow/link-bracket-paranthesis-title.md new file mode 100644 index 0000000..c61641c --- /dev/null +++ b/test/karlcow/link-bracket-paranthesis-title.md @@ -0,0 +1 @@ +[W3C](http://www.w3.org/ "Discover w3c") \ No newline at end of file diff --git a/test/karlcow/link-bracket-paranthesis.html b/test/karlcow/link-bracket-paranthesis.html new file mode 100644 index 0000000..ba65be8 --- /dev/null +++ b/test/karlcow/link-bracket-paranthesis.html @@ -0,0 +1 @@ +

    W3C

    \ No newline at end of file diff --git a/test/karlcow/link-bracket-paranthesis.md b/test/karlcow/link-bracket-paranthesis.md new file mode 100644 index 0000000..8fd5195 --- /dev/null +++ b/test/karlcow/link-bracket-paranthesis.md @@ -0,0 +1 @@ +[W3C](http://www.w3.org/) \ No newline at end of file diff --git a/test/karlcow/link-idref-angle-bracket.html b/test/karlcow/link-idref-angle-bracket.html new file mode 100644 index 0000000..dbee9a9 --- /dev/null +++ b/test/karlcow/link-idref-angle-bracket.html @@ -0,0 +1 @@ +

    World Wide Web Consortium

    \ No newline at end of file diff --git a/test/karlcow/link-idref-angle-bracket.md b/test/karlcow/link-idref-angle-bracket.md new file mode 100644 index 0000000..0f96c3c --- /dev/null +++ b/test/karlcow/link-idref-angle-bracket.md @@ -0,0 +1,3 @@ +[World Wide Web Consortium][w3c] + +[w3c]: \ No newline at end of file diff --git a/test/karlcow/link-idref-implicit-spaces.html b/test/karlcow/link-idref-implicit-spaces.html new file mode 100644 index 0000000..dbee9a9 --- /dev/null +++ b/test/karlcow/link-idref-implicit-spaces.html @@ -0,0 +1 @@ +

    World Wide Web Consortium

    \ No newline at end of file diff --git a/test/karlcow/link-idref-implicit-spaces.md b/test/karlcow/link-idref-implicit-spaces.md new file mode 100644 index 0000000..f49e289 --- /dev/null +++ b/test/karlcow/link-idref-implicit-spaces.md @@ -0,0 +1,3 @@ +[World Wide Web Consortium][] + +[World Wide Web Consortium]: http://www.w3.org/ \ No newline at end of file diff --git a/test/karlcow/link-idref-implicit.html b/test/karlcow/link-idref-implicit.html new file mode 100644 index 0000000..9ba2da6 --- /dev/null +++ b/test/karlcow/link-idref-implicit.html @@ -0,0 +1 @@ +

    w3c

    \ No newline at end of file diff --git a/test/karlcow/link-idref-implicit.md b/test/karlcow/link-idref-implicit.md new file mode 100644 index 0000000..65483c2 --- /dev/null +++ b/test/karlcow/link-idref-implicit.md @@ -0,0 +1,3 @@ +[w3c][] + +[w3c]: http://www.w3.org/ \ No newline at end of file diff --git a/test/karlcow/link-idref-space.html b/test/karlcow/link-idref-space.html new file mode 100644 index 0000000..dbee9a9 --- /dev/null +++ b/test/karlcow/link-idref-space.html @@ -0,0 +1 @@ +

    World Wide Web Consortium

    \ No newline at end of file diff --git a/test/karlcow/link-idref-space.md b/test/karlcow/link-idref-space.md new file mode 100644 index 0000000..9b13c6f --- /dev/null +++ b/test/karlcow/link-idref-space.md @@ -0,0 +1,3 @@ +[World Wide Web Consortium] [w3c] + +[w3c]: http://www.w3.org/ \ No newline at end of file diff --git a/test/karlcow/link-idref-title-next-line.html b/test/karlcow/link-idref-title-next-line.html new file mode 100644 index 0000000..9c2dda6 --- /dev/null +++ b/test/karlcow/link-idref-title-next-line.html @@ -0,0 +1 @@ +

    World Wide Web Consortium

    \ No newline at end of file diff --git a/test/karlcow/link-idref-title-next-line.md b/test/karlcow/link-idref-title-next-line.md new file mode 100644 index 0000000..310e80b --- /dev/null +++ b/test/karlcow/link-idref-title-next-line.md @@ -0,0 +1,4 @@ +[World Wide Web Consortium][w3c] + +[w3c]: http://www.w3.org/ + "Discover W3C" \ No newline at end of file diff --git a/test/karlcow/link-idref-title-paranthesis.html b/test/karlcow/link-idref-title-paranthesis.html new file mode 100644 index 0000000..f80f8ce --- /dev/null +++ b/test/karlcow/link-idref-title-paranthesis.html @@ -0,0 +1 @@ +

    World Wide Web Consortium

    \ No newline at end of file diff --git a/test/karlcow/link-idref-title-paranthesis.md b/test/karlcow/link-idref-title-paranthesis.md new file mode 100644 index 0000000..9bb11ed --- /dev/null +++ b/test/karlcow/link-idref-title-paranthesis.md @@ -0,0 +1,3 @@ +[World Wide Web Consortium][w3c] + +[w3c]: http://www.w3.org/ (Discover w3c) \ No newline at end of file diff --git a/test/karlcow/link-idref-title-single-quote.html b/test/karlcow/link-idref-title-single-quote.html new file mode 100644 index 0000000..f80f8ce --- /dev/null +++ b/test/karlcow/link-idref-title-single-quote.html @@ -0,0 +1 @@ +

    World Wide Web Consortium

    \ No newline at end of file diff --git a/test/karlcow/link-idref-title-single-quote.md b/test/karlcow/link-idref-title-single-quote.md new file mode 100644 index 0000000..a6a81b9 --- /dev/null +++ b/test/karlcow/link-idref-title-single-quote.md @@ -0,0 +1,3 @@ +[World Wide Web Consortium][w3c] + +[w3c]: http://www.w3.org/ 'Discover w3c' \ No newline at end of file diff --git a/test/karlcow/link-idref-title.html b/test/karlcow/link-idref-title.html new file mode 100644 index 0000000..f80f8ce --- /dev/null +++ b/test/karlcow/link-idref-title.html @@ -0,0 +1 @@ +

    World Wide Web Consortium

    \ No newline at end of file diff --git a/test/karlcow/link-idref-title.md b/test/karlcow/link-idref-title.md new file mode 100644 index 0000000..bee4294 --- /dev/null +++ b/test/karlcow/link-idref-title.md @@ -0,0 +1,3 @@ +[World Wide Web Consortium][w3c] + +[w3c]: http://www.w3.org/ "Discover w3c" \ No newline at end of file diff --git a/test/karlcow/link-idref.html b/test/karlcow/link-idref.html new file mode 100644 index 0000000..dbee9a9 --- /dev/null +++ b/test/karlcow/link-idref.html @@ -0,0 +1 @@ +

    World Wide Web Consortium

    \ No newline at end of file diff --git a/test/karlcow/link-idref.md b/test/karlcow/link-idref.md new file mode 100644 index 0000000..2d45629 --- /dev/null +++ b/test/karlcow/link-idref.md @@ -0,0 +1,3 @@ +[World Wide Web Consortium][w3c] + +[w3c]: http://www.w3.org/ \ No newline at end of file diff --git a/test/karlcow/list-blockquote.html b/test/karlcow/list-blockquote.html new file mode 100644 index 0000000..1d99d17 --- /dev/null +++ b/test/karlcow/list-blockquote.html @@ -0,0 +1,7 @@ +
      +
    • a list containing a blockquote

      + +
      +

      this the blockquote in the list

      +
    • +
    diff --git a/test/karlcow/list-blockquote.md b/test/karlcow/list-blockquote.md new file mode 100644 index 0000000..37c0762 --- /dev/null +++ b/test/karlcow/list-blockquote.md @@ -0,0 +1,3 @@ +* a list containing a blockquote + + > this the blockquote in the list \ No newline at end of file diff --git a/test/karlcow/list-code.html b/test/karlcow/list-code.html new file mode 100644 index 0000000..53b3c22 --- /dev/null +++ b/test/karlcow/list-code.html @@ -0,0 +1,7 @@ +
      +
    • a list containing a block of code

      + +
      10 PRINT HELLO INFINITE
      +20 GOTO 10
      +
    • +
    \ No newline at end of file diff --git a/test/karlcow/list-code.md b/test/karlcow/list-code.md new file mode 100644 index 0000000..ed774d2 --- /dev/null +++ b/test/karlcow/list-code.md @@ -0,0 +1,4 @@ +* a list containing a block of code + + 10 PRINT HELLO INFINITE + 20 GOTO 10 \ No newline at end of file diff --git a/test/karlcow/list-multiparagraphs-tab.html b/test/karlcow/list-multiparagraphs-tab.html new file mode 100644 index 0000000..a90759e --- /dev/null +++ b/test/karlcow/list-multiparagraphs-tab.html @@ -0,0 +1,10 @@ +
      +
    • This is a list item with two paragraphs. Lorem ipsum dolor +sit amet, consectetuer adipiscing elit. Aliquam hendrerit +mi posuere lectus.

      + +

      Vestibulum enim wisi, viverra nec, fringilla in, laoreet +vitae, risus. Donec sit amet nisl. Aliquam semper ipsum +sit amet velit.

    • +
    • Suspendisse id sem consectetuer libero luctus adipiscing.

    • +
    \ No newline at end of file diff --git a/test/karlcow/list-multiparagraphs-tab.md b/test/karlcow/list-multiparagraphs-tab.md new file mode 100644 index 0000000..8c50d42 --- /dev/null +++ b/test/karlcow/list-multiparagraphs-tab.md @@ -0,0 +1,9 @@ +* This is a list item with two paragraphs. Lorem ipsum dolor + sit amet, consectetuer adipiscing elit. Aliquam hendrerit + mi posuere lectus. + + Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. Donec sit amet nisl. Aliquam semper ipsum + sit amet velit. + +* Suspendisse id sem consectetuer libero luctus adipiscing. \ No newline at end of file diff --git a/test/karlcow/list-multiparagraphs.html b/test/karlcow/list-multiparagraphs.html new file mode 100644 index 0000000..a90759e --- /dev/null +++ b/test/karlcow/list-multiparagraphs.html @@ -0,0 +1,10 @@ +
      +
    • This is a list item with two paragraphs. Lorem ipsum dolor +sit amet, consectetuer adipiscing elit. Aliquam hendrerit +mi posuere lectus.

      + +

      Vestibulum enim wisi, viverra nec, fringilla in, laoreet +vitae, risus. Donec sit amet nisl. Aliquam semper ipsum +sit amet velit.

    • +
    • Suspendisse id sem consectetuer libero luctus adipiscing.

    • +
    \ No newline at end of file diff --git a/test/karlcow/list-multiparagraphs.md b/test/karlcow/list-multiparagraphs.md new file mode 100644 index 0000000..58d4820 --- /dev/null +++ b/test/karlcow/list-multiparagraphs.md @@ -0,0 +1,9 @@ +* This is a list item with two paragraphs. Lorem ipsum dolor + sit amet, consectetuer adipiscing elit. Aliquam hendrerit + mi posuere lectus. + + Vestibulum enim wisi, viverra nec, fringilla in, laoreet + vitae, risus. Donec sit amet nisl. Aliquam semper ipsum + sit amet velit. + +* Suspendisse id sem consectetuer libero luctus adipiscing. \ No newline at end of file diff --git a/test/karlcow/ordered-list-escaped.html b/test/karlcow/ordered-list-escaped.html new file mode 100644 index 0000000..f6c477d --- /dev/null +++ b/test/karlcow/ordered-list-escaped.html @@ -0,0 +1 @@ +

    1. ordered list escape

    \ No newline at end of file diff --git a/test/karlcow/ordered-list-escaped.md b/test/karlcow/ordered-list-escaped.md new file mode 100644 index 0000000..ec71a7e --- /dev/null +++ b/test/karlcow/ordered-list-escaped.md @@ -0,0 +1 @@ +1\. ordered list escape \ No newline at end of file diff --git a/test/karlcow/ordered-list-inner-par-list.html b/test/karlcow/ordered-list-inner-par-list.html new file mode 100644 index 0000000..2a99d1a --- /dev/null +++ b/test/karlcow/ordered-list-inner-par-list.html @@ -0,0 +1,11 @@ +
      +
    1. +

      1

      +
        +
      • inner par list
      • +
      +
    2. +
    3. +

      2

      +
    4. +
    diff --git a/test/karlcow/ordered-list-inner-par-list.md b/test/karlcow/ordered-list-inner-par-list.md new file mode 100644 index 0000000..05c6490 --- /dev/null +++ b/test/karlcow/ordered-list-inner-par-list.md @@ -0,0 +1,5 @@ +1. 1 + + - inner par list + +2. 2 diff --git a/test/karlcow/ordered-list-items-random-number.html b/test/karlcow/ordered-list-items-random-number.html new file mode 100644 index 0000000..6113b3a --- /dev/null +++ b/test/karlcow/ordered-list-items-random-number.html @@ -0,0 +1,5 @@ +
      +
    1. list item 1
    2. +
    3. list item 2
    4. +
    5. list item 3
    6. +
    \ No newline at end of file diff --git a/test/karlcow/ordered-list-items-random-number.md b/test/karlcow/ordered-list-items-random-number.md new file mode 100644 index 0000000..8f4d9bb --- /dev/null +++ b/test/karlcow/ordered-list-items-random-number.md @@ -0,0 +1,3 @@ +1. list item 1 +8. list item 2 +1. list item 3 \ No newline at end of file diff --git a/test/karlcow/ordered-list-items.html b/test/karlcow/ordered-list-items.html new file mode 100644 index 0000000..6113b3a --- /dev/null +++ b/test/karlcow/ordered-list-items.html @@ -0,0 +1,5 @@ +
      +
    1. list item 1
    2. +
    3. list item 2
    4. +
    5. list item 3
    6. +
    \ No newline at end of file diff --git a/test/karlcow/ordered-list-items.md b/test/karlcow/ordered-list-items.md new file mode 100644 index 0000000..6ba5e88 --- /dev/null +++ b/test/karlcow/ordered-list-items.md @@ -0,0 +1,3 @@ +1. list item 1 +2. list item 2 +3. list item 3 \ No newline at end of file diff --git a/test/karlcow/paragraph-hard-return.html b/test/karlcow/paragraph-hard-return.html new file mode 100644 index 0000000..7915e29 --- /dev/null +++ b/test/karlcow/paragraph-hard-return.html @@ -0,0 +1,3 @@ +

    This is a paragraph +on multiple lines +with hard return.

    \ No newline at end of file diff --git a/test/karlcow/paragraph-hard-return.md b/test/karlcow/paragraph-hard-return.md new file mode 100644 index 0000000..3e4dfbd --- /dev/null +++ b/test/karlcow/paragraph-hard-return.md @@ -0,0 +1,3 @@ +This is a paragraph +on multiple lines +with hard return. \ No newline at end of file diff --git a/test/karlcow/paragraph-line.html b/test/karlcow/paragraph-line.html new file mode 100644 index 0000000..5fc0e44 --- /dev/null +++ b/test/karlcow/paragraph-line.html @@ -0,0 +1 @@ +

    This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph on 1 line.

    \ No newline at end of file diff --git a/test/karlcow/paragraph-line.md b/test/karlcow/paragraph-line.md new file mode 100644 index 0000000..edcdead --- /dev/null +++ b/test/karlcow/paragraph-line.md @@ -0,0 +1 @@ +This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph on 1 line. \ No newline at end of file diff --git a/test/karlcow/paragraph-trailing-leading-spaces.html b/test/karlcow/paragraph-trailing-leading-spaces.html new file mode 100644 index 0000000..d99afcd --- /dev/null +++ b/test/karlcow/paragraph-trailing-leading-spaces.html @@ -0,0 +1 @@ +

    This is a paragraph with a trailing and leading space.

    \ No newline at end of file diff --git a/test/karlcow/paragraph-trailing-leading-spaces.md b/test/karlcow/paragraph-trailing-leading-spaces.md new file mode 100644 index 0000000..3b3353d --- /dev/null +++ b/test/karlcow/paragraph-trailing-leading-spaces.md @@ -0,0 +1 @@ + This is a paragraph with a trailing and leading space. \ No newline at end of file diff --git a/test/karlcow/paragraph-trailing-tab.html b/test/karlcow/paragraph-trailing-tab.html new file mode 100644 index 0000000..f4bcd7c --- /dev/null +++ b/test/karlcow/paragraph-trailing-tab.html @@ -0,0 +1 @@ +

    This is a paragraph with 1 trailing tab.

    \ No newline at end of file diff --git a/test/karlcow/paragraph-trailing-tab.md b/test/karlcow/paragraph-trailing-tab.md new file mode 100644 index 0000000..7b345c2 --- /dev/null +++ b/test/karlcow/paragraph-trailing-tab.md @@ -0,0 +1 @@ +This is a paragraph with 1 trailing tab. \ No newline at end of file diff --git a/test/karlcow/paragraphs-2-leading-spaces.html b/test/karlcow/paragraphs-2-leading-spaces.html new file mode 100644 index 0000000..bd08e95 --- /dev/null +++ b/test/karlcow/paragraphs-2-leading-spaces.html @@ -0,0 +1 @@ +

    This is a paragraph with 2 leading spaces.

    \ No newline at end of file diff --git a/test/karlcow/paragraphs-2-leading-spaces.md b/test/karlcow/paragraphs-2-leading-spaces.md new file mode 100644 index 0000000..1a618de --- /dev/null +++ b/test/karlcow/paragraphs-2-leading-spaces.md @@ -0,0 +1 @@ + This is a paragraph with 2 leading spaces. \ No newline at end of file diff --git a/test/karlcow/paragraphs-3-leading-spaces.html b/test/karlcow/paragraphs-3-leading-spaces.html new file mode 100644 index 0000000..9c91f46 --- /dev/null +++ b/test/karlcow/paragraphs-3-leading-spaces.html @@ -0,0 +1 @@ +

    This is a paragraph with 3 leading spaces.

    \ No newline at end of file diff --git a/test/karlcow/paragraphs-3-leading-spaces.md b/test/karlcow/paragraphs-3-leading-spaces.md new file mode 100644 index 0000000..a38428f --- /dev/null +++ b/test/karlcow/paragraphs-3-leading-spaces.md @@ -0,0 +1 @@ + This is a paragraph with 3 leading spaces. \ No newline at end of file diff --git a/test/karlcow/paragraphs-leading-space.html b/test/karlcow/paragraphs-leading-space.html new file mode 100644 index 0000000..917426d --- /dev/null +++ b/test/karlcow/paragraphs-leading-space.html @@ -0,0 +1 @@ +

    This is a paragraph with 1 leading space.

    \ No newline at end of file diff --git a/test/karlcow/paragraphs-leading-space.md b/test/karlcow/paragraphs-leading-space.md new file mode 100644 index 0000000..0d95f8b --- /dev/null +++ b/test/karlcow/paragraphs-leading-space.md @@ -0,0 +1 @@ + This is a paragraph with 1 leading space. \ No newline at end of file diff --git a/test/karlcow/paragraphs-trailing-spaces.html b/test/karlcow/paragraphs-trailing-spaces.html new file mode 100644 index 0000000..7636c46 --- /dev/null +++ b/test/karlcow/paragraphs-trailing-spaces.html @@ -0,0 +1 @@ +

    This is a paragraph with a trailing space.

    \ No newline at end of file diff --git a/test/karlcow/paragraphs-trailing-spaces.md b/test/karlcow/paragraphs-trailing-spaces.md new file mode 100644 index 0000000..6809b73 --- /dev/null +++ b/test/karlcow/paragraphs-trailing-spaces.md @@ -0,0 +1 @@ +This is a paragraph with a trailing space. \ No newline at end of file diff --git a/test/karlcow/strong-middle-word.html b/test/karlcow/strong-middle-word.html new file mode 100644 index 0000000..4550f32 --- /dev/null +++ b/test/karlcow/strong-middle-word.html @@ -0,0 +1 @@ +

    asterisks

    \ No newline at end of file diff --git a/test/karlcow/strong-middle-word.md b/test/karlcow/strong-middle-word.md new file mode 100644 index 0000000..44651a4 --- /dev/null +++ b/test/karlcow/strong-middle-word.md @@ -0,0 +1 @@ +as**te**risks \ No newline at end of file diff --git a/test/karlcow/strong-star.html b/test/karlcow/strong-star.html new file mode 100644 index 0000000..3181aea --- /dev/null +++ b/test/karlcow/strong-star.html @@ -0,0 +1 @@ +

    double asterisks

    \ No newline at end of file diff --git a/test/karlcow/strong-star.md b/test/karlcow/strong-star.md new file mode 100644 index 0000000..566125c --- /dev/null +++ b/test/karlcow/strong-star.md @@ -0,0 +1 @@ +**double asterisks** \ No newline at end of file diff --git a/test/karlcow/strong-underscore.html b/test/karlcow/strong-underscore.html new file mode 100644 index 0000000..ef613bb --- /dev/null +++ b/test/karlcow/strong-underscore.html @@ -0,0 +1 @@ +

    double underscores

    \ No newline at end of file diff --git a/test/karlcow/strong-underscore.md b/test/karlcow/strong-underscore.md new file mode 100644 index 0000000..69cc179 --- /dev/null +++ b/test/karlcow/strong-underscore.md @@ -0,0 +1 @@ +__double underscores__ \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-asterisk.html b/test/karlcow/unordered-list-items-asterisk.html new file mode 100644 index 0000000..a5d2dfc --- /dev/null +++ b/test/karlcow/unordered-list-items-asterisk.html @@ -0,0 +1,5 @@ +
      +
    • list item 1
    • +
    • list item 2
    • +
    • list item 3
    • +
    \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-asterisk.md b/test/karlcow/unordered-list-items-asterisk.md new file mode 100644 index 0000000..01e3e61 --- /dev/null +++ b/test/karlcow/unordered-list-items-asterisk.md @@ -0,0 +1,3 @@ +* list item 1 +* list item 2 +* list item 3 diff --git a/test/karlcow/unordered-list-items-dashsign.html b/test/karlcow/unordered-list-items-dashsign.html new file mode 100644 index 0000000..a5d2dfc --- /dev/null +++ b/test/karlcow/unordered-list-items-dashsign.html @@ -0,0 +1,5 @@ +
      +
    • list item 1
    • +
    • list item 2
    • +
    • list item 3
    • +
    \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-dashsign.md b/test/karlcow/unordered-list-items-dashsign.md new file mode 100644 index 0000000..bf057f8 --- /dev/null +++ b/test/karlcow/unordered-list-items-dashsign.md @@ -0,0 +1,3 @@ +- list item 1 +- list item 2 +- list item 3 \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-leading-1space.html b/test/karlcow/unordered-list-items-leading-1space.html new file mode 100644 index 0000000..99cec2f --- /dev/null +++ b/test/karlcow/unordered-list-items-leading-1space.html @@ -0,0 +1,5 @@ +
      +
    • list item 1
    • +
    • list item 2
    • +
    • list item 3
    • +
    diff --git a/test/karlcow/unordered-list-items-leading-1space.md b/test/karlcow/unordered-list-items-leading-1space.md new file mode 100644 index 0000000..ec95bb7 --- /dev/null +++ b/test/karlcow/unordered-list-items-leading-1space.md @@ -0,0 +1,3 @@ + * list item 1 + * list item 2 + * list item 3 \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-leading-2spaces.html b/test/karlcow/unordered-list-items-leading-2spaces.html new file mode 100644 index 0000000..a5d2dfc --- /dev/null +++ b/test/karlcow/unordered-list-items-leading-2spaces.html @@ -0,0 +1,5 @@ +
      +
    • list item 1
    • +
    • list item 2
    • +
    • list item 3
    • +
    \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-leading-2spaces.md b/test/karlcow/unordered-list-items-leading-2spaces.md new file mode 100644 index 0000000..0d724cd --- /dev/null +++ b/test/karlcow/unordered-list-items-leading-2spaces.md @@ -0,0 +1,3 @@ + * list item 1 + * list item 2 + * list item 3 \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-leading-3spaces.html b/test/karlcow/unordered-list-items-leading-3spaces.html new file mode 100644 index 0000000..a5d2dfc --- /dev/null +++ b/test/karlcow/unordered-list-items-leading-3spaces.html @@ -0,0 +1,5 @@ +
      +
    • list item 1
    • +
    • list item 2
    • +
    • list item 3
    • +
    \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-leading-3spaces.md b/test/karlcow/unordered-list-items-leading-3spaces.md new file mode 100644 index 0000000..c858766 --- /dev/null +++ b/test/karlcow/unordered-list-items-leading-3spaces.md @@ -0,0 +1,3 @@ + * list item 1 + * list item 2 + * list item 3 \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-plussign.html b/test/karlcow/unordered-list-items-plussign.html new file mode 100644 index 0000000..a5d2dfc --- /dev/null +++ b/test/karlcow/unordered-list-items-plussign.html @@ -0,0 +1,5 @@ +
      +
    • list item 1
    • +
    • list item 2
    • +
    • list item 3
    • +
    \ No newline at end of file diff --git a/test/karlcow/unordered-list-items-plussign.md b/test/karlcow/unordered-list-items-plussign.md new file mode 100644 index 0000000..c91561e --- /dev/null +++ b/test/karlcow/unordered-list-items-plussign.md @@ -0,0 +1,3 @@ ++ list item 1 ++ list item 2 ++ list item 3 \ No newline at end of file diff --git a/test/karlcow/unordered-list-paragraphs.html b/test/karlcow/unordered-list-paragraphs.html new file mode 100644 index 0000000..e78215e --- /dev/null +++ b/test/karlcow/unordered-list-paragraphs.html @@ -0,0 +1,4 @@ +
      +
    • list item in paragraph

    • +
    • another list item in paragraph

    • +
    \ No newline at end of file diff --git a/test/karlcow/unordered-list-paragraphs.md b/test/karlcow/unordered-list-paragraphs.md new file mode 100644 index 0000000..c94b4db --- /dev/null +++ b/test/karlcow/unordered-list-paragraphs.md @@ -0,0 +1,3 @@ +* list item in paragraph + +* another list item in paragraph \ No newline at end of file diff --git a/test/karlcow/unordered-list-unindented-content.html b/test/karlcow/unordered-list-unindented-content.html new file mode 100644 index 0000000..44d07b8 --- /dev/null +++ b/test/karlcow/unordered-list-unindented-content.html @@ -0,0 +1,4 @@ +
      +
    • This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph in a list.
    • +
    • and yet another long long long long long long long long long long long long long long long long long long long long long long line.
    • +
    \ No newline at end of file diff --git a/test/karlcow/unordered-list-unindented-content.md b/test/karlcow/unordered-list-unindented-content.md new file mode 100644 index 0000000..f564c02 --- /dev/null +++ b/test/karlcow/unordered-list-unindented-content.md @@ -0,0 +1,2 @@ +* This a very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long paragraph in a list. +* and yet another long long long long long long long long long long long long long long long long long long long long long long line. \ No newline at end of file diff --git a/test/karlcow/unordered-list-with-indented-content.html b/test/karlcow/unordered-list-with-indented-content.html new file mode 100644 index 0000000..003d8ce --- /dev/null +++ b/test/karlcow/unordered-list-with-indented-content.html @@ -0,0 +1,7 @@ +
      +
    • This is a list item +with the content on +multiline and indented.
    • +
    • And this another list item +with the same principle.
    • +
    \ No newline at end of file diff --git a/test/karlcow/unordered-list-with-indented-content.md b/test/karlcow/unordered-list-with-indented-content.md new file mode 100644 index 0000000..5fcc8e0 --- /dev/null +++ b/test/karlcow/unordered-list-with-indented-content.md @@ -0,0 +1,5 @@ +* This is a list item + with the content on + multiline and indented. +* And this another list item + with the same principle. \ No newline at end of file diff --git a/test/node/cli.js b/test/node/cli.js new file mode 100644 index 0000000..f0829de --- /dev/null +++ b/test/node/cli.js @@ -0,0 +1,18 @@ +/* +var semver = require('semver'), + cmd = 'node bin/showdown.js'; + +describe('showdown cli', function () { + 'use strict'; + if (semver.gt(process.versions.node, '0.12.0')) { + var execSync = require('child_process').execSync; + it('basic stdin stdout', function () { + var otp = execSync(cmd + ' makehtml', { + encoding: 'utf8', + input: '**foo**' + }); + otp.trim().should.equal('

    foo

    '); + }); + } +}); +*/ diff --git a/test/node/legacyExtensionSupport.js b/test/node/legacyExtensionSupport.js new file mode 100644 index 0000000..268bc2b --- /dev/null +++ b/test/node/legacyExtensionSupport.js @@ -0,0 +1,24 @@ +/** + * Created by Estevao on 06-06-2015. + */ +require('source-map-support').install(); +var expect = require('chai').expect, + showdown = require('../bootstrap').showdown; + +describe('showdown legacy extension support', function () { + 'use strict'; + var extObjMock = + { + type: 'lang', + filter: function () {} + }, + extFunc = function () { + return [extObjMock]; + }; + + it('accept extensions loaded by the old mechanism', function () { + showdown.extensions.bazinga = extFunc; + var cnv = new showdown.Converter({extensions: ['bazinga']}); + expect(cnv.getAllExtensions().language).to.eql([extObjMock]); + }); +}); diff --git a/test/node/showdown.Converter.js b/test/node/showdown.Converter.js new file mode 100644 index 0000000..ccbb040 --- /dev/null +++ b/test/node/showdown.Converter.js @@ -0,0 +1,89 @@ +/** + * Created by Estevao on 31-05-2015. + */ +require('source-map-support').install(); +require('chai').should(); +require('sinon'); +var showdown = require('../bootstrap').showdown; + +describe('showdown.Converter', function () { + 'use strict'; + + describe('option methods', function () { + var converter = new showdown.Converter(); + + it('setOption() should set option foo=baz', function () { + converter.setOption('foo', 'baz'); + }); + + it('getOption() should get option foo to equal baz', function () { + converter.getOption('foo').should.equal('baz'); + }); + + it('getOptions() should contain foo=baz', function () { + var options = converter.getOptions(); + options.should.have.ownProperty('foo'); + options.foo.should.equal('baz'); + }); + }); + + describe('setFlavor() github', function () { + var converter = new showdown.Converter(), + ghOpts = { + omitExtraWLInCodeBlocks: true, + prefixHeaderId: 'user-content-', + simplifiedAutoLink: true, + literalMidWordUnderscores: true, + strikethrough: true, + tables: true, + tablesHeaderId: true, + ghCodeBlocks: true, + tasklists: true + }; + + converter.setFlavor('github'); + + for (var opt in ghOpts) { + if (ghOpts.hasOwnProperty(opt)) { + check(opt, ghOpts[opt]); + } + } + function check(key, val) { + it('should set ' + opt + ' to ' + val, function () { + converter.getOption(key).should.equal(val); + }); + } + }); + + describe('extension methods', function () { + var extObjMock = { + type: 'lang', + filter: function () {} + }, + extObjFunc = function () { + return extObjMock; + }; + + it('addExtension() should add an extension Object', function () { + var converter = new showdown.Converter(); + converter.addExtension(extObjMock); + converter.getAllExtensions().language.should.contain(extObjMock); + }); + + it('addExtension() should unwrap an extension wrapped in a function', function () { + var converter = new showdown.Converter(); + + converter.addExtension(extObjFunc); + converter.getAllExtensions().language.should.contain(extObjMock); + }); + + it('useExtension() should use a previous registered extension in showdown', function () { + showdown.extension('foo', extObjMock); + var converter = new showdown.Converter(); + + converter.useExtension('foo'); + converter.getAllExtensions().language.should.contain(extObjMock); + showdown.resetExtensions(); + }); + }); +}); diff --git a/test/node/showdown.Converter.makeHtml.js b/test/node/showdown.Converter.makeHtml.js new file mode 100644 index 0000000..ce683a2 --- /dev/null +++ b/test/node/showdown.Converter.makeHtml.js @@ -0,0 +1,61 @@ +/** + * Created by Estevao on 15-01-2015. + */ + +describe('showdown.Converter', function () { + 'use strict'; + + require('source-map-support').install(); + require('chai').should(); + + var showdown = require('../bootstrap').showdown; + + describe('Converter.options extensions', function () { + showdown.extensions.testext = function () { + return [{ + type: 'output', + filter: function (text) { + runCount = runCount + 1; + return text; + } + }]; + }; + var runCount, + converter = new showdown.Converter({extensions: ['testext']}); + + it('output extensions should run once', function () { + runCount = 0; + converter.makeHtml('# testext'); + runCount.should.equal(1); + }); + }); + + describe('makeHtml() with option omitExtraWLInCodeBlocks', function () { + var converter = new showdown.Converter({omitExtraWLInCodeBlocks: true}), + text = 'var foo = bar;', + html = converter.makeHtml(' ' + text); + it('should omit extra line after code tag', function () { + var expectedHtml = '
    ' + text + '
    '; + html.should.equal(expectedHtml); + }); + }); + + describe('makeHtml() with option prefixHeaderId', function () { + var converter = new showdown.Converter(), + text = 'foo header'; + + it('should prefix header id with "section"', function () { + converter.setOption('prefixHeaderId', true); + var html = converter.makeHtml('# ' + text), + expectedHtml = '

    ' + text + '

    '; + html.should.equal(expectedHtml); + }); + + it('should prefix header id with custom string', function () { + converter.setOption('prefixHeaderId', 'blabla'); + var html = converter.makeHtml('# ' + text), + expectedHtml = '

    ' + text + '

    '; + html.should.equal(expectedHtml); + }); + }); +}); diff --git a/test/node/showdown.js b/test/node/showdown.js new file mode 100644 index 0000000..1862498 --- /dev/null +++ b/test/node/showdown.js @@ -0,0 +1,90 @@ +require('source-map-support').install(); +require('chai').should(); +var expect = require('chai').expect, + showdown = require('../bootstrap').showdown; + +describe('showdown.options', function () { + 'use strict'; + + describe('setOption() and getOption()', function () { + it('should set option foo=bar', function () { + showdown.setOption('foo', 'bar'); + showdown.getOption('foo').should.equal('bar'); + showdown.resetOptions(); + expect(showdown.getOption('foo')).to.be.undefined(); + }); + }); + + describe('getDefaultOptions()', function () { + it('should get default options', function () { + var opts = require('../optionswp').getDefaultOpts(true); + expect(showdown.getDefaultOptions()).to.be.eql(opts); + }); + }); +}); + +describe('showdown.extension()', function () { + 'use strict'; + + var extObjMock = { + type: 'lang', + filter: function () {} + }, + extObjFunc = function () { + return extObjMock; + }; + + describe('should register', function () { + it('an extension object', function () { + showdown.extension('foo', extObjMock); + showdown.extension('foo').should.eql([extObjMock]); + showdown.resetExtensions(); + }); + + it('an extension function', function () { + showdown.extension('foo', extObjFunc); + showdown.extension('foo').should.eql([extObjMock]); + showdown.resetExtensions(); + }); + }); + + describe('should refuse to register', function () { + it('a generic object', function () { + var fn = function () { + showdown.extension('foo', {}); + }; + expect(fn).to.throw(); + }); + + it('an extension with invalid type', function () { + var fn = function () { + showdown.extension('foo', { + type: 'foo' + }); + }; + expect(fn).to.throw(/type .+? is not recognized\. Valid values: "lang" or "output"/); + }); + + it('an extension without regex or filter', function () { + var fn = function () { + showdown.extension('foo', { + type: 'lang' + }); + }; + expect(fn).to.throw(/extensions must define either a "regex" property or a "filter" method/); + }); + }); +}); + +describe('showdown.getAllExtensions()', function () { + 'use strict'; + var extObjMock = { + type: 'lang', + filter: function () {} + }; + + it('should return all extensions', function () { + showdown.extension('bar', extObjMock); + showdown.getAllExtensions().should.eql({bar: [extObjMock]}); + }); +}); diff --git a/test/node/testsuite.features.js b/test/node/testsuite.features.js new file mode 100644 index 0000000..933677a --- /dev/null +++ b/test/node/testsuite.features.js @@ -0,0 +1,50 @@ +/** + * Created by Estevao on 08-06-2015. + */ +var bootstrap = require('../bootstrap.js'), + showdown = bootstrap.showdown, + assertion = bootstrap.assertion, + testsuite = bootstrap.getTestSuite('test/features/'), + tableSuite = bootstrap.getTestSuite('test/features/tables/'); + +describe('makeHtml() features testsuite', function () { + 'use strict'; + for (var i = 0; i < testsuite.length; ++i) { + var converter; + if (testsuite[i].name === '#143.support_image_dimensions') { + converter = new showdown.Converter({parseImgDimensions: true}); + } else if (testsuite[i].name === '#69.header_level_start') { + converter = new showdown.Converter({headerLevelStart: 3}); + } else if (testsuite[i].name === '#164.1.simple_autolink') { + converter = new showdown.Converter({simplifiedAutoLink: true}); + } else if (testsuite[i].name === '#164.2.disallow_underscore_emphasis_mid_word') { + converter = new showdown.Converter({literalMidWordUnderscores: true}); + } else if (testsuite[i].name === '#164.3.strikethrough') { + converter = new showdown.Converter({strikethrough: true}); + } else if (testsuite[i].name === 'disable_gh_codeblocks') { + converter = new showdown.Converter({ghCodeBlocks: false}); + } else if (testsuite[i].name === '#164.4.tasklists') { + converter = new showdown.Converter({tasklists: true}); + } else if (testsuite[i].name === 'autolink_and_disallow_underscores') { + converter = new showdown.Converter({literalMidWordUnderscores: true, simplifiedAutoLink: true}); + } else { + converter = new showdown.Converter(); + } + it(testsuite[i].name, assertion(testsuite[i], converter)); + } + + describe('table support', function () { + var converter; + for (var i = 0; i < tableSuite.length; ++i) { + if (tableSuite[i].name === 'basic_with_header_ids') { + converter = new showdown.Converter({tables: true, tableHeaderId: true}); + } else if (tableSuite[i].name === '#179.parse_md_in_table_ths') { + converter = new showdown.Converter({tables: true, strikethrough: true}); + } else { + converter = new showdown.Converter({tables: true}); + } + it(tableSuite[i].name, assertion(tableSuite[i], converter)); + } + }); + +}); diff --git a/test/node/testsuite.ghost.js b/test/node/testsuite.ghost.js new file mode 100644 index 0000000..d720ef6 --- /dev/null +++ b/test/node/testsuite.ghost.js @@ -0,0 +1,22 @@ +/** + * Created by Estevao on 14-07-2015. + */ +var bootstrap = require('../bootstrap.js'), + converter = new bootstrap.showdown.Converter({ + strikethrough: true, + literalMidWordUnderscores: true, + simplifiedAutoLink: true, + tables: true, + parseImgDimensions: true, //extra + tasklists: true //extra + }), + assertion = bootstrap.assertion, + testsuite = bootstrap.getTestSuite('test/ghost/'); + +//MD-Testsuite (borrowed from karlcow/markdown-testsuite) +describe('makeHtml() ghost testsuite', function () { + 'use strict'; + for (var i = 0; i < testsuite.length; ++i) { + it(testsuite[i].name, assertion(testsuite[i], converter)); + } +}); diff --git a/test/node/testsuite.issues.js b/test/node/testsuite.issues.js new file mode 100644 index 0000000..e2563db --- /dev/null +++ b/test/node/testsuite.issues.js @@ -0,0 +1,14 @@ +/** + * Created by Estevao on 08-06-2015. + */ +var bootstrap = require('../bootstrap.js'), + converter = new bootstrap.showdown.Converter(), + assertion = bootstrap.assertion, + testsuite = bootstrap.getTestSuite('test/issues/'); + +describe('makeHtml() issues testsuite', function () { + 'use strict'; + for (var i = 0; i < testsuite.length; ++i) { + it(testsuite[i].name, assertion(testsuite[i], converter)); + } +}); diff --git a/test/node/testsuite.karlcow.js b/test/node/testsuite.karlcow.js new file mode 100644 index 0000000..2261dc2 --- /dev/null +++ b/test/node/testsuite.karlcow.js @@ -0,0 +1,12 @@ +var bootstrap = require('../bootstrap.js'), + converter = new bootstrap.showdown.Converter({noHeaderId: true}), + assertion = bootstrap.assertion, + testsuite = bootstrap.getTestSuite('test/karlcow/'); + +//MD-Testsuite (borrowed from karlcow/markdown-testsuite) +describe('makeHtml() karlcow testsuite', function () { + 'use strict'; + for (var i = 0; i < testsuite.length; ++i) { + it(testsuite[i].name, assertion(testsuite[i], converter)); + } +}); diff --git a/test/node/testsuite.standard.js b/test/node/testsuite.standard.js new file mode 100644 index 0000000..62c21c8 --- /dev/null +++ b/test/node/testsuite.standard.js @@ -0,0 +1,11 @@ +var bootstrap = require('../bootstrap.js'), + converter = new bootstrap.showdown.Converter(), + assertion = bootstrap.assertion, + testsuite = bootstrap.getTestSuite('test/cases/'); + +describe('makeHtml() standard testsuite', function () { + 'use strict'; + for (var i = 0; i < testsuite.length; ++i) { + it(testsuite[i].name, assertion(testsuite[i], converter)); + } +}); diff --git a/test/optionswp.js b/test/optionswp.js new file mode 100644 index 0000000..dd20264 --- /dev/null +++ b/test/optionswp.js @@ -0,0 +1,9 @@ +/* jshint ignore:start */ +var fs = require('fs'), + filedata; +filedata = fs.readFileSync('src/options.js', 'utf8'); +eval(filedata); +module.exports = { + getDefaultOpts: getDefaultOpts +}; +/* jshint ignore:end */ diff --git a/test/run.js b/test/run.js deleted file mode 100644 index 5e7a677..0000000 --- a/test/run.js +++ /dev/null @@ -1,86 +0,0 @@ -var showdown = new require('../src/showdown'), - fs = require('fs'), - path = require('path'), - should = require('should'); - - -var runTestsInDir = function(dir, converter) { - - // Load test cases from disk - var cases = fs.readdirSync(dir).filter(function(file){ - return ~file.indexOf('.md'); - }).map(function(file){ - return file.replace('.md', ''); - }); - - // Run each test case (markdown -> html) - showdown.forEach(cases, function(test){ - var name = test.replace(/[-.]/g, ' '); - it (name, function(){ - var mdpath = path.join(dir, test + '.md'), - htmlpath = path.join(dir, test + '.html'), - md = fs.readFileSync(mdpath, 'utf8'), - expected = fs.readFileSync(htmlpath, 'utf8').trim(), - actual = converter.makeHtml(md).trim(); - - // Normalize line returns - expected = expected.replace(/\r/g, ''); - - // Ignore all leading/trailing whitespace - expected = expected.split('\n').map(function(x){ - return x.trim(); - }).join('\n'); - actual = actual.split('\n').map(function(x){ - return x.trim(); - }).join('\n'); - - // Convert whitespace to a visible character so that it shows up on error reports - expected = expected.replace(/ /g, '·'); - expected = expected.replace(/\n/g, '•\n'); - actual = actual.replace(/ /g, '·'); - actual = actual.replace(/\n/g, '•\n'); - - // Compare - actual.should.equal(expected); - }); - }); -}; - - -// -// :: Markdown to HTML testing :: -// - -describe('Markdown', function() { - var converter = new showdown.converter(); - runTestsInDir('test/cases', converter); -}); - - -// -// :: Extensions Testing :: -// - -if (path.existsSync('test/extensions')) { - - describe('extensions', function() { - // Search all sub-folders looking for directory-specific tests - var extensions = fs.readdirSync('test/extensions').filter(function(file){ - return fs.lstatSync('test/extensions/' + file).isDirectory(); - }); - - // Run tests in each extension sub-folder - showdown.forEach(extensions, function(ext){ - // Make sure extension exists - var src = 'src/extensions/' + ext + '.js'; - if (!path.existsSync(src)) { - throw "Attempting tests for '" + ext + "' but source file (" + src + ") was not found."; - } - - var converter = new showdown.converter({ extensions: [ ext ] }); - var dir = 'test/extensions/' + ext; - runTestsInDir(dir, converter); - }); - }); - -}