@reallukemanning/folio 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. package/LICENSE +21 -0
  2. package/copy-components.js +31 -0
  3. package/coverage/base.css +224 -0
  4. package/coverage/block-navigation.js +87 -0
  5. package/coverage/core/copy-components.js.html +178 -0
  6. package/coverage/core/eslint.config.js.html +184 -0
  7. package/coverage/core/index.html +146 -0
  8. package/coverage/core/src/__tests__/benchmarks/ProjectCard.bench.tsx.html +364 -0
  9. package/coverage/core/src/__tests__/benchmarks/ProjectView.bench.tsx.html +484 -0
  10. package/coverage/core/src/__tests__/benchmarks/github.bench.ts.html +244 -0
  11. package/coverage/core/src/__tests__/benchmarks/index.html +191 -0
  12. package/coverage/core/src/__tests__/benchmarks/npm.bench.ts.html +271 -0
  13. package/coverage/core/src/__tests__/benchmarks/product-hunt.bench.ts.html +259 -0
  14. package/coverage/core/src/__tests__/benchmarks/utilities.bench.ts.html +478 -0
  15. package/coverage/core/src/components/FeaturedProject.test.tsx.html +697 -0
  16. package/coverage/core/src/components/FeaturedProject.tsx.html +163 -0
  17. package/coverage/core/src/components/ProjectCard/ProjectCard.test.tsx.html +928 -0
  18. package/coverage/core/src/components/ProjectCard/ProjectCard.tsx.html +379 -0
  19. package/coverage/core/src/components/ProjectCard/index.html +146 -0
  20. package/coverage/core/src/components/ProjectCard/index.ts.html +88 -0
  21. package/coverage/core/src/components/ProjectGrid/ProjectGrid.test.tsx.html +292 -0
  22. package/coverage/core/src/components/ProjectGrid/ProjectGrid.tsx.html +103 -0
  23. package/coverage/core/src/components/ProjectGrid/index.html +146 -0
  24. package/coverage/core/src/components/ProjectGrid/index.ts.html +88 -0
  25. package/coverage/core/src/components/ProjectList/ProjectList.test.tsx.html +292 -0
  26. package/coverage/core/src/components/ProjectList/ProjectList.tsx.html +103 -0
  27. package/coverage/core/src/components/ProjectList/index.html +146 -0
  28. package/coverage/core/src/components/ProjectList/index.ts.html +88 -0
  29. package/coverage/core/src/components/ProjectView/ProjectView.test.tsx.html +1108 -0
  30. package/coverage/core/src/components/ProjectView/ProjectView.tsx.html +589 -0
  31. package/coverage/core/src/components/ProjectView/index.html +146 -0
  32. package/coverage/core/src/components/ProjectView/index.ts.html +88 -0
  33. package/coverage/core/src/components/index.html +146 -0
  34. package/coverage/core/src/components/index.ts.html +97 -0
  35. package/coverage/core/src/index.html +116 -0
  36. package/coverage/core/src/index.ts.html +94 -0
  37. package/coverage/core/src/lib/__tests__/defineProjects.test.ts.html +421 -0
  38. package/coverage/core/src/lib/__tests__/filterByFeatured.test.ts.html +523 -0
  39. package/coverage/core/src/lib/__tests__/filterByStatus.test.ts.html +664 -0
  40. package/coverage/core/src/lib/__tests__/filterByType.test.ts.html +631 -0
  41. package/coverage/core/src/lib/__tests__/github.test.ts.html +1783 -0
  42. package/coverage/core/src/lib/__tests__/hybrid-config.test.ts.html +1345 -0
  43. package/coverage/core/src/lib/__tests__/index.html +311 -0
  44. package/coverage/core/src/lib/__tests__/normalise.test.ts.html +1585 -0
  45. package/coverage/core/src/lib/__tests__/npm-config.test.ts.html +385 -0
  46. package/coverage/core/src/lib/__tests__/npm.test.ts.html +1135 -0
  47. package/coverage/core/src/lib/__tests__/product-hunt-config.test.ts.html +397 -0
  48. package/coverage/core/src/lib/__tests__/product-hunt.test.ts.html +505 -0
  49. package/coverage/core/src/lib/__tests__/sortByDate.test.ts.html +751 -0
  50. package/coverage/core/src/lib/__tests__/sortByName.test.ts.html +832 -0
  51. package/coverage/core/src/lib/__tests__/sortByStars.test.ts.html +703 -0
  52. package/coverage/core/src/lib/defineProjects.ts.html +100 -0
  53. package/coverage/core/src/lib/filterByFeatured.ts.html +133 -0
  54. package/coverage/core/src/lib/filterByStatus.ts.html +145 -0
  55. package/coverage/core/src/lib/filterByType.ts.html +133 -0
  56. package/coverage/core/src/lib/github.ts.html +517 -0
  57. package/coverage/core/src/lib/index.html +281 -0
  58. package/coverage/core/src/lib/index.ts.html +130 -0
  59. package/coverage/core/src/lib/normalise.ts.html +868 -0
  60. package/coverage/core/src/lib/npm.ts.html +199 -0
  61. package/coverage/core/src/lib/product-hunt.ts.html +256 -0
  62. package/coverage/core/src/lib/sortByDate.ts.html +175 -0
  63. package/coverage/core/src/lib/sortByName.ts.html +172 -0
  64. package/coverage/core/src/lib/sortByStars.ts.html +172 -0
  65. package/coverage/core/src/types/index.html +116 -0
  66. package/coverage/core/src/types/index.ts.html +517 -0
  67. package/coverage/core/vitest.config.ts.html +178 -0
  68. package/coverage/coverage-final.json +53 -0
  69. package/coverage/coverage-summary.json +54 -0
  70. package/coverage/favicon.png +0 -0
  71. package/coverage/index.html +266 -0
  72. package/coverage/prettify.css +1 -0
  73. package/coverage/prettify.js +2 -0
  74. package/coverage/sort-arrow-sprite.png +0 -0
  75. package/coverage/sorter.js +210 -0
  76. package/dist/cli-components/FeaturedProject/FeaturedProject.d.ts +6 -0
  77. package/dist/cli-components/FeaturedProject/FeaturedProject.d.ts.map +1 -0
  78. package/dist/cli-components/FeaturedProject/FeaturedProject.js +9 -0
  79. package/dist/cli-components/FeaturedProject/FeaturedProject.js.map +1 -0
  80. package/dist/cli-components/FeaturedProject/FeaturedProject.tsx +54 -0
  81. package/dist/cli-components/FeaturedProject/index.d.ts +3 -0
  82. package/dist/cli-components/FeaturedProject/index.d.ts.map +1 -0
  83. package/dist/cli-components/FeaturedProject/index.js +2 -0
  84. package/dist/cli-components/FeaturedProject/index.js.map +1 -0
  85. package/dist/cli-components/FeaturedProject/index.ts +2 -0
  86. package/dist/cli-components/ProjectCard/ProjectCard.d.ts +26 -0
  87. package/dist/cli-components/ProjectCard/ProjectCard.d.ts.map +1 -0
  88. package/dist/cli-components/ProjectCard/ProjectCard.js +33 -0
  89. package/dist/cli-components/ProjectCard/ProjectCard.js.map +1 -0
  90. package/dist/cli-components/ProjectCard/ProjectCard.tsx +90 -0
  91. package/dist/cli-components/ProjectCard/index.d.ts +3 -0
  92. package/dist/cli-components/ProjectCard/index.d.ts.map +1 -0
  93. package/dist/cli-components/ProjectCard/index.js +2 -0
  94. package/dist/cli-components/ProjectCard/index.js.map +1 -0
  95. package/dist/cli-components/ProjectCard/index.ts +2 -0
  96. package/dist/cli-components/ProjectGrid/ProjectGrid.d.ts +5 -0
  97. package/dist/cli-components/ProjectGrid/ProjectGrid.d.ts.map +1 -0
  98. package/dist/cli-components/ProjectGrid/ProjectGrid.js +8 -0
  99. package/dist/cli-components/ProjectGrid/ProjectGrid.js.map +1 -0
  100. package/dist/cli-components/ProjectGrid/ProjectGrid.tsx +6 -0
  101. package/dist/cli-components/ProjectGrid/index.d.ts +3 -0
  102. package/dist/cli-components/ProjectGrid/index.d.ts.map +1 -0
  103. package/dist/cli-components/ProjectGrid/index.js +2 -0
  104. package/dist/cli-components/ProjectGrid/index.js.map +1 -0
  105. package/dist/cli-components/ProjectGrid/index.ts +2 -0
  106. package/dist/cli-components/ProjectList/ProjectList.d.ts +5 -0
  107. package/dist/cli-components/ProjectList/ProjectList.d.ts.map +1 -0
  108. package/dist/cli-components/ProjectList/ProjectList.js +8 -0
  109. package/dist/cli-components/ProjectList/ProjectList.js.map +1 -0
  110. package/dist/cli-components/ProjectList/ProjectList.tsx +6 -0
  111. package/dist/cli-components/ProjectList/index.d.ts +3 -0
  112. package/dist/cli-components/ProjectList/index.d.ts.map +1 -0
  113. package/dist/cli-components/ProjectList/index.js +2 -0
  114. package/dist/cli-components/ProjectList/index.js.map +1 -0
  115. package/dist/cli-components/ProjectList/index.ts +2 -0
  116. package/dist/cli-components/ProjectView/ProjectView.d.ts +17 -0
  117. package/dist/cli-components/ProjectView/ProjectView.d.ts.map +1 -0
  118. package/dist/cli-components/ProjectView/ProjectView.js +39 -0
  119. package/dist/cli-components/ProjectView/ProjectView.js.map +1 -0
  120. package/dist/cli-components/ProjectView/ProjectView.tsx +117 -0
  121. package/dist/cli-components/ProjectView/index.d.ts +3 -0
  122. package/dist/cli-components/ProjectView/index.d.ts.map +1 -0
  123. package/dist/cli-components/ProjectView/index.js +2 -0
  124. package/dist/cli-components/ProjectView/index.js.map +1 -0
  125. package/dist/cli-components/ProjectView/index.ts +2 -0
  126. package/dist/cli-components/types.d.ts +52 -0
  127. package/dist/cli-components/types.d.ts.map +1 -0
  128. package/dist/cli-components/types.js +2 -0
  129. package/dist/cli-components/types.js.map +1 -0
  130. package/dist/cli-components/types.ts +58 -0
  131. package/dist/cli-types.d.ts +52 -0
  132. package/dist/cli-types.d.ts.map +1 -0
  133. package/dist/cli-types.js +2 -0
  134. package/dist/cli-types.js.map +1 -0
  135. package/dist/cli.d.ts +3 -0
  136. package/dist/cli.d.ts.map +1 -0
  137. package/dist/cli.js +21 -0
  138. package/dist/cli.js.map +1 -0
  139. package/dist/commands/add.d.ts +2 -0
  140. package/dist/commands/add.d.ts.map +1 -0
  141. package/dist/commands/add.js +166 -0
  142. package/dist/commands/add.js.map +1 -0
  143. package/dist/commands/init.d.ts +6 -0
  144. package/dist/commands/init.d.ts.map +1 -0
  145. package/dist/commands/init.js +231 -0
  146. package/dist/commands/init.js.map +1 -0
  147. package/dist/components/FeaturedProject.d.ts +7 -0
  148. package/dist/components/FeaturedProject.d.ts.map +1 -0
  149. package/dist/components/FeaturedProject.js +10 -0
  150. package/dist/components/FeaturedProject.js.map +1 -0
  151. package/dist/components/FeaturedProject.test.tsx +204 -0
  152. package/dist/components/FeaturedProject.tsx +26 -0
  153. package/dist/components/ProjectCard/ProjectCard.d.ts +26 -0
  154. package/dist/components/ProjectCard/ProjectCard.d.ts.map +1 -0
  155. package/dist/components/ProjectCard/ProjectCard.js +39 -0
  156. package/dist/components/ProjectCard/ProjectCard.js.map +1 -0
  157. package/dist/components/ProjectCard/ProjectCard.test.tsx +281 -0
  158. package/dist/components/ProjectCard/ProjectCard.tsx +98 -0
  159. package/dist/components/ProjectCard/index.d.ts +2 -0
  160. package/dist/components/ProjectCard/index.d.ts.map +1 -0
  161. package/dist/components/ProjectCard/index.js +2 -0
  162. package/dist/components/ProjectCard/index.js.map +1 -0
  163. package/dist/components/ProjectCard/index.ts +1 -0
  164. package/dist/components/ProjectGrid/ProjectGrid.d.ts +5 -0
  165. package/dist/components/ProjectGrid/ProjectGrid.d.ts.map +1 -0
  166. package/dist/components/ProjectGrid/ProjectGrid.js +8 -0
  167. package/dist/components/ProjectGrid/ProjectGrid.js.map +1 -0
  168. package/dist/components/ProjectGrid/ProjectGrid.test.tsx +69 -0
  169. package/dist/components/ProjectGrid/ProjectGrid.tsx +6 -0
  170. package/dist/components/ProjectGrid/index.d.ts +2 -0
  171. package/dist/components/ProjectGrid/index.d.ts.map +1 -0
  172. package/dist/components/ProjectGrid/index.js +2 -0
  173. package/dist/components/ProjectGrid/index.js.map +1 -0
  174. package/dist/components/ProjectGrid/index.ts +1 -0
  175. package/dist/components/ProjectList/ProjectList.d.ts +5 -0
  176. package/dist/components/ProjectList/ProjectList.d.ts.map +1 -0
  177. package/dist/components/ProjectList/ProjectList.js +8 -0
  178. package/dist/components/ProjectList/ProjectList.js.map +1 -0
  179. package/dist/components/ProjectList/ProjectList.test.tsx +69 -0
  180. package/dist/components/ProjectList/ProjectList.tsx +6 -0
  181. package/dist/components/ProjectList/index.d.ts +2 -0
  182. package/dist/components/ProjectList/index.d.ts.map +1 -0
  183. package/dist/components/ProjectList/index.js +2 -0
  184. package/dist/components/ProjectList/index.js.map +1 -0
  185. package/dist/components/ProjectList/index.ts +1 -0
  186. package/dist/components/ProjectView/ProjectView.d.ts +20 -0
  187. package/dist/components/ProjectView/ProjectView.d.ts.map +1 -0
  188. package/dist/components/ProjectView/ProjectView.js +64 -0
  189. package/dist/components/ProjectView/ProjectView.js.map +1 -0
  190. package/dist/components/ProjectView/ProjectView.test.tsx +341 -0
  191. package/dist/components/ProjectView/ProjectView.tsx +168 -0
  192. package/dist/components/ProjectView/index.d.ts +2 -0
  193. package/dist/components/ProjectView/index.d.ts.map +1 -0
  194. package/dist/components/ProjectView/index.js +2 -0
  195. package/dist/components/ProjectView/index.js.map +1 -0
  196. package/dist/components/ProjectView/index.ts +1 -0
  197. package/dist/components/index.d.ts +5 -0
  198. package/dist/components/index.d.ts.map +1 -0
  199. package/dist/components/index.js +5 -0
  200. package/dist/components/index.js.map +1 -0
  201. package/dist/components/index.ts +4 -0
  202. package/dist/index.d.ts +4 -0
  203. package/dist/index.d.ts.map +1 -0
  204. package/dist/index.js +4 -0
  205. package/dist/index.js.map +1 -0
  206. package/dist/lib/defineProjects.d.ts +3 -0
  207. package/dist/lib/defineProjects.d.ts.map +1 -0
  208. package/dist/lib/defineProjects.js +4 -0
  209. package/dist/lib/defineProjects.js.map +1 -0
  210. package/dist/lib/filterByFeatured.d.ts +3 -0
  211. package/dist/lib/filterByFeatured.d.ts.map +1 -0
  212. package/dist/lib/filterByFeatured.js +10 -0
  213. package/dist/lib/filterByFeatured.js.map +1 -0
  214. package/dist/lib/filterByStatus.d.ts +3 -0
  215. package/dist/lib/filterByStatus.d.ts.map +1 -0
  216. package/dist/lib/filterByStatus.js +13 -0
  217. package/dist/lib/filterByStatus.js.map +1 -0
  218. package/dist/lib/filterByType.d.ts +3 -0
  219. package/dist/lib/filterByType.d.ts.map +1 -0
  220. package/dist/lib/filterByType.js +10 -0
  221. package/dist/lib/filterByType.js.map +1 -0
  222. package/dist/lib/github.d.ts +24 -0
  223. package/dist/lib/github.d.ts.map +1 -0
  224. package/dist/lib/github.js +107 -0
  225. package/dist/lib/github.js.map +1 -0
  226. package/dist/lib/index.d.ts +16 -0
  227. package/dist/lib/index.d.ts.map +1 -0
  228. package/dist/lib/index.js +12 -0
  229. package/dist/lib/index.js.map +1 -0
  230. package/dist/lib/normalise.d.ts +4 -0
  231. package/dist/lib/normalise.d.ts.map +1 -0
  232. package/dist/lib/normalise.js +221 -0
  233. package/dist/lib/normalise.js.map +1 -0
  234. package/dist/lib/npm.d.ts +7 -0
  235. package/dist/lib/npm.d.ts.map +1 -0
  236. package/dist/lib/npm.js +28 -0
  237. package/dist/lib/npm.js.map +1 -0
  238. package/dist/lib/product-hunt.d.ts +12 -0
  239. package/dist/lib/product-hunt.d.ts.map +1 -0
  240. package/dist/lib/product-hunt.js +40 -0
  241. package/dist/lib/product-hunt.js.map +1 -0
  242. package/dist/lib/sortByDate.d.ts +4 -0
  243. package/dist/lib/sortByDate.d.ts.map +1 -0
  244. package/dist/lib/sortByDate.js +21 -0
  245. package/dist/lib/sortByDate.js.map +1 -0
  246. package/dist/lib/sortByName.d.ts +4 -0
  247. package/dist/lib/sortByName.d.ts.map +1 -0
  248. package/dist/lib/sortByName.js +21 -0
  249. package/dist/lib/sortByName.js.map +1 -0
  250. package/dist/lib/sortByStars.d.ts +4 -0
  251. package/dist/lib/sortByStars.d.ts.map +1 -0
  252. package/dist/lib/sortByStars.js +21 -0
  253. package/dist/lib/sortByStars.js.map +1 -0
  254. package/dist/test-setup.d.ts +2 -0
  255. package/dist/test-setup.d.ts.map +1 -0
  256. package/dist/test-setup.js +2 -0
  257. package/dist/test-setup.js.map +1 -0
  258. package/dist/types/index.d.ts +121 -0
  259. package/dist/types/index.d.ts.map +1 -0
  260. package/dist/types/index.js +2 -0
  261. package/dist/types/index.js.map +1 -0
  262. package/eslint.config.js +33 -0
  263. package/package.json +47 -0
  264. package/playwright-report/index.html +85 -0
  265. package/src/__tests__/benchmarks/ProjectCard.bench.tsx +93 -0
  266. package/src/__tests__/benchmarks/ProjectView.bench.tsx +133 -0
  267. package/src/__tests__/benchmarks/github.bench.ts +53 -0
  268. package/src/__tests__/benchmarks/npm.bench.ts +62 -0
  269. package/src/__tests__/benchmarks/product-hunt.bench.ts +58 -0
  270. package/src/__tests__/benchmarks/utilities.bench.ts +131 -0
  271. package/src/cli-components/FeaturedProject/FeaturedProject.tsx +54 -0
  272. package/src/cli-components/FeaturedProject/index.ts +2 -0
  273. package/src/cli-components/ProjectCard/ProjectCard.tsx +90 -0
  274. package/src/cli-components/ProjectCard/index.ts +2 -0
  275. package/src/cli-components/ProjectGrid/ProjectGrid.tsx +6 -0
  276. package/src/cli-components/ProjectGrid/index.ts +2 -0
  277. package/src/cli-components/ProjectList/ProjectList.tsx +6 -0
  278. package/src/cli-components/ProjectList/index.ts +2 -0
  279. package/src/cli-components/ProjectView/ProjectView.tsx +117 -0
  280. package/src/cli-components/ProjectView/index.ts +2 -0
  281. package/src/cli-components/types.ts +58 -0
  282. package/src/cli-types.ts +58 -0
  283. package/src/cli.ts +26 -0
  284. package/src/commands/add.ts +191 -0
  285. package/src/commands/init.ts +260 -0
  286. package/src/components/FeaturedProject.test.tsx +204 -0
  287. package/src/components/FeaturedProject.tsx +26 -0
  288. package/src/components/ProjectCard/ProjectCard.test.tsx +281 -0
  289. package/src/components/ProjectCard/ProjectCard.tsx +98 -0
  290. package/src/components/ProjectCard/index.ts +1 -0
  291. package/src/components/ProjectGrid/ProjectGrid.test.tsx +69 -0
  292. package/src/components/ProjectGrid/ProjectGrid.tsx +6 -0
  293. package/src/components/ProjectGrid/index.ts +1 -0
  294. package/src/components/ProjectList/ProjectList.test.tsx +69 -0
  295. package/src/components/ProjectList/ProjectList.tsx +6 -0
  296. package/src/components/ProjectList/index.ts +1 -0
  297. package/src/components/ProjectView/ProjectView.test.tsx +341 -0
  298. package/src/components/ProjectView/ProjectView.tsx +168 -0
  299. package/src/components/ProjectView/index.ts +1 -0
  300. package/src/components/index.ts +4 -0
  301. package/src/index.ts +3 -0
  302. package/src/lib/__tests__/defineProjects.test.ts +112 -0
  303. package/src/lib/__tests__/filterByFeatured.test.ts +146 -0
  304. package/src/lib/__tests__/filterByStatus.test.ts +193 -0
  305. package/src/lib/__tests__/filterByType.test.ts +182 -0
  306. package/src/lib/__tests__/github.test.ts +566 -0
  307. package/src/lib/__tests__/hybrid-config.test.ts +420 -0
  308. package/src/lib/__tests__/normalise.test.ts +500 -0
  309. package/src/lib/__tests__/npm-config.test.ts +100 -0
  310. package/src/lib/__tests__/npm.test.ts +350 -0
  311. package/src/lib/__tests__/product-hunt-config.test.ts +104 -0
  312. package/src/lib/__tests__/product-hunt.test.ts +140 -0
  313. package/src/lib/__tests__/sortByDate.test.ts +222 -0
  314. package/src/lib/__tests__/sortByName.test.ts +249 -0
  315. package/src/lib/__tests__/sortByStars.test.ts +206 -0
  316. package/src/lib/defineProjects.ts +5 -0
  317. package/src/lib/filterByFeatured.ts +16 -0
  318. package/src/lib/filterByStatus.ts +20 -0
  319. package/src/lib/filterByType.ts +16 -0
  320. package/src/lib/github.ts +144 -0
  321. package/src/lib/index.ts +15 -0
  322. package/src/lib/normalise.ts +261 -0
  323. package/src/lib/npm.ts +38 -0
  324. package/src/lib/product-hunt.ts +57 -0
  325. package/src/lib/sortByDate.ts +30 -0
  326. package/src/lib/sortByName.ts +29 -0
  327. package/src/lib/sortByStars.ts +29 -0
  328. package/src/test-setup.ts +1 -0
  329. package/src/types/index.ts +144 -0
  330. package/test-results/.last-run.json +62 -0
  331. package/tsconfig.json +29 -0
  332. package/vitest.config.ts +31 -0
