fix(cli): cli now works properly

The CLI was completely rewrote. Changed dependency from yargs to commanderjs,
which is cleaner, faster and has no dependencies.
Also added a complete testsuite for the cli.

Closes #893, #894
This commit is contained in:
Estevao Soares dos Santos 2022-03-03 12:15:50 +00:00
parent 612dad0682
commit 3871765ac1
24 changed files with 903 additions and 478 deletions

View File

@ -13,12 +13,12 @@ module.exports = function (grunt) {
pkg: grunt.file.readJSON('package.json'),
concat: {
options: {
sourceMap: true,
banner: ';/*! <%= pkg.name %> v <%= pkg.version %> - <%= grunt.template.today("dd-mm-yyyy") %> */\n(function(){\n',
footer: '}).call(this);\n'
},
dist: {
options: {
sourceMap: true,
banner: ';/*! <%= pkg.name %> v <%= pkg.version %> - <%= grunt.template.today("dd-mm-yyyy") %> */\n(function(){\n',
footer: '}).call(this);\n'
},
src: [
'src/options.js',
'src/showdown.js',
@ -30,6 +30,12 @@ module.exports = function (grunt) {
],
dest: 'dist/<%= pkg.name %>.js'
},
cli: {
src: [
'src/cli/cli.js'
],
dest: 'bin/showdown.js'
},
test: {
src: '<%= concat.dist.src %>',
dest: '.build/<%= pkg.name %>.js',
@ -42,14 +48,23 @@ module.exports = function (grunt) {
clean: ['.build/'],
uglify: {
options: {
sourceMap: true,
banner: '/*! <%= pkg.name %> v <%= pkg.version %> - <%= grunt.template.today("dd-mm-yyyy") %> */'
},
dist: {
options: {
sourceMap: true,
banner: '/*! <%= pkg.name %> v <%= pkg.version %> - <%= grunt.template.today("dd-mm-yyyy") %> */'
},
files: {
'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
}
},
cli: {
options: {
sourceMap: false,
banner: '#!/usr/bin/env node'
},
files: {
'bin/showdown.js': ['<%= concat.cli.dest %>']
}
}
},
@ -164,6 +179,15 @@ module.exports = function (grunt) {
ignoreLeaks: false,
reporter: 'spec'
}
},
cli: {
src: 'test/node/testsuite.cli.js',
options: {
globals: ['should'],
timeout: 3000,
ignoreLeaks: false,
reporter: 'spec'
}
}
}
};
@ -227,19 +251,14 @@ module.exports = function (grunt) {
grunt.task.run(['lint', 'concat:test', 'simplemocha:single', 'clean']);
});
/**
* Test in Legacy Node
*/
grunt.registerTask('test-old', ['concat:test', 'simplemocha:node', 'clean']);
/**
* Tasks for new node versions
*/
grunt.registerTask('test', ['clean', 'lint', 'concat:test', 'simplemocha:node', 'clean']);
grunt.registerTask('test-cli', ['clean', 'lint', 'concat:test', 'simplemocha:cli', 'clean']);
grunt.registerTask('performance', ['concat:test', 'performancejs', 'clean']);
grunt.registerTask('build', ['test', 'concat:dist', 'uglify', 'endline']);
grunt.registerTask('prep-release', ['build', 'generate-changelog']);
grunt.registerTask('build', ['test', 'concat:dist', 'concat:cli', 'uglify:dist', 'uglify:cli', 'endline']);
grunt.registerTask('prep-release', ['build', 'performance', 'generate-changelog']);
// Default task(s).
grunt.registerTask('default', ['test']);

Binary file not shown.

BIN
dist/showdown.js vendored

Binary file not shown.

BIN
dist/showdown.js.map vendored

Binary file not shown.

BIN
dist/showdown.min.js vendored

Binary file not shown.

Binary file not shown.

276
package-lock.json generated
View File

@ -1,21 +1,22 @@
{
"name": "showdown",
"version": "2.0.0",
"version": "2.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "showdown",
"version": "2.0.0",
"version": "2.0.1",
"license": "MIT",
"dependencies": {
"yargs": "^17.2.1"
"commander": "^9.0.0"
},
"bin": {
"showdown": "bin/showdown.js"
},
"devDependencies": {
"chai": "^4.3.4",
"chai": "*",
"chai-match": "*",
"grunt": "^1.4.1",
"grunt-contrib-clean": "^2.0.0",
"grunt-contrib-concat": "^2.0.0",
@ -32,14 +33,14 @@
"quiet-grunt": "^0.2.0",
"semver": "^7.3.0",
"semver-sort": "^0.0.4",
"sinon": "^12.0.1",
"sinon": "*",
"source-map-support": "^0.5.20"
}
},
"node_modules/@eslint/eslintrc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.1.0.tgz",
"integrity": "sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.0.tgz",
"integrity": "sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
@ -84,9 +85,9 @@
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz",
"integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==",
"version": "0.9.5",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
"integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
"dev": true,
"dependencies": {
"@humanwhocodes/object-schema": "^1.2.1",
@ -113,9 +114,9 @@
}
},
"node_modules/@sinonjs/fake-timers": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz",
"integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==",
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.0.tgz",
"integrity": "sha512-M8vapsv9qQupMdzrVzkn5rb9jG7aUTEPAZdMtME2PuBaefksFZVE2C1g4LBRTkF/k3nRDNbDc5tp5NFC1PEYxA==",
"dev": true,
"dependencies": {
"@sinonjs/commons": "^1.7.0"
@ -264,6 +265,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -272,6 +274,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@ -493,6 +496,12 @@
"node": ">=4"
}
},
"node_modules/chai-match": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chai-match/-/chai-match-1.1.1.tgz",
"integrity": "sha1-OfsKLmt8j2OG3P6tSNFIqRX6bEY=",
"dev": true
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -574,6 +583,7 @@
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
@ -584,6 +594,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
@ -594,7 +605,8 @@
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/colors": {
"version": "1.1.2",
@ -617,6 +629,14 @@
"node": ">= 0.8"
}
},
"node_modules/commander": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.0.0.tgz",
"integrity": "sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw==",
"engines": {
"node": "^12.20.0 || >=14"
}
},
"node_modules/compare-func": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.4.tgz",
@ -1293,7 +1313,8 @@
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/entities": {
"version": "1.0.0",
@ -1314,6 +1335,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"dev": true,
"engines": {
"node": ">=6"
}
@ -1414,12 +1436,12 @@
}
},
"node_modules/eslint": {
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz",
"integrity": "sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==",
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.10.0.tgz",
"integrity": "sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw==",
"dev": true,
"dependencies": {
"@eslint/eslintrc": "^1.1.0",
"@eslint/eslintrc": "^1.2.0",
"@humanwhocodes/config-array": "^0.9.2",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
@ -1866,6 +1888,7 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@ -2294,14 +2317,14 @@
}
},
"node_modules/grunt-contrib-jshint": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-3.1.1.tgz",
"integrity": "sha512-EwMY6L91FqTcMlZTVoDeeq/EZL+7MoFyo1rxIea9sxyv73geVggeE37jcUhNbu5hLbxHE82CGIUqitHuR2/q+g==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-3.2.0.tgz",
"integrity": "sha512-pcXWCSZWfoMSvcV4BwH21TUtLtcX0Ms8IGuOPIcLeXK3fud9KclY7iqMKY94jFx8TxZzh028YYtpR+io8DiEaQ==",
"dev": true,
"dependencies": {
"chalk": "^4.1.0",
"chalk": "~4.1.2",
"hooker": "^0.2.3",
"jshint": "~2.13.0"
"jshint": "~2.13.4"
},
"engines": {
"node": ">=10"
@ -3011,6 +3034,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -3875,9 +3899,9 @@
}
},
"node_modules/mocha": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz",
"integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==",
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz",
"integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==",
"dev": true,
"dependencies": {
"@ungap/promise-all-settled": "1.1.2",
@ -3988,24 +4012,6 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/mocha/node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"dependencies": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/modify-values": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz",
@ -4774,6 +4780,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -4960,16 +4967,16 @@
"dev": true
},
"node_modules/sinon": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-12.0.1.tgz",
"integrity": "sha512-iGu29Xhym33ydkAT+aNQFBINakjq69kKO6ByPvTsm3yyIACfyQttRTP03aBP/I8GfhFmLzrnKwNNkr0ORb1udg==",
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-13.0.1.tgz",
"integrity": "sha512-8yx2wIvkBjIq/MGY1D9h1LMraYW+z1X0mb648KZnKSdvLasvDu7maa0dFaNYdTDczFgbjNw2tOmWdTk9saVfwQ==",
"dev": true,
"dependencies": {
"@sinonjs/commons": "^1.8.3",
"@sinonjs/fake-timers": "^8.1.0",
"@sinonjs/samsam": "^6.0.2",
"@sinonjs/fake-timers": "^9.0.0",
"@sinonjs/samsam": "^6.1.1",
"diff": "^5.0.0",
"nise": "^5.1.0",
"nise": "^5.1.1",
"supports-color": "^7.2.0"
},
"funding": {
@ -5077,6 +5084,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -5090,6 +5098,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@ -5287,9 +5296,9 @@
"dev": true
},
"node_modules/uglify-js": {
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.1.tgz",
"integrity": "sha512-FAGKF12fWdkpvNJZENacOH0e/83eG6JyVQyanIJaBXCN1J11TUQv1T1/z8S+Z0CG0ZPk1nPcreF/c7lrTd0TEQ==",
"version": "3.15.2",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz",
"integrity": "sha512-peeoTk3hSwYdoc9nrdiEJk+gx1ALCtTjdYuKSXMTDqq7n1W7dHPqWDdSi+BPL0ni2YMeHD7hKUSdbj3TZauY2A==",
"dev": true,
"bin": {
"uglifyjs": "bin/uglifyjs"
@ -5503,6 +5512,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@ -5570,6 +5580,7 @@
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true,
"engines": {
"node": ">=10"
}
@ -5581,20 +5592,21 @@
"dev": true
},
"node_modules/yargs": {
"version": "17.3.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz",
"integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==",
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"dependencies": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^21.0.0"
"yargs-parser": "^20.2.2"
},
"engines": {
"node": ">=12"
"node": ">=10"
}
},
"node_modules/yargs-parser": {
@ -5654,14 +5666,6 @@
"node": ">=8"
}
},
"node_modules/yargs/node_modules/yargs-parser": {
"version": "21.0.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz",
"integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==",
"engines": {
"node": ">=12"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@ -5677,9 +5681,9 @@
},
"dependencies": {
"@eslint/eslintrc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.1.0.tgz",
"integrity": "sha512-C1DfL7XX4nPqGd6jcP01W9pVM1HYCuUkFk1432D7F0v3JSlUIeOYn9oCoi3eoLZ+iwBSb29BMFxxny0YrrEZqg==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.0.tgz",
"integrity": "sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
@ -5717,9 +5721,9 @@
}
},
"@humanwhocodes/config-array": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz",
"integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==",
"version": "0.9.5",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
"integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
"dev": true,
"requires": {
"@humanwhocodes/object-schema": "^1.2.1",
@ -5743,9 +5747,9 @@
}
},
"@sinonjs/fake-timers": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz",
"integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==",
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.0.tgz",
"integrity": "sha512-M8vapsv9qQupMdzrVzkn5rb9jG7aUTEPAZdMtME2PuBaefksFZVE2C1g4LBRTkF/k3nRDNbDc5tp5NFC1PEYxA==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.0"
@ -5865,12 +5869,14 @@
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
@ -6044,6 +6050,12 @@
"type-detect": "^4.0.5"
}
},
"chai-match": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chai-match/-/chai-match-1.1.1.tgz",
"integrity": "sha1-OfsKLmt8j2OG3P6tSNFIqRX6bEY=",
"dev": true
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@ -6101,6 +6113,7 @@
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
@ -6111,6 +6124,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
@ -6118,7 +6132,8 @@
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"colors": {
"version": "1.1.2",
@ -6135,6 +6150,11 @@
"delayed-stream": "~1.0.0"
}
},
"commander": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.0.0.tgz",
"integrity": "sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw=="
},
"compare-func": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.4.tgz",
@ -6701,7 +6721,8 @@
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"entities": {
"version": "1.0.0",
@ -6721,7 +6742,8 @@
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"dev": true
},
"escape-string-regexp": {
"version": "4.0.0",
@ -6791,12 +6813,12 @@
}
},
"eslint": {
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz",
"integrity": "sha512-PB09IGwv4F4b0/atrbcMFboF/giawbBLVC7fyDamk5Wtey4Jh2K+rYaBhCAbUyEI4QzB1ly09Uglc9iCtFaG2Q==",
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.10.0.tgz",
"integrity": "sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw==",
"dev": true,
"requires": {
"@eslint/eslintrc": "^1.1.0",
"@eslint/eslintrc": "^1.2.0",
"@humanwhocodes/config-array": "^0.9.2",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
@ -7140,7 +7162,8 @@
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"get-func-name": {
"version": "2.0.0",
@ -7467,14 +7490,14 @@
}
},
"grunt-contrib-jshint": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-3.1.1.tgz",
"integrity": "sha512-EwMY6L91FqTcMlZTVoDeeq/EZL+7MoFyo1rxIea9sxyv73geVggeE37jcUhNbu5hLbxHE82CGIUqitHuR2/q+g==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-3.2.0.tgz",
"integrity": "sha512-pcXWCSZWfoMSvcV4BwH21TUtLtcX0Ms8IGuOPIcLeXK3fud9KclY7iqMKY94jFx8TxZzh028YYtpR+io8DiEaQ==",
"dev": true,
"requires": {
"chalk": "^4.1.0",
"chalk": "~4.1.2",
"hooker": "^0.2.3",
"jshint": "~2.13.0"
"jshint": "~2.13.4"
}
},
"grunt-contrib-uglify": {
@ -8021,7 +8044,8 @@
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"is-glob": {
"version": "4.0.3",
@ -8687,9 +8711,9 @@
"dev": true
},
"mocha": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz",
"integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==",
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz",
"integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==",
"dev": true,
"requires": {
"@ungap/promise-all-settled": "1.1.2",
@ -8770,21 +8794,6 @@
"requires": {
"has-flag": "^4.0.0"
}
},
"yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
}
}
}
},
@ -9382,7 +9391,8 @@
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true
},
"resolve": {
"version": "1.22.0",
@ -9522,16 +9532,16 @@
"dev": true
},
"sinon": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-12.0.1.tgz",
"integrity": "sha512-iGu29Xhym33ydkAT+aNQFBINakjq69kKO6ByPvTsm3yyIACfyQttRTP03aBP/I8GfhFmLzrnKwNNkr0ORb1udg==",
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-13.0.1.tgz",
"integrity": "sha512-8yx2wIvkBjIq/MGY1D9h1LMraYW+z1X0mb648KZnKSdvLasvDu7maa0dFaNYdTDczFgbjNw2tOmWdTk9saVfwQ==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.8.3",
"@sinonjs/fake-timers": "^8.1.0",
"@sinonjs/samsam": "^6.0.2",
"@sinonjs/fake-timers": "^9.0.0",
"@sinonjs/samsam": "^6.1.1",
"diff": "^5.0.0",
"nise": "^5.1.0",
"nise": "^5.1.1",
"supports-color": "^7.2.0"
}
},
@ -9628,6 +9638,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@ -9638,6 +9649,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
@ -9781,9 +9793,9 @@
"dev": true
},
"uglify-js": {
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.1.tgz",
"integrity": "sha512-FAGKF12fWdkpvNJZENacOH0e/83eG6JyVQyanIJaBXCN1J11TUQv1T1/z8S+Z0CG0ZPk1nPcreF/c7lrTd0TEQ==",
"version": "3.15.2",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz",
"integrity": "sha512-peeoTk3hSwYdoc9nrdiEJk+gx1ALCtTjdYuKSXMTDqq7n1W7dHPqWDdSi+BPL0ni2YMeHD7hKUSdbj3TZauY2A==",
"dev": true
},
"unc-path-regex": {
@ -9953,6 +9965,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@ -9993,7 +10006,8 @@
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true
},
"yallist": {
"version": "4.0.0",
@ -10002,24 +10016,18 @@
"dev": true
},
"yargs": {
"version": "17.3.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz",
"integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==",
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"requires": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^21.0.0"
},
"dependencies": {
"yargs-parser": {
"version": "21.0.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz",
"integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA=="
}
"yargs-parser": "^20.2.2"
}
},
"yargs-parser": {

View File

@ -38,8 +38,13 @@
"bin": {
"showdown": "bin/showdown.js"
},
"files": [
"bin",
"dist"
],
"devDependencies": {
"chai": "^4.3.4",
"chai": "*",
"chai-match": "*",
"grunt": "^1.4.1",
"grunt-contrib-clean": "^2.0.0",
"grunt-contrib-concat": "^2.0.0",
@ -56,10 +61,10 @@
"quiet-grunt": "^0.2.0",
"semver": "^7.3.0",
"semver-sort": "^0.0.4",
"sinon": "^12.0.1",
"sinon": "*",
"source-map-support": "^0.5.20"
},
"dependencies": {
"yargs": "^17.2.1"
"commander": "^9.0.0"
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,47 @@
# Performance Tests for showdown
## [version 2.0.1](https://github.com/showdownjs/showdown/tree/2.0.1)
### Test Suite: Basic (50 cycles)
| test | avgTime | max | min |
|:-----|--------:|----:|----:|
|Simple "Hello World"|0.387|11.381|0.104|
|performance.testfile.md|30.323|64.084|23.327|
### Test Suite: subParsers (20 cycles)
| test | avgTime | max | min |
|:-----|--------:|----:|----:|
|hashHTMLBlocks|4.436|7.669|2.275|
|anchors|0.315|0.977|0.256|
|autoLinks|0.083|0.230|0.072|
|blockQuotes|4.347|13.862|2.032|
|codeBlocks|0.217|0.371|0.203|
|codeSpans|0.311|0.734|0.226|
|detab|0.062|0.140|0.045|
|encodeAmpsAndAngles|0.168|1.440|0.091|
|encodeBackslashEscapes|0.073|0.150|0.061|
|encodeCode|0.601|1.737|0.526|
|escapeSpecialCharsWithinTagAttributes|0.211|0.289|0.195|
|githubCodeBlocks|0.169|0.267|0.149|
|hashBlock|0.038|0.114|0.034|
|hashElement|0.004|0.057|0.001|
|hashHTMLSpans|4.053|4.394|3.930|
|hashPreCodeTags|0.248|1.891|0.112|
|headers|1.273|3.145|1.023|
|horizontalRule|0.180|0.418|0.147|
|images|0.149|0.402|0.122|
|italicsAndBold|0.278|1.041|0.209|
|lists|2.979|4.758|2.270|
|outdent|0.208|0.427|0.160|
|paragraphs|5.247|7.341|4.531|
|spanGamut|4.851|10.235|3.512|
|strikethrough|0.007|0.101|0.001|
|stripLinkDefinitions|1.714|2.990|1.463|
|tables|0.008|0.108|0.001|
|unescapeSpecialChars|0.012|0.079|0.008|
## [version 1.9.0](https://github.com/showdownjs/showdown/tree/1.9.0)
### Test Suite: Basic (50 cycles)

View File

@ -1,45 +1,324 @@
/**
* Created by tivie
*/
'use strict';
var fs = require('fs'),
json = JSON.parse(fs.readFileSync('package.json', 'utf8')),
version = json.version,
Command = require('commander').Command,
program = new Command(),
showdown;
var yargs = require('yargs');
yargs
.version()
.alias('v', 'version')
.option('h', {
alias: 'help',
description: 'Show help'
})
.option('q', {
alias: 'quiet',
description: 'Quiet mode. Only print errors',
type: 'boolean',
default: false
})
.option('m', {
alias: 'mute',
description: 'Mute mode. Does not print anything',
type: 'boolean',
default: false
})
.usage('Usage: showdown <command> [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();
// require shodown. We use conditional loading for each use case
if (fs.existsSync('../dist/showdown.js')) {
// production. File lives in bin directory
showdown = require('../dist/showdown');
} else if (fs.existsSync('../../.build/showdown.js')) {
// testing envo, uses the concatenated stuff for testing
showdown = require('../../.build/showdown.js');
} else {
yargs.showHelp();
// cold testing (manual) of cli.js in the src file. We load the dist file
showdown = require('../../dist/showdown');
}
if (argv.help) {
yargs.showHelp();
program
.name('showdown')
.description('CLI to Showdownjs markdown parser v' + version)
.version(version)
.usage('<command> [options]')
.option('-q, --quiet', 'Quiet mode. Only print errors')
.option('-m, --mute', 'Mute mode. Does not print anything');
program.command('makehtml')
.description('Converts markdown into html')
.addHelpText('after', '\n\nExamples:')
.addHelpText('after', ' showdown makehtml -i Reads from stdin and outputs to stdout')
.addHelpText('after', ' showdown makehtml -i foo.md -o bar.html Reads \'foo.md\' and writes to \'bar.html\'')
.addHelpText('after', ' showdown makehtml -i --flavor="github" Parses stdin using GFM style')
.addHelpText('after', '\nNote for windows users:')
.addHelpText('after', 'When reading from stdin, use option -u to set the proper encoding or run `chcp 65001` prior to calling showdown cli to set the command line to utf-8')
.option('-i, --input [file]', 'Input source. Usually a md file. If omitted or empty, reads from stdin. Windows users see note below.', true)
.option('-o, --output [file]', 'Output target. Usually a html file. If omitted or empty, writes to stdout', true)
.option('-u, --encoding <encoding>', 'Sets the input encoding', 'utf8')
.option('-y, --output-encoding <encoding>', 'Sets the output encoding', 'utf8')
.option('-a, --append', 'Append data to output instead of overwriting. Ignored if writing to stdout', false)
.option('-e, --extensions <extensions...>', 'Load the specified extensions. Should be valid paths to node compatible extensions')
.option('-p, --flavor <flavor>', 'Run with a predetermined flavor of options. Default is vanilla', 'vanilla')
.option('-c, --config <config...>', 'Enables showdown makehtml parser config options. Overrides flavor')
.option('--config-help', 'Shows configuration options for showdown parser')
.action(makehtmlCommand);
program.parse();
//
// HELPER FUCNTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Messenger helper object to the CLI
* @param {string} writeMode
* @param {boolean} supress
* @param {boolean} mute
* @constructor
*/
function Messenger (writeMode, supress, mute) {
'use strict';
writeMode = writeMode || 'stderr';
supress = (!!supress || !!mute);
mute = !!mute;
this._print = (writeMode === 'stdout') ? console.log : console.error;
this.errorExit = function (e) {
if (!mute) {
console.error('ERROR: ' + e.message);
console.error('Run \'showdown <command> -h\' for help');
}
process.exit(1);
};
this.okExit = function () {
if (!mute) {
this._print('\n');
this._print('DONE!');
}
process.exit(0);
};
this.printMsg = function (msg) {
if (supress || mute || !msg) {
return;
}
this._print(msg);
};
this.printError = function (msg) {
if (mute) {
return;
}
console.error(msg);
};
}
/**
* Helper function to show Showdown Options
*/
function showShowdownOptions () {
'use strict';
var showdownOptions = showdown.getDefaultOptions(false);
console.log('\nshowdown makehtml config options:');
// show showdown options
for (var sopt in showdownOptions) {
if (showdownOptions.hasOwnProperty(sopt)) {
console.log(' ' + sopt + ':', '[default=' + showdownOptions[sopt].defaultValue + ']',showdownOptions[sopt].describe);
}
}
console.log('\n\nExample: showdown makehtml -c openLinksInNewWindow ghMentions ghMentionsLink="https://google.com"');
}
/**
* Helper function to parse showdown options
* @param {{}} configOptions
* @param {{}} defaultOptions
* @returns {{}}
*/
function parseShowdownOptions (configOptions, defaultOptions) {
'use strict';
var shOpt = defaultOptions;
// first prepare passed options
if (configOptions) {
for (var i = 0; i < configOptions.length; ++i) {
var opt = configOptions[i],
key = configOptions[i],
val = true;
if (/=/.test(opt)) {
key = opt.split('=')[0];
val = opt.split('=')[1];
}
shOpt[key] = val;
}
}
return shOpt;
}
/**
* Reads stdin
* @returns {string}
*/
function readFromStdIn (encoding) {
'use strict';
var size = fs.fstatSync(process.stdin.fd).size;
if (size <= 0) {
throw new Error('Could not read from stdin, reason: stdin is empty');
}
encoding = encoding || 'utf8';
try {
return size > 0 ? fs.readFileSync(process.stdin.fd, encoding).toString() : '';
} catch (e) {
throw new Error('Could not read from stdin, reason: ' + e.message);
}
}
/**
* Reads from a file
* @param {string} file Filepath to dile
* @param {string} encoding Encoding of the file
* @returns {Buffer}
*/
function readFromFile (file, encoding) {
'use strict';
try {
return fs.readFileSync(file, encoding);
} catch (err) {
throw new Error('Could not read from file ' + file + ', reason: ' + err.message);
}
}
/**
* Writes to stdout
* @param {string} html
* @returns {boolean}
*/
function writeToStdOut (html) {
'use strict';
if (!process.stdout.write(html)) {
throw new Error('Could not write to StdOut');
}
}
/**
* Writes to file
* @param {string} html HTML to write
* @param {string} file Filepath
* @param {boolean} append If the result should be appended
*/
function writeToFile (html, file, append) {
'use strict';
// If a flag is passed, it means we should append instead of overwriting.
// Only works with files, obviously
var write = (append) ? fs.appendFileSync : fs.writeFileSync;
try {
write(file, html);
} catch (err) {
throw new Error('Could not write to file ' + file + ', readon: ' + err.message);
}
}
/**
* makehtml command
* @param {{}} options
* @param {Command} cmd
*/
function makehtmlCommand (options, cmd) {
'use strict';
// show configuration options for showdown helper if configHelp was passed
if (options.configHelp) {
showShowdownOptions();
return;
}
var quiet = !!(cmd.parent._optionValues.quiet),
mute = !!(cmd.parent._optionValues.mute),
readMode = (!options.input || options.input === '' || options.input === true) ? 'stdin' : 'file',
writeMode = (!options.output || options.output === '' || options.output === true) ? 'stdout' : 'file',
msgMode = (writeMode === 'file') ? 'stdout' : 'stderr',
// initiate Messenger helper, can maybe be replaced with commanderjs internal stuff
messenger = new Messenger(msgMode, quiet, mute),
defaultOptions = showdown.getDefaultOptions(true),
md, html;
// deal with flavor first since config flag overrides flavor individual options
if (options.flavor) {
messenger.printMsg('Enabling flavor ' + options.flavor + '...');
defaultOptions = showdown.getFlavorOptions(options.flavor);
if (!defaultOptions) {
messenger.errorExit(new Error('Flavor ' + options.flavor + ' is not recognised'));
return;
}
messenger.printMsg('OK!');
}
// store config options in the options.config as an object
options.config = parseShowdownOptions(options.config, defaultOptions);
// print enabled options
for (var o in options.config) {
if (options.config.hasOwnProperty(o) && options.config[o] === true) {
messenger.printMsg('Enabling option ' + o);
}
}
// initialize the converter
messenger.printMsg('\nInitializing converter...');
var converter;
try {
converter = new showdown.Converter(options.config);
} catch (e) {
messenger.errorExit(e);
return;
}
messenger.printMsg('OK!');
// load extensions
if (options.extensions) {
messenger.printMsg('\nLoading extensions...');
for (var i = 0; i < options.extensions.length; ++i) {
try {
messenger.printMsg(options.extensions[i]);
var ext = require(options.extensions[i]);
converter.addExtension(ext, options.extensions[i]);
messenger.printMsg(options.extensions[i] + ' loaded...');
} catch (e) {
messenger.printError('Could not load extension ' + options.extensions[i] + '. Reason:');
messenger.errorExit(e);
}
}
}
messenger.printMsg('...');
// read the input
messenger.printMsg('Reading data from ' + readMode + '...');
if (readMode === 'stdin') {
try {
md = readFromStdIn(options.encoding);
} catch (err) {
messenger.errorExit(err);
return;
}
} else {
try {
md = readFromFile(options.input, options.encoding);
} catch (err) {
messenger.errorExit(err);
return;
}
}
// process the input
messenger.printMsg('Parsing markdown...');
html = converter.makeHtml(md);
// write the output
messenger.printMsg('Writing data to ' + writeMode + '...');
if (writeMode === 'stdout') {
try {
writeToStdOut(html);
} catch (err) {
messenger.errorExit(err);
return;
}
} else {
try {
writeToFile(html, options.output, options.append);
} catch (err) {
messenger.errorExit(err);
return;
}
}
messenger.okExit();
}
process.exit(0);

View File

@ -1,195 +0,0 @@
var yargs = require('yargs'),
fs = require('fs'),
Messenger = require('./messenger.js'),
showdown = require('../../dist/showdown'),
showdownOptions = showdown.getDefaultOptions(false);
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\'')
.example('showdown makehtml -i --flavor="github"', 'Parses stdin using GFM style')
.version()
.alias('v', 'version')
.config('c')
.alias('c', 'config')
.help('h')
.alias('h', 'help')
.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',
default: false
})
.option('e', {
alias : 'extensions',
describe: 'Load the specified extensions. Should be valid paths to node compatible extensions',
type: 'array'
})
.option('p', {
alias : 'flavor',
describe: 'Run with a predetermined flavor of options. Default is vanilla',
type: 'string'
})
.option('q', {
alias: 'quiet',
description: 'Quiet mode. Only print errors',
type: 'boolean',
default: false
})
.option('m', {
alias: 'mute',
description: 'Mute mode. Does not print anything',
type: 'boolean',
default: false
});
// load showdown default options
for (var opt in showdownOptions) {
if (showdownOptions.hasOwnProperty(opt)) {
if (showdownOptions[opt].defaultValue === false) {
showdownOptions[opt].default = null;
} else {
showdownOptions[opt].default = showdownOptions[opt].defaultValue;
}
yargs.option(opt, showdownOptions[opt]);
}
}
function run () {
'use strict';
var argv = yargs.argv,
readMode = (!argv.i || argv.i === '') ? 'stdin' : 'file',
writeMode = (!argv.o || argv.o === '') ? 'stdout' : 'file',
msgMode = (writeMode === 'file') ? 'stdout' : 'stderr',
/**
* MSG object
* @type {Messenger}
*/
messenger = new Messenger(msgMode, argv.q, argv.m),
read = (readMode === 'stdin') ? readFromStdIn : readFromFile,
write = (writeMode === 'stdout') ? writeToStdOut : writeToFile,
enc = argv.encoding || 'utf8',
flavor = argv.p,
append = argv.a || false,
options = parseOptions(flavor),
converter = new showdown.Converter(options),
md, html;
// Load extensions
if (argv.e) {
messenger.printMsg('Loading extensions');
for (var i = 0; i < argv.e.length; ++i) {
try {
var ext = require(argv.e[i]);
converter.addExtension(ext, argv.e[i]);
} catch (e) {
messenger.printError('Could not load extension ' + argv.e[i] + '. Reason:');
messenger.errorExit(e);
}
}
}
messenger.printMsg('...');
// read the input
messenger.printMsg('Reading data from ' + readMode + '...');
md = read(enc);
// process the input
messenger.printMsg('Parsing markdown...');
html = converter.makeHtml(md);
// write the output
messenger.printMsg('Writing data to ' + writeMode + '...');
write(html, append);
messenger.okExit();
function parseOptions (flavor) {
var options = {},
flavorOpts = showdown.getFlavorOptions(flavor) || {};
// if flavor is not undefined, let's tell the user we're loading that preset
if (flavor) {
messenger.printMsg('Loading ' + flavor + ' flavor.');
}
for (var opt in argv) {
if (argv.hasOwnProperty(opt)) {
// first we load the default options
if (showdownOptions.hasOwnProperty(opt) && showdownOptions[opt].default !== null) {
options[opt] = showdownOptions[opt].default;
}
// we now override defaults with flavor, if a flavor was indeed passed
if (flavorOpts.hasOwnProperty(opt)) {
options[opt] = flavorOpts[opt];
}
// lastly we override with explicit passed options
// being careful not to pass CLI specific options, such as -v, -h or --extensions
if (showdownOptions.hasOwnProperty(opt)) {
if (argv[opt] === true) {
messenger.printMsg('Enabling option ' + opt);
options[opt] = argv[opt];
} else if (argv[opt] === false) {
options[opt] = argv[opt];
}
}
}
}
return options;
}
function readFromStdIn () {
try {
var size = fs.fstatSync(process.stdin.fd).size;
return size > 0 ? fs.readSync(process.stdin.fd, size)[0] : '';
} catch (e) {
var err = new Error('Could not read from stdin, reason: ' + e.message);
messenger.errorExit(err);
}
}
function readFromFile (encoding) {
try {
return fs.readFileSync(argv.i, encoding);
} catch (err) {
messenger.errorExit(err);
}
}
function writeToStdOut (html) {
return process.stdout.write(html);
}
function writeToFile (html, append) {
// If a flag is passed, it means we should append instead of overwriting.
// Only works with files, obviously
var write = (append) ? fs.appendFileSync : fs.writeFileSync;
try {
write(argv.o, html);
} catch (err) {
messenger.errorExit(err);
}
}
}
module.exports = exports = {
run: run
};

View File

@ -1,40 +0,0 @@
function Messenger (writeMode, supress, mute) {
'use strict';
writeMode = writeMode || 'stderr';
supress = (!!supress || !!mute);
mute = !!mute;
this._print = (writeMode === 'stdout') ? console.log : console.error;
this.errorExit = function (e) {
if (!mute) {
console.error('ERROR: ' + e.message);
console.error('Run \'showdown <command> -h\' for help');
}
process.exit(1);
};
this.okExit = function () {
if (!mute) {
this._print('\n');
this._print('DONE!');
}
process.exit(0);
};
this.printMsg = function (msg) {
if (supress || mute || !msg) {
return;
}
this._print(msg);
};
this.printError = function (msg) {
if (mute) {
return;
}
console.error(msg);
};
}
module.exports = Messenger;

View File

@ -98,77 +98,77 @@ function getDefaultOpts (simple) {
},
smartIndentationFix: {
defaultValue: false,
description: 'Tries to smartly fix indentation in es6 strings',
describe: 'Tries to smartly fix indentation in es6 strings',
type: 'boolean'
},
disableForced4SpacesIndentedSublists: {
defaultValue: false,
description: 'Disables the requirement of indenting nested sublists by 4 spaces',
describe: 'Disables the requirement of indenting nested sublists by 4 spaces',
type: 'boolean'
},
simpleLineBreaks: {
defaultValue: false,
description: 'Parses simple line breaks as <br> (GFM Style)',
describe: 'Parses simple line breaks as <br> (GFM Style)',
type: 'boolean'
},
requireSpaceBeforeHeadingText: {
defaultValue: false,
description: 'Makes adding a space between `#` and the header text mandatory (GFM Style)',
describe: 'Makes adding a space between `#` and the header text mandatory (GFM Style)',
type: 'boolean'
},
ghMentions: {
defaultValue: false,
description: 'Enables github @mentions',
describe: 'Enables github @mentions',
type: 'boolean'
},
ghMentionsLink: {
defaultValue: 'https://github.com/{u}',
description: 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.',
describe: 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.',
type: 'string'
},
encodeEmails: {
defaultValue: true,
description: 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities',
describe: 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities',
type: 'boolean'
},
openLinksInNewWindow: {
defaultValue: false,
description: 'Open all links in new windows',
describe: 'Open all links in new windows',
type: 'boolean'
},
backslashEscapesHTMLTags: {
defaultValue: false,
description: 'Support for HTML Tag escaping. ex: \<div>foo\</div>',
describe: 'Support for HTML Tag escaping. ex: \<div>foo\</div>',
type: 'boolean'
},
emoji: {
defaultValue: false,
description: 'Enable emoji support. Ex: `this is a :smile: emoji`',
describe: 'Enable emoji support. Ex: `this is a :smile: emoji`',
type: 'boolean'
},
underline: {
defaultValue: false,
description: 'Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `<em>` and `<strong>`',
describe: 'Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `<em>` and `<strong>`',
type: 'boolean'
},
ellipsis: {
defaultValue: true,
description: 'Replaces three dots with the ellipsis unicode character',
describe: 'Replaces three dots with the ellipsis unicode character',
type: 'boolean'
},
completeHTMLDocument: {
defaultValue: false,
description: 'Outputs a complete html document, including `<html>`, `<head>` and `<body>` tags',
describe: 'Outputs a complete html document, including `<html>`, `<head>` and `<body>` tags',
type: 'boolean'
},
metadata: {
defaultValue: false,
description: 'Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).',
describe: 'Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).',
type: 'boolean'
},
splitAdjacentBlockquotes: {
defaultValue: false,
description: 'Split adjacent blockquote blocks',
describe: 'Split adjacent blockquote blocks',
type: 'boolean'
}
};

