@adobe-commerce/elsie 1.0.0-alpha04071347

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 (340) hide show
  1. package/.elsie.js +21 -0
  2. package/.eslintrc.js +18 -0
  3. package/README.md +52 -0
  4. package/__mocks__/svg.js +11 -0
  5. package/bin/builders/build/index.js +20 -0
  6. package/bin/builders/generate/api/index.js +65 -0
  7. package/bin/builders/generate/api/templates/function.js +9 -0
  8. package/bin/builders/generate/api/templates/index.js +7 -0
  9. package/bin/builders/generate/api/templates/story.js +23 -0
  10. package/bin/builders/generate/api/templates/unit-test.js +15 -0
  11. package/bin/builders/generate/component/index.js +87 -0
  12. package/bin/builders/generate/component/templates/Component.js +43 -0
  13. package/bin/builders/generate/component/templates/css.js +24 -0
  14. package/bin/builders/generate/component/templates/index.js +8 -0
  15. package/bin/builders/generate/component/templates/stories.js +46 -0
  16. package/bin/builders/generate/component/templates/unit-test.js +19 -0
  17. package/bin/builders/generate/config/index.js +54 -0
  18. package/bin/builders/generate/config/templates/elsie.js +29 -0
  19. package/bin/builders/generate/container/index.js +65 -0
  20. package/bin/builders/generate/container/templates/Component.js +18 -0
  21. package/bin/builders/generate/container/templates/index.js +8 -0
  22. package/bin/builders/generate/container/templates/stories.js +34 -0
  23. package/bin/builders/generate/container/templates/unit-test.js +19 -0
  24. package/bin/builders/generate/index.js +283 -0
  25. package/bin/builders/gql/createOrClearDirectory.js +33 -0
  26. package/bin/builders/gql/getSchemaRef.js +25 -0
  27. package/bin/builders/gql/index.js +71 -0
  28. package/bin/builders/lint/index.js +5 -0
  29. package/bin/builders/serve/index.js +44 -0
  30. package/bin/builders/storybook/index.js +5 -0
  31. package/bin/builders/test/index.js +5 -0
  32. package/bin/index.js +26 -0
  33. package/bin/lib/cli.js +8 -0
  34. package/bin/lib/config.js +12 -0
  35. package/bin/lib/log-message.js +11 -0
  36. package/bin/lib/string.js +26 -0
  37. package/bin/lib/validate-typeof.js +28 -0
  38. package/bin/lib/write-file.js +30 -0
  39. package/bin/lib/write-parent-index.js +45 -0
  40. package/config/eslint.js +113 -0
  41. package/config/jest.js +90 -0
  42. package/config/prettier.js +16 -0
  43. package/config/setEnvVars.js +14 -0
  44. package/config/storybook/addon.js +130 -0
  45. package/config/storybook/components/FileTree/FileTree.jsx +192 -0
  46. package/config/storybook/components/FileTree/index.js +10 -0
  47. package/config/storybook/components/Flex/Flex.jsx +21 -0
  48. package/config/storybook/components/Flex/Flex.module.css +29 -0
  49. package/config/storybook/components/Flex/index.js +10 -0
  50. package/config/storybook/components/OptionsTable/OptionsTable.jsx +88 -0
  51. package/config/storybook/components/OptionsTable/OptionsTable.module.css +104 -0
  52. package/config/storybook/components/OptionsTable/index.js +10 -0
  53. package/config/storybook/components/Panel/Panel.module.css +56 -0
  54. package/config/storybook/components/Panel/Panel.tsx +46 -0
  55. package/config/storybook/components/Panel/index.ts +10 -0
  56. package/config/storybook/components/Screenshot/Screenshot.jsx +23 -0
  57. package/config/storybook/components/Screenshot/Screenshot.module.css +28 -0
  58. package/config/storybook/components/Screenshot/index.js +10 -0
  59. package/config/storybook/components/Steps/Steps.jsx +21 -0
  60. package/config/storybook/components/Steps/Steps.module.css +43 -0
  61. package/config/storybook/components/Steps/index.js +10 -0
  62. package/config/storybook/components/StoryWrapper/StoryWrapper.jsx +18 -0
  63. package/config/storybook/components/StoryWrapper/StoryWrapper.module.css +22 -0
  64. package/config/storybook/components/StoryWrapper/index.js +10 -0
  65. package/config/storybook/components/Summary/Summary.jsx +19 -0
  66. package/config/storybook/components/Summary/Summary.module.css +20 -0
  67. package/config/storybook/components/Summary/index.js +10 -0
  68. package/config/storybook/components/Variants/Variants.js +57 -0
  69. package/config/storybook/components/Variants/docs.css +48 -0
  70. package/config/storybook/components/Variants/index.js +10 -0
  71. package/config/storybook/components/video/index.jsx +28 -0
  72. package/config/storybook/manager.js +23 -0
  73. package/config/storybook/preview.jsx +88 -0
  74. package/config/storybook/theming/fonts.css +68 -0
  75. package/config/storybook/theming/logo.svg +19 -0
  76. package/config/storybook/theming/manager.css +63 -0
  77. package/config/storybook/theming/preview.css +93 -0
  78. package/config/storybook/theming/theme.js +61 -0
  79. package/config/tsconfig-base.json +16 -0
  80. package/config/tsconfig-preact.json +15 -0
  81. package/config/vite.mjs +306 -0
  82. package/package.json +113 -0
  83. package/post-release.sh +5 -0
  84. package/src/components/Accordion/Accordion.css +88 -0
  85. package/src/components/Accordion/Accordion.stories.tsx +582 -0
  86. package/src/components/Accordion/Accordion.tsx +177 -0
  87. package/src/components/Accordion/index.ts +11 -0
  88. package/src/components/ActionButton/ActionButton.css +100 -0
  89. package/src/components/ActionButton/ActionButton.stories.tsx +169 -0
  90. package/src/components/ActionButton/ActionButton.tsx +53 -0
  91. package/src/components/ActionButton/index.ts +10 -0
  92. package/src/components/ActionButtonGroup/ActionButtonGroup.css +77 -0
  93. package/src/components/ActionButtonGroup/ActionButtonGroup.stories.tsx +97 -0
  94. package/src/components/ActionButtonGroup/ActionButtonGroup.tsx +91 -0
  95. package/src/components/ActionButtonGroup/index.ts +10 -0
  96. package/src/components/AlertBanner/AlertBanner.css +144 -0
  97. package/src/components/AlertBanner/AlertBanner.stories.tsx +165 -0
  98. package/src/components/AlertBanner/AlertBanner.tsx +90 -0
  99. package/src/components/AlertBanner/index.ts +11 -0
  100. package/src/components/Breadcrumbs/Breadcrumbs.css +60 -0
  101. package/src/components/Breadcrumbs/Breadcrumbs.stories.tsx +195 -0
  102. package/src/components/Breadcrumbs/Breadcrumbs.tsx +71 -0
  103. package/src/components/Breadcrumbs/index.ts +11 -0
  104. package/src/components/Button/Button.css +213 -0
  105. package/src/components/Button/Button.mdx +133 -0
  106. package/src/components/Button/Button.stories.tsx +398 -0
  107. package/src/components/Button/Button.tsx +121 -0
  108. package/src/components/Button/index.ts +11 -0
  109. package/src/components/Card/Card.css +34 -0
  110. package/src/components/Card/Card.stories.tsx +76 -0
  111. package/src/components/Card/Card.tsx +34 -0
  112. package/src/components/Card/index.ts +10 -0
  113. package/src/components/CartItem/CartItem.css +509 -0
  114. package/src/components/CartItem/CartItem.stories.tsx +628 -0
  115. package/src/components/CartItem/CartItem.tsx +467 -0
  116. package/src/components/CartItem/CartItemSkeleton.tsx +38 -0
  117. package/src/components/CartItem/index.ts +12 -0
  118. package/src/components/CartList/CartList.css +35 -0
  119. package/src/components/CartList/CartList.stories.tsx +111 -0
  120. package/src/components/CartList/CartList.tsx +40 -0
  121. package/src/components/CartList/index.ts +11 -0
  122. package/src/components/Checkbox/Checkbox.css +255 -0
  123. package/src/components/Checkbox/Checkbox.stories.tsx +290 -0
  124. package/src/components/Checkbox/Checkbox.tsx +138 -0
  125. package/src/components/Checkbox/index.ts +10 -0
  126. package/src/components/ColorSwatch/ColorSwatch.css +132 -0
  127. package/src/components/ColorSwatch/ColorSwatch.stories.tsx +274 -0
  128. package/src/components/ColorSwatch/ColorSwatch.tsx +127 -0
  129. package/src/components/ColorSwatch/index.ts +11 -0
  130. package/src/components/ContentGrid/ContentGrid.css +54 -0
  131. package/src/components/ContentGrid/ContentGrid.stories.tsx +137 -0
  132. package/src/components/ContentGrid/ContentGrid.tsx +57 -0
  133. package/src/components/ContentGrid/index.ts +11 -0
  134. package/src/components/Divider/Divider.css +22 -0
  135. package/src/components/Divider/Divider.stories.tsx +62 -0
  136. package/src/components/Divider/Divider.tsx +33 -0
  137. package/src/components/Divider/index.ts +11 -0
  138. package/src/components/Field/Field.css +83 -0
  139. package/src/components/Field/Field.stories.tsx +238 -0
  140. package/src/components/Field/Field.tsx +84 -0
  141. package/src/components/Field/index.ts +10 -0
  142. package/src/components/Header/Header.css +56 -0
  143. package/src/components/Header/Header.stories.tsx +180 -0
  144. package/src/components/Header/Header.tsx +81 -0
  145. package/src/components/Header/index.ts +11 -0
  146. package/src/components/Icon/Icon.css +26 -0
  147. package/src/components/Icon/Icon.stories.helpers.jsx +21 -0
  148. package/src/components/Icon/Icon.stories.tsx +98 -0
  149. package/src/components/Icon/Icon.tsx +112 -0
  150. package/src/components/Icon/index.ts +10 -0
  151. package/src/components/IllustratedMessage/IllustratedMessage.css +61 -0
  152. package/src/components/IllustratedMessage/IllustratedMessage.stories.tsx +126 -0
  153. package/src/components/IllustratedMessage/IllustratedMessage.tsx +78 -0
  154. package/src/components/IllustratedMessage/index.ts +11 -0
  155. package/src/components/Image/Image.css +52 -0
  156. package/src/components/Image/Image.stories.tsx +89 -0
  157. package/src/components/Image/Image.tsx +66 -0
  158. package/src/components/Image/index.ts +10 -0
  159. package/src/components/ImageSwatch/ImageSwatch.css +154 -0
  160. package/src/components/ImageSwatch/ImageSwatch.stories.tsx +310 -0
  161. package/src/components/ImageSwatch/ImageSwatch.tsx +123 -0
  162. package/src/components/ImageSwatch/index.ts +11 -0
  163. package/src/components/InLineAlert/InLineAlert.css +116 -0
  164. package/src/components/InLineAlert/InLineAlert.stories.tsx +326 -0
  165. package/src/components/InLineAlert/InLineAlert.tsx +128 -0
  166. package/src/components/InLineAlert/index.ts +11 -0
  167. package/src/components/Incrementer/Incrementer.css +165 -0
  168. package/src/components/Incrementer/Incrementer.stories.tsx +172 -0
  169. package/src/components/Incrementer/Incrementer.tsx +192 -0
  170. package/src/components/Incrementer/index.ts +10 -0
  171. package/src/components/Input/Input.css +304 -0
  172. package/src/components/Input/Input.stories.tsx +155 -0
  173. package/src/components/Input/Input.tsx +166 -0
  174. package/src/components/Input/index.ts +11 -0
  175. package/src/components/InputDate/InputDate.css +56 -0
  176. package/src/components/InputDate/InputDate.stories.tsx +117 -0
  177. package/src/components/InputDate/InputDate.tsx +120 -0
  178. package/src/components/InputDate/index.ts +11 -0
  179. package/src/components/InputPassword/InputPassword.css +31 -0
  180. package/src/components/InputPassword/InputPassword.stories.tsx +148 -0
  181. package/src/components/InputPassword/InputPassword.tsx +135 -0
  182. package/src/components/InputPassword/PasswordStatusIndicator/PasswordStatusIndicator.css +31 -0
  183. package/src/components/InputPassword/PasswordStatusIndicator/PasswordStatusIndicator.tsx +96 -0
  184. package/src/components/InputPassword/PasswordStatusIndicator/index.ts +11 -0
  185. package/src/components/InputPassword/index.ts +11 -0
  186. package/src/components/Modal/Modal.css +125 -0
  187. package/src/components/Modal/Modal.stories.tsx +250 -0
  188. package/src/components/Modal/Modal.tsx +157 -0
  189. package/src/components/Modal/index.ts +10 -0
  190. package/src/components/Pagination/Pagination.css +95 -0
  191. package/src/components/Pagination/Pagination.stories.tsx +117 -0
  192. package/src/components/Pagination/Pagination.tsx +149 -0
  193. package/src/components/Pagination/index.ts +11 -0
  194. package/src/components/Picker/Picker.css +220 -0
  195. package/src/components/Picker/Picker.stories.tsx +318 -0
  196. package/src/components/Picker/Picker.tsx +203 -0
  197. package/src/components/Picker/index.ts +10 -0
  198. package/src/components/Price/Price.css +57 -0
  199. package/src/components/Price/Price.stories.tsx +110 -0
  200. package/src/components/Price/Price.tsx +75 -0
  201. package/src/components/Price/index.ts +10 -0
  202. package/src/components/PriceRange/PriceRange.css +66 -0
  203. package/src/components/PriceRange/PriceRange.stories.tsx +240 -0
  204. package/src/components/PriceRange/PriceRange.tsx +248 -0
  205. package/src/components/PriceRange/index.ts +11 -0
  206. package/src/components/ProgressSpinner/ProgressSpinner.css +91 -0
  207. package/src/components/ProgressSpinner/ProgressSpinner.stories.tsx +300 -0
  208. package/src/components/ProgressSpinner/ProgressSpinner.tsx +86 -0
  209. package/src/components/ProgressSpinner/index.ts +11 -0
  210. package/src/components/RadioButton/RadioButton.css +134 -0
  211. package/src/components/RadioButton/RadioButton.stories.tsx +126 -0
  212. package/src/components/RadioButton/RadioButton.tsx +86 -0
  213. package/src/components/RadioButton/index.ts +11 -0
  214. package/src/components/Skeleton/Skeleton.css +145 -0
  215. package/src/components/Skeleton/Skeleton.stories.tsx +265 -0
  216. package/src/components/Skeleton/Skeleton.tsx +133 -0
  217. package/src/components/Skeleton/index.ts +10 -0
  218. package/src/components/Tag/Tag.css +26 -0
  219. package/src/components/Tag/Tag.stories.tsx +103 -0
  220. package/src/components/Tag/Tag.tsx +38 -0
  221. package/src/components/Tag/index.ts +11 -0
  222. package/src/components/TextArea/TextArea.css +140 -0
  223. package/src/components/TextArea/TextArea.stories.tsx +130 -0
  224. package/src/components/TextArea/TextArea.tsx +89 -0
  225. package/src/components/TextArea/index.ts +11 -0
  226. package/src/components/TextSwatch/TextSwatch.css +152 -0
  227. package/src/components/TextSwatch/TextSwatch.stories.tsx +277 -0
  228. package/src/components/TextSwatch/TextSwatch.tsx +131 -0
  229. package/src/components/TextSwatch/index.ts +11 -0
  230. package/src/components/ToggleButton/ToggleButton.css +95 -0
  231. package/src/components/ToggleButton/ToggleButton.stories.tsx +190 -0
  232. package/src/components/ToggleButton/ToggleButton.tsx +75 -0
  233. package/src/components/ToggleButton/index.ts +11 -0
  234. package/src/components/UIProvider/UIProvider.css +140 -0
  235. package/src/components/UIProvider/UIProvider.tsx +61 -0
  236. package/src/components/UIProvider/debugger.css +47 -0
  237. package/src/components/UIProvider/index.ts +10 -0
  238. package/src/components/UIProvider/normalize.css +26 -0
  239. package/src/components/index.ts +49 -0
  240. package/src/docs/API/event-bus.mdx +52 -0
  241. package/src/docs/API/graphql.mdx +214 -0
  242. package/src/docs/API/initializer.mdx +119 -0
  243. package/src/docs/API/render.mdx +125 -0
  244. package/src/docs/Design/colors.mdx +202 -0
  245. package/src/docs/Design/designBlocks.jsx +87 -0
  246. package/src/docs/Design/getTokenData.ts +28 -0
  247. package/src/docs/Design/grid.mdx +365 -0
  248. package/src/docs/Design/overview.mdx +69 -0
  249. package/src/docs/Design/shapes.mdx +100 -0
  250. package/src/docs/Design/spacing.mdx +22 -0
  251. package/src/docs/Design/typography.mdx +126 -0
  252. package/src/docs/Utilities/classList.mdx +52 -0
  253. package/src/docs/Utilities/debounce.mdx +49 -0
  254. package/src/docs/Utilities/deepmerge.mdx +12 -0
  255. package/src/docs/Utilities/getFormErrors.mdx +41 -0
  256. package/src/docs/Utilities/getFormValues.mdx +38 -0
  257. package/src/docs/assets/Banner.png +0 -0
  258. package/src/docs/assets/Colors.png +0 -0
  259. package/src/docs/assets/DropinBanner.png +0 -0
  260. package/src/docs/assets/ShapeStyles.png +0 -0
  261. package/src/docs/assets/Spacing.png +0 -0
  262. package/src/docs/assets/Typography.png +0 -0
  263. package/src/docs/cli-usage.mdx +181 -0
  264. package/src/docs/components/overview.mdx +124 -0
  265. package/src/docs/quick-start.mdx +245 -0
  266. package/src/docs/slots.mdx +211 -0
  267. package/src/docs/welcome.mdx +52 -0
  268. package/src/i18n/en_US.json +146 -0
  269. package/src/i18n/index.ts +26 -0
  270. package/src/icons/Add.svg +9 -0
  271. package/src/icons/AddressBook.svg +3 -0
  272. package/src/icons/Bulk.svg +24 -0
  273. package/src/icons/Burger.svg +5 -0
  274. package/src/icons/Card.svg +7 -0
  275. package/src/icons/Cart.svg +11 -0
  276. package/src/icons/Check.svg +8 -0
  277. package/src/icons/CheckWithCircle.svg +4 -0
  278. package/src/icons/ChevronDown.svg +3 -0
  279. package/src/icons/ChevronRight.svg +8 -0
  280. package/src/icons/ChevronUp.svg +3 -0
  281. package/src/icons/Close.svg +4 -0
  282. package/src/icons/Coupon.svg +3 -0
  283. package/src/icons/Date.svg +4 -0
  284. package/src/icons/Delivery.svg +11 -0
  285. package/src/icons/EmptyBox.svg +3 -0
  286. package/src/icons/Eye.svg +3 -0
  287. package/src/icons/EyeClose.svg +3 -0
  288. package/src/icons/Gift.svg +3 -0
  289. package/src/icons/GiftCard.svg +3 -0
  290. package/src/icons/Heart.svg +3 -0
  291. package/src/icons/HeartFilled.svg +3 -0
  292. package/src/icons/InfoFilled.svg +3 -0
  293. package/src/icons/Locker.svg +11 -0
  294. package/src/icons/Minus.svg +3 -0
  295. package/src/icons/Order.svg +6 -0
  296. package/src/icons/OrderError.svg +15 -0
  297. package/src/icons/OrderSuccess.svg +15 -0
  298. package/src/icons/PaymentError.svg +16 -0
  299. package/src/icons/Placeholder.svg +3 -0
  300. package/src/icons/PlaceholderFilled.svg +4 -0
  301. package/src/icons/Search.svg +9 -0
  302. package/src/icons/SearchFilled.svg +10 -0
  303. package/src/icons/Sort.svg +12 -0
  304. package/src/icons/Star.svg +8 -0
  305. package/src/icons/Trash.svg +7 -0
  306. package/src/icons/User.svg +5 -0
  307. package/src/icons/View.svg +14 -0
  308. package/src/icons/Wallet.svg +6 -0
  309. package/src/icons/Warning.svg +12 -0
  310. package/src/icons/WarningFilled.svg +3 -0
  311. package/src/icons/WarningWithCircle.svg +4 -0
  312. package/src/icons/index.ts +42 -0
  313. package/src/lib/classes.ts +34 -0
  314. package/src/lib/config.ts +24 -0
  315. package/src/lib/debounce.ts +16 -0
  316. package/src/lib/deepmerge.ts +45 -0
  317. package/src/lib/deviceUtils.ts +16 -0
  318. package/src/lib/form-values.ts +31 -0
  319. package/src/lib/i18n.ts +18 -0
  320. package/src/lib/image-params-keymap.ts +36 -0
  321. package/src/lib/index.ts +24 -0
  322. package/src/lib/initializer.ts +134 -0
  323. package/src/lib/is-number.ts +12 -0
  324. package/src/lib/render.tsx +138 -0
  325. package/src/lib/resolve-image.ts +101 -0
  326. package/src/lib/signals.ts +11 -0
  327. package/src/lib/slot.tsx +434 -0
  328. package/src/lib/tests.tsx +47 -0
  329. package/src/lib/types.ts +16 -0
  330. package/src/lib/vcomponent.tsx +42 -0
  331. package/static/assets/images/Card.png +0 -0
  332. package/static/assets/images/example.jpg +0 -0
  333. package/static/assets/images/index.ts +11 -0
  334. package/static/dropin.png +0 -0
  335. package/static/favicon.svg +14 -0
  336. package/storybook-stories.js +21 -0
  337. package/tests/__mocks__/browserMocks.ts +28 -0
  338. package/tests/__mocks__/fileMocks.ts +12 -0
  339. package/tests/__mocks__/styleMock.ts +0 -0
  340. package/types/icons.d.ts +18 -0
