import exportJson from '../routers/utils/exportJson' import genId from '../utils/getId' import fs from 'fs-extra' import path from 'path' interface RawField { label: string, type: string } interface Field extends RawField { spaceId: string } interface NamespaceValue { [key: string]: Field } export interface Namespace { spaceId: string, value: NamespaceValue, spacename: string, set: (key: string, f: RawField) => boolean, delete: (key: string) => boolean, add: (key: string, f: RawField) => boolean, has: (key: string) => boolean, [Symbol.iterator]: () => any, } export interface NamespaceContainer { root: string, value: {[namespace: string]: Namespace} has: (spaceId: string) => boolean, create: (spaceId: string) => string, get: (spaceId: string) => Namespace | undefined delete: (spaceId: string) => boolean, refresh: () => void // 刷新当前namespace addField: (spaceId: string, field: Field) => string | false, setField: (spaceId: string, fieldId: string, field: Field) => boolean, deleteField: (spaceId: string, fieldId: string) => boolean, updateFile: (spaceId: string) => void } export class LegoNamespaceContainer implements NamespaceContainer { public value: {[spaceId: string]: Namespace} = {} constructor( public root: string ) { this.refresh() } get namespaceList() { return Object.keys(this.value) || [] } get(spaceId: string): Namespace | undefined { return this.value[spaceId] } has(spaceId: string): boolean { return !!this.value[spaceId] } create(spacename: string): string { const spaceId = genId() if (this.has(spaceId)) { return '' } this.value[spaceId] = new LegoNamespace(spaceId, spacename, {}) this.updateFile(spaceId) return spaceId } delete(spaceId: string): boolean { if (!this.has(spaceId)) { return false } fs.unlinkSync(path.resolve(this.root, `${spaceId}.js`)) this.refresh() return true } refresh() { this.value = {} const files = fs.readdirSync(this.root) files.forEach((file: string) => { const spaceId = file.substr(0, file.length - 3) this.value[spaceId] = new LegoNamespace(spaceId, require(path.resolve(this.root, file))) }) } addField(spaceId: string, field: RawField): string | false { const fieldId = genId() if (this.value[spaceId].add(fieldId, field)) { this.updateFile(spaceId) return fieldId } return false } setField(spaceId: string, fieldId: string, field: RawField) { if (this.value[spaceId].set(fieldId, field)) { this.updateFile(spaceId) return true } return false } deleteField(spaceId: string, fieldId: string) { if (this.value[spaceId].delete(fieldId)) { this.updateFile(spaceId) return true } return false } updateFile(spaceId: string) { const filePath = path.resolve(this.root, `${spaceId}.js`) fs.ensureFileSync(filePath) fs.writeFileSync(filePath, exportJson({ fields: this.value[spaceId].value, spaceId: spaceId, spacename: this.value[spaceId].spacename })) } } export class LegoNamespace implements Namespace { constructor( public spaceId: string, public spacename: string, public value: NamespaceValue = {} ){} public get listValue(): ({fieldId: string} & Field)[] { const listValue: ({fieldId: string} & Field)[] = [] for (let fieldId in this.value) { listValue.push({ fieldId, ...this.value[fieldId] }) } return listValue } private ensureField(field: RawField): Field { return { ...field, spaceId: this.spaceId } } // 设置 public set(fieldId: string, field: RawField): boolean { if (this.has(fieldId)) { this.value[fieldId] = this.ensureField(field) return true } return false } public delete(fieldId: string): boolean { if (this.has(fieldId)) { delete this.value[fieldId] return true } return false } public add(fieldId: string, field: Field): boolean { if (this.has(fieldId)) { return false } this.value[fieldId] = this.ensureField(field) return true } public has(fieldId: string): boolean { return !!this.value[fieldId] } public [Symbol.iterator] = () => { const entries = Object.entries(this.value) let index = 0 return { next: function() { if (index === entries.length) { return {done: true} } const entry = entries[index++] return { value: { key: entry[0], ...entry[1] }, done: false } } } } }