@wp-typia/project-tools 0.16.0 → 0.16.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.
Files changed (24) hide show
  1. package/README.md +6 -0
  2. package/dist/runtime/cli-help.js +1 -1
  3. package/dist/runtime/package-versions.js +7 -2
  4. package/dist/runtime/scaffold.js +21 -13
  5. package/dist/runtime/schema-core.d.ts +5 -266
  6. package/dist/runtime/schema-core.js +5 -775
  7. package/package.json +56 -3
  8. package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +42 -28
  9. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/interactivity.ts.mustache +8 -0
  10. package/templates/_shared/compound/persistence-auth/{{slugKebabCase}}.php.mustache +5 -5
  11. package/templates/_shared/compound/persistence-public/{{slugKebabCase}}.php.mustache +5 -5
  12. package/templates/_shared/persistence/auth/{{slugKebabCase}}.php.mustache +5 -5
  13. package/templates/_shared/persistence/core/src/interactivity.ts.mustache +5 -0
  14. package/templates/_shared/persistence/core/{{slugKebabCase}}.php.mustache +5 -5
  15. package/templates/_shared/persistence/public/{{slugKebabCase}}.php.mustache +5 -5
  16. package/templates/_shared/workspace/persistence-auth/server.php.mustache +7 -5
  17. package/templates/_shared/workspace/persistence-public/server.php.mustache +7 -5
  18. package/templates/compound/src/blocks/{{slugKebabCase}}/types.ts.mustache +5 -0
  19. package/templates/compound/src/blocks/{{slugKebabCase}}/validators.ts.mustache +10 -3
  20. package/templates/compound/src/blocks/{{slugKebabCase}}-item/types.ts.mustache +5 -0
  21. package/templates/compound/src/blocks/{{slugKebabCase}}-item/validators.ts.mustache +10 -3
  22. package/templates/interactivity/src/edit.tsx.mustache +1 -1
  23. package/templates/interactivity/src/save.tsx.mustache +1 -1
  24. package/templates/persistence/src/edit.tsx.mustache +2 -2
package/README.md CHANGED
@@ -14,6 +14,12 @@ Supported public imports:
14
14
  - `@wp-typia/project-tools`
15
15
  - `@wp-typia/project-tools/schema-core`
16
16
 
17
+ Implementation note:
18
+
19
+ - `@wp-typia/project-tools/schema-core` remains the preferred project-tooling
20
+ import path.
21
+ - The shared implementation now lives in `@wp-typia/block-runtime/schema-core`.
22
+
17
23
  Example:
18
24
 
