@starci/eslint-canon-fe 1.4.0 → 1.4.2
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/icon.mjs +10 -95
- package/package.json +1 -1
package/icon.mjs
CHANGED
|
@@ -43,11 +43,13 @@ const GLYPH_PACKAGES = [
|
|
|
43
43
|
/** Package-name signal for a glyph catalogue not yet listed explicitly. */
|
|
44
44
|
const GLYPH_PACKAGE_NAME = /(?:icon|glyph|lucide|feather|tabler|fortawesome)/i
|
|
45
45
|
|
|
46
|
-
/**
|
|
47
|
-
const HEROICON_PACKAGES = new Set([
|
|
48
|
-
"@heroicons/react/24/outline",
|
|
49
|
-
"@heroicons/react/16/solid",
|
|
50
|
-
|
|
46
|
+
/** Upstream Heroicons plus StarCi's custom-only extension, each on the same two optical families. */
|
|
47
|
+
const HEROICON_PACKAGES = new Set([
|
|
48
|
+
"@heroicons/react/24/outline",
|
|
49
|
+
"@heroicons/react/16/solid",
|
|
50
|
+
"@starci/heroicons/24/outline",
|
|
51
|
+
"@starci/heroicons/16/solid",
|
|
52
|
+
])
|
|
51
53
|
|
|
52
54
|
/**
|
|
53
55
|
* Product reactions are attributed artwork rather than glyph-library imports.
|
|
@@ -57,45 +59,6 @@ const HEROICON_PACKAGES = new Set([
|
|
|
57
59
|
*/
|
|
58
60
|
export const REACTION_ASSET_NAMES = new Set(["like", "love", "haha", "wow", "sad", "angry"])
|
|
59
61
|
|
|
60
|
-
/**
|
|
61
|
-
* ICON-11 - rank artwork is a second closed leaf, and it is the only one.
|
|
62
|
-
*
|
|
63
|
-
* A leaderboard place is not a feature, a state or an action, which is what the Heroicons map is
|
|
64
|
-
* for. It is an AWARD, and the product decided - explicitly, twice - that an award is drawn as the
|
|
65
|
-
* Fluent Emoji Flat medal for it. Heroicons ships no medal, so the choice was never between two
|
|
66
|
-
* glyph families; it was between the artwork the product asked for and no artwork at all.
|
|
67
|
-
*
|
|
68
|
-
* WHY THIS IS A NAMED EXEMPTION RATHER THAN A HOLE. It is bounded on three sides at once: one file
|
|
69
|
-
* may import the library, only from `@iconify/react`, and only these four artwork identities. A
|
|
70
|
-
* fifth medal, a second importing file, or a different vendor is still reported. That is the same
|
|
71
|
-
* shape as the reaction vocabulary above - a closed set owned by one leaf - and it is what keeps
|
|
72
|
-
* "the product asked for it" from becoming a sentence any call site can write.
|
|
73
|
-
*
|
|
74
|
-
* WHY IT IS NOT THE `public/` ROUTE THE REACTIONS TOOK. That route is better and it stays the
|
|
75
|
-
* default: checked-in SVG needs no network at render time and no vendor at all. It was not taken
|
|
76
|
-
* here because the four assets are not in the repository, and the exemption records a decision the
|
|
77
|
-
* product owner made knowing that - not a claim that this is the stronger mechanism.
|
|
78
|
-
*/
|
|
79
|
-
const RANK_MARK_RELATIVE = "leaves/RankMark/index.tsx"
|
|
80
|
-
|
|
81
|
-
/** The one glyph package the rank leaf may name, and nothing else may. */
|
|
82
|
-
const RANK_ARTWORK_PACKAGE = "@iconify/react"
|
|
83
|
-
|
|
84
|
-
/** The complete rank artwork vocabulary: three places, then one trophy for everyone below. */
|
|
85
|
-
export const RANK_ARTWORK_IDS = new Set([
|
|
86
|
-
"fluent-emoji-flat:1st-place-medal",
|
|
87
|
-
"fluent-emoji-flat:2nd-place-medal",
|
|
88
|
-
"fluent-emoji-flat:3rd-place-medal",
|
|
89
|
-
"fluent-emoji-flat:trophy",
|
|
90
|
-
])
|
|
91
|
-
|
|
92
|
-
/** True when this file is the rank leaf, which owns the place-to-artwork map. */
|
|
93
|
-
const isRankMarkFile = (filename) => normalizePath(filename).endsWith(`/${RANK_MARK_RELATIVE}`)
|
|
94
|
-
|
|
95
|
-
/** True for the one import the rank leaf is permitted to make. */
|
|
96
|
-
const isRankArtworkImport = (filename, source) =>
|
|
97
|
-
isRankMarkFile(filename) && source === RANK_ARTWORK_PACKAGE
|
|
98
|
-
|
|
99
62
|
/** True when this file is the icon leaf, which owns the meaning-to-glyph map. */
|
|
100
63
|
const isIconLeafFile = (filename) => normalizePath(filename).endsWith(`/${ICON_MODULE_RELATIVE}`)
|
|
101
64
|
|
|
@@ -152,9 +115,7 @@ export const noVendorIconOutsideIconLeaf = {
|
|
|
152
115
|
ImportDeclaration(node) {
|
|
153
116
|
const source = node.source && node.source.value
|
|
154
117
|
if (!isGlyphImport(source)) return
|
|
155
|
-
|
|
156
|
-
if (isRankArtworkImport(file, source)) return
|
|
157
|
-
context.report({ node, messageId: "vendor", data: { source, leaf: ICON_MODULE_RELATIVE } })
|
|
118
|
+
context.report({ node, messageId: "vendor", data: { source, leaf: ICON_MODULE_RELATIVE } })
|
|
158
119
|
},
|
|
159
120
|
}
|
|
160
121
|
},
|
|
@@ -180,9 +141,7 @@ export const heroiconsIsTheGlyphVendor = {
|
|
|
180
141
|
ImportDeclaration(node) {
|
|
181
142
|
const source = node.source && node.source.value
|
|
182
143
|
if (!isGlyphImport(source) || HEROICON_PACKAGES.has(String(source))) return
|
|
183
|
-
|
|
184
|
-
if (isRankArtworkImport(file, source)) return
|
|
185
|
-
context.report({ node, messageId: "vendor", data: { source } })
|
|
144
|
+
context.report({ node, messageId: "vendor", data: { source } })
|
|
186
145
|
},
|
|
187
146
|
}
|
|
188
147
|
},
|
|
@@ -247,57 +206,13 @@ export const noDecorativeIconInMetricCell = {
|
|
|
247
206
|
},
|
|
248
207
|
}
|
|
249
208
|
|
|
250
|
-
// -- ICON-11 ---------------------------------------------------------------------------------------
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* The rank leaf's exemption is a vocabulary, not a door.
|
|
254
|
-
*
|
|
255
|
-
* ICON-11 lets exactly one file import exactly one glyph package. Without this rule that file could
|
|
256
|
-
* then name ANY artwork in that package, and the exemption would have bought the product four
|
|
257
|
-
* medals and handed back an unbounded catalogue - which is the failure the icon leaf exists to
|
|
258
|
-
* prevent, reintroduced one folder over.
|
|
259
|
-
*/
|
|
260
|
-
export const rankArtworkIsAClosedSet = {
|
|
261
|
-
meta: {
|
|
262
|
-
type: "problem",
|
|
263
|
-
docs: { description: "The rank leaf names only the four approved award artworks." },
|
|
264
|
-
schema: [],
|
|
265
|
-
messages: {
|
|
266
|
-
unknown:
|
|
267
|
-
"`{{id}}` is not one of the four approved rank artworks. The vocabulary is `fluent-emoji-flat:1st-place-medal`, `2nd-place-medal`, `3rd-place-medal` and `trophy` for every place below third. A fifth artwork is a product decision about what a place MEANS, so it is made in the icon law rather than in this file.",
|
|
268
|
-
outside:
|
|
269
|
-
"`{{id}}` is rank award artwork, named outside `{{leaf}}`. The place-to-artwork map is kept in one file so a second screen cannot answer the same question differently.",
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
create(context) {
|
|
273
|
-
const file = normalizePath(context.filename || context.getFilename())
|
|
274
|
-
// A twin test proves the map is closed, which it cannot do without naming what is in it and
|
|
275
|
-
// what is not. Same exemption, same reason, as the one the double-cast rule already carries.
|
|
276
|
-
if (!isSourceFile(file) || /\.test\.tsx?$/.test(file)) return {}
|
|
277
|
-
const inRankLeaf = isRankMarkFile(file)
|
|
278
|
-
return {
|
|
279
|
-
Literal(node) {
|
|
280
|
-
if (typeof node.value !== "string") return
|
|
281
|
-
const id = node.value
|
|
282
|
-
if (!id.startsWith("fluent-emoji-flat:")) return
|
|
283
|
-
if (!inRankLeaf) {
|
|
284
|
-
context.report({ node, messageId: "outside", data: { id, leaf: RANK_MARK_RELATIVE } })
|
|
285
|
-
return
|
|
286
|
-
}
|
|
287
|
-
if (!RANK_ARTWORK_IDS.has(id)) context.report({ node, messageId: "unknown", data: { id } })
|
|
288
|
-
},
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
}
|
|
292
|
-
|
|
293
209
|
/** The rules this law contributes to the plugin. */
|
|
294
210
|
export const rules = {
|
|
295
211
|
"no-vendor-icon-outside-icon-leaf": noVendorIconOutsideIconLeaf,
|
|
296
212
|
"heroicons-is-the-glyph-vendor": heroiconsIsTheGlyphVendor,
|
|
297
213
|
"no-off-scale-glyph-size": noOffScaleGlyphSize,
|
|
298
214
|
"no-decorative-icon-in-metric-cell": noDecorativeIconInMetricCell,
|
|
299
|
-
|
|
300
|
-
}
|
|
215
|
+
}
|
|
301
216
|
|
|
302
217
|
/**
|
|
303
218
|
* The level this law asks for, as the plugin's own opinion.
|
package/package.json
CHANGED