@multiplatform.one/config 7.23.1 → 7.24.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/README.md CHANGED
@@ -76,8 +76,8 @@ computed colours, from all but `no-raw-typography`. A project that wants its
76
76
  own levels keeps the older one-line form,
77
77
  `{ "jsPlugins": ["@multiplatform.one/config/oxlint"] }`, and writes its own
78
78
  rules block (mpo's own `oxlintrc.json` turns `no-hex-literals` on for
79
- `apps/**`, `packages/**` and `features/**`, and off for specs and `tests/`
80
- trees). Palette modules (`themes/base.ts`, `themes/accent.ts`,
79
+ `apps/**`, `packages/**`, `features/**`, `public/frappe-ui/src` and
80
+ `public/backoffice/src`, and off for specs and `tests/` trees). Palette modules (`themes/base.ts`, `themes/accent.ts`,
81
81
  `*palette*`) are exempt. Comments are not visited, so a JSDoc `#025` is not
82
82
  a hit. A file no theme token reaches opts out with a `// hex-escape: <reason>`
83
83
  line comment; `lint` fails that comment unless the spec table
@@ -87,16 +87,19 @@ whose comment is gone (MPO-326).
87
87
  `no-chrome-props` and `no-raw-geometry` ship in the same plugin (MPO-17).
88
88
  Enable them the same way when you start that burndown. Drawing-file
89
89
  exceptions come from the spec table `## Drawing files`, not from the code.
90
+ `no-raw-geometry` leaves `0` alone (`00` L8 E1). mpo's own `oxlintrc.json`
91
+ runs it as an error over `public/frappe-ui/src` and `public/backoffice/src`
92
+ (MPO-15), off for specs.
90
93
 
91
94
  `no-child-margin` (MPO-23, `00` L9a) fails a non-zero `margin*` prop, long
92
95
  or shorthand, on any element nested inside another element's JSX: the parent
93
96
  owns the gap. `0` is always legal, the outermost element a file renders is
94
97
  left alone, and slots come from the spec table `## Slot margins`. mpo's own
95
98
  `oxlintrc.json` runs it as an error over `apps/`, `features/`, `packages/` and
96
- `public/`, off for specs and `tests/` trees and for a named burndown list: the
97
- 73 files that carried 133 hits when it was switched on. The list may only
98
- shrink; `scripts/child-margin-ratchet.spec.mjs` fails if it grows, names a
99
- pattern instead of a file, or keeps a file that no longer violates.
99
+ `public/`, off only for specs and `tests/` trees. The burndown list that
100
+ exempted the 73 files carrying 133 hits when it was switched on is empty, and
101
+ `scripts/child-margin-ratchet.spec.mjs` holds its ceiling at 0, so a file
102
+ added back to it fails the spec.
100
103
 
101
104
  ### Lint (node-script checks)
102
105
 
package/oxlint.mjs CHANGED
@@ -23,9 +23,10 @@
23
23
  * stay legal. Exceptions come from the spec DRAWING table's CHROME-ALLOW
24
24
  * row, not from the code (MPO-17).
25
25
  * mpo-conventions/no-raw-geometry — ban numeric height/width/padding/fontSize
26
- * on those same imports. Silent behind sizeRecipeEscape() and inside a
27
- * file listed as DRAWING. An undeclared `// mpo-drawing` pragma is a
28
- * lint.mjs failure, not a skip here.
26
+ * on those same imports. `0` is `00` L8 E1 and stays legal. Silent
27
+ * behind sizeRecipeEscape() and inside a file listed as DRAWING. An
28
+ * undeclared `// mpo-drawing` pragma is a lint.mjs failure, not a skip
29
+ * here.
29
30
  * mpo-conventions/no-child-margin — `00` L9a: the parent owns the gap. Ban a
30
31
  * non-zero margin* prop on any element nested inside another element's
