proscenium 0.6.0-x86_64-darwin → 0.8.0-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +126 -109
  3. data/lib/proscenium/css_module/class_names_resolver.rb +66 -0
  4. data/lib/proscenium/css_module/resolver.rb +76 -0
  5. data/lib/proscenium/css_module.rb +18 -39
  6. data/lib/proscenium/esbuild/golib.rb +97 -0
  7. data/lib/proscenium/esbuild.rb +32 -0
  8. data/lib/proscenium/ext/proscenium +0 -0
  9. data/lib/proscenium/ext/proscenium.h +109 -0
  10. data/lib/proscenium/helper.rb +0 -23
  11. data/lib/proscenium/log_subscriber.rb +26 -0
  12. data/lib/proscenium/middleware/base.rb +28 -36
  13. data/lib/proscenium/middleware/esbuild.rb +18 -44
  14. data/lib/proscenium/middleware/url.rb +1 -6
  15. data/lib/proscenium/middleware.rb +12 -16
  16. data/lib/proscenium/phlex/component_concerns.rb +27 -0
  17. data/lib/proscenium/phlex/page.rb +62 -0
  18. data/lib/proscenium/phlex/react_component.rb +52 -8
  19. data/lib/proscenium/phlex/resolve_css_modules.rb +67 -0
  20. data/lib/proscenium/phlex.rb +34 -33
  21. data/lib/proscenium/railtie.rb +41 -67
  22. data/lib/proscenium/side_load/ensure_loaded.rb +25 -0
  23. data/lib/proscenium/side_load/helper.rb +25 -0
  24. data/lib/proscenium/side_load/monkey.rb +48 -0
  25. data/lib/proscenium/side_load.rb +58 -52
  26. data/lib/proscenium/version.rb +1 -1
  27. data/lib/proscenium/view_component/react_component.rb +14 -0
  28. data/lib/proscenium/view_component.rb +28 -18
  29. data/lib/proscenium.rb +79 -2
  30. metadata +35 -77
  31. data/app/channels/proscenium/connection.rb +0 -13
  32. data/app/channels/proscenium/reload_channel.rb +0 -9
  33. data/bin/esbuild +0 -0
  34. data/bin/lightningcss +0 -0
  35. data/config/routes.rb +0 -7
  36. data/lib/proscenium/compiler.js +0 -84
  37. data/lib/proscenium/compilers/esbuild/argument_error.js +0 -24
  38. data/lib/proscenium/compilers/esbuild/compile_error.js +0 -148
  39. data/lib/proscenium/compilers/esbuild/css/postcss.js +0 -67
  40. data/lib/proscenium/compilers/esbuild/css_plugin.js +0 -172
  41. data/lib/proscenium/compilers/esbuild/env_plugin.js +0 -46
  42. data/lib/proscenium/compilers/esbuild/http_bundle_plugin.js +0 -53
  43. data/lib/proscenium/compilers/esbuild/import_map/parser.js +0 -178
  44. data/lib/proscenium/compilers/esbuild/import_map/read.js +0 -64
  45. data/lib/proscenium/compilers/esbuild/import_map/resolver.js +0 -95
  46. data/lib/proscenium/compilers/esbuild/import_map/utils.js +0 -25
  47. data/lib/proscenium/compilers/esbuild/resolve_plugin.js +0 -207
  48. data/lib/proscenium/compilers/esbuild/setup_plugin.js +0 -45
  49. data/lib/proscenium/compilers/esbuild/solidjs_plugin.js +0 -24
  50. data/lib/proscenium/compilers/esbuild.bench.js +0 -14
  51. data/lib/proscenium/compilers/esbuild.js +0 -179
  52. data/lib/proscenium/link_to_helper.rb +0 -40
  53. data/lib/proscenium/middleware/lightningcss.rb +0 -64
  54. data/lib/proscenium/middleware/outside_root.rb +0 -26
  55. data/lib/proscenium/middleware/runtime.rb +0 -22
  56. data/lib/proscenium/middleware/static.rb +0 -14
  57. data/lib/proscenium/phlex/component.rb +0 -9
  58. data/lib/proscenium/precompile.rb +0 -31
  59. data/lib/proscenium/runtime/auto_reload.js +0 -40
  60. data/lib/proscenium/runtime/react_shim/index.js +0 -1
  61. data/lib/proscenium/runtime/react_shim/package.json +0 -5
  62. data/lib/proscenium/utils.js +0 -12
  63. data/lib/tasks/assets.rake +0 -19
