@cosmicdrift/kumiko-guards 0.371.1 → 0.373.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-guards",
3
- "version": "0.371.1",
3
+ "version": "0.373.0",
4
4
  "description": "AST-based security guards for Kumiko repos: direct-fs/fetch, tenant escalation, admin-API, escape hatches and related checks, run over a shared ts-morph project.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -28,7 +28,7 @@
28
28
  "kumiko-pre-push": "./src/pre-push.sh"
29
29
  },
30
30
  "dependencies": {
31
- "@cosmicdrift/kumiko-repo-manifest": "0.371.1",
31
+ "@cosmicdrift/kumiko-repo-manifest": "0.373.0",
32
32
  "ts-morph": "^28.0.0"
33
33
  },
34
34
  "publishConfig": {
@@ -2,8 +2,9 @@
2
2
  /**
3
3
  * Guard: locale bundle values must follow Mandant/Organización terminology (#2200, fw#2355).
4
4
  *
5
- * German UI copy always says "Mandant" (never "Tenant"/"Organisation"); Spanish always
6
- * says "Organización" (never the "tenant" loanword). Only translation *values* are
5
+ * German UI copy always says "Mandant" (never "Tenant"/"Organisation"); Spanish, French
6
+ * and Italian always say "Organización"/"organisation"/"organizzazione" (never the
7
+ * "tenant" loanword). Only translation *values* are
7
8
  * checked — JSON key names like `tenant.members.*` are ignored. Role identifiers
8
9
  * such as TenantAdmin/SystemAdmin in prose are allowed.
9
10
  *
@@ -29,7 +30,12 @@ const SCAN: ScanSpec = {
29
30
  scope: "source",
30
31
  extensions: ["ts"],
31
32
  kinds: ["framework"],
32
- frameworkWithin: ["packages/locale-de/src/strings.ts", "packages/locale-es/src/strings.ts"],
33
+ frameworkWithin: [
34
+ "packages/locale-de/src/strings.ts",
35
+ "packages/locale-es/src/strings.ts",
36
+ "packages/locale-fr/src/strings.ts",
37
+ "packages/locale-it/src/strings.ts",
38
+ ],
33
39
  };
34
40
  const IGNORE_TAG = "kumiko-lint-ignore i18n-locale-terminology";
35
41
 
@@ -38,7 +44,9 @@ type LocaleRule = {
38
44
  readonly forbidden: readonly RegExp[];
39
45
  };
40
46
 
41
- const RULES: Record<"de" | "es", LocaleRule> = {
47
+ type TerminologyLocale = "de" | "es" | "fr" | "it";
48
+
49
+ const RULES: Record<TerminologyLocale, LocaleRule> = {
42
50
  de: {
43
51
  preferred: "Mandant",
44
52
  // Tenants? covers plural; Organisation(en|s)? without trailing \b so
@@ -50,11 +58,21 @@ const RULES: Record<"de" | "es", LocaleRule> = {
50
58
  preferred: "Organización",
51
59
  forbidden: [/\btenants?\b/i],
52
60
  },
61
+ fr: {
62
+ preferred: "organisation",
63
+ forbidden: [/\btenants?\b/i],
64
+ },
65
+ it: {
66
+ preferred: "organizzazione",
67
+ forbidden: [/\btenants?\b/i],
68
+ },
53
69
  };
54
70
 
55
- function localeFromPath(filePath: string): "de" | "es" | undefined {
71
+ function localeFromPath(filePath: string): TerminologyLocale | undefined {
56
72
  if (filePath.includes("locale-de/src/strings.ts")) return "de";
57
73
  if (filePath.includes("locale-es/src/strings.ts")) return "es";
74
+ if (filePath.includes("locale-fr/src/strings.ts")) return "fr";
75
+ if (filePath.includes("locale-it/src/strings.ts")) return "it";
58
76
  return undefined;
59
77
  }
60
78
 
@@ -104,7 +122,7 @@ export function findViolations(files: readonly SourceFile[]): GuardViolation[] {
104
122
  export const guard: AstGuard = {
105
123
  name: "i18n-Locale-Terminology Guard",
106
124
  scan: SCAN,
107
- hint: "DE: Mandant instead of Tenant/Organisation; ES: Organización instead of the tenant loanword. Roles like TenantAdmin are fine.",
125
+ hint: "DE: Mandant instead of Tenant/Organisation; ES/FR/IT: Organización/organisation/organizzazione instead of the tenant loanword. Roles like TenantAdmin are fine.",
108
126
  run(files, roots: readonly RepoRoot[] = resolveRepoRoots()) {
109
127
  const violations = findViolations(files)
110
128
  .map((v) => ({ ...v, file: relFromRepoRoot(v.file, roots) }))
@@ -60,7 +60,7 @@ const PATH_RULES: readonly (readonly [RegExp, Runtime])[] = [
60
60
  [/(?:^|\/)ui-types\//, "client"],
61
61
 
62
62
  // Same reasoning, two more shapes: a `web.ts`/`web/` subpath is the
63
- // established convention (locale-de, locale-es, bundled-features) for the
63
+ // established convention (locale-de, locale-es, locale-fr, locale-it, bundled-features) for the
64
64
  // client-safe slice of an otherwise `"runtime"`-marked package — the
65
65
  // package.json marker classifies the whole package, this carves the
66
66
  // deliberately-named exception back out. Deliberately workspace-wide (any
@@ -79,10 +79,10 @@ const PATH_RULES: readonly (readonly [RegExp, Runtime])[] = [
79
79
  // More single-file carve-outs, same "package marker is coarser than the
80
80
  // file" shape, verified case by case rather than by a directory
81
81
  // convention:
82
- // - locale-{de,es}/src/strings.ts: pure string-constant data (zero
82
+ // - locale-{de,es,fr,it}/src/strings.ts: pure string-constant data (zero
83
83
  // imports), re-exported by the already-client `web.ts` sibling in the
84
84
  // same package but shadowed by the package's own `"runtime"` marker.
85
- [/^packages\/locale-(?:de|es)\/src\/strings\.ts$/, "client"],
85
+ [/^packages\/locale-(?:de|es|fr|it)\/src\/strings\.ts$/, "client"],
86
86
  // - dev-server/src/env-schema.ts: a zod-only schema, no dev-server-
87
87
  // internal imports — safe to carve out on its own.
88
88
  [/^packages\/dev-server\/src\/env-schema\.ts$/, "client"],