create-carlonicora-app 1.0.0

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 (149) hide show
  1. package/LICENSE +675 -0
  2. package/README.md +104 -0
  3. package/bin/cli.js +3 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +92 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/git.d.ts +7 -0
  9. package/dist/git.d.ts.map +1 -0
  10. package/dist/git.js +80 -0
  11. package/dist/git.js.map +1 -0
  12. package/dist/index.d.ts +5 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +5 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/prompts.d.ts +5 -0
  17. package/dist/prompts.d.ts.map +1 -0
  18. package/dist/prompts.js +30 -0
  19. package/dist/prompts.js.map +1 -0
  20. package/dist/replacer.d.ts +9 -0
  21. package/dist/replacer.d.ts.map +1 -0
  22. package/dist/replacer.js +11 -0
  23. package/dist/replacer.js.map +1 -0
  24. package/dist/scaffold.d.ts +3 -0
  25. package/dist/scaffold.d.ts.map +1 -0
  26. package/dist/scaffold.js +79 -0
  27. package/dist/scaffold.js.map +1 -0
  28. package/dist/types/index.d.ts +16 -0
  29. package/dist/types/index.d.ts.map +1 -0
  30. package/dist/types/index.js +2 -0
  31. package/dist/types/index.js.map +1 -0
  32. package/dist/utils/files.d.ts +6 -0
  33. package/dist/utils/files.d.ts.map +1 -0
  34. package/dist/utils/files.js +103 -0
  35. package/dist/utils/files.js.map +1 -0
  36. package/dist/utils/logger.d.ts +12 -0
  37. package/dist/utils/logger.d.ts.map +1 -0
  38. package/dist/utils/logger.js +35 -0
  39. package/dist/utils/logger.js.map +1 -0
  40. package/dist/utils/validation.d.ts +6 -0
  41. package/dist/utils/validation.d.ts.map +1 -0
  42. package/dist/utils/validation.js +63 -0
  43. package/dist/utils/validation.js.map +1 -0
  44. package/package.json +52 -0
  45. package/template/.env.example +159 -0
  46. package/template/.github/workflows/check-library-updates.yml +71 -0
  47. package/template/.github/workflows/dev.yml +63 -0
  48. package/template/.github/workflows/pull-request.yml +55 -0
  49. package/template/.gitmodules +6 -0
  50. package/template/.husky/pre-commit +1 -0
  51. package/template/.husky/pre-push +1 -0
  52. package/template/.prettierignore +1 -0
  53. package/template/.prettierrc +13 -0
  54. package/template/.releaserc +134 -0
  55. package/template/.vscode/settings.json +16 -0
  56. package/template/CHANGELOG.md +0 -0
  57. package/template/CLAUDE.md +34 -0
  58. package/template/DOCKER.md +1591 -0
  59. package/template/Dockerfile +228 -0
  60. package/template/README.md +1 -0
  61. package/template/apps/api/.prettierrc +12 -0
  62. package/template/apps/api/eslint.config.mjs +54 -0
  63. package/template/apps/api/jest.config.js +29 -0
  64. package/template/apps/api/nest-cli.json +15 -0
  65. package/template/apps/api/package.json +155 -0
  66. package/template/apps/api/src/config/config.ts +17 -0
  67. package/template/apps/api/src/config/enums/job.name.ts +6 -0
  68. package/template/apps/api/src/config/enums/queue.id.ts +3 -0
  69. package/template/apps/api/src/config/interfaces/config.interface.ts +3 -0
  70. package/template/apps/api/src/features/features.modules.ts +6 -0
  71. package/template/apps/api/src/i18n/en/notifications.json +3 -0
  72. package/template/apps/api/src/main.ts +23 -0
  73. package/template/apps/api/src/neo4j.migrations/20250901_001.ts +33 -0
  74. package/template/apps/api/src/neo4j.migrations/20250901_002.ts +90 -0
  75. package/template/apps/api/src/neo4j.migrations/20250901_003.ts +57 -0
  76. package/template/apps/api/src/neo4j.migrations/20250901_004.ts +32 -0
  77. package/template/apps/api/src/neo4j.migrations/queries/migration.queries.ts +49 -0
  78. package/template/apps/api/src/types/langchain.d.ts +56 -0
  79. package/template/apps/api/tsconfig.build.json +4 -0
  80. package/template/apps/api/tsconfig.json +38 -0
  81. package/template/apps/web/.swcrc +26 -0
  82. package/template/apps/web/components.json +21 -0
  83. package/template/apps/web/eslint.config.mjs +33 -0
  84. package/template/apps/web/global.d.ts +7 -0
  85. package/template/apps/web/messages/en.json +249 -0
  86. package/template/apps/web/next.config.js +50 -0
  87. package/template/apps/web/package.json +146 -0
  88. package/template/apps/web/playwright.config.ts +86 -0
  89. package/template/apps/web/postcss.config.mjs +5 -0
  90. package/template/apps/web/public/sw.js +32 -0
  91. package/template/apps/web/src/app/[locale]/(admin)/administration/companies/[id]/page.tsx +46 -0
  92. package/template/apps/web/src/app/[locale]/(admin)/administration/companies/page.tsx +23 -0
  93. package/template/apps/web/src/app/[locale]/(admin)/layout.tsx +49 -0
  94. package/template/apps/web/src/app/[locale]/(auth)/activation/[code]/page.tsx +13 -0
  95. package/template/apps/web/src/app/[locale]/(auth)/auth/page.tsx +11 -0
  96. package/template/apps/web/src/app/[locale]/(auth)/invitation/[code]/page.tsx +7 -0
  97. package/template/apps/web/src/app/[locale]/(auth)/layout.tsx +9 -0
  98. package/template/apps/web/src/app/[locale]/(auth)/login/page.tsx +6 -0
  99. package/template/apps/web/src/app/[locale]/(auth)/logout/page.tsx +5 -0
  100. package/template/apps/web/src/app/[locale]/(auth)/register/page.tsx +6 -0
  101. package/template/apps/web/src/app/[locale]/(auth)/reset/[code]/page.tsx +7 -0
  102. package/template/apps/web/src/app/[locale]/(main)/(foundations)/notifications/page.tsx +9 -0
  103. package/template/apps/web/src/app/[locale]/(main)/(foundations)/roles/[id]/page.tsx +23 -0
  104. package/template/apps/web/src/app/[locale]/(main)/(foundations)/roles/page.tsx +12 -0
  105. package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/error.tsx +14 -0
  106. package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/loading.tsx +21 -0
  107. package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/page.tsx +46 -0
  108. package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/page.tsx +17 -0
  109. package/template/apps/web/src/app/[locale]/(main)/error.tsx +62 -0
  110. package/template/apps/web/src/app/[locale]/(main)/layout.tsx +40 -0
  111. package/template/apps/web/src/app/[locale]/(main)/page.tsx +41 -0
  112. package/template/apps/web/src/app/[locale]/layout.tsx +54 -0
  113. package/template/apps/web/src/app/globals.css +256 -0
  114. package/template/apps/web/src/config/BootstrapProvider.tsx +13 -0
  115. package/template/apps/web/src/config/Bootstrapper.ts +77 -0
  116. package/template/apps/web/src/config/env.ts +51 -0
  117. package/template/apps/web/src/config/middleware-env.ts +14 -0
  118. package/template/apps/web/src/enums/feature.ids.ts +3 -0
  119. package/template/apps/web/src/features/common/components/containers/IndexContainer.tsx +11 -0
  120. package/template/apps/web/src/features/common/components/details/LayoutDetails.tsx +33 -0
  121. package/template/apps/web/src/features/common/components/navigations/CommonSidebar.tsx +233 -0
  122. package/template/apps/web/src/features/common/components/navigations/CreationDropDown.tsx +117 -0
  123. package/template/apps/web/src/features/common/components/navigations/UserSidebarFooter.tsx +115 -0
  124. package/template/apps/web/src/features/common/components/navigations/VersionDisplay.tsx +18 -0
  125. package/template/apps/web/src/features/common/contexts/ErrorContext.tsx +62 -0
  126. package/template/apps/web/src/i18n/request.ts +13 -0
  127. package/template/apps/web/src/i18n/routing.ts +9 -0
  128. package/template/apps/web/src/i18n/useDateFnsLocale.ts +15 -0
  129. package/template/apps/web/src/proxy.ts +107 -0
  130. package/template/apps/web/src/server-actions/auth-cookies.ts +134 -0
  131. package/template/apps/web/src/types/modules.d.ts +10 -0
  132. package/template/apps/web/src/utils/metadata.ts +50 -0
  133. package/template/apps/web/src/utils/revalidation.ts +7 -0
  134. package/template/apps/web/tsconfig.json +51 -0
  135. package/template/docker-compose.yml +211 -0
  136. package/template/package.json +72 -0
  137. package/template/packages/nestjs-neo4jsonapi/.gitkeep +0 -0
  138. package/template/packages/nextjs-jsonapi/.gitkeep +0 -0
  139. package/template/packages/shared/package.json +23 -0
  140. package/template/packages/shared/src/const/roles.id.ts +5 -0
  141. package/template/packages/shared/src/const/system.roles.id.ts +4 -0
  142. package/template/packages/shared/src/index.ts +1 -0
  143. package/template/packages/shared/tsconfig.json +10 -0
  144. package/template/packages/shared/tsup.config.ts +16 -0
  145. package/template/pnpm-workspace.yaml +3 -0
  146. package/template/tsconfig.base.json +62 -0
  147. package/template/tsconfig.json +12 -0
  148. package/template/turbo.json +88 -0
  149. package/template/versions.production.json +4 -0
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # create-carlonicora-app
2
+
3
+ CLI tool to scaffold a new NestJS + Next.js monorepo project with Neo4j and JSON:API.
4
+
5
+ ## Usage
6
+
7
+ ### With npx (recommended)
8
+
9
+ ```bash
10
+ npx create-carlonicora-app my-project
11
+ ```
12
+
13
+ ### With global installation
14
+
15
+ ```bash
16
+ npm install -g create-carlonicora-app
17
+ create-carlonicora-app my-project
18
+ ```
19
+
20
+ ### Options
21
+
22
+ ```bash
23
+ create-carlonicora-app [project-name] [options]
24
+
25
+ Options:
26
+ --skip-git Skip git initialization and submodules
27
+ --skip-install Skip dependency installation
28
+ -V, --version Output version number
29
+ -h, --help Display help
30
+ ```
31
+
32
+ ## What's Included
33
+
34
+ The generated project includes:
35
+
36
+ - **apps/api** - NestJS 11 backend with:
37
+ - Fastify HTTP server
38
+ - Neo4j graph database integration
39
+ - BullMQ job processing
40
+ - JWT authentication
41
+ - JSON:API standard compliance
42
+ - OpenTelemetry observability
43
+ - LangChain AI integration
44
+
45
+ - **apps/web** - Next.js 16 frontend with:
46
+ - React 19
47
+ - Tailwind CSS 4
48
+ - shadcn/ui components
49
+ - next-intl internationalization
50
+ - JSON:API client
51
+
52
+ - **packages/shared** - Shared types and constants
53
+
54
+ - **Git submodules**:
55
+ - `@carlonicora/nestjs-neo4jsonapi`
56
+ - `@carlonicora/nextjs-jsonapi`
57
+
58
+ ## Prerequisites
59
+
60
+ - Node.js 18+
61
+ - pnpm 10+
62
+ - Git
63
+
64
+ ## After Scaffolding
65
+
66
+ ```bash
67
+ cd my-project
68
+ cp .env.example .env
69
+ # Edit .env with your configuration
70
+ pnpm dev
71
+ ```
72
+
73
+ ## Development
74
+
75
+ ### Building the CLI
76
+
77
+ ```bash
78
+ pnpm install
79
+ pnpm build
80
+ ```
81
+
82
+ ### Syncing template from source
83
+
84
+ ```bash
85
+ pnpm sync-template
86
+ ```
87
+
88
+ ### Testing locally
89
+
90
+ ```bash
91
+ # Build first
92
+ pnpm build
93
+
94
+ # Test with node directly
95
+ node bin/cli.js test-project
96
+
97
+ # Or link globally
98
+ npm link
99
+ create-carlonicora-app test-project
100
+ ```
101
+
102
+ ## License
103
+
104
+ GPL-3.0 - See [LICENSE](LICENSE) for details.
package/bin/cli.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../dist/cli.js');
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,92 @@
1
+ import { Command } from 'commander';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import { validateProjectName } from './utils/validation.js';
5
+ import { directoryExists, directoryIsEmpty } from './utils/files.js';
6
+ import { checkGitInstalled, checkPnpmInstalled } from './git.js';
7
+ import { promptProjectName, promptOverwrite, promptContinueWithoutGit, promptContinueWithoutPnpm, } from './prompts.js';
8
+ import { scaffold } from './scaffold.js';
9
+ const program = new Command();
10
+ program
11
+ .name('create-carlonicora-app')
12
+ .description('Create a new NestJS + Next.js monorepo project with Neo4j and JSON:API')
13
+ .version('1.0.0')
14
+ .argument('[project-name]', 'Name of the project')
15
+ .option('--skip-git', 'Skip git initialization and submodules')
16
+ .option('--skip-install', 'Skip dependency installation')
17
+ .action(async (projectName, options) => {
18
+ console.log();
19
+ console.log(chalk.bold.cyan('create-carlonicora-app'));
20
+ console.log(chalk.gray('Creating a new NestJS + Next.js monorepo project'));
21
+ console.log();
22
+ try {
23
+ // 1. Get project name (from argument or prompt)
24
+ let name = projectName;
25
+ if (!name) {
26
+ name = await promptProjectName();
27
+ }
28
+ else {
29
+ const validation = validateProjectName(name);
30
+ if (!validation.valid) {
31
+ console.error(chalk.red(`Error: ${validation.message}`));
32
+ process.exit(1);
33
+ }
34
+ }
35
+ // 2. Determine target directory
36
+ const targetDir = path.resolve(process.cwd(), name);
37
+ // 3. Check if directory exists and is not empty
38
+ if (await directoryExists(targetDir)) {
39
+ if (!(await directoryIsEmpty(targetDir))) {
40
+ const overwrite = await promptOverwrite(name);
41
+ if (!overwrite) {
42
+ console.log(chalk.yellow('Aborted.'));
43
+ process.exit(0);
44
+ }
45
+ }
46
+ }
47
+ // 4. Check prerequisites
48
+ let skipGit = options.skipGit ?? false;
49
+ let skipInstall = options.skipInstall ?? false;
50
+ if (!skipGit && !checkGitInstalled()) {
51
+ console.log(chalk.yellow('Warning: Git is not installed.'));
52
+ const continueWithoutGit = await promptContinueWithoutGit();
53
+ if (continueWithoutGit) {
54
+ skipGit = true;
55
+ }
56
+ else {
57
+ console.log(chalk.yellow('Aborted. Please install git first.'));
58
+ process.exit(0);
59
+ }
60
+ }
61
+ if (!skipInstall && !checkPnpmInstalled()) {
62
+ console.log(chalk.yellow('Warning: pnpm is not installed.'));
63
+ const continueWithoutPnpm = await promptContinueWithoutPnpm();
64
+ if (continueWithoutPnpm) {
65
+ skipInstall = true;
66
+ }
67
+ else {
68
+ console.log(chalk.yellow('Aborted. Please install pnpm first.'));
69
+ process.exit(0);
70
+ }
71
+ }
72
+ // 5. Run scaffold
73
+ await scaffold({
74
+ projectName: name,
75
+ targetDir,
76
+ skipGit,
77
+ skipInstall,
78
+ });
79
+ }
80
+ catch (error) {
81
+ console.error();
82
+ if (error instanceof Error) {
83
+ console.error(chalk.red('Error:'), error.message);
84
+ }
85
+ else {
86
+ console.error(chalk.red('An unexpected error occurred'));
87
+ }
88
+ process.exit(1);
89
+ }
90
+ });
91
+ program.parse();
92
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACjE,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAOzC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,wBAAwB,CAAC;KAC9B,WAAW,CAAC,wEAAwE,CAAC;KACrF,OAAO,CAAC,OAAO,CAAC;KAChB,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC;KACjD,MAAM,CAAC,YAAY,EAAE,wCAAwC,CAAC;KAC9D,MAAM,CAAC,gBAAgB,EAAE,8BAA8B,CAAC;KACxD,MAAM,CAAC,KAAK,EAAE,WAA+B,EAAE,OAAmB,EAAE,EAAE;IACrE,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,IAAI,CAAC;QACH,gDAAgD;QAChD,IAAI,IAAI,GAAG,WAAW,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,MAAM,iBAAiB,EAAE,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;QAEpD,gDAAgD;QAChD,IAAI,MAAM,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,CAAC,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;gBACzC,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;gBAC9C,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;oBACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;YACH,CAAC;QACH,CAAC;QAED,yBAAyB;QACzB,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;QACvC,IAAI,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC;QAE/C,IAAI,CAAC,OAAO,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC,CAAC;YAC5D,MAAM,kBAAkB,GAAG,MAAM,wBAAwB,EAAE,CAAC;YAC5D,IAAI,kBAAkB,EAAE,CAAC;gBACvB,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,oCAAoC,CAAC,CAAC,CAAC;gBAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,IAAI,CAAC,WAAW,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,iCAAiC,CAAC,CAAC,CAAC;YAC7D,MAAM,mBAAmB,GAAG,MAAM,yBAAyB,EAAE,CAAC;YAC9D,IAAI,mBAAmB,EAAE,CAAC;gBACxB,WAAW,GAAG,IAAI,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,qCAAqC,CAAC,CAAC,CAAC;gBACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,kBAAkB;QAClB,MAAM,QAAQ,CAAC;YACb,WAAW,EAAE,IAAI;YACjB,SAAS;YACT,OAAO;YACP,WAAW;SACZ,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC;QAC3D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export declare function initGit(targetDir: string): Promise<void>;
2
+ export declare function addSubmodules(targetDir: string): Promise<void>;
3
+ export declare function installDependencies(targetDir: string): Promise<void>;
4
+ export declare function checkGitInstalled(): boolean;
5
+ export declare function checkPnpmInstalled(): boolean;
6
+ export declare function createInitialCommit(targetDir: string): Promise<void>;
7
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAOA,wBAAsB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCpE;AAED,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAO5C;AAED,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU1E"}
package/dist/git.js ADDED
@@ -0,0 +1,80 @@
1
+ import { execSync, exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import fs from 'fs-extra';
4
+ import path from 'path';
5
+ const execAsync = promisify(exec);
6
+ export async function initGit(targetDir) {
7
+ execSync('git init', { cwd: targetDir, stdio: 'pipe' });
8
+ }
9
+ export async function addSubmodules(targetDir) {
10
+ const submodules = [
11
+ {
12
+ path: 'packages/nestjs-neo4jsonapi',
13
+ url: 'https://github.com/carlonicora/nestjs-neo4jsonapi',
14
+ },
15
+ {
16
+ path: 'packages/nextjs-jsonapi',
17
+ url: 'https://github.com/carlonicora/nextjs-jsonapi',
18
+ },
19
+ ];
20
+ for (const submodule of submodules) {
21
+ // Remove placeholder directory if it exists (contains .gitkeep)
22
+ const submodulePath = path.join(targetDir, submodule.path);
23
+ if (await fs.pathExists(submodulePath)) {
24
+ await fs.remove(submodulePath);
25
+ }
26
+ try {
27
+ execSync(`git submodule add ${submodule.url} ${submodule.path}`, {
28
+ cwd: targetDir,
29
+ stdio: 'pipe',
30
+ });
31
+ }
32
+ catch (error) {
33
+ // If submodule already exists, continue
34
+ const errorMessage = error instanceof Error ? error.message : String(error);
35
+ if (!errorMessage.includes('already exists')) {
36
+ throw error;
37
+ }
38
+ }
39
+ }
40
+ // Initialize submodules
41
+ execSync('git submodule update --init --recursive', {
42
+ cwd: targetDir,
43
+ stdio: 'pipe',
44
+ });
45
+ }
46
+ export async function installDependencies(targetDir) {
47
+ // Use inherit for stdio so user can see the install progress
48
+ execSync('pnpm install', { cwd: targetDir, stdio: 'inherit' });
49
+ }
50
+ export function checkGitInstalled() {
51
+ try {
52
+ execSync('git --version', { stdio: 'pipe' });
53
+ return true;
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ }
59
+ export function checkPnpmInstalled() {
60
+ try {
61
+ execSync('pnpm --version', { stdio: 'pipe' });
62
+ return true;
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ export async function createInitialCommit(targetDir) {
69
+ try {
70
+ execSync('git add .', { cwd: targetDir, stdio: 'pipe' });
71
+ execSync('git commit -m "Initial commit from create-carlonicora-app"', {
72
+ cwd: targetDir,
73
+ stdio: 'pipe',
74
+ });
75
+ }
76
+ catch {
77
+ // Commit might fail if nothing to commit, which is fine
78
+ }
79
+ }
80
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { scaffold } from './scaffold.js';
2
+ export { validateProjectName, toKebabCase, toPascalCase } from './utils/validation.js';
3
+ export { applyReplacements } from './replacer.js';
4
+ export type { ScaffoldOptions, ReplacementConfig, ValidationResult } from './types/index.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // Main entry point - re-exports for programmatic usage
2
+ export { scaffold } from './scaffold.js';
3
+ export { validateProjectName, toKebabCase, toPascalCase } from './utils/validation.js';
4
+ export { applyReplacements } from './replacer.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function promptProjectName(): Promise<string>;
2
+ export declare function promptOverwrite(dirName: string): Promise<boolean>;
3
+ export declare function promptContinueWithoutGit(): Promise<boolean>;
4
+ export declare function promptContinueWithoutPnpm(): Promise<boolean>;
5
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAGA,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQzD;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAKvE;AAED,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,OAAO,CAAC,CAKjE;AAED,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,OAAO,CAAC,CAKlE"}
@@ -0,0 +1,30 @@
1
+ import { input, confirm } from '@inquirer/prompts';
2
+ import { validateProjectName } from './utils/validation.js';
3
+ export async function promptProjectName() {
4
+ return input({
5
+ message: 'What is your project name?',
6
+ validate: (value) => {
7
+ const result = validateProjectName(value);
8
+ return result.valid || result.message;
9
+ },
10
+ });
11
+ }
12
+ export async function promptOverwrite(dirName) {
13
+ return confirm({
14
+ message: `Directory "${dirName}" already exists and is not empty. Overwrite?`,
15
+ default: false,
16
+ });
17
+ }
18
+ export async function promptContinueWithoutGit() {
19
+ return confirm({
20
+ message: 'Git is not installed. Continue without git initialization?',
21
+ default: true,
22
+ });
23
+ }
24
+ export async function promptContinueWithoutPnpm() {
25
+ return confirm({
26
+ message: 'pnpm is not installed. Continue without dependency installation?',
27
+ default: true,
28
+ });
29
+ }
30
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,OAAO,KAAK,CAAC;QACX,OAAO,EAAE,4BAA4B;QACrC,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;YAC1B,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC1C,OAAO,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,OAAQ,CAAC;QACzC,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe;IACnD,OAAO,OAAO,CAAC;QACb,OAAO,EAAE,cAAc,OAAO,+CAA+C;QAC7E,OAAO,EAAE,KAAK;KACf,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,OAAO,OAAO,CAAC;QACb,OAAO,EAAE,4DAA4D;QACrE,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB;IAC7C,OAAO,OAAO,CAAC;QACb,OAAO,EAAE,kEAAkE;QAC3E,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ReplacementConfig } from './types/index.js';
2
+ /**
3
+ * Replaces {{name}} placeholders with the actual project name.
4
+ *
5
+ * The template files use {{name}} as a placeholder which gets replaced
6
+ * with the user's chosen project name during scaffolding.
7
+ */
8
+ export declare function applyReplacements(content: string, config: ReplacementConfig): string;
9
+ //# sourceMappingURL=replacer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replacer.d.ts","sourceRoot":"","sources":["../src/replacer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAGpF"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Replaces {{name}} placeholders with the actual project name.
3
+ *
4
+ * The template files use {{name}} as a placeholder which gets replaced
5
+ * with the user's chosen project name during scaffolding.
6
+ */
7
+ export function applyReplacements(content, config) {
8
+ // Simple replacement of {{name}} placeholder with project name
9
+ return content.split('{{name}}').join(config.projectNameKebab);
10
+ }
11
+ //# sourceMappingURL=replacer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replacer.js","sourceRoot":"","sources":["../src/replacer.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,MAAyB;IAC1E,+DAA+D;IAC/D,OAAO,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ScaffoldOptions } from './types/index.js';
2
+ export declare function scaffold(options: ScaffoldOptions): Promise<void>;
3
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,kBAAkB,CAAC;AAS3E,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA2EtE"}
@@ -0,0 +1,79 @@
1
+ import path from 'path';
2
+ import fs from 'fs-extra';
3
+ import ora from 'ora';
4
+ import { fileURLToPath } from 'url';
5
+ import { copyTemplate, ensureEmptyDir } from './utils/files.js';
6
+ import { toKebabCase, toPascalCase } from './utils/validation.js';
7
+ import { initGit, addSubmodules, installDependencies, createInitialCommit } from './git.js';
8
+ import { printSuccessMessage } from './utils/logger.js';
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+ export async function scaffold(options) {
12
+ const { projectName, targetDir, skipGit, skipInstall } = options;
13
+ const config = {
14
+ projectName,
15
+ projectNameKebab: toKebabCase(projectName),
16
+ projectNamePascal: toPascalCase(projectName),
17
+ };
18
+ const spinner = ora();
19
+ try {
20
+ // Step 1: Create/clean target directory
21
+ spinner.start('Creating project directory...');
22
+ await ensureEmptyDir(targetDir);
23
+ spinner.succeed('Created project directory');
24
+ // Step 2: Copy template files with replacements
25
+ spinner.start('Copying template files...');
26
+ const templateDir = path.join(__dirname, '..', 'template');
27
+ if (!(await fs.pathExists(templateDir))) {
28
+ spinner.fail('Template directory not found');
29
+ throw new Error(`Template directory not found at ${templateDir}. ` +
30
+ 'Please run "npm run sync-template" first.');
31
+ }
32
+ await copyTemplate(templateDir, targetDir, config);
33
+ spinner.succeed('Copied template files');
34
+ // Step 3: Initialize git repository
35
+ if (!skipGit) {
36
+ spinner.start('Initializing git repository...');
37
+ try {
38
+ await initGit(targetDir);
39
+ spinner.succeed('Initialized git repository');
40
+ // Step 4: Add git submodules
41
+ spinner.start('Adding git submodules (this may take a moment)...');
42
+ await addSubmodules(targetDir);
43
+ spinner.succeed('Added git submodules');
44
+ // Create initial commit
45
+ spinner.start('Creating initial commit...');
46
+ await createInitialCommit(targetDir);
47
+ spinner.succeed('Created initial commit');
48
+ }
49
+ catch (error) {
50
+ spinner.warn('Git initialization skipped (git may not be installed)');
51
+ }
52
+ }
53
+ else {
54
+ spinner.info('Skipped git initialization');
55
+ }
56
+ // Step 5: Install dependencies
57
+ if (!skipInstall) {
58
+ spinner.start('Installing dependencies (this may take a few minutes)...');
59
+ spinner.stopAndPersist({ symbol: '📦', text: 'Installing dependencies...' });
60
+ try {
61
+ await installDependencies(targetDir);
62
+ spinner.succeed('Installed dependencies');
63
+ }
64
+ catch (error) {
65
+ spinner.warn('Dependency installation failed. Run "pnpm install" manually.');
66
+ }
67
+ }
68
+ else {
69
+ spinner.info('Skipped dependency installation');
70
+ }
71
+ // Step 6: Print success message
72
+ printSuccessMessage(projectName, targetDir);
73
+ }
74
+ catch (error) {
75
+ spinner.fail('Scaffold failed');
76
+ throw error;
77
+ }
78
+ }
79
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface ScaffoldOptions {
2
+ projectName: string;
3
+ targetDir: string;
4
+ skipGit?: boolean;
5
+ skipInstall?: boolean;
6
+ }
7
+ export interface ReplacementConfig {
8
+ projectName: string;
9
+ projectNameKebab: string;
10
+ projectNamePascal: string;
11
+ }
12
+ export interface ValidationResult {
13
+ valid: boolean;
14
+ message?: string;
15
+ }
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import type { ReplacementConfig } from '../types/index.js';
2
+ export declare function copyTemplate(srcDir: string, destDir: string, config: ReplacementConfig): Promise<void>;
3
+ export declare function ensureEmptyDir(dir: string): Promise<void>;
4
+ export declare function directoryExists(dir: string): Promise<boolean>;
5
+ export declare function directoryIsEmpty(dir: string): Promise<boolean>;
6
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/utils/files.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AA0C3D,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,IAAI,CAAC,CAcf;AAuBD,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/D;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOpE"}
@@ -0,0 +1,103 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { applyReplacements } from '../replacer.js';
4
+ const BINARY_EXTENSIONS = new Set([
5
+ // Images
6
+ '.png',
7
+ '.jpg',
8
+ '.jpeg',
9
+ '.gif',
10
+ '.webp',
11
+ '.ico',
12
+ '.svg',
13
+ '.bmp',
14
+ '.tiff',
15
+ // Fonts
16
+ '.woff',
17
+ '.woff2',
18
+ '.ttf',
19
+ '.eot',
20
+ '.otf',
21
+ // Archives
22
+ '.tar',
23
+ '.zip',
24
+ '.gz',
25
+ '.rar',
26
+ '.7z',
27
+ // Documents
28
+ '.pdf',
29
+ // Lock files (treat as binary to avoid corruption)
30
+ '.lock',
31
+ // Other binary formats
32
+ '.exe',
33
+ '.dll',
34
+ '.so',
35
+ '.dylib',
36
+ ]);
37
+ function isBinaryFile(filePath) {
38
+ const ext = path.extname(filePath).toLowerCase();
39
+ return BINARY_EXTENSIONS.has(ext);
40
+ }
41
+ export async function copyTemplate(srcDir, destDir, config) {
42
+ const entries = await fs.readdir(srcDir, { withFileTypes: true });
43
+ for (const entry of entries) {
44
+ const srcPath = path.join(srcDir, entry.name);
45
+ const destPath = path.join(destDir, entry.name);
46
+ if (entry.isDirectory()) {
47
+ await fs.ensureDir(destPath);
48
+ await copyTemplate(srcPath, destPath, config);
49
+ }
50
+ else {
51
+ await copyFile(srcPath, destPath, config);
52
+ }
53
+ }
54
+ }
55
+ async function copyFile(srcPath, destPath, config) {
56
+ if (isBinaryFile(srcPath)) {
57
+ // Binary file - copy as-is
58
+ await fs.copy(srcPath, destPath);
59
+ }
60
+ else {
61
+ // Text file - apply replacements
62
+ try {
63
+ let content = await fs.readFile(srcPath, 'utf-8');
64
+ content = applyReplacements(content, config);
65
+ await fs.writeFile(destPath, content, 'utf-8');
66
+ }
67
+ catch (error) {
68
+ // If reading as text fails, copy as binary
69
+ await fs.copy(srcPath, destPath);
70
+ }
71
+ }
72
+ }
73
+ export async function ensureEmptyDir(dir) {
74
+ if (await fs.pathExists(dir)) {
75
+ const files = await fs.readdir(dir);
76
+ if (files.length > 0) {
77
+ // Directory exists and is not empty
78
+ await fs.emptyDir(dir);
79
+ }
80
+ }
81
+ else {
82
+ await fs.ensureDir(dir);
83
+ }
84
+ }
85
+ export async function directoryExists(dir) {
86
+ try {
87
+ const stat = await fs.stat(dir);
88
+ return stat.isDirectory();
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ export async function directoryIsEmpty(dir) {
95
+ try {
96
+ const files = await fs.readdir(dir);
97
+ return files.length === 0;
98
+ }
99
+ catch {
100
+ return true;
101
+ }
102
+ }
103
+ //# sourceMappingURL=files.js.map