@@ -4,37 +4,47 @@ require 'view_component'
4
4
 
5
5
  class Proscenium::ViewComponent < ViewComponent::Base
6
6
  extend ActiveSupport::Autoload
7
+ include Proscenium::CssModule
7
8
 
8
9
  autoload :TagBuilder
9
10
  autoload :ReactComponent
10
11
 
11
- def render_in(...)
12
- cssm.compile_class_names(super(...))
12
+ # Side loads the class, and its super classes that respond to `.path`. Assign the `abstract_class`
13
+ # class variable to any abstract class, and it will not be side loaded.
14
+ module Sideload
15
+ def before_render
16
+ klass = self.class
17
+ while !klass.abstract_class && klass.respond_to?(:path) && klass.path
18
+ Proscenium::SideLoad.append klass.path
19
+ klass = klass.superclass
20
+ end
21
+
22
+ super
23
+ end
13
24
  end
14
25
 
15
- def before_render
16
- side_load_assets unless self.class < ReactComponent
17
- end
26
+ class << self
27
+ attr_accessor :path, :abstract_class
18
28
 
19
- def css_module(name)
20
- cssm.class_names!(name).join ' '
21
- end
29
+ def inherited(child)
30
+ child.path = if caller_locations(1, 1).first.label == 'inherited'
31
+ Pathname.new caller_locations(2, 1).first.path
32
+ else
33
+ Pathname.new caller_locations(1, 1).first.path
34
+ end
22
35
 
23
- private
36
+ child.prepend Sideload if Rails.application.config.proscenium.side_load
24
37
 
25
- # Side load any CSS/JS assets for the component. This will side load any `index.{css|js}` in
26
- # the component directory.
27
- def side_load_assets
28
- Proscenium::SideLoad.append asset_path if Rails.application.config.proscenium.side_load
38
+ super
39
+ end
29
40
  end
30
41
 
31
- def asset_path
32
- @asset_path ||= "app/components#{virtual_path}"
42
+ # @override Auto compilation of class names to css modules.
43
+ def render_in(...)
44
+ cssm.compile_class_names(super(...))
33
45
  end
34
46
 
35
- def cssm
36
- @cssm ||= Proscenium::CssModule.new(asset_path)
37
- end
47
+ private
38
48
 
39
49
  # Overrides ActionView::Helpers::TagHelper::TagBuilder, allowing us to intercept the
40
50
  # `css_module` option from the HTML options argument of the `tag` and `content_tag` helpers, and
data/lib/proscenium.rb CHANGED
@@ -12,8 +12,85 @@ module Proscenium
12
12
  autoload :ViewComponent
13
13
  autoload :Phlex
14
14
  autoload :Helper
