@wp-typia/project-tools 0.15.2 → 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.
@@ -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
- async function copyScaffoldedBlockSlice(projectDir, templateId, tempProjectDir, variables) {
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([blockConfigPath, migrationConfigPath]),
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" &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-typia/project-tools",
3
- "version": "0.15.2",
3
+ "version": "0.15.3",
4
4
  "description": "Project orchestration and programmatic tooling for wp-typia",
5
5
  "packageManager": "bun@1.3.11",
6
6
  "type": "module",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@wp-typia/api-client": "^0.4.2",
65
- "@wp-typia/block-runtime": "^0.4.2",
65
+ "@wp-typia/block-runtime": "^0.4.3",
66
66
  "@wp-typia/rest": "^0.3.5",
67
67
  "@wp-typia/block-types": "^0.2.1",
68
68
  "mustache": "^4.2.0",
@@ -1,30 +1,44 @@
1
- import typia from 'typia';
2
-
3
1
  import type { ManifestDefaultsDocument } from '@wp-typia/block-runtime/defaults';
4
2
  import {
5
3
  createScaffoldValidatorToolkit,
6
4
  type ScaffoldValidatorToolkitOptions,
7
5
  } from '@wp-typia/block-runtime/validation';
8
6
 
9
- interface TemplateValidatorToolkitOptions< T extends object > {
7
+ interface TemplateValidatorFunctions< T extends object > {
8
+ assert: ScaffoldValidatorToolkitOptions< T >['assert'];
9
+ clone: ScaffoldValidatorToolkitOptions< T >['clone'];
10
+ is: ScaffoldValidatorToolkitOptions< T >['is'];
11
+ prune: ScaffoldValidatorToolkitOptions< T >['prune'];
12
+ random: ScaffoldValidatorToolkitOptions< T >['random'];
13
+ validate: ScaffoldValidatorToolkitOptions< T >['validate'];
14
+ }
15
+
16
+ interface TemplateValidatorToolkitOptions< T extends object >
17
+ extends TemplateValidatorFunctions< T > {
10
18
  finalize?: ScaffoldValidatorToolkitOptions< T >['finalize'];
11
19
  manifest: unknown;
12
20
  onValidationError?: ScaffoldValidatorToolkitOptions< T >['onValidationError'];
13
21
  }
14
22
 
15
23
  export function createTemplateValidatorToolkit< T extends object >( {
24
+ assert,
25
+ clone,
16
26
  finalize,
27
+ is,
17
28
  manifest,
18
29
  onValidationError,
30
+ prune,
31
+ random,
32
+ validate,
19
33
  }: TemplateValidatorToolkitOptions< T > ) {
20
34
  return createScaffoldValidatorToolkit< T >( {
21
35
  manifest: manifest as ManifestDefaultsDocument,
22
- validate: typia.createValidate< T >(),
23
- assert: typia.createAssert< T >(),
24
- is: typia.createIs< T >(),
25
- random: typia.createRandom< T >() as ( ...args: unknown[] ) => T,
26
- clone: typia.misc.createClone< T >() as ( value: T ) => T,
27
- prune: typia.misc.createPrune< T >(),
36
+ validate,
37
+ assert,
38
+ is,
39
+ random,
40
+ clone,
41
+ prune,
28
42
  finalize,
29
43
  onValidationError,
30
44
  } );
@@ -95,5 +95,6 @@ module.exports = async () => {
95
95
  getArtifactEntries,
96
96
  getOptionalModuleEntries: () => optionalModuleEntries,
97
97
  importTypiaWebpackPlugin: () => import("@typia/unplugin/webpack"),
98
+ projectRoot: process.cwd(),
98
99
  });
99
100
  };
@@ -137,5 +137,6 @@ module.exports = async () => {
137
137
  importTypiaWebpackPlugin: () => import( '@typia/unplugin/webpack' ),
138
138
  moduleEntriesMode: 'replace',
139
139
  nonModuleEntriesMode: 'replace',
140
+ projectRoot: process.cwd(),
140
141
  } );
141
142
  };
@@ -1,3 +1,4 @@
1
+ import typia from 'typia';
1
2
  import currentManifest from './typia.manifest.json';
