securemark 0.294.6 → 0.294.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/index.js +63 -35
- package/package.json +1 -1
- package/src/combinator/control/manipulation/indent.ts +3 -5
- package/src/combinator/control/manipulation/surround.ts +43 -14
- package/src/parser/api/normalize.ts +9 -11
- package/src/parser/api/parse.test.ts +3 -3
- package/src/parser/inline/autolink/account.ts +2 -3
- package/src/parser/inline/autolink/anchor.ts +1 -2
- package/src/parser/inline/autolink/channel.ts +5 -5
- package/src/parser/inline/autolink/hashnum.ts +4 -5
- package/src/parser/inline/autolink/hashtag.ts +5 -5
- package/src/parser/inline/autolink.ts +36 -24
- package/src/parser/inline/html.ts +1 -1
- package/src/parser/inline/htmlentity.ts +1 -1
- package/src/parser/inline.ts +2 -1
- package/src/parser/source/text.ts +3 -3
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.294.
|
|
1
|
+
/*! securemark v0.294.7 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
|
|
2
2
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
3
3
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
4
4
|
module.exports = factory(require("Prism"), require("DOMPurify"));
|
|
@@ -2894,9 +2894,7 @@ function indent(opener, parser = false, separation = false) {
|
|
|
2894
2894
|
} = context;
|
|
2895
2895
|
context.position = source.length;
|
|
2896
2896
|
return new parser_1.List([new parser_1.Data(source.slice(position))]);
|
|
2897
|
-
}))), ([indent]) => indent.length * 2 + -(indent[0] === ' '), [], 2 ** 4 - 1)), separation), (lines, context) =>
|
|
2898
|
-
return parser((0, parser_1.subinput)(trimBlockEnd(lines.foldl((acc, node) => acc + node.value, '')), context));
|
|
2899
|
-
}));
|
|
2897
|
+
}))), ([indent]) => indent.length * 2 + -(indent[0] === ' '), [], 2 ** 4 - 1)), separation), (lines, context) => parser((0, parser_1.subinput)(trimBlockEnd(lines.foldl((acc, node) => acc + node.value, '')), context))));
|
|
2900
2898
|
}
|
|
2901
2899
|
exports.indent = indent;
|
|
2902
2900
|
function trimBlockEnd(block) {
|
|
@@ -3094,6 +3092,11 @@ function surround(opener, parser, closer, optional = false, f, g, backtracks = [
|
|
|
3094
3092
|
case 'object':
|
|
3095
3093
|
opener = (0, combinator_1.clear)((0, combinator_1.matcher)(opener, true));
|
|
3096
3094
|
}
|
|
3095
|
+
switch (typeof parser) {
|
|
3096
|
+
case 'string':
|
|
3097
|
+
case 'object':
|
|
3098
|
+
parser = (0, combinator_1.clear)((0, combinator_1.matcher)(parser, true));
|
|
3099
|
+
}
|
|
3097
3100
|
switch (typeof closer) {
|
|
3098
3101
|
case 'string':
|
|
3099
3102
|
case 'object':
|
|
@@ -3124,16 +3127,14 @@ function surround(opener, parser, closer, optional = false, f, g, backtracks = [
|
|
|
3124
3127
|
if (!nodesM && !optional) {
|
|
3125
3128
|
setBacktrack(context, backtracks, position);
|
|
3126
3129
|
const result = g?.([nodesO, nodesM], context);
|
|
3127
|
-
revert(context, linebreak);
|
|
3128
|
-
return result;
|
|
3130
|
+
return result || void revert(context, linebreak);
|
|
3129
3131
|
}
|
|
3130
3132
|
const nodesC = nodesM || optional ? closer(input) : undefined;
|
|
3131
3133
|
context.range = context.position - position;
|
|
3132
3134
|
if (!nodesC) {
|
|
3133
3135
|
setBacktrack(context, backtracks, position);
|
|
3134
3136
|
const result = g?.([nodesO, nodesM], context);
|
|
3135
|
-
revert(context, linebreak);
|
|
3136
|
-
return result;
|
|
3137
|
+
return result || void revert(context, linebreak);
|
|
3137
3138
|
}
|
|
3138
3139
|
if (context.position === position) {
|
|
3139
3140
|
return void revert(context, linebreak);
|
|
@@ -3142,10 +3143,8 @@ function surround(opener, parser, closer, optional = false, f, g, backtracks = [
|
|
|
3142
3143
|
const result = f ? f([nodesO, nodesM, nodesC], context) : nodesO.import(nodesM ?? new parser_1.List()).import(nodesC);
|
|
3143
3144
|
if (result) {
|
|
3144
3145
|
context.linebreak ||= linebreak;
|
|
3145
|
-
} else {
|
|
3146
|
-
revert(context, linebreak);
|
|
3147
3146
|
}
|
|
3148
|
-
return result;
|
|
3147
|
+
return result || void revert(context, linebreak);
|
|
3149
3148
|
});
|
|
3150
3149
|
}
|
|
3151
3150
|
exports.surround = surround;
|
|
@@ -3183,7 +3182,7 @@ function isBacktrack(context, backtracks, position = context.position, length =
|
|
|
3183
3182
|
}
|
|
3184
3183
|
exports.isBacktrack = isBacktrack;
|
|
3185
3184
|
function setBacktrack(context, backtracks, position, length = 1) {
|
|
3186
|
-
//
|
|
3185
|
+
// バックトラックの可能性がなく記録不要の場合もあるが判別が面倒なので省略
|
|
3187
3186
|
const {
|
|
3188
3187
|
source
|
|
3189
3188
|
} = context;
|
|
@@ -4396,8 +4395,9 @@ exports.normalize = normalize;
|
|
|
4396
4395
|
function format(source) {
|
|
4397
4396
|
return source.replace(/\r\n?/g, '\n');
|
|
4398
4397
|
}
|
|
4398
|
+
const invalid = new RegExp([/(?![\t\r\n])[\x00-\x1F\x7F]/g.source, /(?!\u200D)[\u2006\u200B-\u200F\u202A-\u202F\u2060\uFEFF]|(?<![\u1820\u1821])\u180E/g.source, /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g.source].join('|'), 'g');
|
|
4399
4399
|
function sanitize(source) {
|
|
4400
|
-
return source.replace(
|
|
4400
|
+
return source.replace(invalid, UNICODE_REPLACEMENT_CHARACTER);
|
|
4401
4401
|
}
|
|
4402
4402
|
// https://dev.w3.org/html5/html-author/charref
|
|
4403
4403
|
// https://en.wikipedia.org/wiki/Whitespace_character
|
|
@@ -6041,6 +6041,7 @@ const reference_1 = __webpack_require__(9047);
|
|
|
6041
6041
|
const template_1 = __webpack_require__(4510);
|
|
6042
6042
|
const remark_1 = __webpack_require__(8948);
|
|
6043
6043
|
const extension_1 = __webpack_require__(2743);
|
|
6044
|
+
const label_1 = __webpack_require__(2178);
|
|
6044
6045
|
const link_1 = __webpack_require__(3628);
|
|
6045
6046
|
const ruby_1 = __webpack_require__(7304);
|
|
6046
6047
|
const html_1 = __webpack_require__(5013);
|
|
@@ -6096,7 +6097,7 @@ exports.inline = (0, combinator_1.lazy)(() => (0, combinator_1.union)([input =>
|
|
|
6096
6097
|
return (0, html_1.html)(input);
|
|
6097
6098
|
case '$':
|
|
6098
6099
|
if (source[position + 1] === '{') return (0, math_1.math)(input);
|
|
6099
|
-
return (0,
|
|
6100
|
+
return (0, label_1.label)(input) || (0, math_1.math)(input);
|
|
6100
6101
|
case '+':
|
|
6101
6102
|
if (source[position + 1] === '+') return (0, insertion_1.insertion)(input);
|
|
6102
6103
|
break;
|
|
@@ -6208,16 +6209,45 @@ const account_1 = __webpack_require__(4107);
|
|
|
6208
6209
|
const hashtag_1 = __webpack_require__(5764);
|
|
6209
6210
|
const hashnum_1 = __webpack_require__(8684);
|
|
6210
6211
|
const anchor_1 = __webpack_require__(8535);
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6212
|
+
const text_1 = __webpack_require__(5655);
|
|
6213
|
+
exports.autolink = (0, combinator_1.lazy)(() => (0, combinator_1.state)(~1 /* State.autolink */, input => {
|
|
6214
|
+
const {
|
|
6215
|
+
context: {
|
|
6216
|
+
source,
|
|
6217
|
+
position
|
|
6218
|
+
}
|
|
6219
|
+
} = input;
|
|
6220
|
+
if (position === source.length) return;
|
|
6221
|
+
const fst = source[position];
|
|
6222
|
+
switch (fst) {
|
|
6223
|
+
case '@':
|
|
6224
|
+
return (0, channel_1.channel)(input) || (0, account_1.account)(input);
|
|
6225
|
+
case '#':
|
|
6226
|
+
return (0, hashtag_1.hashtag)(input) || (0, hashnum_1.hashnum)(input);
|
|
6227
|
+
case '>':
|
|
6228
|
+
return (0, anchor_1.anchor)(input);
|
|
6229
|
+
case '!':
|
|
6230
|
+
if (!source.startsWith('http', position + 1)) break;
|
|
6231
|
+
if (position === 0) return (0, url_1.lineurl)(input);
|
|
6232
|
+
switch (source[position - 1]) {
|
|
6233
|
+
case '\r':
|
|
6234
|
+
case '\n':
|
|
6235
|
+
return (0, url_1.lineurl)(input);
|
|
6236
|
+
}
|
|
6237
|
+
break;
|
|
6238
|
+
case 'h':
|
|
6239
|
+
if (!source.startsWith('http', position)) return;
|
|
6240
|
+
if (position === 0) return (0, url_1.lineurl)(input) || (0, url_1.url)(input) || (0, email_1.email)(input);
|
|
6241
|
+
switch (source[position - 1]) {
|
|
6242
|
+
case '\r':
|
|
6243
|
+
case '\n':
|
|
6244
|
+
return (0, url_1.lineurl)(input) || (0, url_1.url)(input) || (0, email_1.email)(input);
|
|
6245
|
+
}
|
|
6246
|
+
return (0, url_1.url)(input) || (0, email_1.email)(input);
|
|
6247
|
+
default:
|
|
6248
|
+
if ((0, text_1.isAlphanumeric)(fst)) return (0, email_1.email)(input);
|
|
6249
|
+
}
|
|
6250
|
+
}));
|
|
6221
6251
|
|
|
6222
6252
|
/***/ },
|
|
6223
6253
|
|
|
@@ -6234,10 +6264,9 @@ exports.account = void 0;
|
|
|
6234
6264
|
const parser_1 = __webpack_require__(605);
|
|
6235
6265
|
const combinator_1 = __webpack_require__(3484);
|
|
6236
6266
|
const link_1 = __webpack_require__(3628);
|
|
6237
|
-
const source_1 = __webpack_require__(8745);
|
|
6238
6267
|
const dom_1 = __webpack_require__(394);
|
|
6239
6268
|
// https://example/@user must be a user page or a redirect page going there.
|
|
6240
|
-
exports.account = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.surround)(/(?<![0-9a-z])@/yi,
|
|
6269
|
+
exports.account = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.surround)(/(?<![0-9a-z])@/yi, /[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*\//yi, /[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*(?![-.]?[0-9a-z@#]|>>|:\S)/yi, true, undefined, undefined, [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.fmap)((0, combinator_1.convert)(source => `[${source}]{ ${source.includes('/') ? `https://${source.slice(1).replace('/', '/@')}` : `/${source}`} }`, (0, combinator_1.union)([link_1.unsafelink]), false), ([{
|
|
6241
6270
|
value
|
|
6242
6271
|
}]) => new parser_1.List([new parser_1.Data((0, dom_1.define)(value, {
|
|
6243
6272
|
class: 'account'
|
|
@@ -6258,7 +6287,6 @@ exports.anchor = void 0;
|
|
|
6258
6287
|
const parser_1 = __webpack_require__(605);
|
|
6259
6288
|
const combinator_1 = __webpack_require__(3484);
|
|
6260
6289
|
const link_1 = __webpack_require__(3628);
|
|
6261
|
-
const source_1 = __webpack_require__(8745);
|
|
6262
6290
|
const dom_1 = __webpack_require__(394);
|
|
6263
6291
|
// Timeline(pseudonym): user/tid
|
|
6264
6292
|
// Thread(anonymous): cid
|
|
@@ -6267,7 +6295,7 @@ const dom_1 = __webpack_require__(394);
|
|
|
6267
6295
|
// cid: YYYY-MMDD-HHMM-SSmmm
|
|
6268
6296
|
// 内部表現はUnixTimeに統一する(時系列順)
|
|
6269
6297
|
// 外部表現は投稿ごとに投稿者の投稿時のタイムゾーンに統一する(非時系列順)
|
|
6270
|
-
exports.anchor = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)(/(?<![0-9a-z])>>/yi,
|
|
6298
|
+
exports.anchor = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)(/(?<![0-9a-z])>>/yi, /(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*\/)?[0-9a-z]+(?:-[0-9a-z]+)*(?!-?[0-9a-z@#]|>>|:\S)/yi, false, [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.fmap)((0, combinator_1.convert)(source => `[${source}]{ ${source.includes('/') ? `/@${source.slice(2).replace('/', '/timeline?at=')}` : `?at=${source.slice(2)}`} }`, (0, combinator_1.union)([link_1.unsafelink]), false), ([{
|
|
6271
6299
|
value
|
|
6272
6300
|
}]) => new parser_1.List([new parser_1.Data((0, dom_1.define)(value, {
|
|
6273
6301
|
class: 'anchor'
|
|
@@ -6292,7 +6320,7 @@ const hashtag_1 = __webpack_require__(5764);
|
|
|
6292
6320
|
const source_1 = __webpack_require__(8745);
|
|
6293
6321
|
const dom_1 = __webpack_require__(394);
|
|
6294
6322
|
// https://example/@user?ch=a+b must be a user channel page or a redirect page going there.
|
|
6295
|
-
exports.channel = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.sequence)([(0, combinator_1.surround)(/(?<![0-9a-z])@/yi,
|
|
6323
|
+
exports.channel = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.sequence)([(0, combinator_1.surround)(/(?<![0-9a-z])@/yi, /[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*\//yi, /[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*(?![-.]?[0-9a-z@]|>>|:\S)/yi, true, undefined, undefined, [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.some)((0, combinator_1.verify)((0, combinator_1.surround)('#', (0, source_1.str)(new RegExp([/(?!['_])(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^\p{C}\p{S}\p{P}\s]|emoji))+/yu.source].join('|').replace(/emoji/g, hashtag_1.emoji.source), 'yu')), new RegExp([/(?![0-9a-z@]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source].join('|').replace(/emoji/g, hashtag_1.emoji.source), 'yu'), false, undefined, undefined, [3 | 0 /* Backtrack.autolink */]), ([{
|
|
6296
6324
|
value
|
|
6297
6325
|
}]) => !/^[0-9]{1,4}$|^[0-9]{5}/.test(value)))]), (0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.fmap)((0, combinator_1.convert)(source => `[${source}]{ ${source.includes('/') ? `https://${source.slice(1, source.indexOf('#')).replace('/', '/@')}` : `/${source.slice(0, source.indexOf('#'))}`} }`, (0, combinator_1.union)([link_1.unsafelink]), false), ([{
|
|
6298
6326
|
value: el
|
|
@@ -6353,9 +6381,8 @@ const parser_1 = __webpack_require__(605);
|
|
|
6353
6381
|
const combinator_1 = __webpack_require__(3484);
|
|
6354
6382
|
const link_1 = __webpack_require__(3628);
|
|
6355
6383
|
const hashtag_1 = __webpack_require__(5764);
|
|
6356
|
-
const source_1 = __webpack_require__(8745);
|
|
6357
6384
|
const dom_1 = __webpack_require__(394);
|
|
6358
|
-
exports.hashnum = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)(new RegExp([/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/
|
|
6385
|
+
exports.hashnum = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)(new RegExp([/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yu.source].join('|').replace(/emoji/g, hashtag_1.emoji.source), 'yu'), new RegExp([/[0-9]{1,9}(?![0-9a-z@#]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source].join('|').replace(/emoji/g, hashtag_1.emoji.source), 'yu'), false, [1 | 0 /* Backtrack.autolink */]), (0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.fmap)((0, combinator_1.convert)(source => `[${source}]{ ${source.slice(1)} }`, (0, combinator_1.union)([link_1.unsafelink]), false), ([{
|
|
6359
6386
|
value
|
|
6360
6387
|
}]) => new parser_1.List([new parser_1.Data((0, dom_1.define)(value, {
|
|
6361
6388
|
class: 'hashnum',
|
|
@@ -6382,7 +6409,7 @@ const dom_1 = __webpack_require__(394);
|
|
|
6382
6409
|
// https://example/hashtags/a must be a hashtag page or a redirect page going there.
|
|
6383
6410
|
// https://github.com/tc39/proposal-regexp-unicode-property-escapes#matching-emoji
|
|
6384
6411
|
exports.emoji = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F|\u200D/u;
|
|
6385
|
-
exports.hashtag = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.verify)((0, combinator_1.surround)(new RegExp([/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/
|
|
6412
|
+
exports.hashtag = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.verify)((0, combinator_1.surround)(new RegExp([/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yu.source].join('|').replace(/emoji/g, exports.emoji.source), 'yu'), (0, source_1.str)(new RegExp([/(?!['_])(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^\p{C}\p{S}\p{P}\s]|emoji))+/yu.source].join('|').replace(/emoji/g, exports.emoji.source), 'yu')), new RegExp([/(?![0-9a-z@#]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source].join('|').replace(/emoji/g, exports.emoji.source), 'yu'), false, undefined, undefined, [3 | 0 /* Backtrack.autolink */]), ([{
|
|
6386
6413
|
value
|
|
6387
6414
|
}]) => !/^[0-9]{1,4}$|^[0-9]{5}/.test(value)), (0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.fmap)((0, combinator_1.convert)(source => `[${source}]{ ${`/hashtags/${source.slice(1)}`} }`, (0, combinator_1.union)([link_1.unsafelink]), false), ([{
|
|
6388
6415
|
value
|
|
@@ -7065,7 +7092,7 @@ Object.setPrototypeOf(attrspecs, null);
|
|
|
7065
7092
|
Object.values(attrspecs).forEach(o => Object.setPrototypeOf(o, null));
|
|
7066
7093
|
exports.html = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(/<[a-z]+(?=[ >])/yi, (0, combinator_1.union)([(0, combinator_1.surround)(
|
|
7067
7094
|
// https://html.spec.whatwg.org/multipage/syntax.html#void-elements
|
|
7068
|
-
(0, source_1.str)(/<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[ >])/
|
|
7095
|
+
(0, source_1.str)(/<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[ >])/y), (0, combinator_1.some)((0, combinator_1.union)([exports.attribute])), (0, combinator_1.open)((0, source_1.str)(/ ?/y), (0, source_1.str)('>'), true), true, ([as, bs = new parser_1.List(), cs], context) => new parser_1.List([new parser_1.Data(elem(as.head.value.slice(1), false, [...(0, util_1.unwrap)(as.import(bs).import(cs))], new parser_1.List(), new parser_1.List(), context))]), ([as, bs = new parser_1.List()], context) => new parser_1.List([new parser_1.Data(elem(as.head.value.slice(1), false, [...(0, util_1.unwrap)(as.import(bs))], new parser_1.List(), new parser_1.List(), context))])), (0, combinator_1.match)(new RegExp(String.raw`<(${TAGS.join('|')})(?=[ >])`, 'y'), (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, combinator_1.open)((0, source_1.str)(/ ?/y), (0, source_1.str)('>'), true), true, ([as, bs = new parser_1.List(), cs]) => as.import(bs).import(cs), ([as, bs = new parser_1.List()]) => as.import(bs)),
|
|
7069
7096
|
// 不可視のHTML構造が可視構造を変化させるべきでない。
|
|
7070
7097
|
// 可視のHTMLは優先度変更を検討する。
|
|
7071
7098
|
// このため<>は将来的に共通構造を変化させる可能性があり
|
|
@@ -8509,7 +8536,7 @@ exports.strs = strs;
|
|
|
8509
8536
|
Object.defineProperty(exports, "__esModule", ({
|
|
8510
8537
|
value: true
|
|
8511
8538
|
}));
|
|
8512
|
-
exports.backToEmailHead = exports.backToUrlHead = exports.backToWhitespace = exports.next = exports.canSkip = exports.linebreak = exports.txt = exports.text = exports.nonWhitespace = void 0;
|
|
8539
|
+
exports.isAlphanumeric = exports.backToEmailHead = exports.backToUrlHead = exports.backToWhitespace = exports.next = exports.canSkip = exports.linebreak = exports.txt = exports.text = exports.nonWhitespace = void 0;
|
|
8513
8540
|
const parser_1 = __webpack_require__(605);
|
|
8514
8541
|
const combinator_1 = __webpack_require__(3484);
|
|
8515
8542
|
const dom_1 = __webpack_require__(394);
|
|
@@ -8670,8 +8697,9 @@ function backToEmailHead(source, position, index) {
|
|
|
8670
8697
|
exports.backToEmailHead = backToEmailHead;
|
|
8671
8698
|
function isAlphanumeric(char) {
|
|
8672
8699
|
if (char < '0' || '\x7F' < char) return false;
|
|
8673
|
-
return '0' <= char && char <= '9' || '
|
|
8700
|
+
return '0' <= char && char <= '9' || 'A' <= char && char <= 'Z' || 'a' <= char && char <= 'z';
|
|
8674
8701
|
}
|
|
8702
|
+
exports.isAlphanumeric = isAlphanumeric;
|
|
8675
8703
|
//const dict = new class {
|
|
8676
8704
|
// constructor() {
|
|
8677
8705
|
// [
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@ export function indent<N>(opener: RegExp | Parser<N>, parser: Parser<N> | boolea
|
|
|
16
16
|
opener = / {1,4}|\t{1,2}/y;
|
|
17
17
|
}
|
|
18
18
|
assert(!opener.flags.match(/[gm]/) && opener.sticky && !opener.source.startsWith('^'));
|
|
19
|
-
assert(parser);
|
|
19
|
+
assert(parser = parser as Parser<N>);
|
|
20
20
|
return failsafe(bind(block(match(
|
|
21
21
|
opener,
|
|
22
22
|
memoize(
|
|
@@ -27,10 +27,8 @@ export function indent<N>(opener: RegExp | Parser<N>, parser: Parser<N> | boolea
|
|
|
27
27
|
return new List([new Data(source.slice(position))]);
|
|
28
28
|
}))),
|
|
29
29
|
([indent]) => indent.length * 2 + -(indent[0] === ' '), [], 2 ** 4 - 1)), separation),
|
|
30
|
-
(lines, context) =>
|
|
31
|
-
|
|
32
|
-
return parser(subinput(trimBlockEnd(lines.foldl((acc, node) => acc + node.value, '')), context));
|
|
33
|
-
}));
|
|
30
|
+
(lines, context) =>
|
|
31
|
+
parser(subinput(trimBlockEnd(lines.foldl((acc, node) => acc + node.value, '')), context))));
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
function trimBlockEnd(block: string): string {
|
|
@@ -29,8 +29,22 @@ export function surround<P extends Parser<unknown>, S = string>(
|
|
|
29
29
|
g?: (rss: [List<Data<S>>, List<Data<Node<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
30
30
|
backtracks?: readonly number[],
|
|
31
31
|
): P;
|
|
32
|
+
export function surround<P extends Parser<string>, S = string>(
|
|
33
|
+
opener: string | RegExp | Parser<S, Context<P>>, parser: string | RegExp | P, closer: string | RegExp | Parser<S, Context<P>>,
|
|
34
|
+
optional?: false,
|
|
35
|
+
f?: (rss: [List<Data<S>>, List<Data<Node<P>>>, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
36
|
+
g?: (rss: [List<Data<S>>, List<Data<Node<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
37
|
+
backtracks?: readonly number[],
|
|
38
|
+
): P;
|
|
39
|
+
export function surround<P extends Parser<string>, S = string>(
|
|
40
|
+
opener: string | RegExp | Parser<S, Context<P>>, parser: string | RegExp | P, closer: string | RegExp | Parser<S, Context<P>>,
|
|
41
|
+
optional?: boolean,
|
|
42
|
+
f?: (rss: [List<Data<S>>, List<Data<Node<P>>> | undefined, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
43
|
+
g?: (rss: [List<Data<S>>, List<Data<Node<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
44
|
+
backtracks?: readonly number[],
|
|
45
|
+
): P;
|
|
32
46
|
export function surround<N>(
|
|
33
|
-
opener: string | RegExp | Parser<N>, parser: Parser<N>, closer: string | RegExp | Parser<N>,
|
|
47
|
+
opener: string | RegExp | Parser<N>, parser: string | RegExp | Parser<N>, closer: string | RegExp | Parser<N>,
|
|
34
48
|
optional: boolean = false,
|
|
35
49
|
f?: (rss: [List<Data<N>>, List<Data<N>>, List<Data<N>>], context: Ctx) => Result<N>,
|
|
36
50
|
g?: (rss: [List<Data<N>>, List<Data<N>> | undefined], context: Ctx) => Result<N>,
|
|
@@ -41,11 +55,19 @@ export function surround<N>(
|
|
|
41
55
|
case 'object':
|
|
42
56
|
opener = clear(matcher(opener, true));
|
|
43
57
|
}
|
|
58
|
+
assert(opener);
|
|
59
|
+
switch (typeof parser) {
|
|
60
|
+
case 'string':
|
|
61
|
+
case 'object':
|
|
62
|
+
parser = clear(matcher(parser, true));
|
|
63
|
+
}
|
|
64
|
+
assert(parser);
|
|
44
65
|
switch (typeof closer) {
|
|
45
66
|
case 'string':
|
|
46
67
|
case 'object':
|
|
47
68
|
closer = clear(matcher(closer, true));
|
|
48
69
|
}
|
|
70
|
+
assert(closer);
|
|
49
71
|
return failsafe(input => {
|
|
50
72
|
const { context } = input;
|
|
51
73
|
const { source, position } = context;
|
|
@@ -66,8 +88,7 @@ export function surround<N>(
|
|
|
66
88
|
if (!nodesM && !optional) {
|
|
67
89
|
setBacktrack(context, backtracks, position);
|
|
68
90
|
const result = g?.([nodesO, nodesM], context);
|
|
69
|
-
revert(context, linebreak);
|
|
70
|
-
return result;
|
|
91
|
+
return result || void revert(context, linebreak);
|
|
71
92
|
}
|
|
72
93
|
const nodesC = nodesM || optional ? closer(input) : undefined;
|
|
73
94
|
assert(context.position >= position);
|
|
@@ -75,8 +96,7 @@ export function surround<N>(
|
|
|
75
96
|
if (!nodesC) {
|
|
76
97
|
setBacktrack(context, backtracks, position);
|
|
77
98
|
const result = g?.([nodesO, nodesM], context);
|
|
78
|
-
revert(context, linebreak);
|
|
79
|
-
return result;
|
|
99
|
+
return result || void revert(context, linebreak);
|
|
80
100
|
}
|
|
81
101
|
if (context.position === position) {
|
|
82
102
|
return void revert(context, linebreak);
|
|
@@ -88,10 +108,7 @@ export function surround<N>(
|
|
|
88
108
|
if (result) {
|
|
89
109
|
context.linebreak ||= linebreak;
|
|
90
110
|
}
|
|
91
|
-
|
|
92
|
-
revert(context, linebreak);
|
|
93
|
-
}
|
|
94
|
-
return result;
|
|
111
|
+
return result || void revert(context, linebreak);
|
|
95
112
|
});
|
|
96
113
|
}
|
|
97
114
|
export function open<P extends Parser<unknown>>(
|
|
@@ -100,13 +117,19 @@ export function open<P extends Parser<unknown>>(
|
|
|
100
117
|
optional?: boolean,
|
|
101
118
|
backtracks?: readonly number[],
|
|
102
119
|
): P;
|
|
120
|
+
export function open<P extends Parser<string>>(
|
|
121
|
+
opener: string | RegExp | Parser<Node<P>, Context<P>>,
|
|
122
|
+
parser: string | RegExp | P,
|
|
123
|
+
optional?: boolean,
|
|
124
|
+
backtracks?: readonly number[],
|
|
125
|
+
): P;
|
|
103
126
|
export function open<N>(
|
|
104
127
|
opener: string | RegExp | Parser<N, Ctx>,
|
|
105
|
-
parser: Parser<N>,
|
|
128
|
+
parser: string | RegExp | Parser<N>,
|
|
106
129
|
optional?: boolean,
|
|
107
130
|
backtracks?: readonly number[],
|
|
108
131
|
): Parser<N> {
|
|
109
|
-
return surround(opener, parser
|
|
132
|
+
return surround(opener, parser as Parser<N>, '', optional, undefined, undefined, backtracks);
|
|
110
133
|
}
|
|
111
134
|
export function close<P extends Parser<unknown>>(
|
|
112
135
|
parser: P,
|
|
@@ -114,13 +137,19 @@ export function close<P extends Parser<unknown>>(
|
|
|
114
137
|
optional?: boolean,
|
|
115
138
|
backtracks?: readonly number[],
|
|
116
139
|
): P;
|
|
140
|
+
export function close<P extends Parser<string>>(
|
|
141
|
+
parser: string | RegExp | P,
|
|
142
|
+
closer: string | RegExp | Parser<Node<P>, Context<P>>,
|
|
143
|
+
optional?: boolean,
|
|
144
|
+
backtracks?: readonly number[],
|
|
145
|
+
): P;
|
|
117
146
|
export function close<N>(
|
|
118
|
-
parser: Parser<N>,
|
|
147
|
+
parser: string | RegExp | Parser<N>,
|
|
119
148
|
closer: string | RegExp | Parser<N, Ctx>,
|
|
120
149
|
optional?: boolean,
|
|
121
150
|
backtracks?: readonly number[],
|
|
122
151
|
): Parser<N> {
|
|
123
|
-
return surround('', parser
|
|
152
|
+
return surround('', parser as Parser<N>, closer, optional, undefined, undefined, backtracks);
|
|
124
153
|
}
|
|
125
154
|
|
|
126
155
|
const statesize = 2;
|
|
@@ -153,7 +182,7 @@ export function setBacktrack(
|
|
|
153
182
|
position: number,
|
|
154
183
|
length: number = 1,
|
|
155
184
|
): void {
|
|
156
|
-
//
|
|
185
|
+
// バックトラックの可能性がなく記録不要の場合もあるが判別が面倒なので省略
|
|
157
186
|
const { source } = context;
|
|
158
187
|
if (position === source.length) return;
|
|
159
188
|
if (length === 0) return;
|
|
@@ -9,17 +9,16 @@ export function normalize(source: string): string {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
function format(source: string): string {
|
|
12
|
-
return source
|
|
13
|
-
.replace(/\r\n?/g, '\n');
|
|
12
|
+
return source.replace(/\r\n?/g, '\n');
|
|
14
13
|
}
|
|
15
14
|
|
|
15
|
+
const invalid = new RegExp([
|
|
16
|
+
/(?![\t\r\n])[\x00-\x1F\x7F]/g.source,
|
|
17
|
+
/(?!\u200D)[\u2006\u200B-\u200F\u202A-\u202F\u2060\uFEFF]|(?<![\u1820\u1821])\u180E/g.source,
|
|
18
|
+
/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g.source,
|
|
19
|
+
].join('|'), 'g');
|
|
16
20
|
function sanitize(source: string): string {
|
|
17
|
-
return source
|
|
18
|
-
.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]|(?!\u200D)[\u2006\u200B-\u200F\u202A-\u202F\u2060\uFEFF]|(?<![\u1820\u1821])\u180E/g, UNICODE_REPLACEMENT_CHARACTER)
|
|
19
|
-
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]?|[\uDC00-\uDFFF]/g, char =>
|
|
20
|
-
char.length === 1
|
|
21
|
-
? UNICODE_REPLACEMENT_CHARACTER
|
|
22
|
-
: char);
|
|
21
|
+
return source.replace(invalid, UNICODE_REPLACEMENT_CHARACTER);
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
// https://dev.w3.org/html5/html-author/charref
|
|
@@ -110,7 +109,6 @@ assert(unreadableSpecialCharacters.every(c => sanitize(c) === UNICODE_REPLACEMEN
|
|
|
110
109
|
|
|
111
110
|
// 特殊不可視文字はエディタおよびソースビューアでは等幅および強調表示により可視化する
|
|
112
111
|
export function escape(source: string): string {
|
|
113
|
-
return source
|
|
114
|
-
.
|
|
115
|
-
`&${unreadableEscapeHTMLEntityNames[unreadableEscapeCharacters.indexOf(char)]};`);
|
|
112
|
+
return source.replace(unreadableEscapeCharacter, char =>
|
|
113
|
+
`&${unreadableEscapeHTMLEntityNames[unreadableEscapeCharacters.indexOf(char)]};`);
|
|
116
114
|
}
|
|
@@ -361,9 +361,9 @@ describe('Unit: parser/api/parse', () => {
|
|
|
361
361
|
|
|
362
362
|
it('backtrack', function () {
|
|
363
363
|
this.timeout(5000);
|
|
364
|
-
// 最悪計算量での実行速度はCommonMarkの公式JS実装の32n
|
|
364
|
+
// 最悪計算量での実行速度はCommonMarkの公式JS実装の32nに対して3倍遅い程度。
|
|
365
365
|
// 5n = annotation/reference + link + url/math + ruby + text
|
|
366
|
-
const source = `((([[[[#$[${'.'.repeat(
|
|
366
|
+
const source = `((([[[[#$[${'.'.repeat(19998)}`;
|
|
367
367
|
assert.deepStrictEqual(
|
|
368
368
|
[...parse(source, {}, { resources: { clock: 100000, recursions: [100] } }).children]
|
|
369
369
|
.map(el => el.tagName),
|
|
@@ -372,7 +372,7 @@ describe('Unit: parser/api/parse', () => {
|
|
|
372
372
|
|
|
373
373
|
it('backtrack error', function () {
|
|
374
374
|
this.timeout(5000);
|
|
375
|
-
const source = `((([[[[#$[${'.'.repeat(
|
|
375
|
+
const source = `((([[[[#$[${'.'.repeat(19998 + 1)}`;
|
|
376
376
|
assert.deepStrictEqual(
|
|
377
377
|
[...parse(source, {}, { resources: { clock: 100000, recursions: [100] } }).children]
|
|
378
378
|
.map(el => el.tagName),
|
|
@@ -3,7 +3,6 @@ import { State, Backtrack } from '../../context';
|
|
|
3
3
|
import { List, Data } from '../../../combinator/data/parser';
|
|
4
4
|
import { union, state, constraint, rewrite, surround, convert, fmap, lazy } from '../../../combinator';
|
|
5
5
|
import { unsafelink } from '../link';
|
|
6
|
-
import { str } from '../../source';
|
|
7
6
|
import { define } from 'typed-dom/dom';
|
|
8
7
|
|
|
9
8
|
// https://example/@user must be a user page or a redirect page going there.
|
|
@@ -11,8 +10,8 @@ import { define } from 'typed-dom/dom';
|
|
|
11
10
|
export const account: AutolinkParser.AccountParser = lazy(() => rewrite(
|
|
12
11
|
surround(
|
|
13
12
|
/(?<![0-9a-z])@/yi,
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
/[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*\//yi,
|
|
14
|
+
/[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*(?![-.]?[0-9a-z@#]|>>|:\S)/yi,
|
|
16
15
|
true, undefined, undefined,
|
|
17
16
|
[3 | Backtrack.autolink]),
|
|
18
17
|
constraint(State.autolink, state(State.autolink, fmap(convert(
|
|
@@ -3,7 +3,6 @@ import { State, Backtrack } from '../../context';
|
|
|
3
3
|
import { List, Data } from '../../../combinator/data/parser';
|
|
4
4
|
import { union, state, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
|
|
5
5
|
import { unsafelink } from '../link';
|
|
6
|
-
import { str } from '../../source';
|
|
7
6
|
import { define } from 'typed-dom/dom';
|
|
8
7
|
|
|
9
8
|
// Timeline(pseudonym): user/tid
|
|
@@ -19,7 +18,7 @@ import { define } from 'typed-dom/dom';
|
|
|
19
18
|
export const anchor: AutolinkParser.AnchorParser = lazy(() => rewrite(
|
|
20
19
|
open(
|
|
21
20
|
/(?<![0-9a-z])>>/yi,
|
|
22
|
-
|
|
21
|
+
/(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*\/)?[0-9a-z]+(?:-[0-9a-z]+)*(?!-?[0-9a-z@#]|>>|:\S)/yi,
|
|
23
22
|
false,
|
|
24
23
|
[3 | Backtrack.autolink]),
|
|
25
24
|
constraint(State.autolink, state(State.autolink, fmap(convert(
|
|
@@ -13,18 +13,18 @@ export const channel: AutolinkParser.ChannelParser = lazy(() => rewrite(
|
|
|
13
13
|
sequence([
|
|
14
14
|
surround(
|
|
15
15
|
/(?<![0-9a-z])@/yi,
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*\//yi,
|
|
17
|
+
/[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*(?![-.]?[0-9a-z@]|>>|:\S)/yi,
|
|
18
18
|
true, undefined, undefined,
|
|
19
19
|
[3 | Backtrack.autolink]),
|
|
20
20
|
some(verify(surround(
|
|
21
21
|
'#',
|
|
22
22
|
str(new RegExp([
|
|
23
23
|
/(?!['_])(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^\p{C}\p{S}\p{P}\s]|emoji))+/yu.source,
|
|
24
|
-
].join('').replace(/emoji/g, emoji.source), 'yu')),
|
|
25
|
-
|
|
24
|
+
].join('|').replace(/emoji/g, emoji.source), 'yu')),
|
|
25
|
+
new RegExp([
|
|
26
26
|
/(?![0-9a-z@]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
|
|
27
|
-
].join('').replace(/emoji/g, emoji.source), 'yu')
|
|
27
|
+
].join('|').replace(/emoji/g, emoji.source), 'yu'),
|
|
28
28
|
false, undefined, undefined,
|
|
29
29
|
[3 | Backtrack.autolink]),
|
|
30
30
|
([{ value }]) => !/^[0-9]{1,4}$|^[0-9]{5}/.test(value as string))),
|
|
@@ -4,17 +4,16 @@ import { List, Data } from '../../../combinator/data/parser';
|
|
|
4
4
|
import { union, state, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
|
|
5
5
|
import { unsafelink } from '../link';
|
|
6
6
|
import { emoji } from './hashtag';
|
|
7
|
-
import { str } from '../../source';
|
|
8
7
|
import { define } from 'typed-dom/dom';
|
|
9
8
|
|
|
10
9
|
export const hashnum: AutolinkParser.HashnumParser = lazy(() => rewrite(
|
|
11
10
|
open(
|
|
12
11
|
new RegExp([
|
|
13
|
-
/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/
|
|
14
|
-
].join('').replace(/emoji/g, emoji.source), 'yu'),
|
|
15
|
-
|
|
12
|
+
/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yu.source,
|
|
13
|
+
].join('|').replace(/emoji/g, emoji.source), 'yu'),
|
|
14
|
+
new RegExp([
|
|
16
15
|
/[0-9]{1,9}(?![0-9a-z@#]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
|
|
17
|
-
].join('').replace(/emoji/g, emoji.source), 'yu')
|
|
16
|
+
].join('|').replace(/emoji/g, emoji.source), 'yu'),
|
|
18
17
|
false,
|
|
19
18
|
[1 | Backtrack.autolink]),
|
|
20
19
|
constraint(State.autolink, state(State.autolink, fmap(convert(
|
|
@@ -14,14 +14,14 @@ export const emoji = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presen
|
|
|
14
14
|
export const hashtag: AutolinkParser.HashtagParser = lazy(() => rewrite(
|
|
15
15
|
verify(surround(
|
|
16
16
|
new RegExp([
|
|
17
|
-
/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/
|
|
18
|
-
].join('').replace(/emoji/g, emoji.source), 'yu'),
|
|
17
|
+
/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yu.source,
|
|
18
|
+
].join('|').replace(/emoji/g, emoji.source), 'yu'),
|
|
19
19
|
str(new RegExp([
|
|
20
20
|
/(?!['_])(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^\p{C}\p{S}\p{P}\s]|emoji))+/yu.source,
|
|
21
|
-
].join('').replace(/emoji/g, emoji.source), 'yu')),
|
|
22
|
-
|
|
21
|
+
].join('|').replace(/emoji/g, emoji.source), 'yu')),
|
|
22
|
+
new RegExp([
|
|
23
23
|
/(?![0-9a-z@#]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
|
|
24
|
-
].join('').replace(/emoji/g, emoji.source), 'yu')
|
|
24
|
+
].join('|').replace(/emoji/g, emoji.source), 'yu'),
|
|
25
25
|
false, undefined, undefined,
|
|
26
26
|
[3 | Backtrack.autolink]),
|
|
27
27
|
([{ value }]) => !/^[0-9]{1,4}$|^[0-9]{5}/.test(value)),
|
|
@@ -1,35 +1,47 @@
|
|
|
1
1
|
import { AutolinkParser } from '../inline';
|
|
2
2
|
import { State } from '../context';
|
|
3
|
-
import {
|
|
3
|
+
import { state, lazy } from '../../combinator';
|
|
4
4
|
import { url, lineurl } from './autolink/url';
|
|
5
5
|
import { email } from './autolink/email';
|
|
6
6
|
import { channel } from './autolink/channel';
|
|
7
7
|
import { account } from './autolink/account';
|
|
8
|
-
import { hashtag
|
|
8
|
+
import { hashtag } from './autolink/hashtag';
|
|
9
9
|
import { hashnum } from './autolink/hashnum';
|
|
10
10
|
import { anchor } from './autolink/anchor';
|
|
11
|
+
import { isAlphanumeric } from '../source/text';
|
|
11
12
|
|
|
12
13
|
export const autolink: AutolinkParser = lazy(() =>
|
|
13
|
-
validate(new RegExp([
|
|
14
|
-
/(?<![0-9a-z])@/yi.source,
|
|
15
|
-
/(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yiu.source,
|
|
16
|
-
/(?<![0-9a-z])>>/yi.source,
|
|
17
|
-
/(?<![0-9a-z][.+-]?|[@#])!?[0-9a-z]/yi.source,
|
|
18
|
-
].join('|').replace(/emoji/g, emoji.source), 'yiu'),
|
|
19
14
|
state(~State.autolink,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
15
|
+
input => {
|
|
16
|
+
const { context: { source, position } } = input;
|
|
17
|
+
if (position === source.length) return;
|
|
18
|
+
const fst = source[position];
|
|
19
|
+
switch (fst) {
|
|
20
|
+
case '@':
|
|
21
|
+
return channel(input) || account(input);
|
|
22
|
+
case '#':
|
|
23
|
+
return hashtag(input) || hashnum(input);
|
|
24
|
+
case '>':
|
|
25
|
+
return anchor(input);
|
|
26
|
+
case '!':
|
|
27
|
+
if (!source.startsWith('http', position + 1)) break;
|
|
28
|
+
if (position === 0) return lineurl(input);
|
|
29
|
+
switch (source[position - 1]) {
|
|
30
|
+
case '\r':
|
|
31
|
+
case '\n':
|
|
32
|
+
return lineurl(input);
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
case 'h':
|
|
36
|
+
if (!source.startsWith('http', position)) return;
|
|
37
|
+
if (position === 0) return lineurl(input) || url(input) || email(input);
|
|
38
|
+
switch (source[position - 1]) {
|
|
39
|
+
case '\r':
|
|
40
|
+
case '\n':
|
|
41
|
+
return lineurl(input) || url(input) || email(input);
|
|
42
|
+
}
|
|
43
|
+
return url(input) || email(input);
|
|
44
|
+
default:
|
|
45
|
+
if (isAlphanumeric(fst)) return email(input);
|
|
46
|
+
}
|
|
47
|
+
}));
|
|
@@ -23,7 +23,7 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
|
|
|
23
23
|
union([
|
|
24
24
|
surround(
|
|
25
25
|
// https://html.spec.whatwg.org/multipage/syntax.html#void-elements
|
|
26
|
-
str(/<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[ >])/
|
|
26
|
+
str(/<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[ >])/y),
|
|
27
27
|
some(union([attribute])),
|
|
28
28
|
open(str(/ ?/y), str('>'), true),
|
|
29
29
|
true,
|
package/src/parser/inline.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { reference } from './inline/reference';
|
|
|
5
5
|
import { template } from './inline/template';
|
|
6
6
|
import { remark } from './inline/remark';
|
|
7
7
|
import { extension } from './inline/extension';
|
|
8
|
+
import { label } from './inline/extension/label';
|
|
8
9
|
import { textlink } from './inline/link';
|
|
9
10
|
import { ruby } from './inline/ruby';
|
|
10
11
|
import { html } from './inline/html';
|
|
@@ -94,7 +95,7 @@ export const inline: InlineParser = lazy(() => union([
|
|
|
94
95
|
return html(input);
|
|
95
96
|
case '$':
|
|
96
97
|
if (source[position + 1] === '{') return math(input);
|
|
97
|
-
return
|
|
98
|
+
return label(input)
|
|
98
99
|
|| math(input);
|
|
99
100
|
case '+':
|
|
100
101
|
if (source[position + 1] === '+') return insertion(input);
|
|
@@ -185,12 +185,12 @@ export function backToEmailHead(source: string, position: number, index: number)
|
|
|
185
185
|
? delim
|
|
186
186
|
: index;
|
|
187
187
|
}
|
|
188
|
-
function isAlphanumeric(char: string): boolean {
|
|
188
|
+
export function isAlphanumeric(char: string): boolean {
|
|
189
189
|
assert(char.length === 1);
|
|
190
190
|
if (char < '0' || '\x7F' < char) return false;
|
|
191
191
|
return '0' <= char && char <= '9'
|
|
192
|
-
|| '
|
|
193
|
-
|| '
|
|
192
|
+
|| 'A' <= char && char <= 'Z'
|
|
193
|
+
|| 'a' <= char && char <= 'z';
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
//const dict = new class {
|