tshex-cli 1.0.15 → 1.0.16

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.
Files changed (32) hide show
  1. package/build/main.js +54 -5
  2. package/package.json +1 -1
  3. package/readme.md +27 -3
  4. package/source/main.ts +61 -10
  5. package/templates/ctx/index.ts +0 -9
  6. package/templates/react-context/adapters/hooks/.gitkeep +0 -0
  7. package/templates/react-context/adapters/schemas/.gitkeep +0 -0
  8. package/templates/react-context/application/.gitkeep +0 -0
  9. package/templates/react-context/domain/.gitkeep +0 -0
  10. package/templates/react-context/languages/.gitkeep +0 -0
  11. package/templates/react-project/core/context/adapters/api/.gitkeep +0 -0
  12. package/templates/react-project/core/context/adapters/hooks/.gitkeep +0 -0
  13. package/templates/react-project/core/context/adapters/schemas/.gitkeep +0 -0
  14. package/templates/react-project/core/context/application/.gitkeep +0 -0
  15. package/templates/react-project/core/context/domain/.gitkeep +0 -0
  16. package/templates/react-project/core/context/languages/.gitkeep +0 -0
  17. package/templates/react-project/core/shared/adapters/i18n/.gitkeep +0 -0
  18. package/templates/react-project/dom-client/context/Example.tsx +11 -0
  19. package/templates/react-project/dom-client/context/assets/.gitkeep +0 -0
  20. package/templates/react-project/dom-client/context/styles/.gitkeep +0 -0
  21. package/templates/react-project/dom-server/context/Example.tsx +11 -0
  22. package/templates/react-project/dom-server/context/assets/.gitkeep +0 -0
  23. package/templates/react-project/dom-server/context/styles/.gitkeep +0 -0
  24. package/templates/react-project/index.d.ts +1 -0
  25. package/templates/react-project/native/context/Example.tsx +11 -0
  26. package/templates/react-project/native/context/assets/.gitkeep +0 -0
  27. package/templates/react-project/native/context/styles/.gitkeep +0 -0
  28. package/templates/react-project/tests/core/.gitkeep +0 -0
  29. package/templates/react-project/tests/dom-client/.gitkeep +0 -0
  30. package/templates/react-project/tests/dom-server/.gitkeep +0 -0
  31. package/templates/react-project/tests/native/.gitkeep +0 -0
  32. /package/{source/index.d.ts → templates/react-context/adapters/api/.gitkeep} +0 -0
package/build/main.js CHANGED
@@ -3,13 +3,15 @@ import { program } from 'commander';
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  function readPackageJson() {
6
- return JSON.parse(fs.readFileSync(path.join(import.meta.dirname, '..', 'package.json'), 'utf-8'));
6
+ const filePath = path.join(import.meta.dirname, '..', 'package.json');
7
+ const fileContents = fs.readFileSync(filePath, 'utf-8');
8
+ return JSON.parse(fileContents);
7
9
  }
