????????開發(fā)中乍炉,經(jīng)常遇到數(shù)據(jù)接口沒有準備好绢片,前端無法進行正常開發(fā)的情況,所以一直有個想法岛琼,想把數(shù)據(jù)模擬的工作變得更簡單底循、易擴展、易讀槐瑞、甚至能從一個已知結(jié)構(gòu)的一條數(shù)據(jù)模擬出多條數(shù)據(jù)此叠。當然這不是一個簡單的工作,但我覺得這是件有意義的事情随珠,至少設計的初衷讓它具備自己的獨特性,不會因為目前已有不少優(yōu)秀的mock數(shù)據(jù)的庫或框架猬错,而讓它變成一件重復造輪子的事情窗看。
????????從易讀性出發(fā),因此對數(shù)據(jù)進行描述性的解讀是個不錯的想法倦炒。我試圖提取一些數(shù)據(jù)通用的屬性显沈,用一些約定的符號來表達。于是便有了以下這些總結(jié):
1. 中括號[a,b]
? ? 可以用來表示范圍逢唤,對于數(shù)字就是數(shù)字的最小值拉讯,最大值;而對于字符串鳖藕,就可以表示為數(shù)字的unicode碼點范圍魔慷。
2. 大括號{a,b}
? ? 可以用來表示長度,對于字符是長度大小著恩,對于數(shù)組院尔,也可表示數(shù)組的長度大小蜻展。
3. 斜杠/a/
? ? 用來表示正則表達式。
4. 且&./a/b
? ? 用來表示對數(shù)據(jù)的引用邀摆,也可以表示為其它路徑的引用纵顾。
5. #[a=1,b=2]
? ? 定義一些變量值,可用來輔助數(shù)據(jù)生成栋盹。
6. @a|b
? ? 定義方法管道施逾,可以對數(shù)據(jù)進行最后的處理。
7. 百分號%
? ? 用來設置數(shù)據(jù)的格式化例获,比如數(shù)字類型汉额,時間類型。
8. 英文冒號:
? 用來標記類型躏敢,同時也作為各個參數(shù)之間的分隔符闷愤。
????????通過以上的這些想法,我需要一個簡單的分析器來將這些配置字符做出分隔件余,這也就是源碼中的parser所做的事情讥脐。每個配置類型都有自己的起始符,可能有自己的結(jié)束符啼器,也可能是一個能匹配到結(jié)束符的正則旬渠。但這里開始符和結(jié)束符的組合必須是唯一的,否則容易造成錯亂端壳。最終這些解析每段配置的parser會被放到一個dispatcher的分配器里告丢,分配器按照最長優(yōu)先匹配的原則來判斷最終使用哪個parser來解析。于是這些不同的配置被解析成了一個個規(guī)則對象损谦,里面包含了配置數(shù)據(jù)所需的所有信息岖免,為接下來的工作做準備。
接下來的工作就是要實現(xiàn)具體的數(shù)據(jù)類型了照捡,上面已經(jīng)獲得了各種屬性配置的值颅湘,具體類型使用的時候可能對具體的配置值有不同的要求,因此每個模擬類型里需要寫一些自己的對配置驗證的方法栗精,以及針對配置如何生成結(jié)果的generate方法闯参。上面說的有兩個配置是比較特殊的,一個是#[]里面的變量配置悲立,一個是@a|b這類的方法配置鹿寨,所有的類型都支持這兩種配置,對于變量配置薪夕,會有一個configOptions的數(shù)據(jù)驗證配置脚草,以保證設置的參數(shù)是符合規(guī)范的。其他的配置則通過添加rule的方式原献,在獲取到配置后會對數(shù)據(jù)進行驗證或更改玩讳。最終會在這些都完成后涩蜘,在generate方法里生成最終的結(jié)果數(shù)據(jù)。
這里內(nèi)置支持的類型有:
1. string
:string[97,120]:{10,20}
如上示例熏纯,表示一個字符串同诫,長度為10到20之間,每個字符的碼點范圍都在97到120之間樟澜。注意類型和第一個屬性配置之間的冒號是可以省略的误窖。
2. number
:number[100,200]:%.2f
如上示例,表示一個數(shù)字秩贰,大小在100到200之間霹俺,注意默認得到的值都是一個浮點數(shù),所以如果需要得到整數(shù)值毒费,可以使用類似c的printf方法進行格式化丙唧,如%d。示例中表示將數(shù)字轉(zhuǎn)化為一個帶兩位小數(shù)點的浮點數(shù)觅玻。
3. date
:date['2018-12-03 00:00:00','2018-12-05 00:00:00']:%yyyy-mm-dd HH\\:MM\\:ss
示例有點長想际,您應該已經(jīng)看出來了,這表示一個時間范圍在2018年12月3日和12月5日之間溪厘,最后格式化為年月日時分秒的一個日期胡本。實際上日期范圍內(nèi)的參數(shù)除了支持能被Date實例化的合理日期格式,也支持像php方法strtotime方法類似tomorrow畸悬,+1 week這種日期寫法侧甫,可以更靈活的使用。
4. regexp
:regexp/[\\u{4e00}-\\u{9afa}]{3,5}/u
表示一個匹配正則表達式的字符蹋宦,這里支持的正則表達式flags包括u,s,i披粟,由于是反解析正則,所以對一些功能有所限制冷冗,但也擴展支持了命名匹配的功能守屉。可以查看reregexp這個包的說明贾惦。
5. id
:id#[start=2,step=2]
通常用在數(shù)組里,表示一個自增的值敦捧,可以設置start和step屬性须板,來表示開始值和每次遞增的大小,默認都是1兢卵。
6. ref
:ref&./a,./b:@join('|')
表示一個對數(shù)據(jù)結(jié)構(gòu)和自身同級的字段a和字段b的引用习瑰,引用到數(shù)據(jù)后,可以通過方法配置來做進一步的處理秽荤。比如示例中的join方法甜奄,因為引用多個字段會轉(zhuǎn)化為數(shù)組柠横,所以可以調(diào)用數(shù)組的原生join方法。
? ? ? ? 以上就是目前所有內(nèi)置類型课兄,實際使用中牍氛,雖然基本可以使用正則來解決大部分的數(shù)據(jù)模擬,但在配置這些參數(shù)時會變得非常困難烟阐,做一些重復的工作搬俊,而且難以維護。所以需要提供一些入口蜒茄,來讓模擬基本數(shù)據(jù)之外的一些數(shù)據(jù)也變得更簡單唉擂。
? ? ? ? 于是在開發(fā)中,提供了以下接口方法:
Such.define()
定義新類型檀葛,第一個參數(shù)是和string玩祟、number這些類似的類型名,第二個參數(shù)可以是一個方法屿聋;也可以是一個基礎類型名空扎,表示這個新類型是從基礎類型擴展而來,不過它固定了某些參數(shù)配置胜臊;還可以是一個包含generate勺卢、init等方法的對象。
這里分別舉個簡單例子:
Such.define('boolean',(options) => { return options.such.utils.isOptional(); });
這里的options里包含了such象对,及全局的Such對象黑忱,Such對象上加入了靜態(tài)屬性utils,包含了系統(tǒng)內(nèi)置使用的一些常用utils方法勒魔。同時包括datas,dpath這兩個可通過數(shù)組作為key設置獲取數(shù)據(jù)的類map對象甫煞。datas里保存了已模擬出來的數(shù)據(jù),dpath保存了一個類似xpath的當前路徑數(shù)組冠绢。有了這些數(shù)據(jù)抚吠,就能更靈活地對數(shù)據(jù)進行模擬了。
Such.define('integer', 'number', '%d')
模擬了一個整數(shù)類型弟胀,這個類型繼承自number楷力,不過它的format參數(shù)配置被固定為%d。
第三種方式定義的類型更全面孵户,和定義原始類型方式是一致的萧朝。可以參考一下dict類型的實現(xiàn)夏哭。
以上就是define方法的簡單介紹检柬,也可以看看?such:recommend?里擴展的一些類型的寫法∈洌總之通過自定義類型何址,可以快速地擴展類型列表里逆,對于node版本,你也可以把一些通用的類型整理開放出來用爪,做成一個npm包原押,提供給他人使用。
Such.alias('short','long-short')
這個不用說项钮,大家就知道這是用來表示別名的班眯,比如上面擴展的integer類型,你覺得integer寫得太費勁了烁巫,就可以Such.alias('int','integer')署隘,記住前面寫短的,后面寫長的亚隙〈挪停可以想象類似bash里alias int=interger,千萬別寫反了阿弃。
有了以上兩個方法诊霹,基本的類型擴展用起來算是比較方便了,如果您有更好的意見渣淳,也歡迎您在Issue提出來脾还,為以后的功能擴展提供更多參考。
? ? ? ? 說到上面的node版本入愧,為了讓對類型擴展使用起來更方便鄙漏,支持了擴展包載入的方式,方便大家可以共享一些類型擴展等棺蛛。如果想要使用這些擴展類型該怎么做呢怔蚌?
Such.config(config)
通過這個config方法,可以將config里的參數(shù)使用對應的Such全局方法將其注冊進來旁赊。
{"extends":["such:recommend"],"types":{"integer":["number","%d"],alias:{"int":"integer"},"parsers":{}}
上面的config參數(shù)大概就長成這樣了桦踊,對于node版本,上面的extends才是生效的终畅,such:開頭的表示是內(nèi)置的擴展籍胯,其它的就可以根據(jù)包名填入了。當然离福,在node版本里杖狼,不需要我們自己來執(zhí)行Such.config方法,而是在項目根目錄配置一個such.config.js的配置文件就好了术徊。
如果你還想將你要模擬的數(shù)據(jù)使用一個json文件替代本刽,你可能需要創(chuàng)建一個文件目錄來作為suchjs模擬的根目錄鲸湃,用來保存這些文件赠涮。如果你還想支持一個多行的dict文件子寓,從里面隨機取一條數(shù)據(jù)做展示的話,你還需要在suchjs根目錄下創(chuàng)建一個數(shù)據(jù)文件目錄笋除。這樣你就可以很規(guī)范地使用它們來輸出模擬數(shù)據(jù)了斜友。
詳細的介紹可以查看項目的readme
當然,為了上述操作使用起來更方便垃它,目前提供了一個乞丐版的cli(太簡陋鲜屏,只支持一個命令),所以你的操作可能是這樣的国拇。
1洛史、進入你的node項目根目錄
2、npm install --save-dev such-cli
3酱吝、such init
好吧也殖,更多的細節(jié)說明放在這個不太詳細的中文文檔里了,感興趣的同學可以看一看务热。
最后忆嗜,貼一下項目的地址:https://github.com/suchjs/such?
感謝大家花費寶貴的時間看到這最后,希望能對實際有數(shù)據(jù)模擬需求的同學有用崎岂。如果您嘗試使用了它捆毫,遇到任何問題或者有任何想法,還請在issue里提出來冲甘,我一定會認真研究的绩卤。再次感謝!