@graphql-mesh/fusion-composition 0.8.43 → 0.8.44

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/cjs/index.js CHANGED
@@ -4,3 +4,4 @@ const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./compose.js"), exports);
5
5
  tslib_1.__exportStar(require("./transforms.js"), exports);
6
6
  tslib_1.__exportStar(require("./future-additions.js"), exports);
7
+ tslib_1.__exportStar(require("./suggestionList/index.js"), exports);
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.suggestionList = suggestionList;
4
+ const naturalCompare_js_1 = require("./naturalCompare.js");
5
+ // Taken from https://github.com/graphql/graphql-js/blob/16.x.x/src/jsutils/suggestionList.ts
6
+ /**
7
+ * Given an invalid input string and a list of valid options, returns a filtered
8
+ * list of valid options sorted based on their similarity with the input.
9
+ */
10
+ function suggestionList(input, options) {
11
+ const optionsByDistance = Object.create(null);
12
+ const lexicalDistance = new LexicalDistance(input);
13
+ const threshold = Math.floor(input.length * 0.4) + 1;
14
+ for (const option of options) {
15
+ const distance = lexicalDistance.measure(option, threshold);
16
+ if (distance !== undefined) {
17
+ optionsByDistance[option] = distance;
18
+ }
19
+ }
20
+ return Object.keys(optionsByDistance).sort((a, b) => {
21
+ const distanceDiff = optionsByDistance[a] - optionsByDistance[b];
22
+ return distanceDiff !== 0 ? distanceDiff : (0, naturalCompare_js_1.naturalCompare)(a, b);
23
+ });
24
+ }
25
+ /**
26
+ * Computes the lexical distance between strings A and B.
27
+ *
28
+ * The "distance" between two strings is given by counting the minimum number
29
+ * of edits needed to transform string A into string B. An edit can be an
30
+ * insertion, deletion, or substitution of a single character, or a swap of two
31
+ * adjacent characters.
32
+ *
33
+ * Includes a custom alteration from Damerau-Levenshtein to treat case changes
34
+ * as a single edit which helps identify mis-cased values with an edit distance
35
+ * of 1.
36
+ *
37
+ * This distance can be useful for detecting typos in input or sorting
38
+ */
39
+ class LexicalDistance {
40
+ constructor(input) {
41
+ this._input = input;
42
+ this._inputLowerCase = input.toLowerCase();
43
+ this._inputArray = stringToArray(this._inputLowerCase);
44
+ this._rows = [
45
+ new Array(input.length + 1).fill(0),
46
+ new Array(input.length + 1).fill(0),
47
+ new Array(input.length + 1).fill(0),
48
+ ];
49
+ }
50
+ measure(option, threshold) {
51
+ if (this._input === option) {
52
+ return 0;
53
+ }
54
+ const optionLowerCase = option.toLowerCase();
55
+ // Any case change counts as a single edit
56
+ if (this._inputLowerCase === optionLowerCase) {
57
+ return 1;
58
+ }
59
+ let a = stringToArray(optionLowerCase);
60
+ let b = this._inputArray;
61
+ if (a.length < b.length) {
62
+ const tmp = a;
63
+ a = b;
64
+ b = tmp;
65
+ }
66
+ const aLength = a.length;
67
+ const bLength = b.length;
68
+ if (aLength - bLength > threshold) {
69
+ return undefined;
70
+ }
71
+ const rows = this._rows;
72
+ for (let j = 0; j <= bLength; j++) {
73
+ rows[0][j] = j;
74
+ }
75
+ for (let i = 1; i <= aLength; i++) {
76
+ const upRow = rows[(i - 1) % 3];
77
+ const currentRow = rows[i % 3];
78
+ let smallestCell = (currentRow[0] = i);
79
+ for (let j = 1; j <= bLength; j++) {
80
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
81
+ let currentCell = Math.min(upRow[j] + 1, // delete
82
+ currentRow[j - 1] + 1, // insert
83
+ upRow[j - 1] + cost);
84
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
85
+ // transposition
86
+ const doubleDiagonalCell = rows[(i - 2) % 3][j - 2];
87
+ currentCell = Math.min(currentCell, doubleDiagonalCell + 1);
88
+ }
89
+ if (currentCell < smallestCell) {
90
+ smallestCell = currentCell;
91
+ }
92
+ currentRow[j] = currentCell;
93
+ }
94
+ // Early exit, since distance can't go smaller than smallest element of the previous row.
95
+ if (smallestCell > threshold) {
96
+ return undefined;
97
+ }
98
+ }
99
+ const distance = rows[aLength % 3][bLength];
100
+ return distance <= threshold ? distance : undefined;
101
+ }
102
+ }
103
+ function stringToArray(str) {
104
+ const strLength = str.length;
105
+ const array = new Array(strLength);
106
+ for (let i = 0; i < strLength; ++i) {
107
+ array[i] = str.charCodeAt(i);
108
+ }
109
+ return array;
110
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.naturalCompare = naturalCompare;
4
+ /**
5
+ * Returns a number indicating whether a reference string comes before, or after,
6
+ * or is the same as the given string in natural sort order.
7
+ *
8
+ * See: https://en.wikipedia.org/wiki/Natural_sort_order
9
+ *
10
+ */
11
+ function naturalCompare(aStr, bStr) {
12
+ let aIndex = 0;
13
+ let bIndex = 0;
14
+ while (aIndex < aStr.length && bIndex < bStr.length) {
15
+ let aChar = aStr.charCodeAt(aIndex);
16
+ let bChar = bStr.charCodeAt(bIndex);
17
+ if (isDigit(aChar) && isDigit(bChar)) {
18
+ let aNum = 0;
19
+ do {
20
+ ++aIndex;
21
+ aNum = aNum * 10 + aChar - DIGIT_0;
22
+ aChar = aStr.charCodeAt(aIndex);
23
+ } while (isDigit(aChar) && aNum > 0);
24
+ let bNum = 0;
25
+ do {
26
+ ++bIndex;
27
+ bNum = bNum * 10 + bChar - DIGIT_0;
28
+ bChar = bStr.charCodeAt(bIndex);
29
+ } while (isDigit(bChar) && bNum > 0);
30
+ if (aNum < bNum) {
31
+ return -1;
32
+ }
33
+ if (aNum > bNum) {
34
+ return 1;
35
+ }
36
+ }
37
+ else {
38
+ if (aChar < bChar) {
39
+ return -1;
40
+ }
41
+ if (aChar > bChar) {
42
+ return 1;
43
+ }
44
+ ++aIndex;
45
+ ++bIndex;
46
+ }
47
+ }
48
+ return aStr.length - bStr.length;
49
+ }
50
+ const DIGIT_0 = 48;
51
+ const DIGIT_9 = 57;
52
+ function isDigit(code) {
53
+ return !isNaN(code) && DIGIT_0 <= code && code <= DIGIT_9;
54
+ }
package/esm/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './compose.js';
2
2
  export * from './transforms.js';
3
3
  export * from './future-additions.js';
4
+ export * from './suggestionList/index.js';
@@ -0,0 +1,107 @@
1
+ import { naturalCompare } from './naturalCompare.js';
2
+ // Taken from https://github.com/graphql/graphql-js/blob/16.x.x/src/jsutils/suggestionList.ts
3
+ /**
4
+ * Given an invalid input string and a list of valid options, returns a filtered
5
+ * list of valid options sorted based on their similarity with the input.
6
+ */
7
+ export function suggestionList(input, options) {
8
+ const optionsByDistance = Object.create(null);
9
+ const lexicalDistance = new LexicalDistance(input);
10
+ const threshold = Math.floor(input.length * 0.4) + 1;
11
+ for (const option of options) {
12
+ const distance = lexicalDistance.measure(option, threshold);
13
+ if (distance !== undefined) {
14
+ optionsByDistance[option] = distance;
15
+ }
16
+ }
17
+ return Object.keys(optionsByDistance).sort((a, b) => {
18
+ const distanceDiff = optionsByDistance[a] - optionsByDistance[b];
19
+ return distanceDiff !== 0 ? distanceDiff : naturalCompare(a, b);
20
+ });
21
+ }
22
+ /**
23
+ * Computes the lexical distance between strings A and B.
24
+ *
25
+ * The "distance" between two strings is given by counting the minimum number
26
+ * of edits needed to transform string A into string B. An edit can be an
27
+ * insertion, deletion, or substitution of a single character, or a swap of two
28
+ * adjacent characters.
29
+ *
30
+ * Includes a custom alteration from Damerau-Levenshtein to treat case changes
31
+ * as a single edit which helps identify mis-cased values with an edit distance
32
+ * of 1.
33
+ *
34
+ * This distance can be useful for detecting typos in input or sorting
35
+ */
36
+ class LexicalDistance {
37
+ constructor(input) {
38
+ this._input = input;
39
+ this._inputLowerCase = input.toLowerCase();
40
+ this._inputArray = stringToArray(this._inputLowerCase);
41
+ this._rows = [
42
+ new Array(input.length + 1).fill(0),
43
+ new Array(input.length + 1).fill(0),
44
+ new Array(input.length + 1).fill(0),
45
+ ];
46
+ }
47
+ measure(option, threshold) {
48
+ if (this._input === option) {
49
+ return 0;
50
+ }
51
+ const optionLowerCase = option.toLowerCase();
52
+ // Any case change counts as a single edit
53
+ if (this._inputLowerCase === optionLowerCase) {
54
+ return 1;
55
+ }
56
+ let a = stringToArray(optionLowerCase);
57
+ let b = this._inputArray;
58
+ if (a.length < b.length) {
59
+ const tmp = a;
60
+ a = b;
61
+ b = tmp;
62
+ }
63
+ const aLength = a.length;
64
+ const bLength = b.length;
65
+ if (aLength - bLength > threshold) {
66
+ return undefined;
67
+ }
68
+ const rows = this._rows;
69
+ for (let j = 0; j <= bLength; j++) {
70
+ rows[0][j] = j;
71
+ }
72
+ for (let i = 1; i <= aLength; i++) {
73
+ const upRow = rows[(i - 1) % 3];
74
+ const currentRow = rows[i % 3];
75
+ let smallestCell = (currentRow[0] = i);
76
+ for (let j = 1; j <= bLength; j++) {
77
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
78
+ let currentCell = Math.min(upRow[j] + 1, // delete
79
+ currentRow[j - 1] + 1, // insert
80
+ upRow[j - 1] + cost);
81
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
82
+ // transposition
83
+ const doubleDiagonalCell = rows[(i - 2) % 3][j - 2];
84
+ currentCell = Math.min(currentCell, doubleDiagonalCell + 1);
85
+ }
86
+ if (currentCell < smallestCell) {
87
+ smallestCell = currentCell;
88
+ }
89
+ currentRow[j] = currentCell;
90
+ }
91
+ // Early exit, since distance can't go smaller than smallest element of the previous row.
92
+ if (smallestCell > threshold) {
93
+ return undefined;
94
+ }
95
+ }
96
+ const distance = rows[aLength % 3][bLength];
97
+ return distance <= threshold ? distance : undefined;
98
+ }
99
+ }
100
+ function stringToArray(str) {
101
+ const strLength = str.length;
102
+ const array = new Array(strLength);
103
+ for (let i = 0; i < strLength; ++i) {
104
+ array[i] = str.charCodeAt(i);
105
+ }
106
+ return array;
107
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Returns a number indicating whether a reference string comes before, or after,
3
+ * or is the same as the given string in natural sort order.
4
+ *
5
+ * See: https://en.wikipedia.org/wiki/Natural_sort_order
6
+ *
7
+ */
8
+ export function naturalCompare(aStr, bStr) {
9
+ let aIndex = 0;
10
+ let bIndex = 0;
11
+ while (aIndex < aStr.length && bIndex < bStr.length) {
12
+ let aChar = aStr.charCodeAt(aIndex);
13
+ let bChar = bStr.charCodeAt(bIndex);
14
+ if (isDigit(aChar) && isDigit(bChar)) {
15
+ let aNum = 0;
16
+ do {
17
+ ++aIndex;
18
+ aNum = aNum * 10 + aChar - DIGIT_0;
19
+ aChar = aStr.charCodeAt(aIndex);
20
+ } while (isDigit(aChar) && aNum > 0);
21
+ let bNum = 0;
22
+ do {
23
+ ++bIndex;
24
+ bNum = bNum * 10 + bChar - DIGIT_0;
25
+ bChar = bStr.charCodeAt(bIndex);
26
+ } while (isDigit(bChar) && bNum > 0);
27
+ if (aNum < bNum) {
28
+ return -1;
29
+ }
30
+ if (aNum > bNum) {
31
+ return 1;
32
+ }
33
+ }
34
+ else {
35
+ if (aChar < bChar) {
36
+ return -1;
37
+ }
38
+ if (aChar > bChar) {
39
+ return 1;
40
+ }
41
+ ++aIndex;
42
+ ++bIndex;
43
+ }
44
+ }
45
+ return aStr.length - bStr.length;
46
+ }
47
+ const DIGIT_0 = 48;
48
+ const DIGIT_9 = 57;
49
+ function isDigit(code) {
50
+ return !isNaN(code) && DIGIT_0 <= code && code <= DIGIT_9;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-mesh/fusion-composition",
3
- "version": "0.8.43",
3
+ "version": "0.8.44",
4
4
  "description": "Basic composition utility for Fusion spec",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
@@ -1,3 +1,4 @@
1
1
  export * from './compose.cjs';
2
2
  export * from './transforms.cjs';
3
3
  export * from './future-additions.cjs';
4
+ export * from './suggestionList/index.cjs';
@@ -1,3 +1,4 @@
1
1
  export * from './compose.js';
2
2
  export * from './transforms.js';
3
3
  export * from './future-additions.js';
4
+ export * from './suggestionList/index.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Given an invalid input string and a list of valid options, returns a filtered
3
+ * list of valid options sorted based on their similarity with the input.
4
+ */
5
+ export declare function suggestionList(input: string, options: ReadonlyArray<string>): Array<string>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Given an invalid input string and a list of valid options, returns a filtered
3
+ * list of valid options sorted based on their similarity with the input.
4
+ */
5
+ export declare function suggestionList(input: string, options: ReadonlyArray<string>): Array<string>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns a number indicating whether a reference string comes before, or after,
3
+ * or is the same as the given string in natural sort order.
4
+ *
5
+ * See: https://en.wikipedia.org/wiki/Natural_sort_order
6
+ *
7
+ */
8
+ export declare function naturalCompare(aStr: string, bStr: string): number;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Returns a number indicating whether a reference string comes before, or after,
3
+ * or is the same as the given string in natural sort order.
4
+ *
5
+ * See: https://en.wikipedia.org/wiki/Natural_sort_order
6
+ *
7
+ */
8
+ export declare function naturalCompare(aStr: string, bStr: string): number;