@jakubmazanec/carson 1.0.1 → 1.1.0-next.c370ab6

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 (34) hide show
  1. package/README.md +17 -1
  2. package/build/commands/create-project/CreateProject.js +14 -0
  3. package/build/commands/create-project/CreateProject.js.map +2 -2
  4. package/build/commands/create-project/runCreateProject.js +1 -0
  5. package/build/commands/create-project/runCreateProject.js.map +2 -2
  6. package/build/commands/create-workspace/runCreateWorkspace.js +1 -0
  7. package/build/commands/create-workspace/runCreateWorkspace.js.map +2 -2
  8. package/build/template/CarsonTemplate.d.ts +2 -0
  9. package/build/template/CarsonTemplateConfig.d.ts +3 -6
  10. package/build/template/CarsonTemplateConfig.js +3 -3
  11. package/build/template/CarsonTemplateConfig.js.map +2 -2
  12. package/build/template/applyTemplateRenders.d.ts +1 -1
  13. package/build/template/applyTemplateRenders.js +5 -3
  14. package/build/template/applyTemplateRenders.js.map +2 -2
  15. package/build/template/internals/readCarsonTemplate.js +1 -0
  16. package/build/template/internals/readCarsonTemplate.js.map +2 -2
  17. package/build/template/renderCarsonTemplate.d.ts +2 -1
  18. package/build/template/renderCarsonTemplate.js +4 -10
  19. package/build/template/renderCarsonTemplate.js.map +2 -2
  20. package/build/workspace/Project.js +10 -5
  21. package/build/workspace/Project.js.map +2 -2
  22. package/build/workspace/Workspace.js +13 -8
  23. package/build/workspace/Workspace.js.map +2 -2
  24. package/package.json +10 -9
  25. package/source/commands/create-project/CreateProject.tsx +19 -0
  26. package/source/commands/create-project/runCreateProject.ts +3 -0
  27. package/source/commands/create-workspace/runCreateWorkspace.ts +3 -0
  28. package/source/template/CarsonTemplate.ts +3 -0
  29. package/source/template/CarsonTemplateConfig.ts +3 -3
  30. package/source/template/applyTemplateRenders.ts +6 -4
  31. package/source/template/internals/readCarsonTemplate.ts +1 -0
  32. package/source/template/renderCarsonTemplate.ts +6 -11
  33. package/source/workspace/Project.ts +16 -5
  34. package/source/workspace/Workspace.ts +19 -8
package/README.md CHANGED
@@ -242,6 +242,20 @@ Creates new workspace.
242
242
  | --path | Path where the workspace should be created. A relative path is appended to the current working directory. |
243
243
  | --template | ID of the Carson template used to create the workspace. |
244
244
 
245
+ #### `eject [<options>]`
246
+
247
+ > ⚠️ Upcoming feature!
248
+
249
+ Ejects Carson from a workspace and all of its projects. That means all `.carson` directories (that
250
+ contain Carson config and snapshot files) will be deleted.
251
+
252
+ You can still add projects to the workspace that has had Carson ejected, but those projects also
253
+ won't contain `.carson` folder.
254
+
255
+ | Option | Description |
256
+ | ------ | -------------------------------------------------------------------------------------------------- |
257
+ | --path | Path where the workspace is located. A relative path is appended to the current working directory. |
258
+
245
259
  ### Carson templates
246
260
 
247
261
  Carson template is just a directory containing `*.ejs` files and `config.json` file. The purpose of
@@ -355,7 +369,9 @@ Global variables available during the rendering:
355
369
 
356
370
  #### Carson template config
357
371
 
358
- Currently, the config isn't used for anything yet.
372
+ | Option | Type | Description |
373
+ | --------- | -------- | ------------------------------------------------------------------------ |
374
+ | autoEject | boolean? | If set to `true`, Carson automatically ejects after using this template. |
359
375
 
360
376
  ### Carson philosophy
361
377
 
@@ -62,6 +62,20 @@ export function CreateProject({ args, workspace }) {
62
62
  value: projectPath,
63
63
  label: path.relative(workspace.path, projectPath).replace("\\", "/")
64
64
  }));
65
+ if (!possiblePaths.length) {
66
+ possiblePaths = workspace.projectGlobs.filter((projectGlob) => !ONLY_ONE_STAR_REGEXP.test(projectGlob)).map((projectGlob) => path.join(workspace.path, projectGlob)).map((projectPath) => ({
67
+ value: projectPath,
68
+ label: path.relative(workspace.path, projectPath).replace("\\", "/")
69
+ }));
70
+ }
71
+ if (!possiblePaths.length) {
72
+ possiblePaths = [
73
+ {
74
+ value: workspace.path,
75
+ label: workspace.path
76
+ }
77
+ ];
78
+ }
65
79
  } else {
66
80
  possiblePaths = [
67
81
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/commands/create-project/CreateProject.tsx"],
4
- "sourcesContent": ["import {colors, type CommandArguments, Header, icons, useProgram} from '@jakubmazanec/cli';\nimport chalk from 'chalk';\nimport {Box, Text} from 'ink';\nimport path from 'node:path';\nimport {useEffect, useState} from 'react';\n\nimport {type Workspace} from '../../workspace.js';\nimport {type CommandStatus, packageNameToDirectory} from '../internals.js';\nimport {type createProjectCommand} from './createProjectCommand.js';\nimport {CreateProjectInput, type CreateProjectInputResult} from './CreateProjectInput.js';\nimport {runCreateProject} from './runCreateProject.js';\n\nconst ONLY_ONE_STAR_REGEXP = /^(?!(.*?\\*){2,}|.*? |\\*$).*?\\*.*$/;\n\nexport type CreateProjectProps = {\n args: CommandArguments<typeof createProjectCommand>;\n workspace: Workspace | Workspace<false>;\n};\n\nexport function CreateProject({args, workspace}: CreateProjectProps) {\n let [status, setStatus] = useState<CommandStatus>('not-started');\n let [subscription, setSubscription] = useState<ZenObservable.Subscription | null>(null);\n let [jobs, setJobs] = useState<string[]>([]);\n let [createProjectInputResult, setCreateProjectInputResult] = useState<CreateProjectInputResult>(\n () => ({\n projectName: {value: args.options.name ?? '', isComplete: !!args.options.name},\n projectPath: {value: '', isComplete: false},\n templateId: {value: args.options.template ?? '', isComplete: !!args.options.template},\n }),\n );\n let {exit} = useProgram();\n\n useEffect(() => {\n if (Object.entries(createProjectInputResult).every(([, result]) => result.isComplete)) {\n setStatus('in-progress');\n }\n }, [createProjectInputResult]);\n\n useEffect(() => {\n if (status === 'in-progress' && !subscription) {\n let newSubscription = runCreateProject({\n projectPath: createProjectInputResult.projectPath.value,\n templateId: createProjectInputResult.templateId.value,\n projectName: createProjectInputResult.projectName.value,\n workspace,\n args,\n }).subscribe({\n next(value) {\n setJobs((previousJobs) => [...previousJobs, value]);\n },\n error(error) {\n exit(error);\n },\n complete() {\n newSubscription.unsubscribe();\n setStatus('finished');\n },\n });\n setSubscription(newSubscription);\n }\n\n return () => {\n if (subscription) {\n subscription.unsubscribe();\n }\n };\n }, [args, createProjectInputResult, exit, status, subscription, workspace]);\n\n let possiblePaths: Array<{value: string; label: string}> = [];\n\n if (createProjectInputResult.projectName.value) {\n let destinationDirectory = packageNameToDirectory(createProjectInputResult.projectName.value);\n\n if (workspace.projectGlobs) {\n possiblePaths = workspace.projectGlobs\n .filter((projectGlob) => ONLY_ONE_STAR_REGEXP.test(projectGlob))\n .map((projectGlob) => projectGlob.replace(/\\*/, destinationDirectory))\n .map((projectGlob) => path.join(workspace.path, projectGlob))\n .map((projectPath) => ({\n value: projectPath,\n label: path.relative(workspace.path, projectPath).replace('\\\\', '/'),\n }));\n } else {\n possiblePaths = [\n {\n value: workspace.path,\n label: workspace.path,\n },\n ];\n }\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text color={colors.body}>\n {`Creating project in the workspace at ${chalk[colors.info](workspace.path)}.`}\n </Text>\n\n <CreateProjectInput\n rows={{\n projectPath: {\n choices: possiblePaths,\n },\n }}\n values={createProjectInputResult}\n marginTop={1}\n onChange={setCreateProjectInputResult}\n onComplete={setCreateProjectInputResult}\n />\n\n {status === 'in-progress' || status === 'finished' ?\n <Box marginTop={1} flexDirection=\"column\">\n <Header showSpinner={status === 'in-progress'} icon={icons.success} marginBottom={1}>\n <Text>Creating project...</Text>\n </Header>\n\n {jobs.map((job) => (\n <Text key={job}>{`${icons.info} ${job}`}</Text>\n ))}\n </Box>\n : null}\n\n {status === 'finished' ?\n <Header marginTop={1} icon={icons.success}>\n <Text>Done.</Text>\n </Header>\n : null}\n </Box>\n );\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {colors, type CommandArguments, Header, icons, useProgram} from '@jakubmazanec/cli';\nimport chalk from 'chalk';\nimport {Box, Text} from 'ink';\nimport path from 'node:path';\nimport {useEffect, useState} from 'react';\n\nimport {type Workspace} from '../../workspace.js';\nimport {type CommandStatus, packageNameToDirectory} from '../internals.js';\nimport {type createProjectCommand} from './createProjectCommand.js';\nimport {CreateProjectInput, type CreateProjectInputResult} from './CreateProjectInput.js';\nimport {runCreateProject} from './runCreateProject.js';\n\nconst ONLY_ONE_STAR_REGEXP = /^(?!(.*?\\*){2,}|.*? |\\*$).*?\\*.*$/;\n\nexport type CreateProjectProps = {\n args: CommandArguments<typeof createProjectCommand>;\n workspace: Workspace | Workspace<false>;\n};\n\nexport function CreateProject({args, workspace}: CreateProjectProps) {\n let [status, setStatus] = useState<CommandStatus>('not-started');\n let [subscription, setSubscription] = useState<ZenObservable.Subscription | null>(null);\n let [jobs, setJobs] = useState<string[]>([]);\n let [createProjectInputResult, setCreateProjectInputResult] = useState<CreateProjectInputResult>(\n () => ({\n projectName: {value: args.options.name ?? '', isComplete: !!args.options.name},\n projectPath: {value: '', isComplete: false},\n templateId: {value: args.options.template ?? '', isComplete: !!args.options.template},\n }),\n );\n let {exit} = useProgram();\n\n useEffect(() => {\n if (Object.entries(createProjectInputResult).every(([, result]) => result.isComplete)) {\n setStatus('in-progress');\n }\n }, [createProjectInputResult]);\n\n useEffect(() => {\n if (status === 'in-progress' && !subscription) {\n let newSubscription = runCreateProject({\n projectPath: createProjectInputResult.projectPath.value,\n templateId: createProjectInputResult.templateId.value,\n projectName: createProjectInputResult.projectName.value,\n workspace,\n args,\n }).subscribe({\n next(value) {\n setJobs((previousJobs) => [...previousJobs, value]);\n },\n error(error) {\n exit(error);\n },\n complete() {\n newSubscription.unsubscribe();\n setStatus('finished');\n },\n });\n setSubscription(newSubscription);\n }\n\n return () => {\n if (subscription) {\n subscription.unsubscribe();\n }\n };\n }, [args, createProjectInputResult, exit, status, subscription, workspace]);\n\n let possiblePaths: Array<{value: string; label: string}> = [];\n\n if (createProjectInputResult.projectName.value) {\n let destinationDirectory = packageNameToDirectory(createProjectInputResult.projectName.value);\n\n if (workspace.projectGlobs) {\n possiblePaths = workspace.projectGlobs\n .filter((projectGlob) => ONLY_ONE_STAR_REGEXP.test(projectGlob))\n .map((projectGlob) => projectGlob.replace(/\\*/, destinationDirectory))\n .map((projectGlob) => path.join(workspace.path, projectGlob))\n .map((projectPath) => ({\n value: projectPath,\n label: path.relative(workspace.path, projectPath).replace('\\\\', '/'),\n }));\n\n if (!possiblePaths.length) {\n possiblePaths = workspace.projectGlobs\n .filter((projectGlob) => !ONLY_ONE_STAR_REGEXP.test(projectGlob))\n .map((projectGlob) => path.join(workspace.path, projectGlob))\n .map((projectPath) => ({\n value: projectPath,\n label: path.relative(workspace.path, projectPath).replace('\\\\', '/'),\n }));\n }\n\n if (!possiblePaths.length) {\n possiblePaths = [\n {\n value: workspace.path,\n label: workspace.path,\n },\n ];\n }\n } else {\n possiblePaths = [\n {\n value: workspace.path,\n label: workspace.path,\n },\n ];\n }\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text color={colors.body}>\n {`Creating project in the workspace at ${chalk[colors.info](workspace.path)}.`}\n </Text>\n\n <CreateProjectInput\n rows={{\n projectPath: {\n choices: possiblePaths,\n },\n }}\n values={createProjectInputResult}\n marginTop={1}\n onChange={setCreateProjectInputResult}\n onComplete={setCreateProjectInputResult}\n />\n\n {status === 'in-progress' || status === 'finished' ?\n <Box marginTop={1} flexDirection=\"column\">\n <Header showSpinner={status === 'in-progress'} icon={icons.success} marginBottom={1}>\n <Text>Creating project...</Text>\n </Header>\n\n {jobs.map((job) => (\n <Text key={job}>{`${icons.info} ${job}`}</Text>\n ))}\n </Box>\n : null}\n\n {status === 'finished' ?\n <Header marginTop={1} icon={icons.success}>\n <Text>Done.</Text>\n </Header>\n : null}\n </Box>\n );\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -17,6 +17,7 @@ export function runCreateProject({
17
17
  args
18
18
  });
19
19
  observer.next("Updating the new project");
20
+ project.config.template ??= templateId;
20
21
  await project.update({ args });
21
22
  })().then(() => {
22
23
  observer.complete();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/commands/create-project/runCreateProject.ts"],
4
- "sourcesContent": ["import {type CommandArguments} from '@jakubmazanec/cli';\nimport Observable from 'zen-observable';\n\nimport {type Workspace} from '../../workspace.js';\nimport {type createProjectCommand} from './createProjectCommand.js';\n\nexport type CreateProjectOptions = {\n projectPath: string;\n projectName: string;\n templateId: string;\n workspace: Workspace | Workspace<false>;\n args: CommandArguments<typeof createProjectCommand>;\n};\n\nexport type CreateProjectStatus = string;\n\nexport function runCreateProject({\n projectPath,\n templateId,\n projectName,\n workspace,\n args,\n}: CreateProjectOptions) {\n return new Observable<CreateProjectStatus>((observer) => {\n (async () => {\n observer.next('Creating files');\n\n let project = await workspace.createProject({\n projectPath,\n projectName,\n templateId,\n args,\n });\n\n observer.next('Updating the new project');\n\n await project.update({args});\n })()\n .then(() => {\n observer.complete();\n })\n .catch((error) => {\n observer.error(error);\n });\n });\n}\n"],
5
- "mappings": ";AACA,OAAO,gBAAgB;AAehB,gBAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,SAAO,IAAI,WAAgC,CAAC,aAAa;AACvD,KAAC,YAAY;AACX,eAAS,KAAK,gBAAgB;AAE9B,UAAI,UAAU,MAAM,UAAU,cAAc;AAAA,QAC1C;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,eAAS,KAAK,0BAA0B;AAExC,YAAM,QAAQ,OAAO,EAAC,KAAI,CAAC;AAAA,IAC7B,GAAG,EACA,KAAK,MAAM;AACV,eAAS,SAAS;AAAA,IACpB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,eAAS,MAAM,KAAK;AAAA,IACtB,CAAC;AAAA,EACL,CAAC;AACH;",
4
+ "sourcesContent": ["import {type CommandArguments} from '@jakubmazanec/cli';\nimport Observable from 'zen-observable';\n\nimport {type Workspace} from '../../workspace.js';\nimport {type createProjectCommand} from './createProjectCommand.js';\n\nexport type CreateProjectOptions = {\n projectPath: string;\n projectName: string;\n templateId: string;\n workspace: Workspace | Workspace<false>;\n args: CommandArguments<typeof createProjectCommand>;\n};\n\nexport type CreateProjectStatus = string;\n\nexport function runCreateProject({\n projectPath,\n templateId,\n projectName,\n workspace,\n args,\n}: CreateProjectOptions) {\n return new Observable<CreateProjectStatus>((observer) => {\n (async () => {\n observer.next('Creating files');\n\n let project = await workspace.createProject({\n projectPath,\n projectName,\n templateId,\n args,\n });\n\n observer.next('Updating the new project');\n\n // if the project doesn't have config with a template ID, it's on purpose, but it's still needed for the next update, so we'll add it manually\n project.config.template ??= templateId;\n\n await project.update({args});\n })()\n .then(() => {\n observer.complete();\n })\n .catch((error) => {\n observer.error(error);\n });\n });\n}\n"],
5
+ "mappings": ";AACA,OAAO,gBAAgB;AAehB,gBAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,SAAO,IAAI,WAAgC,CAAC,aAAa;AACvD,KAAC,YAAY;AACX,eAAS,KAAK,gBAAgB;AAE9B,UAAI,UAAU,MAAM,UAAU,cAAc;AAAA,QAC1C;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,eAAS,KAAK,0BAA0B;AAGxC,cAAQ,OAAO,aAAa;AAE5B,YAAM,QAAQ,OAAO,EAAC,KAAI,CAAC;AAAA,IAC7B,GAAG,EACA,KAAK,MAAM;AACV,eAAS,SAAS;AAAA,IACpB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,eAAS,MAAM,KAAK;AAAA,IACtB,CAAC;AAAA,EACL,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -11,6 +11,7 @@ export function runCreateWorkspace({ workspacePath, templateId, args }) {
11
11
  templateId
12
12
  });
