@wp-typia/project-tools 0.22.10 → 0.23.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.
- package/dist/runtime/ai-feature-artifacts.js +4 -1
- package/dist/runtime/block-generator-service-spec.js +2 -1
- package/dist/runtime/cli-add-block-json.js +5 -1
- package/dist/runtime/cli-add-collision.d.ts +25 -0
- package/dist/runtime/cli-add-collision.js +76 -0
- package/dist/runtime/cli-add-help.js +12 -2
- package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
- package/dist/runtime/cli-add-kind-ids.js +3 -0
- package/dist/runtime/cli-add-types.d.ts +129 -0
- package/dist/runtime/cli-add-types.js +26 -0
- package/dist/runtime/cli-add-validation.d.ts +97 -1
- package/dist/runtime/cli-add-validation.js +313 -1
- package/dist/runtime/cli-add-workspace-ability-scaffold.js +4 -1
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +79 -20
- package/dist/runtime/cli-add-workspace-admin-view-source.js +11 -2
- package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.d.ts +34 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.js +483 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-default.d.ts +30 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-default.js +310 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-rest.d.ts +25 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-rest.js +124 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-settings.d.ts +34 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-settings.js +370 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-shared.d.ts +49 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates-shared.js +259 -0
- package/dist/runtime/cli-add-workspace-admin-view-templates.d.ts +19 -10
- package/dist/runtime/cli-add-workspace-admin-view-templates.js +31 -971
- package/dist/runtime/cli-add-workspace-admin-view-types.d.ts +21 -0
- package/dist/runtime/cli-add-workspace-admin-view-types.js +22 -0
- package/dist/runtime/cli-add-workspace-ai-anchors.js +125 -32
- package/dist/runtime/cli-add-workspace-ai-source-emitters.js +17 -1
- package/dist/runtime/cli-add-workspace-contract-source-emitters.d.ts +15 -0
- package/dist/runtime/cli-add-workspace-contract-source-emitters.js +42 -0
- package/dist/runtime/cli-add-workspace-contract.d.ts +15 -0
- package/dist/runtime/cli-add-workspace-contract.js +65 -0
- package/dist/runtime/cli-add-workspace-integration-env.d.ts +26 -0
- package/dist/runtime/cli-add-workspace-integration-env.js +428 -0
- package/dist/runtime/cli-add-workspace-post-meta-anchors.d.ts +23 -0
- package/dist/runtime/cli-add-workspace-post-meta-anchors.js +244 -0
- package/dist/runtime/cli-add-workspace-post-meta-source-emitters.d.ts +63 -0
- package/dist/runtime/cli-add-workspace-post-meta-source-emitters.js +179 -0
- package/dist/runtime/cli-add-workspace-post-meta.d.ts +15 -0
- package/dist/runtime/cli-add-workspace-post-meta.js +107 -0
- package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-anchors.js +326 -21
- package/dist/runtime/cli-add-workspace-rest-generated.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-generated.js +158 -0
- package/dist/runtime/cli-add-workspace-rest-manual.d.ts +8 -0
- package/dist/runtime/cli-add-workspace-rest-manual.js +279 -0
- package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +24 -0
- package/dist/runtime/cli-add-workspace-rest-php-templates.js +678 -0
- package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +98 -2
- package/dist/runtime/cli-add-workspace-rest-source-emitters.js +323 -29
- package/dist/runtime/cli-add-workspace-rest-types.d.ts +108 -0
- package/dist/runtime/cli-add-workspace-rest-types.js +1 -0
- package/dist/runtime/cli-add-workspace-rest.d.ts +3 -7
- package/dist/runtime/cli-add-workspace-rest.js +34 -481
- package/dist/runtime/cli-add-workspace.d.ts +15 -0
- package/dist/runtime/cli-add-workspace.js +15 -0
- package/dist/runtime/cli-add.d.ts +1 -1
- package/dist/runtime/cli-add.js +1 -1
- package/dist/runtime/cli-core.d.ts +3 -2
- package/dist/runtime/cli-core.js +3 -2
- package/dist/runtime/cli-diagnostics.d.ts +3 -1
- package/dist/runtime/cli-diagnostics.js +17 -5
- package/dist/runtime/cli-doctor-environment.js +1 -3
- package/dist/runtime/cli-doctor-workspace-bindings.js +4 -1
- package/dist/runtime/cli-doctor-workspace-block-addons.d.ts +12 -0
- package/dist/runtime/cli-doctor-workspace-block-addons.js +134 -0
- package/dist/runtime/cli-doctor-workspace-block-iframe.d.ts +9 -0
- package/dist/runtime/cli-doctor-workspace-block-iframe.js +228 -0
- package/dist/runtime/cli-doctor-workspace-block-metadata.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-block-metadata.js +111 -0
- package/dist/runtime/cli-doctor-workspace-blocks.js +6 -424
- package/dist/runtime/cli-doctor-workspace-features-abilities.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-abilities.js +112 -0
- package/dist/runtime/cli-doctor-workspace-features-admin-views.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-admin-views.js +128 -0
- package/dist/runtime/cli-doctor-workspace-features-ai.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-ai.js +57 -0
- package/dist/runtime/cli-doctor-workspace-features-editor-plugins.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-editor-plugins.js +80 -0
- package/dist/runtime/cli-doctor-workspace-features-post-meta.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-post-meta.js +77 -0
- package/dist/runtime/cli-doctor-workspace-features-rest.d.ts +11 -0
- package/dist/runtime/cli-doctor-workspace-features-rest.js +120 -0
- package/dist/runtime/cli-doctor-workspace-features.js +14 -369
- package/dist/runtime/cli-doctor-workspace-package.d.ts +25 -3
- package/dist/runtime/cli-doctor-workspace-package.js +35 -13
- package/dist/runtime/cli-doctor-workspace-shared.d.ts +2 -0
- package/dist/runtime/cli-doctor-workspace-shared.js +2 -0
- package/dist/runtime/cli-doctor-workspace.js +8 -3
- package/dist/runtime/cli-doctor.d.ts +52 -3
- package/dist/runtime/cli-doctor.js +79 -8
- package/dist/runtime/cli-help.js +10 -0
- package/dist/runtime/cli-init-package-json.js +4 -2
- package/dist/runtime/cli-init-templates.js +11 -1
- package/dist/runtime/cli-prompt.d.ts +16 -2
- package/dist/runtime/cli-prompt.js +29 -12
- package/dist/runtime/cli-scaffold.d.ts +2 -1
- package/dist/runtime/cli-scaffold.js +19 -10
- package/dist/runtime/contract-artifacts.d.ts +14 -0
- package/dist/runtime/contract-artifacts.js +15 -0
- package/dist/runtime/external-template-guards.js +4 -6
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/json-utils.d.ts +62 -4
- package/dist/runtime/json-utils.js +78 -4
- package/dist/runtime/local-dev-presets.js +4 -1
- package/dist/runtime/migration-ui-capability.js +4 -1
- package/dist/runtime/migration-utils.js +4 -1
- package/dist/runtime/package-managers.js +6 -1
- package/dist/runtime/package-versions.js +6 -1
- package/dist/runtime/rest-resource-artifacts.d.ts +57 -1
- package/dist/runtime/rest-resource-artifacts.js +97 -1
- package/dist/runtime/scaffold-bootstrap.js +7 -2
- package/dist/runtime/scaffold-package-manager-files.js +5 -1
- package/dist/runtime/scaffold-repository-reference.js +4 -2
- package/dist/runtime/scaffold-template-variables.js +2 -1
- package/dist/runtime/scaffold.d.ts +18 -1
- package/dist/runtime/scaffold.js +55 -2
- package/dist/runtime/temp-roots.js +4 -1
- package/dist/runtime/template-layers.js +4 -1
- package/dist/runtime/template-registry.js +9 -3
- package/dist/runtime/template-render.d.ts +1 -1
- package/dist/runtime/template-render.js +1 -1
- package/dist/runtime/template-source-cache-markers.d.ts +37 -0
- package/dist/runtime/template-source-cache-markers.js +125 -0
- package/dist/runtime/template-source-cache.d.ts +1 -4
- package/dist/runtime/template-source-cache.js +16 -122
- package/dist/runtime/template-source-contracts.d.ts +2 -0
- package/dist/runtime/template-source-external.d.ts +4 -2
- package/dist/runtime/template-source-external.js +4 -2
- package/dist/runtime/template-source-normalization.js +2 -1
- package/dist/runtime/template-source-remote.d.ts +8 -4
- package/dist/runtime/template-source-remote.js +26 -9
- package/dist/runtime/template-source-seeds.js +10 -3
- package/dist/runtime/workspace-inventory-mutations.js +54 -4
- package/dist/runtime/workspace-inventory-parser-entries.d.ts +17 -0
- package/dist/runtime/workspace-inventory-parser-entries.js +157 -0
- package/dist/runtime/workspace-inventory-parser-validation.d.ts +104 -0
- package/dist/runtime/workspace-inventory-parser-validation.js +34 -0
- package/dist/runtime/workspace-inventory-parser.d.ts +3 -44
- package/dist/runtime/workspace-inventory-parser.js +7 -464
- package/dist/runtime/workspace-inventory-read.d.ts +9 -2
- package/dist/runtime/workspace-inventory-read.js +9 -2
- package/dist/runtime/workspace-inventory-section-descriptors.d.ts +19 -0
- package/dist/runtime/workspace-inventory-section-descriptors.js +435 -0
- package/dist/runtime/workspace-inventory-templates.d.ts +16 -1
- package/dist/runtime/workspace-inventory-templates.js +75 -4
- package/dist/runtime/workspace-inventory-types.d.ts +52 -2
- package/dist/runtime/workspace-inventory.d.ts +2 -2
- package/dist/runtime/workspace-inventory.js +1 -1
- package/dist/runtime/workspace-project.js +4 -6
- package/package.json +2 -2
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { quoteTsString } from './cli-add-shared.js';
|
|
2
|
+
import { getAdminViewRelativeModuleSpecifier } from './cli-add-workspace-admin-view-templates-shared.js';
|
|
3
|
+
import { toCamelCase, toPascalCase, toTitleCase } from './string-case.js';
|
|
4
|
+
/**
|
|
5
|
+
* Builds TypeScript request, response, and form-state types for REST settings.
|
|
6
|
+
*
|
|
7
|
+
* @param adminViewSlug - Admin-view slug used to derive generated type names.
|
|
8
|
+
* @param restResource - Manual REST settings resource metadata for imports.
|
|
9
|
+
* @returns Generated TypeScript source for REST settings types.
|
|
10
|
+
*/
|
|
11
|
+
export function buildRestSettingsAdminViewTypesSource(adminViewSlug, restResource) {
|
|
12
|
+
const pascalName = toPascalCase(adminViewSlug);
|
|
13
|
+
const restTypesModule = getAdminViewRelativeModuleSpecifier(adminViewSlug, restResource.typesFile);
|
|
14
|
+
const formStateTypeName = `${pascalName}SettingsFormState`;
|
|
15
|
+
const loadResultTypeName = `${pascalName}SettingsLoadResult`;
|
|
16
|
+
return `import type {
|
|
17
|
+
\t${restResource.bodyTypeName},
|
|
18
|
+
\t${restResource.queryTypeName},
|
|
19
|
+
\t${restResource.responseTypeName},
|
|
20
|
+
} from ${quoteTsString(restTypesModule)};
|
|
21
|
+
|
|
22
|
+
export type ${pascalName}SettingsRequest = ${restResource.bodyTypeName};
|
|
23
|
+
export type ${pascalName}SettingsQuery = ${restResource.queryTypeName};
|
|
24
|
+
export type ${pascalName}SettingsResponse = ${restResource.responseTypeName};
|
|
25
|
+
export type ${formStateTypeName} = Partial<${pascalName}SettingsRequest>;
|
|
26
|
+
|
|
27
|
+
export interface ${loadResultTypeName} {
|
|
28
|
+
\tform: ${formStateTypeName};
|
|
29
|
+
\tresponse: ${pascalName}SettingsResponse | null;
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Builds display metadata for a manual REST settings form admin screen.
|
|
35
|
+
*
|
|
36
|
+
* @param adminViewSlug - Admin-view slug used to derive generated identifiers.
|
|
37
|
+
* @param textDomain - WordPress i18n text domain for generated labels.
|
|
38
|
+
* @param restResource - Manual REST settings metadata, including secret fields.
|
|
39
|
+
* @returns Generated TypeScript source for settings form configuration.
|
|
40
|
+
*/
|
|
41
|
+
export function buildRestSettingsAdminViewConfigSource(adminViewSlug, textDomain, restResource) {
|
|
42
|
+
const pascalName = toPascalCase(adminViewSlug);
|
|
43
|
+
const camelName = toCamelCase(adminViewSlug);
|
|
44
|
+
const title = toTitleCase(adminViewSlug);
|
|
45
|
+
const configName = `${camelName}SettingsConfig`;
|
|
46
|
+
const formStateTypeName = `${pascalName}SettingsFormState`;
|
|
47
|
+
const secretPreserveOnEmpty = restResource.secretPreserveOnEmpty !== false;
|
|
48
|
+
const secretFieldSource = restResource.secretFieldName && restResource.secretStateFieldName
|
|
49
|
+
? `\t{
|
|
50
|
+
\t\tdescription: __( ${quoteTsString(secretPreserveOnEmpty
|
|
51
|
+
? 'Write-only secret value. Leave blank to keep the existing secret.'
|
|
52
|
+
: 'Write-only secret value. Blank submissions are sent to the REST route.')}, ${quoteTsString(textDomain)} ),
|
|
53
|
+
\t\tid: ${quoteTsString(restResource.secretFieldName)},
|
|
54
|
+
\t\tlabel: __( ${quoteTsString(toTitleCase(restResource.secretFieldName))}, ${quoteTsString(textDomain)} ),
|
|
55
|
+
\t\tpreserveOnEmpty: ${secretPreserveOnEmpty},
|
|
56
|
+
\t\tsecretStateField: ${quoteTsString(restResource.secretStateFieldName)},
|
|
57
|
+
\t\ttype: 'secret',
|
|
58
|
+
\t},`
|
|
59
|
+
: '';
|
|
60
|
+
return `import { __ } from '@wordpress/i18n';
|
|
61
|
+
|
|
62
|
+
import type { ${formStateTypeName} } from './types';
|
|
63
|
+
|
|
64
|
+
export type ${pascalName}SettingsFieldType = 'secret' | 'text' | 'textarea';
|
|
65
|
+
|
|
66
|
+
export interface ${pascalName}SettingsField {
|
|
67
|
+
\tdescription?: string;
|
|
68
|
+
\tid: Extract<keyof ${formStateTypeName}, string> | string;
|
|
69
|
+
\tlabel: string;
|
|
70
|
+
\tpreserveOnEmpty?: boolean;
|
|
71
|
+
\tsecretStateField?: string;
|
|
72
|
+
\ttype: ${pascalName}SettingsFieldType;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const ${configName} = {
|
|
76
|
+
\tdescription: __( 'This generated settings form is backed by the ${restResource.slug} REST contract. Adjust config.ts and data.ts as the contract becomes product-specific.', ${quoteTsString(textDomain)} ),
|
|
77
|
+
\tfields: [
|
|
78
|
+
\t\t{
|
|
79
|
+
\t\t\tdescription: __( 'Primary settings payload for this integration.', ${quoteTsString(textDomain)} ),
|
|
80
|
+
\t\t\tid: 'payload',
|
|
81
|
+
\t\t\tlabel: __( 'Payload', ${quoteTsString(textDomain)} ),
|
|
82
|
+
\t\t\ttype: 'textarea',
|
|
83
|
+
\t\t},
|
|
84
|
+
\t\t{
|
|
85
|
+
\t\t\tdescription: __( 'Optional operator note included with the save request.', ${quoteTsString(textDomain)} ),
|
|
86
|
+
\t\t\tid: 'comment',
|
|
87
|
+
\t\t\tlabel: __( 'Comment', ${quoteTsString(textDomain)} ),
|
|
88
|
+
\t\t\ttype: 'text',
|
|
89
|
+
\t\t},
|
|
90
|
+
${secretFieldSource}
|
|
91
|
+
\t] satisfies ${pascalName}SettingsField[],
|
|
92
|
+
\tsecretFieldName: ${restResource.secretFieldName ? quoteTsString(restResource.secretFieldName) : 'undefined'},
|
|
93
|
+
\tsecretPreserveOnEmpty: ${restResource.secretFieldName ? secretPreserveOnEmpty : 'undefined'},
|
|
94
|
+
\tsecretStateFieldName: ${restResource.secretStateFieldName ? quoteTsString(restResource.secretStateFieldName) : 'undefined'},
|
|
95
|
+
\ttitle: __( ${quoteTsString(title)}, ${quoteTsString(textDomain)} ),
|
|
96
|
+
};
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Builds load and save helpers for a manual REST settings form.
|
|
101
|
+
*
|
|
102
|
+
* @param adminViewSlug - Admin-view slug used to derive generated identifiers.
|
|
103
|
+
* @param restResource - Manual REST settings metadata for API imports and secret handling.
|
|
104
|
+
* @returns Generated TypeScript source for settings data helpers.
|
|
105
|
+
*/
|
|
106
|
+
export function buildRestSettingsAdminViewDataSource(adminViewSlug, restResource) {
|
|
107
|
+
const pascalName = toPascalCase(adminViewSlug);
|
|
108
|
+
const restApiModule = getAdminViewRelativeModuleSpecifier(adminViewSlug, restResource.apiFile);
|
|
109
|
+
const formStateTypeName = `${pascalName}SettingsFormState`;
|
|
110
|
+
const loadResultTypeName = `${pascalName}SettingsLoadResult`;
|
|
111
|
+
const loadName = `load${pascalName}Settings`;
|
|
112
|
+
const saveName = `save${pascalName}Settings`;
|
|
113
|
+
const secretPreserveOnEmpty = restResource.secretPreserveOnEmpty !== false;
|
|
114
|
+
const initialFieldLines = [
|
|
115
|
+
'\tpayload: \'\',',
|
|
116
|
+
'\tcomment: \'\',',
|
|
117
|
+
...(restResource.secretFieldName && !secretPreserveOnEmpty
|
|
118
|
+
? [`\t${quoteTsString(restResource.secretFieldName)}: '',`]
|
|
119
|
+
: []),
|
|
120
|
+
];
|
|
121
|
+
const initialFields = initialFieldLines.join('\n');
|
|
122
|
+
const requestBodySource = restResource.secretFieldName && secretPreserveOnEmpty
|
|
123
|
+
? `\tconst requestBody = { ...form } as Record<string, unknown>;
|
|
124
|
+
\tif (requestBody[${quoteTsString(restResource.secretFieldName)}] === '') {
|
|
125
|
+
\t\tdelete requestBody[${quoteTsString(restResource.secretFieldName)}];
|
|
126
|
+
\t}
|
|
127
|
+
`
|
|
128
|
+
: `\tconst requestBody = form as Record<string, unknown>;
|
|
129
|
+
`;
|
|
130
|
+
return `import { callManualRestContract } from ${quoteTsString(restApiModule)};
|
|
131
|
+
import type {
|
|
132
|
+
\t${formStateTypeName},
|
|
133
|
+
\t${loadResultTypeName},
|
|
134
|
+
\t${pascalName}SettingsQuery,
|
|
135
|
+
\t${pascalName}SettingsRequest,
|
|
136
|
+
\t${pascalName}SettingsResponse,
|
|
137
|
+
} from './types';
|
|
138
|
+
|
|
139
|
+
function formatValidationError(prefix: string, errors: unknown): string {
|
|
140
|
+
\tif (!Array.isArray(errors) || errors.length === 0) {
|
|
141
|
+
\t\treturn prefix;
|
|
142
|
+
\t}
|
|
143
|
+
|
|
144
|
+
\treturn \`\${prefix} \${JSON.stringify(errors)}\`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function createInitial${pascalName}SettingsFormState(): ${formStateTypeName} {
|
|
148
|
+
\treturn {
|
|
149
|
+
${initialFields}
|
|
150
|
+
\t} as ${formStateTypeName};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function ${loadName}(): Promise<${loadResultTypeName}> {
|
|
154
|
+
\treturn {
|
|
155
|
+
\t\tform: createInitial${pascalName}SettingsFormState(),
|
|
156
|
+
\t\tresponse: null,
|
|
157
|
+
\t};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export async function ${saveName}(
|
|
161
|
+
\tform: ${formStateTypeName},
|
|
162
|
+
\tquery: Partial<${pascalName}SettingsQuery> = {},
|
|
163
|
+
): Promise<${pascalName}SettingsResponse> {
|
|
164
|
+
${requestBodySource}
|
|
165
|
+
\tconst result = await callManualRestContract({
|
|
166
|
+
\t\tbody: requestBody as unknown as ${pascalName}SettingsRequest,
|
|
167
|
+
\t\tquery: query as ${pascalName}SettingsQuery,
|
|
168
|
+
\t});
|
|
169
|
+
\tif (!result.isValid) {
|
|
170
|
+
\t\tconst message =
|
|
171
|
+
\t\t\tresult.validationTarget === 'request'
|
|
172
|
+
\t\t\t\t? 'Settings request failed validation.'
|
|
173
|
+
\t\t\t\t: 'Settings response failed validation.';
|
|
174
|
+
\t\tthrow new Error(formatValidationError(message, result.errors));
|
|
175
|
+
\t}
|
|
176
|
+
|
|
177
|
+
\treturn result.data as ${pascalName}SettingsResponse;
|
|
178
|
+
}
|
|
179
|
+
`;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Builds the React form screen for a manual REST settings admin view.
|
|
183
|
+
*
|
|
184
|
+
* @param adminViewSlug - Admin-view slug used to derive generated identifiers.
|
|
185
|
+
* @param textDomain - WordPress i18n text domain for generated labels.
|
|
186
|
+
* @returns Generated TSX source for the REST settings screen.
|
|
187
|
+
*/
|
|
188
|
+
export function buildRestSettingsAdminViewScreenSource(adminViewSlug, textDomain) {
|
|
189
|
+
const pascalName = toPascalCase(adminViewSlug);
|
|
190
|
+
const componentName = `${pascalName}AdminViewScreen`;
|
|
191
|
+
const formStateTypeName = `${pascalName}SettingsFormState`;
|
|
192
|
+
const responseTypeName = `${pascalName}SettingsResponse`;
|
|
193
|
+
const camelName = toCamelCase(adminViewSlug);
|
|
194
|
+
const configName = `${camelName}SettingsConfig`;
|
|
195
|
+
const loadName = `load${pascalName}Settings`;
|
|
196
|
+
const saveName = `save${pascalName}Settings`;
|
|
197
|
+
return `import {
|
|
198
|
+
\tButton,
|
|
199
|
+
\tNotice,
|
|
200
|
+
\tSpinner,
|
|
201
|
+
\tTextControl,
|
|
202
|
+
\tTextareaControl,
|
|
203
|
+
} from '@wordpress/components';
|
|
204
|
+
import { useEffect, useState } from '@wordpress/element';
|
|
205
|
+
import { __ } from '@wordpress/i18n';
|
|
206
|
+
|
|
207
|
+
import { ${configName} } from './config';
|
|
208
|
+
import { ${loadName}, ${saveName} } from './data';
|
|
209
|
+
import type { ${formStateTypeName}, ${responseTypeName} } from './types';
|
|
210
|
+
|
|
211
|
+
function getFieldValue(form: ${formStateTypeName}, fieldId: string): string {
|
|
212
|
+
\tconst value = (form as Record<string, unknown>)[fieldId];
|
|
213
|
+
\tif (typeof value === 'string') {
|
|
214
|
+
\t\treturn value;
|
|
215
|
+
\t}
|
|
216
|
+
\tif (value == null) {
|
|
217
|
+
\t\treturn '';
|
|
218
|
+
\t}
|
|
219
|
+
|
|
220
|
+
\treturn String(value);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function getSecretState(response: ${responseTypeName} | null): boolean | null {
|
|
224
|
+
\tconst stateField = ${configName}.secretStateFieldName;
|
|
225
|
+
\tif (!stateField || !response) {
|
|
226
|
+
\t\treturn null;
|
|
227
|
+
\t}
|
|
228
|
+
|
|
229
|
+
\tconst value = (response as unknown as Record<string, unknown>)[stateField];
|
|
230
|
+
\treturn typeof value === 'boolean' ? value : null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function ${componentName}() {
|
|
234
|
+
\tconst [form, setForm] = useState<${formStateTypeName}>({});
|
|
235
|
+
\tconst [response, setResponse] = useState<${responseTypeName} | null>(null);
|
|
236
|
+
\tconst [error, setError] = useState<string | null>(null);
|
|
237
|
+
\tconst [isLoading, setIsLoading] = useState(true);
|
|
238
|
+
\tconst [isSaving, setIsSaving] = useState(false);
|
|
239
|
+
\tconst [successMessage, setSuccessMessage] = useState<string | null>(null);
|
|
240
|
+
|
|
241
|
+
\tuseEffect(() => {
|
|
242
|
+
\t\tlet isCurrent = true;
|
|
243
|
+
\t\tsetIsLoading(true);
|
|
244
|
+
\t\tsetError(null);
|
|
245
|
+
|
|
246
|
+
\t\tvoid ${loadName}()
|
|
247
|
+
\t\t\t.then((result) => {
|
|
248
|
+
\t\t\t\tif (isCurrent) {
|
|
249
|
+
\t\t\t\t\tsetForm(result.form);
|
|
250
|
+
\t\t\t\t\tsetResponse(result.response);
|
|
251
|
+
\t\t\t\t}
|
|
252
|
+
\t\t\t})
|
|
253
|
+
\t\t\t.catch((nextError: unknown) => {
|
|
254
|
+
\t\t\t\tif (isCurrent) {
|
|
255
|
+
\t\t\t\t\tsetError(
|
|
256
|
+
\t\t\t\t\t\tnextError instanceof Error
|
|
257
|
+
\t\t\t\t\t\t\t? nextError.message
|
|
258
|
+
\t\t\t\t\t\t\t: __( 'Unable to prepare settings form.', ${quoteTsString(textDomain)} ),
|
|
259
|
+
\t\t\t\t\t);
|
|
260
|
+
\t\t\t\t}
|
|
261
|
+
\t\t\t})
|
|
262
|
+
\t\t\t.finally(() => {
|
|
263
|
+
\t\t\t\tif (isCurrent) {
|
|
264
|
+
\t\t\t\t\tsetIsLoading(false);
|
|
265
|
+
\t\t\t\t}
|
|
266
|
+
\t\t\t});
|
|
267
|
+
|
|
268
|
+
\t\treturn () => {
|
|
269
|
+
\t\t\tisCurrent = false;
|
|
270
|
+
\t\t};
|
|
271
|
+
\t}, []);
|
|
272
|
+
|
|
273
|
+
\tconst setFormValue = (fieldId: string, value: string) => {
|
|
274
|
+
\t\tsetForm(
|
|
275
|
+
\t\t\t(current) =>
|
|
276
|
+
\t\t\t\t({
|
|
277
|
+
\t\t\t\t\t...current,
|
|
278
|
+
\t\t\t\t\t[fieldId]: value,
|
|
279
|
+
\t\t\t\t}) as ${formStateTypeName},
|
|
280
|
+
\t\t);
|
|
281
|
+
\t};
|
|
282
|
+
\tconst secretState = getSecretState(response);
|
|
283
|
+
|
|
284
|
+
\tconst handleSubmit = (event: { preventDefault: () => void }) => {
|
|
285
|
+
\t\tevent.preventDefault();
|
|
286
|
+
\t\tsetError(null);
|
|
287
|
+
\t\tsetSuccessMessage(null);
|
|
288
|
+
\t\tsetIsSaving(true);
|
|
289
|
+
|
|
290
|
+
\t\tvoid ${saveName}(form)
|
|
291
|
+
\t\t\t.then((nextResponse) => {
|
|
292
|
+
\t\t\t\tsetResponse(nextResponse);
|
|
293
|
+
\t\t\t\tsetSuccessMessage(__( 'Settings saved.', ${quoteTsString(textDomain)} ));
|
|
294
|
+
\t\t\t})
|
|
295
|
+
\t\t\t.catch((nextError: unknown) => {
|
|
296
|
+
\t\t\t\tsetError(
|
|
297
|
+
\t\t\t\t\tnextError instanceof Error
|
|
298
|
+
\t\t\t\t\t\t? nextError.message
|
|
299
|
+
\t\t\t\t\t\t: __( 'Unable to save settings.', ${quoteTsString(textDomain)} ),
|
|
300
|
+
\t\t\t\t);
|
|
301
|
+
\t\t\t})
|
|
302
|
+
\t\t\t.finally(() => setIsSaving(false));
|
|
303
|
+
\t};
|
|
304
|
+
|
|
305
|
+
\treturn (
|
|
306
|
+
\t\t<div className="wp-typia-admin-view-screen wp-typia-admin-view-screen--settings">
|
|
307
|
+
\t\t\t<header className="wp-typia-admin-view-screen__header">
|
|
308
|
+
\t\t\t\t<div>
|
|
309
|
+
\t\t\t\t\t<p className="wp-typia-admin-view-screen__eyebrow">
|
|
310
|
+
\t\t\t\t\t\t{ __( 'Typed settings screen', ${quoteTsString(textDomain)} ) }
|
|
311
|
+
\t\t\t\t\t</p>
|
|
312
|
+
\t\t\t\t\t<h1>{ ${configName}.title }</h1>
|
|
313
|
+
\t\t\t\t\t<p>{ ${configName}.description }</p>
|
|
314
|
+
\t\t\t\t</div>
|
|
315
|
+
\t\t\t\t<div className="wp-typia-admin-view-screen__actions">
|
|
316
|
+
\t\t\t\t\t{ isLoading || isSaving ? <Spinner /> : null }
|
|
317
|
+
\t\t\t\t</div>
|
|
318
|
+
\t\t\t</header>
|
|
319
|
+
\t\t\t{ error ? (
|
|
320
|
+
\t\t\t\t<Notice isDismissible={ false } status="error">
|
|
321
|
+
\t\t\t\t\t{ error }
|
|
322
|
+
\t\t\t\t</Notice>
|
|
323
|
+
\t\t\t) : null }
|
|
324
|
+
\t\t\t{ successMessage ? (
|
|
325
|
+
\t\t\t\t<Notice isDismissible={ false } status="success">
|
|
326
|
+
\t\t\t\t\t{ successMessage }
|
|
327
|
+
\t\t\t\t</Notice>
|
|
328
|
+
\t\t\t) : null }
|
|
329
|
+
\t\t\t{ secretState !== null ? (
|
|
330
|
+
\t\t\t\t<Notice isDismissible={ false } status="info">
|
|
331
|
+
\t\t\t\t\t{ secretState
|
|
332
|
+
\t\t\t\t\t\t? __( 'A secret is currently configured for this integration.', ${quoteTsString(textDomain)} )
|
|
333
|
+
\t\t\t\t\t\t: __( 'No secret is currently configured for this integration.', ${quoteTsString(textDomain)} ) }
|
|
334
|
+
\t\t\t\t</Notice>
|
|
335
|
+
\t\t\t) : null }
|
|
336
|
+
\t\t\t<form className="wp-typia-admin-view-screen__settings-form" onSubmit={ handleSubmit }>
|
|
337
|
+
\t\t\t\t{ ${configName}.fields.map((field) => (
|
|
338
|
+
\t\t\t\t\t<div className="wp-typia-admin-view-screen__field" key={ field.id }>
|
|
339
|
+
\t\t\t\t\t\t{ field.type === 'textarea' ? (
|
|
340
|
+
\t\t\t\t\t\t\t<TextareaControl
|
|
341
|
+
\t\t\t\t\t\t\t\thelp={ field.description }
|
|
342
|
+
\t\t\t\t\t\t\t\tlabel={ field.label }
|
|
343
|
+
\t\t\t\t\t\t\t\tonChange={ (value) => setFormValue(field.id, value) }
|
|
344
|
+
\t\t\t\t\t\t\t\tvalue={ getFieldValue(form, field.id) }
|
|
345
|
+
\t\t\t\t\t\t\t/>
|
|
346
|
+
\t\t\t\t\t\t) : (
|
|
347
|
+
\t\t\t\t\t\t\t<TextControl
|
|
348
|
+
\t\t\t\t\t\t\t\thelp={ field.description }
|
|
349
|
+
\t\t\t\t\t\t\t\tlabel={ field.label }
|
|
350
|
+
\t\t\t\t\t\t\t\tonChange={ (value) => setFormValue(field.id, value) }
|
|
351
|
+
\t\t\t\t\t\t\t\ttype={ field.type === 'secret' ? 'password' : 'text' }
|
|
352
|
+
\t\t\t\t\t\t\t\tvalue={ getFieldValue(form, field.id) }
|
|
353
|
+
\t\t\t\t\t\t\t/>
|
|
354
|
+
\t\t\t\t\t\t) }
|
|
355
|
+
\t\t\t\t\t</div>
|
|
356
|
+
\t\t\t\t)) }
|
|
357
|
+
\t\t\t\t<Button
|
|
358
|
+
\t\t\t\t\tdisabled={ isLoading || isSaving }
|
|
359
|
+
\t\t\t\t\tisBusy={ isSaving }
|
|
360
|
+
\t\t\t\t\ttype="submit"
|
|
361
|
+
\t\t\t\t\tvariant="primary"
|
|
362
|
+
\t\t\t\t>
|
|
363
|
+
\t\t\t\t\t{ __( 'Save settings', ${quoteTsString(textDomain)} ) }
|
|
364
|
+
\t\t\t\t</Button>
|
|
365
|
+
\t\t\t</form>
|
|
366
|
+
\t\t</div>
|
|
367
|
+
\t);
|
|
368
|
+
}
|
|
369
|
+
`;
|
|
370
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type AdminViewSource } from './cli-add-workspace-admin-view-types.js';
|
|
2
|
+
import { type WorkspaceProject } from './workspace-project.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves a relative module specifier from an admin-view module to a workspace file.
|
|
5
|
+
*
|
|
6
|
+
* @param adminViewSlug - Admin-view slug that determines the generated source directory.
|
|
7
|
+
* @param workspaceFile - Workspace file path to import from the admin-view module.
|
|
8
|
+
* @returns Relative extensionless module specifier for generated TypeScript imports.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getAdminViewRelativeModuleSpecifier(adminViewSlug: string, workspaceFile: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Builds one workspace admin-view config entry.
|
|
13
|
+
*
|
|
14
|
+
* @param adminViewSlug - Admin-view slug used for generated file paths.
|
|
15
|
+
* @param source - Optional source metadata stored with the config entry.
|
|
16
|
+
* @returns Generated TypeScript object entry for the admin-view registry.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildAdminViewConfigEntry(adminViewSlug: string, source: AdminViewSource | undefined): string;
|
|
19
|
+
/**
|
|
20
|
+
* Builds the admin-view registry source that imports generated view entries.
|
|
21
|
+
*
|
|
22
|
+
* @param adminViewSlugs - Ordered admin-view slugs to import into the registry.
|
|
23
|
+
* @returns Generated TypeScript source for the admin-view registry module.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildAdminViewRegistrySource(adminViewSlugs: string[]): string;
|
|
26
|
+
/**
|
|
27
|
+
* Builds the generated admin-view browser entrypoint.
|
|
28
|
+
*
|
|
29
|
+
* @param adminViewSlug - Admin-view slug used to derive component and root ids.
|
|
30
|
+
* @param options - Optional entrypoint generation flags.
|
|
31
|
+
* @returns Generated TSX source for mounting the admin-view screen.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildAdminViewEntrySource(adminViewSlug: string, options?: {
|
|
34
|
+
includeDataViewsStyle?: boolean;
|
|
35
|
+
}): string;
|
|
36
|
+
/**
|
|
37
|
+
* Builds shared SCSS for generated admin-view screens.
|
|
38
|
+
*
|
|
39
|
+
* @returns Generated SCSS source for admin-view layouts and settings forms.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildAdminViewStyleSource(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Builds the PHP registration module for a generated admin-view page.
|
|
44
|
+
*
|
|
45
|
+
* @param adminViewSlug - Admin-view slug used for hooks, handles, and root ids.
|
|
46
|
+
* @param workspace - Workspace metadata used for PHP prefixes and text domains.
|
|
47
|
+
* @returns Generated PHP source for registering and enqueueing the admin view.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildAdminViewPhpSource(adminViewSlug: string, workspace: WorkspaceProject): string;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { quoteTsString } from './cli-add-shared.js';
|
|
3
|
+
import { ADMIN_VIEWS_ASSET, ADMIN_VIEWS_SCRIPT, ADMIN_VIEWS_STYLE, ADMIN_VIEWS_STYLE_RTL, formatAdminViewSourceLocator, } from './cli-add-workspace-admin-view-types.js';
|
|
4
|
+
import { quotePhpString } from './php-utils.js';
|
|
5
|
+
import { toPascalCase, toTitleCase } from './string-case.js';
|
|
6
|
+
/**
|
|
7
|
+
* Resolves a relative module specifier from an admin-view module to a workspace file.
|
|
8
|
+
*
|
|
9
|
+
* @param adminViewSlug - Admin-view slug that determines the generated source directory.
|
|
10
|
+
* @param workspaceFile - Workspace file path to import from the admin-view module.
|
|
11
|
+
* @returns Relative extensionless module specifier for generated TypeScript imports.
|
|
12
|
+
*/
|
|
13
|
+
export function getAdminViewRelativeModuleSpecifier(adminViewSlug, workspaceFile) {
|
|
14
|
+
const adminViewDir = `src/admin-views/${adminViewSlug}`;
|
|
15
|
+
const normalizedFile = workspaceFile.replace(/\\/gu, '/');
|
|
16
|
+
const modulePath = normalizedFile.replace(/\.[cm]?[jt]sx?$/u, '');
|
|
17
|
+
const relativeModulePath = path.posix.relative(adminViewDir, modulePath);
|
|
18
|
+
return relativeModulePath.startsWith('.')
|
|
19
|
+
? relativeModulePath
|
|
20
|
+
: `./${relativeModulePath}`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Builds one workspace admin-view config entry.
|
|
24
|
+
*
|
|
25
|
+
* @param adminViewSlug - Admin-view slug used for generated file paths.
|
|
26
|
+
* @param source - Optional source metadata stored with the config entry.
|
|
27
|
+
* @returns Generated TypeScript object entry for the admin-view registry.
|
|
28
|
+
*/
|
|
29
|
+
export function buildAdminViewConfigEntry(adminViewSlug, source) {
|
|
30
|
+
return [
|
|
31
|
+
'\t{',
|
|
32
|
+
`\t\tfile: ${quoteTsString(`src/admin-views/${adminViewSlug}/index.tsx`)},`,
|
|
33
|
+
`\t\tphpFile: ${quoteTsString(`inc/admin-views/${adminViewSlug}.php`)},`,
|
|
34
|
+
`\t\tslug: ${quoteTsString(adminViewSlug)},`,
|
|
35
|
+
source
|
|
36
|
+
? `\t\tsource: ${quoteTsString(formatAdminViewSourceLocator(source))},`
|
|
37
|
+
: null,
|
|
38
|
+
'\t},',
|
|
39
|
+
]
|
|
40
|
+
.filter((line) => typeof line === 'string')
|
|
41
|
+
.join('\n');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Builds the admin-view registry source that imports generated view entries.
|
|
45
|
+
*
|
|
46
|
+
* @param adminViewSlugs - Ordered admin-view slugs to import into the registry.
|
|
47
|
+
* @returns Generated TypeScript source for the admin-view registry module.
|
|
48
|
+
*/
|
|
49
|
+
export function buildAdminViewRegistrySource(adminViewSlugs) {
|
|
50
|
+
const importLines = adminViewSlugs
|
|
51
|
+
.map((adminViewSlug) => `import './${adminViewSlug}';`)
|
|
52
|
+
.join('\n');
|
|
53
|
+
return `${importLines}${importLines ? '\n\n' : ''}// wp-typia add admin-view entries\n`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Builds the generated admin-view browser entrypoint.
|
|
57
|
+
*
|
|
58
|
+
* @param adminViewSlug - Admin-view slug used to derive component and root ids.
|
|
59
|
+
* @param options - Optional entrypoint generation flags.
|
|
60
|
+
* @returns Generated TSX source for mounting the admin-view screen.
|
|
61
|
+
*/
|
|
62
|
+
export function buildAdminViewEntrySource(adminViewSlug, options = {}) {
|
|
63
|
+
const pascalName = toPascalCase(adminViewSlug);
|
|
64
|
+
const componentName = `${pascalName}AdminViewScreen`;
|
|
65
|
+
const rootId = `wp-typia-admin-view-${adminViewSlug}`;
|
|
66
|
+
const dataViewsStyleImport = options.includeDataViewsStyle === false
|
|
67
|
+
? ''
|
|
68
|
+
: "\nimport '@wordpress/dataviews/build-style/style.css';";
|
|
69
|
+
return `import { createRoot } from '@wordpress/element';
|
|
70
|
+
${dataViewsStyleImport}
|
|
71
|
+
import { ${componentName} } from './Screen';
|
|
72
|
+
import './style.scss';
|
|
73
|
+
|
|
74
|
+
const ROOT_ELEMENT_ID = ${quoteTsString(rootId)};
|
|
75
|
+
|
|
76
|
+
function mountAdminView() {
|
|
77
|
+
\tconst rootElement = document.getElementById(ROOT_ELEMENT_ID);
|
|
78
|
+
\tif (!rootElement) {
|
|
79
|
+
\t\treturn;
|
|
80
|
+
\t}
|
|
81
|
+
|
|
82
|
+
\tcreateRoot(rootElement).render(<${componentName} />);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (document.readyState === 'loading') {
|
|
86
|
+
\tdocument.addEventListener('DOMContentLoaded', mountAdminView);
|
|
87
|
+
} else {
|
|
88
|
+
\tmountAdminView();
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Builds shared SCSS for generated admin-view screens.
|
|
94
|
+
*
|
|
95
|
+
* @returns Generated SCSS source for admin-view layouts and settings forms.
|
|
96
|
+
*/
|
|
97
|
+
export function buildAdminViewStyleSource() {
|
|
98
|
+
return `.wp-typia-admin-view-screen {
|
|
99
|
+
\tbox-sizing: border-box;
|
|
100
|
+
\tmax-width: 1180px;
|
|
101
|
+
\tpadding: 24px 24px 48px 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.wp-typia-admin-view-screen__header {
|
|
105
|
+
\talign-items: flex-start;
|
|
106
|
+
\tdisplay: flex;
|
|
107
|
+
\tgap: 24px;
|
|
108
|
+
\tjustify-content: space-between;
|
|
109
|
+
\tmargin-bottom: 24px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.wp-typia-admin-view-screen__header h1 {
|
|
113
|
+
\tfont-size: 28px;
|
|
114
|
+
\tline-height: 1.2;
|
|
115
|
+
\tmargin: 0 0 8px;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.wp-typia-admin-view-screen__header p {
|
|
119
|
+
\tmax-width: 680px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.wp-typia-admin-view-screen__eyebrow {
|
|
123
|
+
\tcolor: #3858e9;
|
|
124
|
+
\tfont-size: 11px;
|
|
125
|
+
\tfont-weight: 600;
|
|
126
|
+
\tletter-spacing: 0.08em;
|
|
127
|
+
\tmargin: 0 0 8px;
|
|
128
|
+
\ttext-transform: uppercase;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.wp-typia-admin-view-screen__actions {
|
|
132
|
+
\talign-items: center;
|
|
133
|
+
\tdisplay: flex;
|
|
134
|
+
\tgap: 12px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.wp-typia-admin-view-screen__settings-form {
|
|
138
|
+
\tbackground: #fff;
|
|
139
|
+
\tborder: 1px solid #dcdcde;
|
|
140
|
+
\tborder-radius: 2px;
|
|
141
|
+
\tbox-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
|
|
142
|
+
\tdisplay: grid;
|
|
143
|
+
\tgap: 20px;
|
|
144
|
+
\tmax-width: 720px;
|
|
145
|
+
\tpadding: 24px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.wp-typia-admin-view-screen__field .components-base-control {
|
|
149
|
+
\tmargin-bottom: 0;
|
|
150
|
+
}
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Builds the PHP registration module for a generated admin-view page.
|
|
155
|
+
*
|
|
156
|
+
* @param adminViewSlug - Admin-view slug used for hooks, handles, and root ids.
|
|
157
|
+
* @param workspace - Workspace metadata used for PHP prefixes and text domains.
|
|
158
|
+
* @returns Generated PHP source for registering and enqueueing the admin view.
|
|
159
|
+
*/
|
|
160
|
+
export function buildAdminViewPhpSource(adminViewSlug, workspace) {
|
|
161
|
+
const workspaceBaseName = workspace.packageName.split('/').pop() ?? workspace.packageName;
|
|
162
|
+
const phpSlug = adminViewSlug.replace(/-/g, '_');
|
|
163
|
+
const functionPrefix = `${workspace.workspace.phpPrefix}_${phpSlug}`;
|
|
164
|
+
const menuSlugFunctionName = `${functionPrefix}_admin_view_menu_slug`;
|
|
165
|
+
const renderFunctionName = `${functionPrefix}_render_admin_view`;
|
|
166
|
+
const registerFunctionName = `${functionPrefix}_register_admin_view`;
|
|
167
|
+
const enqueueFunctionName = `${functionPrefix}_enqueue_admin_view`;
|
|
168
|
+
const hookGlobalName = `${functionPrefix}_admin_view_hook`;
|
|
169
|
+
const rootId = `wp-typia-admin-view-${adminViewSlug}`;
|
|
170
|
+
const title = toTitleCase(adminViewSlug);
|
|
171
|
+
return `<?php
|
|
172
|
+
if ( ! defined( 'ABSPATH' ) ) {
|
|
173
|
+
\treturn;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if ( ! function_exists( '${menuSlugFunctionName}' ) ) {
|
|
177
|
+
\tfunction ${menuSlugFunctionName}() : string {
|
|
178
|
+
\t\treturn '${workspaceBaseName}-${adminViewSlug}';
|
|
179
|
+
\t}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if ( ! function_exists( '${renderFunctionName}' ) ) {
|
|
183
|
+
\tfunction ${renderFunctionName}() : void {
|
|
184
|
+
\t\t?>
|
|
185
|
+
\t\t<div class="wrap">
|
|
186
|
+
\t\t\t<div id="${rootId}"></div>
|
|
187
|
+
\t\t</div>
|
|
188
|
+
\t\t<?php
|
|
189
|
+
\t}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if ( ! function_exists( '${registerFunctionName}' ) ) {
|
|
193
|
+
\tfunction ${registerFunctionName}() : void {
|
|
194
|
+
\t\t$GLOBALS['${hookGlobalName}'] = add_submenu_page(
|
|
195
|
+
\t\t\t'tools.php',
|
|
196
|
+
\t\t\t__( ${quotePhpString(title)}, ${quotePhpString(workspace.workspace.textDomain)} ),
|
|
197
|
+
\t\t\t__( ${quotePhpString(title)}, ${quotePhpString(workspace.workspace.textDomain)} ),
|
|
198
|
+
\t\t\t'edit_posts',
|
|
199
|
+
\t\t\t${menuSlugFunctionName}(),
|
|
200
|
+
\t\t\t'${renderFunctionName}'
|
|
201
|
+
\t\t);
|
|
202
|
+
\t}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if ( ! function_exists( '${enqueueFunctionName}' ) ) {
|
|
206
|
+
\tfunction ${enqueueFunctionName}( string $hook_suffix ) : void {
|
|
207
|
+
\t\t$page_hook = isset( $GLOBALS['${hookGlobalName}'] ) && is_string( $GLOBALS['${hookGlobalName}'] )
|
|
208
|
+
\t\t\t? $GLOBALS['${hookGlobalName}']
|
|
209
|
+
\t\t\t: '';
|
|
210
|
+
|
|
211
|
+
\t\tif ( $page_hook !== $hook_suffix ) {
|
|
212
|
+
\t\t\treturn;
|
|
213
|
+
\t\t}
|
|
214
|
+
|
|
215
|
+
\t\t$plugin_file = dirname( __DIR__, 2 ) . '/${workspaceBaseName}.php';
|
|
216
|
+
\t\t$script_path = dirname( __DIR__, 2 ) . '/${ADMIN_VIEWS_SCRIPT}';
|
|
217
|
+
\t\t$asset_path = dirname( __DIR__, 2 ) . '/${ADMIN_VIEWS_ASSET}';
|
|
218
|
+
\t\t$style_path = dirname( __DIR__, 2 ) . '/${ADMIN_VIEWS_STYLE}';
|
|
219
|
+
\t\t$style_rtl_path = dirname( __DIR__, 2 ) . '/${ADMIN_VIEWS_STYLE_RTL}';
|
|
220
|
+
|
|
221
|
+
\t\tif ( ! file_exists( $script_path ) || ! file_exists( $asset_path ) ) {
|
|
222
|
+
\t\t\treturn;
|
|
223
|
+
\t\t}
|
|
224
|
+
|
|
225
|
+
\t\t$asset = require $asset_path;
|
|
226
|
+
\t\tif ( ! is_array( $asset ) ) {
|
|
227
|
+
\t\t\t$asset = array();
|
|
228
|
+
\t\t}
|
|
229
|
+
|
|
230
|
+
\t\t$dependencies = isset( $asset['dependencies'] ) && is_array( $asset['dependencies'] )
|
|
231
|
+
\t\t\t? $asset['dependencies']
|
|
232
|
+
\t\t\t: array();
|
|
233
|
+
|
|
234
|
+
\t\twp_enqueue_script(
|
|
235
|
+
\t\t\t'${workspaceBaseName}-${adminViewSlug}-admin-view',
|
|
236
|
+
\t\t\tplugins_url( '${ADMIN_VIEWS_SCRIPT}', $plugin_file ),
|
|
237
|
+
\t\t\t$dependencies,
|
|
238
|
+
\t\t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $script_path ),
|
|
239
|
+
\t\t\ttrue
|
|
240
|
+
\t\t);
|
|
241
|
+
|
|
242
|
+
\t\tif ( file_exists( $style_path ) ) {
|
|
243
|
+
\t\t\twp_enqueue_style(
|
|
244
|
+
\t\t\t\t'${workspaceBaseName}-${adminViewSlug}-admin-view',
|
|
245
|
+
\t\t\t\tplugins_url( '${ADMIN_VIEWS_STYLE}', $plugin_file ),
|
|
246
|
+
\t\t\t\tarray( 'wp-components' ),
|
|
247
|
+
\t\t\t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $style_path )
|
|
248
|
+
\t\t\t);
|
|
249
|
+
\t\t\tif ( file_exists( $style_rtl_path ) ) {
|
|
250
|
+
\t\t\t\twp_style_add_data( '${workspaceBaseName}-${adminViewSlug}-admin-view', 'rtl', 'replace' );
|
|
251
|
+
\t\t\t}
|
|
252
|
+
\t\t}
|
|
253
|
+
\t}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
add_action( 'admin_menu', '${registerFunctionName}' );
|
|
257
|
+
add_action( 'admin_enqueue_scripts', '${enqueueFunctionName}' );
|
|
258
|
+
`;
|
|
259
|
+
}
|