15
- autoload :LinkToHelper
16
- autoload :Precompile
15
+ autoload :Esbuild
16
+
17
+ def self.reset_current_side_loaded
18
+ Current.reset
19
+ Current.loaded = SideLoad::EXTENSIONS.to_h { |e| [e, Set.new] }
20
+ end
21
+
22
+ class PathResolutionFailed < StandardError
23
+ def initialize(path)
24
+ @path = path
25
+ super
26
+ end
27
+
28
+ def message
29
+ "Path #{@path.inspect} cannot be resolved"
30
+ end
31
+ end
32
+
33
+ module Utils
34
+ module_function
35
+
36
+ # @param value [#to_s] The value to create the digest from. This will usually be a `Pathname`.
37
+ # @return [String] string digest of the given value.
38
+ def digest(value)
39
+ Digest::SHA1.hexdigest(value.to_s)[..7]
40
+ end
41
+
42
+ # Resolve the given `path` to a URL path.
43
+ #
44
+ # @param path [String] Can be URL path, file system path, or bare specifier (ie. NPM package).
45
+ # @return [String] URL path.
46
+ def resolve_path(path) # rubocop:disable Metrics/AbcSize
47
+ raise ArgumentError, 'path must be a string' unless path.is_a?(String)
48
+
49
+ if path.starts_with?('./', '../')
50
+ raise ArgumentError, 'path must be an absolute file system or URL path'
51
+ end
52
+
53
+ matched_gem = Proscenium.config.side_load_gems.find do |_, opts|
54
+ path.starts_with?("#{opts[:root]}/")
55
+ end
56
+
57
+ if matched_gem
58
+ sroot = "#{matched_gem[1][:root]}/"
59
+ relpath = path.delete_prefix(sroot)
60
+
61
+ if (package_name = matched_gem[1][:package_name] || matched_gem[0])
62
+ return Esbuild::Golib.resolve("#{package_name}/#{relpath}")
63
+ end
64
+
65
+ # TODO: manually resolve the path without esbuild
66
+ raise PathResolutionFailed, path
67
+ end
68
+
69
+ return path.delete_prefix(Rails.root.to_s) if path.starts_with?("#{Rails.root}/")
70
+
71
+ Esbuild::Golib.resolve(path)
72
+ end
73
+
74
+ # Resolves CSS class `names` to CSS module names. Each name will be converted to a CSS module
75
+ # name, consisting of the camelCased name (lower case first character), and suffixed with the
76
+ # given `digest`.
77
+ #
78
+ # @param names [String, Array]
79
+ # @param digest: [String]
80
+ # @returns [Array] of class names generated from the given CSS module `names` and `digest`.
81
+ def css_modularise_class_names(*names, digest: nil)
82
+ names.flatten.compact.map { |name| css_modularise_class_name name, digest: digest }
83
+ end
84
+
85
+ def css_modularise_class_name(name, digest: nil)
86
+ sname = name.to_s
87
+ if sname.starts_with?('_')
88
+ "_#{sname[1..].camelize(:lower)}#{digest}"
89
+ else
90
+ "#{sname.camelize(:lower)}#{digest}"
91
+ end
92
+ end
93
+ end
17
94
  end
18
95
 
19
96
  require 'proscenium/railtie'
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proscenium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: x86_64-darwin
6
6
  authors:
7
7
  - Joel Moss
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-18 00:00:00.000000000 Z
11
+ date: 2023-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: actioncable
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -31,81 +31,75 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: '8.0'
33
33
  - !ruby/object:Gem::Dependency
34
- name: activesupport
34
+ name: ffi
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: 6.1.0
40
- - - "<"
37
+ - - "~>"
41
38
  - !ruby/object:Gem::Version
42
- version: '8.0'
39
+ version: 1.15.5
43
40
  type: :runtime
44
41
  prerelease: false
45
42
  version_requirements: !ruby/object:Gem::Requirement
46
43
  requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 6.1.0
50
- - - "<"
44
+ - - "~>"
51
45
  - !ruby/object:Gem::Version
52
- version: '8.0'
46
+ version: 1.15.5
53
47
  - !ruby/object:Gem::Dependency
54
- name: listen
48
+ name: nokogiri
55
49
  requirement: !ruby/object:Gem::Requirement
56
50
  requirements:
57
51
  - - "~>"
58
52
  - !ruby/object:Gem::Version
59
- version: '3.0'
53
+ version: '1.13'
60
54
  type: :runtime
61
55
  prerelease: false
62
56
  version_requirements: !ruby/object:Gem::Requirement
63
57
  requirements:
64
58
  - - "~>"
65
59
  - !ruby/object:Gem::Version
66
- version: '3.0'
60
+ version: '1.13'
67
61
  - !ruby/object:Gem::Dependency
68
- name: nokogiri
62
+ name: oj
69
63
  requirement: !ruby/object:Gem::Requirement
70
64
  requirements:
71
65
  - - "~>"
72
66
  - !ruby/object:Gem::Version
