@shikijs/engine-javascript 1.22.2 → 1.23.1

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @shikijs/engine-javascript
2
2
 
3
- Engine for Shiki using JavaScript's native RegExp (experimental).
3
+ Engine for Shiki using JavaScript's native RegExp (experimental). Uses [Oniguruma-To-ES](https://github.com/slevithan/oniguruma-to-es) to transpile regex syntax and behavior.
4
4
 
5
5
  [Documentation](https://shiki.style/guide/regex-engines)
6
6
 
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { PatternScanner, RegexEngineString, RegexEngine } from '@shikijs/types';
2
2
  import { IOnigMatch } from '@shikijs/vscode-textmate';
3
+ import { OnigurumaToEsOptions } from 'oniguruma-to-es';
3
4
 
4
5
  interface JavaScriptRegexEngineOptions {
5
6
  /**
@@ -9,11 +10,21 @@ interface JavaScriptRegexEngineOptions {
9
10
  */
10
11
  forgiving?: boolean;
11
12
  /**
12
- * Use JavaScript to simulate some unsupported regex features.
13
+ * The target ECMAScript version.
13
14
  *
14
- * @default true
15
+ * Oniguruma-To-ES uses RegExp features from later versions of ECMAScript to provide improved
16
+ * accuracy and add support for more grammars. If using target `ES2024` or later, the RegExp `v`
17
+ * flag is used which requires Node.js 20+ or Chrome 112+.
18
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicodeSets
19
+ *
20
+ * For maximum compatibility, you can set it to `ES2018` which uses the RegExp `u` flag but
21
+ * supports a few less grammars.
22
+ *
23
+ * Set to `auto` to automatically detect the latest version supported by the environment.
24
+ *
25
+ * @default 'auto'
15
26
  */
16
- simulation?: boolean;
27
+ target?: 'auto' | 'ES2025' | 'ES2024' | 'ES2018';
17
28
  /**
18
29
  * Cache for regex patterns.
19
30
  */
@@ -21,28 +32,28 @@ interface JavaScriptRegexEngineOptions {
21
32
  /**
22
33
  * Custom pattern to RegExp constructor.
23
34
  *
24
- * By default `oniguruma-to-js` is used.
35
+ * By default `oniguruma-to-es` is used.
25
36
  */
26
37
  regexConstructor?: (pattern: string) => RegExp;
27
38
  }
28
39
  /**
29
40
  * The default RegExp constructor for JavaScript regex engine.
30
41
  */
31
- declare function defaultJavaScriptRegexConstructor(pattern: string): RegExp;
42
+ declare function defaultJavaScriptRegexConstructor(pattern: string, options?: OnigurumaToEsOptions): RegExp;
32
43
  declare class JavaScriptScanner implements PatternScanner {
33
44
  patterns: string[];
34
45
  options: JavaScriptRegexEngineOptions;
35
46
  regexps: (RegExp | null)[];
36
- contiguousAnchorSimulation: boolean[];
37
47
  constructor(patterns: string[], options?: JavaScriptRegexEngineOptions);
38
48
  findNextMatchSync(string: string | RegexEngineString, startPosition: number): IOnigMatch | null;
39
49
  }
40
50
  /**
41
51
  * Use the modern JavaScript RegExp engine to implement the OnigScanner.
42
52
  *
43
- * As Oniguruma regex is more powerful than JavaScript regex, some patterns may not be supported.
44
- * Errors will be thrown when parsing TextMate grammars with unsupported patterns.
45
- * Set `forgiving` to `true` to ignore these errors and skip the unsupported patterns.
53
+ * As Oniguruma supports some features that can't be emulated using native JavaScript regexes, some
54
+ * patterns are not supported. Errors will be thrown when parsing TextMate grammars with
55
+ * unsupported patterns, and when the grammar includes patterns that use invalid Oniguruma syntax.
56
+ * Set `forgiving` to `true` to ignore these errors and skip any unsupported or invalid patterns.
46
57
  *
47
58
  * @experimental
48
59
  */
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { PatternScanner, RegexEngineString, RegexEngine } from '@shikijs/types';
2
2
  import { IOnigMatch } from '@shikijs/vscode-textmate';
3
+ import { OnigurumaToEsOptions } from 'oniguruma-to-es';
3
4
 
4
5
  interface JavaScriptRegexEngineOptions {
5
6
  /**
@@ -9,11 +10,21 @@ interface JavaScriptRegexEngineOptions {
9
10
  */
10
11
  forgiving?: boolean;
11
12
  /**
12
- * Use JavaScript to simulate some unsupported regex features.
13
+ * The target ECMAScript version.
13
14
  *
14
- * @default true
15
+ * Oniguruma-To-ES uses RegExp features from later versions of ECMAScript to provide improved
16
+ * accuracy and add support for more grammars. If using target `ES2024` or later, the RegExp `v`
17
+ * flag is used which requires Node.js 20+ or Chrome 112+.
18
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicodeSets
19
+ *
20
+ * For maximum compatibility, you can set it to `ES2018` which uses the RegExp `u` flag but
21
+ * supports a few less grammars.
22
+ *
23
+ * Set to `auto` to automatically detect the latest version supported by the environment.
24
+ *
25
+ * @default 'auto'
15
26
  */
16
- simulation?: boolean;
27
+ target?: 'auto' | 'ES2025' | 'ES2024' | 'ES2018';
17
28
  /**
18
29
  * Cache for regex patterns.
19
30
  */
@@ -21,28 +32,28 @@ interface JavaScriptRegexEngineOptions {
21
32
  /**
22
33
  * Custom pattern to RegExp constructor.
23
34
  *
24
- * By default `oniguruma-to-js` is used.
35
+ * By default `oniguruma-to-es` is used.
25
36
  */
26
37
  regexConstructor?: (pattern: string) => RegExp;
27
38
  }
28
39
  /**
29
40
  * The default RegExp constructor for JavaScript regex engine.
30
41
  */
31
- declare function defaultJavaScriptRegexConstructor(pattern: string): RegExp;
42
+ declare function defaultJavaScriptRegexConstructor(pattern: string, options?: OnigurumaToEsOptions): RegExp;
32
43
  declare class JavaScriptScanner implements PatternScanner {
33
44
  patterns: string[];
34
45
  options: JavaScriptRegexEngineOptions;
35
46
  regexps: (RegExp | null)[];
36
- contiguousAnchorSimulation: boolean[];
37
47
  constructor(patterns: string[], options?: JavaScriptRegexEngineOptions);
38
48
  findNextMatchSync(string: string | RegexEngineString, startPosition: number): IOnigMatch | null;
39
49
  }
40
50
  /**
41
51
  * Use the modern JavaScript RegExp engine to implement the OnigScanner.
42
52
  *
43
- * As Oniguruma regex is more powerful than JavaScript regex, some patterns may not be supported.
44
- * Errors will be thrown when parsing TextMate grammars with unsupported patterns.
45
- * Set `forgiving` to `true` to ignore these errors and skip the unsupported patterns.
53
+ * As Oniguruma supports some features that can't be emulated using native JavaScript regexes, some
54
+ * patterns are not supported. Errors will be thrown when parsing TextMate grammars with
55
+ * unsupported patterns, and when the grammar includes patterns that use invalid Oniguruma syntax.
56
+ * Set `forgiving` to `true` to ignore these errors and skip any unsupported or invalid patterns.
46
57
  *
47
58
  * @experimental
48
59
  */
package/dist/index.mjs CHANGED
@@ -1,15 +1,4 @@
1
- import { onigurumaToRegexp } from 'oniguruma-to-js';
2
-
3
- const replacements = [
4
- [
5
- "(?<square>[^\\[\\]\\\\]|\\\\.|\\[\\g<square>*+\\])",
6
- "(?<square>[^\\[\\]\\\\]|\\\\.|\\[(?:[^\\[\\]\\\\]|\\\\.|\\[(?:[^\\[\\]\\\\]|\\\\.|\\[(?:[^\\[\\]\\\\])*+\\])*+\\])*+\\])"
7
- ],
8
- [
9
- "(?<url>(?>[^\\s()]+)|\\(\\g<url>*\\))",
10
- "(?<url>(?>[^\\s()]+)|\\((?:(?>[^\\s()]+)|\\((?:(?>[^\\s()]+)|\\((?>[^\\s()]+)*\\))*\\))*\\))"
11
- ]
12
- ];
1
+ import { toRegExp } from 'oniguruma-to-es';
13
2
 
14
3
  var __defProp = Object.defineProperty;
15
4
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -18,12 +7,15 @@ var __publicField = (obj, key, value) => {
18
7
  return value;
19
8
  };
20
9
  const MAX = 4294967295;
21
- function defaultJavaScriptRegexConstructor(pattern) {
22
- return onigurumaToRegexp(
10
+ function defaultJavaScriptRegexConstructor(pattern, options) {
11
+ return toRegExp(
23
12
  pattern,
24
13
  {
25
- flags: "dgm",
26
- ignoreContiguousAnchors: true
14
+ accuracy: "loose",
15
+ global: true,
16
+ hasIndices: true,
17
+ tmGrammar: true,
18
+ ...options
27
19
  }
28
20
  );
29
21
  }
@@ -32,19 +24,13 @@ class JavaScriptScanner {
32
24
  this.patterns = patterns;
33
25
  this.options = options;
34
26
  __publicField(this, "regexps");
35
- __publicField(this, "contiguousAnchorSimulation");
36
27
  const {
37
28
  forgiving = false,
38
29
  cache,
39
- simulation = true,
40
- regexConstructor = defaultJavaScriptRegexConstructor
30
+ target = "auto",
31
+ regexConstructor = (pattern) => defaultJavaScriptRegexConstructor(pattern, { target })
41
32
  } = options;
42
- this.contiguousAnchorSimulation = Array.from({ length: patterns.length }, () => false);
43
- this.regexps = patterns.map((p, idx) => {
44
- if (simulation)
45
- p = p.replaceAll("(^|\\\uFFFF)", "(^|\\G)");
46
- if (simulation && (p.startsWith("(^|\\G)") || p.startsWith("(\\G|^)")))
47
- this.contiguousAnchorSimulation[idx] = true;
33
+ this.regexps = patterns.map((p) => {
48
34
  const cached = cache?.get(p);
49
35
  if (cached) {
50
36
  if (cached instanceof RegExp) {
@@ -55,13 +41,7 @@ class JavaScriptScanner {
55
41
  throw cached;
56
42
  }
57
43
  try {
58
- let pattern = p;
59
- if (simulation) {
60
- for (const [from, to] of replacements) {
61
- pattern = pattern.replaceAll(from, to);
62
- }
63
- }
64
- const regex = regexConstructor(pattern);
44
+ const regex = regexConstructor(p);
65
45
  cache?.set(p, regex);
66
46
  return regex;
67
47
  } catch (e) {
@@ -99,20 +79,14 @@ class JavaScriptScanner {
99
79
  if (!regexp)
100
80
  continue;
101
81
  try {
102
- let offset = 0;
103
82
  regexp.lastIndex = startPosition;
104
- let match = regexp.exec(str);
105
- if (!match && this.contiguousAnchorSimulation[i]) {
106
- offset = startPosition;
107
- regexp.lastIndex = 0;
108
- match = regexp.exec(str.slice(startPosition));
109
- }
83
+ const match = regexp.exec(str);
110
84
  if (!match)
111
85
  continue;
112
86
  if (match.index === startPosition) {
113
- return toResult(i, match, offset);
87
+ return toResult(i, match, 0);
114
88
  }
115
- pending.push([i, match, offset]);
89
+ pending.push([i, match, 0]);
116
90
  } catch (e) {
117
91
  if (this.options.forgiving)
118
92
  continue;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shikijs/engine-javascript",
3
3
  "type": "module",
4
- "version": "1.22.2",
4
+ "version": "1.23.1",
5
5
  "description": "Engine for Shiki using JavaScript's native RegExp",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -31,8 +31,8 @@
31
31
  ],
32
32
  "dependencies": {
33
33
  "@shikijs/vscode-textmate": "^9.3.0",
34
- "oniguruma-to-js": "0.4.3",
35
- "@shikijs/types": "1.22.2"
34
+ "oniguruma-to-es": "0.4.1",
35
+ "@shikijs/types": "1.23.1"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "unbuild",