31
32
  * JSX. The outermost element of a tree is left alone (a file cannot see
@@ -182,7 +183,7 @@ export const MARGIN_PROPS = Object.freeze([
182
183
 
183
184
  const CHROME_PROP_SET = new Set(CHROME_PROPS);
184
185
  const MARGIN_PROP_SET = new Set(MARGIN_PROPS);
185
- const ZERO_MARGIN = /^(?:-?0(?:\.0+)?(?:px)?|\$0)$/;
186
+ const ZERO_VALUE = /^(?:-?0(?:\.0+)?(?:px)?|\$0)$/;
186
187
  const GEOMETRY_PROP_SET = new Set(GEOMETRY_PROPS);
187
188
 
188
189
  const RULE_OPTIONS_SCHEMA = [
@@ -222,19 +223,20 @@ function resolveSlotMargins(context) {
222
223
 
223
224
  /**
224
225
  * `0` is `00` L8 E1, legal anywhere: a zero-reset is the absence of an outer
225
- * margin, not one (Tamagui's own headings ship `margin: 0`).
226
+ * margin or a size, not one (Tamagui's own headings ship `margin: 0`, and
227
+ * `minWidth={0}` is what lets a flex child shrink below its content).
226
228
  * @param {unknown} value
227
229
  */
228
- function isZeroMargin(value) {
230
+ function isZeroReset(value) {
229
231
  const node = unwrapJsxValue(value);
230
232
  if (!node || typeof node !== "object") return false;
231
233
  const expr =
232
234
  /** @type {{ type?: string, value?: unknown, operator?: string, argument?: unknown }} */ (node);
233
235
  if (expr.type === "Literal") {
234
236
  if (typeof expr.value === "number") return expr.value === 0;
235
- if (typeof expr.value === "string") return ZERO_MARGIN.test(expr.value.trim());
237
+ if (typeof expr.value === "string") return ZERO_VALUE.test(expr.value.trim());
236
238
  }
237
- if (expr.type === "UnaryExpression" && expr.operator === "-") return isZeroMargin(expr.argument);
239
+ if (expr.type === "UnaryExpression" && expr.operator === "-") return isZeroReset(expr.argument);
238
240
  return false;
239
241
  }
240
242
 
@@ -541,7 +543,7 @@ export const plugin = {
541
543
  type: "problem",
542
544
  docs: {
543
545
  description:
544
- "Ban numeric geometry on imported @multiplatform.one/* components unless wrapped in sizeRecipeEscape or the file is a declared drawing.",
546
+ "Ban non-zero numeric geometry on imported @multiplatform.one/* components unless wrapped in sizeRecipeEscape or the file is a declared drawing.",
545
547
  },
546
548
  schema: RULE_OPTIONS_SCHEMA,
547
549
  messages: {
@@ -557,6 +559,7 @@ export const plugin = {
557
559
  if (!GEOMETRY_PROP_SET.has(prop)) continue;
558
560
  if (isSizeRecipeEscape(attr.value)) continue;
559
561
  if (!isNumericLiteral(attr.value)) continue;
562
+ if (isZeroReset(attr.value)) continue;
560
563
  context.report({
561
564
  node: attr,
562
565
  messageId: "geometry",
@@ -601,7 +604,7 @@ export const plugin = {
601
604
  for (const attr of node.attributes ?? []) {
602
605
  const prop = jsxAttrName(attr);
603
606
  if (!MARGIN_PROP_SET.has(prop)) continue;
604
- if (isZeroMargin(attr.value)) continue;
607
+ if (isZeroReset(attr.value)) continue;
605
608
  context.report({
606
609
  node: attr,
607
610
  messageId: "childMargin",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/config",
3
- "version": "7.23.1",
3
+ "version": "7.24.0",
4
4
  "description": "Shared build and test configuration presets for multiplatform.one",
5
5
  "keywords": [
6
6
  "config",
@@ -99,7 +99,7 @@
99
99
  "access": "public"
100
100
  },
101
101
  "dependencies": {
102
- "@multiplatform.one/utils": "7.23.1",
102
+ "@multiplatform.one/utils": "7.24.0",
103
103
  "@tamagui/vite-plugin": "2.7.6",
104
104
  "@vitejs/plugin-react": "^6.0.1",
105
105
  "dotenv": "^17.4.2",
@@ -266,6 +266,37 @@ describe("mpo-conventions/no-raw-geometry (MPO-17)", () => {
266
266
  expect(wrapped).toEqual([]);
267
267
  });
268
268
 
269
+ it("never flags a zero-reset (00 L8 E1) but still flags any other number", () => {
270
+ const zero = driveHouseRule("no-raw-geometry", filename, [
271
+ importCard,
272
+ jsxOpen("Card", [
273
+ { prop: "minWidth", value: numeric(0) },
274
+ { prop: "padding", value: numeric(0) },
275
+ {
276
+ prop: "minHeight",
277
+ value: {
278
+ type: "JSXExpressionContainer",
279
+ expression: {
280
+ type: "UnaryExpression",
281
+ operator: "-",
282
+ argument: { type: "Literal", value: 0 },
283
+ },
284
+ },
285
+ },
286
+ ]),
287
+ ]);
288
+ expect(zero).toEqual([]);
289
+
290
+ const small = driveHouseRule("no-raw-geometry", filename, [
291
+ importCard,
292
+ jsxOpen("Card", [
293
+ { prop: "padding", value: numeric(2) },
294
+ { prop: "minWidth", value: numeric(0.5) },
295
+ ]),
296
+ ]);
297
+ expect(small.map((r) => r.data?.prop)).toEqual(["padding", "minWidth"]);
298
+ });
299
+
269
300
  it("stays silent inside a registered drawing file", () => {
270
301
  expect(
271
302
  driveHouseRule(