@omnifyjp/ts 5.8.13 → 5.8.15

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.
@@ -7,7 +7,25 @@
7
7
  import { SchemaReader } from './schema-reader.js';
8
8
  import type { GeneratedFile, PhpConfig } from './types.js';
9
9
  import type { SchemaDefinition, SingleCondition } from '../types.js';
10
- /** Generate Laravel Policy classes for all schemas that have policies. */
10
+ /** Generate Laravel Policy classes for project-owned visible schemas.
11
+ *
12
+ * Issue #98 v5.8.14: every `kind: object` schema now gets a generated
13
+ * policy base + editable stub by default — Laravel's policy
14
+ * auto-discovery (`App\\Models\\<Name>` → `App\\Policies\\<Name>Policy`)
15
+ * works out of the box without per-project Gate::policy(...) wiring.
16
+ *
17
+ * Skip rules:
18
+ * - `kind: pivot` — pivots have no API surface
19
+ * - `options.policy: false` — explicit per-schema opt-out
20
+ *
21
+ * Two code paths per schema:
22
+ * - Explicit Cedar-style `policies: [...]` → existing rule-based body
23
+ * generator (forbid / permit / when conditions).
24
+ * - No `policies:` declared → standard CRUD scaffolding (viewAny /
25
+ * view / create / update / delete + restore / forceDelete on
26
+ * softDelete). Default body: `return true;`. Project secures by
27
+ * overriding the method in the editable child.
28
+ */
11
29
  export declare function generatePolicies(reader: SchemaReader, config: PhpConfig): GeneratedFile[];
12
30
  /** Convert a single condition to a PHP expression. */
13
31
  export declare function conditionToPhp(cond: SingleCondition, schema: SchemaDefinition, reader: SchemaReader): string;
@@ -24,11 +24,31 @@ const RECORD_ACTIONS = new Set(['view', 'edit', 'delete']);
24
24
  // ============================================================================
25
25
  // Public API
26
26
  // ============================================================================