8
10
  function executeCreateLib(templatesDir, libraryDir) {
9
11
  try {
10
12
  fs.cpSync(path.join(templatesDir, 'lib'), libraryDir, {
11
13
  recursive: true,
12
- filter: (src) => !src.endsWith('.gitkeep')
14
+ filter: (src) => src.endsWith('.gitkeep') === false
13
15
  });
14
16
  console.log('Library created successfully');
15
17
  }
@@ -21,7 +23,7 @@ function executeCreateContext(templatesDir, contextDir) {
21
23
  try {
22
24
  fs.cpSync(path.join(templatesDir, 'ctx'), contextDir, {
23
25
  recursive: true,
24
- filter: (src) => !src.endsWith('.gitkeep')
26
+ filter: (src) => src.endsWith('.gitkeep') === false
25
27
  });
26
28
  console.log('Context created successfully');
27
29
  }
@@ -29,15 +31,52 @@ function executeCreateContext(templatesDir, contextDir) {
29
31
  console.error(err);
30
32
  }
31
33
  }
34
+ function copyDirectoryContents(sourceDir, destinationDir) {
35
+ const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
36
+ for (const entry of entries) {
37
+ const sourcePath = path.join(sourceDir, entry.name);
38
+ const destinationPath = path.join(destinationDir, entry.name);
39
+ if (fs.existsSync(destinationPath) === false) {
40
+ fs.cpSync(sourcePath, destinationPath, {
41
+ recursive: true,
42
+ filter: (src) => src.endsWith('.gitkeep') === false
43
+ });
44
+ }
45
+ }
46
+ }
47
+ function executeCreateReactProject(templatesDir, projectDir) {
48
+ try {
49
+ fs.cpSync(path.join(templatesDir, 'react-project'), projectDir, {
50
+ recursive: true,
51
+ filter: (src) => src.endsWith('.gitkeep') === false
52
+ });
53
+ copyDirectoryContents(path.join(templatesDir, 'lib', 'shared'), path.join(projectDir, 'core', 'shared'));
54
+ console.log('React project created successfully');
55
+ }
56
+ catch (err) {
57
+ console.error(err);
58
+ }
59
+ }
60
+ function executeCreateReactContext(templatesDir, contextDir) {
61
+ try {
62
+ fs.cpSync(path.join(templatesDir, 'react-context'), contextDir, {
63
+ recursive: true,
64
+ filter: (src) => src.endsWith('.gitkeep') === false
65
+ });
66
+ console.log('React context created successfully');
67
+ }
68
+ catch (err) {
69
+ console.error(err);
70
+ }
71
+ }
32
72
  function main(program) {
33
73
  const templatesDir = path.join(import.meta.dirname, '..', 'templates');
34
74
  const options = program.opts();
35
75
  let targetDir = path.resolve(options.dir ?? process.cwd());
36
76
  if (Object.keys(options).length === 0) {
37
77
  program.help();
38
- return;
39
78
  }
40
- if (!fs.existsSync(targetDir)) {
79
+ if (fs.existsSync(targetDir) === false) {
41
80
  fs.mkdirSync(targetDir, { recursive: true });
42
81
  }
43
82
  if (options.lib !== undefined) {
@@ -48,6 +87,14 @@ function main(program) {
48
87
  targetDir = path.join(targetDir, options.ctx);
49
88
  executeCreateContext(templatesDir, targetDir);
50
89
  }
90
+ if (options.reactProject !== undefined) {
91
+ targetDir = path.join(targetDir, options.reactProject);
92
+ executeCreateReactProject(templatesDir, targetDir);
93
+ }
94
+ if (options.reactContext !== undefined) {
95
+ targetDir = path.join(targetDir, options.reactContext);
96
+ executeCreateReactContext(templatesDir, targetDir);
97
+ }
51
98
  }
52
99
  const packageJson = readPackageJson();
53
100
  program
@@ -56,5 +103,7 @@ program
56
103
  .option('--lib <name>', "creates a new library with it's shared directory")
57
104
  .option('--ctx <name>', 'creates a new context')
58
105
  .option('--dir <path>', 'sets the directory to create the new item')
106
+ .option('--react-project <name>', 'creates a new React project')
107
+ .option('--react-context <name>', 'creates a new React context')
59
108
  .parse(process.argv);
60
109
  main(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tshex-cli",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "author": "https://github.com/virtualitems/",
5
5
  "description": "Typescript Hexagonal Architecture CLI",
6
6
  "type": "module",
package/readme.md CHANGED
@@ -20,10 +20,12 @@ https://github.com/virtualitems/tshex-cli/issues
20
20
 
21
21
  `tshex` scaffolds folders and files for a hexagonal architecture project. It does not write business logic for you; it only generates the structure, so you can fill it in with your own code.
22
22
 
23
- There are two things you can generate:
23
+ There are four things you can generate:
24
24
 
25
25
  - A **library** (`--lib`): the shared foundation of a project. It contains the domain and application contracts (entities, value objects, services, etc.) that the rest of the code depends on.
26
26
  - A **context** (`--ctx`): a specific business area (e.g. `users`, `billing`, `orders`). It contains the `domain/`, `application/`, and `adapters/` folders where you implement that area's logic.
27
+ - A **React project** (`--react-project`): a full React-oriented hexagonal structure with `core/`, `dom-client/`, `dom-server/`, and `native/` folders.
28
+ - A **React context** (`--react-context`): a React-ready context scaffold.
27
29
 
28
30
  A typical project has one library and one or more contexts inside it.
29
31
 
@@ -50,18 +52,20 @@ tshex --help
50
52
  ## Usage
51
53
 
52
54
  ```bash
53
- tshex [--lib <name>] [--ctx <name>] [--dir <path>]
55
+ tshex [--lib <name>] [--ctx <name>] [--react-project <name>] [--react-context <name>] [--dir <path>]
54
56
  ```
55
57
 
56
58
  | Option | Purpose |
57
59
  | -------------- | ------------------------------------------------------------------- |
58
60
  | `--lib <name>` | Generate a library called `<name>`, based on `templates/lib`. |
59
61
  | `--ctx <name>` | Generate a context called `<name>`, based on `templates/ctx`. |
62
+ | `--react-project <name>` | Generate a React project called `<name>`, based on `templates/react-project` and `templates/lib/shared`. |
63
+ | `--react-context <name>` | Generate a React context called `<name>`, based on `templates/react-context`. |
60
64
  | `--dir <path>` | Parent directory where the library/context will be created. Defaults to the current directory. |
61
65
  | `--help` | Show the command options. |
62
66
  | `--version` | Show the installed version. |
63
67
 
64
- `--lib` and `--ctx` can be used together in a single command (see [Create a library and a context together](#create-a-library-and-a-context-together)). Running `tshex` without any options just prints the help text — it does not generate anything.
68
+ `--lib`, `--ctx`, `--react-project`, and `--react-context` can be used together in a single command. Running `tshex` without any options just prints the help text — it does not generate anything.
65
69
 
66
70
  ## Create a library
67
71
 
@@ -203,3 +207,23 @@ src/
203
207
  ├── domain/
204
208
  └── index.ts
205
209
  ```
210
+
211
+ ## Create a React project
212
+
213
+ Use this when you want the React-specific project scaffold with the shared `core/shared` contracts copied from the library template:
214
+
215
+ ```bash
216
+ tshex --react-project app
217
+ ```
218
+
219
+ This generates a `app/` folder in the current directory.
220
+
221
+ ## Create a React context
222
+
223
+ Use this when you want only the React context scaffold:
224
+
225
+ ```bash
226
+ tshex --react-context users
227
+ ```
228
+
229
+ This generates a `users/` folder in the current directory.
package/source/main.ts CHANGED
@@ -12,19 +12,16 @@ import path from 'node:path'
12
12
  // FUNCTIONS
13
13
 
14
14
  function readPackageJson() {
15
- return JSON.parse(
16
- fs.readFileSync(
17
- path.join(import.meta.dirname, '..', 'package.json'),
18
- 'utf-8'
19
- )
20
- )
15
+ const filePath = path.join(import.meta.dirname, '..', 'package.json')
16
+ const fileContents = fs.readFileSync(filePath, 'utf-8')
17
+ return JSON.parse(fileContents)
21
18
  }
22
19
 
23
20
  function executeCreateLib(templatesDir: string, libraryDir: string) {
24
21
  try {
25
22
  fs.cpSync(path.join(templatesDir, 'lib'), libraryDir, {
26
23
  recursive: true,
27
- filter: (src) => !src.endsWith('.gitkeep')
24
+ filter: (src) => src.endsWith('.gitkeep') === false
28
25
  })
29
26
  console.log('Library created successfully')
30
27
  } catch (err) {
@@ -36,7 +33,7 @@ function executeCreateContext(templatesDir: string, contextDir: string) {
36
33
  try {
37
34
  fs.cpSync(path.join(templatesDir, 'ctx'), contextDir, {
38
35
  recursive: true,
39
- filter: (src) => !src.endsWith('.gitkeep')
36
+ filter: (src) => src.endsWith('.gitkeep') === false
40
37
  })
41
38
  console.log('Context created successfully')
42
39
  } catch (err) {
@@ -44,6 +41,49 @@ function executeCreateContext(templatesDir: string, contextDir: string) {
44
41
  }
45
42
  }
46
43
 
44
+ function copyDirectoryContents(sourceDir: string, destinationDir: string) {
45
+ const entries = fs.readdirSync(sourceDir, { withFileTypes: true })
46
+
47
+ for (const entry of entries) {
48
+ const sourcePath = path.join(sourceDir, entry.name)
49
+ const destinationPath = path.join(destinationDir, entry.name)
50
+
51
+ if (fs.existsSync(destinationPath) === false) {
52
+ fs.cpSync(sourcePath, destinationPath, {
53
+ recursive: true,
54
+ filter: (src) => src.endsWith('.gitkeep') === false
55
+ })
56
+ }
57
+ }
58
+ }
59
+
60
+ function executeCreateReactProject(templatesDir: string, projectDir: string) {
61
+ try {
62
+ fs.cpSync(path.join(templatesDir, 'react-project'), projectDir, {
63
+ recursive: true,
64
+ filter: (src) => src.endsWith('.gitkeep') === false
65
+ })
66
+
67
+ copyDirectoryContents(path.join(templatesDir, 'lib', 'shared'), path.join(projectDir, 'core', 'shared'))
68
+
69
+ console.log('React project created successfully')
70
+ } catch (err) {
71
+ console.error(err)
72
+ }
73
+ }
74
+
75
+ function executeCreateReactContext(templatesDir: string, contextDir: string) {
76
+ try {
77
+ fs.cpSync(path.join(templatesDir, 'react-context'), contextDir, {
78
+ recursive: true,
79
+ filter: (src) => src.endsWith('.gitkeep') === false
80
+ })
81
+ console.log('React context created successfully')
82
+ } catch (err) {
83
+ console.error(err)
84
+ }
85
+ }
86
+
47
87
  function main(program: typeof import('commander').program) {
48
88
  const templatesDir = path.join(import.meta.dirname, '..', 'templates')
49
89
 
@@ -53,10 +93,9 @@ function main(program: typeof import('commander').program) {
53
93
 
54
94
  if (Object.keys(options).length === 0) {
55
95
  program.help()
56
- return
57
96
  }
58
97
 
59
- if (!fs.existsSync(targetDir)) {
98
+ if (fs.existsSync(targetDir) === false) {
60
99
  fs.mkdirSync(targetDir, { recursive: true })
61
100
  }
62
101
 
@@ -69,6 +108,16 @@ function main(program: typeof import('commander').program) {
69
108
  targetDir = path.join(targetDir, options.ctx)
70
109
  executeCreateContext(templatesDir, targetDir)
71
110
  }
111
+
112
+ if (options.reactProject !== undefined) {
113
+ targetDir = path.join(targetDir, options.reactProject)
114
+ executeCreateReactProject(templatesDir, targetDir)
115
+ }
116
+
117
+ if (options.reactContext !== undefined) {
118
+ targetDir = path.join(targetDir, options.reactContext)
119
+ executeCreateReactContext(templatesDir, targetDir)
120
+ }
72
121
  }
73
122
 
74
123
  const packageJson = readPackageJson()
@@ -79,6 +128,8 @@ program
79
128
  .option('--lib <name>', "creates a new library with it's shared directory")
80
129
  .option('--ctx <name>', 'creates a new context')
81
130
  .option('--dir <path>', 'sets the directory to create the new item')
131
+ .option('--react-project <name>', 'creates a new React project')
132
+ .option('--react-context <name>', 'creates a new React context')
82
133
  .parse(process.argv)
83
134
 
84
135
  main(program)
@@ -1,9 +0,0 @@
1
- // Ports layer
2
-
3
- // Adapters layer
4
-
5
- // Application layer
6
-
7
- // Domain layer
8
-
9
- // Constants
File without changes
File without changes
File without changes
@@ -0,0 +1,11 @@
1
+ type Props = {
2
+ children?: React.ReactNode
3
+ }
4
+
5
+ /**
6
+ * @description Example component that renders its children.
7
+ */
8
+ export default function Example(props: Props) {
9
+ const { children } = props
10
+ return children
11
+ }
@@ -0,0 +1,11 @@
1
+ type Props = {
2
+ children?: React.ReactNode
3
+ }
4
+
5
+ /**
6
+ * @description Example component that renders its children.
7
+ */
8
+ export default function Example(props: Props) {
9
+ const { children } = props
10
+ return children
11
+ }
@@ -0,0 +1 @@
1
+ type Generic<T=unknown> = Record<string, T>;
@@ -0,0 +1,11 @@
1
+ type Props = {
2
+ children?: React.ReactNode
3
+ }
4
+
5
+ /**
6
+ * @description Example component that renders its children.
7
+ */
8
+ export default function Example(props: Props) {
9
+ const { children } = props
10
+ return children
11
+ }
File without changes
File without changes