securemark 0.277.0 → 0.278.0

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.278.0
4
+
5
+ - Extend account syntax.
6
+
3
7
  ## 0.277.0
4
8
 
5
9
  - Revert emphasis syntax and strong syntax.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.277.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.278.0 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"));
@@ -5856,7 +5856,7 @@ exports.autolink = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(/^(?:
5856
5856
  // Escape unmatched email-like strings.
5857
5857
  (0, source_1.str)(/^[0-9a-z]+(?:[_.+-][0-9a-z]+)*(?:@(?:[0-9a-z]+(?:[.-][0-9a-z]+)*)?)*/i), channel_1.channel, account_1.account,
5858
5858
  // Escape unmatched account-like strings.
5859
- (0, source_1.str)(/^@+[0-9a-z]*(?:-[0-9a-z]+)*/i),
5859
+ (0, source_1.str)(/^@+[0-9a-z]*(?:[-.][0-9a-z]+)*/i),
5860
5860
  // Escape invalid leading characters.
5861
5861
  (0, source_1.str)(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji|['_])(?=#)/u.source.replace('emoji', hashtag_1.emoji), 'u')), hashtag_1.hashtag, hashnum_1.hashnum,
5862
5862
  // Escape unmatched hashtag-like strings.
@@ -5881,7 +5881,7 @@ const link_1 = __webpack_require__(9628);
5881
5881
  const source_1 = __webpack_require__(6743);
5882
5882
  const dom_1 = __webpack_require__(3252);
5883
5883
  // https://example/@user must be a user page or a redirect page going there.
5884
- exports.account = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.rewrite)((0, combinator_1.constraint)(1 /* State.shortcut */, false, (0, combinator_1.open)('@', (0, combinator_1.tails)([(0, source_1.str)(/^[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?)*\//i), (0, source_1.str)(/^[a-z][0-9a-z]*(?:-[0-9a-z]+)*/i)]))), (0, combinator_1.convert)(source => `[${source}]{ ${source.includes('/') ? `https://${source.slice(1).replace('/', '/@')}` : `/${source}`} }`, (0, combinator_1.union)([link_1.unsafelink]))), ([el]) => [(0, dom_1.define)(el, {
5884
+ exports.account = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.rewrite)((0, combinator_1.constraint)(1 /* State.shortcut */, false, (0, combinator_1.open)('@', (0, combinator_1.tails)([(0, source_1.str)(/^[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])?)*\//i), (0, source_1.str)(/^[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*/i)]))), (0, combinator_1.convert)(source => `[${source}]{ ${source.includes('/') ? `https://${source.slice(1).replace('/', '/@')}` : `/${source}`} }`, (0, combinator_1.union)([link_1.unsafelink]))), ([el]) => [(0, dom_1.define)(el, {
5885
5885
  class: 'account'
5886
5886
  })]));
5887
5887
 
@@ -5955,7 +5955,7 @@ const combinator_1 = __webpack_require__(2087);
5955
5955
  const source_1 = __webpack_require__(6743);
5956
5956
  const dom_1 = __webpack_require__(3252);
5957
5957
  // https://html.spec.whatwg.org/multipage/input.html
5958
- exports.email = (0, combinator_1.creation)((0, combinator_1.rewrite)((0, combinator_1.verify)((0, source_1.str)(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?)*(?![0-9a-z])/i), ([source]) => source.length <= 255), ({
5958
+ exports.email = (0, combinator_1.creation)((0, combinator_1.rewrite)((0, combinator_1.verify)((0, source_1.str)(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[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])?)*(?![0-9a-z])/i), ([source]) => source.length <= 255), ({
5959
5959
  source
5960
5960
  }) => [[(0, dom_1.html)('a', {
5961
5961
  class: 'email',
@@ -6631,10 +6631,10 @@ function resolve(uri, host, source) {
6631
6631
  exports.resolve = resolve;
6632
6632
  function decode(uri) {
6633
6633
  if (!uri.includes('%')) return uri;
6634
- const origin = uri.match(/^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
6634
+ const origin = uri.match(/^[a-z](?:[-.](?=[0-9a-z])|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
6635
6635
  try {
6636
6636
  let path = decodeURI(uri.slice(origin.length));
6637
- if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
6637
+ if (!origin && /^[a-z](?:[-.](?=[0-9a-z])|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
6638
6638
  path = uri.slice(origin.length);
6639
6639
  }
6640
6640
  uri = origin + path;
@@ -7036,13 +7036,14 @@ function* figure(target, notes, opts = {}) {
7036
7036
  const refs = new queue_1.MultiQueue((0, array_1.push)((0, query_1.querySelectorAll)(target, 'a.label:not(.disabled)[data-label]'), notes && (0, query_1.querySelectorAll)(notes.references, 'a.label:not(.disabled)') || []).map(el => [el.getAttribute('data-label'), el]));
7037
7037
  const labels = new Set();
7038
7038
  const numbers = new Map();
7039
+ const scope = target instanceof Element ? ':scope > ' : '';
7039
7040
  let base = '0';
7040
7041
  let bases = base.split('.');
7041
7042
  let index = bases;
7042
- for (let defs = target.querySelectorAll('figure[data-label], h1, h2'), len = defs.length, i = 0; i < len; ++i) {
7043
+ for (let defs = target.querySelectorAll(`${scope}:is(figure[data-label], h1, h2)`), len = defs.length, i = 0; i < len; ++i) {
7043
7044
  yield;
7044
7045
  const def = defs[i];
7045
- if (def.parentNode !== target) continue;
7046
+ if (!scope && def.parentNode !== target) continue;
7046
7047
  const {
7047
7048
  tagName
7048
7049
  } = def;
@@ -7199,7 +7200,8 @@ function build(syntax, marker, splitter = '') {
7199
7200
  const defIndexes = new Map();
7200
7201
  const refSubindexes = new Map();
7201
7202
  const defSubindexes = new Map();
7202
- const splitters = splitter ? target.querySelectorAll(splitter) : [];
7203
+ const scope = target instanceof Element ? ':scope > ' : '';
7204
+ const splitters = splitter ? target.querySelectorAll(`${scope}:is(${splitter})`) : [];
7203
7205
  let iSplitters = 0;
7204
7206
  let total = 0;
7205
7207
  let format;
@@ -7212,7 +7214,7 @@ function build(syntax, marker, splitter = '') {
7212
7214
  }
7213
7215
  if (splitter) for (let el; el = splitters[iSplitters], el?.compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING; ++iSplitters) {
7214
7216
  if (~iSplitters << 32 - 8 === 0) yield;
7215
- if (el.parentNode !== target) continue;
7217
+ if (!scope && el.parentNode !== target) continue;
7216
7218
  if (el.tagName === 'OL' && el.nextElementSibling !== splitters[iSplitters + 1]) {
7217
7219
  el.remove();
7218
7220
  continue;
@@ -7284,7 +7286,7 @@ function build(syntax, marker, splitter = '') {
7284
7286
  }
7285
7287
  if (splitter) for (let el; el = splitters[iSplitters]; ++iSplitters) {
7286
7288
  if (~iSplitters << 32 - 8 === 0) yield;
7287
- if (el.parentNode !== target) continue;
7289
+ if (!scope && el.parentNode !== target) continue;
7288
7290
  if (el.tagName === 'OL') {
7289
7291
  el.remove();
7290
7292
  }
@@ -8155,7 +8157,7 @@ const origins = ['https://twitter.com'];
8155
8157
  function twitter(source, url) {
8156
8158
  if (!origins.includes(url.origin)) return;
8157
8159
  if (url.pathname.split('/').pop().includes('.')) return;
8158
- if (!url.pathname.match(/^\/\w+\/status\/[0-9]{15,}(?!\w)/)) return;
8160
+ if (!url.pathname.match(/^\/\w+\/status\/[0-9]{15,}\/?$/)) return;
8159
8161
  const el = (0, dom_1.html)('div', {
8160
8162
  class: source.className,
8161
8163
  'data-type': 'twitter'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.277.0",
3
+ "version": "0.278.0",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
@@ -33,10 +33,12 @@ describe('Unit: parser/inline/autolink/account', () => {
33
33
  assert.deepStrictEqual(inspect(parser('@a-')), [['<a class="account" href="/@a">@a</a>'], '-']);
34
34
  assert.deepStrictEqual(inspect(parser('@a-b')), [['<a class="account" href="/@a-b">@a-b</a>'], '']);
35
35
  assert.deepStrictEqual(inspect(parser('@a--b')), [['<a class="account" href="/@a">@a</a>'], '--b']);
36
+ assert.deepStrictEqual(inspect(parser('@a.')), [['<a class="account" href="/@a">@a</a>'], '.']);
37
+ assert.deepStrictEqual(inspect(parser('@a.domain.com')), [['<a class="account" href="/@a.domain.com">@a.domain.com</a>'], '']);
36
38
  assert.deepStrictEqual(inspect(parser('@http://host')), [['<a class="account" href="/@http">@http</a>'], '://host']);
37
39
  assert.deepStrictEqual(inspect(parser('@ttp://host')), [['<a class="account" href="/@ttp">@ttp</a>'], '://host']);
38
40
  assert.deepStrictEqual(inspect(parser('@domain/a')), [['<a class="account" href="https://domain/@a" target="_blank">@domain/a</a>'], '']);
39
- assert.deepStrictEqual(inspect(parser('@domain.co.jp/a')), [['<a class="account" href="https://domain.co.jp/@a" target="_blank">@domain.co.jp/a</a>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('@domain.com/a')), [['<a class="account" href="https://domain.com/@a" target="_blank">@domain.com/a</a>'], '']);
40
42
  });
41
43
 
42
44
  });
@@ -12,8 +12,8 @@ export const account: AutolinkParser.AccountParser = lazy(() => fmap(rewrite(
12
12
  open(
13
13
  '@',
14
14
  tails([
15
- str(/^[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?)*\//i),
16
- str(/^[a-z][0-9a-z]*(?:-[0-9a-z]+)*/i),
15
+ str(/^[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])?)*\//i),
16
+ str(/^[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*/i),
17
17
  ]))),
18
18
  convert(
19
19
  source =>
@@ -6,6 +6,6 @@ import { html } from 'typed-dom/dom';
6
6
  // https://html.spec.whatwg.org/multipage/input.html
7
7
 
8
8
  export const email: AutolinkParser.EmailParser = creation(rewrite(verify(
9
- str(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?)*(?![0-9a-z])/i),
9
+ str(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[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])?)*(?![0-9a-z])/i),
10
10
  ([source]) => source.length <= 255),
11
11
  ({ source }) => [[html('a', { class: 'email', href: `mailto:${source}` }, source)], '']));
@@ -25,7 +25,7 @@ export const autolink: AutolinkParser = lazy(() =>
25
25
  channel,
26
26
  account,
27
27
  // Escape unmatched account-like strings.
28
- str(/^@+[0-9a-z]*(?:-[0-9a-z]+)*/i),
28
+ str(/^@+[0-9a-z]*(?:[-.][0-9a-z]+)*/i),
29
29
  // Escape invalid leading characters.
30
30
  str(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji|['_])(?=#)/u.source.replace('emoji', emoji), 'u')),
31
31
  hashtag,
@@ -34,7 +34,7 @@ assert(identity(undefined, '0'.repeat(41) + '1'.repeat(38) + '2'.repeat(41) + 3,
34
34
  assert(identity(undefined, '0'.repeat(81) + '1'.repeat(38) + '2'.repeat(81) + 3, 'mark')!.slice(6) === '0'.repeat(38) + '...' + '1'.repeat(38) + '...' + '2'.repeat(38 - 1) + 3);
35
35
 
36
36
  export function index(source: Element, optional = false): string {
37
- assert(source instanceof DocumentFragment || !source.matches('.indexer'));
37
+ assert(!source.matches('.indexer'));
38
38
  assert(source.querySelectorAll(':scope > .indexer').length <= 1);
39
39
  if (!source.firstChild) return '';
40
40
  const indexer = source.querySelector(':scope > .indexer');
@@ -203,10 +203,10 @@ export function resolve(uri: string, host: URL | Location, source: URL | Locatio
203
203
 
204
204
  function decode(uri: string): string {
205
205
  if (!uri.includes('%')) return uri;
206
- const origin = uri.match(/^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
206
+ const origin = uri.match(/^[a-z](?:[-.](?=[0-9a-z])|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
207
207
  try {
208
208
  let path = decodeURI(uri.slice(origin.length));
209
- if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
209
+ if (!origin && /^[a-z](?:[-.](?=[0-9a-z])|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
210
210
  path = uri.slice(origin.length);
211
211
  }
212
212
  uri = origin + path;
@@ -16,15 +16,16 @@ export function* figure(
16
16
  .map(el => [el.getAttribute('data-label')!, el]));
17
17
  const labels = new Set<string>();
18
18
  const numbers = new Map<string, string>();
19
+ const scope = target instanceof Element ? ':scope > ' : '';
19
20
  let base = '0';
20
21
  let bases: readonly string[] = base.split('.');
21
22
  let index: readonly string[] = bases;
22
23
  for (
23
- let defs = target.querySelectorAll('figure[data-label], h1, h2'),
24
+ let defs = target.querySelectorAll(`${scope}:is(figure[data-label], h1, h2)`),
24
25
  len = defs.length, i = 0; i < len; ++i) {
25
26
  yield;
26
27
  const def = defs[i];
27
- if (def.parentNode !== target) continue;
28
+ if (!scope && def.parentNode !== target) continue;
28
29
  const { tagName } = def;
29
30
  if (bases.length === 1 && tagName[0] === 'H') continue;
30
31
  assert(base === '0' || bases.length > 1);
@@ -67,7 +67,8 @@ function build(
67
67
  const defIndexes = new Map<HTMLLIElement, number>();
68
68
  const refSubindexes = new Map<string, number>();
69
69
  const defSubindexes = new Map<string, number>();
70
- const splitters = splitter ? target.querySelectorAll(splitter) : [];
70
+ const scope = target instanceof Element ? ':scope > ' : '';
71
+ const splitters = splitter ? target.querySelectorAll(`${scope}:is(${splitter})`) : [];
71
72
  let iSplitters = 0;
72
73
  let total = 0;
73
74
  let format: 'number' | 'abbr';
@@ -84,7 +85,7 @@ function build(
84
85
  el?.compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING;
85
86
  ++iSplitters) {
86
87
  if (~iSplitters << 32 - 8 === 0) yield;
87
- if (el.parentNode !== target) continue;
88
+ if (!scope && el.parentNode !== target) continue;
88
89
  if (el.tagName === 'OL' && el.nextElementSibling !== splitters[iSplitters + 1]) {
89
90
  assert(el.matches(`.${syntax}s`));
90
91
  el.remove();
@@ -173,7 +174,7 @@ function build(
173
174
  el = splitters[iSplitters];
174
175
  ++iSplitters) {
175
176
  if (~iSplitters << 32 - 8 === 0) yield;
176
- if (el.parentNode !== target) continue;
177
+ if (!scope && el.parentNode !== target) continue;
177
178
  if (el.tagName === 'OL') {
178
179
  assert(el.matches(`.${syntax}s`));
179
180
  el.remove();
@@ -19,7 +19,7 @@ const origins = [
19
19
  export function twitter(source: HTMLImageElement, url: URL): HTMLElement | undefined {
20
20
  if (!origins.includes(url.origin)) return;
21
21
  if (url.pathname.split('/').pop()!.includes('.')) return;
22
- if (!url.pathname.match(/^\/\w+\/status\/[0-9]{15,}(?!\w)/)) return;
22
+ if (!url.pathname.match(/^\/\w+\/status\/[0-9]{15,}\/?$/)) return;
23
23
  const el = h('div', { class: source.className, 'data-type': 'twitter' }, [
24
24
  h('em', `Loading ${source.getAttribute('data-src')}...`),
25
25
  ]);