@@ -0,0 +1,146 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { filterByFeatured } from '../filterByFeatured'
3
+ import type { FolioProject } from '../../types'
4
+
5
+ function createProject(overrides: Partial<FolioProject> = {}): FolioProject {
6
+ return {
7
+ id: 'test-id',
8
+ type: 'github',
9
+ status: 'active',
10
+ featured: false,
11
+ name: 'Test Project',
12
+ tagline: '',
13
+ description: '',
14
+ background: null,
15
+ why: null,
16
+ image: null,
17
+ struggles: [],
18
+ timeline: [],
19
+ posts: [],
20
+ stack: [],
21
+ links: {},
22
+ stats: null,
23
+ language: null,
24
+ languageColor: null,
25
+ createdAt: null,
26
+ updatedAt: null,
27
+ ...overrides,
28
+ }
29
+ }
30
+
31
+ describe('filterByFeatured', () => {
32
+ describe('empty array handling', () => {
33
+ it('should return empty array when input is empty', () => {
34
+ expect(filterByFeatured([], true)).toEqual([])
35
+ })
36
+
37
+ it('should return empty array when input is empty and featured is false', () => {
38
+ expect(filterByFeatured([], false)).toEqual([])
39
+ })
40
+
41
+ it('should return empty array when input is empty and featured is null', () => {
42
+ expect(filterByFeatured([], null)).toEqual([])
43
+ })
44
+
45
+ it('should return empty array when input is empty and featured is undefined', () => {
46
+ expect(filterByFeatured([], undefined)).toEqual([])
47
+ })
48
+ })
49
+
50
+ describe('featured filtering', () => {
51
+ it('should filter projects with featured=true', () => {
52
+ const projects = [
53
+ createProject({ id: '1', featured: true }),
54
+ createProject({ id: '2', featured: false }),
55
+ createProject({ id: '3', featured: true }),
56
+ ]
57
+
58
+ const result = filterByFeatured(projects, true)
59
+
60
+ expect(result).toHaveLength(2)
61
+ expect(result.map(p => p.id)).toEqual(['1', '3'])
62
+ })
63
+
64
+ it('should filter projects with featured=false', () => {
65
+ const projects = [
66
+ createProject({ id: '1', featured: true }),
67
+ createProject({ id: '2', featured: false }),
68
+ createProject({ id: '3', featured: false }),
69
+ ]
70
+
71
+ const result = filterByFeatured(projects, false)
72
+
73
+ expect(result).toHaveLength(2)
74
+ expect(result.map(p => p.id)).toEqual(['2', '3'])
75
+ })
76
+
77
+ it('should return empty array when no projects match featured=true', () => {
78
+ const projects = [
79
+ createProject({ featured: false }),
80
+ createProject({ featured: false }),
81
+ ]
82
+
83
+ const result = filterByFeatured(projects, true)
84
+
85
+ expect(result).toHaveLength(0)
86
+ })
87
+
88
+ it('should return empty array when no projects match featured=false', () => {
89
+ const projects = [
90
+ createProject({ featured: true }),
91
+ createProject({ featured: true }),
92
+ ]
93
+
94
+ const result = filterByFeatured(projects, false)
95
+
96
+ expect(result).toHaveLength(0)
97
+ })
98
+ })
99
+
100
+ describe('null and undefined featured parameter', () => {
101
+ it('should return all projects when featured is null', () => {
102
+ const projects = [
103
+ createProject({ id: '1', featured: true }),
104
+ createProject({ id: '2', featured: false }),
105
+ createProject({ id: '3', featured: true }),
106
+ ]
107
+
108
+ const result = filterByFeatured(projects, null)
109
+
110
+ expect(result).toHaveLength(3)
111
+ })
112
+
113
+ it('should return all projects when featured is undefined', () => {
114
+ const projects = [
115
+ createProject({ id: '1', featured: true }),
116
+ createProject({ id: '2', featured: false }),
117
+ ]
118
+
119
+ const result = filterByFeatured(projects, undefined)
120
+
121
+ expect(result).toHaveLength(2)
122
+ })
123
+ })
124
+
125
+ describe('immutability', () => {
126
+ it('should not mutate the original array', () => {
127
+ const projects = [
128
+ createProject({ id: '1', featured: true }),
129
+ createProject({ id: '2', featured: false }),
130
+ ]
131
+
132
+ const originalLength = projects.length
133
+ filterByFeatured(projects, true)
134
+
135
+ expect(projects.length).toBe(originalLength)
136
+ })
137
+
138
+ it('should return a new array instance', () => {
139
+ const projects = [createProject({ featured: true })]
140
+
141
+ const result = filterByFeatured(projects, null)
142
+
143
+ expect(result).not.toBe(projects)
144
+ })
145
+ })
146
+ })
@@ -0,0 +1,193 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { filterByStatus } from '../filterByStatus'
3
+ import type { FolioProject, ProjectStatus } from '../../types'
4
+
5
+ function createProject(overrides: Partial<FolioProject> = {}): FolioProject {
6
+ return {
7
+ id: 'test-id',
8
+ type: 'github',
9
+ status: 'active',
10
+ featured: false,
11
+ name: 'Test Project',
12
+ tagline: '',
13
+ description: '',
14
+ background: null,
15
+ why: null,
16
+ image: null,
17
+ struggles: [],
18
+ timeline: [],
19
+ posts: [],
20
+ stack: [],
21
+ links: {},
22
+ stats: null,
23
+ language: null,
24
+ languageColor: null,
25
+ createdAt: null,
26
+ updatedAt: null,
27
+ ...overrides,
28
+ }
29
+ }
30
+
31
+ describe('filterByStatus', () => {
32
+ describe('empty array handling', () => {
33
+ it('should return empty array when input is empty', () => {
34
+ expect(filterByStatus([], 'active')).toEqual([])
35
+ })
36
+
37
+ it('should return empty array when input is empty and status is undefined', () => {
38
+ expect(filterByStatus([], undefined)).toEqual([])
39
+ })
40
+
41
+ it('should return empty array when input is empty and status is all', () => {
42
+ expect(filterByStatus([], 'all')).toEqual([])
43
+ })
44
+ })
45
+
46
+ describe('status filtering with single status', () => {
47
+ it('should filter projects by active status', () => {
48
+ const projects = [
49
+ createProject({ id: '1', status: 'active' }),
50
+ createProject({ id: '2', status: 'shipped' }),
51
+ createProject({ id: '3', status: 'active' }),
52
+ ]
53
+
54
+ const result = filterByStatus(projects, 'active')
55
+
56
+ expect(result).toHaveLength(2)
57
+ expect(result.map(p => p.id)).toEqual(['1', '3'])
58
+ })
59
+
60
+ it('should filter projects by shipped status', () => {
61
+ const projects = [
62
+ createProject({ id: '1', status: 'active' }),
63
+ createProject({ id: '2', status: 'shipped' }),
64
+ createProject({ id: '3', status: 'in-progress' }),
65
+ ]
66
+
67
+ const result = filterByStatus(projects, 'shipped')
68
+
69
+ expect(result).toHaveLength(1)
70
+ expect(result[0].id).toBe('2')
71
+ })
72
+
73
+ it('should filter projects by archived status', () => {
74
+ const projects = [
75
+ createProject({ id: '1', status: 'active' }),
76
+ createProject({ id: '2', status: 'archived' }),
77
+ ]
78
+
79
+ const result = filterByStatus(projects, 'archived')
80
+
81
+ expect(result).toHaveLength(1)
82
+ expect(result[0].status).toBe('archived')
83
+ })
84
+
85
+ it('should filter projects by for-sale status', () => {
86
+ const projects = [
87
+ createProject({ id: '1', status: 'for-sale' }),
88
+ createProject({ id: '2', status: 'active' }),
89
+ ]
90
+
91
+ const result = filterByStatus(projects, 'for-sale')
92
+
93
+ expect(result).toHaveLength(1)
94
+ expect(result[0].status).toBe('for-sale')
95
+ })
96
+
97
+ it('should return empty array when no projects match status', () => {
98
+ const projects = [
99
+ createProject({ status: 'active' }),
100
+ createProject({ status: 'shipped' }),
101
+ ]
102
+
103
+ const result = filterByStatus(projects, 'archived')
104
+
105
+ expect(result).toHaveLength(0)
106
+ })
107
+ })
108
+
109
+ describe('status filtering with array of statuses', () => {
110
+ it('should filter projects by multiple statuses', () => {
111
+ const projects = [
112
+ createProject({ id: '1', status: 'active' }),
113
+ createProject({ id: '2', status: 'shipped' }),
114
+ createProject({ id: '3', status: 'archived' }),
115
+ createProject({ id: '4', status: 'in-progress' }),
116
+ ]
117
+
118
+ const result = filterByStatus(projects, ['active', 'shipped'] as ProjectStatus[])
119
+
120
+ expect(result).toHaveLength(2)
121
+ expect(result.map(p => p.id)).toEqual(['1', '2'])
122
+ })
123
+
124
+ it('should handle empty status array', () => {
125
+ const projects = [
126
+ createProject({ id: '1', status: 'active' }),
127
+ ]
128
+
129
+ const result = filterByStatus(projects, [])
130
+
131
+ expect(result).toHaveLength(0)
132
+ })
133
+
134
+ it('should filter by all valid status values', () => {
135
+ const allStatuses: ProjectStatus[] = ['active', 'shipped', 'in-progress', 'coming-soon', 'archived', 'for-sale']
136
+ const projects = allStatuses.map((status, i) => createProject({ id: String(i), status }))
137
+
138
+ const result = filterByStatus(projects, ['active', 'shipped', 'archived'] as ProjectStatus[])
139
+
140
+ expect(result).toHaveLength(3)
141
+ expect(result.map(p => p.status)).toEqual(['active', 'shipped', 'archived'])
142
+ })
143
+ })
144
+
145
+ describe('special status values', () => {
146
+ it('should return all projects when status is "all"', () => {
147
+ const projects = [
148
+ createProject({ id: '1', status: 'active' }),
149
+ createProject({ id: '2', status: 'shipped' }),
150
+ createProject({ id: '3', status: 'archived' }),
151
+ ]
152
+
153
+ const result = filterByStatus(projects, 'all')
154
+
155
+ expect(result).toHaveLength(3)
156
+ })
157
+
158
+ it('should return all projects when status is undefined', () => {
159
+ const projects = [
160
+ createProject({ id: '1', status: 'active' }),
161
+ createProject({ id: '2', status: 'shipped' }),
162
+ ]
163
+
164
+ const result = filterByStatus(projects, undefined)
165
+
166
+ expect(result).toHaveLength(2)
167
+ })
168
+ })
169
+
170
+ describe('immutability', () => {
171
+ it('should not mutate the original array', () => {
172
+ const projects = [
173
+ createProject({ id: '1', status: 'active' }),
174
+ createProject({ id: '2', status: 'shipped' }),
175
+ ]
176
+
177
+ const originalLength = projects.length
178
+ filterByStatus(projects, 'active')
179
+
180
+ expect(projects.length).toBe(originalLength)
181
+ })
182
+
183
+ it('should return a new array instance', () => {
184
+ const projects = [
185
+ createProject({ status: 'active' }),
186
+ ]
187
+
188
+ const result = filterByStatus(projects, 'all')
189
+
190
+ expect(result).not.toBe(projects)
191
+ })
192
+ })
193
+ })
@@ -0,0 +1,182 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { filterByType } from '../filterByType'
3
+ import type { FolioProject, ProjectType } from '../../types'
4
+
5
+ function createProject(overrides: Partial<FolioProject> = {}): FolioProject {
6
+ return {
7
+ id: 'test-id',
8
+ type: 'github',
9
+ status: 'active',
10
+ featured: false,
11
+ name: 'Test Project',
12
+ tagline: '',
13
+ description: '',
14
+ background: null,
15
+ why: null,
16
+ image: null,
17
+ struggles: [],
18
+ timeline: [],
19
+ posts: [],
20
+ stack: [],
21
+ links: {},
22
+ stats: null,
23
+ language: null,
24
+ languageColor: null,
25
+ createdAt: null,
26
+ updatedAt: null,
27
+ ...overrides,
28
+ }
29
+ }
30
+
31
+ describe('filterByType', () => {
32
+ describe('empty array handling', () => {
33
+ it('should return empty array when input is empty', () => {
34
+ expect(filterByType([], 'github')).toEqual([])
35
+ })
36
+
37
+ it('should return empty array when input is empty and type is undefined', () => {
38
+ expect(filterByType([], undefined)).toEqual([])
39
+ })
40
+
41
+ it('should return empty array when input is empty and type is all', () => {
42
+ expect(filterByType([], 'all')).toEqual([])
43
+ })
44
+ })
45
+
46
+ describe('type filtering', () => {
47
+ it('should filter projects by github type', () => {
48
+ const projects = [
49
+ createProject({ id: '1', type: 'github' }),
50
+ createProject({ id: '2', type: 'manual' }),
51
+ createProject({ id: '3', type: 'github' }),
52
+ ]
53
+
54
+ const result = filterByType(projects, 'github')
55
+
56
+ expect(result).toHaveLength(2)
57
+ expect(result.map(p => p.id)).toEqual(['1', '3'])
58
+ })
59
+
60
+ it('should filter projects by npm type', () => {
61
+ const projects = [
62
+ createProject({ id: '1', type: 'github' }),
63
+ createProject({ id: '2', type: 'npm' }),
64
+ createProject({ id: '3', type: 'npm' }),
65
+ ]
66
+
67
+ const result = filterByType(projects, 'npm')
68
+
69
+ expect(result).toHaveLength(2)
70
+ expect(result.map(p => p.id)).toEqual(['2', '3'])
71
+ })
72
+
73
+ it('should filter projects by product-hunt type', () => {
74
+ const projects = [
75
+ createProject({ id: '1', type: 'product-hunt' }),
76
+ createProject({ id: '2', type: 'github' }),
77
+ ]
78
+
79
+ const result = filterByType(projects, 'product-hunt')
80
+
81
+ expect(result).toHaveLength(1)
82
+ expect(result[0].type).toBe('product-hunt')
83
+ })
84
+
85
+ it('should filter projects by hybrid type', () => {
86
+ const projects = [
87
+ createProject({ id: '1', type: 'hybrid' }),
88
+ createProject({ id: '2', type: 'github' }),
89
+ createProject({ id: '3', type: 'hybrid' }),
90
+ ]
91
+
92
+ const result = filterByType(projects, 'hybrid')
93
+
94
+ expect(result).toHaveLength(2)
95
+ expect(result.map(p => p.type)).toEqual(['hybrid', 'hybrid'])
96
+ })
97
+
98
+ it('should filter projects by manual type', () => {
99
+ const projects = [
100
+ createProject({ id: '1', type: 'manual' }),
101
+ createProject({ id: '2', type: 'github' }),
102
+ ]
103
+
104
+ const result = filterByType(projects, 'manual')
105
+
106
+ expect(result).toHaveLength(1)
107
+ expect(result[0].type).toBe('manual')
108
+ })
109
+
110
+ it('should return empty array when no projects match type', () => {
111
+ const projects = [
112
+ createProject({ type: 'github' }),
113
+ createProject({ type: 'npm' }),
114
+ ]
115
+
116
+ const result = filterByType(projects, 'manual')
117
+
118
+ expect(result).toHaveLength(0)
119
+ })
120
+ })
121
+
122
+ describe('all types coverage', () => {
123
+ it('should correctly filter for all ProjectType values', () => {
124
+ const allTypes: ProjectType[] = ['github', 'npm', 'product-hunt', 'hybrid', 'manual']
125
+
126
+ allTypes.forEach(targetType => {
127
+ const projects = allTypes.map((type, i) => createProject({ id: String(i), type }))
128
+ const result = filterByType(projects, targetType)
129
+
130
+ expect(result).toHaveLength(1)
131
+ expect(result[0].type).toBe(targetType)
132
+ })
133
+ })
134
+ })
135
+
136
+ describe('special type values', () => {
137
+ it('should return all projects when type is "all"', () => {
138
+ const projects = [
139
+ createProject({ id: '1', type: 'github' }),
140
+ createProject({ id: '2', type: 'npm' }),
141
+ createProject({ id: '3', type: 'manual' }),
142
+ ]
143
+
144
+ const result = filterByType(projects, 'all')
145
+
146
+ expect(result).toHaveLength(3)
147
+ })
148
+
149
+ it('should return all projects when type is undefined', () => {
150
+ const projects = [
151
+ createProject({ id: '1', type: 'github' }),
152
+ createProject({ id: '2', type: 'npm' }),
153
+ ]
154
+
155
+ const result = filterByType(projects, undefined)
156
+
157
+ expect(result).toHaveLength(2)
158
+ })
159
+ })
160
+
161
+ describe('immutability', () => {
162
+ it('should not mutate the original array', () => {
163
+ const projects = [
164
+ createProject({ id: '1', type: 'github' }),
165
+ createProject({ id: '2', type: 'npm' }),
166
+ ]
167
+
168
+ const originalLength = projects.length
169
+ filterByType(projects, 'github')
170
+
171
+ expect(projects.length).toBe(originalLength)
172
+ })
173
+
174
+ it('should return a new array instance', () => {
175
+ const projects = [createProject({ type: 'github' })]
176
+
177
+ const result = filterByType(projects, 'all')
178
+
179
+ expect(result).not.toBe(projects)
180
+ })
181
+ })
182
+ })