Browse Source

Nuked typographer class, separated core chain class

pull/14/head
Vitaly Puzrin 10 years ago
parent
commit
14c2e920fd
  1. 35
      lib/configs/commonmark.js
  2. 35
      lib/configs/default.js
  3. 38
      lib/configs/full.js
  4. 19
      lib/index.js
  5. 41
      lib/parser_core.js
  6. 52
      lib/rules_core/replacements.js
  7. 19
      lib/rules_core/smartquotes.js
  8. 66
      lib/rules_text/replace.js

35
lib/configs/commonmark.js

@ -10,7 +10,23 @@ module.exports = {
breaks: false, // Convert '\n' in paragraphs into <br> breaks: false, // Convert '\n' in paragraphs into <br>
langPrefix: 'language-', // CSS language prefix for fenced blocks langPrefix: 'language-', // CSS language prefix for fenced blocks
linkify: false, // autoconvert URL-like texts to links linkify: false, // autoconvert URL-like texts to links
typographer: false, // Enable smartypants and other sweet transforms
// Enable some language-neutral replacement + quotes beautification
//
// (c) (C) → ©
// (tm) (TM) → ™
// (r) (R) → ®
// +- → ±
// (p) (P) → §
// ... → …
// ???????? → ???, !!!!! → !!!, `,,` → `,`
// -- → —
//
typographer: false,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
quotes: '“”‘’',
// Highlighter function. Should return escaped HTML, // Highlighter function. Should return escaped HTML,
// or '' if input not changed // or '' if input not changed
@ -21,6 +37,8 @@ module.exports = {
components: { components: {
core: {},
block: { block: {
rules: [ rules: [
'blockquote', 'blockquote',
@ -47,21 +65,6 @@ module.exports = {
'newline', 'newline',
'text' 'text'
] ]
},
typographer: {
options: {
singleQuotes: '‘’', // set empty to disable
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable
copyright: true, // (c) (C) → ©
trademark: true, // (tm) (TM) → ™
registered: true, // (r) (R) → ®
plusminus: true, // +- → ±
paragraph: true, // (p) (P) → §
ellipsis: true, // ... → …
dupes: true, // ???????? → ???, !!!!! → !!!, `,,` → `,`
dashes: true // -- → —
}
} }
} }
}; };

35
lib/configs/default.js

@ -10,7 +10,23 @@ module.exports = {
breaks: false, // Convert '\n' in paragraphs into <br> breaks: false, // Convert '\n' in paragraphs into <br>
langPrefix: 'language-', // CSS language prefix for fenced blocks langPrefix: 'language-', // CSS language prefix for fenced blocks
linkify: false, // autoconvert URL-like texts to links linkify: false, // autoconvert URL-like texts to links
typographer: false, // Enable smartypants and other sweet transforms
// Enable some language-neutral replacement + quotes beautification
//
// (c) (C) → ©
// (tm) (TM) → ™
// (r) (R) → ®
// +- → ±
// (p) (P) → §
// ... → …
// ???????? → ???, !!!!! → !!!, `,,` → `,`
// -- → —
//
typographer: false,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
quotes: '“”‘’',
// Highlighter function. Should return escaped HTML, // Highlighter function. Should return escaped HTML,
// or '' if input not changed // or '' if input not changed
@ -21,6 +37,8 @@ module.exports = {
components: { components: {
core: {},
block: { block: {
rules: [ rules: [
'blockquote', 'blockquote',
@ -49,21 +67,6 @@ module.exports = {
'newline', 'newline',
'text' 'text'
] ]
},
typographer: {
options: {
singleQuotes: '‘’', // set empty to disable
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable
copyright: true, // (c) (C) → ©
trademark: true, // (tm) (TM) → ™
registered: true, // (r) (R) → ®
plusminus: true, // +- → ±
paragraph: true, // (p) (P) → §
ellipsis: true, // ... → …
dupes: true, // ???????? → ???, !!!!! → !!!, `,,` → `,`
dashes: true // -- → —
}
} }
} }
}; };

38
lib/configs/full.js

@ -10,7 +10,23 @@ module.exports = {
breaks: false, // Convert '\n' in paragraphs into <br> breaks: false, // Convert '\n' in paragraphs into <br>
langPrefix: 'language-', // CSS language prefix for fenced blocks langPrefix: 'language-', // CSS language prefix for fenced blocks
linkify: false, // autoconvert URL-like texts to links linkify: false, // autoconvert URL-like texts to links
typographer: false, // Enable smartypants and other sweet transforms
// Enable some language-neutral replacement + quotes beautification
//
// (c) (C) → ©
// (tm) (TM) → ™
// (r) (R) → ®
// +- → ±
// (p) (P) → §
// ... → …
// ???????? → ???, !!!!! → !!!, `,,` → `,`
// -- → —
//
typographer: false,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
quotes: '“”‘’',
// Highlighter function. Should return escaped HTML, // Highlighter function. Should return escaped HTML,
// or '' if input not changed // or '' if input not changed
@ -21,23 +37,9 @@ module.exports = {
components: { components: {
// Don't restrict block/inline rules // Don't restrict core/block/inline rules
core: {},
block: {}, block: {},
inline: {}, inline: {}
typographer: {
options: {
singleQuotes: '‘’', // set empty to disable
doubleQuotes: '“”', // set '«»' for Russian, '„“' for German, empty to disable
copyright: true, // (c) (C) → ©
trademark: true, // (tm) (TM) → ™
registered: true, // (r) (R) → ®
plusminus: true, // +- → ±
paragraph: true, // (p) (P) → §
ellipsis: true, // ... → …
dupes: true, // ???????? → ???, !!!!! → !!!, `,,` → `,`
dashes: true // -- → —
}
}
} }
}; };

19
lib/index.js

@ -6,9 +6,9 @@
var assign = require('./common/utils').assign; var assign = require('./common/utils').assign;
var isString = require('./common/utils').isString; var isString = require('./common/utils').isString;
var Renderer = require('./renderer'); var Renderer = require('./renderer');
var ParserCore = require('./parser_core');
var ParserBlock = require('./parser_block'); var ParserBlock = require('./parser_block');
var ParserInline = require('./parser_inline'); var ParserInline = require('./parser_inline');
var Typographer = require('./typographer');
var Ruler = require('./ruler'); var Ruler = require('./ruler');
var config = { var config = {
@ -17,14 +17,6 @@ var config = {
commonmark: require('./configs/commonmark') commonmark: require('./configs/commonmark')
}; };
var _rules = [
[ 'block', require('./rules_core/block') ],
[ 'references', require('./rules_core/references') ],
[ 'inline', require('./rules_core/inline') ],
[ 'linkify', require('./rules_core/linkify') ],
[ 'typographer', require('./rules_core/typographer') ]
];
function StateCore(self, src, env) { function StateCore(self, src, env) {
this.src = src; this.src = src;
@ -50,17 +42,14 @@ function Remarkable(presetName, options) {
this.inline = new ParserInline(); this.inline = new ParserInline();
this.block = new ParserBlock(); this.block = new ParserBlock();
this.core = new ParserCore();
this.renderer = new Renderer(); this.renderer = new Renderer();
this.ruler = new Ruler(); this.ruler = new Ruler();
this.typographer = new Typographer();
this.options = {}; this.options = {};
this.configure(config[presetName]); this.configure(config[presetName]);
if (options) { this.set(options); }
for (var i = 0; i < _rules.length; i++) { if (options) { this.set(options); }
this.ruler.push(_rules[i][0], _rules[i][1]);
}
} }
@ -112,7 +101,7 @@ Remarkable.prototype.use = function (plugin, opts) {
// //
Remarkable.prototype.parse = function (src, env) { Remarkable.prototype.parse = function (src, env) {
var i, len, var i, len,
rules = this.ruler.getRules(''), rules = this.core.ruler.getRules(''),
state = new StateCore(this, src, env); state = new StateCore(this, src, env);
len = rules.length; len = rules.length;

41
lib/parser_core.js

@ -0,0 +1,41 @@
// Class of top level (`core`) rules
//
'use strict';
var Ruler = require('./ruler');
var _rules = [
[ 'block', require('./rules_core/block') ],
[ 'references', require('./rules_core/references') ],
[ 'inline', require('./rules_core/inline') ],
[ 'replacements', require('./rules_core/replacements') ],
[ 'smartquotes', require('./rules_core/smartquotes') ],
[ 'linkify', require('./rules_core/linkify') ]
];
function Core() {
this.options = {};
this.ruler = new Ruler();
for (var i = 0; i < _rules.length; i++) {
this.ruler.push(_rules[i][0], _rules[i][1]);
}
}
Core.prototype.process = function (state) {
var i, l, rules;
rules = this.ruler.getRules('');
for (i = 0, l = rules.length; i < l; i++) {
rules[i](state);
}
};
module.exports = Core;

52
lib/rules_core/replacements.js

@ -0,0 +1,52 @@
// Simple typographyc replacements
//
'use strict';
// TODO:
// - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾
// - miltiplication 2 x 4 -> 2 × 4
var COPY_RE = /\((c|tm|r|p)\)/i;
var RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/;
module.exports = function replace(state) {
var i, token, text, inlineTokens, blkIdx;
if (!state.options.typographer) { return; }
for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
if (state.tokens[blkIdx].type !== 'inline') { continue; }
inlineTokens = state.tokens[blkIdx].children;
for (i = inlineTokens.length - 1; i >= 0; i--) {
token = inlineTokens[i];
if (token.type === 'text') {
text = token.content;
if (COPY_RE.test(text)) {
text = text.replace(/\(c\)/gi, '©')
.replace(/\(tm\)/gi, '™')
.replace(/\(r\)/gi, '®')
.replace(/\(p\)/gi, '§');
}
if (RARE_RE.test(text)) {
text = text.replace(/\+-/g, '±')
// .., ..., ....... -> …
// but ?..... & !..... -> ?.. & !..
.replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..')
.replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')
// em-dash
.replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2')
// en-dash
.replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2')
.replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2');
}
token.content = text;
}
}
}
};

19
lib/rules_text/smartquotes.js → lib/rules_core/smartquotes.js

@ -24,11 +24,12 @@ function replaceAt(str, index, ch) {
module.exports = function smartquotes(state) { module.exports = function smartquotes(state) {
/*eslint max-depth:0*/ /*eslint max-depth:0*/
var i, token, text, t, pos, max, thisLevel, lastSpace, nextSpace, item, var i, token, text, t, pos, max, thisLevel, lastSpace, nextSpace, item,
canOpen, canClose, j, isSingle, chars, blkIdx, tokens, canOpen, canClose, j, isSingle, blkIdx, tokens,
typographer = state.typographer, stack;
options = typographer.options,
stack = [];
if (!state.options.typographer) { return; }
stack = [];
for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) { for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
@ -83,10 +84,12 @@ module.exports = function smartquotes(state) {
if (stack[j].level < thisLevel) { break; } if (stack[j].level < thisLevel) { break; }
if (item.single === isSingle && stack[j].level === thisLevel) { if (item.single === isSingle && stack[j].level === thisLevel) {
item = stack[j]; item = stack[j];
chars = isSingle ? options.singleQuotes : options.doubleQuotes; if (isSingle) {
if (chars) { tokens[item.token].content = replaceAt(tokens[item.token].content, item.pos, state.options.quotes[2]);
tokens[item.token].content = replaceAt(tokens[item.token].content, item.pos, chars[0]); token.content = replaceAt(token.content, t.index, state.options.quotes[3]);
token.content = replaceAt(token.content, t.index, chars[1]); } else {
tokens[item.token].content = replaceAt(tokens[item.token].content, item.pos, state.options.quotes[0]);
token.content = replaceAt(token.content, t.index, state.options.quotes[1]);
} }
stack.length = j; stack.length = j;
continue OUTER; continue OUTER;

66
lib/rules_text/replace.js

@ -1,66 +0,0 @@
// Simple typographyc replacements
//
'use strict';
var COPY_RE = /\((c|tm|r|p)\)/i;
var RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/;
module.exports = function replace(state) {
var i, token, text, inlineTokens, blkIdx,
typographer = state.typographer,
options = typographer.options;
for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
if (state.tokens[blkIdx].type !== 'inline') { continue; }
inlineTokens = state.tokens[blkIdx].children;
for (i = inlineTokens.length - 1; i >= 0; i--) {
token = inlineTokens[i];
if (token.type === 'text') {
text = token.content;
if (COPY_RE.test(text)) {
if (options.copyright) {
text = text.replace(/\(c\)/gi, '©');
}
if (options.trademark) {
text = text.replace(/\(tm\)/gi, '™');
}
if (options.registered) {
text = text.replace(/\(r\)/gi, '®');
}
if (options.paragraph) {
text = text.replace(/\(p\)/gi, '§');
}
}
if (RARE_RE.test(text)) {
if (options.plusminus) {
text = text.replace(/\+-/g, '±');
}
if (options.ellipsis) {
// .., ..., ....... -> …
// but ?..... & !..... -> ?.. & !..
text = text.replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..');
}
if (options.dupes) {
text = text.replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',');
}
if (options.dashes) {
text = text
// em-dash
.replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2')
// en-dash
.replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2')
.replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2');
}
}
token.content = text;
}
}
}
};
Loading…
Cancel
Save