@wp-typia/project-tools 0.20.0 → 0.20.1
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.
|
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import { promises as fsp } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { syncTypeSchemas } from "@wp-typia/block-runtime/metadata-core";
|
|
5
|
+
import semver from "semver";
|
|
5
6
|
import { appendWorkspaceInventoryEntries, readWorkspaceInventory, } from "./workspace-inventory.js";
|
|
6
7
|
import { resolveWorkspaceProject } from "./workspace-project.js";
|
|
7
8
|
import { toTitleCase } from "./string-case.js";
|
|
@@ -12,14 +13,63 @@ const ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
|
|
|
12
13
|
const ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
|
|
13
14
|
const ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end";
|
|
14
15
|
const ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start";
|
|
15
|
-
const
|
|
16
|
-
const
|
|
16
|
+
const WP_ABILITIES_PACKAGE_VERSION = "^0.10.0";
|
|
17
|
+
const WP_CORE_ABILITIES_PACKAGE_VERSION = "^0.9.0";
|
|
18
|
+
const WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities";
|
|
19
|
+
const WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";
|
|
17
20
|
function escapeRegex(value) {
|
|
18
21
|
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
19
22
|
}
|
|
20
23
|
function quotePhpString(value) {
|
|
21
24
|
return `'${value.replace(/\\/gu, "\\\\").replace(/'/gu, "\\'")}'`;
|
|
22
25
|
}
|
|
26
|
+
function findPhpFunctionRange(source, functionName) {
|
|
27
|
+
const functionPattern = new RegExp(`function\\s+${escapeRegex(functionName)}\\s*\\([^)]*\\)\\s*\\{`, "u");
|
|
28
|
+
const match = functionPattern.exec(source);
|
|
29
|
+
if (!match) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const openingBraceIndex = match.index + match[0].length - 1;
|
|
33
|
+
let depth = 0;
|
|
34
|
+
for (let index = openingBraceIndex; index < source.length; index += 1) {
|
|
35
|
+
const character = source[index];
|
|
36
|
+
if (character === "{") {
|
|
37
|
+
depth += 1;
|
|
38
|
+
}
|
|
39
|
+
else if (character === "}") {
|
|
40
|
+
depth -= 1;
|
|
41
|
+
if (depth === 0) {
|
|
42
|
+
const end = index + 1;
|
|
43
|
+
return {
|
|
44
|
+
end,
|
|
45
|
+
source: source.slice(match.index, end),
|
|
46
|
+
start: match.index,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
function replacePhpFunctionDefinition(source, functionName, replacement) {
|
|
54
|
+
const functionRange = findPhpFunctionRange(source, functionName);
|
|
55
|
+
if (!functionRange) {
|
|
56
|
+
return source;
|
|
57
|
+
}
|
|
58
|
+
return `${source.slice(0, functionRange.start)}${replacement.trimStart()}${source.slice(functionRange.end)}`;
|
|
59
|
+
}
|
|
60
|
+
function resolveManagedDependencyVersion(existingVersion, requiredVersion) {
|
|
61
|
+
if (!existingVersion) {
|
|
62
|
+
return requiredVersion;
|
|
63
|
+
}
|
|
64
|
+
const existingMinimum = semver.minVersion(existingVersion);
|
|
65
|
+
const requiredMinimum = semver.minVersion(requiredVersion);
|
|
66
|
+
if (!existingMinimum || !requiredMinimum) {
|
|
67
|
+
return requiredVersion;
|
|
68
|
+
}
|
|
69
|
+
return semver.gte(existingMinimum, requiredMinimum)
|
|
70
|
+
? existingVersion
|
|
71
|
+
: requiredVersion;
|
|
72
|
+
}
|
|
23
73
|
function toPascalCaseFromAbilitySlug(abilitySlug) {
|
|
24
74
|
return normalizeBlockSlug(abilitySlug)
|
|
25
75
|
.split("-")
|
|
@@ -98,7 +148,14 @@ function buildAbilityDataSource(abilitySlug) {
|
|
|
98
148
|
.replace(/[^A-Z0-9]+/gu, "_")
|
|
99
149
|
.replace(/_{2,}/gu, "_")
|
|
100
150
|
.replace(/^_|_$/gu, "");
|
|
101
|
-
return `import
|
|
151
|
+
return `import {
|
|
152
|
+
\texecuteAbility,
|
|
153
|
+
\tgetAbilities,
|
|
154
|
+
\tgetAbility as getRegisteredAbility,
|
|
155
|
+
} from '@wordpress/abilities';
|
|
156
|
+
import '@wordpress/core-abilities';
|
|
157
|
+
|
|
158
|
+
import abilityConfig from './ability.config.json';
|
|
102
159
|
|
|
103
160
|
import type { ${pascalCase}AbilityInput, ${pascalCase}AbilityOutput } from './types';
|
|
104
161
|
|
|
@@ -110,55 +167,56 @@ interface WordPressAbilityDefinition {
|
|
|
110
167
|
\tname?: string;
|
|
111
168
|
}
|
|
112
169
|
|
|
113
|
-
interface WordPressAbilitiesClient {
|
|
114
|
-
\texecuteAbility( name: string, input?: unknown ): Promise< unknown >;
|
|
115
|
-
\tgetAbilities( args?: { category?: string } ): WordPressAbilityDefinition[];
|
|
116
|
-
\tgetAbility( name: string ): WordPressAbilityDefinition | undefined;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const ABILITY_CLIENT_UNAVAILABLE_MESSAGE =
|
|
120
|
-
\t'The WordPress abilities client is unavailable on this screen. Ensure the Abilities API and @wordpress/core-abilities integration are loaded before using this scaffold.';
|
|
121
|
-
|
|
122
170
|
export const ${abilityConstBase}_ABILITY = abilityConfig;
|
|
123
171
|
export const ${abilityConstBase}_ABILITY_CATEGORY = abilityConfig.category;
|
|
124
172
|
export const ${abilityConstBase}_ABILITY_ID = abilityConfig.abilityId;
|
|
125
173
|
export const ${abilityConstBase}_ABILITY_META = abilityConfig.meta;
|
|
174
|
+
const ABILITY_DISCOVERY_POLL_INTERVAL_MS = 50;
|
|
175
|
+
const ABILITY_DISCOVERY_TIMEOUT_MS = 5000;
|
|
126
176
|
|
|
127
177
|
export type {
|
|
128
178
|
\t${pascalCase}AbilityInput,
|
|
129
179
|
\t${pascalCase}AbilityOutput,
|
|
130
180
|
};
|
|
131
181
|
|
|
132
|
-
function
|
|
133
|
-
\
|
|
134
|
-
\t\
|
|
135
|
-
\t
|
|
136
|
-
|
|
137
|
-
\t\t\t};
|
|
138
|
-
\t\t};
|
|
139
|
-
\t};
|
|
140
|
-
\tconst client = runtime.window?.wp?.abilities;
|
|
141
|
-
\tif ( ! client ) {
|
|
142
|
-
\t\tthrow new Error( ABILITY_CLIENT_UNAVAILABLE_MESSAGE );
|
|
143
|
-
\t}
|
|
182
|
+
function sleep( milliseconds: number ): Promise< void > {
|
|
183
|
+
\treturn new Promise( ( resolve ) => {
|
|
184
|
+
\t\tsetTimeout( resolve, milliseconds );
|
|
185
|
+
\t} );
|
|
186
|
+
}
|
|
144
187
|
|
|
145
|
-
|
|
188
|
+
async function waitFor${pascalCase}AbilityRegistration(): Promise< void > {
|
|
189
|
+
\tconst deadline = Date.now() + ABILITY_DISCOVERY_TIMEOUT_MS;
|
|
190
|
+
\twhile ( ! getRegisteredAbility( ${abilityConstBase}_ABILITY_ID ) ) {
|
|
191
|
+
\t\tif ( Date.now() >= deadline ) {
|
|
192
|
+
\t\t\treturn;
|
|
193
|
+
\t\t}
|
|
194
|
+
|
|
195
|
+
\t\tawait sleep( ABILITY_DISCOVERY_POLL_INTERVAL_MS );
|
|
196
|
+
\t}
|
|
146
197
|
}
|
|
147
198
|
|
|
148
|
-
export function list${pascalCase}CategoryAbilities(): WordPressAbilityDefinition[] {
|
|
149
|
-
\
|
|
199
|
+
export async function list${pascalCase}CategoryAbilities(): Promise< WordPressAbilityDefinition[] > {
|
|
200
|
+
\tawait waitFor${pascalCase}AbilityRegistration();
|
|
201
|
+
|
|
202
|
+
\treturn getAbilities( {
|
|
150
203
|
\t\tcategory: ${abilityConstBase}_ABILITY_CATEGORY.slug,
|
|
151
|
-
\t} );
|
|
204
|
+
\t} ) as WordPressAbilityDefinition[];
|
|
152
205
|
}
|
|
153
206
|
|
|
154
|
-
export function get${pascalCase}Ability():
|
|
207
|
+
export async function get${pascalCase}Ability(): Promise<
|
|
155
208
|
\t| WordPressAbilityDefinition
|
|
156
|
-
\t| undefined
|
|
157
|
-
|
|
209
|
+
\t| undefined
|
|
210
|
+
> {
|
|
211
|
+
\tawait waitFor${pascalCase}AbilityRegistration();
|
|
212
|
+
|
|
213
|
+
\treturn getRegisteredAbility( ${abilityConstBase}_ABILITY_ID ) as
|
|
214
|
+
\t\t| WordPressAbilityDefinition
|
|
215
|
+
\t\t| undefined;
|
|
158
216
|
}
|
|
159
217
|
|
|
160
|
-
export function require${pascalCase}Ability(): WordPressAbilityDefinition {
|
|
161
|
-
\tconst ability = get${pascalCase}Ability();
|
|
218
|
+
export async function require${pascalCase}Ability(): Promise< WordPressAbilityDefinition > {
|
|
219
|
+
\tconst ability = await get${pascalCase}Ability();
|
|
162
220
|
\tif ( ability ) {
|
|
163
221
|
\t\treturn ability;
|
|
164
222
|
\t}
|
|
@@ -174,7 +232,9 @@ export function require${pascalCase}Ability(): WordPressAbilityDefinition {
|
|
|
174
232
|
export async function run${pascalCase}Ability(
|
|
175
233
|
\tinput: ${pascalCase}AbilityInput
|
|
176
234
|
): Promise< ${pascalCase}AbilityOutput > {
|
|
177
|
-
\
|
|
235
|
+
\tawait waitFor${pascalCase}AbilityRegistration();
|
|
236
|
+
|
|
237
|
+
\treturn ( await executeAbility(
|
|
178
238
|
\t\t${abilityConstBase}_ABILITY_ID,
|
|
179
239
|
\t\tinput
|
|
180
240
|
\t) ) as ${pascalCase}AbilityOutput;
|
|
@@ -186,8 +246,8 @@ function buildAbilityClientSource(abilitySlug) {
|
|
|
186
246
|
return `/**
|
|
187
247
|
* Re-export the typed ${pascalCase} ability client helpers.
|
|
188
248
|
*
|
|
189
|
-
* The
|
|
190
|
-
*
|
|
249
|
+
* The helper methods load the WordPress core abilities integration and wait for
|
|
250
|
+
* this server-registered ability before reading or executing it.
|
|
191
251
|
*/
|
|
192
252
|
export * from './data';
|
|
193
253
|
`;
|
|
@@ -559,22 +619,31 @@ function ${enqueueFunctionName}() {
|
|
|
559
619
|
\t\t? $asset['dependencies']
|
|
560
620
|
\t\t: array();
|
|
561
621
|
|
|
562
|
-
\tforeach ( array( '${
|
|
563
|
-
\t\
|
|
564
|
-
\t\
|
|
565
|
-
\t\t\
|
|
566
|
-
\t\t\t
|
|
567
|
-
\t\t
|
|
622
|
+
\tforeach ( array( '${WP_CORE_ABILITIES_SCRIPT_MODULE_ID}', '${WP_ABILITIES_SCRIPT_MODULE_ID}' ) as $ability_dependency ) {
|
|
623
|
+
\t\t$has_dependency = false;
|
|
624
|
+
\t\tforeach ( $dependencies as $dependency ) {
|
|
625
|
+
\t\t\t$dependency_id = is_array( $dependency ) && isset( $dependency['id'] )
|
|
626
|
+
\t\t\t\t? $dependency['id']
|
|
627
|
+
\t\t\t\t: $dependency;
|
|
628
|
+
\t\t\tif ( $dependency_id === $ability_dependency ) {
|
|
629
|
+
\t\t\t\t$has_dependency = true;
|
|
630
|
+
\t\t\t\tbreak;
|
|
631
|
+
\t\t\t}
|
|
632
|
+
\t\t}
|
|
633
|
+
\t\tif ( ! $has_dependency ) {
|
|
568
634
|
\t\t\t$dependencies[] = $ability_dependency;
|
|
569
635
|
\t\t}
|
|
570
636
|
\t}
|
|
571
637
|
|
|
572
|
-
\
|
|
638
|
+
\tif ( ! function_exists( 'wp_enqueue_script_module' ) ) {
|
|
639
|
+
\t\treturn;
|
|
640
|
+
\t}
|
|
641
|
+
|
|
642
|
+
\twp_enqueue_script_module(
|
|
573
643
|
\t\t'${workspaceBaseName}-abilities',
|
|
574
644
|
\t\tplugins_url( '${ABILITY_EDITOR_SCRIPT}', __FILE__ ),
|
|
575
645
|
\t\t$dependencies,
|
|
576
|
-
\t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $script_path )
|
|
577
|
-
\t\ttrue
|
|
646
|
+
\t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $script_path )
|
|
578
647
|
\t);
|
|
579
648
|
}
|
|
580
649
|
`;
|
|
@@ -607,6 +676,9 @@ function ${enqueueFunctionName}() {
|
|
|
607
676
|
if (!hasPhpFunctionDefinition(enqueueFunctionName)) {
|
|
608
677
|
insertPhpSnippet(enqueueFunction);
|
|
609
678
|
}
|
|
679
|
+
else if (!findPhpFunctionRange(nextSource, enqueueFunctionName)?.source.includes("wp_enqueue_script_module")) {
|
|
680
|
+
nextSource = replacePhpFunctionDefinition(nextSource, enqueueFunctionName, enqueueFunction);
|
|
681
|
+
}
|
|
610
682
|
if (!nextSource.includes(loadHook)) {
|
|
611
683
|
appendPhpSnippet(loadHook);
|
|
612
684
|
}
|
|
@@ -626,10 +698,17 @@ async function ensureAbilityPackageScripts(workspace) {
|
|
|
626
698
|
...(packageJson.scripts ?? {}),
|
|
627
699
|
"sync-abilities": packageJson.scripts?.["sync-abilities"] ?? "tsx scripts/sync-abilities.ts",
|
|
628
700
|
};
|
|
629
|
-
|
|
701
|
+
const nextDependencies = {
|
|
702
|
+
...(packageJson.dependencies ?? {}),
|
|
703
|
+
[WP_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_ABILITIES_SCRIPT_MODULE_ID], WP_ABILITIES_PACKAGE_VERSION),
|
|
704
|
+
[WP_CORE_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_CORE_ABILITIES_SCRIPT_MODULE_ID], WP_CORE_ABILITIES_PACKAGE_VERSION),
|
|
705
|
+
};
|
|
706
|
+
if (JSON.stringify(nextScripts) === JSON.stringify(packageJson.scripts ?? {}) &&
|
|
707
|
+
JSON.stringify(nextDependencies) === JSON.stringify(packageJson.dependencies ?? {})) {
|
|
630
708
|
return;
|
|
631
709
|
}
|
|
632
710
|
packageJson.scripts = nextScripts;
|
|
711
|
+
packageJson.dependencies = nextDependencies;
|
|
633
712
|
await fsp.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, "\t")}\n`, "utf8");
|
|
634
713
|
}
|
|
635
714
|
async function ensureAbilitySyncProjectAnchors(workspace) {
|
|
@@ -702,6 +781,28 @@ async function ensureAbilityWebpackAnchors(workspace) {
|
|
|
702
781
|
if (/['"]abilities\/index['"]/u.test(source)) {
|
|
703
782
|
return source;
|
|
704
783
|
}
|
|
784
|
+
const optionalModuleReturnPattern = /(function\s+getOptionalModuleEntries\s*\(\)\s*\{[\s\S]*?)(\n\treturn Object\.fromEntries\(\s*entries\s*\);\n\})/u;
|
|
785
|
+
if (optionalModuleReturnPattern.test(source)) {
|
|
786
|
+
return source.replace(optionalModuleReturnPattern, `$1
|
|
787
|
+
|
|
788
|
+
\tfor ( const [ entryName, candidates ] of [
|
|
789
|
+
\t\t[
|
|
790
|
+
\t\t\t'abilities/index',
|
|
791
|
+
\t\t\t[ 'src/abilities/index.ts', 'src/abilities/index.js' ],
|
|
792
|
+
\t\t],
|
|
793
|
+
\t] ) {
|
|
794
|
+
\t\tfor ( const relativePath of candidates ) {
|
|
795
|
+
\t\t\tconst entryPath = path.resolve( process.cwd(), relativePath );
|
|
796
|
+
\t\t\tif ( ! fs.existsSync( entryPath ) ) {
|
|
797
|
+
\t\t\t\tcontinue;
|
|
798
|
+
\t\t\t}
|
|
799
|
+
|
|
800
|
+
\t\t\tentries.push( [ entryName, entryPath ] );
|
|
801
|
+
\t\t\tbreak;
|
|
802
|
+
\t\t}
|
|
803
|
+
\t}
|
|
804
|
+
$2`);
|
|
805
|
+
}
|
|
705
806
|
const sharedEntriesPattern = /for\s*\(\s*const\s+\[\s*entryName\s*,\s*candidates\s*\]\s+of\s+\[([\s\S]*?)\]\s*\)\s*\{/u;
|
|
706
807
|
const match = source.match(sharedEntriesPattern);
|
|
707
808
|
if (!match ||
|
|
@@ -446,7 +446,6 @@ export async function runAddRestResourceCommand({ cwd = process.cwd(), methods,
|
|
|
446
446
|
const validatorsFilePath = path.join(restResourceDir, "api-validators.ts");
|
|
447
447
|
const apiFilePath = path.join(restResourceDir, "api.ts");
|
|
448
448
|
const dataFilePath = path.join(restResourceDir, "data.ts");
|
|
449
|
-
const clientFilePath = path.join(restResourceDir, "api-client.ts");
|
|
450
449
|
const phpFilePath = path.join(workspace.projectDir, "inc", "rest", `${restResourceSlug}.php`);
|
|
451
450
|
const mutationSnapshot = {
|
|
452
451
|
fileSources: await snapshotWorkspaceFiles([
|
|
@@ -303,21 +303,24 @@ function checkWorkspaceAbilityBootstrap(projectDir, packageName, phpPrefix) {
|
|
|
303
303
|
const hasServerGlob = source.includes(WORKSPACE_ABILITY_GLOB);
|
|
304
304
|
const hasEditorScript = source.includes(WORKSPACE_ABILITY_EDITOR_SCRIPT);
|
|
305
305
|
const hasEditorAsset = source.includes(WORKSPACE_ABILITY_EDITOR_ASSET);
|
|
306
|
+
const hasScriptModuleEnqueue = source.includes("wp_enqueue_script_module");
|
|
306
307
|
return createDoctorCheck("Ability bootstrap", hasLoaderHook &&
|
|
307
308
|
hasAdminEnqueueHook &&
|
|
308
309
|
hasEditorEnqueueHook &&
|
|
309
310
|
hasServerGlob &&
|
|
310
311
|
hasEditorScript &&
|
|
311
|
-
hasEditorAsset
|
|
312
|
+
hasEditorAsset &&
|
|
313
|
+
hasScriptModuleEnqueue
|
|
312
314
|
? "pass"
|
|
313
315
|
: "fail", hasLoaderHook &&
|
|
314
316
|
hasAdminEnqueueHook &&
|
|
315
317
|
hasEditorEnqueueHook &&
|
|
316
318
|
hasServerGlob &&
|
|
317
319
|
hasEditorScript &&
|
|
318
|
-
hasEditorAsset
|
|
319
|
-
|
|
320
|
-
|
|
320
|
+
hasEditorAsset &&
|
|
321
|
+
hasScriptModuleEnqueue
|
|
322
|
+
? "Ability loader and admin/editor script-module bootstrap hooks are present"
|
|
323
|
+
: "Missing ability loader hook, script-module enqueue, or build/abilities asset references");
|
|
321
324
|
}
|
|
322
325
|
function checkWorkspaceAbilityIndex(projectDir, abilities) {
|
|
323
326
|
const indexRelativePath = [
|
|
@@ -14,6 +14,8 @@ export interface TypiaLlmEndpointMethodDescriptor {
|
|
|
14
14
|
description?: string;
|
|
15
15
|
/** Input type used by the generated controller method, or null for no input. */
|
|
16
16
|
inputTypeName: string | null;
|
|
17
|
+
/** Type names that must be imported when inputTypeName is an inline composite. */
|
|
18
|
+
inputTypeImportNames?: readonly string[];
|
|
17
19
|
/** HTTP method from the source endpoint manifest. */
|
|
18
20
|
method: EndpointManifestEndpointDefinition['method'];
|
|
19
21
|
/** Stable operation identifier used as the generated method name. */
|
|
@@ -84,21 +84,36 @@ const TYPESCRIPT_RESERVED_WORDS = new Set([
|
|
|
84
84
|
function cloneJsonValueIfDefined(value) {
|
|
85
85
|
return value === undefined ? undefined : cloneJsonValue(value);
|
|
86
86
|
}
|
|
87
|
-
function
|
|
87
|
+
function getContractSourceTypeName(manifest, endpoint, contractName) {
|
|
88
|
+
const contract = manifest.contracts[contractName];
|
|
89
|
+
if (!contract) {
|
|
90
|
+
throw new Error(`Endpoint "${endpoint.operationId}" references missing input contract "${contractName}".`);
|
|
91
|
+
}
|
|
92
|
+
return contract.sourceTypeName;
|
|
93
|
+
}
|
|
94
|
+
function getEndpointInputTypeDescriptor(manifest, endpoint) {
|
|
88
95
|
if (endpoint.bodyContract && endpoint.queryContract) {
|
|
89
|
-
|
|
96
|
+
const bodyTypeName = getContractSourceTypeName(manifest, endpoint, endpoint.bodyContract);
|
|
97
|
+
const queryTypeName = getContractSourceTypeName(manifest, endpoint, endpoint.queryContract);
|
|
98
|
+
return {
|
|
99
|
+
importTypeNames: [bodyTypeName, queryTypeName],
|
|
100
|
+
signatureTypeName: `{ body: ${bodyTypeName}; query: ${queryTypeName} }`,
|
|
101
|
+
};
|
|
90
102
|
}
|
|
91
103
|
const contractName = endpoint.method === 'GET'
|
|
92
104
|
? endpoint.queryContract ?? null
|
|
93
105
|
: endpoint.bodyContract ?? endpoint.queryContract ?? null;
|
|
94
106
|
if (!contractName) {
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
throw new Error(`Endpoint "${endpoint.operationId}" references missing input contract "${contractName}".`);
|
|
107
|
+
return {
|
|
108
|
+
importTypeNames: [],
|
|
109
|
+
signatureTypeName: null,
|
|
110
|
+
};
|
|
100
111
|
}
|
|
101
|
-
|
|
112
|
+
const sourceTypeName = getContractSourceTypeName(manifest, endpoint, contractName);
|
|
113
|
+
return {
|
|
114
|
+
importTypeNames: [sourceTypeName],
|
|
115
|
+
signatureTypeName: sourceTypeName,
|
|
116
|
+
};
|
|
102
117
|
}
|
|
103
118
|
function getEndpointOutputTypeName(manifest, endpoint) {
|
|
104
119
|
const contract = manifest.contracts[endpoint.responseContract];
|
|
@@ -157,7 +172,12 @@ function renderTypiaLlmModuleFromMethodDescriptors({ applicationExportName, inte
|
|
|
157
172
|
const importedTypeNames = new Set([structuredOutputTypeName]);
|
|
158
173
|
for (const method of methods) {
|
|
159
174
|
importedTypeNames.add(method.outputTypeName);
|
|
160
|
-
if (method.
|
|
175
|
+
if (method.inputTypeImportNames) {
|
|
176
|
+
for (const inputTypeImportName of method.inputTypeImportNames) {
|
|
177
|
+
importedTypeNames.add(inputTypeImportName);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else if (method.inputTypeName) {
|
|
161
181
|
importedTypeNames.add(method.inputTypeName);
|
|
162
182
|
}
|
|
163
183
|
}
|
|
@@ -233,11 +253,19 @@ async function reconcileGeneratedTypiaLlmArtifacts(artifacts, check) {
|
|
|
233
253
|
export function buildTypiaLlmEndpointMethodDescriptors(manifest) {
|
|
234
254
|
return manifest.endpoints.map((endpoint) => {
|
|
235
255
|
const normalizedAuth = normalizeEndpointAuthDefinition(endpoint);
|
|
256
|
+
const inputTypeDescriptor = getEndpointInputTypeDescriptor(manifest, endpoint);
|
|
257
|
+
const inputTypeName = inputTypeDescriptor.signatureTypeName;
|
|
258
|
+
const shouldUseInlineInputImports = inputTypeName !== null &&
|
|
259
|
+
inputTypeDescriptor.importTypeNames.length > 0 &&
|
|
260
|
+
inputTypeDescriptor.importTypeNames[0] !== inputTypeName;
|
|
236
261
|
return {
|
|
237
262
|
authIntent: normalizedAuth.auth,
|
|
238
263
|
...(normalizedAuth.authMode ? { authMode: normalizedAuth.authMode } : {}),
|
|
239
264
|
description: endpoint.summary,
|
|
240
|
-
inputTypeName
|
|
265
|
+
inputTypeName,
|
|
266
|
+
...(shouldUseInlineInputImports
|
|
267
|
+
? { inputTypeImportNames: inputTypeDescriptor.importTypeNames }
|
|
268
|
+
: {}),
|
|
241
269
|
method: endpoint.method,
|
|
242
270
|
operationId: endpoint.operationId,
|
|
243
271
|
outputTypeName: getEndpointOutputTypeName(manifest, endpoint),
|