wip -- disambiguation works, tests passing
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
function disambiguateAsteriskRuns(line: string): string {
|
||||
const SENTINEL = '\u200C';
|
||||
const ASTERISK_RUN = /\*{1,3}/g;
|
||||
const stack: ('*' | '**')[] = [];
|
||||
let result = '';
|
||||
let lastIndex = 0;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
console.log(`DISAMBIGUATE: '${line}'`);
|
||||
|
||||
while ((match = ASTERISK_RUN.exec(line)) !== null) {
|
||||
|
||||
result += line.slice(lastIndex, match.index);
|
||||
const run = match[0];
|
||||
|
||||
console.log(`DISAMBIGUATE: run == '${run}', stack == ${stack}`);
|
||||
|
||||
if (run.length === 3 && stack.length === 2) {
|
||||
const innerCloser = stack.pop()!;
|
||||
const outerCloser = stack.pop()!;
|
||||
result += innerCloser + SENTINEL + outerCloser;
|
||||
} else if (run.length === 3 && stack.length === 0) {
|
||||
if (match.index == 0) {
|
||||
result += '***';
|
||||
} else {
|
||||
result += '*' + SENTINEL + '**';
|
||||
stack.push('**');
|
||||
stack.push('*');
|
||||
}
|
||||
} else if (run.length === 3) {
|
||||
result += run;
|
||||
} else if (stack.length > 0 && stack[stack.length - 1] === run) {
|
||||
stack.pop();
|
||||
result += run;
|
||||
} else {
|
||||
stack.push(run as '*' | '**');
|
||||
result += run;
|
||||
}
|
||||
|
||||
lastIndex = match.index + run.length;
|
||||
}
|
||||
|
||||
result += line.slice(lastIndex);
|
||||
console.log(`DISAMBIGUATE: '${result}'`);
|
||||
return result;
|
||||
}
|
||||
|
||||
function assert(condition, message) {
|
||||
if (!condition) { throw new Error(message); }
|
||||
}
|
||||
|
||||
function rewrite(line: string): string {
|
||||
const SENTINEL = '|' //'\u200C';
|
||||
const ASTERISK_RUN = /\*{1,3}/g;
|
||||
const stack: ('*' | '**' | '***')[] = [];
|
||||
let result = '';
|
||||
let lastIndex = 0;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
const bold = '**';
|
||||
const italic = '*';
|
||||
|
||||
let lastSequence = '';
|
||||
|
||||
while ((match = ASTERISK_RUN.exec(line)) !== null) {
|
||||
result += line.slice(lastIndex, match.index);
|
||||
const sequence = match[0];
|
||||
|
||||
if (sequence.length === 3) {
|
||||
|
||||
// split *** into opening ** and *
|
||||
if (stack.length === 0) {
|
||||
result += sequence;
|
||||
stack.push('***');
|
||||
|
||||
// closing ***, close the stack
|
||||
} else if (stack.length === 1 && stack[0] === sequence) {
|
||||
result = result.replace('***', bold + SENTINEL + italic);
|
||||
result += italic + SENTINEL + bold;
|
||||
stack.pop();
|
||||
|
||||
} else if (stack.length === 2) {
|
||||
const inner = stack.pop();
|
||||
const outer = stack.pop();
|
||||
result += inner + SENTINEL + outer;
|
||||
|
||||
} else if (stack.length === 1) {
|
||||
console.warn(`Cannot parsed line '${line}': invalid sequence ${sequence} with stack ${stack}!`);
|
||||
|
||||
} else {
|
||||
console.warn(`UNHANDLED '${sequence}', last sequence '${lastSequence}'`);
|
||||
}
|
||||
} else if (stack.length) {
|
||||
if (stack[stack.length - 1] === sequence) {
|
||||
result += stack.pop();
|
||||
} else if (stack.length === 1 && stack[0] === '***') {
|
||||
const opener = stack[0].substring(0, stack[0].length - sequence.length);
|
||||
result = result.replace('***', opener + SENTINEL + sequence);
|
||||
result += sequence;
|
||||
stack[0] = opener as '*' | '**';
|
||||
} else {
|
||||
result += sequence;
|
||||
stack.push(sequence as '*' | '**');
|
||||
}
|
||||
} else {
|
||||
stack.push(sequence as '*' | '**');
|
||||
result += sequence;
|
||||
}
|
||||
|
||||
lastIndex = match.index + sequence.length;
|
||||
}
|
||||
|
||||
result += line.slice(lastIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function test_it() {
|
||||
console.log(rewrite('*italic **bold***'));
|
||||
let cases = [
|
||||
{
|
||||
'input': '***bold-italic***',
|
||||
'expected': '**|*bold-italic*|**'
|
||||
},
|
||||
{
|
||||
'input': '***bold** italic*',
|
||||
'expected': '*|**bold** italic*',
|
||||
},
|
||||
{
|
||||
'input': '***italic* bold**',
|
||||
'expected': '**|*italic* bold**',
|
||||
},
|
||||
{
|
||||
'input': '**bold, *italic***',
|
||||
'expected': '**bold, *italic*|**'
|
||||
},
|
||||
{
|
||||
'input': '*italic, **bold***',
|
||||
'expected': '*italic, **bold**|*'
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of cases) {
|
||||
let result = rewrite(testCase.input);
|
||||
assert(result == testCase.expected, `'${result}' (${result.length}) != '${testCase.expected}' (${testCase.expected.length})`);
|
||||
}
|
||||
};
|
||||
|
||||
test_it();
|
||||
Reference in New Issue
Block a user