@wp-typia/project-tools 0.15.0 → 0.15.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/dist/runtime/cli-add.js +26 -70
- package/dist/runtime/cli-doctor.js +25 -9
- package/dist/runtime/cli-help.js +1 -0
- package/dist/runtime/cli-templates.js +10 -0
- package/dist/runtime/json-utils.d.ts +5 -8
- package/dist/runtime/json-utils.js +5 -10
- package/dist/runtime/metadata-analysis.d.ts +7 -11
- package/dist/runtime/metadata-analysis.js +7 -285
- package/dist/runtime/metadata-model.d.ts +7 -84
- package/dist/runtime/metadata-model.js +7 -59
- package/dist/runtime/metadata-parser.d.ts +5 -51
- package/dist/runtime/metadata-parser.js +5 -792
- package/dist/runtime/metadata-php-render.d.ts +5 -27
- package/dist/runtime/metadata-php-render.js +5 -547
- package/dist/runtime/metadata-projection.d.ts +7 -7
- package/dist/runtime/metadata-projection.js +7 -233
- package/dist/runtime/object-utils.d.ts +1 -1
- package/dist/runtime/object-utils.js +3 -6
- package/dist/runtime/persistence-rest-artifacts.d.ts +76 -0
- package/dist/runtime/persistence-rest-artifacts.js +99 -0
- package/dist/runtime/scaffold.d.ts +10 -2
- package/dist/runtime/scaffold.js +95 -1
- package/dist/runtime/template-builtins.js +1 -1
- package/dist/runtime/template-registry.d.ts +2 -1
- package/dist/runtime/template-registry.js +13 -2
- package/package.json +9 -8
- package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +103 -7
- package/templates/_shared/persistence/core/src/api-validators.ts.mustache +14 -0
- package/templates/_shared/persistence/core/src/api.ts.mustache +28 -9
- package/templates/_shared/persistence/core/src/interactivity.ts.mustache +17 -11
- package/templates/interactivity/src/block.json.mustache +1 -0
- package/templates/interactivity/src/editor.scss.mustache +8 -0
- package/templates/interactivity/src/index.tsx.mustache +1 -0
- package/templates/persistence/src/edit.tsx.mustache +6 -6
|
@@ -1,29 +1,7 @@
|
|
|
1
|
-
import type { ManifestAttribute, ManifestDocument } from "./metadata-model.js";
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @returns Generated PHP source plus any warn-only coverage gaps discovered
|
|
8
|
-
* while traversing the manifest.
|
|
2
|
+
* Re-exports PHP metadata rendering helpers from `@wp-typia/block-runtime`.
|
|
3
|
+
* This adapter keeps the public project-tools runtime path stable while the
|
|
4
|
+
* implementation is consolidated in block-runtime.
|
|
5
|
+
* @module
|
|
9
6
|
*/
|
|
10
|
-
export
|
|
11
|
-
source: string;
|
|
12
|
-
warnings: string[];
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* Collect warn-only PHP validator generation gaps for one manifest branch.
|
|
16
|
-
*
|
|
17
|
-
* @param attribute Manifest attribute metadata to inspect.
|
|
18
|
-
* @param pathLabel Human-readable path used in emitted warning messages.
|
|
19
|
-
* @param warnings Mutable accumulator that receives any discovered warnings.
|
|
20
|
-
*/
|
|
21
|
-
export declare function collectPhpGenerationWarnings(attribute: ManifestAttribute, pathLabel: string, warnings: string[]): void;
|
|
22
|
-
/**
|
|
23
|
-
* Render one JavaScript value into a PHP literal string.
|
|
24
|
-
*
|
|
25
|
-
* @param value JSON-like value to encode for the generated validator manifest.
|
|
26
|
-
* @param indentLevel Current indentation depth, expressed in tab levels.
|
|
27
|
-
* @returns PHP source code representing the provided value.
|
|
28
|
-
*/
|
|
29
|
-
export declare function renderPhpValue(value: unknown, indentLevel: number): string;
|
|
7
|
+
export * from "@wp-typia/block-runtime/metadata-php-render";
|
|
@@ -1,549 +1,7 @@
|
|
|
1
|
-
const SUPPORTED_PHP_FORMATS = new Set([
|
|
2
|
-
"uuid",
|
|
3
|
-
"email",
|
|
4
|
-
"url",
|
|
5
|
-
"uri",
|
|
6
|
-
"ipv4",
|
|
7
|
-
"ipv6",
|
|
8
|
-
"date-time",
|
|
9
|
-
]);
|
|
10
|
-
const SUPPORTED_PHP_TYPE_TAGS = new Set([
|
|
11
|
-
"uint32",
|
|
12
|
-
"int32",
|
|
13
|
-
"uint64",
|
|
14
|
-
"float",
|
|
15
|
-
"double",
|
|
16
|
-
]);
|
|
17
1
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* @returns Generated PHP source plus any warn-only coverage gaps discovered
|
|
23
|
-
* while traversing the manifest.
|
|
2
|
+
* Re-exports PHP metadata rendering helpers from `@wp-typia/block-runtime`.
|
|
3
|
+
* This adapter keeps the public project-tools runtime path stable while the
|
|
4
|
+
* implementation is consolidated in block-runtime.
|
|
5
|
+
* @module
|
|
24
6
|
*/
|
|
25
|
-
export
|
|
26
|
-
const warnings = [];
|
|
27
|
-
for (const [key, attribute] of Object.entries(manifest.attributes)) {
|
|
28
|
-
collectPhpGenerationWarnings(attribute, key, warnings);
|
|
29
|
-
}
|
|
30
|
-
const phpManifest = renderPhpValue(manifest, 2);
|
|
31
|
-
return {
|
|
32
|
-
source: `<?php
|
|
33
|
-
declare(strict_types=1);
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Generated from typia.manifest.json. Do not edit manually.
|
|
37
|
-
*/
|
|
38
|
-
return new class {
|
|
39
|
-
\tprivate array $manifest = ${phpManifest};
|
|
40
|
-
|
|
41
|
-
\tpublic function apply_defaults(array $attributes): array
|
|
42
|
-
\t{
|
|
43
|
-
\t\treturn $this->applyDefaultsForObject($attributes, $this->manifest['attributes'] ?? []);
|
|
44
|
-
\t}
|
|
45
|
-
|
|
46
|
-
\tpublic function validate(array $attributes): array
|
|
47
|
-
\t{
|
|
48
|
-
\t\t$normalized = $this->apply_defaults($attributes);
|
|
49
|
-
\t\t$errors = [];
|
|
50
|
-
|
|
51
|
-
\t\tforeach (($this->manifest['attributes'] ?? []) as $name => $attribute) {
|
|
52
|
-
\t\t\t$this->validateAttribute(
|
|
53
|
-
\t\t\t\tarray_key_exists($name, $normalized),
|
|
54
|
-
\t\t\t\t$normalized[$name] ?? null,
|
|
55
|
-
\t\t\t\t$attribute,
|
|
56
|
-
\t\t\t\t(string) $name,
|
|
57
|
-
\t\t\t\t$errors,
|
|
58
|
-
\t\t\t);
|
|
59
|
-
\t\t}
|
|
60
|
-
|
|
61
|
-
\t\treturn [
|
|
62
|
-
\t\t\t'errors' => $errors,
|
|
63
|
-
\t\t\t'valid' => count($errors) === 0,
|
|
64
|
-
\t\t];
|
|
65
|
-
\t}
|
|
66
|
-
|
|
67
|
-
\tpublic function is_valid(array $attributes): bool
|
|
68
|
-
\t{
|
|
69
|
-
\t\treturn $this->validate($attributes)['valid'];
|
|
70
|
-
\t}
|
|
71
|
-
|
|
72
|
-
\tprivate function applyDefaultsForObject(array $attributes, array $schema): array
|
|
73
|
-
\t{
|
|
74
|
-
\t\t$result = $attributes;
|
|
75
|
-
|
|
76
|
-
\t\tforeach ($schema as $name => $attribute) {
|
|
77
|
-
\t\t\tif (!array_key_exists($name, $result)) {
|
|
78
|
-
\t\t\t\t$derivedDefault = $this->deriveDefaultValue($attribute);
|
|
79
|
-
\t\t\t\tif ($derivedDefault !== null) {
|
|
80
|
-
\t\t\t\t\t$result[$name] = $derivedDefault;
|
|
81
|
-
\t\t\t\t}
|
|
82
|
-
\t\t\t\tcontinue;
|
|
83
|
-
\t\t\t}
|
|
84
|
-
|
|
85
|
-
\t\t\t$result[$name] = $this->applyDefaultsForNode($result[$name], $attribute);
|
|
86
|
-
\t\t}
|
|
87
|
-
|
|
88
|
-
\t\treturn $result;
|
|
89
|
-
\t}
|
|
90
|
-
|
|
91
|
-
\tprivate function applyDefaultsForNode($value, array $attribute)
|
|
92
|
-
\t{
|
|
93
|
-
\t\tif ($value === null) {
|
|
94
|
-
\t\t\treturn null;
|
|
95
|
-
\t\t}
|
|
96
|
-
|
|
97
|
-
\t\t$kind = $attribute['ts']['kind'] ?? $attribute['wp']['type'] ?? null;
|
|
98
|
-
\t\tif ($kind === 'union') {
|
|
99
|
-
\t\t\treturn $this->applyDefaultsForUnion($value, $attribute);
|
|
100
|
-
\t\t}
|
|
101
|
-
\t\tif ($kind === 'object' && is_array($value) && !$this->isListArray($value)) {
|
|
102
|
-
\t\t\treturn $this->applyDefaultsForObject($value, $attribute['ts']['properties'] ?? []);
|
|
103
|
-
\t\t}
|
|
104
|
-
\t\tif (
|
|
105
|
-
\t\t\t$kind === 'array' &&
|
|
106
|
-
\t\t\tis_array($value) &&
|
|
107
|
-
\t\t\t$this->isListArray($value) &&
|
|
108
|
-
\t\t\tisset($attribute['ts']['items']) &&
|
|
109
|
-
\t\t\tis_array($attribute['ts']['items'])
|
|
110
|
-
\t\t) {
|
|
111
|
-
\t\t\t$result = [];
|
|
112
|
-
\t\t\tforeach ($value as $index => $item) {
|
|
113
|
-
\t\t\t\t$result[$index] = $this->applyDefaultsForNode($item, $attribute['ts']['items']);
|
|
114
|
-
\t\t\t}
|
|
115
|
-
\t\t\treturn $result;
|
|
116
|
-
\t\t}
|
|
117
|
-
|
|
118
|
-
\t\treturn $value;
|
|
119
|
-
\t}
|
|
120
|
-
|
|
121
|
-
\tprivate function deriveDefaultValue(array $attribute)
|
|
122
|
-
\t{
|
|
123
|
-
\t\tif ($this->hasDefault($attribute)) {
|
|
124
|
-
\t\t\treturn $attribute['typia']['defaultValue'];
|
|
125
|
-
\t\t}
|
|
126
|
-
|
|
127
|
-
\t\t$kind = $attribute['ts']['kind'] ?? $attribute['wp']['type'] ?? null;
|
|
128
|
-
\t\tif ($kind !== 'object') {
|
|
129
|
-
\t\t\treturn null;
|
|
130
|
-
\t\t}
|
|
131
|
-
|
|
132
|
-
\t\t$properties = $attribute['ts']['properties'] ?? null;
|
|
133
|
-
\t\tif (!is_array($properties)) {
|
|
134
|
-
\t\t\treturn null;
|
|
135
|
-
\t\t}
|
|
136
|
-
|
|
137
|
-
\t\t$derived = [];
|
|
138
|
-
\t\tforeach ($properties as $name => $child) {
|
|
139
|
-
\t\t\tif (!is_array($child)) {
|
|
140
|
-
\t\t\t\tcontinue;
|
|
141
|
-
\t\t\t}
|
|
142
|
-
\t\t\t$childDefault = $this->deriveDefaultValue($child);
|
|
143
|
-
\t\t\tif ($childDefault !== null) {
|
|
144
|
-
\t\t\t\t$derived[$name] = $childDefault;
|
|
145
|
-
\t\t\t}
|
|
146
|
-
\t\t}
|
|
147
|
-
|
|
148
|
-
\t\treturn count($derived) > 0 ? $derived : null;
|
|
149
|
-
\t}
|
|
150
|
-
|
|
151
|
-
\tprivate function applyDefaultsForUnion($value, array $attribute)
|
|
152
|
-
\t{
|
|
153
|
-
\t\tif (!is_array($value) || $this->isListArray($value)) {
|
|
154
|
-
\t\t\treturn $value;
|
|
155
|
-
\t\t}
|
|
156
|
-
|
|
157
|
-
\t\t$union = $attribute['ts']['union'] ?? null;
|
|
158
|
-
\t\tif (!is_array($union)) {
|
|
159
|
-
\t\t\treturn $value;
|
|
160
|
-
\t\t}
|
|
161
|
-
|
|
162
|
-
\t\t$discriminator = $union['discriminator'] ?? null;
|
|
163
|
-
\t\tif (!is_string($discriminator) || !array_key_exists($discriminator, $value)) {
|
|
164
|
-
\t\t\treturn $value;
|
|
165
|
-
\t\t}
|
|
166
|
-
|
|
167
|
-
\t\t$branchKey = $value[$discriminator];
|
|
168
|
-
\t\tif (!is_string($branchKey) || !isset($union['branches'][$branchKey]) || !is_array($union['branches'][$branchKey])) {
|
|
169
|
-
\t\t\treturn $value;
|
|
170
|
-
\t\t}
|
|
171
|
-
|
|
172
|
-
\t\treturn $this->applyDefaultsForNode($value, $union['branches'][$branchKey]);
|
|
173
|
-
\t}
|
|
174
|
-
|
|
175
|
-
\tprivate function validateAttribute(bool $exists, $value, array $attribute, string $path, array &$errors): void
|
|
176
|
-
\t{
|
|
177
|
-
\t\tif (!$exists) {
|
|
178
|
-
\t\t\tif (($attribute['ts']['required'] ?? false) && !$this->hasDefault($attribute)) {
|
|
179
|
-
\t\t\t\t$errors[] = sprintf('%s is required', $path);
|
|
180
|
-
\t\t\t}
|
|
181
|
-
\t\t\treturn;
|
|
182
|
-
\t\t}
|
|
183
|
-
|
|
184
|
-
\t\t$kind = $attribute['ts']['kind'] ?? $attribute['wp']['type'] ?? null;
|
|
185
|
-
\t\tif (!is_string($kind) || $kind === '') {
|
|
186
|
-
\t\t\t$errors[] = sprintf('%s has an invalid schema kind', $path);
|
|
187
|
-
\t\t\treturn;
|
|
188
|
-
\t\t}
|
|
189
|
-
\t\tif ($value === null) {
|
|
190
|
-
\t\t\t$errors[] = sprintf('%s must be %s', $path, $this->expectedKindLabel($attribute));
|
|
191
|
-
\t\t\treturn;
|
|
192
|
-
\t\t}
|
|
193
|
-
|
|
194
|
-
\t\tif (($attribute['wp']['enum'] ?? null) !== null && !$this->valueInEnum($value, $attribute['wp']['enum'])) {
|
|
195
|
-
\t\t\t$errors[] = sprintf('%s must be one of %s', $path, implode(', ', $attribute['wp']['enum']));
|
|
196
|
-
\t\t}
|
|
197
|
-
|
|
198
|
-
\t\tswitch ($kind) {
|
|
199
|
-
\t\t\tcase 'string':
|
|
200
|
-
\t\t\t\tif (!is_string($value)) {
|
|
201
|
-
\t\t\t\t\t$errors[] = sprintf('%s must be string', $path);
|
|
202
|
-
\t\t\t\t\treturn;
|
|
203
|
-
\t\t\t\t}
|
|
204
|
-
\t\t\t\t$this->validateString($value, $attribute, $path, $errors);
|
|
205
|
-
\t\t\t\treturn;
|
|
206
|
-
\t\t\tcase 'number':
|
|
207
|
-
\t\t\t\t$allowsUint64String =
|
|
208
|
-
\t\t\t\t\t($attribute['typia']['constraints']['typeTag'] ?? null) === 'uint64' &&
|
|
209
|
-
\t\t\t\t\t$this->matchesUint64($value);
|
|
210
|
-
\t\t\t\tif (!$this->isNumber($value) && !$allowsUint64String) {
|
|
211
|
-
\t\t\t\t\t$errors[] = sprintf('%s must be number', $path);
|
|
212
|
-
\t\t\t\t\treturn;
|
|
213
|
-
\t\t\t\t}
|
|
214
|
-
\t\t\t\t$this->validateNumber($value, $attribute, $path, $errors);
|
|
215
|
-
\t\t\t\treturn;
|
|
216
|
-
\t\t\tcase 'boolean':
|
|
217
|
-
\t\t\t\tif (!is_bool($value)) {
|
|
218
|
-
\t\t\t\t\t$errors[] = sprintf('%s must be boolean', $path);
|
|
219
|
-
\t\t\t\t}
|
|
220
|
-
\t\t\t\treturn;
|
|
221
|
-
\t\t\tcase 'array':
|
|
222
|
-
\t\t\t\tif (!is_array($value) || !$this->isListArray($value)) {
|
|
223
|
-
\t\t\t\t\t$errors[] = sprintf('%s must be array', $path);
|
|
224
|
-
\t\t\t\t\treturn;
|
|
225
|
-
\t\t\t\t}
|
|
226
|
-
\t\t\t\t$this->validateArray($value, $attribute, $path, $errors);
|
|
227
|
-
\t\t\t\tif (isset($attribute['ts']['items']) && is_array($attribute['ts']['items'])) {
|
|
228
|
-
\t\t\t\t\tforeach ($value as $index => $item) {
|
|
229
|
-
\t\t\t\t\t\t$this->validateAttribute(true, $item, $attribute['ts']['items'], sprintf('%s[%s]', $path, (string) $index), $errors);
|
|
230
|
-
\t\t\t\t\t}
|
|
231
|
-
\t\t\t\t}
|
|
232
|
-
\t\t\t\treturn;
|
|
233
|
-
\t\t\tcase 'object':
|
|
234
|
-
\t\t\t\tif (!is_array($value) || $this->isListArray($value)) {
|
|
235
|
-
\t\t\t\t\t$errors[] = sprintf('%s must be object', $path);
|
|
236
|
-
\t\t\t\t\treturn;
|
|
237
|
-
\t\t\t\t}
|
|
238
|
-
\t\t\t\tforeach (($attribute['ts']['properties'] ?? []) as $name => $child) {
|
|
239
|
-
\t\t\t\t\t$this->validateAttribute(
|
|
240
|
-
\t\t\t\t\t\tarray_key_exists($name, $value),
|
|
241
|
-
\t\t\t\t\t\t$value[$name] ?? null,
|
|
242
|
-
\t\t\t\t\t\t$child,
|
|
243
|
-
\t\t\t\t\t\tsprintf('%s.%s', $path, (string) $name),
|
|
244
|
-
\t\t\t\t\t\t$errors,
|
|
245
|
-
\t\t\t\t\t);
|
|
246
|
-
\t\t\t\t}
|
|
247
|
-
\t\t\t\treturn;
|
|
248
|
-
\t\t\tcase 'union':
|
|
249
|
-
\t\t\t\t$this->validateUnion($value, $attribute, $path, $errors);
|
|
250
|
-
\t\t\t\treturn;
|
|
251
|
-
\t\t\tdefault:
|
|
252
|
-
\t\t\t\t$errors[] = sprintf('%s has unsupported schema kind %s', $path, $kind);
|
|
253
|
-
\t\t}
|
|
254
|
-
\t}
|
|
255
|
-
|
|
256
|
-
\tprivate function validateUnion($value, array $attribute, string $path, array &$errors): void
|
|
257
|
-
\t{
|
|
258
|
-
\t\tif (!is_array($value) || $this->isListArray($value)) {
|
|
259
|
-
\t\t\t$errors[] = sprintf('%s must be object', $path);
|
|
260
|
-
\t\t\treturn;
|
|
261
|
-
\t\t}
|
|
262
|
-
|
|
263
|
-
\t\t$union = $attribute['ts']['union'] ?? null;
|
|
264
|
-
\t\tif (!is_array($union)) {
|
|
265
|
-
\t\t\t$errors[] = sprintf('%s has invalid union schema metadata', $path);
|
|
266
|
-
\t\t\treturn;
|
|
267
|
-
\t\t}
|
|
268
|
-
|
|
269
|
-
\t\t$discriminator = $union['discriminator'] ?? null;
|
|
270
|
-
\t\tif (!is_string($discriminator) || $discriminator === '') {
|
|
271
|
-
\t\t\t$errors[] = sprintf('%s has invalid union discriminator metadata', $path);
|
|
272
|
-
\t\t\treturn;
|
|
273
|
-
\t\t}
|
|
274
|
-
\t\tif (!array_key_exists($discriminator, $value)) {
|
|
275
|
-
\t\t\t$errors[] = sprintf('%s.%s is required', $path, $discriminator);
|
|
276
|
-
\t\t\treturn;
|
|
277
|
-
\t\t}
|
|
278
|
-
|
|
279
|
-
\t\t$branchKey = $value[$discriminator];
|
|
280
|
-
\t\tif (!is_string($branchKey)) {
|
|
281
|
-
\t\t\t$errors[] = sprintf('%s.%s must be string', $path, $discriminator);
|
|
282
|
-
\t\t\treturn;
|
|
283
|
-
\t\t}
|
|
284
|
-
\t\tif (!isset($union['branches'][$branchKey]) || !is_array($union['branches'][$branchKey])) {
|
|
285
|
-
\t\t\t$errors[] = sprintf('%s.%s must be one of %s', $path, $discriminator, implode(', ', array_keys($union['branches'] ?? [])));
|
|
286
|
-
\t\t\treturn;
|
|
287
|
-
\t\t}
|
|
288
|
-
|
|
289
|
-
\t\t$this->validateAttribute(true, $value, $union['branches'][$branchKey], $path, $errors);
|
|
290
|
-
\t}
|
|
291
|
-
|
|
292
|
-
\tprivate function validateString(string $value, array $attribute, string $path, array &$errors): void
|
|
293
|
-
\t{
|
|
294
|
-
\t\t$constraints = $attribute['typia']['constraints'] ?? [];
|
|
295
|
-
|
|
296
|
-
\t\tif (isset($constraints['minLength']) && is_int($constraints['minLength']) && strlen($value) < $constraints['minLength']) {
|
|
297
|
-
\t\t\t$errors[] = sprintf('%s must be at least %d characters', $path, $constraints['minLength']);
|
|
298
|
-
\t\t}
|
|
299
|
-
\t\tif (isset($constraints['maxLength']) && is_int($constraints['maxLength']) && strlen($value) > $constraints['maxLength']) {
|
|
300
|
-
\t\t\t$errors[] = sprintf('%s must be at most %d characters', $path, $constraints['maxLength']);
|
|
301
|
-
\t\t}
|
|
302
|
-
\t\tif (
|
|
303
|
-
\t\t\tisset($constraints['pattern']) &&
|
|
304
|
-
\t\t\tis_string($constraints['pattern']) &&
|
|
305
|
-
\t\t\t$constraints['pattern'] !== '' &&
|
|
306
|
-
\t\t\t!$this->matchesPattern($constraints['pattern'], $value)
|
|
307
|
-
\t\t) {
|
|
308
|
-
\t\t\t$errors[] = sprintf('%s does not match %s', $path, $constraints['pattern']);
|
|
309
|
-
\t\t}
|
|
310
|
-
\t\tif (
|
|
311
|
-
\t\t\tisset($constraints['format']) &&
|
|
312
|
-
\t\t\tis_string($constraints['format']) &&
|
|
313
|
-
\t\t\t!$this->matchesFormat($constraints['format'], $value)
|
|
314
|
-
\t\t) {
|
|
315
|
-
\t\t\t$errors[] = sprintf('%s must match format %s', $path, $constraints['format']);
|
|
316
|
-
\t\t}
|
|
317
|
-
\t}
|
|
318
|
-
|
|
319
|
-
\tprivate function validateArray(array $value, array $attribute, string $path, array &$errors): void
|
|
320
|
-
\t{
|
|
321
|
-
\t\t$constraints = $attribute['typia']['constraints'] ?? [];
|
|
322
|
-
|
|
323
|
-
\t\tif (isset($constraints['minItems']) && is_int($constraints['minItems']) && count($value) < $constraints['minItems']) {
|
|
324
|
-
\t\t\t$errors[] = sprintf('%s must have at least %d items', $path, $constraints['minItems']);
|
|
325
|
-
\t\t}
|
|
326
|
-
\t\tif (isset($constraints['maxItems']) && is_int($constraints['maxItems']) && count($value) > $constraints['maxItems']) {
|
|
327
|
-
\t\t\t$errors[] = sprintf('%s must have at most %d items', $path, $constraints['maxItems']);
|
|
328
|
-
\t\t}
|
|
329
|
-
\t}
|
|
330
|
-
|
|
331
|
-
\tprivate function validateNumber($value, array $attribute, string $path, array &$errors): void
|
|
332
|
-
\t{
|
|
333
|
-
\t\t$constraints = $attribute['typia']['constraints'] ?? [];
|
|
334
|
-
|
|
335
|
-
\t\tif (isset($constraints['minimum']) && $this->isNumber($constraints['minimum']) && $value < $constraints['minimum']) {
|
|
336
|
-
\t\t\t$errors[] = sprintf('%s must be >= %s', $path, (string) $constraints['minimum']);
|
|
337
|
-
\t\t}
|
|
338
|
-
\t\tif (isset($constraints['maximum']) && $this->isNumber($constraints['maximum']) && $value > $constraints['maximum']) {
|
|
339
|
-
\t\t\t$errors[] = sprintf('%s must be <= %s', $path, (string) $constraints['maximum']);
|
|
340
|
-
\t\t}
|
|
341
|
-
\t\tif (
|
|
342
|
-
\t\t\tisset($constraints['exclusiveMinimum']) &&
|
|
343
|
-
\t\t\t$this->isNumber($constraints['exclusiveMinimum']) &&
|
|
344
|
-
\t\t\t$value <= $constraints['exclusiveMinimum']
|
|
345
|
-
\t\t) {
|
|
346
|
-
\t\t\t$errors[] = sprintf('%s must be > %s', $path, (string) $constraints['exclusiveMinimum']);
|
|
347
|
-
\t\t}
|
|
348
|
-
\t\tif (
|
|
349
|
-
\t\t\tisset($constraints['exclusiveMaximum']) &&
|
|
350
|
-
\t\t\t$this->isNumber($constraints['exclusiveMaximum']) &&
|
|
351
|
-
\t\t\t$value >= $constraints['exclusiveMaximum']
|
|
352
|
-
\t\t) {
|
|
353
|
-
\t\t\t$errors[] = sprintf('%s must be < %s', $path, (string) $constraints['exclusiveMaximum']);
|
|
354
|
-
\t\t}
|
|
355
|
-
\t\tif (
|
|
356
|
-
\t\t\tisset($constraints['multipleOf']) &&
|
|
357
|
-
\t\t\t$this->isNumber($constraints['multipleOf']) &&
|
|
358
|
-
\t\t\t!$this->matchesMultipleOf($value, $constraints['multipleOf'])
|
|
359
|
-
\t\t) {
|
|
360
|
-
\t\t\t$errors[] = sprintf('%s must be a multiple of %s', $path, (string) $constraints['multipleOf']);
|
|
361
|
-
\t\t}
|
|
362
|
-
\t\tif (
|
|
363
|
-
\t\t\tisset($constraints['typeTag']) &&
|
|
364
|
-
\t\t\tis_string($constraints['typeTag']) &&
|
|
365
|
-
\t\t\t!$this->matchesTypeTag($value, $constraints['typeTag'])
|
|
366
|
-
\t\t) {
|
|
367
|
-
\t\t\t$errors[] = sprintf('%s must be a %s', $path, $constraints['typeTag']);
|
|
368
|
-
\t\t}
|
|
369
|
-
\t}
|
|
370
|
-
|
|
371
|
-
\tprivate function hasDefault(array $attribute): bool
|
|
372
|
-
\t{
|
|
373
|
-
\t\treturn ($attribute['typia']['hasDefault'] ?? false) === true;
|
|
374
|
-
\t}
|
|
375
|
-
|
|
376
|
-
\tprivate function valueInEnum($value, array $enum): bool
|
|
377
|
-
\t{
|
|
378
|
-
\t\tforeach ($enum as $candidate) {
|
|
379
|
-
\t\t\tif ($candidate === $value) {
|
|
380
|
-
\t\t\t\treturn true;
|
|
381
|
-
\t\t\t}
|
|
382
|
-
\t\t}
|
|
383
|
-
\t\treturn false;
|
|
384
|
-
\t}
|
|
385
|
-
|
|
386
|
-
\tprivate function matchesPattern(string $pattern, string $value): bool
|
|
387
|
-
\t{
|
|
388
|
-
\t\t$escapedPattern = str_replace('~', '\\\\~', $pattern);
|
|
389
|
-
\t\t$result = @preg_match('~' . $escapedPattern . '~u', $value);
|
|
390
|
-
\t\treturn $result === 1;
|
|
391
|
-
\t}
|
|
392
|
-
|
|
393
|
-
\tprivate function matchesFormat(string $format, string $value): bool
|
|
394
|
-
\t{
|
|
395
|
-
\t\tswitch ($format) {
|
|
396
|
-
\t\t\tcase 'uuid':
|
|
397
|
-
\t\t\t\treturn preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', $value) === 1;
|
|
398
|
-
\t\t\tcase 'email':
|
|
399
|
-
\t\t\t\treturn filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
|
|
400
|
-
\t\t\tcase 'url':
|
|
401
|
-
\t\t\tcase 'uri':
|
|
402
|
-
\t\t\t\treturn filter_var($value, FILTER_VALIDATE_URL) !== false;
|
|
403
|
-
\t\t\tcase 'ipv4':
|
|
404
|
-
\t\t\t\treturn filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false;
|
|
405
|
-
\t\t\tcase 'ipv6':
|
|
406
|
-
\t\t\t\treturn filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false;
|
|
407
|
-
\t\t\tcase 'date-time':
|
|
408
|
-
\t\t\t\treturn preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/', $value) === 1;
|
|
409
|
-
\t\t\tdefault:
|
|
410
|
-
\t\t\t\treturn true;
|
|
411
|
-
\t\t}
|
|
412
|
-
\t}
|
|
413
|
-
|
|
414
|
-
\tprivate function matchesTypeTag($value, string $typeTag): bool
|
|
415
|
-
\t{
|
|
416
|
-
\t\tswitch ($typeTag) {
|
|
417
|
-
\t\t\tcase 'uint32':
|
|
418
|
-
\t\t\t\treturn is_int($value) && $value >= 0 && $value <= 4294967295;
|
|
419
|
-
\t\t\tcase 'int32':
|
|
420
|
-
\t\t\t\treturn is_int($value) && $value >= -2147483648 && $value <= 2147483647;
|
|
421
|
-
\t\t\tcase 'uint64':
|
|
422
|
-
\t\t\t\treturn $this->matchesUint64($value);
|
|
423
|
-
\t\t\tcase 'float':
|
|
424
|
-
\t\t\tcase 'double':
|
|
425
|
-
\t\t\t\treturn is_int($value) || is_float($value);
|
|
426
|
-
\t\t\tdefault:
|
|
427
|
-
\t\t\t\treturn true;
|
|
428
|
-
\t\t}
|
|
429
|
-
\t}
|
|
430
|
-
|
|
431
|
-
\tprivate function matchesUint64($value): bool
|
|
432
|
-
\t{
|
|
433
|
-
\t\tif (is_int($value)) {
|
|
434
|
-
\t\t\treturn $value >= 0;
|
|
435
|
-
\t\t}
|
|
436
|
-
\t\tif (!is_string($value) || $value === '' || !ctype_digit($value)) {
|
|
437
|
-
\t\t\treturn false;
|
|
438
|
-
\t\t}
|
|
439
|
-
\t\tif (strlen($value) < 20) {
|
|
440
|
-
\t\t\treturn true;
|
|
441
|
-
\t\t}
|
|
442
|
-
\t\tif (strlen($value) > 20) {
|
|
443
|
-
\t\t\treturn false;
|
|
444
|
-
\t\t}
|
|
445
|
-
\t\treturn strcmp($value, '18446744073709551615') <= 0;
|
|
446
|
-
\t}
|
|
447
|
-
|
|
448
|
-
\tprivate function matchesMultipleOf($value, $multipleOf): bool
|
|
449
|
-
\t{
|
|
450
|
-
\t\tif ($multipleOf === 0) {
|
|
451
|
-
\t\t\treturn true;
|
|
452
|
-
\t\t}
|
|
453
|
-
\t\tif (is_int($value) && is_int($multipleOf)) {
|
|
454
|
-
\t\t\treturn $value % $multipleOf === 0;
|
|
455
|
-
\t\t}
|
|
456
|
-
|
|
457
|
-
\t\t$remainder = fmod((float) $value, (float) $multipleOf);
|
|
458
|
-
\t\t$epsilon = 0.000000001;
|
|
459
|
-
\t\treturn abs($remainder) < $epsilon || abs(abs((float) $multipleOf) - abs($remainder)) < $epsilon;
|
|
460
|
-
\t}
|
|
461
|
-
|
|
462
|
-
\tprivate function isNumber($value): bool
|
|
463
|
-
\t{
|
|
464
|
-
\t\treturn is_int($value) || is_float($value);
|
|
465
|
-
\t}
|
|
466
|
-
|
|
467
|
-
\tprivate function isListArray(array $value): bool
|
|
468
|
-
\t{
|
|
469
|
-
\t\t$expectedKey = 0;
|
|
470
|
-
\t\tforeach ($value as $key => $_item) {
|
|
471
|
-
\t\t\tif ($key !== $expectedKey) {
|
|
472
|
-
\t\t\t\treturn false;
|
|
473
|
-
\t\t\t}
|
|
474
|
-
\t\t\t$expectedKey += 1;
|
|
475
|
-
\t\t}
|
|
476
|
-
\t\treturn true;
|
|
477
|
-
\t}
|
|
478
|
-
|
|
479
|
-
\tprivate function expectedKindLabel(array $attribute): string
|
|
480
|
-
\t{
|
|
481
|
-
\t\t$kind = $attribute['ts']['kind'] ?? $attribute['wp']['type'] ?? 'value';
|
|
482
|
-
\t\treturn $kind === 'union' ? 'object' : (string) $kind;
|
|
483
|
-
\t}
|
|
484
|
-
};
|
|
485
|
-
`,
|
|
486
|
-
warnings,
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* Collect warn-only PHP validator generation gaps for one manifest branch.
|
|
491
|
-
*
|
|
492
|
-
* @param attribute Manifest attribute metadata to inspect.
|
|
493
|
-
* @param pathLabel Human-readable path used in emitted warning messages.
|
|
494
|
-
* @param warnings Mutable accumulator that receives any discovered warnings.
|
|
495
|
-
*/
|
|
496
|
-
export function collectPhpGenerationWarnings(attribute, pathLabel, warnings) {
|
|
497
|
-
const { format, typeTag } = attribute.typia.constraints;
|
|
498
|
-
if (format !== null && !SUPPORTED_PHP_FORMATS.has(format)) {
|
|
499
|
-
warnings.push(`${pathLabel}: unsupported PHP validator format "${format}"`);
|
|
500
|
-
}
|
|
501
|
-
if (typeTag !== null && !SUPPORTED_PHP_TYPE_TAGS.has(typeTag)) {
|
|
502
|
-
warnings.push(`${pathLabel}: unsupported PHP validator type tag "${typeTag}"`);
|
|
503
|
-
}
|
|
504
|
-
if (attribute.ts.items) {
|
|
505
|
-
collectPhpGenerationWarnings(attribute.ts.items, `${pathLabel}[]`, warnings);
|
|
506
|
-
}
|
|
507
|
-
for (const [key, property] of Object.entries(attribute.ts.properties ?? {})) {
|
|
508
|
-
collectPhpGenerationWarnings(property, `${pathLabel}.${key}`, warnings);
|
|
509
|
-
}
|
|
510
|
-
for (const [branchKey, branch] of Object.entries(attribute.ts.union?.branches ?? {})) {
|
|
511
|
-
collectPhpGenerationWarnings(branch, `${pathLabel}<${branchKey}>`, warnings);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Render one JavaScript value into a PHP literal string.
|
|
516
|
-
*
|
|
517
|
-
* @param value JSON-like value to encode for the generated validator manifest.
|
|
518
|
-
* @param indentLevel Current indentation depth, expressed in tab levels.
|
|
519
|
-
* @returns PHP source code representing the provided value.
|
|
520
|
-
*/
|
|
521
|
-
export function renderPhpValue(value, indentLevel) {
|
|
522
|
-
const indent = "\t".repeat(indentLevel);
|
|
523
|
-
const nestedIndent = "\t".repeat(indentLevel + 1);
|
|
524
|
-
if (value === null) {
|
|
525
|
-
return "null";
|
|
526
|
-
}
|
|
527
|
-
if (typeof value === "string") {
|
|
528
|
-
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
529
|
-
}
|
|
530
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
531
|
-
return String(value);
|
|
532
|
-
}
|
|
533
|
-
if (Array.isArray(value)) {
|
|
534
|
-
if (value.length === 0) {
|
|
535
|
-
return "[]";
|
|
536
|
-
}
|
|
537
|
-
const items = value.map((item) => `${nestedIndent}${renderPhpValue(item, indentLevel + 1)}`);
|
|
538
|
-
return `[\n${items.join(",\n")}\n${indent}]`;
|
|
539
|
-
}
|
|
540
|
-
if (typeof value === "object") {
|
|
541
|
-
const entries = Object.entries(value);
|
|
542
|
-
if (entries.length === 0) {
|
|
543
|
-
return "[]";
|
|
544
|
-
}
|
|
545
|
-
const items = entries.map(([key, item]) => `${nestedIndent}'${key.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}' => ${renderPhpValue(item, indentLevel + 1)}`);
|
|
546
|
-
return `[\n${items.join(",\n")}\n${indent}]`;
|
|
547
|
-
}
|
|
548
|
-
throw new Error(`Unable to encode PHP value for manifest node: ${String(value)}`);
|
|
549
|
-
}
|
|
7
|
+
export * from "@wp-typia/block-runtime/metadata-php-render";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports metadata projection utilities from `@wp-typia/block-runtime`.
|
|
3
|
+
* This adapter keeps the public project-tools runtime path stable while the
|
|
4
|
+
* implementation is consolidated in block-runtime.
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
export * from "@wp-typia/block-runtime/metadata-projection";
|