@jakubmazanec/carson 0.1.0-c5ebb6f → 0.1.0-next.336fe21

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 (225) hide show
  1. package/README.md +65 -10
  2. package/dist/commands/create-project/CreateProject.js.map +1 -1
  3. package/dist/commands/create-project/CreateProjectInput.js +1 -1
  4. package/dist/commands/create-project/CreateProjectInput.js.map +1 -1
  5. package/dist/commands/create-project/createProjectCommand.js +3 -4
  6. package/dist/commands/create-project/createProjectCommand.js.map +1 -1
  7. package/dist/commands/create-project/runCreateProject.js +3 -13
  8. package/dist/commands/create-project/runCreateProject.js.map +1 -1
  9. package/dist/commands/create-workspace/CreateWorkspace.d.ts +1 -2
  10. package/dist/commands/create-workspace/CreateWorkspace.js +7 -5
  11. package/dist/commands/create-workspace/CreateWorkspace.js.map +1 -1
  12. package/dist/commands/create-workspace/createWorkspaceCommand.js +1 -11
  13. package/dist/commands/create-workspace/createWorkspaceCommand.js.map +1 -1
  14. package/dist/commands/create-workspace/runCreateWorkspace.js +3 -12
  15. package/dist/commands/create-workspace/runCreateWorkspace.js.map +1 -1
  16. package/dist/commands/internals/CommandStatus.d.ts +1 -0
  17. package/dist/commands/internals/CommandStatus.js +3 -0
  18. package/dist/commands/internals/CommandStatus.js.map +1 -0
  19. package/dist/commands/internals.d.ts +1 -0
  20. package/dist/commands/internals.js +1 -0
  21. package/dist/commands/internals.js.map +1 -1
  22. package/dist/commands/update-workspace/UpdateWorkspace.js +1 -1
  23. package/dist/commands/update-workspace/UpdateWorkspace.js.map +1 -1
  24. package/dist/commands/update-workspace/updateWorkspaceCommand.js +3 -4
  25. package/dist/commands/update-workspace/updateWorkspaceCommand.js.map +1 -1
  26. package/dist/template/CarsonTemplate.d.ts +1 -1
  27. package/dist/template/CarsonTemplate.js.map +1 -1
  28. package/dist/template/CarsonTemplateConfig.d.ts +1 -1
  29. package/dist/template/CarsonTemplateConfig.js.map +1 -1
  30. package/dist/template/CarsonTemplateError.d.ts +8 -0
  31. package/dist/template/CarsonTemplateError.js +13 -0
  32. package/dist/template/CarsonTemplateError.js.map +1 -0
  33. package/dist/template/TemplateAttributes.d.ts +3 -3
  34. package/dist/template/TemplateAttributes.js +2 -1
  35. package/dist/template/TemplateAttributes.js.map +1 -1
  36. package/dist/template/TemplateRender.d.ts +6 -2
  37. package/dist/template/TemplateRender.js.map +1 -1
  38. package/dist/template/TemplateRenders.d.ts +1 -1
  39. package/dist/template/TemplateRenders.js.map +1 -1
  40. package/dist/template/applyTemplateRenders.d.ts +3 -0
  41. package/dist/template/applyTemplateRenders.js +36 -6
  42. package/dist/template/applyTemplateRenders.js.map +1 -1
  43. package/dist/template/internals/TemplateRenderSnapshot.d.ts +18 -5
  44. package/dist/template/internals/TemplateRenderSnapshot.js +4 -1
  45. package/dist/template/internals/TemplateRenderSnapshot.js.map +1 -1
  46. package/dist/template/internals/TemplateRenderSnapshots.d.ts +18 -5
  47. package/dist/template/internals/deleteUsingTemplateRender.d.ts +4 -1
  48. package/dist/template/internals/deleteUsingTemplateRender.js +16 -3
  49. package/dist/template/internals/deleteUsingTemplateRender.js.map +1 -1
  50. package/dist/template/internals/insertUsingTemplateRender.js +11 -1
  51. package/dist/template/internals/insertUsingTemplateRender.js.map +1 -1
  52. package/dist/template/internals/loadTemplateRenderSnapshots.d.ts +4 -1
  53. package/dist/template/internals/mergeUsingTemplateRender.js +11 -1
  54. package/dist/template/internals/mergeUsingTemplateRender.js.map +1 -1
  55. package/dist/template/internals/parseCarsonTemplateId.js +6 -1
  56. package/dist/template/internals/parseCarsonTemplateId.js.map +1 -1
  57. package/dist/template/internals/readCarsonTemplate.js +7 -1
  58. package/dist/template/internals/readCarsonTemplate.js.map +1 -1
  59. package/dist/template/internals/saveTemplateRenderSnapshots.js +4 -4
  60. package/dist/template/internals/saveTemplateRenderSnapshots.js.map +1 -1
  61. package/dist/template/internals/uninsertUsingTemplateRender.js +11 -1
  62. package/dist/template/internals/uninsertUsingTemplateRender.js.map +1 -1
  63. package/dist/template/internals/unmerge.d.ts +1 -1
  64. package/dist/template/internals/unmerge.js +1 -1
  65. package/dist/template/internals/unmerge.js.map +1 -1
  66. package/dist/template/internals/unmergeUsingTemplateRender.js +11 -1
  67. package/dist/template/internals/unmergeUsingTemplateRender.js.map +1 -1
  68. package/dist/template/renderCarsonTemplate.d.ts +3 -0
  69. package/dist/template/renderCarsonTemplate.js +15 -4
  70. package/dist/template/renderCarsonTemplate.js.map +1 -1
  71. package/dist/template.d.ts +1 -0
  72. package/dist/template.js +1 -0
  73. package/dist/template.js.map +1 -1
  74. package/dist/workspace/Project.d.ts +2 -2
  75. package/dist/workspace/Project.js +19 -4
  76. package/dist/workspace/Project.js.map +1 -1
  77. package/dist/workspace/ProjectConfig.d.ts +3 -0
  78. package/dist/workspace/ProjectConfig.js.map +1 -1
  79. package/dist/workspace/ProjectCreateOptions.d.ts +3 -0
  80. package/dist/workspace/ProjectCreateOptions.js.map +1 -1
  81. package/dist/workspace/ProjectError.d.ts +5 -2
  82. package/dist/workspace/ProjectError.js +6 -2
  83. package/dist/workspace/ProjectError.js.map +1 -1
  84. package/dist/workspace/ProjectOptions.d.ts +1 -1
  85. package/dist/workspace/ProjectOptions.js.map +1 -1
  86. package/dist/workspace/ProjectUpdateOptions.d.ts +3 -0
  87. package/dist/workspace/ProjectUpdateOptions.js +3 -1
  88. package/dist/workspace/ProjectUpdateOptions.js.map +1 -1
  89. package/dist/workspace/Workspace.d.ts +8 -6
  90. package/dist/workspace/Workspace.js +106 -33
  91. package/dist/workspace/Workspace.js.map +1 -1
  92. package/dist/workspace/WorkspaceConfig.d.ts +3 -0
  93. package/dist/workspace/WorkspaceConfig.js.map +1 -1
  94. package/dist/workspace/WorkspaceCreateOptions.d.ts +3 -0
  95. package/dist/workspace/WorkspaceCreateOptions.js +3 -1
  96. package/dist/workspace/WorkspaceCreateOptions.js.map +1 -1
  97. package/dist/workspace/WorkspaceCreateProjectOptions.d.ts +3 -0
  98. package/dist/workspace/WorkspaceCreateProjectOptions.js +3 -1
  99. package/dist/workspace/WorkspaceCreateProjectOptions.js.map +1 -1
  100. package/dist/workspace/WorkspaceDependencies.d.ts +26 -19
  101. package/dist/workspace/WorkspaceDependencies.js +27 -9
  102. package/dist/workspace/WorkspaceDependencies.js.map +1 -1
  103. package/dist/workspace/WorkspaceDependenciesFromWorkspaceOptions.d.ts +8 -0
  104. package/dist/workspace/WorkspaceDependenciesFromWorkspaceOptions.js +5 -0
  105. package/dist/workspace/WorkspaceDependenciesFromWorkspaceOptions.js.map +1 -0
  106. package/dist/workspace/WorkspaceDependenciesGetVersionsOptions.d.ts +6 -0
  107. package/dist/workspace/WorkspaceDependenciesGetVersionsOptions.js +5 -0
  108. package/dist/workspace/WorkspaceDependenciesGetVersionsOptions.js.map +1 -0
  109. package/dist/workspace/WorkspaceDependency.d.ts +14 -0
  110. package/dist/workspace/WorkspaceDependency.js +3 -0
  111. package/dist/workspace/WorkspaceDependency.js.map +1 -0
  112. package/dist/workspace/WorkspaceDependencyProject.d.ts +11 -0
  113. package/dist/workspace/WorkspaceDependencyProject.js +5 -0
  114. package/dist/workspace/WorkspaceDependencyProject.js.map +1 -0
  115. package/dist/workspace/WorkspaceError.d.ts +5 -2
  116. package/dist/workspace/WorkspaceError.js +10 -3
  117. package/dist/workspace/WorkspaceError.js.map +1 -1
  118. package/dist/workspace/WorkspaceFindAndReadOptions.d.ts +6 -0
  119. package/dist/workspace/WorkspaceFindAndReadOptions.js +5 -0
  120. package/dist/workspace/WorkspaceFindAndReadOptions.js.map +1 -0
  121. package/dist/workspace/WorkspaceOptions.d.ts +4 -4
  122. package/dist/workspace/WorkspaceOptions.js.map +1 -1
  123. package/dist/workspace/{WorkspaceOptionsProjectOptions.d.ts → WorkspaceOptionsProject.d.ts} +4 -1
  124. package/dist/workspace/WorkspaceOptionsProject.js +3 -0
  125. package/dist/workspace/WorkspaceOptionsProject.js.map +1 -0
  126. package/dist/workspace/WorkspacePackageJson.d.ts +3 -0
  127. package/dist/workspace/WorkspacePackageJson.js.map +1 -1
  128. package/dist/workspace/WorkspaceProjectGlobs.d.ts +3 -0
  129. package/dist/workspace/WorkspaceProjectGlobs.js +3 -1
  130. package/dist/workspace/WorkspaceProjectGlobs.js.map +1 -1
  131. package/dist/workspace/WorkspaceProjects.d.ts +3 -0
  132. package/dist/workspace/WorkspaceProjects.js.map +1 -1
  133. package/dist/workspace/WorkspaceRepository.d.ts +4 -1
  134. package/dist/workspace/WorkspaceRepository.js +3 -1
  135. package/dist/workspace/WorkspaceRepository.js.map +1 -1
  136. package/dist/workspace/WorkspaceUpdateOptions.d.ts +3 -0
  137. package/dist/workspace/WorkspaceUpdateOptions.js +3 -1
  138. package/dist/workspace/WorkspaceUpdateOptions.js.map +1 -1
  139. package/dist/workspace/internals/compareProjectPath.d.ts +2 -0
  140. package/dist/workspace/internals/compareProjectPath.js +10 -0
  141. package/dist/workspace/internals/compareProjectPath.js.map +1 -0
  142. package/dist/workspace/internals/compareWorkspaceDependencyProjectName.d.ts +2 -0
  143. package/dist/workspace/internals/compareWorkspaceDependencyProjectName.js +10 -0
  144. package/dist/workspace/internals/compareWorkspaceDependencyProjectName.js.map +1 -0
  145. package/dist/workspace/internals/getRepositoryBranches.js +6 -0
  146. package/dist/workspace/internals/getRepositoryBranches.js.map +1 -1
  147. package/dist/workspace/internals/getRepositoryUrl.js +0 -1
  148. package/dist/workspace/internals/getRepositoryUrl.js.map +1 -1
  149. package/dist/workspace/internals.d.ts +2 -0
  150. package/dist/workspace/internals.js +2 -0
  151. package/dist/workspace/internals.js.map +1 -1
  152. package/dist/workspace/saveProjectConfig.d.ts +8 -0
  153. package/dist/workspace/saveProjectConfig.js +5 -1
  154. package/dist/workspace/saveProjectConfig.js.map +1 -1
  155. package/dist/workspace/saveWorkspaceConfig.d.ts +8 -0
  156. package/dist/workspace/saveWorkspaceConfig.js +5 -1
  157. package/dist/workspace/saveWorkspaceConfig.js.map +1 -1
  158. package/dist/workspace.d.ts +12 -0
  159. package/dist/workspace.js +12 -0
  160. package/dist/workspace.js.map +1 -1
  161. package/package.json +10 -10
  162. package/src/commands/create-project/CreateProject.tsx +2 -2
  163. package/src/commands/create-project/CreateProjectInput.ts +1 -1
  164. package/src/commands/create-project/createProjectCommand.tsx +1 -5
  165. package/src/commands/create-project/runCreateProject.ts +4 -17
  166. package/src/commands/create-workspace/CreateWorkspace.tsx +8 -6
  167. package/src/commands/create-workspace/createWorkspaceCommand.tsx +1 -14
  168. package/src/commands/create-workspace/runCreateWorkspace.ts +4 -16
  169. package/src/commands/internals/CommandStatus.ts +1 -0
  170. package/src/commands/internals.ts +1 -0
  171. package/src/commands/update-workspace/UpdateWorkspace.tsx +1 -1
  172. package/src/commands/update-workspace/updateWorkspaceCommand.tsx +1 -5
  173. package/src/template/CarsonTemplate.ts +1 -2
  174. package/src/template/CarsonTemplateConfig.ts +1 -1
  175. package/src/template/CarsonTemplateError.ts +19 -0
  176. package/src/template/TemplateAttributes.ts +2 -1
  177. package/src/template/TemplateRender.ts +6 -2
  178. package/src/template/TemplateRenders.ts +1 -1
  179. package/src/template/applyTemplateRenders.ts +40 -4
  180. package/src/template/internals/TemplateRenderSnapshot.ts +5 -0
  181. package/src/template/internals/deleteUsingTemplateRender.ts +21 -2
  182. package/src/template/internals/insertUsingTemplateRender.ts +11 -1
  183. package/src/template/internals/mergeUsingTemplateRender.ts +11 -1
  184. package/src/template/internals/parseCarsonTemplateId.ts +5 -1
  185. package/src/template/internals/readCarsonTemplate.ts +4 -1
  186. package/src/template/internals/saveTemplateRenderSnapshots.ts +3 -2
  187. package/src/template/internals/uninsertUsingTemplateRender.ts +11 -1
  188. package/src/template/internals/unmerge.ts +1 -1
  189. package/src/template/internals/unmergeUsingTemplateRender.ts +11 -1
  190. package/src/template/renderCarsonTemplate.ts +28 -7
  191. package/src/template.ts +1 -0
  192. package/src/workspace/Project.ts +16 -4
  193. package/src/workspace/ProjectConfig.ts +3 -0
  194. package/src/workspace/ProjectCreateOptions.ts +3 -0
  195. package/src/workspace/ProjectError.ts +5 -0
  196. package/src/workspace/ProjectOptions.ts +1 -1
  197. package/src/workspace/ProjectUpdateOptions.ts +3 -0
  198. package/src/workspace/Workspace.ts +125 -42
  199. package/src/workspace/WorkspaceConfig.ts +3 -0
  200. package/src/workspace/WorkspaceCreateOptions.ts +3 -0
  201. package/src/workspace/WorkspaceCreateProjectOptions.ts +3 -0
  202. package/src/workspace/WorkspaceDependencies.ts +30 -27
  203. package/src/workspace/WorkspaceDependenciesFromWorkspaceOptions.ts +8 -0
  204. package/src/workspace/WorkspaceDependenciesGetVersionsOptions.ts +6 -0
  205. package/src/workspace/WorkspaceDependency.ts +18 -0
  206. package/src/workspace/WorkspaceDependencyProject.ts +13 -0
  207. package/src/workspace/WorkspaceError.ts +10 -1
  208. package/src/workspace/WorkspaceFindAndReadOptions.ts +6 -0
  209. package/src/workspace/WorkspaceOptions.ts +4 -4
  210. package/src/workspace/{WorkspaceOptionsProjectOptions.ts → WorkspaceOptionsProject.ts} +4 -1
  211. package/src/workspace/WorkspacePackageJson.ts +3 -0
  212. package/src/workspace/WorkspaceProjectGlobs.ts +3 -0
  213. package/src/workspace/WorkspaceProjects.ts +3 -0
  214. package/src/workspace/WorkspaceRepository.ts +4 -1
  215. package/src/workspace/WorkspaceUpdateOptions.ts +3 -0
  216. package/src/workspace/internals/compareProjectPath.ts +14 -0
  217. package/src/workspace/internals/compareWorkspaceDependencyProjectName.ts +14 -0
  218. package/src/workspace/internals/getRepositoryBranches.ts +8 -0
  219. package/src/workspace/internals/getRepositoryUrl.ts +0 -1
  220. package/src/workspace/internals.ts +2 -0
  221. package/src/workspace/saveProjectConfig.ts +8 -0
  222. package/src/workspace/saveWorkspaceConfig.ts +8 -0
  223. package/src/workspace.ts +12 -0
  224. package/dist/workspace/WorkspaceOptionsProjectOptions.js +0 -3
  225. package/dist/workspace/WorkspaceOptionsProjectOptions.js.map +0 -1
