@terpjs/eslint-boundaries 0.22.0 → 0.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/package.json +2 -2
- package/src/i18n.test.js +12 -0
- package/src/index.js +15 -1
- package/src/spec.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@terpjs/eslint-boundaries",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Terp frontend boundary rules (as data) + the ESLint adapter: no cross-module imports, no package internals, design-token-only styling (no style/className/module stylesheets), token-styled components for raw HTML tags, router-only in-app links, generated-client-only, and browser XSS/navigation sink bans. Strict-only (no modes); governed opt-outs via terp-allow markers + the escape-hatch budget ratchet (terp-boundaries-budget).",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"typescript-eslint": "^8.69.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@terpjs/spec": "0.
|
|
28
|
+
"@terpjs/spec": "0.35.0",
|
|
29
29
|
"eslint": "^10.10.0",
|
|
30
30
|
"vitest": "^5.0.0"
|
|
31
31
|
},
|
package/src/i18n.test.js
CHANGED
|
@@ -144,6 +144,18 @@ describe("locale catalog completeness", () => {
|
|
|
144
144
|
expect(dynamicTrans.find((message) => message.ruleId === "terp/locale-catalogs-complete")?.message)
|
|
145
145
|
.toContain("requires static non-empty id and message");
|
|
146
146
|
|
|
147
|
+
// A spread is still refused - the catalog is inventoried statically - but it is the
|
|
148
|
+
// one shape with a sanctioned alternative, so the refusal names it. Sharing one
|
|
149
|
+
// descriptor between two screens is ordinary; only its JSX-body spelling is not.
|
|
150
|
+
const spreadTrans = await lintWithCatalog(
|
|
151
|
+
{ sourceLocale: "en", locales: { en: {}, nl: {} } },
|
|
152
|
+
'export const W = () => <Trans {...TITLE} />;',
|
|
153
|
+
);
|
|
154
|
+
const spreadMessage = spreadTrans
|
|
155
|
+
.find((message) => message.ruleId === "terp/locale-catalogs-complete")?.message;
|
|
156
|
+
expect(spreadMessage).toContain("useUiText");
|
|
157
|
+
expect(spreadMessage).toContain("text(DESCRIPTOR)");
|
|
158
|
+
|
|
147
159
|
const staleAllowlist = await lintWithCatalog(
|
|
148
160
|
{
|
|
149
161
|
sourceLocale: "en",
|
package/src/index.js
CHANGED
|
@@ -788,9 +788,23 @@ const localeCatalogsComplete = {
|
|
|
788
788
|
if (jsxName(node.name) !== "Trans") return;
|
|
789
789
|
const descriptor = transDescriptor(node);
|
|
790
790
|
if (descriptor === null) {
|
|
791
|
+
// A spread is the one shape with a sanctioned alternative, and the generic
|
|
792
|
+
// message sent authors looking for a way to make the spread work instead.
|
|
793
|
+
// One descriptor shared by two screens is ordinary; what cannot be shared is
|
|
794
|
+
// the JSX-body spelling of it, because the catalog is inventoried statically
|
|
795
|
+
// and `{...DESCRIPTOR}` carries no attributes to read. The resolver renders
|
|
796
|
+
// the same copy from the same constant, so name it rather than the refusal.
|
|
797
|
+
const spread = node.attributes.some(
|
|
798
|
+
(attribute) => attribute.type === "JSXSpreadAttribute",
|
|
799
|
+
);
|
|
791
800
|
context.report({
|
|
792
801
|
node,
|
|
793
|
-
message:
|
|
802
|
+
message: spread
|
|
803
|
+
? "<Trans> reads its id and message as static attributes, so a shared UiText " +
|
|
804
|
+
"constant cannot be spread into it. Render the same constant through the " +
|
|
805
|
+
"resolver instead: const text = useUiText() in the component, then " +
|
|
806
|
+
"{text(DESCRIPTOR)} where the copy goes."
|
|
807
|
+
: "<Trans> requires static non-empty id and message attributes.",
|
|
794
808
|
});
|
|
795
809
|
return;
|
|
796
810
|
}
|
package/src/spec.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* NOT by this package's own suite, which certification runs against candidate spec releases
|
|
17
17
|
* whose version is allowed to be newer).
|
|
18
18
|
*/
|
|
19
|
-
export const SPEC_VERSION = "0.
|
|
19
|
+
export const SPEC_VERSION = "0.35.0";
|
|
20
20
|
|
|
21
21
|
export const BOUNDARY_SPEC = {
|
|
22
22
|
/** Every app-authored TypeScript source file whose user-facing copy must be cataloged. */
|