@shopify/cli-hydrogen 5.0.2 → 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.
- package/dist/commands/hydrogen/build.js +16 -2
- package/dist/commands/hydrogen/codegen-unstable.js +13 -24
- package/dist/commands/hydrogen/dev.js +45 -39
- package/dist/commands/hydrogen/env/list.js +25 -24
- package/dist/commands/hydrogen/env/list.test.js +46 -43
- package/dist/commands/hydrogen/env/pull.js +53 -25
- package/dist/commands/hydrogen/env/pull.test.js +123 -42
- package/dist/commands/hydrogen/generate/route.js +31 -132
- package/dist/commands/hydrogen/generate/route.test.js +34 -126
- package/dist/commands/hydrogen/init.js +46 -127
- package/dist/commands/hydrogen/init.test.js +352 -100
- package/dist/commands/hydrogen/link.js +70 -69
- package/dist/commands/hydrogen/link.test.js +72 -107
- package/dist/commands/hydrogen/list.js +22 -12
- package/dist/commands/hydrogen/list.test.js +51 -48
- package/dist/commands/hydrogen/login.js +31 -0
- package/dist/commands/hydrogen/logout.js +21 -0
- package/dist/commands/hydrogen/setup/css.js +79 -0
- package/dist/commands/hydrogen/setup/markets.js +53 -0
- package/dist/commands/hydrogen/setup.js +133 -0
- package/dist/commands/hydrogen/shortcut.js +2 -45
- package/dist/commands/hydrogen/shortcut.test.js +10 -37
- package/dist/generator-templates/assets/css-modules/package.json +6 -0
- package/dist/generator-templates/assets/postcss/package.json +10 -0
- package/dist/generator-templates/assets/postcss/postcss.config.js +8 -0
- package/dist/generator-templates/assets/tailwind/package.json +13 -0
- package/dist/generator-templates/assets/tailwind/postcss.config.js +10 -0
- package/dist/generator-templates/assets/tailwind/tailwind.config.js +8 -0
- package/dist/generator-templates/assets/tailwind/tailwind.css +3 -0
- package/dist/generator-templates/assets/vanilla-extract/package.json +9 -0
- package/dist/generator-templates/starter/.eslintignore +5 -0
- package/dist/generator-templates/starter/.eslintrc.js +18 -0
- package/dist/generator-templates/starter/.graphqlrc.yml +1 -0
- package/dist/generator-templates/starter/README.md +40 -0
- package/dist/generator-templates/starter/app/components/Aside.tsx +47 -0
- package/dist/generator-templates/starter/app/components/Cart.tsx +340 -0
- package/dist/generator-templates/starter/app/components/Footer.tsx +99 -0
- package/dist/generator-templates/starter/app/components/Header.tsx +178 -0
- package/dist/generator-templates/starter/app/components/Layout.tsx +95 -0
- package/dist/generator-templates/starter/app/components/Search.tsx +480 -0
- package/dist/generator-templates/starter/app/entry.client.tsx +12 -0
- package/dist/generator-templates/starter/app/entry.server.tsx +33 -0
- package/dist/generator-templates/starter/app/root.tsx +270 -0
- package/dist/generator-templates/starter/app/routes/$.tsx +7 -0
- package/dist/generator-templates/{routes → starter/app/routes}/[robots.txt].tsx +47 -69
- package/dist/generator-templates/starter/app/routes/[sitemap.xml].tsx +174 -0
- package/dist/generator-templates/starter/app/routes/_index.tsx +145 -0
- package/dist/generator-templates/starter/app/routes/account.$.tsx +9 -0
- package/dist/generator-templates/starter/app/routes/account.addresses.tsx +563 -0
- package/dist/generator-templates/starter/app/routes/account.orders.$id.tsx +309 -0
- package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +196 -0
- package/dist/generator-templates/starter/app/routes/account.profile.tsx +289 -0
- package/dist/generator-templates/starter/app/routes/account.tsx +203 -0
- package/dist/generator-templates/starter/app/routes/account_.activate.$id.$activationToken.tsx +157 -0
- package/dist/generator-templates/starter/app/routes/account_.login.tsx +143 -0
- package/dist/generator-templates/starter/app/routes/account_.logout.tsx +33 -0
- package/dist/generator-templates/starter/app/routes/account_.recover.tsx +124 -0
- package/dist/generator-templates/starter/app/routes/account_.register.tsx +207 -0
- package/dist/generator-templates/starter/app/routes/account_.reset.$id.$resetToken.tsx +136 -0
- package/dist/generator-templates/starter/app/routes/api.predictive-search.tsx +342 -0
- package/dist/generator-templates/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +88 -0
- package/dist/generator-templates/starter/app/routes/blogs.$blogHandle._index.tsx +162 -0
- package/dist/generator-templates/starter/app/routes/blogs._index.tsx +94 -0
- package/dist/generator-templates/starter/app/routes/cart.tsx +104 -0
- package/dist/generator-templates/starter/app/routes/collections.$handle.tsx +184 -0
- package/dist/generator-templates/starter/app/routes/collections._index.tsx +120 -0
- package/dist/generator-templates/starter/app/routes/pages.$handle.tsx +57 -0
- package/dist/generator-templates/starter/app/routes/policies.$handle.tsx +94 -0
- package/dist/generator-templates/starter/app/routes/policies._index.tsx +63 -0
- package/dist/generator-templates/starter/app/routes/products.$handle.tsx +418 -0
- package/dist/generator-templates/starter/app/routes/search.tsx +168 -0
- package/dist/generator-templates/starter/app/styles/app.css +473 -0
- package/dist/generator-templates/starter/app/styles/reset.css +129 -0
- package/dist/generator-templates/starter/app/utils.ts +46 -0
- package/dist/generator-templates/starter/package.json +43 -0
- package/dist/generator-templates/starter/public/favicon.svg +28 -0
- package/dist/generator-templates/starter/remix.config.js +26 -0
- package/dist/generator-templates/starter/remix.env.d.ts +39 -0
- package/dist/generator-templates/starter/server.ts +253 -0
- package/dist/generator-templates/starter/storefrontapi.generated.d.ts +1906 -0
- package/dist/generator-templates/starter/tsconfig.json +22 -0
- package/dist/lib/auth.js +123 -0
- package/dist/lib/auth.test.js +157 -0
- package/dist/lib/build.js +51 -0
- package/dist/lib/check-version.js +3 -3
- package/dist/lib/check-version.test.js +24 -0
- package/dist/lib/codegen.js +26 -17
- package/dist/lib/environment-variables.js +68 -0
- package/dist/lib/environment-variables.test.js +147 -0
- package/dist/lib/file.js +41 -0
- package/dist/lib/file.test.js +69 -0
- package/dist/lib/flags.js +39 -2
- package/dist/lib/format-code.js +26 -0
- package/dist/lib/gid.js +12 -0
- package/dist/lib/{graphql.test.js → gid.test.js} +1 -1
- package/dist/lib/graphql/admin/client.js +27 -0
- package/dist/lib/graphql/admin/client.test.js +51 -0
- package/dist/lib/graphql/admin/create-storefront.js +13 -15
- package/dist/lib/graphql/admin/create-storefront.test.js +64 -0
- package/dist/lib/graphql/admin/fetch-job.js +6 -15
- package/dist/lib/graphql/admin/link-storefront.js +7 -11
- package/dist/lib/graphql/admin/link-storefront.test.js +38 -0
- package/dist/lib/graphql/admin/list-environments.js +2 -2
- package/dist/lib/graphql/admin/list-environments.test.js +44 -0
- package/dist/lib/graphql/admin/list-storefronts.js +7 -11
- package/dist/lib/graphql/admin/list-storefronts.test.js +44 -0
- package/dist/lib/graphql/admin/pull-variables.js +3 -3
- package/dist/lib/graphql/admin/pull-variables.test.js +37 -0
- package/dist/lib/graphql/business-platform/user-account.js +83 -0
- package/dist/lib/graphql/business-platform/user-account.test.js +80 -0
- package/dist/lib/log.js +185 -9
- package/dist/lib/log.test.js +92 -0
- package/dist/lib/mini-oxygen.js +19 -9
- package/dist/lib/missing-routes.js +0 -2
- package/dist/lib/onboarding/common.js +456 -0
- package/dist/lib/onboarding/index.js +2 -0
- package/dist/lib/onboarding/local.js +229 -0
- package/dist/lib/onboarding/remote.js +89 -0
- package/dist/lib/remix-version-interop.js +5 -5
- package/dist/lib/remix-version-interop.test.js +11 -1
- package/dist/lib/render-errors.js +13 -11
- package/dist/lib/setups/css/assets.js +89 -0
- package/dist/lib/setups/css/css-modules.js +22 -0
- package/dist/lib/setups/css/index.js +44 -0
- package/dist/lib/setups/css/postcss.js +34 -0
- package/dist/lib/setups/css/replacers.js +137 -0
- package/dist/lib/setups/css/tailwind.js +54 -0
- package/dist/lib/setups/css/vanilla-extract.js +22 -0
- package/dist/lib/setups/i18n/domains.test.js +25 -0
- package/dist/lib/setups/i18n/index.js +46 -0
- package/dist/lib/setups/i18n/replacers.js +227 -0
- package/dist/lib/setups/i18n/subdomains.test.js +25 -0
- package/dist/lib/setups/i18n/subfolders.test.js +25 -0
- package/dist/lib/setups/i18n/templates/domains.js +14 -0
- package/dist/lib/setups/i18n/templates/domains.ts +25 -0
- package/dist/lib/setups/i18n/templates/subdomains.js +14 -0
- package/dist/lib/setups/i18n/templates/subdomains.ts +24 -0
- package/dist/lib/setups/i18n/templates/subfolders.js +14 -0
- package/dist/lib/setups/i18n/templates/subfolders.ts +28 -0
- package/dist/lib/setups/routes/generate.js +244 -0
- package/dist/lib/setups/routes/generate.test.js +313 -0
- package/dist/lib/shell.js +52 -5
- package/dist/lib/shell.test.js +42 -16
- package/dist/lib/shopify-config.js +23 -18
- package/dist/lib/shopify-config.test.js +63 -73
- package/dist/lib/template-downloader.js +9 -7
- package/dist/lib/transpile-ts.js +9 -29
- package/dist/virtual-routes/routes/index.jsx +40 -19
- package/oclif.manifest.json +710 -1
- package/package.json +16 -16
- package/dist/commands/hydrogen/build.d.ts +0 -23
- package/dist/commands/hydrogen/check.d.ts +0 -15
- package/dist/commands/hydrogen/codegen-unstable.d.ts +0 -15
- package/dist/commands/hydrogen/dev.d.ts +0 -21
- package/dist/commands/hydrogen/env/list.d.ts +0 -18
- package/dist/commands/hydrogen/env/pull.d.ts +0 -22
- package/dist/commands/hydrogen/g.d.ts +0 -10
- package/dist/commands/hydrogen/generate/route.d.ts +0 -32
- package/dist/commands/hydrogen/generate/route.test.d.ts +0 -1
- package/dist/commands/hydrogen/generate/routes.d.ts +0 -16
- package/dist/commands/hydrogen/init.d.ts +0 -24
- package/dist/commands/hydrogen/init.test.d.ts +0 -1
- package/dist/commands/hydrogen/link.d.ts +0 -23
- package/dist/commands/hydrogen/link.test.d.ts +0 -1
- package/dist/commands/hydrogen/list.d.ts +0 -21
- package/dist/commands/hydrogen/list.test.d.ts +0 -1
- package/dist/commands/hydrogen/preview.d.ts +0 -17
- package/dist/commands/hydrogen/shortcut.d.ts +0 -9
- package/dist/commands/hydrogen/shortcut.test.d.ts +0 -1
- package/dist/commands/hydrogen/unlink.d.ts +0 -16
- package/dist/commands/hydrogen/unlink.test.d.ts +0 -1
- package/dist/create-app.d.ts +0 -1
- package/dist/generator-templates/routes/[sitemap.xml].tsx +0 -235
- package/dist/generator-templates/routes/account/login.tsx +0 -103
- package/dist/generator-templates/routes/account/register.tsx +0 -103
- package/dist/generator-templates/routes/cart.tsx +0 -81
- package/dist/generator-templates/routes/collections/$collectionHandle.tsx +0 -104
- package/dist/generator-templates/routes/collections/index.tsx +0 -102
- package/dist/generator-templates/routes/graphiql.tsx +0 -10
- package/dist/generator-templates/routes/index.tsx +0 -40
- package/dist/generator-templates/routes/pages/$pageHandle.tsx +0 -112
- package/dist/generator-templates/routes/policies/$policyHandle.tsx +0 -140
- package/dist/generator-templates/routes/policies/index.tsx +0 -117
- package/dist/generator-templates/routes/products/$productHandle.tsx +0 -92
- package/dist/hooks/init.d.ts +0 -5
- package/dist/lib/admin-session.d.ts +0 -6
- package/dist/lib/admin-session.js +0 -16
- package/dist/lib/admin-session.test.d.ts +0 -1
- package/dist/lib/admin-session.test.js +0 -27
- package/dist/lib/admin-urls.d.ts +0 -8
- package/dist/lib/check-lockfile.d.ts +0 -3
- package/dist/lib/check-lockfile.test.d.ts +0 -1
- package/dist/lib/check-version.d.ts +0 -16
- package/dist/lib/check-version.test.d.ts +0 -1
- package/dist/lib/codegen.d.ts +0 -26
- package/dist/lib/combined-environment-variables.d.ts +0 -8
- package/dist/lib/combined-environment-variables.js +0 -57
- package/dist/lib/combined-environment-variables.test.d.ts +0 -1
- package/dist/lib/combined-environment-variables.test.js +0 -111
- package/dist/lib/config.d.ts +0 -20
- package/dist/lib/flags.d.ts +0 -27
- package/dist/lib/flags.test.d.ts +0 -1
- package/dist/lib/graphql/admin/create-storefront.d.ts +0 -17
- package/dist/lib/graphql/admin/fetch-job.d.ts +0 -23
- package/dist/lib/graphql/admin/link-storefront.d.ts +0 -14
- package/dist/lib/graphql/admin/list-environments.d.ts +0 -21
- package/dist/lib/graphql/admin/list-storefronts.d.ts +0 -25
- package/dist/lib/graphql/admin/pull-variables.d.ts +0 -21
- package/dist/lib/graphql.d.ts +0 -21
- package/dist/lib/graphql.js +0 -18
- package/dist/lib/graphql.test.d.ts +0 -1
- package/dist/lib/log.d.ts +0 -6
- package/dist/lib/mini-oxygen.d.ts +0 -22
- package/dist/lib/missing-routes.d.ts +0 -8
- package/dist/lib/missing-routes.test.d.ts +0 -1
- package/dist/lib/missing-storefronts.d.ts +0 -5
- package/dist/lib/missing-storefronts.js +0 -18
- package/dist/lib/process.d.ts +0 -6
- package/dist/lib/pull-environment-variables.d.ts +0 -20
- package/dist/lib/pull-environment-variables.js +0 -57
- package/dist/lib/pull-environment-variables.test.d.ts +0 -1
- package/dist/lib/pull-environment-variables.test.js +0 -174
- package/dist/lib/remix-version-interop.d.ts +0 -11
- package/dist/lib/remix-version-interop.test.d.ts +0 -1
- package/dist/lib/render-errors.d.ts +0 -16
- package/dist/lib/shell.d.ts +0 -11
- package/dist/lib/shell.test.d.ts +0 -1
- package/dist/lib/shop.d.ts +0 -7
- package/dist/lib/shop.js +0 -32
- package/dist/lib/shop.test.d.ts +0 -1
- package/dist/lib/shop.test.js +0 -78
- package/dist/lib/shopify-config.d.ts +0 -35
- package/dist/lib/shopify-config.test.d.ts +0 -1
- package/dist/lib/string.d.ts +0 -3
- package/dist/lib/string.test.d.ts +0 -1
- package/dist/lib/template-downloader.d.ts +0 -6
- package/dist/lib/transpile-ts.d.ts +0 -16
- package/dist/lib/user-errors.d.ts +0 -9
- package/dist/lib/user-errors.js +0 -11
- package/dist/lib/virtual-routes.d.ts +0 -7
- package/dist/lib/virtual-routes.test.d.ts +0 -1
- /package/dist/{commands/hydrogen/env/list.test.d.ts → lib/setups/css/common.js} +0 -0
- /package/dist/{commands/hydrogen/env/pull.test.d.ts → lib/setups/i18n/mock-i18n-types.js} +0 -0
|
@@ -3,10 +3,11 @@ import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
|
|
|
3
3
|
import { inTemporaryDirectory, fileExists, readFile, writeFile } from '@shopify/cli-kit/node/fs';
|
|
4
4
|
import { joinPath } from '@shopify/cli-kit/node/path';
|
|
5
5
|
import { renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { login } from '../../../lib/auth.js';
|
|
7
|
+
import { getStorefrontEnvVariables } from '../../../lib/graphql/admin/pull-variables.js';
|
|
8
|
+
import { runEnvPull } from './pull.js';
|
|
9
|
+
import { renderMissingLink, renderMissingStorefront } from '../../../lib/render-errors.js';
|
|
10
|
+
import { linkStorefront } from '../link.js';
|
|
10
11
|
|
|
11
12
|
vi.mock("@shopify/cli-kit/node/ui", async () => {
|
|
12
13
|
const original = await vi.importActual("@shopify/cli-kit/node/ui");
|
|
@@ -16,58 +17,65 @@ vi.mock("@shopify/cli-kit/node/ui", async () => {
|
|
|
16
17
|
};
|
|
17
18
|
});
|
|
18
19
|
vi.mock("../link.js");
|
|
19
|
-
vi.mock("../../../lib/
|
|
20
|
-
vi.mock("../../../lib/
|
|
21
|
-
vi.mock("../../../lib/pull-
|
|
22
|
-
vi.mock("../../../lib/shop.js", () => ({
|
|
23
|
-
getHydrogenShop: () => "my-shop"
|
|
24
|
-
}));
|
|
20
|
+
vi.mock("../../../lib/auth.js");
|
|
21
|
+
vi.mock("../../../lib/render-errors.js");
|
|
22
|
+
vi.mock("../../../lib/graphql/admin/pull-variables.js");
|
|
25
23
|
describe("pullVariables", () => {
|
|
26
24
|
const ADMIN_SESSION = {
|
|
27
25
|
token: "abc123",
|
|
28
26
|
storeFqdn: "my-shop"
|
|
29
27
|
};
|
|
28
|
+
const SHOPIFY_CONFIG = {
|
|
29
|
+
shop: "my-shop",
|
|
30
|
+
shopName: "My Shop",
|
|
31
|
+
email: "email",
|
|
32
|
+
storefront: {
|
|
33
|
+
id: "gid://shopify/HydrogenStorefront/2",
|
|
34
|
+
title: "Existing Link"
|
|
35
|
+
}
|
|
36
|
+
};
|
|
30
37
|
beforeEach(async () => {
|
|
31
|
-
vi.mocked(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
vi.mocked(login).mockResolvedValue({
|
|
39
|
+
session: ADMIN_SESSION,
|
|
40
|
+
config: SHOPIFY_CONFIG
|
|
41
|
+
});
|
|
42
|
+
vi.mocked(getStorefrontEnvVariables).mockResolvedValue({
|
|
43
|
+
id: SHOPIFY_CONFIG.storefront.id,
|
|
44
|
+
environmentVariables: [
|
|
45
|
+
{
|
|
46
|
+
id: "gid://shopify/HydrogenStorefrontEnvironmentVariable/1",
|
|
47
|
+
key: "PUBLIC_API_TOKEN",
|
|
48
|
+
value: "abc123",
|
|
49
|
+
isSecret: false
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "gid://shopify/HydrogenStorefrontEnvironmentVariable/2",
|
|
53
|
+
key: "PRIVATE_API_TOKEN",
|
|
54
|
+
value: "",
|
|
55
|
+
isSecret: true
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
});
|
|
52
59
|
});
|
|
53
60
|
afterEach(() => {
|
|
54
61
|
vi.resetAllMocks();
|
|
55
62
|
mockAndCaptureOutput().clear();
|
|
56
63
|
});
|
|
57
|
-
it("calls
|
|
64
|
+
it("calls getStorefrontEnvVariables", async () => {
|
|
58
65
|
await inTemporaryDirectory(async (tmpDir) => {
|
|
59
|
-
await
|
|
60
|
-
expect(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
await runEnvPull({ path: tmpDir, envBranch: "staging" });
|
|
67
|
+
expect(getStorefrontEnvVariables).toHaveBeenCalledWith(
|
|
68
|
+
ADMIN_SESSION,
|
|
69
|
+
SHOPIFY_CONFIG.storefront.id,
|
|
70
|
+
"staging"
|
|
71
|
+
);
|
|
64
72
|
});
|
|
65
73
|
});
|
|
66
74
|
it("writes environment variables to a .env file", async () => {
|
|
67
75
|
await inTemporaryDirectory(async (tmpDir) => {
|
|
68
76
|
const filePath = joinPath(tmpDir, ".env");
|
|
69
77
|
expect(await fileExists(filePath)).toBeFalsy();
|
|
70
|
-
await
|
|
78
|
+
await runEnvPull({ path: tmpDir });
|
|
71
79
|
expect(await readFile(filePath)).toStrictEqual(
|
|
72
80
|
'PUBLIC_API_TOKEN=abc123\nPRIVATE_API_TOKEN=""'
|
|
73
81
|
);
|
|
@@ -76,7 +84,7 @@ describe("pullVariables", () => {
|
|
|
76
84
|
it("warns about secret environment variables", async () => {
|
|
77
85
|
await inTemporaryDirectory(async (tmpDir) => {
|
|
78
86
|
const outputMock = mockAndCaptureOutput();
|
|
79
|
-
await
|
|
87
|
+
await runEnvPull({ path: tmpDir });
|
|
80
88
|
expect(outputMock.warn()).toMatch(
|
|
81
89
|
/Existing Link contains environment variables marked as secret, so their/
|
|
82
90
|
);
|
|
@@ -86,12 +94,85 @@ describe("pullVariables", () => {
|
|
|
86
94
|
it("renders a success message", async () => {
|
|
87
95
|
await inTemporaryDirectory(async (tmpDir) => {
|
|
88
96
|
const outputMock = mockAndCaptureOutput();
|
|
89
|
-
await
|
|
97
|
+
await runEnvPull({ path: tmpDir });
|
|
90
98
|
expect(outputMock.info()).toMatch(
|
|
91
99
|
/Changes have been made to your \.env file/
|
|
92
100
|
);
|
|
93
101
|
});
|
|
94
102
|
});
|
|
103
|
+
describe("when environment variables are empty", () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
vi.mocked(getStorefrontEnvVariables).mockResolvedValue({
|
|
106
|
+
id: "gid://shopify/HydrogenStorefront/1",
|
|
107
|
+
environmentVariables: []
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
it("renders a message", async () => {
|
|
111
|
+
await inTemporaryDirectory(async (tmpDir) => {
|
|
112
|
+
const outputMock = mockAndCaptureOutput();
|
|
113
|
+
await runEnvPull({ path: tmpDir });
|
|
114
|
+
expect(outputMock.info()).toMatch(/No environment variables found\./);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe("when there is no linked storefront", () => {
|
|
119
|
+
beforeEach(async () => {
|
|
120
|
+
vi.mocked(login).mockResolvedValue({
|
|
121
|
+
session: ADMIN_SESSION,
|
|
122
|
+
config: {
|
|
123
|
+
...SHOPIFY_CONFIG,
|
|
124
|
+
storefront: void 0
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
it("calls renderMissingLink", async () => {
|
|
129
|
+
await inTemporaryDirectory(async (tmpDir) => {
|
|
130
|
+
await runEnvPull({ path: tmpDir });
|
|
131
|
+
expect(renderMissingLink).toHaveBeenCalledOnce();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
it("prompts the user to create a link", async () => {
|
|
135
|
+
vi.mocked(renderConfirmationPrompt).mockResolvedValue(true);
|
|
136
|
+
await inTemporaryDirectory(async (tmpDir) => {
|
|
137
|
+
await runEnvPull({ path: tmpDir });
|
|
138
|
+
expect(renderConfirmationPrompt).toHaveBeenCalledWith({
|
|
139
|
+
message: expect.stringMatching(/Run .* link.*\?/i)
|
|
140
|
+
});
|
|
141
|
+
expect(linkStorefront).toHaveBeenCalledWith(
|
|
142
|
+
tmpDir,
|
|
143
|
+
ADMIN_SESSION,
|
|
144
|
+
{ ...SHOPIFY_CONFIG, storefront: void 0 },
|
|
145
|
+
expect.anything()
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
it("ends without requesting variables", async () => {
|
|
150
|
+
await inTemporaryDirectory(async (tmpDir) => {
|
|
151
|
+
await runEnvPull({ path: tmpDir });
|
|
152
|
+
expect(getStorefrontEnvVariables).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
describe("and the user does not create a new link", () => {
|
|
156
|
+
it("ends without requesting variables", async () => {
|
|
157
|
+
vi.mocked(renderConfirmationPrompt).mockResolvedValue(false);
|
|
158
|
+
await inTemporaryDirectory(async (tmpDir) => {
|
|
159
|
+
await runEnvPull({ path: tmpDir });
|
|
160
|
+
expect(getStorefrontEnvVariables).not.toHaveBeenCalled();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
describe("when there is no matching storefront in the shop", () => {
|
|
166
|
+
beforeEach(() => {
|
|
167
|
+
vi.mocked(getStorefrontEnvVariables).mockResolvedValue(null);
|
|
168
|
+
});
|
|
169
|
+
it("renders missing storefronts message and ends", async () => {
|
|
170
|
+
await inTemporaryDirectory(async (tmpDir) => {
|
|
171
|
+
await runEnvPull({ path: tmpDir });
|
|
172
|
+
expect(renderMissingStorefront).toHaveBeenCalledOnce();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
});
|
|
95
176
|
describe("when a .env file already exists", () => {
|
|
96
177
|
beforeEach(() => {
|
|
97
178
|
vi.mocked(renderConfirmationPrompt).mockResolvedValue(true);
|
|
@@ -100,7 +181,7 @@ describe("pullVariables", () => {
|
|
|
100
181
|
await inTemporaryDirectory(async (tmpDir) => {
|
|
101
182
|
const filePath = joinPath(tmpDir, ".env");
|
|
102
183
|
await writeFile(filePath, "EXISTING_TOKEN=1");
|
|
103
|
-
await
|
|
184
|
+
await runEnvPull({ path: tmpDir });
|
|
104
185
|
expect(renderConfirmationPrompt).toHaveBeenCalledWith({
|
|
105
186
|
confirmationMessage: `Yes, confirm changes`,
|
|
106
187
|
cancellationMessage: `No, make changes later`,
|
|
@@ -115,7 +196,7 @@ describe("pullVariables", () => {
|
|
|
115
196
|
await inTemporaryDirectory(async (tmpDir) => {
|
|
116
197
|
const filePath = joinPath(tmpDir, ".env");
|
|
117
198
|
await writeFile(filePath, "EXISTING_TOKEN=1");
|
|
118
|
-
await
|
|
199
|
+
await runEnvPull({ path: tmpDir, force: true });
|
|
119
200
|
expect(renderConfirmationPrompt).not.toHaveBeenCalled();
|
|
120
201
|
});
|
|
121
202
|
});
|
|
@@ -1,27 +1,11 @@
|
|
|
1
|
-
import { fileURLToPath } from 'url';
|
|
2
1
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import { renderSuccess, renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
|
|
2
|
+
import { resolvePath } from '@shopify/cli-kit/node/path';
|
|
3
|
+
import { renderSuccess } from '@shopify/cli-kit/node/ui';
|
|
4
|
+
import colors from '@shopify/cli-kit/node/colors';
|
|
7
5
|
import { commonFlags } from '../../../lib/flags.js';
|
|
8
6
|
import { Flags, Args } from '@oclif/core';
|
|
9
|
-
import {
|
|
10
|
-
import { getV2Flags, convertRouteToV2, convertTemplateToRemixVersion } from '../../../lib/remix-version-interop.js';
|
|
7
|
+
import { ALL_ROUTE_CHOICES, generateRoutes } from '../../../lib/setups/routes/generate.js';
|
|
11
8
|
|
|
12
|
-
const GENERATOR_TEMPLATES_DIR = "generator-templates";
|
|
13
|
-
const ROUTE_MAP = {
|
|
14
|
-
home: "/index",
|
|
15
|
-
page: "/pages/$pageHandle",
|
|
16
|
-
cart: "/cart",
|
|
17
|
-
products: "/products/$productHandle",
|
|
18
|
-
collections: "/collections/$collectionHandle",
|
|
19
|
-
policies: ["/policies/index", "/policies/$policyHandle"],
|
|
20
|
-
robots: "/[robots.txt]",
|
|
21
|
-
sitemap: "/[sitemap.xml]",
|
|
22
|
-
account: ["/account/login", "/account/register"]
|
|
23
|
-
};
|
|
24
|
-
const ROUTES = [...Object.keys(ROUTE_MAP), "all"];
|
|
25
9
|
class GenerateRoute extends Command {
|
|
26
10
|
static description = "Generates a standard Shopify route.";
|
|
27
11
|
static flags = {
|
|
@@ -38,131 +22,46 @@ class GenerateRoute extends Command {
|
|
|
38
22
|
};
|
|
39
23
|
static hidden;
|
|
40
24
|
static args = {
|
|
41
|
-
|
|
42
|
-
name: "
|
|
43
|
-
description: `The route to generate. One of ${
|
|
25
|
+
routeName: Args.string({
|
|
26
|
+
name: "routeName",
|
|
27
|
+
description: `The route to generate. One of ${ALL_ROUTE_CHOICES.join()}.`,
|
|
44
28
|
required: true,
|
|
45
|
-
options:
|
|
29
|
+
options: ALL_ROUTE_CHOICES,
|
|
46
30
|
env: "SHOPIFY_HYDROGEN_ARG_ROUTE"
|
|
47
31
|
})
|
|
48
32
|
};
|
|
49
33
|
async run() {
|
|
50
|
-
const result = /* @__PURE__ */ new Map();
|
|
51
34
|
const {
|
|
52
35
|
flags,
|
|
53
|
-
args: {
|
|
36
|
+
args: { routeName }
|
|
54
37
|
} = await this.parse(GenerateRoute);
|
|
55
|
-
const routePath = route === "all" ? Object.values(ROUTE_MAP).flat() : ROUTE_MAP[route];
|
|
56
|
-
if (!routePath) {
|
|
57
|
-
throw new AbortError(
|
|
58
|
-
`No route found for ${route}. Try one of ${ROUTES.join()}.`
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
38
|
const directory = flags.path ? resolvePath(flags.path) : process.cwd();
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
for (const item of routesArray) {
|
|
67
|
-
const routeFrom = item;
|
|
68
|
-
const routeTo = isV2RouteConvention ? convertRouteToV2(item) : item;
|
|
69
|
-
result.set(
|
|
70
|
-
routeTo,
|
|
71
|
-
await runGenerate(routeFrom, routeTo, {
|
|
72
|
-
directory,
|
|
73
|
-
typescript: isTypescript,
|
|
74
|
-
force: flags.force,
|
|
75
|
-
adapter: flags.adapter,
|
|
76
|
-
v2Flags
|
|
77
|
-
})
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
} catch (err) {
|
|
81
|
-
throw new AbortError(err.message);
|
|
82
|
-
}
|
|
83
|
-
const extension = isTypescript ? ".tsx" : ".jsx";
|
|
84
|
-
const success = Array.from(result.values()).filter(
|
|
85
|
-
(result2) => result2.operation !== "skipped"
|
|
86
|
-
);
|
|
87
|
-
renderSuccess({
|
|
88
|
-
headline: `${success.length} of ${result.size} route${result.size > 1 ? "s" : ""} generated`,
|
|
89
|
-
body: {
|
|
90
|
-
list: {
|
|
91
|
-
items: Array.from(result.entries()).map(
|
|
92
|
-
([path, { operation }]) => `[${operation}] app/routes${path}${extension}`
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
39
|
+
await runGenerate({
|
|
40
|
+
...flags,
|
|
41
|
+
directory,
|
|
42
|
+
routeName
|
|
96
43
|
});
|
|
97
44
|
}
|
|
98
45
|
}
|
|
99
|
-
async function runGenerate(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
templatesRoot = fileURLToPath(new URL("../../../", import.meta.url)),
|
|
105
|
-
v2Flags = {}
|
|
106
|
-
}) {
|
|
107
|
-
let operation;
|
|
108
|
-
const extension = typescript ? ".tsx" : ".jsx";
|
|
109
|
-
const templatePath = joinPath(
|
|
110
|
-
templatesRoot,
|
|
111
|
-
GENERATOR_TEMPLATES_DIR,
|
|
112
|
-
"routes",
|
|
113
|
-
`${routeFrom}.tsx`
|
|
46
|
+
async function runGenerate(options) {
|
|
47
|
+
const { routes } = await generateRoutes(options);
|
|
48
|
+
const padEnd = 3 + routes.reduce(
|
|
49
|
+
(acc, route) => Math.max(acc, route.destinationRoute.length),
|
|
50
|
+
0
|
|
114
51
|
);
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
`${
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
)} already exists. Do you want to overwrite it?`,
|
|
127
|
-
defaultValue: false
|
|
128
|
-
});
|
|
129
|
-
operation = shouldOverwrite ? "overwritten" : "skipped";
|
|
130
|
-
if (operation === "skipped") {
|
|
131
|
-
return { operation };
|
|
52
|
+
const successfulGenerationCount = routes.filter(
|
|
53
|
+
({ operation }) => operation !== "skipped"
|
|
54
|
+
).length;
|
|
55
|
+
renderSuccess({
|
|
56
|
+
headline: `${successfulGenerationCount} of ${routes.length} route${routes.length > 1 ? "s" : ""} generated`,
|
|
57
|
+
body: {
|
|
58
|
+
list: {
|
|
59
|
+
items: routes.map(
|
|
60
|
+
({ operation, destinationRoute }) => destinationRoute.padEnd(padEnd) + colors.dim(`[${operation}]`)
|
|
61
|
+
)
|
|
62
|
+
}
|
|
132
63
|
}
|
|
133
|
-
}
|
|
134
|
-
operation = "generated";
|
|
135
|
-
}
|
|
136
|
-
let templateContent = await readFile(templatePath);
|
|
137
|
-
templateContent = convertTemplateToRemixVersion(templateContent, v2Flags);
|
|
138
|
-
if (!typescript) {
|
|
139
|
-
const jsConfigPath = joinPath(directory, "jsconfig.json");
|
|
140
|
-
const config = await fileExists(jsConfigPath) ? JSON.parse(
|
|
141
|
-
(await readFile(jsConfigPath, { encoding: "utf8" })).replace(
|
|
142
|
-
/^\s*\/\/.*$/gm,
|
|
143
|
-
""
|
|
144
|
-
)
|
|
145
|
-
) : void 0;
|
|
146
|
-
templateContent = transpileFile(templateContent, config?.compilerOptions);
|
|
147
|
-
}
|
|
148
|
-
if (adapter) {
|
|
149
|
-
templateContent = templateContent.replace(
|
|
150
|
-
/@shopify\/remix-oxygen/g,
|
|
151
|
-
adapter
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
templateContent = format(
|
|
155
|
-
templateContent,
|
|
156
|
-
await resolveFormatConfig(destinationPath),
|
|
157
|
-
destinationPath
|
|
158
|
-
);
|
|
159
|
-
if (!await fileExists(dirname(destinationPath))) {
|
|
160
|
-
await mkdir(dirname(destinationPath));
|
|
161
|
-
}
|
|
162
|
-
await writeFile(destinationPath, templateContent);
|
|
163
|
-
return {
|
|
164
|
-
operation
|
|
165
|
-
};
|
|
64
|
+
});
|
|
166
65
|
}
|
|
167
66
|
|
|
168
|
-
export {
|
|
67
|
+
export { GenerateRoute as default, runGenerate };
|
|
@@ -1,134 +1,42 @@
|
|
|
1
|
-
import { describe, beforeEach, vi, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
import { runGenerate
|
|
4
|
-
import {
|
|
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("
|
|
6
|
+
describe("runGenerate", () => {
|
|
7
|
+
const outputMock = mockAndCaptureOutput();
|
|
10
8
|
beforeEach(() => {
|
|
11
9
|
vi.resetAllMocks();
|
|
12
|
-
vi.mock("
|
|
13
|
-
vi.mock("@shopify/cli-kit/node/ui");
|
|
10
|
+
vi.mock("../../../lib/setups/routes/generate.js");
|
|
14
11
|
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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("
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
}
|