pnevyk / tipograph Goto Github PK
View Code? Open in Web Editor NEWA little javascript library and command line tool that makes your written content more typographically correct.
License: MIT License
A little javascript library and command line tool that makes your written content more typographically correct.
License: MIT License
Hi there,
I think I may have come across a bug in Tipograph relating to smartening a string that has multiple 2-digit years inside the string (or something?). Here’s a test case:
replace.all('I wasn\'t a particular fan of the music in the \'80s. And then she blurted, "I thought you said, \'I don\'t like \'80s music\'?"');
Or if it might help, here’s that string in a more human-readable form:
I wasn't a particular fan of the music in the '80s. And then she blurted, "I thought you said, 'I don't like '80s music'?"
Here’s the result:
I wasn’t a particular fan of the music in the ‘80s. And then she blurted, “I thought you said, ’I don’t like ‘80s music’?”
And here’s the result that I’d expect:
I wasn’t a particular fan of the music in the ’80s. And then she blurted, “I thought you said, ‘I don’t like ’80s music’?”
If you happen to be viewing this issue on GitHub.com, you might be stuck seeing this in San Francisco, which happens to have nearly identical left-single-quote and right-single-quote characters. So if it might help, here’s a screenshot of those test cases but with Helvetica:
The current codebase of Tipograph is old and I have some ideas to make it better.
NodeJS interface should be changed into more "node" way: no capital letters.
// ES2015 modules
import { replace, languages } from 'tipograph';
replace('text'); // replace.all()
replace.quotes('text');
// CommonJS
const { replace, languages } = require('tipograph');
Regexes are quick and sort of nice and clear way how to express things. But regex-based solution has some drawbacks: mainly that it has to go through the whole source on every rule, input format has to be plain text (HTML support is now quite hacky) and I think it can choke on very large inputs.
I am thinking about a different approach based on theory of finite state transducers. This would be the data pipeline in new architecture:
format
and content
. Format tokens will be just passed along the pipeline without change and then copied to the output. Content tokens will be a subject of further analysis. The advantage is that Tipograph can eventually support any input format without need to change the core engine.word
, space
, number
, quote
and so on.This is going to be a long way and I have no much time to do it now. But hopefully, in the future I (we?) will make Tipograph much better tool. If you have any comment, feel free to put it here.
Markdown is one of the most used formats for writing content. Tipograph should have support for it. The parser should follow commonmark spec, and possibly be extended with some widely used extensions.
There is a very basic parser in scripts/readme.js
file in this repository, but I think it is not a good place to start.
Some examples of how to integrate tipograph into other tools could be useful. These come into my mind at the moment:
Optionally collect the changes made by rules in the source text. This can be used to inform the user about what has changed and also help to implement wysiwyg editors where the cursor must be properly moved according to changes.
The changes can be identified by computing an edit distance/alignment between the original and the converted text. Vast majority of characters are not affected by the conversion so some more clever way should be used instead of traditional dynamic programming techniques executed on whole texts.
This changes information can be retrieved via a callback passed to the conversion. The callback will also override the returned value from "typo"
function (it will be the return value of the callback). The callback is of course optional.
var typo = tipograph();
// keep the original behavior
var converted = typo(original, function (converted, changes) {
// process the changes
return converted;
});
// make a structure
var contentAndChanges = typo(original, function (converted, changes) {
return { content: converted, changes: changes };
});
// stream
fs.createReadStream('input.txt')
.pipe(tipograph.createStream(/*{ options }*/, function (converted, changes) {
return { content: converted, changes: changes };
})
.pipe(/* a stream that processes contentAndConverted */);
The changes object will have the interface similar to the following:
var original = '"Foo --- bar"';
var converted = '\u201CFoo\u200A\u2014\u200Abar\u201D';
// Array<[fromRange, toRange]>
var changes = [
[[0, 1], [0, 1]], // '"' -> '\u201C'
[[4, 9], [4, 7]], // ' --- ' -> '\u200A\u2014\u200A'
[[12, 13], [10, 11]] // '"' -> '\u201D'
];
Rough idea of the algorithm:
function align(fst, snd) {
// returns [a, b] where fst[a] == snd[b] and for all i, j, i < a, j < b, fst[i] != snd[j]
// returns null if a == fst.length or b == snd.length, in other words, no such a, b exist
}
// artificial chars which always match each other
original += '\0';
converted += '\0';
var changes = [];
var i = 0;
var j = 0;
while (i < original.length && j < converted.length) {
if (original[i] == converted[j]) {
i++;
j++;
} else {
var alignment;
var bound = 5;
// NOTE: this loop is guaranteed to terminate because of '\0' at the ends
do {
alignment = align(original.slice(i, i + bound), converted.slice(j, j + bound));
bound *= 2;
} while (alignment === null);
changes.push([[i, i + alignment[0]], [j, j + alignment[1]]]);
i += alignment[0] + 1;
j += alignment[1] + 1;
}
}
// remove the artificial '\0' from the end
converted = converted.slice(0, -1);
return [converted, changes];
For some use cases it might be handy to replace unicode characters in converted text with special sequences of various formats (e.g. \u2026
to …
for html and \textellipsis
for latex).
Hello,
Thanks for this code!
I have this function:
import tipograph from 'tipograph';
makePrettyItem: function(item) {
return tipograph.Replace.all( ... );
},
I am getting:
return _tipograph2.default.Replace.all( ... );
^
TypeError: Cannot read property 'all' of undefined
I can't seem to figure out how to migrate this old syntax to the new ...
Can you point me in the right direction?
As pointed out here:
There’s a small typo in the readme:
In process of making PR now.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.