@@ -4,6 +4,7 @@ import path from 'node:path';
4
4
 
5
5
  import {prettify} from './prettify.js';
6
6
  import {type TemplateRenderSnapshot} from './TemplateRenderSnapshot.js';
7
+ import {CarsonTemplateError} from '../CarsonTemplateError.js';
7
8
  import {type TemplateRender} from '../TemplateRender.js';
8
9
 
9
10
  export async function uninsertUsingTemplateRender(
@@ -33,7 +34,16 @@ export async function uninsertUsingTemplateRender(
33
34
  }
34
35
 
35
36
  default: {
36
- throw new Error(`File extension "${extension}" is not supported!`);
37
+ throw new CarsonTemplateError('STRATEGY_UNSUPPORTED_EXTENSION', {
38
+ messageParameters: [
39
+ templateRender.attributes.strategy,
40
+ templateRender.template.path,
41
+ extension,
42
+ ],
43
+ data: {
44
+ path: templateRender.template.path,
45
+ },
46
+ });
37
47
  }
38
48
  }
39
49
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Reverts {@linkcode merge}.
2
+ * Reverts {@link merge}.
3
3
  */
4
4
  export function unmerge(a: unknown, b: unknown) {
5
5
  if (b === undefined || b == null) {
@@ -7,6 +7,7 @@ import yaml from 'yaml';
7
7
  import {prettify} from './prettify.js';
8
8
  import {type TemplateRenderSnapshot} from './TemplateRenderSnapshot.js';
9
9
  import {unmerge} from './unmerge.js';
10
+ import {CarsonTemplateError} from '../CarsonTemplateError.js';
10
11
  import {type TemplateRender} from '../TemplateRender.js';
11
12
 
12
13
  export async function unmergeUsingTemplateRender(
@@ -38,7 +39,16 @@ export async function unmergeUsingTemplateRender(
38
39
  }
39
40
 
40
41
  default: {
41
- throw new Error(`File extension "${extension}" is not supported!`);
42
+ throw new CarsonTemplateError('STRATEGY_UNSUPPORTED_EXTENSION', {
43
+ messageParameters: [
44
+ templateRender.attributes.strategy,
45
+ templateRender.template.path,
46
+ extension,
47
+ ],
48
+ data: {
49
+ path: templateRender.template.path,
50
+ },
51
+ });
42
52
  }
43
53
  }
44
54
  }
@@ -1,6 +1,13 @@
1
+ import {pathToPosixPath} from '@jakubmazanec/fs-utils';
1
2
  import _ from 'lodash';
3
+ import path from 'node:path';
2
4
 
3
- import {importCarsonTemplate, readCarsonTemplate} from './internals.js';
5
+ import {
6
+ importCarsonTemplate,
7
+ parseCarsonTemplateId,
8
+ readCarsonTemplate,
9
+ resolveModule,
10
+ } from './internals.js';
4
11
  import {type TemplateData} from './TemplateData.js';
5
12
  import {type TemplateRenders} from './TemplateRenders.js';
6
13
 
@@ -9,22 +16,36 @@ export type RenderCarsonTemplateOptions = {
9
16
  templateData: TemplateData;
10
17
  };
11
18
 
19
+ /**
20
+ * Renders a Carson template with provided template data.
21
+ */
12
22
  export async function renderCarsonTemplate(
13
23
  options: RenderCarsonTemplateOptions,
14
24
  ): Promise<TemplateRenders> {
25
+ let [moduleId] = parseCarsonTemplateId(options.templateId);
26
+ let modulePath = await resolveModule(moduleId);
15
27
  let template = await readCarsonTemplate(options.templateId);
16
28
  let templateModule = await importCarsonTemplate(options.templateId);
17
29
  let templateRenders: TemplateRenders = [];
18
30
 
19
31
  for (let file of template.files) {
20
32
  templateRenders.push(
21
- ...(await file.render(
22
- {
23
- ...templateModule,
24
- ...options.templateData,
33
+ ...(
34
+ await file.render(
35
+ {
36
+ ...templateModule,
37
+ ...options.templateData,
38
+ },
39
+ {disablePrettier: true},
40
+ )
41
+ ).map((templateRender) => ({
42
+ ...templateRender,
43
+ template: {
44
+ path: pathToPosixPath(
45
+ `${moduleId}/${path.relative(modulePath, file.path ?? modulePath)}`,
46
+ ),
25
47
  },
26
- {disablePrettier: true},
27
- )),
48
+ })),
28
49
  );
29
50
  }
30
51
 
package/src/template.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './template/applyTemplateRenders.js';
2
2
  export * from './template/CarsonTemplate.js';
3
3
  export * from './template/CarsonTemplateConfig.js';
4
+ export * from './template/CarsonTemplateError.js';
4
5
  export * from './template/renderCarsonTemplate.js';
5
6
  export * from './template/TemplateAttributes.js';
6
7
  export * from './template/TemplateData.js';
@@ -17,7 +17,7 @@ import {applyTemplateRenders} from '../template/applyTemplateRenders.js';
17
17
  import {renderCarsonTemplate} from '../template/renderCarsonTemplate.js';
18
18
 
19
19
  /**
20
- * Project represent a self-contained piece of software (e.g. a package, or an app) that is part of a {@linkcode Workspace}. Currently only Node.js projects are supported.
20
+ * Project represent a self-contained piece of software (e.g. a package, or an app) that is part of a {@link Workspace}. Currently only Node.js projects are supported.
21
21
  *
22
22
  * @typeParam M If true, the project belongs to a multi-project workspace.
23
23
  */
@@ -37,7 +37,7 @@ export class Project<M extends boolean = true> {
37
37
  /** Parsed project `package.json` file; if it's not found, the default is an empty object. */
38
38
  packageJson: PackageJson;
39
39
 
40
- /** Parent {@linkcode Workspace} instance. */
40
+ /** Parent {@link Workspace} instance. */
41
41
  workspace: Workspace<M>;
42
42
 
43
43
  /** Errors found during reading from the file system. */
@@ -99,7 +99,17 @@ export class Project<M extends boolean = true> {
99
99
  workspace,
100
100
  });
101
101
 
102
- await ensureEmptyDirectory(project.path);
102
+ try {
103
+ await ensureEmptyDirectory(project.path);
104
+ } catch {
105
+ throw new ProjectError('PROJECT_PATH_NOT_EMPTY', {
106
+ messageParameters: [project.path],
107
+ data: {
108
+ path: project.path,
109
+ },
110
+ });
111
+ }
112
+
103
113
  await saveProjectConfig({projectPath: project.path, projectConfig: {template: templateId}});
104
114
 
105
115
  let templateRenders = await renderCarsonTemplate({
@@ -219,7 +229,9 @@ export class Project<M extends boolean = true> {
219
229
 
220
230
  async update({args}: ProjectUpdateOptions): Promise<this> {
221
231
  if (!this.config.template) {
222
- throw new Error('Template ID is missing in the project config!');
232
+ throw new ProjectError('MISSING_CARSON_TEMPLATE_ID', {
233
+ messageParameters: [path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_CONFIG_FILENAME)],
234
+ });
223
235
  }
224
236
 
225
237
  let templateRenders = await renderCarsonTemplate({
@@ -6,4 +6,7 @@ export const projectConfigSchema = z
6
6
  })
7
7
  .catchall(z.unknown());
8
8
 
9
+ /**
10
+ * A project configuration.
11
+ */
9
12
  export type ProjectConfig = z.infer<typeof projectConfigSchema>;
@@ -1,5 +1,8 @@
1
1
  import {type Workspace} from './Workspace.js';
2
2
 
3
+ /**
4
+ * {@link Project.create | Project.create} options parameter.
5
+ */
3
6
  export type ProjectCreateOptions<M extends boolean> = {
4
7
  templateId: string;
5
8
  workspace: Workspace<M>;
@@ -1,12 +1,17 @@
1
1
  import {createCustomErrorWithData} from '@jakubmazanec/error';
2
2
  import {type ZodIssue} from 'zod';
3
3
 
4
+ /**
5
+ * A subclass of `Error` that indicates a project failure.
6
+ */
4
7
  export const ProjectError = createCustomErrorWithData(
5
8
  'ProjectError',
6
9
  {
7
10
  INVALID_PACKAGE_JSON: 'Invalid package.json file "{0}".',
8
11
  INVALID_PROJECT_CONFIG: 'Invalid project config file "{0}".',
9
12
  NO_SUCH_PROJECT_PATH: 'Project path "{0}" doesn\'t exist.',
13
+ PROJECT_PATH_NOT_EMPTY: 'Project path "{0}" must be an empty directory.',
14
+ MISSING_CARSON_TEMPLATE_ID: 'Project config "{0}" is missing the Carson template ID.',
10
15
  },
11
16
  class ProjectErrorData {
12
17
  path?: string;
@@ -5,7 +5,7 @@ import {type ProjectError} from './ProjectError.js';
5
5
  import {type Workspace} from './Workspace.js';
6
6
 
7
7
  /**
8
- * New project options.
8
+ * {@link Project.constructor | Project constructor} options parameter.
9
9
  */
10
10
  export type ProjectOptions<M extends boolean> = {
11
11
  path: string;
@@ -1,3 +1,6 @@
1
+ /**
2
+ * {@link Project.update | Project.update} options parameter.
3
+ */
1
4
  export type ProjectUpdateOptions = {
2
5
  args: Record<string, unknown>;
3
6
  };
@@ -6,7 +6,12 @@ import json5 from 'json5';
6
6
  import path from 'node:path';
7
7
  import {z} from 'zod';
8
8
 
9
- import {getPackageJsonWorkspaces, getRepositoryBranches, getRepositoryUrl} from './internals.js';
9
+ import {
10
+ compareProjectPath,
11
+ getPackageJsonWorkspaces,
12
+ getRepositoryBranches,
13
+ getRepositoryUrl,
14
+ } from './internals.js';
10
15
  import {Project} from './Project.js';
11
16
  import {saveWorkspaceConfig} from './saveWorkspaceConfig.js';
12
17
  import {workspaceConfigSchema} from './WorkspaceConfig.js';
@@ -15,6 +20,7 @@ import {type WorkspaceCreateOptions} from './WorkspaceCreateOptions.js';
15
20
  import {type WorkspaceCreateProjectOptions} from './WorkspaceCreateProjectOptions.js';
16
21
  import {WorkspaceDependencies} from './WorkspaceDependencies.js';
17
22
  import {WorkspaceError} from './WorkspaceError.js';
23
+ import {type WorkspaceFindAndReadOptions} from './WorkspaceFindAndReadOptions.js';
18
24
  import type {WorkspaceOptions} from './WorkspaceOptions.js';
19
25
  import {type WorkspacePackageJson} from './WorkspacePackageJson.js';
20
26
  import type {WorkspaceProjectGlobs} from './WorkspaceProjectGlobs.js';
@@ -26,7 +32,7 @@ import {applyTemplateRenders} from '../template/applyTemplateRenders.js';
26
32
  import {renderCarsonTemplate} from '../template/renderCarsonTemplate.js';
27
33
 
28
34
  /**
29
- * Workspace represent a directory, usually a git repository, that contains {@linkcode Project} instances.
35
+ * Workspace represent a directory, usually a git repository, that contains {@link Project} instances.
30
36
  *
31
37
  * @typeParam M If true, the workspace is multi-project workspace (so-called "monorepo").
32
38
  */
@@ -81,14 +87,12 @@ export class Workspace<M extends boolean = true> {
81
87
  this.projectGlobs = [] as string[] as WorkspaceProjectGlobs<M>;
82
88
  }
83
89
 
90
+ this.projects = [] as Array<Project<M>> as WorkspaceProjects<M>;
91
+
84
92
  let {projects} = options as WorkspaceOptions<true>;
85
93
 
86
94
  if (projects) {
87
- this.projects = projects.map(
88
- (project) => new Project({...project, workspace: this}),
89
- ) as WorkspaceProjects<M>;
90
- } else {
91
- this.projects = [] as Array<Project<M>> as WorkspaceProjects<M>;
95
+ this.addProjects(projects.map((project) => new Project({...project, workspace: this})));
92
96
  }
93
97
 
94
98
  let packageJsonOption = (options as WorkspaceOptions<true>).packageJson;
@@ -104,19 +108,12 @@ export class Workspace<M extends boolean = true> {
104
108
  this.isMultiProject = false as M;
105
109
  this.projectGlobs = null as M extends true ? string[] : null;
106
110
  this.packageJson = null as M extends true ? PackageJson : null;
111
+ this.projects = [] as Array<Project<M>> as WorkspaceProjects<M>;
107
112
 
108
113
  let {projects} = options as WorkspaceOptions<false>;
109
114
 
110
115
  if (projects) {
111
- this.projects = projects.map(
112
- (project) => new Project({...project, workspace: this}),
113
- ) as WorkspaceProjects<M>;
114
-
115
- if ((this.projects[0] as Project<false>).path !== this.path) {
116
- throw new WorkspaceError('PATH_MISMATCH');
117
- }
118
- } else {
119
- this.projects = [] as Array<Project<M>> as WorkspaceProjects<M>;
116
+ this.addProjects(projects.map((project) => new Project({...project, workspace: this})));
120
117
  }
121
118
  }
122
119
 
@@ -147,6 +144,7 @@ export class Workspace<M extends boolean = true> {
147
144
  }
148
145
  }
149
146
 
147
+ this.sortProjects();
150
148
  this.updateDependencies();
151
149
  }
152
150
 
@@ -154,7 +152,7 @@ export class Workspace<M extends boolean = true> {
154
152
  * Creates new workspace within the file system.
155
153
  *
156
154
  * @param options Options.
157
- * @returns The new workspace
155
+ * @returns The new workspace.
158
156
  */
159
157
  static async create({args, path: workspacePath, templateId}: WorkspaceCreateOptions) {
160
158
  // TODO: test that workspace returned by this method has the same value of isMultiProject when the same workspace is after its creation re-read with .read()
@@ -165,7 +163,17 @@ export class Workspace<M extends boolean = true> {
165
163
  },
166
164
  });
167
165
 
168
- await ensureEmptyDirectory(workspace.path);
166
+ try {
167
+ await ensureEmptyDirectory(workspace.path);
168
+ } catch {
169
+ throw new WorkspaceError('WORKSPACE_PATH_NOT_EMPTY', {
170
+ messageParameters: [workspace.path],
171
+ data: {
172
+ path: workspace.path,
173
+ },
174
+ });
175
+ }
176
+
169
177
  await saveWorkspaceConfig({
170
178
  workspacePath: workspace.path,
171
179
  workspaceConfig: {template: templateId},
@@ -293,14 +301,42 @@ export class Workspace<M extends boolean = true> {
293
301
  /**
294
302
  * Traverses file system up from the search path and tries to find and read a workspace.
295
303
  */
296
- static async findAndRead(searchPath: string): Promise<Workspace | Workspace<false> | undefined> {
304
+ static async findAndRead<O extends WorkspaceFindAndReadOptions | undefined = undefined>(
305
+ searchPath: string,
306
+ options?: O,
307
+ ): Promise<
308
+ O extends undefined
309
+ ? Workspace | Workspace<false> | undefined
310
+ : NonNullable<O>['throwIfNotFound'] extends true
311
+ ? Workspace | Workspace<false>
312
+ : Workspace | Workspace<false> | undefined
313
+ > {
297
314
  let workspacePath = await Workspace.find(searchPath);
298
315
 
299
316
  if (workspacePath) {
300
- return Workspace.read(workspacePath);
317
+ return Workspace.read(workspacePath) as Promise<
318
+ O extends undefined
319
+ ? Workspace | Workspace<false> | undefined
320
+ : NonNullable<O>['throwIfNotFound'] extends true
321
+ ? Workspace | Workspace<false>
322
+ : Workspace | Workspace<false> | undefined
323
+ >;
324
+ } else if (options?.throwIfNotFound) {
325
+ throw new WorkspaceError('NO_WORKSPACE_FOUND', {
326
+ messageParameters: [searchPath],
327
+ data: {
328
+ path: searchPath,
329
+ },
330
+ });
301
331
  }
302
332
 
303
- return undefined;
333
+ return undefined as unknown as Promise<
334
+ O extends undefined
335
+ ? Workspace | Workspace<false> | undefined
336
+ : NonNullable<O>['throwIfNotFound'] extends true
337
+ ? Workspace | Workspace<false>
338
+ : Workspace | Workspace<false> | undefined
339
+ >;
304
340
  }
305
341
 
306
342
  async read(): Promise<this> {
@@ -390,6 +426,10 @@ export class Workspace<M extends boolean = true> {
390
426
  url: repositoryUrl,
391
427
  branches: repositoryBranches ?? [],
392
428
  };
429
+ } else if (repositoryBranches) {
430
+ this.repository = {
431
+ branches: repositoryBranches,
432
+ };
393
433
  }
394
434
 
395
435
  await this.readProjects();
@@ -406,6 +446,10 @@ export class Workspace<M extends boolean = true> {
406
446
  url: repositoryUrl,
407
447
  branches: repositoryBranches ?? [],
408
448
  };
449
+ } else if (repositoryBranches) {
450
+ this.repository = {
451
+ branches: repositoryBranches,
452
+ };
409
453
  }
410
454
 
411
455
  await this.readProjects();
@@ -415,7 +459,11 @@ export class Workspace<M extends boolean = true> {
415
459
 
416
460
  async update({args}: WorkspaceUpdateOptions): Promise<this> {
417
461
  if (!this.config.template) {
418
- throw new Error('Templat ID is missing in the workspace config!');
462
+ throw new WorkspaceError('MISSING_CARSON_TEMPLATE_ID', {
463
+ messageParameters: [
464
+ path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_CONFIG_FILENAME),
465
+ ],
466
+ });
419
467
  }
420
468
 
421
469
  let templateRenders = await renderCarsonTemplate({
@@ -453,16 +501,24 @@ export class Workspace<M extends boolean = true> {
453
501
  projectName,
454
502
  args,
455
503
  }: WorkspaceCreateProjectOptions): Promise<Project<M>> {
456
- if (this.projects.some((project) => projectPath === project.path)) {
457
- throw new Error('Project with same path already exists!');
504
+ let resolvedProjectPath = path.resolve(projectPath);
505
+
506
+ if (this.projects.some((project) => resolvedProjectPath === project.path)) {
507
+ throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {
508
+ messageParameters: [resolvedProjectPath],
509
+ });
458
510
  }
459
511
 
460
512
  if (this.projects.some((project) => projectName === project.name)) {
461
- throw new Error('Project with same name already exists!');
513
+ throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [projectName]});
462
514
  }
463
515
 
464
516
  if (!this.isMultiProject && this.projects.length >= 1) {
465
- throw new Error('Only multi-project Workspace can have more than 1 project!');
517
+ throw new WorkspaceError('TOO_MANY_PROJECTS');
518
+ }
519
+
520
+ if (!this.isMultiProject && projectPath !== this.path) {
521
+ throw new WorkspaceError('PATH_MISMATCH');
466
522
  }
467
523
 
468
524
  let newProject = await Project.create({
@@ -478,24 +534,59 @@ export class Workspace<M extends boolean = true> {
478
534
  return newProject;
479
535
  }
480
536
 
481
- addProject(newProject: Project<M>): Project<M> {
537
+ addProject(newProject: Project<M>): this {
482
538
  if (this.projects.some((project) => newProject.path === project.path)) {
483
- throw new Error('Project with same path already exists!');
539
+ throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {
540
+ messageParameters: [newProject.path],
541
+ });
484
542
  }
485
543
 
486
544
  if (this.projects.some((project) => newProject.name === project.name)) {
487
- throw new Error('Project with same name already exists!');
545
+ throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [newProject.name]});
488
546
  }
489
547
 
490
548
  if (!this.isMultiProject && this.projects.length >= 1) {
491
- throw new Error('Only multi-project Workspace can have more than 1 project!');
549
+ throw new WorkspaceError('TOO_MANY_PROJECTS');
550
+ }
551
+
552
+ if (!this.isMultiProject && newProject.path !== this.path) {
553
+ throw new WorkspaceError('PATH_MISMATCH');
492
554
  }
493
555
 
494
556
  this.projects.push(newProject);
495
557
  this.sortProjects();
496
558
  this.updateDependencies();
497
559
 
498
- return newProject;
560
+ return this;
561
+ }
562
+
563
+ addProjects(newProjects: Array<Project<M>>): this {
564
+ for (let newProject of newProjects) {
565
+ if (this.projects.some((project) => newProject.path === project.path)) {
566
+ throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {
567
+ messageParameters: [newProject.path],
568
+ });
569
+ }
570
+
571
+ if (this.projects.some((project) => newProject.name === project.name)) {
572
+ throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [newProject.name]});
573
+ }
574
+
575
+ if (!this.isMultiProject && this.projects.length >= 1) {
576
+ throw new WorkspaceError('TOO_MANY_PROJECTS');
577
+ }
578
+
579
+ if (!this.isMultiProject && newProject.path !== this.path) {
580
+ throw new WorkspaceError('PATH_MISMATCH');
581
+ }
582
+
583
+ this.projects.push(newProject);
584
+ }
585
+
586
+ this.sortProjects();
587
+ this.updateDependencies();
588
+
589
+ return this;
499
590
  }
500
591
 
501
592
  async readProjects(): Promise<Array<Project<M>>> {
@@ -523,19 +614,11 @@ export class Workspace<M extends boolean = true> {
523
614
  return this.projects;
524
615
  }
525
616
 
526
- private sortProjects(): void {
527
- this.projects.sort((projectA, projectB) => {
528
- if (projectA.path < projectB.path) {
529
- return -1;
530
- } else if (projectA.path > projectB.path) {
531
- return 1;
532
- }
533
-
534
- return 0;
535
- });
617
+ protected sortProjects(): void {
618
+ this.projects.sort(compareProjectPath);
536
619
  }
537
620
 
538
- private updateDependencies(): void {
621
+ protected updateDependencies(): void {
539
622
  this.dependencies = WorkspaceDependencies.fromWorkspace(this);
540
623
  this.devDependencies = WorkspaceDependencies.fromWorkspace(this, {
541
624
  includeOnlyDevDependencies: true,
@@ -6,4 +6,7 @@ export const workspaceConfigSchema = z
6
6
  })
7
7
  .catchall(z.unknown());
8
8
 
9
+ /**
10
+ * A workspace configuration.
11
+ */
9
12
  export type WorkspaceConfig = z.infer<typeof workspaceConfigSchema>;
@@ -1,3 +1,6 @@
1
+ /**
2
+ * {@link Workspace.create} options parameter.
3
+ */
1
4
  export type WorkspaceCreateOptions = {
2
5
  path: string;
3
6
  templateId: string;
@@ -1,3 +1,6 @@
1
+ /**
2
+ * {@link Workspace.createProject | Workspace.createProject} options parameter.
3
+ */
1
4
  export type WorkspaceCreateProjectOptions = {
2
5
  templateId: string;
3
6
  projectPath: string;
@@ -1,34 +1,19 @@
1
+ // TODO: try to fix
2
+ /* eslint-disable complexity -- TODO */
1
3
  import _ from 'lodash';
2
4
  import semver from 'semver';
3
5
 
4
- import {compareSemver} from './internals.js';
6
+ import {compareSemver, compareWorkspaceDependencyProjectName} from './internals.js';
5
7
  import {type Workspace} from './Workspace.js';
8
+ import {type WorkspaceDependenciesFromWorkspaceOptions} from './WorkspaceDependenciesFromWorkspaceOptions.js';
9
+ import {type WorkspaceDependenciesGetVersionsOptions} from './WorkspaceDependenciesGetVersionsOptions.js';
10
+ import {type WorkspaceDependency} from './WorkspaceDependency.js';
6
11
 
7
- export interface WorkspaceDependencyProject {
8
- name: string;
9
- version: string;
10
- exactVersion: string;
11
- }
12
-
13
- export interface WorkspaceDependency {
14
- name: string;
15
- versions: string[];
16
- exactVersions: string[];
17
-
18
- projects: WorkspaceDependencyProject[];
19
- }
20
-
21
- export interface WorkspaceDependenciesGetVersionsOptions {
22
- useExactVersions?: boolean;
23
- }
24
-
25
- export interface WorkspaceDependenciesFromWorkspaceOptions {
26
- includeDevDependencies?: boolean;
27
- includeOnlyDevDependencies?: boolean;
28
- includeWorkspaceDependencies?: boolean;
29
- }
30
-
12
+ /**
13
+ * A collection of {@link WorkspaceDependency | workspace dependencies} that are installed in {@link Workspace | a workspace}.
14
+ */
31
15
  export class WorkspaceDependencies<M extends boolean = true> extends Array<WorkspaceDependency> {
16
+ /** The workspace the dependencies are installed in. */
32
17
  workspace: Workspace<M>;
33
18
 
34
19
  constructor(...args: [...WorkspaceDependency[], Workspace<M>]) {
@@ -46,6 +31,12 @@ export class WorkspaceDependencies<M extends boolean = true> extends Array<Works
46
31
  }
47
32
  }
48
33
 
34
+ /**
35
+ * Adds one or more new dependencies.
36
+ *
37
+ * @param newWorkspaceDependencies The dependencies to add.
38
+ * @returns The new length of the collection.
39
+ */
49
40
  override push(...newWorkspaceDependencies: WorkspaceDependency[]): number {
50
41
  for (let newWorkspaceDependency of newWorkspaceDependencies) {
51
42
  let doesExist = false;
@@ -70,6 +61,7 @@ export class WorkspaceDependencies<M extends boolean = true> extends Array<Works
70
61
 
71
62
  workspaceDependency.versions.sort(compareSemver);
72
63
  workspaceDependency.exactVersions.sort(compareSemver);
64
+ workspaceDependency.projects.sort(compareWorkspaceDependencyProjectName);
73
65
  }
74
66
  }
75
67
 
@@ -81,8 +73,13 @@ export class WorkspaceDependencies<M extends boolean = true> extends Array<Works
81
73
  return this.length;
82
74
  }
83
75
 
84
- // TODO: fix
85
- // eslint-disable-next-line complexity -- TODO
76
+ /**
77
+ * Creates new {@link WorkspaceDependencies} instance from a {@link Workspace} instance and its dependencies.
78
+ *
79
+ * @param workspace The workspace from which the dependnecies are taken.
80
+ * @param options Options.
81
+ * @returns The new {@link WorkspaceDependencies} instance.
82
+ */
86
83
  static fromWorkspace<M extends boolean = true>(
87
84
  workspace: Workspace<M>,
88
85
  options?: WorkspaceDependenciesFromWorkspaceOptions,
@@ -178,6 +175,12 @@ export class WorkspaceDependencies<M extends boolean = true> extends Array<Works
178
175
  return new this(...workspaceDependencies, workspace);
179
176
  }
180
177
 
178
+ /**
179
+ * Creates map of all dependnecies and their installed version.
180
+ *
181
+ * @param options Options.
182
+ * @returns Object whose keys are dependency names and values are sorted versions.
183
+ */
181
184
  getVersions(options?: WorkspaceDependenciesGetVersionsOptions) {
182
185
  let versions: Record<string, string[]> = {};
183
186
 
@@ -0,0 +1,8 @@
1
+ /**
2
+ * {@link WorkspaceDependencies.fromWorkspace | WorkspaceDependencies.fromWorkspace} options parameter.
3
+ */
4
+ export type WorkspaceDependenciesFromWorkspaceOptions = {
5
+ includeDevDependencies?: boolean;
6
+ includeOnlyDevDependencies?: boolean;
7
+ includeWorkspaceDependencies?: boolean;
8
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * {@link WorkspaceDependencies.getVersions | WorkspaceDependencies.getVersions} options parameter.
3
+ */
4
+ export type WorkspaceDependenciesGetVersionsOptions = {
5
+ useExactVersions?: boolean;
6
+ };