@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.
Files changed (2) hide show
  1. package/icon.mjs +10 -95
  2. 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
- /** The two Heroicon families selected by the product roles. */
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
- // ICON-11: the rank leaf owns award artwork the Heroicons map does not carry.
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
- // ICON-11: Heroicons ships no medal, so the award vocabulary has its own closed leaf.
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
- "rank-artwork-is-a-closed-set": rankArtworkIsAClosedSet,
300
- }
215
+ }
301
216
 
302
217
  /**
303
218
  * The level this law asks for, as the plugin's own opinion.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starci/eslint-canon-fe",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "The StarCi front-end lint canon: every rule its laws publish, gathered as one flat-config plugin.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",