27
- /** Generate Laravel Policy classes for all schemas that have policies. */
27
+ /** Generate Laravel Policy classes for project-owned visible schemas.
28
+ *
29
+ * Issue #98 v5.8.14: every `kind: object` schema now gets a generated
30
+ * policy base + editable stub by default — Laravel's policy
31
+ * auto-discovery (`App\\Models\\<Name>` → `App\\Policies\\<Name>Policy`)
32
+ * works out of the box without per-project Gate::policy(...) wiring.
33
+ *
34
+ * Skip rules:
35
+ * - `kind: pivot` — pivots have no API surface
36
+ * - `options.policy: false` — explicit per-schema opt-out
37
+ *
38
+ * Two code paths per schema:
39
+ * - Explicit Cedar-style `policies: [...]` → existing rule-based body
40
+ * generator (forbid / permit / when conditions).
41
+ * - No `policies:` declared → standard CRUD scaffolding (viewAny /
42
+ * view / create / update / delete + restore / forceDelete on
43
+ * softDelete). Default body: `return true;`. Project secures by
44
+ * overriding the method in the editable child.
45
+ */
28
46
  export function generatePolicies(reader, config) {
29
47
  const files = [];
30
48
  for (const [name, schema] of Object.entries(reader.getProjectVisibleObjectSchemas())) {
31
- if (!schema.policies || schema.policies.length === 0)
49
+ if (schema.kind === 'pivot')
50
+ continue;
51
+ if (schema.options?.policy === false)
32
52
  continue;
33
53
  files.push(...generateForSchema(name, schema, reader, config));
34
54
  }
@@ -45,7 +65,16 @@ function generateForSchema(name, schema, reader, config) {
45
65
  }
46
66
  function generateBasePolicyClass(name, schema, reader, config) {
47
67
  const modelName = toPascalCase(name);
48
- const baseNamespace = resolveModularBaseNamespace(config, name, 'Policies', config.policies.baseNamespace);
68
+ // Issue #98 v5.8.15: legacy structure must nest the policy base's
69
+ // `namespace ...;` declaration by group folder so it matches the
70
+ // grouped path on disk. Pre-fix every base emitted
71
+ // `namespace App\\Omnify\\Policies;` (FLAT) while the file lived at
72
+ // `app/Omnify/Policies/<Group>/<Name>Policy.php` — PSR-4 autoload
73
+ // failed at runtime for every grouped policy. Same template fix
74
+ // that v5.8.2 applied to Requests / Resources / Services.
75
+ const baseNamespace = config.structure === 'modular'
76
+ ? resolveModularBaseNamespace(config, name, 'Policies', config.policies.baseNamespace)
77
+ : nestByGroup({ path: '', namespace: config.policies.baseNamespace }, schema.group).namespace;
49
78
  // Issue #98 v5.8.13: policy method signatures (`view(User $user,
50
79
  // <Model> $record): bool`) must type-hint the USER-EDITABLE Model
51
80
  // class. Same root cause + fix as the v5.8.11 service / controller
@@ -59,24 +88,36 @@ function generateBasePolicyClass(name, schema, reader, config) {
59
88
  : (config.models.userEditableGroupByFolder
60
89
  ? nestByGroup({ path: '', namespace: config.models.userEditableNamespace }, schema.group).namespace
61
90
  : config.models.userEditableNamespace);
62
- const policies = schema.policies;
91
+ // Issue #98 v5.8.14: when no Cedar-style `policies:` array is defined,
92
+ // emit the standard CRUD scaffold with `return true;` bodies.
93
+ // The project secures the policy by overriding methods in the
94
+ // editable child (e.g. `return $user->hasPermission('manage.banner');`).
95
+ const policies = schema.policies ?? [];
96
+ const hasExplicitPolicies = policies.length > 0;
63
97
  const hasSoftDelete = schema.options?.softDelete ?? false;
64
- const needsCidrHelper = policiesUseCidr(policies);
65
- // Collect all actions that have policies
66
- const expandedPolicies = expandWildcards(policies);
98
+ const needsCidrHelper = hasExplicitPolicies ? policiesUseCidr(policies) : false;
99
+ // Collect all actions that have policies (only relevant for the
100
+ // explicit-policy path; standard CRUD doesn't need wildcard expansion).
101
+ const expandedPolicies = hasExplicitPolicies ? expandWildcards(policies) : policies;
67
102
  // Build methods
68
103
  const methods = [];
69
104
  for (const action of ALL_ACTIONS) {
70
105
  const methodName = ACTION_METHOD_MAP[action];
71
106
  const hasRecord = RECORD_ACTIONS.has(action);
72
- const body = generateMethodBody(action, expandedPolicies, schema, reader, hasRecord);
107
+ const body = hasExplicitPolicies
108
+ ? generateMethodBody(action, expandedPolicies, schema, reader, hasRecord)
109
+ : ' return true;';
73
110
  methods.push(buildMethod(methodName, modelName, hasRecord, body));
74
111
  }
75
112
  // SoftDelete: restore + forceDelete
76
113
  if (hasSoftDelete) {
77
- const restoreBody = generateMethodBody('delete', expandedPolicies, schema, reader);
114
+ const restoreBody = hasExplicitPolicies
115
+ ? generateMethodBody('delete', expandedPolicies, schema, reader)
116
+ : ' return true;';
78
117
  methods.push(buildMethod('restore', modelName, true, restoreBody));
79
- const forceDeleteBody = generateMethodBody('delete', expandedPolicies, schema, reader);
118
+ const forceDeleteBody = hasExplicitPolicies
119
+ ? generateMethodBody('delete', expandedPolicies, schema, reader)
120
+ : ' return true;';
80
121
  methods.push(buildMethod('forceDelete', modelName, true, forceDeleteBody));
81
122
  }
82
123
  const cidrHelper = needsCidrHelper ? buildCidrHelper() : '';
package/dist/types.d.ts CHANGED
@@ -208,6 +208,17 @@ export interface SchemaOptions {
208
208
  * generate time).
209
209
  */
210
210
  readonly service?: ServiceOptions | false;
211
+ /**
212
+ * Per-schema opt-out for the auto-generated Policy. Issue #98 v5.8.14:
213
+ * every `kind: object` schema gets a generated policy base + editable
214
+ * stub by default. Set `policy: false` on schemas that should NOT have
215
+ * an authorization policy (translation tables, internal sidecars, etc).
216
+ * Cedar-style ABAC `policies:` array on the root schema definition
217
+ * still drives the generated method bodies when present; otherwise the
218
+ * generator emits a standard 5-method CRUD scaffold with
219
+ * `return true;` bodies for the project to override in the editable.
220
+ */
221
+ readonly policy?: false;
211
222
  /** Schema-level default ordering — generates a global Eloquent scope. Issue #40. */
212
223
  readonly defaultOrder?: readonly OrderByItem[];
213
224
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnifyjp/ts",
3
- "version": "5.8.13",
3
+ "version": "5.8.15",
4
4
  "description": "TypeScript model type generator from Omnify schemas.json",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",