19
25
  ```ts
@@ -34,7 +34,7 @@ Package managers: ${PACKAGE_MANAGER_IDS.join(", ")}
34
34
  Notes:
35
35
  \`wp-typia create\` is the canonical scaffold command.
36
36
  \`wp-typia <project-dir>\` remains a backward-compatible alias to \`create\`.
37
- Use \`--template @wp-typia/create-workspace-template\` for the official empty workspace scaffold behind \`wp-typia add ...\`.
37
+ Use \`--template workspace\` as shorthand for \`@wp-typia/create-workspace-template\`, the official empty workspace scaffold behind \`wp-typia add ...\`.
38
38
  \`add variation\` uses an existing workspace block from \`scripts/block-config.ts\`.
39
39
  \`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/\`.
40
40
  \`add binding-source\` scaffolds shared PHP and editor registration under \`src/bindings/\`.
@@ -15,6 +15,9 @@ function normalizeVersionRange(value) {
15
15
  if (!trimmed) {
16
16
  return DEFAULT_VERSION_RANGE;
17
17
  }
18
+ if (trimmed.startsWith("workspace:")) {
19
+ return DEFAULT_VERSION_RANGE;
20
+ }
18
21
  return /^[~^<>=]/.test(trimmed) ? trimmed : `^${trimmed}`;
19
22
  }
20
23
  function readPackageManifest(packageJsonPath) {
@@ -52,11 +55,13 @@ export function getPackageVersions() {
52
55
  const wpTypiaManifest = readPackageManifest(path.join(PROJECT_TOOLS_PACKAGE_ROOT, "..", "wp-typia", "package.json")) ??
53
56
  resolveInstalledPackageManifest("wp-typia") ??
54
57
  {};
58
+ const blockRuntimeDependencyVersion = normalizeVersionRange(createManifest.dependencies?.["@wp-typia/block-runtime"]);
55
59
  cachedPackageVersions = {
56
60
  apiClientPackageVersion: normalizeVersionRange(createManifest.dependencies?.["@wp-typia/api-client"] ??
57
61
  resolveInstalledPackageManifest("@wp-typia/api-client")?.version),
58
- blockRuntimePackageVersion: normalizeVersionRange(createManifest.dependencies?.["@wp-typia/block-runtime"] ??
59
- blockRuntimeManifest.version),
62
+ blockRuntimePackageVersion: blockRuntimeDependencyVersion !== DEFAULT_VERSION_RANGE
63
+ ? blockRuntimeDependencyVersion
64
+ : normalizeVersionRange(blockRuntimeManifest.version),
60
65
  blockTypesPackageVersion: normalizeVersionRange(createManifest.dependencies?.["@wp-typia/block-types"] ??
61
66
  resolveInstalledPackageManifest("@wp-typia/block-types")?.version),
62
67
  projectToolsPackageVersion: normalizeVersionRange(createManifest.version),
@@ -19,6 +19,7 @@ const BLOCK_SLUG_PATTERN = /^[a-z][a-z0-9-]*$/;
19
19
  const PHP_PREFIX_PATTERN = /^[a-z_][a-z0-9_]*$/;
20
20
  const PHP_PREFIX_MAX_LENGTH = 50;
21
21
  const OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE = "@wp-typia/create-workspace-template";
22
+ const WORKSPACE_TEMPLATE_ALIAS = "workspace";
22
23
  const EPHEMERAL_NODE_MODULES_LINK_TYPE = process.platform === "win32" ? "junction" : "dir";
23
24
  const LOCKFILES = {
24
25
  bun: ["bun.lock", "bun.lockb"],
@@ -138,15 +139,21 @@ export function getDefaultAnswers(projectName, templateId) {
138
139
  title: toTitleCase(slugDefault),
139
140
  };
140
141
  }
142
+ function normalizeTemplateSelection(templateId) {
143
+ return templateId === WORKSPACE_TEMPLATE_ALIAS
144
+ ? OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
145
+ : templateId;
146
+ }
141
147
  export async function resolveTemplateId({ templateId, yes = false, isInteractive = false, selectTemplate, }) {
142
148
  if (templateId) {
149
+ const normalizedTemplateId = normalizeTemplateSelection(templateId);
143
150
  if (isRemovedBuiltInTemplateId(templateId)) {
144
151
  throw new Error(getRemovedBuiltInTemplateMessage(templateId));
145
152
  }
146
- if (isBuiltInTemplateId(templateId)) {
147
- return getTemplateById(templateId).id;
153
+ if (isBuiltInTemplateId(normalizedTemplateId)) {
154
+ return getTemplateById(normalizedTemplateId).id;
148
155
  }
149
- return templateId;
156
+ return normalizedTemplateId;
150
157
  }
151
158
  if (yes) {
152
159
  return "basic";
@@ -154,7 +161,7 @@ export async function resolveTemplateId({ templateId, yes = false, isInteractive
154
161
  if (!isInteractive || !selectTemplate) {
155
162
  throw new Error(`Template is required in non-interactive mode. Use --template <${TEMPLATE_IDS.join("|")}|./path|github:owner/repo/path[#ref]|npm-package>.`);
156
163
  }
157
- return selectTemplate();
164
+ return normalizeTemplateSelection(await selectTemplate());
158
165
  }
