@unocss/autocomplete 66.5.10 → 66.5.12
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 +35 -32
- package/dist/index.mjs +370 -429
- package/package.json +6 -7
- package/dist/index.d.ts +0 -57
package/dist/index.d.mts
CHANGED
|
@@ -1,57 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LRUCache } from
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
+
matchType?: AutoCompleteMatchType;
|
|
18
|
+
throwErrors?: boolean;
|
|
17
19
|
}
|
|
18
20
|
type AutocompleteTemplatePart = AutocompleteTemplateStatic | AutocompleteTemplateGroup | AutocompleteTemplateTheme;
|
|
19
21
|
interface AutocompleteTemplateStatic {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
type: 'static';
|
|
23
|
+
value: string;
|
|
22
24
|
}
|
|
23
25
|
interface AutocompleteTemplateGroup {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
type: 'group';
|
|
27
|
+
values: string[];
|
|
26
28
|
}
|
|
27
29
|
interface AutocompleteTemplateTheme {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
type: 'theme';
|
|
31
|
+
objects: Record<string, unknown>[];
|
|
30
32
|
}
|
|
31
33
|
interface ParsedAutocompleteTemplate {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
parts: AutocompleteTemplatePart[];
|
|
35
|
+
suggest: (input: string, matchType?: AutoCompleteMatchType) => string[] | undefined;
|
|
36
|
+
errors: AutocompleteParseError[];
|
|
35
37
|
}
|
|
36
38
|
interface UnocssAutocomplete {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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 {
|
|
2
|
-
import { Fzf,
|
|
3
|
-
import { LRUCache } from
|
|
1
|
+
import { escapeRegExp, toArray, uniq } from "@unocss/core";
|
|
2
|
+
import { Fzf, byLengthAsc, byStartAsc } from "fzf";
|
|
3
|
+
import { LRUCache } from "lru-cache";
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
61
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
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
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
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.
|
|
4
|
+
"version": "66.5.12",
|
|
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.
|
|
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.
|
|
37
|
+
"lru-cache": "^11.2.4"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@unocss/core": "66.5.
|
|
40
|
+
"@unocss/core": "66.5.12"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
|
-
"build": "
|
|
44
|
-
"
|
|
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 };
|