@unocss/autocomplete 66.5.10 → 66.5.11

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
@@ -1,57 +1,60 @@
1
- import { SuggestResult, AutoCompleteFunction, UnoGenerator } from '@unocss/core';
2
- import { LRUCache } from 'lru-cache';
1
+ import { AutoCompleteFunction, SuggestResult, UnoGenerator } from "@unocss/core";
2
+ import { LRUCache } from "lru-cache";
3
3
 
4
+ //#region src/parse.d.ts
4
5
  declare class AutocompleteParseError extends Error {
5
- readonly template?: string | undefined;
6
- constructor(message: string, template?: string | undefined);
7
- toString(): string;
6
+ readonly template?: string | undefined;
7
+ constructor(message: string, template?: string | undefined);
8
+ toString(): string;
8
9
  }
9
10
  declare const shorthands: Record<string, string>;
10
11
  declare const ignoredThemeKeys: string[];
11
12
  declare function parseAutocomplete(template: string, theme?: any, extraShorthands?: Record<string, string>): ParsedAutocompleteTemplate;
12
-
13
+ //#endregion
14
+ //#region src/types.d.ts
13
15
  type AutoCompleteMatchType = 'prefix' | 'fuzzy';
14
16
  interface AutocompleteOptions {
15
- matchType?: AutoCompleteMatchType;
16
- throwErrors?: boolean;
17
+ matchType?: AutoCompleteMatchType;
18
+ throwErrors?: boolean;
17
19
  }
18
20
  type AutocompleteTemplatePart = AutocompleteTemplateStatic | AutocompleteTemplateGroup | AutocompleteTemplateTheme;
19
21
  interface AutocompleteTemplateStatic {
20
- type: 'static';
21
- value: string;
22
+ type: 'static';
23
+ value: string;
22
24
  }
23
25
  interface AutocompleteTemplateGroup {
24
- type: 'group';
25
- values: string[];
26
+ type: 'group';
27
+ values: string[];
26
28
  }
27
29
  interface AutocompleteTemplateTheme {
28
- type: 'theme';
29
- objects: Record<string, unknown>[];
30
+ type: 'theme';
31
+ objects: Record<string, unknown>[];
30
32
  }
31
33
  interface ParsedAutocompleteTemplate {
32
- parts: AutocompleteTemplatePart[];
33
- suggest: (input: string, matchType?: AutoCompleteMatchType) => string[] | undefined;
34
- errors: AutocompleteParseError[];
34
+ parts: AutocompleteTemplatePart[];
35
+ suggest: (input: string, matchType?: AutoCompleteMatchType) => string[] | undefined;
36
+ errors: AutocompleteParseError[];
35
37
  }
36
38
  interface UnocssAutocomplete {
37
- suggest: (input: string, allowsEmptyInput?: boolean) => Promise<string[]>;
38
- suggestInFile: (content: string, cursor: number) => Promise<SuggestResult | undefined>;
39
- templates: (string | AutoCompleteFunction)[];
40
- cache: LRUCache<string, string[]>;
41
- errorCache: Map<string, AutocompleteParseError[]>;
42
- reset: () => void;
43
- enumerate: () => Promise<Set<string>>;
39
+ suggest: (input: string, allowsEmptyInput?: boolean) => Promise<string[]>;
40
+ suggestInFile: (content: string, cursor: number) => Promise<SuggestResult | undefined>;
41
+ templates: (string | AutoCompleteFunction)[];
42
+ cache: LRUCache<string, string[]>;
43
+ errorCache: Map<string, AutocompleteParseError[]>;
44
+ reset: () => void;
45
+ enumerate: () => Promise<Set<string>>;
44
46
  }
45
-
47
+ //#endregion
48
+ //#region src/create.d.ts
46
49
  declare function createAutocomplete(uno: UnoGenerator, options?: AutocompleteOptions): UnocssAutocomplete;
47
-
50
+ //#endregion
51
+ //#region src/utils.d.ts
48
52
  declare function searchUsageBoundary(line: string, index: number, attributify?: boolean): {
49
- content: string;
50
- start: number;
51
- end: number;
53
+ content: string;
54
+ start: number;
55
+ end: number;
52
56
  } | undefined;
53
57
  declare function searchAttrKey(content: string, cursor: number): string | undefined;
54
58
  declare function cartesian<T>(arr: T[][]): T[][];
