@corva/create-app 0.0.0-2576df8 → 0.0.0-5fb771a
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 +352 -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 +24 -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 +75 -65
- 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 +3 -2
- 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 +1 -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/AGENTS.md +10 -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
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
// Ported from corva-monorepo-frontend tools/vite-config. Moves to
|
|
2
|
+
// @corva/dc-platform-shared once the standalone flow is proven, which is why
|
|
3
|
+
// nothing here imports from the app's own source.
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { join, resolve } from 'node:path';
|
|
7
|
+
|
|
8
|
+
import dotenv from 'dotenv';
|
|
9
|
+
import { expand } from 'dotenv-expand';
|
|
10
|
+
import react from '@vitejs/plugin-react';
|
|
11
|
+
import license from 'rollup-plugin-license';
|
|
12
|
+
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
|
13
|
+
import presetEnv from 'postcss-preset-env';
|
|
14
|
+
import { defineConfig } from 'vitest/config';
|
|
15
|
+
|
|
16
|
+
const require = createRequire(import.meta.url);
|
|
17
|
+
|
|
18
|
+
const {
|
|
19
|
+
CORVA_API_ENVS,
|
|
20
|
+
CORVA_API_ENV_VARIABLES,
|
|
21
|
+
CORVA_GLOBAL_DEPENDENCIES,
|
|
22
|
+
} = require('@corva/dc-platform-shared/cjs/devcenter/webpack/constants.js');
|
|
23
|
+
const validateDependencies = require('@corva/dc-platform-shared/cjs/devcenter/webpack/validators/index.js');
|
|
24
|
+
const { updateDotEnv } = require('@corva/dc-platform-shared/cjs/devcenter/webpack/utils/serializeDotEnv.js');
|
|
25
|
+
|
|
26
|
+
const PLATFORM_SHARED_DIR = join(
|
|
27
|
+
require.resolve('@corva/dc-platform-shared/package.json'),
|
|
28
|
+
'..',
|
|
29
|
+
);
|
|
30
|
+
// NOTE: These imports are always bundled, never taken from the platform globals
|
|
31
|
+
const SKIP_IN_EXTERNALS = ['react/jsx-runtime', 'highcharts/'];
|
|
32
|
+
|
|
33
|
+
const isLegalIdentifier = value => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
|
34
|
+
|
|
35
|
+
const toLegalIdentifier = value => {
|
|
36
|
+
const identifier = value.replace(/[^A-Za-z0-9_$]/g, '_');
|
|
37
|
+
|
|
38
|
+
return isLegalIdentifier(identifier) ? identifier : `_${identifier}`;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const toGlobalSegmentAccess = segment =>
|
|
42
|
+
/^\d+$/.test(segment) ? `[${segment}]` : `[${JSON.stringify(segment)}]`;
|
|
43
|
+
|
|
44
|
+
const getSegmentedGlobalAssignmentPrefix = appIdentifier => {
|
|
45
|
+
const [rootSegment, ...segments] = appIdentifier.split('.');
|
|
46
|
+
const rootAccessor = `this[${JSON.stringify(rootSegment)}]`;
|
|
47
|
+
|
|
48
|
+
if (segments.length === 0) {
|
|
49
|
+
return `${rootAccessor}=`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let currentAccessor = rootAccessor;
|
|
53
|
+
const initializers = [`${rootAccessor}=${rootAccessor}||{}`];
|
|
54
|
+
|
|
55
|
+
segments.slice(0, -1).forEach(segment => {
|
|
56
|
+
currentAccessor += toGlobalSegmentAccess(segment);
|
|
57
|
+
initializers.push(`${currentAccessor}=${currentAccessor}||{}`);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
currentAccessor += toGlobalSegmentAccess(segments[segments.length - 1]);
|
|
61
|
+
|
|
62
|
+
return `${initializers.join(',')},${currentAccessor}=`;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const getGlobalAssignmentPrefixes = globalName =>
|
|
66
|
+
[
|
|
67
|
+
...new Set([
|
|
68
|
+
isLegalIdentifier(globalName) ? `var ${globalName}=` : '',
|
|
69
|
+
isLegalIdentifier(globalName)
|
|
70
|
+
? `this.${globalName}=`
|
|
71
|
+
: `this[${JSON.stringify(globalName)}]=`,
|
|
72
|
+
`this[${JSON.stringify(globalName)}]=`,
|
|
73
|
+
getSegmentedGlobalAssignmentPrefix(globalName),
|
|
74
|
+
]),
|
|
75
|
+
].filter(Boolean);
|
|
76
|
+
|
|
77
|
+
const normalizeIifeGlobalAssignment = (jsContent, appIdentifier, emittedGlobalName) => {
|
|
78
|
+
const normalizedAssignment = `this[${JSON.stringify(appIdentifier)}]=`;
|
|
79
|
+
|
|
80
|
+
if (jsContent.includes(normalizedAssignment)) {
|
|
81
|
+
return jsContent;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const assignmentPrefix = getGlobalAssignmentPrefixes(emittedGlobalName).find(prefix =>
|
|
85
|
+
jsContent.includes(prefix),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (assignmentPrefix) {
|
|
89
|
+
return jsContent.replace(assignmentPrefix, normalizedAssignment);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Rolldown doesn't emit a global assignment for IIFE output — inject one.
|
|
93
|
+
// Terser rewrites `(function(){})()` → `!function(){}()` when the result is discarded.
|
|
94
|
+
// Replacing `!` with the assignment (`this["name"]=function(){}()`) is valid JS
|
|
95
|
+
// because after `=` the `function` keyword is an expression, not a declaration.
|
|
96
|
+
if (jsContent.trimStart().startsWith('!function')) {
|
|
97
|
+
return jsContent.replace('!function', `${normalizedAssignment}function`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return normalizedAssignment + jsContent;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const createCssInjection = cssContent =>
|
|
104
|
+
`(function(){var s=document.createElement('style');s.textContent=${JSON.stringify(
|
|
105
|
+
cssContent,
|
|
106
|
+
)};document.head.appendChild(s)})();`;
|
|
107
|
+
|
|
108
|
+
// The platform loads a single file, so the emitted stylesheets are folded back into it.
|
|
109
|
+
const finalizeJsBundle = ({ outDir, cssFileNames, appIdentifier, emittedGlobalName }) => {
|
|
110
|
+
const jsPath = join(outDir, 'app.js');
|
|
111
|
+
const css = cssFileNames
|
|
112
|
+
.map(fileName => readFileSync(join(outDir, fileName), 'utf-8'))
|
|
113
|
+
.join('');
|
|
114
|
+
const jsContent = readFileSync(jsPath, 'utf-8');
|
|
115
|
+
|
|
116
|
+
writeFileSync(
|
|
117
|
+
jsPath,
|
|
118
|
+
normalizeIifeGlobalAssignment(
|
|
119
|
+
css ? createCssInjection(css) + jsContent : jsContent,
|
|
120
|
+
appIdentifier,
|
|
121
|
+
emittedGlobalName,
|
|
122
|
+
),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
cssFileNames.forEach(fileName => unlinkSync(join(outDir, fileName)));
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const getCorvaApiEnvVariables = () => {
|
|
129
|
+
const apiEnv = process.env.CORVA_API_ENV || CORVA_API_ENVS.production;
|
|
130
|
+
|
|
131
|
+
if (apiEnv in CORVA_API_ENVS) {
|
|
132
|
+
return CORVA_API_ENV_VARIABLES[apiEnv];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
console.error(`CORVA_API_ENV should be one of [${Object.keys(CORVA_API_ENVS).join(', ')}]`);
|
|
136
|
+
|
|
137
|
+
return process.exit(1);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// The DevCenter dev page edits the app's .env through this endpoint.
|
|
141
|
+
const dotEnvEndpointPlugin = appDirectory => ({
|
|
142
|
+
name: 'corva-dotenv-endpoint',
|
|
143
|
+
configureServer(server) {
|
|
144
|
+
server.middlewares.use('/dotenv', (req, res, next) => {
|
|
145
|
+
if (req.method !== 'PATCH') {
|
|
146
|
+
return next();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const envPath = resolve(appDirectory, '.env');
|
|
150
|
+
const chunks = [];
|
|
151
|
+
|
|
152
|
+
req.on('data', chunk => chunks.push(chunk));
|
|
153
|
+
req.on('end', () => {
|
|
154
|
+
const currentEnv = existsSync(envPath) ? readFileSync(envPath, 'utf-8') : '';
|
|
155
|
+
|
|
156
|
+
writeFileSync(envPath, updateDotEnv(currentEnv, JSON.parse(Buffer.concat(chunks))));
|
|
157
|
+
res.statusCode = 200;
|
|
158
|
+
res.end();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
export const createViteConfig = ({ pwd }) => {
|
|
165
|
+
expand(dotenv.config({ path: resolve(pwd, '.env'), quiet: true }));
|
|
166
|
+
|
|
167
|
+
const packageJson = JSON.parse(readFileSync(resolve(pwd, 'package.json'), 'utf-8'));
|
|
168
|
+
const manifestJson = JSON.parse(readFileSync(resolve(pwd, 'manifest.json'), 'utf-8'));
|
|
169
|
+
|
|
170
|
+
const appKey = manifestJson.application.key;
|
|
171
|
+
const version = packageJson.version;
|
|
172
|
+
const appIdentifier = `${appKey.replace(/\./g, '_')}-${version}`;
|
|
173
|
+
const appIifeName = toLegalIdentifier(appIdentifier);
|
|
174
|
+
|
|
175
|
+
const globalDependencies = Object.keys(CORVA_GLOBAL_DEPENDENCIES);
|
|
176
|
+
const externalPatterns = globalDependencies.map(
|
|
177
|
+
libName => new RegExp(`(^${libName}$|^${libName}/)([^]+)?`),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const isExternal = source =>
|
|
181
|
+
!SKIP_IN_EXTERNALS.some(skipped => source.startsWith(skipped)) &&
|
|
182
|
+
externalPatterns.some(pattern => pattern.test(source));
|
|
183
|
+
|
|
184
|
+
// Package names are not valid JS identifiers, so every global is read off `this`.
|
|
185
|
+
const toGlobal = id => {
|
|
186
|
+
const staticGlobal = globalDependencies.find(libName => libName === id);
|
|
187
|
+
|
|
188
|
+
if (staticGlobal) {
|
|
189
|
+
return `this["${staticGlobal}"].default || this["${staticGlobal}"]`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const dep = globalDependencies.find(libName => id.startsWith(libName));
|
|
193
|
+
|
|
194
|
+
if (!dep) {
|
|
195
|
+
throw new Error(`Unknown dependency: ${id}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return `this["${dep}"]${id.replace(dep, '').replace(/\//g, '.')}`;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const getAlias = () => {
|
|
202
|
+
const tsconfigPath = resolve(pwd, 'tsconfig.json');
|
|
203
|
+
|
|
204
|
+
if (!existsSync(tsconfigPath)) {
|
|
205
|
+
return {};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const { compilerOptions } = JSON.parse(readFileSync(tsconfigPath, 'utf-8'));
|
|
209
|
+
|
|
210
|
+
return Object.fromEntries(
|
|
211
|
+
Object.entries(compilerOptions?.paths || {}).map(([key, [value]]) => [
|
|
212
|
+
key.replace('/*', ''),
|
|
213
|
+
resolve(pwd, value.replace('/*', '')),
|
|
214
|
+
]),
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
return defineConfig(({ command }) => {
|
|
219
|
+
validateDependencies({ packageJson });
|
|
220
|
+
|
|
221
|
+
const config = {
|
|
222
|
+
root: pwd,
|
|
223
|
+
server: {
|
|
224
|
+
host: process.env.HOST || 'app.local.corva.ai',
|
|
225
|
+
port: Number(process.env.PORT) || 8080,
|
|
226
|
+
},
|
|
227
|
+
css: {
|
|
228
|
+
modules: { localsConvention: 'camelCase' },
|
|
229
|
+
postcss: { plugins: [presetEnv({ stage: 3 })] },
|
|
230
|
+
},
|
|
231
|
+
plugins: [react(), dotEnvEndpointPlugin(pwd)],
|
|
232
|
+
resolve: { alias: getAlias() },
|
|
233
|
+
test: {
|
|
234
|
+
watch: false,
|
|
235
|
+
globals: true,
|
|
236
|
+
environment: 'jsdom',
|
|
237
|
+
setupFiles: ['./vitest.setup.js'],
|
|
238
|
+
globalSetup: ['./vitest.global-setup.js'],
|
|
239
|
+
coverage: {
|
|
240
|
+
provider: 'v8',
|
|
241
|
+
include: ['src/**/*.{js,jsx,ts,tsx}'],
|
|
242
|
+
thresholds: { branches: 60, functions: 60, lines: 60, statements: 60 },
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
if (command === 'serve') {
|
|
248
|
+
return {
|
|
249
|
+
...config,
|
|
250
|
+
define: {
|
|
251
|
+
global: {},
|
|
252
|
+
// Webpack's EnvironmentPlugin exposed the whole environment, so apps read
|
|
253
|
+
// their own REACT_APP_* vars straight off process.env.
|
|
254
|
+
'process.env': {
|
|
255
|
+
...process.env,
|
|
256
|
+
DEV_CENTER_APP_PATH: '',
|
|
257
|
+
NODE_ENV: 'development',
|
|
258
|
+
REACT_APP_ENVIRONMENT: process.env.REACT_APP_ENVIRONMENT || 'development',
|
|
259
|
+
...getCorvaApiEnvVariables(),
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
plugins: [
|
|
263
|
+
...config.plugins,
|
|
264
|
+
viteStaticCopy({
|
|
265
|
+
watch: { reloadPageOnChange: false },
|
|
266
|
+
targets: [
|
|
267
|
+
{ src: `${PLATFORM_SHARED_DIR}/assets/*`, dest: 'static/media' },
|
|
268
|
+
{
|
|
269
|
+
src: `${join(PLATFORM_SHARED_DIR, '../ui/assets')}/*`,
|
|
270
|
+
dest: 'static/media',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
}),
|
|
274
|
+
],
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
...config,
|
|
280
|
+
define: {
|
|
281
|
+
'process.env': { NODE_ENV: 'production' },
|
|
282
|
+
'process.env.NODE_ENV': '"production"',
|
|
283
|
+
},
|
|
284
|
+
plugins: [
|
|
285
|
+
...config.plugins,
|
|
286
|
+
viteStaticCopy({ targets: [{ src: 'manifest.json', dest: '.' }] }),
|
|
287
|
+
{
|
|
288
|
+
name: 'corva-single-file-bundle',
|
|
289
|
+
writeBundle(_options, bundle) {
|
|
290
|
+
finalizeJsBundle({
|
|
291
|
+
outDir: resolve(pwd, 'dist'),
|
|
292
|
+
cssFileNames: Object.keys(bundle).filter(fileName => fileName.endsWith('.css')),
|
|
293
|
+
appIdentifier,
|
|
294
|
+
emittedGlobalName: appIifeName,
|
|
295
|
+
});
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
build: {
|
|
300
|
+
outDir: 'dist',
|
|
301
|
+
emptyOutDir: true,
|
|
302
|
+
copyPublicDir: false,
|
|
303
|
+
sourcemap: false,
|
|
304
|
+
cssCodeSplit: false,
|
|
305
|
+
minify: 'terser',
|
|
306
|
+
terserOptions: {
|
|
307
|
+
compress: { drop_console: true, drop_debugger: true },
|
|
308
|
+
format: { comments: false },
|
|
309
|
+
},
|
|
310
|
+
// lib mode plus named exports keeps the IIFE compatible with the platform
|
|
311
|
+
// loader, which reads `this["appKey-version"].default.component`.
|
|
312
|
+
lib: {
|
|
313
|
+
entry: resolve(pwd, 'src/index.js'),
|
|
314
|
+
name: appIifeName,
|
|
315
|
+
fileName: () => 'app.js',
|
|
316
|
+
formats: ['iife'],
|
|
317
|
+
},
|
|
318
|
+
rolldownOptions: {
|
|
319
|
+
external: isExternal,
|
|
320
|
+
moduleTypes: { '.cjs': 'js' },
|
|
321
|
+
output: {
|
|
322
|
+
format: 'iife',
|
|
323
|
+
name: appIifeName,
|
|
324
|
+
entryFileNames: 'app.js',
|
|
325
|
+
globals: toGlobal,
|
|
326
|
+
exports: 'named',
|
|
327
|
+
// Rolldown doesn't rewrite `require()` inside bundled CJS modules (e.g.
|
|
328
|
+
// react-is) to their external global references. This shim resolves them
|
|
329
|
+
// to the globals the IIFE receives as params.
|
|
330
|
+
intro:
|
|
331
|
+
'var require=function(id){var g=globalThis[id];return g&&g.default||g;};',
|
|
332
|
+
},
|
|
333
|
+
plugins: [
|
|
334
|
+
{
|
|
335
|
+
// Rolldown rejects `typeof require` as a define key (not an identifier),
|
|
336
|
+
// so the CJS-detection branches are stripped by transform instead.
|
|
337
|
+
name: 'replace-typeof-require',
|
|
338
|
+
transform(code) {
|
|
339
|
+
if (!code.includes('typeof require')) return null;
|
|
340
|
+
|
|
341
|
+
return { code: code.replaceAll('typeof require', '"undefined"'), map: null };
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
license({
|
|
345
|
+
thirdParty: { output: resolve(pwd, 'dist/app.js.LICENSE.txt') },
|
|
346
|
+
}),
|
|
347
|
+
],
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
});
|
|
352
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@corva/dc-platform-shared/cjs/devcenter/webpack/DevServerEntryPoint.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<link rel="icon" href="/favicon.ico" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
<meta name="theme-color" content="#000000" />
|
|
8
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" />
|
|
9
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
|
10
|
+
<title>Corva React App</title>
|
|
11
|
+
</head>
|
|
12
|
+
<body data-corva-theme-dark>
|
|
13
|
+
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
14
|
+
<div id="root"></div>
|
|
15
|
+
<script type="module" src="/devApp.js"></script>
|
|
16
|
+
</body>
|
|
17
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@corva/dc-platform-shared/cjs/devcenter/webpack/DevServerIsolatedAppEntryPoint.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<link rel="icon" href="/favicon.ico" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
<meta name="theme-color" content="#000000" />
|
|
8
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" />
|
|
9
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
|
10
|
+
<title>Corva React App</title>
|
|
11
|
+
</head>
|
|
12
|
+
<body data-corva-theme-dark>
|
|
13
|
+
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
14
|
+
<div id="root"></div>
|
|
15
|
+
<!-- Vite only injects the react-refresh preamble into index.html, so this page installs it itself. -->
|
|
16
|
+
<script type="module">
|
|
17
|
+
import RefreshRuntime from '/@react-refresh';
|
|
18
|
+
|
|
19
|
+
RefreshRuntime.injectIntoGlobalHook(window);
|
|
20
|
+
window.$RefreshReg$ = () => {};
|
|
21
|
+
window.$RefreshSig$ = () => type => type;
|
|
22
|
+
window.__vite_plugin_react_preamble_installed__ = true;
|
|
23
|
+
</script>
|
|
24
|
+
<script type="module" src="/isolatedApp.js"></script>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
|
|
3
|
+
class FakeObserver {
|
|
4
|
+
observe() {}
|
|
5
|
+
|
|
6
|
+
unobserve() {}
|
|
7
|
+
|
|
8
|
+
disconnect() {}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
globalThis.ResizeObserver = FakeObserver;
|
|
12
|
+
globalThis.MutationObserver = FakeObserver;
|
|
13
|
+
|
|
14
|
+
// jsdom 22 cannot parse the container queries @corva/ui's components inject, and
|
|
15
|
+
// reports that straight to stderr on every import. Drop those lines only.
|
|
16
|
+
const writeToStderr = process.stderr.write.bind(process.stderr);
|
|
17
|
+
|
|
18
|
+
process.stderr.write = (chunk, ...rest) => {
|
|
19
|
+
if (String(chunk).includes('Could not parse CSS stylesheet')) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return writeToStderr(chunk, ...rest);
|
|
24
|
+
};
|
package/lib/commands/create.js
CHANGED
|
@@ -205,6 +205,10 @@ async function addTemplate(root, manifest, runtime, opts) {
|
|
|
205
205
|
|
|
206
206
|
copyFolderRecursiveSync(templateFolder, root, excludeFiles);
|
|
207
207
|
|
|
208
|
+
if (manifest.isUi()) {
|
|
209
|
+
copyFolderRecursiveSync(join(cliRoot, 'common', 'ui'), root);
|
|
210
|
+
}
|
|
211
|
+
|
|
208
212
|
if (manifest.isNode()) {
|
|
209
213
|
copyFolderRecursiveSync(join(cliRoot, 'common', 'node'), root);
|
|
210
214
|
}
|
|
@@ -236,7 +240,11 @@ async function addTemplate(root, manifest, runtime, opts) {
|
|
|
236
240
|
const extPath = join(cliRoot, 'template_extensions', extension);
|
|
237
241
|
|
|
238
242
|
if (fs.existsSync(extPath)) {
|
|
239
|
-
|
|
243
|
+
// the extension's .eslintrc is the typescript one; a javascript app keeps
|
|
244
|
+
// its own @babel/eslint-parser config instead
|
|
245
|
+
const excludeFiles = runtime.language === 'javascript' ? ['.eslintrc'] : [];
|
|
246
|
+
|
|
247
|
+
copyFolderRecursiveSync(extPath, root, excludeFiles);
|
|
240
248
|
}
|
|
241
249
|
});
|
|
242
250
|
|
|
@@ -345,7 +353,7 @@ function addPackageJSON(root, manifest, runtime, opts) {
|
|
|
345
353
|
private: isPrivate,
|
|
346
354
|
license,
|
|
347
355
|
engines: {
|
|
348
|
-
node: `^${runtime.version}`,
|
|
356
|
+
node: runtime.enginesNode || `^${runtime.version}`,
|
|
349
357
|
[runtime.packageManager]: '*',
|
|
350
358
|
},
|
|
351
359
|
scripts,
|
|
@@ -383,7 +391,7 @@ async function installDependencies(root, manifest, runtime) {
|
|
|
383
391
|
args.push('--cache-folder=".yarn-cache"');
|
|
384
392
|
}
|
|
385
393
|
|
|
386
|
-
logger.log(chalk.yellow(`Installing template dependencies using ${
|
|
394
|
+
logger.log(chalk.yellow(`Installing template dependencies using ${command}...`));
|
|
387
395
|
|
|
388
396
|
const nvmOpts = {
|
|
389
397
|
shell: true,
|
package/lib/commands/release.js
CHANGED
|
@@ -11,6 +11,8 @@ import { silentOption } from '../options/silent.js';
|
|
|
11
11
|
import { ensureBumpVersion } from '../helpers/cli-version.js';
|
|
12
12
|
import { ERROR_ICON } from '../constants/messages.js';
|
|
13
13
|
import { appKeyOption } from '../options/app-key.js';
|
|
14
|
+
import { zipFileNameOption } from '../options/zip-file-name.js';
|
|
15
|
+
import { logger } from '../helpers/logger.js';
|
|
14
16
|
|
|
15
17
|
export const releaseCommand = new Command('release')
|
|
16
18
|
.description('Release app')
|
|
@@ -35,7 +37,7 @@ export const releaseCommand = new Command('release')
|
|
|
35
37
|
'If package version is already taken - remove the previously published package and upload a new one',
|
|
36
38
|
).default(false),
|
|
37
39
|
)
|
|
38
|
-
|
|
40
|
+
.addOption(zipFileNameOption)
|
|
39
41
|
.addOption(new Option('--author [string]', 'Author name for the audit'))
|
|
40
42
|
.action(async (dirName, patterns, options) => {
|
|
41
43
|
// if author is present in CLI, save it to process.env
|
|
@@ -43,7 +45,20 @@ export const releaseCommand = new Command('release')
|
|
|
43
45
|
process.env.githubUsername = options.author;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
// Only the zip flow bumps the version, and a prebuilt archive skips it — nothing to prompt for.
|
|
49
|
+
if (options.zipFileName) {
|
|
50
|
+
if (options.bumpVersion && options.bumpVersion !== 'skip') {
|
|
51
|
+
logger.log(
|
|
52
|
+
`⚠️ ${chalk.yellow(
|
|
53
|
+
`--bump-version=${options.bumpVersion} is ignored with --zip-file-name: the version inside ${options.zipFileName} is used as is.`,
|
|
54
|
+
)}`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
options.bumpVersion = 'skip';
|
|
59
|
+
} else {
|
|
60
|
+
options.bumpVersion = await ensureBumpVersion(options.bumpVersion);
|
|
61
|
+
}
|
|
47
62
|
|
|
48
63
|
await runFlow(RELEASE_FLOW, {
|
|
49
64
|
dirName: getRealWorkingDir(dirName, options),
|
package/lib/constants/cli.js
CHANGED
|
@@ -3,18 +3,15 @@ export const APP_RUNTIMES = {
|
|
|
3
3
|
// NODE12: 'nodejs12.x',
|
|
4
4
|
// NODE14: 'nodejs14.x',
|
|
5
5
|
// NODE16: 'nodejs16.x',
|
|
6
|
-
NODE18: 'nodejs18.x',
|
|
7
|
-
NODE20: 'nodejs20.x',
|
|
8
|
-
NODE22: 'nodejs22.x',
|
|
9
6
|
NODE24: 'nodejs24.x',
|
|
10
|
-
// PYTHON3_8: 'python3.8',
|
|
11
|
-
// PYTHON3_9: 'python3.9',
|
|
12
|
-
// PYTHON3_10: 'python3.10',
|
|
13
|
-
PYTHON3_11: 'python3.11',
|
|
14
|
-
PYTHON3_12: 'python3.12',
|
|
15
7
|
PYTHON3_13: 'python3.13',
|
|
8
|
+
PYTHON3_14: 'python3.14',
|
|
16
9
|
};
|
|
17
10
|
|
|
11
|
+
export const SUPPORTED_NODE_APP_RUNTIMES = [APP_RUNTIMES.NODE24];
|
|
12
|
+
export const SUPPORTED_PYTHON_APP_RUNTIMES = [APP_RUNTIMES.PYTHON3_14, APP_RUNTIMES.PYTHON3_13];
|
|
13
|
+
export const SUPPORTED_NON_UI_APP_RUNTIMES = [...SUPPORTED_NODE_APP_RUNTIMES, ...SUPPORTED_PYTHON_APP_RUNTIMES];
|
|
14
|
+
|
|
18
15
|
export const TEMPLATE_TYPES = {
|
|
19
16
|
UI: 'js',
|
|
20
17
|
UI_TS: 'ts',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APP_RUNTIMES, APP_TYPES, TEMPLATE_TYPES } from './cli.js';
|
|
1
|
+
import { APP_RUNTIMES, APP_TYPES, SUPPORTED_NON_UI_APP_RUNTIMES, TEMPLATE_TYPES } from './cli.js';
|
|
2
2
|
|
|
3
3
|
export const defaultManifest = {
|
|
4
4
|
format: 1,
|
|
@@ -215,10 +215,10 @@ export const manifestOptions = (projectName = 'Corva Dev Center App') => [
|
|
|
215
215
|
message: 'Choose runtime',
|
|
216
216
|
choices: (answers) => {
|
|
217
217
|
if (answers && answers.appType !== APP_TYPES.UI) {
|
|
218
|
-
return
|
|
218
|
+
return SUPPORTED_NON_UI_APP_RUNTIMES;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
return
|
|
221
|
+
return [APP_RUNTIMES.UI, ...SUPPORTED_NON_UI_APP_RUNTIMES];
|
|
222
222
|
},
|
|
223
223
|
when: (answers) => answers.appType !== APP_TYPES.UI,
|
|
224
224
|
},
|