@wp-typia/project-tools 0.15.1 → 0.15.3
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 +109 -3
- 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/package.json +8 -8
- package/templates/_shared/base/src/validator-toolkit.ts.mustache +23 -9
- package/templates/_shared/base/webpack.config.js.mustache +1 -0
- package/templates/_shared/compound/core/webpack.config.js.mustache +1 -0
- package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/validators.ts.mustache +11 -0
- package/templates/_shared/persistence/core/src/validators.ts.mustache +11 -0
- package/templates/basic/src/validators.ts.mustache +11 -0
- package/templates/compound/src/blocks/{{slugKebabCase}}/validators.ts.mustache +11 -0
- package/templates/compound/src/blocks/{{slugKebabCase}}-item/validators.ts.mustache +11 -0
- package/templates/interactivity/src/validators.ts.mustache +11 -0
package/dist/runtime/cli-add.js
CHANGED
|
@@ -643,8 +643,103 @@ async function renderWorkspacePersistenceServerModule(projectDir, variables) {
|
|
|
643
643
|
const templateDir = buildServerTemplateRoot(variables.persistencePolicy);
|
|
644
644
|
await copyInterpolatedDirectory(templateDir, targetDir, variables);
|
|
645
645
|
}
|
|
646
|
-
|
|
646
|
+
const COMPOUND_SHARED_SUPPORT_FILES = ["hooks.ts", "validator-toolkit.ts"];
|
|
647
|
+
const LEGACY_ASSERT_PATTERN = /assert:\s*typia\.createAssert</u;
|
|
648
|
+
const LEGACY_MANIFEST_PATTERN = /\r?\n[ \t]*manifest:\s*currentManifest,/u;
|
|
649
|
+
const LEGACY_TOOLKIT_CALL_PATTERN = /createTemplateValidatorToolkit<\s*(?<typeName>[A-Za-z0-9_]+)\s*>\s*\(\s*\{/u;
|
|
650
|
+
const LEGACY_VALIDATOR_TOOLKIT_IMPORT_PATTERN = /from\s*["']\.\.\/\.\.\/validator-toolkit["']/u;
|
|
651
|
+
const COMPATIBLE_COMPOUND_TOOLKIT_PATTERNS = [
|
|
652
|
+
/interface\s+TemplateValidatorFunctions\s*<\s*T\s+extends\s+object\s*>\s*\{/u,
|
|
653
|
+
/\bassert\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']assert["']\s*\]/u,
|
|
654
|
+
/\bclone\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']clone["']\s*\]/u,
|
|
655
|
+
/\bis\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']is["']\s*\]/u,
|
|
656
|
+
/\bprune\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']prune["']\s*\]/u,
|
|
657
|
+
/\brandom\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']random["']\s*\]/u,
|
|
658
|
+
/\bvalidate\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']validate["']\s*\]/u,
|
|
659
|
+
/createTemplateValidatorToolkit\s*<\s*T\s+extends\s+object\s*>\s*\(\s*\{/u,
|
|
660
|
+
];
|
|
661
|
+
function shouldRefreshCompoundValidatorToolkit(source) {
|
|
662
|
+
return (source === null ||
|
|
663
|
+
!COMPATIBLE_COMPOUND_TOOLKIT_PATTERNS.every((pattern) => pattern.test(source)));
|
|
664
|
+
}
|
|
665
|
+
function isLegacyCompoundValidatorSource(source) {
|
|
666
|
+
return (typeof source === "string" &&
|
|
667
|
+
LEGACY_VALIDATOR_TOOLKIT_IMPORT_PATTERN.test(source) &&
|
|
668
|
+
!LEGACY_ASSERT_PATTERN.test(source));
|
|
669
|
+
}
|
|
670
|
+
function upgradeLegacyCompoundValidatorSource(source) {
|
|
671
|
+
const typeNameMatch = source.match(LEGACY_TOOLKIT_CALL_PATTERN);
|
|
672
|
+
const typeName = typeNameMatch?.groups?.typeName;
|
|
673
|
+
if (!typeName) {
|
|
674
|
+
throw new Error("Unable to upgrade a legacy compound validator without a generated type import.");
|
|
675
|
+
}
|
|
676
|
+
let nextSource = source;
|
|
677
|
+
if (!nextSource.includes("import typia from 'typia';")) {
|
|
678
|
+
nextSource = `import typia from 'typia';\n${nextSource}`;
|
|
679
|
+
}
|
|
680
|
+
nextSource = nextSource.replace(LEGACY_TOOLKIT_CALL_PATTERN, [
|
|
681
|
+
`createTemplateValidatorToolkit< ${typeName} >( {`,
|
|
682
|
+
`\tassert: typia.createAssert< ${typeName} >(),`,
|
|
683
|
+
`\tclone: typia.misc.createClone< ${typeName} >() as (`,
|
|
684
|
+
`\t\tvalue: ${typeName},`,
|
|
685
|
+
`\t) => ${typeName},`,
|
|
686
|
+
`\tis: typia.createIs< ${typeName} >(),`,
|
|
687
|
+
].join("\n") + "\n");
|
|
688
|
+
const replacedManifest = nextSource.replace(LEGACY_MANIFEST_PATTERN, [
|
|
689
|
+
"",
|
|
690
|
+
"\tmanifest: currentManifest,",
|
|
691
|
+
`\tprune: typia.misc.createPrune< ${typeName} >(),`,
|
|
692
|
+
`\trandom: typia.createRandom< ${typeName} >() as (`,
|
|
693
|
+
"\t\t...args: unknown[]",
|
|
694
|
+
`\t) => ${typeName},`,
|
|
695
|
+
`\tvalidate: typia.createValidate< ${typeName} >(),`,
|
|
696
|
+
].join("\n"));
|
|
697
|
+
if (replacedManifest === nextSource) {
|
|
698
|
+
throw new Error("Unable to upgrade legacy compound validator: manifest anchor not found.");
|
|
699
|
+
}
|
|
700
|
+
return replacedManifest;
|
|
701
|
+
}
|
|
702
|
+
async function collectLegacyCompoundValidatorPaths(projectDir) {
|
|
703
|
+
const blocksDir = path.join(projectDir, "src", "blocks");
|
|
704
|
+
if (!fs.existsSync(blocksDir)) {
|
|
705
|
+
return [];
|
|
706
|
+
}
|
|
707
|
+
const blockEntries = await fsp.readdir(blocksDir, { withFileTypes: true });
|
|
708
|
+
const validatorPaths = await Promise.all(blockEntries
|
|
709
|
+
.filter((entry) => entry.isDirectory())
|
|
710
|
+
.map(async (entry) => {
|
|
711
|
+
const validatorPath = path.join(blocksDir, entry.name, "validators.ts");
|
|
712
|
+
const validatorSource = await readOptionalFile(validatorPath);
|
|
713
|
+
return isLegacyCompoundValidatorSource(validatorSource) ? validatorPath : null;
|
|
714
|
+
}));
|
|
715
|
+
return validatorPaths.filter((validatorPath) => validatorPath !== null);
|
|
716
|
+
}
|
|
717
|
+
async function ensureCompoundWorkspaceSupportFiles(projectDir, tempProjectDir, legacyValidatorPaths) {
|
|
718
|
+
for (const fileName of COMPOUND_SHARED_SUPPORT_FILES) {
|
|
719
|
+
const sourcePath = path.join(tempProjectDir, "src", fileName);
|
|
720
|
+
if (!fs.existsSync(sourcePath)) {
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
const targetPath = path.join(projectDir, "src", fileName);
|
|
724
|
+
const currentSource = await readOptionalFile(targetPath);
|
|
725
|
+
if (fileName === "validator-toolkit.ts"
|
|
726
|
+
? shouldRefreshCompoundValidatorToolkit(currentSource)
|
|
727
|
+
: currentSource === null) {
|
|
728
|
+
await fsp.mkdir(path.dirname(targetPath), { recursive: true });
|
|
729
|
+
await fsp.copyFile(sourcePath, targetPath);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
for (const validatorPath of legacyValidatorPaths) {
|
|
733
|
+
const currentSource = await readOptionalFile(validatorPath);
|
|
734
|
+
if (!isLegacyCompoundValidatorSource(currentSource)) {
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
await fsp.writeFile(validatorPath, upgradeLegacyCompoundValidatorSource(currentSource), "utf8");
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
async function copyScaffoldedBlockSlice(projectDir, templateId, tempProjectDir, variables, legacyValidatorPaths = []) {
|
|
647
741
|
if (templateId === "compound") {
|
|
742
|
+
await ensureCompoundWorkspaceSupportFiles(projectDir, tempProjectDir, legacyValidatorPaths);
|
|
648
743
|
await copyTempDirectory(path.join(tempProjectDir, "src", "blocks", variables.slugKebabCase), path.join(projectDir, "src", "blocks", variables.slugKebabCase));
|
|
649
744
|
await copyTempDirectory(path.join(tempProjectDir, "src", "blocks", `${variables.slugKebabCase}-item`), path.join(projectDir, "src", "blocks", `${variables.slugKebabCase}-item`));
|
|
650
745
|
if (variables.compoundPersistenceEnabled === "true") {
|
|
@@ -809,6 +904,12 @@ export async function runAddBlockCommand({ blockName, cwd = process.cwd(), dataS
|
|
|
809
904
|
const blockPhpPrefix = buildWorkspacePhpPrefix(workspace.workspace.phpPrefix, normalizedSlug);
|
|
810
905
|
const migrationConfigSource = await readOptionalFile(migrationConfigPath);
|
|
811
906
|
const migrationConfig = migrationConfigSource === null ? null : parseMigrationConfig(migrationConfigSource);
|
|
907
|
+
const compoundSupportPaths = resolvedTemplateId === "compound"
|
|
908
|
+
? COMPOUND_SHARED_SUPPORT_FILES.map((fileName) => path.join(workspace.projectDir, "src", fileName))
|
|
909
|
+
: [];
|
|
910
|
+
const legacyCompoundValidatorPaths = resolvedTemplateId === "compound"
|
|
911
|
+
? await collectLegacyCompoundValidatorPaths(workspace.projectDir)
|
|
912
|
+
: [];
|
|
812
913
|
const result = await scaffoldProject({
|
|
813
914
|
answers: {
|
|
814
915
|
...defaults,
|
|
@@ -829,14 +930,19 @@ export async function runAddBlockCommand({ blockName, cwd = process.cwd(), dataS
|
|
|
829
930
|
});
|
|
830
931
|
assertBlockTargetsDoNotExist(workspace.projectDir, resolvedTemplateId, result.variables);
|
|
831
932
|
const mutationSnapshot = {
|
|
832
|
-
fileSources: await snapshotWorkspaceFiles([
|
|
933
|
+
fileSources: await snapshotWorkspaceFiles([
|
|
934
|
+
blockConfigPath,
|
|
935
|
+
migrationConfigPath,
|
|
936
|
+
...compoundSupportPaths,
|
|
937
|
+
...legacyCompoundValidatorPaths,
|
|
938
|
+
]),
|
|
833
939
|
snapshotDirs: migrationConfig === null
|
|
834
940
|
? []
|
|
835
941
|
: buildMigrationBlocks(resolvedTemplateId, result.variables).map((block) => path.join(workspace.projectDir, ...migrationConfig.snapshotDir.split("/"), migrationConfig.currentMigrationVersion, block.key)),
|
|
836
942
|
targetPaths: collectWorkspaceBlockPaths(workspace.projectDir, resolvedTemplateId, result.variables),
|
|
837
943
|
};
|
|
838
944
|
try {
|
|
839
|
-
await copyScaffoldedBlockSlice(workspace.projectDir, resolvedTemplateId, tempProjectDir, result.variables);
|
|
945
|
+
await copyScaffoldedBlockSlice(workspace.projectDir, resolvedTemplateId, tempProjectDir, result.variables, legacyCompoundValidatorPaths);
|
|
840
946
|
await addCollectionImportsForTemplate(workspace.projectDir, resolvedTemplateId, result.variables);
|
|
841
947
|
await appendBlockConfigEntries(workspace.projectDir, buildConfigEntries(resolvedTemplateId, result.variables), resolvedTemplateId === "persistence" ||
|
|
842
948
|
(resolvedTemplateId === "compound" &&
|
|
@@ -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";
|
|
@@ -1,59 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
maximum: null,
|
|
9
|
-
minLength: null,
|
|
10
|
-
minItems: null,
|
|
11
|
-
minimum: null,
|
|
12
|
-
multipleOf: null,
|
|
13
|
-
pattern: null,
|
|
14
|
-
typeTag: null,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
export function getWordPressKind(node) {
|
|
18
|
-
return node.kind === "union" ? "object" : node.kind;
|
|
19
|
-
}
|
|
20
|
-
export function baseNode(kind, pathLabel) {
|
|
21
|
-
return {
|
|
22
|
-
constraints: defaultAttributeConstraints(),
|
|
23
|
-
enumValues: null,
|
|
24
|
-
kind,
|
|
25
|
-
path: pathLabel,
|
|
26
|
-
required: true,
|
|
27
|
-
union: null,
|
|
28
|
-
wp: {
|
|
29
|
-
selector: null,
|
|
30
|
-
source: null,
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
export function withRequired(node, required) {
|
|
35
|
-
return {
|
|
36
|
-
...node,
|
|
37
|
-
items: node.items
|
|
38
|
-
? withRequired(node.items, node.items.required)
|
|
39
|
-
: undefined,
|
|
40
|
-
properties: node.properties ? cloneProperties(node.properties) : undefined,
|
|
41
|
-
required,
|
|
42
|
-
union: node.union ? cloneUnion(node.union) : null,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
export function cloneUnion(union) {
|
|
46
|
-
return {
|
|
47
|
-
branches: Object.fromEntries(Object.entries(union.branches).map(([key, branch]) => [
|
|
48
|
-
key,
|
|
49
|
-
withRequired(branch, branch.required),
|
|
50
|
-
])),
|
|
51
|
-
discriminator: union.discriminator,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
export function cloneProperties(properties) {
|
|
55
|
-
return Object.fromEntries(Object.entries(properties).map(([key, node]) => [
|
|
56
|
-
key,
|
|
57
|
-
withRequired(node, node.required),
|
|
58
|
-
]));
|
|
59
|
-
}
|
|
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";
|