2
3
  import type {
3
4
  {{pascalCase}}Attributes,
@@ -7,7 +8,16 @@ import { generateResourceKey } from '@wp-typia/block-runtime/identifiers';
7
8
  import { createTemplateValidatorToolkit } from '../../validator-toolkit';
8
9
 
9
10
  const scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attributes >( {
11
+ assert: typia.createAssert< {{pascalCase}}Attributes >(),
12
+ clone: typia.misc.createClone< {{pascalCase}}Attributes >() as (
13
+ value: {{pascalCase}}Attributes,
14
+ ) => {{pascalCase}}Attributes,
15
+ is: typia.createIs< {{pascalCase}}Attributes >(),
10
16
  manifest: currentManifest,
17
+ prune: typia.misc.createPrune< {{pascalCase}}Attributes >(),
18
+ random: typia.createRandom< {{pascalCase}}Attributes >() as (
19
+ ...args: unknown[]
20
+ ) => {{pascalCase}}Attributes,
11
21
  finalize: ( normalized ) => ( {
12
22
  ...normalized,
13
23
  resourceKey:
@@ -15,6 +25,7 @@ const scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attribu
15
25
  ? normalized.resourceKey
16
26
  : generateResourceKey( '{{slugKebabCase}}' ),
17
27
  } ),
28
+ validate: typia.createValidate< {{pascalCase}}Attributes >(),
18
29
  } );
19
30
 
20
31
  export const validators = scaffoldValidators.validators;
@@ -1,3 +1,4 @@
1
+ import typia from 'typia';
1
2
  import currentManifest from './typia.manifest.json';
2
3
  import type {
3
4
  {{pascalCase}}Attributes,
@@ -7,7 +8,16 @@ import { generateResourceKey } from '@wp-typia/block-runtime/identifiers';
7
8
  import { createTemplateValidatorToolkit } from './validator-toolkit';
8
9
 
9
10
  const scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attributes >( {
11
+ assert: typia.createAssert< {{pascalCase}}Attributes >(),
12
+ clone: typia.misc.createClone< {{pascalCase}}Attributes >() as (
13
+ value: {{pascalCase}}Attributes,
14
+ ) => {{pascalCase}}Attributes,
15
+ is: typia.createIs< {{pascalCase}}Attributes >(),
10
16
  manifest: currentManifest,
17
+ prune: typia.misc.createPrune< {{pascalCase}}Attributes >(),
18
+ random: typia.createRandom< {{pascalCase}}Attributes >() as (
19
+ ...args: unknown[]
20
+ ) => {{pascalCase}}Attributes,
11
21
  finalize: ( normalized ) => ( {
12
22
  ...normalized,
13
23
  resourceKey:
@@ -15,6 +25,7 @@ const scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attribu
15
25
  ? normalized.resourceKey
16
26
  : generateResourceKey( '{{slugKebabCase}}' ),
17
27
  } ),
28
+ validate: typia.createValidate< {{pascalCase}}Attributes >(),
18
29
  } );
19
30
 
20
31
  export const validators = scaffoldValidators.validators;
@@ -1,14 +1,25 @@
1
+ import typia from 'typia';
1
2
  import currentManifest from "./typia.manifest.json";
2
3
  import { {{pascalCase}}Attributes, {{pascalCase}}ValidationResult } from "./types";
3
4
  import { generateBlockId } from "@wp-typia/block-runtime/identifiers";
4
5
  import { createTemplateValidatorToolkit } from "./validator-toolkit";
5
6
 
6
7
  const scaffoldValidators = createTemplateValidatorToolkit<{{pascalCase}}Attributes>({
8
+ assert: typia.createAssert<{{pascalCase}}Attributes>(),
9
+ clone: typia.misc.createClone<{{pascalCase}}Attributes>() as (
10
+ value: {{pascalCase}}Attributes,
11
+ ) => {{pascalCase}}Attributes,
12
+ is: typia.createIs<{{pascalCase}}Attributes>(),
7
13
  manifest: currentManifest,
14
+ prune: typia.misc.createPrune<{{pascalCase}}Attributes>(),
15
+ random: typia.createRandom<{{pascalCase}}Attributes>() as (
16
+ ...args: unknown[]
17
+ ) => {{pascalCase}}Attributes,
8
18
  finalize: (normalized) => ({
9
19
  ...normalized,
10
20
  id: normalized.id && normalized.id.length > 0 ? normalized.id : generateBlockId(),
11
21
  }),
22
+ validate: typia.createValidate<{{pascalCase}}Attributes>(),
12
23
  });
13
24
 
14
25
  export const validate{{pascalCase}}Attributes =
@@ -1,9 +1,20 @@
1
+ import typia from 'typia';
1
2
  import currentManifest from './typia.manifest.json';
2
3
  import type { {{pascalCase}}Attributes } from './types';
3
4
  import { createTemplateValidatorToolkit } from '../../validator-toolkit';
4
5
 
5
6
  const scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attributes >( {
7
+ assert: typia.createAssert< {{pascalCase}}Attributes >(),
8
+ clone: typia.misc.createClone< {{pascalCase}}Attributes >() as (
9
+ value: {{pascalCase}}Attributes,
10
+ ) => {{pascalCase}}Attributes,
11
+ is: typia.createIs< {{pascalCase}}Attributes >(),
6
12
  manifest: currentManifest,
13
+ prune: typia.misc.createPrune< {{pascalCase}}Attributes >(),
14
+ random: typia.createRandom< {{pascalCase}}Attributes >() as (
15
+ ...args: unknown[]
16
+ ) => {{pascalCase}}Attributes,
17
+ validate: typia.createValidate< {{pascalCase}}Attributes >(),
7
18
  } );
8
19
 
9
20
  export const validate{{pascalCase}}Attributes =
@@ -1,9 +1,20 @@
1
+ import typia from 'typia';
1
2
  import currentManifest from './typia.manifest.json';
2
3
  import type { {{pascalCase}}ItemAttributes } from './types';
3
4
  import { createTemplateValidatorToolkit } from '../../validator-toolkit';
4
5
 
5
6
  const scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}ItemAttributes >( {
7
+ assert: typia.createAssert< {{pascalCase}}ItemAttributes >(),
8
+ clone: typia.misc.createClone< {{pascalCase}}ItemAttributes >() as (
9
+ value: {{pascalCase}}ItemAttributes,
10
+ ) => {{pascalCase}}ItemAttributes,
11
+ is: typia.createIs< {{pascalCase}}ItemAttributes >(),
6
12
  manifest: currentManifest,
13
+ prune: typia.misc.createPrune< {{pascalCase}}ItemAttributes >(),
14
+ random: typia.createRandom< {{pascalCase}}ItemAttributes >() as (
15
+ ...args: unknown[]
16
+ ) => {{pascalCase}}ItemAttributes,
17
+ validate: typia.createValidate< {{pascalCase}}ItemAttributes >(),
7
18
  } );
8
19
 
9
20
  export const validate{{pascalCase}}ItemAttributes =
@@ -1,10 +1,20 @@
1
+ import typia from 'typia';
1
2
  import currentManifest from "./typia.manifest.json";
2
3
  import { {{pascalCase}}Attributes, {{pascalCase}}ValidationResult } from "./types";
3
4
  import { generateScopedClientId } from "@wp-typia/block-runtime/identifiers";
4
5
  import { createTemplateValidatorToolkit } from "./validator-toolkit";
5
6
 
6
7
  const scaffoldValidators = createTemplateValidatorToolkit<{{pascalCase}}Attributes>({
8
+ assert: typia.createAssert<{{pascalCase}}Attributes>(),
9
+ clone: typia.misc.createClone<{{pascalCase}}Attributes>() as (
10
+ value: {{pascalCase}}Attributes,
11
+ ) => {{pascalCase}}Attributes,
12
+ is: typia.createIs<{{pascalCase}}Attributes>(),
7
13
  manifest: currentManifest,
14
+ prune: typia.misc.createPrune<{{pascalCase}}Attributes>(),
15
+ random: typia.createRandom<{{pascalCase}}Attributes>() as (
16
+ ...args: unknown[]
17
+ ) => {{pascalCase}}Attributes,
8
18
  finalize: (normalized) => ({
9
19
  ...normalized,
10
20
  uniqueId:
@@ -12,6 +22,7 @@ const scaffoldValidators = createTemplateValidatorToolkit<{{pascalCase}}Attribut
12
22
  ? normalized.uniqueId
13
23
  : generateScopedClientId("{{slugKebabCase}}"),
14
24
  }),
25
+ validate: typia.createValidate<{{pascalCase}}Attributes>(),
15
26
  });
16
27
 
17
28
  export const validate{{pascalCase}}Attributes =