@tanstack/cta-engine 0.10.0-alpha.18 → 0.10.0-alpha.19

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.
@@ -94,16 +94,7 @@ Use the following commands to start your app:
94
94
  }
95
95
  export async function createApp(options, { silent = false, environment, cwd, appName = 'TanStack', }) {
96
96
  environment.startRun();
97
- let targetDir = cwd || '';
98
- if (!targetDir.length) {
99
- targetDir = resolve(process.cwd(), options.projectName);
100
- if (environment.exists(targetDir)) {
101
- if (!silent) {
102
- environment.error(`Directory "${options.projectName}" already exists`);
103
- }
104
- return;
105
- }
106
- }
97
+ const targetDir = cwd || resolve(process.cwd(), options.projectName);
107
98
  await writeFiles(environment, targetDir, options);
108
99
  await runCommandsAndInstallDependencies(environment, targetDir, options, silent);
109
100
  environment.finishRun();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/cta-engine",
3
- "version": "0.10.0-alpha.18",
3
+ "version": "0.10.0-alpha.19",
4
4
  "description": "Tanstack Application Builder Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/create-app.ts CHANGED
@@ -174,17 +174,7 @@ export async function createApp(
174
174
  ) {
175
175
  environment.startRun()
176
176
 
177
- let targetDir: string = cwd || ''
178
- if (!targetDir.length) {
179
- targetDir = resolve(process.cwd(), options.projectName)
180
-
181
- if (environment.exists(targetDir)) {
182
- if (!silent) {
183
- environment.error(`Directory "${options.projectName}" already exists`)
184
- }
185
- return
186
- }
187
- }
177
+ const targetDir: string = cwd || resolve(process.cwd(), options.projectName)
188
178
 
189
179
  await writeFiles(environment, targetDir, options)
190
180
 
@@ -1,11 +1,19 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { fs, vol } from 'memfs'
2
3
  import { resolve } from 'node:path'
3
4
 
4
- import { writeConfigFile } from '../src/config-file.js'
5
+ import { readConfigFile, writeConfigFile } from '../src/config-file.js'
5
6
  import { CONFIG_FILE } from '../src/constants.js'
6
7
 
7
8
  import type { AddOn, Environment, Framework, Options } from '../src/types.js'
8
9
 
10
+ vi.mock('node:fs', () => fs)
11
+ vi.mock('node:fs/promises', () => fs.promises)
12
+
13
+ beforeEach(() => {
14
+ vol.reset()
15
+ })
16
+
9
17
  describe('writeConfigFile', () => {
10
18
  it('should write the config file', async () => {
11
19
  const options = {
@@ -37,3 +45,20 @@ describe('writeConfigFile', () => {
37
45
  await writeConfigFile(env, targetDir, options)
38
46
  })
39
47
  })
48
+
49
+ describe('readConfigFile', () => {
50
+ it('should read the config file', async () => {
51
+ const persistedOptions = {
52
+ version: 1,
53
+ framework: 'react-cra',
54
+ existingAddOns: ['add-on-1'],
55
+ }
56
+ vol.mkdirSync('/test')
57
+ vol.writeFileSync(
58
+ resolve('/test', CONFIG_FILE),
59
+ JSON.stringify(persistedOptions, null, 2),
60
+ )
61
+ const config = await readConfigFile('/test')
62
+ expect(config).toEqual(persistedOptions)
63
+ })
64
+ })
@@ -138,7 +138,6 @@ describe('createApp', () => {
138
138
  },
139
139
  )
140
140
 
141
- console.log(output.commands)
142
141
  expect(output.files['/src/test2.txt']).toEqual('hello')
143
142
  expect(output.commands.some(({ command }) => command === 'echo')).toBe(true)
144
143
  })
@@ -1,13 +1,31 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { fs, vol } from 'memfs'
2
3
 
3
- import { createMemoryEnvironment } from '../src/environment.js'
4
+ vi.mock('node:fs', () => fs)
5
+ vi.mock('node:fs/promises', () => fs.promises)
6
+
7
+ beforeEach(() => {
8
+ vol.reset()
9
+ })
10
+
11
+ import {
12
+ createMemoryEnvironment,
13
+ createDefaultEnvironment,
14
+ } from '../src/environment.js'
4
15
 
5
16
  describe('createMemoryEnvironment', () => {
6
17
  it('should handle basic file operations', async () => {
7
18
  const { environment, output } = createMemoryEnvironment()
8
19
 
9
20
  environment.startRun()
21
+
22
+ await environment.writeFile('/test.txt', 'test')
23
+
24
+ environment.deleteFile('/test.txt')
25
+ expect(environment.exists('/test.txt')).toBe(false)
26
+
10
27
  await environment.writeFile('/test.txt', 'test')
28
+
11
29
  environment.finishRun()
12
30
 
13
31
  expect(output.files['/test.txt']).toEqual('test')
@@ -25,3 +43,54 @@ describe('createMemoryEnvironment', () => {
25
43
  expect(output.commands[0].args).toEqual(['test'])
26
44
  })
27
45
  })
46
+
47
+ describe('createDefaultEnvironment', () => {
48
+ it('should create a default environment', async () => {
49
+ const environment = createDefaultEnvironment()
50
+ expect(environment).toBeDefined()
51
+ })
52
+
53
+ it('should write to the file system', async () => {
54
+ const environment = createDefaultEnvironment()
55
+ environment.startRun()
56
+ await environment.writeFile('/test.txt', 'test')
57
+ await environment.appendFile('/test.txt', 'test2')
58
+ await environment.copyFile('/test.txt', '/test2.txt')
59
+ environment.finishRun()
60
+
61
+ expect(fs.readFileSync('/test.txt', 'utf8')).toEqual('testtest2')
62
+ })
63
+
64
+ it('should allow deletes', async () => {
65
+ const environment = createDefaultEnvironment()
66
+ await environment.writeFile('/test.txt', 'test')
67
+ expect(fs.readFileSync('/test.txt', 'utf8')).toEqual('test')
68
+ await environment.deleteFile('/test.txt')
69
+ expect(environment.exists('/test.txt')).toBe(false)
70
+ })
71
+
72
+ it('should record errors', async () => {
73
+ const environment = createDefaultEnvironment()
74
+ environment.startRun()
75
+ await environment.execute('command-that-does-not-exist', ['test'], '')
76
+ environment.finishRun()
77
+ expect(environment.getErrors()).toEqual([
78
+ 'Command "command-that-does-not-exist test" did not run successfully. Please run this manually in your project.',
79
+ ])
80
+ })
81
+
82
+ it('should have UI methods', async () => {
83
+ const environment = createDefaultEnvironment()
84
+ environment.startRun()
85
+ environment.intro('test')
86
+ environment.outro('test')
87
+ environment.info('test')
88
+ environment.error('test')
89
+ environment.warn('test')
90
+ const s = environment.spinner()
91
+ s.start('foo')
92
+ s.stop('bar')
93
+ environment.finishRun()
94
+ expect(await environment.confirm('test')).toEqual(true)
95
+ })
96
+ })
@@ -1,6 +1,19 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { fs, vol } from 'memfs'
2
3
 
3
- import { relativePath } from '../src/file-helpers.js'
4
+ import {
5
+ findFilesRecursively,
6
+ isDirectory,
7
+ readFileHelper,
8
+ relativePath,
9
+ } from '../src/file-helpers.js'
10
+
11
+ vi.mock('node:fs', () => fs)
12
+ vi.mock('node:fs/promises', () => fs.promises)
13
+
14
+ beforeEach(() => {
15
+ vol.reset()
16
+ })
4
17
 
5
18
  describe('relativePath', () => {
6
19
  it('relative path with the same directory', () => {
@@ -35,3 +48,43 @@ describe('relativePath', () => {
35
48
  ).toBe('../integrations/tanstack-query/layout.tsx')
36
49
  })
37
50
  })
51
+
52
+ describe('readFileHelper', () => {
53
+ it('should read a file', async () => {
54
+ vol.mkdirSync('/src')
55
+ fs.writeFileSync('/src/test.txt', 'Hello')
56
+ expect(readFileHelper('/src/test.txt')).toBe('Hello')
57
+ })
58
+ it('should read a binary file', async () => {
59
+ vol.mkdirSync('/src')
60
+ fs.writeFileSync('/src/test.jpg', 'Hello')
61
+ expect(readFileHelper('/src/test.jpg')).toBe('base64::SGVsbG8=')
62
+ })
63
+ })
64
+
65
+ describe('isDirectory', () => {
66
+ it('should check on files and directories', () => {
67
+ vol.mkdirSync('/src')
68
+ fs.writeFileSync('/src/test.txt', 'Hello')
69
+ expect(isDirectory('/src/test.txt')).toBe(false)
70
+ expect(isDirectory('/src')).toBe(true)
71
+ })
72
+ })
73
+
74
+ describe('findFilesRecursively', () => {
75
+ it('find files recursively', () => {
76
+ vol.mkdirSync('/src/subdir/subdir2', { recursive: true })
77
+ fs.writeFileSync('/src/test.txt', 'Hello')
78
+ fs.writeFileSync('/src/subdir/test.txt', 'Hello')
79
+ fs.writeFileSync('/src/subdir/subdir2/test.txt', 'Hello')
80
+
81
+ const files = {}
82
+ findFilesRecursively('/src', files)
83
+
84
+ expect(Object.keys(files)).toEqual([
85
+ '/src/subdir/subdir2/test.txt',
86
+ '/src/subdir/test.txt',
87
+ '/src/test.txt',
88
+ ])
89
+ })
90
+ })
@@ -0,0 +1,95 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { fs, vol } from 'memfs'
3
+
4
+ import {
5
+ getFrameworks,
6
+ getFrameworkById,
7
+ getFrameworkByName,
8
+ registerFramework,
9
+ } from '../src/frameworks.js'
10
+
11
+ vi.mock('node:fs', () => fs)
12
+ vi.mock('node:fs/promises', () => fs.promises)
13
+
14
+ beforeEach(() => {
15
+ vol.reset()
16
+ })
17
+
18
+ describe('registerFramework', () => {
19
+ it('should register a framework', async () => {
20
+ const addOnPackageJSON = {
21
+ id: 'test',
22
+ name: 'Test',
23
+ description: 'Test',
24
+ version: '1.0.0',
25
+ }
26
+ const basePackageJSON = {
27
+ name: 'Test',
28
+ version: '1.0.0',
29
+ }
30
+
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
+ registerFramework({
68
+ id: 'test',
69
+ name: 'Test',
70
+ addOnsDirectories: ['/test/add-ons'],
71
+ description: 'Test',
72
+ version: '1.0.0',
73
+ baseDirectory: '/test/project',
74
+ examplesDirectory: '/test/examples',
75
+ })
76
+
77
+ const f = getFrameworkById('test')!
78
+
79
+ const baseFiles = await f.getFiles()
80
+ expect(baseFiles).toEqual(['./package.json'])
81
+
82
+ const fileContents = await f.getFileContents('./package.json')
83
+ expect(fileContents).toEqual(JSON.stringify(basePackageJSON))
84
+
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
+ expect(getFrameworkByName('Test')).not.toBeUndefined()
93
+ expect(getFrameworks().length).toEqual(1)
94
+ })
95
+ })
@@ -0,0 +1,9 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { createApp } from '../src/index.js'
4
+
5
+ describe('index', () => {
6
+ it('should be a test', () => {
7
+ expect(createApp).toBeDefined()
8
+ })
9
+ })
@@ -154,8 +154,6 @@ describe('createTemplateFile', () => {
154
154
  )
155
155
  environment.finishRun()
156
156
 
157
- console.log(output.files['/test/test.txt'])
158
-
159
157
  expect(output.files['/test/test.txt']).toEqual('/test')
160
158
  })
161
159
 
@@ -0,0 +1,19 @@
1
+ import { defineConfig } from 'vitest/config'
2
+ import path from 'node:path'
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ deps: {
7
+ moduleDirectories: ['node_modules', path.resolve('../../packages')],
8
+ },
9
+ coverage: {
10
+ exclude: [
11
+ 'node_modules',
12
+ 'dist',
13
+ 'build',
14
+ '**/types.ts',
15
+ 'vitest.config.ts',
16
+ ],
17
+ },
18
+ },
19
+ })