UNPKG

@node-novel/layout

Version:
370 lines (369 loc) 11.8 kB
"use strict"; /** * Created by user on 2019/5/29. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.create = exports.TextLayout = exports.SP_REGEXP = exports.SP_KEY = void 0; const blank_line_1 = require("blank-line"); const crlf_normalize_1 = require("crlf-normalize"); const env_bool_1 = require("env-bool"); const array_hyper_unique_1 = require("array-hyper-unique"); const util_1 = require("./util"); const str_util_trim_1 = require("@lazy-cjk/str-util-trim"); const str_util_normalize_1 = require("@lazy-cjk/str-util-normalize"); exports.SP_KEY = "#_@_#"; exports.SP_REGEXP = "(?:@|(·?)|-|/|\\(\\)|%|¥|_|\\?|?|\\||#|\\$|[(\\(](?:和谐|河蟹)[\\))]|(河)(蟹)|[(\\(][河蟹]{1,2}[\\))]| |\\.|[・·]|\\*|□|圌|[==]|\\\\\\\\|\\/\\/||)"; /** * 排版處理核心 */ class TextLayout { constructor(options, ...argv) { this.SP_KEY = exports.SP_KEY; this.SP_REGEXP = exports.SP_REGEXP; this._cache_ = { replace: [], words: new Map(), }; this._data_ = { m0: /([^a-z0-9\-\.\s])?([a-z0-9\-\.]+(?:[a-z0-9\-\.\s]+[a-z0-9\-\.]+)?)([^a-z0-9\-\.\s])?/uig, r1: /[「」①→\'\":\-\+()╮(╯_╰)╭\(\)\[\]■【】《》~~“”‘’:::,**@。ω・、。`\u3000─一\d『』◆~、?!\?\!×\.\<\>=…・]/i, rtrim: /[ \t\uFEFF\xA0\u3000]+$/, words: [], }; this.options = null; let arr = (options && options.words_block) ? options.words_block.slice() : []; if (options) { if (options.rtrim) { this._data_.rtrim = options.rtrim; } if (options.words) { this._data_.words = options.words; } if (options.m0) { this._data_.m0 = options.m0; } if (options.r1) { this._data_.r1 = options.r1; } if (options.SP_KEY) { this.SP_KEY = options.SP_KEY; } if (options.SP_REGEXP) { let v = options.SP_REGEXP; if (v instanceof RegExp) { v = v.source; } this.SP_REGEXP = v; } if (options.RegExpClass) { this._RegExpClass = options.RegExpClass; } } this.options = options || null; this._init(arr); } static create(options, ...argv) { return new this(options, ...argv); } _init(arr) { this._data_.words = this._words1(arr, this._data_.words); this._data_.words = this._words2(this._data_.words); } get RegExp() { return this._RegExpClass || RegExp; } /** * 簡易型樣式處理 適用於 屏蔽字或者人名或者因為編碼問題而變成 ? 那些之類的點 * * @private */ _words1(arr, words = []) { const SP_REGEXP = this.SP_REGEXP; const RC = this.RegExp; (0, array_hyper_unique_1.array_unique)(arr) .forEach(function (value) { let a = value.split('@'); /* _self._data_.words.push({ s: new RegExp(`(${a[0]})${r}(${a[1]})`, 'g'), r: '$1$2', }); */ let s = a.join(`)${SP_REGEXP}(`); words.push({ s: new RC(`(${s})`, 'g'), r: a.map(function (value, index, array) { return '$' + (index + 1); }).join(''), }); }); return words; } /** * 將樣式轉換成實際使用的樣式物件 * * @private */ _words2(words) { const SP_REGEXP = this.SP_REGEXP; const RC = this.RegExp; return words.map(function (value, index, array) { // @ts-ignore if (value.no_regex) { return value; } if ((0, util_1._isIwordsArray)(value)) { value = { _source: value, s: value[0], r: value[1], flags: value[2], }; } if ((0, util_1._isIwordsArray2)(value)) { return value[0]; } else if ((0, util_1._isIwordsUserSp)(value)) { if (!value._source) value._source = value.s; let a = value.s.split(exports.SP_KEY); let s = a.join(`)${SP_REGEXP}(`); // @ts-ignore value.s = new RC(`(${s})`, value.flags ? value.flags : 'g'); //console.log(value.s); if (value.r === null) { value.r = a.map(function (value, index, array) { return '$' + (index + 1); }).join(''); } } else if (typeof value.s == 'string') { // @ts-ignore if (!value._source) value._source = value.s; value.s = new RC(value.s, value.flags ? value.flags : 'g'); } else if (typeof value.fn == 'function') { return value.fn; } return value; }); } replace(text, options = {}) { if (!text || !/[^\s]/.test(text)) { return text; } let _self = this; let _ret = this.toStr(text) .replace(_self._data_.rtrim, ''); if (options.pad_eng) { _ret = this.paddingEng(_ret); } if (options.words) { _ret = this.replace_words(_ret, _self._data_.words, _self._cache_.words).value; } return _ret; } /** * for run rule one by one */ replace_row(_ret, value, cacheMap) { let _new; if (typeof value == 'function') { _new = value(_ret, cacheMap); } else { let _r = value.s; _new = _ret.replace(_r, value.r); } if (cacheMap && _new !== _ret) { let myMap = []; if (cacheMap.has(value)) { myMap = cacheMap.get(value); } myMap.push({ old: _ret, new: _new, }); cacheMap.set(value, myMap); } return _new; } replace_words(_ret, words, cacheMap) { if (cacheMap) { if (cacheMap === true) { cacheMap = new Map(); } } else { cacheMap = null; } for (let value of words) { _ret = this.replace_row(_ret, value, cacheMap); if (!/[\S]/.test(_ret)) { break; } } return { value: _ret, cache: cacheMap, }; } /** * @deprecated */ paddingEng(text) { let _self = this; return this.toStr(text) .replace(_self._data_.m0, function (...argv) { if (argv[2]) { let old = argv[2]; if (argv[2].length > 1 && argv[1] && !_self._data_.r1.test(argv[1])) { argv[2] = ' ' + argv[2]; } if (argv[3] && !_self._data_.r1.test(argv[3])) { argv[2] = argv[2] + ' '; } if (old != argv[2]) { _self._cache_.replace.push({ old, new: argv[2], data: argv, }); } else { //console.debug([old, argv[2]], argv); } return (argv[1] || '') + argv[2].replace(/( ){2,}/g, '$1') + (argv[3] || ''); } return argv[0]; }); } /** * @deprecated */ clearLF(text) { return this.trim(text) .replace(/\n{4,}/g, '\n\n') .replace(/\n{3,}/g, '\n\n'); } trim(text, options) { if (typeof options == 'boolean') { options = { trim: options, }; } else if (typeof options == 'string') { options = { trim: options, }; } let ret = this.toStr(text, options) .replace(/[ \t\u3000\xA0\u3000]+\n/g, '\n') .replace(/^\n+|[\s\u3000\xA0\u3000]+$/g, ''); if (options) { if (typeof options.trim == 'string') { ret = (0, str_util_trim_1.trim)(ret, '\u3000' + options.trim); } else if (options.trim) { ret = (0, str_util_trim_1.trim)(ret, '\u3000'); } } return ret; } /** * 轉換為文字並且標準化 */ toStr(str, options) { if (typeof options == 'string') { options = { LF: options, }; } options = Object.assign({ LF: "\n", allow_nbsp: false, allow_bom: false, }, options); let ret = (0, crlf_normalize_1.crlf)(str.toString(), options.LF || crlf_normalize_1.LF); ret = (0, str_util_normalize_1.normalize)(ret, options); /* if (!options.allow_bom) { ret = ret.replace(/\uFEFF/g, ''); } if (!options.allow_nbsp) { ret = ret.replace(/[  \xA0]/g, ' '); } */ return ret; } fixOptions(options) { Object.entries(options) .forEach(([k, v]) => options[k] = (0, env_bool_1.envVal)(v)); return options; } /** * @deprecated */ reduceLine(html, options = {}) { options = this.fixOptions(options); if (options.allow_lf2) { return html; } let old = this.trim(html, options); old = //html //.replace(/\r\n|\r(?!\n)/g, "\n") old .replace(/[ \u3000\t]+\n/g, "\n") .replace(/[\s\u3000]+$/g, '') .replace(/^[\n \t]+/g, '') .replace(/\n{4,}/g, "\n\n\n\n"); let _html = old; if (!_html.match(/[^\n]\n[^\n]/g)) { let [min, mid, max] = (0, blank_line_1.getMinMidMax)(_html.toString()); if (min > 2) { options.allow_lf2 = false; } if (max >= 3) { if (min > 2) { let r = new RegExp(`\\n{${min - 1}}(\\n+)`, 'g'); _html = _html //.replace(/\n{2}(\n*)/g, '$1') .replace(r, '$1'); } _html = _html .replace(/\n{3,}/g, "\n\n\n"); } //console.log(options); if (!options.allow_lf2) { _html = _html .replace(/\n\n/g, "\n"); } if (_html != old) { return _html; } } return html; } /** * 通用型段落調整 * * @returns {string} */ textlayout(input, options = {}) { options = this.fixOptions(options); let html = this.trim(input, options); html = html .replace(/[ \u3000\t]+\n/g, "\n") .replace(/[\s\u3000]+$/g, '') .replace(/^[\n \t]+/g, '') .replace(/\n{4,}/g, "\n\n\n\n" /* EnumLF.LF4 */); return (0, util_1._handleTextLayout)(html, options); } } exports.TextLayout = TextLayout; exports.create = TextLayout.create.bind(TextLayout); exports.default = TextLayout; //# sourceMappingURL=index.js.map