diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..43c97e71 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e17867a..0e296b14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 1.6.2 (2022-01-04) + +### Bug fixes + +Fix a bug where URL text in links and images was overzealously escaped. + +## 1.6.1 (2021-12-16) + +### Bug fixes + +Fix a bug where `MarkdownParser.parse` could return null when the parsed content doesn't fit the schema. + +Make sure underscores are escaped when serializing to Markdown. + ## 1.6.0 (2021-09-21) ### New features diff --git a/package.json b/package.json index f121b88d..63d32275 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prosemirror-markdown", - "version": "1.6.0", + "version": "1.6.2", "description": "ProseMirror Markdown integration", "main": "dist/index.js", "module": "dist/index.es.js", @@ -22,7 +22,7 @@ }, "devDependencies": { "ist": "1.0.0", - "mocha": "^3.0.2", + "mocha": "^9.1.2", "prosemirror-test-builder": "^1.0.0", "punycode": "^1.4.0", "rollup": "^2.26.3", diff --git a/src/from_markdown.js b/src/from_markdown.js index 5037dfd0..38f067b4 100644 --- a/src/from_markdown.js +++ b/src/from_markdown.js @@ -135,8 +135,8 @@ function tokenHandlers(schema, tokens) { if (noCloseToken(spec, type)) { handlers[type] = noOp } else { - handlers[type + '_open'] = noOp - handlers[type + '_close'] = noOp + handlers[type + "_open"] = noOp + handlers[type + "_close"] = noOp } } else { throw new RangeError("Unrecognized parsing spec " + JSON.stringify(spec)) @@ -219,7 +219,7 @@ export class MarkdownParser { let state = new MarkdownParseState(this.schema, this.tokenHandlers), doc state.parseTokens(this.tokenizer.parse(text, {})) do { doc = state.closeNode() } while (state.stack.length) - return doc + return doc || this.schema.topNodeType.createAndFill() } } diff --git a/src/to_markdown.js b/src/to_markdown.js index a5a3eddb..ae8c458e 100644 --- a/src/to_markdown.js +++ b/src/to_markdown.js @@ -95,8 +95,8 @@ export const defaultMarkdownSerializer = new MarkdownSerializer({ }, image(state, node) { - state.write("![" + state.esc(node.attrs.alt || "") + "](" + state.esc(node.attrs.src) + - (node.attrs.title ? " " + state.quote(node.attrs.title) : "") + ")") + state.write("![" + state.esc(node.attrs.alt || "") + "](" + node.attrs.src + + (node.attrs.title ? ' "' + node.attrs.title.replace(/"/g, '\\"') + '"' : "") + ")") }, hard_break(state, node, parent, index) { for (let i = index + 1; i < parent.childCount; i++) @@ -117,7 +117,7 @@ export const defaultMarkdownSerializer = new MarkdownSerializer({ }, close(state, mark, parent, index) { return isPlainURL(mark, parent, index, -1) ? ">" - : "](" + state.esc(mark.attrs.href) + (mark.attrs.title ? " " + state.quote(mark.attrs.title) : "") + ")" + : "](" + mark.attrs.href + (mark.attrs.title ? ' "' + mark.attrs.title.replace(/"/g, '\\"') + '"' : "") + ")" } }, code: {open(_state, _mark, parent, index) { return backticksFor(parent.child(index), -1) }, @@ -364,7 +364,7 @@ export class MarkdownSerializerState { // content. If `startOfLine` is true, also escape characters that // have special meaning only at the start of the line. esc(str, startOfLine) { - str = str.replace(/[`*\\~\[\]]/g, "\\$&") + str = str.replace(/[`*\\~\[\]_]/g, "\\$&") if (startOfLine) str = str.replace(/^[:#\-*+>]/, "\\$&").replace(/^(\s*\d+)\./, "$1\\.") return str } diff --git a/test/test-parse.js b/test/test-parse.js index c762d3ca..14c2ffdc 100644 --- a/test/test-parse.js +++ b/test/test-parse.js @@ -95,6 +95,16 @@ describe("markdown", () => { doc(p(link({href: "foo.html"}, "foo.html")))) }) + it("can handle link titles", () => { + same('[a](x.html "title \\"quoted\\"")', + doc(p(link({href: "x.html", title: 'title "quoted"'}, "a")))) + }) + + it("doesn't escape underscores in link", () => { + same('[link](http://foo.com/a_b_c)', + doc(p(link({href: "http://foo.com/a_b_c"}, "link")))) + }) + it("parses emphasized urls", () => same("Link to **", doc(p("Link to ", em(link({href: "https://prosemirror.net"}, "https://prosemirror.net"))))))