glob.test.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. // test src/glob.ts
  2. import { describe, expect, it } from 'vitest';
  3. import { Glob } from '../src/utils/glob';
  4. describe('glob', () => {
  5. describe('isMatch', () => {
  6. it('* at the end', () => {
  7. expect(Glob.isMatch('a.b.*', 'a.b.c')).toBe(true);
  8. expect(Glob.isMatch('a.b.*', 'a.k.c')).toBe(false);
  9. });
  10. it('* at the start', () => {
  11. expect(Glob.isMatch('*.b.c', 'a.b.c')).toBe(true);
  12. expect(Glob.isMatch('*.b.c', 'a.b.x')).toBe(false);
  13. });
  14. it('multiple *', () => {
  15. expect(Glob.isMatch('*.b.*', 'a.b.c')).toBe(true);
  16. expect(Glob.isMatch('a.b.*', 'a.k.c')).toBe(false);
  17. });
  18. it('no *', () => {
  19. expect(Glob.isMatch('a.b.c', 'a.b.c')).toBe(true);
  20. });
  21. it('length not match', () => {
  22. expect(Glob.isMatch('a.b.*', 'a.b.c.c')).toBe(false);
  23. });
  24. });
  25. describe('isMatchOrParent', () => {
  26. it('* at the end', () => {
  27. expect(Glob.isMatchOrParent('a.b.*', 'a.b.c')).toBe(true);
  28. expect(Glob.isMatchOrParent('a.b.*', 'a.k.c')).toBe(false);
  29. });
  30. it('* at the start', () => {
  31. expect(Glob.isMatchOrParent('*.b.c', 'a.b.c')).toBe(true);
  32. expect(Glob.isMatchOrParent('*.b.c', 'a.b.x')).toBe(false);
  33. expect(Glob.isMatchOrParent('*.b', 'a.b.x')).toBe(true);
  34. });
  35. it('multiple *', () => {
  36. expect(Glob.isMatchOrParent('*.b.*', 'a.b.c')).toBe(true);
  37. expect(Glob.isMatchOrParent('*.b.*', 'a.k.c')).toBe(false);
  38. });
  39. it('no *', () => {
  40. expect(Glob.isMatchOrParent('a.b.c', 'a.b.c')).toBe(true);
  41. expect(Glob.isMatchOrParent('a.b', 'a.b.c')).toBe(true);
  42. expect(Glob.isMatchOrParent('a', 'a.b.c')).toBe(true);
  43. expect(Glob.isMatchOrParent('', 'a.b.c.')).toBe(true);
  44. });
  45. it('length not match', () => {
  46. expect(Glob.isMatchOrParent('a.b.*', 'a.b.c.c')).toBe(true);
  47. expect(Glob.isMatchOrParent('a.b.c.d', 'a.b.c.')).toBe(false);
  48. });
  49. });
  50. describe('getParentPathByPattern', () => {
  51. it('should get parent path correctly', () => {
  52. expect(Glob.getParentPathByPattern('a.b.*', 'a.b.c')).toBe('a.b.c');
  53. expect(Glob.getParentPathByPattern('a.b.*', 'a.b.c.d')).toBe('a.b.c');
  54. expect(Glob.getParentPathByPattern('a.b', 'a.b.c.d')).toBe('a.b');
  55. expect(Glob.getParentPathByPattern('a.*.c', 'a.b.c.d')).toBe('a.b.c');
  56. });
  57. });
  58. describe('findMatchPaths', () => {
  59. it('return original path array if no *', () => {
  60. const obj = { a: { b: { c: 1 } } };
  61. expect(Glob.findMatchPaths(obj, 'a.b.c')).toEqual(['a.b.c']);
  62. });
  63. it('object: when * is in middle of the path', () => {
  64. const obj = {
  65. a: { b: { c: 1 } },
  66. x: { y: { z: 2 } },
  67. };
  68. expect(Glob.findMatchPaths(obj, 'a.*.c')).toEqual(['a.b.c']);
  69. });
  70. it('object:when * is at the end of the path', () => {
  71. const obj = {
  72. a: { b: { c: 1 } },
  73. x: { y: { z: 2 } },
  74. };
  75. expect(Glob.findMatchPaths(obj, 'a.*')).toEqual(['a.b']);
  76. });
  77. // 暂时不支持该场景,见glob.ts 中 143行说明
  78. it('object: * 后面数据异构', () => {
  79. const obj = {
  80. a: { b: { c: 1 } },
  81. x: { y: { z: 2 } },
  82. };
  83. expect(Glob.findMatchPaths(obj, '*.y')).toEqual(['x.y']);
  84. });
  85. it('object:when * is at the start and end of the path', () => {
  86. const obj = {
  87. a: { b: { c: 1 } },
  88. x: { y: { z: 2 } },
  89. };
  90. expect(Glob.findMatchPaths(obj, '*.y.*')).toEqual(['x.y.z']);
  91. });
  92. it('array: when * is at the end of the path', () => {
  93. const obj = {
  94. other: 100,
  95. arr: [
  96. {
  97. x: 1,
  98. y: { a: 1, b: 2 },
  99. },
  100. {
  101. x: 10,
  102. y: {
  103. a: 10,
  104. b: 20,
  105. },
  106. },
  107. ],
  108. };
  109. expect(Glob.findMatchPaths(obj, 'arr.*')).toEqual(['arr.0', 'arr.1']);
  110. });
  111. it('array: when * is at the start of the path', () => {
  112. const arr = [
  113. {
  114. x: 1,
  115. y: { a: 1, b: 2 },
  116. },
  117. {
  118. x: 10,
  119. y: {
  120. a: 10,
  121. b: 20,
  122. },
  123. },
  124. ];
  125. expect(Glob.findMatchPaths(arr, '*')).toEqual(['0', '1']);
  126. });
  127. it('array: when * is in the middle of the path', () => {
  128. const obj = {
  129. other: 100,
  130. arr: [
  131. {
  132. x: 1,
  133. y: { a: 1, b: 2 },
  134. },
  135. {
  136. x: 10,
  137. y: {
  138. a: 10,
  139. b: 20,
  140. },
  141. },
  142. ],
  143. };
  144. expect(Glob.findMatchPaths(obj, 'arr.*.y')).toEqual(['arr.0.y', 'arr.1.y']);
  145. });
  146. it('array in array: when double * ', () => {
  147. const obj = {
  148. other: 100,
  149. arr: [
  150. {
  151. x: 1,
  152. y: ['1', '2'],
  153. },
  154. ],
  155. };
  156. expect(Glob.findMatchPaths(obj, 'arr.*.y.*')).toEqual(['arr.0.y.0', 'arr.0.y.1']);
  157. });
  158. it('array in object: when double * ', () => {
  159. const obj = {
  160. x: 100,
  161. y: {
  162. arr: [1, 2],
  163. },
  164. };
  165. expect(Glob.findMatchPaths(obj, 'y.*.*')).toEqual(['y.arr.0', 'y.arr.1']);
  166. });
  167. it('array in object: when double * start ', () => {
  168. const obj = {
  169. x: 100,
  170. y: {
  171. arr: [{ a: 1, b: 2 }],
  172. },
  173. };
  174. expect(Glob.findMatchPaths(obj, '*.arr.*')).toEqual(['y.arr.0']);
  175. });
  176. it('when value after * is empty string ', () => {
  177. const obj = {
  178. $$input_decorator$$: {
  179. inputParameters: [{ name: '', input: 2 }],
  180. },
  181. };
  182. expect(Glob.findMatchPaths(obj, '$$input_decorator$$.inputParameters.*.name')).toEqual([
  183. '$$input_decorator$$.inputParameters.0.name',
  184. ]);
  185. });
  186. it('when value after * is undefined ', () => {
  187. const obj = {
  188. x: {
  189. arr: [{ name: undefined, input: 2 }],
  190. },
  191. };
  192. expect(Glob.findMatchPaths(obj, 'x.arr.*.name')).toEqual(['x.arr.0.name']);
  193. });
  194. it('when value not directly after * is undefined ', () => {
  195. const obj = {
  196. x: {
  197. arr: [{ name: { a: undefined }, input: 2 }],
  198. },
  199. };
  200. expect(Glob.findMatchPaths(obj, 'x.arr.*.name.a')).toEqual(['x.arr.0.name.a']);
  201. });
  202. });
  203. describe('splitPattern', () => {
  204. it('should splict pattern correctly', () => {
  205. expect(Glob.splitPattern('a.b.*.c.*.d')).toEqual(['a.b', '*', 'c', '*', 'd']);
  206. expect(Glob.splitPattern('a.b.*.c.*')).toEqual(['a.b', '*', 'c', '*']);
  207. expect(Glob.splitPattern('a.b.*.*.*.d')).toEqual(['a.b', '*', '*', '*', 'd']);
  208. expect(Glob.splitPattern('*.*.c.*.d')).toEqual(['*', '*', 'c', '*', 'd']);
  209. });
  210. });
  211. describe('getSubPaths', () => {
  212. it('should get sub paths for valid object', () => {
  213. const obj = {
  214. a: {
  215. b: {
  216. x1: {
  217. y1: 1,
  218. },
  219. x2: {
  220. y2: 2,
  221. },
  222. },
  223. },
  224. };
  225. expect(Glob.getSubPaths(['a.b'], obj)).toEqual(['a.b.x1', 'a.b.x2']);
  226. expect(Glob.getSubPaths(['a.b', 'a.b.x1'], obj)).toEqual(['a.b.x1', 'a.b.x2', 'a.b.x1.y1']);
  227. });
  228. it('should get sub paths for array', () => {
  229. const obj = {
  230. a: {
  231. b: {
  232. x1: [1, 2],
  233. },
  234. },
  235. };
  236. expect(Glob.getSubPaths(['a.b.x1'], obj)).toEqual(['a.b.x1.0', 'a.b.x1.1']);
  237. });
  238. it('should get sub paths when root obj is array', () => {
  239. const obj = [
  240. {
  241. x1: [1, 2],
  242. },
  243. {
  244. x2: [1, 2],
  245. },
  246. ];
  247. expect(Glob.getSubPaths(['0.x1'], obj)).toEqual(['0.x1.0', '0.x1.1']);
  248. });
  249. it('should return empty array when obj is not object nor array', () => {
  250. expect(Glob.getSubPaths(['x.y'], 1)).toEqual([]);
  251. expect(Glob.getSubPaths(['x.y'], 'x')).toEqual([]);
  252. expect(Glob.getSubPaths(['x.y'], undefined)).toEqual([]);
  253. });
  254. it('should return empty array when obj has no value for given path', () => {
  255. const obj = {
  256. a: {
  257. b: {
  258. x1: [1, 2],
  259. },
  260. },
  261. };
  262. expect(Glob.getSubPaths(['a.b.c'], obj)).toEqual([]);
  263. });
  264. });
  265. describe('findMatchPathsWithEmptyValue', () => {
  266. it('return original path array if no *', () => {
  267. const obj = { a: { b: { c: 1 } } };
  268. expect(Glob.findMatchPathsWithEmptyValue(obj, 'a.b.c')).toEqual(['a.b.c']);
  269. });
  270. it('return original path array if no * and value is empty on multiple layers', () => {
  271. const obj = { a: {} };
  272. expect(Glob.findMatchPathsWithEmptyValue(obj, 'a.b.c')).toEqual(['a.b.c']);
  273. });
  274. it('return original path array if no * and value is empty on multiple layers', () => {
  275. const obj = { a: { b: {} } };
  276. expect(Glob.findMatchPathsWithEmptyValue(obj, 'a.x.y')).toEqual(['a.x.y']);
  277. });
  278. it('return array with original path even if path does not exists, but the original path does not contain * ', () => {
  279. const obj = { a: { b: { c: 1 } } };
  280. expect(Glob.findMatchPathsWithEmptyValue(obj, 'a.b.c.d')).toEqual(['a.b.c.d']);
  281. });
  282. it('return original path array if no * and path related value is undefined in object', () => {
  283. const obj = { a: { b: { c: {} } } };
  284. expect(Glob.findMatchPathsWithEmptyValue(obj, 'a.b.c.d')).toEqual(['a.b.c.d']);
  285. });
  286. it('object: when * is in middle of the path', () => {
  287. const obj = {
  288. a: { b: { c: 1 } },
  289. x: { y: { z: 2 } },
  290. };
  291. expect(Glob.findMatchPathsWithEmptyValue(obj, 'a.*.c')).toEqual(['a.b.c']);
  292. });
  293. it('object:when * is at the end of the path', () => {
  294. const obj = {
  295. a: { b: { c: 1 } },
  296. x: { y: { z: 2 } },
  297. };
  298. expect(Glob.findMatchPathsWithEmptyValue(obj, 'a.*')).toEqual(['a.b']);
  299. });
  300. // 暂时不支持该场景,见glob.ts 中 143行说明
  301. it('object: * 后面数据异构', () => {
  302. const obj = {
  303. a: { b: { c: 1 } },
  304. x: { y: { z: 2 } },
  305. };
  306. expect(Glob.findMatchPathsWithEmptyValue(obj, '*.y')).toEqual(['a.y', 'x.y']);
  307. });
  308. it('object:when * is at the start and end of the path', () => {
  309. const obj = {
  310. a: { b: { c: 1 } },
  311. x: { y: { z: 2 } },
  312. };
  313. expect(Glob.findMatchPathsWithEmptyValue(obj, '*.y.*')).toEqual(['x.y.z']);
  314. });
  315. it('array: when * is at the end of the path', () => {
  316. const obj = {
  317. other: 100,
  318. arr: [
  319. {
  320. x: 1,
  321. y: { a: 1, b: 2 },
  322. },
  323. {
  324. x: 10,
  325. y: {
  326. a: 10,
  327. b: 20,
  328. },
  329. },
  330. ],
  331. };
  332. expect(Glob.findMatchPathsWithEmptyValue(obj, 'arr.*')).toEqual(['arr.0', 'arr.1']);
  333. });
  334. it('array: when * is at the start of the path', () => {
  335. const arr = [
  336. {
  337. x: 1,
  338. y: { a: 1, b: 2 },
  339. },
  340. {
  341. x: 10,
  342. y: {
  343. a: 10,
  344. b: 20,
  345. },
  346. },
  347. ];
  348. expect(Glob.findMatchPathsWithEmptyValue(arr, '*')).toEqual(['0', '1']);
  349. });
  350. it('array: when * is in the middle of the path', () => {
  351. const obj = {
  352. other: 100,
  353. arr: [
  354. {
  355. x: 1,
  356. y: { a: 1, b: 2 },
  357. },
  358. {
  359. x: 10,
  360. y: {
  361. a: 10,
  362. b: 20,
  363. },
  364. },
  365. ],
  366. };
  367. expect(Glob.findMatchPathsWithEmptyValue(obj, 'arr.*.y')).toEqual(['arr.0.y', 'arr.1.y']);
  368. });
  369. it('array: when data related to path is undefined', () => {
  370. const obj = [{ a: 1 }, { a: 2, b: 3 }];
  371. expect(Glob.findMatchPathsWithEmptyValue(obj, '*.b')).toEqual(['0.b', '1.b']);
  372. });
  373. it('array in array: when double * ', () => {
  374. const obj = {
  375. other: 100,
  376. arr: [
  377. {
  378. x: 1,
  379. y: ['1', '2'],
  380. },
  381. ],
  382. };
  383. expect(Glob.findMatchPathsWithEmptyValue(obj, 'arr.*.y.*')).toEqual([
  384. 'arr.0.y.0',
  385. 'arr.0.y.1',
  386. ]);
  387. });
  388. it('array in object: when double * ', () => {
  389. const obj = {
  390. x: 100,
  391. y: {
  392. arr: [1, 2],
  393. },
  394. };
  395. expect(Glob.findMatchPathsWithEmptyValue(obj, 'y.*.*')).toEqual(['y.arr.0', 'y.arr.1']);
  396. });
  397. it('array in object: when double * start ', () => {
  398. const obj = {
  399. x: 100,
  400. y: {
  401. arr: [{ a: 1, b: 2 }],
  402. },
  403. };
  404. expect(Glob.findMatchPathsWithEmptyValue(obj, '*.arr.*')).toEqual(['y.arr.0']);
  405. });
  406. it('when value after * is empty string ', () => {
  407. const obj = {
  408. $$input_decorator$$: {
  409. inputParameters: [{ name: '', input: 2 }],
  410. },
  411. };
  412. expect(
  413. Glob.findMatchPathsWithEmptyValue(obj, '$$input_decorator$$.inputParameters.*.name')
  414. ).toEqual(['$$input_decorator$$.inputParameters.0.name']);
  415. });
  416. it('when value after * is undefined ', () => {
  417. const obj = {
  418. x: {
  419. arr: [{ name: undefined, input: 2 }],
  420. },
  421. };
  422. expect(Glob.findMatchPathsWithEmptyValue(obj, 'x.arr.*.name')).toEqual(['x.arr.0.name']);
  423. });
  424. it('when value not directly after * is undefined ', () => {
  425. const obj = {
  426. x: {
  427. arr: [{ name: { a: undefined }, input: 2 }],
  428. },
  429. };
  430. expect(Glob.findMatchPathsWithEmptyValue(obj, 'x.arr.*.name.a')).toEqual(['x.arr.0.name.a']);
  431. });
  432. });
  433. });