@shopify/cli-kit 3.46.1 → 3.46.3
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/assets/cli-ruby/lib/project_types/theme/cli.rb +1 -0
- package/assets/cli-ruby/lib/project_types/theme/commands/token.rb +19 -0
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/cdn_fonts.rb +8 -3
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server/local_assets.rb +13 -4
- package/assets/cli-ruby/lib/shopify_cli/theme/dev_server.rb +1 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/dev_server/local_assets.rb +2 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/extension/dev_server.rb +1 -1
- package/assets/cli-ruby/lib/shopify_cli/theme/repl/auth_dev_server.rb +1 -1
- package/dist/private/node/session/schema.d.ts +27 -27
- package/dist/private/node/ui/components/ConcurrentOutput.js +6 -8
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +7 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +1 -1
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/ruby.d.ts +2 -2
- package/dist/public/node/ruby.js +2 -2
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/session.d.ts +2 -1
- package/dist/public/node/session.js +3 -2
- package/dist/public/node/session.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -20,6 +20,7 @@ module Theme
|
|
|
20
20
|
subcommand :Share, "share", Project.project_filepath("commands/share")
|
|
21
21
|
subcommand :LanguageServer, "language-server", Project.project_filepath("commands/language_server")
|
|
22
22
|
subcommand :Console, "console", Project.project_filepath("commands/console")
|
|
23
|
+
subcommand :Token, "token", Project.project_filepath("commands/token")
|
|
23
24
|
end
|
|
24
25
|
ShopifyCLI::Commands.register("Theme::Command", "theme")
|
|
25
26
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Theme
|
|
4
|
+
class Command
|
|
5
|
+
class Token < ShopifyCLI::Command::SubCommand
|
|
6
|
+
options do |parser, flags|
|
|
7
|
+
parser.on("--admin ADMIN_TOKEN") { |token| flags[:admin_token] = token }
|
|
8
|
+
parser.on("--sfr STOREFRONT_RENDERER_TOKEN") { |token| flags[:sfr_token] = token }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call(_args, _name)
|
|
12
|
+
admin_token = options.flags[:admin_token]
|
|
13
|
+
sfr_token = options.flags[:sfr_token]
|
|
14
|
+
ShopifyCLI::DB.set(shopify_exchange_token: admin_token) if admin_token
|
|
15
|
+
ShopifyCLI::DB.set(storefront_renderer_production_exchange_token: sfr_token) if sfr_token
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -6,9 +6,9 @@ module ShopifyCLI
|
|
|
6
6
|
class CdnFonts
|
|
7
7
|
FONTS_PATH = "/fonts"
|
|
8
8
|
FONTS_CDN = "https://fonts.shopifycdn.com"
|
|
9
|
-
FONTS_REGEX = %r{#{FONTS_CDN}}
|
|
10
9
|
|
|
11
|
-
def initialize(app, theme:)
|
|
10
|
+
def initialize(ctx, app, theme:)
|
|
11
|
+
@ctx = ctx
|
|
12
12
|
@app = app
|
|
13
13
|
@theme = theme
|
|
14
14
|
end
|
|
@@ -69,7 +69,12 @@ module ShopifyCLI
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def replace_font_urls(body)
|
|
72
|
-
|
|
72
|
+
fonts_regex = %r{#{FONTS_CDN}|((http:|https:)?//#{shop}/cdn/fonts)}
|
|
73
|
+
[body.join.gsub(fonts_regex, FONTS_PATH)]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def shop
|
|
77
|
+
@shop ||= ShopifyCLI::Theme::ThemeAdminAPI.new(@ctx).get_shop_or_abort
|
|
73
78
|
end
|
|
74
79
|
end
|
|
75
80
|
end
|
|
@@ -4,8 +4,9 @@ module ShopifyCLI
|
|
|
4
4
|
module Theme
|
|
5
5
|
class DevServer
|
|
6
6
|
class LocalAssets
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
SUPPORTED_EXTENSIONS = [:jpg, :jpeg, :js, :css, :png, :svg].join("|")
|
|
8
|
+
CDN_REGEX = %r{(//cdn)\.shopify\.com/s/.+?/(assets/.+?\.(?:#{SUPPORTED_EXTENSIONS}))}
|
|
9
|
+
VANITY_CDN_REGEX = %r{(/cdn)/shop/.+?/(assets/.+?\.(?:#{SUPPORTED_EXTENSIONS}))}
|
|
9
10
|
|
|
10
11
|
class FileBody
|
|
11
12
|
def initialize(path)
|
|
@@ -42,13 +43,17 @@ module ShopifyCLI
|
|
|
42
43
|
end
|
|
43
44
|
end
|
|
44
45
|
|
|
46
|
+
def shop_regex
|
|
47
|
+
%r{(http:|https:)?//#{shop}/(assets/.+?\.(?:#{SUPPORTED_EXTENSIONS}))}
|
|
48
|
+
end
|
|
49
|
+
|
|
45
50
|
private
|
|
46
51
|
|
|
47
52
|
def replace_asset_urls(body)
|
|
48
53
|
replaced_body = body.join
|
|
49
|
-
[
|
|
54
|
+
[CDN_REGEX, VANITY_CDN_REGEX, shop_regex].each do |regex|
|
|
50
55
|
replaced_body = replaced_body.gsub(regex) do |match|
|
|
51
|
-
path = Regexp.last_match[
|
|
56
|
+
path = Regexp.last_match[2]
|
|
52
57
|
@target.static_asset_paths.include?(path) ? "/#{path}" : match
|
|
53
58
|
end
|
|
54
59
|
end
|
|
@@ -86,6 +91,10 @@ module ShopifyCLI
|
|
|
86
91
|
serve_fail(404, "Not found")
|
|
87
92
|
end
|
|
88
93
|
end
|
|
94
|
+
|
|
95
|
+
def shop
|
|
96
|
+
@shop ||= ShopifyCLI::Theme::ThemeAdminAPI.new(@ctx).get_shop_or_abort
|
|
97
|
+
end
|
|
89
98
|
end
|
|
90
99
|
end
|
|
91
100
|
end
|
|
@@ -168,7 +168,7 @@ module ShopifyCLI
|
|
|
168
168
|
|
|
169
169
|
def middleware_stack
|
|
170
170
|
@app = Proxy.new(ctx, theme, param_builder)
|
|
171
|
-
@app = CdnFonts.new(@app, theme: theme)
|
|
171
|
+
@app = CdnFonts.new(ctx, @app, theme: theme)
|
|
172
172
|
@app = LocalAssets.new(ctx, @app, theme)
|
|
173
173
|
@app = HotReload.new(ctx, @app, broadcast_hooks: broadcast_hooks, watcher: watcher, mode: mode,
|
|
174
174
|
script_injector: script_injector)
|
|
@@ -7,7 +7,8 @@ module ShopifyCLI
|
|
|
7
7
|
module Extension
|
|
8
8
|
class DevServer < ShopifyCLI::Theme::DevServer
|
|
9
9
|
class LocalAssets < ShopifyCLI::Theme::DevServer::LocalAssets
|
|
10
|
-
|
|
10
|
+
SUPPORTED_EXTENSIONS = [:jpg, :jpeg, :js, :css, :png, :svg].join("|")
|
|
11
|
+
TAE_ASSET_REGEX = %r{(http:|https:)?//cdn\.shopify\.com/extensions/.+?/(assets/.+?\.(?:#{SUPPORTED_EXTENSIONS}))}
|
|
11
12
|
|
|
12
13
|
private
|
|
13
14
|
|
|
@@ -44,7 +44,7 @@ module ShopifyCLI
|
|
|
44
44
|
|
|
45
45
|
def middleware_stack
|
|
46
46
|
@app = Proxy.new(ctx, theme, param_builder)
|
|
47
|
-
@app = CdnFonts.new(@app, theme: theme)
|
|
47
|
+
@app = CdnFonts.new(ctx, @app, theme: theme)
|
|
48
48
|
@app = LocalAssets.new(ctx, @app, extension)
|
|
49
49
|
@app = HotReload.new(ctx, @app, broadcast_hooks: broadcast_hooks, watcher: watcher, mode: mode,
|
|
50
50
|
script_injector: script_injector)
|
|
@@ -9,13 +9,13 @@ declare const IdentityTokenSchema: zod.ZodObject<{
|
|
|
9
9
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
10
10
|
}, "strip", zod.ZodTypeAny, {
|
|
11
11
|
accessToken: string;
|
|
12
|
+
scopes: string[];
|
|
12
13
|
refreshToken: string;
|
|
13
14
|
expiresAt: Date;
|
|
14
|
-
scopes: string[];
|
|
15
15
|
}, {
|
|
16
16
|
accessToken: string;
|
|
17
|
-
refreshToken: string;
|
|
18
17
|
scopes: string[];
|
|
18
|
+
refreshToken: string;
|
|
19
19
|
expiresAt?: unknown;
|
|
20
20
|
}>;
|
|
21
21
|
/**
|
|
@@ -27,8 +27,8 @@ declare const ApplicationTokenSchema: zod.ZodObject<{
|
|
|
27
27
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
28
28
|
}, "strip", zod.ZodTypeAny, {
|
|
29
29
|
accessToken: string;
|
|
30
|
-
expiresAt: Date;
|
|
31
30
|
scopes: string[];
|
|
31
|
+
expiresAt: Date;
|
|
32
32
|
}, {
|
|
33
33
|
accessToken: string;
|
|
34
34
|
scopes: string[];
|
|
@@ -70,13 +70,13 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
70
70
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
71
71
|
}, "strip", zod.ZodTypeAny, {
|
|
72
72
|
accessToken: string;
|
|
73
|
+
scopes: string[];
|
|
73
74
|
refreshToken: string;
|
|
74
75
|
expiresAt: Date;
|
|
75
|
-
scopes: string[];
|
|
76
76
|
}, {
|
|
77
77
|
accessToken: string;
|
|
78
|
-
refreshToken: string;
|
|
79
78
|
scopes: string[];
|
|
79
|
+
refreshToken: string;
|
|
80
80
|
expiresAt?: unknown;
|
|
81
81
|
}>;
|
|
82
82
|
/**
|
|
@@ -89,8 +89,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
89
89
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
90
90
|
}, "strip", zod.ZodTypeAny, {
|
|
91
91
|
accessToken: string;
|
|
92
|
-
expiresAt: Date;
|
|
93
92
|
scopes: string[];
|
|
93
|
+
expiresAt: Date;
|
|
94
94
|
}, {
|
|
95
95
|
accessToken: string;
|
|
96
96
|
scopes: string[];
|
|
@@ -101,8 +101,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
101
101
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
102
102
|
}, "strip", zod.ZodTypeAny, {
|
|
103
103
|
accessToken: string;
|
|
104
|
-
expiresAt: Date;
|
|
105
104
|
scopes: string[];
|
|
105
|
+
expiresAt: Date;
|
|
106
106
|
}, {
|
|
107
107
|
accessToken: string;
|
|
108
108
|
scopes: string[];
|
|
@@ -113,8 +113,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
113
113
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
114
114
|
}, "strip", zod.ZodTypeAny, {
|
|
115
115
|
accessToken: string;
|
|
116
|
-
expiresAt: Date;
|
|
117
116
|
scopes: string[];
|
|
117
|
+
expiresAt: Date;
|
|
118
118
|
}, {
|
|
119
119
|
accessToken: string;
|
|
120
120
|
scopes: string[];
|
|
@@ -123,22 +123,22 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
123
123
|
}, "strip", zod.ZodTypeAny, {
|
|
124
124
|
identity: {
|
|
125
125
|
accessToken: string;
|
|
126
|
+
scopes: string[];
|
|
126
127
|
refreshToken: string;
|
|
127
128
|
expiresAt: Date;
|
|
128
|
-
scopes: string[];
|
|
129
129
|
};
|
|
130
130
|
applications: {} & {
|
|
131
131
|
[k: string]: {
|
|
132
132
|
accessToken: string;
|
|
133
|
-
expiresAt: Date;
|
|
134
133
|
scopes: string[];
|
|
134
|
+
expiresAt: Date;
|
|
135
135
|
};
|
|
136
136
|
};
|
|
137
137
|
}, {
|
|
138
138
|
identity: {
|
|
139
139
|
accessToken: string;
|
|
140
|
-
refreshToken: string;
|
|
141
140
|
scopes: string[];
|
|
141
|
+
refreshToken: string;
|
|
142
142
|
expiresAt?: unknown;
|
|
143
143
|
};
|
|
144
144
|
applications: {} & {
|
|
@@ -161,13 +161,13 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
161
161
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
162
162
|
}, "strip", zod.ZodTypeAny, {
|
|
163
163
|
accessToken: string;
|
|
164
|
+
scopes: string[];
|
|
164
165
|
refreshToken: string;
|
|
165
166
|
expiresAt: Date;
|
|
166
|
-
scopes: string[];
|
|
167
167
|
}, {
|
|
168
168
|
accessToken: string;
|
|
169
|
-
refreshToken: string;
|
|
170
169
|
scopes: string[];
|
|
170
|
+
refreshToken: string;
|
|
171
171
|
expiresAt?: unknown;
|
|
172
172
|
}>;
|
|
173
173
|
/**
|
|
@@ -180,8 +180,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
180
180
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
181
181
|
}, "strip", zod.ZodTypeAny, {
|
|
182
182
|
accessToken: string;
|
|
183
|
-
expiresAt: Date;
|
|
184
183
|
scopes: string[];
|
|
184
|
+
expiresAt: Date;
|
|
185
185
|
}, {
|
|
186
186
|
accessToken: string;
|
|
187
187
|
scopes: string[];
|
|
@@ -192,8 +192,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
192
192
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
193
193
|
}, "strip", zod.ZodTypeAny, {
|
|
194
194
|
accessToken: string;
|
|
195
|
-
expiresAt: Date;
|
|
196
195
|
scopes: string[];
|
|
196
|
+
expiresAt: Date;
|
|
197
197
|
}, {
|
|
198
198
|
accessToken: string;
|
|
199
199
|
scopes: string[];
|
|
@@ -204,8 +204,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
204
204
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
205
205
|
}, "strip", zod.ZodTypeAny, {
|
|
206
206
|
accessToken: string;
|
|
207
|
-
expiresAt: Date;
|
|
208
207
|
scopes: string[];
|
|
208
|
+
expiresAt: Date;
|
|
209
209
|
}, {
|
|
210
210
|
accessToken: string;
|
|
211
211
|
scopes: string[];
|
|
@@ -214,22 +214,22 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
214
214
|
}, "strip", zod.ZodTypeAny, {
|
|
215
215
|
identity: {
|
|
216
216
|
accessToken: string;
|
|
217
|
+
scopes: string[];
|
|
217
218
|
refreshToken: string;
|
|
218
219
|
expiresAt: Date;
|
|
219
|
-
scopes: string[];
|
|
220
220
|
};
|
|
221
221
|
applications: {} & {
|
|
222
222
|
[k: string]: {
|
|
223
223
|
accessToken: string;
|
|
224
|
-
expiresAt: Date;
|
|
225
224
|
scopes: string[];
|
|
225
|
+
expiresAt: Date;
|
|
226
226
|
};
|
|
227
227
|
};
|
|
228
228
|
}, {
|
|
229
229
|
identity: {
|
|
230
230
|
accessToken: string;
|
|
231
|
-
refreshToken: string;
|
|
232
231
|
scopes: string[];
|
|
232
|
+
refreshToken: string;
|
|
233
233
|
expiresAt?: unknown;
|
|
234
234
|
};
|
|
235
235
|
applications: {} & {
|
|
@@ -252,13 +252,13 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
252
252
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
253
253
|
}, "strip", zod.ZodTypeAny, {
|
|
254
254
|
accessToken: string;
|
|
255
|
+
scopes: string[];
|
|
255
256
|
refreshToken: string;
|
|
256
257
|
expiresAt: Date;
|
|
257
|
-
scopes: string[];
|
|
258
258
|
}, {
|
|
259
259
|
accessToken: string;
|
|
260
|
-
refreshToken: string;
|
|
261
260
|
scopes: string[];
|
|
261
|
+
refreshToken: string;
|
|
262
262
|
expiresAt?: unknown;
|
|
263
263
|
}>;
|
|
264
264
|
/**
|
|
@@ -271,8 +271,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
271
271
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
272
272
|
}, "strip", zod.ZodTypeAny, {
|
|
273
273
|
accessToken: string;
|
|
274
|
-
expiresAt: Date;
|
|
275
274
|
scopes: string[];
|
|
275
|
+
expiresAt: Date;
|
|
276
276
|
}, {
|
|
277
277
|
accessToken: string;
|
|
278
278
|
scopes: string[];
|
|
@@ -283,8 +283,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
283
283
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
284
284
|
}, "strip", zod.ZodTypeAny, {
|
|
285
285
|
accessToken: string;
|
|
286
|
-
expiresAt: Date;
|
|
287
286
|
scopes: string[];
|
|
287
|
+
expiresAt: Date;
|
|
288
288
|
}, {
|
|
289
289
|
accessToken: string;
|
|
290
290
|
scopes: string[];
|
|
@@ -295,8 +295,8 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
295
295
|
scopes: zod.ZodArray<zod.ZodString, "many">;
|
|
296
296
|
}, "strip", zod.ZodTypeAny, {
|
|
297
297
|
accessToken: string;
|
|
298
|
-
expiresAt: Date;
|
|
299
298
|
scopes: string[];
|
|
299
|
+
expiresAt: Date;
|
|
300
300
|
}, {
|
|
301
301
|
accessToken: string;
|
|
302
302
|
scopes: string[];
|
|
@@ -305,22 +305,22 @@ export declare const SessionSchema: zod.ZodObject<{}, "strip", zod.ZodObject<{
|
|
|
305
305
|
}, "strip", zod.ZodTypeAny, {
|
|
306
306
|
identity: {
|
|
307
307
|
accessToken: string;
|
|
308
|
+
scopes: string[];
|
|
308
309
|
refreshToken: string;
|
|
309
310
|
expiresAt: Date;
|
|
310
|
-
scopes: string[];
|
|
311
311
|
};
|
|
312
312
|
applications: {} & {
|
|
313
313
|
[k: string]: {
|
|
314
314
|
accessToken: string;
|
|
315
|
-
expiresAt: Date;
|
|
316
315
|
scopes: string[];
|
|
316
|
+
expiresAt: Date;
|
|
317
317
|
};
|
|
318
318
|
};
|
|
319
319
|
}, {
|
|
320
320
|
identity: {
|
|
321
321
|
accessToken: string;
|
|
322
|
-
refreshToken: string;
|
|
323
322
|
scopes: string[];
|
|
323
|
+
refreshToken: string;
|
|
324
324
|
expiresAt?: unknown;
|
|
325
325
|
};
|
|
326
326
|
applications: {} & {
|
|
@@ -80,13 +80,12 @@ const ConcurrentOutput = ({ processes, abortSignal, showTimestamps = true, onInp
|
|
|
80
80
|
await process.action(stdout, stderr, abortSignal);
|
|
81
81
|
}));
|
|
82
82
|
};
|
|
83
|
+
const { isAborted } = useAbortSignal(abortSignal);
|
|
84
|
+
const useShortcuts = isRawModeSupported && state === ConcurrentOutputState.Running && !isAborted;
|
|
83
85
|
useInput((input, key) => {
|
|
84
86
|
handleCtrlC(input, key);
|
|
85
87
|
onInput(input, key, () => treeKill('SIGINT'));
|
|
86
|
-
},
|
|
87
|
-
// isRawModeSupported can be undefined even if the type doesn't say so
|
|
88
|
-
// Ink is checking that isActive is actually === false, not falsey
|
|
89
|
-
{ isActive: typeof onInput !== 'undefined' && Boolean(isRawModeSupported) });
|
|
88
|
+
}, { isActive: typeof onInput !== 'undefined' && useShortcuts });
|
|
90
89
|
useAsyncAndUnmount(runProcesses, {
|
|
91
90
|
onFulfilled: () => {
|
|
92
91
|
setState(ConcurrentOutputState.Stopped);
|
|
@@ -95,7 +94,6 @@ const ConcurrentOutput = ({ processes, abortSignal, showTimestamps = true, onInp
|
|
|
95
94
|
setState(ConcurrentOutputState.Stopped);
|
|
96
95
|
},
|
|
97
96
|
});
|
|
98
|
-
const { isAborted } = useAbortSignal(abortSignal);
|
|
99
97
|
return (React.createElement(React.Fragment, null,
|
|
100
98
|
React.createElement(Static, { items: processOutput }, (chunk, index) => {
|
|
101
99
|
return (React.createElement(Box, { flexDirection: "column", key: index }, chunk.lines.map((line, index) => (React.createElement(Box, { key: index, flexDirection: "row" },
|
|
@@ -109,8 +107,8 @@ const ConcurrentOutput = ({ processes, abortSignal, showTimestamps = true, onInp
|
|
|
109
107
|
React.createElement(Box, { flexGrow: 1, paddingLeft: 1 },
|
|
110
108
|
React.createElement(Text, { color: chunk.color }, line)))))));
|
|
111
109
|
}),
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
footer ? (React.createElement(Box, { marginY: 1, flexDirection: "column", flexGrow: 1 },
|
|
111
|
+
useShortcuts ? (React.createElement(Box, { flexDirection: "column" }, footer.shortcuts.map((shortcut, index) => (React.createElement(Text, { key: index },
|
|
114
112
|
figures.pointerSmall,
|
|
115
113
|
" Press ",
|
|
116
114
|
React.createElement(Text, { bold: true }, shortcut.key),
|
|
@@ -118,7 +116,7 @@ const ConcurrentOutput = ({ processes, abortSignal, showTimestamps = true, onInp
|
|
|
118
116
|
figures.lineVertical,
|
|
119
117
|
" ",
|
|
120
118
|
shortcut.action))))) : null,
|
|
121
|
-
footer.subTitle ? (React.createElement(Box, { marginTop:
|
|
119
|
+
footer.subTitle ? (React.createElement(Box, { marginTop: useShortcuts ? 1 : 0 },
|
|
122
120
|
React.createElement(Text, null, footer.subTitle))) : null)) : null));
|
|
123
121
|
};
|
|
124
122
|
export { ConcurrentOutput };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {OutputProcess} from '../../../../public/node/output.js'\nimport useAsyncAndUnmount from '../hooks/use-async-and-unmount.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {handleCtrlC} from '../../ui.js'\nimport {addOrUpdateConcurrentUIEventOutput} from '../../demo-recorder.js'\nimport {treeKill} from '../../tree-kill.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport React, {FunctionComponent, useState} from 'react'\nimport {Box, Key, Static, Text, useInput, TextProps, useStdin} from 'ink'\nimport stripAnsi from 'strip-ansi'\nimport figures from 'figures'\nimport {Writable} from 'stream'\n\nexport type WritableStream = (process: OutputProcess, index: number) => Writable\n\ninterface Shortcut {\n key: string\n action: string\n}\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n abortSignal: AbortSignal\n showTimestamps?: boolean\n onInput?: (input: string, key: Key, exit: () => void) => void\n footer?: {\n shortcuts: Shortcut[]\n subTitle?: string\n }\n}\ninterface Chunk {\n color: TextProps['color']\n prefix: string\n lines: string[]\n}\n\nenum ConcurrentOutputState {\n Running = 'running',\n Stopped = 'stopped',\n}\n\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n abortSignal,\n showTimestamps = true,\n onInput,\n footer,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const concurrentColors: TextProps['color'][] = ['yellow', 'cyan', 'magenta', 'green', 'blue']\n const prefixColumnSize = Math.max(...processes.map((process) => process.prefix.length))\n const {isRawModeSupported} = useStdin()\n const [state, setState] = useState<ConcurrentOutputState>(ConcurrentOutputState.Running)\n\n function lineColor(index: number) {\n const colorIndex = index < concurrentColors.length ? index : index % concurrentColors.length\n return concurrentColors[colorIndex]!\n }\n\n const writableStream = (process: OutputProcess, index: number) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const lines = stripAnsi(chunk.toString('utf8').replace(/(\\n)$/, '')).split(/\\n/)\n addOrUpdateConcurrentUIEventOutput({prefix: process.prefix, index, output: lines.join('\\n')}, {footer})\n\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix: process.prefix,\n lines,\n },\n ])\n\n next()\n },\n })\n }\n\n const runProcesses = () => {\n return Promise.all(\n processes.map(async (process, index) => {\n const stdout = writableStream(process, index)\n const stderr = writableStream(process, index)\n\n await process.action(stdout, stderr, abortSignal)\n }),\n )\n }\n\n useInput(\n (input, key) => {\n handleCtrlC(input, key)\n\n onInput!(input, key, () => treeKill('SIGINT'))\n },\n // isRawModeSupported can be undefined even if the type doesn't say so\n // Ink is checking that isActive is actually === false, not falsey\n {isActive: typeof onInput !== 'undefined' && Boolean(isRawModeSupported)},\n )\n\n useAsyncAndUnmount(runProcesses, {\n onFulfilled: () => {\n setState(ConcurrentOutputState.Stopped)\n },\n onRejected: () => {\n setState(ConcurrentOutputState.Stopped)\n },\n })\n\n const {isAborted} = useAbortSignal(abortSignal)\n\n return (\n <>\n <Static items={processOutput}>\n {(chunk, index) => {\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n {showTimestamps ? (\n <Box>\n <Box marginRight={1}>\n <Text color={chunk.color}>\n {new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '')}\n </Text>\n </Box>\n\n <Text bold color={chunk.color}>\n {figures.lineVertical}\n </Text>\n </Box>\n ) : null}\n\n <Box width={prefixColumnSize} marginX={1}>\n <Text color={chunk.color}>{chunk.prefix}</Text>\n </Box>\n\n <Text bold color={chunk.color}>\n {figures.lineVertical}\n </Text>\n\n <Box flexGrow={1} paddingLeft={1}>\n <Text color={chunk.color}>{line}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n {state === ConcurrentOutputState.Running && !isAborted && footer ? (\n <Box marginY={1} flexDirection=\"column\" flexGrow={1}>\n {isRawModeSupported ? (\n <Box flexDirection=\"column\">\n {footer.shortcuts.map((shortcut, index) => (\n <Text key={index}>\n {figures.pointerSmall} Press <Text bold>{shortcut.key}</Text> {figures.lineVertical} {shortcut.action}\n </Text>\n ))}\n </Box>\n ) : null}\n {footer.subTitle ? (\n <Box marginTop={isRawModeSupported ? 1 : 0}>\n <Text>{footer.subTitle}</Text>\n </Box>\n ) : null}\n </Box>\n ) : null}\n </>\n )\n}\n\nexport {ConcurrentOutput}\n"]}
|
|
1
|
+
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {OutputProcess} from '../../../../public/node/output.js'\nimport useAsyncAndUnmount from '../hooks/use-async-and-unmount.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {handleCtrlC} from '../../ui.js'\nimport {addOrUpdateConcurrentUIEventOutput} from '../../demo-recorder.js'\nimport {treeKill} from '../../tree-kill.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport React, {FunctionComponent, useState} from 'react'\nimport {Box, Key, Static, Text, useInput, TextProps, useStdin} from 'ink'\nimport stripAnsi from 'strip-ansi'\nimport figures from 'figures'\nimport {Writable} from 'stream'\n\nexport type WritableStream = (process: OutputProcess, index: number) => Writable\n\ninterface Shortcut {\n key: string\n action: string\n}\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n abortSignal: AbortSignal\n showTimestamps?: boolean\n onInput?: (input: string, key: Key, exit: () => void) => void\n footer?: {\n shortcuts: Shortcut[]\n subTitle?: string\n }\n}\ninterface Chunk {\n color: TextProps['color']\n prefix: string\n lines: string[]\n}\n\nenum ConcurrentOutputState {\n Running = 'running',\n Stopped = 'stopped',\n}\n\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n abortSignal,\n showTimestamps = true,\n onInput,\n footer,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const concurrentColors: TextProps['color'][] = ['yellow', 'cyan', 'magenta', 'green', 'blue']\n const prefixColumnSize = Math.max(...processes.map((process) => process.prefix.length))\n const {isRawModeSupported} = useStdin()\n const [state, setState] = useState<ConcurrentOutputState>(ConcurrentOutputState.Running)\n\n function lineColor(index: number) {\n const colorIndex = index < concurrentColors.length ? index : index % concurrentColors.length\n return concurrentColors[colorIndex]!\n }\n\n const writableStream = (process: OutputProcess, index: number) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const lines = stripAnsi(chunk.toString('utf8').replace(/(\\n)$/, '')).split(/\\n/)\n addOrUpdateConcurrentUIEventOutput({prefix: process.prefix, index, output: lines.join('\\n')}, {footer})\n\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix: process.prefix,\n lines,\n },\n ])\n\n next()\n },\n })\n }\n\n const runProcesses = () => {\n return Promise.all(\n processes.map(async (process, index) => {\n const stdout = writableStream(process, index)\n const stderr = writableStream(process, index)\n\n await process.action(stdout, stderr, abortSignal)\n }),\n )\n }\n\n const {isAborted} = useAbortSignal(abortSignal)\n\n const useShortcuts = isRawModeSupported && state === ConcurrentOutputState.Running && !isAborted\n\n useInput(\n (input, key) => {\n handleCtrlC(input, key)\n\n onInput!(input, key, () => treeKill('SIGINT'))\n },\n {isActive: typeof onInput !== 'undefined' && useShortcuts},\n )\n\n useAsyncAndUnmount(runProcesses, {\n onFulfilled: () => {\n setState(ConcurrentOutputState.Stopped)\n },\n onRejected: () => {\n setState(ConcurrentOutputState.Stopped)\n },\n })\n\n return (\n <>\n <Static items={processOutput}>\n {(chunk, index) => {\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n {showTimestamps ? (\n <Box>\n <Box marginRight={1}>\n <Text color={chunk.color}>\n {new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '')}\n </Text>\n </Box>\n\n <Text bold color={chunk.color}>\n {figures.lineVertical}\n </Text>\n </Box>\n ) : null}\n\n <Box width={prefixColumnSize} marginX={1}>\n <Text color={chunk.color}>{chunk.prefix}</Text>\n </Box>\n\n <Text bold color={chunk.color}>\n {figures.lineVertical}\n </Text>\n\n <Box flexGrow={1} paddingLeft={1}>\n <Text color={chunk.color}>{line}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n {footer ? (\n <Box marginY={1} flexDirection=\"column\" flexGrow={1}>\n {useShortcuts ? (\n <Box flexDirection=\"column\">\n {footer.shortcuts.map((shortcut, index) => (\n <Text key={index}>\n {figures.pointerSmall} Press <Text bold>{shortcut.key}</Text> {figures.lineVertical} {shortcut.action}\n </Text>\n ))}\n </Box>\n ) : null}\n {footer.subTitle ? (\n <Box marginTop={useShortcuts ? 1 : 0}>\n <Text>{footer.subTitle}</Text>\n </Box>\n ) : null}\n </Box>\n ) : null}\n </>\n )\n}\n\nexport {ConcurrentOutput}\n"]}
|
|
@@ -175,6 +175,8 @@ describe('ConcurrentOutput', () => {
|
|
|
175
175
|
"0000-00-00 00:00:00 │ backend │ first backend message
|
|
176
176
|
0000-00-00 00:00:00 │ backend │ second backend message
|
|
177
177
|
0000-00-00 00:00:00 │ backend │ third backend message
|
|
178
|
+
|
|
179
|
+
Preview URL: https://shopify.com
|
|
178
180
|
"
|
|
179
181
|
`);
|
|
180
182
|
await expect(promise).resolves.toEqual(undefined);
|
|
@@ -209,10 +211,12 @@ describe('ConcurrentOutput', () => {
|
|
|
209
211
|
"0000-00-00 00:00:00 │ backend │ first backend message
|
|
210
212
|
0000-00-00 00:00:00 │ backend │ second backend message
|
|
211
213
|
0000-00-00 00:00:00 │ backend │ third backend message
|
|
214
|
+
|
|
215
|
+
Preview URL: https://shopify.com
|
|
212
216
|
"
|
|
213
217
|
`);
|
|
214
218
|
});
|
|
215
|
-
test("doesn't render the
|
|
219
|
+
test("doesn't render the shortcuts when the processes resolve", async () => {
|
|
216
220
|
// Given
|
|
217
221
|
const backendProcess = {
|
|
218
222
|
prefix: 'backend',
|
|
@@ -241,6 +245,8 @@ describe('ConcurrentOutput', () => {
|
|
|
241
245
|
"0000-00-00 00:00:00 │ backend │ first backend message
|
|
242
246
|
0000-00-00 00:00:00 │ backend │ second backend message
|
|
243
247
|
0000-00-00 00:00:00 │ backend │ third backend message
|
|
248
|
+
|
|
249
|
+
Preview URL: https://shopify.com
|
|
244
250
|
"
|
|
245
251
|
`);
|
|
246
252
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcurrentOutput.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {ConcurrentOutput} from './ConcurrentOutput.js'\nimport {getLastFrameAfterUnmount, waitForInputsToBeReady, render, Stdin} from '../../testing/ui.js'\nimport {AbortController, AbortSignal} from '../../../../public/node/abort.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport React from 'react'\nimport {describe, expect, test, vi} from 'vitest'\nimport {Writable} from 'stream'\n\ndescribe('ConcurrentOutput', () => {\n test('renders a stream of concurrent outputs from sub-processes', async () => {\n // Given\n let backendPromiseResolve: () => void\n let frontendPromiseResolve: () => void\n\n const backendPromise = new Promise<void>(function (resolve, _reject) {\n backendPromiseResolve = resolve\n })\n\n const frontendPromise = new Promise<void>(function (resolve, _reject) {\n frontendPromiseResolve = resolve\n })\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n backendPromiseResolve()\n },\n }\n\n const frontendProcess = {\n prefix: 'frontend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n await backendPromise\n\n stdout.write('first frontend message')\n stdout.write('second frontend message')\n stdout.write('third frontend message')\n\n frontendPromiseResolve()\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess, frontendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await frontendPromise\n\n // Then\n expect(unstyled(renderInstance.lastFrame()!.replace(/\\d/g, '0'))).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n 0000-00-00 00:00:00 │ frontend │ first frontend message\n 0000-00-00 00:00:00 │ frontend │ second frontend message\n 0000-00-00 00:00:00 │ frontend │ third frontend message\n\n › Press p │ preview in your browser\n › Press q │ quit\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test(\"doesn't render shortcuts if the stdin is not a TTY\", async () => {\n // Given\n let backendPromiseResolve: () => void\n let frontendPromiseResolve: () => void\n\n const backendPromise = new Promise<void>(function (resolve, _reject) {\n backendPromiseResolve = resolve\n })\n\n const frontendPromise = new Promise<void>(function (resolve, _reject) {\n frontendPromiseResolve = resolve\n })\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n backendPromiseResolve()\n },\n }\n\n const frontendProcess = {\n prefix: 'frontend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n await backendPromise\n\n stdout.write('first frontend message')\n stdout.write('second frontend message')\n stdout.write('third frontend message')\n\n frontendPromiseResolve()\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess, frontendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n {stdin: new Stdin({isTTY: false})},\n )\n\n await frontendPromise\n\n // Then\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!.replace(/\\d/g, '0'))).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n 0000-00-00 00:00:00 │ frontend │ first frontend message\n 0000-00-00 00:00:00 │ frontend │ second frontend message\n 0000-00-00 00:00:00 │ frontend │ third frontend message\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test('accepts a onInput function that fires when a key is pressed', async () => {\n const neverEndingPromise = new Promise<void>(function (_resolve, _reject) {})\n\n const neverEndingProcess = {\n prefix: 'never-ending-process',\n action: async () => {\n await neverEndingPromise\n },\n }\n\n const onInput = vi.fn()\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[neverEndingProcess]}\n onInput={(input, key) => onInput(input, key)}\n abortSignal={new AbortController().signal}\n />,\n )\n\n await waitForInputsToBeReady()\n expect(onInput).toHaveBeenCalledTimes(0)\n\n renderInstance.stdin.write('a')\n expect(onInput).toHaveBeenCalledTimes(1)\n expect(onInput.mock.calls[0]![0]).toBe('a')\n })\n\n test('abortController can be used to exit from outside and should preserve static output', async () => {\n // Given\n const abortController = new AbortController()\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={abortController.signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n const promise = renderInstance.waitUntilExit()\n\n abortController.abort()\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n \"\n `)\n\n await expect(promise).resolves.toEqual(undefined)\n })\n\n test('rejects with the error thrown inside one of the processes', async () => {\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n throw new Error('something went wrong')\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await expect(renderInstance.waitUntilExit()).rejects.toThrowError('something went wrong')\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n \"\n `)\n })\n\n test(\"doesn't render the footer when the processes resolve\", async () => {\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await renderInstance.waitUntilExit()\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n \"\n `)\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"ConcurrentOutput.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAC,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,EAAE,KAAK,EAAC,MAAM,qBAAqB,CAAA;AACnG,OAAO,EAAC,eAAe,EAAc,MAAM,kCAAkC,CAAA;AAC7E,OAAO,EAAC,QAAQ,EAAC,MAAM,mCAAmC,CAAA;AAC1D,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAC,MAAM,QAAQ,CAAA;AAGjD,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAC3E,QAAQ;QACR,IAAI,qBAAiC,CAAA;QACrC,IAAI,sBAAkC,CAAA;QAEtC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAO,UAAU,OAAO,EAAE,OAAO;YACjE,qBAAqB,GAAG,OAAO,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,MAAM,eAAe,GAAG,IAAI,OAAO,CAAO,UAAU,OAAO,EAAE,OAAO;YAClE,sBAAsB,GAAG,OAAO,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBAErC,qBAAqB,EAAE,CAAA;YACzB,CAAC;SACF,CAAA;QAED,MAAM,eAAe,GAAG;YACtB,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,cAAc,CAAA;gBAEpB,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAA;gBACvC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBAEtC,sBAAsB,EAAE,CAAA;gBAExB,oCAAoC;gBACpC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC7B,CAAC;SACF,CAAA;QACD,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC,EAC5C,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,CACH,CAAA;QAED,MAAM,eAAe,CAAA;QAErB,OAAO;QACP,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,EAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;KAavF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QACpE,QAAQ;QACR,IAAI,qBAAiC,CAAA;QACrC,IAAI,sBAAkC,CAAA;QAEtC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAO,UAAU,OAAO,EAAE,OAAO;YACjE,qBAAqB,GAAG,OAAO,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,MAAM,eAAe,GAAG,IAAI,OAAO,CAAO,UAAU,OAAO,EAAE,OAAO;YAClE,sBAAsB,GAAG,OAAO,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBAErC,qBAAqB,EAAE,CAAA;YACzB,CAAC;SACF,CAAA;QAED,MAAM,eAAe,GAAG;YACtB,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,cAAc,CAAA;gBAEpB,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAA;gBACvC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBAEtC,sBAAsB,EAAE,CAAA;gBAExB,oCAAoC;gBACpC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC7B,CAAC;SACF,CAAA;QACD,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC,EAC5C,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,EACF,EAAC,KAAK,EAAE,IAAI,KAAK,CAAC,EAAC,KAAK,EAAE,KAAK,EAAC,CAAC,EAAC,CACnC,CAAA;QAED,MAAM,eAAe,CAAA;QAErB,OAAO;QACP,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;KAUrG,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,kBAAkB,GAAG,IAAI,OAAO,CAAO,UAAU,QAAQ,EAAE,OAAO,IAAG,CAAC,CAAC,CAAA;QAE7E,MAAM,kBAAkB,GAAG;YACzB,MAAM,EAAE,sBAAsB;YAC9B,MAAM,EAAE,KAAK,IAAI,EAAE;gBACjB,MAAM,kBAAkB,CAAA;YAC1B,CAAC;SACF,CAAA;QAED,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QAEvB,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,kBAAkB,CAAC,EAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAC5C,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,GACzC,CACH,CAAA;QAED,MAAM,sBAAsB,EAAE,CAAA;QAC9B,MAAM,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;QAExC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;QACxC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QACpG,QAAQ;QACR,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;QAE7C,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBAErC,oCAAoC;gBACpC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC7B,CAAC;SACF,CAAA;QAED,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,CAAC,EAC3B,WAAW,EAAE,eAAe,CAAC,MAAM,EACnC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,CACH,CAAA;QAED,MAAM,OAAO,GAAG,cAAc,CAAC,aAAa,EAAE,CAAA;QAE9C,eAAe,CAAC,KAAK,EAAE,CAAA;QAEvB,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;KAOrG,CAAC,CAAA;QAEF,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAC3E,QAAQ;QACR,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBAErC,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAA;YACzC,CAAC;SACF,CAAA;QAED,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,CAAC,EAC3B,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,CACH,CAAA;QAED,MAAM,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAA;QAEzF,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;KAOrG,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACzE,QAAQ;QACR,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;YACvC,CAAC;SACF,CAAA;QAED,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,CAAC,EAC3B,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,CACH,CAAA;QAED,MAAM,cAAc,CAAC,aAAa,EAAE,CAAA;QAEpC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;KAOrG,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {ConcurrentOutput} from './ConcurrentOutput.js'\nimport {getLastFrameAfterUnmount, waitForInputsToBeReady, render, Stdin} from '../../testing/ui.js'\nimport {AbortController, AbortSignal} from '../../../../public/node/abort.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport React from 'react'\nimport {describe, expect, test, vi} from 'vitest'\nimport {Writable} from 'stream'\n\ndescribe('ConcurrentOutput', () => {\n test('renders a stream of concurrent outputs from sub-processes', async () => {\n // Given\n let backendPromiseResolve: () => void\n let frontendPromiseResolve: () => void\n\n const backendPromise = new Promise<void>(function (resolve, _reject) {\n backendPromiseResolve = resolve\n })\n\n const frontendPromise = new Promise<void>(function (resolve, _reject) {\n frontendPromiseResolve = resolve\n })\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n backendPromiseResolve()\n },\n }\n\n const frontendProcess = {\n prefix: 'frontend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n await backendPromise\n\n stdout.write('first frontend message')\n stdout.write('second frontend message')\n stdout.write('third frontend message')\n\n frontendPromiseResolve()\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess, frontendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await frontendPromise\n\n // Then\n expect(unstyled(renderInstance.lastFrame()!.replace(/\\d/g, '0'))).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n 0000-00-00 00:00:00 │ frontend │ first frontend message\n 0000-00-00 00:00:00 │ frontend │ second frontend message\n 0000-00-00 00:00:00 │ frontend │ third frontend message\n\n › Press p │ preview in your browser\n › Press q │ quit\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test(\"doesn't render shortcuts if the stdin is not a TTY\", async () => {\n // Given\n let backendPromiseResolve: () => void\n let frontendPromiseResolve: () => void\n\n const backendPromise = new Promise<void>(function (resolve, _reject) {\n backendPromiseResolve = resolve\n })\n\n const frontendPromise = new Promise<void>(function (resolve, _reject) {\n frontendPromiseResolve = resolve\n })\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n backendPromiseResolve()\n },\n }\n\n const frontendProcess = {\n prefix: 'frontend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n await backendPromise\n\n stdout.write('first frontend message')\n stdout.write('second frontend message')\n stdout.write('third frontend message')\n\n frontendPromiseResolve()\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess, frontendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n {stdin: new Stdin({isTTY: false})},\n )\n\n await frontendPromise\n\n // Then\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!.replace(/\\d/g, '0'))).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n 0000-00-00 00:00:00 │ frontend │ first frontend message\n 0000-00-00 00:00:00 │ frontend │ second frontend message\n 0000-00-00 00:00:00 │ frontend │ third frontend message\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test('accepts a onInput function that fires when a key is pressed', async () => {\n const neverEndingPromise = new Promise<void>(function (_resolve, _reject) {})\n\n const neverEndingProcess = {\n prefix: 'never-ending-process',\n action: async () => {\n await neverEndingPromise\n },\n }\n\n const onInput = vi.fn()\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[neverEndingProcess]}\n onInput={(input, key) => onInput(input, key)}\n abortSignal={new AbortController().signal}\n />,\n )\n\n await waitForInputsToBeReady()\n expect(onInput).toHaveBeenCalledTimes(0)\n\n renderInstance.stdin.write('a')\n expect(onInput).toHaveBeenCalledTimes(1)\n expect(onInput.mock.calls[0]![0]).toBe('a')\n })\n\n test('abortController can be used to exit from outside and should preserve static output', async () => {\n // Given\n const abortController = new AbortController()\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={abortController.signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n const promise = renderInstance.waitUntilExit()\n\n abortController.abort()\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n\n Preview URL: https://shopify.com\n \"\n `)\n\n await expect(promise).resolves.toEqual(undefined)\n })\n\n test('rejects with the error thrown inside one of the processes', async () => {\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n throw new Error('something went wrong')\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await expect(renderInstance.waitUntilExit()).rejects.toThrowError('something went wrong')\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test(\"doesn't render the shortcuts when the processes resolve\", async () => {\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await renderInstance.waitUntilExit()\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 │ backend │ first backend message\n 0000-00-00 00:00:00 │ backend │ second backend message\n 0000-00-00 00:00:00 │ backend │ third backend message\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n})\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_KIT_VERSION = "3.46.
|
|
1
|
+
export declare const CLI_KIT_VERSION = "3.46.3";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const CLI_KIT_VERSION = '3.46.
|
|
1
|
+
export const CLI_KIT_VERSION = '3.46.3';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.46.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.46.3'\n"]}
|
|
@@ -75,7 +75,7 @@ interface InstallNPMDependenciesRecursivelyOptions {
|
|
|
75
75
|
export declare function installNPMDependenciesRecursively(options: InstallNPMDependenciesRecursivelyOptions): Promise<void>;
|
|
76
76
|
interface InstallNodeModulesOptions {
|
|
77
77
|
directory: string;
|
|
78
|
-
args
|
|
78
|
+
args?: string[];
|
|
79
79
|
packageManager: PackageManager;
|
|
80
80
|
stdout?: Writable;
|
|
81
81
|
stderr?: Writable;
|