@shikijs/engine-javascript 1.17.4 → 1.17.5

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/dist/index.d.mts CHANGED
@@ -3,12 +3,20 @@ import { PatternScanner, RegexEngineString, RegexEngine } from '@shikijs/types';
3
3
  interface JavaScriptRegexEngineOptions {
4
4
  /**
5
5
  * Whether to allow invalid regex patterns.
6
+ *
7
+ * @default false
6
8
  */
7
9
  forgiving?: boolean;
10
+ /**
11
+ * Use JavaScript to simulate some unsupported regex features.
12
+ *
13
+ * @default true
14
+ */
15
+ simulation?: boolean;
8
16
  /**
9
17
  * Cache for regex patterns.
10
18
  */
11
- cache?: Map<string, RegExp | Error>;
19
+ cache?: Map<string, RegExp | Error> | null;
12
20
  /**
13
21
  * Custom pattern to RegExp constructor.
14
22
  *
@@ -22,11 +30,10 @@ interface JavaScriptRegexEngineOptions {
22
30
  declare function defaultJavaScriptRegexConstructor(pattern: string): RegExp;
23
31
  declare class JavaScriptScanner implements PatternScanner {
24
32
  patterns: string[];
25
- cache: Map<string, RegExp | Error>;
26
- forgiving: boolean;
27
- regexConstructor: (pattern: string) => RegExp;
33
+ options: JavaScriptRegexEngineOptions;
28
34
  regexps: (RegExp | null)[];
29
- constructor(patterns: string[], cache: Map<string, RegExp | Error>, forgiving: boolean, regexConstructor?: (pattern: string) => RegExp);
35
+ contiguousAnchorSimulation: boolean[];
36
+ constructor(patterns: string[], options?: JavaScriptRegexEngineOptions);
30
37
  findNextMatchSync(string: string | RegexEngineString, startPosition: number): {
31
38
  index: number;
32
39
  captureIndices: {
package/dist/index.d.ts CHANGED
@@ -3,12 +3,20 @@ import { PatternScanner, RegexEngineString, RegexEngine } from '@shikijs/types';
3
3
  interface JavaScriptRegexEngineOptions {
4
4
  /**
5
5
  * Whether to allow invalid regex patterns.
6
+ *
7
+ * @default false
6
8
  */
7
9
  forgiving?: boolean;
10
+ /**
11
+ * Use JavaScript to simulate some unsupported regex features.
12
+ *
13
+ * @default true
14
+ */
15
+ simulation?: boolean;
8
16
  /**
9
17
  * Cache for regex patterns.
10
18
  */
11
- cache?: Map<string, RegExp | Error>;
19
+ cache?: Map<string, RegExp | Error> | null;
12
20
  /**
13
21
  * Custom pattern to RegExp constructor.
14
22
  *
@@ -22,11 +30,10 @@ interface JavaScriptRegexEngineOptions {
22
30
  declare function defaultJavaScriptRegexConstructor(pattern: string): RegExp;
23
31
  declare class JavaScriptScanner implements PatternScanner {
24
32
  patterns: string[];
25
- cache: Map<string, RegExp | Error>;
26
- forgiving: boolean;
27
- regexConstructor: (pattern: string) => RegExp;
33
+ options: JavaScriptRegexEngineOptions;
28
34
  regexps: (RegExp | null)[];
29
- constructor(patterns: string[], cache: Map<string, RegExp | Error>, forgiving: boolean, regexConstructor?: (pattern: string) => RegExp);
35
+ contiguousAnchorSimulation: boolean[];
36
+ constructor(patterns: string[], options?: JavaScriptRegexEngineOptions);
30
37
  findNextMatchSync(string: string | RegexEngineString, startPosition: number): {
31
38
  index: number;
32
39
  captureIndices: {
package/dist/index.mjs CHANGED
@@ -17,13 +17,21 @@ function defaultJavaScriptRegexConstructor(pattern) {
17
17
  );
18
18
  }
19
19
  class JavaScriptScanner {
20
- constructor(patterns, cache, forgiving, regexConstructor = defaultJavaScriptRegexConstructor) {
20
+ constructor(patterns, options = {}) {
21
21
  this.patterns = patterns;
22
- this.cache = cache;
23
- this.forgiving = forgiving;
24
- this.regexConstructor = regexConstructor;
22
+ this.options = options;
25
23
  __publicField(this, "regexps");
26
- this.regexps = patterns.map((p) => {
24
+ __publicField(this, "contiguousAnchorSimulation");
25
+ const {
26
+ forgiving = false,
27
+ cache,
28
+ simulation = true,
29
+ regexConstructor = defaultJavaScriptRegexConstructor
30
+ } = options;
31
+ this.contiguousAnchorSimulation = Array.from({ length: patterns.length }, () => false);
32
+ this.regexps = patterns.map((p, idx) => {
33
+ if (simulation && (p.startsWith("(^|\\G)") || p.startsWith("(\\G|^)")))
34
+ this.contiguousAnchorSimulation[idx] = true;
27
35
  const cached = cache?.get(p);
28
36
  if (cached) {
29
37
  if (cached instanceof RegExp) {
@@ -48,7 +56,7 @@ class JavaScriptScanner {
48
56
  findNextMatchSync(string, startPosition) {
49
57
  const str = typeof string === "string" ? string : string.content;
50
58
  const pending = [];
51
- function toResult(index, match) {
59
+ function toResult(index, match, offset = 0) {
52
60
  return {
53
61
  index,
54
62
  captureIndices: match.indices.map((indice) => {
@@ -60,9 +68,9 @@ class JavaScriptScanner {
60
68
  };
61
69
  }
62
70
  return {
63
- start: indice[0],
71
+ start: indice[0] + offset,
64
72
  length: indice[1] - indice[0],
65
- end: indice[1]
73
+ end: indice[1] + offset
66
74
  };
67
75
  })
68
76
  };
@@ -72,25 +80,31 @@ class JavaScriptScanner {
72
80
  if (!regexp)
73
81
  continue;
74
82
  try {
83
+ let offset = 0;
75
84
  regexp.lastIndex = startPosition;
76
- const match = regexp.exec(str);
85
+ let match = regexp.exec(str);
86
+ if (!match && this.contiguousAnchorSimulation[i]) {
87
+ offset = startPosition;
88
+ regexp.lastIndex = 0;
89
+ match = regexp.exec(str.slice(startPosition));
90
+ }
77
91
  if (!match)
78
92
  continue;
79
93
  if (match.index === startPosition) {
80
- return toResult(i, match);
94
+ return toResult(i, match, offset);
81
95
  }
82
- pending.push([i, match]);
96
+ pending.push([i, match, offset]);
83
97
  } catch (e) {
84
- if (this.forgiving)
98
+ if (this.options.forgiving)
85
99
  continue;
86
100
  throw e;
87
101
  }
88
102
  }
89
103
  if (pending.length) {
90
104
  const minIndex = Math.min(...pending.map((m) => m[1].index));
91
- for (const [i, match] of pending) {
105
+ for (const [i, match, offset] of pending) {
92
106
  if (match.index === minIndex) {
93
- return toResult(i, match);
107
+ return toResult(i, match, offset);
94
108
  }
95
109
  }
96
110
  }
@@ -98,13 +112,13 @@ class JavaScriptScanner {
98
112
  }
99
113
  }
100
114
  function createJavaScriptRegexEngine(options = {}) {
101
- const {
102
- forgiving = false,
103
- cache = /* @__PURE__ */ new Map()
104
- } = options;
115
+ const _options = {
116
+ cache: /* @__PURE__ */ new Map(),
117
+ ...options
118
+ };
105
119
  return {
106
120
  createScanner(patterns) {
107
- return new JavaScriptScanner(patterns, cache, forgiving, options.regexConstructor);
121
+ return new JavaScriptScanner(patterns, _options);
108
122
  },
109
123
  createString(s) {
110
124
  return {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shikijs/engine-javascript",
3
3
  "type": "module",
4
- "version": "1.17.4",
4
+ "version": "1.17.5",
5
5
  "description": "Engine for Shiki using JavaScript's native RegExp",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -31,7 +31,7 @@
31
31
  ],
32
32
  "dependencies": {
33
33
  "oniguruma-to-js": "0.4.0",
34
- "@shikijs/types": "1.17.4"
34
+ "@shikijs/types": "1.17.5"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "unbuild",