sass-embedded 0.9.3 → 0.13.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/LICENSE +1 -1
- data/README.md +3 -23
- data/ext/sass/extconf.rb +1 -3
- data/lib/sass/compile_error.rb +24 -0
- data/lib/sass/compile_result.rb +18 -0
- data/lib/sass/embedded/compile_context.rb +204 -136
- data/lib/sass/embedded/compiler/requirements.rb +1 -1
- data/lib/sass/embedded/compiler.rb +3 -3
- data/lib/sass/embedded/protocol_error.rb +7 -0
- data/lib/sass/embedded/render.rb +328 -0
- data/lib/sass/embedded/url.rb +35 -0
- data/lib/sass/embedded/version.rb +1 -1
- data/lib/sass/embedded.rb +93 -212
- data/lib/sass/file_importer.rb +10 -0
- data/lib/sass/importer.rb +14 -0
- data/lib/sass/importer_result.rb +14 -0
- data/lib/sass/logger/source_location.rb +24 -0
- data/lib/sass/logger/source_span.rb +30 -0
- data/lib/sass/logger.rb +24 -0
- data/lib/sass.rb +31 -1
- metadata +53 -17
- data/lib/sass/embedded/error.rb +0 -29
- data/lib/sass/embedded/result.rb +0 -28
- data/lib/sass/embedded/util.rb +0 -33
data/lib/sass/embedded.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require_relative 'compile_error'
|
4
|
+
require_relative 'compile_result'
|
5
|
+
require_relative 'importer_result'
|
5
6
|
require_relative 'embedded/channel'
|
6
7
|
require_relative 'embedded/compile_context'
|
7
|
-
require_relative 'embedded/
|
8
|
-
require_relative 'embedded/
|
9
|
-
require_relative 'embedded/util'
|
8
|
+
require_relative 'embedded/render'
|
9
|
+
require_relative 'embedded/url'
|
10
10
|
require_relative 'embedded/version'
|
11
11
|
require_relative 'embedded/version_context'
|
12
|
+
require_relative 'logger'
|
12
13
|
|
13
14
|
module Sass
|
14
15
|
# The {Embedded} host for using dart-sass-embedded. Each instance creates
|
@@ -16,109 +17,113 @@ module Sass
|
|
16
17
|
#
|
17
18
|
# @example
|
18
19
|
# embedded = Sass::Embedded.new
|
19
|
-
# result = embedded.
|
20
|
-
# result = embedded.
|
20
|
+
# result = embedded.compile_string('h1 { font-size: 40px; }')
|
21
|
+
# result = embedded.compile('style.scss')
|
21
22
|
# embedded.close
|
22
23
|
class Embedded
|
23
|
-
def self.include_paths
|
24
|
-
@include_paths ||= if ENV['SASS_PATH']
|
25
|
-
ENV['SASS_PATH'].split(File::PATH_SEPARATOR)
|
26
|
-
else
|
27
|
-
[]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
24
|
def initialize
|
32
25
|
@channel = Channel.new
|
33
26
|
end
|
34
27
|
|
35
|
-
# The {Embedded#
|
28
|
+
# The {Embedded#compile} method.
|
36
29
|
#
|
30
|
+
# @return [CompileResult]
|
31
|
+
# @raise [CompileError]
|
37
32
|
# @raise [ProtocolError]
|
38
|
-
def
|
39
|
-
|
40
|
-
end
|
33
|
+
def compile(path,
|
34
|
+
load_paths: [],
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
#
|
46
|
-
# @return [RenderResult]
|
47
|
-
# @raise [ProtocolError]
|
48
|
-
# @raise [RenderError]
|
49
|
-
def render(data: nil,
|
50
|
-
file: nil,
|
51
|
-
indented_syntax: false,
|
52
|
-
include_paths: [],
|
53
|
-
output_style: :expanded,
|
54
|
-
indent_type: :space,
|
55
|
-
indent_width: 2,
|
56
|
-
linefeed: :lf,
|
57
|
-
source_map: false,
|
58
|
-
out_file: nil,
|
59
|
-
omit_source_map_url: false,
|
60
|
-
source_map_contents: false,
|
61
|
-
source_map_embed: false,
|
62
|
-
source_map_root: '',
|
63
|
-
functions: {},
|
64
|
-
importer: [])
|
65
|
-
start = Util.now
|
36
|
+
source_map: false,
|
37
|
+
source_map_include_sources: false,
|
38
|
+
style: :expanded,
|
66
39
|
|
67
|
-
|
68
|
-
|
69
|
-
|
40
|
+
functions: {},
|
41
|
+
importers: [],
|
42
|
+
|
43
|
+
alert_ascii: false,
|
44
|
+
alert_color: $stderr.tty?,
|
45
|
+
logger: nil,
|
46
|
+
quiet_deps: false,
|
47
|
+
verbose: false)
|
48
|
+
|
49
|
+
raise ArgumentError, 'path must be set' if path.nil?
|
70
50
|
|
71
51
|
message = CompileContext.new(@channel,
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
52
|
+
path: path,
|
53
|
+
source: nil,
|
54
|
+
importer: nil,
|
55
|
+
load_paths: load_paths,
|
56
|
+
syntax: nil,
|
57
|
+
url: nil,
|
77
58
|
source_map: source_map,
|
78
|
-
|
59
|
+
source_map_include_sources: source_map_include_sources,
|
60
|
+
style: style,
|
79
61
|
functions: functions,
|
80
|
-
|
62
|
+
importers: importers,
|
63
|
+
alert_color: alert_color,
|
64
|
+
alert_ascii: alert_ascii,
|
65
|
+
logger: logger,
|
66
|
+
quiet_deps: quiet_deps,
|
67
|
+
verbose: verbose).receive_message
|
68
|
+
|
69
|
+
raise CompileError.from_proto(message.failure) if message.failure
|
81
70
|
|
82
|
-
|
83
|
-
|
84
|
-
message.failure.message,
|
85
|
-
message.failure.formatted,
|
86
|
-
if message.failure.span.nil?
|
87
|
-
nil
|
88
|
-
elsif message.failure.span.url == ''
|
89
|
-
'stdin'
|
90
|
-
else
|
91
|
-
Util.path_from_file_uri(message.failure.span.url)
|
92
|
-
end,
|
93
|
-
message.failure.span ? message.failure.span.start.line + 1 : nil,
|
94
|
-
message.failure.span ? message.failure.span.start.column + 1 : nil,
|
95
|
-
1
|
96
|
-
)
|
97
|
-
end
|
71
|
+
CompileResult.from_proto(message.success)
|
72
|
+
end
|
98
73
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
74
|
+
# The {Embedded#compile_string} method.
|
75
|
+
#
|
76
|
+
# @return [CompileResult]
|
77
|
+
# @raise [CompileError]
|
78
|
+
# @raise [ProtocolError]
|
79
|
+
def compile_string(source,
|
80
|
+
importer: nil,
|
81
|
+
load_paths: [],
|
82
|
+
syntax: :scss,
|
83
|
+
url: nil,
|
84
|
+
|
85
|
+
source_map: false,
|
86
|
+
source_map_include_sources: false,
|
87
|
+
style: :expanded,
|
88
|
+
|
89
|
+
functions: {},
|
90
|
+
importers: [],
|
91
|
+
|
92
|
+
alert_ascii: false,
|
93
|
+
alert_color: $stderr.tty?,
|
94
|
+
logger: nil,
|
95
|
+
quiet_deps: false,
|
96
|
+
verbose: false)
|
97
|
+
raise ArgumentError, 'source must be set' if source.nil?
|
106
98
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
99
|
+
message = CompileContext.new(@channel,
|
100
|
+
path: nil,
|
101
|
+
source: source,
|
102
|
+
importer: importer,
|
103
|
+
load_paths: load_paths,
|
104
|
+
syntax: syntax,
|
105
|
+
url: url,
|
106
|
+
source_map: source_map,
|
107
|
+
source_map_include_sources: source_map_include_sources,
|
108
|
+
style: style,
|
109
|
+
functions: functions,
|
110
|
+
importers: importers,
|
111
|
+
alert_color: alert_color,
|
112
|
+
alert_ascii: alert_ascii,
|
113
|
+
logger: logger,
|
114
|
+
quiet_deps: quiet_deps,
|
115
|
+
verbose: verbose).receive_message
|
116
116
|
|
117
|
-
|
117
|
+
raise CompileError.from_proto(message.failure) if message.failure
|
118
118
|
|
119
|
-
|
119
|
+
CompileResult.from_proto(message.success)
|
120
|
+
end
|
120
121
|
|
121
|
-
|
122
|
+
# The {Embedded#info} method.
|
123
|
+
#
|
124
|
+
# @raise [ProtocolError]
|
125
|
+
def info
|
126
|
+
@info ||= VersionContext.new(@channel).receive_message
|
122
127
|
end
|
123
128
|
|
124
129
|
def close
|
@@ -128,129 +133,5 @@ module Sass
|
|
128
133
|
def closed?
|
129
134
|
@channel.closed?
|
130
135
|
end
|
131
|
-
|
132
|
-
private
|
133
|
-
|
134
|
-
def post_process_map(map:,
|
135
|
-
data:,
|
136
|
-
file:,
|
137
|
-
out_file:,
|
138
|
-
source_map:,
|
139
|
-
source_map_contents:,
|
140
|
-
source_map_root:)
|
141
|
-
return if map.nil? || map.empty?
|
142
|
-
|
143
|
-
map_data = JSON.parse(map)
|
144
|
-
|
145
|
-
map_data['sourceRoot'] = source_map_root
|
146
|
-
|
147
|
-
source_map_path = if source_map.is_a? String
|
148
|
-
source_map
|
149
|
-
else
|
150
|
-
"#{out_file}.map"
|
151
|
-
end
|
152
|
-
|
153
|
-
source_map_dir = File.dirname(source_map_path)
|
154
|
-
|
155
|
-
if out_file
|
156
|
-
map_data['file'] = Util.relative_path(source_map_dir, out_file)
|
157
|
-
elsif file
|
158
|
-
ext = File.extname(file)
|
159
|
-
map_data['file'] = "#{file[0..(ext.empty? ? -1 : -ext.length - 1)]}.css"
|
160
|
-
else
|
161
|
-
map_data['file'] = 'stdin.css'
|
162
|
-
end
|
163
|
-
|
164
|
-
map_data['sourcesContent'] = [] if source_map_contents
|
165
|
-
|
166
|
-
file = File.absolute_path(file) unless file.nil?
|
167
|
-
|
168
|
-
map_data['sources'].map! do |source|
|
169
|
-
if source.start_with? 'file://'
|
170
|
-
path = Util.path_from_file_uri(source)
|
171
|
-
content = if path == file && !data.nil?
|
172
|
-
data
|
173
|
-
else
|
174
|
-
begin
|
175
|
-
File.read(path)
|
176
|
-
rescue StandardError
|
177
|
-
nil
|
178
|
-
end
|
179
|
-
end
|
180
|
-
map_data['sourcesContent'].push(content) if source_map_contents
|
181
|
-
Util.relative_path(source_map_dir, path)
|
182
|
-
else
|
183
|
-
map_data['sourcesContent'].push(nil) if source_map_contents
|
184
|
-
source
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
[-JSON.generate(map_data), source_map_path]
|
189
|
-
end
|
190
|
-
|
191
|
-
def post_process_css(css:,
|
192
|
-
indent_type:,
|
193
|
-
indent_width:,
|
194
|
-
linefeed:,
|
195
|
-
map:,
|
196
|
-
omit_source_map_url:,
|
197
|
-
out_file:,
|
198
|
-
source_map:,
|
199
|
-
source_map_embed:)
|
200
|
-
css = +css
|
201
|
-
if indent_width != 2 || indent_type.to_sym != :space
|
202
|
-
indent = indent_type * indent_width
|
203
|
-
css.gsub!(/^ +/) do |space|
|
204
|
-
indent * (space.length / 2)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
css.gsub!("\n", linefeed) if linefeed != "\n"
|
208
|
-
|
209
|
-
unless map.nil? || omit_source_map_url == true
|
210
|
-
url = if source_map_embed
|
211
|
-
"data:application/json;base64,#{Base64.strict_encode64(map)}"
|
212
|
-
elsif out_file
|
213
|
-
Util.relative_path(File.dirname(out_file), source_map)
|
214
|
-
else
|
215
|
-
source_map
|
216
|
-
end
|
217
|
-
css += "#{linefeed}#{linefeed}/*# sourceMappingURL=#{url} */"
|
218
|
-
end
|
219
|
-
|
220
|
-
-css
|
221
|
-
end
|
222
|
-
|
223
|
-
def parse_indent_type(indent_type)
|
224
|
-
case indent_type.to_sym
|
225
|
-
when :space
|
226
|
-
' '
|
227
|
-
when :tab
|
228
|
-
"\t"
|
229
|
-
else
|
230
|
-
raise ArgumentError, 'indent_type must be one of :space, :tab'
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def parse_indent_width(indent_width)
|
235
|
-
raise ArgumentError, 'indent_width must be an integer' unless indent_width.is_a? Integer
|
236
|
-
raise RangeError, 'indent_width must be in between 0 and 10 (inclusive)' unless indent_width.between? 0, 10
|
237
|
-
|
238
|
-
indent_width
|
239
|
-
end
|
240
|
-
|
241
|
-
def parse_linefeed(linefeed)
|
242
|
-
case linefeed.to_sym
|
243
|
-
when :lf
|
244
|
-
"\n"
|
245
|
-
when :lfcr
|
246
|
-
"\n\r"
|
247
|
-
when :cr
|
248
|
-
"\r"
|
249
|
-
when :crlf
|
250
|
-
"\r\n"
|
251
|
-
else
|
252
|
-
raise ArgumentError, 'linefeed must be one of :lf, :lfcr, :cr, :crlf'
|
253
|
-
end
|
254
|
-
end
|
255
136
|
end
|
256
137
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
# The {FileImporter} interface.
|
5
|
+
class FileImporter
|
6
|
+
def find_file_url(url, from_import:) # rubocop:disable Lint/UnusedMethodArgument
|
7
|
+
raise NotImplementedError, 'FileImporter#find_file_url must be implemented'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
# The {Importer} interface.
|
5
|
+
class Importer
|
6
|
+
def canonicalize(url) # rubocop:disable Lint/UnusedMethodArgument
|
7
|
+
raise NotImplementedError, 'Importer#canonicalize must be implemented'
|
8
|
+
end
|
9
|
+
|
10
|
+
def load(canonical_url) # rubocop:disable Lint/UnusedMethodArgument
|
11
|
+
raise NotImplementedError, 'Importer#load must be implemented'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
# The {ImporterResult} of {Importer#load}.
|
5
|
+
class ImporterResult
|
6
|
+
attr_reader :contents, :syntax, :source_map_url
|
7
|
+
|
8
|
+
def initialize(contents, syntax, source_map_url = nil)
|
9
|
+
@contents = contents
|
10
|
+
@syntax = syntax
|
11
|
+
@source_map_url = source_map_url
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
module Logger
|
5
|
+
# The {SourceLocation} in {SourceSpan}.
|
6
|
+
class SourceLocation
|
7
|
+
attr_reader :offset, :line, :column
|
8
|
+
|
9
|
+
def initialize(offset, line, column)
|
10
|
+
@offset = offset
|
11
|
+
@line = line
|
12
|
+
@column = column
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.from_proto(source_location)
|
16
|
+
return nil if source_location.nil?
|
17
|
+
|
18
|
+
SourceLocation.new(source_location.offset,
|
19
|
+
source_location.line,
|
20
|
+
source_location.column)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'source_location'
|
4
|
+
|
5
|
+
module Sass
|
6
|
+
module Logger
|
7
|
+
# The {SourceSpan} in {CompileError}.
|
8
|
+
class SourceSpan
|
9
|
+
attr_reader :start, :end, :text, :url, :context
|
10
|
+
|
11
|
+
def initialize(start, end_, text, url, context)
|
12
|
+
@start = start
|
13
|
+
@end = end_
|
14
|
+
@text = text
|
15
|
+
@url = url == '' ? nil : url
|
16
|
+
@context = context == '' ? nil : context
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.from_proto(source_span)
|
20
|
+
return nil if source_span.nil?
|
21
|
+
|
22
|
+
SourceSpan.new(SourceLocation.from_proto(source_span.start),
|
23
|
+
SourceLocation.from_proto(source_span.end),
|
24
|
+
source_span.text,
|
25
|
+
source_span.url,
|
26
|
+
source_span.context)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/sass/logger.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
# The {Logger} module.
|
5
|
+
module Logger
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# The instance of a silent {Logger}.
|
9
|
+
def silent
|
10
|
+
Silent
|
11
|
+
end
|
12
|
+
|
13
|
+
# The silent {Logger}.
|
14
|
+
module Silent
|
15
|
+
module_function
|
16
|
+
|
17
|
+
def warn(message, deprecation: false, span: nil, stack: nil); end
|
18
|
+
|
19
|
+
def debug(message, span: nil); end
|
20
|
+
end
|
21
|
+
|
22
|
+
private_constant :Silent
|
23
|
+
end
|
24
|
+
end
|
data/lib/sass.rb
CHANGED
@@ -6,6 +6,35 @@ require_relative 'sass/embedded'
|
|
6
6
|
# the Embedded Sass protocol.
|
7
7
|
module Sass
|
8
8
|
class << self
|
9
|
+
# The global {.compile} method. This instantiates a global {Embedded} instance
|
10
|
+
# and calls {Embedded#compile}.
|
11
|
+
#
|
12
|
+
# See {Embedded#compile} for supported options.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# Sass.compile('style.scss')
|
16
|
+
# @return [CompileResult]
|
17
|
+
# @raise [CompileError]
|
18
|
+
# @raise [ProtocolError]
|
19
|
+
def compile(path, **kwargs)
|
20
|
+
instance.compile(path, **kwargs)
|
21
|
+
end
|
22
|
+
|
23
|
+
# The global {.compile_string} method. This instantiates a global {Embedded} instance
|
24
|
+
# and calls {Embedded#compile_string}.
|
25
|
+
#
|
26
|
+
# See {Embedded#compile_string} for supported options.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# Sass.compile_string('h1 { font-size: 40px; }')
|
30
|
+
# @return [CompileResult]
|
31
|
+
# @raise [CompileError]
|
32
|
+
# @raise [ProtocolError]
|
33
|
+
def compile_string(source, **kwargs)
|
34
|
+
instance.compile_string(source, **kwargs)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @deprecated
|
9
38
|
# The global {.include_paths} for Sass files. This is meant for plugins and
|
10
39
|
# libraries to register the paths to their Sass stylesheets to that they may
|
11
40
|
# be included via `@import` or `@use`. This include path is used by every
|
@@ -32,10 +61,11 @@ module Sass
|
|
32
61
|
instance.info
|
33
62
|
end
|
34
63
|
|
64
|
+
# @deprecated
|
35
65
|
# The global {.render} method. This instantiates a global {Embedded} instance
|
36
66
|
# and calls {Embedded#render}.
|
37
67
|
#
|
38
|
-
# See {
|
68
|
+
# See {Embedded#render} for supported options.
|
39
69
|
#
|
40
70
|
# @example
|
41
71
|
# Sass.render(data: 'h1 { font-size: 40px; }')
|