73
- version: '1.13'
67
+ version: '3.13'
74
68
  type: :runtime
75
69
  prerelease: false
76
70
  version_requirements: !ruby/object:Gem::Requirement
77
71
  requirements:
78
72
  - - "~>"
79
73
  - !ruby/object:Gem::Version
80
- version: '1.13'
74
+ version: '3.13'
81
75
  - !ruby/object:Gem::Dependency
82
- name: oj
76
+ name: phlex
83
77
  requirement: !ruby/object:Gem::Requirement
84
78
  requirements:
85
79
  - - "~>"
86
80
  - !ruby/object:Gem::Version
87
- version: '3.13'
81
+ version: 1.8.1
88
82
  type: :runtime
89
83
  prerelease: false
90
84
  version_requirements: !ruby/object:Gem::Requirement
91
85
  requirements:
92
86
  - - "~>"
93
87
  - !ruby/object:Gem::Version
94
- version: '3.13'
88
+ version: 1.8.1
95
89
  - !ruby/object:Gem::Dependency
96
- name: phlex
90
+ name: phlex-rails
97
91
  requirement: !ruby/object:Gem::Requirement
98
92
  requirements:
99
93
  - - "~>"
100
94
  - !ruby/object:Gem::Version
101
- version: 0.4.0
95
+ version: 1.0.0
102
96
  type: :runtime
103
97
  prerelease: false
104
98
  version_requirements: !ruby/object:Gem::Requirement
105
99
  requirements:
106
100
  - - "~>"
107
101
  - !ruby/object:Gem::Version
108
- version: 0.4.0
102
+ version: 1.0.0
109
103
  - !ruby/object:Gem::Dependency
110
104
  name: railties
111
105
  requirement: !ruby/object:Gem::Requirement
@@ -126,81 +120,45 @@ dependencies:
126
120
  - - "<"
127
121
  - !ruby/object:Gem::Version
128
122
  version: '8.0'
129
- - !ruby/object:Gem::Dependency
130
- name: view_component
131
- requirement: !ruby/object:Gem::Requirement
132
- requirements:
133
- - - "~>"
134
- - !ruby/object:Gem::Version
135
- version: 2.74.1
136
- type: :runtime
137
- prerelease: false
138
- version_requirements: !ruby/object:Gem::Requirement
139
- requirements:
140
- - - "~>"
141
- - !ruby/object:Gem::Version
142
- version: 2.74.1
143
123
  description:
144
124
  email:
145
125
  - joel@developwithstyle.com
146
- executables:
147
- - esbuild
148
- - lightningcss
126
+ executables: []
149
127
  extensions: []
150
128
  extra_rdoc_files: []
151
129
  files:
152
130
  - CODE_OF_CONDUCT.md
153
131
  - LICENSE.txt
154
132
  - README.md
155
- - app/channels/proscenium/connection.rb
156
- - app/channels/proscenium/reload_channel.rb
157
- - bin/esbuild
158
- - bin/lightningcss
159
- - config/routes.rb
160
133
  - lib/proscenium.rb
161
- - lib/proscenium/compiler.js
162
- - lib/proscenium/compilers/esbuild.bench.js
163
- - lib/proscenium/compilers/esbuild.js
164
- - lib/proscenium/compilers/esbuild/argument_error.js
165
- - lib/proscenium/compilers/esbuild/compile_error.js
166
- - lib/proscenium/compilers/esbuild/css/postcss.js
167
- - lib/proscenium/compilers/esbuild/css_plugin.js
168
- - lib/proscenium/compilers/esbuild/env_plugin.js
169
- - lib/proscenium/compilers/esbuild/http_bundle_plugin.js
170
- - lib/proscenium/compilers/esbuild/import_map/parser.js
171
- - lib/proscenium/compilers/esbuild/import_map/read.js
172
- - lib/proscenium/compilers/esbuild/import_map/resolver.js
173
- - lib/proscenium/compilers/esbuild/import_map/utils.js
174
- - lib/proscenium/compilers/esbuild/resolve_plugin.js
175
- - lib/proscenium/compilers/esbuild/setup_plugin.js
176
- - lib/proscenium/compilers/esbuild/solidjs_plugin.js
177
134
  - lib/proscenium/css_module.rb
