@wp-typia/project-tools 0.15.2 → 0.15.4

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,107 @@ 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 TYPIA_IMPORT_PATTERN = /^[\uFEFF \t]*import\s+typia\s+from\s*["']typia["'];?/mu;
652
+ const COMPATIBLE_COMPOUND_TOOLKIT_PATTERNS = [
653
+ /interface\s+TemplateValidatorFunctions\s*<\s*T\s+extends\s+object\s*>\s*\{/u,
654
+ /\bassert\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']assert["']\s*\]/u,
655
+ /\bclone\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']clone["']\s*\]/u,
656
+ /\bis\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']is["']\s*\]/u,
657
+ /\bprune\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']prune["']\s*\]/u,
658
+ /\brandom\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']random["']\s*\]/u,
659
+ /\bvalidate\s*:\s*ScaffoldValidatorToolkitOptions\s*<\s*T\s*>\s*\[\s*["']validate["']\s*\]/u,
660
+ /createTemplateValidatorToolkit\s*<\s*T\s+extends\s+object\s*>\s*\(\s*\{/u,
661
+ ];
662
+ function shouldRefreshCompoundValidatorToolkit(source) {
663
+ return (source === null ||
664
+ !COMPATIBLE_COMPOUND_TOOLKIT_PATTERNS.every((pattern) => pattern.test(source)));
665
+ }
666
+ function isLegacyCompoundValidatorSource(source) {
667
+ return (typeof source === "string" &&
668
+ LEGACY_VALIDATOR_TOOLKIT_IMPORT_PATTERN.test(source) &&
669
+ !LEGACY_ASSERT_PATTERN.test(source));
670
+ }
671
+ function hasTypiaImport(source) {
672
+ return TYPIA_IMPORT_PATTERN.test(source.replace(/\/\*[\s\S]*?\*\//gu, ""));
673
+ }
674
+ function upgradeLegacyCompoundValidatorSource(source) {
675
+ const typeNameMatch = source.match(LEGACY_TOOLKIT_CALL_PATTERN);
676
+ const typeName = typeNameMatch?.groups?.typeName;
677
+ if (!typeName) {
678
+ throw new Error("Unable to upgrade a legacy compound validator without a generated type import.");
679
+ }
680
+ let nextSource = source;
681
+ if (!hasTypiaImport(nextSource)) {
682
+ nextSource = `import typia from 'typia';\n${nextSource}`;
683
+ }
684
+ nextSource = nextSource.replace(LEGACY_TOOLKIT_CALL_PATTERN, [
685
+ `createTemplateValidatorToolkit< ${typeName} >( {`,
686
+ `\tassert: typia.createAssert< ${typeName} >(),`,
687
+ `\tclone: typia.misc.createClone< ${typeName} >() as (`,
688
+ `\t\tvalue: ${typeName},`,
689
+ `\t) => ${typeName},`,
690
+ `\tis: typia.createIs< ${typeName} >(),`,
691
+ ].join("\n") + "\n");
692
+ const replacedManifest = nextSource.replace(LEGACY_MANIFEST_PATTERN, [
693
+ "",
694
+ "\tmanifest: currentManifest,",
695
+ `\tprune: typia.misc.createPrune< ${typeName} >(),`,
696
+ `\trandom: typia.createRandom< ${typeName} >() as (`,
697
+ "\t\t...args: unknown[]",
698
+ `\t) => ${typeName},`,
699
+ `\tvalidate: typia.createValidate< ${typeName} >(),`,
700
+ ].join("\n"));
701
+ if (replacedManifest === nextSource) {
702
+ throw new Error("Unable to upgrade legacy compound validator: manifest anchor not found.");
703
+ }
704
+ return replacedManifest;
705
+ }
706
+ async function collectLegacyCompoundValidatorPaths(projectDir) {
707
+ const blocksDir = path.join(projectDir, "src", "blocks");
708
+ if (!fs.existsSync(blocksDir)) {
709
+ return [];
710
+ }
711
+ const blockEntries = await fsp.readdir(blocksDir, { withFileTypes: true });
712
+ const validatorPaths = await Promise.all(blockEntries
713
+ .filter((entry) => entry.isDirectory())
714
+ .map(async (entry) => {
715
+ const validatorPath = path.join(blocksDir, entry.name, "validators.ts");
716
+ const validatorSource = await readOptionalFile(validatorPath);
717
+ return isLegacyCompoundValidatorSource(validatorSource) ? validatorPath : null;
718
+ }));
719
+ return validatorPaths.filter((validatorPath) => validatorPath !== null);
720
+ }
721
+ async function ensureCompoundWorkspaceSupportFiles(projectDir, tempProjectDir, legacyValidatorPaths) {
722
+ for (const fileName of COMPOUND_SHARED_SUPPORT_FILES) {
723
+ const sourcePath = path.join(tempProjectDir, "src", fileName);
724
+ if (!fs.existsSync(sourcePath)) {
725
+ continue;
726
+ }
727
+ const targetPath = path.join(projectDir, "src", fileName);
728
+ const currentSource = await readOptionalFile(targetPath);
729
+ if (fileName === "validator-toolkit.ts"
730
+ ? shouldRefreshCompoundValidatorToolkit(currentSource)
731
+ : currentSource === null) {
732
+ await fsp.mkdir(path.dirname(targetPath), { recursive: true });
733
+ await fsp.copyFile(sourcePath, targetPath);
734
+ }
735
+ }
736
+ for (const validatorPath of legacyValidatorPaths) {
737
+ const currentSource = await readOptionalFile(validatorPath);
738
+ if (!isLegacyCompoundValidatorSource(currentSource)) {
739
+ continue;
740
+ }
741
+ await fsp.writeFile(validatorPath, upgradeLegacyCompoundValidatorSource(currentSource), "utf8");
742
+ }
743
+ }
744
+ async function copyScaffoldedBlockSlice(projectDir, templateId, tempProjectDir, variables, legacyValidatorPaths = []) {
647
745
  if (templateId === "compound") {
746
+ await ensureCompoundWorkspaceSupportFiles(projectDir, tempProjectDir, legacyValidatorPaths);
648
747
  await copyTempDirectory(path.join(tempProjectDir, "src", "blocks", variables.slugKebabCase), path.join(projectDir, "src", "blocks", variables.slugKebabCase));
649
748
  await copyTempDirectory(path.join(tempProjectDir, "src", "blocks", `${variables.slugKebabCase}-item`), path.join(projectDir, "src", "blocks", `${variables.slugKebabCase}-item`));
650
749
  if (variables.compoundPersistenceEnabled === "true") {
@@ -809,6 +908,12 @@ export async function runAddBlockCommand({ blockName, cwd = process.cwd(), dataS
809
908
  const blockPhpPrefix = buildWorkspacePhpPrefix(workspace.workspace.phpPrefix, normalizedSlug);
810
909
  const migrationConfigSource = await readOptionalFile(migrationConfigPath);
811
910
  const migrationConfig = migrationConfigSource === null ? null : parseMigrationConfig(migrationConfigSource);
911
+ const compoundSupportPaths = resolvedTemplateId === "compound"
912
+ ? COMPOUND_SHARED_SUPPORT_FILES.map((fileName) => path.join(workspace.projectDir, "src", fileName))
913
+ : [];
914
+ const legacyCompoundValidatorPaths = resolvedTemplateId === "compound"
915
+ ? await collectLegacyCompoundValidatorPaths(workspace.projectDir)
916
+ : [];
812
917
  const result = await scaffoldProject({
813
918
  answers: {
814
919
  ...defaults,
@@ -829,14 +934,19 @@ export async function runAddBlockCommand({ blockName, cwd = process.cwd(), dataS
829
934
  });
830
935
  assertBlockTargetsDoNotExist(workspace.projectDir, resolvedTemplateId, result.variables);
831
936
  const mutationSnapshot = {
832
- fileSources: await snapshotWorkspaceFiles([blockConfigPath, migrationConfigPath]),
937
+ fileSources: await snapshotWorkspaceFiles([
938
+ blockConfigPath,
939
+ migrationConfigPath,
940
+ ...compoundSupportPaths,
941
+ ...legacyCompoundValidatorPaths,
942
+ ]),
833
943
  snapshotDirs: migrationConfig === null
834
944
  ? []
835
945
  : buildMigrationBlocks(resolvedTemplateId, result.variables).map((block) => path.join(workspace.projectDir, ...migrationConfig.snapshotDir.split("/"), migrationConfig.currentMigrationVersion, block.key)),
836
946
  targetPaths: collectWorkspaceBlockPaths(workspace.projectDir, resolvedTemplateId, result.variables),
837
947
  };
838
948
  try {
839
- await copyScaffoldedBlockSlice(workspace.projectDir, resolvedTemplateId, tempProjectDir, result.variables);
949
+ await copyScaffoldedBlockSlice(workspace.projectDir, resolvedTemplateId, tempProjectDir, result.variables, legacyCompoundValidatorPaths);
840
950
  await addCollectionImportsForTemplate(workspace.projectDir, resolvedTemplateId, result.variables);
841
951
  await appendBlockConfigEntries(workspace.projectDir, buildConfigEntries(resolvedTemplateId, result.variables), resolvedTemplateId === "persistence" ||
842
952
  (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.4",
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 =