@starci/eslint-canon-fe 1.3.0 → 1.3.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/file-layout.mjs CHANGED
@@ -22,7 +22,7 @@ const TWO_FILE_TIERS = /\/src\/components\/(pages|layouts)\/([^/]+)\/(.+)$/
22
22
  const TWO_FILE_TIERS_WITH_CATEGORY = /\/src\/components\/(overlays)\/[^/]+\/([^/]+)\/(.+)$/
23
23
 
24
24
  /** The two halves, and the twin test of each, are the whole of what a surface folder may hold. */
25
- const ALLOWED_IN_SURFACE_FOLDER = /^(?:component|index)(?:\.test)?\.tsx?$/
25
+ const ALLOWED_IN_SURFACE_FOLDER = /^(?:component|index)(?:\.spec)?\.tsx?$/
26
26
 
27
27
  /** Folders that are not component code, whatever they are nested inside. */
28
28
  const NON_COMPONENT_FOLDERS = /\/src\/components\/.*\/(constants|utils|types|hooks)\//
@@ -240,9 +240,9 @@ const ROUTE_TREE_EXEMPT = /^(?:api\/|_)/
240
240
  *
241
241
  * The name is deliberately not required to match `page` or `layout`. A route's tests split by
242
242
  * CONCERN - what the screen renders, who may reach it, where the boundary sits - and forcing them
243
- * into one `page.test.tsx` would buy nothing but a longer file.
243
+ * into one `page.spec.tsx` would buy nothing but a longer file.
244
244
  */
245
- const ROUTE_TREE_TEST = /\.test\.(?:tsx?|jsx?)$/
245
+ const ROUTE_TREE_TEST = /\.spec\.(?:tsx?|jsx?)$/
246
246
 
247
247
  /**
248
248
  * A file under `app/` names which page renders at which URL, and does nothing else.
@@ -362,6 +362,35 @@ export const noShellTier = {
362
362
  },
363
363
  }
364
364
 
365
+ // -- FILE-9 --------------------------------------------------------------------------------------
366
+
367
+ const UNIT_TEST_FILE = /\.(test|spec)\.[cm]?[jt]sx?$/
368
+ const SEPARATE_FRONTEND_TEST_TREE = /\/(?:src\/tests|tests?\/unit|e2e)(?:\/|$)/
369
+
370
+ /** Frontend units are `.spec.` twins beside the source they exercise. */
371
+ export const unitTestColocated = {
372
+ meta: {
373
+ type: "problem",
374
+ docs: { description: "Frontend unit tests are colocated `.spec.` files; frontend owns no separate test tree." },
375
+ schema: [],
376
+ messages: {
377
+ suffix: "`{{name}}` uses the generic `.test.` suffix. A frontend unit is a colocated `.spec.` twin beside its production owner.",
378
+ bucket: "`{{path}}` files a frontend unit in a separate test bucket. Move the cases beside their production owner; only backend E2E owns a separate test tree.",
379
+ },
380
+ },
381
+ create(context) {
382
+ const file = normalizePath(context.filename || context.getFilename())
383
+ const match = file.match(UNIT_TEST_FILE)
384
+ if (!match) return {}
385
+ return {
386
+ Program(node) {
387
+ if (match[1] === "test") context.report({ node, messageId: "suffix", data: { name: file.slice(file.lastIndexOf("/") + 1) } })
388
+ if (SEPARATE_FRONTEND_TEST_TREE.test(file)) context.report({ node, messageId: "bucket", data: { path: file } })
389
+ },
390
+ }
391
+ },
392
+ }
393
+
365
394
  export const rules = {
366
395
  "no-shell-tier": noShellTier,
367
396
  "source-tier-marker-matches-folder": sourceTierMarkerMatchesFolder,
@@ -371,6 +400,7 @@ export const rules = {
371
400
  "export-matches-folder": exportMatchesFolder,
372
401
  "no-runtime-namespace": noRuntimeNamespace,
373
402
  "monorepo-tier-belongs-to-its-side": monorepoTierBelongsToItsSide,
403
+ "unit-test-colocated": unitTestColocated,
374
404
  }
375
405
 
376
406
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starci/eslint-canon-fe",
3
- "version": "1.3.0",
3
+ "version": "1.3.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",
package/the-split.mjs CHANGED
@@ -66,7 +66,7 @@ export const presentationalPurity = {
66
66
  export const connectedBlockHasPresentationalTwin = {
67
67
  meta: {
68
68
  type: "problem",
69
- docs: { description: "A connected block index renders only its exact `_X` twin from component.tsx." },
69
+ docs: { description: "A connected block index renders only its exact `XBase` twin from component.tsx." },
70
70
  schema: [],
71
71
  messages: {
72
72
  missing:
@@ -81,7 +81,7 @@ export const connectedBlockHasPresentationalTwin = {
81
81
  const block = connectedBlock(context.filename || context.getFilename())
82
82
  if (!block) return {}
83
83
 
84
- const twin = `_${block}`
84
+ const twin = `${block}Base`
85
85
  const worldBindings = new Set()
86
86
  const rendered = []
87
87
  let importsTwin = false