@shopify/cli-hydrogen 5.0.1 → 5.1.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 (240) hide show
  1. package/dist/commands/hydrogen/build.js +38 -8
  2. package/dist/commands/hydrogen/codegen-unstable.js +13 -24
  3. package/dist/commands/hydrogen/dev.js +61 -41
  4. package/dist/commands/hydrogen/env/list.js +25 -24
  5. package/dist/commands/hydrogen/env/list.test.js +46 -43
  6. package/dist/commands/hydrogen/env/pull.js +53 -25
  7. package/dist/commands/hydrogen/env/pull.test.js +123 -42
  8. package/dist/commands/hydrogen/generate/route.js +31 -132
  9. package/dist/commands/hydrogen/generate/route.test.js +34 -126
  10. package/dist/commands/hydrogen/init.js +46 -127
  11. package/dist/commands/hydrogen/init.test.js +352 -100
  12. package/dist/commands/hydrogen/link.js +101 -43
  13. package/dist/commands/hydrogen/link.test.js +108 -74
  14. package/dist/commands/hydrogen/list.js +22 -12
  15. package/dist/commands/hydrogen/list.test.js +51 -48
  16. package/dist/commands/hydrogen/login.js +31 -0
  17. package/dist/commands/hydrogen/logout.js +21 -0
  18. package/dist/commands/hydrogen/preview.js +2 -1
  19. package/dist/commands/hydrogen/setup/css.js +79 -0
  20. package/dist/commands/hydrogen/setup/markets.js +53 -0
  21. package/dist/commands/hydrogen/setup.js +133 -0
  22. package/dist/commands/hydrogen/shortcut.js +2 -45
  23. package/dist/commands/hydrogen/shortcut.test.js +10 -37
  24. package/dist/generator-templates/assets/css-modules/package.json +6 -0
  25. package/dist/generator-templates/assets/postcss/package.json +10 -0
  26. package/dist/generator-templates/assets/postcss/postcss.config.js +8 -0
  27. package/dist/generator-templates/assets/tailwind/package.json +13 -0
  28. package/dist/generator-templates/assets/tailwind/postcss.config.js +10 -0
  29. package/dist/generator-templates/assets/tailwind/tailwind.config.js +8 -0
  30. package/dist/generator-templates/assets/tailwind/tailwind.css +3 -0
  31. package/dist/generator-templates/assets/vanilla-extract/package.json +9 -0
  32. package/dist/generator-templates/starter/.eslintignore +5 -0
  33. package/dist/generator-templates/starter/.eslintrc.js +18 -0
  34. package/dist/generator-templates/starter/.graphqlrc.yml +1 -0
  35. package/dist/generator-templates/starter/README.md +40 -0
  36. package/dist/generator-templates/starter/app/components/Aside.tsx +47 -0
  37. package/dist/generator-templates/starter/app/components/Cart.tsx +340 -0
  38. package/dist/generator-templates/starter/app/components/Footer.tsx +99 -0
  39. package/dist/generator-templates/starter/app/components/Header.tsx +178 -0
  40. package/dist/generator-templates/starter/app/components/Layout.tsx +95 -0
  41. package/dist/generator-templates/starter/app/components/Search.tsx +480 -0
  42. package/dist/generator-templates/starter/app/entry.client.tsx +12 -0
  43. package/dist/generator-templates/starter/app/entry.server.tsx +33 -0
  44. package/dist/generator-templates/starter/app/root.tsx +270 -0
  45. package/dist/generator-templates/starter/app/routes/$.tsx +7 -0
  46. package/dist/generator-templates/{routes → starter/app/routes}/[robots.txt].tsx +47 -69
  47. package/dist/generator-templates/starter/app/routes/[sitemap.xml].tsx +174 -0
  48. package/dist/generator-templates/starter/app/routes/_index.tsx +145 -0
  49. package/dist/generator-templates/starter/app/routes/account.$.tsx +9 -0
  50. package/dist/generator-templates/starter/app/routes/account.addresses.tsx +563 -0
  51. package/dist/generator-templates/starter/app/routes/account.orders.$id.tsx +309 -0
  52. package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +196 -0
  53. package/dist/generator-templates/starter/app/routes/account.profile.tsx +289 -0
  54. package/dist/generator-templates/starter/app/routes/account.tsx +203 -0
  55. package/dist/generator-templates/starter/app/routes/account_.activate.$id.$activationToken.tsx +157 -0
  56. package/dist/generator-templates/starter/app/routes/account_.login.tsx +143 -0
  57. package/dist/generator-templates/starter/app/routes/account_.logout.tsx +33 -0
  58. package/dist/generator-templates/starter/app/routes/account_.recover.tsx +124 -0
  59. package/dist/generator-templates/starter/app/routes/account_.register.tsx +207 -0
  60. package/dist/generator-templates/starter/app/routes/account_.reset.$id.$resetToken.tsx +136 -0
  61. package/dist/generator-templates/starter/app/routes/api.predictive-search.tsx +342 -0
  62. package/dist/generator-templates/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +88 -0
  63. package/dist/generator-templates/starter/app/routes/blogs.$blogHandle._index.tsx +162 -0
  64. package/dist/generator-templates/starter/app/routes/blogs._index.tsx +94 -0
  65. package/dist/generator-templates/starter/app/routes/cart.tsx +104 -0
  66. package/dist/generator-templates/starter/app/routes/collections.$handle.tsx +184 -0
  67. package/dist/generator-templates/starter/app/routes/collections._index.tsx +120 -0
  68. package/dist/generator-templates/starter/app/routes/pages.$handle.tsx +57 -0
  69. package/dist/generator-templates/starter/app/routes/policies.$handle.tsx +94 -0
  70. package/dist/generator-templates/starter/app/routes/policies._index.tsx +63 -0
  71. package/dist/generator-templates/starter/app/routes/products.$handle.tsx +418 -0
  72. package/dist/generator-templates/starter/app/routes/search.tsx +168 -0
  73. package/dist/generator-templates/starter/app/styles/app.css +473 -0
  74. package/dist/generator-templates/starter/app/styles/reset.css +129 -0
  75. package/dist/generator-templates/starter/app/utils.ts +46 -0
  76. package/dist/generator-templates/starter/package.json +43 -0
  77. package/dist/generator-templates/starter/public/favicon.svg +28 -0
  78. package/dist/generator-templates/starter/remix.config.js +26 -0
  79. package/dist/generator-templates/starter/remix.env.d.ts +39 -0
  80. package/dist/generator-templates/starter/server.ts +253 -0
  81. package/dist/generator-templates/starter/storefrontapi.generated.d.ts +1906 -0
  82. package/dist/generator-templates/starter/tsconfig.json +22 -0
  83. package/dist/lib/auth.js +123 -0
  84. package/dist/lib/auth.test.js +157 -0
  85. package/dist/lib/build.js +51 -0
  86. package/dist/lib/check-version.js +3 -3
  87. package/dist/lib/check-version.test.js +24 -0
  88. package/dist/lib/codegen.js +26 -17
  89. package/dist/lib/environment-variables.js +68 -0
  90. package/dist/lib/environment-variables.test.js +147 -0
  91. package/dist/lib/file.js +41 -0
  92. package/dist/lib/file.test.js +69 -0
  93. package/dist/lib/flags.js +39 -2
  94. package/dist/lib/format-code.js +26 -0
  95. package/dist/lib/gid.js +12 -0
  96. package/dist/lib/{graphql.test.js → gid.test.js} +1 -1
  97. package/dist/lib/graphql/admin/client.js +27 -0
  98. package/dist/lib/graphql/admin/client.test.js +51 -0
  99. package/dist/lib/graphql/admin/create-storefront.js +36 -0
  100. package/dist/lib/graphql/admin/create-storefront.test.js +64 -0
  101. package/dist/lib/graphql/admin/fetch-job.js +39 -0
  102. package/dist/lib/graphql/admin/link-storefront.js +7 -11
  103. package/dist/lib/graphql/admin/link-storefront.test.js +38 -0
  104. package/dist/lib/graphql/admin/list-environments.js +2 -2
  105. package/dist/lib/graphql/admin/list-environments.test.js +44 -0
  106. package/dist/lib/graphql/admin/list-storefronts.js +7 -11
  107. package/dist/lib/graphql/admin/list-storefronts.test.js +44 -0
  108. package/dist/lib/graphql/admin/pull-variables.js +3 -3
  109. package/dist/lib/graphql/admin/pull-variables.test.js +37 -0
  110. package/dist/lib/graphql/business-platform/user-account.js +83 -0
  111. package/dist/lib/graphql/business-platform/user-account.test.js +80 -0
  112. package/dist/lib/log.js +185 -9
  113. package/dist/lib/log.test.js +92 -0
  114. package/dist/lib/mini-oxygen.js +32 -14
  115. package/dist/lib/missing-routes.js +0 -2
  116. package/dist/lib/onboarding/common.js +456 -0
  117. package/dist/lib/onboarding/index.js +2 -0
  118. package/dist/lib/onboarding/local.js +229 -0
  119. package/dist/lib/onboarding/remote.js +89 -0
  120. package/dist/lib/remix-version-interop.js +5 -5
  121. package/dist/lib/remix-version-interop.test.js +11 -1
  122. package/dist/lib/render-errors.js +13 -11
  123. package/dist/lib/setups/css/assets.js +89 -0
  124. package/dist/lib/setups/css/css-modules.js +22 -0
  125. package/dist/lib/setups/css/index.js +44 -0
  126. package/dist/lib/setups/css/postcss.js +34 -0
  127. package/dist/lib/setups/css/replacers.js +137 -0
  128. package/dist/lib/setups/css/tailwind.js +54 -0
  129. package/dist/lib/setups/css/vanilla-extract.js +22 -0
  130. package/dist/lib/setups/i18n/domains.test.js +25 -0
  131. package/dist/lib/setups/i18n/index.js +46 -0
  132. package/dist/lib/setups/i18n/replacers.js +227 -0
  133. package/dist/lib/setups/i18n/subdomains.test.js +25 -0
  134. package/dist/lib/setups/i18n/subfolders.test.js +25 -0
  135. package/dist/lib/setups/i18n/templates/domains.js +14 -0
  136. package/dist/lib/setups/i18n/templates/domains.ts +25 -0
  137. package/dist/lib/setups/i18n/templates/subdomains.js +14 -0
  138. package/dist/lib/setups/i18n/templates/subdomains.ts +24 -0
  139. package/dist/lib/setups/i18n/templates/subfolders.js +14 -0
  140. package/dist/lib/setups/i18n/templates/subfolders.ts +28 -0
  141. package/dist/lib/setups/routes/generate.js +244 -0
  142. package/dist/lib/setups/routes/generate.test.js +313 -0
  143. package/dist/lib/shell.js +52 -5
  144. package/dist/lib/shell.test.js +42 -16
  145. package/dist/lib/shopify-config.js +23 -18
  146. package/dist/lib/shopify-config.test.js +63 -73
  147. package/dist/lib/string.js +7 -0
  148. package/dist/lib/string.test.js +16 -0
  149. package/dist/lib/template-downloader.js +9 -7
  150. package/dist/lib/transpile-ts.js +9 -29
  151. package/dist/virtual-routes/routes/index.jsx +40 -19
  152. package/oclif.manifest.json +710 -1
  153. package/package.json +16 -16
  154. package/dist/commands/hydrogen/build.d.ts +0 -23
  155. package/dist/commands/hydrogen/check.d.ts +0 -15
  156. package/dist/commands/hydrogen/codegen-unstable.d.ts +0 -15
  157. package/dist/commands/hydrogen/dev.d.ts +0 -21
  158. package/dist/commands/hydrogen/env/list.d.ts +0 -18
  159. package/dist/commands/hydrogen/env/pull.d.ts +0 -22
  160. package/dist/commands/hydrogen/g.d.ts +0 -10
  161. package/dist/commands/hydrogen/generate/route.d.ts +0 -32
  162. package/dist/commands/hydrogen/generate/route.test.d.ts +0 -1
  163. package/dist/commands/hydrogen/generate/routes.d.ts +0 -16
  164. package/dist/commands/hydrogen/init.d.ts +0 -24
  165. package/dist/commands/hydrogen/init.test.d.ts +0 -1
  166. package/dist/commands/hydrogen/link.d.ts +0 -23
  167. package/dist/commands/hydrogen/link.test.d.ts +0 -1
  168. package/dist/commands/hydrogen/list.d.ts +0 -21
  169. package/dist/commands/hydrogen/list.test.d.ts +0 -1
  170. package/dist/commands/hydrogen/preview.d.ts +0 -17
  171. package/dist/commands/hydrogen/shortcut.d.ts +0 -9
  172. package/dist/commands/hydrogen/shortcut.test.d.ts +0 -1
  173. package/dist/commands/hydrogen/unlink.d.ts +0 -16
  174. package/dist/commands/hydrogen/unlink.test.d.ts +0 -1
  175. package/dist/create-app.d.ts +0 -1
  176. package/dist/generator-templates/routes/[sitemap.xml].tsx +0 -235
  177. package/dist/generator-templates/routes/account/login.tsx +0 -103
  178. package/dist/generator-templates/routes/account/register.tsx +0 -103
  179. package/dist/generator-templates/routes/cart.tsx +0 -81
  180. package/dist/generator-templates/routes/collections/$collectionHandle.tsx +0 -104
  181. package/dist/generator-templates/routes/collections/index.tsx +0 -102
  182. package/dist/generator-templates/routes/graphiql.tsx +0 -10
  183. package/dist/generator-templates/routes/index.tsx +0 -40
  184. package/dist/generator-templates/routes/pages/$pageHandle.tsx +0 -112
  185. package/dist/generator-templates/routes/policies/$policyHandle.tsx +0 -140
  186. package/dist/generator-templates/routes/policies/index.tsx +0 -117
  187. package/dist/generator-templates/routes/products/$productHandle.tsx +0 -92
  188. package/dist/hooks/init.d.ts +0 -5
  189. package/dist/lib/admin-session.d.ts +0 -6
  190. package/dist/lib/admin-session.js +0 -16
  191. package/dist/lib/admin-session.test.d.ts +0 -1
  192. package/dist/lib/admin-session.test.js +0 -27
  193. package/dist/lib/admin-urls.d.ts +0 -8
  194. package/dist/lib/check-lockfile.d.ts +0 -3
  195. package/dist/lib/check-lockfile.test.d.ts +0 -1
  196. package/dist/lib/check-version.d.ts +0 -16
  197. package/dist/lib/check-version.test.d.ts +0 -1
  198. package/dist/lib/codegen.d.ts +0 -26
  199. package/dist/lib/combined-environment-variables.d.ts +0 -8
  200. package/dist/lib/combined-environment-variables.js +0 -57
  201. package/dist/lib/combined-environment-variables.test.d.ts +0 -1
  202. package/dist/lib/combined-environment-variables.test.js +0 -111
  203. package/dist/lib/config.d.ts +0 -20
  204. package/dist/lib/flags.d.ts +0 -27
  205. package/dist/lib/flags.test.d.ts +0 -1
  206. package/dist/lib/graphql/admin/link-storefront.d.ts +0 -14
  207. package/dist/lib/graphql/admin/list-environments.d.ts +0 -21
  208. package/dist/lib/graphql/admin/list-storefronts.d.ts +0 -25
  209. package/dist/lib/graphql/admin/pull-variables.d.ts +0 -21
  210. package/dist/lib/graphql.d.ts +0 -21
  211. package/dist/lib/graphql.js +0 -18
  212. package/dist/lib/graphql.test.d.ts +0 -1
  213. package/dist/lib/log.d.ts +0 -6
  214. package/dist/lib/mini-oxygen.d.ts +0 -14
  215. package/dist/lib/missing-routes.d.ts +0 -8
  216. package/dist/lib/missing-routes.test.d.ts +0 -1
  217. package/dist/lib/missing-storefronts.d.ts +0 -5
  218. package/dist/lib/missing-storefronts.js +0 -18
  219. package/dist/lib/process.d.ts +0 -6
  220. package/dist/lib/pull-environment-variables.d.ts +0 -20
  221. package/dist/lib/pull-environment-variables.js +0 -57
  222. package/dist/lib/pull-environment-variables.test.d.ts +0 -1
  223. package/dist/lib/pull-environment-variables.test.js +0 -174
  224. package/dist/lib/remix-version-interop.d.ts +0 -11
  225. package/dist/lib/remix-version-interop.test.d.ts +0 -1
  226. package/dist/lib/render-errors.d.ts +0 -16
  227. package/dist/lib/shell.d.ts +0 -11
  228. package/dist/lib/shell.test.d.ts +0 -1
  229. package/dist/lib/shop.d.ts +0 -7
  230. package/dist/lib/shop.js +0 -32
  231. package/dist/lib/shop.test.d.ts +0 -1
  232. package/dist/lib/shop.test.js +0 -78
  233. package/dist/lib/shopify-config.d.ts +0 -35
  234. package/dist/lib/shopify-config.test.d.ts +0 -1
  235. package/dist/lib/template-downloader.d.ts +0 -6
  236. package/dist/lib/transpile-ts.d.ts +0 -16
  237. package/dist/lib/virtual-routes.d.ts +0 -7
  238. package/dist/lib/virtual-routes.test.d.ts +0 -1
  239. /package/dist/{commands/hydrogen/env/list.test.d.ts → lib/setups/css/common.js} +0 -0
  240. /package/dist/{commands/hydrogen/env/pull.test.d.ts → lib/setups/i18n/mock-i18n-types.js} +0 -0