135
+ - lib/proscenium/css_module/class_names_resolver.rb
136
+ - lib/proscenium/css_module/resolver.rb
178
137
  - lib/proscenium/current.rb
138
+ - lib/proscenium/esbuild.rb
139
+ - lib/proscenium/esbuild/golib.rb
140
+ - lib/proscenium/ext/proscenium
141
+ - lib/proscenium/ext/proscenium.h
179
142
  - lib/proscenium/helper.rb
180
- - lib/proscenium/link_to_helper.rb
143
+ - lib/proscenium/log_subscriber.rb
181
144
  - lib/proscenium/middleware.rb
182
145
  - lib/proscenium/middleware/base.rb
183
146
  - lib/proscenium/middleware/esbuild.rb
184
- - lib/proscenium/middleware/lightningcss.rb
185
- - lib/proscenium/middleware/outside_root.rb
186
- - lib/proscenium/middleware/runtime.rb
187
- - lib/proscenium/middleware/static.rb
188
147
  - lib/proscenium/middleware/url.rb
189
148
  - lib/proscenium/phlex.rb
190
- - lib/proscenium/phlex/component.rb
149
+ - lib/proscenium/phlex/component_concerns.rb
150
+ - lib/proscenium/phlex/page.rb
191
151
  - lib/proscenium/phlex/react_component.rb
192
- - lib/proscenium/precompile.rb
152
+ - lib/proscenium/phlex/resolve_css_modules.rb
193
153
  - lib/proscenium/railtie.rb
194
- - lib/proscenium/runtime/auto_reload.js
195
- - lib/proscenium/runtime/react_shim/index.js
196
- - lib/proscenium/runtime/react_shim/package.json
197
154
  - lib/proscenium/side_load.rb
198
- - lib/proscenium/utils.js
155
+ - lib/proscenium/side_load/ensure_loaded.rb
156
+ - lib/proscenium/side_load/helper.rb
157
+ - lib/proscenium/side_load/monkey.rb
199
158
  - lib/proscenium/version.rb
200
159
  - lib/proscenium/view_component.rb
201
160
  - lib/proscenium/view_component/react_component.rb
202
161
  - lib/proscenium/view_component/tag_builder.rb
203
- - lib/tasks/assets.rake
204
162
  homepage: https://github.com/joelmoss/proscenium
205
163
  licenses:
206
164
  - MIT
@@ -224,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
224
182
  - !ruby/object:Gem::Version
225
183
  version: '0'
226
184
  requirements: []
227
- rubygems_version: 3.3.7
185
+ rubygems_version: 3.4.13
228
186
  signing_key:
229
187
  specification_version: 4
