├── .gitignore ├── test ├── test.js ├── benchmark.js ├── fixtures │ └── sample.textile └── core.js ├── Makefile ├── package.json ├── README.textile ├── bin └── stextile ├── LICENSE └── lib └── stextile.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *.DS_Store 4 | node_modules 5 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var tests = require(__dirname + '/core') 2 | , textile = require(__dirname + '/../lib/stextile'); 3 | 4 | tests.run(textile); 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | sample: 2 | @./bin/stextile test/fixtures/sample.textile 3 | 4 | test: 5 | node test/test.js 6 | 7 | benchmark: 8 | node test/benchmark.js 9 | 10 | .PHONY: test 11 | -------------------------------------------------------------------------------- /test/benchmark.js: -------------------------------------------------------------------------------- 1 | var tests = require(__dirname + '/core') 2 | , Benchmark = require('benchmark') 3 | , suite = new Benchmark.Suite; 4 | 5 | suite.add('textile', function() { 6 | tests.run(require(__dirname + '/../lib/stextile')); 7 | }) 8 | .on('cycle', function(event, bench) { 9 | console.log(String(bench)); 10 | }) 11 | .on('complete', function() { 12 | }) 13 | .run(true); 14 | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stextile", 3 | "description": "Simple textile parser", 4 | "version": "0.0.8", 5 | "author": "Alex R. Young ", 6 | "repository": "git://github.com/alexyoung/stextile", 7 | "main": "./lib/stextile.js", 8 | "bin": { "stextile": "./bin/stextile" }, 9 | "devDependencies": { "benchmark": "latest" }, 10 | "engines": { "node": ">= 0.4.0" } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h3. stextile 2 | 3 | A simple "textile":http://www.textism.com/tools/textile/index.php parser, designed to be good enough to parse the formatting used in DailyJS articles. 4 | 5 | h3. Installation 6 | 7 | npm install stextile 8 | 9 | h3. Usage 10 | 11 | In a Node project: 12 | 13 |
14 | var textile = require('stextile');
15 | 
16 | textile('h1. A header');
17 | 
18 | 19 | In the shell: 20 | 21 |
22 | $ stextile file.textile
23 | 
24 | # HTML printed to stdout
25 | 
26 | 27 | h3. TO-DO 28 | 29 | * Footnotes 30 | * Acronyms 31 | * Benchmarks 32 | * Optimisation 33 | * Attributes for inline elements 34 | * Indentation 35 | 36 | h3. Notes 37 | 38 | https://github.com/jgm/peg-markdown/blob/master/markdown_parser.leg 39 | https://github.com/jgarber/redcloth/blob/master/ragel/redcloth_scan.rl 40 | 41 | h3. License 42 | 43 | The MIT License. 44 | -------------------------------------------------------------------------------- /bin/stextile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var textile; 4 | 5 | try { 6 | textile = require('../lib/stextile'); 7 | } catch (err) { 8 | textile = require('stextile'); 9 | } 10 | 11 | var args = process.argv.slice(2) 12 | , files = []; 13 | 14 | while (args.length) { 15 | arg = args.shift(); 16 | switch (arg) { 17 | case '-h': 18 | case '--help': 19 | console.log('TO-DO'); 20 | process.exit(1); 21 | default: 22 | files.push(arg); 23 | } 24 | } 25 | 26 | if (files.length) { 27 | var fs = require('fs'); 28 | 29 | while (files.length) { 30 | var file = files.shift(); 31 | fs.readFile(file, 'utf8', function(err, data) { 32 | if (err) throw(err); 33 | console.log(textile(data)); 34 | }); 35 | } 36 | } else { 37 | var buf = ''; 38 | process.stdin.setEncoding('utf8'); 39 | process.stdin.on('data', function(chunk) { 40 | buf += chunk; 41 | }).on('end', function() { 42 | console.log(textile(buf)); 43 | }).resume(); 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2011 Alex R. Young 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /test/fixtures/sample.textile: -------------------------------------------------------------------------------- 1 | h2{color:green}. This is a title 2 | 3 | h3. This is a subhead 4 | 5 | p{color:red}. This is some text of 'dubious character'. Isn't the use of "quotes" just lazy writing -- and theft of 'intellectual property' besides? I think the time has come to see a block quote. 6 | 7 | bq[fr]. This is a block quote. I'll admit it's not the most exciting block quote ever devised. 8 | 9 | Simple list: 10 | 11 | #{color:blue} one 12 | # two 13 | # three 14 | 15 | Multi-level list: 16 | 17 | # one 18 | ## aye 19 | ## bee 20 | ## see 21 | # two 22 | ## x 23 | ## y 24 | # three 25 | 26 | Mixed list: 27 | 28 | * Point one 29 | * Point two 30 | ## Step 1 31 | ## Step 2 32 | ## Step 3 33 | * Point three 34 | ** Sub point 1 35 | ** Sub point 2 36 | 37 | 38 | Well, that went well. How about we insert an old-fashioned hypertext link? Will the quote marks in the tags get messed up? No! 39 | 40 | "This is a link (optional title)":http://www.textism.com 41 | 42 | This is a simple table: 43 | 44 | |A|_B_|C| 45 | |D|*E*|F| 46 | 47 | This table has a rowspan: 48 | 49 | |A|\2. C| 50 | |D|/2. E |F| 51 | 52 | table{border:1px solid black}. 53 | |_. this|_. is|_. a|_. header| 54 | <{background:gray}[en](test). |\2. this is|{background:red;width:200px}. a|^<>{height:200px}. row| 55 | |this|<>{padding:10px}. is|^. another|>(bob#bob). row| 56 | 57 | An image: 58 | 59 | !http://dailyjs.com/images/posts/d3.jpg(optional alt text)! 60 | 61 | # Librarians rule 62 | # Yes they do 63 | # But you knew that 64 | 65 | Some more text of dubious character. Here is some string of CAPITAL letters. Here is something we want to _emphasize_. 66 | That was a linebreak. And something to indicate *strength*. Of course I could use my own HTML tags if I felt like it. 67 | 68 | h3. Coding 69 | 70 | This is some code, "isn't it". Watch those quote marks! Now for some preformatted text: 71 | 72 |
73 | 
74 | 	$text = str_replace("

%::%

","",$text); 75 | $text = str_replace("%::%

","",$text); 76 | $text = str_replace("%::%","",$text); 77 |
78 |
79 | 80 | This isn't code. 81 | 82 | 83 | So you see, my friends: 84 | 85 | * The time is now 86 | * The time is not later 87 | * The time is not yesterday 88 | * We must act 89 | 90 | -------------------------------------------------------------------------------- /test/core.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | , textile 3 | , tests; 4 | 5 | tests = { 6 | 'run': function(t) { 7 | textile = t; 8 | 9 | for (var key in tests) { 10 | if (/^test/.test(key)) { 11 | tests[key](); 12 | } 13 | } 14 | }, 15 | 16 | 'test paragraphs': function() { 17 | assert.equal('

A paragraph

\n', textile('A paragraph\n')); 18 | assert.equal('

A paragraph

\n', textile('p. A paragraph\n')); 19 | assert.equal('

A paragraph

\n', textile('p=. A paragraph\n')); 20 | }, 21 | 22 | 'test headers': function() { 23 | assert.equal('

Hello World

\n', textile('h3. Hello World')); 24 | assert.equal('

Hello World

\n

Deeper

\n', textile('h3. Hello World\nh4. Deeper')); 25 | assert.equal('

Hello World

\n

Hello again.

\n', textile('h3. Hello World\n\nHello again.\n')); 26 | }, 27 | 28 | 'test performatted with links': function() { 29 | assert.equal("

some code: '{\"key\":\"value\"}', and this is not

\n", textile('some code: \'{"key":"value"}\', and this is not')); 30 | assert.equal("

'{\"key\":\"value\"}',

\n", textile('\'{"key":"value"}\',')); 31 | assert.equal("

'{\"key (example)\":\"value\"}',

\n", textile('\'{"key (example)":"value"}\',')); 32 | }, 33 | 34 | 'test links': function() { 35 | assert.equal('

This is a link: Example and sometimes another example 2

\n', textile('This is a link: "Example":http://example.com/a_and_b and sometimes another "example 2":http://example.com/2')); 36 | 37 | // Links with fullstops 38 | assert.equal('

Example.

\n', textile('"Example":http://example.com.')); 39 | 40 | // Commas 41 | assert.equal('

Example, text

\n', textile('"Example":http://example.com, text')); 42 | 43 | // Links 44 | assert.equal('

Example

\n', textile('"Example":http://example.com')); 45 | assert.equal('

Example

\n', textile('"Example (Title)":http://example.com')); 46 | 47 | // Multiple links 48 | assert.equal( 49 | '

Example and Example 2

\n', 50 | textile('"Example":http://example.com and "Example 2":http://example.com/2') 51 | ); 52 | }, 53 | 54 | 'test escapeHTML': function() { 55 | assert.equal('
\na & p\n
\n', textile('
\na & p\n
')); 56 | assert.equal('
\n<a>\n
\n', textile('
\n\n
')); 57 | }, 58 | 59 | 'test bold': function() { 60 | assert.equal('

Some bold text here

\n', textile('Some *bold text* here')); 61 | assert.equal('

Some emphasised text here

\n', textile('Some _emphasised text_ here')); 62 | assert.equal('

Some added text here

\n', textile('Some +added text+ here')); 63 | assert.equal('

Some removed text here

\n', textile('Some -removed text- here')); 64 | }, 65 | 66 | 'test unordered lists': function() { 67 | assert.equal('\n', textile('* A list item\n')); 68 | 69 | // Lists with links 70 | assert.equal('
\n', textile('* "Part 1: Introduction":http://dailyjs.com/2010/11/01/node-tutorial/\n')); 71 | assert.equal( 72 | '