mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
[CS2] Fix handling of tabbed code blocks in .litcoffee files (#4485)
* Add tabbed literate test; modernize Markdown title heading * Better parsing of Literate CoffeeScript files, including now correct parsing of tabbed .litcoffee files; and more accurate stack traces (assuming you don’t do your own word wrapping within list items) * Swap Marked for MarkdownIt for parsing the Markdown of Literate CoffeeScript files; use MarkdownIt’s `map` property to preserve correct line numbers * Literate CoffeeScript tests: remove trailing whitespace, fix spelling * Literate CoffeeScript tests: add block quote test * Literate CoffeeScript (tabbed, at least) seems to need a consistent starting indentation * Restore test * Reference links work now in MarkdownIt * Breaking change in Literate CoffeeScript: code blocks within HTML tags must be unindented * Breaking change in Literate CoffeeScript: code blocks within lists need a blank line separating them from the list item text
This commit is contained in:
parent
57c0b16eeb
commit
5e1d978946
5 changed files with 227 additions and 93 deletions
|
@ -1,8 +1,8 @@
|
|||
// Generated by CoffeeScript 2.0.0-alpha1
|
||||
(function() {
|
||||
var buildLocationData, extend, flatten, marked, ref, repeat, syntaxErrorToString;
|
||||
var buildLocationData, extend, flatten, md, ref, repeat, syntaxErrorToString;
|
||||
|
||||
marked = require('marked');
|
||||
md = require('markdown-it')();
|
||||
|
||||
exports.starts = function(string, literal, start) {
|
||||
return literal === string.substr(start, literal.length);
|
||||
|
@ -28,10 +28,10 @@
|
|||
};
|
||||
|
||||
exports.compact = function(array) {
|
||||
var i, item, len1, results;
|
||||
var item, j, len1, results;
|
||||
results = [];
|
||||
for (i = 0, len1 = array.length; i < len1; i++) {
|
||||
item = array[i];
|
||||
for (j = 0, len1 = array.length; j < len1; j++) {
|
||||
item = array[j];
|
||||
if (item) {
|
||||
results.push(item);
|
||||
}
|
||||
|
@ -65,10 +65,10 @@
|
|||
};
|
||||
|
||||
exports.flatten = flatten = function(array) {
|
||||
var element, flattened, i, len1;
|
||||
var element, flattened, j, len1;
|
||||
flattened = [];
|
||||
for (i = 0, len1 = array.length; i < len1; i++) {
|
||||
element = array[i];
|
||||
for (j = 0, len1 = array.length; j < len1; j++) {
|
||||
element = array[j];
|
||||
if ('[object Array]' === Object.prototype.toString.call(element)) {
|
||||
flattened = flattened.concat(flatten(element));
|
||||
} else {
|
||||
|
@ -86,10 +86,10 @@
|
|||
};
|
||||
|
||||
exports.some = (ref = Array.prototype.some) != null ? ref : function(fn) {
|
||||
var e, i, len1, ref1;
|
||||
var e, j, len1, ref1;
|
||||
ref1 = this;
|
||||
for (i = 0, len1 = ref1.length; i < len1; i++) {
|
||||
e = ref1[i];
|
||||
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
||||
e = ref1[j];
|
||||
if (fn(e)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -98,24 +98,23 @@
|
|||
};
|
||||
|
||||
exports.invertLiterate = function(code) {
|
||||
var generateRandomToken, i, item, len1, out, ref1, token;
|
||||
generateRandomToken = function() {
|
||||
return `${Math.random() * Date.now()}`;
|
||||
var out;
|
||||
out = [];
|
||||
md.renderer.rules = {
|
||||
code_block: function(tokens, idx) {
|
||||
var i, j, len1, line, lines, results, startLine;
|
||||
startLine = tokens[idx].map[0];
|
||||
lines = tokens[idx].content.split('\n');
|
||||
results = [];
|
||||
for (i = j = 0, len1 = lines.length; j < len1; i = ++j) {
|
||||
line = lines[i];
|
||||
results.push(out[startLine + i] = line);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
};
|
||||
while (token === void 0 || code.indexOf(token) !== -1) {
|
||||
token = generateRandomToken();
|
||||
}
|
||||
code = code.replace("\t", token);
|
||||
out = "";
|
||||
ref1 = marked.lexer(code, {});
|
||||
for (i = 0, len1 = ref1.length; i < len1; i++) {
|
||||
item = ref1[i];
|
||||
if (item.type === 'code') {
|
||||
out += `${item.text}\n`;
|
||||
}
|
||||
}
|
||||
out.replace(token, "\t");
|
||||
return out;
|
||||
md.render(code);
|
||||
return out.join('\n');
|
||||
};
|
||||
|
||||
buildLocationData = function(first, last) {
|
||||
|
|
|
@ -47,6 +47,6 @@
|
|||
"underscore": "~1.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"marked": "~0.3.6"
|
||||
"markdown-it": "^8.3.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,7 @@
|
|||
# the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
|
||||
# arrays, count characters, that sort of thing.
|
||||
|
||||
marked = require 'marked'
|
||||
# marked.setOptions
|
||||
# renderer: new marked.Renderer()
|
||||
# gfm: true
|
||||
# tables: true
|
||||
# breaks: false
|
||||
# pedantic: false
|
||||
# sanitize: true
|
||||
# smartLists: true
|
||||
# smartypants: false
|
||||
md = require('markdown-it')()
|
||||
|
||||
# Peek at the beginning of a given string to see if it matches a sequence.
|
||||
exports.starts = (string, literal, start) ->
|
||||
|
@ -80,23 +71,18 @@ exports.some = Array::some ? (fn) ->
|
|||
|
||||
# Simple function for extracting code from Literate CoffeeScript by stripping
|
||||
# out all non-code blocks, producing a string of CoffeeScript code that can
|
||||
# be compiled “normally.”
|
||||
# be compiled “normally.” Uses [MarkdownIt](https://markdown-it.github.io/)
|
||||
# to tell the difference between Markdown and code blocks.
|
||||
exports.invertLiterate = (code) ->
|
||||
# Create a placeholder for tabs, that isn’t used anywhere in `code`, and then
|
||||
# re-insert the tabs after code extraction.
|
||||
generateRandomToken = ->
|
||||
"#{Math.random() * Date.now()}"
|
||||
while token is undefined or code.indexOf(token) isnt -1
|
||||
token = generateRandomToken()
|
||||
|
||||
code = code.replace "\t", token
|
||||
# Parse as markdown, discard everything except code blocks.
|
||||
out = ""
|
||||
for item in marked.lexer code, {}
|
||||
out += "#{item.text}\n" if item.type is 'code'
|
||||
# Put the tabs back in.
|
||||
out.replace token, "\t"
|
||||
out
|
||||
out = []
|
||||
md.renderer.rules =
|
||||
code_block: (tokens, idx) ->
|
||||
startLine = tokens[idx].map[0]
|
||||
lines = tokens[idx].content.split '\n'
|
||||
for line, i in lines
|
||||
out[startLine + i] = line
|
||||
md.render code
|
||||
out.join '\n'
|
||||
|
||||
# Merge two jison-style location data objects together.
|
||||
# If `last` is not provided, this will simply return `first`.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
Literate CoffeeScript Test
|
||||
--------------------------
|
||||
# Literate CoffeeScript Test
|
||||
|
||||
comment comment
|
||||
|
||||
|
@ -63,11 +62,12 @@ Tabs work too:
|
|||
|
||||
<p>
|
||||
|
||||
if true
|
||||
executed = true # should not execute, this is just HTML para, not code!
|
||||
|
||||
</p>
|
||||
|
||||
test "should ignore indented sections inside HTML", ->
|
||||
test "should ignore code blocks inside HTML", ->
|
||||
eq executed, false
|
||||
|
||||
---
|
||||
|
@ -119,24 +119,8 @@ Tabs work too:
|
|||
|
||||
---
|
||||
|
||||
This next one probably passes because a string is inoffensive in compiled js, also, can't get `marked` to parse it correctly, and not sure if empty line is permitted between title and reference
|
||||
|
||||
This is [an example][id] reference-style link.
|
||||
[id]: http://example.com/
|
||||
|
||||
"Optional Title Here"
|
||||
|
||||
---
|
||||
|
||||
executed = no
|
||||
|
||||
1986. What a great season.
|
||||
executed = yes
|
||||
|
||||
and test...
|
||||
|
||||
test "should recognise indented code blocks in lists", ->
|
||||
ok executed
|
||||
[id]: http://example.com/ "Optional Title Here"
|
||||
|
||||
---
|
||||
|
||||
|
@ -148,7 +132,7 @@ and test...
|
|||
|
||||
and test...
|
||||
|
||||
test "should recognise indented code blocks in lists with empty line as separator", ->
|
||||
test "should recognize indented code blocks in lists with empty line as separator", ->
|
||||
ok executed
|
||||
|
||||
---
|
||||
|
@ -163,3 +147,11 @@ and test...
|
|||
test "should ignore indented code in escaped list like number", ->
|
||||
eq executed, no
|
||||
|
||||
one last test!
|
||||
|
||||
test "block quotes should render correctly", ->
|
||||
quote = '''
|
||||
foo
|
||||
and bar!
|
||||
'''
|
||||
eq quote, 'foo\n and bar!'
|
||||
|
|
157
test/literate_tabbed.litcoffee
Normal file
157
test/literate_tabbed.litcoffee
Normal file
|
@ -0,0 +1,157 @@
|
|||
# Tabbed Literate CoffeeScript Test
|
||||
|
||||
comment comment
|
||||
|
||||
test "basic literate CoffeeScript parsing", ->
|
||||
ok yes
|
||||
|
||||
now with a...
|
||||
|
||||
test "broken up indentation", ->
|
||||
|
||||
... broken up ...
|
||||
|
||||
do ->
|
||||
|
||||
... nested block.
|
||||
|
||||
ok yes
|
||||
|
||||
Code must be separated from text by a blank line.
|
||||
|
||||
test "code blocks must be preceded by a blank line", ->
|
||||
|
||||
The next line is part of the text and will not be executed.
|
||||
fail()
|
||||
|
||||
ok yes
|
||||
|
||||
Code in `backticks is not parsed` and...
|
||||
|
||||
test "comments in indented blocks work", ->
|
||||
do ->
|
||||
do ->
|
||||
# Regular comment.
|
||||
|
||||
###
|
||||
Block comment.
|
||||
###
|
||||
|
||||
ok yes
|
||||
|
||||
Regular [Markdown](http://example.com/markdown) features, like links
|
||||
and unordered lists, are fine:
|
||||
|
||||
* I
|
||||
|
||||
* Am
|
||||
|
||||
* A
|
||||
|
||||
* List
|
||||
|
||||
Spaces work too:
|
||||
|
||||
test "spaced code", ->
|
||||
ok yes
|
||||
|
||||
---
|
||||
|
||||
# keep track of whether code blocks are executed or not
|
||||
executed = false
|
||||
|
||||
<p>
|
||||
|
||||
if true
|
||||
executed = true # should not execute, this is just HTML para, not code!
|
||||
|
||||
</p>
|
||||
|
||||
test "should ignore code blocks inside HTML", ->
|
||||
eq executed, false
|
||||
|
||||
---
|
||||
|
||||
* A list item with a code block:
|
||||
|
||||
test "basic literate CoffeeScript parsing", ->
|
||||
ok yes
|
||||
|
||||
---
|
||||
|
||||
* 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.
|
||||
|
||||
---
|
||||
|
||||
1. 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.
|
||||
|
||||
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
---
|
||||
|
||||
1. 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.
|
||||
|
||||
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
---
|
||||
|
||||
* A list item with a blockquote:
|
||||
|
||||
> This is a blockquote
|
||||
> inside a list item.
|
||||
|
||||
---
|
||||
|
||||
This is [an example][id] reference-style link.
|
||||
[id]: http://example.com/ "Optional Title Here"
|
||||
|
||||
---
|
||||
|
||||
executed = no
|
||||
|
||||
1986. What a great season.
|
||||
|
||||
executed = yes
|
||||
|
||||
and test...
|
||||
|
||||
test "should recognize indented code blocks in lists with empty line as separator", ->
|
||||
ok executed
|
||||
|
||||
---
|
||||
|
||||
executed = no
|
||||
|
||||
1986\. What a great season.
|
||||
executed = yes
|
||||
|
||||
and test...
|
||||
|
||||
test "should ignore indented code in escaped list like number", ->
|
||||
eq executed, no
|
||||
|
||||
one last test!
|
||||
|
||||
test "block quotes should render correctly", ->
|
||||
quote = '''
|
||||
foo
|
||||
and bar!
|
||||
'''
|
||||
eq quote, 'foo\n\t\tand bar!'
|
Loading…
Reference in a new issue