@unocss/autocomplete 66.4.1 → 66.5.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/dist/index.d.mts CHANGED
@@ -1,9 +1,19 @@
1
1
  import { SuggestResult, AutoCompleteFunction, UnoGenerator } from '@unocss/core';
2
2
  import { LRUCache } from 'lru-cache';
3
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
+
4
13
  type AutoCompleteMatchType = 'prefix' | 'fuzzy';
5
14
  interface AutocompleteOptions {
6
15
  matchType?: AutoCompleteMatchType;
16
+ throwErrors?: boolean;
7
17
  }
8
18
  type AutocompleteTemplatePart = AutocompleteTemplateStatic | AutocompleteTemplateGroup | AutocompleteTemplateTheme;
9
19
  interface AutocompleteTemplateStatic {
@@ -21,21 +31,19 @@ interface AutocompleteTemplateTheme {
21
31
  interface ParsedAutocompleteTemplate {
22
32
  parts: AutocompleteTemplatePart[];
23
33
  suggest: (input: string, matchType?: AutoCompleteMatchType) => string[] | undefined;
34
+ errors: AutocompleteParseError[];
24
35
  }
25
36
  interface UnocssAutocomplete {
26
37
  suggest: (input: string, allowsEmptyInput?: boolean) => Promise<string[]>;
27
38
  suggestInFile: (content: string, cursor: number) => Promise<SuggestResult | undefined>;
28
39
  templates: (string | AutoCompleteFunction)[];
29
40
  cache: LRUCache<string, string[]>;
30
- reset: () => Promise<void>;
41
+ errorCache: Map<string, AutocompleteParseError[]>;
42
+ reset: () => void;
31
43
  enumerate: () => Promise<Set<string>>;
32
44
  }
33
45
 
34
- declare function createAutocomplete(_uno: UnoGenerator | Promise<UnoGenerator>, options?: AutocompleteOptions): UnocssAutocomplete;
35
-
36
- declare const shorthands: Record<string, string>;
37
- declare const ignoredThemeKeys: string[];
38
- declare function parseAutocomplete(template: string, theme?: any, extraShorthands?: Record<string, string>): ParsedAutocompleteTemplate;
46
+ declare function createAutocomplete(uno: UnoGenerator, options?: AutocompleteOptions): UnocssAutocomplete;
39
47
 
40
48
  declare function searchUsageBoundary(line: string, index: number, attributify?: boolean): {
41
49
  content: string;
@@ -45,5 +53,5 @@ declare function searchUsageBoundary(line: string, index: number, attributify?:
45
53
  declare function searchAttrKey(content: string, cursor: number): string | undefined;
46
54
  declare function cartesian<T>(arr: T[][]): T[][];
47
55
 
48
- export { cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
56
+ export { AutocompleteParseError, cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
49
57
  export type { AutoCompleteMatchType, AutocompleteOptions, AutocompleteTemplateGroup, AutocompleteTemplatePart, AutocompleteTemplateStatic, AutocompleteTemplateTheme, ParsedAutocompleteTemplate, UnocssAutocomplete };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,19 @@
1
1
  import { SuggestResult, AutoCompleteFunction, UnoGenerator } from '@unocss/core';
2
2
  import { LRUCache } from 'lru-cache';
3
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
+
4
13
  type AutoCompleteMatchType = 'prefix' | 'fuzzy';
5
14
  interface AutocompleteOptions {
6
15
  matchType?: AutoCompleteMatchType;
16
+ throwErrors?: boolean;
7
17
  }
8
18
  type AutocompleteTemplatePart = AutocompleteTemplateStatic | AutocompleteTemplateGroup | AutocompleteTemplateTheme;
9
19
  interface AutocompleteTemplateStatic {
@@ -21,21 +31,19 @@ interface AutocompleteTemplateTheme {
21
31
  interface ParsedAutocompleteTemplate {
22
32
  parts: AutocompleteTemplatePart[];
23
33
  suggest: (input: string, matchType?: AutoCompleteMatchType) => string[] | undefined;
34
+ errors: AutocompleteParseError[];
24
35
  }
25
36
  interface UnocssAutocomplete {
26
37
  suggest: (input: string, allowsEmptyInput?: boolean) => Promise<string[]>;
27
38
  suggestInFile: (content: string, cursor: number) => Promise<SuggestResult | undefined>;
28
39
  templates: (string | AutoCompleteFunction)[];
29
40
  cache: LRUCache<string, string[]>;
30
- reset: () => Promise<void>;
41
+ errorCache: Map<string, AutocompleteParseError[]>;
42
+ reset: () => void;
31
43
  enumerate: () => Promise<Set<string>>;
32
44
  }
33
45
 
34
- declare function createAutocomplete(_uno: UnoGenerator | Promise<UnoGenerator>, options?: AutocompleteOptions): UnocssAutocomplete;
35
-
36
- declare const shorthands: Record<string, string>;
37
- declare const ignoredThemeKeys: string[];
38
- declare function parseAutocomplete(template: string, theme?: any, extraShorthands?: Record<string, string>): ParsedAutocompleteTemplate;
46
+ declare function createAutocomplete(uno: UnoGenerator, options?: AutocompleteOptions): UnocssAutocomplete;
39
47
 
40
48
  declare function searchUsageBoundary(line: string, index: number, attributify?: boolean): {
41
49
  content: string;
@@ -45,5 +53,5 @@ declare function searchUsageBoundary(line: string, index: number, attributify?:
45
53
  declare function searchAttrKey(content: string, cursor: number): string | undefined;
46
54
  declare function cartesian<T>(arr: T[][]): T[][];
47
55
 
48
- export { cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
56
+ export { AutocompleteParseError, cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
49
57
  export type { AutoCompleteMatchType, AutocompleteOptions, AutocompleteTemplateGroup, AutocompleteTemplatePart, AutocompleteTemplateStatic, AutocompleteTemplateTheme, ParsedAutocompleteTemplate, UnocssAutocomplete };
package/dist/index.mjs CHANGED
@@ -2,6 +2,8 @@ import { uniq, escapeRegExp, toArray } from '@unocss/core';
2
2
  import { Fzf, byStartAsc, byLengthAsc } from 'fzf';
3
3
  import { LRUCache } from 'lru-cache';
4
4
 
5
+ const name = "@unocss/autocomplete";
6
+
5
7
  function searchUsageBoundary(line, index, attributify = true) {
6
8
  let start = index;
7
9
  let end = index;
@@ -74,6 +76,17 @@ function cartesian(arr) {
74
76
  );
75
77
  }
76
78
 
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
+ }
77
90
  const shorthands = {
78
91
  directions: "(x|y|t|b|l|r|s|e)",
79
92
  num: `(${[0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 24, 36].join("|")})`,
@@ -95,20 +108,27 @@ function handleRegexMatch(str, regex, onMatched, onNotMatched) {
95
108
  }
96
109
  function parseAutocomplete(template, theme = {}, extraShorthands = {}) {
97
110
  const parts = [];
111
+ const errors = [];
98
112
  const newShorthands = {
99
113
  ...shorthands,
100
114
  ...extraShorthands
101
115
  };
102
- template = template.replace(/<(\w+)>/g, (_, key) => {
103
- if (!newShorthands[key])
104
- throw new Error(`Unknown template shorthand: ${key}`);
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
+ }
105
121
  return newShorthands[key];
106
122
  });
107
123
  handleGroups(template);
124
+ if (errors.length) {
125
+ parts.length = 0;
126
+ }
108
127
  const fzf = new Fzf(getAllCombination(parts));
109
128
  return {
110
129
  parts,
111
- suggest
130
+ suggest,
131
+ errors
112
132
  };
113
133
  function handleNonGroup(input) {
114
134
  handleRegexMatch(
@@ -119,8 +139,10 @@ function parseAutocomplete(template, theme = {}, extraShorthands = {}) {
119
139
  type: "theme",
120
140
  objects: m[1].split("|").map((i) => {
121
141
  return i.split(".").reduce((v, k) => {
122
- if (!k || !v[k])
123
- throw new Error(`Invalid theme key ${k}`);
142
+ if (!k || !v[k]) {
143
+ errors.push(new AutocompleteParseError(`Invalid theme key: ${k}`, m.input));
144
+ return {};
145
+ }
124
146
  return v[k];
125
147
  }, theme);
126
148
  })
@@ -248,19 +270,23 @@ function getAllCombination(parts) {
248
270
  return list;
249
271
  }
250
272
 
251
- function createAutocomplete(_uno, options = {}) {
273
+ function createAutocomplete(uno, options = {}) {
252
274
  const templateCache = /* @__PURE__ */ new Map();
253
275
  const cache = new LRUCache({ max: 5e3 });
276
+ const errorCache = /* @__PURE__ */ new Map();
254
277
  let staticUtils = [];
255
278
  const templates = [];
256
- const matchType = options.matchType ?? "prefix";
257
- let uno;
258
- const ready = reset();
279
+ const {
280
+ matchType = "prefix",
281
+ throwErrors = true
282
+ } = options;
283
+ reset();
259
284
  return {
260
285
  suggest,
261
286
  suggestInFile,
262
287
  templates,
263
288
  cache,
289
+ errorCache,
264
290
  reset,
265
291
  /**
266
292
  * Enumerate possible suggestions from 'aa' - 'zz'
@@ -283,13 +309,7 @@ function createAutocomplete(_uno, options = {}) {
283
309
  );
284
310
  return matched;
285
311
  }
286
- function getParsed(template) {
287
- if (!templateCache.has(template))
288
- templateCache.set(template, parseAutocomplete(template, uno.config.theme, uno.config.autocomplete.shorthands));
289
- return templateCache.get(template).suggest;
290
- }
291
312
  async function suggest(input, allowsEmptyInput = false) {
292
- await ready;
293
313
  if (!allowsEmptyInput && input.length < 1)
294
314
  return [];
295
315
  if (cache.has(input))
@@ -298,7 +318,7 @@ function createAutocomplete(_uno, options = {}) {
298
318
  const attributifyPrefix = attributify?.options?.prefix;
299
319
  const _input = attributifyPrefix ? input.startsWith(attributifyPrefix) ? input.slice(attributifyPrefix.length) : input.replace(`:${attributifyPrefix}`, ":") : input;
300
320
  const matched = await uno.matchVariants(_input);
301
- let result = (await Promise.all(matched.map(async ([, processed, , variants]) => {
321
+ let result = (await Promise.all(matched.map(async ([, processed]) => {
302
322
  let idx = processed ? input.search(escapeRegExp(processed)) : input.length;
303
323
  if (idx === -1)
304
324
  idx = 0;
@@ -309,8 +329,7 @@ function createAutocomplete(_uno, options = {}) {
309
329
  suggestSelf(processed),
310
330
  suggestStatic(processed),
311
331
  suggestUnoCache(processed),
312
- ...suggestFromPreset(processed),
313
- ...suggestVariant(processed, variants)
332
+ suggestFromTemplates(processed)
314
333
  ]),
315
334
  variantPrefix,
316
335
  variantSuffix
@@ -327,7 +346,6 @@ function createAutocomplete(_uno, options = {}) {
327
346
  return result;
328
347
  }
329
348
  async function suggestInFile(content, cursor) {
330
- await ready;
331
349
  const isInsideAttrValue = searchAttrKey(content, cursor) !== void 0;
332
350
  const byExtractor = await searchUsageByExtractor(content, cursor);
333
351
  if (byExtractor) {
@@ -378,18 +396,17 @@ function createAutocomplete(_uno, options = {}) {
378
396
  const keys = Array.from(uno.cache.entries());
379
397
  return keys.filter((i) => i[1] && i[0].startsWith(input)).map((i) => i[0]);
380
398
  }
381
- function suggestFromPreset(input) {
382
- return templates.map((fn) => typeof fn === "function" ? fn(input) : getParsed(fn)(input, matchType)) || [];
383
- }
384
- function suggestVariant(input, used) {
385
- return uno.config.variants.filter((v) => v.autocomplete && (v.multiPass || !used.has(v))).flatMap((v) => toArray(v.autocomplete || [])).map((fn) => typeof fn === "function" ? fn(input) : getParsed(fn)(input, matchType));
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 : []);
386
405
  }
387
- async function reset() {
406
+ function reset() {
388
407
  templateCache.clear();
389
408
  cache.clear();
390
- if (!uno) {
391
- uno = await Promise.resolve(_uno);
392
- }
409
+ errorCache.clear();
393
410
  staticUtils = [
394
411
  ...Object.keys(uno.config.rulesStaticMap),
395
412
  ...uno.config.shortcuts.filter((i) => typeof i[0] === "string").map((i) => i[0])
@@ -398,8 +415,25 @@ function createAutocomplete(_uno, options = {}) {
398
415
  templates.push(
399
416
  ...uno.config.autocomplete.templates || [],
400
417
  ...uno.config.rulesDynamic.flatMap((i) => toArray(i?.[2]?.autocomplete || [])),
401
- ...uno.config.shortcuts.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 || []))
402
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
+ }
403
437
  }
404
438
  function processSuggestions(suggestions, prefix = "", suffix = "") {
405
439
  return uniq(suggestions.flat()).filter((i) => !!(i && !i.endsWith("-") && !uno.isBlocked(i))).sort((a, b) => {
@@ -416,4 +450,4 @@ function createAutocomplete(_uno, options = {}) {
416
450
  }
417
451
  }
418
452
 
419
- export { cartesian, createAutocomplete, ignoredThemeKeys, parseAutocomplete, searchAttrKey, searchUsageBoundary, shorthands };
453
+ 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.4.1",
4
+ "version": "66.5.0",
5
5
  "description": "Autocomplete utils for UnoCSS",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "lru-cache": "^11.1.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@unocss/core": "66.4.1"
40
+ "@unocss/core": "66.5.0"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "unbuild",