shopify-cli 2.18.0 → 2.20.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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.yaml +2 -1
- data/.github/ISSUE_TEMPLATE/config.yml +9 -0
- data/CHANGELOG.md +16 -2
- data/Gemfile.lock +4 -4
- data/README.md +7 -6
- data/dev.yml +0 -1
- data/docs/users/installation.md +1 -1
- data/lib/project_types/extension/forms/questions/ask_template.rb +3 -3
- data/lib/project_types/extension/messages/messages.rb +17 -1
- data/lib/project_types/extension/models/development_server_requirements.rb +2 -7
- data/lib/project_types/extension/models/server_config/development.rb +9 -0
- data/lib/project_types/extension/models/server_config/development_renderer.rb +1 -1
- data/lib/project_types/extension/models/specification_handlers/{beacon_extension.rb → web_pixel_extension.rb} +11 -10
- data/lib/project_types/extension/models/specification_handlers/{beacon_extension_utils → web_pixel_extension_utils}/script_config.rb +1 -1
- data/lib/project_types/extension/models/specification_handlers/{beacon_extension_utils → web_pixel_extension_utils}/script_config_repository.rb +2 -2
- data/lib/project_types/extension/tasks/configure_options.rb +1 -1
- data/lib/project_types/extension/tasks/execute_commands/outdated_extension_detection.rb +5 -1
- data/lib/project_types/extension/tasks/fetch_specifications.rb +4 -1
- data/lib/project_types/script/commands/create.rb +1 -1
- data/lib/project_types/script/config/extension_points.yml +15 -15
- data/lib/project_types/script/forms/ask_app.rb +0 -5
- data/lib/project_types/script/layers/domain/metadata.rb +3 -5
- data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +5 -3
- data/lib/project_types/script/layers/infrastructure/script_service.rb +1 -1
- data/lib/project_types/script/messages/messages.rb +1 -1
- data/lib/project_types/theme/commands/push.rb +3 -1
- data/lib/project_types/theme/commands/serve.rb +1 -0
- data/lib/project_types/theme/messages/messages.rb +38 -1
- data/lib/shopify_cli/assets/post_auth_page/index.html.erb +34 -0
- data/lib/shopify_cli/assets/post_auth_page/style.css +58 -0
- data/lib/shopify_cli/git.rb +7 -2
- data/lib/shopify_cli/identity_auth/servlet.rb +4 -20
- data/lib/shopify_cli/messages/messages.rb +7 -9
- data/lib/shopify_cli/services/app/create/node_service.rb +1 -1
- data/lib/shopify_cli/services/app/create/php_service.rb +1 -1
- data/lib/shopify_cli/theme/dev_server/hot-reload-no-script.html +27 -0
- data/lib/shopify_cli/theme/dev_server/hot-reload.js +16 -4
- data/lib/shopify_cli/theme/dev_server/hot_reload.rb +2 -0
- data/lib/shopify_cli/theme/dev_server.rb +3 -2
- data/lib/shopify_cli/theme/file.rb +5 -0
- data/lib/shopify_cli/theme/syncer/json_update_handler.rb +16 -6
- data/lib/shopify_cli/theme/syncer/operation.rb +7 -6
- data/lib/shopify_cli/theme/syncer/unsupported_script_warning.rb +90 -0
- data/lib/shopify_cli/theme/syncer.rb +73 -29
- data/lib/shopify_cli/theme/theme_admin_api.rb +16 -11
- data/lib/shopify_cli/theme/theme_admin_api_throttler/bulk.rb +102 -0
- data/lib/shopify_cli/theme/theme_admin_api_throttler/bulk_job.rb +75 -0
- data/lib/shopify_cli/theme/theme_admin_api_throttler/errors.rb +7 -0
- data/lib/shopify_cli/theme/theme_admin_api_throttler/put_request.rb +52 -0
- data/lib/shopify_cli/theme/theme_admin_api_throttler/request_parser.rb +39 -0
- data/lib/shopify_cli/theme/theme_admin_api_throttler/response_parser.rb +21 -0
- data/lib/shopify_cli/theme/theme_admin_api_throttler.rb +62 -0
- data/lib/shopify_cli/version.rb +1 -1
- data/shopify-cli.gemspec +1 -1
- metadata +20 -8
|
@@ -16,6 +16,8 @@ module Theme
|
|
|
16
16
|
ensure_user_try_this: <<~ENSURE_USER,
|
|
17
17
|
Check if your user is activated, has permission to edit themes at the store, and try to re-login.
|
|
18
18
|
ENSURE_USER
|
|
19
|
+
stable_flag_suggestion: "If the current command isn't working as expected," \
|
|
20
|
+
" we suggest re-running the command with the {{command: --stable}} flag",
|
|
19
21
|
init: {
|
|
20
22
|
help: <<~HELP,
|
|
21
23
|
{{command:%s theme init}}: Clones a Git repository to use as a starting point for building a new theme.
|
|
@@ -179,6 +181,41 @@ module Theme
|
|
|
179
181
|
exit: "Exit",
|
|
180
182
|
},
|
|
181
183
|
},
|
|
184
|
+
warnings: {
|
|
185
|
+
unsupported_script: "unsupported script",
|
|
186
|
+
unsupported_script_text: <<~UNSUPPORTED_SCRIPT,
|
|
187
|
+
|
|
188
|
+
{{underline:Unsupported external checkout script}}
|
|
189
|
+
|
|
190
|
+
You have a code snippet on your storefront that violates
|
|
191
|
+
Shopify's Terms of Service. This script removes Shopify's
|
|
192
|
+
ability to protect your store against fraudulent orders,
|
|
193
|
+
could steal customer data and may cause customers to be
|
|
194
|
+
charged the wrong amount.
|
|
195
|
+
|
|
196
|
+
%s
|
|
197
|
+
By proceeding, you're acknowledging that you understand the
|
|
198
|
+
risks and will not hold Shopify liable for any problems that
|
|
199
|
+
occur due to the use of an external checkout, including:
|
|
200
|
+
|
|
201
|
+
- Discounts
|
|
202
|
+
- Shipping rules
|
|
203
|
+
- Multi-currency rules
|
|
204
|
+
- Variant selection
|
|
205
|
+
- Orders and fulfillment workflows
|
|
206
|
+
- Shopify Fraud Protection
|
|
207
|
+
- Payment settings
|
|
208
|
+
- Cart
|
|
209
|
+
|
|
210
|
+
You also acknowledge that you will not be able to reliably
|
|
211
|
+
get support for those features from Shopify because you are
|
|
212
|
+
violating Shopify's terms of service and that your account
|
|
213
|
+
may become suspended as a result.
|
|
214
|
+
UNSUPPORTED_SCRIPT
|
|
215
|
+
line_and_column: <<~LINE_AND_COLUMN,
|
|
216
|
+
- Line: %s Column: %s
|
|
217
|
+
LINE_AND_COLUMN
|
|
218
|
+
},
|
|
182
219
|
},
|
|
183
220
|
error: {
|
|
184
221
|
address_binding_error: "Couldn't bind to localhost."\
|
|
@@ -309,7 +346,7 @@ module Theme
|
|
|
309
346
|
{{command:-t, --theme=NAME_OR_ID}} Theme ID or name of your theme.
|
|
310
347
|
{{command:-l, --live}} Open your live theme.
|
|
311
348
|
{{command:-d, --development}} Open your development theme.
|
|
312
|
-
{{command:-e, --editor}} Open the editor
|
|
349
|
+
{{command:-e, --editor}} Open the theme editor for the specified theme in the browser.
|
|
313
350
|
HELP
|
|
314
351
|
},
|
|
315
352
|
list: {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Shopify CLI</title>
|
|
8
|
+
<style><%= locals[:css] %></style>
|
|
9
|
+
<link rel="icon" href="data:image/svg+xml;charset=UTF-8,%3c?xml version='1.0' encoding='utf-8'?%3e%3c!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3e%3csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 109.5 124.5' style='enable-background:new 0 0 109.5 124.5;' xml:space='preserve'%3e%3cstyle type='text/css'%3e .st0%7bfill:%2395BF47;%7d .st1%7bfill:%235E8E3E;%7d .st2%7bfill:%23FFFFFF;%7d %3c/style%3e%3cg%3e%3cpath class='st0' d='M95.9,23.9c-0.1-0.6-0.6-1-1.1-1c-0.5,0-9.3-0.2-9.3-0.2s-7.4-7.2-8.1-7.9c-0.7-0.7-2.2-0.5-2.7-0.3 c0,0-1.4,0.4-3.7,1.1c-0.4-1.3-1-2.8-1.8-4.4c-2.6-5-6.5-7.7-11.1-7.7c0,0,0,0,0,0c-0.3,0-0.6,0-1,0.1c-0.1-0.2-0.3-0.3-0.4-0.5 c-2-2.2-4.6-3.2-7.7-3.1c-6,0.2-12,4.5-16.8,12.2c-3.4,5.4-6,12.2-6.8,17.5c-6.9,2.1-11.7,3.6-11.8,3.7c-3.5,1.1-3.6,1.2-4,4.5 c-0.3,2.5-9.5,73-9.5,73l76.4,13.2l33.1-8.2C109.5,115.8,96,24.5,95.9,23.9z M67.2,16.8c-1.8,0.5-3.8,1.2-5.9,1.8 c0-3-0.4-7.3-1.8-10.9C64,8.6,66.2,13.7,67.2,16.8z M57.2,19.9c-4,1.2-8.4,2.6-12.8,3.9c1.2-4.7,3.6-9.4,6.4-12.5 c1.1-1.1,2.6-2.4,4.3-3.2C56.9,11.6,57.3,16.5,57.2,19.9z M49.1,4c1.4,0,2.6,0.3,3.6,0.9C51.1,5.8,49.5,7,48,8.6 c-3.8,4.1-6.7,10.5-7.9,16.6c-3.6,1.1-7.2,2.2-10.5,3.2C31.7,18.8,39.8,4.3,49.1,4z'/%3e%3cg%3e%3cpath class='st1' d='M94.8,22.9c-0.5,0-9.3-0.2-9.3-0.2s-7.4-7.2-8.1-7.9c-0.3-0.3-0.6-0.4-1-0.5l0,109.7l33.1-8.2 c0,0-13.5-91.3-13.6-92C95.8,23.3,95.3,22.9,94.8,22.9z'/%3e%3cpath class='st2' d='M58,39.9l-3.8,14.4c0,0-4.3-2-9.4-1.6c-7.5,0.5-7.5,5.2-7.5,6.4c0.4,6.4,17.3,7.8,18.3,22.9 c0.7,11.9-6.3,20-16.4,20.6c-12.2,0.8-18.9-6.4-18.9-6.4l2.6-11c0,0,6.7,5.1,12.1,4.7c3.5-0.2,4.8-3.1,4.7-5.1 c-0.5-8.4-14.3-7.9-15.2-21.7c-0.7-11.6,6.9-23.4,23.7-24.4C54.7,38.2,58,39.9,58,39.9z'/%3e%3c/g%3e%3c/g%3e%3c/svg%3e" sizes="any" type="image/svg+xml">
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<% if successful %>
|
|
13
|
+
<body class="body-success">
|
|
14
|
+
<div class="app-success">
|
|
15
|
+
<div class="container">
|
|
16
|
+
<h1><%= locals[:message] %></h1>
|
|
17
|
+
<p>You can close this tab and return to your terminal.</p>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</body>
|
|
21
|
+
<% else %>
|
|
22
|
+
<body class="body-error">
|
|
23
|
+
<div class="app-error">
|
|
24
|
+
<div class="container">
|
|
25
|
+
<h1>Something went wrong!</h1>
|
|
26
|
+
<p><%= locals[:message] %></p>
|
|
27
|
+
<br>
|
|
28
|
+
<br>
|
|
29
|
+
<p>Return to your terminal and try running the previous command again.</p>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</body>
|
|
33
|
+
<% end %>
|
|
34
|
+
</html>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
html {
|
|
2
|
+
font-family: -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
|
3
|
+
text-size-adjust: 100%;
|
|
4
|
+
text-rendering: optimizeLegibility;
|
|
5
|
+
-webkit-font-smoothing: antialiased;
|
|
6
|
+
-moz-osx-font-smoothing: grayscale;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
body {
|
|
10
|
+
font-size: 26px;
|
|
11
|
+
line-height: normal;
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
button, input, optgroup, select, textarea {
|
|
17
|
+
font-family: inherit;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
h1 {
|
|
21
|
+
font-weight: 600;
|
|
22
|
+
font-size: 1em;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
p {
|
|
26
|
+
font-weight: 400;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.body-success {
|
|
30
|
+
color: #F6F6F7;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.body-error {
|
|
34
|
+
color: #202223;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.app-success {
|
|
38
|
+
width: 100vw;
|
|
39
|
+
height: 100vh;
|
|
40
|
+
background-color: #054A49;
|
|
41
|
+
display: flex;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.app-error {
|
|
45
|
+
width: 100vw;
|
|
46
|
+
height: 100vh;
|
|
47
|
+
background-color: #F6F6F7;
|
|
48
|
+
display: flex;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.container {
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
width: 100%;
|
|
56
|
+
height: 100%;
|
|
57
|
+
padding-left: 7.5em;
|
|
58
|
+
}
|
data/lib/shopify_cli/git.rb
CHANGED
|
@@ -67,9 +67,14 @@ module ShopifyCLI
|
|
|
67
67
|
if Dir.exist?(dest)
|
|
68
68
|
ctx.abort(ctx.message("core.git.error.directory_exists"))
|
|
69
69
|
else
|
|
70
|
+
repo, branch = repository.split("#")
|
|
70
71
|
success_message = ctx.message("core.git.cloned", dest)
|
|
71
|
-
CLI::UI::Frame.open(ctx.message("core.git.cloning",
|
|
72
|
-
|
|
72
|
+
CLI::UI::Frame.open(ctx.message("core.git.cloning", repo, dest), success_text: success_message) do
|
|
73
|
+
if branch
|
|
74
|
+
clone_progress("clone", "--single-branch", "--branch", branch, repo, dest, ctx: ctx)
|
|
75
|
+
else
|
|
76
|
+
clone_progress("clone", "--single-branch", repo, dest, ctx: ctx)
|
|
77
|
+
end
|
|
73
78
|
end
|
|
74
79
|
end
|
|
75
80
|
end
|
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
module ShopifyCLI
|
|
2
2
|
class IdentityAuth
|
|
3
3
|
class Servlet < WEBrick::HTTPServlet::AbstractServlet
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<head>
|
|
7
|
-
<title>%{title}</title>
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<h1 style="color: #%{color};">%{message}</h1>
|
|
11
|
-
%{autoclose}
|
|
12
|
-
</body>
|
|
13
|
-
</html>
|
|
14
|
-
}
|
|
15
|
-
AUTOCLOSE_TEMPLATE = %{
|
|
16
|
-
<script>window.close();</script>
|
|
17
|
-
}
|
|
4
|
+
ERB_FILENAME = File.join(ROOT, "lib/shopify_cli/assets/post_auth_page/index.html.erb")
|
|
5
|
+
CSS_FILENAME = File.join(ROOT, "lib/shopify_cli/assets/post_auth_page/style.css")
|
|
18
6
|
|
|
19
7
|
def initialize(server, identity_auth, token)
|
|
20
8
|
super
|
|
@@ -46,14 +34,10 @@ module ShopifyCLI
|
|
|
46
34
|
locals = {
|
|
47
35
|
status: status,
|
|
48
36
|
message: message,
|
|
49
|
-
|
|
50
|
-
title: Context.message(
|
|
51
|
-
successful ? "core.identity_auth.servlet.authenticated" : "core.identity_auth.servlet.not_authenticated"
|
|
52
|
-
),
|
|
53
|
-
autoclose: successful ? AUTOCLOSE_TEMPLATE : "",
|
|
37
|
+
css: File.read(CSS_FILENAME),
|
|
54
38
|
}
|
|
55
39
|
response.status = status
|
|
56
|
-
response.body =
|
|
40
|
+
response.body = ERB.new(File.read(ERB_FILENAME)).result(binding)
|
|
57
41
|
end
|
|
58
42
|
end
|
|
59
43
|
end
|
|
@@ -285,7 +285,7 @@ module ShopifyCLI
|
|
|
285
285
|
},
|
|
286
286
|
extension: {
|
|
287
287
|
push: {
|
|
288
|
-
|
|
288
|
+
web_pixel_extension: {
|
|
289
289
|
error: {
|
|
290
290
|
file_read_error: "There was a problem reading %s",
|
|
291
291
|
missing_config_key_error: "Configuration is missing key: %s",
|
|
@@ -449,7 +449,7 @@ module ShopifyCLI
|
|
|
449
449
|
login: {
|
|
450
450
|
help: <<~HELP,
|
|
451
451
|
Log in to the Shopify CLI by authenticating with a store or partner organization
|
|
452
|
-
Usage: {{command:%s login [--store STORE]}}
|
|
452
|
+
Usage: {{command:%s login [--store/-s STORE]}}
|
|
453
453
|
HELP
|
|
454
454
|
invalid_shop: <<~MESSAGE,
|
|
455
455
|
Invalid store provided (%s). Please provide the store in the following format: my-store.myshopify.com
|
|
@@ -476,7 +476,7 @@ module ShopifyCLI
|
|
|
476
476
|
switch: {
|
|
477
477
|
help: <<~HELP,
|
|
478
478
|
Switch between development stores in your partner organization
|
|
479
|
-
Usage: {{command:%s switch [--store STORE]}}
|
|
479
|
+
Usage: {{command:%s switch [--store/-s STORE]}}
|
|
480
480
|
HELP
|
|
481
481
|
disabled_as_shopify_org: "Can't switch development stores logged in as {{green:Shopify partners org}}",
|
|
482
482
|
success: "Switched development store to {{green:%s}}",
|
|
@@ -498,11 +498,9 @@ module ShopifyCLI
|
|
|
498
498
|
"{{i}} Authentication required. Login to the URL below with your %s credentials to continue.",
|
|
499
499
|
|
|
500
500
|
servlet: {
|
|
501
|
-
success_response: "
|
|
501
|
+
success_response: "You've successfuly logged into the Shopify CLI!",
|
|
502
502
|
invalid_request_response: "Invalid request: %s",
|
|
503
|
-
invalid_state_response: "
|
|
504
|
-
authenticated: "Authenticated successfully",
|
|
505
|
-
not_authenticated: "Failed to authenticate",
|
|
503
|
+
invalid_state_response: "The anti-forgery state token does not match the initial request.",
|
|
506
504
|
},
|
|
507
505
|
login_prompt: "Please ensure you've logged in with {{command:%s login}} and try again",
|
|
508
506
|
token_authentication: "%s environment variable. We'll authenticate using its value as a token.",
|
|
@@ -589,7 +587,7 @@ module ShopifyCLI
|
|
|
589
587
|
HELP
|
|
590
588
|
|
|
591
589
|
error: {
|
|
592
|
-
no_shop: "No store found. Please run {{command:%s login --store STORE}} to login to a specific store",
|
|
590
|
+
no_shop: "No store found. Please run {{command:%s login --store/-s STORE}} to login to a specific store",
|
|
593
591
|
},
|
|
594
592
|
|
|
595
593
|
customer: {
|
|
@@ -820,7 +818,7 @@ module ShopifyCLI
|
|
|
820
818
|
not_logged_in: <<~MESSAGE,
|
|
821
819
|
It doesn't appear that you're logged in. You must log into a partner organization or a store staff account.
|
|
822
820
|
|
|
823
|
-
If trying to log into a store staff account, please use {{command:%s login --store STORE}} to log in.
|
|
821
|
+
If trying to log into a store staff account, please use {{command:%s login --store/-s STORE}} to log in.
|
|
824
822
|
MESSAGE
|
|
825
823
|
logged_in_shop_only: <<~MESSAGE,
|
|
826
824
|
Logged into store {{green:%s}} as staff (no partner organizations available for this login)
|
|
@@ -117,7 +117,7 @@ module ShopifyCLI
|
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
def build(name)
|
|
120
|
-
ShopifyCLI::Git.clone("https://github.com/Shopify/shopify-app-node.git", name)
|
|
120
|
+
ShopifyCLI::Git.clone("https://github.com/Shopify/shopify-app-template-node.git#cli_two", name)
|
|
121
121
|
|
|
122
122
|
context.root = File.join(context.root, name)
|
|
123
123
|
|
|
@@ -74,7 +74,7 @@ module ShopifyCLI
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def build(form)
|
|
77
|
-
ShopifyCLI::Git.clone("https://github.com/Shopify/shopify-app-php.git", form.name)
|
|
77
|
+
ShopifyCLI::Git.clone("https://github.com/Shopify/shopify-app-template-php.git#cli_two", form.name)
|
|
78
78
|
|
|
79
79
|
context.root = File.join(context.root, form.name)
|
|
80
80
|
context.chdir(context.root)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<noscript>
|
|
2
|
+
<style type="text/css">
|
|
3
|
+
.shopify-cli-no-script-message {
|
|
4
|
+
font-family: -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif;
|
|
5
|
+
text-size-adjust: 100%;
|
|
6
|
+
text-rendering: optimizeLegibility;
|
|
7
|
+
-webkit-font-smoothing: antialiased;
|
|
8
|
+
-moz-osx-font-smoothing: grayscale;
|
|
9
|
+
position: fixed;
|
|
10
|
+
z-index: 999;
|
|
11
|
+
font-weight: 500;
|
|
12
|
+
left: 0;
|
|
13
|
+
top: 0;
|
|
14
|
+
width: 100vw;
|
|
15
|
+
height: 100vh;
|
|
16
|
+
padding: 10rem 0;
|
|
17
|
+
color: #202223;
|
|
18
|
+
text-align: center;
|
|
19
|
+
background-color: #F6F6F7;
|
|
20
|
+
}
|
|
21
|
+
</style>
|
|
22
|
+
<div class="shopify-cli-no-script-message">
|
|
23
|
+
Shopify CLI requires JavaScript to work.
|
|
24
|
+
<br />
|
|
25
|
+
Activate JavaScript support or try a different browser.
|
|
26
|
+
</div>
|
|
27
|
+
</noscript>
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
function verifySSE() {
|
|
3
|
+
if (typeof (EventSource) === "undefined") {
|
|
4
|
+
console.error("[HotReload] Error: SSE features are not supported. Try a different browser.");
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
console.log("[HotReload] Initializing...");
|
|
9
|
+
|
|
10
|
+
verifySSE();
|
|
11
|
+
})();
|
|
12
|
+
|
|
1
13
|
(() => {
|
|
2
14
|
function connect() {
|
|
3
15
|
const eventSource = new EventSource('/hot-reload');
|
|
@@ -32,7 +44,7 @@
|
|
|
32
44
|
|
|
33
45
|
function fetchDOMSections(name) {
|
|
34
46
|
const domSections = sectionNamesByType(name).flatMap((n) => querySelectDOMSections(n));
|
|
35
|
-
|
|
47
|
+
|
|
36
48
|
if (domSections.length > 0) {
|
|
37
49
|
return domSections;
|
|
38
50
|
}
|
|
@@ -40,11 +52,11 @@
|
|
|
40
52
|
return querySelectDOMSections(name);
|
|
41
53
|
}
|
|
42
54
|
|
|
43
|
-
function isFullPageReloadMode(){
|
|
55
|
+
function isFullPageReloadMode() {
|
|
44
56
|
return reloadMode() === 'full-page';
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
function isReloadModeActive(){
|
|
59
|
+
function isReloadModeActive() {
|
|
48
60
|
return reloadMode() !== 'off';
|
|
49
61
|
}
|
|
50
62
|
|
|
@@ -72,7 +84,7 @@
|
|
|
72
84
|
|
|
73
85
|
// Hot reload cookie expires in 3 seconds
|
|
74
86
|
date.setSeconds(date.getSeconds() + 3);
|
|
75
|
-
|
|
87
|
+
|
|
76
88
|
var sections = files.join(',');
|
|
77
89
|
var expires = date.toUTCString();
|
|
78
90
|
|
|
@@ -67,7 +67,9 @@ module ShopifyCLI
|
|
|
67
67
|
|
|
68
68
|
def inject_hot_reload_javascript(body)
|
|
69
69
|
hot_reload_js = ::File.read("#{__dir__}/hot-reload.js")
|
|
70
|
+
hot_reload_no_script = ::File.read("#{__dir__}/hot-reload-no-script.html")
|
|
70
71
|
hot_reload_script = [
|
|
72
|
+
hot_reload_no_script,
|
|
71
73
|
"<script>",
|
|
72
74
|
params_js,
|
|
73
75
|
hot_reload_js,
|
|
@@ -28,11 +28,12 @@ module ShopifyCLI
|
|
|
28
28
|
attr_accessor :ctx
|
|
29
29
|
|
|
30
30
|
def start(ctx, root, host: "127.0.0.1", theme: nil, port: 9292, poll: false, editor_sync: false,
|
|
31
|
-
mode: ReloadMode.default)
|
|
31
|
+
mode: ReloadMode.default, stable: false)
|
|
32
32
|
@ctx = ctx
|
|
33
33
|
theme = find_theme(root, theme)
|
|
34
34
|
ignore_filter = IgnoreFilter.from_path(root)
|
|
35
|
-
@syncer = Syncer.new(ctx, theme: theme, ignore_filter: ignore_filter, overwrite_json: !editor_sync
|
|
35
|
+
@syncer = Syncer.new(ctx, theme: theme, ignore_filter: ignore_filter, overwrite_json: !editor_sync,
|
|
36
|
+
stable: stable)
|
|
36
37
|
watcher = Watcher.new(ctx, theme: theme, ignore_filter: ignore_filter, syncer: @syncer, poll: poll)
|
|
37
38
|
remote_watcher = RemoteWatcher.to(theme: theme, syncer: @syncer)
|
|
38
39
|
|
|
@@ -5,6 +5,7 @@ module ShopifyCLI
|
|
|
5
5
|
module Theme
|
|
6
6
|
class File < Struct.new(:path)
|
|
7
7
|
attr_accessor :remote_checksum
|
|
8
|
+
attr_writer :warnings
|
|
8
9
|
|
|
9
10
|
def initialize(path, root)
|
|
10
11
|
super(Pathname.new(path))
|
|
@@ -104,6 +105,10 @@ module ShopifyCLI
|
|
|
104
105
|
@relative_path.to_s
|
|
105
106
|
end
|
|
106
107
|
|
|
108
|
+
def warnings
|
|
109
|
+
@warnings || []
|
|
110
|
+
end
|
|
111
|
+
|
|
107
112
|
private
|
|
108
113
|
|
|
109
114
|
def normalize_json(content)
|
|
@@ -8,16 +8,11 @@ module ShopifyCLI
|
|
|
8
8
|
class Syncer
|
|
9
9
|
module JsonUpdateHandler
|
|
10
10
|
def enqueue_json_updates(files)
|
|
11
|
-
# Some files must be uploaded after the other ones
|
|
12
|
-
delayed_files = [
|
|
13
|
-
theme["config/settings_schema.json"],
|
|
14
|
-
theme["config/settings_data.json"],
|
|
15
|
-
]
|
|
16
|
-
|
|
17
11
|
# Update remote JSON files and delays `delayed_files` update
|
|
18
12
|
files = files
|
|
19
13
|
.select { |file| !ignore_file?(file) && file.exist? && checksums.file_has_changed?(file) }
|
|
20
14
|
.sort_by { |file| delayed_files.include?(file) ? 1 : 0 }
|
|
15
|
+
.reject { |file| overwrite_json? && delayed_files.include?(file) }
|
|
21
16
|
|
|
22
17
|
if overwrite_json?
|
|
23
18
|
enqueue_updates(files)
|
|
@@ -27,6 +22,21 @@ module ShopifyCLI
|
|
|
27
22
|
end
|
|
28
23
|
end
|
|
29
24
|
|
|
25
|
+
def enqueue_delayed_files_updates
|
|
26
|
+
return unless overwrite_json?
|
|
27
|
+
# Update delayed files synchronously
|
|
28
|
+
delayed_files.each do |file|
|
|
29
|
+
update(file) if checksums.file_has_changed?(file)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def delayed_files
|
|
34
|
+
[
|
|
35
|
+
theme["config/settings_schema.json"],
|
|
36
|
+
theme["config/settings_data.json"],
|
|
37
|
+
]
|
|
38
|
+
end
|
|
39
|
+
|
|
30
40
|
private
|
|
31
41
|
|
|
32
42
|
def handle_update_conflicts(files)
|
|
@@ -9,6 +9,7 @@ module ShopifyCLI
|
|
|
9
9
|
COLOR_BY_STATUS = {
|
|
10
10
|
error: :red,
|
|
11
11
|
synced: :green,
|
|
12
|
+
warning: :yellow,
|
|
12
13
|
fixed: :cyan,
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -26,8 +27,8 @@ module ShopifyCLI
|
|
|
26
27
|
as_message_with(status: :error)
|
|
27
28
|
end
|
|
28
29
|
|
|
29
|
-
def as_synced_message
|
|
30
|
-
as_message_with(status: :synced)
|
|
30
|
+
def as_synced_message(color: :green)
|
|
31
|
+
as_message_with(status: :synced, color: color)
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
def as_fix_message
|
|
@@ -40,11 +41,11 @@ module ShopifyCLI
|
|
|
40
41
|
|
|
41
42
|
private
|
|
42
43
|
|
|
43
|
-
def as_message_with(status:)
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
def as_message_with(status:, color: nil)
|
|
45
|
+
color ||= COLOR_BY_STATUS[status]
|
|
46
|
+
text = @ctx.message("theme.serve.operation.status.#{status}").ljust(6)
|
|
46
47
|
|
|
47
|
-
"#{timestamp} {{#{
|
|
48
|
+
"#{timestamp} {{#{color}:#{text}}} {{>}} {{blue:#{self}}}"
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
def timestamp
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ShopifyCLI
|
|
4
|
+
module Theme
|
|
5
|
+
class Syncer
|
|
6
|
+
class UnsupportedScriptWarning
|
|
7
|
+
attr_reader :ctx
|
|
8
|
+
|
|
9
|
+
def initialize(ctx, file)
|
|
10
|
+
@ctx = ctx
|
|
11
|
+
@file = file
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
"\n\n#{occurrences} #{long_text}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def occurrences
|
|
21
|
+
warnings.map { |w| occurrence(w) }.join("\n")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def occurrence(warning)
|
|
25
|
+
line_number = "{{blue: #{warning.line} |}}"
|
|
26
|
+
pointer = pointer_message(warning)
|
|
27
|
+
|
|
28
|
+
<<~OCCURRENCE
|
|
29
|
+
#{line_number} #{warning.line_content}
|
|
30
|
+
#{pointer}
|
|
31
|
+
OCCURRENCE
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def long_text
|
|
35
|
+
lines_and_columns = warnings.map do |warning|
|
|
36
|
+
message("line_and_column", warning.line, warning.column)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
message("unsupported_script_text", lines_and_columns.join)
|
|
40
|
+
.split("\n")
|
|
41
|
+
.reduce("") do |text, line|
|
|
42
|
+
# Add indentation in the long text to improve readability
|
|
43
|
+
line = " #{line}"
|
|
44
|
+
|
|
45
|
+
# Inline yellow (otherwise `CLI::UI::Frame` breaks multiline formatting)
|
|
46
|
+
line = "{{yellow:#{line}}}"
|
|
47
|
+
|
|
48
|
+
"#{text}#{line}\n"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def pointer_message(warning)
|
|
53
|
+
padding = warning.column + warning.line.to_s.size + 2
|
|
54
|
+
text = message("unsupported_script")
|
|
55
|
+
|
|
56
|
+
"{{yellow:#{" " * padding} ^ {{bold:#{text}}}}}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def message(*args)
|
|
60
|
+
key = args.shift
|
|
61
|
+
@ctx.message("theme.serve.syncer.warnings.#{key}", *args)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def warnings
|
|
65
|
+
@warnings ||= @file.warnings.map { |w| Warning.new(@file, w) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class Warning
|
|
69
|
+
attr_reader :line, :column
|
|
70
|
+
|
|
71
|
+
def initialize(file, warning_hash)
|
|
72
|
+
@file = file
|
|
73
|
+
@line = warning_hash["line"].to_i
|
|
74
|
+
@column = warning_hash["column"].to_i
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def line_content
|
|
78
|
+
file_lines[line - 1]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def file_lines
|
|
84
|
+
@file_lines ||= @file.read.split("\n")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|