UNPKG

clsregister

Version:

通过配置来生成符合“姓氏命名法”的className对象

196 lines (167 loc) 5.66 kB
const fs = require('fs'); const camelcase = require('camelcase'); const {compose, resolveSrc} = require('./utils'); const defaultConfig = require(resolveSrc('clsregister.config.js')); const {namespace, className, middlewares} = defaultConfig; class ClsContext { constructor(path, fileName, handler) { this.path = path this.fileName = fileName this.handler = handler this.classNames = [] } getClassNames = () => { return [...this.classNames] } /** * 读取filePath中的写入路径,并写入对应目录 */ writeFile = (data) => { if (typeof data !== 'string') { throw new Error(`写入${this.fileName}文件错误!writeFile函数只接受string属性`); } const fileName = this.fileName const fullPath = resolveSrc(`${this.path}/${fileName}`); fs.writeFile(fullPath, data, {encoding: 'utf8'}, err => { if (err) throw err; console.log(`${fileName} file generated successfully`); }); }; addClassName = (className) => { this.classNames.push(className) } } class ClsBuilder { constructor(namespace, className) { this.namespace = namespace; this.className = className; // 格式化以後的className this.formatedCls = []; this.middlewares = []; this.handler = new Map(); // [[filename],[path]] this.formatConfig(); } use(newMiddleware) { if (typeof newMiddleware !== 'function') throw new TypeError('middleware must be a function!'); this.middlewares.push(newMiddleware); } formatConfig() { // cls集合,通过二维数组表示[[key,value]] const clsCollection = []; // 所有类名的集合,防止出现重复情况 const clsPool = []; // 所有类名key的集合,防止出现重复情况 const clsKeyPool = []; function clsInjection(key, value) { clsPool.push(value); clsKeyPool.push(key); clsCollection.push([key, value]); } // 通过区分scoped生成key值, const createClsKey = (scoped, key, parentsKey) => { return scoped ? camelcase(`${parentsKey}-${key}`) : key; }; // 生成className const createCls = (key, parentsCls) => { return `${parentsCls}-${key}`; }; // 将children转换为能够解析的对象 const handleClsChildren = (clsInfo, {parentsKey, parentsCls}, scoped) => { const temp = {}; clsInfo.forEach(v => { temp[v] = {}; // 存在scoped时增加私有属性 if (scoped) { temp[v]._scoped_ = scoped; } }); handleItem(temp, {parentsKey, parentsCls}); }; const handleItem = (cls, {parentsKey, parentsCls}) => { for (const key in cls) { if (key === '_scoped_') { continue; } if (key === '_children_') { handleClsChildren(cls[key], {parentsKey, parentsCls}); continue; } if (key === '_scopedChildren_') { handleClsChildren(cls[key], {parentsKey, parentsCls}, true); continue; } const _key = createClsKey(cls[key]._scoped_, key, parentsKey); const _cls = createCls(key, parentsCls); // 判断新key是否已存在 if (clsKeyPool.includes(_key)) { throw new Error(`${_key}(生成自${key}) 已存在。`); } // 判断新value是否已存在 if (clsPool.includes(cls[key])) { throw new Error(`${cls[key]} 已存在。`); } // 将生成好的cls注入到集合中 clsInjection(_key, _cls); handleItem(cls[key], {parentsKey: _key, parentsCls: _cls}); } }; handleItem(this.className, {parentsCls: this.namespace}); this.formatedCls = clsCollection; } midRegister = (path, fileName, handler) => { if (!path) { throw new Error(`未接收到path参数`); } if (!fileName) { throw new Error(`未接收到fileName参数`); } if (!handler) { throw new Error(`未接收到handler参数`); } if (this.handler.has(fileName)) { throw new Error(`处理${fileName}文件的handler已存在!`); } const ctx = new ClsContext(path, fileName, handler) this.handler.set(fileName, ctx); return ctx }; // 核心中间件,负责通过注册的handler处理formatedCls coreMiddlewares = (ctx, next) => { if (!ctx) return next(); this.formatedCls.forEach((([key, value]) => { // 取出已注册的handler,每次遍历时,执行所有handler for (const mapKey of this.handler.keys()) { // 从当前注册的handler取出当前触发的 const currentHandler = this.handler.get(mapKey); // 通过中间件注册的handler来处理每一项数据 const singleClassName = currentHandler.handler(key, value); // 如果处理失败,则抛错 if (typeof singleClassName !== 'string') { throw new Error(`${currentHandler.fileName}的handler应该返回‘string’类型,但是却返回了${typeof singleClassName}`); } currentHandler.addClassName(singleClassName); } })); next(); }; output = () => { const fn = compose([ ...this.middlewares, this.coreMiddlewares, ]); return fn({ register: this.midRegister, }); }; } const cls = new ClsBuilder(namespace, className); middlewares.forEach(fn => { cls.use(fn); }); module.exports = { run: cls.output, }