@@ -0,0 +1,34 @@
1
+ const { source } = require('common-tags');
2
+
3
+ module.exports = ({ pathname, basename, importPath = '.' }) => {
4
+ return `${source`
5
+ // https://storybook.js.org/docs/7.0/preact/writing-stories/introduction
6
+ import type { Meta, StoryObj } from '@storybook/preact';
7
+ import { ${basename} as component, ${basename}Props } from '${importPath}';
8
+
9
+ const meta: Meta<${basename}Props> = {
10
+ title: 'Containers/${pathname}',
11
+ component,
12
+ tags: ['autodocs'],
13
+ parameters: {
14
+ layout: 'centered', // centered | fullscreen
15
+ },
16
+ };
17
+
18
+ export default meta;
19
+
20
+ type Story = StoryObj<${basename}Props>;
21
+
22
+ /**
23
+ * \`\`\`ts
24
+ * import { ${basename} } from '${importPath}';
25
+ * \`\`\`
26
+ */
27
+
28
+ export const ${basename}: Story = {
29
+ args: {
30
+ children: "👋 Howdy, I'm Howdy!",
31
+ },
32
+ };
33
+ `}\n`;
34
+ };
@@ -0,0 +1,19 @@
1
+ const { source } = require('common-tags');
2
+
3
+ module.exports = ({ name, basename, pathname, importPath = '.' }) => {
4
+ return `${source`
5
+ /** https://preactjs.com/guide/v10/preact-testing-library/ */
6
+
7
+ import { render } from '@adobe-commerce/elsie/lib/tests';
8
+
9
+ import { ${basename} } from '${importPath}';
10
+
11
+ describe('${name}/Containers/${pathname}', () => {
12
+ test('renders', () => {
13
+ const { container } = render(<${basename} />);
14
+
15
+ expect(!!container).toEqual(true);
16
+ });
17
+ });
18
+ `}\n`;
19
+ };
@@ -0,0 +1,283 @@
1
+ const path = require('path');
2
+ const { toPascalCase, toCamelCase } = require('../../lib/string');
3
+ const m = require('../../lib/log-message');
4
+ const validateTypeOf = require('../../lib/validate-typeof');
5
+ const config = require('../../lib/config')();
6
+
7
+ module.exports = function generateResourceBuilder(yargs) {
8
+ yargs
9
+ .usage('usage: $0 generate <resource> [options]')
10
+
11
+ // Configuration
12
+ .command(
13
+ 'config',
14
+ 'Generate configuration file',
15
+ (yargs) => {
16
+ return yargs.options({
17
+ name: {
18
+ alias: 'n',
19
+ decription: 'Namespace of the project',
20
+ type: 'string',
21
+ demandOption: m('Missing project name.', 'error'),
22
+ },
23
+ force: {
24
+ description: 'Rewrite existing file',
25
+ type: 'boolean',
26
+ },
27
+ });
28
+ },
29
+ require('./config')
30
+ )
31
+
32
+ // New Api Function
33
+ .command(
34
+ 'api',
35
+ 'Generate a new API function',
36
+ (yargs) => {
37
+ return yargs
38
+ .options({
39
+ pathname: {
40
+ alias: 'n',
41
+ demandOption: true,
42
+ description: 'Resource pathname',
43
+ type: 'string',
44
+ },
45
+ force: {
46
+ description: 'Rewrite existing files',
47
+ type: 'boolean',
48
+ },
49
+ })
50
+ .check((args) => {
51
+ if (!config) {
52
+ throw new Error(
53
+ m(
54
+ 'Configuration file ".elsie.js" not found. Make sure you are in the root directory of your project or generate a new one.',
55
+ 'error'
56
+ )
57
+ );
58
+ }
59
+
60
+ if (!config.name) {
61
+ throw new Error(
62
+ m(`Missing \x1b[31mname\x1b[0m in "./.elsie.js".`, 'error')
63
+ );
64
+ }
65
+
66
+ const basename = path.basename(args.pathname);
67
+
68
+ // Is the configuration valid
69
+ const errors = validateTypeOf(config.api, {
70
+ root: { required: true, type: 'string' },
71
+ importAliasRoot: { type: 'string' },
72
+ });
73
+
74
+ if (errors.length) {
75
+ throw new Error(
76
+ errors
77
+ .map((e) =>
78
+ m(
79
+ `Invalid \x1b[31mapi.${e}\x1b[0m value "${config.api[e]}" in "./.elsie.js".`,
80
+ 'error'
81
+ )
82
+ )
83
+ .join('\n')
84
+ );
85
+ }
86
+
87
+ // Check the basename is camelCase
88
+ if (!/^[a-z]+([A-Z]|[a-z]|[0-9]+)+$/.test(basename)) {
89
+ throw new Error(
90
+ m(
91
+ `\x1b[4m${basename}\x1b[0m is not a valid API function name. Try naming your API function with camel case. i.e. \x1b[4m${toCamelCase(
92
+ basename
93
+ )}\x1b[0m`,
94
+ 'error'
95
+ )
96
+ );
97
+ }
98
+
99
+ return true;
100
+ }, false);
101
+ },
102
+ require('./api')
103
+ )
104
+
105
+ // New Component
106
+ .command(
107
+ 'component',
108
+ 'Generate a new UI Component',
109
+ (yargs) => {
110
+ return yargs
111
+ .options({
112
+ group: {
113
+ alias: 'g',
114
+ default: config?.components?.find((x) => x.default)?.id,
115
+ description: 'Components group',
116
+ choices: config?.components?.map((x) => x.id) || undefined,
117
+ },
118
+ pathname: {
119
+ alias: 'n',
120
+ demandOption: true,
121
+ description: 'Resource pathname',
122
+ type: 'string',
123
+ },
124
+ force: {
125
+ description: 'Rewrite existing files',
126
+ type: 'boolean',
127
+ },
128
+ })
129
+ .check((args) => {
130
+ if (!config) {
131
+ throw new Error(
132
+ m(
133
+ 'Configuration file ".elsie.js" not found. Make sure you are in the root directory of your project or generate a new one.',
134
+ 'error'
135
+ )
136
+ );
137
+ }
138
+
139
+ if (!args.group) {
140
+ throw new Error(m('Missing component group name.', 'error'));
141
+ }
142
+
143
+ if (!config.name) {
144
+ throw new Error(
145
+ m(`Missing \x1b[31mname\x1b[0m in "./.elsie.js".`, 'error')
146
+ );
147
+ }
148
+
149
+ const group = config.components.find((x) => x.id === args.group);
150
+ const basename = path.basename(args.pathname);
151
+
152
+ // Is the configuration valid
153
+ const errors = validateTypeOf(group, {
154
+ root: { required: true, type: 'string' },
155
+ importAliasRoot: { type: 'string' },
156
+ cssPrefix: {
157
+ required: !group.skipCSS,
158
+ type: 'string',
159
+ },
160
+ skipCSS: { type: 'boolean' },
161
+ default: { type: 'boolean' },
162
+ });
163
+
164
+ if (errors.length) {
165
+ throw new Error(
166
+ errors
167
+ .map((e) =>
168
+ m(
169
+ `Invalid \x1b[31mcomponents[${group.id}].${e}\x1b[0m value "${group[e]}" in "./.elsie.js".`,
170
+ 'error'
171
+ )
172
+ )
173
+ .join('\n')
174
+ );
175
+ }
176
+
177
+ // Check the basename is PascalCase
178
+ if (!/^([A-Z][a-z0-9]+)*[A-Z][a-z0-9]*$/.test(basename)) {
179
+ throw new Error(
180
+ m(
181
+ `\x1b[4m${basename}\x1b[0m is not a valid component name. Try naming your component with pascal case. i.e. \x1b[4m${toPascalCase(
182
+ basename
183
+ )}\x1b[0m`,
184
+ 'error'
185
+ )
186
+ );
187
+ }
188
+
189
+ return true;
190
+ }, false);
191
+ },
192
+ require('./component')
193
+ )
194
+
195
+ // New Container
196
+ .command(
197
+ 'container',
198
+ 'Generate a new Frontend Container',
199
+ (yargs) => {
200
+ return yargs
201
+ .options({
202
+ pathname: {
203
+ alias: 'n',
204
+ demandOption: true,
205
+ description: 'Resource pathname',
206
+ type: 'string',
207
+ },
208
+ force: {
209
+ description: 'Rewrite existing files',
210
+ type: 'boolean',
211
+ },
212
+ })
213
+ .check((args) => {
214
+ if (!config) {
215
+ throw new Error(
216
+ m(
217
+ 'Configuration file ".elsie.js" not found. Make sure you are in the root directory of your project or generate a new one.',
218
+ 'error'
219
+ )
220
+ );
221
+ }
222
+
223
+ if (!config.containers) {
224
+ throw new Error(
225
+ m(
226
+ `Missing \x1b[31mcontainers\x1b[0m in "./.elsie.js".`,
227
+ 'error'
228
+ )
229
+ );
230
+ }
231
+
232
+ if (!config.name) {
233
+ throw new Error(
234
+ m(`Missing \x1b[31mname\x1b[0m in "./.elsie.js".`, 'error')
235
+ );
236
+ }
237
+
238
+ const basename = path.basename(args.pathname);
239
+
240
+ // Is the configuration valid
241
+ const errors = validateTypeOf(config.containers, {
242
+ root: { required: true, type: 'string' },
243
+ importAliasRoot: { type: 'string' },
244
+ default: { type: 'boolean' },
245
+ });
246
+
247
+ if (errors.length) {
248
+ throw new Error(
249
+ errors
250
+ .map((e) =>
251
+ m(
252
+ `Invalid \x1b[31mcontainers.${e}\x1b[0m value "${config.containers[e]}" in "./.elsie.js".`,
253
+ 'error'
254
+ )
255
+ )
256
+ .join('\n')
257
+ );
258
+ }
259
+
260
+ // Check the basename is PascalCase
261
+ if (!/^([A-Z][a-z0-9]+)*[A-Z][a-z0-9]*$/.test(basename)) {
262
+ throw new Error(
263
+ m(
264
+ `\x1b[4m${basename}\x1b[0m is not a valid container name. Try naming your container with pascal case. i.e. \x1b[4m${toPascalCase(
265
+ basename
266
+ )}\x1b[0m`,
267
+ 'error'
268
+ )
269
+ );
270
+ }
271
+
272
+ return true;
273
+ }, false);
274
+ },
275
+ require('./container')
276
+ )
277
+
278
+ //
279
+ .updateStrings({
280
+ 'Commands:': 'Tools & Resources:',
281
+ })
282
+ .demandCommand();
283
+ };
@@ -0,0 +1,33 @@
1
+ const path = require('path');
2
+ const fsPromises = require('node:fs/promises');
3
+
4
+ module.exports = async function createOrClearDirectory(fileName) {
5
+ const directoryPath = path.join(process.cwd(), 'src/__generated__');
6
+
7
+ try {
8
+ // Check if the directory exists
9
+ const dirStats = await fsPromises.stat(directoryPath);
10
+
11
+ if (dirStats.isDirectory()) {
12
+ // If it's a directory, remove all files and subdirectories
13
+ const entries = await fsPromises.readdir(directoryPath);
14
+ for (const entry of entries) {
15
+ // If fileName is provided and it matches the current entry, remove it
16
+ // If fileName is not provided, remove all entries
17
+ if (!fileName || fileName === entry) {
18
+ const entryPath = path.join(directoryPath, entry);
19
+ await fsPromises.rm(entryPath, { recursive: true });
20
+ }
21
+ }
22
+ } else {
23
+ await fsPromises.mkdir(directoryPath, { recursive: true });
24
+ }
25
+ } catch (error) {
26
+ // If the directory doesn't exist, create it
27
+ if (error.code === 'ENOENT') {
28
+ await fsPromises.mkdir(directoryPath, { recursive: true });
29
+ } else {
30
+ throw error; // Re-throw any unexpected errors
31
+ }
32
+ }
33
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Returns the schema reference as defined in implementation's .elsie.js
3
+ *
4
+ * @see https://the-guild.dev/graphql/codegen/docs/config-reference/schema-field
5
+ * @returns [graphql-config.SchemaPointer] or [graphql-config.SchemaPointer[]]
6
+ */
7
+
8
+ const config = require('../../lib/config');
9
+
10
+ module.exports = function getSchemaRef() {
11
+ const { schema } = config();
12
+ if (!schema || !schema.endpoint) {
13
+ throw new Error('Missing schema.endpoint in .elsie.js');
14
+ }
15
+
16
+ return [
17
+ {
18
+ [schema.endpoint]: {
19
+ headers: {
20
+ ...(schema.headers || {}),
21
+ },
22
+ },
23
+ },
24
+ ];
25
+ };
@@ -0,0 +1,71 @@
1
+ const path = require('path');
2
+ const createOrClearDirectory = require('./createOrClearDirectory');
3
+ const getSchemaRef = require('./getSchemaRef');
4
+ require('dotenv').config();
5
+
6
+ const generate = require('@graphql-codegen/cli').generate;
7
+
8
+ module.exports = async function generateResourceBuilder(yargs) {
9
+ yargs
10
+ .command('types', 'Generate types', async () => {
11
+ await createOrClearDirectory('types.ts');
12
+ await generate(
13
+ {
14
+ schema: getSchemaRef(),
15
+ ignoreNoDocuments: true,
16
+ documents: [
17
+ `${path.resolve(process.cwd(), './src/**/*.graphql.ts')}`,
18
+ `!${path.resolve(process.cwd(), './src/__generated__/**')}`,
19
+ ],
20
+ generates: {
21
+ [`${path.resolve(process.cwd(), './src/__generated__/types.ts')}`]:
22
+ {
23
+ plugins: [
24
+ '@graphql-codegen/typescript',
25
+ '@graphql-codegen/typescript-operations',
26
+ ],
27
+ hooks: { afterOneFileWrite: ['prettier --write'] },
28
+ },
29
+ },
30
+ },
31
+ true
32
+ );
33
+ })
34
+ .command('mocks', 'Generate mocks and types', async () => {
35
+ await createOrClearDirectory();
36
+ await generate({
37
+ schema: getSchemaRef(),
38
+ ignoreNoDocuments: true,
39
+ documents: [
40
+ `${path.resolve(process.cwd(), './src/**/*.graphql.ts')}`,
41
+ `!${path.resolve(process.cwd(), './src/__generated__/**')}`,
42
+ ],
43
+ generates: {
44
+ [`${path.resolve(process.cwd(), './src/__generated__/types.ts')}`]: {
45
+ plugins: [
46
+ '@graphql-codegen/typescript',
47
+ '@graphql-codegen/typescript-operations',
48
+ ],
49
+ hooks: { afterOneFileWrite: ['prettier --write'] },
50
+ },
51
+ [`${path.resolve(process.cwd(), './src/__generated__/mocks.ts')}`]: {
52
+ plugins: [
53
+ {
54
+ 'typescript-mock-data': {
55
+ addTypename: true,
56
+ prefix: 'mock',
57
+ scalars: {
58
+ Date: 'date',
59
+ },
60
+ // relative to the mocks.ts file
61
+ typesFile: './types.ts',
62
+ terminateCircularRelationships: true,
63
+ },
64
+ },
65
+ ],
66
+ },
67
+ },
68
+ });
69
+ })
70
+ .demandCommand(1, 1, 'choose a command: types or mocks');
71
+ };
@@ -0,0 +1,5 @@
1
+ const cli = require('../../lib/cli');
2
+
3
+ module.exports = function generateResourceBuilder() {
4
+ cli('eslint "*/**/*.{ts,tsx}"');
5
+ };
@@ -0,0 +1,44 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ module.exports = async function generateResourceBuilder({ argv }) {
5
+ const { build, preview } = await import('vite');
6
+
7
+ const configFile = argv?.config ?? path.resolve(__dirname, '../../../config/vite.mjs');
8
+
9
+ let built = false;
10
+
11
+ return build({
12
+ build: { watch: { buildDelay: 200 }, emptyOutDir: false },
13
+ logLevel: 'error',
14
+ clearScreen: true,
15
+ configFile,
16
+ })
17
+ .then((buildWatcher) => {
18
+ return new Promise((resolve) => {
19
+ buildWatcher.on('event', async ({ code }) => {
20
+ if (code === 'END') {
21
+ fs.writeFileSync(
22
+ path.resolve(process.cwd(), './dist/reload'),
23
+ JSON.stringify({
24
+ at: Date.now(),
25
+ })
26
+ );
27
+
28
+ console.log('\n📦 Dropin assets built\n');
29
+
30
+ if (!built) {
31
+ built = true;
32
+ resolve();
33
+ }
34
+ }
35
+ });
36
+ });
37
+ })
38
+ .then(async () => {
39
+ const previewServer = await preview({ configFile });
40
+ console.log('\n📡 Serving dropin assets:');
41
+ previewServer.printUrls();
42
+ console.log('\n');
43
+ });
44
+ };
@@ -0,0 +1,5 @@
1
+ const cli = require('../../lib/cli');
2
+
3
+ module.exports = function generateResourceBuilder() {
4
+ cli('storybook dev -h localhost -p 6006 --disable-telemetry --quiet');
5
+ };
@@ -0,0 +1,5 @@
1
+ const cli = require('../../lib/cli');
2
+
3
+ module.exports = function generateResourceBuilder() {
4
+ cli('jest');
5
+ };
package/bin/index.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ const yargs = require('yargs');
4
+
5
+ yargs
6
+ .usage('usage: $0 <command>')
7
+ .showHelpOnFail(true)
8
+ .command('storybook', 'Launch Storybook', require('./builders/storybook'))
9
+ .command('serve', 'Serve bundles', require('./builders/serve'))
10
+ .command(
11
+ 'gql',
12
+ 'Generates types or mocks for your API',
13
+ require('./builders/gql')
14
+ )
15
+ .command('build', 'Build bundles', require('./builders/build'))
16
+ .command('test', 'Run Jest tests', require('./builders/test'))
17
+ .command('lint', 'Run ESLint code analysis', require('./builders/lint'))
18
+ .command(
19
+ 'generate',
20
+ 'Generate a new <resource>',
21
+ require('./builders/generate')
22
+ )
23
+
24
+ .help('help')
25
+
26
+ .demandCommand().argv;
package/bin/lib/cli.js ADDED
@@ -0,0 +1,8 @@
1
+ const { spawn } = require('child_process');
2
+
3
+ module.exports = function cli(command) {
4
+ let cmd = command;
5
+ const argvs = process.argv.slice(3).join(' ');
6
+ if (argvs) cmd += ` ${argvs}`;
7
+ return spawn(cmd, { shell: true, stdio: 'inherit' });
8
+ };
@@ -0,0 +1,12 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+
4
+ module.exports = function getConfig() {
5
+ const configPath = path.resolve(process.cwd(), './.elsie.js');
6
+
7
+ if (!fs.existsSync(configPath)) {
8
+ return null;
9
+ }
10
+
11
+ return require(configPath);
12
+ };
@@ -0,0 +1,11 @@
1
+ module.exports = function logMessage(message, type = 'default') {
2
+ const TYPES = {
3
+ default: '',
4
+ warning: '⚠️ ',
5
+ error: '⛔️ ',
6
+ success: '👌 ',
7
+ created: '🆕 ',
8
+ updated: '✍️ ',
9
+ };
10
+ return `${TYPES[type]}${message}`;
11
+ };
@@ -0,0 +1,26 @@
1
+ function toPascalCase(str) {
2
+ return str
3
+ .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
4
+ .map((x) => x.charAt(0).toUpperCase() + x.slice(1).toLowerCase())
5
+ .join('');
6
+ }
7
+
8
+ function hyphenatedName(str) {
9
+ return str
10
+ .replace(/([A-Z])/g, (g) => `-${g.toLowerCase()}`)
11
+ .replace(/^-/, '');
12
+ }
13
+
14
+ function toCamelCase(str) {
15
+ return toPascalCase(str)
16
+ .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
17
+ return index === 0 ? word.toLowerCase() : word.toUpperCase();
18
+ })
19
+ .replace(/\s+/g, '');
20
+ }
21
+
22
+ module.exports = {
23
+ toPascalCase,
24
+ hyphenatedName,
25
+ toCamelCase,
26
+ };
@@ -0,0 +1,28 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ module.exports = function validateTypeOf(values, rules) {
11
+ if (!values || !rules) return null;
12
+
13
+ return Object.entries(rules).reduce((result, [key, itemRules]) => {
14
+ if (itemRules.required && typeof values[key] === 'undefined') {
15
+ return [...result, key];
16
+ }
17
+
18
+ if (
19
+ itemRules.type &&
20
+ typeof values[key] !== 'undefined' &&
21
+ typeof values[key] !== itemRules.type
22
+ ) {
23
+ return [...result, key];
24
+ }
25
+
26
+ return [...result];
27
+ }, []);
28
+ };
@@ -0,0 +1,30 @@
1
+ /********************************************************************
2
+ * Copyright 2024 Adobe
3
+ * All Rights Reserved.
4
+ *
5
+ * NOTICE: Adobe permits you to use, modify, and distribute this
6
+ * file in accordance with the terms of the Adobe license agreement
7
+ * accompanying it.
8
+ *******************************************************************/
9
+
10
+ const path = require('path');
11
+ const fs = require('fs');
12
+ const m = require('./log-message');
13
+
14
+ module.exports = async function writeFile(filePath, content, force = false) {
15
+ const relativePath = path.relative('.', filePath);
16
+
17
+ if (force !== true && fs.existsSync(filePath)) {
18
+ console.error(m(`\x1b[31m${relativePath} \x1b[0malready exists`, 'error'));
19
+ return false;
20
+ } else {
21
+ await fs.promises.writeFile(filePath, content);
22
+
23
+ if (force) {
24
+ console.log(m(`\x1b[33m${relativePath} \x1b[0mupdated`, 'updated'));
25
+ } else {
26
+ console.log(m(`\x1b[33m${relativePath} \x1b[0mcreated`, 'created'));
27
+ }
28
+ return true;
29
+ }
30
+ };