159
166
  export async function resolvePackageManagerId({ packageManager, yes = false, isInteractive = false, selectPackageManager, }) {
160
167
  if (packageManager) {
@@ -628,14 +635,15 @@ async function applyWorkspaceMigrationCapability(projectDir, packageManager) {
628
635
  writeInitialMigrationScaffold(projectDir, "v1", []);
629
636
  }
630
637
  export async function scaffoldProject({ projectDir, templateId, answers, dataStorageMode, persistencePolicy, packageManager, cwd = process.cwd(), allowExistingDir = false, noInstall = false, installDependencies = undefined, variant, withMigrationUi = false, withTestPreset = false, withWpEnv = false, }) {
638
+ const resolvedTemplateId = normalizeTemplateSelection(templateId);
631
639
  const resolvedPackageManager = getPackageManager(packageManager).id;
632
- const isBuiltInTemplate = isBuiltInTemplateId(templateId);
633
- const variables = getTemplateVariables(templateId, {
640
+ const isBuiltInTemplate = isBuiltInTemplateId(resolvedTemplateId);
641
+ const variables = getTemplateVariables(resolvedTemplateId, {
634
642
  ...answers,
635
643
  dataStorageMode: dataStorageMode ?? answers.dataStorageMode,
636
644
  persistencePolicy: persistencePolicy ?? answers.persistencePolicy,
637
645
  });
638
- const templateSource = await resolveTemplateSource(templateId, cwd, variables, variant);
646
+ const templateSource = await resolveTemplateSource(resolvedTemplateId, cwd, variables, variant);
639
647
  const supportsMigrationUi = isBuiltInTemplate || templateSource.isOfficialWorkspaceTemplate === true;
640
648
  if (withMigrationUi && !supportsMigrationUi) {
641
649
  await templateSource.cleanup?.();
@@ -652,8 +660,8 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
652
660
  }
653
661
  const isOfficialWorkspace = isOfficialWorkspaceProject(projectDir);
654
662
  if (isBuiltInTemplate) {
655
- await writeStarterManifestFiles(projectDir, templateId, variables);
656
- await seedBuiltInPersistenceArtifacts(projectDir, templateId, variables);
663
+ await writeStarterManifestFiles(projectDir, resolvedTemplateId, variables);
664
+ await seedBuiltInPersistenceArtifacts(projectDir, resolvedTemplateId, variables);
657
665
  await applyLocalDevPresetFiles({
658
666
  projectDir,
659
667
  variables,
@@ -664,7 +672,7 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
664
672
  await applyMigrationUiCapability({
665
673
  packageManager: resolvedPackageManager,
666
674
  projectDir,
667
- templateId,
675
+ templateId: resolvedTemplateId,
668
676
  variables,
669
677
  });
670
678
  }
@@ -674,7 +682,7 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
674
682
  }
675
683
  const readmePath = path.join(projectDir, "README.md");
676
684
  if (!fs.existsSync(readmePath)) {
677
- await fsp.writeFile(readmePath, buildReadme(templateId, variables, resolvedPackageManager, {
685
+ await fsp.writeFile(readmePath, buildReadme(resolvedTemplateId, variables, resolvedPackageManager, {
678
686
  withMigrationUi: isBuiltInTemplate || isOfficialWorkspace ? withMigrationUi : false,
679
687
  withTestPreset: isBuiltInTemplate ? withTestPreset : false,
680
688
  withWpEnv: isBuiltInTemplate ? withWpEnv : false,
@@ -691,7 +699,7 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
691
699
  compoundPersistenceEnabled: variables.compoundPersistenceEnabled === "true",
692
700
  packageManager: resolvedPackageManager,
693
701
  projectDir,
694
- templateId,
702
+ templateId: resolvedTemplateId,
695
703
  withTestPreset,
696
704
  withWpEnv,
697
705
  });
@@ -709,7 +717,7 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
709
717
  return {
710
718
  projectDir,
711
719
  selectedVariant: templateSource.selectedVariant ?? null,
712
- templateId,
720
+ templateId: resolvedTemplateId,
713
721
  packageManager: resolvedPackageManager,
714
722
  variables,
715
723
  warnings: templateSource.warnings ?? [],
@@ -1,268 +1,7 @@
1
- import type { JsonValue, ManifestAttribute, ManifestDocument } from "./migration-types.js";
2
- export interface JsonSchemaObject {
3
- [key: string]: JsonValue | JsonSchemaObject | JsonSchemaObject[] | undefined;
4
- }
5
1
  /**
6
- * Full JSON Schema document for a manifest-derived root object.
2
+ * Re-exports schema and OpenAPI helpers from `@wp-typia/block-runtime`.
3
+ * This adapter preserves the public `@wp-typia/project-tools/schema-core`
4
+ * path while sharing the canonical implementation with block-runtime.
5
+ * @module
7
6
  */
8
- export interface JsonSchemaDocument extends JsonSchemaObject {
9
- $schema: string;
10
- additionalProperties: boolean;
11
- properties: Record<string, JsonSchemaObject>;
12
- required: string[];
13
- title: string;
14
- type: "object";
15
- }
16
- /**
17
- * Document-level metadata applied to generated OpenAPI files.
18
- */
19
- export interface OpenApiInfo {
20
- description?: string;
21
- title?: string;
22
- version?: string;
23
- }
24
- /**
25
- * JSON Schema reference used inside generated OpenAPI documents.
26
- */
27
- export interface OpenApiSchemaReference extends JsonSchemaObject {
28
- $ref: string;
29
- }
30
- /**
31
- * OpenAPI query parameter emitted from a manifest attribute.
32
- */
33
- export interface OpenApiParameter extends JsonSchemaObject {
34
- in: "query";
35
- name: string;
36
- required: boolean;
37
- schema: JsonSchemaObject;
38
- }
39
- /**
40
- * OpenAPI media type wrapper for JSON responses and request bodies.
41
- */
42
- export interface OpenApiMediaType extends JsonSchemaObject {
43
- schema: OpenApiSchemaReference;
44
- }
45
- /**
46
- * OpenAPI request body definition for generated JSON endpoints.
47
- */
48
- export interface OpenApiRequestBody extends JsonSchemaObject {
49
- content: {
50
- "application/json": OpenApiMediaType;
51
- };
52
- required: true;
53
- }
54
- /**
55
- * Successful JSON response entry in the generated OpenAPI document.
56
- */
57
- export interface OpenApiResponse extends JsonSchemaObject {
58
- content: {
59
- "application/json": OpenApiMediaType;
60
- };
61
- description: string;
62
- headers?: Record<string, JsonSchemaObject>;
63
- }
64
- /**
65
- * Header-based security scheme used by authenticated WordPress REST routes.
66
- */
67
- export interface OpenApiSecurityScheme extends JsonSchemaObject {
68
- description?: string;
69
- in: "header";
70
- name: string;
71
- type: "apiKey";
72
- }
73
- /**
74
- * One generated OpenAPI operation for a scaffolded REST endpoint.
75
- */
76
- export interface OpenApiOperation extends JsonSchemaObject {
77
- operationId: string;
78
- parameters?: OpenApiParameter[];
79
- requestBody?: OpenApiRequestBody;
80
- responses: Record<string, OpenApiResponse>;
81
- security?: Array<Record<string, string[]>>;
82
- summary?: string;
83
- tags: string[];
84
- "x-typia-authIntent": EndpointAuthIntent;
85
- "x-wp-typia-authPolicy"?: EndpointOpenApiAuthMode;
86
- "x-wp-typia-publicTokenField"?: string;
87
- }
88
- /**
89
- * Path item containing one or more generated REST operations.
90
- */
91
- export type OpenApiPathItem = JsonSchemaObject & Partial<Record<Lowercase<EndpointOpenApiMethod>, OpenApiOperation>>;
92
- /**
93
- * Named tag entry surfaced at the top level of generated OpenAPI docs.
94
- */
95
- export interface OpenApiTag extends JsonSchemaObject {
96
- name: string;
97
- }
98
- /**
99
- * OpenAPI component registry for generated schemas and security schemes.
100
- */
101
- export interface OpenApiComponents extends JsonSchemaObject {
102
- schemas: Record<string, JsonSchemaDocument>;
103
- securitySchemes?: Record<string, OpenApiSecurityScheme>;
104
- }
105
- /**
106
- * Complete OpenAPI 3.1 document emitted for endpoint-aware REST contracts.
107
- */
108
- export interface OpenApiDocument extends JsonSchemaObject {
109
- components: OpenApiComponents;
110
- info: {
111
- description?: string;
112
- title: string;
113
- version: string;
114
- };
115
- openapi: "3.1.0";
116
- paths: Record<string, OpenApiPathItem>;
117
- tags?: OpenApiTag[];
118
- }
119
- /**
120
- * Backend-neutral auth intent for one manifest-defined endpoint.
121
- */
122
- export type EndpointAuthIntent = "authenticated" | "public" | "public-write-protected";
123
- /**
124
- * WordPress-specific authentication mechanisms that can implement neutral auth intent.
125
- */
126
- export type EndpointWordPressAuthMechanism = "public-signed-token" | "rest-nonce";
127
- /**
128
- * Optional WordPress adapter metadata that explains how the default runtime satisfies auth intent.
129
- */
130
- export interface EndpointWordPressAuthDefinition {
131
- mechanism: EndpointWordPressAuthMechanism;
132
- publicTokenField?: string;
133
- }
134
- /**
135
- * Legacy WordPress auth-mode literals kept for backward compatibility.
136
- */
137
- export type EndpointOpenApiAuthMode = "authenticated-rest-nonce" | "public-read" | "public-signed-token";
138
- /**
139
- * Supported HTTP methods for generated REST OpenAPI endpoints.
140
- */
141
- export type EndpointOpenApiMethod = "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
142
- /**
143
- * Contract document used when composing an endpoint-aware OpenAPI file.
144
- */
145
- export interface EndpointOpenApiContractDocument {
146
- /** Manifest-derived contract document for this schema component. */
147
- document: ManifestDocument;
148
- /** Optional component name override for the generated schema reference. */
149
- schemaName?: string;
150
- }
151
- interface EndpointOpenApiEndpointBaseDefinition {
152
- /** Authentication policy surfaced in OpenAPI metadata. */
153
- auth?: EndpointAuthIntent;
154
- /** @deprecated Prefer `auth` plus `wordpressAuth` for new manifests. */
155
- authMode?: EndpointOpenApiAuthMode;
156
- /** Contract key for a JSON request body, when the endpoint accepts one. */
157
- bodyContract?: string;
158
- /** HTTP method exposed by the route. */
159
- method: EndpointOpenApiMethod;
160
- /** Stable OpenAPI operation id for this route. */
161
- operationId: string;
162
- /** Absolute REST path including namespace and version. */
163
- path: string;
164
- /** Contract key for query parameters, when the endpoint reads from the query string. */
165
- queryContract?: string;
166
- /** Contract key for the successful JSON response body. */
167
- responseContract: string;
168
- /** Optional short endpoint summary shown in generated docs. */
169
- summary?: string;
170
- /** OpenAPI tag names applied to this endpoint. */
171
- tags: readonly string[];
172
- /** Optional WordPress adapter metadata for the default runtime. */
173
- wordpressAuth?: EndpointWordPressAuthDefinition;
174
- }
175
- /**
176
- * Route metadata for one REST endpoint in the aggregate OpenAPI document.
177
- */
178
- export type EndpointOpenApiEndpointDefinition = (EndpointOpenApiEndpointBaseDefinition & {
179
- auth: EndpointAuthIntent;
180
- }) | (EndpointOpenApiEndpointBaseDefinition & {
181
- /** @deprecated Prefer `auth` plus `wordpressAuth` for new manifests. */
182
- authMode: EndpointOpenApiAuthMode;
183
- });
184
- export interface NormalizedEndpointAuthDefinition {
185
- auth: EndpointAuthIntent;
186
- authMode?: EndpointOpenApiAuthMode;
187
- wordpressAuth?: EndpointWordPressAuthDefinition;
188
- }
189
- /**
190
- * Options for building an aggregate endpoint-aware OpenAPI document.
191
- */
192
- export interface EndpointOpenApiDocumentOptions {
193
- /** Named contract documents keyed by the endpoint registry identifiers. */
194
- contracts: Readonly<Record<string, EndpointOpenApiContractDocument>>;
195
- /** Route definitions that should appear in the generated OpenAPI file. */
196
- endpoints: readonly EndpointOpenApiEndpointDefinition[];
197
- /** Optional document-level OpenAPI info metadata. */
198
- info?: OpenApiInfo;
199
- }
200
- /**
201
- * Supported schema projection profiles derived from one canonical wp-typia JSON Schema document.
202
- */
203
- export type JsonSchemaProjectionProfile = "ai-structured-output" | "rest";
204
- /**
205
- * Options for projecting one generated JSON Schema document into another consumer-facing profile.
206
- */
207
- export interface JsonSchemaProjectionOptions {
208
- /** Projection profile that controls schema transformation rules. */
209
- profile: JsonSchemaProjectionProfile;
210
- }
211
- /**
212
- * Converts one manifest attribute definition into a JSON Schema fragment.
213
- *
214
- * @param attribute Manifest-derived attribute metadata.
215
- * @returns A JSON-compatible schema fragment for the attribute.
216
- */
217
- export declare function manifestAttributeToJsonSchema(attribute: ManifestAttribute): JsonSchemaObject;
218
- /**
219
- * Builds a full JSON Schema document from a Typia manifest document.
220
- *
221
- * @param doc Manifest-derived attribute document.
222
- * @returns A draft 2020-12 JSON Schema document for the manifest root object.
223
- */
224
- export declare function manifestToJsonSchema(doc: ManifestDocument): JsonSchemaDocument;
225
- /**
226
- * Projects one generated wp-typia JSON Schema document into a consumer-facing profile.
227
- *
228
- * @param schema Existing generated JSON Schema document.
229
- * @param options Projection profile options.
230
- * @returns A cloned schema document adjusted for the requested profile.
231
- */
232
- export declare function projectJsonSchemaDocument<Schema extends JsonSchemaDocument | JsonSchemaObject>(schema: Schema, options: JsonSchemaProjectionOptions): Schema;
233
- /**
234
- * Wraps a manifest-derived JSON Schema document in a minimal OpenAPI 3.1 shell.
235
- *
236
- * @param doc Manifest-derived attribute document.
237
- * @param info Optional OpenAPI document metadata.
238
- * @returns An OpenAPI document containing the schema as a single component.
239
- */
240
- export declare function manifestToOpenApi(doc: ManifestDocument, info?: OpenApiInfo): OpenApiDocument;
241
- /**
242
- * Normalizes endpoint auth metadata into backend-neutral intent plus optional
243
- * WordPress adapter details.
244
- *
245
- * This public runtime helper accepts either the authored `auth` and optional
246
- * `wordpressAuth` shape or the deprecated `authMode` field. It validates that
247
- * the provided fields are compatible, resolves the legacy compatibility mode,
248
- * and returns a normalized definition without mutating the input endpoint.
249
- *
250
- * @param endpoint - Endpoint auth fields to normalize, including `auth`,
251
- * `authMode`, `wordpressAuth`, and optional identity fields used in error
252
- * messages (`operationId`, `path`, and `method`).
253
- * @returns The normalized auth definition for the endpoint.
254
- * @throws When `auth` and deprecated `authMode` conflict.
255
- * @throws When `wordpressAuth` is attached to the `public` auth intent.
256
- * @throws When the selected `wordpressAuth` mechanism is incompatible with the
257
- * chosen auth intent.
258
- * @throws When neither `auth` nor deprecated `authMode` is defined.
259
- */
260
- export declare function normalizeEndpointAuthDefinition(endpoint: Pick<EndpointOpenApiEndpointDefinition, "auth" | "authMode" | "operationId" | "path" | "wordpressAuth" | "method">): NormalizedEndpointAuthDefinition;
261
- /**
262
- * Build a complete OpenAPI 3.1 document from contract manifests and route metadata.
263
- *
264
- * @param options Aggregate contract and endpoint definitions for the REST surface.
265
- * @returns A JSON-compatible OpenAPI document with paths, components, and auth metadata.
266
- */
267
- export declare function buildEndpointOpenApiDocument(options: EndpointOpenApiDocumentOptions): OpenApiDocument;
268
- export {};
7
+ export * from "@wp-typia/block-runtime/schema-core";