@atlaskit/editor-plugin-autocomplete 0.2.0 → 0.4.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 +19 -0
- package/afm-cc/tsconfig.json +1 -4
- package/afm-jira/tsconfig.json +1 -4
- package/afm-products/tsconfig.json +1 -4
- package/build/tsconfig.json +1 -6
- package/dist/cjs/pm-plugins/autocomplete-plugin.js +7 -3
- package/dist/cjs/pm-plugins/scoring-pipeline.js +1 -3
- package/dist/cjs/pm-plugins/slow-lane-client.js +3 -1
- package/dist/cjs/pm-plugins/text-predictor.js +47 -23
- package/dist/es2019/pm-plugins/autocomplete-plugin.js +7 -3
- package/dist/es2019/pm-plugins/scoring-pipeline.js +0 -3
- package/dist/es2019/pm-plugins/slow-lane-client.js +5 -2
- package/dist/es2019/pm-plugins/text-predictor.js +24 -9
- package/dist/esm/pm-plugins/autocomplete-plugin.js +7 -3
- package/dist/esm/pm-plugins/scoring-pipeline.js +0 -3
- package/dist/esm/pm-plugins/slow-lane-client.js +3 -1
- package/dist/esm/pm-plugins/text-predictor.js +47 -23
- package/dist/types/pm-plugins/autocomplete-plugin.d.ts +6 -0
- package/dist/types/pm-plugins/text-predictor.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/autocomplete-plugin.d.ts +6 -0
- package/dist/types-ts4.5/pm-plugins/text-predictor.d.ts +1 -1
- package/package.json +2 -2
- package/src/pm-plugins/autocomplete-plugin.ts +20 -5
- package/src/pm-plugins/data/combined_l2_l3_pos_tags.json +73571 -3
- package/src/pm-plugins/data/ghost_pos_tags.json +43 -3
- package/src/pm-plugins/data/grammar_transitions_10k.json +46 -3
- package/src/pm-plugins/data/l3_vocabulary.json +20002 -3
- package/src/pm-plugins/data/vocabulary_10k.json +38794 -3
- package/src/pm-plugins/data/word_index_10k.json +7760 -3
- package/src/pm-plugins/scoring-pipeline.ts +0 -3
- package/src/pm-plugins/slow-lane-client.ts +4 -2
- package/src/pm-plugins/text-predictor.ts +30 -10
- package/tsconfig.app.json +2 -2
- package/tsconfig.json +1 -1
- package/src/pm-plugins/typings.d.ts +0 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-autocomplete
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`603cd44e7b8c3`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/603cd44e7b8c3) -
|
|
8
|
+
Fetch vectors through media client
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
|
|
14
|
+
## 0.3.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- [`87965237565b6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/87965237565b6) -
|
|
19
|
+
[ux] Add autocomplete plugin to inline comment editor behind
|
|
20
|
+
`platform_editor_ai_autocomplete_conf_comments` experiment
|
|
21
|
+
|
|
3
22
|
## 0.2.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/afm-cc/tsconfig.json
CHANGED
|
@@ -6,10 +6,7 @@
|
|
|
6
6
|
"rootDir": "../",
|
|
7
7
|
"composite": true,
|
|
8
8
|
"noCheck": true,
|
|
9
|
-
|
|
10
|
-
// that appear as pointer text (not valid JSON) in CI environments where LFS is skipped.
|
|
11
|
-
// Enabling resolveJsonModule would cause TS to attempt parsing these files and fail.
|
|
12
|
-
"resolveJsonModule": false
|
|
9
|
+
"resolveJsonModule": true
|
|
13
10
|
},
|
|
14
11
|
"include": [
|
|
15
12
|
"../src/**/*.ts",
|
package/afm-jira/tsconfig.json
CHANGED
|
@@ -6,10 +6,7 @@
|
|
|
6
6
|
"rootDir": "../",
|
|
7
7
|
"composite": true,
|
|
8
8
|
"noCheck": true,
|
|
9
|
-
|
|
10
|
-
// that appear as pointer text (not valid JSON) in CI environments where LFS is skipped.
|
|
11
|
-
// Enabling resolveJsonModule would cause TS to attempt parsing these files and fail.
|
|
12
|
-
"resolveJsonModule": false
|
|
9
|
+
"resolveJsonModule": true
|
|
13
10
|
},
|
|
14
11
|
"include": [
|
|
15
12
|
"../src/**/*.ts",
|
|
@@ -6,10 +6,7 @@
|
|
|
6
6
|
"rootDir": "../",
|
|
7
7
|
"composite": true,
|
|
8
8
|
"noCheck": true,
|
|
9
|
-
|
|
10
|
-
// that appear as pointer text (not valid JSON) in CI environments where LFS is skipped.
|
|
11
|
-
// Enabling resolveJsonModule would cause TS to attempt parsing these files and fail.
|
|
12
|
-
"resolveJsonModule": false
|
|
9
|
+
"resolveJsonModule": true
|
|
13
10
|
},
|
|
14
11
|
"include": [
|
|
15
12
|
"../src/**/*.ts",
|
package/build/tsconfig.json
CHANGED
|
@@ -2,12 +2,7 @@
|
|
|
2
2
|
"extends": "../tsconfig",
|
|
3
3
|
"compilerOptions": {
|
|
4
4
|
"paths": {},
|
|
5
|
-
|
|
6
|
-
// that appear as pointer text (not valid JSON) in CI environments where LFS is skipped.
|
|
7
|
-
// We also intentionally do not set "target": "es5" here (unlike the standard generated
|
|
8
|
-
// build tsconfig) because the ESLint require-unicode-regexp rule enforces the 'u' flag
|
|
9
|
-
// on regexes, which requires es6+ target to compile.
|
|
10
|
-
"resolveJsonModule": false
|
|
5
|
+
"resolveJsonModule": true
|
|
11
6
|
},
|
|
12
7
|
"include": ["../src/**/*.ts", "../src/**/*.tsx"],
|
|
13
8
|
"exclude": [
|
|
@@ -214,14 +214,16 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
|
|
|
214
214
|
return;
|
|
215
215
|
}
|
|
216
216
|
var lastChar = newText[newText.length - 1];
|
|
217
|
-
|
|
217
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
218
|
+
if (!/[\s.,;:!?]/.test(lastChar)) {
|
|
218
219
|
return;
|
|
219
220
|
}
|
|
220
221
|
|
|
221
222
|
// Only fire if the previous state did not already end on a boundary,
|
|
222
223
|
// so we don't double-count when multiple boundary chars are inserted.
|
|
223
224
|
var prevLastChar = prevText[prevText.length - 1];
|
|
224
|
-
|
|
225
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
226
|
+
if (prevLastChar && /[\s.,;:!?]/.test(prevLastChar)) {
|
|
225
227
|
return;
|
|
226
228
|
}
|
|
227
229
|
var beforeBoundary = newText.slice(0, -1).trimEnd();
|
|
@@ -299,7 +301,9 @@ var createAutocompletePlugin = exports.createAutocompletePlugin = function creat
|
|
|
299
301
|
},
|
|
300
302
|
focus: function focus() {
|
|
301
303
|
(0, _textPredictor.loadDefaultVocabulary)();
|
|
302
|
-
(0, _textPredictor.loadVectorsAsync)(
|
|
304
|
+
(0, _textPredictor.loadVectorsAsync)({
|
|
305
|
+
getBinaryUrl: options === null || options === void 0 ? void 0 : options.getVectorsBinaryUrl
|
|
306
|
+
}).catch(function () {});
|
|
303
307
|
if (!hasIngestedPage) {
|
|
304
308
|
hasIngestedPage = true;
|
|
305
309
|
if (options !== null && options !== void 0 && options.getContext) {
|
|
@@ -16,9 +16,7 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
16
16
|
*
|
|
17
17
|
* Operates synchronously on pre-loaded data. Each stage gracefully degrades
|
|
18
18
|
* when its required data isn't available (cold → warm → full warm).
|
|
19
|
-
*/
|
|
20
|
-
// TypeScript from parsing LFS pointer files during CI typecheck. JSON imports
|
|
21
|
-
// are typed via the '*.json' declaration in typings.d.ts.
|
|
19
|
+
*/
|
|
22
20
|
// ─── Types ──────────────────────────────────────────────────
|
|
23
21
|
|
|
24
22
|
/** Metadata returned by the grammar filter for debug logging in the caller. */
|
|
@@ -25,7 +25,8 @@ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/
|
|
|
25
25
|
|
|
26
26
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
29
|
+
var WORD_BOUNDARY_CHARS = /[\s.,;:!?]/;
|
|
29
30
|
var DEFAULT_DEBOUNCE_MS = 300;
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -75,6 +76,7 @@ var createSlowLaneClient = exports.createSlowLaneClient = function createSlowLan
|
|
|
75
76
|
}
|
|
76
77
|
return _context.abrupt("return");
|
|
77
78
|
case 2:
|
|
79
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
78
80
|
url = "".concat(baseUrl.replace(/\/$/, '')).concat(endpoint);
|
|
79
81
|
payload = {
|
|
80
82
|
text: text,
|
|
@@ -37,7 +37,8 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
37
37
|
// import { rankCandidates, isGrammarAllowed } from './scoring-pipeline';
|
|
38
38
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
41
|
+
var PUNCTUATION_BOUNDARY_REGEX = /^[.,;:!?()\[\]{}"'`]+|[.,;:!?()\[\]{}"'`]+$/g;
|
|
41
42
|
var MIN_PREFIX_LENGTH = 3;
|
|
42
43
|
var MAX_CANDIDATES = 200;
|
|
43
44
|
var CONTEXT_WORDS = 10;
|
|
@@ -311,8 +312,8 @@ var getContextVectorForScoring = function getContextVectorForScoring(textBefore)
|
|
|
311
312
|
};
|
|
312
313
|
var tokenize = function tokenize(text) {
|
|
313
314
|
var tokens = [];
|
|
314
|
-
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace
|
|
315
|
-
var _iterator7 = _createForOfIteratorHelper(text.toLowerCase().split(
|
|
315
|
+
// eslint-disable-next-line require-unicode-regexp, @atlassian/perf-linting/no-expensive-split-replace
|
|
316
|
+
var _iterator7 = _createForOfIteratorHelper(text.toLowerCase().split(/\s+/)),
|
|
316
317
|
_step7;
|
|
317
318
|
try {
|
|
318
319
|
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
@@ -332,13 +333,15 @@ var tokenize = function tokenize(text) {
|
|
|
332
333
|
};
|
|
333
334
|
var extractPreviousWord = function extractPreviousWord(text) {
|
|
334
335
|
// 1. Split the text by newlines or punctuation (. ? !)
|
|
335
|
-
|
|
336
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
337
|
+
var sentences = text.split(/[\n.?!]+/);
|
|
336
338
|
|
|
337
339
|
// 2. Only look at the current sentence/line the user is typing in
|
|
338
340
|
var currentSentence = sentences[sentences.length - 1];
|
|
339
341
|
|
|
340
342
|
// 3. Extract the previous word as normal
|
|
341
|
-
|
|
343
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
344
|
+
var words = currentSentence.trimEnd().split(/\s+/);
|
|
342
345
|
return words.length >= 2 ? words[words.length - 2] : '';
|
|
343
346
|
};
|
|
344
347
|
|
|
@@ -489,7 +492,8 @@ var predict = exports.predict = function predict(textBefore) {
|
|
|
489
492
|
// }
|
|
490
493
|
|
|
491
494
|
// ── Step 2: Prefix completion (≥3 chars typed) ──────────────────────────
|
|
492
|
-
|
|
495
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
496
|
+
if (textBefore.length > 0 && /\s$/.test(textBefore)) {
|
|
493
497
|
return null;
|
|
494
498
|
}
|
|
495
499
|
var trimmed = textBefore.trimEnd();
|
|
@@ -689,10 +693,8 @@ var predict = exports.predict = function predict(textBefore) {
|
|
|
689
693
|
|
|
690
694
|
// ─── Data Loading ────────────────────────────────────────────────────────────
|
|
691
695
|
|
|
692
|
-
var DEFAULT_VECTORS_URL = '/data/word-vectors_10k.bin';
|
|
693
696
|
var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
694
697
|
var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(options) {
|
|
695
|
-
var _options$vectorsUrl;
|
|
696
698
|
var url, res, buffer, float32, wordIndex, nWords, dim;
|
|
697
699
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
698
700
|
while (1) switch (_context.prev = _context.next) {
|
|
@@ -703,25 +705,47 @@ var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
703
705
|
}
|
|
704
706
|
return _context.abrupt("return");
|
|
705
707
|
case 2:
|
|
708
|
+
if (options !== null && options !== void 0 && options.getBinaryUrl) {
|
|
709
|
+
_context.next = 5;
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
// eslint-disable-next-line no-console
|
|
713
|
+
console.warn('[text-predictor] loadVectorsAsync called without a getBinaryUrl — vectors will not load. Pass getVectorsBinaryUrl via plugin options.');
|
|
714
|
+
return _context.abrupt("return");
|
|
715
|
+
case 5:
|
|
706
716
|
vectorsLoadStarted = true;
|
|
707
|
-
|
|
708
|
-
_context.
|
|
709
|
-
|
|
717
|
+
_context.prev = 6;
|
|
718
|
+
_context.next = 9;
|
|
719
|
+
return options.getBinaryUrl();
|
|
720
|
+
case 9:
|
|
721
|
+
url = _context.sent;
|
|
722
|
+
_context.next = 17;
|
|
723
|
+
break;
|
|
724
|
+
case 12:
|
|
725
|
+
_context.prev = 12;
|
|
726
|
+
_context.t0 = _context["catch"](6);
|
|
727
|
+
vectorsLoadStarted = false;
|
|
728
|
+
// eslint-disable-next-line no-console
|
|
729
|
+
console.warn('[text-predictor] Failed to resolve vectors URL:', _context.t0);
|
|
730
|
+
return _context.abrupt("return");
|
|
731
|
+
case 17:
|
|
732
|
+
_context.prev = 17;
|
|
733
|
+
_context.next = 20;
|
|
710
734
|
return fetch(url);
|
|
711
|
-
case
|
|
735
|
+
case 20:
|
|
712
736
|
res = _context.sent;
|
|
713
737
|
if (res.ok) {
|
|
714
|
-
_context.next =
|
|
738
|
+
_context.next = 25;
|
|
715
739
|
break;
|
|
716
740
|
}
|
|
717
741
|
vectorsLoadStarted = false;
|
|
718
742
|
// eslint-disable-next-line no-console
|
|
719
743
|
console.warn("[text-predictor] Failed to load vectors: ".concat(res.status));
|
|
720
744
|
return _context.abrupt("return");
|
|
721
|
-
case
|
|
722
|
-
_context.next =
|
|
745
|
+
case 25:
|
|
746
|
+
_context.next = 27;
|
|
723
747
|
return res.arrayBuffer();
|
|
724
|
-
case
|
|
748
|
+
case 27:
|
|
725
749
|
buffer = _context.sent;
|
|
726
750
|
float32 = new Float32Array(buffer);
|
|
727
751
|
wordIndex = _word_index_10k.default;
|
|
@@ -741,19 +765,19 @@ var loadVectorsAsync = exports.loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
741
765
|
sizeBytes: float32.byteLength
|
|
742
766
|
});
|
|
743
767
|
}
|
|
744
|
-
_context.next =
|
|
768
|
+
_context.next = 41;
|
|
745
769
|
break;
|
|
746
|
-
case
|
|
747
|
-
_context.prev =
|
|
748
|
-
_context.
|
|
770
|
+
case 37:
|
|
771
|
+
_context.prev = 37;
|
|
772
|
+
_context.t1 = _context["catch"](17);
|
|
749
773
|
vectorsLoadStarted = false;
|
|
750
774
|
// eslint-disable-next-line no-console
|
|
751
|
-
console.warn('[text-predictor] Failed to load vectors:', _context.
|
|
752
|
-
case
|
|
775
|
+
console.warn('[text-predictor] Failed to load vectors:', _context.t1);
|
|
776
|
+
case 41:
|
|
753
777
|
case "end":
|
|
754
778
|
return _context.stop();
|
|
755
779
|
}
|
|
756
|
-
}, _callee, null, [[
|
|
780
|
+
}, _callee, null, [[6, 12], [17, 37]]);
|
|
757
781
|
}));
|
|
758
782
|
return function loadVectorsAsync(_x) {
|
|
759
783
|
return _ref4.apply(this, arguments);
|
|
@@ -212,14 +212,16 @@ export const createAutocompletePlugin = options => {
|
|
|
212
212
|
return;
|
|
213
213
|
}
|
|
214
214
|
const lastChar = newText[newText.length - 1];
|
|
215
|
-
|
|
215
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
216
|
+
if (!/[\s.,;:!?]/.test(lastChar)) {
|
|
216
217
|
return;
|
|
217
218
|
}
|
|
218
219
|
|
|
219
220
|
// Only fire if the previous state did not already end on a boundary,
|
|
220
221
|
// so we don't double-count when multiple boundary chars are inserted.
|
|
221
222
|
const prevLastChar = prevText[prevText.length - 1];
|
|
222
|
-
|
|
223
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
224
|
+
if (prevLastChar && /[\s.,;:!?]/.test(prevLastChar)) {
|
|
223
225
|
return;
|
|
224
226
|
}
|
|
225
227
|
const beforeBoundary = newText.slice(0, -1).trimEnd();
|
|
@@ -300,7 +302,9 @@ export const createAutocompletePlugin = options => {
|
|
|
300
302
|
},
|
|
301
303
|
focus: () => {
|
|
302
304
|
loadDefaultVocabulary();
|
|
303
|
-
loadVectorsAsync(
|
|
305
|
+
loadVectorsAsync({
|
|
306
|
+
getBinaryUrl: options === null || options === void 0 ? void 0 : options.getVectorsBinaryUrl
|
|
307
|
+
}).catch(() => {});
|
|
304
308
|
if (!hasIngestedPage) {
|
|
305
309
|
hasIngestedPage = true;
|
|
306
310
|
if (options !== null && options !== void 0 && options.getContext) {
|
|
@@ -5,9 +5,6 @@
|
|
|
5
5
|
* when its required data isn't available (cold → warm → full warm).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
// resolveJsonModule is disabled for this package (see tsconfig.json) to prevent
|
|
9
|
-
// TypeScript from parsing LFS pointer files during CI typecheck. JSON imports
|
|
10
|
-
// are typed via the '*.json' declaration in typings.d.ts.
|
|
11
8
|
import posTagsData from './data/combined_l2_l3_pos_tags.json';
|
|
12
9
|
import ghostPosTagsData from './data/ghost_pos_tags.json';
|
|
13
10
|
import grammarTransitionsData from './data/grammar_transitions_10k.json';
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
19
|
+
const WORD_BOUNDARY_CHARS = /[\s.,;:!?]/;
|
|
19
20
|
const DEFAULT_DEBOUNCE_MS = 300;
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -55,7 +56,9 @@ export const createSlowLaneClient = config => {
|
|
|
55
56
|
if (!text || text.trim().length === 0) {
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
+
|
|
60
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
61
|
+
const url = `${baseUrl.replace(/\/$/, '')}${endpoint}`;
|
|
59
62
|
const payload = {
|
|
60
63
|
text,
|
|
61
64
|
session_id: sessionId
|
|
@@ -26,7 +26,8 @@ import { getStoredContextVector, getStoredLmLogits } from './slow-lane-client';
|
|
|
26
26
|
|
|
27
27
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
30
|
+
const PUNCTUATION_BOUNDARY_REGEX = /^[.,;:!?()\[\]{}"'`]+|[.,;:!?()\[\]{}"'`]+$/g;
|
|
30
31
|
const MIN_PREFIX_LENGTH = 3;
|
|
31
32
|
const MAX_CANDIDATES = 200;
|
|
32
33
|
const CONTEXT_WORDS = 10;
|
|
@@ -236,8 +237,8 @@ const getContextVectorForScoring = textBefore => {
|
|
|
236
237
|
};
|
|
237
238
|
const tokenize = text => {
|
|
238
239
|
const tokens = [];
|
|
239
|
-
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace
|
|
240
|
-
for (const raw of text.toLowerCase().split(/\s+/
|
|
240
|
+
// eslint-disable-next-line require-unicode-regexp, @atlassian/perf-linting/no-expensive-split-replace
|
|
241
|
+
for (const raw of text.toLowerCase().split(/\s+/)) {
|
|
241
242
|
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace
|
|
242
243
|
const clean = raw.replace(PUNCTUATION_BOUNDARY_REGEX, '');
|
|
243
244
|
if (clean.length >= 2) {
|
|
@@ -248,13 +249,15 @@ const tokenize = text => {
|
|
|
248
249
|
};
|
|
249
250
|
const extractPreviousWord = text => {
|
|
250
251
|
// 1. Split the text by newlines or punctuation (. ? !)
|
|
251
|
-
|
|
252
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
253
|
+
const sentences = text.split(/[\n.?!]+/);
|
|
252
254
|
|
|
253
255
|
// 2. Only look at the current sentence/line the user is typing in
|
|
254
256
|
const currentSentence = sentences[sentences.length - 1];
|
|
255
257
|
|
|
256
258
|
// 3. Extract the previous word as normal
|
|
257
|
-
|
|
259
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
260
|
+
const words = currentSentence.trimEnd().split(/\s+/);
|
|
258
261
|
return words.length >= 2 ? words[words.length - 2] : '';
|
|
259
262
|
};
|
|
260
263
|
|
|
@@ -387,7 +390,8 @@ export const predict = textBefore => {
|
|
|
387
390
|
// }
|
|
388
391
|
|
|
389
392
|
// ── Step 2: Prefix completion (≥3 chars typed) ──────────────────────────
|
|
390
|
-
|
|
393
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
394
|
+
if (textBefore.length > 0 && /\s$/.test(textBefore)) {
|
|
391
395
|
return null;
|
|
392
396
|
}
|
|
393
397
|
const trimmed = textBefore.trimEnd();
|
|
@@ -561,14 +565,25 @@ export const predict = textBefore => {
|
|
|
561
565
|
|
|
562
566
|
// ─── Data Loading ────────────────────────────────────────────────────────────
|
|
563
567
|
|
|
564
|
-
const DEFAULT_VECTORS_URL = '/data/word-vectors_10k.bin';
|
|
565
568
|
export const loadVectorsAsync = async options => {
|
|
566
|
-
var _options$vectorsUrl;
|
|
567
569
|
if (vectorStore || vectorsLoadStarted) {
|
|
568
570
|
return;
|
|
569
571
|
}
|
|
572
|
+
if (!(options !== null && options !== void 0 && options.getBinaryUrl)) {
|
|
573
|
+
// eslint-disable-next-line no-console
|
|
574
|
+
console.warn('[text-predictor] loadVectorsAsync called without a getBinaryUrl — vectors will not load. Pass getVectorsBinaryUrl via plugin options.');
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
570
577
|
vectorsLoadStarted = true;
|
|
571
|
-
|
|
578
|
+
let url;
|
|
579
|
+
try {
|
|
580
|
+
url = await options.getBinaryUrl();
|
|
581
|
+
} catch (e) {
|
|
582
|
+
vectorsLoadStarted = false;
|
|
583
|
+
// eslint-disable-next-line no-console
|
|
584
|
+
console.warn('[text-predictor] Failed to resolve vectors URL:', e);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
572
587
|
try {
|
|
573
588
|
const res = await fetch(url);
|
|
574
589
|
if (!res.ok) {
|
|
@@ -207,14 +207,16 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options)
|
|
|
207
207
|
return;
|
|
208
208
|
}
|
|
209
209
|
var lastChar = newText[newText.length - 1];
|
|
210
|
-
|
|
210
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
211
|
+
if (!/[\s.,;:!?]/.test(lastChar)) {
|
|
211
212
|
return;
|
|
212
213
|
}
|
|
213
214
|
|
|
214
215
|
// Only fire if the previous state did not already end on a boundary,
|
|
215
216
|
// so we don't double-count when multiple boundary chars are inserted.
|
|
216
217
|
var prevLastChar = prevText[prevText.length - 1];
|
|
217
|
-
|
|
218
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
219
|
+
if (prevLastChar && /[\s.,;:!?]/.test(prevLastChar)) {
|
|
218
220
|
return;
|
|
219
221
|
}
|
|
220
222
|
var beforeBoundary = newText.slice(0, -1).trimEnd();
|
|
@@ -292,7 +294,9 @@ export var createAutocompletePlugin = function createAutocompletePlugin(options)
|
|
|
292
294
|
},
|
|
293
295
|
focus: function focus() {
|
|
294
296
|
loadDefaultVocabulary();
|
|
295
|
-
loadVectorsAsync(
|
|
297
|
+
loadVectorsAsync({
|
|
298
|
+
getBinaryUrl: options === null || options === void 0 ? void 0 : options.getVectorsBinaryUrl
|
|
299
|
+
}).catch(function () {});
|
|
296
300
|
if (!hasIngestedPage) {
|
|
297
301
|
hasIngestedPage = true;
|
|
298
302
|
if (options !== null && options !== void 0 && options.getContext) {
|
|
@@ -9,9 +9,6 @@ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length)
|
|
|
9
9
|
* when its required data isn't available (cold → warm → full warm).
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
// resolveJsonModule is disabled for this package (see tsconfig.json) to prevent
|
|
13
|
-
// TypeScript from parsing LFS pointer files during CI typecheck. JSON imports
|
|
14
|
-
// are typed via the '*.json' declaration in typings.d.ts.
|
|
15
12
|
import posTagsData from './data/combined_l2_l3_pos_tags.json';
|
|
16
13
|
import ghostPosTagsData from './data/ghost_pos_tags.json';
|
|
17
14
|
import grammarTransitionsData from './data/grammar_transitions_10k.json';
|
|
@@ -18,7 +18,8 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
|
18
18
|
|
|
19
19
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
22
|
+
var WORD_BOUNDARY_CHARS = /[\s.,;:!?]/;
|
|
22
23
|
var DEFAULT_DEBOUNCE_MS = 300;
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -68,6 +69,7 @@ export var createSlowLaneClient = function createSlowLaneClient(config) {
|
|
|
68
69
|
}
|
|
69
70
|
return _context.abrupt("return");
|
|
70
71
|
case 2:
|
|
72
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
71
73
|
url = "".concat(baseUrl.replace(/\/$/, '')).concat(endpoint);
|
|
72
74
|
payload = {
|
|
73
75
|
text: text,
|
|
@@ -34,7 +34,8 @@ import { getStoredContextVector, getStoredLmLogits } from './slow-lane-client';
|
|
|
34
34
|
|
|
35
35
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
38
|
+
var PUNCTUATION_BOUNDARY_REGEX = /^[.,;:!?()\[\]{}"'`]+|[.,;:!?()\[\]{}"'`]+$/g;
|
|
38
39
|
var MIN_PREFIX_LENGTH = 3;
|
|
39
40
|
var MAX_CANDIDATES = 200;
|
|
40
41
|
var CONTEXT_WORDS = 10;
|
|
@@ -308,8 +309,8 @@ var getContextVectorForScoring = function getContextVectorForScoring(textBefore)
|
|
|
308
309
|
};
|
|
309
310
|
var tokenize = function tokenize(text) {
|
|
310
311
|
var tokens = [];
|
|
311
|
-
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace
|
|
312
|
-
var _iterator7 = _createForOfIteratorHelper(text.toLowerCase().split(
|
|
312
|
+
// eslint-disable-next-line require-unicode-regexp, @atlassian/perf-linting/no-expensive-split-replace
|
|
313
|
+
var _iterator7 = _createForOfIteratorHelper(text.toLowerCase().split(/\s+/)),
|
|
313
314
|
_step7;
|
|
314
315
|
try {
|
|
315
316
|
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
@@ -329,13 +330,15 @@ var tokenize = function tokenize(text) {
|
|
|
329
330
|
};
|
|
330
331
|
var extractPreviousWord = function extractPreviousWord(text) {
|
|
331
332
|
// 1. Split the text by newlines or punctuation (. ? !)
|
|
332
|
-
|
|
333
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
334
|
+
var sentences = text.split(/[\n.?!]+/);
|
|
333
335
|
|
|
334
336
|
// 2. Only look at the current sentence/line the user is typing in
|
|
335
337
|
var currentSentence = sentences[sentences.length - 1];
|
|
336
338
|
|
|
337
339
|
// 3. Extract the previous word as normal
|
|
338
|
-
|
|
340
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
341
|
+
var words = currentSentence.trimEnd().split(/\s+/);
|
|
339
342
|
return words.length >= 2 ? words[words.length - 2] : '';
|
|
340
343
|
};
|
|
341
344
|
|
|
@@ -486,7 +489,8 @@ export var predict = function predict(textBefore) {
|
|
|
486
489
|
// }
|
|
487
490
|
|
|
488
491
|
// ── Step 2: Prefix completion (≥3 chars typed) ──────────────────────────
|
|
489
|
-
|
|
492
|
+
// eslint-disable-next-line require-unicode-regexp
|
|
493
|
+
if (textBefore.length > 0 && /\s$/.test(textBefore)) {
|
|
490
494
|
return null;
|
|
491
495
|
}
|
|
492
496
|
var trimmed = textBefore.trimEnd();
|
|
@@ -686,10 +690,8 @@ export var predict = function predict(textBefore) {
|
|
|
686
690
|
|
|
687
691
|
// ─── Data Loading ────────────────────────────────────────────────────────────
|
|
688
692
|
|
|
689
|
-
var DEFAULT_VECTORS_URL = '/data/word-vectors_10k.bin';
|
|
690
693
|
export var loadVectorsAsync = /*#__PURE__*/function () {
|
|
691
694
|
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(options) {
|
|
692
|
-
var _options$vectorsUrl;
|
|
693
695
|
var url, res, buffer, float32, wordIndex, nWords, dim;
|
|
694
696
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
695
697
|
while (1) switch (_context.prev = _context.next) {
|
|
@@ -700,25 +702,47 @@ export var loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
700
702
|
}
|
|
701
703
|
return _context.abrupt("return");
|
|
702
704
|
case 2:
|
|
705
|
+
if (options !== null && options !== void 0 && options.getBinaryUrl) {
|
|
706
|
+
_context.next = 5;
|
|
707
|
+
break;
|
|
708
|
+
}
|
|
709
|
+
// eslint-disable-next-line no-console
|
|
710
|
+
console.warn('[text-predictor] loadVectorsAsync called without a getBinaryUrl — vectors will not load. Pass getVectorsBinaryUrl via plugin options.');
|
|
711
|
+
return _context.abrupt("return");
|
|
712
|
+
case 5:
|
|
703
713
|
vectorsLoadStarted = true;
|
|
704
|
-
|
|
705
|
-
_context.
|
|
706
|
-
|
|
714
|
+
_context.prev = 6;
|
|
715
|
+
_context.next = 9;
|
|
716
|
+
return options.getBinaryUrl();
|
|
717
|
+
case 9:
|
|
718
|
+
url = _context.sent;
|
|
719
|
+
_context.next = 17;
|
|
720
|
+
break;
|
|
721
|
+
case 12:
|
|
722
|
+
_context.prev = 12;
|
|
723
|
+
_context.t0 = _context["catch"](6);
|
|
724
|
+
vectorsLoadStarted = false;
|
|
725
|
+
// eslint-disable-next-line no-console
|
|
726
|
+
console.warn('[text-predictor] Failed to resolve vectors URL:', _context.t0);
|
|
727
|
+
return _context.abrupt("return");
|
|
728
|
+
case 17:
|
|
729
|
+
_context.prev = 17;
|
|
730
|
+
_context.next = 20;
|
|
707
731
|
return fetch(url);
|
|
708
|
-
case
|
|
732
|
+
case 20:
|
|
709
733
|
res = _context.sent;
|
|
710
734
|
if (res.ok) {
|
|
711
|
-
_context.next =
|
|
735
|
+
_context.next = 25;
|
|
712
736
|
break;
|
|
713
737
|
}
|
|
714
738
|
vectorsLoadStarted = false;
|
|
715
739
|
// eslint-disable-next-line no-console
|
|
716
740
|
console.warn("[text-predictor] Failed to load vectors: ".concat(res.status));
|
|
717
741
|
return _context.abrupt("return");
|
|
718
|
-
case
|
|
719
|
-
_context.next =
|
|
742
|
+
case 25:
|
|
743
|
+
_context.next = 27;
|
|
720
744
|
return res.arrayBuffer();
|
|
721
|
-
case
|
|
745
|
+
case 27:
|
|
722
746
|
buffer = _context.sent;
|
|
723
747
|
float32 = new Float32Array(buffer);
|
|
724
748
|
wordIndex = wordIndexData;
|
|
@@ -738,19 +762,19 @@ export var loadVectorsAsync = /*#__PURE__*/function () {
|
|
|
738
762
|
sizeBytes: float32.byteLength
|
|
739
763
|
});
|
|
740
764
|
}
|
|
741
|
-
_context.next =
|
|
765
|
+
_context.next = 41;
|
|
742
766
|
break;
|
|
743
|
-
case
|
|
744
|
-
_context.prev =
|
|
745
|
-
_context.
|
|
767
|
+
case 37:
|
|
768
|
+
_context.prev = 37;
|
|
769
|
+
_context.t1 = _context["catch"](17);
|
|
746
770
|
vectorsLoadStarted = false;
|
|
747
771
|
// eslint-disable-next-line no-console
|
|
748
|
-
console.warn('[text-predictor] Failed to load vectors:', _context.
|
|
749
|
-
case
|
|
772
|
+
console.warn('[text-predictor] Failed to load vectors:', _context.t1);
|
|
773
|
+
case 41:
|
|
750
774
|
case "end":
|
|
751
775
|
return _context.stop();
|
|
752
776
|
}
|
|
753
|
-
}, _callee, null, [[
|
|
777
|
+
}, _callee, null, [[6, 12], [17, 37]]);
|
|
754
778
|
}));
|
|
755
779
|
return function loadVectorsAsync(_x) {
|
|
756
780
|
return _ref4.apply(this, arguments);
|
|
@@ -32,5 +32,11 @@ export interface AutocompletePluginOptions {
|
|
|
32
32
|
* word-frequency boosting. Called lazily so the preset can remain synchronous.
|
|
33
33
|
*/
|
|
34
34
|
getContext?: () => Promise<AutocompleteContext | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* Async function that resolves to a URL for the word vectors binary file.
|
|
37
|
+
* When provided, this takes precedence over the bundled asset URL.
|
|
38
|
+
* Use this to serve vectors from a CDN or media service in production.
|
|
39
|
+
*/
|
|
40
|
+
getVectorsBinaryUrl?: () => Promise<string>;
|
|
35
41
|
}
|
|
36
42
|
export declare const createAutocompletePlugin: (options?: AutocompletePluginOptions) => SafePlugin<AutocompletePluginState>;
|
|
@@ -83,7 +83,7 @@ export declare const incrementSessionFreq: (word: string) => void;
|
|
|
83
83
|
export declare const ingestDocumentPage: (pageContent: string | undefined) => void;
|
|
84
84
|
export declare const predict: (textBefore: string) => string | null;
|
|
85
85
|
export declare const loadVectorsAsync: (options?: {
|
|
86
|
-
|
|
86
|
+
getBinaryUrl?: () => Promise<string>;
|
|
87
87
|
}) => Promise<void>;
|
|
88
88
|
export declare const initVectors: (store: VectorStore) => void;
|
|
89
89
|
export declare const loadDefaultVocabulary: () => void;
|