1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

Fix tabbed Literate CoffeeScript (#4345)

* failing test case

* add markdown parser for literate coffeescript

this should help to handle ligitimate markdown with indentation correctly

* Update generated code

* Update package.json

* Add `marked` dependency to browser version of CoffeeScript

* Update invertLiterate to use a randomly-generated token that we check for uniqueness, rather than a magic number that we hope might not occur in the code

* Fix typos
This commit is contained in:
Geoffrey Booth 2016-10-23 08:37:51 -07:00 committed by GitHub
parent b35bb20a18
commit 70a7265f35
6 changed files with 176 additions and 37 deletions

View file

@ -140,6 +140,14 @@ task 'build:parser', 'rebuild the Jison parser (run build first)', ->
task 'build:browser', 'rebuild the merged script for inclusion in the browser', -> task 'build:browser', 'rebuild the merged script for inclusion in the browser', ->
code = '' code = ''
for {name, src} in [{name: 'marked', src: 'lib/marked.js'}]
code += """
require['#{name}'] = (function() {
var exports = {}, module = {exports: exports};
#{fs.readFileSync "node_modules/#{name}/#{src}"}
return module.exports;
})();
"""
for name in ['helpers', 'rewriter', 'lexer', 'parser', 'scope', 'nodes', 'sourcemap', 'coffee-script', 'browser'] for name in ['helpers', 'rewriter', 'lexer', 'parser', 'scope', 'nodes', 'sourcemap', 'coffee-script', 'browser']
code += """ code += """
require['./#{name}'] = (function() { require['./#{name}'] = (function() {

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,8 @@
// Generated by CoffeeScript 2.0.0-alpha // Generated by CoffeeScript 2.0.0-alpha
(function() { (function() {
var buildLocationData, extend, flatten, ref, repeat, syntaxErrorToString; var buildLocationData, extend, flatten, marked, ref, repeat, syntaxErrorToString;
marked = require('marked');
exports.starts = function(string, literal, start) { exports.starts = function(string, literal, start) {
return literal === string.substr(start, literal.length); return literal === string.substr(start, literal.length);
@ -96,25 +98,24 @@
}; };
exports.invertLiterate = function(code) { exports.invertLiterate = function(code) {
var line, lines, maybe_code; var generateRandomToken, i, item, len1, out, ref1, token;
maybe_code = true; generateRandomToken = function() {
lines = (function() { return "" + (Math.random() * Date.now());
var i, len1, ref1, results; };
ref1 = code.split('\n'); while (token === void 0 || code.indexOf(token) !== -1) {
results = []; token = generateRandomToken();
}
code = code.replace("\t", token);
out = "";
ref1 = marked.lexer(code, {});
for (i = 0, len1 = ref1.length; i < len1; i++) { for (i = 0, len1 = ref1.length; i < len1; i++) {
line = ref1[i]; item = ref1[i];
if (maybe_code && /^([ ]{4}|[ ]{0,3}\t)/.test(line)) { if (item.type === 'code') {
results.push(line); out += item.text + "\n";
} else if (maybe_code = /^\s*$/.test(line)) {
results.push(line);
} else {
results.push('# ' + line);
} }
} }
return results; out.replace(token, "\t");
})(); return out;
return lines.join('\n');
}; };
buildLocationData = function(first, last) { buildLocationData = function(first, last) {

View file

@ -44,5 +44,8 @@
"highlight.js": "~9.7.0", "highlight.js": "~9.7.0",
"underscore": "~1.8.3", "underscore": "~1.8.3",
"docco": "~0.7.0" "docco": "~0.7.0"
},
"dependencies": {
"marked": "~0.3.6"
} }
} }

View file

@ -2,6 +2,17 @@
# the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten # the **Lexer**, **Rewriter**, and the **Nodes**. Merge objects, flatten
# arrays, count characters, that sort of thing. # 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
# Peek at the beginning of a given string to see if it matches a sequence. # Peek at the beginning of a given string to see if it matches a sequence.
exports.starts = (string, literal, start) -> exports.starts = (string, literal, start) ->
literal is string.substr start, literal.length literal is string.substr start, literal.length
@ -67,19 +78,25 @@ exports.some = Array::some ? (fn) ->
return true for e in this when fn e return true for e in this when fn e
false false
# Simple function for inverting Literate CoffeeScript code by putting the # Simple function for extracting code from Literate CoffeeScript by stripping
# documentation in comments, producing a string of CoffeeScript code that # out all non-code blocks, producing a string of CoffeeScript code that can
# can be compiled "normally". # be compiled normally.
exports.invertLiterate = (code) -> exports.invertLiterate = (code) ->
maybe_code = true # Create a placeholder for tabs, that isnt used anywhere in `code`, and then
lines = for line in code.split('\n') # re-insert the tabs after code extraction.
if maybe_code and /^([ ]{4}|[ ]{0,3}\t)/.test line generateRandomToken = ->
line "#{Math.random() * Date.now()}"
else if maybe_code = /^\s*$/.test line while token is undefined or code.indexOf(token) isnt -1
line token = generateRandomToken()
else
'# ' + line code = code.replace "\t", token
lines.join '\n' # 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
# Merge two jison-style location data objects together. # Merge two jison-style location data objects together.
# If `last` is not provided, this will simply return `first`. # If `last` is not provided, this will simply return `first`.

View file

@ -55,3 +55,111 @@ Tabs work too:
test "tabbed code", -> test "tabbed code", ->
ok yes ok yes
---
# keep track of whether code blocks are executed or not
executed = false
<p>
executed = true # should not execute, this is just HTML para, not code!
</p>
test "should ignore indented sections 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 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
---
executed = no
1986. What a great season.
executed = yes
and test...
test "should recognise 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