@airiot/cli 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.
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from 'child_process';
3
+ import { fileURLToPath } from 'url';
4
+ import path from 'path';
5
+
6
+ const args = process.argv.slice(2);
7
+
8
+ const scriptIndex = args.findIndex(
9
+ x => ['build', 'start', 'preview', 'test', 'upload', 'install', 'pack', 'deploy'].includes(x)
10
+ );
11
+
12
+ const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
13
+ const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : [];
14
+
15
+ const runScript = async (script) => {
16
+ const scriptPath = path.resolve(fileURLToPath(import.meta.url), `../../scripts/${script}.js`)
17
+ const { status, signal } = spawnSync(
18
+ 'node',
19
+ nodeArgs
20
+ .concat(scriptPath)
21
+ .concat(args.slice(scriptIndex + 1)),
22
+ { stdio: 'inherit' }
23
+ );
24
+
25
+ if (signal) {
26
+ if (signal === 'SIGKILL') {
27
+ console.log(
28
+ '构建失败,因为进程提前退出。这可能意味着系统内存不足或有人调用了 ' +
29
+ '`kill -9` 终止了进程。'
30
+ );
31
+ } else if (signal === 'SIGTERM') {
32
+ console.log(
33
+ '构建失败,因为进程提前退出。有人可能调用了 `kill` 或 `killall`,或者系统正在 ' +
34
+ '关机。'
35
+ );
36
+ }
37
+ process.exit(1);
38
+ }
39
+
40
+ if (status !== 0) {
41
+ process.exit(status);
42
+ }
43
+ };
44
+
45
+ switch (script) {
46
+ case 'build':
47
+ case 'start':
48
+ case 'upload':
49
+ case 'install':
50
+ case 'preview':
51
+ case 'pack':
52
+ case 'i18n-scanner':
53
+ case 'i18n-translate':
54
+ case 'eslint':
55
+ case 'test': {
56
+ await runScript(script);
57
+ break;
58
+ }
59
+ case 'deploy': {
60
+ await runScript('build');
61
+ await runScript('upload');
62
+ break;
63
+ }
64
+ default:
65
+ console.log(`未知的脚本 "${script}"。`);
66
+ break;
67
+ }
package/config/envs.js ADDED
@@ -0,0 +1,105 @@
1
+ import paths from './paths.js';
2
+ import { URL } from 'url';
3
+
4
+ let developConfig = {};
5
+
6
+ try {
7
+ const module = await import(new URL(`file://${paths.developConfig}`));
8
+ developConfig = module.default;
9
+ } catch (err) {
10
+ if (err.code !== 'ERR_MODULE_NOT_FOUND') {
11
+ throw err;
12
+ }
13
+ }
14
+ const getHost = () => {
15
+ if (developConfig.host) {
16
+ return developConfig.host;
17
+ }
18
+
19
+ const envs = process.env;
20
+ const args = process.argv;
21
+
22
+ let host;
23
+ const hostArgs = args.filter(arg => arg.startsWith("--host="));
24
+ if (hostArgs.length !== 0) {
25
+ host = hostArgs[0].replace('--host=', '');
26
+ } else if (envs.IOT_URL) {
27
+ host = envs.IOT_URL;
28
+ } else {
29
+ console.error('[iot:envs] 请设置环境变量 IOT_URL');
30
+ process.exit();
31
+ }
32
+
33
+ if (host.endsWith('/')) {
34
+ host = host.substring(0, host.length - 1);
35
+ }
36
+
37
+ return host;
38
+ };
39
+
40
+ const getBaseUrl = () => {
41
+ const envs = process.env;
42
+ const args = process.argv;
43
+
44
+ let baseUrl = null;
45
+
46
+ if (developConfig.base) {
47
+ baseUrl = developConfig.base;
48
+ } else if (developConfig.branch) {
49
+ baseUrl = developConfig.branch;
50
+ } else {
51
+ const hostArgs = args.filter(arg => arg.startsWith("--base="));
52
+ if (hostArgs.length !== 0) {
53
+ baseUrl = hostArgs[0].replace('--base=', '');
54
+ } else if (envs.IOT_BASEURL) {
55
+ baseUrl = envs.IOT_BASEURL;
56
+ }
57
+ }
58
+
59
+ if (!baseUrl) {
60
+ baseUrl = getHost();
61
+ } else if (!(baseUrl.startsWith('http://') || baseUrl.startsWith('https://') || baseUrl.startsWith('//'))) {
62
+ // baseUrl = new URL(baseUrl, getHost()).href;
63
+ }
64
+
65
+ return baseUrl;
66
+ };
67
+
68
+ const getModule = () => {
69
+ const envs = process.env;
70
+ const args = process.argv;
71
+
72
+ let modules = 'all';
73
+
74
+ const hostArgs = args.filter(arg => arg.startsWith("--module="));
75
+ if (hostArgs.length !== 0) {
76
+ modules = hostArgs[0].replace('--module=', '');
77
+ } else if (envs.IOT_MODULE) {
78
+ useLocal = envs.IOT_MODULE;
79
+ }
80
+
81
+ return modules;
82
+ };
83
+
84
+ const translateKeys = () => {
85
+ const envs = process.env;
86
+ const args = process.argv;
87
+
88
+ let appid, secret
89
+
90
+ if (developConfig.translate) {
91
+ appid = developConfig.translate.appid;
92
+ secret = developConfig.translate.secret;
93
+ } else {
94
+ const appArgs = args.filter(arg => arg.startsWith("--translate="));
95
+ if (appArgs.length !== 0) {
96
+ [appid, secret] = appArgs[0].replace('--translate=', '').split(',');
97
+ } else if (envs.IOT_TRANSLATE) {
98
+ [appid, secret] = envs.IOT_TRANSLATE.split(',');
99
+ }
100
+ }
101
+
102
+ return { appid, secret };
103
+ }
104
+
105
+ export { getHost, getBaseUrl, getModule, developConfig, translateKeys };
@@ -0,0 +1,89 @@
1
+ // eslint.config.js
2
+ import { defineConfig } from "eslint/config";
3
+ import js from '@eslint/js';
4
+ import globals from 'globals';
5
+ import reactPlugin from 'eslint-plugin-react';
6
+ import importPlugin from 'eslint-plugin-import';
7
+ import paths from './paths.js';
8
+
9
+ export default defineConfig([
10
+ // 基础 JS 配置
11
+ {
12
+ basePath: paths.appPath,
13
+ files: ["**/*.js"],
14
+ ...js.configs.recommended,
15
+ languageOptions: {
16
+ ecmaVersion: 'latest',
17
+ sourceType: 'module',
18
+ globals: {
19
+ ...globals.browser,
20
+ moment: "readonly",
21
+ _: "readonly",
22
+ _t1: "writable",
23
+ _r: 'writable',
24
+ _t: 'writable',
25
+ require: 'readonly',
26
+ Atomics: "readonly",
27
+ SharedArrayBuffer: "readonly",
28
+ Cookies: "readonly",
29
+ process: "readonly"
30
+ }
31
+ },
32
+ },
33
+
34
+ // React JSX 配置
35
+ {
36
+ files: ["**/*.js", "**/*.jsx"],
37
+ plugins: {
38
+ react: reactPlugin,
39
+ import: importPlugin
40
+ },
41
+ languageOptions: {
42
+ parserOptions: {
43
+ ecmaFeatures: {
44
+ jsx: true
45
+ }
46
+ }
47
+ },
48
+ rules: {
49
+ "semi": "off",
50
+ 'arrow-parens': "off",
51
+ 'no-debugger': process.env.NODE_ENV === 'production' ? "error" : "off",
52
+ "no-unused-vars": "off",
53
+ "no-extra-boolean-cast": "off",
54
+ "no-empty": "off",
55
+ "no-console": ["error", { allow: ["warn", "error"] }],
56
+ "no-useless-escape": "off",
57
+ "no-unsafe-optional-chaining": "off",
58
+ "comma-dangle": "off",
59
+ "react/jsx-uses-react": "error",
60
+ "react/jsx-no-undef": "error",
61
+ "react/jsx-wrap-multilines": "off",
62
+ "react/prop-types": "off",
63
+
64
+ // 3. require 动态文件问题
65
+ 'import/no-dynamic-require': 'error',
66
+ 'import/no-unresolved': 'error',
67
+
68
+ // 4. ES Module 导入导出规范
69
+ 'import/no-absolute-path': 'error',
70
+ 'import/no-webpack-loader-syntax': 'error',
71
+ 'import/no-self-import': 'error',
72
+ 'import/no-cycle': 'error',
73
+ 'import/no-useless-path-segments': 'error',
74
+
75
+ // 1. 变量先使用后定义问题
76
+ 'no-use-before-define': ['error', {
77
+ functions: false,
78
+ classes: true,
79
+ variables: true
80
+ }],
81
+ }
82
+ },
83
+
84
+ // 添加默认文件匹配规则(防止 "empty config" 警告)
85
+ {
86
+ ignores: ['**/node_modules/**', '**/dist/**'],
87
+ rules: {}
88
+ }
89
+ ]);
@@ -0,0 +1,78 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { fileURLToPath } from 'url';
4
+ import { createRequire } from 'module';
5
+
6
+ const appDirectory = fs.realpathSync(process.cwd());
7
+ const devtoolDirectory = path.resolve(fileURLToPath(import.meta.url), '../..');
8
+
9
+ const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
10
+ const resolveDevtool = relativePath => path.resolve(devtoolDirectory, relativePath);
11
+
12
+ function ensureSlash(inputPath, needsSlash) {
13
+ const hasSlash = inputPath.endsWith('/');
14
+ if (hasSlash && !needsSlash) {
15
+ return inputPath.substr(0, inputPath.length - 1);
16
+ } else if (!hasSlash && needsSlash) {
17
+ return `${inputPath}/`;
18
+ } else {
19
+ return inputPath;
20
+ }
21
+ }
22
+
23
+ const moduleFileExtensions = [
24
+ 'web.mjs',
25
+ 'mjs',
26
+ 'web.js',
27
+ 'js',
28
+ 'web.ts',
29
+ 'ts',
30
+ 'web.tsx',
31
+ 'tsx',
32
+ 'json',
33
+ 'web.jsx',
34
+ 'jsx',
35
+ ];
36
+
37
+ // Resolve file paths in the same order as webpack
38
+ const resolveModule = (resolveFn, filePath) => {
39
+ const extension = moduleFileExtensions.find(extension =>
40
+ fs.existsSync(resolveFn(`${filePath}.${extension}`))
41
+ );
42
+
43
+ if (extension) {
44
+ return resolveFn(`${filePath}.${extension}`);
45
+ }
46
+
47
+ return resolveFn(`${filePath}.js`);
48
+ };
49
+
50
+ const appRequire = createRequire(resolveModule(resolveApp, 'src/index'));
51
+ const ReactPath = appRequire.resolve('react');
52
+ const appNodeModules = path.resolve(ReactPath, '../..');
53
+
54
+ // config after eject: we're in ./config/
55
+ export default {
56
+ dotenv: resolveApp('.env'),
57
+ appPath: resolveApp('.'),
58
+ buildPath: resolveApp('dist'),
59
+ appHtml: resolveDevtool('dist/index.html'),
60
+ appIndexJs: resolveModule(resolveApp, 'src/index'),
61
+ appFrontJs: resolveModule(resolveApp, 'src/front'),
62
+ appDevIndexJs: resolveModule(resolveApp, 'src/dev'),
63
+ appPackageJson: resolveApp('package.json'),
64
+ appSrc: resolveApp('src'),
65
+ appTsConfig: resolveApp('tsconfig.json'),
66
+ appWebpackConfig: resolveApp('webpack.js'),
67
+ appVitePlugin: resolveApp('vite.plugin.js'),
68
+ developConfig: resolveApp('.dev.js'),
69
+ testsSetup: resolveModule(resolveApp, 'src/setupTests'),
70
+ devtoolDirectory: devtoolDirectory,
71
+ devtoolBuild: resolveDevtool('dist'),
72
+ devtoolNodeModules: resolveDevtool('node_modules'),
73
+ proxySetup: resolveApp('src/setupProxy.js'),
74
+ appNodeModules,
75
+ clientBuildPath: path.resolve(appNodeModules, '@gtiot/iot-client/dist'),
76
+ };
77
+
78
+ export { moduleFileExtensions };