@spcsn/taro-cli 0.1.6 → 1.0.0
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 +10 -7
- package/define-config.d.ts +1 -0
- package/define-config.js +1 -0
- package/dist/cli.js +140 -110
- package/dist/cli.js.map +1 -1
- package/dist/commands/{customCommand.d.ts → custom-command.d.ts} +1 -1
- package/dist/commands/custom-command.js +23 -0
- package/dist/commands/custom-command.js.map +1 -0
- package/dist/create/creator.js +2 -0
- package/dist/create/creator.js.map +1 -1
- package/dist/create/{fetchTemplate.js → fetch-template.js} +26 -33
- package/dist/create/fetch-template.js.map +1 -0
- package/dist/create/project.d.ts +2 -6
- package/dist/create/project.js +240 -285
- package/dist/create/project.js.map +1 -1
- package/dist/create/template-creator.d.ts +75 -0
- package/dist/create/template-creator.js +275 -0
- package/dist/create/template-creator.js.map +1 -0
- package/dist/doctor/validators.d.ts +7 -6
- package/dist/doctor/validators.js +6 -7
- package/dist/doctor/validators.js.map +1 -1
- package/dist/platform-weapp/apis-list.d.ts +1 -0
- package/dist/platform-weapp/apis-list.js +37 -0
- package/dist/platform-weapp/apis-list.js.map +1 -0
- package/dist/platform-weapp/apis.d.ts +16 -0
- package/dist/platform-weapp/apis.js +34 -0
- package/dist/platform-weapp/apis.js.map +1 -0
- package/dist/platform-weapp/components-react.d.ts +80 -0
- package/dist/platform-weapp/components-react.js +86 -0
- package/dist/platform-weapp/components-react.js.map +1 -0
- package/dist/platform-weapp/components.d.ts +4 -0
- package/dist/platform-weapp/components.js +520 -0
- package/dist/platform-weapp/components.js.map +1 -0
- package/dist/platform-weapp/index.d.ts +11 -0
- package/dist/platform-weapp/index.js +17 -0
- package/dist/platform-weapp/index.js.map +1 -0
- package/dist/platform-weapp/program.d.ts +35 -0
- package/dist/platform-weapp/program.js +64 -0
- package/dist/platform-weapp/program.js.map +1 -0
- package/dist/platform-weapp/runtime-utils.d.ts +27 -0
- package/dist/platform-weapp/runtime-utils.js +48 -0
- package/dist/platform-weapp/runtime-utils.js.map +1 -0
- package/dist/platform-weapp/runtime.d.ts +1 -0
- package/dist/platform-weapp/runtime.js +7 -0
- package/dist/platform-weapp/runtime.js.map +1 -0
- package/dist/platform-weapp/template.d.ts +39 -0
- package/dist/platform-weapp/template.js +119 -0
- package/dist/platform-weapp/template.js.map +1 -0
- package/dist/presets/commands/build.js +25 -45
- package/dist/presets/commands/build.js.map +1 -1
- package/dist/presets/commands/init.js +2 -4
- package/dist/presets/commands/init.js.map +1 -1
- package/dist/presets/constant/hooks.d.ts +0 -2
- package/dist/presets/constant/hooks.js +1 -3
- package/dist/presets/constant/hooks.js.map +1 -1
- package/dist/presets/files/generate-framework-info.js +68 -0
- package/dist/presets/files/generate-framework-info.js.map +1 -0
- package/dist/presets/files/{generateProjectConfig.js → generate-project-config.js} +1 -1
- package/dist/presets/files/generate-project-config.js.map +1 -0
- package/dist/presets/files/{writeFileToDist.js → write-file-to-dist.js} +1 -1
- package/dist/presets/files/write-file-to-dist.js.map +1 -0
- package/dist/presets/hooks/build.js +1 -3
- package/dist/presets/hooks/build.js.map +1 -1
- package/dist/presets/index.js +3 -5
- package/dist/presets/index.js.map +1 -1
- package/dist/util/{appConfig.d.ts → app-config.d.ts} +2 -2
- package/dist/util/{appConfig.js → app-config.js} +4 -3
- package/dist/util/app-config.js.map +1 -0
- package/dist/util/defineConfig.d.ts +5 -5
- package/dist/util/defineConfig.js.map +1 -1
- package/dist/util/index.d.ts +9 -1
- package/dist/util/index.js +54 -23
- package/dist/util/index.js.map +1 -1
- package/package.json +36 -39
- package/postinstall.js +1 -17
- package/src/cli.ts +185 -132
- package/src/commands/custom-command.ts +22 -0
- package/src/create/{fetchTemplate.ts → fetch-template.ts} +30 -35
- package/src/create/project.ts +31 -78
- package/src/create/template-creator.ts +325 -0
- package/src/doctor/validators.js +1 -0
- package/src/doctor/validators.ts +8 -6
- package/src/platform-weapp/apis-list.ts +33 -0
- package/src/platform-weapp/apis.ts +48 -0
- package/src/platform-weapp/components-react.ts +81 -0
- package/src/platform-weapp/components.ts +521 -0
- package/src/platform-weapp/index.ts +25 -0
- package/src/platform-weapp/program.ts +70 -0
- package/src/platform-weapp/runtime-utils.ts +57 -0
- package/src/platform-weapp/runtime.ts +6 -0
- package/src/platform-weapp/template.ts +150 -0
- package/src/presets/commands/build.ts +20 -40
- package/src/presets/commands/init.ts +1 -4
- package/src/presets/constant/hooks.js +12 -0
- package/src/presets/constant/hooks.ts +0 -2
- package/src/presets/files/{generateFrameworkInfo.ts → generate-framework-info.ts} +7 -1
- package/src/presets/hooks/build.ts +1 -3
- package/src/presets/index.ts +3 -5
- package/src/util/app-config.js +1 -0
- package/src/util/{appConfig.ts → app-config.ts} +5 -4
- package/src/util/defineConfig.ts +6 -6
- package/src/util/index.ts +67 -25
- package/templates/default/config/dev.js +1 -1
- package/templates/default/config/index.js +28 -40
- package/templates/default/config/prod.js +1 -1
- package/templates/default/package.json.tmpl +2 -17
- package/templates/default/types/global.d.ts +0 -4
- package/templates/plugin-compile/README.md +3 -1
- package/templates/plugin-compile/package.json.tmpl +1 -2
- package/templates/plugin-compile/src/index.ts +18 -28
- package/LICENSE +0 -174
- package/dist/commands/customCommand.js +0 -23
- package/dist/commands/customCommand.js.map +0 -1
- package/dist/config/packagesManagement.d.ts +0 -19
- package/dist/config/packagesManagement.js +0 -22
- package/dist/config/packagesManagement.js.map +0 -1
- package/dist/create/fetchTemplate.js.map +0 -1
- package/dist/create/page.d.ts +0 -65
- package/dist/create/page.js +0 -266
- package/dist/create/page.js.map +0 -1
- package/dist/create/plugin.d.ts +0 -16
- package/dist/create/plugin.js +0 -77
- package/dist/create/plugin.js.map +0 -1
- package/dist/presets/commands/config.js +0 -121
- package/dist/presets/commands/config.js.map +0 -1
- package/dist/presets/commands/create.js +0 -112
- package/dist/presets/commands/create.js.map +0 -1
- package/dist/presets/commands/doctor.js +0 -15
- package/dist/presets/commands/doctor.js.map +0 -1
- package/dist/presets/commands/global-config.d.ts +0 -3
- package/dist/presets/commands/global-config.js +0 -175
- package/dist/presets/commands/global-config.js.map +0 -1
- package/dist/presets/commands/help.d.ts +0 -3
- package/dist/presets/commands/help.js +0 -16
- package/dist/presets/commands/help.js.map +0 -1
- package/dist/presets/commands/info.d.ts +0 -3
- package/dist/presets/commands/info.js +0 -96
- package/dist/presets/commands/info.js.map +0 -1
- package/dist/presets/commands/inspect.d.ts +0 -3
- package/dist/presets/commands/inspect.js +0 -155
- package/dist/presets/commands/inspect.js.map +0 -1
- package/dist/presets/commands/update.d.ts +0 -3
- package/dist/presets/commands/update.js +0 -187
- package/dist/presets/commands/update.js.map +0 -1
- package/dist/presets/files/generateFrameworkInfo.d.ts +0 -3
- package/dist/presets/files/generateFrameworkInfo.js +0 -30
- package/dist/presets/files/generateFrameworkInfo.js.map +0 -1
- package/dist/presets/files/generateProjectConfig.d.ts +0 -3
- package/dist/presets/files/generateProjectConfig.js.map +0 -1
- package/dist/presets/files/writeFileToDist.d.ts +0 -3
- package/dist/presets/files/writeFileToDist.js.map +0 -1
- package/dist/presets/hooks/create.d.ts +0 -3
- package/dist/presets/hooks/create.js +0 -42
- package/dist/presets/hooks/create.js.map +0 -1
- package/dist/presets/platforms/plugin.d.ts +0 -3
- package/dist/presets/platforms/plugin.js +0 -106
- package/dist/presets/platforms/plugin.js.map +0 -1
- package/dist/presets/platforms/rn.d.ts +0 -3
- package/dist/presets/platforms/rn.js +0 -130
- package/dist/presets/platforms/rn.js.map +0 -1
- package/dist/util/appConfig.js.map +0 -1
- package/dist/util/createPage.d.ts +0 -9
- package/dist/util/createPage.js +0 -114
- package/dist/util/createPage.js.map +0 -1
- package/src/commands/customCommand.ts +0 -22
- package/src/config/packagesManagement.ts +0 -20
- package/src/config/rn-stylelint.json +0 -4
- package/src/create/page.ts +0 -325
- package/src/create/plugin.ts +0 -55
- package/src/presets/commands/config.ts +0 -86
- package/src/presets/commands/create.ts +0 -104
- package/src/presets/commands/doctor.ts +0 -21
- package/src/presets/commands/global-config.ts +0 -140
- package/src/presets/commands/help.ts +0 -17
- package/src/presets/commands/info.ts +0 -81
- package/src/presets/commands/inspect.ts +0 -137
- package/src/presets/commands/update.ts +0 -175
- package/src/presets/hooks/create.ts +0 -9
- package/src/presets/platforms/plugin.ts +0 -75
- package/src/presets/platforms/rn.ts +0 -125
- package/src/util/createPage.ts +0 -139
- package/templates/default/babel.config.js +0 -14
- /package/dist/create/{fetchTemplate.d.ts → fetch-template.d.ts} +0 -0
- /package/dist/presets/{commands/config.d.ts → files/generate-framework-info.d.ts} +0 -0
- /package/dist/presets/{commands/create.d.ts → files/generate-project-config.d.ts} +0 -0
- /package/dist/presets/{commands/doctor.d.ts → files/write-file-to-dist.d.ts} +0 -0
- /package/src/presets/files/{generateProjectConfig.ts → generate-project-config.ts} +0 -0
- /package/src/presets/files/{writeFileToDist.ts → write-file-to-dist.ts} +0 -0
package/src/create/project.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as path from 'node:path';
|
|
2
2
|
|
|
3
|
-
import { CompilerType, createProject, CSSType, FrameworkType, NpmType, PeriodType } from '@spcsn/taro-binding';
|
|
4
3
|
import {
|
|
5
4
|
chalk,
|
|
6
5
|
DEFAULT_TEMPLATE_SRC,
|
|
@@ -12,17 +11,16 @@ import {
|
|
|
12
11
|
TARO_CONFIG_FOLDER,
|
|
13
12
|
} from '@spcsn/taro-helper';
|
|
14
13
|
import { isArray } from '@spcsn/taro-shared';
|
|
15
|
-
import axios from 'axios';
|
|
16
14
|
import * as inquirer from 'inquirer';
|
|
17
15
|
import ora from 'ora';
|
|
18
|
-
import * as semver from 'semver';
|
|
19
16
|
|
|
20
17
|
import { clearConsole, getPkgVersion, getRootPath } from '../util';
|
|
21
18
|
import { TEMPLATE_CREATOR } from './constants';
|
|
22
19
|
import Creator from './creator';
|
|
23
|
-
import fetchTemplate from './
|
|
20
|
+
import fetchTemplate from './fetch-template';
|
|
21
|
+
import { CompilerType, createProject, CSSType, FrameworkType, NpmType, PeriodType } from './template-creator';
|
|
24
22
|
|
|
25
|
-
import type { ITemplates } from './
|
|
23
|
+
import type { ITemplates } from './fetch-template';
|
|
26
24
|
|
|
27
25
|
export interface IProjectConf {
|
|
28
26
|
projectName: string;
|
|
@@ -33,7 +31,6 @@ export interface IProjectConf {
|
|
|
33
31
|
template: string;
|
|
34
32
|
description?: string;
|
|
35
33
|
typescript?: boolean;
|
|
36
|
-
buildEs5?: boolean;
|
|
37
34
|
css: CSSType;
|
|
38
35
|
date?: string;
|
|
39
36
|
src?: string;
|
|
@@ -67,8 +64,8 @@ export default class Project extends Creator {
|
|
|
67
64
|
|
|
68
65
|
constructor(options: IProjectConfOptions) {
|
|
69
66
|
super(options.sourceRoot);
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
67
|
+
const nodeMajorVersion = Number(process.versions.node.split('.')[0]);
|
|
68
|
+
if (nodeMajorVersion < 18) {
|
|
72
69
|
throw new Error('Node.js 版本过低,推荐升级 Node.js 至 v18.0.0+');
|
|
73
70
|
}
|
|
74
71
|
this.rootPath = this._rootPath;
|
|
@@ -111,8 +108,6 @@ export default class Project extends Creator {
|
|
|
111
108
|
this.askProjectName(conf, prompts);
|
|
112
109
|
this.askDescription(conf, prompts);
|
|
113
110
|
this.askTypescript(conf, prompts);
|
|
114
|
-
this.askBuildEs5(conf, prompts);
|
|
115
|
-
this.askCSS(conf, prompts);
|
|
116
111
|
this.askNpm(conf, prompts);
|
|
117
112
|
const answers = await inquirer.prompt<IProjectConf>(prompts);
|
|
118
113
|
|
|
@@ -205,54 +200,8 @@ export default class Project extends Creator {
|
|
|
205
200
|
});
|
|
206
201
|
}
|
|
207
202
|
};
|
|
208
|
-
|
|
209
|
-
askBuildEs5: AskMethods = function (conf, prompts) {
|
|
210
|
-
if (typeof conf.buildEs5 !== 'boolean') {
|
|
211
|
-
prompts.push({
|
|
212
|
-
type: 'confirm',
|
|
213
|
-
name: 'buildEs5',
|
|
214
|
-
message: '是否需要编译为 ES5 ?',
|
|
215
|
-
default: false,
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
askCSS: AskMethods = function (conf, prompts) {
|
|
221
|
-
const cssChoices = [
|
|
222
|
-
{
|
|
223
|
-
name: 'Sass',
|
|
224
|
-
value: CSSType.Sass,
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
name: 'Less',
|
|
228
|
-
value: CSSType.Less,
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
name: 'Stylus',
|
|
232
|
-
value: CSSType.Stylus,
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
name: '无',
|
|
236
|
-
value: CSSType.None,
|
|
237
|
-
},
|
|
238
|
-
];
|
|
239
|
-
|
|
240
|
-
if (typeof conf.css !== 'string') {
|
|
241
|
-
prompts.push({
|
|
242
|
-
type: 'list',
|
|
243
|
-
name: 'css',
|
|
244
|
-
message: '请选择 CSS 预处理器(Sass/Less/Stylus)',
|
|
245
|
-
choices: cssChoices,
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
|
|
250
203
|
askCompiler: AskMethods = function (conf, prompts) {
|
|
251
204
|
const compilerChoices = [
|
|
252
|
-
{
|
|
253
|
-
name: 'Webpack5',
|
|
254
|
-
value: CompilerType.Webpack5,
|
|
255
|
-
},
|
|
256
205
|
{
|
|
257
206
|
name: 'Vite',
|
|
258
207
|
value: CompilerType.Vite,
|
|
@@ -486,12 +435,11 @@ export default class Project extends Creator {
|
|
|
486
435
|
template,
|
|
487
436
|
npm,
|
|
488
437
|
framework,
|
|
489
|
-
css:
|
|
438
|
+
css: CSSType.None,
|
|
490
439
|
autoInstall: autoInstall,
|
|
491
440
|
templateRoot: getRootPath(),
|
|
492
441
|
version: getPkgVersion(),
|
|
493
442
|
typescript: this.conf.typescript,
|
|
494
|
-
buildEs5: this.conf.buildEs5,
|
|
495
443
|
date: this.conf.date,
|
|
496
444
|
description: this.conf.description,
|
|
497
445
|
compiler: this.conf.compiler,
|
|
@@ -504,24 +452,29 @@ export default class Project extends Creator {
|
|
|
504
452
|
}
|
|
505
453
|
}
|
|
506
454
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
return
|
|
525
|
-
|
|
526
|
-
|
|
455
|
+
interface OpenSourceTemplateCollection {
|
|
456
|
+
react?: unknown;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
async function getOpenSourceTemplates(platform: string) {
|
|
460
|
+
const spinner = ora({ text: '正在拉取开源模板列表...', discardStdin: false }).start();
|
|
461
|
+
|
|
462
|
+
try {
|
|
463
|
+
const response = await fetch('https://gitee.com/NervJS/awesome-taro/raw/next/index.json');
|
|
464
|
+
if (!response.ok) {
|
|
465
|
+
throw new Error(`HTTP ${response.status} ${response.statusText}`);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
spinner.succeed(`${chalk.grey('拉取开源模板列表成功!')}`);
|
|
469
|
+
const collection = (await response.json()) as OpenSourceTemplateCollection;
|
|
470
|
+
switch (platform.toLowerCase()) {
|
|
471
|
+
case 'react':
|
|
472
|
+
return collection.react;
|
|
473
|
+
default:
|
|
474
|
+
return [NONE_AVAILABLE_TEMPLATE];
|
|
475
|
+
}
|
|
476
|
+
} catch {
|
|
477
|
+
spinner.fail(chalk.red('拉取开源模板列表失败!'));
|
|
478
|
+
throw new Error();
|
|
479
|
+
}
|
|
527
480
|
}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { copyFile, mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { chalk } from '@spcsn/taro-helper';
|
|
6
|
+
|
|
7
|
+
export enum CompilerType {
|
|
8
|
+
Webpack4 = 'Webpack4',
|
|
9
|
+
Webpack5 = 'Webpack5',
|
|
10
|
+
Vite = 'Vite',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum CSSType {
|
|
14
|
+
None = 'None',
|
|
15
|
+
Sass = 'Sass',
|
|
16
|
+
Stylus = 'Stylus',
|
|
17
|
+
Less = 'Less',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export enum FrameworkType {
|
|
21
|
+
React = 'React',
|
|
22
|
+
Preact = 'Preact',
|
|
23
|
+
Vue3 = 'Vue3',
|
|
24
|
+
Solid = 'Solid',
|
|
25
|
+
None = 'None',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export enum NpmType {
|
|
29
|
+
Yarn = 'Yarn',
|
|
30
|
+
Cnpm = 'Cnpm',
|
|
31
|
+
Pnpm = 'Pnpm',
|
|
32
|
+
Npm = 'Npm',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export enum PeriodType {
|
|
36
|
+
CreateAPP = 'CreateAPP',
|
|
37
|
+
CreatePage = 'CreatePage',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface CreateOptions {
|
|
41
|
+
css?: CSSType;
|
|
42
|
+
cssExt?: string;
|
|
43
|
+
framework?: FrameworkType;
|
|
44
|
+
description?: string;
|
|
45
|
+
projectName: string;
|
|
46
|
+
version?: string;
|
|
47
|
+
date?: string;
|
|
48
|
+
typescript?: boolean;
|
|
49
|
+
buildEs5?: boolean;
|
|
50
|
+
template: string;
|
|
51
|
+
pageName?: string;
|
|
52
|
+
compiler?: CompilerType;
|
|
53
|
+
setPageName?: string;
|
|
54
|
+
subPkg?: string;
|
|
55
|
+
pageDir?: string;
|
|
56
|
+
setSubPkgPageName?: string;
|
|
57
|
+
changeExt?: boolean;
|
|
58
|
+
isCustomTemplate?: boolean;
|
|
59
|
+
pluginType?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ProjectConfig {
|
|
63
|
+
projectRoot: string;
|
|
64
|
+
projectName: string;
|
|
65
|
+
npm: NpmType;
|
|
66
|
+
description?: string;
|
|
67
|
+
typescript?: boolean;
|
|
68
|
+
buildEs5?: boolean;
|
|
69
|
+
template: string;
|
|
70
|
+
css: CSSType;
|
|
71
|
+
autoInstall?: boolean;
|
|
72
|
+
framework: FrameworkType;
|
|
73
|
+
templateRoot: string;
|
|
74
|
+
version: string;
|
|
75
|
+
date?: string;
|
|
76
|
+
compiler?: CompilerType;
|
|
77
|
+
period: PeriodType;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type TemplateHandlerResult = boolean | { setPageName?: string; setSubPkgName?: string; changeExt?: boolean };
|
|
81
|
+
type TemplateHandler = (error: Error | null, options: CreateOptions) => TemplateHandlerResult;
|
|
82
|
+
type TemplateHandlers = Record<string, TemplateHandler>;
|
|
83
|
+
|
|
84
|
+
const TEMPLATE_CREATOR = 'template_creator.js';
|
|
85
|
+
const FILE_FILTER = new Set([TEMPLATE_CREATOR, '.DS_Store', '.npmrc']);
|
|
86
|
+
const MEDIA_FILE_PATTERN = /\.(png|jpe?g|gif|svg|webp|jar|keystore|tgz)$/i;
|
|
87
|
+
const STYLE_EXTENSIONS: Record<CSSType, string> = {
|
|
88
|
+
[CSSType.None]: 'css',
|
|
89
|
+
[CSSType.Sass]: 'scss',
|
|
90
|
+
[CSSType.Stylus]: 'styl',
|
|
91
|
+
[CSSType.Less]: 'less',
|
|
92
|
+
};
|
|
93
|
+
const PACKAGE_MANAGERS: Record<NpmType, string> = {
|
|
94
|
+
[NpmType.Yarn]: 'yarn',
|
|
95
|
+
[NpmType.Cnpm]: 'cnpm',
|
|
96
|
+
[NpmType.Pnpm]: 'pnpm',
|
|
97
|
+
[NpmType.Npm]: 'npm',
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export async function createProject(conf: ProjectConfig, handlers: TemplateHandlers): Promise<void> {
|
|
101
|
+
const projectPath = path.join(conf.projectRoot, conf.projectName);
|
|
102
|
+
const templatePath = path.join(conf.templateRoot, 'templates', conf.template);
|
|
103
|
+
const templateFiles = await collectTemplateFiles(templatePath);
|
|
104
|
+
const createOptions: CreateOptions = {
|
|
105
|
+
css: conf.css,
|
|
106
|
+
cssExt: STYLE_EXTENSIONS[conf.css],
|
|
107
|
+
framework: conf.framework,
|
|
108
|
+
description: conf.description,
|
|
109
|
+
projectName: conf.projectName,
|
|
110
|
+
version: conf.version,
|
|
111
|
+
date: conf.date,
|
|
112
|
+
typescript: conf.typescript,
|
|
113
|
+
buildEs5: conf.buildEs5,
|
|
114
|
+
template: conf.template,
|
|
115
|
+
pageName: 'index',
|
|
116
|
+
compiler: conf.compiler,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
console.log();
|
|
120
|
+
console.log(`${chalk.green('✔')} ${chalk.rgb(102, 102, 102)(`创建项目: ${conf.projectName}`)}`);
|
|
121
|
+
|
|
122
|
+
for (const templateFile of templateFiles) {
|
|
123
|
+
await createTemplateFile({ templateFile, templatePath, projectPath, options: createOptions, handlers });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log();
|
|
127
|
+
await initGit(conf.projectName, projectPath);
|
|
128
|
+
|
|
129
|
+
if (conf.autoInstall ?? true) {
|
|
130
|
+
await installDeps(conf.npm, projectPath, () => printCreateSuccess(conf.projectName));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
printCreateSuccess(conf.projectName);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function createTemplateFile(args: {
|
|
138
|
+
templateFile: string;
|
|
139
|
+
templatePath: string;
|
|
140
|
+
projectPath: string;
|
|
141
|
+
options: CreateOptions;
|
|
142
|
+
handlers: TemplateHandlers;
|
|
143
|
+
}): Promise<void> {
|
|
144
|
+
const { templateFile, templatePath, projectPath, options, handlers } = args;
|
|
145
|
+
const relativeTemplatePath = normalizePath(templateFile.replace(templatePath, ''));
|
|
146
|
+
if (shouldSkipByFramework(relativeTemplatePath, options.framework)) return;
|
|
147
|
+
|
|
148
|
+
const handlerResult = handlers[relativeTemplatePath]?.(null, { ...options });
|
|
149
|
+
if (handlerResult === false) return;
|
|
150
|
+
|
|
151
|
+
const destinationRelativePath = resolveDestinationRelativePath(relativeTemplatePath, handlerResult, options);
|
|
152
|
+
const sourcePath = path.join(templatePath, relativeTemplatePath);
|
|
153
|
+
const destinationPath = normalizeTemplateDestination(path.join(projectPath, destinationRelativePath));
|
|
154
|
+
|
|
155
|
+
await writeTemplateFile(sourcePath, destinationPath, options);
|
|
156
|
+
console.log(`${chalk.green('✔')} ${chalk.rgb(102, 102, 102)(`创建文件: ${destinationPath}`)}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function shouldSkipByFramework(relativeTemplatePath: string, framework?: FrameworkType): boolean {
|
|
160
|
+
const isVueFramework = framework === FrameworkType.Vue3;
|
|
161
|
+
if (isVueFramework && relativeTemplatePath.endsWith('.jsx')) return true;
|
|
162
|
+
return !isVueFramework && relativeTemplatePath.endsWith('.vue');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function resolveDestinationRelativePath(
|
|
166
|
+
relativeTemplatePath: string,
|
|
167
|
+
handlerResult: TemplateHandlerResult | undefined,
|
|
168
|
+
options: CreateOptions,
|
|
169
|
+
): string {
|
|
170
|
+
const handlerDestination = typeof handlerResult === 'object' ? handlerResult : undefined;
|
|
171
|
+
let destinationRelativePath = handlerDestination?.setPageName ?? relativeTemplatePath;
|
|
172
|
+
|
|
173
|
+
if (options.subPkg && handlerDestination?.setSubPkgName) {
|
|
174
|
+
destinationRelativePath = handlerDestination.setSubPkgName;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (destinationRelativePath.startsWith('/')) {
|
|
178
|
+
destinationRelativePath = destinationRelativePath.slice(1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const shouldChangeExt = handlerDestination?.changeExt ?? true;
|
|
182
|
+
if (options.typescript && shouldChangeExt && shouldConvertScriptExtension(destinationRelativePath)) {
|
|
183
|
+
destinationRelativePath = destinationRelativePath.replace(/\.jsx?$/, (extension) =>
|
|
184
|
+
extension === '.jsx' ? '.tsx' : '.ts',
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (shouldChangeExt && destinationRelativePath.endsWith('.css')) {
|
|
189
|
+
destinationRelativePath = destinationRelativePath.replace(/\.css$/, `.${options.cssExt ?? 'css'}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return destinationRelativePath;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function shouldConvertScriptExtension(filePath: string): boolean {
|
|
196
|
+
if (!(filePath.endsWith('.js') || filePath.endsWith('.jsx'))) return false;
|
|
197
|
+
return !(filePath.endsWith('babel.config.js') || filePath.endsWith('.eslintrc.js'));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function writeTemplateFile(sourcePath: string, destinationPath: string, options: CreateOptions): Promise<void> {
|
|
201
|
+
await mkdir(path.dirname(destinationPath), { recursive: true });
|
|
202
|
+
|
|
203
|
+
if (MEDIA_FILE_PATTERN.test(sourcePath)) {
|
|
204
|
+
await copyFile(sourcePath, destinationPath);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const templateContent = await readFile(sourcePath, 'utf8');
|
|
209
|
+
const renderedContent = renderTemplate(templateContent, options);
|
|
210
|
+
await writeFile(destinationPath, renderedContent);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function renderTemplate(templateContent: string, options: CreateOptions): string {
|
|
214
|
+
return templateContent
|
|
215
|
+
.replace(/{{#if \(eq css "Sass"\) }}([\s\S]*?){{\/if}}/g, options.css === CSSType.Sass ? '$1' : '')
|
|
216
|
+
.replace(/{{#if \(eq css "Less"\) }}([\s\S]*?){{\/if}}/g, options.css === CSSType.Less ? '$1' : '')
|
|
217
|
+
.replace(/{{#if \(eq css "Stylus"\) }}([\s\S]*?){{\/if}}/g, options.css === CSSType.Stylus ? '$1' : '')
|
|
218
|
+
.replace(/{{#if typescript }}([\s\S]*?){{\/if}}/g, options.typescript ? '$1' : '')
|
|
219
|
+
.replace(/{{\s*to_pascal_case\s+pageName\s*}}/g, toPascalCase(options.pageName ?? 'index'))
|
|
220
|
+
.replace(/{{\s*projectName\s*}}/g, options.projectName)
|
|
221
|
+
.replace(/{{\s*description\s*}}/g, options.description ?? '')
|
|
222
|
+
.replace(/{{\s*template\s*}}/g, options.template)
|
|
223
|
+
.replace(/{{\s*typescript\s*}}/g, String(Boolean(options.typescript)))
|
|
224
|
+
.replace(/{{\s*css\s*}}/g, options.css ?? CSSType.None)
|
|
225
|
+
.replace(/{{\s*framework\s*}}/g, options.framework ?? FrameworkType.React)
|
|
226
|
+
.replace(/{{\s*version\s*}}/g, options.version ?? '')
|
|
227
|
+
.replace(/{{\s*date\s*}}/g, options.date ?? '')
|
|
228
|
+
.replace(/{{\s*cssExt\s*}}/g, options.cssExt ?? 'css')
|
|
229
|
+
.replace(/{{\s*pageName\s*}}/g, options.pageName ?? 'index');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function toPascalCase(value: string): string {
|
|
233
|
+
return value
|
|
234
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
235
|
+
.filter(Boolean)
|
|
236
|
+
.map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)
|
|
237
|
+
.join('');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function normalizeTemplateDestination(destinationPath: string): string {
|
|
241
|
+
const parsedPath = path.parse(destinationPath);
|
|
242
|
+
let normalizedPath = destinationPath;
|
|
243
|
+
|
|
244
|
+
if (parsedPath.ext === '.tmpl') {
|
|
245
|
+
normalizedPath = path.join(parsedPath.dir, parsedPath.name);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const basename = path.basename(normalizedPath);
|
|
249
|
+
if (basename.startsWith('_')) {
|
|
250
|
+
normalizedPath = path.join(path.dirname(normalizedPath), basename.slice(1));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return normalizedPath;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function collectTemplateFiles(templatePath: string): Promise<string[]> {
|
|
257
|
+
const entries = await readdir(templatePath, { withFileTypes: true });
|
|
258
|
+
const files = await Promise.all(
|
|
259
|
+
entries.map(async (entry) => {
|
|
260
|
+
const entryPath = path.join(templatePath, entry.name);
|
|
261
|
+
if (entry.isDirectory()) return collectTemplateFiles(entryPath);
|
|
262
|
+
if (FILE_FILTER.has(entry.name)) return [];
|
|
263
|
+
return [entryPath];
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
return files.flat();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function initGit(projectName: string, projectPath: string): Promise<void> {
|
|
271
|
+
console.log(`cd ${projectName}, 执行 ${chalk.cyan.bold('git init')}`);
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
await executeCommand('git', ['init'], projectPath);
|
|
275
|
+
console.log(`${chalk.green('✔')} ${chalk.green('初始化 git 成功')}`);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.log(`${chalk.red('✘')} ${chalk.red('初始化 git 失败')}`);
|
|
278
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
279
|
+
console.log('没有找到命令 git, 请检查!');
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
console.log(error);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async function installDeps(npm: NpmType, projectPath: string, onSuccess: () => void): Promise<void> {
|
|
287
|
+
const command = PACKAGE_MANAGERS[npm];
|
|
288
|
+
if (!command) return;
|
|
289
|
+
|
|
290
|
+
console.log(`执行安装项目依赖 ${chalk.cyan.bold(`${command} install`)}, 需要一会儿...`);
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
await executeCommand(command, ['install'], projectPath);
|
|
294
|
+
console.log(`${chalk.green('✔')} ${chalk.green('安装项目依赖成功')}`);
|
|
295
|
+
onSuccess();
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.log(`${chalk.red('✘')} ${chalk.red('安装项目依赖失败,请自行重新安装!')}`);
|
|
298
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
299
|
+
console.log(`没有找到命令 ${command}, 请检查!`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function executeCommand(command: string, args: string[], cwd: string): Promise<void> {
|
|
305
|
+
return new Promise((resolve, reject) => {
|
|
306
|
+
const childProcess = spawn(command, args, { cwd, stdio: 'inherit' });
|
|
307
|
+
childProcess.on('error', reject);
|
|
308
|
+
childProcess.on('close', (exitCode) => {
|
|
309
|
+
if (exitCode === 0) {
|
|
310
|
+
resolve();
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
reject(new Error(`${command} ${args.join(' ')} failed with exit code ${exitCode}`));
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function printCreateSuccess(projectName: string): void {
|
|
319
|
+
console.log(chalk.green(`创建项目 ${chalk.green.bold(projectName)} 成功!`));
|
|
320
|
+
console.log(chalk.green(`请进入项目目录 ${chalk.green.bold(projectName)} 开始工作吧!😝`));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function normalizePath(value: string): string {
|
|
324
|
+
return value.replace(/\\/g, '/').replace(/\/{2,}/g, '/');
|
|
325
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./validators.ts');
|
package/src/doctor/validators.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
export
|
|
2
|
-
Error
|
|
3
|
-
Warning
|
|
4
|
-
Success
|
|
5
|
-
Manual
|
|
6
|
-
}
|
|
1
|
+
export const MessageKind = {
|
|
2
|
+
Error: 'error',
|
|
3
|
+
Warning: 'warning',
|
|
4
|
+
Success: 'success',
|
|
5
|
+
Manual: 'manual',
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
export type MessageKind = (typeof MessageKind)[keyof typeof MessageKind];
|
|
7
9
|
|
|
8
10
|
export interface ValidateMessage {
|
|
9
11
|
kind: MessageKind;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const needPromiseApis = new Set([
|
|
2
|
+
'addFileToFavorites',
|
|
3
|
+
'addVideoToFavorites',
|
|
4
|
+
'authPrivateMessage',
|
|
5
|
+
'checkIsAddedToMyMiniProgram',
|
|
6
|
+
'chooseContact',
|
|
7
|
+
'cropImage',
|
|
8
|
+
'disableAlertBeforeUnload',
|
|
9
|
+
'editImage',
|
|
10
|
+
'enableAlertBeforeUnload',
|
|
11
|
+
'getBackgroundFetchData',
|
|
12
|
+
'getChannelsLiveInfo',
|
|
13
|
+
'getChannelsLiveNoticeInfo',
|
|
14
|
+
'getFuzzyLocation',
|
|
15
|
+
'getGroupEnterInfo',
|
|
16
|
+
'getLocalIPAddress',
|
|
17
|
+
'getShareInfo',
|
|
18
|
+
'getUserProfile',
|
|
19
|
+
'getWeRunData',
|
|
20
|
+
'join1v1Chat',
|
|
21
|
+
'openChannelsActivity',
|
|
22
|
+
'openChannelsEvent',
|
|
23
|
+
'openChannelsLive',
|
|
24
|
+
'openChannelsUserProfile',
|
|
25
|
+
'openCustomerServiceChat',
|
|
26
|
+
'openVideoEditor',
|
|
27
|
+
'saveFileToDisk',
|
|
28
|
+
'scanItem',
|
|
29
|
+
'setEnable1v1Chat',
|
|
30
|
+
'setWindowSize',
|
|
31
|
+
'sendBizRedPacket',
|
|
32
|
+
'startFacialRecognitionVerify',
|
|
33
|
+
]);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { processApis } from '@spcsn/taro-shared';
|
|
2
|
+
|
|
3
|
+
import { needPromiseApis } from './apis-list';
|
|
4
|
+
|
|
5
|
+
interface WeappNativeApi {
|
|
6
|
+
cloud?: unknown;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface TaroApiTarget {
|
|
10
|
+
cloud?: unknown;
|
|
11
|
+
getTabBar?: (pageCtx?: { getTabBar?: () => { $taroInstances?: unknown } }) => unknown;
|
|
12
|
+
getRenderer?: () => string;
|
|
13
|
+
getCurrentInstance?: () => { page?: { renderer?: string } };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare const wx: WeappNativeApi;
|
|
17
|
+
|
|
18
|
+
export function initNativeApi(taro: TaroApiTarget) {
|
|
19
|
+
processApis(taro, wx, {
|
|
20
|
+
needPromiseApis,
|
|
21
|
+
modifyApis(apis) {
|
|
22
|
+
// fix https://github.com/NervJS/taro/issues/9899
|
|
23
|
+
apis.delete('lanDebug');
|
|
24
|
+
},
|
|
25
|
+
transformMeta(api: string, options: Record<string, unknown>) {
|
|
26
|
+
if (api === 'showShareMenu') {
|
|
27
|
+
const showShareItems = Array.isArray(options.showShareItems) ? options.showShareItems : [];
|
|
28
|
+
options.menus = showShareItems.map((item) =>
|
|
29
|
+
item === 'wechatFriends' ? 'shareAppMessage' : item === 'wechatMoment' ? 'shareTimeline' : item,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
key: api,
|
|
35
|
+
options,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
taro.cloud = wx.cloud;
|
|
40
|
+
taro.getTabBar = function (pageCtx) {
|
|
41
|
+
if (typeof pageCtx?.getTabBar === 'function') {
|
|
42
|
+
return pageCtx.getTabBar()?.$taroInstances;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
taro.getRenderer = function () {
|
|
46
|
+
return taro.getCurrentInstance?.()?.page?.renderer ?? 'webview';
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// For React.createElement's type
|
|
2
|
+
export const View = 'view';
|
|
3
|
+
export const Block = 'block';
|
|
4
|
+
export const CustomWrapper = 'custom-wrapper';
|
|
5
|
+
export const Slot = 'slot';
|
|
6
|
+
export const NativeSlot = 'native-slot';
|
|
7
|
+
export const Icon = 'icon';
|
|
8
|
+
export const Progress = 'progress';
|
|
9
|
+
export const RichText = 'rich-text';
|
|
10
|
+
export const Text = 'text';
|
|
11
|
+
export const Button = 'button';
|
|
12
|
+
export const Checkbox = 'checkbox';
|
|
13
|
+
export const CheckboxGroup = 'checkbox-group';
|
|
14
|
+
export const Form = 'form';
|
|
15
|
+
export const Input = 'input';
|
|
16
|
+
export const Label = 'label';
|
|
17
|
+
export const Picker = 'picker';
|
|
18
|
+
export const PickerView = 'picker-view';
|
|
19
|
+
export const PickerViewColumn = 'picker-view-column';
|
|
20
|
+
export const Radio = 'radio';
|
|
21
|
+
export const RadioGroup = 'radio-group';
|
|
22
|
+
export const Slider = 'slider';
|
|
23
|
+
export const Switch = 'switch';
|
|
24
|
+
export const Textarea = 'textarea';
|
|
25
|
+
export const CoverImage = 'cover-image';
|
|
26
|
+
export const CoverView = 'cover-view';
|
|
27
|
+
export const MovableArea = 'movable-area';
|
|
28
|
+
export const MovableView = 'movable-view';
|
|
29
|
+
export const ScrollView = 'scroll-view';
|
|
30
|
+
export const Swiper = 'swiper';
|
|
31
|
+
export const SwiperItem = 'swiper-item';
|
|
32
|
+
export const Navigator = 'navigator';
|
|
33
|
+
export const Editor = 'editor';
|
|
34
|
+
export const MatchMedia = 'match-media';
|
|
35
|
+
export const FunctionalPageNavigator = 'functional-page-navigator';
|
|
36
|
+
export const Audio = 'audio';
|
|
37
|
+
export const Camera = 'camera';
|
|
38
|
+
export const Image = 'image';
|
|
39
|
+
export const LivePlayer = 'live-player';
|
|
40
|
+
export const LivePusher = 'live-pusher';
|
|
41
|
+
export const Video = 'video';
|
|
42
|
+
export const Canvas = 'canvas';
|
|
43
|
+
export const Ad = 'ad';
|
|
44
|
+
export const OfficialAccount = 'official-account';
|
|
45
|
+
export const OpenData = 'open-data';
|
|
46
|
+
export const WebView = 'web-view';
|
|
47
|
+
export const Map = 'map';
|
|
48
|
+
export const NavigationBar = 'navigation-bar';
|
|
49
|
+
export const PageMeta = 'page-meta';
|
|
50
|
+
export const VoipRoom = 'voip-room';
|
|
51
|
+
export const AdCustom = 'ad-custom';
|
|
52
|
+
export const PageContainer = 'page-container';
|
|
53
|
+
export const ShareElement = 'share-element';
|
|
54
|
+
export const KeyboardAccessory = 'keyboard-accessory';
|
|
55
|
+
export const RootPortal = 'root-portal';
|
|
56
|
+
export const ChannelLive = 'channel-live';
|
|
57
|
+
export const ChannelVideo = 'channel-video';
|
|
58
|
+
export const ListView = 'list-view';
|
|
59
|
+
export const ListBuilder = 'list-builder';
|
|
60
|
+
export const List = 'list';
|
|
61
|
+
export const ListItem = 'list-item';
|
|
62
|
+
export const GridView = 'grid-view';
|
|
63
|
+
export const GridBuilder = 'grid-builder';
|
|
64
|
+
export const StickyHeader = 'sticky-header';
|
|
65
|
+
export const StickySection = 'sticky-section';
|
|
66
|
+
export const NestedScrollHeader = 'nested-scroll-header';
|
|
67
|
+
export const NestedScrollBody = 'nested-scroll-body';
|
|
68
|
+
export const PullToRefresh = 'pull-to-refresh';
|
|
69
|
+
export const Script = 'script';
|
|
70
|
+
export const Snapshot = 'snapshot';
|
|
71
|
+
export const Span = 'span';
|
|
72
|
+
export const OpenContainer = 'open-container';
|
|
73
|
+
export const DraggableSheet = 'draggable-sheet';
|
|
74
|
+
export const DoubleTapGestureHandler = 'double-tap-gesture-handler';
|
|
75
|
+
export const ForcePressGestureHandler = 'force-press-gesture-handler';
|
|
76
|
+
export const HorizontalDragGestureHandler = 'horizontal-drag-gesture-handler';
|
|
77
|
+
export const LongPressGestureHandler = 'long-press-gesture-handler';
|
|
78
|
+
export const PanGestureHandler = 'pan-gesture-handler';
|
|
79
|
+
export const ScaleGestureHandler = 'scale-gesture-handler';
|
|
80
|
+
export const TapGestureHandler = 'tap-gesture-handler';
|
|
81
|
+
export const VerticalDragGestureHandler = 'vertical-drag-gesture-handler';
|