graphmatch 1.0.1 → 1.0.2

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/types.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  type Node = {
2
- regex?: RegExp;
2
+ regex: RegExp;
3
3
  children?: Node[];
4
+ } | {
5
+ regex?: RegExp;
6
+ children: Node[];
4
7
  };
5
8
  type Options = {
6
9
  partial?: boolean;
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { Node } from './types.js';
2
2
  declare const getNodeFlags: (node: Node) => string;
3
3
  declare const getNodeSource: (node: Node, partial: boolean) => string;
4
- declare const visitNode: (node: Node, visitor: (node: Node) => void) => void;
5
- export { getNodeFlags, getNodeSource, visitNode };
4
+ export { getNodeFlags, getNodeSource };
package/dist/utils.js CHANGED
@@ -1,27 +1,49 @@
1
1
  /* IMPORT */
2
2
  /* MAIN */
3
+ const getNodes = (node) => {
4
+ const nodes = new Set();
5
+ const queue = [node];
6
+ for (let i = 0; i < queue.length; i++) {
7
+ const node = queue[i];
8
+ if (nodes.has(node))
9
+ continue;
10
+ nodes.add(node);
11
+ const { children } = node;
12
+ if (!children?.length)
13
+ continue;
14
+ for (let ci = 0, cl = children.length; ci < cl; ci++) {
15
+ queue.push(children[ci]);
16
+ }
17
+ }
18
+ return Array.from(nodes);
19
+ };
3
20
  const getNodeFlags = (node) => {
4
21
  let flags = '';
5
- visitNode(node, node => {
22
+ const nodes = getNodes(node);
23
+ for (let i = 0, l = nodes.length; i < l; i++) { // From root to leaves
24
+ const node = nodes[i];
6
25
  if (!node.regex)
7
- return;
26
+ continue;
8
27
  const nodeFlags = node.regex.flags;
9
28
  flags || (flags = nodeFlags);
10
- if (flags !== nodeFlags) {
11
- throw new Error(`Inconsistent RegExp flags used: "${flags}" and "${nodeFlags}"`);
12
- }
13
- });
29
+ if (flags === nodeFlags)
30
+ continue;
31
+ throw new Error(`Inconsistent RegExp flags used: "${flags}" and "${nodeFlags}"`);
32
+ }
14
33
  return flags;
15
34
  };
16
- const getNodeSource = (node, partial) => {
35
+ const getNodeSourceWithCache = (node, partial, cache) => {
36
+ const cached = cache.get(node);
37
+ if (cached !== undefined)
38
+ return cached;
17
39
  let source = '';
18
40
  if (node.regex) {
19
41
  source += partial ? '(?:$|' : '';
20
42
  source += node.regex.source;
21
43
  }
22
44
  if (node.children?.length) {
23
- const children = node.children.map(node => getNodeSource(node, partial)).filter(Boolean);
24
- if (children.length) {
45
+ const children = uniq(node.children.map(node => getNodeSourceWithCache(node, partial, cache)).filter(Boolean));
46
+ if (children?.length) {
25
47
  const needsWrapperGroup = (children.length > 1) || (partial && !source.length);
26
48
  source += needsWrapperGroup ? partial ? '(?:$|' : '(?:' : '';
27
49
  source += children.join('|');
@@ -31,13 +53,22 @@ const getNodeSource = (node, partial) => {
31
53
  if (node.regex) {
32
54
  source += partial ? ')' : '';
33
55
  }
56
+ cache.set(node, source);
34
57
  return source;
35
58
  };
36
- const visitNode = (node, visitor) => {
37
- visitor(node);
38
- node.children?.forEach(node => {
39
- visitNode(node, visitor);
40
- });
59
+ const getNodeSource = (node, partial) => {
60
+ const cache = new Map();
61
+ const nodes = getNodes(node);
62
+ for (let i = nodes.length - 1; i >= 0; i--) { // From leaves to root
63
+ const source = getNodeSourceWithCache(nodes[i], partial, cache);
64
+ if (i > 0)
65
+ continue;
66
+ return source;
67
+ }
68
+ return '';
69
+ };
70
+ const uniq = (values) => {
71
+ return Array.from(new Set(values));
41
72
  };
42
73
  /* EXPORT */
43
- export { getNodeFlags, getNodeSource, visitNode };
74
+ export { getNodeFlags, getNodeSource };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "graphmatch",
3
3
  "repository": "github:fabiospampinato/graphmatch",
4
4
  "description": "A low-level utility for matching a string against a directed acyclic graph of regexes.",
5
- "version": "1.0.1",
5
+ "version": "1.0.2",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "exports": "./dist/index.js",
package/asd.js DELETED
@@ -1,81 +0,0 @@
1
-
2
- import graphmatch from './dist/index.js';
3
-
4
-
5
- const GRAPH = {
6
- regex: /foo/,
7
- children: [
8
- {
9
- regex: /\//,
10
- children: [
11
- {
12
- regex: /bar/,
13
- children: [
14
- {
15
- regex: /\//,
16
- children: [
17
- {
18
- regex: /qux/
19
- }
20
- ]
21
- }
22
- ]
23
- },
24
- {
25
- regex: /baz/,
26
- children: [
27
- {
28
- regex: /\//,
29
- children: [
30
- {
31
- regex: /qux/
32
- }
33
- ]
34
- }
35
- ]
36
- }
37
- ]
38
- }
39
- ]
40
- };
41
-
42
- // Let's now match against the graph, fully
43
-
44
- console.log ('1.');
45
-
46
- console.log ( graphmatch ( GRAPH, 'foo/bar/qux' ) ); // => true
47
- console.log ( graphmatch ( GRAPH, 'foo/baz/qux' ) ); // => true
48
-
49
- console.log ( graphmatch ( GRAPH, 'foo/bar/whoops' ) ); // => false
50
- console.log ( graphmatch ( GRAPH, 'foo/baz' ) ); // => false
51
-
52
- // Let's now match against the graph, partially
53
- // A partial match happens when any matching node in the graph reaches the end of the string
54
-
55
- console.log ('2.');
56
-
57
- console.log ( graphmatch ( GRAPH, 'foo/bar/qux', { partial: true } ) ); // => true
58
- console.log ( graphmatch ( GRAPH, 'foo/bar/', { partial: true } ) ); // => true
59
- console.log ( graphmatch ( GRAPH, 'foo/bar', { partial: true } ) ); // => true
60
- console.log ( graphmatch ( GRAPH, 'foo/', { partial: true } ) ); // => true
61
- console.log ( graphmatch ( GRAPH, 'foo', { partial: true } ) ); // => true
62
-
63
- console.log ( graphmatch ( GRAPH, 'foo/bar/whoops', { partial: true } ) ); // => false
64
- console.log ( graphmatch ( GRAPH, 'foo/barsomething', { partial: true } ) ); // => false
65
- console.log ( graphmatch ( GRAPH, 'bar', { partial: true } ) ); // => false
66
-
67
- // Let's now compile the whole graph to a single regex
68
- // This is useful if you expect to match against the graph multiple times
69
- // It's faster to compile the graph once and match against it multiple times
70
-
71
- console.log ('3.');
72
-
73
- const fullRe = graphmatch.compile ( GRAPH ); // => RegExp
74
-
75
- console.log ( fullRe.test ( 'foo/bar/qux' ) ); // => true
76
- console.log ( fullRe.test ( 'foo/bar' ) ); // => false
77
-
78
- const partialRe = graphmatch.compile ( GRAPH, { partial: true } ); // => RegExp
79
-
80
- console.log ( partialRe.test ( 'foo/bar/qux' ) ); // => true
81
- console.log ( partialRe.test ( 'foo/bar' ) ); // => true