@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,428 @@
|
|
|
1
|
+
import { promises as fsp } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { assertValidGeneratedSlug, assertValidIntegrationEnvService, normalizeBlockSlug, } from "./cli-add-shared.js";
|
|
4
|
+
import { formatRunScript, } from "./package-managers.js";
|
|
5
|
+
import { pathExists, readOptionalUtf8File } from "./fs-async.js";
|
|
6
|
+
import { readJsonFile } from "./json-utils.js";
|
|
7
|
+
import { executeWorkspaceMutationPlan } from "./cli-add-workspace-mutation.js";
|
|
8
|
+
import { resolveWorkspaceProject } from "./workspace-project.js";
|
|
9
|
+
import { toTitleCase } from "./string-case.js";
|
|
10
|
+
const WP_ENV_PACKAGE_VERSION = "^11.2.0";
|
|
11
|
+
function buildWpEnvConfigSource() {
|
|
12
|
+
return `${JSON.stringify({
|
|
13
|
+
$schema: "https://schemas.wp.org/trunk/wp-env.json",
|
|
14
|
+
core: null,
|
|
15
|
+
port: 8888,
|
|
16
|
+
testsEnvironment: false,
|
|
17
|
+
plugins: ["."],
|
|
18
|
+
config: {
|
|
19
|
+
WP_DEBUG: true,
|
|
20
|
+
WP_DEBUG_LOG: true,
|
|
21
|
+
WP_DEBUG_DISPLAY: false,
|
|
22
|
+
SCRIPT_DEBUG: true,
|
|
23
|
+
WP_ENVIRONMENT_TYPE: "local",
|
|
24
|
+
},
|
|
25
|
+
}, null, 2)}\n`;
|
|
26
|
+
}
|
|
27
|
+
function buildDockerComposeSource() {
|
|
28
|
+
return `services:
|
|
29
|
+
integration-service:
|
|
30
|
+
image: node:22-alpine
|
|
31
|
+
working_dir: /workspace
|
|
32
|
+
volumes:
|
|
33
|
+
- .:/workspace
|
|
34
|
+
command: >
|
|
35
|
+
node -e "require('node:http').createServer((request, response) => {
|
|
36
|
+
response.writeHead(request.url === '/health' ? 200 : 404, {
|
|
37
|
+
'content-type': 'application/json'
|
|
38
|
+
});
|
|
39
|
+
response.end(JSON.stringify({
|
|
40
|
+
ok: request.url === '/health',
|
|
41
|
+
service: 'wp-typia-integration-starter'
|
|
42
|
+
}));
|
|
43
|
+
}).listen(3000, '0.0.0.0')"
|
|
44
|
+
ports:
|
|
45
|
+
- "3000:3000"
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
function buildIntegrationSmokeScriptSource(integrationEnvSlug) {
|
|
49
|
+
return `import fs from "node:fs";
|
|
50
|
+
import path from "node:path";
|
|
51
|
+
import { fileURLToPath } from "node:url";
|
|
52
|
+
|
|
53
|
+
const ROOT_DIR = path.resolve(
|
|
54
|
+
fileURLToPath(new URL("../..", import.meta.url)),
|
|
55
|
+
);
|
|
56
|
+
const ENV_FILE = path.join(ROOT_DIR, ".env");
|
|
57
|
+
|
|
58
|
+
function parseEnvValue(value) {
|
|
59
|
+
const trimmed = value.trim();
|
|
60
|
+
if (
|
|
61
|
+
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
62
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
|
63
|
+
) {
|
|
64
|
+
return trimmed.slice(1, -1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return trimmed;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function readEnvFile(filePath) {
|
|
71
|
+
if (!fs.existsSync(filePath)) {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return Object.fromEntries(
|
|
76
|
+
fs
|
|
77
|
+
.readFileSync(filePath, "utf8")
|
|
78
|
+
.split(/\\r?\\n/u)
|
|
79
|
+
.map((line) => line.trim())
|
|
80
|
+
.filter((line) => line.length > 0 && !line.startsWith("#"))
|
|
81
|
+
.map((line) => {
|
|
82
|
+
const separatorIndex = line.indexOf("=");
|
|
83
|
+
if (separatorIndex === -1) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return [
|
|
88
|
+
line.slice(0, separatorIndex).trim(),
|
|
89
|
+
parseEnvValue(line.slice(separatorIndex + 1)),
|
|
90
|
+
];
|
|
91
|
+
})
|
|
92
|
+
.filter(Boolean),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const envFile = readEnvFile(ENV_FILE);
|
|
97
|
+
|
|
98
|
+
function getEnv(name, fallback) {
|
|
99
|
+
return process.env[name] ?? envFile[name] ?? fallback;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function resolveEndpointUrl(baseUrl, endpointPath) {
|
|
103
|
+
const normalizedBaseUrl = new URL(baseUrl);
|
|
104
|
+
if (!normalizedBaseUrl.pathname.endsWith("/")) {
|
|
105
|
+
normalizedBaseUrl.pathname = \`\${normalizedBaseUrl.pathname}/\`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const relativePath = endpointPath.replace(/^\\/+/u, "");
|
|
109
|
+
return new URL(relativePath, normalizedBaseUrl);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function assertJsonEndpoint(label, url) {
|
|
113
|
+
const response = await fetch(url, {
|
|
114
|
+
headers: {
|
|
115
|
+
accept: "application/json",
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
\`\${label} failed at \${url} with HTTP \${response.status}.\`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
126
|
+
if (!contentType.includes("application/json")) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
\`\${label} at \${url} did not return JSON (content-type: \${contentType || "missing"}).\`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return response.json();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const baseUrl = new URL(
|
|
136
|
+
getEnv("WP_TYPIA_SMOKE_BASE_URL", "http://localhost:8888"),
|
|
137
|
+
);
|
|
138
|
+
const serviceUrl = getEnv("WP_TYPIA_SERVICE_URL", "").trim();
|
|
139
|
+
|
|
140
|
+
// Extend this starter with project-specific generated REST clients or schema
|
|
141
|
+
// checks as the workspace grows. For example, read JSON schemas under
|
|
142
|
+
// src/rest/<resource>/api-schemas or import TS clients through a tsx-powered
|
|
143
|
+
// smoke runner when you need authenticated route coverage.
|
|
144
|
+
|
|
145
|
+
await assertJsonEndpoint(
|
|
146
|
+
"WordPress REST index",
|
|
147
|
+
resolveEndpointUrl(baseUrl, "wp-json/"),
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
if (serviceUrl.length > 0) {
|
|
151
|
+
await assertJsonEndpoint(
|
|
152
|
+
"Local integration service healthcheck",
|
|
153
|
+
resolveEndpointUrl(serviceUrl, "health"),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.log("wp-typia integration smoke passed: ${integrationEnvSlug}");
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
function buildEnvExampleSource(service) {
|
|
161
|
+
return [
|
|
162
|
+
"# wp-typia integration smoke settings",
|
|
163
|
+
"WP_TYPIA_SMOKE_BASE_URL=http://localhost:8888",
|
|
164
|
+
"WP_TYPIA_SMOKE_USERNAME=admin",
|
|
165
|
+
"WP_TYPIA_SMOKE_PASSWORD=password",
|
|
166
|
+
...(service === "docker-compose"
|
|
167
|
+
? [
|
|
168
|
+
"",
|
|
169
|
+
"# Optional docker-compose integration service starter.",
|
|
170
|
+
"WP_TYPIA_SERVICE_URL=http://localhost:3000",
|
|
171
|
+
]
|
|
172
|
+
: [
|
|
173
|
+
"",
|
|
174
|
+
"# Set this when your smoke test needs a project-specific service.",
|
|
175
|
+
"# WP_TYPIA_SERVICE_URL=http://localhost:3000",
|
|
176
|
+
]),
|
|
177
|
+
"",
|
|
178
|
+
].join("\n");
|
|
179
|
+
}
|
|
180
|
+
function buildIntegrationEnvReadmeSource({ integrationEnvSlug, service, withReleaseZip, withWpEnv, }) {
|
|
181
|
+
const title = toTitleCase(integrationEnvSlug);
|
|
182
|
+
const setupSteps = [
|
|
183
|
+
"Copy `.env.example` to `.env` and adjust the URLs or credentials for your local project.",
|
|
184
|
+
...(withWpEnv
|
|
185
|
+
? [
|
|
186
|
+
"Run `npm run wp-env:start` to start the generated WordPress environment.",
|
|
187
|
+
]
|
|
188
|
+
: [
|
|
189
|
+
"Point `WP_TYPIA_SMOKE_BASE_URL` at the WordPress environment you already run locally.",
|
|
190
|
+
]),
|
|
191
|
+
...(service === "docker-compose"
|
|
192
|
+
? [
|
|
193
|
+
"Run `npm run service:start` if you want the placeholder docker-compose service available at `WP_TYPIA_SERVICE_URL`.",
|
|
194
|
+
]
|
|
195
|
+
: [
|
|
196
|
+
"Set `WP_TYPIA_SERVICE_URL` only when your integration smoke needs a local service dependency.",
|
|
197
|
+
]),
|
|
198
|
+
`Run \`npm run smoke:${integrationEnvSlug}\` to execute the starter smoke check.`,
|
|
199
|
+
...(withReleaseZip
|
|
200
|
+
? [
|
|
201
|
+
"Run `npm run release:zip` after smoke checks pass to build a distributable plugin zip.",
|
|
202
|
+
]
|
|
203
|
+
: []),
|
|
204
|
+
];
|
|
205
|
+
return `# ${title} Integration Environment
|
|
206
|
+
|
|
207
|
+
This starter keeps local WordPress integration smoke checks opt-in and editable.
|
|
208
|
+
It does not change default block scaffolds or require wp-env unless this add
|
|
209
|
+
workflow was run with \`--wp-env\`.
|
|
210
|
+
|
|
211
|
+
## Setup
|
|
212
|
+
|
|
213
|
+
${setupSteps.map((step, index) => `${index + 1}. ${step}`).join("\n")}
|
|
214
|
+
|
|
215
|
+
## Adapting the Starter
|
|
216
|
+
|
|
217
|
+
- Extend \`scripts/integration-smoke/${integrationEnvSlug}.mjs\` with the REST,
|
|
218
|
+
editor, or service assertions that matter for this project.
|
|
219
|
+
- Keep secrets in \`.env\`; \`.env.example\` should document only safe defaults.
|
|
220
|
+
- If your project uses a real service stack, replace the placeholder
|
|
221
|
+
\`docker-compose.integration.yml\` service with your database, queue, API, or
|
|
222
|
+
emulator containers.
|
|
223
|
+
- Keep the smoke script focused on high-signal integration checks so CI and
|
|
224
|
+
local debugging stay fast.
|
|
225
|
+
${withReleaseZip ? "- Treat `release:zip:check` as a CI guard before packaging release artifacts.\n" : ""}
|
|
226
|
+
`;
|
|
227
|
+
}
|
|
228
|
+
async function appendMissingLines(filePath, lines) {
|
|
229
|
+
const current = (await readOptionalUtf8File(filePath)) ?? "";
|
|
230
|
+
const missingLines = lines.filter((line) => !current.includes(`${line}\n`) && !current.endsWith(line));
|
|
231
|
+
if (missingLines.length === 0) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const separator = current.length === 0 || current.endsWith("\n") ? "" : "\n";
|
|
235
|
+
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
236
|
+
await fsp.writeFile(filePath, `${current}${separator}${missingLines.join("\n")}\n`, "utf8");
|
|
237
|
+
}
|
|
238
|
+
async function writeFileIfAbsent({ filePath, source, warnings, }) {
|
|
239
|
+
if (await pathExists(filePath)) {
|
|
240
|
+
warnings.push(`Preserved existing ${path.basename(filePath)}; review it manually if you need different local integration settings.`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
244
|
+
await fsp.writeFile(filePath, source, "utf8");
|
|
245
|
+
}
|
|
246
|
+
async function writeNewScaffoldFile(filePath, source) {
|
|
247
|
+
if (await pathExists(filePath)) {
|
|
248
|
+
throw new Error(`An integration environment scaffold already exists at ${filePath}. Choose a different name.`);
|
|
249
|
+
}
|
|
250
|
+
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
251
|
+
await fsp.writeFile(filePath, source, "utf8");
|
|
252
|
+
}
|
|
253
|
+
function addScriptIfMissing({ scriptName, scripts, scriptValue, warnings, }) {
|
|
254
|
+
if (scripts[scriptName] === undefined) {
|
|
255
|
+
scripts[scriptName] = scriptValue;
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (scripts[scriptName] !== scriptValue) {
|
|
259
|
+
warnings.push(`Preserved existing package script "${scriptName}"; add "${scriptValue}" manually if you want the generated integration command.`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function mutatePackageJson(projectDir, mutate) {
|
|
263
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
264
|
+
const packageJson = await readJsonFile(packageJsonPath, {
|
|
265
|
+
context: "integration env package manifest",
|
|
266
|
+
});
|
|
267
|
+
mutate(packageJson);
|
|
268
|
+
await fsp.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, "\t")}\n`, "utf8");
|
|
269
|
+
}
|
|
270
|
+
function addIntegrationEnvPackageJsonEntries({ integrationEnvSlug, packageManager, packageJson, withReleaseZip, service, warnings, withWpEnv, }) {
|
|
271
|
+
const devDependencies = {
|
|
272
|
+
...(packageJson.devDependencies ?? {}),
|
|
273
|
+
};
|
|
274
|
+
if (withWpEnv && devDependencies["@wordpress/env"] === undefined) {
|
|
275
|
+
devDependencies["@wordpress/env"] = WP_ENV_PACKAGE_VERSION;
|
|
276
|
+
}
|
|
277
|
+
packageJson.devDependencies = devDependencies;
|
|
278
|
+
const scripts = {
|
|
279
|
+
...(packageJson.scripts ?? {}),
|
|
280
|
+
};
|
|
281
|
+
addScriptIfMissing({
|
|
282
|
+
scriptName: `smoke:${integrationEnvSlug}`,
|
|
283
|
+
scriptValue: `node scripts/integration-smoke/${integrationEnvSlug}.mjs`,
|
|
284
|
+
scripts,
|
|
285
|
+
warnings,
|
|
286
|
+
});
|
|
287
|
+
addScriptIfMissing({
|
|
288
|
+
scriptName: "smoke:integration",
|
|
289
|
+
scriptValue: formatRunScript(packageManager, `smoke:${integrationEnvSlug}`),
|
|
290
|
+
scripts,
|
|
291
|
+
warnings,
|
|
292
|
+
});
|
|
293
|
+
if (withWpEnv) {
|
|
294
|
+
addScriptIfMissing({
|
|
295
|
+
scriptName: "wp-env:start",
|
|
296
|
+
scriptValue: "wp-env start",
|
|
297
|
+
scripts,
|
|
298
|
+
warnings,
|
|
299
|
+
});
|
|
300
|
+
addScriptIfMissing({
|
|
301
|
+
scriptName: "wp-env:stop",
|
|
302
|
+
scriptValue: "wp-env stop",
|
|
303
|
+
scripts,
|
|
304
|
+
warnings,
|
|
305
|
+
});
|
|
306
|
+
addScriptIfMissing({
|
|
307
|
+
scriptName: "wp-env:reset",
|
|
308
|
+
scriptValue: "wp-env destroy all && wp-env start",
|
|
309
|
+
scripts,
|
|
310
|
+
warnings,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (withReleaseZip) {
|
|
314
|
+
addScriptIfMissing({
|
|
315
|
+
scriptName: "release:zip",
|
|
316
|
+
scriptValue: `${formatRunScript(packageManager, "sync-rest:package")} && ${formatRunScript(packageManager, "build")} && wp-scripts plugin-zip`,
|
|
317
|
+
scripts,
|
|
318
|
+
warnings,
|
|
319
|
+
});
|
|
320
|
+
addScriptIfMissing({
|
|
321
|
+
scriptName: "release:zip:check",
|
|
322
|
+
scriptValue: `${formatRunScript(packageManager, "sync-rest:package:check")} && ${formatRunScript(packageManager, "build")}`,
|
|
323
|
+
scripts,
|
|
324
|
+
warnings,
|
|
325
|
+
});
|
|
326
|
+
addScriptIfMissing({
|
|
327
|
+
scriptName: "qa:check",
|
|
328
|
+
scriptValue: `${formatRunScript(packageManager, "wp-typia:doctor:workspace")} && ${formatRunScript(packageManager, "release:zip:check")}`,
|
|
329
|
+
scripts,
|
|
330
|
+
warnings,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
if (service === "docker-compose") {
|
|
334
|
+
addScriptIfMissing({
|
|
335
|
+
scriptName: "service:start",
|
|
336
|
+
scriptValue: "docker compose -f docker-compose.integration.yml up -d",
|
|
337
|
+
scripts,
|
|
338
|
+
warnings,
|
|
339
|
+
});
|
|
340
|
+
addScriptIfMissing({
|
|
341
|
+
scriptName: "service:stop",
|
|
342
|
+
scriptValue: "docker compose -f docker-compose.integration.yml down",
|
|
343
|
+
scripts,
|
|
344
|
+
warnings,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
packageJson.scripts = scripts;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Add an opt-in local WordPress integration environment starter to an official
|
|
351
|
+
* workspace.
|
|
352
|
+
*/
|
|
353
|
+
export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integrationEnvName, service, withReleaseZip = false, withWpEnv = false, }) {
|
|
354
|
+
const workspace = resolveWorkspaceProject(cwd);
|
|
355
|
+
const integrationEnvSlug = assertValidGeneratedSlug("Integration environment name", normalizeBlockSlug(integrationEnvName), "wp-typia add integration-env <name> [--wp-env] [--release-zip]");
|
|
356
|
+
const serviceId = assertValidIntegrationEnvService(service);
|
|
357
|
+
const warnings = [];
|
|
358
|
+
const packageJsonPath = path.join(workspace.projectDir, "package.json");
|
|
359
|
+
const gitignorePath = path.join(workspace.projectDir, ".gitignore");
|
|
360
|
+
const envExamplePath = path.join(workspace.projectDir, ".env.example");
|
|
361
|
+
const wpEnvPath = path.join(workspace.projectDir, ".wp-env.json");
|
|
362
|
+
const dockerComposePath = path.join(workspace.projectDir, "docker-compose.integration.yml");
|
|
363
|
+
const smokeDir = path.join(workspace.projectDir, "scripts", "integration-smoke");
|
|
364
|
+
const docsDir = path.join(workspace.projectDir, "docs", "integration-env");
|
|
365
|
+
const smokeScriptPath = path.join(smokeDir, `${integrationEnvSlug}.mjs`);
|
|
366
|
+
const docsPath = path.join(docsDir, `${integrationEnvSlug}.md`);
|
|
367
|
+
const shouldRemoveSmokeDirOnRollback = !(await pathExists(smokeDir));
|
|
368
|
+
const shouldRemoveDocsDirOnRollback = !(await pathExists(docsDir));
|
|
369
|
+
await executeWorkspaceMutationPlan({
|
|
370
|
+
filePaths: [
|
|
371
|
+
packageJsonPath,
|
|
372
|
+
gitignorePath,
|
|
373
|
+
envExamplePath,
|
|
374
|
+
...(withWpEnv ? [wpEnvPath] : []),
|
|
375
|
+
...(serviceId === "docker-compose" ? [dockerComposePath] : []),
|
|
376
|
+
],
|
|
377
|
+
targetPaths: [
|
|
378
|
+
smokeScriptPath,
|
|
379
|
+
docsPath,
|
|
380
|
+
...(shouldRemoveSmokeDirOnRollback ? [smokeDir] : []),
|
|
381
|
+
...(shouldRemoveDocsDirOnRollback ? [docsDir] : []),
|
|
382
|
+
],
|
|
383
|
+
run: async () => {
|
|
384
|
+
await writeNewScaffoldFile(smokeScriptPath, buildIntegrationSmokeScriptSource(integrationEnvSlug));
|
|
385
|
+
await writeNewScaffoldFile(docsPath, buildIntegrationEnvReadmeSource({
|
|
386
|
+
integrationEnvSlug,
|
|
387
|
+
service: serviceId,
|
|
388
|
+
withReleaseZip,
|
|
389
|
+
withWpEnv,
|
|
390
|
+
}));
|
|
391
|
+
await appendMissingLines(envExamplePath, [
|
|
392
|
+
...buildEnvExampleSource(serviceId).trimEnd().split("\n"),
|
|
393
|
+
]);
|
|
394
|
+
await appendMissingLines(gitignorePath, [".env", ".env.local"]);
|
|
395
|
+
if (withWpEnv) {
|
|
396
|
+
await writeFileIfAbsent({
|
|
397
|
+
filePath: wpEnvPath,
|
|
398
|
+
source: buildWpEnvConfigSource(),
|
|
399
|
+
warnings,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
if (serviceId === "docker-compose") {
|
|
403
|
+
await writeFileIfAbsent({
|
|
404
|
+
filePath: dockerComposePath,
|
|
405
|
+
source: buildDockerComposeSource(),
|
|
406
|
+
warnings,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
await mutatePackageJson(workspace.projectDir, (packageJson) => addIntegrationEnvPackageJsonEntries({
|
|
410
|
+
integrationEnvSlug,
|
|
411
|
+
packageManager: workspace.packageManager,
|
|
412
|
+
packageJson,
|
|
413
|
+
service: serviceId,
|
|
414
|
+
withReleaseZip,
|
|
415
|
+
warnings,
|
|
416
|
+
withWpEnv,
|
|
417
|
+
}));
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
return {
|
|
421
|
+
integrationEnvSlug,
|
|
422
|
+
projectDir: workspace.projectDir,
|
|
423
|
+
service: serviceId,
|
|
424
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
425
|
+
withReleaseZip,
|
|
426
|
+
withWpEnv,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { WorkspaceProject } from "./workspace-project.js";
|
|
2
|
+
/**
|
|
3
|
+
* Ensure the workspace bootstrap loads generated post-meta PHP modules.
|
|
4
|
+
*
|
|
5
|
+
* Inserts the generated loader function, appends its `init` hook, and rejects
|
|
6
|
+
* incompatible existing loader functions that omit the generated post-meta glob.
|
|
7
|
+
*
|
|
8
|
+
* @param workspace Resolved official workspace metadata and paths.
|
|
9
|
+
* @returns A promise that resolves after the bootstrap has been patched.
|
|
10
|
+
* @throws {Error} When the bootstrap cannot be read, written, or safely patched.
|
|
11
|
+
*/
|
|
12
|
+
export declare function ensurePostMetaBootstrapAnchors(workspace: WorkspaceProject): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Ensure `scripts/sync-rest-contracts.ts` handles post-meta schema contracts.
|
|
15
|
+
*
|
|
16
|
+
* Patches inventory imports, type guards, no-resource checks, sync loops, and
|
|
17
|
+
* success copy so generated post-meta schemas participate in REST contract sync.
|
|
18
|
+
*
|
|
19
|
+
* @param workspace Resolved official workspace metadata and paths.
|
|
20
|
+
* @returns A promise that resolves after the sync script has been patched.
|
|
21
|
+
* @throws {Error} When expected anchors are missing or file IO fails.
|
|
22
|
+
*/
|
|
23
|
+
export declare function ensurePostMetaSyncScriptAnchors(workspace: WorkspaceProject): Promise<void>;
|