@diplodoc/translation
Version:
markdown translation utilities
1,614 lines (1,582 loc) • 183 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/experiment/plugins/attrs/markdown-it-attrs/utils.js
var require_utils = __commonJS({
"src/experiment/plugins/attrs/markdown-it-attrs/utils.js"(exports2) {
"use strict";
exports2.getAttrs = function(str, start, options) {
const allowedKeyChars = /[^\t\n\f />"'=]/;
const pairSeparator = " ";
const keySeparator = "=";
const classChar = ".";
const idChar = "#";
const attrs2 = [];
let key = "";
let value = "";
let parsingKey = true;
let valueInsideQuotes = false;
for (let i = start + options.leftDelimiter.length; i < str.length; i++) {
if (str.slice(i, i + options.rightDelimiter.length) === options.rightDelimiter) {
if (key !== "") {
attrs2.push([key, value]);
}
break;
}
const char_ = str.charAt(i);
if (char_ === keySeparator && parsingKey) {
parsingKey = false;
continue;
}
if (char_ === classChar && key === "") {
if (str.charAt(i + 1) === classChar) {
key = "css-module";
i += 1;
} else {
key = "class";
}
parsingKey = false;
continue;
}
if (char_ === idChar && key === "") {
key = "id";
parsingKey = false;
continue;
}
if (char_ === '"' && value === "" && !valueInsideQuotes) {
valueInsideQuotes = true;
continue;
}
if (char_ === '"' && valueInsideQuotes) {
valueInsideQuotes = false;
continue;
}
if (char_ === pairSeparator && !valueInsideQuotes) {
if (key === "") {
continue;
}
attrs2.push([key, value]);
key = "";
value = "";
parsingKey = true;
continue;
}
if (parsingKey && char_.search(allowedKeyChars) === -1) {
continue;
}
if (parsingKey) {
key += char_;
continue;
}
value += char_;
}
if (options.allowedAttributes && options.allowedAttributes.length) {
const allowedAttributes = options.allowedAttributes;
return attrs2.filter(function(attrPair) {
const attr2 = attrPair[0];
function isAllowedAttribute(allowedAttribute) {
return attr2 === allowedAttribute || allowedAttribute instanceof RegExp && allowedAttribute.test(attr2);
}
return allowedAttributes.some(isAllowedAttribute);
});
}
return attrs2;
};
exports2.addAttrs = function(attrs2, token2) {
for (let j = 0, l = attrs2.length; j < l; ++j) {
const key = attrs2[j][0];
if (key === "class") {
token2.attrJoin("class", attrs2[j][1]);
} else if (key === "css-module") {
token2.attrJoin("css-module", attrs2[j][1]);
} else {
token2.attrPush(attrs2[j]);
}
}
return token2;
};
exports2.hasDelimiters = function(where, options) {
if (!where) {
throw new Error('Parameter `where` not passed. Should be "start", "end" or "only".');
}
return function(str) {
const minCurlyLength = options.leftDelimiter.length + 1 + options.rightDelimiter.length;
if (!str || typeof str !== "string" || str.length < minCurlyLength) {
return false;
}
function validCurlyLength(curly) {
const isClass = curly.charAt(options.leftDelimiter.length) === ".";
const isId = curly.charAt(options.leftDelimiter.length) === "#";
return isClass || isId ? curly.length >= minCurlyLength + 1 : curly.length >= minCurlyLength;
}
let start, end, slice, nextChar;
const rightDelimiterMinimumShift = minCurlyLength - options.rightDelimiter.length;
switch (where) {
case "start":
slice = str.slice(0, options.leftDelimiter.length);
start = slice === options.leftDelimiter ? 0 : -1;
end = start === -1 ? -1 : str.indexOf(options.rightDelimiter, rightDelimiterMinimumShift);
nextChar = str.charAt(end + options.rightDelimiter.length);
if (nextChar && options.rightDelimiter.indexOf(nextChar) !== -1) {
end = -1;
}
break;
case "end":
start = str.lastIndexOf(options.leftDelimiter);
end = start === -1 ? -1 : str.indexOf(options.rightDelimiter, start + rightDelimiterMinimumShift);
end = end === str.length - options.rightDelimiter.length ? end : -1;
break;
case "only":
slice = str.slice(0, options.leftDelimiter.length);
start = slice === options.leftDelimiter ? 0 : -1;
slice = str.slice(str.length - options.rightDelimiter.length);
end = slice === options.rightDelimiter ? str.length - options.rightDelimiter.length : -1;
break;
default:
throw new Error(`Unexpected case ${where}, expected 'start', 'end' or 'only'`);
}
return start !== -1 && end !== -1 && validCurlyLength(str.substring(start, end + options.rightDelimiter.length));
};
};
exports2.removeDelimiter = function(str, options) {
const start = escapeRegExp(options.leftDelimiter);
const end = escapeRegExp(options.rightDelimiter);
const curly = new RegExp("[ \\n]?" + start + "[^" + start + end + "]+" + end + "$");
const pos = str.search(curly);
return pos !== -1 ? str.slice(0, pos) : str;
};
function escapeRegExp(s) {
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
}
exports2.escapeRegExp = escapeRegExp;
exports2.getMatchingOpeningToken = function(tokens, i) {
if (tokens[i].type === "softbreak") {
return false;
}
if (tokens[i].nesting === 0) {
return tokens[i];
}
const level = tokens[i].level;
const type2 = tokens[i].type.replace("_close", "_open");
for (; i >= 0; --i) {
if (tokens[i].type === type2 && tokens[i].level === level) {
return tokens[i];
}
}
return false;
};
var HTML_ESCAPE_TEST_RE = /[&<>"]/;
var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g;
var HTML_REPLACEMENTS = {
"&": "&",
"<": "<",
">": ">",
'"': """
};
function replaceUnsafeChar(ch) {
return HTML_REPLACEMENTS[ch];
}
exports2.escapeHtml = function(str) {
if (HTML_ESCAPE_TEST_RE.test(str)) {
return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);
}
return str;
};
}
});
// src/experiment/plugins/attrs/markdown-it-attrs/patterns.js
var require_patterns = __commonJS({
"src/experiment/plugins/attrs/markdown-it-attrs/patterns.js"(exports2, module2) {
"use strict";
var utils = require_utils();
var Token13 = require("markdown-it/lib/token");
module2.exports = (options) => {
const __hr = new RegExp(
"^ {0,3}[-*_]{3,} ?" + utils.escapeRegExp(options.leftDelimiter) + "[^" + utils.escapeRegExp(options.rightDelimiter) + "]"
);
return [
{
/**
* ```python {.cls}
* for i in range(10):
* print(i)
* ```
*/
name: "fenced code blocks",
tests: [
{
shift: 0,
block: true,
info: utils.hasDelimiters("end", options)
}
],
transform: (tokens, i) => {
const token2 = tokens[i];
const start = token2.info.lastIndexOf(options.leftDelimiter);
const attrs2 = utils.getAttrs(token2.info, start, options);
utils.addAttrs(attrs2, token2);
token2.info = utils.removeDelimiter(token2.info, options);
}
},
{
/**
* bla `click()`{.c} {.d}
*
* differs from 'inline attributes' as it does
* not have a closing tag (nesting: -1)
*/
name: "inline nesting 0",
tests: [
{
shift: 0,
type: "inline",
children: [
{
shift: -1,
type: (str) => str === "image" || str === "code_inline"
},
{
shift: 0,
type: "text",
content: utils.hasDelimiters("start", options),
__attrPluginSkip: void 0
}
]
}
],
transform: (tokens, i, j) => {
const token2 = tokens[i].children[j];
const endChar = token2.content.indexOf(options.rightDelimiter);
const attrToken = tokens[i].children[j - 1];
const attrs2 = utils.getAttrs(token2.content, 0, options);
utils.addAttrs(attrs2, attrToken);
if (token2.content.length === endChar + options.rightDelimiter.length) {
token2.__attrPluginSkip = true;
} else {
const startPos = endChar + options.rightDelimiter.length;
token2.content = token2.content.slice(startPos);
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "inline nesting 0" };
headerToken.content = token2.content.slice(0, startPos);
tokens[i].children.splice(j, 0, headerToken);
}
}
},
{
/**
* | h1 |
* | -- |
* | c1 |
*
* {.c}
*/
name: "tables",
tests: [
{
// let this token be i, such that for-loop continues at
// next token after tokens.splice
shift: 0,
type: "table_close"
},
{
shift: 1,
type: "paragraph_open"
},
{
shift: 2,
type: "inline",
content: utils.hasDelimiters("only", options)
}
],
transform: (tokens, i) => {
const token2 = tokens[i + 2];
const tableOpen = utils.getMatchingOpeningToken(tokens, i);
const attrs2 = utils.getAttrs(token2.content, 0, options);
utils.addAttrs(attrs2, tableOpen);
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "tables" };
headerToken.content = token2.content;
tokens.splice(i + 2, 1, headerToken);
}
},
{
/**
* *emphasis*{.with attrs=1}
*/
name: "inline attributes",
tests: [
{
shift: 0,
type: "inline",
children: [
{
shift: -1,
nesting: -1
// closing inline tag, </em>{.a}
},
{
shift: 0,
type: "text",
content: utils.hasDelimiters("start", options)
}
]
}
],
transform: (tokens, i, j) => {
const token2 = tokens[i].children[j];
const content = token2.content;
const attrs2 = utils.getAttrs(content, 0, options);
const openingToken = utils.getMatchingOpeningToken(tokens[i].children, j - 1);
utils.addAttrs(attrs2, openingToken);
const startPos = content.indexOf(options.rightDelimiter) + options.rightDelimiter.length;
token2.content = content.slice(startPos);
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "inline attributes" };
headerToken.content = content.slice(0, startPos);
tokens[i].children.splice(j, 0, headerToken);
}
},
{
/**
* - item
* {.a}
*/
name: "list softbreak",
tests: [
{
shift: -2,
type: "list_item_open"
},
{
shift: 0,
type: "inline",
children: [
{
position: -2,
type: "softbreak"
},
{
position: -1,
type: "text",
content: utils.hasDelimiters("only", options)
}
]
}
],
transform: (tokens, i, j) => {
const token2 = tokens[i].children[j];
const content = token2.content;
const attrs2 = utils.getAttrs(content, 0, options);
let ii = i - 2;
while (tokens[ii - 1] && tokens[ii - 1].type !== "ordered_list_open" && tokens[ii - 1].type !== "bullet_list_open") {
ii--;
}
utils.addAttrs(attrs2, tokens[ii - 1]);
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "list softbreak" };
headerToken.content = content;
tokens[i].children.splice(j, 1, headerToken);
}
},
{
/**
* - nested list
* - with double \n
* {.a} <-- apply to nested ul
*
* {.b} <-- apply to root <ul>
*/
name: "list double softbreak",
tests: [
{
// let this token be i = 0 so that we can erase
// the <p>{.a}</p> tokens below
shift: 0,
type: (str) => str === "bullet_list_close" || str === "ordered_list_close"
},
{
shift: 1,
type: "paragraph_open"
},
{
shift: 2,
type: "inline",
content: utils.hasDelimiters("only", options),
children: (arr) => arr.length === 1
},
{
shift: 3,
type: "paragraph_close"
}
],
transform: (tokens, i) => {
const token2 = tokens[i + 2];
const content = token2.content;
const attrs2 = utils.getAttrs(content, 0, options);
const openingToken = utils.getMatchingOpeningToken(tokens, i);
utils.addAttrs(attrs2, openingToken);
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "list double softbreak" };
headerToken.content = content;
tokens.splice(i + 2, 1, headerToken);
}
},
{
/**
* - end of {.list-item}
*/
name: "list item end",
tests: [
{
shift: -2,
type: "list_item_open"
},
{
shift: 0,
type: "inline",
children: [
{
position: -1,
type: "text",
content: utils.hasDelimiters("end", options)
}
]
}
],
transform: (tokens, i, j) => {
const token2 = tokens[i].children[j];
const content = token2.content;
const attrs2 = utils.getAttrs(
content,
content.lastIndexOf(options.leftDelimiter),
options
);
utils.addAttrs(attrs2, tokens[i - 2]);
const startPos = content.lastIndexOf(options.leftDelimiter);
token2.content = content.slice(0, startPos);
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "end of" };
headerToken.content = content.slice(startPos);
tokens[i].children.splice(j + 1, 0, headerToken);
}
},
{
/**
* something with softbreak
* {.cls}
*/
name: "\n{.a} softbreak then curly in start",
tests: [
{
shift: 0,
type: "inline",
children: [
{
position: -2,
type: "softbreak"
},
{
position: -1,
type: "text",
content: utils.hasDelimiters("only", options)
}
]
}
],
transform: (tokens, i, j) => {
const token2 = tokens[i].children[j];
const attrs2 = utils.getAttrs(token2.content, 0, options);
let ii = i + 1;
while (tokens[ii + 1] && tokens[ii + 1].nesting === -1) {
ii++;
}
const openingToken = utils.getMatchingOpeningToken(tokens, ii);
utils.addAttrs(attrs2, openingToken);
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "softbreak then curly in start" };
headerToken.content = token2.content;
tokens[i].children.splice(j, 1, headerToken);
}
},
{
/**
* horizontal rule --- {#id}
*/
name: "horizontal rule",
tests: [
{
shift: 0,
type: "paragraph_open"
},
{
shift: 1,
type: "inline",
children: (arr) => arr.length === 1,
content: (str) => str.match(__hr) !== null
},
{
shift: 2,
type: "paragraph_close"
}
],
transform: (tokens, i) => {
const token2 = tokens[i];
token2.type = "hr";
token2.tag = "hr";
token2.nesting = 0;
const content = tokens[i + 1].content;
const start = content.lastIndexOf(options.leftDelimiter);
const attrs2 = utils.getAttrs(content, start, options);
utils.addAttrs(attrs2, token2);
token2.markup = content;
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "horizontal rule" };
headerToken.content = content;
tokens.splice(i + 1, 1, headerToken);
}
},
{
/**
* end of {.block}
*/
name: "end of block",
tests: [
{
shift: 0,
type: "inline",
children: [
{
position: -1,
content: utils.hasDelimiters("end", options),
type: (t) => t !== "code_inline" && t !== "math_inline" && t !== "attr_anchor"
}
]
}
],
transform: (tokens, i, j) => {
const token2 = tokens[i].children[j];
const content = token2.content;
const attrs2 = utils.getAttrs(
content,
content.lastIndexOf(options.leftDelimiter),
options
);
let ii = i + 1;
while (tokens[ii + 1] && tokens[ii + 1].nesting === -1) {
ii++;
}
const openingToken = utils.getMatchingOpeningToken(tokens, ii);
utils.addAttrs(attrs2, openingToken);
const startPos = content.lastIndexOf(options.leftDelimiter);
token2.content = content.slice(0, startPos);
const headerToken = new Token13("attr_anchor", "", 0);
headerToken.meta = { rule: "end of block" };
headerToken.content = content.slice(startPos);
tokens[i].children.splice(j + 1, 0, headerToken);
}
}
];
};
}
});
// src/experiment/plugins/attrs/markdown-it-attrs/index.js
var require_markdown_it_attrs = __commonJS({
"src/experiment/plugins/attrs/markdown-it-attrs/index.js"(exports2, module2) {
"use strict";
var patternsConfig = require_patterns();
var defaultOptions = {
leftDelimiter: "{",
rightDelimiter: "}",
allowedAttributes: []
};
module2.exports = function attributes2(md3, options_) {
let options = Object.assign({}, defaultOptions);
options = Object.assign(options, options_);
const patterns = patternsConfig(options);
function curlyAttrs(state2) {
const tokens = state2.tokens;
for (let i = 0; i < tokens.length; i++) {
for (let p = 0; p < patterns.length; p++) {
const pattern = patterns[p];
let j = null;
const match = pattern.tests.every((t) => {
const res = test(tokens, i, t);
if (res.j !== null) {
j = res.j;
}
return res.match;
});
if (match) {
pattern.transform(tokens, i, j);
if (pattern.name === "inline attributes" || pattern.name === "inline nesting 0") {
p--;
}
}
}
}
}
md3.core.ruler.before("linkify", "curly_attributes", curlyAttrs);
};
function test(tokens, i, t) {
const res = {
match: false,
j: null
// position of child
};
const ii = t.shift !== void 0 ? i + t.shift : t.position;
if (t.shift !== void 0 && ii < 0) {
return res;
}
const token2 = get3(tokens, ii);
if (token2 === void 0) {
return res;
}
for (const key of Object.keys(t)) {
if (key === "shift" || key === "position") {
continue;
}
if (token2[key] === void 0) {
return res;
}
if (key === "children" && isArrayOfObjects(t.children)) {
if (token2.children.length === 0) {
return res;
}
let match;
const childTests = t.children;
const children = token2.children;
if (childTests.every((tt) => tt.position !== void 0)) {
match = childTests.every((tt) => test(children, tt.position, tt).match);
if (match) {
const j = last2(childTests).position;
res.j = j >= 0 ? j : children.length + j;
}
} else {
for (let j = 0; j < children.length; j++) {
match = childTests.every((tt) => test(children, j, tt).match);
if (match) {
res.j = j;
break;
}
}
}
if (match === false) {
return res;
}
continue;
}
switch (typeof t[key]) {
case "boolean":
case "number":
case "string":
if (token2[key] !== t[key]) {
return res;
}
break;
case "function":
if (!t[key](token2[key])) {
return res;
}
break;
case "object":
if (isArrayOfFunctions(t[key])) {
const r = t[key].every((tt) => tt(token2[key]));
if (r === false) {
return res;
}
break;
}
// fall through for objects !== arrays of functions
default:
throw new Error(
`Unknown type of pattern test (key: ${key}). Test should be of type boolean, number, string, function or array of functions.`
);
}
}
res.match = true;
return res;
}
function isArrayOfObjects(arr) {
return Array.isArray(arr) && arr.length && arr.every((i) => typeof i === "object");
}
function isArrayOfFunctions(arr) {
return Array.isArray(arr) && arr.length && arr.every((i) => typeof i === "function");
}
function get3(arr, n) {
return n >= 0 ? arr[n] : arr[arr.length + n];
}
function last2(arr) {
return arr.slice(-1)[0] || {};
}
}
});
// src/index.ts
var src_exports = {};
__export(src_exports, {
CriticalProcessingError: () => CriticalProcessingError,
compose: () => compose5,
extract: () => extract5,
linkRefs: () => linkRefs,
unlinkRefs: () => unlinkRefs
});
module.exports = __toCommonJS(src_exports);
// src/xliff/md-xliff/index.ts
var import_markdown_it4 = __toESM(require("markdown-it"));
// src/renderer/index.ts
var import_renderer = __toESM(require("markdown-it/lib/renderer"));
var CustomRendererLifeCycle = /* @__PURE__ */ ((CustomRendererLifeCycle2) => {
CustomRendererLifeCycle2[CustomRendererLifeCycle2["BeforeRender"] = 0] = "BeforeRender";
CustomRendererLifeCycle2[CustomRendererLifeCycle2["AfterRender"] = 1] = "AfterRender";
CustomRendererLifeCycle2[CustomRendererLifeCycle2["BeforeInlineRender"] = 2] = "BeforeInlineRender";
CustomRendererLifeCycle2[CustomRendererLifeCycle2["AfterInlineRender"] = 3] = "AfterInlineRender";
return CustomRendererLifeCycle2;
})(CustomRendererLifeCycle || {});
function isCustomRendererLifeCycle(cycle) {
return Object.keys(CustomRendererLifeCycle).includes(
cycle
);
}
function getMap(tokens, i) {
let depth = 0;
while (tokens[i]) {
const token2 = tokens[i--];
depth += token2.nesting;
if (token2.map && depth >= 0) {
return token2.map;
}
}
return null;
}
var CustomRenderer = class extends import_renderer.default {
constructor({ hooks: hooks3 = {}, rules: rules4 = {}, state: state2 = {} }, parser) {
super();
this.setRules(rules4);
this.md = parser;
this.state = state2;
this.hooks = /* @__PURE__ */ new Map();
this.setHooks({ ...hooks3 });
}
setRules(rules4) {
for (const [name, rule] of Object.entries(rules4)) {
if (!rule || !(name == null ? void 0 : name.length)) {
continue;
}
this.rules[name] = rule.bind(this);
}
}
setHooks(hooks3) {
for (const [name, hook] of Object.entries(hooks3)) {
if (isCustomRendererLifeCycle(name)) {
this.hook(parseInt(name, 10), hook);
}
}
}
hook(cycle, hook) {
const hooks3 = this.hooks.get(cycle) ?? [];
const normalized = (Array.isArray(hook) ? hook : [hook]).map((h) => h.bind(this));
this.hooks.set(cycle, [...hooks3, ...normalized]);
}
render(tokens, options, env) {
let rendered = "";
let children;
let type2;
let map;
let len;
let i;
const parameters = { tokens, options, env };
rendered += this.runHooks(0 /* BeforeRender */, parameters);
for (i = 0, len = tokens.length; i < len; i++) {
type2 = tokens[i].type;
children = tokens[i].children;
map = getMap(tokens, i - 1);
if (type2 === "inline" && Array.isArray(children)) {
rendered += this.renderInline(children, options, env, map, tokens[i]);
continue;
}
rendered += this.processToken(tokens, i, options, env);
}
rendered += this.runHooks(1 /* AfterRender */, parameters);
return rendered;
}
// @ts-ignore
renderInline(tokens, options, env, map, inline2) {
const rendered = [];
const parameters = { tokens, options, env, rendered, map, inline: inline2 };
rendered.push(this.runHooks(2 /* BeforeInlineRender */, parameters));
for (let i = 0; i < tokens.length; i++) {
rendered.push(this.processToken(tokens, i, options, env));
}
rendered.push(this.runHooks(3 /* AfterInlineRender */, parameters));
return rendered.join("");
}
// renderInline provides rendered array
// we accumulate render results into it
// allowing us to access current render artifacts
// at the time each before/after inline render hook runs
runHooks(cycle, parameters) {
const hooks3 = this.hooks.get(cycle) ?? [];
let rendered = "";
let result = "";
for (const hook of hooks3) {
result = hook(parameters);
if (Array.isArray(parameters.rendered)) {
parameters.rendered.push(result);
} else {
rendered += result;
}
}
return Array.isArray(parameters.rendered) ? "" : rendered;
}
processToken(tokens, i, options, env) {
let rendered = "";
const type2 = tokens[i].type;
const rule = this.rules[type2];
if (rule) {
rendered += rule(tokens, i, options, env, this);
} else {
rendered += this.renderToken(tokens, i, options);
}
return rendered;
}
};
function customRenderer(parser, parameters = {}) {
parser.renderer = new CustomRenderer(parameters, parser);
}
// src/utils/index.ts
var import_markdown_it = __toESM(require("markdown-it"));
var md = new import_markdown_it.default();
var state = new md.core.State("", md, {});
function token(type2, props = {}) {
return Object.assign(new state.Token(type2, "", 0), props);
}
function find(type2, tokens, idx) {
while (tokens.length > idx) {
if (tokens[idx].type === type2) {
return tokens[idx];
}
idx++;
}
return null;
}
function replace(source, units) {
let matched = false;
const result = source.replace(/%%%(\d+)%%%/g, (_2, id3) => {
matched = true;
id3 = Number(id3);
if (!units[id3]) {
throw new Error(`Translation token not found. Token id: ${id3}`);
}
let [value, submatch] = replace(units[id3], units);
while (submatch) {
[value, submatch] = replace(value, units);
}
return value;
});
return [result, matched];
}
// src/xliff/generator/template.ts
var import_i18n_iso_languages = __toESM(require("@cospired/i18n-iso-languages"));
var languagesList = import_i18n_iso_languages.default.langs();
function unit(source, index) {
return `
<trans-unit id="${index}">
${source}
</trans-unit>
`.trim();
}
function template(units, { source, target }) {
return `
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file original="file.ext" source-language="${source.language}-${source.locale}" target-language="${target.language}-${target.locale}" datatype="markdown">
<header>
<skeleton>
<external-file href="file.skl"></external-file>
</skeleton>
</header>
<body>
${units.map(unit).join("\n ")}
</body>
</file>
</xliff>
`.trim();
}
// src/xliff/generator/transunit.ts
function transunit(parameters) {
const { source, sourceLangLocale, target, targetLangLocale, compact } = parameters;
let rendered = ``;
if (target == null ? void 0 : target.length) {
rendered += "\n";
rendered += `<target`;
if (!compact) {
rendered += ` xml:space="preserve"`;
if (targetLangLocale == null ? void 0 : targetLangLocale.length) {
rendered += ` xml:lang="${targetLangLocale}"`;
}
}
rendered += ">";
rendered += `${target}</target>`;
}
if (source) {
rendered += "\n";
rendered += `<source`;
if (!compact) {
rendered += ` xml:space="preserve"`;
if (sourceLangLocale == null ? void 0 : sourceLangLocale.length) {
rendered += ` xml:lang="${sourceLangLocale}"`;
}
}
rendered += ">";
rendered += `${source}</source>`;
}
return rendered.trim();
}
// src/symbols.ts
var import_node_crypto = __toESM(require("crypto"));
var gt = import_node_crypto.default.randomUUID();
var lt = import_node_crypto.default.randomUUID();
var sl = import_node_crypto.default.randomUUID();
var qt = import_node_crypto.default.randomUUID();
var mt = "E" + import_node_crypto.default.randomUUID() + "e";
var vr = "V" + import_node_crypto.default.randomUUID();
var gtre = new RegExp(`${gt}`, "gmu");
var ltre = new RegExp(`${lt}`, "gmu");
var qtre = new RegExp(`${qt}`, "gmu");
var slre = new RegExp(`${sl}`, "gmu");
var mtre = new RegExp(`${mt}`, "gmu");
var vrre = new RegExp(`${vr}-\\d+-v`, "gmu");
function unescapeSymbols(str) {
return str.replace(gtre, ">").replace(ltre, "<").replace(qtre, '"').replace(slre, "/").replace(mtre, "");
}
// src/xliff/generator/utils.ts
function snakeCase(key) {
return key.replace(/[A-Z]/g, (s) => "-" + s.toLowerCase());
}
// src/xliff/generator/g.ts
function generateOpenG(parameters) {
parameters = { ...parameters, ...id() };
const props = Object.keys(parameters).sort().map((key) => `${snakeCase(key)}=${qt}${parameters[key]}${qt}`).join(" ");
return `${lt}g ${props}${gt}`;
}
function generateCloseG() {
return `${lt}${sl}g${gt}`;
}
var ID = 1;
function id() {
if (process.env.JEST_WORKER_ID) {
return { id: "g-test" };
}
return { id: "g-" + ID++ };
}
// src/xliff/generator/x.ts
function generateX(parameters) {
parameters = { ...parameters, ...id2() };
const props = Object.keys(parameters).sort().map((key) => `${snakeCase(key)}=${qt}${parameters[key]}${qt}`).join(" ");
return `${lt}x ${props}${sl + gt}`;
}
var ID2 = 1;
function id2() {
if (process.env.JEST_WORKER_ID) {
return { id: "g-test" };
}
return { id: "x-" + ID2++ };
}
// src/xliff/md-xliff/hooks/after-inline.ts
var import_markdown_it2 = __toESM(require("markdown-it"));
var escapeHTML = new import_markdown_it2.default().utils.escapeHtml;
function afterInline(parameters) {
if (!parameters.rendered) {
return "";
}
let rendered = parameters.rendered.join("");
if (!rendered.length) {
return "";
}
rendered = escapeHTML(rendered);
rendered = unescapeSymbols(rendered);
parameters.rendered.splice(0, parameters.rendered.length, rendered);
return "";
}
// src/xliff/md-xliff/hooks/index.ts
var hooks = {
[3 /* AfterInlineRender */]: [afterInline]
};
// src/xliff/md-xliff/rules/diplodoc/index.ts
var always = (a) => () => a;
var alwaysEmptyString = always("");
var rules = {
// notes
yfm_note_open: alwaysEmptyString,
yfm_note_close: alwaysEmptyString,
yfm_note_title_open: alwaysEmptyString,
yfm_note_title_close: alwaysEmptyString,
yfm_note_content_open: alwaysEmptyString,
yfm_note_content_close: alwaysEmptyString,
// cuts
yfm_cut_open: alwaysEmptyString,
yfm_cut_title_open: alwaysEmptyString,
yfm_cut_title_close: alwaysEmptyString,
yfm_cut_content_open: alwaysEmptyString,
yfm_cut_content_close: alwaysEmptyString,
yfm_cut_close: alwaysEmptyString,
// gfm tables
table_open: alwaysEmptyString,
thead_open: alwaysEmptyString,
tr_open: alwaysEmptyString,
tr_close: alwaysEmptyString,
th_open: alwaysEmptyString,
th_close: alwaysEmptyString,
thead_close: alwaysEmptyString,
tbody_open: alwaysEmptyString,
tbody_close: alwaysEmptyString,
td_open: alwaysEmptyString,
td_close: alwaysEmptyString,
table_close: alwaysEmptyString,
// checkbox
checkbox_open: alwaysEmptyString,
checkbox_input: alwaysEmptyString,
checkbox_label_open: alwaysEmptyString,
checkbox_label_close: alwaysEmptyString,
checkbox_close: alwaysEmptyString,
// monospace
monospace_open: alwaysEmptyString,
monospace_close: alwaysEmptyString,
// include
include: alwaysEmptyString,
// tabs
tabs_open: alwaysEmptyString,
tabs_close: alwaysEmptyString,
"tab-list_open": alwaysEmptyString,
"tab-list_close": alwaysEmptyString,
tab_open: alwaysEmptyString,
tab_close: alwaysEmptyString,
"tab-panel_open": alwaysEmptyString,
"tab-panel_close": alwaysEmptyString,
// anchors
span_open: alwaysEmptyString,
span_close: alwaysEmptyString,
// table
yfm_tbody_open: alwaysEmptyString,
yfm_tbody_close: alwaysEmptyString,
yfm_table_open: alwaysEmptyString,
yfm_table_close: alwaysEmptyString,
yfm_tr_open: alwaysEmptyString,
yfm_tr_close: alwaysEmptyString,
yfm_td_open: alwaysEmptyString,
yfm_td_close: alwaysEmptyString
};
// src/xliff/md-xliff/rules/link.ts
var link = {
link_auto: linkAuto,
link_open: linkOpen,
link_close: linkClose
};
function linkAuto(tokens, i) {
const href = tokens[i].content;
return generateX({
ctype: "link_autolink",
equivText: `${href}`
});
}
function linkOpen(tokens, i) {
const open3 = tokens[i];
if (open3.g) {
const title = open3.attrGet("title");
const href = open3.attrGet("href");
const begin = "[" + (open3.reflink ? "{#T}" : "");
const end = "](" + [href, title && '"' + title + '"'].filter(Boolean).join(" ") + ")";
return generateOpenG({
ctype: "link",
equivText: `${begin}{{text}}${end}`,
xBegin: begin,
xEnd: end
});
} else {
if (open3.reflink) {
return "";
}
return generateX({
ctype: "link_text_part_open",
equivText: "["
});
}
}
function linkClose(tokens, i) {
const close3 = tokens[i];
if (close3.g) {
return generateCloseG();
}
const open3 = close3.open;
const title = open3.attrGet("title");
const href = open3.attrGet("href");
let rendered = "";
if (open3.reflink) {
rendered += generateX({
ctype: "link_reflink",
equivText: "[{#T}]"
});
} else {
rendered += generateX({
ctype: "link_text_part_close",
equivText: "]"
});
}
rendered += generateX({
ctype: "link_attributes_part_open",
equivText: "("
});
if (href == null ? void 0 : href.length) {
rendered += generateX({
ctype: "link_attributes_href",
equivText: href
});
}
if (title == null ? void 0 : title.length) {
rendered += generateX({
ctype: "link_attributes_title",
equivText: title
});
}
rendered += generateX({
ctype: "link_attributes_part_close",
equivText: ")"
});
return rendered;
}
// src/xliff/md-xliff/rules/breaks.ts
function generateBreak(tokens, i) {
const _break = tokens[i];
return generateX({
ctype: `lb`,
equivText: _break.content || "\n"
});
}
var breaks = {
hardbreak: generateBreak,
softbreak: generateBreak
};
// src/xliff/md-xliff/rules/pair.ts
var open = (ctype) => (tokens, i) => {
const token2 = tokens[i];
const markup = token2.markup;
if (token2.g) {
return generateOpenG({
ctype,
equivText: `${markup}{{text}}${markup}`,
xBegin: markup,
xEnd: markup
});
}
return generateX({
ctype: ctype + "_open",
equivText: markup
});
};
var close = (ctype) => (tokens, i) => {
const token2 = tokens[i];
const markup = token2.markup;
if (token2.g) {
return generateCloseG();
}
return generateX({
ctype: ctype + "_close",
equivText: markup
});
};
var pair = {
strong_open: open("bold"),
strong_close: close("bold"),
em_open: open("italic"),
em_close: close("italic"),
s_open: open("strikethrough"),
s_close: close("strikethrough"),
sup_open: open("sup"),
sup_close: close("sup"),
monospace_open: open("monospace"),
monospace_close: close("monospace")
};
// src/xliff/md-xliff/rules/code-inline.ts
var codeInline = {
code_inline_open: codeInlineRule("open"),
code_inline_close: codeInlineRule("close")
};
function codeInlineRule(dir) {
return function(tokens, i) {
const { markup } = tokens[i];
return generateX({
ctype: `code_${dir}`,
equivText: markup
});
};
}
// src/xliff/md-xliff/rules/text.ts
var text = {
text: function(tokens, i) {
var _a;
const text3 = tokens[i];
if (!((_a = text3.content) == null ? void 0 : _a.length) || text3.reflink) {
return "";
}
return text3.content;
}
};
// src/xliff/md-xliff/rules/liquid.ts
var liquid = {
liquid: function(tokens, i) {
const { subtype, content, markup } = tokens[i];
return generateX({
ctype: `liquid_${subtype}`,
equivText: markup || content
});
}
};
// src/xliff/md-xliff/rules/image.ts
var import_markdown_it3 = __toESM(require("markdown-it"));
var decodeURL = new import_markdown_it3.default().utils.lib.mdurl.decode;
var image = {
image_open: imageOpen,
image_close: imageClose
};
function imageOpen(tokens, idx) {
const open3 = tokens[idx];
if (open3.g) {
const close3 = open3.g;
const src = close3.attrGet("src");
const title = close3.attrGet("title");
const height = close3.attrGet("height");
const width = close3.attrGet("width");
const begin = ", title && '"' + title + '"', size(width, height)].filter(Boolean).join(" ") + ")";
return generateOpenG({
ctype: "image",
equivText: `${begin}{{text}}${end}`,
xBegin: begin,
xEnd: end
});
} else {
return generateX({
ctype: "image_text_part_open",
equivText: "!["
});
}
}
function imageClose(tokens, idx) {
const close3 = tokens[idx];
if (close3.g) {
return generateCloseG();
}
let rendered = "";
rendered += generateX({
ctype: "image_text_part_close",
equivText: "]"
});
rendered += generateX({
ctype: "image_attributes_part_open",
equivText: "("
});
let src = close3.attrGet("src");
if (src == null ? void 0 : src.length) {
src = decodeURL(src);
rendered += generateX({
ctype: "image_attributes_src",
equivText: src
});
}
const title = close3.attrGet("title");
if (title == null ? void 0 : title.length) {
rendered += generateX({
ctype: "image_attributes_title",
equivText: title
});
}
const height = close3.attrGet("height");
const width = close3.attrGet("width");
if ((width == null ? void 0 : width.length) || (height == null ? void 0 : height.length)) {
rendered += generateX({
ctype: "image_attributes_size",
equivText: size(width, height)
});
}
rendered += generateX({
ctype: "image_attributes_part_close",
equivText: ")"
});
return rendered;
}
function size(width, height) {
if (!(width == null ? void 0 : width.length) && !(height == null ? void 0 : height.length)) {
return "";
}
let equivText = "=";
if (width == null ? void 0 : width.length) {
equivText += width;
}
equivText += "x";
if (height == null ? void 0 : height.length) {
equivText += height;
}
return equivText;
}
// src/xliff/md-xliff/rules/video.ts
var video = {
video: videoRule
};
function videoRule(tokens, i) {
const { service, videoID } = tokens[i];
return generateX({ ctype: "video", equivText: `@[${service}](${videoID})` });
}
// src/xliff/md-xliff/rules/file.ts
var file = {
yfm_file: fileRule
};
var attributes = /* @__PURE__ */ new Map([
["href", "src"],
["download", "name"],
["hreflang", "lang"],
["type", "type"],
["target", "target"],
["rel", "rel"],
["referrerpolicy", "referrerpolicy"]
]);
var translatable = /* @__PURE__ */ new Set(["download"]);
function fileRule(tokens, i) {
const { attrs: attrs2 } = tokens[i];
if (!(attrs2 == null ? void 0 : attrs2.length)) {
throw new Error(`failed to render token: ${tokens[i]}`);
}
let rendered = generateX({
ctype: "file_open",
equivText: "{%"
});
for (const [key, val] of attrs2) {
const attribute = attributes.get(key);
if (!(attribute == null ? void 0 : attribute.length)) {
continue;
}
const ctype = `file_${attribute}`;
const equivText = `${attribute}="${val}"`;
if (translatable.has(key)) {
rendered += generateX({
ctype: `${ctype}_open`,
equivText: `${attribute}="`
});
rendered += val;
rendered += generateX({
ctype: `${ctype}_close`,
equivText: '"'
});
} else {
rendered += generateX({ ctype, equivText });
}
}
rendered += generateX({
ctype: "file_close",
equivText: "%}"
});
return rendered;
}
// src/xliff/md-xliff/rules/html-inline.ts
var htmlInline = {
html_inline: function(tokens, i) {
const { skip: skip2, type: type2 } = tokens[i];
return generateX({ ctype: type2, equivText: (skip2 || "").toString() });
}
};
// src/xliff/md-xliff/rules/index.ts
var rules2 = {
code_block: () => "",
fence: () => "",
html_block: () => "",
heading_open: () => "",
heading_close: () => "",
paragraph_open: () => "",
paragraph_close: () => "",
bullet_list_open: () => "",
bullet_list_close: () => "",
ordered_list_open: () => "",
ordered_list_close: () => "",
blockquote_open: () => "",
blockquote_close: () => "",
list_item_open: () => "",
list_item_close: () => "",
...rules,
...breaks,
...pair,
...codeInline,
...link,
...text,
...liquid,
...image,
...video,
...file,
...htmlInline
};
// src/xliff/md-xliff/index.ts
function render(tokens, unitId, compact = false) {
const xliffRenderer = new import_markdown_it4.default({ html: true });
xliffRenderer.use(customRenderer, { rules: rules2, hooks, compact });
const source = xliffRenderer.renderer.render(
[
token("inline", {
children: groupUselessTokens(tokens)
})
],
xliffRenderer.options,
{}
);
return transunit({
source,
compact,
id: unitId
});
}
function groupUselessTokens(tokens) {
const map = {};
const result = [];
for (const part of tokens) {
if (!part.content) {
const [name, type2] = part.type.split("_");
if (type2 === "open") {
map[part.type] = map[part.type] || [];
map[part.type].push(part);
} else if (type2 === "close") {
map[name + "_open"] = map[name + "_open"] || [];
const opener = map[name + "_open"].pop();
if (opener) {
opener.g = part;
part.g = opener;
}
}
}
result.push(part);
}
return result;
}
// src/xliff/xliff-md/index.ts
var import_assert = __toESM(require("assert"));
// src/xliff/token.ts
var xliffTagTokenNodeTypes = /* @__PURE__ */ new Set(["open", "close", "self-closing"]);
function isXLFTextToken(token2) {
return (token2 == null ? void 0 : token2.type) === "text";
}
function isXLFTagToken(token2) {
return (token2 == null ? void 0 : token2.type) === "tag" && xliffTagTokenNodeTypes.has(token2.nodeType);
}
// src/xliff/xliff-md/index.ts
var literal = (token2) => {
(0, import_assert.default)(isXLFTagToken(token2));
token2;
const { equivText } = token2;
(0, import_assert.default)(
equivText == null ? void 0 : equivText.length,
"literal tag should contain original markup inside equiv-text attritbute"
);
return equivText;
};
var openclose = (token2) => {
(0, import_assert.default)(isXLFTagToken(token2));
token2;
if (token2.nodeType === "open") {
return token2.begin;
} else {
return token2.end;
}
};
var spaced = (actor) => (token2) => " " + actor(token2);
var quoted = (actor) => (token2) => '"' + actor(token2) + '"';
var attr = spaced(quoted(literal));
var XLFMDRenderer = class {
constructor() {
this.rules = {
text: this.text.bind(this),
tag: this.tag.bind(this),
x: this.x.bind(this),
g: this.g.bind(this),
// simple pair syntax
// strong
bold: openclose,
bold_open: literal,
bold_close: literal,
// em
italic: openclose,
italic_open: literal,
italic_close: literal,
// s
strikethrough: openclose,
strikethrough_open: literal,
strikethrough_close: literal,
// sup
sup: openclose,
sup_open: literal,
sup_close: literal,
// sup
monospace: openclose,
monospace_open: literal,
monospace_close: literal,
// samp
samp_open: literal,
samp_close: literal,
// code
code_open: literal,
code_close: literal,
lb: literal,
// link
link: openclose,
link_text_part_open: literal,
link_text_part_close: literal,
link_attributes_part_open: literal,
link_attributes_part_close: literal,
link_attributes_href: literal,
link_attributes_title: attr,
link_autolink: literal,
link_reflink: literal,
// image
image: openclose,
image_text_part_open: literal,
image_text_part_close: literal,
image_attributes_part_open: literal,
image_attributes_part_close: literal,
image_attributes_src: literal,
image_attributes_title: attr,
image_attributes_size: spaced(literal),
// video
video: literal,
// anchor
anchor: literal,
// file
file_open: literal,
file_src: spaced(literal),
file_name_open: spaced(literal),
file_name_close: literal,
file_referrerpolicy: spaced(literal),
file_rel: spaced(literal),
file_target: spaced(literal),
file_type: spaced(literal),