mirror of
https://github.com/VickScarlet/lifeRestart.git
synced 2026-08-30 02:24:42 +08:00
update: ts
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import { expect, test, describe } from 'bun:test'
|
||||
import { checkCondition } from '.'
|
||||
|
||||
// 定义属性 mock 字典的类型契约
|
||||
interface MockProperties {
|
||||
[key: string]: number | number[]
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性注入高阶函数:模拟角色属性管理类
|
||||
*/
|
||||
function withProp(prop: MockProperties) {
|
||||
const p = {
|
||||
get(key: string): any {
|
||||
return prop[key]
|
||||
},
|
||||
}
|
||||
return (condition: string): boolean => checkCondition(p, condition)
|
||||
}
|
||||
|
||||
describe('condition', () => {
|
||||
// 实例化一个带满各种脏数据(数字、数组、空数组)的强类型测试代理
|
||||
const check = withProp({
|
||||
n1: 0,
|
||||
n2: -10,
|
||||
n3: 10,
|
||||
nl1: [1, 2, 3],
|
||||
nl2: [0],
|
||||
nl3: [],
|
||||
})
|
||||
|
||||
test('gt(>)', () => {
|
||||
expect(check('n3>11')).toBe(false)
|
||||
expect(check('n3>10')).toBe(false)
|
||||
expect(check('n3>9')).toBe(true)
|
||||
})
|
||||
|
||||
test('gte(>=)', () => {
|
||||
expect(check('n3>=11')).toBe(false)
|
||||
expect(check('n3>=10')).toBe(true)
|
||||
expect(check('n3>=9')).toBe(true)
|
||||
})
|
||||
|
||||
test('lt(<)', () => {
|
||||
expect(check('n3<9')).toBe(false)
|
||||
expect(check('n3<10')).toBe(false)
|
||||
expect(check('n3<11')).toBe(true)
|
||||
})
|
||||
|
||||
test('lte(<=)', () => {
|
||||
expect(check('n3<=9')).toBe(false)
|
||||
expect(check('n3<=10')).toBe(true)
|
||||
expect(check('n3<=11')).toBe(true)
|
||||
})
|
||||
|
||||
test('eq(=)', () => {
|
||||
expect(check('n3=9')).toBe(false)
|
||||
expect(check('n3=10')).toBe(true)
|
||||
expect(check('n3=11')).toBe(false)
|
||||
expect(check('nl1=0')).toBe(false)
|
||||
expect(check('nl1=1')).toBe(true)
|
||||
expect(check('nl1=2')).toBe(true)
|
||||
expect(check('nl1=3')).toBe(true)
|
||||
})
|
||||
|
||||
test('ne(!=)', () => {
|
||||
expect(check('n3!=9')).toBe(true)
|
||||
expect(check('n3!=10')).toBe(false)
|
||||
expect(check('n3!=11')).toBe(true)
|
||||
expect(check('nl1!=0')).toBe(true)
|
||||
expect(check('nl1!=1')).toBe(false)
|
||||
expect(check('nl1!=2')).toBe(false)
|
||||
expect(check('nl1!=3')).toBe(false)
|
||||
})
|
||||
|
||||
test('in(?)', () => {
|
||||
expect(check('n3?[1,2,3]')).toBe(false)
|
||||
expect(check('n3?[10,11,12]')).toBe(true)
|
||||
expect(check('nl1?[0,1]')).toBe(true)
|
||||
expect(check('nl2?[1,2,3]')).toBe(false)
|
||||
expect(check('nl3?[1,2,3]')).toBe(false)
|
||||
expect(check('nl2?[]')).toBe(false)
|
||||
expect(check('nl3?[]')).toBe(false)
|
||||
})
|
||||
|
||||
test('notin(!)', () => {
|
||||
expect(check('n3![1,2,3]')).toBe(true)
|
||||
expect(check('n3![10,11,12]')).toBe(false)
|
||||
expect(check('nl1![0,1]')).toBe(false)
|
||||
expect(check('nl2![1,2,3]')).toBe(true)
|
||||
expect(check('nl3![1,2,3]')).toBe(true)
|
||||
expect(check('nl2![]')).toBe(true)
|
||||
expect(check('nl3![]')).toBe(true)
|
||||
})
|
||||
|
||||
test('and(&)', () => {
|
||||
expect(check('n1>=0&n2<0')).toBe(true)
|
||||
expect(check('n2>0&n3>0')).toBe(false)
|
||||
expect(check('n2<0&n3<0')).toBe(false)
|
||||
expect(check('n2<0&n3>0')).toBe(true)
|
||||
expect(check('n1=0&n2<0&n3>0')).toBe(true)
|
||||
expect(check('n1=0&n2>0&n3>0')).toBe(false)
|
||||
})
|
||||
|
||||
test('or(|)', () => {
|
||||
expect(check('n1>=0|n2<0')).toBe(true)
|
||||
expect(check('n2>0|n3>0')).toBe(true)
|
||||
expect(check('n2<0|n3<0')).toBe(true)
|
||||
expect(check('n2<0|n3>0')).toBe(true)
|
||||
expect(check('n2>0|n3<0')).toBe(false)
|
||||
expect(check('n1=0|n2<0|n3>0')).toBe(true)
|
||||
expect(check('n1=0|n2>0|n3>0')).toBe(true)
|
||||
expect(check('n1!=0|n2>0|n3<0')).toBe(false)
|
||||
})
|
||||
|
||||
test('mix', () => {
|
||||
expect(check('(n1=0|n2<0|n3>0)&(n1=0|n2>0|n3>0)')).toBe(true)
|
||||
expect(check('(n1=0|n2<0|n3>0)&(n1!=0|n2>0|n3<0)')).toBe(false)
|
||||
expect(check('n1=0|n2<0|n3>0&n1!=0|n2>0|n3<0')).toBe(true)
|
||||
expect(check('(n1>0|n1?[-10,0])&(n2>0|n3![0,1])')).toBe(true)
|
||||
expect(check('(n1>0&n1?[-10,0])|(n2<0&n3![0,1])')).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,202 @@
|
||||
// 条件节点可以是一个纯字符串表达式(如 'AGE>18'),或者是一个无限嵌套自身的数组
|
||||
export type ConditionNode = string | ConditionTree
|
||||
export interface ConditionTree extends Array<ConditionNode> {}
|
||||
|
||||
// 🌟 核心类型定义 2:定义满足有 .get 提取器属性的游戏对象约束(如玩家属性管理类或原生 Map)
|
||||
export interface PropertyContainer {
|
||||
get(key: string): any
|
||||
}
|
||||
|
||||
/**
|
||||
* 词法解析器:将条件字符串切分为多维嵌套的语法树树(AST)
|
||||
* @param condition 原始字符串表达式,例如 "AGE > 10 & (SEX = 1 | CHR >= 5)"
|
||||
*/
|
||||
function parseCondition(condition: string): ConditionTree {
|
||||
const conditions: ConditionTree = []
|
||||
const length = condition.length
|
||||
const stack: ConditionTree[] = []
|
||||
stack.unshift(conditions)
|
||||
let cursor = 0
|
||||
|
||||
const catchString = (i: number): void => {
|
||||
const str = condition.substring(cursor, i).trim()
|
||||
cursor = i
|
||||
if (str) {
|
||||
stack[0]?.push(str)
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
switch (condition[i]) {
|
||||
case ' ':
|
||||
continue
|
||||
|
||||
case '(': {
|
||||
catchString(i)
|
||||
cursor++
|
||||
const sub: ConditionTree = []
|
||||
stack[0]?.push(sub)
|
||||
stack.unshift(sub)
|
||||
break
|
||||
}
|
||||
case ')':
|
||||
catchString(i)
|
||||
cursor++
|
||||
stack.shift()
|
||||
break
|
||||
|
||||
case '|':
|
||||
case '&':
|
||||
catchString(i)
|
||||
catchString(i + 1)
|
||||
break
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
catchString(length)
|
||||
return conditions
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部核心接口:判定某个角色的属性是否完美符合该文本条件限制
|
||||
* @param property 玩家或局内属性提取器
|
||||
* @param condition 原始条件表达式
|
||||
*/
|
||||
export function checkCondition(
|
||||
property: PropertyContainer,
|
||||
condition: string,
|
||||
): boolean {
|
||||
const conditions = parseCondition(condition)
|
||||
return checkParsedConditions(property, conditions)
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归计算已解析出来的多维语法树结果
|
||||
*/
|
||||
function checkParsedConditions(
|
||||
property: PropertyContainer,
|
||||
conditions: ConditionNode,
|
||||
): boolean {
|
||||
// 如果已经剥离到了最底层的纯字符串表达式(如 'AGE>10'),直接移交核心原子判定器
|
||||
if (!Array.isArray(conditions)) {
|
||||
return checkProp(property, conditions)
|
||||
}
|
||||
|
||||
if (conditions.length === 0) return true
|
||||
if (conditions.length === 1) {
|
||||
return checkParsedConditions(property, conditions[0]!)
|
||||
}
|
||||
|
||||
let ret = checkParsedConditions(property, conditions[0]!)
|
||||
for (let i = 1; i < conditions.length; i += 2) {
|
||||
const operator = conditions[i]
|
||||
const nextNode = conditions[i + 1]
|
||||
|
||||
// 防御性拦截,防止表达式残缺或配置错误引发崩溃
|
||||
if (nextNode === undefined) return false
|
||||
|
||||
switch (operator) {
|
||||
case '&':
|
||||
if (ret) {
|
||||
ret = checkParsedConditions(property, nextNode)
|
||||
}
|
||||
break
|
||||
case '|':
|
||||
if (ret) return true
|
||||
ret = checkParsedConditions(property, nextNode)
|
||||
break
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* 原子逻辑判定器:负责处理诸如 '>', '<', '=', '?', '!' 各种操作符的最终生死判定
|
||||
*/
|
||||
function checkProp(property: PropertyContainer, condition: string): boolean {
|
||||
const length = condition.length
|
||||
let i = condition.search(/[><!?=]/)
|
||||
|
||||
// 防御处理:如果没有找到任何操作符,视为非法表达式直接拒签
|
||||
if (i === -1) return false
|
||||
|
||||
const prop = condition.substring(0, i)
|
||||
// 判断是否是双字符操作符(如 >=, <=, !=),若是则向前多吞一个字符位
|
||||
const isDoubleSymbol = condition[i + 1] === '='
|
||||
const symbol = condition.substring(i, (i += isDoubleSymbol ? 2 : 1))
|
||||
const d = condition.substring(i, length)
|
||||
|
||||
const propData = property.get(prop)
|
||||
const conditionData: number | any[] =
|
||||
d[0] === '[' ? JSON.parse(d) : Number(d)
|
||||
|
||||
switch (symbol) {
|
||||
case '>':
|
||||
return propData > conditionData
|
||||
case '<':
|
||||
return propData < conditionData
|
||||
case '>=':
|
||||
return propData >= conditionData
|
||||
case '<=':
|
||||
return propData <= conditionData
|
||||
case '=':
|
||||
if (Array.isArray(propData)) {
|
||||
return propData.includes(conditionData)
|
||||
}
|
||||
return propData == conditionData
|
||||
case '!=':
|
||||
if (Array.isArray(propData)) {
|
||||
return !propData.includes(conditionData)
|
||||
}
|
||||
return propData != conditionData
|
||||
|
||||
case '?': // 🌟 包含判定符(如 属性值 是否在 [1,2,3] 数组范围内)
|
||||
if (Array.isArray(propData)) {
|
||||
if (Array.isArray(conditionData)) {
|
||||
for (const p of propData) {
|
||||
if (conditionData.includes(p)) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
if (Array.isArray(conditionData)) {
|
||||
return conditionData.includes(propData)
|
||||
}
|
||||
return false
|
||||
|
||||
case '!': // 🌟 排除判定符(如 属性值 是否不存在于 [1,2,3] 数组中)
|
||||
if (Array.isArray(propData)) {
|
||||
if (Array.isArray(conditionData)) {
|
||||
for (const p of propData) {
|
||||
if (conditionData.includes(p)) return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
if (Array.isArray(conditionData)) {
|
||||
return !conditionData.includes(propData)
|
||||
}
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function extractMaxTriggers(condition: string): number {
|
||||
// Assuming only age related talents can be triggered multiple times.
|
||||
const RE_AGE_CONDITION = /AGE\?\[([0-9,]+)\]/
|
||||
const matchObject = RE_AGE_CONDITION.exec(condition)
|
||||
|
||||
if (matchObject === null) {
|
||||
// Not age related, single trigger.
|
||||
return 1
|
||||
}
|
||||
|
||||
return matchObject[1]?.split(',')?.length ?? 1
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@remake/condition",
|
||||
"type": "module",
|
||||
"version": "3.0.0",
|
||||
"main": "./index.ts",
|
||||
"author": "Vick Scarlet <vick@syaro.io>",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"test": "bun test"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "../../package.json"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"types": ["bun"],
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["**/*"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@remake/core",
|
||||
"type": "module",
|
||||
"version": "3.0.0",
|
||||
"author": "Vick Scarlet <vick@syaro.io>",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"test": "bun test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@remake/condition": "workspace:*",
|
||||
"@remake/data": "workspace:*"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "../../package.json"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import { age } from '@remake/data/age'
|
||||
import { checkCondition } from '@remake/condition'
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"types": ["bun"],
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
},
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["**/*"]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dist
|
||||
node_modules
|
||||
~$*.xlsx
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "@remake/data",
|
||||
"type": "module",
|
||||
"version": "3.0.0",
|
||||
"main": "src/index.ts",
|
||||
"author": "Vick Scarlet <vick@syaro.io>",
|
||||
"scripts": {
|
||||
"build": "bunx --bun v-transform@3.0.0 transform -t ts -w src -d dist \"**/[!~$]*.xlsx\" ",
|
||||
"lint": "eslint .",
|
||||
"test": "bun test"
|
||||
},
|
||||
"exports": {
|
||||
"./*": {
|
||||
"types": "./dist/*.ts",
|
||||
"import": "./dist/*.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
export type Grade = 0 | 1 | 2 | 3
|
||||
export type Opportunity =
|
||||
| 'START' // 分配完成点数,点击开始新人生后
|
||||
| 'TRAJECTORY' // 每一年的人生经历中
|
||||
| 'SUMMARY' // 人生结束,点击人生总结后
|
||||
| 'END' // 游戏完成,点击重开 重开次数在这之后才会+1
|
||||
export type Achievement = {
|
||||
/** 序号 */
|
||||
readonly id: number
|
||||
/** 成就名 */
|
||||
readonly name: string
|
||||
/** 成就文案 */
|
||||
readonly description: string
|
||||
/** 稀有度 */
|
||||
readonly grade: Grade
|
||||
/** 触发条件 */
|
||||
readonly condition: string
|
||||
/** 是否隐藏成就 */
|
||||
readonly hide: boolean
|
||||
/** 触发时机 */
|
||||
readonly opportunity: Opportunity
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
export type EventWithWeight = [number, number]
|
||||
export type Age = {
|
||||
/** 年龄 */
|
||||
readonly age: number
|
||||
/** 事件列表 */
|
||||
readonly event: EventWithWeight[]
|
||||
}
|
||||
// @vt-types-end
|
||||
|
||||
export const transformers = {
|
||||
event: (val: any) => {
|
||||
if (val === null || val === undefined)
|
||||
throw new Error(`Invalid event value: ${val}`)
|
||||
if (Array.isArray(val))
|
||||
return val.map(v => {
|
||||
switch (typeof v) {
|
||||
case 'number':
|
||||
return [v, 1]
|
||||
case 'string':
|
||||
const [event, weight] = v.split('*').map(Number)
|
||||
if (event == null || isNaN(event))
|
||||
throw new Error(`Invalid event value: ${v}`)
|
||||
if (weight != null && isNaN(weight))
|
||||
throw new Error(
|
||||
`Invalid weight value: ${v} ${JSON.stringify({ event, weight })}`,
|
||||
)
|
||||
return [event, weight ?? 1]
|
||||
default:
|
||||
throw new Error(`Invalid event value: ${v}`)
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
export type Property = {
|
||||
readonly CHR: number
|
||||
readonly INT: number
|
||||
readonly STR: number
|
||||
readonly MNY: number
|
||||
}
|
||||
export type Character = {
|
||||
/** ID */
|
||||
readonly id: number
|
||||
/** 事件列表 */
|
||||
readonly name: string
|
||||
readonly property: Property
|
||||
readonly talent: number[]
|
||||
}
|
||||
// @vt-types-end
|
||||
|
||||
export const transformers = {
|
||||
id: Number,
|
||||
talent: (val: (string | number)[]) => val.map(Number),
|
||||
property: (val: any) => {
|
||||
if (val === null || val === undefined)
|
||||
throw new Error(`Invalid property value: ${JSON.stringify(val)}`)
|
||||
for (const key of ['CHR', 'INT', 'STR', 'MNY']) {
|
||||
val[key] = Number(val[key])
|
||||
if (isNaN(val[key]))
|
||||
throw new Error(`Invalid property value: ${key}=${val[key]}`)
|
||||
}
|
||||
return val
|
||||
},
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,38 @@
|
||||
export type Grade = 0 | 1 | 2 | 3
|
||||
|
||||
export type Effect = {
|
||||
MNY?: number
|
||||
STR?: number
|
||||
INT?: number
|
||||
CHR?: number
|
||||
SPR?: number
|
||||
LIF?: number
|
||||
}
|
||||
|
||||
export type Event = {
|
||||
/** ID */
|
||||
readonly id: number
|
||||
/** 事件列表 */
|
||||
readonly event: string
|
||||
readonly postEvent?: string
|
||||
readonly grade?: number
|
||||
readonly effect?: Effect
|
||||
readonly branch?: string[]
|
||||
readonly NoRandom?: boolean
|
||||
readonly include?: string
|
||||
readonly exclude?: string
|
||||
}
|
||||
// @vt-types-end
|
||||
|
||||
export const transformers = {
|
||||
id: Number,
|
||||
effect: (val: any) => {
|
||||
if (!val) return
|
||||
for (const key in val) {
|
||||
val[key] = Number(val[key])
|
||||
if (isNaN(val[key]))
|
||||
throw new Error(`Invalid property value: ${key}=${val[key]}`)
|
||||
}
|
||||
return val
|
||||
},
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
export type Group = 1 | 2
|
||||
export type SpecialThanks = {
|
||||
readonly group: Group
|
||||
readonly name: string
|
||||
readonly comment?: string
|
||||
readonly color?: string
|
||||
}
|
||||
// @vt-types-end
|
||||
|
||||
export const transformers = {
|
||||
group: Number,
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
export type Grade = 0 | 1 | 2 | 3
|
||||
|
||||
export type Effect = {
|
||||
MNY?: number
|
||||
STR?: number
|
||||
INT?: number
|
||||
CHR?: number
|
||||
SPR?: number
|
||||
}
|
||||
|
||||
export type Talent = {
|
||||
readonly id: number
|
||||
readonly name: string
|
||||
readonly description: string
|
||||
readonly grade: number
|
||||
readonly effect?: Effect
|
||||
readonly exclude?: number[]
|
||||
}
|
||||
// @vt-types-end
|
||||
|
||||
export const transformers = {
|
||||
id: Number,
|
||||
grade: Number,
|
||||
exclude: (val: (string | number)[] | undefined) => val?.map(Number),
|
||||
effect: (val: any) => {
|
||||
if (!val) return
|
||||
for (const key in val) {
|
||||
val[key] = Number(val[key])
|
||||
if (isNaN(val[key]))
|
||||
throw new Error(`Invalid property value: ${key}=${val[key]}`)
|
||||
}
|
||||
return val
|
||||
},
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"types": ["bun"],
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["**/*"]
|
||||
}
|
||||
Reference in New Issue
Block a user