@wp-typia/project-tools 0.22.6 → 0.22.7
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/cli-add-block-json.d.ts +2 -2
- package/dist/runtime/cli-add-block-json.js +5 -4
- package/dist/runtime/cli-add-workspace.js +8 -11
- package/dist/runtime/cli-init-plan-presentation.d.ts +16 -0
- package/dist/runtime/cli-init-plan-presentation.js +74 -0
- package/dist/runtime/cli-init-plan.js +5 -77
- package/dist/runtime/package-versions.d.ts +1 -1
- package/dist/runtime/package-versions.js +1 -1
- package/dist/runtime/php-utils.js +91 -154
- package/dist/runtime/string-case.js +2 -0
- package/package.json +1 -1
|
@@ -16,10 +16,10 @@ export declare function resolveWorkspaceBlock(inventory: WorkspaceInventory, blo
|
|
|
16
16
|
* @returns Parsed block metadata and the absolute `block.json` path.
|
|
17
17
|
* @throws {Error} When the file is missing or cannot be parsed as scaffold metadata.
|
|
18
18
|
*/
|
|
19
|
-
export declare function readWorkspaceBlockJson(projectDir: string, blockSlug: string): {
|
|
19
|
+
export declare function readWorkspaceBlockJson(projectDir: string, blockSlug: string): Promise<{
|
|
20
20
|
blockJson: Record<string, unknown>;
|
|
21
21
|
blockJsonPath: string;
|
|
22
|
-
}
|
|
22
|
+
}>;
|
|
23
23
|
/**
|
|
24
24
|
* Return a mutable `blockHooks` object for a parsed block metadata document.
|
|
25
25
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { parseScaffoldBlockMetadata } from "@wp-typia/block-runtime/blocks";
|
|
3
|
+
import { readOptionalUtf8File } from "./fs-async.js";
|
|
4
4
|
/**
|
|
5
5
|
* Resolve an existing workspace block inventory entry by slug.
|
|
6
6
|
*
|
|
@@ -24,14 +24,15 @@ export function resolveWorkspaceBlock(inventory, blockSlug) {
|
|
|
24
24
|
* @returns Parsed block metadata and the absolute `block.json` path.
|
|
25
25
|
* @throws {Error} When the file is missing or cannot be parsed as scaffold metadata.
|
|
26
26
|
*/
|
|
27
|
-
export function readWorkspaceBlockJson(projectDir, blockSlug) {
|
|
27
|
+
export async function readWorkspaceBlockJson(projectDir, blockSlug) {
|
|
28
28
|
const blockJsonPath = path.join(projectDir, "src", "blocks", blockSlug, "block.json");
|
|
29
|
-
|
|
29
|
+
const source = await readOptionalUtf8File(blockJsonPath);
|
|
30
|
+
if (source === null) {
|
|
30
31
|
throw new Error(`Missing ${path.relative(projectDir, blockJsonPath)} for workspace block "${blockSlug}".`);
|
|
31
32
|
}
|
|
32
33
|
let blockJson;
|
|
33
34
|
try {
|
|
34
|
-
blockJson = parseScaffoldBlockMetadata(JSON.parse(
|
|
35
|
+
blockJson = parseScaffoldBlockMetadata(JSON.parse(source));
|
|
35
36
|
}
|
|
36
37
|
catch (error) {
|
|
37
38
|
throw new Error(error instanceof Error
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
1
|
import { promises as fsp } from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
3
|
+
import { pathExists } from "./fs-async.js";
|
|
4
4
|
import { resolveWorkspaceProject } from "./workspace-project.js";
|
|
5
5
|
import { appendWorkspaceInventoryEntries, readWorkspaceInventory } from "./workspace-inventory.js";
|
|
6
6
|
import { toKebabCase, toSnakeCase, toTitleCase } from "./string-case.js";
|
|
@@ -381,8 +381,7 @@ async function writeVariationRegistry(projectDir, blockSlug, variationSlug) {
|
|
|
381
381
|
const variationsDir = path.join(projectDir, "src", "blocks", blockSlug, "variations");
|
|
382
382
|
const variationsIndexPath = path.join(variationsDir, "index.ts");
|
|
383
383
|
await fsp.mkdir(variationsDir, { recursive: true });
|
|
384
|
-
const existingVariationSlugs =
|
|
385
|
-
.readdirSync(variationsDir)
|
|
384
|
+
const existingVariationSlugs = (await fsp.readdir(variationsDir))
|
|
386
385
|
.filter((entry) => entry.endsWith(".ts") && entry !== "index.ts")
|
|
387
386
|
.map((entry) => entry.replace(/\.ts$/u, ""));
|
|
388
387
|
const nextVariationSlugs = Array.from(new Set([...existingVariationSlugs, variationSlug])).sort();
|
|
@@ -392,8 +391,7 @@ async function writeBlockStyleRegistry(projectDir, blockSlug, styleSlug) {
|
|
|
392
391
|
const stylesDir = path.join(projectDir, "src", "blocks", blockSlug, "styles");
|
|
393
392
|
const stylesIndexPath = path.join(stylesDir, "index.ts");
|
|
394
393
|
await fsp.mkdir(stylesDir, { recursive: true });
|
|
395
|
-
const existingStyleSlugs =
|
|
396
|
-
.readdirSync(stylesDir)
|
|
394
|
+
const existingStyleSlugs = (await fsp.readdir(stylesDir))
|
|
397
395
|
.filter((entry) => entry.endsWith(".ts") && entry !== "index.ts")
|
|
398
396
|
.map((entry) => entry.replace(/\.ts$/u, ""));
|
|
399
397
|
const nextStyleSlugs = Array.from(new Set([...existingStyleSlugs, styleSlug])).sort();
|
|
@@ -403,8 +401,7 @@ async function writeBlockTransformRegistry(projectDir, blockSlug, transformSlug)
|
|
|
403
401
|
const transformsDir = path.join(projectDir, "src", "blocks", blockSlug, "transforms");
|
|
404
402
|
const transformsIndexPath = path.join(transformsDir, "index.ts");
|
|
405
403
|
await fsp.mkdir(transformsDir, { recursive: true });
|
|
406
|
-
const existingTransformSlugs =
|
|
407
|
-
.readdirSync(transformsDir)
|
|
404
|
+
const existingTransformSlugs = (await fsp.readdir(transformsDir))
|
|
408
405
|
.filter((entry) => entry.endsWith(".ts") && entry !== "index.ts")
|
|
409
406
|
.map((entry) => entry.replace(/\.ts$/u, ""));
|
|
410
407
|
const nextTransformSlugs = Array.from(new Set([...existingTransformSlugs, transformSlug])).sort();
|
|
@@ -495,7 +492,7 @@ export async function runAddVariationCommand({ blockName, cwd = process.cwd(), v
|
|
|
495
492
|
const variationsDir = path.join(workspace.projectDir, "src", "blocks", blockSlug, "variations");
|
|
496
493
|
const variationFilePath = path.join(variationsDir, `${variationSlug}.ts`);
|
|
497
494
|
const variationsIndexPath = path.join(variationsDir, "index.ts");
|
|
498
|
-
const shouldRemoveVariationsDirOnRollback = !
|
|
495
|
+
const shouldRemoveVariationsDirOnRollback = !(await pathExists(variationsDir));
|
|
499
496
|
const mutationSnapshot = {
|
|
500
497
|
fileSources: await snapshotWorkspaceFiles([
|
|
501
498
|
blockConfigPath,
|
|
@@ -555,7 +552,7 @@ export async function runAddBlockStyleCommand({ blockName, cwd = process.cwd(),
|
|
|
555
552
|
const stylesDir = path.join(workspace.projectDir, "src", "blocks", blockSlug, "styles");
|
|
556
553
|
const styleFilePath = path.join(stylesDir, `${styleSlug}.ts`);
|
|
557
554
|
const stylesIndexPath = path.join(stylesDir, "index.ts");
|
|
558
|
-
const shouldRemoveStylesDirOnRollback = !
|
|
555
|
+
const shouldRemoveStylesDirOnRollback = !(await pathExists(stylesDir));
|
|
559
556
|
const mutationSnapshot = {
|
|
560
557
|
fileSources: await snapshotWorkspaceFiles([
|
|
561
558
|
blockConfigPath,
|
|
@@ -624,7 +621,7 @@ export async function runAddBlockTransformCommand({ cwd = process.cwd(), fromBlo
|
|
|
624
621
|
const transformsDir = path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "transforms");
|
|
625
622
|
const transformFilePath = path.join(transformsDir, `${transformSlug}.ts`);
|
|
626
623
|
const transformsIndexPath = path.join(transformsDir, "index.ts");
|
|
627
|
-
const shouldRemoveTransformsDirOnRollback = !
|
|
624
|
+
const shouldRemoveTransformsDirOnRollback = !(await pathExists(transformsDir));
|
|
628
625
|
const mutationSnapshot = {
|
|
629
626
|
fileSources: await snapshotWorkspaceFiles([
|
|
630
627
|
blockConfigPath,
|
|
@@ -695,7 +692,7 @@ export async function runAddHookedBlockCommand({ anchorBlockName, blockName, cwd
|
|
|
695
692
|
if (resolvedAnchorBlockName === selfHookAnchor) {
|
|
696
693
|
throw new Error("`wp-typia add hooked-block` cannot hook a block relative to its own block name.");
|
|
697
694
|
}
|
|
698
|
-
const { blockJson, blockJsonPath } = readWorkspaceBlockJson(workspace.projectDir, blockSlug);
|
|
695
|
+
const { blockJson, blockJsonPath } = await readWorkspaceBlockJson(workspace.projectDir, blockSlug);
|
|
699
696
|
const blockJsonRelativePath = path.relative(workspace.projectDir, blockJsonPath);
|
|
700
697
|
const blockHooks = getMutableBlockHooks(blockJson, blockJsonRelativePath);
|
|
701
698
|
if (Object.prototype.hasOwnProperty.call(blockHooks, resolvedAnchorBlockName)) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type PackageManagerId } from "./package-managers.js";
|
|
2
|
+
import type { InitCommandMode, InitPlanLayoutKind, InitPlanStatus, RetrofitInitPlan } from "./cli-init-types.js";
|
|
3
|
+
export declare function buildInitPlanChangeSummary(changes: Pick<RetrofitInitPlan, "generatedArtifacts" | "packageChanges" | "plannedFiles">, options: {
|
|
4
|
+
includeGeneratedArtifacts: boolean;
|
|
5
|
+
}): string[];
|
|
6
|
+
export declare function buildInitPlanNextSteps(options: {
|
|
7
|
+
commandMode: InitCommandMode;
|
|
8
|
+
dependencyChangeCount: number;
|
|
9
|
+
hasPlannedChanges: boolean;
|
|
10
|
+
layoutKind: InitPlanLayoutKind;
|
|
11
|
+
packageManager: PackageManagerId;
|
|
12
|
+
}): string[];
|
|
13
|
+
export declare function buildRetrofitPlanSummary(options: {
|
|
14
|
+
commandMode: InitCommandMode;
|
|
15
|
+
status: InitPlanStatus;
|
|
16
|
+
}): string;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { formatAddDevDependenciesCommand, formatPackageExecCommand, formatRunScript, } from "./package-managers.js";
|
|
2
|
+
import { buildRequiredDevDependencyMapEntries, getWpTypiaCliSpecifier, } from "./cli-init-package-json.js";
|
|
3
|
+
export function buildInitPlanChangeSummary(changes, options) {
|
|
4
|
+
const lines = [];
|
|
5
|
+
for (const dependencyChange of changes.packageChanges.addDevDependencies) {
|
|
6
|
+
lines.push(`devDependency ${dependencyChange.action} ${dependencyChange.name} -> ${dependencyChange.requiredValue}`);
|
|
7
|
+
}
|
|
8
|
+
if (changes.packageChanges.packageManagerField) {
|
|
9
|
+
lines.push(`packageManager ${changes.packageChanges.packageManagerField.action} -> ${changes.packageChanges.packageManagerField.requiredValue}`);
|
|
10
|
+
}
|
|
11
|
+
for (const scriptChange of changes.packageChanges.scripts) {
|
|
12
|
+
lines.push(`script ${scriptChange.action} ${scriptChange.name} -> ${scriptChange.requiredValue}`);
|
|
13
|
+
}
|
|
14
|
+
for (const filePlan of changes.plannedFiles) {
|
|
15
|
+
lines.push(`file ${filePlan.action} ${filePlan.path} (${filePlan.purpose})`);
|
|
16
|
+
}
|
|
17
|
+
if (options.includeGeneratedArtifacts) {
|
|
18
|
+
for (const artifactPath of changes.generatedArtifacts) {
|
|
19
|
+
lines.push(`generated artifact ${artifactPath}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return lines;
|
|
23
|
+
}
|
|
24
|
+
export function buildInitPlanNextSteps(options) {
|
|
25
|
+
const cliSpecifier = getWpTypiaCliSpecifier();
|
|
26
|
+
const syncTypesRun = formatRunScript(options.packageManager, "sync-types");
|
|
27
|
+
const syncRun = formatRunScript(options.packageManager, "sync");
|
|
28
|
+
const doctorRun = formatPackageExecCommand(options.packageManager, cliSpecifier, "doctor");
|
|
29
|
+
const migrationInitRun = formatPackageExecCommand(options.packageManager, cliSpecifier, "migrate init --current-migration-version v1");
|
|
30
|
+
const dependencyInstallCommand = formatAddDevDependenciesCommand(options.packageManager, buildRequiredDevDependencyMapEntries());
|
|
31
|
+
if (options.layoutKind === "unsupported") {
|
|
32
|
+
return [
|
|
33
|
+
"Align the project to one of the supported retrofit layouts listed below, then rerun `wp-typia init`.",
|
|
34
|
+
dependencyInstallCommand,
|
|
35
|
+
syncTypesRun,
|
|
36
|
+
doctorRun,
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
if (options.commandMode === "apply") {
|
|
40
|
+
return [
|
|
41
|
+
...(options.dependencyChangeCount > 0
|
|
42
|
+
? [
|
|
43
|
+
"Install or reinstall project dependencies so the retrofit sync scripts and metadata generators are available locally.",
|
|
44
|
+
dependencyInstallCommand,
|
|
45
|
+
]
|
|
46
|
+
: []),
|
|
47
|
+
syncRun,
|
|
48
|
+
doctorRun,
|
|
49
|
+
`Optional migration bootstrap: ${migrationInitRun}`,
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
return [
|
|
53
|
+
...(options.hasPlannedChanges
|
|
54
|
+
? [
|
|
55
|
+
"Re-run `wp-typia init --apply` to write the planned package.json changes and helper files automatically.",
|
|
56
|
+
...(options.dependencyChangeCount > 0 ? [dependencyInstallCommand] : []),
|
|
57
|
+
]
|
|
58
|
+
: []),
|
|
59
|
+
syncRun,
|
|
60
|
+
doctorRun,
|
|
61
|
+
`Optional migration bootstrap: ${migrationInitRun}`,
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
export function buildRetrofitPlanSummary(options) {
|
|
65
|
+
if (options.status === "already-initialized") {
|
|
66
|
+
return options.commandMode === "apply"
|
|
67
|
+
? "This project already exposes the minimum wp-typia retrofit surface. No files were changed."
|
|
68
|
+
: "This project already exposes the minimum wp-typia retrofit surface.";
|
|
69
|
+
}
|
|
70
|
+
if (options.commandMode === "apply") {
|
|
71
|
+
return "Applied the minimum wp-typia retrofit surface so package.json and helper scripts are ready for the next install and sync run.";
|
|
72
|
+
}
|
|
73
|
+
return "This command previews the minimum wp-typia adoption layer for the current project without rewriting it into a full scaffold.";
|
|
74
|
+
}
|
|
@@ -3,9 +3,10 @@ import path from "node:path";
|
|
|
3
3
|
import { analyzeSourceTypes } from "@wp-typia/block-runtime/metadata-parser";
|
|
4
4
|
import ts from "typescript";
|
|
5
5
|
import { discoverMigrationInitLayout } from "./migration-project.js";
|
|
6
|
-
import {
|
|
6
|
+
import { formatPackageExecCommand, formatRunScript } from "./package-managers.js";
|
|
7
7
|
import { toPascalCase } from "./string-case.js";
|
|
8
|
-
import { buildDependencyChanges, buildPackageManagerFieldChange,
|
|
8
|
+
import { buildDependencyChanges, buildPackageManagerFieldChange, buildScriptChanges, getWpTypiaCliSpecifier, hasExistingWpTypiaProjectSurface, readProjectPackageJson, resolveInitPackageManager, } from "./cli-init-package-json.js";
|
|
9
|
+
import { buildInitPlanChangeSummary, buildInitPlanNextSteps, buildRetrofitPlanSummary, } from "./cli-init-plan-presentation.js";
|
|
9
10
|
import { RETROFIT_APPLY_PREVIEW_NOTE, SUPPORTED_RETROFIT_LAYOUT_NOTE, } from "./cli-init-types.js";
|
|
10
11
|
import { tryResolveWorkspaceProject } from "./workspace-project.js";
|
|
11
12
|
function normalizeRelativePath(value) {
|
|
@@ -161,82 +162,9 @@ function buildPlannedFiles(projectDir, layoutKind) {
|
|
|
161
162
|
},
|
|
162
163
|
];
|
|
163
164
|
}
|
|
164
|
-
function buildChangeSummary(changes, options) {
|
|
165
|
-
const lines = [];
|
|
166
|
-
for (const dependencyChange of changes.packageChanges.addDevDependencies) {
|
|
167
|
-
lines.push(`devDependency ${dependencyChange.action} ${dependencyChange.name} -> ${dependencyChange.requiredValue}`);
|
|
168
|
-
}
|
|
169
|
-
if (changes.packageChanges.packageManagerField) {
|
|
170
|
-
lines.push(`packageManager ${changes.packageChanges.packageManagerField.action} -> ${changes.packageChanges.packageManagerField.requiredValue}`);
|
|
171
|
-
}
|
|
172
|
-
for (const scriptChange of changes.packageChanges.scripts) {
|
|
173
|
-
lines.push(`script ${scriptChange.action} ${scriptChange.name} -> ${scriptChange.requiredValue}`);
|
|
174
|
-
}
|
|
175
|
-
for (const filePlan of changes.plannedFiles) {
|
|
176
|
-
lines.push(`file ${filePlan.action} ${filePlan.path} (${filePlan.purpose})`);
|
|
177
|
-
}
|
|
178
|
-
if (options.includeGeneratedArtifacts) {
|
|
179
|
-
for (const artifactPath of changes.generatedArtifacts) {
|
|
180
|
-
lines.push(`generated artifact ${artifactPath}`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return lines;
|
|
184
|
-
}
|
|
185
|
-
function buildNextSteps(options) {
|
|
186
|
-
const cliSpecifier = getWpTypiaCliSpecifier();
|
|
187
|
-
const syncTypesRun = formatRunScript(options.packageManager, "sync-types");
|
|
188
|
-
const syncRun = formatRunScript(options.packageManager, "sync");
|
|
189
|
-
const doctorRun = formatPackageExecCommand(options.packageManager, cliSpecifier, "doctor");
|
|
190
|
-
const migrationInitRun = formatPackageExecCommand(options.packageManager, cliSpecifier, "migrate init --current-migration-version v1");
|
|
191
|
-
const dependencyInstallCommand = formatAddDevDependenciesCommand(options.packageManager, buildRequiredDevDependencyMapEntries());
|
|
192
|
-
if (options.layoutKind === "unsupported") {
|
|
193
|
-
return [
|
|
194
|
-
"Align the project to one of the supported retrofit layouts listed below, then rerun `wp-typia init`.",
|
|
195
|
-
dependencyInstallCommand,
|
|
196
|
-
syncTypesRun,
|
|
197
|
-
doctorRun,
|
|
198
|
-
];
|
|
199
|
-
}
|
|
200
|
-
if (options.commandMode === "apply") {
|
|
201
|
-
return [
|
|
202
|
-
...(options.dependencyChangeCount > 0
|
|
203
|
-
? [
|
|
204
|
-
"Install or reinstall project dependencies so the retrofit sync scripts and metadata generators are available locally.",
|
|
205
|
-
dependencyInstallCommand,
|
|
206
|
-
]
|
|
207
|
-
: []),
|
|
208
|
-
syncRun,
|
|
209
|
-
doctorRun,
|
|
210
|
-
`Optional migration bootstrap: ${migrationInitRun}`,
|
|
211
|
-
];
|
|
212
|
-
}
|
|
213
|
-
const steps = [
|
|
214
|
-
...(options.hasPlannedChanges
|
|
215
|
-
? [
|
|
216
|
-
"Re-run `wp-typia init --apply` to write the planned package.json changes and helper files automatically.",
|
|
217
|
-
...(options.dependencyChangeCount > 0 ? [dependencyInstallCommand] : []),
|
|
218
|
-
]
|
|
219
|
-
: []),
|
|
220
|
-
syncRun,
|
|
221
|
-
doctorRun,
|
|
222
|
-
`Optional migration bootstrap: ${migrationInitRun}`,
|
|
223
|
-
];
|
|
224
|
-
return steps;
|
|
225
|
-
}
|
|
226
|
-
function buildRetrofitPlanSummary(options) {
|
|
227
|
-
if (options.status === "already-initialized") {
|
|
228
|
-
return options.commandMode === "apply"
|
|
229
|
-
? "This project already exposes the minimum wp-typia retrofit surface. No files were changed."
|
|
230
|
-
: "This project already exposes the minimum wp-typia retrofit surface.";
|
|
231
|
-
}
|
|
232
|
-
if (options.commandMode === "apply") {
|
|
233
|
-
return "Applied the minimum wp-typia retrofit surface so package.json and helper scripts are ready for the next install and sync run.";
|
|
234
|
-
}
|
|
235
|
-
return "This command previews the minimum wp-typia adoption layer for the current project without rewriting it into a full scaffold.";
|
|
236
|
-
}
|
|
237
165
|
export function createRetrofitPlan(options) {
|
|
238
166
|
const includeGeneratedArtifacts = options.commandMode === "preview-only";
|
|
239
|
-
const plannedChanges =
|
|
167
|
+
const plannedChanges = buildInitPlanChangeSummary({
|
|
240
168
|
generatedArtifacts: options.generatedArtifacts,
|
|
241
169
|
packageChanges: options.packageChanges,
|
|
242
170
|
plannedFiles: options.plannedFiles,
|
|
@@ -249,7 +177,7 @@ export function createRetrofitPlan(options) {
|
|
|
249
177
|
detectedLayout: options.detectedLayout,
|
|
250
178
|
generatedArtifacts: options.generatedArtifacts,
|
|
251
179
|
nextSteps: options.nextSteps ??
|
|
252
|
-
|
|
180
|
+
buildInitPlanNextSteps({
|
|
253
181
|
commandMode: options.commandMode,
|
|
254
182
|
dependencyChangeCount: options.packageChanges.addDevDependencies.length,
|
|
255
183
|
hasPlannedChanges: plannedChanges.length > 0,
|
|
@@ -23,7 +23,7 @@ export declare const DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION = "^0.9.0";
|
|
|
23
23
|
export declare const DEFAULT_WORDPRESS_CORE_DATA_VERSION = "^7.44.0";
|
|
24
24
|
export declare const DEFAULT_WORDPRESS_DATA_VERSION = "^9.28.0";
|
|
25
25
|
export declare const DEFAULT_WORDPRESS_DATAVIEWS_VERSION = "^14.1.0";
|
|
26
|
-
export declare const DEFAULT_WP_TYPIA_DATAVIEWS_VERSION = "^0.1.
|
|
26
|
+
export declare const DEFAULT_WP_TYPIA_DATAVIEWS_VERSION = "^0.1.1";
|
|
27
27
|
/**
|
|
28
28
|
* Resolve a managed package version range from linked workspace packages first,
|
|
29
29
|
* then installed package manifests, while preserving the shared normalization
|
|
@@ -19,7 +19,7 @@ export const DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION = '^0.9.0';
|
|
|
19
19
|
export const DEFAULT_WORDPRESS_CORE_DATA_VERSION = '^7.44.0';
|
|
20
20
|
export const DEFAULT_WORDPRESS_DATA_VERSION = '^9.28.0';
|
|
21
21
|
export const DEFAULT_WORDPRESS_DATAVIEWS_VERSION = '^14.1.0';
|
|
22
|
-
export const DEFAULT_WP_TYPIA_DATAVIEWS_VERSION = '^0.1.
|
|
22
|
+
export const DEFAULT_WP_TYPIA_DATAVIEWS_VERSION = '^0.1.1';
|
|
23
23
|
let cachedPackageVersions = null;
|
|
24
24
|
function getErrorCode(error) {
|
|
25
25
|
return typeof error === 'object' && error !== null && 'code' in error
|
|
@@ -139,6 +139,84 @@ function matchesPhpFunctionCallAt(source, index, functionName) {
|
|
|
139
139
|
const callStart = skipPhpCallTrivia(source, cursor);
|
|
140
140
|
return callStart !== null && source[callStart] === "(";
|
|
141
141
|
}
|
|
142
|
+
function createPhpScannerState() {
|
|
143
|
+
return {
|
|
144
|
+
heredocDelimiter: "",
|
|
145
|
+
mode: "code",
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function advancePhpScanner(source, index, state) {
|
|
149
|
+
const character = source[index];
|
|
150
|
+
if (state.mode === "heredoc") {
|
|
151
|
+
const closingEnd = findPhpHeredocClosingEnd(source, index, state.heredocDelimiter);
|
|
152
|
+
if (closingEnd !== null) {
|
|
153
|
+
state.mode = "code";
|
|
154
|
+
state.heredocDelimiter = "";
|
|
155
|
+
return { ambiguous: false, inCode: false, index: closingEnd };
|
|
156
|
+
}
|
|
157
|
+
const nextLineStart = findPhpLineBoundary(source, index).nextStart;
|
|
158
|
+
if (nextLineStart <= index) {
|
|
159
|
+
return { ambiguous: true, inCode: false, index };
|
|
160
|
+
}
|
|
161
|
+
return { ambiguous: false, inCode: false, index: nextLineStart };
|
|
162
|
+
}
|
|
163
|
+
if (state.mode === "single-quoted" || state.mode === "double-quoted") {
|
|
164
|
+
const quote = state.mode === "single-quoted" ? "'" : '"';
|
|
165
|
+
if (character === "\\") {
|
|
166
|
+
return { ambiguous: false, inCode: false, index: index + 2 };
|
|
167
|
+
}
|
|
168
|
+
if (character === quote) {
|
|
169
|
+
state.mode = "code";
|
|
170
|
+
}
|
|
171
|
+
return { ambiguous: false, inCode: false, index: index + 1 };
|
|
172
|
+
}
|
|
173
|
+
if (state.mode === "line-comment") {
|
|
174
|
+
if (character === "\r" || character === "\n") {
|
|
175
|
+
state.mode = "code";
|
|
176
|
+
}
|
|
177
|
+
return { ambiguous: false, inCode: false, index: index + 1 };
|
|
178
|
+
}
|
|
179
|
+
if (state.mode === "block-comment") {
|
|
180
|
+
if (character === "*" && source[index + 1] === "/") {
|
|
181
|
+
state.mode = "code";
|
|
182
|
+
return { ambiguous: false, inCode: false, index: index + 2 };
|
|
183
|
+
}
|
|
184
|
+
return { ambiguous: false, inCode: false, index: index + 1 };
|
|
185
|
+
}
|
|
186
|
+
if (character === "'") {
|
|
187
|
+
state.mode = "single-quoted";
|
|
188
|
+
return { ambiguous: false, inCode: false, index: index + 1 };
|
|
189
|
+
}
|
|
190
|
+
if (character === '"') {
|
|
191
|
+
state.mode = "double-quoted";
|
|
192
|
+
return { ambiguous: false, inCode: false, index: index + 1 };
|
|
193
|
+
}
|
|
194
|
+
if (character === "/" && source[index + 1] === "/") {
|
|
195
|
+
state.mode = "line-comment";
|
|
196
|
+
return { ambiguous: false, inCode: false, index: index + 2 };
|
|
197
|
+
}
|
|
198
|
+
if (character === "#" && source[index + 1] !== "[") {
|
|
199
|
+
state.mode = "line-comment";
|
|
200
|
+
return { ambiguous: false, inCode: false, index: index + 1 };
|
|
201
|
+
}
|
|
202
|
+
if (character === "/" && source[index + 1] === "*") {
|
|
203
|
+
state.mode = "block-comment";
|
|
204
|
+
return { ambiguous: false, inCode: false, index: index + 2 };
|
|
205
|
+
}
|
|
206
|
+
if (character === "<") {
|
|
207
|
+
const heredocStart = parsePhpHeredocStart(source, index);
|
|
208
|
+
if (heredocStart) {
|
|
209
|
+
state.mode = "heredoc";
|
|
210
|
+
state.heredocDelimiter = heredocStart.delimiter;
|
|
211
|
+
return {
|
|
212
|
+
ambiguous: false,
|
|
213
|
+
inCode: false,
|
|
214
|
+
index: heredocStart.contentStart,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return { ambiguous: false, inCode: true, index };
|
|
219
|
+
}
|
|
142
220
|
/**
|
|
143
221
|
* Detect a PHP function call outside strings, comments, heredoc, and nowdoc blocks.
|
|
144
222
|
*
|
|
@@ -147,88 +225,17 @@ function matchesPhpFunctionCallAt(source, index, functionName) {
|
|
|
147
225
|
* @returns Whether `source` contains a code-mode call to `functionName`.
|
|
148
226
|
*/
|
|
149
227
|
export function hasPhpFunctionCall(source, functionName) {
|
|
150
|
-
|
|
151
|
-
let heredocDelimiter = "";
|
|
228
|
+
const scanner = createPhpScannerState();
|
|
152
229
|
let index = 0;
|
|
153
230
|
while (index < source.length) {
|
|
154
|
-
const
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
if (closingEnd !== null) {
|
|
158
|
-
mode = "code";
|
|
159
|
-
heredocDelimiter = "";
|
|
160
|
-
index = closingEnd;
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
const nextLineStart = findPhpLineBoundary(source, index).nextStart;
|
|
164
|
-
if (nextLineStart <= index) {
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
index = nextLineStart;
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
if (mode === "single-quoted" || mode === "double-quoted") {
|
|
171
|
-
const quote = mode === "single-quoted" ? "'" : '"';
|
|
172
|
-
if (character === "\\") {
|
|
173
|
-
index += 2;
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
if (character === quote) {
|
|
177
|
-
mode = "code";
|
|
178
|
-
}
|
|
179
|
-
index += 1;
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
if (mode === "line-comment") {
|
|
183
|
-
if (character === "\r" || character === "\n") {
|
|
184
|
-
mode = "code";
|
|
185
|
-
}
|
|
186
|
-
index += 1;
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
if (mode === "block-comment") {
|
|
190
|
-
if (character === "*" && source[index + 1] === "/") {
|
|
191
|
-
mode = "code";
|
|
192
|
-
index += 2;
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
index += 1;
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
if (character === "'") {
|
|
199
|
-
mode = "single-quoted";
|
|
200
|
-
index += 1;
|
|
201
|
-
continue;
|
|
231
|
+
const scan = advancePhpScanner(source, index, scanner);
|
|
232
|
+
if (scan.ambiguous) {
|
|
233
|
+
return false;
|
|
202
234
|
}
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
index += 1;
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
if (character === "/" && source[index + 1] === "/") {
|
|
209
|
-
mode = "line-comment";
|
|
210
|
-
index += 2;
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
if (character === "#" && source[index + 1] !== "[") {
|
|
214
|
-
mode = "line-comment";
|
|
215
|
-
index += 1;
|
|
235
|
+
if (!scan.inCode) {
|
|
236
|
+
index = scan.index;
|
|
216
237
|
continue;
|
|
217
238
|
}
|
|
218
|
-
if (character === "/" && source[index + 1] === "*") {
|
|
219
|
-
mode = "block-comment";
|
|
220
|
-
index += 2;
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
if (character === "<") {
|
|
224
|
-
const heredocStart = parsePhpHeredocStart(source, index);
|
|
225
|
-
if (heredocStart) {
|
|
226
|
-
mode = "heredoc";
|
|
227
|
-
heredocDelimiter = heredocStart.delimiter;
|
|
228
|
-
index = heredocStart.contentStart;
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
239
|
if (matchesPhpFunctionCallAt(source, index, functionName)) {
|
|
233
240
|
return true;
|
|
234
241
|
}
|
|
@@ -257,88 +264,18 @@ export function findPhpFunctionRange(source, functionName, options = {}) {
|
|
|
257
264
|
}
|
|
258
265
|
const openBraceIndex = functionStart + openBraceOffset;
|
|
259
266
|
let depth = 0;
|
|
260
|
-
|
|
261
|
-
let heredocDelimiter = "";
|
|
267
|
+
const scanner = createPhpScannerState();
|
|
262
268
|
let index = openBraceIndex;
|
|
263
269
|
while (index < source.length) {
|
|
264
|
-
const
|
|
265
|
-
if (
|
|
266
|
-
|
|
267
|
-
if (closingEnd !== null) {
|
|
268
|
-
mode = "code";
|
|
269
|
-
heredocDelimiter = "";
|
|
270
|
-
index = closingEnd;
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
const nextLineStart = findPhpLineBoundary(source, index).nextStart;
|
|
274
|
-
if (nextLineStart <= index) {
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
index = nextLineStart;
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
if (mode === "single-quoted" || mode === "double-quoted") {
|
|
281
|
-
const quote = mode === "single-quoted" ? "'" : '"';
|
|
282
|
-
if (character === "\\") {
|
|
283
|
-
index += 2;
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
if (character === quote) {
|
|
287
|
-
mode = "code";
|
|
288
|
-
}
|
|
289
|
-
index += 1;
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
if (mode === "line-comment") {
|
|
293
|
-
if (character === "\r" || character === "\n") {
|
|
294
|
-
mode = "code";
|
|
295
|
-
}
|
|
296
|
-
index += 1;
|
|
297
|
-
continue;
|
|
298
|
-
}
|
|
299
|
-
if (mode === "block-comment") {
|
|
300
|
-
if (character === "*" && source[index + 1] === "/") {
|
|
301
|
-
mode = "code";
|
|
302
|
-
index += 2;
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
index += 1;
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
|
-
if (character === "'") {
|
|
309
|
-
mode = "single-quoted";
|
|
310
|
-
index += 1;
|
|
311
|
-
continue;
|
|
312
|
-
}
|
|
313
|
-
if (character === '"') {
|
|
314
|
-
mode = "double-quoted";
|
|
315
|
-
index += 1;
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
|
-
if (character === "/" && source[index + 1] === "/") {
|
|
319
|
-
mode = "line-comment";
|
|
320
|
-
index += 2;
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
if (character === "#" && source[index + 1] !== "[") {
|
|
324
|
-
mode = "line-comment";
|
|
325
|
-
index += 1;
|
|
326
|
-
continue;
|
|
270
|
+
const scan = advancePhpScanner(source, index, scanner);
|
|
271
|
+
if (scan.ambiguous) {
|
|
272
|
+
return null;
|
|
327
273
|
}
|
|
328
|
-
if (
|
|
329
|
-
|
|
330
|
-
index += 2;
|
|
274
|
+
if (!scan.inCode) {
|
|
275
|
+
index = scan.index;
|
|
331
276
|
continue;
|
|
332
277
|
}
|
|
333
|
-
|
|
334
|
-
const heredocStart = parsePhpHeredocStart(source, index);
|
|
335
|
-
if (heredocStart) {
|
|
336
|
-
mode = "heredoc";
|
|
337
|
-
heredocDelimiter = heredocStart.delimiter;
|
|
338
|
-
index = heredocStart.contentStart;
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
278
|
+
const character = source[index];
|
|
342
279
|
if (character === "{") {
|
|
343
280
|
depth += 1;
|
|
344
281
|
index += 1;
|