@keyline-icons/cli 0.3.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/icons.json +1 -1
- package/package.json +1 -1
- package/src/index.mjs +58 -4
package/package.json
CHANGED
package/src/index.mjs
CHANGED
|
@@ -26,7 +26,7 @@ const data = JSON.parse(
|
|
|
26
26
|
// older icons.json still runs rather than reading `undefined.includes`.
|
|
27
27
|
const { icons, styles, corners = ["regular"], keywords = {} } = data
|
|
28
28
|
const NAMES = Object.keys(icons)
|
|
29
|
-
const VERSION = "0.
|
|
29
|
+
const VERSION = "0.4.0"
|
|
30
30
|
|
|
31
31
|
/** Colour only when a human is looking. Piped output stays clean. */
|
|
32
32
|
const tty = process.stdout.isTTY
|
|
@@ -159,6 +159,54 @@ function keywordsFor(name) {
|
|
|
159
159
|
|
|
160
160
|
const haystackFor = (name) => `${name} ${keywordsFor(name).join(" ")}`
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* A word reduced to its singular, so a plural finds the family.
|
|
164
|
+
*
|
|
165
|
+
* Every name in the set is singular: `arrow-down`, `file`, `bar-chart`. Every
|
|
166
|
+
* heading on the site's category rail is plural. So "Arrows" sat on the screen
|
|
167
|
+
* while typing `arrows` returned one drawing out of 585, `git-compare-arrows`,
|
|
168
|
+
* the only name carrying the letter. `charts`, `stars` and `bells` returned
|
|
169
|
+
* nothing at all. The plural is what someone reads off our own sidebar and
|
|
170
|
+
* what every other set answers, and here it was the one word that could not
|
|
171
|
+
* work.
|
|
172
|
+
*
|
|
173
|
+
* Applied to both sides, the query word and each word of the haystack, which
|
|
174
|
+
* also carries the other direction: `chevron` reaches `chevrons-left`, which
|
|
175
|
+
* whole words alone could not.
|
|
176
|
+
*
|
|
177
|
+
* Deliberately blunt: no dictionary, no suffix ladder, one `s`. The guards are
|
|
178
|
+
* the whole design, and they are read off this vocabulary rather than guessed.
|
|
179
|
+
* Every `-ss`, `-us` and `-is` word in it is already a word: `progress`,
|
|
180
|
+
* `compass`, `plus`, `minus`, `status`, `axis`. Past those, `lens`, `atlas`
|
|
181
|
+
* and `sideways` are the only three that end in `s` without being a plural.
|
|
182
|
+
* `lens` is the one that mattered. Cut to `len` it lands inside `calendar` and
|
|
183
|
+
* `silence`, and the word someone types for the camera came back with
|
|
184
|
+
* seventeen drawings that are not it.
|
|
185
|
+
*
|
|
186
|
+
* `arrows` is in the list for the opposite reason. The rule would not damage
|
|
187
|
+
* it, it would erase it: the plural asks for the drawings carrying more than
|
|
188
|
+
* one arrowhead, `fullscreen`, `chevrons-up-down`, `refresh-cw`, and folding it
|
|
189
|
+
* into `arrow` answers with the ninety-nine single arrows instead. The word is
|
|
190
|
+
* a keyword on those drawings, in lib/icon-aliases.json, and this is what keeps
|
|
191
|
+
* the two questions apart.
|
|
192
|
+
*
|
|
193
|
+
* Same rule as the site, the MCP server and the Figma plugin, checked by
|
|
194
|
+
* pipeline/check-search.mjs.
|
|
195
|
+
*/
|
|
196
|
+
const singular = (w) =>
|
|
197
|
+
w.length < 4 ||
|
|
198
|
+
!w.endsWith("s") ||
|
|
199
|
+
/(ss|us|is|arrows|lens|atlas|sideways)$/.test(w)
|
|
200
|
+
? w
|
|
201
|
+
: w.endsWith("ies")
|
|
202
|
+
? `${w.slice(0, -3)}y`
|
|
203
|
+
: /(ch|sh|x|z)es$/.test(w)
|
|
204
|
+
? w.slice(0, -2)
|
|
205
|
+
: w.slice(0, -1)
|
|
206
|
+
|
|
207
|
+
/** Every word in `hay` singular, delimiters kept so `wholeWord` still works. */
|
|
208
|
+
const stemmed = (hay) => hay.replace(/[a-z0-9]+/g, singular)
|
|
209
|
+
|
|
162
210
|
/**
|
|
163
211
|
* What another set calls a drawing here: `message-square` for `message`,
|
|
164
212
|
* `arrow-big-up` for `arrow-up`, `loader-2` for `loader`.
|
|
@@ -198,6 +246,12 @@ const wholeWord = (hay, needle) => {
|
|
|
198
246
|
return false
|
|
199
247
|
}
|
|
200
248
|
|
|
249
|
+
/** Whether one haystack answers every word of a query, whole words only. */
|
|
250
|
+
const answers = (hay, words) =>
|
|
251
|
+
words.every(
|
|
252
|
+
(w) => wholeWord(hay, w) || wholeWord(stemmed(hay), singular(w))
|
|
253
|
+
)
|
|
254
|
+
|
|
201
255
|
function search(query, style, limit, corners = "regular") {
|
|
202
256
|
const q = query.toLowerCase().trim()
|
|
203
257
|
const words = wordsOf(query)
|
|
@@ -208,8 +262,8 @@ function search(query, style, limit, corners = "regular") {
|
|
|
208
262
|
(!style || svgFor(n, style, corners)) &&
|
|
209
263
|
(foreign[q] === n ||
|
|
210
264
|
wholeWord(n, q) ||
|
|
211
|
-
|
|
212
|
-
|
|
265
|
+
answers(n, words) ||
|
|
266
|
+
answers(haystackFor(n), words))
|
|
213
267
|
)
|
|
214
268
|
.map((n) => {
|
|
215
269
|
const rank =
|
|
@@ -221,7 +275,7 @@ function search(query, style, limit, corners = "regular") {
|
|
|
221
275
|
? 2
|
|
222
276
|
: wholeWord(n, q)
|
|
223
277
|
? 3
|
|
224
|
-
:
|
|
278
|
+
: answers(n, words)
|
|
225
279
|
? 4
|
|
226
280
|
: 5
|
|
227
281
|
return { n, rank }
|