@@ -1,134 +1,42 @@
1
- import { describe, beforeEach, vi, it, expect } from 'vitest';
2
- import { temporaryDirectoryTask } from 'tempy';
3
- import { runGenerate, GENERATOR_TEMPLATES_DIR } from './route.js';
4
- import { renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
5
- import { readFile, mkdir, writeFile } from '@shopify/cli-kit/node/fs';
6
- import { joinPath, dirname } from '@shopify/cli-kit/node/path';
7
- import { convertRouteToV2 } from '../../../lib/remix-version-interop.js';
1
+ import { describe, beforeEach, vi, afterEach, it, expect } from 'vitest';
2
+ import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
3
+ import { runGenerate } from './route.js';
4
+ import { generateRoutes } from '../../../lib/setups/routes/generate.js';
8
5
 
9
- describe("generate/route", () => {
6
+ describe("runGenerate", () => {
7
+ const outputMock = mockAndCaptureOutput();
10
8
  beforeEach(() => {
11
9
  vi.resetAllMocks();
12
- vi.mock("@shopify/cli-kit/node/output");
13
- vi.mock("@shopify/cli-kit/node/ui");
10
+ vi.mock("../../../lib/setups/routes/generate.js");
14
11
  });
15
- it("generates a route file", async () => {
16
- await temporaryDirectoryTask(async (tmpDir) => {
17
- const route = "pages/$pageHandle";
18
- const { appRoot, templatesRoot } = await createHydrogen(tmpDir, {
19
- files: [],
20
- templates: [[route, `const str = "hello world"`]]
21
- });
22
- await runGenerate(route, route, {
23
- directory: appRoot,
24
- templatesRoot
25
- });
26
- expect(
27
- await readFile(joinPath(appRoot, "app/routes", `${route}.jsx`))
28
- ).toContain(`const str = 'hello world'`);
29
- });
30
- });
31
- it("generates a route file for Remix v2", async () => {
32
- await temporaryDirectoryTask(async (tmpDir) => {
33
- const route = "custom/path/$handle/index";
34
- const { appRoot, templatesRoot } = await createHydrogen(tmpDir, {
35
- files: [],
36
- templates: [[route, `const str = "hello world"`]]
37
- });
38
- await runGenerate(route, convertRouteToV2(route), {
39
- directory: appRoot,
40
- templatesRoot
41
- });
42
- expect(
43
- await readFile(
44
- joinPath(appRoot, "app/routes", `custom.path.$handle._index.jsx`)
45
- )
46
- ).toContain(`const str = 'hello world'`);
47
- });
48
- });
49
- it("produces a typescript file when typescript argument is true", async () => {
50
- await temporaryDirectoryTask(async (tmpDir) => {
51
- const route = "pages/$pageHandle";
52
- const { appRoot, templatesRoot } = await createHydrogen(tmpDir, {
53
- files: [],
54
- templates: [[route, 'const str = "hello typescript"']]
55
- });
56
- await runGenerate(route, route, {
57
- directory: appRoot,
58
- templatesRoot,
59
- typescript: true
60
- });
61
- expect(
62
- await readFile(joinPath(appRoot, "app/routes", `${route}.tsx`))
63
- ).toContain(`const str = 'hello typescript'`);
64
- });
65
- });
66
- it("prompts the user if there the file already exists", async () => {
67
- await temporaryDirectoryTask(async (tmpDir) => {
68
- vi.mocked(renderConfirmationPrompt).mockImplementationOnce(
69
- async () => true
70
- );
71
- const route = "page/$pageHandle";
72
- const { appRoot, templatesRoot } = await createHydrogen(tmpDir, {
73
- files: [[`app/routes/${route}.jsx`, 'const str = "I exist"']],
74
- templates: [[route, 'const str = "hello world"']]
75
- });
76
- await runGenerate(route, route, {
77
- directory: appRoot,
78
- templatesRoot
79
- });
80
- expect(renderConfirmationPrompt).toHaveBeenCalledWith(
81
- expect.objectContaining({
82
- message: expect.stringContaining("already exists")
83
- })
84
- );
85
- });
12
+ afterEach(() => {
13
+ vi.resetAllMocks();
14
+ outputMock.clear();
86
15
  });
87
- it("does not prompt the user if the force property is true", async () => {
88
- await temporaryDirectoryTask(async (tmpDir) => {
89
- vi.mocked(renderConfirmationPrompt).mockImplementationOnce(
90
- async () => true
91
- );
92
- const route = "page/$pageHandle";
93
- const { appRoot, templatesRoot } = await createHydrogen(tmpDir, {
94
- files: [[`app/routes/${route}.jsx`, 'const str = "I exist"']],
95
- templates: [[route, 'const str = "hello world"']]
96
- });
97
- await runGenerate(route, route, {
98
- directory: appRoot,
99
- templatesRoot,
100
- force: true
101
- });
102
- expect(renderConfirmationPrompt).not.toHaveBeenCalled();
16
+ it("calls route generation and renders the result", async () => {
17
+ vi.mocked(generateRoutes).mockResolvedValue({
18
+ isTypescript: true,
19
+ transpilerOptions: {},
20
+ formatOptions: {},
21
+ v2Flags: {},
22
+ routeGroups: {},
23
+ routes: [
24
+ { sourceRoute: "", destinationRoute: "/cart", operation: "created" },
25
+ { sourceRoute: "", destinationRoute: "/about", operation: "skipped" },
26
+ {
27
+ sourceRoute: "",
28
+ destinationRoute: "/collections",
29
+ operation: "created"
30
+ }
31
+ ]
103
32
  });
33
+ const options = {
34
+ routeName: "all",
35
+ directory: "there",
36
+ typescript: true
37
+ };
38
+ await runGenerate(options);
39
+ expect(generateRoutes).toHaveBeenCalledWith(options);
40
+ expect(outputMock.info()).toMatch(/2 of 3 routes/i);
104
41
  });
105
42
  });
106
- async function createHydrogen(directory, {
107
- files,
108
- templates
109
- } = {
110
- files: [],
111
- templates: []
112
- }) {
113
- for (const item of files) {
114
- const [filePath, fileContent] = item;
115
- const fullFilePath = joinPath(directory, "app", filePath);
116
- await mkdir(dirname(fullFilePath));
117
- await writeFile(fullFilePath, fileContent);
118
- }
119
- for (const item of templates) {
120
- const [filePath, fileContent] = item;
121
- const fullFilePath = joinPath(
122
- directory,
123
- GENERATOR_TEMPLATES_DIR,
124
- "routes",
125
- `${filePath}.tsx`
126
- );
127
- await mkdir(dirname(fullFilePath));
128
- await writeFile(fullFilePath, fileContent);
129
- }
130
- return {
131
- appRoot: joinPath(directory, "app"),
132
- templatesRoot: directory
133
- };
134
- }
@@ -1,19 +1,17 @@
1
1
  import Command from '@shopify/cli-kit/node/base-command';
2
- import { readdir } from 'node:fs/promises';
3
2
  import { fileURLToPath } from 'node:url';
4
- import { packageManagerUsedForCreating, installNodeModules } from '@shopify/cli-kit/node/node-package-manager';
5
- import { renderFatalError, renderSelectPrompt, renderTextPrompt, renderConfirmationPrompt, renderInfo, renderTasks, renderSuccess } from '@shopify/cli-kit/node/ui';
3
+ import { packageManagerUsedForCreating } from '@shopify/cli-kit/node/node-package-manager';
6
4
  import { Flags } from '@oclif/core';
7
- import { basename, resolvePath, joinPath } from '@shopify/cli-kit/node/path';
8
- import { rmdir, copyFile, fileExists, isDirectory } from '@shopify/cli-kit/node/fs';
9
- import { outputContent, outputToken } from '@shopify/cli-kit/node/output';
5
+ import { AbortError } from '@shopify/cli-kit/node/error';
6
+ import { AbortController } from '@shopify/cli-kit/node/abort';
10
7
  import { commonFlags, flagsToCamelObject, parseProcessFlags } from '../../lib/flags.js';
11
- import { transpileProject } from '../../lib/transpile-ts.js';
12
- import { getLatestTemplates } from '../../lib/template-downloader.js';
13
8
  import { checkHydrogenVersion } from '../../lib/check-version.js';
9
+ import { SETUP_CSS_STRATEGIES } from './../../lib/setups/css/index.js';
10
+ import { I18N_CHOICES } from '../../lib/setups/i18n/index.js';
14
11
  import { supressNodeExperimentalWarnings } from '../../lib/process.js';
12
+ import { setupRemoteTemplate, setupLocalStarterTemplate } from '../../lib/onboarding/index.js';
13
+ import { LANGUAGES } from '../../lib/onboarding/common.js';
15
14
 
16
- const STARTER_TEMPLATES = ["hello-world", "demo-store"];
17
15
  const FLAG_MAP = { f: "force" };
18
16
  class Init extends Command {
19
17
  static description = "Creates a new Hydrogen storefront.";
@@ -25,148 +23,69 @@ class Init extends Command {
25
23
  }),
26
24
  language: Flags.string({
27
25
  description: "Sets the template language to use. One of `js` or `ts`.",
28
- choices: ["js", "ts"],
26
+ choices: Object.keys(LANGUAGES),
29
27
  env: "SHOPIFY_HYDROGEN_FLAG_LANGUAGE"
30
28
  }),
31
29
  template: Flags.string({
32
- description: "Sets the template to use. One of `demo-store` or `hello-world`.",
33
- choices: STARTER_TEMPLATES,
30
+ description: "Sets the template to use. Pass `demo-store` for a fully-featured store template or `hello-world` for a barebones project.",
34
31
  env: "SHOPIFY_HYDROGEN_FLAG_TEMPLATE"
35
32
  }),
36
- "install-deps": Flags.boolean({
37
- description: "Auto install dependencies using the active package manager",
38
- env: "SHOPIFY_HYDROGEN_FLAG_INSTALL_DEPS",
33
+ "install-deps": commonFlags.installDeps,
34
+ "mock-shop": Flags.boolean({
35
+ description: "Use mock.shop as the data source for the storefront.",
36
+ default: false,
37
+ env: "SHOPIFY_HYDROGEN_FLAG_MOCK_DATA"
38
+ }),
39
+ styling: commonFlags.styling,
40
+ markets: commonFlags.markets,
41
+ shortcut: commonFlags.shortcut,
42
+ routes: Flags.boolean({
43
+ description: "Generate routes for all pages.",
44
+ env: "SHOPIFY_HYDROGEN_FLAG_ROUTES",
45
+ hidden: true
46
+ }),
47
+ git: Flags.boolean({
48
+ description: "Init Git and create initial commits.",
49
+ env: "SHOPIFY_HYDROGEN_FLAG_GIT",
50
+ default: true,
39
51
  allowNo: true
40
52
  })
41
53
  };
42
54
  async run() {
43
55
  const { flags } = await this.parse(Init);
56
+ if (flags.markets && !I18N_CHOICES.includes(flags.markets)) {
57
+ throw new AbortError(
58
+ `Invalid URL structure strategy: ${flags.markets}. Must be one of ${I18N_CHOICES.join(", ")}`
59
+ );
60
+ }
61
+ if (flags.styling && !SETUP_CSS_STRATEGIES.includes(flags.styling)) {
62
+ throw new AbortError(
63
+ `Invalid styling strategy: ${flags.styling}. Must be one of ${SETUP_CSS_STRATEGIES.join(", ")}`
64
+ );
65
+ }
44
66
  await runInit(flagsToCamelObject(flags));
45
67
  }
46
68
  }
47
69
  async function runInit(options = parseProcessFlags(process.argv, FLAG_MAP)) {
48
70
  supressNodeExperimentalWarnings();
71
+ options.git ??= true;
49
72
  const showUpgrade = await checkHydrogenVersion(
50
73
  fileURLToPath(new URL("../../../package.json", import.meta.url)),
51
74
  "cli"
52
75
  );
53
76
  if (showUpgrade) {
54
- const packageManager2 = await packageManagerUsedForCreating();
77
+ const packageManager = await packageManagerUsedForCreating();
55
78
  showUpgrade(
56
- packageManager2 === "unknown" ? "" : `Please use the latest version with \`${packageManager2} create @shopify/hydrogen@latest\``
79
+ packageManager === "unknown" ? "" : `Please use the latest version with \`${packageManager} create @shopify/hydrogen@latest\``
57
80
  );
58
81
  }
59
- let templatesDownloaded = false;
60
- const templatesPromise = getLatestTemplates().then((result) => {
61
- templatesDownloaded = true;
62
- return result;
63
- }).catch((error) => {
64
- renderFatalError(error);
65
- process.exit(1);
66
- });
67
- const appTemplate = options.template ?? await renderSelectPrompt({
68
- message: "Choose a template",
69
- defaultValue: "hello-world",
70
- choices: STARTER_TEMPLATES.map((value) => ({
71
- label: value.replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
72
- value
73
- }))
74
- });
75
- const language = options.language ?? await renderSelectPrompt({
76
- message: "Choose a language",
77
- choices: [
78
- { label: "JavaScript", value: "js" },
79
- { label: "TypeScript", value: "ts" }
80
- ],
81
- defaultValue: "js"
82
- });
83
- const location = options.path ?? await renderTextPrompt({
84
- message: "Where would you like to create your app?",
85
- defaultValue: "hydrogen-storefront"
86
- });
87
- const projectName = basename(location);
88
- const projectDir = resolvePath(process.cwd(), location);
89
- if (await projectExists(projectDir)) {
90
- if (!options.force) {
91
- const deleteFiles = await renderConfirmationPrompt({
92
- message: `${location} is not an empty directory. Do you want to delete the existing files and continue?`,
93
- defaultValue: false
94
- });
95
- if (!deleteFiles) {
96
- renderInfo({
97
- headline: `Destination path ${location} already exists and is not an empty directory. You may use \`--force\` or \`-f\` to override it.`
98
- });
99
- return;
100
- }
101
- }
102
- await rmdir(projectDir, { force: true });
103
- }
104
- if (!templatesDownloaded) {
105
- await renderTasks([
106
- {
107
- title: "Downloading templates",
108
- task: async () => {
109
- await templatesPromise;
110
- }
111
- }
112
- ]);
82
+ const controller = new AbortController();
83
+ try {
84
+ return options.template ? await setupRemoteTemplate(options, controller) : await setupLocalStarterTemplate(options, controller);
85
+ } catch (error) {
86
+ controller.abort();
87
+ throw error;
113
88
  }
114
- const { templatesDir } = await templatesPromise;
115
- await copyFile(joinPath(templatesDir, appTemplate), projectDir);
116
- if (language === "js") {
117
- try {
118
- await transpileProject(projectDir);
119
- } catch (error) {
120
- await rmdir(projectDir, { force: true });
121
- throw error;
122
- }
123
- }
124
- let depsInstalled = false;
125
- let packageManager = await packageManagerUsedForCreating();
126
- if (packageManager !== "unknown") {
127
- const installDeps = options.installDeps ?? await renderConfirmationPrompt({
128
- message: `Install dependencies with ${packageManager}?`
129
- });
130
- if (installDeps) {
131
- await installNodeModules({
132
- directory: projectDir,
133
- packageManager,
134
- args: [],
135
- stdout: process.stdout,
136
- stderr: process.stderr
137
- });
138
- depsInstalled = true;
139
- }
140
- } else {
141
- packageManager = "npm";
142
- }
143
- renderSuccess({
144
- headline: `${projectName} is ready to build.`,
145
- nextSteps: [
146
- outputContent`Run ${outputToken.genericShellCommand(`cd ${location}`)}`.value,
147
- depsInstalled ? void 0 : outputContent`Run ${outputToken.genericShellCommand(
148
- `${packageManager} install`
149
- )} to install the dependencies`.value,
150
- outputContent`Run ${outputToken.packagejsonScript(
151
- packageManager,
152
- "dev"
153
- )} to start your local development server and start building`.value
154
- ].filter((step) => Boolean(step)),
155
- reference: [
156
- "Getting started with Hydrogen: https://shopify.dev/docs/custom-storefronts/hydrogen/building/begin-development",
157
- "Hydrogen project structure: https://shopify.dev/docs/custom-storefronts/hydrogen/project-structure",
158
- "Setting up Hydrogen environment variables: https://shopify.dev/docs/custom-storefronts/hydrogen/environment-variables"
159
- ]
160
- });
161
- if (appTemplate === "demo-store") {
162
- renderInfo({
163
- headline: `Your project will display inventory from the Hydrogen Demo Store.`,
164
- body: `To connect this project to your Shopify store\u2019s inventory, update \`${projectName}/.env\` with your store ID and Storefront API key.`
165
- });
166
- }
167
- }
168
- async function projectExists(projectDir) {
169
- return await fileExists(projectDir) && await isDirectory(projectDir) && (await readdir(projectDir)).length > 0;
170
89
  }
171
90
 
172
91
  export { Init as default, runInit };