55
-
56
- export { AutocompleteParseError, cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
57
- export type { AutoCompleteMatchType, AutocompleteOptions, AutocompleteTemplateGroup, AutocompleteTemplatePart, AutocompleteTemplateStatic, AutocompleteTemplateTheme, ParsedAutocompleteTemplate, UnocssAutocomplete };
59
+ //#endregion
60
+ export { AutoCompleteMatchType, AutocompleteOptions, AutocompleteParseError, AutocompleteTemplateGroup, AutocompleteTemplatePart, AutocompleteTemplateStatic, AutocompleteTemplateTheme, ParsedAutocompleteTemplate, UnocssAutocomplete, cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
package/dist/index.mjs CHANGED
@@ -1,453 +1,394 @@
1
- import { uniq, escapeRegExp, toArray } from '@unocss/core';
2
- import { Fzf, byStartAsc, byLengthAsc } from 'fzf';
3
- import { LRUCache } from 'lru-cache';
1
+ import { escapeRegExp, toArray, uniq } from "@unocss/core";
2
+ import { Fzf, byLengthAsc, byStartAsc } from "fzf";
3
+ import { LRUCache } from "lru-cache";
4
4
 
5
- const name = "@unocss/autocomplete";
5
+ //#region package.json
6
+ var name = "@unocss/autocomplete";
6
7
 
8
+ //#endregion
9
+ //#region src/utils.ts
7
10
  function searchUsageBoundary(line, index, attributify = true) {
8
- let start = index;
9
- let end = index;
10
- const regex = /[^\s>"'`;]/;
11
- while (start && regex.test(line.charAt(start - 1))) --start;
12
- while (end < line.length && regex.test(line.charAt(end))) ++end;
13
- if (attributify) {
14
- return {
15
- content: line.slice(start, end),
16
- start,
17
- end
18
- };
19
- }
20
- let temp = start - 1;
21
- const matchClassText = "class";
22
- const matchClassNameText = "className";
23
- const applyText = "@apply";
24
- while (temp > matchClassText.length && !/[="'{}><@;]/.test(line[temp--])) {
25
- }
26
- if (line[temp + 1] === "@") {
27
- const data = line.slice(temp + 1, temp + applyText.length + 1);
28
- if (data === applyText) {
29
- return {
30
- content: line.slice(start, end),
31
- start,
32
- end
33
- };
34
- }
35
- }
36
- if (line[temp] !== "=")
37
- return;
38
- if (temp > matchClassNameText.length) {
39
- const data = line.slice(temp - matchClassNameText.length, temp);
40
- if (data === matchClassNameText) {
41
- return {
42
- content: line.slice(start, end),
43
- start,
44
- end
45
- };
46
- }
47
- }
48
- if (temp > matchClassText.length) {
49
- const data = line.slice(temp - matchClassText.length, temp);
50
- if (data === matchClassText) {
51
- return {
52
- content: line.slice(start, end),
53
- start,
54
- end
55
- };
56
- }
57
- }
11
+ let start = index;
12
+ let end = index;
13
+ const regex = /[^\s>"'`;]/;
14
+ while (start && regex.test(line.charAt(start - 1))) --start;
15
+ while (end < line.length && regex.test(line.charAt(end))) ++end;
16
+ if (attributify) return {
17
+ content: line.slice(start, end),
18
+ start,
19
+ end
20
+ };
21
+ let temp = start - 1;
22
+ const matchClassText = "class";
23
+ const matchClassNameText = "className";
24
+ const applyText = "@apply";
25
+ while (temp > 5 && !/[="'{}><@;]/.test(line[temp--]));
26
+ if (line[temp + 1] === "@") {
27
+ if (line.slice(temp + 1, temp + 6 + 1) === applyText) return {
28
+ content: line.slice(start, end),
29
+ start,
30
+ end
31
+ };
32
+ }
33
+ if (line[temp] !== "=") return;
34
+ if (temp > 9) {
35
+ if (line.slice(temp - 9, temp) === matchClassNameText) return {
36
+ content: line.slice(start, end),
37
+ start,
38
+ end
39
+ };
40
+ }
41
+ if (temp > 5) {
42
+ if (line.slice(temp - 5, temp) === matchClassText) return {
43
+ content: line.slice(start, end),
44
+ start,
45
+ end
46
+ };
47
+ }
58
48
  }
59
49
  function searchAttrKey(content, cursor) {
60
- const text = content.substring(0, cursor);
61
- if (/<\w[^>]*$/.test(text))
62
- return text.match(/\S+(?=\s*=(?:\s*["'])?[^"']*$)/)?.[0];
50
+ const text = content.substring(0, cursor);
51
+ if (/<\w[^>]*$/.test(text)) return text.match(/\S+(?=\s*=(?:\s*["'])?[^"']*$)/)?.[0];
63
52
  }
64
53
  function cartesian(arr) {
65
- return arr.reduce(
66
- (a, b) => {
67
- const ret = [];
68
- a.forEach((a2) => {
69
- b.forEach((b2) => {
70
- ret.push(a2.concat([b2]));
71
- });
72
- });
73
- return ret;
74
- },
75
- [[]]
76
- );
54
+ return arr.reduce((a, b) => {
55
+ const ret = [];
56
+ a.forEach((a$1) => {
57
+ b.forEach((b$1) => {
58
+ ret.push(a$1.concat([b$1]));
59
+ });
60
+ });
61
+ return ret;
62
+ }, [[]]);
77
63
  }
78
64
 
79
- class AutocompleteParseError extends Error {
80
- constructor(message, template) {
81
- super(message);
82
- this.template = template;
83
- this.name = name;
84
- this.template = template;
85
- }
86
- toString() {
87
- return `\u26A0\uFE0F [${this.name}]: ${this.message}. ${this.template ? `Template: ${this.template}.` : ""}`;
88
- }
89
- }
65
+ //#endregion
66
+ //#region src/parse.ts
67
+ var AutocompleteParseError = class extends Error {
68
+ constructor(message, template) {
69
+ super(message);
70
+ this.template = template;
71
+ this.name = name;
72
+ this.template = template;
73
+ }
74
+ toString() {
75
+ return `⚠️ [${this.name}]: ${this.message}. ${this.template ? `Template: ${this.template}.` : ""}`;
76
+ }
77
+ };
90
78
  const shorthands = {
91
- directions: "(x|y|t|b|l|r|s|e)",
92
- num: `(${[0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 24, 36].join("|")})`,
93
- percent: `(${[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100].join("|")})`,
94
- percentage: `(${["10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"].join("|")})`
79
+ directions: "(x|y|t|b|l|r|s|e)",
80
+ num: `(${[
81
+ 0,
82
+ 1,
83
+ 2,
84
+ 3,
85
+ 4,
86
+ 5,
87
+ 6,
88
+ 8,
89
+ 10,
90
+ 12,
91
+ 24,
92
+ 36
93
+ ].join("|")})`,
94
+ percent: `(${[
95
+ 0,
96
+ 10,
97
+ 20,
98
+ 30,
99
+ 40,
100
+ 50,
101
+ 60,
102
+ 70,
103
+ 80,
104
+ 90,
105
+ 100
106
+ ].join("|")})`,
107
+ percentage: `(${[
108
+ "10%",
109
+ "20%",
110
+ "30%",
111
+ "40%",
112
+ "50%",
113
+ "60%",
114
+ "70%",
115
+ "80%",
116
+ "90%",
117
+ "100%"
118
+ ].join("|")})`
95
119
  };
96
120
  const ignoredThemeKeys = ["DEFAULT"];
97
121
  function handleRegexMatch(str, regex, onMatched, onNotMatched) {
98
- let lastIndex = 0;
99
- Array.from(str.matchAll(regex)).forEach((m) => {
100
- const index = m.index;
101
- if (lastIndex !== index)
102
- onNotMatched(str.slice(lastIndex, index), lastIndex, index);
103
- onMatched(m);
104
- lastIndex = index + m[0].length;
105
- });
106
- if (lastIndex !== str.length)
107
- onNotMatched(str.slice(lastIndex), lastIndex, str.length);
122
+ let lastIndex = 0;
123
+ Array.from(str.matchAll(regex)).forEach((m) => {
124
+ const index = m.index;
125
+ if (lastIndex !== index) onNotMatched(str.slice(lastIndex, index), lastIndex, index);
126
+ onMatched(m);
127
+ lastIndex = index + m[0].length;
128
+ });
129
+ if (lastIndex !== str.length) onNotMatched(str.slice(lastIndex), lastIndex, str.length);
108
130
  }
109
131
  function parseAutocomplete(template, theme = {}, extraShorthands = {}) {
110
- const parts = [];
111
- const errors = [];
112
- const newShorthands = {
113
- ...shorthands,
114
- ...extraShorthands
115
- };
116
- template = template.replace(/<(\w+)>/g, (match, key, _, raw) => {
117
- if (!newShorthands[key]) {
118
- errors.push(new AutocompleteParseError(`Unknown template shorthand: <${key}>`, raw));
119
- return match;
120
- }
121
- return newShorthands[key];
122
- });
123
- handleGroups(template);
124
- if (errors.length) {
125
- parts.length = 0;
126
- }
127
- const fzf = new Fzf(getAllCombination(parts));
128
- return {
129
- parts,
130
- suggest,
131
- errors
132
- };
133
- function handleNonGroup(input) {
134
- handleRegexMatch(
135
- input,
136
- /\$([\w.|]+)/g,
137
- (m) => {
138
- parts.push({
139
- type: "theme",
140
- objects: m[1].split("|").map((i) => {
141
- return i.split(".").reduce((v, k) => {
142
- if (!k || !v[k]) {
143
- errors.push(new AutocompleteParseError(`Invalid theme key: ${k}`, m.input));
144
- return {};
145
- }
146
- return v[k];
147
- }, theme);
148
- })
149
- });
150
- },
151
- (str) => {
152
- parts.push({
153
- type: "static",
154
- value: str
155
- });
156
- }
157
- );
158
- }
159
- function handleGroups(input) {
160
- handleRegexMatch(
161
- input,
162
- /\((.*?)\)/g,
163
- (m) => {
164
- parts.push({
165
- type: "group",
166
- values: m[1].split("|")
167
- });
168
- },
169
- (str) => {
170
- handleNonGroup(str);
171
- }
172
- );
173
- }
174
- function suggest(input, matchType = "prefix") {
175
- if (input.length > 1 && matchType === "fuzzy")
176
- return fzf.find(input).map((i) => i.item);
177
- let rest = input.replace(/-/g, "");
178
- let matched = [""];
179
- let combinations = [""];
180
- const tempParts = [...parts];
181
- while (tempParts.length) {
182
- const part = tempParts.shift();
183
- if (part.type === "static") {
184
- const temp = part.value.replace(/-/g, "");
185
- if (!rest.startsWith(temp) && !part.value.startsWith(rest))
186
- return [""];
187
- matched = matched.map((m) => m + part.value);
188
- rest = rest.slice(temp.length);
189
- } else if (part.type === "group") {
190
- const fullMatched = part.values.find((i) => i && rest.startsWith(i));
191
- if (fullMatched) {
192
- matched = matched.map((m) => m + fullMatched);
193
- rest = rest.slice(fullMatched.length);
194
- if (!tempParts[0] && rest)
195
- return [];
196
- continue;
197
- } else {
198
- if (tempParts[0]) {
199
- const values = part.values.filter((i) => i && i.startsWith(rest));
200
- rest = "";
201
- if (values.length) {
202
- matched = matched.map((m) => values.map((n) => m + n)).flat();
203
- continue;
204
- }
205
- break;
206
- }
207
- if (matched[0] === "")
208
- break;
209
- combinations = part.values.filter((p) => p.startsWith(rest));
210
- break;
211
- }
212
- } else if (part.type === "theme") {
213
- const keys = part.objects.flatMap((i) => Object.keys(i)).filter((i) => i && !ignoredThemeKeys.includes(i) && i[0] !== "_");
214
- const fullMatched = keys.find((i) => i && rest.startsWith(i));
215
- if (fullMatched != null) {
216
- rest = rest.slice(fullMatched.length);
217
- const subObjects = part.objects.map((i) => i[fullMatched]).filter((i) => !!i && typeof i === "object");
218
- if (subObjects.length) {
219
- matched = matched.map((m) => `${m + fullMatched}-`);
220
- tempParts.unshift({
221
- type: "theme",
222
- objects: subObjects
223
- });
224
- } else {
225
- combinations = keys.filter((i) => i.startsWith(rest));
226
- }
227
- } else {
228
- if (tempParts[0] && tempParts[0].type !== "static") {
229
- const values = tempParts[0].values;
230
- if (values)
231
- matched = matched.filter((i) => i && rest.startsWith(i)).map((m) => values.map((n) => m + n)).flat();
232
- } else {
233
- combinations = keys.filter((i) => i.startsWith(rest));
234
- }
235
- break;
236
- }
237
- }
238
- }
239
- return combinations.map((i) => matched.map((m) => m + i)).flat().filter((i) => i.length >= input.length);
240
- }
132
+ const parts = [];
133
+ const errors = [];
134
+ const newShorthands = {
135
+ ...shorthands,
136
+ ...extraShorthands
137
+ };
138
+ template = template.replace(/<(\w+)>/g, (match, key, _, raw) => {
139
+ if (!newShorthands[key]) {
140
+ errors.push(new AutocompleteParseError(`Unknown template shorthand: <${key}>`, raw));
141
+ return match;
142
+ }
143
+ return newShorthands[key];
144
+ });
145
+ handleGroups(template);
146
+ if (errors.length) parts.length = 0;
147
+ const fzf = new Fzf(getAllCombination(parts));
148
+ return {
149
+ parts,
150
+ suggest,
151
+ errors
152
+ };
153
+ function handleNonGroup(input) {
154
+ handleRegexMatch(input, /\$([\w.|]+)/g, (m) => {
155
+ parts.push({
156
+ type: "theme",
157
+ objects: m[1].split("|").map((i) => {
158
+ return i.split(".").reduce((v, k) => {
159
+ if (!k || !v[k]) {
160
+ errors.push(new AutocompleteParseError(`Invalid theme key: ${k}`, m.input));
161
+ return {};
162
+ }
163
+ return v[k];
164
+ }, theme);
165
+ })
166
+ });
167
+ }, (str) => {
168
+ parts.push({
169
+ type: "static",
170
+ value: str
171
+ });
172
+ });
173
+ }
174
+ function handleGroups(input) {
175
+ handleRegexMatch(input, /\((.*?)\)/g, (m) => {
176
+ parts.push({
177
+ type: "group",
178
+ values: m[1].split("|")
179
+ });
180
+ }, (str) => {
181
+ handleNonGroup(str);
182
+ });
183
+ }
184
+ function suggest(input, matchType = "prefix") {
185
+ if (input.length > 1 && matchType === "fuzzy") return fzf.find(input).map((i) => i.item);
186
+ let rest = input.replace(/-/g, "");
187
+ let matched = [""];
188
+ let combinations = [""];
189
+ const tempParts = [...parts];
190
+ while (tempParts.length) {
191
+ const part = tempParts.shift();
192
+ if (part.type === "static") {
193
+ const temp = part.value.replace(/-/g, "");
194
+ if (!rest.startsWith(temp) && !part.value.startsWith(rest)) return [""];
195
+ matched = matched.map((m) => m + part.value);
196
+ rest = rest.slice(temp.length);
197
+ } else if (part.type === "group") {
198
+ const fullMatched = part.values.find((i) => i && rest.startsWith(i));
199
+ if (fullMatched) {
200
+ matched = matched.map((m) => m + fullMatched);
201
+ rest = rest.slice(fullMatched.length);
202
+ if (!tempParts[0] && rest) return [];
203
+ continue;
204
+ } else {
205
+ if (tempParts[0]) {
206
+ const values = part.values.filter((i) => i && i.startsWith(rest));
207
+ rest = "";
208
+ if (values.length) {
209
+ matched = matched.map((m) => values.map((n) => m + n)).flat();
210
+ continue;
211
+ }
212
+ break;
213
+ }
214
+ if (matched[0] === "") break;
215
+ combinations = part.values.filter((p) => p.startsWith(rest));
216
+ break;
217
+ }
218
+ } else if (part.type === "theme") {
219
+ const keys = part.objects.flatMap((i) => Object.keys(i)).filter((i) => i && !ignoredThemeKeys.includes(i) && i[0] !== "_");
220
+ const fullMatched = keys.find((i) => i && rest.startsWith(i));
221
+ if (fullMatched != null) {
222
+ rest = rest.slice(fullMatched.length);
223
+ const subObjects = part.objects.map((i) => i[fullMatched]).filter((i) => !!i && typeof i === "object");
224
+ if (subObjects.length) {
225
+ matched = matched.map((m) => `${m + fullMatched}-`);
226
+ tempParts.unshift({
227
+ type: "theme",
228
+ objects: subObjects
229
+ });
230
+ } else combinations = keys.filter((i) => i.startsWith(rest));
231
+ } else {
232
+ if (tempParts[0] && tempParts[0].type !== "static") {
233
+ const values = tempParts[0].values;
234
+ if (values) matched = matched.filter((i) => i && rest.startsWith(i)).map((m) => values.map((n) => m + n)).flat();
235
+ } else combinations = keys.filter((i) => i.startsWith(rest));
236
+ break;
237
+ }
238
+ }
239
+ }
240
+ return combinations.map((i) => matched.map((m) => m + i)).flat().filter((i) => i.length >= input.length);
241
+ }
241
242
  }
242
243
  function getValuesFromPartTemplate(part) {
243
- if (part.type === "static")
244
- return [part.value];
245
- if (part.type === "theme") {
246
- return part.objects.flatMap((i) => {
247
- const keys = Object.keys(i).filter((i2) => i2 && i2[0] !== "_");
248
- for (const key in i) {
249
- const value = i[key];
250
- if (value === null || value === void 0)
251
- continue;
252
- if (typeof value === "object" && !Array.isArray(value)) {
253
- const subKeys = getValuesFromPartTemplate({
254
- type: "theme",
255
- objects: [value]
256
- }).map((i2) => `${key}-${i2}`);
257
- keys.push(...subKeys);
258
- }
259
- }
260
- return keys;
261
- });
262
- }
263
- if (part.type === "group")
264
- return [...part.values];
265
- return [];
244
+ if (part.type === "static") return [part.value];
245
+ if (part.type === "theme") return part.objects.flatMap((i) => {
246
+ const keys = Object.keys(i).filter((i$1) => i$1 && i$1[0] !== "_");
247
+ for (const key in i) {
248
+ const value = i[key];
249
+ if (value === null || value === void 0) continue;
250
+ if (typeof value === "object" && !Array.isArray(value)) {
251
+ const subKeys = getValuesFromPartTemplate({
252
+ type: "theme",
253
+ objects: [value]
254
+ }).map((i$1) => `${key}-${i$1}`);
255
+ keys.push(...subKeys);
256
+ }
257
+ }
258
+ return keys;
259
+ });
260
+ if (part.type === "group") return [...part.values];
261
+ return [];
266
262
  }
267
263
  function getAllCombination(parts) {
268
- const values = parts.map((i) => getValuesFromPartTemplate(i));
269
- const list = uniq(cartesian(values).flatMap((i) => i.join("").replace("-DEFAULT", "")));
270
- return list;
264
+ return uniq(cartesian(parts.map((i) => getValuesFromPartTemplate(i))).flatMap((i) => i.join("").replace("-DEFAULT", "")));
271
265
  }
272
266
 
267
+ //#endregion
268
+ //#region src/create.ts
273
269
  function createAutocomplete(uno, options = {}) {
274
- const templateCache = /* @__PURE__ */ new Map();
275
- const cache = new LRUCache({ max: 5e3 });
276
- const errorCache = /* @__PURE__ */ new Map();
277
- let staticUtils = [];
278
- const templates = [];
279
- const {
280
- matchType = "prefix",
281
- throwErrors = true
282
- } = options;
283
- reset();
284
- return {
285
- suggest,
286
- suggestInFile,
287
- templates,
288
- cache,
289
- errorCache,
290
- reset,
291
- /**
292
- * Enumerate possible suggestions from 'aa' - 'zz'
293
- */
294
- enumerate
295
- };
296
- async function enumerate() {
297
- const matched = /* @__PURE__ */ new Set();
298
- const a2z = Array.from("abcdefghijklmnopqrstuvwxyz");
299
- const a2zd = [...a2z, "-"];
300
- const keys = a2z.flatMap((i) => [
301
- i,
302
- ...a2zd.map((j) => `${i}${j}`)
303
- ]);
304
- await Promise.all(
305
- keys.map((key) => suggest(key).then((i) => i.forEach((j) => matched.add(j))))
306
- );
307
- await Promise.all(
308
- [...matched].filter((i) => /^\w+$/.test(i) && i.length > 3).map((i) => suggest(`${i}-`).then((i2) => i2.forEach((j) => matched.add(j))))
309
- );
310
- return matched;
311
- }
312
- async function suggest(input, allowsEmptyInput = false) {
313
- if (!allowsEmptyInput && input.length < 1)
314
- return [];
315
- if (cache.has(input))
316
- return cache.get(input);
317
- const attributify = uno.config.presets.find((i) => i.name === "@unocss/preset-attributify");
318
- const attributifyPrefix = attributify?.options?.prefix;
319
- const _input = attributifyPrefix ? input.startsWith(attributifyPrefix) ? input.slice(attributifyPrefix.length) : input.replace(`:${attributifyPrefix}`, ":") : input;
320
- const matched = await uno.matchVariants(_input);
321
- let result = (await Promise.all(matched.map(async ([, processed]) => {
322
- let idx = processed ? input.search(escapeRegExp(processed)) : input.length;
323
- if (idx === -1)
324
- idx = 0;
325
- const variantPrefix = input.slice(0, idx);
326
- const variantSuffix = input.slice(idx + input.length);
327
- const result2 = processSuggestions(
328
- await Promise.all([
329
- suggestSelf(processed),
330
- suggestStatic(processed),
331
- suggestUnoCache(processed),
332
- suggestFromTemplates(processed)
333
- ]),
334
- variantPrefix,
335
- variantSuffix
336
- );
337
- return result2;
338
- }))).flat();
339
- if (matchType === "fuzzy") {
340
- const fzf = new Fzf(result, {
341
- tiebreakers: [byStartAsc, byLengthAsc]
342
- });
343
- result = fzf.find(input).map((i) => i.item);
344
- }
345
- cache.set(input, result);
346
- return result;
347
- }
348
- async function suggestInFile(content, cursor) {
349
- const isInsideAttrValue = searchAttrKey(content, cursor) !== void 0;
350
- const byExtractor = await searchUsageByExtractor(content, cursor);
351
- if (byExtractor) {
352
- const suggestions2 = await suggest(byExtractor.extracted, isInsideAttrValue);
353
- const formatted = byExtractor.transformSuggestions ? byExtractor.transformSuggestions(suggestions2) : suggestions2;
354
- return {
355
- suggestions: suggestions2.map((v, i) => [v, formatted[i]]),
356
- resolveReplacement: byExtractor.resolveReplacement
357
- };
358
- }
359
- const regular = searchUsageBoundary(
360
- content,
361
- cursor,
362
- (uno.config.presets || []).some((i) => i.name === "@unocss/preset-attributify")
363
- );
364
- if (!regular)
365
- return;
366
- const suggestions = await suggest(regular.content, isInsideAttrValue);
367
- return {
368
- suggestions: suggestions.map((v) => [v, v]),
369
- resolveReplacement: (suggestion) => ({
370
- start: regular.start,
371
- end: regular.end,
372
- replacement: suggestion
373
- })
374
- };
375
- }
376
- async function searchUsageByExtractor(content, cursor) {
377
- if (!uno.config.autocomplete.extractors.length)
378
- return null;
379
- for (const extractor of uno.config.autocomplete.extractors) {
380
- const res = await extractor.extract({ content, cursor });
381
- if (res)
382
- return res;
383
- }
384
- return null;
385
- }
386
- async function suggestSelf(input) {
387
- const i = await uno.parseToken(input, "-");
388
- return i ? [input] : [];
389
- }
390
- async function suggestStatic(input) {
391
- if (matchType === "fuzzy")
392
- return staticUtils;
393
- return staticUtils.filter((i) => i.startsWith(input));
394
- }
395
- async function suggestUnoCache(input) {
396
- const keys = Array.from(uno.cache.entries());
397
- return keys.filter((i) => i[1] && i[0].startsWith(input)).map((i) => i[0]);
398
- }
399
- async function suggestFromTemplates(input) {
400
- const ps = await Promise.allSettled([
401
- Array.from(templateCache.values()).flatMap(({ suggest: suggest2 }) => suggest2(input, matchType) ?? []),
402
- ...templates.filter((fn) => typeof fn === "function").map((fn) => fn(input))
403
- ]);
404
- return ps.flatMap((i) => i.status === "fulfilled" ? i.value : []);
405
- }
406
- function reset() {
407
- templateCache.clear();
408
- cache.clear();
409
- errorCache.clear();
410
- staticUtils = [
411
- ...Object.keys(uno.config.rulesStaticMap),
412
- ...uno.config.shortcuts.filter((i) => typeof i[0] === "string").map((i) => i[0])
413
- ];
414
- templates.length = 0;
415
- templates.push(
416
- ...uno.config.autocomplete.templates || [],
417
- ...uno.config.rulesDynamic.flatMap((i) => toArray(i?.[2]?.autocomplete || [])),
418
- ...uno.config.shortcuts.flatMap((i) => toArray(i?.[2]?.autocomplete || [])),
419
- ...uno.config.variants.flatMap((v) => toArray(v.autocomplete || []))
420
- );
421
- for (const template of templates) {
422
- if (typeof template !== "function") {
423
- if (templateCache.has(template) || errorCache.has(template)) {
424
- continue;
425
- }
426
- const parsed = parseAutocomplete(template, uno.config.theme, uno.config.autocomplete.shorthands);
427
- if (parsed.errors.length) {
428
- errorCache.set(template, parsed.errors);
429
- }
430
- templateCache.set(template, parsed);
431
- }
432
- }
433
- if (errorCache.size && throwErrors) {
434
- const message = Array.from(errorCache.values()).flat().map((error) => error.toString()).join("\n");
435
- throw new Error(message);
436
- }
437
- }
438
- function processSuggestions(suggestions, prefix = "", suffix = "") {
439
- return uniq(suggestions.flat()).filter((i) => !!(i && !i.endsWith("-") && !uno.isBlocked(i))).sort((a, b) => {
440
- if (/\d/.test(a) && /\D/.test(b))
441
- return 1;
442
- if (/\D/.test(a) && /\d/.test(b))
443
- return -1;
444
- const numA = +(a.match(/\d+$/)?.[0] || Number.NaN);
445
- const numB = +(b.match(/\d+$/)?.[0] || Number.NaN);
446
- if (!Number.isNaN(numA) && !Number.isNaN(numB))
447
- return numA - numB;
448
- return a.localeCompare(b);
449
- }).map((i) => prefix + i + suffix);
450
- }
270
+ const templateCache = /* @__PURE__ */ new Map();
271
+ const cache = new LRUCache({ max: 5e3 });
272
+ const errorCache = /* @__PURE__ */ new Map();
273
+ let staticUtils = [];
274
+ const templates = [];
275
+ const { matchType = "prefix", throwErrors = true } = options;
276
+ reset();
277
+ return {
278
+ suggest,
279
+ suggestInFile,
280
+ templates,
281
+ cache,
282
+ errorCache,
283
+ reset,
284
+ enumerate
285
+ };
286
+ async function enumerate() {
287
+ const matched = /* @__PURE__ */ new Set();
288
+ const a2z = Array.from("abcdefghijklmnopqrstuvwxyz");
289
+ const a2zd = [...a2z, "-"];
290
+ const keys = a2z.flatMap((i) => [i, ...a2zd.map((j) => `${i}${j}`)]);
291
+ await Promise.all(keys.map((key) => suggest(key).then((i) => i.forEach((j) => matched.add(j)))));
292
+ await Promise.all([...matched].filter((i) => /^\w+$/.test(i) && i.length > 3).map((i) => suggest(`${i}-`).then((i$1) => i$1.forEach((j) => matched.add(j)))));
293
+ return matched;
294
+ }
295
+ async function suggest(input, allowsEmptyInput = false) {
296
+ if (!allowsEmptyInput && input.length < 1) return [];
297
+ if (cache.has(input)) return cache.get(input);
298
+ const attributifyPrefix = uno.config.presets.find((i) => i.name === "@unocss/preset-attributify")?.options?.prefix;
299
+ const _input = attributifyPrefix ? input.startsWith(attributifyPrefix) ? input.slice(attributifyPrefix.length) : input.replace(`:${attributifyPrefix}`, ":") : input;
300
+ const matched = await uno.matchVariants(_input);
301
+ let result = (await Promise.all(matched.map(async ([, processed]) => {
302
+ let idx = processed ? input.search(escapeRegExp(processed)) : input.length;
303
+ if (idx === -1) idx = 0;
304
+ const variantPrefix = input.slice(0, idx);
305
+ const variantSuffix = input.slice(idx + input.length);
306
+ return processSuggestions(await Promise.all([
307
+ suggestSelf(processed),
308
+ suggestStatic(processed),
309
+ suggestUnoCache(processed),
310
+ suggestFromTemplates(processed)
311
+ ]), variantPrefix, variantSuffix);
312
+ }))).flat();
313
+ if (matchType === "fuzzy") result = new Fzf(result, { tiebreakers: [byStartAsc, byLengthAsc] }).find(input).map((i) => i.item);
314
+ cache.set(input, result);
315
+ return result;
316
+ }
317
+ async function suggestInFile(content, cursor) {
318
+ const isInsideAttrValue = searchAttrKey(content, cursor) !== void 0;
319
+ const byExtractor = await searchUsageByExtractor(content, cursor);
320
+ if (byExtractor) {
321
+ const suggestions = await suggest(byExtractor.extracted, isInsideAttrValue);
322
+ const formatted = byExtractor.transformSuggestions ? byExtractor.transformSuggestions(suggestions) : suggestions;
323
+ return {
324
+ suggestions: suggestions.map((v, i) => [v, formatted[i]]),
325
+ resolveReplacement: byExtractor.resolveReplacement
326
+ };
327
+ }
328
+ const regular = searchUsageBoundary(content, cursor, (uno.config.presets || []).some((i) => i.name === "@unocss/preset-attributify"));
329
+ if (!regular) return;
330
+ return {
331
+ suggestions: (await suggest(regular.content, isInsideAttrValue)).map((v) => [v, v]),
332
+ resolveReplacement: (suggestion) => ({
333
+ start: regular.start,
334
+ end: regular.end,
335
+ replacement: suggestion
336
+ })
337
+ };
338
+ }
339
+ async function searchUsageByExtractor(content, cursor) {
340
+ if (!uno.config.autocomplete.extractors.length) return null;
341
+ for (const extractor of uno.config.autocomplete.extractors) {
342
+ const res = await extractor.extract({
343
+ content,
344
+ cursor
345
+ });
346
+ if (res) return res;
347
+ }
348
+ return null;
349
+ }
350
+ async function suggestSelf(input) {
351
+ return await uno.parseToken(input, "-") ? [input] : [];
352
+ }
353
+ async function suggestStatic(input) {
354
+ if (matchType === "fuzzy") return staticUtils;
355
+ return staticUtils.filter((i) => i.startsWith(input));
356
+ }
357
+ async function suggestUnoCache(input) {
358
+ return Array.from(uno.cache.entries()).filter((i) => i[1] && i[0].startsWith(input)).map((i) => i[0]);
359
+ }
360
+ async function suggestFromTemplates(input) {
361
+ return (await Promise.allSettled([Array.from(templateCache.values()).flatMap(({ suggest: suggest$1 }) => suggest$1(input, matchType) ?? []), ...templates.filter((fn) => typeof fn === "function").map((fn) => fn(input))])).flatMap((i) => i.status === "fulfilled" ? i.value : []);
362
+ }
363
+ function reset() {
364
+ templateCache.clear();
365
+ cache.clear();
366
+ errorCache.clear();
367
+ staticUtils = [...Object.keys(uno.config.rulesStaticMap), ...uno.config.shortcuts.filter((i) => typeof i[0] === "string").map((i) => i[0])];
368
+ templates.length = 0;
369
+ templates.push(...uno.config.autocomplete.templates || [], ...uno.config.rulesDynamic.flatMap((i) => toArray(i?.[2]?.autocomplete || [])), ...uno.config.shortcuts.flatMap((i) => toArray(i?.[2]?.autocomplete || [])), ...uno.config.variants.flatMap((v) => toArray(v.autocomplete || [])));
370
+ for (const template of templates) if (typeof template !== "function") {
371
+ if (templateCache.has(template) || errorCache.has(template)) continue;
372
+ const parsed = parseAutocomplete(template, uno.config.theme, uno.config.autocomplete.shorthands);
373
+ if (parsed.errors.length) errorCache.set(template, parsed.errors);
374
+ templateCache.set(template, parsed);
375
+ }
376
+ if (errorCache.size && throwErrors) {
377
+ const message = Array.from(errorCache.values()).flat().map((error) => error.toString()).join("\n");
378
+ throw new Error(message);
379
+ }
380
+ }
381
+ function processSuggestions(suggestions, prefix = "", suffix = "") {
382
+ return uniq(suggestions.flat()).filter((i) => !!(i && !i.endsWith("-") && !uno.isBlocked(i))).sort((a, b) => {
383
+ if (/\d/.test(a) && /\D/.test(b)) return 1;
384
+ if (/\D/.test(a) && /\d/.test(b)) return -1;
385
+ const numA = +(a.match(/\d+$/)?.[0] || NaN);
386
+ const numB = +(b.match(/\d+$/)?.[0] || NaN);
387
+ if (!Number.isNaN(numA) && !Number.isNaN(numB)) return numA - numB;
388
+ return a.localeCompare(b);
389
+ }).map((i) => prefix + i + suffix);
390
+ }
451
391
  }
452
392
 
453
- export { AutocompleteParseError, cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
393
+ //#endregion
394
+ export { AutocompleteParseError, cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unocss/autocomplete",
3
3
  "type": "module",
4
- "version": "66.5.10",
4
+ "version": "66.5.11",
5
5
  "description": "Autocomplete utils for UnoCSS",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -28,20 +28,19 @@
28
28
  },
29
29
  "main": "./dist/index.mjs",
30
30
  "module": "./dist/index.mjs",
31
- "types": "./dist/index.d.ts",
31
+ "types": "./dist/index.d.mts",
32
32
  "files": [
33
33
  "dist"
34
34
  ],
35
35
  "dependencies": {
36
36
  "fzf": "^0.5.2",
37
- "lru-cache": "^11.2.2"
37
+ "lru-cache": "^11.2.4"
38
38
  },
39
39
  "devDependencies": {
40
- "@unocss/core": "66.5.10"
40
+ "@unocss/core": "66.5.11"
41
41
  },
42
42
  "scripts": {
43
- "build": "unbuild",
44
- "stub": "unbuild --stub",
45
- "test:attw": "attw --pack --config-path ../../.attw-esm-only.json"
43
+ "build": "tsdown --config-loader unrun",
44
+ "dev": "tsdown --config-loader unrun --watch"
46
45
  }
47
46
  }
package/dist/index.d.ts DELETED
@@ -1,57 +0,0 @@
1
- import { SuggestResult, AutoCompleteFunction, UnoGenerator } from '@unocss/core';
2
- import { LRUCache } from 'lru-cache';
3
-
4
- declare class AutocompleteParseError extends Error {
5
- readonly template?: string | undefined;
6
- constructor(message: string, template?: string | undefined);
7
- toString(): string;
8
- }
9
- declare const shorthands: Record<string, string>;
10
- declare const ignoredThemeKeys: string[];
11
- declare function parseAutocomplete(template: string, theme?: any, extraShorthands?: Record<string, string>): ParsedAutocompleteTemplate;
12
-
13
- type AutoCompleteMatchType = 'prefix' | 'fuzzy';
14
- interface AutocompleteOptions {
15
- matchType?: AutoCompleteMatchType;
16
- throwErrors?: boolean;
17
- }
18
- type AutocompleteTemplatePart = AutocompleteTemplateStatic | AutocompleteTemplateGroup | AutocompleteTemplateTheme;
19
- interface AutocompleteTemplateStatic {
20
- type: 'static';
21
- value: string;
22
- }
23
- interface AutocompleteTemplateGroup {
24
- type: 'group';
25
- values: string[];
26
- }
27
- interface AutocompleteTemplateTheme {
28
- type: 'theme';
29
- objects: Record<string, unknown>[];
30
- }
31
- interface ParsedAutocompleteTemplate {
32
- parts: AutocompleteTemplatePart[];
33
- suggest: (input: string, matchType?: AutoCompleteMatchType) => string[] | undefined;
34
- errors: AutocompleteParseError[];
35
- }
36
- interface UnocssAutocomplete {
37
- suggest: (input: string, allowsEmptyInput?: boolean) => Promise<string[]>;
38
- suggestInFile: (content: string, cursor: number) => Promise<SuggestResult | undefined>;
39
- templates: (string | AutoCompleteFunction)[];
40
- cache: LRUCache<string, string[]>;
41
- errorCache: Map<string, AutocompleteParseError[]>;
42
- reset: () => void;
43
- enumerate: () => Promise<Set<string>>;
44
- }
45
-
46
- declare function createAutocomplete(uno: UnoGenerator, options?: AutocompleteOptions): UnocssAutocomplete;
47
-
48
- declare function searchUsageBoundary(line: string, index: number, attributify?: boolean): {
49
- content: string;
50
- start: number;
51
- end: number;
52
- } | undefined;
53
- declare function searchAttrKey(content: string, cursor: number): string | undefined;
54
- declare function cartesian<T>(arr: T[][]): T[][];
55
-
56
- export { AutocompleteParseError, cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
57
- export type { AutoCompleteMatchType, AutocompleteOptions, AutocompleteTemplateGroup, AutocompleteTemplatePart, AutocompleteTemplateStatic, AutocompleteTemplateTheme, ParsedAutocompleteTemplate, UnocssAutocomplete };