@tanstack/cta-engine 0.15.2 → 0.15.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/constants.js CHANGED
@@ -1,3 +1 @@
1
- export const CODE_ROUTER = 'code-router';
2
- export const FILE_ROUTER = 'file-router';
3
1
  export const CONFIG_FILE = '.cta.json';
@@ -171,7 +171,7 @@ Use the following commands to start your app:
171
171
  % cd ${options.projectName}
172
172
  % ${formatCommand(getPackageManagerScriptCommand(options.packageManager, ['dev']))}
173
173
 
174
- Please check the README.md for more information on testing, styling, adding routes, etc.${errorStatement}`);
174
+ Please read the README.md for information on testing, styling, adding routes, etc.${errorStatement}`);
175
175
  }
176
176
  export async function createApp(environment, options) {
177
177
  environment.startRun();
@@ -61,8 +61,8 @@ export default (parentRoute: RootRoute) => createRoute({
61
61
  }
62
62
  export async function validateAddOnSetup(environment) {
63
63
  const options = await readCurrentProjectOptions(environment);
64
- if (options.mode !== 'file-router') {
65
- environment.error('This project is not using file-router mode.', 'To create an add-on, the project must be created with the file-router mode.');
64
+ if (options.mode === 'code-router') {
65
+ environment.error('This project is using code-router mode.', 'To create an add-on, the project must not use code-router mode.');
66
66
  process.exit(1);
67
67
  }
68
68
  if (!options.tailwind) {
@@ -2,9 +2,28 @@ import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
3
  import { findFilesRecursively, isDirectory, readFileHelper, } from './file-helpers.js';
4
4
  const frameworks = [];
5
- function getAddOns(framework) {
5
+ export function scanProjectDirectory(projectDirectory, baseDirectory) {
6
+ const absolutePaths = {};
7
+ findFilesRecursively(baseDirectory, absolutePaths);
8
+ const files = Object.keys(absolutePaths).reduce((acc, path) => {
9
+ acc[path.replace(baseDirectory, '.')] = absolutePaths[path];
10
+ return acc;
11
+ }, {});
12
+ const basePackageJSON = existsSync(resolve(baseDirectory, 'package.json'))
13
+ ? JSON.parse(readFileSync(resolve(baseDirectory, 'package.json'), 'utf8'))
14
+ : {};
15
+ const optionalPackages = existsSync(resolve(projectDirectory, 'packages.json'))
16
+ ? JSON.parse(readFileSync(resolve(projectDirectory, 'packages.json'), 'utf8'))
17
+ : {};
18
+ return {
19
+ files,
20
+ basePackageJSON,
21
+ optionalPackages,
22
+ };
23
+ }
24
+ export function scanAddOnDirectories(addOnsDirectories) {
6
25
  const addOns = [];
7
- for (const addOnsBase of framework.addOnsDirectories) {
26
+ for (const addOnsBase of addOnsDirectories) {
8
27
  for (const dir of readdirSync(addOnsBase).filter((file) => isDirectory(resolve(addOnsBase, file)))) {
9
28
  const filePath = resolve(addOnsBase, dir, 'info.json');
10
29
  const fileContent = readFileSync(filePath, 'utf-8');
@@ -58,25 +77,16 @@ export function __testClearFrameworks() {
58
77
  frameworks.length = 0;
59
78
  }
60
79
  export function registerFramework(framework) {
61
- const baseAssetsDirectory = resolve(framework.baseDirectory, 'base');
62
- const basePackageJSON = JSON.parse(readFileSync(resolve(baseAssetsDirectory, 'package.json'), 'utf8'));
63
- const optionalPackages = JSON.parse(readFileSync(resolve(framework.baseDirectory, 'packages.json'), 'utf8'));
64
- const addOns = getAddOns(framework);
80
+ const { addOns, base, ...rest } = framework;
65
81
  const frameworkWithBundler = {
66
- ...framework,
67
- getFiles: () => {
68
- const files = {};
69
- findFilesRecursively(baseAssetsDirectory, files);
70
- return Promise.resolve(Object.keys(files).map((path) => path.replace(baseAssetsDirectory, '.')));
71
- },
82
+ ...rest,
83
+ getFiles: () => Promise.resolve(Object.keys(base)),
72
84
  getFileContents: (path) => {
73
- return Promise.resolve(readFileHelper(resolve(baseAssetsDirectory, path)));
85
+ return Promise.resolve(base[path]);
74
86
  },
75
87
  getDeletedFiles: () => {
76
88
  return Promise.resolve([]);
77
89
  },
78
- basePackageJSON,
79
- optionalPackages,
80
90
  getAddOns: () => addOns,
81
91
  };
82
92
  frameworks.push(frameworkWithBundler);
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@ export { finalizeAddOns, getAllAddOns } from './add-ons.js';
4
4
  export { loadRemoteAddOn } from './custom-add-ons/add-on.js';
5
5
  export { loadStarter } from './custom-add-ons/starter.js';
6
6
  export { createMemoryEnvironment, createDefaultEnvironment, } from './environment.js';
7
- export { CODE_ROUTER, CONFIG_FILE, FILE_ROUTER } from './constants.js';
7
+ export { CONFIG_FILE } from './constants.js';
8
8
  export { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getPackageManager, } from './package-manager.js';
9
- export { registerFramework, getFrameworkById, getFrameworkByName, getFrameworks, } from './frameworks.js';
9
+ export { registerFramework, getFrameworkById, getFrameworkByName, getFrameworks, scanProjectDirectory, scanAddOnDirectories, } from './frameworks.js';
10
10
  export { writeConfigFileToEnvironment, readConfigFileFromEnvironment, readConfigFile, } from './config-file.js';
11
11
  export { cleanUpFiles, cleanUpFileArray, readFileHelper, getBinaryFile, recursivelyGatherFiles, relativePath, } from './file-helpers.js';
12
12
  export { formatCommand, handleSpecialURL } from './utils.js';
@@ -1,4 +1,3 @@
1
- import { FILE_ROUTER } from './constants.js';
2
1
  import { sortObject } from './utils.js';
3
2
  export function mergePackageJSON(packageJSON, overlayPackageJSON) {
4
3
  return {
@@ -29,9 +28,7 @@ export function createPackageJSON(options) {
29
28
  options.tailwind
30
29
  ? options.framework.optionalPackages.tailwindcss
31
30
  : undefined,
32
- options.mode === FILE_ROUTER
33
- ? options.framework.optionalPackages['file-router']
34
- : undefined,
31
+ options.mode ? options.framework.optionalPackages[options.mode] : undefined,
35
32
  ];
36
33
  for (const addition of additions.filter(Boolean)) {
37
34
  packageJSON = mergePackageJSON(packageJSON, addition);
package/dist/registry.js CHANGED
@@ -9,7 +9,7 @@ const registrySchema = z.object({
9
9
  description: z.string(),
10
10
  url: z.string(),
11
11
  banner: z.string().optional(),
12
- mode: z.enum(['code-router', 'file-router']),
12
+ mode: z.string(),
13
13
  framework: z.string(),
14
14
  }))
15
15
  .optional(),
@@ -18,7 +18,7 @@ const registrySchema = z.object({
18
18
  name: z.string(),
19
19
  description: z.string(),
20
20
  url: z.string(),
21
- modes: z.array(z.enum(['code-router', 'file-router'])),
21
+ modes: z.array(z.string()),
22
22
  framework: z.string(),
23
23
  }))
24
24
  .optional(),
@@ -1,7 +1,6 @@
1
1
  import { resolve, sep } from 'node:path';
2
2
  import { render } from 'ejs';
3
3
  import { format } from 'prettier';
4
- import { CODE_ROUTER, FILE_ROUTER } from './constants.js';
5
4
  import { formatCommand } from './utils.js';
6
5
  import { getPackageManagerInstallCommand, getPackageManagerScriptCommand, } from './package-manager.js';
7
6
  import { relativePath } from './file-helpers.js';
@@ -53,8 +52,8 @@ export function createTemplateFile(environment, options) {
53
52
  tailwind: options.tailwind,
54
53
  js: options.typescript ? 'ts' : 'js',
55
54
  jsx: options.typescript ? 'tsx' : 'jsx',
56
- fileRouter: options.mode === FILE_ROUTER,
57
- codeRouter: options.mode === CODE_ROUTER,
55
+ fileRouter: options.mode === 'file-router',
56
+ codeRouter: options.mode === 'code-router',
58
57
  addOnEnabled,
59
58
  addOns: options.chosenAddOns,
60
59
  integrations,
@@ -1,3 +1,3 @@
1
- import type { AddOn, Framework, Mode } from './types.js';
2
- export declare function getAllAddOns(framework: Framework, mode: Mode): Array<AddOn>;
3
- export declare function finalizeAddOns(framework: Framework, mode: Mode, chosenAddOnIDs: Array<string>): Promise<Array<AddOn>>;
1
+ import type { AddOn, Framework } from './types.js';
2
+ export declare function getAllAddOns(framework: Framework, mode: string): Array<AddOn>;
3
+ export declare function finalizeAddOns(framework: Framework, mode: string, chosenAddOnIDs: Array<string>): Promise<Array<AddOn>>;
@@ -1,3 +1 @@
1
- export declare const CODE_ROUTER = "code-router";
2
- export declare const FILE_ROUTER = "file-router";
3
1
  export declare const CONFIG_FILE = ".cta.json";
@@ -1,4 +1,10 @@
1
- import type { Framework, FrameworkDefinition } from './types.js';
1
+ import type { AddOn, Framework, FrameworkDefinition } from './types.js';
2
+ export declare function scanProjectDirectory(projectDirectory: string, baseDirectory: string): {
3
+ files: Record<string, string>;
4
+ basePackageJSON: any;
5
+ optionalPackages: any;
6
+ };
7
+ export declare function scanAddOnDirectories(addOnsDirectories: Array<string>): AddOn[];
2
8
  export declare function __testRegisterFramework(framework: Framework): void;
3
9
  export declare function __testClearFrameworks(): void;
4
10
  export declare function registerFramework(framework: FrameworkDefinition): void;
@@ -4,9 +4,9 @@ export { finalizeAddOns, getAllAddOns } from './add-ons.js';
4
4
  export { loadRemoteAddOn } from './custom-add-ons/add-on.js';
5
5
  export { loadStarter } from './custom-add-ons/starter.js';
6
6
  export { createMemoryEnvironment, createDefaultEnvironment, } from './environment.js';
7
- export { CODE_ROUTER, CONFIG_FILE, FILE_ROUTER } from './constants.js';
7
+ export { CONFIG_FILE } from './constants.js';
8
8
  export { DEFAULT_PACKAGE_MANAGER, SUPPORTED_PACKAGE_MANAGERS, getPackageManager, } from './package-manager.js';
9
- export { registerFramework, getFrameworkById, getFrameworkByName, getFrameworks, } from './frameworks.js';
9
+ export { registerFramework, getFrameworkById, getFrameworkByName, getFrameworks, scanProjectDirectory, scanAddOnDirectories, } from './frameworks.js';
10
10
  export { writeConfigFileToEnvironment, readConfigFileFromEnvironment, readConfigFile, } from './config-file.js';
11
11
  export { cleanUpFiles, cleanUpFileArray, readFileHelper, getBinaryFile, recursivelyGatherFiles, relativePath, } from './file-helpers.js';
12
12
  export { formatCommand, handleSpecialURL } from './utils.js';
@@ -16,6 +16,6 @@ export { createAppOptionsFromPersisted, createSerializedOptionsFromPersisted, }
16
16
  export { createSerializedOptions } from './options.js';
17
17
  export { getRawRegistry, getRegistry, getRegistryAddOns, getRegistryStarters, } from './registry.js';
18
18
  export { StarterCompiledSchema, StatusEvent, StatusStepType, StopEvent, AddOnCompiledSchema, AddOnInfoSchema, IntegrationSchema, } from './types.js';
19
- export type { AddOn, Environment, FileBundleHandler, Framework, FrameworkDefinition, Mode, Options, SerializedOptions, Starter, StarterCompiled, } from './types.js';
19
+ export type { AddOn, Environment, FileBundleHandler, Framework, FrameworkDefinition, Options, SerializedOptions, Starter, StarterCompiled, } from './types.js';
20
20
  export type { PersistedOptions } from './config-file.js';
21
21
  export type { PackageManager } from './package-manager.js';
@@ -6,41 +6,41 @@ declare const registrySchema: z.ZodObject<{
6
6
  description: z.ZodString;
7
7
  url: z.ZodString;
8
8
  banner: z.ZodOptional<z.ZodString>;
9
- mode: z.ZodEnum<["code-router", "file-router"]>;
9
+ mode: z.ZodString;
10
10
  framework: z.ZodString;
11
11
  }, "strip", z.ZodTypeAny, {
12
12
  name: string;
13
13
  description: string;
14
14
  url: string;
15
15
  framework: string;
16
- mode: "code-router" | "file-router";
16
+ mode: string;
17
17
  banner?: string | undefined;
18
18
  }, {
19
19
  name: string;
20
20
  description: string;
21
21
  url: string;
22
22
  framework: string;
23
- mode: "code-router" | "file-router";
23
+ mode: string;
24
24
  banner?: string | undefined;
25
25
  }>, "many">>;
26
26
  'add-ons': z.ZodOptional<z.ZodArray<z.ZodObject<{
27
27
  name: z.ZodString;
28
28
  description: z.ZodString;
29
29
  url: z.ZodString;
30
- modes: z.ZodArray<z.ZodEnum<["code-router", "file-router"]>, "many">;
30
+ modes: z.ZodArray<z.ZodString, "many">;
31
31
  framework: z.ZodString;
32
32
  }, "strip", z.ZodTypeAny, {
33
33
  name: string;
34
34
  description: string;
35
35
  url: string;
36
36
  framework: string;
37
- modes: ("code-router" | "file-router")[];
37
+ modes: string[];
38
38
  }, {
39
39
  name: string;
40
40
  description: string;
41
41
  url: string;
42
42
  framework: string;
43
- modes: ("code-router" | "file-router")[];
43
+ modes: string[];
44
44
  }>, "many">>;
45
45
  }, "strip", z.ZodTypeAny, {
46
46
  starters?: {
@@ -48,7 +48,7 @@ declare const registrySchema: z.ZodObject<{
48
48
  description: string;
49
49
  url: string;
50
50
  framework: string;
51
- mode: "code-router" | "file-router";
51
+ mode: string;
52
52
  banner?: string | undefined;
53
53
  }[] | undefined;
54
54
  'add-ons'?: {
@@ -56,7 +56,7 @@ declare const registrySchema: z.ZodObject<{
56
56
  description: string;
57
57
  url: string;
58
58
  framework: string;
59
- modes: ("code-router" | "file-router")[];
59
+ modes: string[];
60
60
  }[] | undefined;
61
61
  }, {
62
62
  starters?: {
@@ -64,7 +64,7 @@ declare const registrySchema: z.ZodObject<{
64
64
  description: string;
65
65
  url: string;
66
66
  framework: string;
67
- mode: "code-router" | "file-router";
67
+ mode: string;
68
68
  banner?: string | undefined;
69
69
  }[] | undefined;
70
70
  'add-ons'?: {
@@ -72,7 +72,7 @@ declare const registrySchema: z.ZodObject<{
72
72
  description: string;
73
73
  url: string;
74
74
  framework: string;
75
- modes: ("code-router" | "file-router")[];
75
+ modes: string[];
76
76
  }[] | undefined;
77
77
  }>;
78
78
  export type Registry = z.infer<typeof registrySchema>;
@@ -1,7 +1,5 @@
1
1
  import z from 'zod';
2
- import type { CODE_ROUTER, FILE_ROUTER } from './constants.js';
3
2
  import type { PackageManager } from './package-manager.js';
4
- export type Mode = typeof CODE_ROUTER | typeof FILE_ROUTER;
5
3
  export type StatusStepType = 'file' | 'command' | 'info' | 'package-manager' | 'other';
6
4
  export declare const AddOnBaseSchema: z.ZodObject<{
7
5
  id: z.ZodString;
@@ -736,20 +734,24 @@ export type FrameworkDefinition = {
736
734
  name: string;
737
735
  description: string;
738
736
  version: string;
739
- baseDirectory: string;
740
- addOnsDirectories: Array<string>;
741
- examplesDirectory: string;
742
- };
743
- export type Framework = FrameworkDefinition & FileBundleHandler & {
737
+ base: Record<string, string>;
738
+ addOns: Array<AddOn>;
744
739
  basePackageJSON: Record<string, any>;
745
740
  optionalPackages: Record<string, any>;
741
+ supportedModes: Record<string, {
742
+ displayName: string;
743
+ description: string;
744
+ forceTypescript: boolean;
745
+ }>;
746
+ };
747
+ export type Framework = Omit<FrameworkDefinition, 'base' | 'addOns'> & FileBundleHandler & {
746
748
  getAddOns: () => Array<AddOn>;
747
749
  };
748
750
  export interface Options {
749
751
  projectName: string;
750
752
  targetDir: string;
751
753
  framework: Framework;
752
- mode: Mode;
754
+ mode: string;
753
755
  typescript: boolean;
754
756
  tailwind: boolean;
755
757
  packageManager: PackageManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/cta-engine",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "description": "Tanstack Application Builder Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/add-ons.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import { loadRemoteAddOn } from './custom-add-ons/add-on.js'
2
2
 
3
- import type { AddOn, Framework, Mode } from './types.js'
3
+ import type { AddOn, Framework } from './types.js'
4
4
 
5
- export function getAllAddOns(framework: Framework, mode: Mode): Array<AddOn> {
5
+ export function getAllAddOns(framework: Framework, mode: string): Array<AddOn> {
6
6
  return framework.getAddOns().filter((a) => a.modes.includes(mode))
7
7
  }
8
8
 
9
9
  // Turn the list of chosen add-on IDs into a final list of add-ons by resolving dependencies
10
10
  export async function finalizeAddOns(
11
11
  framework: Framework,
12
- mode: Mode,
12
+ mode: string,
13
13
  chosenAddOnIDs: Array<string>,
14
14
  ): Promise<Array<AddOn>> {
15
15
  const finalAddOnIDs = new Set(chosenAddOnIDs)
package/src/add-to-app.ts CHANGED
@@ -19,7 +19,7 @@ import { mergePackageJSON } from './package-json.js'
19
19
  import { runSpecialSteps } from './special-steps/index.js'
20
20
  import { loadStarter } from './custom-add-ons/starter.js'
21
21
 
22
- import type { Environment, Mode, Options } from './types.js'
22
+ import type { Environment, Options } from './types.js'
23
23
  import type { PersistedOptions } from './config-file.js'
24
24
 
25
25
  export async function hasPendingGitChanges(
@@ -48,7 +48,7 @@ async function createOptions(
48
48
  framework,
49
49
  tailwind: true,
50
50
  addOns: true,
51
- chosenAddOns: await finalizeAddOns(framework!, json.mode as Mode, [
51
+ chosenAddOns: await finalizeAddOns(framework!, json.mode!, [
52
52
  ...json.chosenAddOns,
53
53
  ...addOns,
54
54
  ]),
package/src/constants.ts CHANGED
@@ -1,4 +1 @@
1
- export const CODE_ROUTER = 'code-router'
2
- export const FILE_ROUTER = 'file-router'
3
-
4
1
  export const CONFIG_FILE = '.cta.json'
package/src/create-app.ts CHANGED
@@ -233,7 +233,7 @@ Use the following commands to start your app:
233
233
  getPackageManagerScriptCommand(options.packageManager, ['dev']),
234
234
  )}
235
235
 
236
- Please check the README.md for more information on testing, styling, adding routes, etc.${errorStatement}`,
236
+ Please read the README.md for information on testing, styling, adding routes, etc.${errorStatement}`,
237
237
  )
238
238
  }
239
239
 
@@ -100,10 +100,10 @@ export default (parentRoute: RootRoute) => createRoute({
100
100
  export async function validateAddOnSetup(environment: Environment) {
101
101
  const options = await readCurrentProjectOptions(environment)
102
102
 
103
- if (options.mode !== 'file-router') {
103
+ if (options.mode === 'code-router') {
104
104
  environment.error(
105
- 'This project is not using file-router mode.',
106
- 'To create an add-on, the project must be created with the file-router mode.',
105
+ 'This project is using code-router mode.',
106
+ 'To create an add-on, the project must not use code-router mode.',
107
107
  )
108
108
  process.exit(1)
109
109
  }
@@ -8,7 +8,7 @@ import { readConfigFileFromEnvironment } from '../config-file.js'
8
8
  import { readFileHelper } from '../file-helpers.js'
9
9
  import { loadStarter } from '../custom-add-ons/starter.js'
10
10
 
11
- import type { Environment, Mode, Options, SerializedOptions } from '../types.js'
11
+ import type { Environment, Options, SerializedOptions } from '../types.js'
12
12
  import type { PersistedOptions } from '../config-file.js'
13
13
 
14
14
  export function createPackageAdditions(
@@ -68,7 +68,7 @@ export async function createAppOptionsFromPersisted(
68
68
  const framework = getFrameworkById(rest.framework)
69
69
  return {
70
70
  ...rest,
71
- mode: json.mode as Mode,
71
+ mode: json.mode!,
72
72
  projectName: json.projectName!,
73
73
  typescript: json.typescript!,
74
74
  tailwind: json.tailwind!,
@@ -77,7 +77,7 @@ export async function createAppOptionsFromPersisted(
77
77
  targetDir: '',
78
78
  framework: framework!,
79
79
  starter: json.starter ? await loadStarter(json.starter) : undefined,
80
- chosenAddOns: await finalizeAddOns(framework!, json.mode as Mode, [
80
+ chosenAddOns: await finalizeAddOns(framework!, json.mode!, [
81
81
  ...json.chosenAddOns,
82
82
  ]),
83
83
  }
@@ -91,7 +91,7 @@ export function createSerializedOptionsFromPersisted(
91
91
  /* eslint-enable unused-imports/no-unused-vars */
92
92
  return {
93
93
  ...rest,
94
- mode: json.mode as Mode,
94
+ mode: json.mode!,
95
95
  projectName: json.projectName!,
96
96
  typescript: json.typescript!,
97
97
  tailwind: json.tailwind!,
package/src/frameworks.ts CHANGED
@@ -11,10 +11,44 @@ import type { AddOn, Framework, FrameworkDefinition } from './types.js'
11
11
 
12
12
  const frameworks: Array<Framework> = []
13
13
 
14
- function getAddOns(framework: FrameworkDefinition) {
14
+ export function scanProjectDirectory(
15
+ projectDirectory: string,
16
+ baseDirectory: string,
17
+ ) {
18
+ const absolutePaths: Record<string, string> = {}
19
+ findFilesRecursively(baseDirectory, absolutePaths)
20
+
21
+ const files = Object.keys(absolutePaths).reduce(
22
+ (acc, path) => {
23
+ acc[path.replace(baseDirectory, '.')] = absolutePaths[path]
24
+ return acc
25
+ },
26
+ {} as Record<string, string>,
27
+ )
28
+
29
+ const basePackageJSON = existsSync(resolve(baseDirectory, 'package.json'))
30
+ ? JSON.parse(readFileSync(resolve(baseDirectory, 'package.json'), 'utf8'))
31
+ : {}
32
+
33
+ const optionalPackages = existsSync(
34
+ resolve(projectDirectory, 'packages.json'),
35
+ )
36
+ ? JSON.parse(
37
+ readFileSync(resolve(projectDirectory, 'packages.json'), 'utf8'),
38
+ )
39
+ : {}
40
+
41
+ return {
42
+ files,
43
+ basePackageJSON,
44
+ optionalPackages,
45
+ }
46
+ }
47
+
48
+ export function scanAddOnDirectories(addOnsDirectories: Array<string>) {
15
49
  const addOns: Array<AddOn> = []
16
50
 
17
- for (const addOnsBase of framework.addOnsDirectories) {
51
+ for (const addOnsBase of addOnsDirectories) {
18
52
  for (const dir of readdirSync(addOnsBase).filter((file) =>
19
53
  isDirectory(resolve(addOnsBase, file)),
20
54
  )) {
@@ -85,36 +119,17 @@ export function __testClearFrameworks() {
85
119
  }
86
120
 
87
121
  export function registerFramework(framework: FrameworkDefinition) {
88
- const baseAssetsDirectory = resolve(framework.baseDirectory, 'base')
89
-
90
- const basePackageJSON = JSON.parse(
91
- readFileSync(resolve(baseAssetsDirectory, 'package.json'), 'utf8'),
92
- )
93
- const optionalPackages = JSON.parse(
94
- readFileSync(resolve(framework.baseDirectory, 'packages.json'), 'utf8'),
95
- )
96
-
97
- const addOns = getAddOns(framework)
122
+ const { addOns, base, ...rest } = framework
98
123
 
99
124
  const frameworkWithBundler: Framework = {
100
- ...framework,
101
- getFiles: () => {
102
- const files: Record<string, string> = {}
103
- findFilesRecursively(baseAssetsDirectory, files)
104
- return Promise.resolve(
105
- Object.keys(files).map((path) =>
106
- path.replace(baseAssetsDirectory, '.'),
107
- ),
108
- )
109
- },
125
+ ...rest,
126
+ getFiles: () => Promise.resolve(Object.keys(base)),
110
127
  getFileContents: (path: string) => {
111
- return Promise.resolve(readFileHelper(resolve(baseAssetsDirectory, path)))
128
+ return Promise.resolve(base[path])
112
129
  },
113
130
  getDeletedFiles: () => {
114
131
  return Promise.resolve([])
115
132
  },
116
- basePackageJSON,
117
- optionalPackages,
118
133
  getAddOns: () => addOns,
119
134
  }
120
135
 
package/src/index.ts CHANGED
@@ -11,7 +11,7 @@ export {
11
11
  createDefaultEnvironment,
12
12
  } from './environment.js'
13
13
 
14
- export { CODE_ROUTER, CONFIG_FILE, FILE_ROUTER } from './constants.js'
14
+ export { CONFIG_FILE } from './constants.js'
15
15
 
16
16
  export {
17
17
  DEFAULT_PACKAGE_MANAGER,
@@ -24,6 +24,8 @@ export {
24
24
  getFrameworkById,
25
25
  getFrameworkByName,
26
26
  getFrameworks,
27
+ scanProjectDirectory,
28
+ scanAddOnDirectories,
27
29
  } from './frameworks.js'
28
30
 
29
31
  export {
@@ -75,7 +77,6 @@ export type {
75
77
  FileBundleHandler,
76
78
  Framework,
77
79
  FrameworkDefinition,
78
- Mode,
79
80
  Options,
80
81
  SerializedOptions,
81
82
  Starter,
@@ -1,4 +1,3 @@
1
- import { FILE_ROUTER } from './constants.js'
2
1
  import { sortObject } from './utils.js'
3
2
 
4
3
  import type { Options } from './types.js'
@@ -37,9 +36,7 @@ export function createPackageJSON(options: Options) {
37
36
  options.tailwind
38
37
  ? options.framework.optionalPackages.tailwindcss
39
38
  : undefined,
40
- options.mode === FILE_ROUTER
41
- ? options.framework.optionalPackages['file-router']
42
- : undefined,
39
+ options.mode ? options.framework.optionalPackages[options.mode] : undefined,
43
40
  ]
44
41
  for (const addition of additions.filter(Boolean)) {
45
42
  packageJSON = mergePackageJSON(packageJSON, addition)
package/src/registry.ts CHANGED
@@ -13,7 +13,7 @@ const registrySchema = z.object({
13
13
  description: z.string(),
14
14
  url: z.string(),
15
15
  banner: z.string().optional(),
16
- mode: z.enum(['code-router', 'file-router']),
16
+ mode: z.string(),
17
17
  framework: z.string(),
18
18
  }),
19
19
  )
@@ -24,7 +24,7 @@ const registrySchema = z.object({
24
24
  name: z.string(),
25
25
  description: z.string(),
26
26
  url: z.string(),
27
- modes: z.array(z.enum(['code-router', 'file-router'])),
27
+ modes: z.array(z.string()),
28
28
  framework: z.string(),
29
29
  }),
30
30
  )
@@ -2,7 +2,6 @@ import { resolve, sep } from 'node:path'
2
2
  import { render } from 'ejs'
3
3
  import { format } from 'prettier'
4
4
 
5
- import { CODE_ROUTER, FILE_ROUTER } from './constants.js'
6
5
  import { formatCommand } from './utils.js'
7
6
  import {
8
7
  getPackageManagerInstallCommand,
@@ -83,8 +82,8 @@ export function createTemplateFile(environment: Environment, options: Options) {
83
82
  tailwind: options.tailwind,
84
83
  js: options.typescript ? 'ts' : 'js',
85
84
  jsx: options.typescript ? 'tsx' : 'jsx',
86
- fileRouter: options.mode === FILE_ROUTER,
87
- codeRouter: options.mode === CODE_ROUTER,
85
+ fileRouter: options.mode === 'file-router',
86
+ codeRouter: options.mode === 'code-router',
88
87
  addOnEnabled,
89
88
  addOns: options.chosenAddOns,
90
89
  integrations,
package/src/types.ts CHANGED
@@ -1,10 +1,7 @@
1
1
  import z from 'zod'
2
2
 
3
- import type { CODE_ROUTER, FILE_ROUTER } from './constants.js'
4
3
  import type { PackageManager } from './package-manager.js'
5
4
 
6
- export type Mode = typeof CODE_ROUTER | typeof FILE_ROUTER
7
-
8
5
  export type StatusStepType =
9
6
  | 'file'
10
7
  | 'command'
@@ -112,16 +109,23 @@ export type FrameworkDefinition = {
112
109
  description: string
113
110
  version: string
114
111
 
115
- baseDirectory: string
116
- addOnsDirectories: Array<string>
117
- examplesDirectory: string
112
+ base: Record<string, string>
113
+ addOns: Array<AddOn>
114
+ basePackageJSON: Record<string, any>
115
+ optionalPackages: Record<string, any>
116
+
117
+ supportedModes: Record<
118
+ string,
119
+ {
120
+ displayName: string
121
+ description: string
122
+ forceTypescript: boolean
123
+ }
124
+ >
118
125
  }
119
126
 
120
- export type Framework = FrameworkDefinition &
127
+ export type Framework = Omit<FrameworkDefinition, 'base' | 'addOns'> &
121
128
  FileBundleHandler & {
122
- basePackageJSON: Record<string, any>
123
- optionalPackages: Record<string, any>
124
-
125
129
  getAddOns: () => Array<AddOn>
126
130
  }
127
131
 
@@ -130,7 +134,7 @@ export interface Options {
130
134
  targetDir: string
131
135
 
132
136
  framework: Framework
133
- mode: Mode
137
+ mode: string
134
138
 
135
139
  typescript: boolean
136
140
  tailwind: boolean
@@ -50,7 +50,6 @@ beforeEach(() => {
50
50
  version: '1.0.0',
51
51
  baseDirectory: '/foo',
52
52
  addOnsDirectories: [],
53
- examplesDirectory: '',
54
53
  basePackageJSON: {},
55
54
  optionalPackages: {},
56
55
  getAddOns: () => [
@@ -38,9 +38,18 @@ beforeEach(() => {
38
38
  version: '1.0.0',
39
39
  baseDirectory: '/foo',
40
40
  addOnsDirectories: [],
41
- examplesDirectory: '',
42
41
  basePackageJSON: {},
43
42
  optionalPackages: {},
43
+ supportedModes: {
44
+ 'code-router': {
45
+ displayName: 'Code Router',
46
+ description: 'Code Router',
47
+ },
48
+ 'file-router': {
49
+ displayName: 'File Router',
50
+ description: 'File Router',
51
+ },
52
+ },
44
53
  getAddOns: () => [
45
54
  {
46
55
  id: 'test',
@@ -6,6 +6,8 @@ import {
6
6
  getFrameworkById,
7
7
  getFrameworkByName,
8
8
  registerFramework,
9
+ scanAddOnDirectories,
10
+ scanProjectDirectory,
9
11
  } from '../src/frameworks.js'
10
12
 
11
13
  vi.mock('node:fs', () => fs)
@@ -28,50 +30,24 @@ describe('registerFramework', () => {
28
30
  version: '1.0.0',
29
31
  }
30
32
 
31
- vol.mkdirSync('/test/add-ons/test/assets', { recursive: true })
32
- vol.writeFileSync(
33
- '/test/add-ons/test/info.json',
34
- JSON.stringify({
35
- id: 'test',
36
- name: 'Test',
37
- description: 'Test',
38
- version: '1.0.0',
39
- }),
40
- )
41
- vol.writeFileSync(
42
- '/test/add-ons/test/package.json',
43
- JSON.stringify({
44
- id: 'test',
45
- name: 'Test',
46
- description: 'Test',
47
- version: '1.0.0',
48
- }),
49
- )
50
- vol.writeFileSync(
51
- '/test/add-ons/test/assets/package.json',
52
- JSON.stringify(addOnPackageJSON),
53
- )
54
- vol.writeFileSync('/test/add-ons/test/README.md', 'foo')
55
- vol.mkdirSync('/test/project/base/assets', { recursive: true })
56
- vol.writeFileSync(
57
- '/test/project/base/package.json',
58
- JSON.stringify(basePackageJSON),
59
- )
60
- vol.writeFileSync(
61
- '/test/project/packages.json',
62
- JSON.stringify({
63
- typescript: {},
64
- }),
65
- )
66
-
67
33
  registerFramework({
68
34
  id: 'test',
69
35
  name: 'Test',
70
- addOnsDirectories: ['/test/add-ons'],
36
+ addOns: [],
71
37
  description: 'Test',
72
38
  version: '1.0.0',
73
- baseDirectory: '/test/project',
74
- examplesDirectory: '/test/examples',
39
+ base: {
40
+ './package.json': JSON.stringify(basePackageJSON),
41
+ },
42
+ basePackageJSON,
43
+ optionalPackages: {},
44
+ supportedModes: {
45
+ 'code-router': {
46
+ displayName: 'Code Router',
47
+ description: 'Code Router',
48
+ forceTypescript: false,
49
+ },
50
+ },
75
51
  })
76
52
 
77
53
  const f = getFrameworkById('test')!
@@ -82,13 +58,6 @@ describe('registerFramework', () => {
82
58
  const fileContents = await f.getFileContents('./package.json')
83
59
  expect(fileContents).toEqual(JSON.stringify(basePackageJSON))
84
60
 
85
- const addOns = await f.getAddOns()
86
- const addOnFiles = await addOns[0].getFiles()
87
- expect(addOnFiles).toEqual(['./package.json'])
88
-
89
- const addOnFileContents = await addOns[0].getFileContents('./package.json')
90
- expect(addOnFileContents).toEqual(JSON.stringify(addOnPackageJSON))
91
-
92
61
  expect(getFrameworkByName('Test')).not.toBeUndefined()
93
62
  expect(getFrameworks().length).toEqual(1)
94
63
  })
@@ -1,7 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
3
  import { createPackageJSON } from '../src/package-json.js'
4
- import { FILE_ROUTER } from '../src/constants.js'
5
4
 
6
5
  import type { Options, Framework } from '../src/types.js'
7
6
 
@@ -17,7 +16,7 @@ describe('createPackageJSON', () => {
17
16
  },
18
17
  },
19
18
  ],
20
- mode: FILE_ROUTER,
19
+ mode: 'file-router',
21
20
  typescript: true,
22
21
  tailwind: true,
23
22
  projectName: 'test',