13
13
  observer.next("Updating the new workspace");
14
+ workspace.config.template ??= templateId;
14
15
  await workspace.update({ args });
15
16
  })().then(() => {
16
17
  observer.complete();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/commands/create-workspace/runCreateWorkspace.ts"],
4
- "sourcesContent": ["import {type CommandArguments} from '@jakubmazanec/cli';\nimport Observable from 'zen-observable';\n\nimport {Workspace} from '../../workspace.js';\nimport {type createWorkspaceCommand} from './createWorkspaceCommand.js';\n\nexport type CreateWorkspaceOptions = {\n workspacePath: string;\n templateId: string;\n args: CommandArguments<typeof createWorkspaceCommand>;\n};\n\nexport type CreateWorkspaceStatus = string;\n\nexport function runCreateWorkspace({workspacePath, templateId, args}: CreateWorkspaceOptions) {\n return new Observable<CreateWorkspaceStatus>((observer) => {\n (async () => {\n observer.next('Creating files');\n\n let workspace = await Workspace.create({\n args,\n path: workspacePath,\n templateId,\n });\n\n observer.next('Updating the new workspace');\n\n await workspace.update({args});\n })()\n .then(() => {\n observer.complete();\n })\n .catch((error) => {\n observer.error(error);\n });\n });\n}\n"],
5
- "mappings": ";AACA,OAAO,gBAAgB;AAEvB,SAAQ,iBAAgB;AAWjB,gBAAS,mBAAmB,EAAC,eAAe,YAAY,KAAI,GAA2B;AAC5F,SAAO,IAAI,WAAkC,CAAC,aAAa;AACzD,KAAC,YAAY;AACX,eAAS,KAAK,gBAAgB;AAE9B,UAAI,YAAY,MAAM,UAAU,OAAO;AAAA,QACrC;AAAA,QACA,MAAM;AAAA,QACN;AAAA,MACF,CAAC;AAED,eAAS,KAAK,4BAA4B;AAE1C,YAAM,UAAU,OAAO,EAAC,KAAI,CAAC;AAAA,IAC/B,GAAG,EACA,KAAK,MAAM;AACV,eAAS,SAAS;AAAA,IACpB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,eAAS,MAAM,KAAK;AAAA,IACtB,CAAC;AAAA,EACL,CAAC;AACH;",
4
+ "sourcesContent": ["import {type CommandArguments} from '@jakubmazanec/cli';\nimport Observable from 'zen-observable';\n\nimport {Workspace} from '../../workspace.js';\nimport {type createWorkspaceCommand} from './createWorkspaceCommand.js';\n\nexport type CreateWorkspaceOptions = {\n workspacePath: string;\n templateId: string;\n args: CommandArguments<typeof createWorkspaceCommand>;\n};\n\nexport type CreateWorkspaceStatus = string;\n\nexport function runCreateWorkspace({workspacePath, templateId, args}: CreateWorkspaceOptions) {\n return new Observable<CreateWorkspaceStatus>((observer) => {\n (async () => {\n observer.next('Creating files');\n\n let workspace = await Workspace.create({\n args,\n path: workspacePath,\n templateId,\n });\n\n observer.next('Updating the new workspace');\n\n // if the workspace doesn't have config with a template ID, it's on purpose, but it's still needed for the next update, so we'll add it manually\n workspace.config.template ??= templateId;\n\n await workspace.update({args});\n })()\n .then(() => {\n observer.complete();\n })\n .catch((error) => {\n observer.error(error);\n });\n });\n}\n"],
5
+ "mappings": ";AACA,OAAO,gBAAgB;AAEvB,SAAQ,iBAAgB;AAWjB,gBAAS,mBAAmB,EAAC,eAAe,YAAY,KAAI,GAA2B;AAC5F,SAAO,IAAI,WAAkC,CAAC,aAAa;AACzD,KAAC,YAAY;AACX,eAAS,KAAK,gBAAgB;AAE9B,UAAI,YAAY,MAAM,UAAU,OAAO;AAAA,QACrC;AAAA,QACA,MAAM;AAAA,QACN;AAAA,MACF,CAAC;AAED,eAAS,KAAK,4BAA4B;AAG1C,gBAAU,OAAO,aAAa;AAE9B,YAAM,UAAU,OAAO,EAAC,KAAI,CAAC;AAAA,IAC/B,GAAG,EACA,KAAK,MAAM;AACV,eAAS,SAAS;AAAA,IACpB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,eAAS,MAAM,KAAK;AAAA,IACtB,CAAC;AAAA,EACL,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -6,6 +6,8 @@ import { type templateDataSchema } from './TemplateData.js';
6
6
  * Carson template.
7
7
  */
8
8
  export type CarsonTemplate = {
9
+ /** Carson template ID. */
10
+ id: string;
9
11
  /** Carson template name. */
10
12
  name: string;
11
13
  /** Carson template config. */
@@ -1,13 +1,10 @@
1
1
  import { z } from 'zod';
2
2
  export declare const carsonTemplateConfigSchema: z.ZodObject<{
3
- disallowMultiProjectWorkspace: z.ZodOptional<z.ZodBoolean>;
4
- disallowSingleProjectWorkspace: z.ZodOptional<z.ZodBoolean>;
3
+ autoEject: z.ZodOptional<z.ZodBoolean>;
5
4
  }, "strict", z.ZodTypeAny, {
6
- disallowMultiProjectWorkspace?: boolean | undefined;
7
- disallowSingleProjectWorkspace?: boolean | undefined;
5
+ autoEject?: boolean | undefined;
8
6
  }, {
9
- disallowMultiProjectWorkspace?: boolean | undefined;
10
- disallowSingleProjectWorkspace?: boolean | undefined;
7
+ autoEject?: boolean | undefined;
11
8
  }>;
12
9
  /**
13
10
  * Carson template config.
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  import { z } from "zod";
3
3
  export const carsonTemplateConfigSchema = z.object({
4
- disallowMultiProjectWorkspace: z.boolean().optional(),
5
- disallowSingleProjectWorkspace: z.boolean().optional()
6
- // TODO: add extends property to allow reuisng template files from another carson template
4
+ // disallowMultiProjectWorkspace: z.boolean().optional(),
5
+ // disallowSingleProjectWorkspace: z.boolean().optional(),
6
+ autoEject: z.boolean().optional()
7
7
  }).strict();
8
8
  //# sourceMappingURL=CarsonTemplateConfig.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/template/CarsonTemplateConfig.ts"],
4
- "sourcesContent": ["import {z} from 'zod';\n\nexport const carsonTemplateConfigSchema = z\n .object({\n disallowMultiProjectWorkspace: z.boolean().optional(),\n disallowSingleProjectWorkspace: z.boolean().optional(),\n\n // TODO: add extends property to allow reuisng template files from another carson template\n })\n .strict();\n\n/**\n * Carson template config.\n */\nexport type CarsonTemplateConfig = z.infer<typeof carsonTemplateConfigSchema>;\n"],
5
- "mappings": ";AAAA,SAAQ,SAAQ;AAET,aAAM,6BAA6B,EACvC,OAAO;AAAA,EACN,+BAA+B,EAAE,QAAQ,EAAE,SAAS;AAAA,EACpD,gCAAgC,EAAE,QAAQ,EAAE,SAAS;AAAA;AAGvD,CAAC,EACA,OAAO;",
4
+ "sourcesContent": ["import {z} from 'zod';\n\nexport const carsonTemplateConfigSchema = z\n .object({\n // disallowMultiProjectWorkspace: z.boolean().optional(),\n // disallowSingleProjectWorkspace: z.boolean().optional(),\n\n autoEject: z.boolean().optional(),\n })\n .strict();\n\n/**\n * Carson template config.\n */\nexport type CarsonTemplateConfig = z.infer<typeof carsonTemplateConfigSchema>;\n"],
5
+ "mappings": ";AAAA,SAAQ,SAAQ;AAET,aAAM,6BAA6B,EACvC,OAAO;AAAA;AAAA;AAAA,EAIN,WAAW,EAAE,QAAQ,EAAE,SAAS;AAClC,CAAC,EACA,OAAO;",
6
6
  "names": []
7
7
  }
@@ -2,7 +2,7 @@ import { type TemplateRenders } from './TemplateRenders.js';
2
2
  export type ApplyTemplateRendersOptions = {
3
3
  templateRenders: TemplateRenders;
4
4
  targetPath: string;
5
- snapshotPath: string;
5
+ snapshotPath?: string | undefined;
6
6
  ignoreStrategies: string[];
7
7
  };
8
8
  /**
@@ -22,7 +22,7 @@ export async function applyTemplateRenders({
22
22
  ignoreStrategies
23
23
  }) {
24
24
  await prettier.clearConfigCache();
25
- if (await fs.pathExists(snapshotPath)) {
25
+ if (snapshotPath && await fs.pathExists(snapshotPath)) {
26
26
  let templateRenderSnapshots = await loadTemplateRenderSnapshots(snapshotPath);
27
27
  for (let templateRenderSnapshot of templateRenderSnapshots) {
28
28
  let strategy = typeof templateRenderSnapshot.attributes.strategy === "string" ? templateRenderSnapshot.attributes.strategy : templateRenderSnapshot.attributes.strategy[0];
@@ -88,7 +88,9 @@ export async function applyTemplateRenders({
88
88
  }
89
89
  }
90
90
  }
91
- await fs.ensureDir(path.join(targetPath, CARSON_CONFIG_DIRECTORY));
92
- await saveTemplateRenderSnapshots(templateRenders, snapshotPath);
91
+ if (snapshotPath) {
92
+ await fs.ensureDir(path.join(targetPath, CARSON_CONFIG_DIRECTORY));
93
+ await saveTemplateRenderSnapshots(templateRenders, snapshotPath);
94
+ }
93
95
  }
94
96
  //# sourceMappingURL=applyTemplateRenders.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/template/applyTemplateRenders.ts"],
4
- "sourcesContent": ["// TODO: can this be fixed?\n/* eslint-disable complexity -- TODO */\nimport fs from 'fs-extra';\nimport path from 'node:path';\nimport prettier from 'prettier';\n\nimport {CARSON_CONFIG_DIRECTORY} from '../constants.js';\nimport {CarsonTemplateError} from './CarsonTemplateError.js';\nimport {\n createUsingTemplateRender,\n deleteUsingTemplateRender,\n insertUsingTemplateRender,\n loadTemplateRenderSnapshots,\n mergeUsingTemplateRender,\n overwriteUsingTemplateRender,\n saveTemplateRenderSnapshots,\n uninsertUsingTemplateRender,\n unmergeUsingTemplateRender,\n} from './internals.js';\nimport {type TemplateRenders} from './TemplateRenders.js';\n\nexport type ApplyTemplateRendersOptions = {\n templateRenders: TemplateRenders;\n targetPath: string;\n snapshotPath: string;\n ignoreStrategies: string[];\n};\n\n/**\n * Applies rendered Carson template to a specified path, i.e. creates and updates files based on the result of rendering each Carson template file.\n */\nexport async function applyTemplateRenders({\n templateRenders,\n targetPath,\n snapshotPath,\n ignoreStrategies,\n}: ApplyTemplateRendersOptions) {\n // we need to clear Prettier cache, because we are changing file system\n await prettier.clearConfigCache();\n\n // first, we read the existing snapshots and use them to undo previous changes\n if (await fs.pathExists(snapshotPath)) {\n let templateRenderSnapshots = await loadTemplateRenderSnapshots(snapshotPath);\n\n for (let templateRenderSnapshot of templateRenderSnapshots) {\n let strategy =\n typeof templateRenderSnapshot.attributes.strategy === 'string' ?\n templateRenderSnapshot.attributes.strategy\n : templateRenderSnapshot.attributes.strategy[0];\n\n if (ignoreStrategies.includes(strategy)) {\n continue;\n }\n\n if (templateRenderSnapshot.attributes.strategy === 'ensure') {\n await deleteUsingTemplateRender(templateRenderSnapshot, targetPath, {\n onlyDeleteWhenContentsMatch: true,\n });\n }\n\n if (templateRenderSnapshot.attributes.strategy === 'overwrite') {\n await deleteUsingTemplateRender(templateRenderSnapshot, targetPath);\n }\n\n if (templateRenderSnapshot.attributes.strategy === 'merge') {\n await unmergeUsingTemplateRender(templateRenderSnapshot, targetPath);\n }\n\n if (templateRenderSnapshot.attributes.strategy[0] === 'insert') {\n await uninsertUsingTemplateRender(templateRenderSnapshot, targetPath);\n }\n }\n }\n\n // second, we apply strategies that create files\n for (let templateRender of templateRenders) {\n let strategy =\n typeof templateRender.attributes.strategy === 'string' ?\n templateRender.attributes.strategy\n : templateRender.attributes.strategy[0];\n\n if (ignoreStrategies.includes(strategy)) {\n continue;\n }\n\n if (templateRender.attributes.strategy === 'create') {\n await createUsingTemplateRender(templateRender, targetPath);\n }\n\n if (templateRender.attributes.strategy === 'ensure') {\n let to = path.join(targetPath, templateRender.attributes.to);\n let doesToExist = await fs.pathExists(to);\n\n if (!doesToExist) {\n await createUsingTemplateRender(templateRender, targetPath);\n }\n }\n }\n\n // third, we apply strategies that change files\n for (let templateRender of templateRenders) {\n let strategy =\n typeof templateRender.attributes.strategy === 'string' ?\n templateRender.attributes.strategy\n : templateRender.attributes.strategy[0];\n\n if (ignoreStrategies.includes(strategy)) {\n continue;\n }\n\n if (templateRender.attributes.strategy === 'overwrite') {\n await overwriteUsingTemplateRender(templateRender, targetPath);\n }\n\n if (templateRender.attributes.strategy === 'merge') {\n await mergeUsingTemplateRender(templateRender, targetPath);\n }\n\n if (templateRender.attributes.strategy[0] === 'insert') {\n await insertUsingTemplateRender(templateRender, targetPath);\n }\n\n if (templateRender.attributes.strategy === 'check') {\n let to = path.join(targetPath, templateRender.attributes.to);\n let doesToExist = await fs.pathExists(to);\n\n if (!doesToExist) {\n throw new CarsonTemplateError('STRATEGY_MISSING_FILE', {\n messageParameters: [templateRender.attributes.strategy, templateRender.template.path, to],\n data: {\n path: to,\n },\n });\n }\n }\n }\n\n await fs.ensureDir(path.join(targetPath, CARSON_CONFIG_DIRECTORY));\n\n await saveTemplateRenderSnapshots(templateRenders, snapshotPath);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// TODO: can this be fixed?\n/* eslint-disable complexity -- TODO */\nimport fs from 'fs-extra';\nimport path from 'node:path';\nimport prettier from 'prettier';\n\nimport {CARSON_CONFIG_DIRECTORY} from '../constants.js';\nimport {CarsonTemplateError} from './CarsonTemplateError.js';\nimport {\n createUsingTemplateRender,\n deleteUsingTemplateRender,\n insertUsingTemplateRender,\n loadTemplateRenderSnapshots,\n mergeUsingTemplateRender,\n overwriteUsingTemplateRender,\n saveTemplateRenderSnapshots,\n uninsertUsingTemplateRender,\n unmergeUsingTemplateRender,\n} from './internals.js';\nimport {type TemplateRenders} from './TemplateRenders.js';\n\nexport type ApplyTemplateRendersOptions = {\n templateRenders: TemplateRenders;\n targetPath: string;\n snapshotPath?: string | undefined;\n ignoreStrategies: string[];\n};\n\n/**\n * Applies rendered Carson template to a specified path, i.e. creates and updates files based on the result of rendering each Carson template file.\n */\nexport async function applyTemplateRenders({\n templateRenders,\n targetPath,\n snapshotPath,\n ignoreStrategies,\n}: ApplyTemplateRendersOptions) {\n // we need to clear Prettier cache, because we are changing file system\n await prettier.clearConfigCache();\n\n // first, we read the existing snapshots and use them to undo previous changes\n if (snapshotPath && (await fs.pathExists(snapshotPath))) {\n let templateRenderSnapshots = await loadTemplateRenderSnapshots(snapshotPath);\n\n for (let templateRenderSnapshot of templateRenderSnapshots) {\n let strategy =\n typeof templateRenderSnapshot.attributes.strategy === 'string' ?\n templateRenderSnapshot.attributes.strategy\n : templateRenderSnapshot.attributes.strategy[0];\n\n if (ignoreStrategies.includes(strategy)) {\n continue;\n }\n\n if (templateRenderSnapshot.attributes.strategy === 'ensure') {\n await deleteUsingTemplateRender(templateRenderSnapshot, targetPath, {\n onlyDeleteWhenContentsMatch: true,\n });\n }\n\n if (templateRenderSnapshot.attributes.strategy === 'overwrite') {\n await deleteUsingTemplateRender(templateRenderSnapshot, targetPath);\n }\n\n if (templateRenderSnapshot.attributes.strategy === 'merge') {\n await unmergeUsingTemplateRender(templateRenderSnapshot, targetPath);\n }\n\n if (templateRenderSnapshot.attributes.strategy[0] === 'insert') {\n await uninsertUsingTemplateRender(templateRenderSnapshot, targetPath);\n }\n }\n }\n\n // second, we apply strategies that create files\n for (let templateRender of templateRenders) {\n let strategy =\n typeof templateRender.attributes.strategy === 'string' ?\n templateRender.attributes.strategy\n : templateRender.attributes.strategy[0];\n\n if (ignoreStrategies.includes(strategy)) {\n continue;\n }\n\n if (templateRender.attributes.strategy === 'create') {\n await createUsingTemplateRender(templateRender, targetPath);\n }\n\n if (templateRender.attributes.strategy === 'ensure') {\n let to = path.join(targetPath, templateRender.attributes.to);\n let doesToExist = await fs.pathExists(to);\n\n if (!doesToExist) {\n await createUsingTemplateRender(templateRender, targetPath);\n }\n }\n }\n\n // third, we apply strategies that change files\n for (let templateRender of templateRenders) {\n let strategy =\n typeof templateRender.attributes.strategy === 'string' ?\n templateRender.attributes.strategy\n : templateRender.attributes.strategy[0];\n\n if (ignoreStrategies.includes(strategy)) {\n continue;\n }\n\n if (templateRender.attributes.strategy === 'overwrite') {\n await overwriteUsingTemplateRender(templateRender, targetPath);\n }\n\n if (templateRender.attributes.strategy === 'merge') {\n await mergeUsingTemplateRender(templateRender, targetPath);\n }\n\n if (templateRender.attributes.strategy[0] === 'insert') {\n await insertUsingTemplateRender(templateRender, targetPath);\n }\n\n if (templateRender.attributes.strategy === 'check') {\n let to = path.join(targetPath, templateRender.attributes.to);\n let doesToExist = await fs.pathExists(to);\n\n if (!doesToExist) {\n throw new CarsonTemplateError('STRATEGY_MISSING_FILE', {\n messageParameters: [templateRender.attributes.strategy, templateRender.template.path, to],\n data: {\n path: to,\n },\n });\n }\n }\n }\n\n if (snapshotPath) {\n await fs.ensureDir(path.join(targetPath, CARSON_CONFIG_DIRECTORY));\n\n await saveTemplateRenderSnapshots(templateRenders, snapshotPath);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -24,6 +24,7 @@ export async function readCarsonTemplate(templateId) {
24
24
  dot: true
25
25
  });
26
26
  let carsonTemplate = {
27
+ id: templateId,
27
28
  name: templateName,
28
29
  config: templateConfig,
29
30
  files: []
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../source/template/internals/readCarsonTemplate.ts"],
4
- "sourcesContent": ["import {Template} from '@jakubmazanec/template';\nimport {readFile} from '@jakubmazanec/zod-utils';\nimport glob from 'fast-glob';\nimport fs from 'fs-extra';\nimport path from 'node:path';\n\nimport {TEMPLATE_CONFIG_FILENAME, TEMPLATES_PATH} from '../../constants.js';\nimport {type CarsonTemplate} from '../CarsonTemplate.js';\nimport {carsonTemplateConfigSchema} from '../CarsonTemplateConfig.js';\nimport {CarsonTemplateError} from '../CarsonTemplateError.js';\nimport {templateAttributesSchema} from '../TemplateAttributes.js';\nimport {parseCarsonTemplateId} from './parseCarsonTemplateId.js';\nimport {resolveModule} from './resolveModule.js';\n\nexport async function readCarsonTemplate(templateId: string): Promise<CarsonTemplate> {\n let [moduleId, templateName] = parseCarsonTemplateId(templateId);\n let modulePath = await resolveModule(moduleId);\n let carsonTemplatePath = path.join(modulePath, TEMPLATES_PATH, templateName);\n\n if (await fs.pathExists(carsonTemplatePath)) {\n let templateConfigPath = path.join(carsonTemplatePath, TEMPLATE_CONFIG_FILENAME);\n let templateConfig = await readFile(templateConfigPath, carsonTemplateConfigSchema, {\n throwOnZodError: true,\n });\n let templateFilePaths = await glob('**/*.ejs', {\n cwd: carsonTemplatePath,\n dot: true,\n });\n let carsonTemplate: CarsonTemplate = {\n name: templateName,\n config: templateConfig,\n files: [],\n };\n\n for (let templateFilePath of templateFilePaths) {\n carsonTemplate.files.push(\n await Template.read(path.join(carsonTemplatePath, templateFilePath), {\n attributesSchema: templateAttributesSchema,\n }),\n );\n }\n\n return carsonTemplate;\n }\n\n throw new CarsonTemplateError('CARSON_TEMPLATE_NOT_FOUND', {\n messageParameters: [templateId, moduleId],\n });\n}\n"],
5
- "mappings": ";AAAA,SAAQ,gBAAe;AACvB,SAAQ,gBAAe;AACvB,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,SAAQ,0BAA0B,sBAAqB;AAEvD,SAAQ,kCAAiC;AACzC,SAAQ,2BAA0B;AAClC,SAAQ,gCAA+B;AACvC,SAAQ,6BAA4B;AACpC,SAAQ,qBAAoB;AAE5B,sBAAsB,mBAAmB,YAA6C;AACpF,MAAI,CAAC,UAAU,YAAY,IAAI,sBAAsB,UAAU;AAC/D,MAAI,aAAa,MAAM,cAAc,QAAQ;AAC7C,MAAI,qBAAqB,KAAK,KAAK,YAAY,gBAAgB,YAAY;AAE3E,MAAI,MAAM,GAAG,WAAW,kBAAkB,GAAG;AAC3C,QAAI,qBAAqB,KAAK,KAAK,oBAAoB,wBAAwB;AAC/E,QAAI,iBAAiB,MAAM,SAAS,oBAAoB,4BAA4B;AAAA,MAClF,iBAAiB;AAAA,IACnB,CAAC;AACD,QAAI,oBAAoB,MAAM,KAAK,YAAY;AAAA,MAC7C,KAAK;AAAA,MACL,KAAK;AAAA,IACP,CAAC;AACD,QAAI,iBAAiC;AAAA,MACnC,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,OAAO,CAAC;AAAA,IACV;AAEA,aAAS,oBAAoB,mBAAmB;AAC9C,qBAAe,MAAM;AAAA,QACnB,MAAM,SAAS,KAAK,KAAK,KAAK,oBAAoB,gBAAgB,GAAG;AAAA,UACnE,kBAAkB;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,oBAAoB,6BAA6B;AAAA,IACzD,mBAAmB,CAAC,YAAY,QAAQ;AAAA,EAC1C,CAAC;AACH;",
4
+ "sourcesContent": ["import {Template} from '@jakubmazanec/template';\nimport {readFile} from '@jakubmazanec/zod-utils';\nimport glob from 'fast-glob';\nimport fs from 'fs-extra';\nimport path from 'node:path';\n\nimport {TEMPLATE_CONFIG_FILENAME, TEMPLATES_PATH} from '../../constants.js';\nimport {type CarsonTemplate} from '../CarsonTemplate.js';\nimport {carsonTemplateConfigSchema} from '../CarsonTemplateConfig.js';\nimport {CarsonTemplateError} from '../CarsonTemplateError.js';\nimport {templateAttributesSchema} from '../TemplateAttributes.js';\nimport {parseCarsonTemplateId} from './parseCarsonTemplateId.js';\nimport {resolveModule} from './resolveModule.js';\n\nexport async function readCarsonTemplate(templateId: string): Promise<CarsonTemplate> {\n let [moduleId, templateName] = parseCarsonTemplateId(templateId);\n let modulePath = await resolveModule(moduleId);\n let carsonTemplatePath = path.join(modulePath, TEMPLATES_PATH, templateName);\n\n if (await fs.pathExists(carsonTemplatePath)) {\n let templateConfigPath = path.join(carsonTemplatePath, TEMPLATE_CONFIG_FILENAME);\n let templateConfig = await readFile(templateConfigPath, carsonTemplateConfigSchema, {\n throwOnZodError: true,\n });\n let templateFilePaths = await glob('**/*.ejs', {\n cwd: carsonTemplatePath,\n dot: true,\n });\n let carsonTemplate: CarsonTemplate = {\n id: templateId,\n name: templateName,\n config: templateConfig,\n files: [],\n };\n\n for (let templateFilePath of templateFilePaths) {\n carsonTemplate.files.push(\n await Template.read(path.join(carsonTemplatePath, templateFilePath), {\n attributesSchema: templateAttributesSchema,\n }),\n );\n }\n\n return carsonTemplate;\n }\n\n throw new CarsonTemplateError('CARSON_TEMPLATE_NOT_FOUND', {\n messageParameters: [templateId, moduleId],\n });\n}\n"],
5
+ "mappings": ";AAAA,SAAQ,gBAAe;AACvB,SAAQ,gBAAe;AACvB,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,SAAQ,0BAA0B,sBAAqB;AAEvD,SAAQ,kCAAiC;AACzC,SAAQ,2BAA0B;AAClC,SAAQ,gCAA+B;AACvC,SAAQ,6BAA4B;AACpC,SAAQ,qBAAoB;AAE5B,sBAAsB,mBAAmB,YAA6C;AACpF,MAAI,CAAC,UAAU,YAAY,IAAI,sBAAsB,UAAU;AAC/D,MAAI,aAAa,MAAM,cAAc,QAAQ;AAC7C,MAAI,qBAAqB,KAAK,KAAK,YAAY,gBAAgB,YAAY;AAE3E,MAAI,MAAM,GAAG,WAAW,kBAAkB,GAAG;AAC3C,QAAI,qBAAqB,KAAK,KAAK,oBAAoB,wBAAwB;AAC/E,QAAI,iBAAiB,MAAM,SAAS,oBAAoB,4BAA4B;AAAA,MAClF,iBAAiB;AAAA,IACnB,CAAC;AACD,QAAI,oBAAoB,MAAM,KAAK,YAAY;AAAA,MAC7C,KAAK;AAAA,MACL,KAAK;AAAA,IACP,CAAC;AACD,QAAI,iBAAiC;AAAA,MACnC,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,OAAO,CAAC;AAAA,IACV;AAEA,aAAS,oBAAoB,mBAAmB;AAC9C,qBAAe,MAAM;AAAA,QACnB,MAAM,SAAS,KAAK,KAAK,KAAK,oBAAoB,gBAAgB,GAAG;AAAA,UACnE,kBAAkB;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,oBAAoB,6BAA6B;AAAA,IACzD,mBAAmB,CAAC,YAAY,QAAQ;AAAA,EAC1C,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,8 @@
1
+ import { type CarsonTemplate } from './CarsonTemplate.js';
1
2
  import { type TemplateData } from './TemplateData.js';
2
3
  import { type TemplateRenders } from './TemplateRenders.js';
3
4
  export type RenderCarsonTemplateOptions = {
4
- templateId: string;
5
+ template: CarsonTemplate;
5
6
  templateData: TemplateData;
6
7
  };
7
8
  /**
@@ -2,19 +2,13 @@
2
2
  import { pathToPosixPath } from "@jakubmazanec/fs-utils";
3
3
  import _ from "lodash";
4
4
  import path from "node:path";
5
- import {
6
- importCarsonTemplate,
7
- parseCarsonTemplateId,
8
- readCarsonTemplate,
9
- resolveModule
10
- } from "./internals.js";
5
+ import { importCarsonTemplate, parseCarsonTemplateId, resolveModule } from "./internals.js";
11
6
  export async function renderCarsonTemplate(options) {
12
- let [moduleId] = parseCarsonTemplateId(options.templateId);
7
+ let [moduleId] = parseCarsonTemplateId(options.template.id);
13
8
  let modulePath = await resolveModule(moduleId);
14
- let template = await readCarsonTemplate(options.templateId);
15
- let templateModule = await importCarsonTemplate(options.templateId);
9
+ let templateModule = await importCarsonTemplate(options.template.id);
16
10
  let templateRenders = [];
17
- for (let file of template.files) {
11
+ for (let file of options.template.files) {
18
12
  templateRenders.push(
19
13
  ...(await file.render(
20
14
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/template/renderCarsonTemplate.ts"],
4
- "sourcesContent": ["import {pathToPosixPath} from '@jakubmazanec/fs-utils';\nimport _ from 'lodash';\nimport path from 'node:path';\n\nimport {\n importCarsonTemplate,\n parseCarsonTemplateId,\n readCarsonTemplate,\n resolveModule,\n} from './internals.js';\nimport {type TemplateData} from './TemplateData.js';\nimport {type TemplateRenders} from './TemplateRenders.js';\n\nexport type RenderCarsonTemplateOptions = {\n templateId: string;\n templateData: TemplateData;\n};\n\n/**\n * Renders a Carson template with provided template data.\n */\nexport async function renderCarsonTemplate(\n options: RenderCarsonTemplateOptions,\n): Promise<TemplateRenders> {\n let [moduleId] = parseCarsonTemplateId(options.templateId);\n let modulePath = await resolveModule(moduleId);\n let template = await readCarsonTemplate(options.templateId);\n let templateModule = await importCarsonTemplate(options.templateId);\n let templateRenders: TemplateRenders = [];\n\n for (let file of template.files) {\n templateRenders.push(\n ...(\n await file.render(\n {\n ...templateModule,\n ...options.templateData,\n },\n {disablePrettier: true},\n )\n ).map((templateRender) => ({\n ...templateRender,\n template: {\n path: pathToPosixPath(\n `${moduleId}/${path.relative(modulePath, file.path ?? modulePath)}`,\n ),\n },\n })),\n );\n }\n\n templateRenders = _.sortBy(templateRenders, [\n (templateRender) => templateRender.attributes.to,\n (templateRender) => templateRender.attributes.strategy,\n (templateRender) => templateRender.content,\n ]);\n\n return templateRenders;\n}\n"],
5
- "mappings": ";AAAA,SAAQ,uBAAsB;AAC9B,OAAO,OAAO;AACd,OAAO,UAAU;AAEjB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAYP,sBAAsB,qBACpB,SAC0B;AAC1B,MAAI,CAAC,QAAQ,IAAI,sBAAsB,QAAQ,UAAU;AACzD,MAAI,aAAa,MAAM,cAAc,QAAQ;AAC7C,MAAI,WAAW,MAAM,mBAAmB,QAAQ,UAAU;AAC1D,MAAI,iBAAiB,MAAM,qBAAqB,QAAQ,UAAU;AAClE,MAAI,kBAAmC,CAAC;AAExC,WAAS,QAAQ,SAAS,OAAO;AAC/B,oBAAgB;AAAA,MACd,IACE,MAAM,KAAK;AAAA,QACT;AAAA,UACE,GAAG;AAAA,UACH,GAAG,QAAQ;AAAA,QACb;AAAA,QACA,EAAC,iBAAiB,KAAI;AAAA,MACxB,GACA,IAAI,CAAC,oBAAoB;AAAA,QACzB,GAAG;AAAA,QACH,UAAU;AAAA,UACR,MAAM;AAAA,YACJ,GAAG,QAAQ,IAAI,KAAK,SAAS,YAAY,KAAK,QAAQ,UAAU,CAAC;AAAA,UACnE;AAAA,QACF;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,EACF;AAEA,oBAAkB,EAAE,OAAO,iBAAiB;AAAA,IAC1C,CAAC,mBAAmB,eAAe,WAAW;AAAA,IAC9C,CAAC,mBAAmB,eAAe,WAAW;AAAA,IAC9C,CAAC,mBAAmB,eAAe;AAAA,EACrC,CAAC;AAED,SAAO;AACT;",
4
+ "sourcesContent": ["import {pathToPosixPath} from '@jakubmazanec/fs-utils';\nimport _ from 'lodash';\nimport path from 'node:path';\n\nimport {type CarsonTemplate} from './CarsonTemplate.js';\nimport {importCarsonTemplate, parseCarsonTemplateId, resolveModule} from './internals.js';\nimport {type TemplateData} from './TemplateData.js';\nimport {type TemplateRenders} from './TemplateRenders.js';\n\nexport type RenderCarsonTemplateOptions = {\n template: CarsonTemplate;\n templateData: TemplateData;\n};\n\n/**\n * Renders a Carson template with provided template data.\n */\nexport async function renderCarsonTemplate(\n options: RenderCarsonTemplateOptions,\n): Promise<TemplateRenders> {\n let [moduleId] = parseCarsonTemplateId(options.template.id);\n let modulePath = await resolveModule(moduleId);\n let templateModule = await importCarsonTemplate(options.template.id);\n let templateRenders: TemplateRenders = [];\n\n for (let file of options.template.files) {\n templateRenders.push(\n ...(\n await file.render(\n {\n ...templateModule,\n ...options.templateData,\n },\n {disablePrettier: true},\n )\n ).map((templateRender) => ({\n ...templateRender,\n template: {\n path: pathToPosixPath(\n `${moduleId}/${path.relative(modulePath, file.path ?? modulePath)}`,\n ),\n },\n })),\n );\n }\n\n templateRenders = _.sortBy(templateRenders, [\n (templateRender) => templateRender.attributes.to,\n (templateRender) => templateRender.attributes.strategy,\n (templateRender) => templateRender.content,\n ]);\n\n return templateRenders;\n}\n"],
5
+ "mappings": ";AAAA,SAAQ,uBAAsB;AAC9B,OAAO,OAAO;AACd,OAAO,UAAU;AAGjB,SAAQ,sBAAsB,uBAAuB,qBAAoB;AAYzE,sBAAsB,qBACpB,SAC0B;AAC1B,MAAI,CAAC,QAAQ,IAAI,sBAAsB,QAAQ,SAAS,EAAE;AAC1D,MAAI,aAAa,MAAM,cAAc,QAAQ;AAC7C,MAAI,iBAAiB,MAAM,qBAAqB,QAAQ,SAAS,EAAE;AACnE,MAAI,kBAAmC,CAAC;AAExC,WAAS,QAAQ,QAAQ,SAAS,OAAO;AACvC,oBAAgB;AAAA,MACd,IACE,MAAM,KAAK;AAAA,QACT;AAAA,UACE,GAAG;AAAA,UACH,GAAG,QAAQ;AAAA,QACb;AAAA,QACA,EAAC,iBAAiB,KAAI;AAAA,MACxB,GACA,IAAI,CAAC,oBAAoB;AAAA,QACzB,GAAG;AAAA,QACH,UAAU;AAAA,UACR,MAAM;AAAA,YACJ,GAAG,QAAQ,IAAI,KAAK,SAAS,YAAY,KAAK,QAAQ,UAAU,CAAC;AAAA,UACnE;AAAA,QACF;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,EACF;AAEA,oBAAkB,EAAE,OAAO,iBAAiB;AAAA,IAC1C,CAAC,mBAAmB,eAAe,WAAW;AAAA,IAC9C,CAAC,mBAAmB,eAAe,WAAW;AAAA,IAC9C,CAAC,mBAAmB,eAAe;AAAA,EACrC,CAAC;AAED,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -11,6 +11,7 @@ import {
11
11
  PROJECT_SNAPSHOT_FILENAME
12
12
  } from "../constants.js";
13
13
  import { applyTemplateRenders } from "../template/applyTemplateRenders.js";
14
+ import { readCarsonTemplate } from "../template/internals.js";
14
15
  import { renderCarsonTemplate } from "../template/renderCarsonTemplate.js";
15
16
  import { projectConfigSchema } from "./ProjectConfig.js";
16
17
  import { ProjectError } from "./ProjectError.js";
@@ -88,8 +89,9 @@ export class Project {
88
89
  });
