init:框架
This commit is contained in:
當前提交
d500a2da57
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
.idea/*
|
||||
/config.yaml
|
||||
node_modules/*
|
||||
/pnpm-lock.yaml
|
36
config.yaml.example
Normal file
36
config.yaml.example
Normal file
@ -0,0 +1,36 @@
|
||||
# 教务cookie
|
||||
cookie: "JSESSIONID=asd;"
|
||||
# 在 https://qmsg.zendee.cn 申请
|
||||
qmsgKey: "v9631222364dd7ae99909cb63b7445c5"
|
||||
# 轮询间隔毫秒
|
||||
interval: 100
|
||||
# 监控列表
|
||||
# channel: bx(必修),xx(限选),rx(任选)
|
||||
# kch:课程号;kxh:课序号
|
||||
monit:
|
||||
list:
|
||||
- kch: sd01332200
|
||||
kxh: 100
|
||||
channel: rx
|
||||
# 抢课列表,列表中全抢
|
||||
acquire:
|
||||
list:
|
||||
- kch: sd01332200
|
||||
kxh: 100
|
||||
channel: rx
|
||||
- kch: sd00812930
|
||||
kxh: 900
|
||||
channel: xx
|
||||
# 换课列表(先退掉冲突的课再抢课),列表中任抢其一
|
||||
replace:
|
||||
list:
|
||||
- kch: sd01332200
|
||||
kxh: 100
|
||||
channel: bx
|
||||
- kch: sd01332200
|
||||
kxh: 100
|
||||
channel: bx
|
||||
exit:
|
||||
kch: sd01332299
|
||||
kxh: 100
|
||||
channel: bx
|
23
package.json
Normal file
23
package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "sdu-course-bot",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "ts-node src/test.ts",
|
||||
"start": "ts-node src/index.ts"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/node": "^16.9.1",
|
||||
"@types/qs": "^6.9.7",
|
||||
"axios": "^0.21.4",
|
||||
"axios-retry": "^3.1.9",
|
||||
"dayjs": "^1.10.7",
|
||||
"qs": "^6.10.1",
|
||||
"ts-node": "^10.2.1",
|
||||
"typescript": "^4.4.3",
|
||||
"yaml": "^1.10.2"
|
||||
}
|
||||
}
|
79
src/actions.ts
Normal file
79
src/actions.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import {ICourse} from "./types"
|
||||
import {acquireCourse, exitCourse, findJsonCourse, getTimeNow, logAndNotifyUser, sleep} from "./includes"
|
||||
import {JsonCourseList} from "./poll"
|
||||
|
||||
export async function monitProcess(course: ICourse) {
|
||||
let lastSyrs = -1
|
||||
while (true) {
|
||||
let single = findJsonCourse(course)
|
||||
if (single == undefined) {
|
||||
console.log('[monit]无法找到课程 ' + course.kch + ' on channel ' + course.channel)
|
||||
} else {
|
||||
if (lastSyrs == -1) {
|
||||
console.log('[monit]开始监控 ' + single.kcmc + ' ,当前剩余人数:' + single.syrs)
|
||||
lastSyrs = parseInt(single.syrs)
|
||||
} else {
|
||||
if (lastSyrs != parseInt(single.syrs)) {
|
||||
logAndNotifyUser('[monit]' + single.kcmc + ' 新剩余人数:' + single.syrs + ' at ' + getTimeNow())
|
||||
lastSyrs = parseInt(single.syrs)
|
||||
}
|
||||
}
|
||||
}
|
||||
await sleep(50)
|
||||
}
|
||||
}
|
||||
|
||||
export async function acquireProcess(course: ICourse) {
|
||||
while (true) {
|
||||
let single = findJsonCourse(course)
|
||||
if (single == undefined) {
|
||||
console.log('[acquire]无法找到课程 ' + course.kch + ' on channel ' + course.channel)
|
||||
} else {
|
||||
if (parseInt(single.syrs) > 0) {
|
||||
logAndNotifyUser('[acquire]发现 ' + single.kcmc + ' 剩余人数为' + single.syrs + ',进行抢课 at ' + getTimeNow())
|
||||
if (await acquireCourse(single, course.channel)) {
|
||||
logAndNotifyUser('[acquire]抢课成功 ' + single.kcmc + ' at ' + getTimeNow())
|
||||
return
|
||||
} else {
|
||||
logAndNotifyUser('[acquire]抢课失败 ' + single.kcmc + ' at ' + getTimeNow())
|
||||
}
|
||||
}
|
||||
}
|
||||
await sleep(50)
|
||||
}
|
||||
}
|
||||
|
||||
export async function replaceProcess(courseList: ICourse[], exit: ICourse) {
|
||||
while (true) {
|
||||
let exitJsonCourse = findJsonCourse(exit)
|
||||
if (exitJsonCourse == undefined) {
|
||||
console.log('[replace]找不到需要需要退课的课程 ' + exit.kch + ' on channel ' + exit.channel)
|
||||
} else {
|
||||
for (let course of courseList) {
|
||||
let single = findJsonCourse(course)
|
||||
if (single == undefined) {
|
||||
console.log('[replace]无法找到课程 ' + course.kch + ' on channel ' + course.channel)
|
||||
continue
|
||||
}
|
||||
if (parseInt(single.syrs) > 0) {
|
||||
logAndNotifyUser('[replace]发现 ' + single.kcmc + ' 剩余人数为' + single.syrs + ',进行换课 at ' + getTimeNow())
|
||||
if (!(await exitCourse(exitJsonCourse, exit.channel))) {
|
||||
logAndNotifyUser('[replace]退课 ' + exitJsonCourse.kcmc + ' 失败 at ' + getTimeNow())
|
||||
}
|
||||
if (await acquireCourse(single, course.channel)) {
|
||||
logAndNotifyUser('[replace]换课 ' + single.kcmc + ' 成功 at ' + getTimeNow())
|
||||
return
|
||||
} else {
|
||||
logAndNotifyUser('[replace]选课 ' + single.kcmc + ' 失败,进行回滚 at ' + getTimeNow())
|
||||
if (await acquireCourse(exitJsonCourse, exit.channel)) {
|
||||
logAndNotifyUser('[replace]回滚 ' + single.kcmc + ' 成功 at ' + getTimeNow())
|
||||
} else {
|
||||
logAndNotifyUser('[replace]回滚 ' + single.kcmc + ' 失败 at ' + getTimeNow())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await sleep(50)
|
||||
}
|
||||
}
|
25
src/config.ts
Normal file
25
src/config.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import yaml from "yaml"
|
||||
import * as fs from "fs"
|
||||
import {IAppConfig, TChannel} from "./types"
|
||||
|
||||
let appConfig: IAppConfig = yaml.parse(fs.readFileSync('config.yaml', 'utf-8'))
|
||||
let channels: TChannel[] = []
|
||||
for (let course of appConfig.monit?.list || []) {
|
||||
if (!channels.includes(course.channel)) {
|
||||
channels.push(course.channel)
|
||||
}
|
||||
}
|
||||
for (let course of appConfig.acquire?.list || []) {
|
||||
if (!channels.includes(course.channel)) {
|
||||
channels.push(course.channel)
|
||||
}
|
||||
}
|
||||
if (appConfig.replace) {
|
||||
for (let course of appConfig.replace.list) {
|
||||
if (!channels.includes(course.channel)) {
|
||||
channels.push(course.channel)
|
||||
}
|
||||
}
|
||||
}
|
||||
appConfig.channels = channels
|
||||
export {appConfig}
|
66
src/includes.ts
Normal file
66
src/includes.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import axios from 'axios'
|
||||
import {appConfig} from "./config"
|
||||
import * as qs from "qs"
|
||||
import dayjs from "dayjs"
|
||||
import {ICourse, IJsonCourse, TChannel} from "./types"
|
||||
import {JsonCourseList} from "./poll"
|
||||
import axiosRetry from "axios-retry"
|
||||
|
||||
let sduAxios = axios.create({
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'Cookie': appConfig.cookie
|
||||
},
|
||||
baseURL: 'https://bkzhjx.wh.sdu.edu.cn/',
|
||||
timeout: 5,
|
||||
// maxRedirects: 0
|
||||
})
|
||||
|
||||
axiosRetry(sduAxios, {
|
||||
retries: 2,
|
||||
shouldResetTimeout: true,
|
||||
retryCondition: (_error) => true,
|
||||
})
|
||||
|
||||
export async function logAndNotifyUser(text: string) {
|
||||
console.log(text)
|
||||
await axios.post('https://qmsg.zendee.cn/send/' + appConfig.qmsgKey, qs.stringify({
|
||||
msg: text
|
||||
}), {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
export function getTimeNow() {
|
||||
return dayjs().format('hh:mm:ss A')
|
||||
}
|
||||
|
||||
export function findJsonCourse(course: ICourse): IJsonCourse | undefined {
|
||||
return JsonCourseList[course.channel].find(single => single.kch == course.kch && parseInt(single.kxh) == course.kxh)
|
||||
}
|
||||
|
||||
export async function acquireCourse(course: IJsonCourse, channel: TChannel): Promise<boolean> {
|
||||
if (channel == 'bx' || channel == 'xx') {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export async function exitCourse(course: IJsonCourse, channel: TChannel): Promise<boolean> {
|
||||
if (channel == 'bx' || channel == 'xx') {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export {sduAxios}
|
35
src/index.ts
Normal file
35
src/index.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import {JsonCourseList, poll} from "./poll"
|
||||
import {appConfig} from "./config"
|
||||
import {acquireProcess, monitProcess, replaceProcess} from "./actions"
|
||||
import {sleep} from "./includes"
|
||||
|
||||
async function start() {
|
||||
console.log('开始启动轮询进程')
|
||||
poll()
|
||||
while (true) {
|
||||
let pollInitComplete = true
|
||||
for (let channel of appConfig.channels) {
|
||||
if (JsonCourseList[channel].length == 0) {
|
||||
pollInitComplete = false
|
||||
}
|
||||
}
|
||||
if (pollInitComplete) {
|
||||
break
|
||||
}
|
||||
await sleep(50)
|
||||
}
|
||||
console.log('轮询进程启动完毕')
|
||||
console.log('开始启动用户进程')
|
||||
for (let course of appConfig.monit?.list || []) {
|
||||
monitProcess(course)
|
||||
}
|
||||
for (let course of appConfig.acquire?.list || []) {
|
||||
acquireProcess(course)
|
||||
}
|
||||
if (appConfig.replace) {
|
||||
replaceProcess(appConfig.replace.list, appConfig.replace.exit)
|
||||
}
|
||||
console.log('用户进程启动完毕')
|
||||
}
|
||||
|
||||
start()
|
79
src/poll.ts
Normal file
79
src/poll.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import {IJsonCourse} from "./types"
|
||||
import {getTimeNow, sduAxios, sleep} from "./includes"
|
||||
import {appConfig} from "./config"
|
||||
import * as qs from "qs"
|
||||
|
||||
let reqData = [
|
||||
{"name": "sEcho", "value": "1"},
|
||||
{"name": "iColumns", "value": "2000"},// 1
|
||||
{"name": "sColumns", "value": ""},
|
||||
{"name": "iDisplayStart", "value": "0"},
|
||||
{"name": "iDisplayLength", "value": "2000"},// 1
|
||||
{"name": "mDataProp_0", "value": "kch"},
|
||||
{"name": "mDataProp_1", "value": "kcmc"},
|
||||
{"name": "mDataProp_2", "value": "kxhnew"},
|
||||
{"name": "mDataProp_3", "value": "jkfs"},
|
||||
{"name": "mDataProp_4", "value": "xmmc"},
|
||||
{"name": "mDataProp_5", "value": "xf"},
|
||||
{"name": "mDataProp_6", "value": "skls"},
|
||||
{"name": "mDataProp_7", "value": "sksj"},
|
||||
{"name": "mDataProp_8", "value": "skdd"},
|
||||
{"name": "mDataProp_9", "value": "xqmc"},
|
||||
{"name": "mDataProp_10", "value": "xkrs"},
|
||||
{"name": "mDataProp_11", "value": "syrs"},
|
||||
{"name": "mDataProp_12", "value": "ctsm"},
|
||||
{"name": "mDataProp_13", "value": "szkcflmc"},
|
||||
{"name": "mDataProp_14", "value": "czOper"}
|
||||
]
|
||||
export const JsonCourseList = <{ bx: IJsonCourse[], xx: IJsonCourse[], rx: IJsonCourse[] }>{
|
||||
bx: [],
|
||||
xx: [],
|
||||
rx: []
|
||||
}
|
||||
|
||||
async function updateBx() {
|
||||
try {
|
||||
let resp = await sduAxios.post('/jsxsd/xsxkkc/xsxkBxxk?1=1&kcxx=&skls=&skfs=', qs.stringify(reqData))
|
||||
JsonCourseList.bx.length = 0
|
||||
JsonCourseList.bx.push(...resp.data.aaData)
|
||||
console.log('更新必修JsonList成功')
|
||||
} catch (e) {
|
||||
console.log('获取必修JsonList失败 at ' + getTimeNow())
|
||||
}
|
||||
}
|
||||
|
||||
async function updateXx() {
|
||||
try {
|
||||
let resp = await sduAxios.post('/jsxsd/xsxkkc/xsxkXxxk?1=1&kcxx=&skls=&skfs=', qs.stringify(reqData))
|
||||
JsonCourseList.xx.length = 0
|
||||
JsonCourseList.xx.push(...resp.data.aaData)
|
||||
} catch (e) {
|
||||
console.log('获取限选JsonList失败 at ' + getTimeNow())
|
||||
}
|
||||
}
|
||||
|
||||
async function updateRx() {
|
||||
try {
|
||||
let resp = await sduAxios.post('/jsxsd/xsxkkc/xsxkGgxxkxk?kcxx=&skls=&skxq=&skjc=&sfym=false&sfct=false&szjylb=&sfxx=false&skfs=', qs.stringify(reqData))
|
||||
JsonCourseList.rx.length = 0
|
||||
JsonCourseList.rx.push(...resp.data.aaData)
|
||||
} catch (e) {
|
||||
console.log('获取任选JsonList失败 at ' + getTimeNow())
|
||||
}
|
||||
}
|
||||
|
||||
export async function poll() {
|
||||
if (appConfig.channels.includes('bx')) {
|
||||
await updateBx()
|
||||
await sleep(appConfig.interval)
|
||||
}
|
||||
if (appConfig.channels.includes('xx')) {
|
||||
await updateXx()
|
||||
await sleep(appConfig.interval)
|
||||
}
|
||||
if (appConfig.channels.includes('rx')) {
|
||||
await updateRx()
|
||||
await sleep(appConfig.interval)
|
||||
}
|
||||
setImmediate(poll)
|
||||
}
|
15
src/test.ts
Normal file
15
src/test.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {appConfig} from "./config"
|
||||
|
||||
console.log('channels: ' + appConfig.channels)
|
||||
for (let course of appConfig.monit?.list || []) {
|
||||
console.log('添加监控课程 ' + course.kch + ' on channel ' + course.channel)
|
||||
}
|
||||
for (let course of appConfig.acquire?.list || []) {
|
||||
console.log('添加抢课课程 ' + course.kch + ' on channel ' + course.channel)
|
||||
}
|
||||
if (appConfig.replace) {
|
||||
console.log('添加退课课程 ' + appConfig.replace.exit.kch + ' on channel ' + appConfig.replace.exit.channel)
|
||||
for (let course of appConfig.replace.list) {
|
||||
console.log('添加换课课程 ' + course.kch + ' on channel ' + course.channel)
|
||||
}
|
||||
}
|
91
src/types.ts
Normal file
91
src/types.ts
Normal file
@ -0,0 +1,91 @@
|
||||
export type TChannel = 'bx' | 'xx' | 'rx'
|
||||
|
||||
export interface ICourse {
|
||||
kch: string,
|
||||
kxh: number,
|
||||
channel: TChannel
|
||||
}
|
||||
|
||||
export interface IAppConfig {
|
||||
cookie: string,
|
||||
qmsgKey: string,
|
||||
interval: number,
|
||||
channels: TChannel[],
|
||||
monit?: {
|
||||
list: ICourse[]
|
||||
},
|
||||
acquire?: {
|
||||
list: ICourse[]
|
||||
},
|
||||
replace?: {
|
||||
list: ICourse[],
|
||||
exit: ICourse
|
||||
}
|
||||
}
|
||||
|
||||
export interface IJsonCourse {
|
||||
parentjx0404id: null;
|
||||
mfkc: string;
|
||||
ksfs: string;
|
||||
jx02kcmkid: null;
|
||||
ktmc: string;
|
||||
tzdlb: string;
|
||||
kcsx: string;
|
||||
skfs: string;
|
||||
kch: string;
|
||||
syrs: string;
|
||||
kxh: string;
|
||||
sksj: string;
|
||||
szkcfl: string;
|
||||
kcjj: null;
|
||||
skfsmc: string;
|
||||
wlpt: null;
|
||||
kcxzmc: string;
|
||||
kexuhao: null;
|
||||
xbyq: null;
|
||||
sftk: null;
|
||||
kkdw: string;
|
||||
kcxzm: string;
|
||||
szkcflmc: string;
|
||||
xnxq01id: string;
|
||||
dwmc: string;
|
||||
kxhnew: string;
|
||||
pkrs: number;
|
||||
xkrs: number;
|
||||
fzmc: null;
|
||||
cfbs: null;
|
||||
kcmc: string;
|
||||
xyxsnj: null;
|
||||
kkapList: KkapList[];
|
||||
dyrsbl: null;
|
||||
isnetworkcourse: string;
|
||||
sklsid: string;
|
||||
skls: string;
|
||||
xqid: string;
|
||||
sfkfxk: string;
|
||||
skdd: string;
|
||||
xf: number;
|
||||
skdws: null;
|
||||
txsfkxq: string;
|
||||
xmmc: null;
|
||||
zxs: number;
|
||||
jx0404id: string;
|
||||
xqmc: string;
|
||||
jx02id: string;
|
||||
xbyqmc: null;
|
||||
jkfs: null;
|
||||
}
|
||||
|
||||
export interface KkapList {
|
||||
jssj: string;
|
||||
jzwmc: string;
|
||||
jgxm: string;
|
||||
skjcmc: string;
|
||||
skzcList: string[];
|
||||
xq: string;
|
||||
kbjcmsid: string;
|
||||
kkzc: string;
|
||||
kssj: string;
|
||||
jsmc: string;
|
||||
kkdlb: string;
|
||||
}
|
86
tsconfig.json
Normal file
86
tsconfig.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "ES2016",
|
||||
/* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "commonjs",
|
||||
/* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
"allowJs": true,
|
||||
/* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "./build",
|
||||
/* Redirect output structure to the directory. */
|
||||
"rootDir": "./src",
|
||||
/* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true,
|
||||
/* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
"typeRoots": [
|
||||
// "./node_modules/**/*",
|
||||
"./node_modules/@types"
|
||||
],
|
||||
/* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true,
|
||||
/* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
"experimentalDecorators": true,
|
||||
/* Enables experimental support for ES7 decorators. */
|
||||
"emitDecoratorMetadata": true,
|
||||
/* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true,
|
||||
/* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true
|
||||
/* Disallow inconsistently-cased references to the same file. */
|
||||
}
|
||||
}
|
載入中…
x
新增問題並參考
Block a user