export default class Topic { public readonly type: 'Indirect' | 'Direct' public path: string private value: string[] = [] private queryKey: string[] = [] constructor(path: string) { this.path = path if (path === undefined) throw new Error('请设定 Path') if (this.isDirect(path)) { this.type = 'Direct' this.value = this.path.split('.') } else if (path.indexOf('*') > -1) { if (path.indexOf('*') !== path.length - 1) throw new Error('* 只能出现在 path 的最后一个位置上,例如 A.B.*') this.type = 'Indirect' this.value = this.path.split('.') } else { let flag = false // 是否出现 query const rawValue = this.path.split('.') this.type = 'Indirect' rawValue.map((v, i) => { if (v[0] === '<') { if (!flag) { flag = true this.value.push('*') } if (v[v.length - 1] !== '>') throw new Error(' <> 必须成对出现,例如 A.B.') this.queryKey.push(v.slice(1, v.length - 1)) } else { if (flag) return new Error(' 必须在所有的非 query 之后, 例如 A.B.. 不能出现 A..B.') this.value.push(v) } }) } } public equal(path: string) :{isEqual: boolean, query: {[key: string]: string}} { if (path === undefined) throw new Error('请设定 Path') if (!this.isDirect(path)) throw new Error('Request 的 path 只能为 Direct 形式,即 A.B.C, 不能出现 与 *, 同时不能为 null') if (this.type === 'Direct' && this.path === path) return { isEqual: true, query: {} } const tmpValue = path.split('.') if (this.type === 'Indirect' && this.value.length <= tmpValue.length) { for (let i = 0; i < this.value.length; i ++) { if (this.value[i] !== '*') { if (this.value[i] !== tmpValue[i]) break } else { const restValue = tmpValue.slice(i) if (this.queryKey.length > restValue.length) break if (restValue.length > 0) { // 如果请求为 A.B.C 监听为 A. 则 query = B.C // 如果请求为 A.B 监听为 A. 则 query = B // 如果请求为 A.B.C.D 监听为 A.. 则 query1 = B, query2 = C.D const query = {} this.queryKey.map((key, i) => { if (i === this.queryKey.length - 1) { query[key] = restValue.join('.') } else { query[key] = restValue[i] } }) return { isEqual: true, query: query } } else { // 有 * 无 query 的情况 return { isEqual: true, query: {} } } } } } return { isEqual: false, query: {} } } private isDirect(path: string): boolean { if (path === null) return false // 排除 'pathA.pathB.*' 情况 if (path.indexOf('*') > -1) return false // 排除 'pathA.' if (path.indexOf('<') > -1 && path.indexOf('>') > -1) return false return true } }