89
90
  }
90
91
  }
92
+ let template = await readCarsonTemplate(templateId);
91
93
  let templateRenders = await renderCarsonTemplate({
92
- templateId,
94
+ template,
93
95
  templateData: {
94
96
  workspace,
95
97
  project,
@@ -99,10 +101,12 @@ export class Project {
99
101
  await applyTemplateRenders({
100
102
  templateRenders,
101
103
  targetPath: project.path,
102
- snapshotPath: path.join(project.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),
104
+ snapshotPath: template.config.autoEject || !workspace.config.template ? void 0 : path.join(project.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),
103
105
  ignoreStrategies: ["check"]
104
106
  });
105
- await saveProjectConfig({ projectPath: project.path, projectConfig: { template: templateId } });
107
+ if (!template.config.autoEject && workspace.config.template) {
108
+ await saveProjectConfig({ projectPath: project.path, projectConfig: { template: templateId } });
109
+ }
106
110
  await project.read();
107
111
  return project;
108
112
  }
@@ -184,8 +188,9 @@ export class Project {
184
188
  messageParameters: [path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_CONFIG_FILENAME)]
185
189
  });
186
190
  }
191
+ let template = await readCarsonTemplate(this.config.template);
187
192
  let templateRenders = await renderCarsonTemplate({
188
- templateId: this.config.template,
193
+ template,
189
194
  templateData: {
190
195
  workspace: this.workspace,
191
196
  project: this,
@@ -195,7 +200,7 @@ export class Project {
195
200
  await applyTemplateRenders({
196
201
  templateRenders,
197
202
  targetPath: this.path,
198
- snapshotPath: path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),
203
+ snapshotPath: template.config.autoEject || !this.workspace.config.template ? void 0 : path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),
199
204
  ignoreStrategies: ["create"]
200
205
  });
201
206
  await this.read();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/workspace/Project.ts"],
4
- "sourcesContent": ["import {ensureEmptyDirectory, pathToPosixPath} from '@jakubmazanec/fs-utils';\nimport {type PackageJson, packageJsonSchema, readFile} from '@jakubmazanec/zod-utils';\nimport fs from 'fs-extra';\nimport json5 from 'json5';\nimport path from 'node:path';\nimport {z} from 'zod';\n\nimport {\n CARSON_CONFIG_DIRECTORY,\n PROJECT_CONFIG_FILENAME,\n PROJECT_SNAPSHOT_FILENAME,\n} from '../constants.js';\nimport {applyTemplateRenders} from '../template/applyTemplateRenders.js';\nimport {renderCarsonTemplate} from '../template/renderCarsonTemplate.js';\nimport {type ProjectConfig, projectConfigSchema} from './ProjectConfig.js';\nimport {type ProjectCreateOptions} from './ProjectCreateOptions.js';\nimport {ProjectError} from './ProjectError.js';\nimport {type ProjectOptions} from './ProjectOptions.js';\nimport {type ProjectUpdateOptions} from './ProjectUpdateOptions.js';\nimport {saveProjectConfig} from './saveProjectConfig.js';\nimport {type Workspace} from './Workspace.js';\n\n/**\n * 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.\n *\n * @typeParam M If true, the project belongs to a multi-project workspace.\n */\nexport class Project<M extends boolean = true> {\n /** Project name. */\n name?: string;\n\n /** Project path. */\n path: string;\n\n /** Project path relative to workspace path. */\n relativePath: string;\n\n /** Project configuration; if it's not found, the default is an empty object. */\n config: ProjectConfig;\n\n /** Parsed project `package.json` file; if it's not found, the default is an empty object. */\n packageJson: PackageJson;\n\n /** Parent {@link Workspace} instance. */\n workspace: Workspace<M>;\n\n /** Errors found during reading from the file system. */\n errors: Array<InstanceType<typeof ProjectError>> = [];\n\n constructor({\n path: projectPath,\n name,\n config,\n packageJson,\n workspace,\n errors,\n }: ProjectOptions<M>) {\n // TODO: check that this path and workspace path are correct, i.e. project path must always be inside of workspace path\n this.path = projectPath;\n\n if (name) {\n this.name = name;\n }\n\n if (config) {\n this.config = config;\n } else {\n this.config = {};\n }\n\n if (packageJson) {\n this.packageJson = packageJson;\n } else {\n this.packageJson = {};\n }\n\n this.workspace = workspace;\n\n if (errors) {\n this.errors = errors;\n }\n\n if (this.packageJson.name?.length) {\n this.name = this.packageJson.name;\n }\n\n this.relativePath = pathToPosixPath(path.relative(this.workspace.path, this.path));\n }\n\n static async create<M extends boolean>({\n templateId,\n workspace,\n projectPath,\n projectName,\n args,\n }: ProjectCreateOptions<M>): Promise<Project<M>> {\n let project = new this({\n path: projectPath,\n name: projectName,\n config: {\n template: templateId,\n },\n workspace,\n });\n\n // if the workspace is single-project, it shares a directory with the project, so we can't insist on it being an empty directory\n if (workspace.isMultiProject) {\n try {\n await ensureEmptyDirectory(project.path);\n } catch {\n throw new ProjectError('PROJECT_PATH_NOT_EMPTY', {\n messageParameters: [project.path],\n data: {\n path: project.path,\n },\n });\n }\n }\n\n let templateRenders = await renderCarsonTemplate({\n templateId,\n templateData: {\n workspace,\n project,\n args,\n },\n });\n\n await applyTemplateRenders({\n templateRenders,\n targetPath: project.path,\n snapshotPath: path.join(project.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),\n ignoreStrategies: ['check'],\n });\n\n await saveProjectConfig({projectPath: project.path, projectConfig: {template: templateId}});\n\n await project.read();\n\n return project;\n }\n\n static async read<M extends boolean>(\n projectPath: string,\n workspace: Workspace<M>,\n ): Promise<Project<M>> {\n let project = new this({\n path: projectPath,\n workspace,\n });\n\n await project.read();\n\n return project;\n }\n\n async read() {\n if (!(await fs.pathExists(this.path))) {\n throw new ProjectError('NO_SUCH_PROJECT_PATH', {\n messageParameters: [this.path],\n data: {\n path: this.path,\n },\n });\n }\n\n let errors: Array<InstanceType<typeof ProjectError>> = [];\n\n // load project config\n let projectConfigPath = path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_CONFIG_FILENAME);\n let doesProjectConfigExist = await fs.pathExists(projectConfigPath);\n let projectConfig: ProjectConfig | z.ZodError;\n\n if (doesProjectConfigExist) {\n projectConfig = await readFile(projectConfigPath, projectConfigSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n projectConfig = {};\n }\n\n if (projectConfig instanceof z.ZodError) {\n let zodError = projectConfig;\n\n errors.push(\n new ProjectError('INVALID_PROJECT_CONFIG', {\n messageParameters: [projectConfigPath],\n data: {\n path: projectConfigPath,\n zodIssues: zodError.issues,\n },\n }),\n );\n\n projectConfig = {};\n }\n\n // load package.json\n let packageJsonPath = path.join(this.path, 'package.json');\n let doesPackageJsonExist = await fs.pathExists(packageJsonPath);\n let packageJson: PackageJson | z.ZodError;\n\n if (doesPackageJsonExist) {\n packageJson = await readFile(packageJsonPath, packageJsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n packageJson = {};\n }\n\n if (packageJson instanceof z.ZodError) {\n let zodError = packageJson;\n\n errors.push(\n new ProjectError('INVALID_PACKAGE_JSON', {\n messageParameters: [packageJsonPath],\n data: {\n path: packageJsonPath,\n zodIssues: zodError.issues,\n },\n }),\n );\n\n packageJson = {};\n }\n\n if (packageJson.name?.length) {\n this.name = packageJson.name;\n }\n\n this.config = projectConfig;\n this.packageJson = packageJson;\n this.errors = errors;\n\n return this;\n }\n\n async update({args}: ProjectUpdateOptions): Promise<this> {\n if (!this.config.template) {\n throw new ProjectError('MISSING_CARSON_TEMPLATE_ID', {\n messageParameters: [path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_CONFIG_FILENAME)],\n });\n }\n\n let templateRenders = await renderCarsonTemplate({\n templateId: this.config.template,\n templateData: {\n workspace: this.workspace,\n project: this,\n args,\n },\n });\n\n await applyTemplateRenders({\n templateRenders,\n targetPath: this.path,\n snapshotPath: path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),\n ignoreStrategies: ['create'],\n });\n\n await this.read();\n\n return this;\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {ensureEmptyDirectory, pathToPosixPath} from '@jakubmazanec/fs-utils';\nimport {type PackageJson, packageJsonSchema, readFile} from '@jakubmazanec/zod-utils';\nimport fs from 'fs-extra';\nimport json5 from 'json5';\nimport path from 'node:path';\nimport {z} from 'zod';\n\nimport {\n CARSON_CONFIG_DIRECTORY,\n PROJECT_CONFIG_FILENAME,\n PROJECT_SNAPSHOT_FILENAME,\n} from '../constants.js';\nimport {applyTemplateRenders} from '../template/applyTemplateRenders.js';\nimport {readCarsonTemplate} from '../template/internals.js';\nimport {renderCarsonTemplate} from '../template/renderCarsonTemplate.js';\nimport {type ProjectConfig, projectConfigSchema} from './ProjectConfig.js';\nimport {type ProjectCreateOptions} from './ProjectCreateOptions.js';\nimport {ProjectError} from './ProjectError.js';\nimport {type ProjectOptions} from './ProjectOptions.js';\nimport {type ProjectUpdateOptions} from './ProjectUpdateOptions.js';\nimport {saveProjectConfig} from './saveProjectConfig.js';\nimport {type Workspace} from './Workspace.js';\n\n/**\n * 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.\n *\n * @typeParam M If true, the project belongs to a multi-project workspace.\n */\nexport class Project<M extends boolean = true> {\n /** Project name. */\n name?: string;\n\n /** Project path. */\n path: string;\n\n /** Project path relative to workspace path. */\n relativePath: string;\n\n /** Project configuration; if it's not found, the default is an empty object. */\n config: ProjectConfig;\n\n /** Parsed project `package.json` file; if it's not found, the default is an empty object. */\n packageJson: PackageJson;\n\n /** Parent {@link Workspace} instance. */\n workspace: Workspace<M>;\n\n /** Errors found during reading from the file system. */\n errors: Array<InstanceType<typeof ProjectError>> = [];\n\n constructor({\n path: projectPath,\n name,\n config,\n packageJson,\n workspace,\n errors,\n }: ProjectOptions<M>) {\n // TODO: check that this path and workspace path are correct, i.e. project path must always be inside of workspace path\n this.path = projectPath;\n\n if (name) {\n this.name = name;\n }\n\n if (config) {\n this.config = config;\n } else {\n this.config = {};\n }\n\n if (packageJson) {\n this.packageJson = packageJson;\n } else {\n this.packageJson = {};\n }\n\n this.workspace = workspace;\n\n if (errors) {\n this.errors = errors;\n }\n\n if (this.packageJson.name?.length) {\n this.name = this.packageJson.name;\n }\n\n this.relativePath = pathToPosixPath(path.relative(this.workspace.path, this.path));\n }\n\n static async create<M extends boolean>({\n templateId,\n workspace,\n projectPath,\n projectName,\n args,\n }: ProjectCreateOptions<M>): Promise<Project<M>> {\n let project = new this({\n path: projectPath,\n name: projectName,\n config: {\n template: templateId,\n },\n workspace,\n });\n\n // if the workspace is single-project, it shares a directory with the project, so we can't insist on it being an empty directory\n if (workspace.isMultiProject) {\n try {\n await ensureEmptyDirectory(project.path);\n } catch {\n throw new ProjectError('PROJECT_PATH_NOT_EMPTY', {\n messageParameters: [project.path],\n data: {\n path: project.path,\n },\n });\n }\n }\n\n let template = await readCarsonTemplate(templateId);\n let templateRenders = await renderCarsonTemplate({\n template,\n templateData: {\n workspace,\n project,\n args,\n },\n });\n\n await applyTemplateRenders({\n templateRenders,\n targetPath: project.path,\n snapshotPath:\n template.config.autoEject || !workspace.config.template ?\n undefined\n : path.join(project.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),\n ignoreStrategies: ['check'],\n });\n\n if (!template.config.autoEject && workspace.config.template) {\n await saveProjectConfig({projectPath: project.path, projectConfig: {template: templateId}});\n }\n\n await project.read();\n\n return project;\n }\n\n static async read<M extends boolean>(\n projectPath: string,\n workspace: Workspace<M>,\n ): Promise<Project<M>> {\n let project = new this({\n path: projectPath,\n workspace,\n });\n\n await project.read();\n\n return project;\n }\n\n async read() {\n if (!(await fs.pathExists(this.path))) {\n throw new ProjectError('NO_SUCH_PROJECT_PATH', {\n messageParameters: [this.path],\n data: {\n path: this.path,\n },\n });\n }\n\n let errors: Array<InstanceType<typeof ProjectError>> = [];\n\n // load project config\n let projectConfigPath = path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_CONFIG_FILENAME);\n let doesProjectConfigExist = await fs.pathExists(projectConfigPath);\n let projectConfig: ProjectConfig | z.ZodError;\n\n if (doesProjectConfigExist) {\n projectConfig = await readFile(projectConfigPath, projectConfigSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n projectConfig = {};\n }\n\n if (projectConfig instanceof z.ZodError) {\n let zodError = projectConfig;\n\n errors.push(\n new ProjectError('INVALID_PROJECT_CONFIG', {\n messageParameters: [projectConfigPath],\n data: {\n path: projectConfigPath,\n zodIssues: zodError.issues,\n },\n }),\n );\n\n projectConfig = {};\n }\n\n // load package.json\n let packageJsonPath = path.join(this.path, 'package.json');\n let doesPackageJsonExist = await fs.pathExists(packageJsonPath);\n let packageJson: PackageJson | z.ZodError;\n\n if (doesPackageJsonExist) {\n packageJson = await readFile(packageJsonPath, packageJsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n packageJson = {};\n }\n\n if (packageJson instanceof z.ZodError) {\n let zodError = packageJson;\n\n errors.push(\n new ProjectError('INVALID_PACKAGE_JSON', {\n messageParameters: [packageJsonPath],\n data: {\n path: packageJsonPath,\n zodIssues: zodError.issues,\n },\n }),\n );\n\n packageJson = {};\n }\n\n if (packageJson.name?.length) {\n this.name = packageJson.name;\n }\n\n this.config = projectConfig;\n this.packageJson = packageJson;\n this.errors = errors;\n\n return this;\n }\n\n async update({args}: ProjectUpdateOptions): Promise<this> {\n if (!this.config.template) {\n throw new ProjectError('MISSING_CARSON_TEMPLATE_ID', {\n messageParameters: [path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_CONFIG_FILENAME)],\n });\n }\n\n let template = await readCarsonTemplate(this.config.template);\n let templateRenders = await renderCarsonTemplate({\n template,\n templateData: {\n workspace: this.workspace,\n project: this,\n args,\n },\n });\n\n await applyTemplateRenders({\n templateRenders,\n targetPath: this.path,\n snapshotPath:\n template.config.autoEject || !this.workspace.config.template ?\n undefined\n : path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),\n ignoreStrategies: ['create'],\n });\n\n await this.read();\n\n return this;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -13,6 +13,7 @@ import {
13
13
  WORKSPACE_SNAPSHOT_FILENAME
14
14
  } from "../constants.js";
15
15
  import { applyTemplateRenders } from "../template/applyTemplateRenders.js";
16
+ import { readCarsonTemplate } from "../template/internals.js";
16
17
  import { renderCarsonTemplate } from "../template/renderCarsonTemplate.js";
17
18
  import {
18
19
  compareProjectPath,
@@ -129,8 +130,9 @@ export class Workspace {
129
130
  }
130
131
  });
131
132
  }