View File

@ -188,7 +188,7 @@ showdown.subParser = function (name, func) {
* Gets or registers an extension
* @static
* @param {string} name
* @param {object|function=} ext
* @param {object|object[]|function=} ext
* @returns {*}
*/
showdown.extension = function (name, ext) {

View File

@ -1,3 +1,2 @@
<h1 id="sometitle">some title</h1>
<p>Test <strong>bold</strong> and <em>italic</em></p>

View File

@ -0,0 +1,14 @@
var showdown = require('../../.build/showdown.js');
var ext = {
type: 'lang',
regex: /foo/g,
replace: 'bar'
};
showdown.extension('mockextension', function () {
'use strict';
return [ext];
});
module.exports = ext;

View File

@ -1,18 +0,0 @@
/*
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 -q', {
encoding: 'utf8',
input: '**foo**'
});
otp.trim().should.equal('<p><strong>foo</strong></p>');
});
}
});
*/

293
test/node/testsuite.cli.js Normal file
View File

@ -0,0 +1,293 @@
var fs = require('fs'),
path = require('path'),
chai = require('chai'),
expect = chai.expect,
chaiMatch = require('chai-match'),
execSync = require('child_process').execSync,
spawnSync = require('child_process').spawnSync,
cmd = 'node src/cli/cli.js',
packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
require('sinon');
chai.should();
chai.use(chaiMatch);
/**
* Spawns a CLI process synchrously
* @param {string|null} command
* @param {string[]} args
* @param {{}} [options]
* @returns {{output: *, stdout: string, stderr: string, status: number}}
*/
function spawnCLI (command, args, options) {
'use strict';
var nargs = ['src/cli/cli.js'];
if (command) { nargs.push(command);}
args = nargs.concat(args);
var otp = spawnSync('node', args, options),
stdout = otp.stdout.toString(),
stderr = otp.stderr.toString(),
output = otp.output[0],
status = otp.status;
return {stdout: stdout, stderr: stderr, output: output, status: status};
}
describe('showdown cli', function () {
'use strict';
describe('without commands', function () {
it('should display help if no commands are specified', function () {
var proc = spawnCLI(null, [], {});
proc.status.should.equal(1);
proc.stderr.should.contain('CLI to Showdownjs markdown parser');
proc.stderr.should.contain('Usage:');
proc.stderr.should.contain('Options:');
proc.stderr.should.contain('Commands:');
proc.stdout.should.equal('');
});
describe('-h', function () {
it('should display help', function () {
var proc = spawnCLI(null, ['-h'], {});
proc.status.should.equal(0);
proc.stdout.should.contain('CLI to Showdownjs markdown parser');
proc.stdout.should.contain('Usage:');
proc.stdout.should.contain('Options:');
proc.stdout.should.contain('Commands:');
proc.stderr.should.equal('');
});
});
describe('-v', function () {
it('should display version', function () {
var proc = spawnCLI(null, ['-V'], {});
proc.status.should.equal(0);
proc.stdout.should.match(/^\d{1,2}\.\d{1,3}\.\d{1,3}/);
proc.stdout.should.match(/^(\d{1,2}\.\d{1,3}\.\d{1,3})/).and.capture(0).equals(packageJson.version);
proc.stderr.should.equal('');
});
});
});
describe('makehtml command', function () {
describe('makehtml without flags', function () {
it('should read from stdin and output to stdout', function () {
var proc = spawnCLI('makehtml', [], {
input: '**foo**',
encoding: 'utf-8'
});
proc.status.should.equal(0);
proc.stdout.should.equal('<p><strong>foo</strong></p>');
proc.stderr.should.not.equal('');
});
});
describe('makehtml -p', function () {
it('should enable a flavor', function () {
var proc = spawnCLI('makehtml', ['-p', 'github'], {
input: 'this is a :smile:', // test the emoji option as a proxy
encoding: 'utf-8'
});
proc.status.should.equal(0);
proc.stderr.should.contain('Enabling flavor github...');
proc.stdout.should.equal('<p>this is a 😄</p>');
//'Here in London'.should.match(/(here|there) in (\w+)/i).and.capture(1).equals('London');
});
it('should give an error if a flavor is not recognised', function () {
var proc = spawnCLI('makehtml', ['-p', 'foobar'], {
input: '**foo**',
encoding: 'utf-8'
});
proc.status.should.equal(1);
});
});
describe('makehtml -c', function () {
it('should not parse emoji if config option is not passed', function () {
var proc = spawnCLI('makehtml', [], {
input: 'this is a :smile:',
encoding: 'utf-8'
});
proc.status.should.equal(0);
proc.stderr.should.not.contain('Enabling option emoji');
proc.stdout.should.equal('<p>this is a :smile:</p>');
});
it('should enable a showdown option', function () {
var proc = spawnCLI('makehtml', ['-c', 'emoji'], {
input: 'this is a :smile:',
encoding: 'utf-8'
});
proc.status.should.equal(0);
proc.stderr.should.contain('Enabling option emoji');
proc.stdout.should.equal('<p>this is a 😄</p>');
});
it('should ignore unrecognized options', function () {
var proc = spawnCLI('makehtml', ['-c', 'foobar'], {
input: 'foo',
encoding: 'utf-8'
});
proc.status.should.equal(0);
proc.stderr.should.contain('Enabling option foobar');
proc.stdout.should.equal('<p>foo</p>');
});
});
describe('makehtml -m', function () {
it('should mute information', function () {
var proc = spawnCLI('makehtml', ['-m', '-i'], {input: '**foo**'});
proc.status.should.equal(0);
expect(proc.output).to.be.null; // jshint ignore:line
proc.stdout.should.equal('<p><strong>foo</strong></p>');
proc.stderr.should.equal('');
});
it('should mute everything, even errors', function () {
var proc = spawnCLI('makehtml', ['-m', '-i']);
proc.status.should.equal(1);
expect(proc.output).to.be.null; // jshint ignore:line
proc.stdout.should.equal('');
proc.stderr.should.equal('');
});
it('should not mute parsed html', function () {
var proc = spawnCLI('makehtml', ['-m', '-i'], {
input: '**foo**',
encoding: 'utf-8'
});
proc.status.should.equal(0);
proc.stdout.should.equal('<p><strong>foo</strong></p>');
proc.stderr.should.equal('');
});
});
describe('makehtml -q', function () {
it('should not display information', function () {
var proc = spawnCLI('makehtml', ['-q', '-i'], {input: '**foo**'});
proc.status.should.equal(0);
expect(proc.output).to.be.null; // jshint ignore:line
proc.stdout.should.equal('<p><strong>foo</strong></p>');
proc.stderr.should.match(/^\s*DONE!\s*$/);
});
it('should display errors', function () {
var proc = spawnCLI('makehtml', ['-q', '-i']);
proc.status.should.equal(1);
expect(proc.output).to.be.null; // jshint ignore:line
proc.stdout.should.equal('');
proc.stderr.should.match(/^ERROR:/);
});
it('should not mute parsed html', function () {
var proc = spawnCLI('makehtml', ['-q', '-i'], {
input: '**foo**',
encoding: 'utf-8'
});
proc.status.should.equal(0);
proc.stdout.should.equal('<p><strong>foo</strong></p>');
proc.stderr.should.match(/^\s*DONE!\s*$/);
});
});
describe('makehtml -i -o', function () {
it('should read from stdin and output to stdout', function () {
var proc = spawnCLI('makehtml', ['-i', '-o'], {
input: '**foo**',
encoding: 'utf-8'
});
proc.status.should.equal(0);
proc.stdout.should.equal('<p><strong>foo</strong></p>');
proc.stderr.should.not.equal('');
});
});
describe('makehtml -i <file> -o', function () {
it('should read from a file and output to stdout', function () {
var expectedOtp = fs.readFileSync('test/cli/basic.html', 'utf8').toString().trim(),
proc = spawnCLI('makehtml', ['-i', 'test/cli/basic.md'], {encoding: 'utf-8'});
proc.status.should.equal(0);
proc.stdout.should.equal(expectedOtp);
proc.stderr.should.not.equal('');
});
});
describe('makehtml -i -o <file>', function () {
it('should read from stdin and output to a file', function () {
execSync(cmd + ' makehtml -m -i -o .build/io1.html', {
encoding: 'utf8',
input: '**foo**'
});
var otp = fs.readFileSync('.build/io1.html', 'utf8').toString().trim(),
expectedOtp = '<p><strong>foo</strong></p>';
otp.trim().should.equal(expectedOtp);
});
});
describe('makehtml -i <file> -o <file>', function () {
it('should read from a file and output to a file', function () {
var expectedOtp = fs.readFileSync('test/cli/basic.html', 'utf8').toString().trim(),
proc = spawnCLI('makehtml', ['-i', 'test/cli/basic.md', '-o', '.build/io2.html'], {encoding: 'utf-8'}),
otp = fs.readFileSync('.build/io2.html', 'utf8').toString().trim();
otp.trim().should.equal(expectedOtp);
proc.stdout.should.not.equal(expectedOtp);
proc.stderr.should.equal('');
proc.status.should.equal(0);
});
});
describe('makehtml -a', function () {
it('should read from stdin and append to a file', function () {
fs.writeFileSync('.build/io3.html', '<p>foo</p>');
var expectedOtp = '<p>foo</p><p><strong>foo</strong></p>',
proc = spawnCLI('makehtml', ['-i', '-o', '.build/io3.html', '-a'], {
encoding: 'utf8',
input: '**foo**'
}),
otp = fs.readFileSync('.build/io3.html', 'utf8').toString().trim();
proc.status.should.equal(0);
otp.trim().should.equal(expectedOtp);
// since the output is to a file, messages are logged to stdout
proc.stdout.should.not.equal(expectedOtp);
// stderr should be empty
proc.stderr.should.equal('');
});
it('should ignore -a flag if -o <file> is missing', function () {
var expectedOtp = '<p><strong>foo</strong></p>',
proc = spawnCLI('makehtml', ['-a'], {encoding: 'utf8', input: '**foo**'});
proc.status.should.equal(0);
proc.stderr.should.not.equal('');
proc.stdout.should.equal(expectedOtp);
});
});
describe('makehtml -e', function () {
it('should load the extension', function () {
var expectedOtp = '<p><strong>bar</strong></p>',
extPath = path.resolve(__dirname + '/../mocks/mock-extension.js'),
proc = spawnCLI('makehtml', ['-i', '-o', '-e', extPath], {
encoding: 'utf8',
input: '**foo**'
});
proc.status.should.equal(0, 'Process exited with error state');
proc.stdout.trim().should.equal(expectedOtp);
});
});
});
});

View File

@ -3,6 +3,7 @@ require('chai').should();
var expect = require('chai').expect,
showdown = require('../bootstrap').showdown;
describe('showdown.options', function () {
'use strict';
@ -34,21 +35,37 @@ describe('showdown.extension()', function () {
return extObjMock;
};
describe('should register', function () {
it('an extension object', function () {
describe('file loading', function () {
beforeEach(function () {
this.extension = require('../mocks/mock-extension');
});
it('should register an extension from a file', function () {
showdown.extension('mockextension').should.be.an('array');
showdown.extension('mockextension').should.eql([this.extension]);
});
afterEach(function () {
showdown.resetExtensions();
});
});
describe('objects', function () {
it('should register 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();
it('should register an extension function', function () {
showdown.extension('bar', extObjFunc);
showdown.extension('bar').should.eql([extObjMock]);
});
it('a listener extension', function () {
showdown.extension('foo', {
it('should register a listener extension', function () {
showdown.extension('baz', {
type: 'listener',
listeners: {
foo: function (name, txt) {
@ -56,19 +73,16 @@ describe('showdown.extension()', function () {
}
}
});
showdown.resetExtensions();
});
});
describe('should refuse to register', function () {
it('a generic object', function () {
it('should refuse to register a generic object', function () {
var fn = function () {
showdown.extension('foo', {});
};
expect(fn).to.throw();
});
it('an extension with invalid type', function () {
it('should refuse to register an extension with invalid type', function () {
var fn = function () {
showdown.extension('foo', {
type: 'foo'
@ -77,7 +91,7 @@ describe('showdown.extension()', function () {
expect(fn).to.throw(/type .+? is not recognized\. Valid values: "lang\/language", "output\/html" or "listener"/);
});
it('an extension without regex or filter', function () {
it('should refuse to register an extension without regex or filter', function () {
var fn = function () {
showdown.extension('foo', {
type: 'lang'
@ -86,7 +100,7 @@ describe('showdown.extension()', function () {
expect(fn).to.throw(/extensions must define either a "regex" property or a "filter" method/);
});
it('a listener extension without a listeners property', function () {
it('should refuse to register a listener extension without a listeners property', function () {
var fn = function () {
showdown.extension('foo', {
type: 'listener'
@ -94,7 +108,13 @@ describe('showdown.extension()', function () {
};
expect(fn).to.throw(/Extensions of type "listener" must have a property called "listeners"/);
});
afterEach(function () {
showdown.resetExtensions();
});
});
});
describe('showdown.getAllExtensions()', function () {