230
188
  summary: The engine powering your Rails frontend
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Proscenium
4
- class Connection < ActionCable::Connection::Base
5
- identified_by :uid
6
-
7
- def connect
8
- self.uid = request.params[:uid]
9
- logger.add_tags(uid)
10
- logger.info 'connected to Proscenium'
11
- end
12
- end
13
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Proscenium
4
- class ReloadChannel < ActionCable::Channel::Base
5
- def subscribed
6
- stream_from 'reload'
7
- end
8
- end
9
- end
data/bin/esbuild DELETED
Binary file
data/bin/lightningcss DELETED
Binary file
data/config/routes.rb DELETED
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- Proscenium::Railtie.routes.draw do
4
- if Proscenium.config.auto_reload
5
- mount Proscenium::Railtie.websocket => Proscenium.config.cable_mount_path
6
- end
7
- end
@@ -1,84 +0,0 @@
1
- // Recursively Scans the /app path for any JS/JSX/CSS files, and compiles each one, while also
2
- // building a manifest (JSON) of all files that are built. The manifest contains a simple mapping of
3
- // source file => compiled file. The compiled files are appended with the content digest, for
4
- // caching.
5
-
6
- import { writeAll } from 'std/streams/mod.ts'
7
- import { MuxAsyncIterator } from 'std/async/mod.ts'
8
- import { expandGlob, ensureDir } from 'std/fs/mod.ts'
9
- import { extname, relative, join, dirname, parse } from 'std/path/mod.ts'
10
-
11
- import build from './cli.js'
12
-
13
- const extnameToBuilderMap = {
14
- '.js': 'javascript'
15
- }
16
-
17
- async function main(args = []) {
18
- const [root, ...paths] = args
19
- const outDir = join(root, 'public', 'assets')
20
- const manifest = {}
21
- const promises = []
22
- const mux = new MuxAsyncIterator()
23
-
24
- paths.forEach(path => {
25
- mux.add(expandGlob(`${path}/**/*.{css,js,jsx}`, { root }))
26
- })
27
-
28
- for await (const file of mux) {
29
- const builder = extnameToBuilderMap[extname(file.path)]
30
-
31
- if (!builder) {
32
- console.error('--! Failed to compile %o (unknown builder)', relative(root, file.path))
33
- continue
34
- }
35
-
36
- promises.push(
37
- compile({ ...file, root, outDir }).then(({ inPath, outPath }) => {
38
- manifest[inPath] = outPath
39
- })
40
- )
41
- }
42
-
43
- await Promise.allSettled(promises)
44
-
45
- return new TextEncoder().encode(JSON.stringify(manifest))
46
- }
47
-
48
- function compile({ root, path, outDir }) {
49
- const entrypoint = relative(root, path)
50
- const { dir, name, ext } = parse(entrypoint)
51
- const builder = extnameToBuilderMap[ext]
52
-
53
- console.log('--- Compiling %o with %s builder...', entrypoint, builder)
54
-
55
- return build([root, entrypoint, builder])
56
- .then(src => {
57
- console.log(2)
58
- return digest(src)
59
- })
60
- .then(({ hash, source }) => {
61
- const path = join(outDir, dir, `${name}-${hash}${ext}`)
62
-
63
- return ensureDir(dirname(path))
64
- .then(() => Deno.writeTextFile(path, new TextDecoder().decode(source)))
65
- .then(() => ({ inPath: entrypoint, outPath: relative(outDir, path) }))
66
- })
67
- }
68
-
69
- async function digest(source) {
70
- const view = new DataView(await crypto.subtle.digest('SHA-1', source))
71
-
72
- let hash = ''
73
- for (let index = 0; index < view.byteLength; index += 4) {
74
- hash += view.getUint32(index).toString(16).padStart(8, '0')
75
- }
76
-
77
- return { hash, source }
78
- }
79
-
80
- export default main
81
-
82
- if (import.meta.main) {
83
- await writeAll(Deno.stdout, await main(Deno.args))
84
- }
@@ -1,24 +0,0 @@
1
- export default class ArgumentError extends Error {
2
- static MESSAGES = {
3
- rootRequired: 'Current working directory is required as --root.',
4
- lightningcssBinRequired:
5
- 'Path to the lightningcss CLI binary is required as --lightningcss-bin.',
6
- pathsRequired: 'One or more file paths or globs are required.',
7
-
8
- rootUnknown: ({ root }) => `A valid working directory is required - received ${root}`
9
- }
10
-
11
- constructor(reason, options) {
12
- let message = ArgumentError.MESSAGES[reason]
13
- if (typeof message === 'function') {
14
- message = message(options)
15
- }
16
-
17
- message = `${reason}: ${message}`
18
-
19
- super(message, options)
20
-
21
- this.reason = reason
22
- this.message = message
23
- }
24
- }
@@ -1,148 +0,0 @@
1
- export default function () {
2
- if (Deno.env.get('RAILS_ENV') === 'development') {
3
- return function (detail) {
4
- const template = `
5
- <style>
6
- :host {
7
- position: fixed;
8
- z-index: 99999;
9
- top: 0;
10
- left: 0;
11
- width: 100%;
12
- height: 100%;
13
- overflow-y: scroll;
14
- margin: 0;
15
- background: rgba(0, 0, 0, 0.66);
16
- display: flex;
17
- align-items: center;
18
- --monospace: 'SFMono-Regular', Consolas,
19
- 'Liberation Mono', Menlo, Courier, monospace;
20
- --red: #ff5555;
21
- --yellow: #e2aa53;
22
- --purple: #cfa4ff;
23
- --cyan: #2dd9da;
24
- --dim: #c9c9c9;
25
- }
26
-
27
- .window {
28
- font-family: var(--monospace);
29
- line-height: 1.5;
30
- width: 800px;
31
- height: 66vh;
32
- color: #d8d8d8;
33
- margin: 30px auto;
34
- padding: 25px 40px;
35
- position: relative;
36
- background: #181818;
37
- border-radius: 6px 6px 8px 8px;
38
- box-shadow: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22);
39
- overflow: hidden;
40
- border-top: 8px solid var(--red);
41
- }
42
-
43
- pre {
44
- font-family: var(--monospace);
45
- font-size: 16px;
46
- margin: 0 0 1em 0;
47
- overflow-x: scroll;
48
- scrollbar-width: none;
49
- }
50
-
51
- pre::-webkit-scrollbar {
52
- display: none;
53
- }
54
-
55
- .title, .message {
56
- line-height: 1.3;
57
- font-weight: 600;
58
- white-space: pre-wrap;
59
- }
60
-
61
- .message-body {
62
- color: var(--red);
63
- }
64
-
65
- .file {
66
- color: var(--cyan);
67
- margin-bottom: 0;
68
- white-space: pre-wrap;
69
- word-break: break-all;
70
- }
71
-
72
- .code {
73
- background: black;
74
- border-left: 3px solid gray;
75
- padding: 10px 0 0 20px;
76
- }
77
- .lineText {
78
- display: block;
79
- white-space: pre-wrap;
80
- }
81
- .lineCursor {
82
- white-space: pre;
83
- color: blueviolet;
84
- display: block;
85
- }
86
- </style>
87
- <div class="window">
88
- <pre class="title">COMPILE ERROR!</pre>
89
- <pre class="message"><span class="message-body"></span> in <span class="file"></span></pre>
90
- <pre class="code"><span class="lineText"></span><span class="lineCursor"></span></pre>
91
- </div>
92
- `
93
-
94
- class ErrorOverlay extends HTMLElement {
95
- constructor(err) {
96
- super()
97
-
98
- this.root = this.attachShadow({ mode: 'open' })
99
- this.root.innerHTML = template
100
- this.root.querySelector('.message-body').textContent = err.text.trim()
101
- if (err.location) {
102
- const location = [err.location.file]
103
- err.location.line && location.push(err.location.line)
104
- err.location.column && location.push(err.location.column)
105
- this.root.querySelector('.file').textContent = `/${location.join(':')}`
106
-
107
- if (err.location.lineText) {
108
- this.root.querySelector('.lineText').textContent = err.location.lineText
109
- this.root.querySelector('.lineCursor').textContent =
110
- ''.padStart(err.location.column - 1, ' ') + '^'
111
- } else {
112
- this.root.querySelector('.code').remove()
113
- }
114
-
115
- console.error('%s at %O', err.text, location)
116
- } else {
117
- console.error(err.text)
118
- }
119
-
120
- this.root.querySelector('.window').addEventListener('click', e => {
121
- e.stopPropagation()
122
- })
123
-
124
- this.addEventListener('click', () => {
125
- this.close()
126
- })
127
- }
128
-
129
- close() {
130
- this.parentNode?.removeChild(this)
131
- }
132
- }
133
-
134
- const overlayId = 'proscenium-error-overlay'
135
- if (customElements && !customElements.get(overlayId)) {
136
- customElements.define(overlayId, ErrorOverlay)
137
- }
138
-
139
- document.body.appendChild(new ErrorOverlay(detail))
140
- }
141
- } else {
142
- return function (detail) {
143
- const location = `/${detail.location.file}:${detail.location.line}:${detail.location.column}`
144
- console.error('%s at %O', detail.text, location)
145
- throw `${detail.text} at ${location}`
146
- }
147
- }
148
- }