133
+ let template = await readCarsonTemplate(templateId);
132
134
  let templateRenders = await renderCarsonTemplate({
133
- templateId,
135
+ template,
134
136
  templateData: {
135
137
  workspace,
136
138
  args
@@ -139,13 +141,15 @@ export class Workspace {
139
141
  await applyTemplateRenders({
140
142
  templateRenders,
141
143
  targetPath: workspace.path,
142
- snapshotPath: path.join(workspace.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),
144
+ snapshotPath: template.config.autoEject ? void 0 : path.join(workspace.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),
143
145
  ignoreStrategies: ["check"]
144
146
  });
145
- await saveWorkspaceConfig({
146
- workspacePath: workspace.path,
147
- workspaceConfig: { template: templateId }
148
- });
147
+ if (!template.config.autoEject) {
148
+ await saveWorkspaceConfig({
149
+ workspacePath: workspace.path,
150
+ workspaceConfig: { template: templateId }
151
+ });
152
+ }
149
153
  return Workspace.read(workspace.path);
150
154
  }
151
155
  static async read(workspacePath) {
@@ -360,8 +364,9 @@ export class Workspace {
360
364
  ]
361
365
  });
362
366
  }
367
+ let template = await readCarsonTemplate(this.config.template);
363
368
  let templateRenders = await renderCarsonTemplate({
364
- templateId: this.config.template,
369
+ template,
365
370
  templateData: {
366
371
  workspace: this,
367
372
  args
@@ -370,7 +375,7 @@ export class Workspace {
370
375
  await applyTemplateRenders({
371
376
  templateRenders,
372
377
  targetPath: this.path,
373
- snapshotPath: path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),
378
+ snapshotPath: template.config.autoEject ? void 0 : path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),
374
379
  ignoreStrategies: ["create"]
375
380
  });
376
381
  await this.read();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../source/workspace/Workspace.ts"],
4
- "sourcesContent": ["import {ensureEmptyDirectory, findExistingDirectory, isRootPath} from '@jakubmazanec/fs-utils';\nimport {jsonSchema, type PackageJson, packageJsonSchema, readFile} from '@jakubmazanec/zod-utils';\nimport glob from 'fast-glob';\nimport fs from 'fs-extra';\nimport json5 from 'json5';\nimport path from 'node:path';\nimport {z} from 'zod';\n\nimport {\n CARSON_CONFIG_DIRECTORY,\n PACKAGE_JSON_FILENAME,\n WORKSPACE_CONFIG_FILENAME,\n WORKSPACE_SNAPSHOT_FILENAME,\n} from '../constants.js';\nimport {applyTemplateRenders} from '../template/applyTemplateRenders.js';\nimport {renderCarsonTemplate} from '../template/renderCarsonTemplate.js';\nimport {\n compareProjectPath,\n containsProject,\n containsWorkspace,\n getPackageJsonWorkspaces,\n getRepositoryBranches,\n getRepositoryUrl,\n} from './internals.js';\nimport {Project} from './Project.js';\nimport {saveWorkspaceConfig} from './saveWorkspaceConfig.js';\nimport {workspaceConfigSchema} from './WorkspaceConfig.js';\nimport {type WorkspaceConfig} from './WorkspaceConfig.js';\nimport {type WorkspaceCreateOptions} from './WorkspaceCreateOptions.js';\nimport {type WorkspaceCreateProjectOptions} from './WorkspaceCreateProjectOptions.js';\nimport {WorkspaceDependencies} from './WorkspaceDependencies.js';\nimport {WorkspaceError} from './WorkspaceError.js';\nimport {type WorkspaceFindAndReadOptions} from './WorkspaceFindAndReadOptions.js';\nimport {type WorkspaceOptions} from './WorkspaceOptions.js';\nimport {type WorkspacePackageJson} from './WorkspacePackageJson.js';\nimport {type WorkspaceProjectGlobs} from './WorkspaceProjectGlobs.js';\nimport {type WorkspaceProjects} from './WorkspaceProjects.js';\nimport {type WorkspaceRepository} from './WorkspaceRepository.js';\nimport {type WorkspaceUpdateOptions} from './WorkspaceUpdateOptions.js';\n\n/**\n * Workspace represent a directory, usually a git repository, that contains {@link Project} instances.\n *\n * @typeParam M If true, the workspace is multi-project workspace (so-called \"monorepo\").\n */\nexport class Workspace<M extends boolean = true> {\n /** Workspace path. */\n readonly path: string;\n\n /** Does the workspace contain a multiple projects? */\n readonly isMultiProject: M;\n\n /** Globs used to find projects. */\n projectGlobs: WorkspaceProjectGlobs<M>;\n\n /** Workspace projects. */\n projects: WorkspaceProjects<M>;\n\n /** Workspace configuration; if it's not found, the default is an empty object. */\n config: WorkspaceConfig;\n\n /** Parsed workspace `package.json` file (if the workspace contains multiple projects); if it's not found, the default is an empty object. */\n packageJson: WorkspacePackageJson<M>;\n\n /** Workspace git repository. */\n repository?: WorkspaceRepository;\n\n /** Dependencies of all projects. */\n dependencies: WorkspaceDependencies<M> = [] as unknown as WorkspaceDependencies<M>;\n\n /** Development dependencies of all projects. */\n devDependencies: WorkspaceDependencies<M> = [] as unknown as WorkspaceDependencies<M>;\n\n /** All dependencies of all projects and workspace dependencies. */\n allDependencies: WorkspaceDependencies<M> = [] as unknown as WorkspaceDependencies<M>;\n\n /** Versions of each dependency. */\n dependencyVersions: Record<string, string[]> = {};\n\n /** Errors found during reading from the file system. */\n errors: Array<InstanceType<typeof WorkspaceError>> = [];\n\n constructor(options: WorkspaceOptions<M>) {\n this.path = options.path;\n\n if (options.isMultiProject === undefined || options.isMultiProject) {\n this.isMultiProject = true as M;\n\n let projectGlobOption = (options as WorkspaceOptions<true>).projectGlobs;\n\n if (projectGlobOption) {\n this.projectGlobs = projectGlobOption as WorkspaceProjectGlobs<M>;\n } else {\n this.projectGlobs = [] as string[] as WorkspaceProjectGlobs<M>;\n }\n\n this.projects = [] as Array<Project<M>> as WorkspaceProjects<M>;\n\n let {projects} = options as WorkspaceOptions<true>;\n\n if (projects) {\n this.addProjects(projects.map((project) => new Project({...project, workspace: this})));\n }\n\n let packageJsonOption = (options as WorkspaceOptions<true>).packageJson;\n\n if (packageJsonOption) {\n this.packageJson = packageJsonOption as M extends true ? PackageJson : null;\n } else {\n let emptyPackageJson: PackageJson = {};\n\n this.packageJson = emptyPackageJson as M extends true ? PackageJson : null;\n }\n } else {\n this.isMultiProject = false as M;\n this.projectGlobs = null as M extends true ? string[] : null;\n this.packageJson = null as M extends true ? PackageJson : null;\n this.projects = [] as Array<Project<M>> as WorkspaceProjects<M>;\n\n let {projects} = options as WorkspaceOptions<false>;\n\n if (projects) {\n this.addProjects(projects.map((project) => new Project({...project, workspace: this})));\n }\n }\n\n let configOption = options.config;\n\n if (configOption) {\n this.config = configOption;\n } else {\n let emptyWorkspaceConfig: WorkspaceConfig = {};\n\n this.config = emptyWorkspaceConfig;\n }\n\n if (options.repository) {\n this.repository = options.repository;\n }\n\n if (options.errors) {\n this.errors = options.errors;\n }\n\n // add missing project globs\n if (this.isMultiProject && !(this.projectGlobs as string[]).length) {\n let packageJsonWorkspaces = getPackageJsonWorkspaces(this.packageJson as PackageJson);\n\n if (packageJsonWorkspaces) {\n this.projectGlobs = [...packageJsonWorkspaces] as M extends true ? string[] : null;\n }\n }\n\n this.sortProjects();\n this.updateDependencies();\n }\n\n /**\n * Creates new workspace within the file system.\n *\n * @param options Options.\n * @returns The new workspace.\n */\n static async create({args, path: workspacePath, templateId}: WorkspaceCreateOptions) {\n // 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()\n let workspace = new this({\n path: workspacePath,\n config: {\n template: templateId,\n },\n });\n\n try {\n await ensureEmptyDirectory(workspace.path, {allowGit: true});\n } catch {\n throw new WorkspaceError('WORKSPACE_PATH_NOT_EMPTY', {\n messageParameters: [workspace.path],\n data: {\n path: workspace.path,\n },\n });\n }\n\n let templateRenders = await renderCarsonTemplate({\n templateId,\n templateData: {\n workspace,\n args,\n },\n });\n\n await applyTemplateRenders({\n templateRenders,\n targetPath: workspace.path,\n snapshotPath: path.join(workspace.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),\n ignoreStrategies: ['check'],\n });\n\n await saveWorkspaceConfig({\n workspacePath: workspace.path,\n workspaceConfig: {template: templateId},\n });\n\n return Workspace.read(workspace.path);\n }\n\n static async read(workspacePath: string): Promise<Workspace | Workspace<false>> {\n let resolvedWorkspacePath = path.resolve(workspacePath);\n\n if (!(await fs.pathExists(resolvedWorkspacePath))) {\n throw new WorkspaceError('NO_SUCH_WORKSPACE_PATH', {\n messageParameters: [resolvedWorkspacePath],\n data: {\n path: resolvedWorkspacePath,\n },\n });\n }\n\n // load root package.json\n let rootPackageJsonPath = path.join(resolvedWorkspacePath, 'package.json');\n let doesRootPackageJsonExist = await fs.pathExists(rootPackageJsonPath);\n let rootPackageJson: PackageJson | z.ZodError;\n\n if (doesRootPackageJsonExist) {\n rootPackageJson = await readFile(rootPackageJsonPath, packageJsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n rootPackageJson = {};\n }\n\n if (rootPackageJson instanceof z.ZodError) {\n rootPackageJson = {};\n\n // even if the package.json file has errors, maybe there's still a correct workspace field\n try {\n let rootJson = await readFile(rootPackageJsonPath, jsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n throwOnZodError: true,\n });\n let projectGlobs = getPackageJsonWorkspaces(rootJson);\n\n // add back to the empty package.json object\n if (projectGlobs) {\n rootPackageJson.workspaces = projectGlobs;\n }\n } catch {\n // no-op\n }\n }\n\n // add projects\n let projectGlobs = getPackageJsonWorkspaces(rootPackageJson);\n\n // we're dealing with single-project workspace\n if (!projectGlobs) {\n let workspace = new this({\n path: resolvedWorkspacePath,\n isMultiProject: false,\n });\n\n await workspace.read();\n await workspace.readProjects();\n\n return workspace;\n }\n\n // assemble workspace options\n let workspace = new this({\n path: resolvedWorkspacePath,\n isMultiProject: true,\n projectGlobs,\n packageJson: rootPackageJson,\n });\n\n await workspace.read();\n await workspace.readProjects();\n\n return workspace;\n }\n\n /**\n * Traverses file system up from the search path and tries to find a directory that is a root of a workspace.\n *\n * @param searchPath Search path.\n * @returns Workspace path, if found.\n */\n static async find(searchPath: string): Promise<string | undefined> {\n let startingPath = await findExistingDirectory(path.resolve(searchPath));\n let currentPath = startingPath;\n let singlePackageWorkspacePath: string | undefined;\n let multiPackageWorkspacePath: string | undefined;\n\n while (\n !(isRootPath(currentPath) || (singlePackageWorkspacePath && multiPackageWorkspacePath))\n ) {\n if (await containsWorkspace(currentPath)) {\n const packageJsonPath = path.join(currentPath, PACKAGE_JSON_FILENAME);\n\n if (await fs.pathExists(packageJsonPath)) {\n const packageJson = await readFile(packageJsonPath, jsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n\n if (!(packageJson instanceof Error)) {\n const projectGlobs = getPackageJsonWorkspaces(packageJson);\n\n if (projectGlobs?.length) {\n multiPackageWorkspacePath ??= currentPath;\n } else {\n singlePackageWorkspacePath ??= currentPath;\n }\n }\n } else {\n singlePackageWorkspacePath ??= currentPath;\n }\n }\n\n currentPath = path.dirname(currentPath);\n }\n\n if (multiPackageWorkspacePath) {\n return multiPackageWorkspacePath;\n } else if (singlePackageWorkspacePath) {\n return singlePackageWorkspacePath;\n }\n\n return undefined;\n }\n\n /**\n * Traverses file system up from the search path and tries to find and read a workspace.\n */\n static async findAndRead<O extends WorkspaceFindAndReadOptions | undefined = undefined>(\n searchPath: string,\n options?: O,\n ): Promise<\n O extends undefined ? Workspace | Workspace<false> | undefined\n : NonNullable<O>['throwIfNotFound'] extends true ? Workspace | Workspace<false>\n : Workspace | Workspace<false> | undefined\n > {\n let workspacePath = await Workspace.find(searchPath);\n\n if (workspacePath) {\n return Workspace.read(workspacePath) as Promise<\n O extends undefined ? Workspace | Workspace<false> | undefined\n : NonNullable<O>['throwIfNotFound'] extends true ? Workspace | Workspace<false>\n : Workspace | Workspace<false> | undefined\n >;\n } else if (options?.throwIfNotFound) {\n throw new WorkspaceError('NO_WORKSPACE_FOUND', {\n messageParameters: [searchPath],\n data: {\n path: searchPath,\n },\n });\n }\n\n return undefined as unknown as Promise<\n O extends undefined ? Workspace | Workspace<false> | undefined\n : NonNullable<O>['throwIfNotFound'] extends true ? Workspace | Workspace<false>\n : Workspace | Workspace<false> | undefined\n >;\n }\n\n async read(): Promise<this> {\n if (!(await fs.pathExists(this.path))) {\n throw new WorkspaceError('NO_SUCH_WORKSPACE_PATH', {\n messageParameters: [this.path],\n data: {\n path: this.path,\n },\n });\n }\n\n let errors: Array<InstanceType<typeof WorkspaceError>> = [];\n let repositoryUrl = await getRepositoryUrl(this.path);\n let repositoryBranches = await getRepositoryBranches(this.path);\n\n // load workspace config\n let workspaceConfigPath = path.join(\n this.path,\n CARSON_CONFIG_DIRECTORY,\n WORKSPACE_CONFIG_FILENAME,\n );\n let doesWorkspaceConfigExist = await fs.pathExists(workspaceConfigPath);\n let workspaceConfig: WorkspaceConfig | z.ZodError;\n\n if (doesWorkspaceConfigExist) {\n workspaceConfig = await readFile(workspaceConfigPath, workspaceConfigSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n workspaceConfig = {};\n }\n\n if (workspaceConfig instanceof z.ZodError) {\n let zodError = workspaceConfig;\n let workspaceError = new WorkspaceError('INVALID_WORKSPACE_CONFIG', {\n messageParameters: [workspaceConfigPath],\n data: {\n path: workspaceConfigPath,\n zodIssues: zodError.issues,\n },\n });\n\n errors.push(workspaceError);\n\n workspaceConfig = {};\n }\n\n if (this.isMultiProject) {\n // load root package.json\n let rootPackageJsonPath = path.join(this.path, 'package.json');\n let doesRootPackageJsonExist = await fs.pathExists(rootPackageJsonPath);\n let rootPackageJson: PackageJson | z.ZodError;\n\n if (doesRootPackageJsonExist) {\n rootPackageJson = await readFile(rootPackageJsonPath, packageJsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n rootPackageJson = {};\n }\n\n if (rootPackageJson instanceof z.ZodError) {\n let zodError = rootPackageJson;\n let workspaceError = new WorkspaceError('INVALID_PACKAGE_JSON', {\n messageParameters: [rootPackageJsonPath],\n data: {\n path: rootPackageJsonPath,\n zodIssues: zodError.issues,\n },\n });\n\n errors.push(workspaceError);\n\n rootPackageJson = {};\n }\n\n let projectGlobs = getPackageJsonWorkspaces(rootPackageJson);\n\n this.projectGlobs = (projectGlobs ?? []) as WorkspaceProjectGlobs<M>;\n this.packageJson = rootPackageJson as WorkspacePackageJson<M>;\n this.config = workspaceConfig;\n this.errors = errors;\n\n if (repositoryUrl) {\n this.repository = {\n url: repositoryUrl,\n branches: repositoryBranches ?? [],\n };\n } else if (repositoryBranches) {\n this.repository = {\n branches: repositoryBranches,\n };\n }\n\n await this.readProjects();\n\n return this;\n }\n\n // we're dealing with single-project workspace\n this.config = workspaceConfig;\n this.errors = errors;\n\n if (repositoryUrl) {\n this.repository = {\n url: repositoryUrl,\n branches: repositoryBranches ?? [],\n };\n } else if (repositoryBranches) {\n this.repository = {\n branches: repositoryBranches,\n };\n }\n\n await this.readProjects();\n\n return this;\n }\n\n async update({args}: WorkspaceUpdateOptions): Promise<this> {\n if (!this.config.template) {\n throw new WorkspaceError('MISSING_CARSON_TEMPLATE_ID', {\n messageParameters: [\n path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_CONFIG_FILENAME),\n ],\n });\n }\n\n let templateRenders = await renderCarsonTemplate({\n templateId: this.config.template,\n templateData: {\n workspace: this,\n args,\n },\n });\n\n await applyTemplateRenders({\n templateRenders,\n targetPath: this.path,\n snapshotPath: path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),\n ignoreStrategies: ['create'],\n });\n\n await this.read();\n\n return this;\n }\n\n getProject(projectName: Project<M> | string): Project<M> | undefined {\n for (let project of this.projects) {\n if (project.name === projectName || project === projectName) {\n return project;\n }\n }\n\n return undefined;\n }\n\n async createProject({\n templateId,\n projectPath,\n projectName,\n args,\n }: WorkspaceCreateProjectOptions): Promise<Project<M>> {\n let resolvedProjectPath = path.resolve(projectPath);\n\n if (this.projects.some((project) => resolvedProjectPath === project.path)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {\n messageParameters: [resolvedProjectPath],\n });\n }\n\n if (this.projects.some((project) => projectName === project.name)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [projectName]});\n }\n\n if (!this.isMultiProject && this.projects.length >= 1) {\n throw new WorkspaceError('TOO_MANY_PROJECTS');\n }\n\n if (!this.isMultiProject && projectPath !== this.path) {\n throw new WorkspaceError('PATH_MISMATCH');\n }\n\n let newProject = await Project.create({\n templateId,\n projectPath,\n projectName,\n args,\n workspace: this,\n });\n\n this.addProject(newProject);\n\n return newProject;\n }\n\n addProject(newProject: Project<M>): this {\n if (this.projects.some((project) => newProject.path === project.path)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {\n messageParameters: [newProject.path],\n });\n }\n\n if (this.projects.some((project) => newProject.name === project.name)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [newProject.name]});\n }\n\n if (!this.isMultiProject && this.projects.length >= 1) {\n throw new WorkspaceError('TOO_MANY_PROJECTS');\n }\n\n if (!this.isMultiProject && newProject.path !== this.path) {\n throw new WorkspaceError('PATH_MISMATCH');\n }\n\n this.projects.push(newProject);\n this.sortProjects();\n this.updateDependencies();\n\n return this;\n }\n\n addProjects(newProjects: Array<Project<M>>): this {\n for (let newProject of newProjects) {\n if (this.projects.some((project) => newProject.path === project.path)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {\n messageParameters: [newProject.path],\n });\n }\n\n if (this.projects.some((project) => newProject.name === project.name)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [newProject.name]});\n }\n\n if (!this.isMultiProject && this.projects.length >= 1) {\n throw new WorkspaceError('TOO_MANY_PROJECTS');\n }\n\n if (!this.isMultiProject && newProject.path !== this.path) {\n throw new WorkspaceError('PATH_MISMATCH');\n }\n\n this.projects.push(newProject);\n }\n\n this.sortProjects();\n this.updateDependencies();\n\n return this;\n }\n\n async readProjects(): Promise<Array<Project<M>>> {\n if (this.projectGlobs) {\n let projects: Array<Project<M>> = [];\n let packagePaths = await glob(this.projectGlobs, {\n cwd: this.path,\n onlyDirectories: true,\n });\n\n for (let packagePath of packagePaths) {\n let projectPath = path.join(this.path, packagePath);\n\n if (await containsProject(projectPath)) {\n let project = await Project.read(projectPath, this);\n\n projects.push(project);\n }\n }\n\n this.projects = projects;\n\n this.sortProjects();\n this.updateDependencies();\n } else if (await containsProject(this.path)) {\n this.projects = [await Project.read(this.path, this)];\n\n this.sortProjects();\n this.updateDependencies();\n }\n\n return this.projects;\n }\n\n protected sortProjects(): void {\n this.projects.sort(compareProjectPath);\n }\n\n protected updateDependencies(): void {\n this.dependencies = WorkspaceDependencies.fromWorkspace(this);\n this.devDependencies = WorkspaceDependencies.fromWorkspace(this, {\n includeOnlyDevDependencies: true,\n });\n this.allDependencies = WorkspaceDependencies.fromWorkspace(this, {\n includeDevDependencies: true,\n includeWorkspaceDependencies: true,\n });\n this.dependencyVersions = this.allDependencies.getVersions({\n useExactVersions: true,\n });\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {ensureEmptyDirectory, findExistingDirectory, isRootPath} from '@jakubmazanec/fs-utils';\nimport {jsonSchema, type PackageJson, packageJsonSchema, readFile} from '@jakubmazanec/zod-utils';\nimport glob from 'fast-glob';\nimport fs from 'fs-extra';\nimport json5 from 'json5';\nimport path from 'node:path';\nimport {z} from 'zod';\n\nimport {\n CARSON_CONFIG_DIRECTORY,\n PACKAGE_JSON_FILENAME,\n WORKSPACE_CONFIG_FILENAME,\n WORKSPACE_SNAPSHOT_FILENAME,\n} from '../constants.js';\nimport {applyTemplateRenders} from '../template/applyTemplateRenders.js';\nimport {readCarsonTemplate} from '../template/internals.js';\nimport {renderCarsonTemplate} from '../template/renderCarsonTemplate.js';\nimport {\n compareProjectPath,\n containsProject,\n containsWorkspace,\n getPackageJsonWorkspaces,\n getRepositoryBranches,\n getRepositoryUrl,\n} from './internals.js';\nimport {Project} from './Project.js';\nimport {saveWorkspaceConfig} from './saveWorkspaceConfig.js';\nimport {workspaceConfigSchema} from './WorkspaceConfig.js';\nimport {type WorkspaceConfig} from './WorkspaceConfig.js';\nimport {type WorkspaceCreateOptions} from './WorkspaceCreateOptions.js';\nimport {type WorkspaceCreateProjectOptions} from './WorkspaceCreateProjectOptions.js';\nimport {WorkspaceDependencies} from './WorkspaceDependencies.js';\nimport {WorkspaceError} from './WorkspaceError.js';\nimport {type WorkspaceFindAndReadOptions} from './WorkspaceFindAndReadOptions.js';\nimport {type WorkspaceOptions} from './WorkspaceOptions.js';\nimport {type WorkspacePackageJson} from './WorkspacePackageJson.js';\nimport {type WorkspaceProjectGlobs} from './WorkspaceProjectGlobs.js';\nimport {type WorkspaceProjects} from './WorkspaceProjects.js';\nimport {type WorkspaceRepository} from './WorkspaceRepository.js';\nimport {type WorkspaceUpdateOptions} from './WorkspaceUpdateOptions.js';\n\n/**\n * Workspace represent a directory, usually a git repository, that contains {@link Project} instances.\n *\n * @typeParam M If true, the workspace is multi-project workspace (so-called \"monorepo\").\n */\nexport class Workspace<M extends boolean = true> {\n /** Workspace path. */\n readonly path: string;\n\n /** Does the workspace contain a multiple projects? */\n readonly isMultiProject: M;\n\n /** Globs used to find projects. */\n projectGlobs: WorkspaceProjectGlobs<M>;\n\n /** Workspace projects. */\n projects: WorkspaceProjects<M>;\n\n /** Workspace configuration; if it's not found, the default is an empty object. */\n config: WorkspaceConfig;\n\n /** Parsed workspace `package.json` file (if the workspace contains multiple projects); if it's not found, the default is an empty object. */\n packageJson: WorkspacePackageJson<M>;\n\n /** Workspace git repository. */\n repository?: WorkspaceRepository;\n\n /** Dependencies of all projects. */\n dependencies: WorkspaceDependencies<M> = [] as unknown as WorkspaceDependencies<M>;\n\n /** Development dependencies of all projects. */\n devDependencies: WorkspaceDependencies<M> = [] as unknown as WorkspaceDependencies<M>;\n\n /** All dependencies of all projects and workspace dependencies. */\n allDependencies: WorkspaceDependencies<M> = [] as unknown as WorkspaceDependencies<M>;\n\n /** Versions of each dependency. */\n dependencyVersions: Record<string, string[]> = {};\n\n /** Errors found during reading from the file system. */\n errors: Array<InstanceType<typeof WorkspaceError>> = [];\n\n constructor(options: WorkspaceOptions<M>) {\n this.path = options.path;\n\n if (options.isMultiProject === undefined || options.isMultiProject) {\n this.isMultiProject = true as M;\n\n let projectGlobOption = (options as WorkspaceOptions<true>).projectGlobs;\n\n if (projectGlobOption) {\n this.projectGlobs = projectGlobOption as WorkspaceProjectGlobs<M>;\n } else {\n this.projectGlobs = [] as string[] as WorkspaceProjectGlobs<M>;\n }\n\n this.projects = [] as Array<Project<M>> as WorkspaceProjects<M>;\n\n let {projects} = options as WorkspaceOptions<true>;\n\n if (projects) {\n this.addProjects(projects.map((project) => new Project({...project, workspace: this})));\n }\n\n let packageJsonOption = (options as WorkspaceOptions<true>).packageJson;\n\n if (packageJsonOption) {\n this.packageJson = packageJsonOption as M extends true ? PackageJson : null;\n } else {\n let emptyPackageJson: PackageJson = {};\n\n this.packageJson = emptyPackageJson as M extends true ? PackageJson : null;\n }\n } else {\n this.isMultiProject = false as M;\n this.projectGlobs = null as M extends true ? string[] : null;\n this.packageJson = null as M extends true ? PackageJson : null;\n this.projects = [] as Array<Project<M>> as WorkspaceProjects<M>;\n\n let {projects} = options as WorkspaceOptions<false>;\n\n if (projects) {\n this.addProjects(projects.map((project) => new Project({...project, workspace: this})));\n }\n }\n\n let configOption = options.config;\n\n if (configOption) {\n this.config = configOption;\n } else {\n let emptyWorkspaceConfig: WorkspaceConfig = {};\n\n this.config = emptyWorkspaceConfig;\n }\n\n if (options.repository) {\n this.repository = options.repository;\n }\n\n if (options.errors) {\n this.errors = options.errors;\n }\n\n // add missing project globs\n if (this.isMultiProject && !(this.projectGlobs as string[]).length) {\n let packageJsonWorkspaces = getPackageJsonWorkspaces(this.packageJson as PackageJson);\n\n if (packageJsonWorkspaces) {\n this.projectGlobs = [...packageJsonWorkspaces] as M extends true ? string[] : null;\n }\n }\n\n this.sortProjects();\n this.updateDependencies();\n }\n\n /**\n * Creates new workspace within the file system.\n *\n * @param options Options.\n * @returns The new workspace.\n */\n static async create({args, path: workspacePath, templateId}: WorkspaceCreateOptions) {\n // 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()\n let workspace = new this({\n path: workspacePath,\n config: {\n template: templateId,\n },\n });\n\n try {\n await ensureEmptyDirectory(workspace.path, {allowGit: true});\n } catch {\n throw new WorkspaceError('WORKSPACE_PATH_NOT_EMPTY', {\n messageParameters: [workspace.path],\n data: {\n path: workspace.path,\n },\n });\n }\n\n let template = await readCarsonTemplate(templateId);\n let templateRenders = await renderCarsonTemplate({\n template,\n templateData: {\n workspace,\n args,\n },\n });\n\n await applyTemplateRenders({\n templateRenders,\n targetPath: workspace.path,\n snapshotPath:\n template.config.autoEject ?\n undefined\n : path.join(workspace.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),\n ignoreStrategies: ['check'],\n });\n\n if (!template.config.autoEject) {\n await saveWorkspaceConfig({\n workspacePath: workspace.path,\n workspaceConfig: {template: templateId},\n });\n }\n\n return Workspace.read(workspace.path);\n }\n\n static async read(workspacePath: string): Promise<Workspace | Workspace<false>> {\n let resolvedWorkspacePath = path.resolve(workspacePath);\n\n if (!(await fs.pathExists(resolvedWorkspacePath))) {\n throw new WorkspaceError('NO_SUCH_WORKSPACE_PATH', {\n messageParameters: [resolvedWorkspacePath],\n data: {\n path: resolvedWorkspacePath,\n },\n });\n }\n\n // load root package.json\n let rootPackageJsonPath = path.join(resolvedWorkspacePath, 'package.json');\n let doesRootPackageJsonExist = await fs.pathExists(rootPackageJsonPath);\n let rootPackageJson: PackageJson | z.ZodError;\n\n if (doesRootPackageJsonExist) {\n rootPackageJson = await readFile(rootPackageJsonPath, packageJsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n rootPackageJson = {};\n }\n\n if (rootPackageJson instanceof z.ZodError) {\n rootPackageJson = {};\n\n // even if the package.json file has errors, maybe there's still a correct workspace field\n try {\n let rootJson = await readFile(rootPackageJsonPath, jsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n throwOnZodError: true,\n });\n let projectGlobs = getPackageJsonWorkspaces(rootJson);\n\n // add back to the empty package.json object\n if (projectGlobs) {\n rootPackageJson.workspaces = projectGlobs;\n }\n } catch {\n // no-op\n }\n }\n\n // add projects\n let projectGlobs = getPackageJsonWorkspaces(rootPackageJson);\n\n // we're dealing with single-project workspace\n if (!projectGlobs) {\n let workspace = new this({\n path: resolvedWorkspacePath,\n isMultiProject: false,\n });\n\n await workspace.read();\n await workspace.readProjects();\n\n return workspace;\n }\n\n // assemble workspace options\n let workspace = new this({\n path: resolvedWorkspacePath,\n isMultiProject: true,\n projectGlobs,\n packageJson: rootPackageJson,\n });\n\n await workspace.read();\n await workspace.readProjects();\n\n return workspace;\n }\n\n /**\n * Traverses file system up from the search path and tries to find a directory that is a root of a workspace.\n *\n * @param searchPath Search path.\n * @returns Workspace path, if found.\n */\n static async find(searchPath: string): Promise<string | undefined> {\n let startingPath = await findExistingDirectory(path.resolve(searchPath));\n let currentPath = startingPath;\n let singlePackageWorkspacePath: string | undefined;\n let multiPackageWorkspacePath: string | undefined;\n\n while (\n !(isRootPath(currentPath) || (singlePackageWorkspacePath && multiPackageWorkspacePath))\n ) {\n if (await containsWorkspace(currentPath)) {\n const packageJsonPath = path.join(currentPath, PACKAGE_JSON_FILENAME);\n\n if (await fs.pathExists(packageJsonPath)) {\n const packageJson = await readFile(packageJsonPath, jsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n\n if (!(packageJson instanceof Error)) {\n const projectGlobs = getPackageJsonWorkspaces(packageJson);\n\n if (projectGlobs?.length) {\n multiPackageWorkspacePath ??= currentPath;\n } else {\n singlePackageWorkspacePath ??= currentPath;\n }\n }\n } else {\n singlePackageWorkspacePath ??= currentPath;\n }\n }\n\n currentPath = path.dirname(currentPath);\n }\n\n if (multiPackageWorkspacePath) {\n return multiPackageWorkspacePath;\n } else if (singlePackageWorkspacePath) {\n return singlePackageWorkspacePath;\n }\n\n return undefined;\n }\n\n /**\n * Traverses file system up from the search path and tries to find and read a workspace.\n */\n static async findAndRead<O extends WorkspaceFindAndReadOptions | undefined = undefined>(\n searchPath: string,\n options?: O,\n ): Promise<\n O extends undefined ? Workspace | Workspace<false> | undefined\n : NonNullable<O>['throwIfNotFound'] extends true ? Workspace | Workspace<false>\n : Workspace | Workspace<false> | undefined\n > {\n let workspacePath = await Workspace.find(searchPath);\n\n if (workspacePath) {\n return Workspace.read(workspacePath) as Promise<\n O extends undefined ? Workspace | Workspace<false> | undefined\n : NonNullable<O>['throwIfNotFound'] extends true ? Workspace | Workspace<false>\n : Workspace | Workspace<false> | undefined\n >;\n } else if (options?.throwIfNotFound) {\n throw new WorkspaceError('NO_WORKSPACE_FOUND', {\n messageParameters: [searchPath],\n data: {\n path: searchPath,\n },\n });\n }\n\n return undefined as unknown as Promise<\n O extends undefined ? Workspace | Workspace<false> | undefined\n : NonNullable<O>['throwIfNotFound'] extends true ? Workspace | Workspace<false>\n : Workspace | Workspace<false> | undefined\n >;\n }\n\n async read(): Promise<this> {\n if (!(await fs.pathExists(this.path))) {\n throw new WorkspaceError('NO_SUCH_WORKSPACE_PATH', {\n messageParameters: [this.path],\n data: {\n path: this.path,\n },\n });\n }\n\n let errors: Array<InstanceType<typeof WorkspaceError>> = [];\n let repositoryUrl = await getRepositoryUrl(this.path);\n let repositoryBranches = await getRepositoryBranches(this.path);\n\n // load workspace config\n let workspaceConfigPath = path.join(\n this.path,\n CARSON_CONFIG_DIRECTORY,\n WORKSPACE_CONFIG_FILENAME,\n );\n let doesWorkspaceConfigExist = await fs.pathExists(workspaceConfigPath);\n let workspaceConfig: WorkspaceConfig | z.ZodError;\n\n if (doesWorkspaceConfigExist) {\n workspaceConfig = await readFile(workspaceConfigPath, workspaceConfigSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n workspaceConfig = {};\n }\n\n if (workspaceConfig instanceof z.ZodError) {\n let zodError = workspaceConfig;\n let workspaceError = new WorkspaceError('INVALID_WORKSPACE_CONFIG', {\n messageParameters: [workspaceConfigPath],\n data: {\n path: workspaceConfigPath,\n zodIssues: zodError.issues,\n },\n });\n\n errors.push(workspaceError);\n\n workspaceConfig = {};\n }\n\n if (this.isMultiProject) {\n // load root package.json\n let rootPackageJsonPath = path.join(this.path, 'package.json');\n let doesRootPackageJsonExist = await fs.pathExists(rootPackageJsonPath);\n let rootPackageJson: PackageJson | z.ZodError;\n\n if (doesRootPackageJsonExist) {\n rootPackageJson = await readFile(rootPackageJsonPath, packageJsonSchema, {\n parser: (rawString: string) => json5.parse<unknown>(rawString),\n });\n } else {\n rootPackageJson = {};\n }\n\n if (rootPackageJson instanceof z.ZodError) {\n let zodError = rootPackageJson;\n let workspaceError = new WorkspaceError('INVALID_PACKAGE_JSON', {\n messageParameters: [rootPackageJsonPath],\n data: {\n path: rootPackageJsonPath,\n zodIssues: zodError.issues,\n },\n });\n\n errors.push(workspaceError);\n\n rootPackageJson = {};\n }\n\n let projectGlobs = getPackageJsonWorkspaces(rootPackageJson);\n\n this.projectGlobs = (projectGlobs ?? []) as WorkspaceProjectGlobs<M>;\n this.packageJson = rootPackageJson as WorkspacePackageJson<M>;\n this.config = workspaceConfig;\n this.errors = errors;\n\n if (repositoryUrl) {\n this.repository = {\n url: repositoryUrl,\n branches: repositoryBranches ?? [],\n };\n } else if (repositoryBranches) {\n this.repository = {\n branches: repositoryBranches,\n };\n }\n\n await this.readProjects();\n\n return this;\n }\n\n // we're dealing with single-project workspace\n this.config = workspaceConfig;\n this.errors = errors;\n\n if (repositoryUrl) {\n this.repository = {\n url: repositoryUrl,\n branches: repositoryBranches ?? [],\n };\n } else if (repositoryBranches) {\n this.repository = {\n branches: repositoryBranches,\n };\n }\n\n await this.readProjects();\n\n return this;\n }\n\n async update({args}: WorkspaceUpdateOptions): Promise<this> {\n if (!this.config.template) {\n throw new WorkspaceError('MISSING_CARSON_TEMPLATE_ID', {\n messageParameters: [\n path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_CONFIG_FILENAME),\n ],\n });\n }\n\n let template = await readCarsonTemplate(this.config.template);\n let templateRenders = await renderCarsonTemplate({\n template,\n templateData: {\n workspace: this,\n args,\n },\n });\n\n await applyTemplateRenders({\n templateRenders,\n targetPath: this.path,\n snapshotPath:\n template.config.autoEject ?\n undefined\n : path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),\n ignoreStrategies: ['create'],\n });\n\n await this.read();\n\n return this;\n }\n\n getProject(projectName: Project<M> | string): Project<M> | undefined {\n for (let project of this.projects) {\n if (project.name === projectName || project === projectName) {\n return project;\n }\n }\n\n return undefined;\n }\n\n async createProject({\n templateId,\n projectPath,\n projectName,\n args,\n }: WorkspaceCreateProjectOptions): Promise<Project<M>> {\n let resolvedProjectPath = path.resolve(projectPath);\n\n if (this.projects.some((project) => resolvedProjectPath === project.path)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {\n messageParameters: [resolvedProjectPath],\n });\n }\n\n if (this.projects.some((project) => projectName === project.name)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [projectName]});\n }\n\n if (!this.isMultiProject && this.projects.length >= 1) {\n throw new WorkspaceError('TOO_MANY_PROJECTS');\n }\n\n if (!this.isMultiProject && projectPath !== this.path) {\n throw new WorkspaceError('PATH_MISMATCH');\n }\n\n let newProject = await Project.create({\n templateId,\n projectPath,\n projectName,\n args,\n workspace: this,\n });\n\n this.addProject(newProject);\n\n return newProject;\n }\n\n addProject(newProject: Project<M>): this {\n if (this.projects.some((project) => newProject.path === project.path)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {\n messageParameters: [newProject.path],\n });\n }\n\n if (this.projects.some((project) => newProject.name === project.name)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [newProject.name]});\n }\n\n if (!this.isMultiProject && this.projects.length >= 1) {\n throw new WorkspaceError('TOO_MANY_PROJECTS');\n }\n\n if (!this.isMultiProject && newProject.path !== this.path) {\n throw new WorkspaceError('PATH_MISMATCH');\n }\n\n this.projects.push(newProject);\n this.sortProjects();\n this.updateDependencies();\n\n return this;\n }\n\n addProjects(newProjects: Array<Project<M>>): this {\n for (let newProject of newProjects) {\n if (this.projects.some((project) => newProject.path === project.path)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_PATH', {\n messageParameters: [newProject.path],\n });\n }\n\n if (this.projects.some((project) => newProject.name === project.name)) {\n throw new WorkspaceError('DUPLICATE_PROJECT_NAME', {messageParameters: [newProject.name]});\n }\n\n if (!this.isMultiProject && this.projects.length >= 1) {\n throw new WorkspaceError('TOO_MANY_PROJECTS');\n }\n\n if (!this.isMultiProject && newProject.path !== this.path) {\n throw new WorkspaceError('PATH_MISMATCH');\n }\n\n this.projects.push(newProject);\n }\n\n this.sortProjects();\n this.updateDependencies();\n\n return this;\n }\n\n async readProjects(): Promise<Array<Project<M>>> {\n if (this.projectGlobs) {\n let projects: Array<Project<M>> = [];\n let packagePaths = await glob(this.projectGlobs, {\n cwd: this.path,\n onlyDirectories: true,\n });\n\n for (let packagePath of packagePaths) {\n let projectPath = path.join(this.path, packagePath);\n\n if (await containsProject(projectPath)) {\n let project = await Project.read(projectPath, this);\n\n projects.push(project);\n }\n }\n\n this.projects = projects;\n\n this.sortProjects();\n this.updateDependencies();\n } else if (await containsProject(this.path)) {\n this.projects = [await Project.read(this.path, this)];\n\n this.sortProjects();\n this.updateDependencies();\n }\n\n return this.projects;\n }\n\n protected sortProjects(): void {\n this.projects.sort(compareProjectPath);\n }\n\n protected updateDependencies(): void {\n this.dependencies = WorkspaceDependencies.fromWorkspace(this);\n this.devDependencies = WorkspaceDependencies.fromWorkspace(this, {\n includeOnlyDevDependencies: true,\n });\n this.allDependencies = WorkspaceDependencies.fromWorkspace(this, {\n includeDevDependencies: true,\n includeWorkspaceDependencies: true,\n });\n this.dependencyVersions = this.allDependencies.getVersions({\n useExactVersions: true,\n });\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["projectGlobs", "workspace"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jakubmazanec/carson",
3
- "version": "1.0.1",
3
+ "version": "1.1.0-next.c370ab6",
4
4
  "description": "Tool for managing workspace and project configuration.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -32,13 +32,13 @@
32
32
  "typecheck": "tsc --project tsconfig.typecheck.json"
33
33
  },
34
34
  "dependencies": {
35
- "@jakubmazanec/args": "^2.0.0",
36
- "@jakubmazanec/cli": "^0.3.0",
37
- "@jakubmazanec/error": "^3.0.0",
38
- "@jakubmazanec/fs-utils": "^0.2.0",
39
- "@jakubmazanec/template": "^2.0.0",
40
- "@jakubmazanec/ts-utils": "^3.0.0",
41
- "@jakubmazanec/zod-utils": "^2.0.0",
35
+ "@jakubmazanec/args": "2.0.2-next.c370ab6",
36
+ "@jakubmazanec/cli": "0.3.2-next.c370ab6",
37
+ "@jakubmazanec/error": "3.0.2-next.c370ab6",
38
+ "@jakubmazanec/fs-utils": "0.2.2-next.c370ab6",
39
+ "@jakubmazanec/template": "2.0.2-next.c370ab6",
40
+ "@jakubmazanec/ts-utils": "3.0.2-next.c370ab6",
41
+ "@jakubmazanec/zod-utils": "2.0.2-next.c370ab6",
42
42
  "chalk": "^5.3.0",
43
43
  "fast-glob": "^3.3.2",
44
44
  "fflate": "^0.8.2",
@@ -55,7 +55,7 @@
55
55
  "zod": "^3.22.4"
56
56
  },
57
57
  "devDependencies": {
58
- "@jakubmazanec/eslint-config": "^3.0.0",
58
+ "@jakubmazanec/eslint-config": "3.2.0-next.c370ab6",
59
59
  "@types/fs-extra": "^11.0.4",
60
60
  "@types/lodash": "^4.14.202",
61
61
  "@types/micromatch": "^4.0.6",
@@ -69,6 +69,7 @@
69
69
  "esbuild": "^0.20.1",
70
70
  "eslint": "^8.56.0",
71
71
  "ink": "^4.4.1",
72
+ "lodash": "^4.17.21",
72
73
  "prettier": "^3.2.5",
73
74
  "prettier-plugin-packagejson": "^2.4.12",
74
75
  "react": "^18.2.0",
@@ -80,6 +80,25 @@ export function CreateProject({args, workspace}: CreateProjectProps) {
80
80
  value: projectPath,
81
81
  label: path.relative(workspace.path, projectPath).replace('\\', '/'),
82
82
  }));
83
+
84
+ if (!possiblePaths.length) {
85
+ possiblePaths = workspace.projectGlobs
86
+ .filter((projectGlob) => !ONLY_ONE_STAR_REGEXP.test(projectGlob))
87
+ .map((projectGlob) => path.join(workspace.path, projectGlob))
88
+ .map((projectPath) => ({
89
+ value: projectPath,
90
+ label: path.relative(workspace.path, projectPath).replace('\\', '/'),
91
+ }));
92
+ }
93
+
94
+ if (!possiblePaths.length) {
95
+ possiblePaths = [
96
+ {
97
+ value: workspace.path,
98
+ label: workspace.path,
99
+ },
100
+ ];
101
+ }
83
102
  } else {
84
103
  possiblePaths = [
85
104
  {
@@ -34,6 +34,9 @@ export function runCreateProject({
34
34
 
35
35
  observer.next('Updating the new project');
36
36
 
37
+ // if the project doesn't have config with a template ID, it's on purpose, but it's still needed for the next update, so we'll add it manually
38
+ project.config.template ??= templateId;
39
+
37
40
  await project.update({args});
38
41
  })()
39
42
  .then(() => {
@@ -25,6 +25,9 @@ export function runCreateWorkspace({workspacePath, templateId, args}: CreateWork
25
25
 
26
26
  observer.next('Updating the new workspace');
27
27
 
28
+ // if the workspace doesn't have config with a template ID, it's on purpose, but it's still needed for the next update, so we'll add it manually
29
+ workspace.config.template ??= templateId;
30
+
28
31
  await workspace.update({args});
29
32
  })()
30
33
  .then(() => {
@@ -8,6 +8,9 @@ import {type templateDataSchema} from './TemplateData.js';
8
8
  * Carson template.
9
9
  */
10
10
  export type CarsonTemplate = {
11
+ /** Carson template ID. */
12
+ id: string;
13
+
11
14
  /** Carson template name. */
12
15
  name: string;
13
16
 
@@ -2,10 +2,10 @@ import {z} from 'zod';
2
2
 
3
3
  export const carsonTemplateConfigSchema = z
4
4
  .object({
5
- disallowMultiProjectWorkspace: z.boolean().optional(),
6
- disallowSingleProjectWorkspace: z.boolean().optional(),
5
+ // disallowMultiProjectWorkspace: z.boolean().optional(),
6
+ // disallowSingleProjectWorkspace: z.boolean().optional(),
7
7
 
8
- // TODO: add extends property to allow reuisng template files from another carson template
8
+ autoEject: z.boolean().optional(),
9
9
  })
10
10
  .strict();
11
11
 
@@ -22,7 +22,7 @@ import {type TemplateRenders} from './TemplateRenders.js';
22
22
  export type ApplyTemplateRendersOptions = {
23
23
  templateRenders: TemplateRenders;
24
24
  targetPath: string;
25
- snapshotPath: string;
25
+ snapshotPath?: string | undefined;
26
26
  ignoreStrategies: string[];
27
27
  };
28
28
 
@@ -39,7 +39,7 @@ export async function applyTemplateRenders({
39
39
  await prettier.clearConfigCache();
40
40
 
41
41
  // first, we read the existing snapshots and use them to undo previous changes
42
- if (await fs.pathExists(snapshotPath)) {
42
+ if (snapshotPath && (await fs.pathExists(snapshotPath))) {
43
43
  let templateRenderSnapshots = await loadTemplateRenderSnapshots(snapshotPath);
44
44
 
45
45
  for (let templateRenderSnapshot of templateRenderSnapshots) {
@@ -135,7 +135,9 @@ export async function applyTemplateRenders({
135
135
  }
136
136
  }
137
137
 
138
- await fs.ensureDir(path.join(targetPath, CARSON_CONFIG_DIRECTORY));
138
+ if (snapshotPath) {
139
+ await fs.ensureDir(path.join(targetPath, CARSON_CONFIG_DIRECTORY));
139
140
 
140
- await saveTemplateRenderSnapshots(templateRenders, snapshotPath);
141
+ await saveTemplateRenderSnapshots(templateRenders, snapshotPath);
142
+ }
141
143
  }
@@ -27,6 +27,7 @@ export async function readCarsonTemplate(templateId: string): Promise<CarsonTemp
27
27
  dot: true,
28
28
  });
29
29
  let carsonTemplate: CarsonTemplate = {
30
+ id: templateId,
30
31
  name: templateName,
31
32
  config: templateConfig,
32
33
  files: [],
@@ -2,17 +2,13 @@ import {pathToPosixPath} from '@jakubmazanec/fs-utils';
2
2
  import _ from 'lodash';
3
3
  import path from 'node:path';
4
4
 
5
- import {
6
- importCarsonTemplate,
7
- parseCarsonTemplateId,
8
- readCarsonTemplate,
9
- resolveModule,
10
- } from './internals.js';
5
+ import {type CarsonTemplate} from './CarsonTemplate.js';
6
+ import {importCarsonTemplate, parseCarsonTemplateId, resolveModule} from './internals.js';
11
7
  import {type TemplateData} from './TemplateData.js';
12
8
  import {type TemplateRenders} from './TemplateRenders.js';
13
9
 
14
10
  export type RenderCarsonTemplateOptions = {
15
- templateId: string;
11
+ template: CarsonTemplate;
16
12
  templateData: TemplateData;
17
13
  };
18
14
 
@@ -22,13 +18,12 @@ export type RenderCarsonTemplateOptions = {
22
18
  export async function renderCarsonTemplate(
23
19
  options: RenderCarsonTemplateOptions,
24
20
  ): Promise<TemplateRenders> {
25
- let [moduleId] = parseCarsonTemplateId(options.templateId);
21
+ let [moduleId] = parseCarsonTemplateId(options.template.id);
26
22
  let modulePath = await resolveModule(moduleId);
27
- let template = await readCarsonTemplate(options.templateId);
28
- let templateModule = await importCarsonTemplate(options.templateId);
23
+ let templateModule = await importCarsonTemplate(options.template.id);
29
24
  let templateRenders: TemplateRenders = [];
30
25
 
31
- for (let file of template.files) {
26
+ for (let file of options.template.files) {
32
27
  templateRenders.push(
33
28
  ...(
34
29
  await file.render(
@@ -11,6 +11,7 @@ import {
11
11
  PROJECT_SNAPSHOT_FILENAME,
12
12
  } from '../constants.js';
13
13
  import {applyTemplateRenders} from '../template/applyTemplateRenders.js';
14
+ import {readCarsonTemplate} from '../template/internals.js';
14
15
  import {renderCarsonTemplate} from '../template/renderCarsonTemplate.js';
15
16
  import {type ProjectConfig, projectConfigSchema} from './ProjectConfig.js';
16
17
  import {type ProjectCreateOptions} from './ProjectCreateOptions.js';
@@ -117,8 +118,9 @@ export class Project<M extends boolean = true> {
117
118
  }
118
119
  }
119
120
 
121
+ let template = await readCarsonTemplate(templateId);
120
122
  let templateRenders = await renderCarsonTemplate({
121
- templateId,
123
+ template,
122
124
  templateData: {
123
125
  workspace,
124
126
  project,
@@ -129,11 +131,16 @@ export class Project<M extends boolean = true> {
129
131
  await applyTemplateRenders({
130
132
  templateRenders,
131
133
  targetPath: project.path,
132
- snapshotPath: path.join(project.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),
134
+ snapshotPath:
135
+ template.config.autoEject || !workspace.config.template ?
136
+ undefined
137
+ : path.join(project.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),
133
138
  ignoreStrategies: ['check'],
134
139
  });
135
140
 
136
- await saveProjectConfig({projectPath: project.path, projectConfig: {template: templateId}});
141
+ if (!template.config.autoEject && workspace.config.template) {
142
+ await saveProjectConfig({projectPath: project.path, projectConfig: {template: templateId}});
143
+ }
137
144
 
138
145
  await project.read();
139
146
 
@@ -242,8 +249,9 @@ export class Project<M extends boolean = true> {
242
249
  });
243
250
  }
244
251
 
252
+ let template = await readCarsonTemplate(this.config.template);
245
253
  let templateRenders = await renderCarsonTemplate({
246
- templateId: this.config.template,
254
+ template,
247
255
  templateData: {
248
256
  workspace: this.workspace,
249
257
  project: this,
@@ -254,7 +262,10 @@ export class Project<M extends boolean = true> {
254
262
  await applyTemplateRenders({
255
263
  templateRenders,
256
264
  targetPath: this.path,
257
- snapshotPath: path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),
265
+ snapshotPath:
266
+ template.config.autoEject || !this.workspace.config.template ?
267
+ undefined
268
+ : path.join(this.path, CARSON_CONFIG_DIRECTORY, PROJECT_SNAPSHOT_FILENAME),
258
269
  ignoreStrategies: ['create'],
259
270
  });
260
271
 
@@ -13,6 +13,7 @@ import {
13
13
  WORKSPACE_SNAPSHOT_FILENAME,
14
14
  } from '../constants.js';
15
15
  import {applyTemplateRenders} from '../template/applyTemplateRenders.js';
16
+ import {readCarsonTemplate} from '../template/internals.js';
16
17
  import {renderCarsonTemplate} from '../template/renderCarsonTemplate.js';
17
18
  import {
18
19
  compareProjectPath,
@@ -181,8 +182,9 @@ export class Workspace<M extends boolean = true> {
181
182
  });
182
183
  }
183
184
 
185
+ let template = await readCarsonTemplate(templateId);
184
186
  let templateRenders = await renderCarsonTemplate({
185
- templateId,
187
+ template,
186
188
  templateData: {
187
189
  workspace,
188
190
  args,
@@ -192,14 +194,19 @@ export class Workspace<M extends boolean = true> {
192
194
  await applyTemplateRenders({
193
195
  templateRenders,
194
196
  targetPath: workspace.path,
195
- snapshotPath: path.join(workspace.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),
197
+ snapshotPath:
198
+ template.config.autoEject ?
199
+ undefined
200
+ : path.join(workspace.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),
196
201
  ignoreStrategies: ['check'],
197
202
  });
198
203
 
199
- await saveWorkspaceConfig({
200
- workspacePath: workspace.path,
201
- workspaceConfig: {template: templateId},
202
- });
204
+ if (!template.config.autoEject) {
205
+ await saveWorkspaceConfig({
206
+ workspacePath: workspace.path,
207
+ workspaceConfig: {template: templateId},
208
+ });
209
+ }
203
210
 
204
211
  return Workspace.read(workspace.path);
205
212
  }
@@ -490,8 +497,9 @@ export class Workspace<M extends boolean = true> {
490
497
  });
491
498
  }
492
499
 
500
+ let template = await readCarsonTemplate(this.config.template);
493
501
  let templateRenders = await renderCarsonTemplate({
494
- templateId: this.config.template,
502
+ template,
495
503
  templateData: {
496
504
  workspace: this,
497
505
  args,
@@ -501,7 +509,10 @@ export class Workspace<M extends boolean = true> {
501
509
  await applyTemplateRenders({
502
510
  templateRenders,
503
511
  targetPath: this.path,
504
- snapshotPath: path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),
512
+ snapshotPath:
513
+ template.config.autoEject ?
514
+ undefined
515
+ : path.join(this.path, CARSON_CONFIG_DIRECTORY, WORKSPACE_SNAPSHOT_FILENAME),
505
516
  ignoreStrategies: ['create'],
506
517
  });
507
518