diff --git a/.flowconfig b/.flowconfig index 6f52e39..f5e83a0 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,6 +1,4 @@ [ignore] -.*node_modules/babel.* -.*node_modules/fbjs.* [include] @@ -8,5 +6,6 @@ [options] esproposal.class_static_fields=enable +module.system=haste suppress_type=$FlowIssue suppress_comment=\\(.\\|\n\\)*\\$FlowIssue diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b14ae35 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +test/*.txt text eol=lf \ No newline at end of file diff --git a/LICENSE b/LICENSE index 2684d70..9197c59 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,5 @@ +ISC License + Copyright (c) 2016, Simon Sturmer Permission to use, copy, modify, and/or distribute this software for any diff --git a/README.md b/README.md index cd2d83c..6fe4451 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,4 @@ This project is still under development. If you want to help out, please open an ## License -This software is [BSD Licensed](/LICENSE). +This software is [ISC Licensed](/LICENSE). diff --git a/flow-typed/globals.js b/flow-typed/globals.js new file mode 100644 index 0000000..e83dbaa --- /dev/null +++ b/flow-typed/globals.js @@ -0,0 +1,3 @@ +// @flow +/* eslint-disable no-unused-vars */ +declare var __DEV__: bool; diff --git a/package.json b/package.json index 7017cf1..118e69c 100644 --- a/package.json +++ b/package.json @@ -1,35 +1,40 @@ { "name": "draft-js-export-markdown", - "version": "0.1.2", + "version": "0.2.1", "description": "DraftJS: Export ContentState to Markdown", "main": "lib/main.js", "scripts": { "build": "babel src --ignore '_*' --out-dir lib", "lint": "eslint --max-warnings 0 .", + "typecheck": "flow", "prepublish": "npm run build", - "test": "npm run lint && npm run test-src", - "test-src": "mocha" + "test": "npm run lint && npm run typecheck && npm run test-src", + "test-src": "mocha src/__tests__/*.js src/**/__tests__/*.js" }, "dependencies": { - "draft-js-tools": "^0.1.2" + "draft-js-utils": "^0.1.5" + }, + "peerDependencies": { + "draft-js": ">=0.5.0", + "immutable": "3.x.x" }, "devDependencies": { - "babel-core": "^6.7.2", - "babel-eslint": "^5.0.0", - "babel-plugin-transform-class-properties": "^6.6.0", - "babel-preset-es2015": "^6.6.0", + "babel-cli": "^6.9.0", + "babel-core": "^6.9.0", + "babel-eslint": "^7.0.0", + "babel-plugin-transform-class-properties": "^6.9.0", + "babel-preset-es2015": "^6.9.0", "babel-preset-react": "^6.5.0", "babel-preset-stage-2": "^6.5.0", - "draft-js": "^0.2.2", - "eslint": "2.2.0", - "eslint-plugin-babel": "^3.1.0", - "eslint-plugin-flow-vars": "^0.2.1", - "eslint-plugin-react": "^4.2.1", - "expect": "^1.15.2", - "immutable": "^3.7.6", - "mocha": "^2.4.5", - "react": "^0.14.7", - "react-dom": "^0.14.7" + "eslint": "^3.7.1", + "eslint-plugin-babel": "^3.2.0", + "eslint-plugin-flow-vars": "^0.5.0", + "eslint-plugin-react": "^6.3.0", + "expect": "^1.20.1", + "flow-bin": "^0.32.0", + "mocha": "^3.1.0", + "react": "^15.0.2", + "react-dom": "^15.0.2" }, "repository": { "type": "git", @@ -40,6 +45,16 @@ "export-markdown" ], "author": "sstur@me.com", + "contributors": [ + { + "name": "Freddy Harris", + "url": "https://github.com/Freddy03h" + }, + { + "name": "Simon Sturmer", + "url": "https://github.com/sstur" + } + ], "license": "ISC", "bugs": { "url": "https://github.com/sstur/draft-js-export-markdown/issues" diff --git a/src/__tests__/stateToMarkdown-test.js b/src/__tests__/stateToMarkdown-test.js index 85b1c84..d4e784a 100644 --- a/src/__tests__/stateToMarkdown-test.js +++ b/src/__tests__/stateToMarkdown-test.js @@ -1,7 +1,7 @@ /* @flow */ const {describe, it} = global; import expect from 'expect'; -import {ContentState, convertFromRaw} from 'draft-js'; +import {convertFromRaw} from 'draft-js'; import stateToMarkdown from '../stateToMarkdown'; import fs from 'fs'; import {join} from 'path'; @@ -26,9 +26,7 @@ describe('stateToMarkdown', () => { testCases.forEach((testCase) => { let {description, state, markdown} = testCase; it(`should render ${description}`, () => { - let contentState = ContentState.createFromBlockArray( - convertFromRaw(state) - ); + let contentState = convertFromRaw(state); expect(stateToMarkdown(contentState)).toBe(markdown + '\n'); }); }); diff --git a/src/stateToMarkdown.js b/src/stateToMarkdown.js index 1bfe776..0838e6d 100644 --- a/src/stateToMarkdown.js +++ b/src/stateToMarkdown.js @@ -5,7 +5,7 @@ import { BLOCK_TYPE, ENTITY_TYPE, INLINE_STYLE, -} from 'draft-js-tools'; +} from 'draft-js-utils'; import {Entity} from 'draft-js'; import type {ContentState, ContentBlock} from 'draft-js'; @@ -63,6 +63,21 @@ class MarkupGenerator { this.output.push('### ' + this.renderBlockContent(block) + '\n'); break; } + case BLOCK_TYPE.HEADER_FOUR: { + this.insertLineBreaks(1); + this.output.push('#### ' + this.renderBlockContent(block) + '\n'); + break; + } + case BLOCK_TYPE.HEADER_FIVE: { + this.insertLineBreaks(1); + this.output.push('##### ' + this.renderBlockContent(block) + '\n'); + break; + } + case BLOCK_TYPE.HEADER_SIX: { + this.insertLineBreaks(1); + this.output.push('###### ' + this.renderBlockContent(block) + '\n'); + break; + } case BLOCK_TYPE.UNORDERED_LIST_ITEM: { let blockDepth = block.getDepth(); let lastBlock = this.getLastBlock(); @@ -80,7 +95,7 @@ class MarkupGenerator { this.insertLineBreaks(1); } } - let indent = ' '.repeat(block.depth * 2); + let indent = ' '.repeat(block.depth * 4); this.output.push( indent + '- ' + this.renderBlockContent(block) + '\n' ); @@ -100,7 +115,7 @@ class MarkupGenerator { this.insertLineBreaks(1); } } - let indent = ' '.repeat(blockDepth * 2); + let indent = ' '.repeat(blockDepth * 4); // TODO: figure out what to do with two-digit numbers let count = this.getListItemCount(block) % 10; this.output.push( @@ -193,7 +208,7 @@ class MarkupGenerator { content = `++${content}++`; } if (style.has(ITALIC)) { - content = `_${content}_`; + content = `*${content}*`; } if (style.has(STRIKETHROUGH)) { // TODO: encode `~`? @@ -210,6 +225,11 @@ class MarkupGenerator { let url = data.url || ''; let title = data.title ? ` "${escapeTitle(data.title)}"` : ''; return `[${content}](${encodeURL(url)}${title})`; + } else if (entity != null && entity.getType() === ENTITY_TYPE.IMAGE) { + let data = entity.getData(); + let src = data.src || ''; + let alt = data.alt ? ` "${escapeTitle(data.alt)}"` : ''; + return `![${alt}](${encodeURL(src)})`; } else { return content; } diff --git a/test/mocha.opts b/test/mocha.opts index 67c5129..ccd1f09 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,2 +1 @@ --compilers js:babel-core/register -src/__tests__/*.js src/**/__tests__/*.js diff --git a/test/test-cases.txt b/test/test-cases.txt index baca361..799d13a 100644 --- a/test/test-cases.txt +++ b/test/test-cases.txt @@ -14,6 +14,14 @@ _**BoldItalic**_ {"entityMap":{},"blocks":[{"key":"9nc73","text":"BoldItalic","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":4,"length":6,"style":"BOLD"},{"offset":0,"length":4,"style":"ITALIC"}],"entityRanges":[]}]} _Bold_**Italic** +>> Image with alt +{"entityMap":{"0":{"type":"IMAGE","mutability":"MUTABLE","data":{"src":"/a.jpg","alt":"x"}}},"blocks":[{"key":"f131g","text":"Hello World.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":5,"length":1,"key":0}]}]} +Hello![ "x"](/a.jpg)World. + +>> Image with empty alt +{"entityMap":{"0":{"type":"IMAGE","mutability":"MUTABLE","data":{"src":"/a.jpg","alt":""}}},"blocks":[{"key":"f131g","text":"Hello World.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":5,"length":1,"key":0}]}]} +Hello![](/a.jpg)World. + >> Link without title {"entityMap":{"0":{"type":"LINK","mutability":"MUTABLE","data":{"url":"/a","foo":"x"}}},"blocks":[{"key":"f131g","text":"Hello World.","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[{"offset":6,"length":5,"key":0}]}]} Hello [World](/a).