init for deploy files
This commit is contained in:
parent
b2acf93806
commit
ef21829ffe
38
.github/workflows/publish.yml
vendored
Normal file
38
.github/workflows/publish.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
name: Publish to npm
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*' # 当推送带有版本号的 tag 时触发,例如 v1.0.0
|
||||||
|
workflow_dispatch: # 添加手动触发器
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# Step 1: Clone current Git repository
|
||||||
|
- name: Checkout this repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
# Step 3: Setup Node.js and install dependencies
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '20.6'
|
||||||
|
registry-url: 'https://registry.npmjs.org/'
|
||||||
|
cache: 'npm' # 启用 npm 缓存,提高安装速度
|
||||||
|
- name: Configure npm authentication
|
||||||
|
run: npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
- name: Build project
|
||||||
|
run: npm run build
|
||||||
|
# Step 6: 发布到 npm
|
||||||
|
- name: Publish package
|
||||||
|
run: npm publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
# Step 7: 发布成功后,更新版本标签
|
||||||
|
# - name: Create Git tag
|
||||||
|
# run: |
|
||||||
|
# TAG="v$(node -p -e "require('./package.json').version")"
|
||||||
|
# git tag $TAG
|
||||||
|
# git push origin $TAG
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
dist
|
||||||
|
2
bin/envision.js
Executable file
2
bin/envision.js
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import '../dist/app.js';
|
3
docs/readme.md
Normal file
3
docs/readme.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# envision-cli
|
||||||
|
|
||||||
|
## 上传文件
|
37
package.json
37
package.json
@ -7,16 +7,41 @@
|
|||||||
"bin": {
|
"bin": {
|
||||||
"envision": "./bin/envision"
|
"envision": "./bin/envision"
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"bin"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"dev": "tsx src/index.ts ",
|
||||||
|
"build": "rimraf dist && rollup -c",
|
||||||
|
"b": "./bin/envision.js"
|
||||||
},
|
},
|
||||||
"keywords": ["kevisual","cli"],
|
"keywords": [
|
||||||
|
"kevisual",
|
||||||
|
"cli"
|
||||||
|
],
|
||||||
"author": "abearxiong",
|
"author": "abearxiong",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-commonjs": "^28.0.0",
|
||||||
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||||
|
"@rollup/plugin-typescript": "^12.1.0",
|
||||||
"@types/node": "^22.5.5",
|
"@types/node": "^22.5.5",
|
||||||
"commander": "^12.1.0"
|
"commander": "^12.1.0",
|
||||||
|
"rollup": "^4.24.0",
|
||||||
|
"tslib": "^2.7.0",
|
||||||
|
"typescript": "^5.6.3",
|
||||||
|
"@kevisual/query": "0.0.7-alpha.1",
|
||||||
|
"chalk": "^5.3.0",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"glob": "^11.0.0",
|
||||||
|
"inquirer": "^12.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {},
|
||||||
"chalk": "^5.3.0"
|
"resolutions": {
|
||||||
|
"picomatch": "^4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
1016
pnpm-lock.yaml
generated
1016
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
27
rollup.config.js
Normal file
27
rollup.config.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// rollup.config.js
|
||||||
|
|
||||||
|
import typescript from '@rollup/plugin-typescript';
|
||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import json from '@rollup/plugin-json';
|
||||||
|
/**
|
||||||
|
* @type {import('rollup').RollupOptions}
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
input: 'src/index.ts', // TypeScript 入口文件
|
||||||
|
output: {
|
||||||
|
file: 'dist/app.js', // 输出文件
|
||||||
|
format: 'es', // 输出格式设置为 ES 模块
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
resolve(), // 使用 @rollup/plugin-node-resolve 解析 node_modules 中的模块
|
||||||
|
commonjs(),
|
||||||
|
json(),
|
||||||
|
typescript({
|
||||||
|
allowImportingTsExtensions: true,
|
||||||
|
noEmit: true,
|
||||||
|
// 不生成声明文件
|
||||||
|
declaration: false,
|
||||||
|
}), // 使用 @rollup/plugin-typescript 处理 TypeScript 文件
|
||||||
|
],
|
||||||
|
};
|
16
src/app.ts
Normal file
16
src/app.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { program , Command} from 'commander';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
// 将多个子命令加入主程序中
|
||||||
|
program.name('app').description('A CLI tool with envison').version('0.0.1');
|
||||||
|
|
||||||
|
const ls =new Command('ls')
|
||||||
|
.description('List files in the current directory')
|
||||||
|
.action(() => {
|
||||||
|
console.log('List files');
|
||||||
|
console.log(fs.readdirSync(process.cwd()));
|
||||||
|
});
|
||||||
|
program.addCommand(ls);
|
||||||
|
|
||||||
|
export const app = program;
|
||||||
|
export { program, Command };
|
118
src/command/deploy.ts
Normal file
118
src/command/deploy.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { app, Command } from '@/app.ts';
|
||||||
|
import { glob } from 'glob';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import FormData from 'form-data';
|
||||||
|
import { baseURL } from '@/module/query.ts';
|
||||||
|
import { getConfig } from '@/module/index.ts';
|
||||||
|
import inquirer from 'inquirer';
|
||||||
|
|
||||||
|
const command = new Command('deploy')
|
||||||
|
.description('deploy to server')
|
||||||
|
.argument('<filePath>', 'Path to the file to be uploaded') // 定义文件路径参数
|
||||||
|
.option('-v, --version <version>', 'verbose')
|
||||||
|
.option('-k, --key <key>', 'key')
|
||||||
|
.action(async (filePath, options) => {
|
||||||
|
try {
|
||||||
|
let { version, key } = options;
|
||||||
|
if (!version || !key) {
|
||||||
|
const answers = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'version',
|
||||||
|
message: 'Enter your version:',
|
||||||
|
when: () => !version,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'key',
|
||||||
|
message: 'Enter your key:',
|
||||||
|
when: () => !key,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
version = answers.version || version;
|
||||||
|
key = answers.key || key;
|
||||||
|
}
|
||||||
|
const pwd = process.cwd();
|
||||||
|
const directory = path.join(pwd, filePath);
|
||||||
|
const gPath = path.join(directory, '**/*');
|
||||||
|
const files = await glob(gPath, { cwd: pwd, ignore: ['node_modules/**/*'] });
|
||||||
|
const _relativeFiles = files.map((file) => file.replace(directory + '/', ''));
|
||||||
|
console.log('upload Files', _relativeFiles);
|
||||||
|
console.log('upload Files Key', key, version);
|
||||||
|
// 确认是否上传
|
||||||
|
const confirm = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'confirm',
|
||||||
|
message: 'Do you want to upload these files?',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
if (!confirm.confirm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await uploadFiles(_relativeFiles, directory, { key, version });
|
||||||
|
if (res?.code === 200) {
|
||||||
|
console.log('File uploaded successfully!');
|
||||||
|
res.data?.data?.files?.map?.((d) => {
|
||||||
|
console.log('uploaded file', d?.name, d?.path);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('File upload failed', res?.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('error', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadFiles = async (files: string[], directory: string, { key, version }: { key: string; version: string }): Promise<any> => {
|
||||||
|
const config = await getConfig();
|
||||||
|
const form = new FormData();
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(directory, file);
|
||||||
|
form.append('file', fs.createReadStream(filePath), {
|
||||||
|
filename: file,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
form.append('appKey', key);
|
||||||
|
form.append('version', version);
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const url = new URL(baseURL);
|
||||||
|
console.log('upload url', url.hostname, url.protocol, url.port);
|
||||||
|
form.submit(
|
||||||
|
{
|
||||||
|
path: '/api/app/upload',
|
||||||
|
host: url.hostname,
|
||||||
|
protocol: url.protocol as any,
|
||||||
|
port: url.port,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: 'Bearer ' + config.token,
|
||||||
|
...form.getHeaders(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
(err, res) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error uploading file:', err.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 处理服务器响应
|
||||||
|
let body = '';
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
body += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on('end', () => {
|
||||||
|
try {
|
||||||
|
const res = JSON.parse(body);
|
||||||
|
resolve(res);
|
||||||
|
} catch (e) {
|
||||||
|
resolve({ code: 500, message: body });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
app.addCommand(command);
|
59
src/command/login.ts
Normal file
59
src/command/login.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { app, program, Command } from '@/app.ts';
|
||||||
|
import { getConfig, writeConfig } from '@/module/get-config.ts';
|
||||||
|
import { queryLogin, queryMe } from '@/route/index.ts';
|
||||||
|
import inquirer from 'inquirer';
|
||||||
|
|
||||||
|
// 导入 login 命令
|
||||||
|
|
||||||
|
// 定义login命令,支持 `-u` 和 `-p` 参数来输入用户名和密码
|
||||||
|
const loginCommand = new Command('login')
|
||||||
|
.description('Login to the application')
|
||||||
|
.option('-u, --username <username>', 'Specify username')
|
||||||
|
.option('-p, --password <password>', 'Specify password')
|
||||||
|
.action(async (options) => {
|
||||||
|
const config = getConfig();
|
||||||
|
let { username, password } = options;
|
||||||
|
|
||||||
|
// 如果没有传递参数,则通过交互式输入
|
||||||
|
if (!username || !password) {
|
||||||
|
const answers = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'username',
|
||||||
|
message: 'Enter your username:',
|
||||||
|
when: () => !username, // 当 username 为空时,提示用户输入
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'password',
|
||||||
|
name: 'password',
|
||||||
|
message: 'Enter your password:',
|
||||||
|
mask: '*', // 隐藏输入的字符
|
||||||
|
when: () => !password, // 当 password 为空时,提示用户输入
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
username = answers.username || username;
|
||||||
|
password = answers.password || password;
|
||||||
|
}
|
||||||
|
if (config.token) {
|
||||||
|
const res = await queryMe();
|
||||||
|
if (res.code === 200) {
|
||||||
|
const data = res.data;
|
||||||
|
if (data.username === username) {
|
||||||
|
console.log('Already Login For', data.username);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await queryLogin(username, password);
|
||||||
|
if (res.code === 200) {
|
||||||
|
console.log('登录成功');
|
||||||
|
const { token } = res.data;
|
||||||
|
writeConfig({ ...config, token });
|
||||||
|
} else {
|
||||||
|
console.log('登录失败', res.message || '');
|
||||||
|
}
|
||||||
|
console.log('u', username, password);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.addCommand(loginCommand);
|
11
src/command/logout.ts
Normal file
11
src/command/logout.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { app, Command } from '@/app.ts';
|
||||||
|
import { getConfig, writeConfig } from '@/module/index.ts';
|
||||||
|
|
||||||
|
const command = new Command('logout')
|
||||||
|
.description('')
|
||||||
|
.action(async () => {
|
||||||
|
const config = getConfig();
|
||||||
|
writeConfig({ ...config, token: '' });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.addCommand(command);
|
37
src/command/ls-token.ts
Normal file
37
src/command/ls-token.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { app, Command } from '@/app.ts';
|
||||||
|
import { getConfig, query, writeConfig } from '@/module/index.ts';
|
||||||
|
import inquirer from 'inquirer';
|
||||||
|
|
||||||
|
const token = new Command('token').description('show token').action(async () => {
|
||||||
|
const config = getConfig();
|
||||||
|
console.log('token', config.token);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.addCommand(token);
|
||||||
|
|
||||||
|
const baseURL = new Command('baseURL').description('show baseURL').action(async () => {
|
||||||
|
const config = getConfig();
|
||||||
|
console.log('baseURL', config.baseURL);
|
||||||
|
});
|
||||||
|
app.addCommand(baseURL);
|
||||||
|
|
||||||
|
const setBaseURL = new Command('setBaseURL').description('set baseURL').action(async () => {
|
||||||
|
const config = getConfig();
|
||||||
|
const answers = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'baseURL',
|
||||||
|
message: `Enter your baseURL:(current: ${config.baseURL})`,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const baseURL = answers.baseURL;
|
||||||
|
writeConfig({ ...config, baseURL });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.addCommand(setBaseURL);
|
||||||
|
|
||||||
|
// const showQueryURL = new Command('showQueryURL').description('show query URL').action(async () => {
|
||||||
|
// console.log("url", query.url);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// app.addCommand(showQueryURL);
|
19
src/command/me.ts
Normal file
19
src/command/me.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { app, Command } from '@/app.ts';
|
||||||
|
import { getConfig, writeConfig } from '@/module/index.ts';
|
||||||
|
import {queryMe} from '../route/index.ts';
|
||||||
|
|
||||||
|
|
||||||
|
const command = new Command('me')
|
||||||
|
.description('')
|
||||||
|
.action(async () => {
|
||||||
|
const config = getConfig()
|
||||||
|
const res = await queryMe();
|
||||||
|
if(res.code===200) {
|
||||||
|
console.log('me', res.data)
|
||||||
|
} else {
|
||||||
|
console.log('not login')
|
||||||
|
writeConfig({ ...config, token: '' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.addCommand(command);
|
9
src/index.ts
Normal file
9
src/index.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { app } from '@/app.ts';
|
||||||
|
import './command/login.ts';
|
||||||
|
import './command/logout.ts';
|
||||||
|
import './command/ls-token.ts';
|
||||||
|
import './command/me.ts';
|
||||||
|
import './command/deploy.ts';
|
||||||
|
|
||||||
|
|
||||||
|
app.parse(process.argv);
|
33
src/module/get-config.ts
Normal file
33
src/module/get-config.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import os from 'os';
|
||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
const envisionPath = path.join(os.homedir(), '.config', 'envision');
|
||||||
|
const configPath = path.join(os.homedir(), '.config', 'envision', 'config.json');
|
||||||
|
|
||||||
|
export const checkFileExists = (filePath: string) => {
|
||||||
|
try {
|
||||||
|
fs.accessSync(filePath, fs.constants.F_OK);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const getConfig = () => {
|
||||||
|
if (!checkFileExists(envisionPath)) {
|
||||||
|
fs.mkdirSync(envisionPath, { recursive: true });
|
||||||
|
}
|
||||||
|
if (checkFileExists(configPath)) {
|
||||||
|
const config = fs.readFileSync(configPath, 'utf-8');
|
||||||
|
try {
|
||||||
|
return JSON.parse(config);
|
||||||
|
} catch (e) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const writeConfig = (config: Record<string, any>) => {
|
||||||
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||||
|
};
|
3
src/module/index.ts
Normal file
3
src/module/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './query.ts';
|
||||||
|
|
||||||
|
export * from './get-config.ts';
|
18
src/module/query.ts
Normal file
18
src/module/query.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Query } from '@kevisual/query';
|
||||||
|
import { getConfig } from './get-config.ts';
|
||||||
|
const config = getConfig();
|
||||||
|
export const baseURL = config?.baseURL || 'https://envision.xiongxiao.me';
|
||||||
|
|
||||||
|
export const query = new Query({
|
||||||
|
url: `${baseURL}/api/router`,
|
||||||
|
});
|
||||||
|
|
||||||
|
query.beforeRequest = async (config) => {
|
||||||
|
if (config.headers) {
|
||||||
|
const token = await getConfig()?.token;
|
||||||
|
if (token) {
|
||||||
|
config.headers['Authorization'] = 'Bearer ' + token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
};
|
1
src/route/index.ts
Normal file
1
src/route/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './user/login.ts';
|
19
src/route/user/login.ts
Normal file
19
src/route/user/login.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { query } from '@/module/query.ts';
|
||||||
|
|
||||||
|
export const queryLogin = async (username: string, password: string) => {
|
||||||
|
return await query.post({
|
||||||
|
path: 'user',
|
||||||
|
key: 'login',
|
||||||
|
payload: {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const queryMe = async () => {
|
||||||
|
return await query.post({
|
||||||
|
path: 'user',
|
||||||
|
key: 'me',
|
||||||
|
});
|
||||||
|
};
|
15
src/scripts/login.ts
Normal file
15
src/scripts/login.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { query } from '@/module/query.ts';
|
||||||
|
|
||||||
|
export const login = async () => {
|
||||||
|
const res = await query.post({
|
||||||
|
path: 'user',
|
||||||
|
key: 'login',
|
||||||
|
payload: {
|
||||||
|
username: 'demo',
|
||||||
|
password: '123456',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(res);
|
||||||
|
};
|
||||||
|
|
||||||
|
login();
|
37
tsconfig.json
Normal file
37
tsconfig.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"target": "esnext",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"sourceMap": false,
|
||||||
|
"allowJs": true,
|
||||||
|
"newLine": "LF",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types",
|
||||||
|
],
|
||||||
|
"declaration": true,
|
||||||
|
"noEmit": false,
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"emitDeclarationOnly": true,
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"typings.d.ts",
|
||||||
|
"src/**/*.ts",
|
||||||
|
"test/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist",
|
||||||
|
],
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user