@wp-typia/project-tools 0.22.0 → 0.22.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/built-in-block-code-templates/interactivity.d.ts +1 -1
- package/dist/runtime/built-in-block-code-templates/interactivity.js +2 -2
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +257 -0
- package/dist/runtime/cli-add-workspace-admin-view-source.d.ts +5 -0
- package/dist/runtime/cli-add-workspace-admin-view-source.js +86 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates.d.ts +23 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates.js +991 -0
- package/dist/runtime/cli-add-workspace-admin-view-types.d.ts +29 -0
- package/dist/runtime/cli-add-workspace-admin-view-types.js +29 -0
- package/dist/runtime/cli-add-workspace-admin-view.d.ts +1 -16
- package/dist/runtime/cli-add-workspace-admin-view.js +22 -1388
- package/dist/runtime/cli-add-workspace-ai-source-emitters.js +119 -1
- package/dist/runtime/cli-add-workspace-ai.js +253 -30
- package/dist/runtime/package-versions.d.ts +15 -0
- package/dist/runtime/package-versions.js +72 -42
- package/dist/runtime/scaffold-compatibility.d.ts +2 -0
- package/dist/runtime/scaffold-compatibility.js +2 -0
- package/dist/runtime/string-case.d.ts +7 -0
- package/dist/runtime/string-case.js +21 -11
- package/dist/runtime/typia-llm.d.ts +37 -2
- package/dist/runtime/typia-llm.js +240 -3
- package/dist/runtime/workspace-inventory.js +24 -0
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import { createRequire } from
|
|
3
|
-
import path from
|
|
4
|
-
import { PROJECT_TOOLS_PACKAGE_ROOT } from
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { PROJECT_TOOLS_PACKAGE_ROOT } from './template-registry.js';
|
|
5
5
|
const require = createRequire(import.meta.url);
|
|
6
|
-
const DEFAULT_VERSION_RANGE =
|
|
7
|
-
const DEFAULT_EXACT_VERSION =
|
|
8
|
-
const DEFAULT_TSX_PACKAGE_VERSION =
|
|
9
|
-
const DEFAULT_TYPIA_UNPLUGIN_PACKAGE_VERSION =
|
|
6
|
+
const DEFAULT_VERSION_RANGE = '^0.0.0';
|
|
7
|
+
const DEFAULT_EXACT_VERSION = '0.0.0';
|
|
8
|
+
const DEFAULT_TSX_PACKAGE_VERSION = '^4.20.5';
|
|
9
|
+
const DEFAULT_TYPIA_UNPLUGIN_PACKAGE_VERSION = '^12.0.1';
|
|
10
10
|
/**
|
|
11
11
|
* Explicit fallback ranges for managed WordPress-facing workspace dependencies.
|
|
12
12
|
*
|
|
@@ -14,15 +14,15 @@ const DEFAULT_TYPIA_UNPLUGIN_PACKAGE_VERSION = "^12.0.1";
|
|
|
14
14
|
* fresher local or installed manifest version first, so add-command defaults do
|
|
15
15
|
* not drift across runtime modules.
|
|
16
16
|
*/
|
|
17
|
-
export const DEFAULT_WORDPRESS_ABILITIES_VERSION =
|
|
18
|
-
export const DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION =
|
|
19
|
-
export const DEFAULT_WORDPRESS_CORE_DATA_VERSION =
|
|
20
|
-
export const DEFAULT_WORDPRESS_DATA_VERSION =
|
|
21
|
-
export const DEFAULT_WORDPRESS_DATAVIEWS_VERSION =
|
|
22
|
-
export const DEFAULT_WP_TYPIA_DATAVIEWS_VERSION =
|
|
17
|
+
export const DEFAULT_WORDPRESS_ABILITIES_VERSION = '^0.10.0';
|
|
18
|
+
export const DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION = '^0.9.0';
|
|
19
|
+
export const DEFAULT_WORDPRESS_CORE_DATA_VERSION = '^7.44.0';
|
|
20
|
+
export const DEFAULT_WORDPRESS_DATA_VERSION = '^9.28.0';
|
|
21
|
+
export const DEFAULT_WORDPRESS_DATAVIEWS_VERSION = '^14.1.0';
|
|
22
|
+
export const DEFAULT_WP_TYPIA_DATAVIEWS_VERSION = '^0.1.0';
|
|
23
23
|
let cachedPackageVersions = null;
|
|
24
24
|
function getErrorCode(error) {
|
|
25
|
-
return typeof error ===
|
|
25
|
+
return typeof error === 'object' && error !== null && 'code' in error
|
|
26
26
|
? String(error.code)
|
|
27
27
|
: undefined;
|
|
28
28
|
}
|
|
@@ -31,7 +31,7 @@ function normalizeVersionRange(value) {
|
|
|
31
31
|
if (!trimmed) {
|
|
32
32
|
return DEFAULT_VERSION_RANGE;
|
|
33
33
|
}
|
|
34
|
-
if (trimmed.startsWith(
|
|
34
|
+
if (trimmed.startsWith('workspace:')) {
|
|
35
35
|
return DEFAULT_VERSION_RANGE;
|
|
36
36
|
}
|
|
37
37
|
return /^[~^<>=]/.test(trimmed) ? trimmed : `^${trimmed}`;
|
|
@@ -41,10 +41,10 @@ function normalizeExactVersion(value) {
|
|
|
41
41
|
if (!trimmed) {
|
|
42
42
|
return DEFAULT_EXACT_VERSION;
|
|
43
43
|
}
|
|
44
|
-
if (trimmed.startsWith(
|
|
44
|
+
if (trimmed.startsWith('workspace:')) {
|
|
45
45
|
return DEFAULT_EXACT_VERSION;
|
|
46
46
|
}
|
|
47
|
-
return trimmed.replace(/^[~^<>=]+/,
|
|
47
|
+
return trimmed.replace(/^[~^<>=]+/, '');
|
|
48
48
|
}
|
|
49
49
|
function normalizeVersionRangeWithFallback(value, fallback) {
|
|
50
50
|
const normalized = normalizeVersionRange(value);
|
|
@@ -61,7 +61,7 @@ function createContentFingerprint(source) {
|
|
|
61
61
|
function resolvePackageManifestLocation(packageJsonPath) {
|
|
62
62
|
try {
|
|
63
63
|
const stats = fs.statSync(packageJsonPath);
|
|
64
|
-
const source = fs.readFileSync(packageJsonPath,
|
|
64
|
+
const source = fs.readFileSync(packageJsonPath, 'utf8');
|
|
65
65
|
return {
|
|
66
66
|
cacheKey: `file:${packageJsonPath}:${stats.ino}:${stats.mtimeMs}:${stats.ctimeMs}:${stats.size}:${createContentFingerprint(source)}`,
|
|
67
67
|
packageJsonPath,
|
|
@@ -69,7 +69,7 @@ function resolvePackageManifestLocation(packageJsonPath) {
|
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
catch (error) {
|
|
72
|
-
if (getErrorCode(error) ===
|
|
72
|
+
if (getErrorCode(error) === 'ENOENT') {
|
|
73
73
|
return {
|
|
74
74
|
cacheKey: `missing-file:${packageJsonPath}`,
|
|
75
75
|
packageJsonPath: null,
|
|
@@ -85,12 +85,23 @@ function readPackageManifest(location) {
|
|
|
85
85
|
}
|
|
86
86
|
return JSON.parse(location.source);
|
|
87
87
|
}
|
|
88
|
+
function tryReadPackageManifest(location) {
|
|
89
|
+
if (!location) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
return readPackageManifest(location);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
88
99
|
function resolveInstalledPackageManifestLocation(packageName) {
|
|
89
100
|
try {
|
|
90
101
|
return resolvePackageManifestLocation(require.resolve(`${packageName}/package.json`));
|
|
91
102
|
}
|
|
92
103
|
catch (error) {
|
|
93
|
-
if (getErrorCode(error) ===
|
|
104
|
+
if (getErrorCode(error) === 'MODULE_NOT_FOUND') {
|
|
94
105
|
return {
|
|
95
106
|
cacheKey: `missing-module:${packageName}`,
|
|
96
107
|
packageJsonPath: null,
|
|
@@ -101,7 +112,26 @@ function resolveInstalledPackageManifestLocation(packageName) {
|
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
function composePackageVersionsCacheKey(locations) {
|
|
104
|
-
return locations.map((location) => location.cacheKey).join(
|
|
115
|
+
return locations.map((location) => location.cacheKey).join('|');
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Resolve a managed package version range from linked workspace packages first,
|
|
119
|
+
* then installed package manifests, while preserving the shared normalization
|
|
120
|
+
* and manifest fingerprinting rules used by `getPackageVersions()`.
|
|
121
|
+
*
|
|
122
|
+
* @param packageName npm package whose manifest version should be consulted.
|
|
123
|
+
* @param fallback Canonical range to use when no usable manifest version exists.
|
|
124
|
+
* @param workspacePackageDirName Optional sibling monorepo package directory name.
|
|
125
|
+
* @returns A normalized semver range suitable for generated dependency entries.
|
|
126
|
+
*/
|
|
127
|
+
export function resolveManagedPackageVersionRange(options) {
|
|
128
|
+
const workspaceManifestLocation = options.workspacePackageDirName
|
|
129
|
+
? resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT, '..', options.workspacePackageDirName, 'package.json'))
|
|
130
|
+
: null;
|
|
131
|
+
const installedManifestLocation = resolveInstalledPackageManifestLocation(options.packageName);
|
|
132
|
+
const workspaceManifest = tryReadPackageManifest(workspaceManifestLocation);
|
|
133
|
+
const installedManifest = tryReadPackageManifest(installedManifestLocation);
|
|
134
|
+
return normalizeVersionRangeWithFallback(workspaceManifest?.version ?? installedManifest?.version, options.fallback);
|
|
105
135
|
}
|
|
106
136
|
/**
|
|
107
137
|
* Clears the in-memory cache used by `getPackageVersions()`.
|
|
@@ -128,20 +158,20 @@ export function invalidatePackageVersionsCache() {
|
|
|
128
158
|
* disk, the cache key changes and the returned version object is refreshed.
|
|
129
159
|
*/
|
|
130
160
|
export function getPackageVersions() {
|
|
131
|
-
const createManifestLocation = resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT,
|
|
132
|
-
const monorepoManifestLocation = resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT,
|
|
133
|
-
const blockRuntimeManifestLocation = resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT,
|
|
134
|
-
const wpTypiaManifestLocation = resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT,
|
|
135
|
-
const installedProjectToolsManifestLocation = resolveInstalledPackageManifestLocation(
|
|
136
|
-
const installedApiClientManifestLocation = resolveInstalledPackageManifestLocation(
|
|
137
|
-
const installedBlockRuntimeManifestLocation = resolveInstalledPackageManifestLocation(
|
|
138
|
-
const installedBlockTypesManifestLocation = resolveInstalledPackageManifestLocation(
|
|
139
|
-
const installedRestManifestLocation = resolveInstalledPackageManifestLocation(
|
|
140
|
-
const installedTsxManifestLocation = resolveInstalledPackageManifestLocation(
|
|
141
|
-
const installedTypiaManifestLocation = resolveInstalledPackageManifestLocation(
|
|
142
|
-
const installedTypiaUnpluginManifestLocation = resolveInstalledPackageManifestLocation(
|
|
143
|
-
const installedTypescriptManifestLocation = resolveInstalledPackageManifestLocation(
|
|
144
|
-
const installedWpTypiaManifestLocation = resolveInstalledPackageManifestLocation(
|
|
161
|
+
const createManifestLocation = resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT, 'package.json'));
|
|
162
|
+
const monorepoManifestLocation = resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT, '..', '..', 'package.json'));
|
|
163
|
+
const blockRuntimeManifestLocation = resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT, '..', 'wp-typia-block-runtime', 'package.json'));
|
|
164
|
+
const wpTypiaManifestLocation = resolvePackageManifestLocation(path.join(PROJECT_TOOLS_PACKAGE_ROOT, '..', 'wp-typia', 'package.json'));
|
|
165
|
+
const installedProjectToolsManifestLocation = resolveInstalledPackageManifestLocation('@wp-typia/project-tools');
|
|
166
|
+
const installedApiClientManifestLocation = resolveInstalledPackageManifestLocation('@wp-typia/api-client');
|
|
167
|
+
const installedBlockRuntimeManifestLocation = resolveInstalledPackageManifestLocation('@wp-typia/block-runtime');
|
|
168
|
+
const installedBlockTypesManifestLocation = resolveInstalledPackageManifestLocation('@wp-typia/block-types');
|
|
169
|
+
const installedRestManifestLocation = resolveInstalledPackageManifestLocation('@wp-typia/rest');
|
|
170
|
+
const installedTsxManifestLocation = resolveInstalledPackageManifestLocation('tsx');
|
|
171
|
+
const installedTypiaManifestLocation = resolveInstalledPackageManifestLocation('typia');
|
|
172
|
+
const installedTypiaUnpluginManifestLocation = resolveInstalledPackageManifestLocation('@typia/unplugin');
|
|
173
|
+
const installedTypescriptManifestLocation = resolveInstalledPackageManifestLocation('typescript');
|
|
174
|
+
const installedWpTypiaManifestLocation = resolveInstalledPackageManifestLocation('wp-typia');
|
|
145
175
|
const cacheKey = composePackageVersionsCacheKey([
|
|
146
176
|
createManifestLocation,
|
|
147
177
|
monorepoManifestLocation,
|
|
@@ -171,17 +201,17 @@ export function getPackageVersions() {
|
|
|
171
201
|
const wpTypiaManifest = readPackageManifest(wpTypiaManifestLocation) ??
|
|
172
202
|
readPackageManifest(installedWpTypiaManifestLocation) ??
|
|
173
203
|
{};
|
|
174
|
-
const blockRuntimeDependencyVersion = normalizeVersionRange(createManifest.dependencies?.[
|
|
204
|
+
const blockRuntimeDependencyVersion = normalizeVersionRange(createManifest.dependencies?.['@wp-typia/block-runtime']);
|
|
175
205
|
const versions = {
|
|
176
|
-
apiClientPackageVersion: normalizeVersionRange(createManifest.dependencies?.[
|
|
206
|
+
apiClientPackageVersion: normalizeVersionRange(createManifest.dependencies?.['@wp-typia/api-client'] ??
|
|
177
207
|
readPackageManifest(installedApiClientManifestLocation)?.version),
|
|
178
208
|
blockRuntimePackageVersion: blockRuntimeDependencyVersion !== DEFAULT_VERSION_RANGE
|
|
179
209
|
? blockRuntimeDependencyVersion
|
|
180
210
|
: normalizeVersionRange(blockRuntimeManifest.version),
|
|
181
|
-
blockTypesPackageVersion: normalizeVersionRange(createManifest.dependencies?.[
|
|
211
|
+
blockTypesPackageVersion: normalizeVersionRange(createManifest.dependencies?.['@wp-typia/block-types'] ??
|
|
182
212
|
readPackageManifest(installedBlockTypesManifestLocation)?.version),
|
|
183
213
|
projectToolsPackageVersion: normalizeVersionRange(createManifest.version),
|
|
184
|
-
restPackageVersion: normalizeVersionRange(createManifest.dependencies?.[
|
|
214
|
+
restPackageVersion: normalizeVersionRange(createManifest.dependencies?.['@wp-typia/rest'] ??
|
|
185
215
|
readPackageManifest(installedRestManifestLocation)?.version),
|
|
186
216
|
tsxPackageVersion: normalizeVersionRangeWithFallback(monorepoManifest.dependencies?.tsx ??
|
|
187
217
|
monorepoManifest.devDependencies?.tsx ??
|
|
@@ -190,8 +220,8 @@ export function getPackageVersions() {
|
|
|
190
220
|
monorepoManifest.devDependencies?.typia ??
|
|
191
221
|
createManifest.dependencies?.typia ??
|
|
192
222
|
readPackageManifest(installedTypiaManifestLocation)?.version, DEFAULT_VERSION_RANGE),
|
|
193
|
-
typiaUnpluginPackageVersion: normalizeVersionRangeWithFallback(monorepoManifest.dependencies?.[
|
|
194
|
-
monorepoManifest.devDependencies?.[
|
|
223
|
+
typiaUnpluginPackageVersion: normalizeVersionRangeWithFallback(monorepoManifest.dependencies?.['@typia/unplugin'] ??
|
|
224
|
+
monorepoManifest.devDependencies?.['@typia/unplugin'] ??
|
|
195
225
|
readPackageManifest(installedTypiaUnpluginManifestLocation)?.version, DEFAULT_TYPIA_UNPLUGIN_PACKAGE_VERSION),
|
|
196
226
|
typescriptPackageVersion: normalizeVersionRangeWithFallback(monorepoManifest.dependencies?.typescript ??
|
|
197
227
|
monorepoManifest.devDependencies?.typescript ??
|
|
@@ -26,7 +26,9 @@ export interface ScaffoldCompatibilityPolicy {
|
|
|
26
26
|
export interface ScaffoldCompatibilityConfig {
|
|
27
27
|
hardMinimums: AiFeatureCompatibilityFloor;
|
|
28
28
|
mode: 'baseline' | 'optional' | 'required';
|
|
29
|
+
optionalFeatureIds: string[];
|
|
29
30
|
optionalFeatures: string[];
|
|
31
|
+
requiredFeatureIds: string[];
|
|
30
32
|
requiredFeatures: string[];
|
|
31
33
|
runtimeGates: string[];
|
|
32
34
|
}
|
|
@@ -88,7 +88,9 @@ export function createScaffoldCompatibilityConfig(policy) {
|
|
|
88
88
|
return {
|
|
89
89
|
hardMinimums: capabilityPlan.hardMinimums,
|
|
90
90
|
mode: getPolicyMode(capabilityPlan),
|
|
91
|
+
optionalFeatureIds: capabilityPlan.optionalFeatures.map((feature) => feature.id),
|
|
91
92
|
optionalFeatures: capabilityPlan.optionalFeatures.map((feature) => feature.label),
|
|
93
|
+
requiredFeatureIds: capabilityPlan.requiredFeatures.map((feature) => feature.id),
|
|
92
94
|
requiredFeatures: capabilityPlan.requiredFeatures.map((feature) => feature.label),
|
|
93
95
|
runtimeGates: [
|
|
94
96
|
...capabilityPlan.requiredFeatures.flatMap(formatRuntimeGate),
|
|
@@ -19,6 +19,13 @@ export declare function toSnakeCase(input: string): string;
|
|
|
19
19
|
* @returns A PascalCase string derived from the normalized kebab-case form.
|
|
20
20
|
*/
|
|
21
21
|
export declare function toPascalCase(input: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Normalize arbitrary text into a camelCase identifier.
|
|
24
|
+
*
|
|
25
|
+
* @param input Raw text that may contain spaces, punctuation, or camelCase.
|
|
26
|
+
* @returns A camelCase string derived from the normalized PascalCase form.
|
|
27
|
+
*/
|
|
28
|
+
export declare function toCamelCase(input: string): string;
|
|
22
29
|
/**
|
|
23
30
|
* Convert delimited text to PascalCase while preserving each segment's
|
|
24
31
|
* existing internal casing.
|
|
@@ -10,10 +10,10 @@ function capitalizeSegment(segment) {
|
|
|
10
10
|
export function toKebabCase(input) {
|
|
11
11
|
return input
|
|
12
12
|
.trim()
|
|
13
|
-
.replace(/([a-z0-9])([A-Z])/g,
|
|
14
|
-
.replace(/[^A-Za-z0-9]+/g,
|
|
15
|
-
.replace(/^-+|-+$/g,
|
|
16
|
-
.replace(/-{2,}/g,
|
|
13
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
14
|
+
.replace(/[^A-Za-z0-9]+/g, '-')
|
|
15
|
+
.replace(/^-+|-+$/g, '')
|
|
16
|
+
.replace(/-{2,}/g, '-')
|
|
17
17
|
.toLowerCase();
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
@@ -23,7 +23,7 @@ export function toKebabCase(input) {
|
|
|
23
23
|
* @returns A lowercase snake_case string derived from the kebab-case form.
|
|
24
24
|
*/
|
|
25
25
|
export function toSnakeCase(input) {
|
|
26
|
-
return toKebabCase(input).replace(/-/g,
|
|
26
|
+
return toKebabCase(input).replace(/-/g, '_');
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Normalize arbitrary text into a PascalCase identifier.
|
|
@@ -33,10 +33,20 @@ export function toSnakeCase(input) {
|
|
|
33
33
|
*/
|
|
34
34
|
export function toPascalCase(input) {
|
|
35
35
|
return toKebabCase(input)
|
|
36
|
-
.split(
|
|
36
|
+
.split('-')
|
|
37
37
|
.filter(Boolean)
|
|
38
38
|
.map(capitalizeSegment)
|
|
39
|
-
.join(
|
|
39
|
+
.join('');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Normalize arbitrary text into a camelCase identifier.
|
|
43
|
+
*
|
|
44
|
+
* @param input Raw text that may contain spaces, punctuation, or camelCase.
|
|
45
|
+
* @returns A camelCase string derived from the normalized PascalCase form.
|
|
46
|
+
*/
|
|
47
|
+
export function toCamelCase(input) {
|
|
48
|
+
const pascalCase = toPascalCase(input);
|
|
49
|
+
return `${pascalCase.charAt(0).toLowerCase()}${pascalCase.slice(1)}`;
|
|
40
50
|
}
|
|
41
51
|
/**
|
|
42
52
|
* Convert delimited text to PascalCase while preserving each segment's
|
|
@@ -47,12 +57,12 @@ export function toPascalCase(input) {
|
|
|
47
57
|
*/
|
|
48
58
|
export function toSegmentPascalCase(input) {
|
|
49
59
|
return input
|
|
50
|
-
.replace(/[^A-Za-z0-9]+/g,
|
|
60
|
+
.replace(/[^A-Za-z0-9]+/g, ' ')
|
|
51
61
|
.trim()
|
|
52
62
|
.split(/\s+/)
|
|
53
63
|
.filter(Boolean)
|
|
54
64
|
.map(capitalizeSegment)
|
|
55
|
-
.join(
|
|
65
|
+
.join('');
|
|
56
66
|
}
|
|
57
67
|
/**
|
|
58
68
|
* Normalize arbitrary text into a human-readable title.
|
|
@@ -62,8 +72,8 @@ export function toSegmentPascalCase(input) {
|
|
|
62
72
|
*/
|
|
63
73
|
export function toTitleCase(input) {
|
|
64
74
|
return toKebabCase(input)
|
|
65
|
-
.split(
|
|
75
|
+
.split('-')
|
|
66
76
|
.filter(Boolean)
|
|
67
77
|
.map(capitalizeSegment)
|
|
68
|
-
.join(
|
|
78
|
+
.join(' ');
|
|
69
79
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ArtifactSyncExecutionOptions, EndpointManifestDefinition, EndpointManifestEndpointDefinition } from '@wp-typia/block-runtime/metadata-core';
|
|
2
2
|
import type { ILlmFunction, ILlmSchema, ILlmStructuredOutput } from 'typia';
|
|
3
|
-
import { type EndpointAuthIntent, type EndpointWordPressAuthDefinition } from './schema-core.js';
|
|
3
|
+
import { type EndpointAuthIntent, type EndpointWordPressAuthDefinition, type OpenApiDocument } from './schema-core.js';
|
|
4
4
|
/**
|
|
5
5
|
* Method-level descriptor projected from an endpoint manifest for a generated
|
|
6
6
|
* `typia.llm` controller interface.
|
|
@@ -140,6 +140,16 @@ export interface ProjectedTypiaLlmStructuredOutputArtifact {
|
|
|
140
140
|
/** Structured output parameters generated by `typia.llm`. */
|
|
141
141
|
parameters: ILlmStructuredOutput['parameters'];
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Configures optional OpenAPI-backed constraint restoration for projected
|
|
145
|
+
* `typia.llm` function artifacts.
|
|
146
|
+
*/
|
|
147
|
+
export interface ProjectTypiaLlmOpenApiProjectionOptions {
|
|
148
|
+
/** Canonical endpoint-aware OpenAPI document for the projected contracts. */
|
|
149
|
+
openApiDocument: OpenApiDocument;
|
|
150
|
+
/** Optional override for resolving one function schema to an operation id. */
|
|
151
|
+
resolveOperationId?: (functionSchema: TypiaLlmFunctionLike, functionArtifact: ProjectedTypiaLlmFunctionArtifact) => string;
|
|
152
|
+
}
|
|
143
153
|
/**
|
|
144
154
|
* Configures projection of a compiled `typia.llm.application(...)` result into
|
|
145
155
|
* the JSON-friendly adapter artifact.
|
|
@@ -149,9 +159,23 @@ export interface ProjectTypiaLlmApplicationArtifactOptions {
|
|
|
149
159
|
application: TypiaLlmApplicationLike;
|
|
150
160
|
/** Source metadata for the generated JSON artifact. */
|
|
151
161
|
generatedFrom: ProjectedTypiaLlmApplicationArtifact['generatedFrom'];
|
|
162
|
+
/** Optional OpenAPI projection that restores canonical schema constraints. */
|
|
163
|
+
openApiProjection?: ProjectTypiaLlmOpenApiProjectionOptions;
|
|
152
164
|
/** Optional hook for adapter-specific function schema normalization. */
|
|
153
165
|
transformFunction?: (functionArtifact: ProjectedTypiaLlmFunctionArtifact, functionSchema: TypiaLlmFunctionLike) => ProjectedTypiaLlmFunctionArtifact;
|
|
154
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Configures direct OpenAPI-backed constraint restoration for one projected
|
|
169
|
+
* function artifact.
|
|
170
|
+
*/
|
|
171
|
+
export interface ApplyOpenApiConstraintsToTypiaLlmFunctionArtifactOptions {
|
|
172
|
+
/** Projected function artifact to enrich with canonical constraints. */
|
|
173
|
+
functionArtifact: ProjectedTypiaLlmFunctionArtifact;
|
|
174
|
+
/** Canonical endpoint-aware OpenAPI document. */
|
|
175
|
+
openApiDocument: OpenApiDocument;
|
|
176
|
+
/** Operation id that owns the request/response contract for this function. */
|
|
177
|
+
operationId: string;
|
|
178
|
+
}
|
|
155
179
|
/**
|
|
156
180
|
* Configures projection of a compiled `typia.llm.structuredOutput(...)` result
|
|
157
181
|
* into the JSON-friendly adapter artifact.
|
|
@@ -197,6 +221,17 @@ export declare function syncTypiaLlmAdapterModule({ check, generatedSourceFile,
|
|
|
197
221
|
* @returns JSON-friendly function artifact.
|
|
198
222
|
*/
|
|
199
223
|
export declare function projectTypiaLlmApplicationFunction(functionSchema: TypiaLlmFunctionLike): ProjectedTypiaLlmFunctionArtifact;
|
|
224
|
+
/**
|
|
225
|
+
* Restores canonical request and response constraints from an endpoint-aware
|
|
226
|
+
* OpenAPI document onto one projected `typia.llm` function artifact.
|
|
227
|
+
*
|
|
228
|
+
* Query-only inputs merge into the root parameter object. Mixed body/query
|
|
229
|
+
* inputs merge into the generated `body` and `query` properties.
|
|
230
|
+
*
|
|
231
|
+
* @param options Projected artifact plus the canonical OpenAPI document.
|
|
232
|
+
* @returns A cloned artifact enriched with OpenAPI-backed constraints when available.
|
|
233
|
+
*/
|
|
234
|
+
export declare function applyOpenApiConstraintsToTypiaLlmFunctionArtifact({ functionArtifact, openApiDocument, operationId, }: ApplyOpenApiConstraintsToTypiaLlmFunctionArtifactOptions): ProjectedTypiaLlmFunctionArtifact;
|
|
200
235
|
/**
|
|
201
236
|
* Projects a compiled `typia.llm.application(...)` result into a JSON-friendly
|
|
202
237
|
* downstream adapter artifact.
|
|
@@ -204,7 +239,7 @@ export declare function projectTypiaLlmApplicationFunction(functionSchema: Typia
|
|
|
204
239
|
* @param options Compiled application value and source metadata.
|
|
205
240
|
* @returns JSON-friendly application artifact.
|
|
206
241
|
*/
|
|
207
|
-
export declare function projectTypiaLlmApplicationArtifact({ application, generatedFrom, transformFunction, }: ProjectTypiaLlmApplicationArtifactOptions): ProjectedTypiaLlmApplicationArtifact;
|
|
242
|
+
export declare function projectTypiaLlmApplicationArtifact({ application, generatedFrom, openApiProjection, transformFunction, }: ProjectTypiaLlmApplicationArtifactOptions): ProjectedTypiaLlmApplicationArtifact;
|
|
208
243
|
/**
|
|
209
244
|
* Projects a compiled `typia.llm.structuredOutput(...)` result into a
|
|
210
245
|
* JSON-friendly downstream adapter artifact.
|
|
@@ -81,9 +81,195 @@ const TYPESCRIPT_RESERVED_WORDS = new Set([
|
|
|
81
81
|
'with',
|
|
82
82
|
'yield',
|
|
83
83
|
]);
|
|
84
|
+
const JSON_SCHEMA_CONSTRAINT_KEYS = [
|
|
85
|
+
'additionalProperties',
|
|
86
|
+
'const',
|
|
87
|
+
'default',
|
|
88
|
+
'enum',
|
|
89
|
+
'exclusiveMaximum',
|
|
90
|
+
'exclusiveMinimum',
|
|
91
|
+
'format',
|
|
92
|
+
'maxItems',
|
|
93
|
+
'maxLength',
|
|
94
|
+
'maximum',
|
|
95
|
+
'minItems',
|
|
96
|
+
'minLength',
|
|
97
|
+
'minimum',
|
|
98
|
+
'multipleOf',
|
|
99
|
+
'pattern',
|
|
100
|
+
'type',
|
|
101
|
+
];
|
|
84
102
|
function cloneJsonValueIfDefined(value) {
|
|
85
103
|
return value === undefined ? undefined : cloneJsonValue(value);
|
|
86
104
|
}
|
|
105
|
+
function isJsonSchemaObject(value) {
|
|
106
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
107
|
+
}
|
|
108
|
+
function decodeJsonPointerSegment(segment) {
|
|
109
|
+
return segment.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
110
|
+
}
|
|
111
|
+
function resolveOpenApiReferenceTarget(document, reference) {
|
|
112
|
+
if (!reference.startsWith('#/')) {
|
|
113
|
+
throw new Error(`Unsupported OpenAPI schema reference "${reference}".`);
|
|
114
|
+
}
|
|
115
|
+
let current = document;
|
|
116
|
+
for (const rawSegment of reference.slice(2).split('/')) {
|
|
117
|
+
const segment = decodeJsonPointerSegment(rawSegment);
|
|
118
|
+
if (Array.isArray(current)) {
|
|
119
|
+
const index = Number.parseInt(segment, 10);
|
|
120
|
+
current = Number.isInteger(index) ? current[index] : undefined;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (!isJsonSchemaObject(current)) {
|
|
124
|
+
current = undefined;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
current = current[segment];
|
|
128
|
+
}
|
|
129
|
+
if (!isJsonSchemaObject(current)) {
|
|
130
|
+
throw new Error(`Unable to resolve OpenAPI schema reference "${reference}".`);
|
|
131
|
+
}
|
|
132
|
+
return current;
|
|
133
|
+
}
|
|
134
|
+
function resolveOpenApiSchemaObject(document, schema, seenReferences = new Set()) {
|
|
135
|
+
if (!isJsonSchemaObject(schema)) {
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
138
|
+
const reference = schema.$ref;
|
|
139
|
+
if (typeof reference !== 'string') {
|
|
140
|
+
return schema;
|
|
141
|
+
}
|
|
142
|
+
if (seenReferences.has(reference)) {
|
|
143
|
+
return schema;
|
|
144
|
+
}
|
|
145
|
+
return resolveOpenApiSchemaObject(document, resolveOpenApiReferenceTarget(document, reference), new Set([...seenReferences, reference]));
|
|
146
|
+
}
|
|
147
|
+
function collectOpenApiSeenReferences(schema, seenReferences) {
|
|
148
|
+
const reference = schema.$ref;
|
|
149
|
+
if (typeof reference !== 'string' || seenReferences.has(reference)) {
|
|
150
|
+
return seenReferences;
|
|
151
|
+
}
|
|
152
|
+
return new Set([...seenReferences, reference]);
|
|
153
|
+
}
|
|
154
|
+
function mergeJsonSchemaConstraintProperties(document, target, source, seenReferences = new Set()) {
|
|
155
|
+
const nextSeenReferences = collectOpenApiSeenReferences(source, seenReferences);
|
|
156
|
+
const resolvedSource = resolveOpenApiSchemaObject(document, source, seenReferences);
|
|
157
|
+
const merged = target;
|
|
158
|
+
for (const key of JSON_SCHEMA_CONSTRAINT_KEYS) {
|
|
159
|
+
if (resolvedSource[key] !== undefined) {
|
|
160
|
+
merged[key] = cloneJsonValue(resolvedSource[key]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (Array.isArray(resolvedSource.required)) {
|
|
164
|
+
merged.required = resolvedSource.required.filter((value) => typeof value === 'string');
|
|
165
|
+
}
|
|
166
|
+
if (Array.isArray(resolvedSource.items)) {
|
|
167
|
+
merged.items = cloneJsonValue(resolvedSource.items);
|
|
168
|
+
}
|
|
169
|
+
else if (isJsonSchemaObject(resolvedSource.items)) {
|
|
170
|
+
const nextItems = isJsonSchemaObject(merged.items) ? merged.items : {};
|
|
171
|
+
merged.items = mergeJsonSchemaConstraintProperties(document, nextItems, resolvedSource.items, nextSeenReferences);
|
|
172
|
+
}
|
|
173
|
+
if (isJsonSchemaObject(resolvedSource.properties)) {
|
|
174
|
+
const targetProperties = isJsonSchemaObject(merged.properties)
|
|
175
|
+
? merged.properties
|
|
176
|
+
: {};
|
|
177
|
+
for (const [propertyName, propertySchema] of Object.entries(resolvedSource.properties)) {
|
|
178
|
+
if (!isJsonSchemaObject(propertySchema)) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
const nextProperty = isJsonSchemaObject(targetProperties[propertyName])
|
|
182
|
+
? targetProperties[propertyName]
|
|
183
|
+
: {};
|
|
184
|
+
targetProperties[propertyName] = mergeJsonSchemaConstraintProperties(document, nextProperty, propertySchema, nextSeenReferences);
|
|
185
|
+
}
|
|
186
|
+
merged.properties = targetProperties;
|
|
187
|
+
}
|
|
188
|
+
return merged;
|
|
189
|
+
}
|
|
190
|
+
function findOpenApiOperationById(document, operationId) {
|
|
191
|
+
for (const pathItem of Object.values(document.paths)) {
|
|
192
|
+
if (!isJsonSchemaObject(pathItem)) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
for (const method of ['delete', 'get', 'patch', 'post', 'put']) {
|
|
196
|
+
const operation = resolveOpenApiSchemaObject(document, pathItem[method]);
|
|
197
|
+
if (!isJsonSchemaObject(operation) ||
|
|
198
|
+
typeof operation.operationId !== 'string') {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (operation.operationId === operationId) {
|
|
202
|
+
return operation;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
function resolveOpenApiRequestBodySchema(operation, document) {
|
|
209
|
+
const requestBody = resolveOpenApiSchemaObject(document, operation.requestBody);
|
|
210
|
+
const content = isJsonSchemaObject(requestBody.content)
|
|
211
|
+
? requestBody.content
|
|
212
|
+
: null;
|
|
213
|
+
const jsonMediaType = content && isJsonSchemaObject(content['application/json'])
|
|
214
|
+
? content['application/json']
|
|
215
|
+
: null;
|
|
216
|
+
const schema = jsonMediaType?.schema;
|
|
217
|
+
if (!isJsonSchemaObject(schema)) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
return resolveOpenApiSchemaObject(document, schema);
|
|
221
|
+
}
|
|
222
|
+
function resolveOpenApiSuccessResponseSchema(operation, document) {
|
|
223
|
+
for (const [statusCode, response] of Object.entries(operation.responses)) {
|
|
224
|
+
const resolvedResponse = resolveOpenApiSchemaObject(document, response);
|
|
225
|
+
if (!/^2(?:\d\d|XX)$/u.test(statusCode) ||
|
|
226
|
+
!isJsonSchemaObject(resolvedResponse)) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const content = isJsonSchemaObject(resolvedResponse.content)
|
|
230
|
+
? resolvedResponse.content
|
|
231
|
+
: null;
|
|
232
|
+
const jsonMediaType = content && isJsonSchemaObject(content['application/json'])
|
|
233
|
+
? content['application/json']
|
|
234
|
+
: null;
|
|
235
|
+
const schema = jsonMediaType?.schema;
|
|
236
|
+
if (!isJsonSchemaObject(schema)) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
return resolveOpenApiSchemaObject(document, schema);
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
function getOrCreateObjectProperty(target, propertyName) {
|
|
244
|
+
const targetProperties = isJsonSchemaObject(target.properties)
|
|
245
|
+
? target.properties
|
|
246
|
+
: {};
|
|
247
|
+
const nextProperty = isJsonSchemaObject(targetProperties[propertyName])
|
|
248
|
+
? targetProperties[propertyName]
|
|
249
|
+
: {};
|
|
250
|
+
targetProperties[propertyName] = nextProperty;
|
|
251
|
+
target.properties = targetProperties;
|
|
252
|
+
return nextProperty;
|
|
253
|
+
}
|
|
254
|
+
function applyOpenApiQueryParameterConstraints(target, operation, document) {
|
|
255
|
+
for (const parameter of operation.parameters ?? []) {
|
|
256
|
+
const resolvedParameter = resolveOpenApiSchemaObject(document, parameter);
|
|
257
|
+
if (!isJsonSchemaObject(resolvedParameter) ||
|
|
258
|
+
resolvedParameter.in !== 'query' ||
|
|
259
|
+
typeof resolvedParameter.name !== 'string') {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
const propertyTarget = getOrCreateObjectProperty(target, resolvedParameter.name);
|
|
263
|
+
mergeJsonSchemaConstraintProperties(document, propertyTarget, resolveOpenApiSchemaObject(document, resolvedParameter.schema));
|
|
264
|
+
if (resolvedParameter.required === true) {
|
|
265
|
+
const required = new Set(Array.isArray(target.required)
|
|
266
|
+
? target.required.filter((value) => typeof value === 'string')
|
|
267
|
+
: []);
|
|
268
|
+
required.add(resolvedParameter.name);
|
|
269
|
+
target.required = [...required];
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
87
273
|
function getContractSourceTypeName(manifest, endpoint, contractName) {
|
|
88
274
|
const contract = manifest.contracts[contractName];
|
|
89
275
|
if (!contract) {
|
|
@@ -342,6 +528,50 @@ function cloneProjectedTypiaLlmFunctionArtifact(functionArtifact) {
|
|
|
342
528
|
...(functionArtifact.tags ? { tags: [...functionArtifact.tags] } : {}),
|
|
343
529
|
};
|
|
344
530
|
}
|
|
531
|
+
/**
|
|
532
|
+
* Restores canonical request and response constraints from an endpoint-aware
|
|
533
|
+
* OpenAPI document onto one projected `typia.llm` function artifact.
|
|
534
|
+
*
|
|
535
|
+
* Query-only inputs merge into the root parameter object. Mixed body/query
|
|
536
|
+
* inputs merge into the generated `body` and `query` properties.
|
|
537
|
+
*
|
|
538
|
+
* @param options Projected artifact plus the canonical OpenAPI document.
|
|
539
|
+
* @returns A cloned artifact enriched with OpenAPI-backed constraints when available.
|
|
540
|
+
*/
|
|
541
|
+
export function applyOpenApiConstraintsToTypiaLlmFunctionArtifact({ functionArtifact, openApiDocument, operationId, }) {
|
|
542
|
+
const constrainedArtifact = cloneProjectedTypiaLlmFunctionArtifact(functionArtifact);
|
|
543
|
+
const operation = findOpenApiOperationById(openApiDocument, operationId);
|
|
544
|
+
if (!operation) {
|
|
545
|
+
return constrainedArtifact;
|
|
546
|
+
}
|
|
547
|
+
const hasQueryParameters = (operation.parameters ?? []).some((parameter) => {
|
|
548
|
+
const resolvedParameter = resolveOpenApiSchemaObject(openApiDocument, parameter);
|
|
549
|
+
return (isJsonSchemaObject(resolvedParameter) &&
|
|
550
|
+
resolvedParameter.in === 'query' &&
|
|
551
|
+
typeof resolvedParameter.name === 'string');
|
|
552
|
+
});
|
|
553
|
+
const requestBodySchema = resolveOpenApiRequestBodySchema(operation, openApiDocument);
|
|
554
|
+
if (requestBodySchema) {
|
|
555
|
+
if (hasQueryParameters) {
|
|
556
|
+
mergeJsonSchemaConstraintProperties(openApiDocument, getOrCreateObjectProperty(constrainedArtifact.parameters, 'body'), requestBodySchema);
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
mergeJsonSchemaConstraintProperties(openApiDocument, constrainedArtifact.parameters, requestBodySchema);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
if (hasQueryParameters) {
|
|
563
|
+
applyOpenApiQueryParameterConstraints(requestBodySchema
|
|
564
|
+
? getOrCreateObjectProperty(constrainedArtifact.parameters, 'query')
|
|
565
|
+
: constrainedArtifact.parameters, operation, openApiDocument);
|
|
566
|
+
}
|
|
567
|
+
if (constrainedArtifact.output) {
|
|
568
|
+
const responseSchema = resolveOpenApiSuccessResponseSchema(operation, openApiDocument);
|
|
569
|
+
if (responseSchema) {
|
|
570
|
+
mergeJsonSchemaConstraintProperties(openApiDocument, constrainedArtifact.output, responseSchema);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return constrainedArtifact;
|
|
574
|
+
}
|
|
345
575
|
/**
|
|
346
576
|
* Projects a compiled `typia.llm.application(...)` result into a JSON-friendly
|
|
347
577
|
* downstream adapter artifact.
|
|
@@ -349,13 +579,20 @@ function cloneProjectedTypiaLlmFunctionArtifact(functionArtifact) {
|
|
|
349
579
|
* @param options Compiled application value and source metadata.
|
|
350
580
|
* @returns JSON-friendly application artifact.
|
|
351
581
|
*/
|
|
352
|
-
export function projectTypiaLlmApplicationArtifact({ application, generatedFrom, transformFunction, }) {
|
|
582
|
+
export function projectTypiaLlmApplicationArtifact({ application, generatedFrom, openApiProjection, transformFunction, }) {
|
|
353
583
|
return {
|
|
354
584
|
functions: application.functions.map((functionSchema) => {
|
|
355
585
|
const functionArtifact = projectTypiaLlmApplicationFunction(functionSchema);
|
|
356
|
-
const
|
|
357
|
-
?
|
|
586
|
+
const openApiAlignedArtifact = openApiProjection
|
|
587
|
+
? applyOpenApiConstraintsToTypiaLlmFunctionArtifact({
|
|
588
|
+
functionArtifact,
|
|
589
|
+
openApiDocument: openApiProjection.openApiDocument,
|
|
590
|
+
operationId: openApiProjection.resolveOperationId?.(functionSchema, functionArtifact) ?? functionSchema.name,
|
|
591
|
+
})
|
|
358
592
|
: functionArtifact;
|
|
593
|
+
const transformedArtifact = transformFunction
|
|
594
|
+
? transformFunction(openApiAlignedArtifact, functionSchema)
|
|
595
|
+
: openApiAlignedArtifact;
|
|
359
596
|
return cloneProjectedTypiaLlmFunctionArtifact(transformedArtifact);
|
|
360
597
|
}),
|
|
361
598
|
generatedFrom: cloneJsonValue(generatedFrom),
|