@wp-typia/project-tools 0.15.0 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/runtime/cli-add.js +26 -70
- package/dist/runtime/cli-doctor.js +25 -9
- package/dist/runtime/cli-help.js +1 -0
- package/dist/runtime/cli-templates.js +10 -0
- package/dist/runtime/json-utils.d.ts +5 -8
- package/dist/runtime/json-utils.js +5 -10
- package/dist/runtime/metadata-analysis.d.ts +7 -11
- package/dist/runtime/metadata-analysis.js +7 -285
- package/dist/runtime/metadata-model.d.ts +7 -84
- package/dist/runtime/metadata-model.js +7 -59
- package/dist/runtime/metadata-parser.d.ts +5 -51
- package/dist/runtime/metadata-parser.js +5 -792
- package/dist/runtime/metadata-php-render.d.ts +5 -27
- package/dist/runtime/metadata-php-render.js +5 -547
- package/dist/runtime/metadata-projection.d.ts +7 -7
- package/dist/runtime/metadata-projection.js +7 -233
- package/dist/runtime/object-utils.d.ts +1 -1
- package/dist/runtime/object-utils.js +3 -6
- package/dist/runtime/persistence-rest-artifacts.d.ts +76 -0
- package/dist/runtime/persistence-rest-artifacts.js +99 -0
- package/dist/runtime/scaffold.d.ts +10 -2
- package/dist/runtime/scaffold.js +95 -1
- package/dist/runtime/template-builtins.js +1 -1
- package/dist/runtime/template-registry.d.ts +2 -1
- package/dist/runtime/template-registry.js +13 -2
- package/package.json +9 -8
- package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +103 -7
- package/templates/_shared/persistence/core/src/api-validators.ts.mustache +14 -0
- package/templates/_shared/persistence/core/src/api.ts.mustache +28 -9
- package/templates/_shared/persistence/core/src/interactivity.ts.mustache +17 -11
- package/templates/interactivity/src/block.json.mustache +1 -0
- package/templates/interactivity/src/editor.scss.mustache +8 -0
- package/templates/interactivity/src/index.tsx.mustache +1 -0
- package/templates/persistence/src/edit.tsx.mustache +6 -6
package/dist/runtime/cli-add.js
CHANGED
|
@@ -2,8 +2,9 @@ import fs from "node:fs";
|
|
|
2
2
|
import { promises as fsp } from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { syncBlockMetadata, } from "@wp-typia/block-runtime/metadata-core";
|
|
6
6
|
import { ensureMigrationDirectories, parseMigrationConfig, writeInitialMigrationScaffold, writeMigrationConfig, } from "./migration-project.js";
|
|
7
|
+
import { syncPersistenceRestArtifacts, } from "./persistence-rest-artifacts.js";
|
|
7
8
|
import { snapshotProjectVersion } from "./migrations.js";
|
|
8
9
|
import { getDefaultAnswers, scaffoldProject } from "./scaffold.js";
|
|
9
10
|
import { SHARED_WORKSPACE_TEMPLATE_ROOT, } from "./template-registry.js";
|
|
@@ -84,15 +85,21 @@ function buildPersistenceBlockConfigEntry(variables) {
|
|
|
84
85
|
`\t\tattributeTypeName: ${quoteTsString(`${variables.pascalCase}Attributes`)},`,
|
|
85
86
|
"\t\trestManifest: defineEndpointManifest( {",
|
|
86
87
|
"\t\t\tcontracts: {",
|
|
88
|
+
"\t\t\t\t'bootstrap-query': {",
|
|
89
|
+
`\t\t\t\t\tsourceTypeName: ${quoteTsString(`${variables.pascalCase}BootstrapQuery`)},`,
|
|
90
|
+
"\t\t\t\t},",
|
|
91
|
+
"\t\t\t\t'bootstrap-response': {",
|
|
92
|
+
`\t\t\t\t\tsourceTypeName: ${quoteTsString(`${variables.pascalCase}BootstrapResponse`)},`,
|
|
93
|
+
"\t\t\t\t},",
|
|
87
94
|
"\t\t\t\t'state-query': {",
|
|
88
95
|
`\t\t\t\t\tsourceTypeName: ${quoteTsString(`${variables.pascalCase}StateQuery`)},`,
|
|
89
96
|
"\t\t\t\t},",
|
|
90
|
-
"\t\t\t\t'write-state-request': {",
|
|
91
|
-
`\t\t\t\t\tsourceTypeName: ${quoteTsString(`${variables.pascalCase}WriteStateRequest`)},`,
|
|
92
|
-
"\t\t\t\t},",
|
|
93
97
|
"\t\t\t\t'state-response': {",
|
|
94
98
|
`\t\t\t\t\tsourceTypeName: ${quoteTsString(`${variables.pascalCase}StateResponse`)},`,
|
|
95
99
|
"\t\t\t\t},",
|
|
100
|
+
"\t\t\t\t'write-state-request': {",
|
|
101
|
+
`\t\t\t\t\tsourceTypeName: ${quoteTsString(`${variables.pascalCase}WriteStateRequest`)},`,
|
|
102
|
+
"\t\t\t\t},",
|
|
96
103
|
"\t\t\t},",
|
|
97
104
|
"\t\t\tendpoints: [",
|
|
98
105
|
"\t\t\t\t{",
|
|
@@ -118,6 +125,16 @@ function buildPersistenceBlockConfigEntry(variables) {
|
|
|
118
125
|
`\t\t\t\t\t\tmechanism: ${quoteTsString(variables.restWriteAuthMechanism)},`,
|
|
119
126
|
"\t\t\t\t\t},",
|
|
120
127
|
"\t\t\t\t},",
|
|
128
|
+
"\t\t\t\t{",
|
|
129
|
+
"\t\t\t\t\tauth: 'public',",
|
|
130
|
+
"\t\t\t\t\tmethod: 'GET',",
|
|
131
|
+
`\t\t\t\t\toperationId: ${quoteTsString(`get${variables.pascalCase}Bootstrap`)},`,
|
|
132
|
+
`\t\t\t\t\tpath: ${quoteTsString(`/${variables.namespace}/v1/${variables.slugKebabCase}/bootstrap`)},`,
|
|
133
|
+
"\t\t\t\t\tqueryContract: 'bootstrap-query',",
|
|
134
|
+
"\t\t\t\t\tresponseContract: 'bootstrap-response',",
|
|
135
|
+
`\t\t\t\t\tsummary: 'Read fresh session bootstrap state for the current viewer.',`,
|
|
136
|
+
`\t\t\t\t\ttags: [ ${quoteTsString(variables.title)} ],`,
|
|
137
|
+
"\t\t\t\t},",
|
|
121
138
|
"\t\t\t],",
|
|
122
139
|
"\t\t\tinfo: {",
|
|
123
140
|
`\t\t\t\ttitle: ${quoteTsString(`${variables.title} REST API`)},`,
|
|
@@ -130,50 +147,6 @@ function buildPersistenceBlockConfigEntry(variables) {
|
|
|
130
147
|
"\t},",
|
|
131
148
|
].join("\n");
|
|
132
149
|
}
|
|
133
|
-
function buildPersistenceEndpointManifest(variables) {
|
|
134
|
-
return defineEndpointManifest({
|
|
135
|
-
contracts: {
|
|
136
|
-
"state-query": {
|
|
137
|
-
sourceTypeName: `${variables.pascalCase}StateQuery`,
|
|
138
|
-
},
|
|
139
|
-
"write-state-request": {
|
|
140
|
-
sourceTypeName: `${variables.pascalCase}WriteStateRequest`,
|
|
141
|
-
},
|
|
142
|
-
"state-response": {
|
|
143
|
-
sourceTypeName: `${variables.pascalCase}StateResponse`,
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
endpoints: [
|
|
147
|
-
{
|
|
148
|
-
auth: "public",
|
|
149
|
-
method: "GET",
|
|
150
|
-
operationId: `get${variables.pascalCase}State`,
|
|
151
|
-
path: `/${variables.namespace}/v1/${variables.slugKebabCase}/state`,
|
|
152
|
-
queryContract: "state-query",
|
|
153
|
-
responseContract: "state-response",
|
|
154
|
-
summary: "Read the current persisted state.",
|
|
155
|
-
tags: [variables.title],
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
auth: variables.restWriteAuthIntent,
|
|
159
|
-
bodyContract: "write-state-request",
|
|
160
|
-
method: "POST",
|
|
161
|
-
operationId: `write${variables.pascalCase}State`,
|
|
162
|
-
path: `/${variables.namespace}/v1/${variables.slugKebabCase}/state`,
|
|
163
|
-
responseContract: "state-response",
|
|
164
|
-
summary: "Write the current persisted state.",
|
|
165
|
-
tags: [variables.title],
|
|
166
|
-
wordpressAuth: {
|
|
167
|
-
mechanism: variables.restWriteAuthMechanism,
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
],
|
|
171
|
-
info: {
|
|
172
|
-
title: `${variables.title} REST API`,
|
|
173
|
-
version: "1.0.0",
|
|
174
|
-
},
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
150
|
function buildCompoundChildConfigEntry(variables) {
|
|
178
151
|
return [
|
|
179
152
|
"\t{",
|
|
@@ -732,28 +705,11 @@ async function syncWorkspaceBlockMetadata(projectDir, slug, sourceTypeName, type
|
|
|
732
705
|
});
|
|
733
706
|
}
|
|
734
707
|
async function syncWorkspacePersistenceArtifacts(projectDir, variables) {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
openApiFile: path.join("src", "blocks", variables.slugKebabCase, "api-schemas", `${baseName}.openapi.json`),
|
|
741
|
-
projectRoot: projectDir,
|
|
742
|
-
sourceTypeName: contract.sourceTypeName,
|
|
743
|
-
typesFile: apiTypesFile,
|
|
744
|
-
});
|
|
745
|
-
}
|
|
746
|
-
await syncRestOpenApi({
|
|
747
|
-
manifest,
|
|
748
|
-
openApiFile: path.join("src", "blocks", variables.slugKebabCase, "api.openapi.json"),
|
|
749
|
-
projectRoot: projectDir,
|
|
750
|
-
typesFile: apiTypesFile,
|
|
751
|
-
});
|
|
752
|
-
await syncEndpointClient({
|
|
753
|
-
clientFile: path.join("src", "blocks", variables.slugKebabCase, "api-client.ts"),
|
|
754
|
-
manifest,
|
|
755
|
-
projectRoot: projectDir,
|
|
756
|
-
typesFile: apiTypesFile,
|
|
708
|
+
await syncPersistenceRestArtifacts({
|
|
709
|
+
apiTypesFile: path.join("src", "blocks", variables.slugKebabCase, "api-types.ts"),
|
|
710
|
+
outputDir: path.join("src", "blocks", variables.slugKebabCase),
|
|
711
|
+
projectDir,
|
|
712
|
+
variables,
|
|
757
713
|
});
|
|
758
714
|
}
|
|
759
715
|
async function syncWorkspaceAddedBlockArtifacts(projectDir, templateId, variables) {
|
|
@@ -5,7 +5,7 @@ import { execFileSync } from "node:child_process";
|
|
|
5
5
|
import { access, constants as fsConstants, rm, writeFile } from "node:fs/promises";
|
|
6
6
|
import { getBuiltInTemplateLayerDirs } from "./template-builtins.js";
|
|
7
7
|
import { HOOKED_BLOCK_ANCHOR_PATTERN, HOOKED_BLOCK_POSITION_SET, } from "./hooked-blocks.js";
|
|
8
|
-
import { listTemplates } from "./template-registry.js";
|
|
8
|
+
import { isBuiltInTemplateId, listTemplates } from "./template-registry.js";
|
|
9
9
|
import { readWorkspaceInventory } from "./workspace-inventory.js";
|
|
10
10
|
import { getInvalidWorkspaceProjectReason, parseWorkspacePackageJson, WORKSPACE_TEMPLATE_PACKAGE, tryResolveWorkspaceProject, } from "./workspace-project.js";
|
|
11
11
|
const WORKSPACE_COLLECTION_IMPORT_LINE = "import '../../collection';";
|
|
@@ -285,24 +285,40 @@ export async function getDoctorChecks(cwd) {
|
|
|
285
285
|
detail: tempWritable ? "Writable" : "Not writable",
|
|
286
286
|
});
|
|
287
287
|
for (const template of listTemplates()) {
|
|
288
|
-
|
|
288
|
+
if (!isBuiltInTemplateId(template.id)) {
|
|
289
|
+
const templateDirExists = fs.existsSync(template.templateDir);
|
|
290
|
+
const hasAssets = templateDirExists &&
|
|
291
|
+
fs.existsSync(path.join(template.templateDir, "package.json.mustache"));
|
|
292
|
+
checks.push({
|
|
293
|
+
status: !templateDirExists || hasAssets ? "pass" : "fail",
|
|
294
|
+
label: `Template ${template.id}`,
|
|
295
|
+
detail: !templateDirExists
|
|
296
|
+
? "External template metadata only; local overlay package is not installed."
|
|
297
|
+
: hasAssets
|
|
298
|
+
? template.templateDir
|
|
299
|
+
: "Missing core template assets",
|
|
300
|
+
});
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const builtInTemplateId = template.id;
|
|
304
|
+
const layerDirs = builtInTemplateId === "persistence"
|
|
289
305
|
? Array.from(new Set([
|
|
290
|
-
...getBuiltInTemplateLayerDirs(
|
|
291
|
-
...getBuiltInTemplateLayerDirs(
|
|
306
|
+
...getBuiltInTemplateLayerDirs(builtInTemplateId, { persistencePolicy: "authenticated" }),
|
|
307
|
+
...getBuiltInTemplateLayerDirs(builtInTemplateId, { persistencePolicy: "public" }),
|
|
292
308
|
]))
|
|
293
|
-
:
|
|
309
|
+
: builtInTemplateId === "compound"
|
|
294
310
|
? Array.from(new Set([
|
|
295
|
-
...getBuiltInTemplateLayerDirs(
|
|
296
|
-
...getBuiltInTemplateLayerDirs(
|
|
311
|
+
...getBuiltInTemplateLayerDirs(builtInTemplateId),
|
|
312
|
+
...getBuiltInTemplateLayerDirs(builtInTemplateId, {
|
|
297
313
|
persistenceEnabled: true,
|
|
298
314
|
persistencePolicy: "authenticated",
|
|
299
315
|
}),
|
|
300
|
-
...getBuiltInTemplateLayerDirs(
|
|
316
|
+
...getBuiltInTemplateLayerDirs(builtInTemplateId, {
|
|
301
317
|
persistenceEnabled: true,
|
|
302
318
|
persistencePolicy: "public",
|
|
303
319
|
}),
|
|
304
320
|
]))
|
|
305
|
-
: getBuiltInTemplateLayerDirs(
|
|
321
|
+
: getBuiltInTemplateLayerDirs(builtInTemplateId);
|
|
306
322
|
const hasAssets = layerDirs.every((layerDir) => fs.existsSync(layerDir)) &&
|
|
307
323
|
layerDirs.some((layerDir) => fs.existsSync(path.join(layerDir, "package.json.mustache"))) &&
|
|
308
324
|
layerDirs.some((layerDir) => fs.existsSync(path.join(layerDir, "src")));
|
package/dist/runtime/cli-help.js
CHANGED
|
@@ -34,6 +34,7 @@ Package managers: ${PACKAGE_MANAGER_IDS.join(", ")}
|
|
|
34
34
|
Notes:
|
|
35
35
|
\`wp-typia create\` is the canonical scaffold command.
|
|
36
36
|
\`wp-typia <project-dir>\` remains a backward-compatible alias to \`create\`.
|
|
37
|
+
Use \`--template @wp-typia/create-workspace-template\` for the official empty workspace scaffold behind \`wp-typia add ...\`.
|
|
37
38
|
\`add variation\` uses an existing workspace block from \`scripts/block-config.ts\`.
|
|
38
39
|
\`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/\`.
|
|
39
40
|
\`add binding-source\` scaffolds shared PHP and editor registration under \`src/bindings/\`.
|
|
@@ -30,6 +30,16 @@ export function formatTemplateFeatures(template) {
|
|
|
30
30
|
* @returns Multi-line template details text for CLI output.
|
|
31
31
|
*/
|
|
32
32
|
export function formatTemplateDetails(template) {
|
|
33
|
+
if (!isBuiltInTemplateId(template.id)) {
|
|
34
|
+
return [
|
|
35
|
+
template.id,
|
|
36
|
+
template.description,
|
|
37
|
+
`Category: ${template.defaultCategory}`,
|
|
38
|
+
`Overlay path: ${template.templateDir}`,
|
|
39
|
+
"Layers: workspace package scaffold",
|
|
40
|
+
`Features: ${template.features.join(", ")}`,
|
|
41
|
+
].join("\n");
|
|
42
|
+
}
|
|
33
43
|
const layers = template.id === "persistence"
|
|
34
44
|
? [
|
|
35
45
|
`authenticated: ${getBuiltInTemplateLayerDirs(template.id, { persistencePolicy: "authenticated" }).join(" -> ")}`,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* @
|
|
6
|
-
*
|
|
7
|
-
* Values that are not JSON-serializable, such as functions, `undefined`,
|
|
8
|
-
* `BigInt`, class instances, and `Date` objects, are not preserved faithfully.
|
|
2
|
+
* Re-exports JSON cloning helpers from `@wp-typia/block-runtime`.
|
|
3
|
+
* This adapter keeps the existing project-tools module path stable while the
|
|
4
|
+
* runtime implementation now lives in block-runtime.
|
|
5
|
+
* @module
|
|
9
6
|
*/
|
|
10
|
-
export
|
|
7
|
+
export * from "@wp-typia/block-runtime/json-utils";
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* @
|
|
6
|
-
*
|
|
7
|
-
* Values that are not JSON-serializable, such as functions, `undefined`,
|
|
8
|
-
* `BigInt`, class instances, and `Date` objects, are not preserved faithfully.
|
|
2
|
+
* Re-exports JSON cloning helpers from `@wp-typia/block-runtime`.
|
|
3
|
+
* This adapter keeps the existing project-tools module path stable while the
|
|
4
|
+
* runtime implementation now lives in block-runtime.
|
|
5
|
+
* @module
|
|
9
6
|
*/
|
|
10
|
-
export
|
|
11
|
-
return JSON.parse(JSON.stringify(value));
|
|
12
|
-
}
|
|
7
|
+
export * from "@wp-typia/block-runtime/json-utils";
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
recursionGuard: Set<string>;
|
|
9
|
-
}
|
|
10
|
-
export declare function getTaggedSyncBlockMetadataFailureCode(error: Error): "typescript-diagnostic" | undefined;
|
|
11
|
-
export declare function createAnalysisContext(projectRoot: string, typesFilePath: string): AnalysisContext;
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports metadata analysis helpers from `@wp-typia/block-runtime`.
|
|
3
|
+
* This adapter preserves the public project-tools module path while sharing
|
|
4
|
+
* the runtime implementation with block-runtime.
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
export * from "@wp-typia/block-runtime/metadata-analysis";
|
|
@@ -1,285 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
this.entries = new Map();
|
|
9
|
-
}
|
|
10
|
-
get(key) {
|
|
11
|
-
const value = this.entries.get(key);
|
|
12
|
-
if (value === undefined) {
|
|
13
|
-
return undefined;
|
|
14
|
-
}
|
|
15
|
-
this.entries.delete(key);
|
|
16
|
-
this.entries.set(key, value);
|
|
17
|
-
return value;
|
|
18
|
-
}
|
|
19
|
-
set(key, value) {
|
|
20
|
-
if (this.entries.has(key)) {
|
|
21
|
-
this.entries.delete(key);
|
|
22
|
-
}
|
|
23
|
-
this.entries.set(key, value);
|
|
24
|
-
if (this.entries.size <= this.maxEntries) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const oldestKey = this.entries.keys().next().value;
|
|
28
|
-
if (oldestKey !== undefined) {
|
|
29
|
-
this.entries.delete(oldestKey);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
const DEFAULT_ALLOWED_EXTERNAL_PACKAGES = ["@wp-typia/block-types"];
|
|
34
|
-
const ANALYSIS_PROGRAM_CACHE_MAX_ENTRIES = 20;
|
|
35
|
-
const TYPESCRIPT_LIB_DIRECTORY = path.dirname(ts.getDefaultLibFilePath({}));
|
|
36
|
-
const RUNTIME_DIRECTORY = path.dirname(fileURLToPath(import.meta.url));
|
|
37
|
-
const SYNC_BLOCK_METADATA_FAILURE_CODE = Symbol("sync-block-metadata-failure-code");
|
|
38
|
-
const analysisProgramCache = new LruCache(ANALYSIS_PROGRAM_CACHE_MAX_ENTRIES);
|
|
39
|
-
function tagMetadataDiagnosticError(error) {
|
|
40
|
-
error[SYNC_BLOCK_METADATA_FAILURE_CODE] = "typescript-diagnostic";
|
|
41
|
-
return error;
|
|
42
|
-
}
|
|
43
|
-
export function getTaggedSyncBlockMetadataFailureCode(error) {
|
|
44
|
-
return error[SYNC_BLOCK_METADATA_FAILURE_CODE];
|
|
45
|
-
}
|
|
46
|
-
function isProjectLocalSourceFile(filePath, projectRoot) {
|
|
47
|
-
if (filePath.startsWith(TYPESCRIPT_LIB_DIRECTORY)) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
if (filePath.includes(`${path.sep}node_modules${path.sep}`)) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
return !path.relative(projectRoot, filePath).startsWith("..");
|
|
54
|
-
}
|
|
55
|
-
function collectSourceFileModuleSpecifiers(sourceFile) {
|
|
56
|
-
const moduleSpecifiers = [];
|
|
57
|
-
for (const statement of sourceFile.statements) {
|
|
58
|
-
if ((ts.isImportDeclaration(statement) ||
|
|
59
|
-
ts.isExportDeclaration(statement)) &&
|
|
60
|
-
statement.moduleSpecifier &&
|
|
61
|
-
ts.isStringLiteralLike(statement.moduleSpecifier)) {
|
|
62
|
-
moduleSpecifiers.push(statement.moduleSpecifier.text);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
ts.forEachChild(sourceFile, (node) => {
|
|
66
|
-
if (ts.isImportTypeNode(node) &&
|
|
67
|
-
ts.isLiteralTypeNode(node.argument) &&
|
|
68
|
-
ts.isStringLiteral(node.argument.literal)) {
|
|
69
|
-
moduleSpecifiers.push(node.argument.literal.text);
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
return moduleSpecifiers;
|
|
73
|
-
}
|
|
74
|
-
function collectReferencedLocalSourceFiles(program, entryFilePath, compilerOptions, projectRoot) {
|
|
75
|
-
const visited = new Set();
|
|
76
|
-
const queue = [entryFilePath];
|
|
77
|
-
while (queue.length > 0) {
|
|
78
|
-
const filePath = queue.pop();
|
|
79
|
-
if (filePath === undefined ||
|
|
80
|
-
visited.has(filePath) ||
|
|
81
|
-
!isProjectLocalSourceFile(filePath, projectRoot)) {
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
visited.add(filePath);
|
|
85
|
-
const sourceFile = program.getSourceFile(filePath);
|
|
86
|
-
if (sourceFile === undefined) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
for (const moduleSpecifier of collectSourceFileModuleSpecifiers(sourceFile)) {
|
|
90
|
-
const resolved = ts.resolveModuleName(moduleSpecifier, filePath, compilerOptions, ts.sys).resolvedModule;
|
|
91
|
-
const resolvedFileName = resolved?.resolvedFileName;
|
|
92
|
-
if (resolvedFileName &&
|
|
93
|
-
isProjectLocalSourceFile(resolvedFileName, projectRoot)) {
|
|
94
|
-
queue.push(resolvedFileName);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return visited;
|
|
99
|
-
}
|
|
100
|
-
function stableSerializeAnalysisValue(value) {
|
|
101
|
-
if (value === undefined) {
|
|
102
|
-
return '"__undefined__"';
|
|
103
|
-
}
|
|
104
|
-
if (value === null || typeof value !== "object") {
|
|
105
|
-
return JSON.stringify(value);
|
|
106
|
-
}
|
|
107
|
-
if (Array.isArray(value)) {
|
|
108
|
-
return `[${value.map((entry) => stableSerializeAnalysisValue(entry)).join(",")}]`;
|
|
109
|
-
}
|
|
110
|
-
return `{${Object.entries(value)
|
|
111
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
112
|
-
.map(([key, entry]) => `${JSON.stringify(key)}:${stableSerializeAnalysisValue(entry)}`)
|
|
113
|
-
.join(",")}}`;
|
|
114
|
-
}
|
|
115
|
-
function buildAnalysisProgramStructureKey(projectRoot, typesFilePath, { compilerOptions, configPath, rootNames, typiaTagsAugmentationPath, }) {
|
|
116
|
-
return stableSerializeAnalysisValue({
|
|
117
|
-
compilerOptions,
|
|
118
|
-
configPath,
|
|
119
|
-
projectRoot,
|
|
120
|
-
rootNames: [...rootNames].sort(),
|
|
121
|
-
typiaTagsAugmentationPath,
|
|
122
|
-
typesFilePath,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
function createAnalysisProgramContentFingerprint(filePaths, onMissingFile = "throw") {
|
|
126
|
-
const hash = createHash("sha1");
|
|
127
|
-
const fingerprintPaths = [...new Set(filePaths)].sort();
|
|
128
|
-
for (const filePath of fingerprintPaths) {
|
|
129
|
-
const fileContents = ts.sys.readFile(filePath);
|
|
130
|
-
if (fileContents === undefined) {
|
|
131
|
-
if (onMissingFile === "return-null") {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
if (onMissingFile === "hash-missing") {
|
|
135
|
-
hash.update(filePath);
|
|
136
|
-
hash.update("\0");
|
|
137
|
-
hash.update("__missing__");
|
|
138
|
-
hash.update("\0");
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
throw new Error(`Unable to read metadata analysis dependency: ${filePath}`);
|
|
142
|
-
}
|
|
143
|
-
hash.update(filePath);
|
|
144
|
-
hash.update("\0");
|
|
145
|
-
hash.update(fileContents);
|
|
146
|
-
hash.update("\0");
|
|
147
|
-
}
|
|
148
|
-
return hash.digest("hex");
|
|
149
|
-
}
|
|
150
|
-
function getAnalysisProgramDependencyPaths(program, configPath) {
|
|
151
|
-
const sourceFilePaths = program
|
|
152
|
-
.getSourceFiles()
|
|
153
|
-
.map((sourceFile) => sourceFile.fileName)
|
|
154
|
-
.filter((filePath) => !filePath.startsWith(TYPESCRIPT_LIB_DIRECTORY));
|
|
155
|
-
const dependencyPaths = new Set(sourceFilePaths);
|
|
156
|
-
for (const filePath of sourceFilePaths) {
|
|
157
|
-
let currentDir = path.dirname(filePath);
|
|
158
|
-
while (true) {
|
|
159
|
-
dependencyPaths.add(path.join(currentDir, "package.json"));
|
|
160
|
-
const parentDir = path.dirname(currentDir);
|
|
161
|
-
if (parentDir === currentDir) {
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
currentDir = parentDir;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
if (configPath) {
|
|
168
|
-
dependencyPaths.add(configPath);
|
|
169
|
-
}
|
|
170
|
-
return [...dependencyPaths].sort();
|
|
171
|
-
}
|
|
172
|
-
function resolveAnalysisProgramInputs(projectRoot, typesFilePath) {
|
|
173
|
-
const configPath = ts.findConfigFile(projectRoot, ts.sys.fileExists, "tsconfig.json");
|
|
174
|
-
const compilerOptions = {
|
|
175
|
-
allowJs: false,
|
|
176
|
-
esModuleInterop: true,
|
|
177
|
-
module: ts.ModuleKind.NodeNext,
|
|
178
|
-
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
179
|
-
resolveJsonModule: true,
|
|
180
|
-
skipLibCheck: true,
|
|
181
|
-
target: ts.ScriptTarget.ES2022,
|
|
182
|
-
};
|
|
183
|
-
let rootNames = [typesFilePath];
|
|
184
|
-
const typiaTagsAugmentationPath = resolveTypiaTagsAugmentationPath();
|
|
185
|
-
if (configPath !== undefined) {
|
|
186
|
-
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
187
|
-
if (configFile.error) {
|
|
188
|
-
throw formatDiagnosticError(configFile.error);
|
|
189
|
-
}
|
|
190
|
-
const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configPath), compilerOptions, configPath);
|
|
191
|
-
if (parsed.errors.length > 0) {
|
|
192
|
-
throw formatDiagnosticError(parsed.errors[0]);
|
|
193
|
-
}
|
|
194
|
-
rootNames = parsed.fileNames.includes(typesFilePath)
|
|
195
|
-
? parsed.fileNames
|
|
196
|
-
: [...parsed.fileNames, typesFilePath];
|
|
197
|
-
if (typiaTagsAugmentationPath &&
|
|
198
|
-
!rootNames.includes(typiaTagsAugmentationPath)) {
|
|
199
|
-
rootNames = [...rootNames, typiaTagsAugmentationPath];
|
|
200
|
-
}
|
|
201
|
-
Object.assign(compilerOptions, parsed.options);
|
|
202
|
-
}
|
|
203
|
-
else if (typiaTagsAugmentationPath) {
|
|
204
|
-
rootNames = [...rootNames, typiaTagsAugmentationPath];
|
|
205
|
-
}
|
|
206
|
-
const structureKey = buildAnalysisProgramStructureKey(projectRoot, typesFilePath, {
|
|
207
|
-
compilerOptions,
|
|
208
|
-
configPath: configPath ?? null,
|
|
209
|
-
rootNames,
|
|
210
|
-
typiaTagsAugmentationPath,
|
|
211
|
-
});
|
|
212
|
-
return {
|
|
213
|
-
compilerOptions,
|
|
214
|
-
configPath: configPath ?? null,
|
|
215
|
-
rootNames,
|
|
216
|
-
structureKey,
|
|
217
|
-
typiaTagsAugmentationPath,
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
export function createAnalysisContext(projectRoot, typesFilePath) {
|
|
221
|
-
const analysisInputs = resolveAnalysisProgramInputs(projectRoot, typesFilePath);
|
|
222
|
-
const cachedAnalysis = analysisProgramCache.get(analysisInputs.structureKey);
|
|
223
|
-
if (cachedAnalysis) {
|
|
224
|
-
const currentDependencyFingerprint = createAnalysisProgramContentFingerprint(cachedAnalysis.dependencyPaths, "hash-missing");
|
|
225
|
-
if (currentDependencyFingerprint !== null &&
|
|
226
|
-
currentDependencyFingerprint === cachedAnalysis.dependencyFingerprint) {
|
|
227
|
-
return {
|
|
228
|
-
allowedExternalPackages: new Set(DEFAULT_ALLOWED_EXTERNAL_PACKAGES),
|
|
229
|
-
checker: cachedAnalysis.checker,
|
|
230
|
-
packageNameCache: new Map(),
|
|
231
|
-
projectRoot,
|
|
232
|
-
program: cachedAnalysis.program,
|
|
233
|
-
recursionGuard: new Set(),
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
const program = ts.createProgram({
|
|
238
|
-
oldProgram: cachedAnalysis?.program,
|
|
239
|
-
options: analysisInputs.compilerOptions,
|
|
240
|
-
rootNames: analysisInputs.rootNames,
|
|
241
|
-
});
|
|
242
|
-
const diagnostics = ts.getPreEmitDiagnostics(program);
|
|
243
|
-
const localSourceFiles = collectReferencedLocalSourceFiles(program, typesFilePath, analysisInputs.compilerOptions, projectRoot);
|
|
244
|
-
const blockingDiagnostic = diagnostics.find((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error &&
|
|
245
|
-
diagnostic.file !== undefined &&
|
|
246
|
-
localSourceFiles.has(diagnostic.file.fileName));
|
|
247
|
-
if (blockingDiagnostic) {
|
|
248
|
-
throw formatDiagnosticError(blockingDiagnostic);
|
|
249
|
-
}
|
|
250
|
-
const checker = program.getTypeChecker();
|
|
251
|
-
const dependencyPaths = getAnalysisProgramDependencyPaths(program, analysisInputs.configPath);
|
|
252
|
-
const dependencyFingerprint = createAnalysisProgramContentFingerprint(dependencyPaths, "hash-missing");
|
|
253
|
-
if (dependencyFingerprint === null) {
|
|
254
|
-
throw new Error("Unable to fingerprint metadata analysis dependencies.");
|
|
255
|
-
}
|
|
256
|
-
analysisProgramCache.set(analysisInputs.structureKey, {
|
|
257
|
-
checker,
|
|
258
|
-
dependencyFingerprint,
|
|
259
|
-
dependencyPaths,
|
|
260
|
-
program,
|
|
261
|
-
});
|
|
262
|
-
return {
|
|
263
|
-
allowedExternalPackages: new Set(DEFAULT_ALLOWED_EXTERNAL_PACKAGES),
|
|
264
|
-
checker,
|
|
265
|
-
packageNameCache: new Map(),
|
|
266
|
-
projectRoot,
|
|
267
|
-
program,
|
|
268
|
-
recursionGuard: new Set(),
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
function resolveTypiaTagsAugmentationPath() {
|
|
272
|
-
const candidates = [
|
|
273
|
-
path.join(RUNTIME_DIRECTORY, "typia-tags.d.ts"),
|
|
274
|
-
path.join(RUNTIME_DIRECTORY, "typia-tags.ts"),
|
|
275
|
-
];
|
|
276
|
-
for (const candidate of candidates) {
|
|
277
|
-
if (ts.sys.fileExists(candidate)) {
|
|
278
|
-
return candidate;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
return null;
|
|
282
|
-
}
|
|
283
|
-
function formatDiagnosticError(diagnostic) {
|
|
284
|
-
return tagMetadataDiagnosticError(new Error(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")));
|
|
285
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports metadata analysis helpers from `@wp-typia/block-runtime`.
|
|
3
|
+
* This adapter preserves the public project-tools module path while sharing
|
|
4
|
+
* the runtime implementation with block-runtime.
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
export * from "@wp-typia/block-runtime/metadata-analysis";
|
|
@@ -1,84 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
export interface AttributeConstraints {
|
|
9
|
-
exclusiveMaximum: number | null;
|
|
10
|
-
exclusiveMinimum: number | null;
|
|
11
|
-
format: string | null;
|
|
12
|
-
maxLength: number | null;
|
|
13
|
-
maxItems: number | null;
|
|
14
|
-
maximum: number | null;
|
|
15
|
-
minLength: number | null;
|
|
16
|
-
minItems: number | null;
|
|
17
|
-
minimum: number | null;
|
|
18
|
-
multipleOf: number | null;
|
|
19
|
-
pattern: string | null;
|
|
20
|
-
typeTag: string | null;
|
|
21
|
-
}
|
|
22
|
-
export interface AttributeNode {
|
|
23
|
-
constraints: AttributeConstraints;
|
|
24
|
-
defaultValue?: JsonValue;
|
|
25
|
-
enumValues: Array<string | number | boolean> | null;
|
|
26
|
-
items?: AttributeNode;
|
|
27
|
-
kind: AttributeKind;
|
|
28
|
-
path: string;
|
|
29
|
-
properties?: Record<string, AttributeNode>;
|
|
30
|
-
required: boolean;
|
|
31
|
-
union?: AttributeUnion | null;
|
|
32
|
-
wp: {
|
|
33
|
-
selector: string | null;
|
|
34
|
-
source: WordPressAttributeSource | null;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
export interface AttributeUnion {
|
|
38
|
-
branches: Record<string, AttributeNode>;
|
|
39
|
-
discriminator: string;
|
|
40
|
-
}
|
|
41
|
-
export interface BlockJsonAttribute {
|
|
42
|
-
default?: JsonValue;
|
|
43
|
-
enum?: Array<string | number | boolean>;
|
|
44
|
-
selector?: string;
|
|
45
|
-
source?: WordPressAttributeSource;
|
|
46
|
-
type: WordPressAttributeKind;
|
|
47
|
-
}
|
|
48
|
-
export interface ManifestAttribute {
|
|
49
|
-
typia: {
|
|
50
|
-
constraints: AttributeConstraints;
|
|
51
|
-
defaultValue: JsonValue | null;
|
|
52
|
-
hasDefault: boolean;
|
|
53
|
-
};
|
|
54
|
-
ts: {
|
|
55
|
-
items: ManifestAttribute | null;
|
|
56
|
-
kind: AttributeKind;
|
|
57
|
-
properties: Record<string, ManifestAttribute> | null;
|
|
58
|
-
required: boolean;
|
|
59
|
-
union: ManifestUnion | null;
|
|
60
|
-
};
|
|
61
|
-
wp: {
|
|
62
|
-
defaultValue: JsonValue | null;
|
|
63
|
-
enum: Array<string | number | boolean> | null;
|
|
64
|
-
hasDefault: boolean;
|
|
65
|
-
selector?: string | null;
|
|
66
|
-
source?: WordPressAttributeSource | null;
|
|
67
|
-
type: WordPressAttributeKind;
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
export interface ManifestUnion {
|
|
71
|
-
branches: Record<string, ManifestAttribute>;
|
|
72
|
-
discriminator: string;
|
|
73
|
-
}
|
|
74
|
-
export interface ManifestDocument {
|
|
75
|
-
attributes: Record<string, ManifestAttribute>;
|
|
76
|
-
manifestVersion: 2;
|
|
77
|
-
sourceType: string;
|
|
78
|
-
}
|
|
79
|
-
export declare function defaultAttributeConstraints(): AttributeConstraints;
|
|
80
|
-
export declare function getWordPressKind(node: AttributeNode): WordPressAttributeKind;
|
|
81
|
-
export declare function baseNode(kind: AttributeKind, pathLabel: string): AttributeNode;
|
|
82
|
-
export declare function withRequired(node: AttributeNode, required: boolean): AttributeNode;
|
|
83
|
-
export declare function cloneUnion(union: AttributeUnion): AttributeUnion;
|
|
84
|
-
export declare function cloneProperties(properties: Record<string, AttributeNode>): Record<string, AttributeNode>;
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports the metadata model types and helpers from `@wp-typia/block-runtime`.
|
|
3
|
+
* This adapter keeps the public project-tools runtime path stable while the
|
|
4
|
+
* implementation is consolidated in block-runtime.
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
export * from "@wp-typia/block-runtime/metadata-model";
|