@corva/create-app 0.0.0-2576df8 → 0.0.0-62a5f2b
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/README.md +8 -6
- package/common/python/Makefile +8 -5
- package/common/python/pyproject.toml +25 -0
- package/common/python/uv.lock +381 -0
- package/common/ui/config/vite/corva-vite-config.mjs +396 -0
- package/common/ui/devApp.js +1 -0
- package/common/ui/index.html +17 -0
- package/common/ui/isolatedApp.js +1 -0
- package/common/ui/public/DevCenterIsolatedAppPage.html +26 -0
- package/common/ui/public/favicon.ico +0 -0
- package/common/ui/vite.config.mjs +3 -0
- package/common/ui/vitest.global-setup.js +4 -0
- package/common/ui/vitest.setup.js +26 -0
- package/lib/commands/create.js +11 -3
- package/lib/commands/release.js +17 -2
- package/lib/constants/cli.js +5 -8
- package/lib/constants/manifest.js +3 -3
- package/lib/constants/package.js +78 -66
- package/lib/flow.js +6 -0
- package/lib/flows/lib/manifest.js +1 -1
- package/lib/flows/release.js +4 -0
- package/lib/flows/steps/release/resolve-prebuilt-zip.js +35 -0
- package/lib/flows/steps/zip-file-list-resolve.js +8 -1
- package/lib/flows/zip-simple.js +2 -0
- package/lib/helpers/cli-version.js +14 -1
- package/lib/helpers/resolve-app-runtime.js +25 -14
- package/lib/helpers/utils.js +7 -3
- package/lib/main.js +2 -3
- package/lib/options/zip-file-name.js +18 -0
- package/package.json +1 -1
- package/templates/ui/javascript/.eslintrc +4 -2
- package/templates/ui/javascript/AGENTS.md +13 -11
- package/templates/ui/javascript/src/{App.completion.js → App.completion.jsx} +3 -3
- package/templates/ui/javascript/src/{App.drilling.js → App.drilling.jsx} +3 -3
- package/templates/ui/javascript/src/{AppSettings.js → AppSettings.jsx} +1 -1
- package/templates/ui/javascript/src/__tests__/{AppSettings.test.js → AppSettings.test.jsx} +1 -1
- package/templates/ui/typescript/.eslintrc +3 -0
- package/templates/ui/typescript/AGENTS.md +11 -8
- package/templates/ui/typescript/src/App.completion.tsx +1 -1
- package/templates/ui/typescript/src/App.drilling.tsx +1 -1
- package/templates/ui/typescript/src/__tests__/AppSettings.test.tsx +1 -1
- package/templates/ui/typescript/tsconfig.json +17 -4
- package/common/python/requirements.txt +0 -2
- package/templates/ui/javascript/config/jest/babelTransform.js +0 -16
- package/templates/ui/javascript/config/jest/cssTransform.js +0 -16
- package/templates/ui/javascript/config/jest/fileTransform.js +0 -48
- package/templates/ui/javascript/config/jest/globalSetup.js +0 -5
- package/templates/ui/javascript/config/jest/setupTests.js +0 -30
- package/templates/ui/javascript/config-overrides.js +0 -10
- package/templates/ui/typescript/config/jest/babelTransform.js +0 -16
- package/templates/ui/typescript/config/jest/cssTransform.js +0 -16
- package/templates/ui/typescript/config/jest/fileTransform.js +0 -48
- package/templates/ui/typescript/config/jest/globalSetup.js +0 -5
- package/templates/ui/typescript/config/jest/setupTests.js +0 -30
- package/templates/ui/typescript/config-overrides.js +0 -10
- /package/templates/ui/javascript/src/{App.scss → App.module.scss} +0 -0
- /package/templates/ui/javascript/src/__tests__/{App.test.js → App.test.jsx} +0 -0
- /package/templates/ui/javascript/src/__tests__/{TestsExample.test.js → TestsExample.test.jsx} +0 -0
- /package/templates/ui/typescript/src/{App.scss → App.module.scss} +0 -0
package/lib/constants/package.js
CHANGED
|
@@ -12,47 +12,49 @@ const uiDependencies = {
|
|
|
12
12
|
'corva-convert-units': '1.10.33',
|
|
13
13
|
'highcharts': '10.3.3',
|
|
14
14
|
'highcharts-react-official': '2.2.2',
|
|
15
|
-
'lodash': '^4.
|
|
16
|
-
'mapbox
|
|
15
|
+
'lodash': '^4.18.1',
|
|
16
|
+
'mapbox-gl': '3.16.0',
|
|
17
17
|
'moment': '2.29.4',
|
|
18
18
|
'moment-timezone': '0.5.43',
|
|
19
|
-
'react': '
|
|
20
|
-
'react-dom': '
|
|
19
|
+
'react': '18.3.1',
|
|
20
|
+
'react-dom': '18.3.1',
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const jsUiDevDependencies = {
|
|
24
24
|
'@corva/dc-platform-shared': 'latest',
|
|
25
25
|
'@corva/eslint-config-browser': '0.2.2',
|
|
26
|
-
|
|
27
|
-
'@testing-library/
|
|
28
|
-
'@testing-library/
|
|
29
|
-
'@testing-library/
|
|
30
|
-
'
|
|
31
|
-
'
|
|
26
|
+
// @testing-library/react 16 moved this from a dependency to a peer
|
|
27
|
+
'@testing-library/dom': '10.4.1',
|
|
28
|
+
'@testing-library/jest-dom': '7.0.1',
|
|
29
|
+
'@testing-library/react': '16.3.2',
|
|
30
|
+
'@testing-library/user-event': '14.6.6',
|
|
31
|
+
'@vitejs/plugin-react': '6.1.1',
|
|
32
|
+
'@vitest/coverage-v8': '4.1.11',
|
|
33
|
+
'dotenv': '16.4.7',
|
|
34
|
+
'dotenv-expand': '11.0.7',
|
|
32
35
|
'eslint': '7.32.0',
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
36
|
+
'jsdom': '22.1.0',
|
|
37
|
+
'postcss-preset-env': '11.3.0',
|
|
38
|
+
'rollup-plugin-license': '3.6.0',
|
|
39
|
+
'sass-embedded': '1.100.0',
|
|
40
|
+
'terser': '5.47.1',
|
|
41
|
+
'vite': '8.3.0',
|
|
42
|
+
'vite-plugin-static-copy': '4.1.0',
|
|
43
|
+
'vitest': '4.1.11',
|
|
39
44
|
};
|
|
40
45
|
|
|
41
46
|
const tsUiDevDependencies = {
|
|
42
47
|
...jsUiDevDependencies,
|
|
43
|
-
'@
|
|
44
|
-
'@types/lodash': '4.17.5',
|
|
48
|
+
'@types/lodash': '^4.17.25',
|
|
45
49
|
'@types/material-ui': '0.21.9',
|
|
46
50
|
'@types/minimatch': '3.0.5',
|
|
47
51
|
'@types/mime': '3.0.1',
|
|
48
|
-
'@types/node': '
|
|
49
|
-
'@types/react': '
|
|
50
|
-
'@types/react-dom': '^
|
|
51
|
-
'@types/jest': '^27.0.1',
|
|
52
|
+
'@types/node': '24.12.2',
|
|
53
|
+
'@types/react': '18.2.42',
|
|
54
|
+
'@types/react-dom': '^18.2',
|
|
52
55
|
'@typescript-eslint/eslint-plugin': '^4.31.2',
|
|
53
56
|
'@typescript-eslint/parser': '^4.31.2',
|
|
54
|
-
'
|
|
55
|
-
'typescript': '4.6.3',
|
|
57
|
+
'typescript': '^5.9.3',
|
|
56
58
|
};
|
|
57
59
|
|
|
58
60
|
const corvaUiExtension = {
|
|
@@ -90,13 +92,13 @@ function applyUiExtension(packageJson, extensionNames) {
|
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
const uiScripts = {
|
|
93
|
-
build: '
|
|
94
|
-
start: '
|
|
95
|
+
build: 'vite build',
|
|
96
|
+
start: 'vite --open',
|
|
95
97
|
zip: 'create-corva-app zip .',
|
|
96
|
-
lint: 'eslint --cache ./src/',
|
|
98
|
+
lint: 'eslint --cache --ext .js,.jsx,.ts,.tsx ./src/',
|
|
97
99
|
release: 'create-corva-app release .',
|
|
98
|
-
test: '
|
|
99
|
-
coverage: '
|
|
100
|
+
test: 'vitest run',
|
|
101
|
+
coverage: 'vitest run --coverage',
|
|
100
102
|
};
|
|
101
103
|
|
|
102
104
|
const uiPackage = {
|
|
@@ -105,49 +107,18 @@ const uiPackage = {
|
|
|
105
107
|
'scripts': uiScripts,
|
|
106
108
|
'dependencies': uiDependencies,
|
|
107
109
|
'devDependencies': jsUiDevDependencies,
|
|
108
|
-
'jest': {
|
|
109
|
-
roots: ['<rootDir>/src'],
|
|
110
|
-
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
|
|
111
|
-
coverageThreshold: {
|
|
112
|
-
global: {
|
|
113
|
-
branches: 60,
|
|
114
|
-
functions: 60,
|
|
115
|
-
lines: 60,
|
|
116
|
-
statements: 60,
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
setupFilesAfterEnv: ['<rootDir>/config/jest/setupTests.js'],
|
|
120
|
-
globalSetup: '<rootDir>/config/jest/globalSetup.js',
|
|
121
|
-
testMatch: ['<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}', '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}'],
|
|
122
|
-
testEnvironment: 'jsdom',
|
|
123
|
-
transform: {
|
|
124
|
-
'^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': '<rootDir>/config/jest/babelTransform.js',
|
|
125
|
-
'^.+\\.css$': '<rootDir>/config/jest/cssTransform.js',
|
|
126
|
-
'^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': '<rootDir>/config/jest/fileTransform.js',
|
|
127
|
-
},
|
|
128
|
-
transformIgnorePatterns: [
|
|
129
|
-
'/node_modules/(?!.*@babel/runtime|@icon-park/react/es).+\\.(js|jsx|mjs|cjs|ts|tsx)$',
|
|
130
|
-
'^.+\\.(css|sass|scss)$',
|
|
131
|
-
],
|
|
132
|
-
modulePaths: [],
|
|
133
|
-
moduleNameMapper: {
|
|
134
|
-
'~(.*)': '<rootDir>/src/$1',
|
|
135
|
-
'^.+\\.(css|sass|scss)$': 'identity-obj-proxy',
|
|
136
|
-
'@corva/ui(.*)': '@corva/ui/cjs-bundle/$1',
|
|
137
|
-
},
|
|
138
|
-
watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
|
|
139
|
-
resetMocks: true,
|
|
140
|
-
},
|
|
141
110
|
'lint-staged': {
|
|
142
111
|
'src/**/*.{js,jsx,ts,tsx}': 'eslint --fix',
|
|
143
112
|
},
|
|
144
113
|
'resolutions': {
|
|
145
114
|
'@noble/hashes': '1.8.0',
|
|
115
|
+
'lodash': '4.18.1',
|
|
146
116
|
},
|
|
147
117
|
};
|
|
148
118
|
|
|
149
119
|
const tsUiPackage = {
|
|
150
120
|
...uiPackage,
|
|
121
|
+
scripts: { ...uiScripts, typecheck: 'tsc --noEmit' },
|
|
151
122
|
devDependencies: tsUiDevDependencies,
|
|
152
123
|
// todo: temporary solution, ref https://github.com/oppia/oppia/issues/22283#issuecomment-2756641371
|
|
153
124
|
resolutions: {
|
|
@@ -165,16 +136,19 @@ const nodeNpmScripts = {
|
|
|
165
136
|
};
|
|
166
137
|
|
|
167
138
|
const nodeDependencies = {
|
|
168
|
-
'@corva/node-sdk': '^8.
|
|
139
|
+
'@corva/node-sdk': '^8.5.0',
|
|
169
140
|
};
|
|
170
141
|
|
|
171
142
|
const nodeDevDependencies = {
|
|
172
|
-
'@corva/eslint-config-node': '^
|
|
143
|
+
'@corva/eslint-config-node': '^6.0.0',
|
|
144
|
+
'@typescript-eslint/eslint-plugin': '^8.58.1',
|
|
145
|
+
'@typescript-eslint/parser': '^8.58.1',
|
|
173
146
|
'jest': '^29.7.0',
|
|
174
147
|
'dotenv': '^16.0.3',
|
|
175
148
|
'eslint': '^8.2.0',
|
|
149
|
+
'eslint-plugin-jest': '^27.1.5',
|
|
176
150
|
'prettier': '^2.0.0',
|
|
177
|
-
'typescript': '^5.
|
|
151
|
+
'typescript': '^5.9.3',
|
|
178
152
|
};
|
|
179
153
|
|
|
180
154
|
const nodeTsDevDependencies = {
|
|
@@ -219,12 +193,47 @@ const nodeNpmPackage = {
|
|
|
219
193
|
eslintConfig: {
|
|
220
194
|
root: true,
|
|
221
195
|
extends: '@corva/eslint-config-node',
|
|
196
|
+
overrides: [
|
|
197
|
+
{
|
|
198
|
+
files: ['**/*.ts'],
|
|
199
|
+
parser: '@typescript-eslint/parser',
|
|
200
|
+
parserOptions: {
|
|
201
|
+
project: 'tsconfig.json',
|
|
202
|
+
sourceType: 'module',
|
|
203
|
+
},
|
|
204
|
+
plugins: ['@typescript-eslint/eslint-plugin'],
|
|
205
|
+
rules: {
|
|
206
|
+
'@typescript-eslint/padding-line-between-statements': 'off',
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
files: [
|
|
211
|
+
'**/*.spec.js',
|
|
212
|
+
'**/*.spec.ts',
|
|
213
|
+
'**/*.spec.mjs',
|
|
214
|
+
'**/*.spec.cjs',
|
|
215
|
+
'**/__mocks__/**/*.js',
|
|
216
|
+
'**/__mocks__/**/*.ts',
|
|
217
|
+
'**/__mocks__/**/*.cjs',
|
|
218
|
+
'**/__mocks__/**/*.mjs',
|
|
219
|
+
],
|
|
220
|
+
plugins: ['jest'],
|
|
221
|
+
env: {
|
|
222
|
+
jest: true,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
},
|
|
227
|
+
overrides: {
|
|
228
|
+
lodash: '4.18.1',
|
|
222
229
|
},
|
|
223
230
|
};
|
|
224
231
|
|
|
225
232
|
const nodeYarnPackage = {
|
|
226
233
|
...nodeNpmPackage,
|
|
227
234
|
scripts: nodeYarnScripts,
|
|
235
|
+
overrides: undefined,
|
|
236
|
+
resolutions: nodeNpmPackage.overrides,
|
|
228
237
|
};
|
|
229
238
|
|
|
230
239
|
const nodeTsNpmPackage = {
|
|
@@ -241,11 +250,14 @@ const nodeTsNpmPackage = {
|
|
|
241
250
|
const nodeTsYarnPackage = {
|
|
242
251
|
...nodeTsNpmPackage,
|
|
243
252
|
scripts: nodeTsYarnScripts,
|
|
253
|
+
overrides: undefined,
|
|
254
|
+
resolutions: nodeNpmPackage.overrides,
|
|
244
255
|
};
|
|
245
256
|
|
|
246
257
|
const extendWithTsConfig = (packageJson, version) => {
|
|
247
258
|
packageJson.devDependencies = {
|
|
248
|
-
|
|
259
|
+
// New @tsconfig/nodeX package versioning: it starts with X major version
|
|
260
|
+
[`@tsconfig/node${version}`]: `^${version}`,
|
|
249
261
|
...packageJson.devDependencies,
|
|
250
262
|
};
|
|
251
263
|
|
package/lib/flow.js
CHANGED
|
@@ -29,6 +29,12 @@ export const runFlow = async (flow, context, indent = '') => {
|
|
|
29
29
|
|
|
30
30
|
const runSteps = async (steps = [], context = {}, indent = '') => {
|
|
31
31
|
for (const step of steps) {
|
|
32
|
+
if (typeof step.skip === 'function' && step.skip(context)) {
|
|
33
|
+
debug('Skipping %s', step.name || step.message);
|
|
34
|
+
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
if (step.name) {
|
|
33
39
|
const result = await runFlow(step, context, indent);
|
|
34
40
|
|
|
@@ -11,7 +11,7 @@ const SCHEDULER_MAPPING = [SCHEDULER_TYPE_DATA_TIME, SCHEDULER_TYPE_DEPTH, SCHED
|
|
|
11
11
|
{},
|
|
12
12
|
);
|
|
13
13
|
|
|
14
|
-
const NODE_RUNTIMES = [APP_RUNTIMES.
|
|
14
|
+
const NODE_RUNTIMES = [APP_RUNTIMES.NODE24];
|
|
15
15
|
|
|
16
16
|
export class Manifest {
|
|
17
17
|
constructor(manifest) {
|
package/lib/flows/release.js
CHANGED
|
@@ -8,6 +8,7 @@ import { ADD_LABEL_STEP } from './steps/release/add-label.js';
|
|
|
8
8
|
import { ADD_NOTES_STEP } from './steps/release/add-notes.js';
|
|
9
9
|
import { PUBLISH_PACKAGE_STEP } from './steps/release/publish.js';
|
|
10
10
|
import { RELEASE_PREPARE_DATA_STEP } from './steps/release/prepare-data.js';
|
|
11
|
+
import { RESOLVE_PREBUILT_ZIP_STEP } from './steps/release/resolve-prebuilt-zip.js';
|
|
11
12
|
|
|
12
13
|
export const RELEASE_FLOW = {
|
|
13
14
|
name: 'release',
|
|
@@ -15,6 +16,9 @@ export const RELEASE_FLOW = {
|
|
|
15
16
|
PREPARE_FLOW,
|
|
16
17
|
SETUP_API_CLIENT_STEP,
|
|
17
18
|
RELEASE_PREPARE_DATA_STEP,
|
|
19
|
+
// With --zip-file-name the archive already exists, so the zip flow is skipped entirely. That
|
|
20
|
+
// also lets runtimes the zip flow has no file list for (e.g. `provided.*`) be released.
|
|
21
|
+
RESOLVE_PREBUILT_ZIP_STEP,
|
|
18
22
|
ZIP_SIMPLE_FLOW,
|
|
19
23
|
UPLOAD_ZIP_TO_CORVA_STEP,
|
|
20
24
|
WAIT_FOR_BUILD_FINISH_STEP,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { StepError } from '../../lib/step-error.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Handles `--zip-file-name`: the caller has already built the package archive, so this records it
|
|
8
|
+
* as the archive to upload and marks the zip flow as a no-op.
|
|
9
|
+
*/
|
|
10
|
+
export const RESOLVE_PREBUILT_ZIP_STEP = {
|
|
11
|
+
message: 'Resolving prebuilt archive...',
|
|
12
|
+
fn: async ({ dirName, options }) => {
|
|
13
|
+
const { zipFileName } = options;
|
|
14
|
+
|
|
15
|
+
if (!zipFileName) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const zipPath = resolve(dirName, zipFileName);
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
await fs.access(zipPath);
|
|
23
|
+
} catch {
|
|
24
|
+
throw new StepError(`Prebuilt archive ${zipFileName} not found in ${dirName}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
zipFileName,
|
|
29
|
+
skipZip: true,
|
|
30
|
+
// The archive belongs to the caller. Neither flag reaches the context today; this is defensive.
|
|
31
|
+
removeOnSuccess: false,
|
|
32
|
+
removeOnFail: false,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -110,7 +110,13 @@ const resolveDataToZipUiApp = async (itemsToZip = [], { options, pkg, dirName, m
|
|
|
110
110
|
|
|
111
111
|
itemsToZip.push(
|
|
112
112
|
'manifest.json',
|
|
113
|
+
// both build systems are listed: missing entries are filtered out in
|
|
114
|
+
// createZipArchive, so one CLI serves webpack apps and Vite apps alike
|
|
113
115
|
'config-overrides.js',
|
|
116
|
+
'vite.config.mjs',
|
|
117
|
+
'index.html',
|
|
118
|
+
'devApp.js',
|
|
119
|
+
'isolatedApp.js',
|
|
114
120
|
'eslint.config.js',
|
|
115
121
|
'eslint.config.mjs',
|
|
116
122
|
'tsconfig.json',
|
|
@@ -125,6 +131,7 @@ const resolveDataToZipUiApp = async (itemsToZip = [], { options, pkg, dirName, m
|
|
|
125
131
|
},
|
|
126
132
|
...(await transformPatternsIntoFileNames(dirName, ['src/**/*'], options.ignoredFiles)),
|
|
127
133
|
...(await transformPatternsIntoFileNames(dirName, ['config/**/*'], options.ignoredFiles)),
|
|
134
|
+
...(await transformPatternsIntoFileNames(dirName, ['public/**/*'], options.ignoredFiles)),
|
|
128
135
|
);
|
|
129
136
|
|
|
130
137
|
if (options.appKey) {
|
|
@@ -255,7 +262,7 @@ const resolveDataForZipPythonApp = async (itemsToZip = [], { manifest, dirName,
|
|
|
255
262
|
);
|
|
256
263
|
}
|
|
257
264
|
|
|
258
|
-
itemsToZip.push('manifest.json', 'requirements.txt');
|
|
265
|
+
itemsToZip.push('manifest.json', 'pyproject.toml', 'uv.lock', 'requirements.txt');
|
|
259
266
|
|
|
260
267
|
return {
|
|
261
268
|
zipFileName,
|
package/lib/flows/zip-simple.js
CHANGED
|
@@ -75,7 +75,20 @@ export async function warnIfOutdated() {
|
|
|
75
75
|
logger.write('Checking for updates...\n');
|
|
76
76
|
|
|
77
77
|
const currentVersion = await getCurrentVersion();
|
|
78
|
-
|
|
78
|
+
|
|
79
|
+
let latestVersion;
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
latestVersion = await getLatestVersion();
|
|
83
|
+
} catch (caughtError) {
|
|
84
|
+
if (!(caughtError instanceof StepError)) {
|
|
85
|
+
throw caughtError;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
logger.write(' ⚠️ Skipping version check (could not reach npm registry).\n');
|
|
89
|
+
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
79
92
|
|
|
80
93
|
// Skip version check if current version is a prerelease (dev or next)
|
|
81
94
|
if (!isRegularVersion(currentVersion)) {
|
|
@@ -6,6 +6,8 @@ import os from 'os';
|
|
|
6
6
|
import semver from 'semver';
|
|
7
7
|
|
|
8
8
|
const debug = debugFn('cca:resolve-app-runtime');
|
|
9
|
+
const DEFAULT_UI_NODE_VERSION = '24';
|
|
10
|
+
const DEFAULT_UI_NODE_RANGE = '>=24 <25';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
*
|
|
@@ -37,11 +39,14 @@ const checkCliVersion = async (command, version) =>
|
|
|
37
39
|
|
|
38
40
|
debug(`%s version output: %s`, command, data.toString());
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
const currentVersion = semver.coerce(data.toString('utf-8'));
|
|
43
|
+
const requiredVersion = semver.coerce(semverVersionsMapping.node[version] || version);
|
|
44
|
+
|
|
45
|
+
resolve(semver.gte(currentVersion, requiredVersion));
|
|
41
46
|
});
|
|
42
47
|
});
|
|
43
48
|
|
|
44
|
-
const checkNodeVersion = (
|
|
49
|
+
const checkNodeVersion = (range) => async () => {
|
|
45
50
|
try {
|
|
46
51
|
await fs.access(`${os.homedir()}/.nvm/nvm.sh`);
|
|
47
52
|
|
|
@@ -52,7 +57,7 @@ const checkNodeVersion = (version) => async () => {
|
|
|
52
57
|
debug(e);
|
|
53
58
|
debug('nvm is not installed, checking node version');
|
|
54
59
|
|
|
55
|
-
return checkCliVersion('node',
|
|
60
|
+
return checkCliVersion('node', range);
|
|
56
61
|
}
|
|
57
62
|
};
|
|
58
63
|
|
|
@@ -60,19 +65,22 @@ export const IS_WINDOWS = process.platform === 'win32';
|
|
|
60
65
|
|
|
61
66
|
const semverVersionsMapping = {
|
|
62
67
|
node: {
|
|
63
|
-
18: '18.
|
|
64
|
-
20: '20.
|
|
65
|
-
24: '24.
|
|
68
|
+
18: '18.20.8',
|
|
69
|
+
20: '20.20.1',
|
|
70
|
+
24: '24.15.0',
|
|
66
71
|
},
|
|
67
72
|
python: {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
'3.10': '3.10.9',
|
|
71
|
-
'3.11': '3.11.1',
|
|
72
|
-
'3.13': '3.13.7',
|
|
73
|
+
3.13: '3.13.13',
|
|
74
|
+
3.14: '3.14.4',
|
|
73
75
|
},
|
|
74
76
|
};
|
|
75
77
|
|
|
78
|
+
const nodeVersionRanges = {
|
|
79
|
+
18: '>=18 <19',
|
|
80
|
+
20: '>=20 <21',
|
|
81
|
+
24: '>=24 <25',
|
|
82
|
+
};
|
|
83
|
+
|
|
76
84
|
/**
|
|
77
85
|
* @typedef {Object} Runtime
|
|
78
86
|
* @property {string} language
|
|
@@ -80,18 +88,20 @@ const semverVersionsMapping = {
|
|
|
80
88
|
* @property {string} packageManager
|
|
81
89
|
* @property {string} version
|
|
82
90
|
* @property {string} semver
|
|
91
|
+
* @property {string} [enginesNode]
|
|
83
92
|
*/
|
|
84
93
|
export const resolveAppRuntime = (opts) => {
|
|
85
94
|
if (opts.appType === APP_TYPES.UI) {
|
|
86
|
-
const version =
|
|
95
|
+
const version = DEFAULT_UI_NODE_VERSION;
|
|
87
96
|
|
|
88
97
|
return {
|
|
89
98
|
environment: 'node',
|
|
90
99
|
language: opts.useTypescript ? 'typescript' : 'javascript',
|
|
91
|
-
isRuntimeAvailable: checkNodeVersion(
|
|
100
|
+
isRuntimeAvailable: checkNodeVersion(DEFAULT_UI_NODE_RANGE),
|
|
92
101
|
packageManager: opts.packageManager,
|
|
93
102
|
version,
|
|
94
103
|
semver: semverVersionsMapping.node[version],
|
|
104
|
+
enginesNode: DEFAULT_UI_NODE_RANGE,
|
|
95
105
|
};
|
|
96
106
|
}
|
|
97
107
|
|
|
@@ -101,10 +111,11 @@ export const resolveAppRuntime = (opts) => {
|
|
|
101
111
|
return {
|
|
102
112
|
environment: 'node',
|
|
103
113
|
language: opts.useTypescript ? 'typescript' : 'javascript',
|
|
104
|
-
isRuntimeAvailable: checkNodeVersion(version),
|
|
114
|
+
isRuntimeAvailable: checkNodeVersion(nodeVersionRanges[version]),
|
|
105
115
|
packageManager: opts.packageManager,
|
|
106
116
|
version,
|
|
107
117
|
semver: semverVersionsMapping.node[version],
|
|
118
|
+
enginesNode: `^${version}`,
|
|
108
119
|
};
|
|
109
120
|
}
|
|
110
121
|
|
package/lib/helpers/utils.js
CHANGED
|
@@ -7,7 +7,7 @@ export const addUiAppFile = (templateFolder, root, runtime, manifest, opts) => {
|
|
|
7
7
|
try {
|
|
8
8
|
logger.log(chalk.green('adding app file'));
|
|
9
9
|
|
|
10
|
-
const fileExtension = runtime.language === 'typescript' ? 'tsx' : '
|
|
10
|
+
const fileExtension = runtime.language === 'typescript' ? 'tsx' : 'jsx';
|
|
11
11
|
|
|
12
12
|
const segment =
|
|
13
13
|
{
|
|
@@ -26,9 +26,13 @@ export const addUiAppFile = (templateFolder, root, runtime, manifest, opts) => {
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
export const getExcludedFiles = (manifest) => {
|
|
29
|
-
|
|
29
|
+
const excludedFiles = ['.ruff_cache', '.venv', '.pytest_cache', '__pycache__'];
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
if (manifest.isUi()) {
|
|
32
|
+
return [...excludedFiles, 'App.drilling.jsx', 'App.completion.jsx', 'App.drilling.tsx', 'App.completion.tsx'];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return excludedFiles;
|
|
32
36
|
};
|
|
33
37
|
|
|
34
38
|
export function copyFileSync(source, target) {
|
package/lib/main.js
CHANGED
|
@@ -17,17 +17,16 @@ import { StepError } from './flows/lib/step-error.js';
|
|
|
17
17
|
function checkNodeVersion() {
|
|
18
18
|
logger.write('Checking node version...');
|
|
19
19
|
|
|
20
|
-
const unsupportedNodeVersion = !semver.satisfies(process.version, '>=
|
|
20
|
+
const unsupportedNodeVersion = !semver.satisfies(process.version, '>=24 <25');
|
|
21
21
|
|
|
22
22
|
if (unsupportedNodeVersion) {
|
|
23
23
|
logger.log(
|
|
24
24
|
chalk.red(
|
|
25
25
|
`\nYou are using Node ${process.version}.\n\n` +
|
|
26
|
-
`Please update to Node
|
|
26
|
+
`Please update to Node 24.x for a better, fully supported experience.\n`,
|
|
27
27
|
),
|
|
28
28
|
);
|
|
29
29
|
|
|
30
|
-
// Fall back to latest supported react-scripts on Node 4
|
|
31
30
|
return process.exit(1);
|
|
32
31
|
}
|
|
33
32
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { InvalidArgumentError, Option } from 'commander';
|
|
2
|
+
|
|
3
|
+
const flags = '--zip-file-name <string>';
|
|
4
|
+
const description =
|
|
5
|
+
'Upload an already-built .zip from the project directory instead of zipping it here. ' +
|
|
6
|
+
'The archive belongs to the caller and is never deleted after upload.';
|
|
7
|
+
|
|
8
|
+
// An unset CI variable arrives as `--zip-file-name=`, and commander 9 takes the next token as the
|
|
9
|
+
// value even when it is another flag — neither should pass for an archive name.
|
|
10
|
+
function argParser(value) {
|
|
11
|
+
if (typeof value !== 'string' || !value.trim() || value.startsWith('-')) {
|
|
12
|
+
throw new InvalidArgumentError('Expected a file name, e.g. --zip-file-name=package.zip.');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const zipFileNameOption = new Option(flags, description).argParser(argParser);
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@corva/create-app","version":"0.0.0-
|
|
1
|
+
{"name":"@corva/create-app","version":"0.0.0-62a5f2b","private":false,"description":"Create an app to use it in CORVA.AI","keywords":["react"],"bugs":{"url":"https://github.com/facebook/create-react-app/issues"},"repository":{"type":"git","url":"https://github.com/corva-ai/create-corva-app"},"license":"MIT","type":"module","bin":{"create-corva-app":"./bin/create-corva-app.cjs"},"files":["bin/**/*.cjs","bin/**/*.js","lib/**/*.js","templates","template_extensions","common"],"scripts":{"build":"echo \"build is not configured for package \\\"×\\\", skipping.\"","get-changelog":"conventional-changelog -r 2 -p angular","lint":"eslint . --resolve-plugins-relative-to $(pwd) --max-warnings 0","lint:fix":"eslint . --fix","release":"git add -A && standard-version -a","release-rc":"npm run release -- --prerelease","run:local-ui-ts-completion":"node ./bin/create-corva-app.cjs ../test-app-ui-ts-completions --appName 'TestAppUiTsCompletions' --segments 'completion' --category 'analytics' --appKey 'corva.testappuitscompletions.ui' --appType 'ui' --runtime 'ui' -t --extensions corva","run:local-ui-ts-drilling":"node ./bin/create-corva-app.cjs ../test-app-ui-ts-drilling --appName 'TestAppUiTsDrilling' --segments 'drilling' --category 'analytics' --appKey 'corva.testappuitsdrilling.ui' --appType 'ui' --runtime 'ui' -t --extensions corva","run:local-ui-ts-intervention":"node ./bin/create-corva-app.cjs ../test-app-ui-ts-intervention --appName 'TestAppUiTsIntervention' --segments 'intervention' --category 'analytics' --appKey 'corva.testappuitsintervention.ui' --appType 'ui' --runtime 'ui' -t --extensions corva","test":"NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"},"lint-staged":{"*.js":"npm run lint:fix"},"resolutions":{"lodash":"4.18.1"},"dependencies":{"archiver":"^5.3.0","chalk":"^4.1.0","commander":"^9.1.0","cross-spawn":"^7.0.3","debug":"^4.3.4","dotenv":"^16.0.0","figlet":"^1.5.0","form-data":"^4.0.0","fs-extra":"^9.0.1","glob":"^8.0.1","got":"^12.5.1","inquirer":"^8.2.3","is-glob":"^4.0.3","lodash":"^4.18.1","npm-api":"^1.0.0","semver":"^7.3.2","terminal-link":"^3.0.0"},"devDependencies":{"@babel/core":"^7.11.0","@babel/eslint-parser":"^7.19.1","@babel/plugin-proposal-class-properties":"^7.18.6","@babel/plugin-syntax-import-assertions":"^7.20.0","@babel/preset-react":"^7.18.6","@commitlint/cli":"^17.3.0","@commitlint/config-conventional":"^17.3.0","@corva/eslint-config-browser":"^0.1.7","@corva/eslint-config-node":"^6.0.0","@corva/node-sdk":"^8.5.0","@types/cross-spawn":"^6.0.2","@types/jest":"^29.5.4","@typescript-eslint/eslint-plugin":"^8.58.1","@typescript-eslint/parser":"^8.58.1","conventional-changelog-cli":"^2.1.0","eslint":"^8.2.0","eslint-config-google":"^0.14.0","eslint-config-prettier":"^8.5.0","eslint-plugin-import":"^2.26.0","eslint-plugin-jest":"^27.1.5","eslint-plugin-jsx-a11y":"^6.7.1","eslint-plugin-prettier":"^4.2.1","eslint-plugin-react":"^7.32.0","eslint-plugin-react-hooks":"^4.6.0","eslint-plugin-require-sort":"^1.3.0","husky":"^8.0.2","jest":"^29.6.4","prettier":"^2.0.0","prettier-plugin-packagejson":"^2.3.0","standard-version":"^9.0.0","typescript":"^5.9.3","zx":"^7.2.3"},"packageManager":"yarn@1.22.19+sha512.ff4579ab459bb25aa7c0ff75b62acebe576f6084b36aa842971cf250a5d8c6cd3bc9420b22ce63c7f93a0857bc6ef29291db39c3e7a23aab5adfd5a4dd6c5d71","standard-version":{"skip":{"tag":true}}}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"root": true,
|
|
3
3
|
"extends": "@corva/eslint-config-browser",
|
|
4
|
+
"globals": {
|
|
5
|
+
"vi": "readonly"
|
|
6
|
+
},
|
|
4
7
|
"parserOptions": {
|
|
5
8
|
"requireConfigFile": false,
|
|
6
9
|
"babelOptions": {
|
|
7
|
-
"presets": ["@babel/preset-react"]
|
|
8
|
-
"plugins": ["@babel/plugin-proposal-class-properties"]
|
|
10
|
+
"presets": ["@babel/preset-react"]
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
13
|
}
|
|
@@ -10,22 +10,24 @@ These constraints are enforced by the platform. Violating them breaks the build
|
|
|
10
10
|
1. **Root export** — `src/index.js` MUST default-export `{ component: App, settings: AppSettings }`. The component may also be a `ParentApp` wrapper (e.g., `{ component: ParentApp, settings: AppSettings }`) that wraps `App` with Context.Providers and prop initialization. This is the platform loader contract.
|
|
11
11
|
2. **UI components** — Use only `@corva/ui` components. Import from `@corva/ui/componentsV2`; fall back to `@corva/ui/components` only when a V2 version doesn't exist yet. `@material-ui/core` v4 is available as the underlying library.
|
|
12
12
|
3. **HTTP clients** — Use `corvaDataAPI` / `corvaAPI` from `@corva/ui/clients` for all network requests.
|
|
13
|
-
4. **Do not rename or delete** `App.
|
|
13
|
+
4. **Do not rename or delete** `App.jsx`, `AppSettings.jsx`, or `index.js` — they are platform entry points.
|
|
14
14
|
|
|
15
15
|
## Project Structure
|
|
16
16
|
|
|
17
17
|
```
|
|
18
18
|
src/
|
|
19
|
-
App.
|
|
20
|
-
AppSettings.
|
|
19
|
+
App.jsx — Main app component (default export required)
|
|
20
|
+
AppSettings.jsx — Settings panel component (default export required)
|
|
21
21
|
index.js — Root export: { component, settings }
|
|
22
22
|
constants.js — Default settings values
|
|
23
|
-
App.scss — Component styles
|
|
24
|
-
__tests__/ —
|
|
23
|
+
App.module.scss — Component styles
|
|
24
|
+
__tests__/ — Vitest test files
|
|
25
25
|
__mocks__/ — Mock data (mockAppProps.js, mockAppSettingsProps.js)
|
|
26
26
|
assets/ — Static assets (SVGs, images)
|
|
27
|
-
config/
|
|
28
|
-
config
|
|
27
|
+
config/vite/ — Shared Corva Vite config
|
|
28
|
+
vite.config.mjs — Vite entry config
|
|
29
|
+
vitest.setup.js — Test environment setup
|
|
30
|
+
index.html — Dev server host page
|
|
29
31
|
manifest.json — Corva platform app metadata (generated at scaffold time)
|
|
30
32
|
```
|
|
31
33
|
|
|
@@ -98,7 +100,7 @@ transition: transition(color, background-color);
|
|
|
98
100
|
**Import in component:**
|
|
99
101
|
|
|
100
102
|
```javascript
|
|
101
|
-
import styles from './App.scss';
|
|
103
|
+
import styles from './App.module.scss';
|
|
102
104
|
// Use: <div className={styles.container}>
|
|
103
105
|
```
|
|
104
106
|
|
|
@@ -265,11 +267,11 @@ General rules:
|
|
|
265
267
|
|
|
266
268
|
## Testing
|
|
267
269
|
|
|
268
|
-
- **Framework:**
|
|
270
|
+
- **Framework:** Vitest + React Testing Library
|
|
269
271
|
- **Wrapper:** Use `AppTestWrapper` from `@corva/ui/testing` to wrap components
|
|
270
|
-
- **Mocking:** Mock network requests (
|
|
272
|
+
- **Mocking:** Mock network requests (`vi.mock`/`vi.fn` or msw), never call real APIs
|
|
271
273
|
- **Timezone:** UTC is enforced (`process.env.TZ = 'UTC'`)
|
|
272
|
-
- **Mocked globals:** `ResizeObserver`, `MutationObserver` (in `
|
|
274
|
+
- **Mocked globals:** `ResizeObserver`, `MutationObserver` (in `vitest.setup.js`)
|
|
273
275
|
|
|
274
276
|
## Commands
|
|
275
277
|
|