sassc-embedded 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 01b39ff3df99a2a2c1d9e9aa76ad7d06462a0ba970c8ed907753dc094ac93f54
4
+ data.tar.gz: aa75aa2ff62c0b50c48fd0c7594aadee3ff7180b215df76c9efbc7f3e4112ace
5
+ SHA512:
6
+ metadata.gz: 9eec5413a5ef0da29d752c421889cb0f4bf278f10a48ca7a0ffdd002d7217f04f99d3553dbdf9396077c23e66ed24d5baa7005bb6a7a324f094533300a2d9d20
7
+ data.tar.gz: 59348aae444404fba124bc4717ac51f8433739f5ff6c26ab394b3191483ccc5aa67ffb5df917a3c0643c5ca2fd93da1ab563c8c460fd6c27083e04c1aaeb1551
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 なつき
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Embedded Sass Polyfill for SassC Ruby
2
+
3
+ [![build](https://github.com/ntkme/sassc-embedded-polyfill-ruby/actions/workflows/build.yml/badge.svg)](https://github.com/ntkme/sassc-embedded-polyfill-ruby/actions/workflows/build.yml)
4
+ [![gem](https://badge.fury.io/rb/sassc-embedded.svg)](https://rubygems.org/gems/sassc-embedded)
5
+
6
+ Use `sass-embedded` with SassC Ruby!
7
+
8
+ This library polyfills [`sassc`](https://github.com/sass/sassc-ruby) with the [`sass-embedded`](https://github.com/ntkme/sass-embedded-host-ruby) implementation.
9
+
10
+
11
+ ## Install
12
+
13
+ ``` sh
14
+ gem install sassc-embedded
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ To compile, `require 'sassc/embedded'` before use a `SassC::Engine`, e.g.:
20
+
21
+ ``` ruby
22
+ require 'sassc/embedded'
23
+
24
+ SassC::Engine.new(sass, style: :compressed).render
25
+ ```
26
+
27
+ See [rubydoc.info/gems/sassc](https://rubydoc.info/gems/sassc) for full API documentation.
28
+
29
+ ## Behavioral Differences from SassC Ruby
30
+
31
+ 1. Option `:style => :nested` behaves as `:expanded`.
32
+ 2. Option `:style => :compact` behaves as `:compressed`.
33
+ 3. Option `:precision` is ignored.
34
+ 4. Option `:line_comments` is ignored.
35
+ 5. Argument `parent_path` in `Importer#imports` is set to value of option `:filename`.
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SassC
4
+ module Embedded
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,402 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sassc'
4
+ require 'sass-embedded'
5
+
6
+ require 'base64'
7
+ require 'json'
8
+ require 'pathname'
9
+ require 'uri'
10
+
11
+ require_relative 'embedded/version'
12
+
13
+ module SassC
14
+ class Engine
15
+ def render
16
+ return @template.dup if @template.empty?
17
+
18
+ result = ::Sass.compile_string(
19
+ @template,
20
+ importer: nil,
21
+ load_paths: load_paths,
22
+ syntax: syntax,
23
+ url: file_url,
24
+
25
+ source_map: !source_map_file.nil?,
26
+ source_map_include_sources: source_map_contents?,
27
+ style: output_style,
28
+
29
+ functions: FunctionsHandler.new(@options).setup(nil, functions: @functions),
30
+ importers: ImportHandler.new(@options).setup(nil),
31
+
32
+ alert_ascii: @options.fetch(:alert_ascii, false),
33
+ alert_color: @options.fetch(:alert_color, nil),
34
+ logger: @options.fetch(:logger, nil),
35
+ quiet_deps: @options.fetch(:quiet_deps, false),
36
+ verbose: @options.fetch(:verbose, false)
37
+ )
38
+
39
+ @dependencies = result.loaded_urls
40
+ .filter { |url| url.start_with?('file:') && url != file_url }
41
+ .map { |url| Util.file_url_to_path(url) }
42
+ @source_map = post_process_source_map(result.source_map)
43
+
44
+ return post_process_css(result.css) unless quiet?
45
+ rescue ::Sass::CompileError => e
46
+ line = e.span&.start&.line
47
+ line += 1 unless line.nil?
48
+ path = Util.file_url_to_path(e.span&.url)
49
+ path = relative_path(Dir.pwd, path)
50
+ raise SyntaxError.new(e.message, filename: path, line: line)
51
+ end
52
+
53
+ private
54
+
55
+ def file_url
56
+ @file_url ||= Util.path_to_file_url(filename || 'stdin')
57
+ end
58
+
59
+ def syntax
60
+ syntax = @options.fetch(:syntax, :scss)
61
+ syntax = :indented if syntax.to_sym == :sass
62
+ syntax
63
+ end
64
+
65
+ def output_style
66
+ @output_style ||= begin
67
+ style = @options.fetch(:style, :sass_style_nested).to_s
68
+ style = "sass_style_#{style}" unless style.include?('sass_style_')
69
+ raise InvalidStyleError unless OUTPUT_STYLES.include?(style.to_sym)
70
+
71
+ style = style.delete_prefix('sass_style_').to_sym
72
+ case style
73
+ when :nested
74
+ :expanded
75
+ when :compact
76
+ :compressed
77
+ else
78
+ style
79
+ end
80
+ end
81
+ end
82
+
83
+ def load_paths
84
+ @load_paths ||= (@options[:load_paths] || []) + SassC.load_paths
85
+ end
86
+
87
+ def post_process_source_map(source_map)
88
+ return unless source_map
89
+
90
+ data = JSON.parse(source_map)
91
+
92
+ data['sources'].map! do |source|
93
+ if source.start_with? 'file:'
94
+ relative_path(Dir.pwd, Util.file_url_to_path(source))
95
+ else
96
+ source
97
+ end
98
+ end
99
+
100
+ -JSON.generate(data)
101
+ end
102
+
103
+ def post_process_css(css)
104
+ css += "\n" if css.end_with? '}'
105
+ unless @source_map.nil? || omit_source_map_url?
106
+ url = if source_map_embed?
107
+ "data:application/json;base64,#{Base64.strict_encode64(@source_map)}"
108
+ else
109
+ URI::DEFAULT_PARSER.escape(source_map_file)
110
+ end
111
+ css += "\n/*# sourceMappingURL=#{url} */"
112
+ end
113
+ -css
114
+ end
115
+
116
+ def relative_path(from, to)
117
+ Pathname.new(to).relative_path_from(Pathname.new(from)).to_s
118
+ end
119
+ end
120
+
121
+ class FunctionsHandler
122
+ def setup(_native_options, functions: Script::Functions)
123
+ @callbacks = {}
124
+
125
+ functions_wrapper = Class.new do
126
+ attr_accessor :options
127
+
128
+ include functions
129
+ end.new
130
+ functions_wrapper.options = @options
131
+
132
+ Script.custom_functions(functions: functions).each do |custom_function|
133
+ callback = lambda do |native_argument_list|
134
+ function_arguments = arguments_from_native_list(native_argument_list)
135
+ begin
136
+ result = functions_wrapper.send(custom_function, *function_arguments)
137
+ rescue StandardError
138
+ raise ::Sass::ScriptError, "Error: error in C function #{custom_function}"
139
+ end
140
+ to_native_value(result)
141
+ rescue StandardError => e
142
+ warn "[SassC::FunctionsHandler] #{e.cause.message}"
143
+ raise e
144
+ end
145
+
146
+ @callbacks[Script.formatted_function_name(custom_function, functions: functions)] = callback
147
+ end
148
+
149
+ @callbacks
150
+ end
151
+
152
+ private
153
+
154
+ def arguments_from_native_list(native_argument_list)
155
+ native_argument_list.map do |embedded_value|
156
+ Script::ValueConversion.from_native embedded_value
157
+ end
158
+ end
159
+
160
+ begin
161
+ begin
162
+ raise
163
+ rescue StandardError
164
+ raise ::Sass::ScriptError
165
+ end
166
+ rescue StandardError => e
167
+ unless e.full_message.include? e.cause.full_message
168
+ ::Sass::ScriptError.class_eval do
169
+ def full_message(*args, **kwargs)
170
+ full_message = super(*args, **kwargs)
171
+ if cause
172
+ "#{full_message}\n#{cause.full_message(*args, **kwargs)}"
173
+ else
174
+ full_message
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ class ImportHandler
183
+ def setup(_native_options)
184
+ if @importer
185
+ [FileImporter.new, Importer.new(@importer)]
186
+ else
187
+ [FileImporter.new]
188
+ end
189
+ end
190
+
191
+ class FileImporter
192
+ def find_file_url(url, **_kwargs)
193
+ return url if url.start_with?('file:')
194
+ end
195
+ end
196
+
197
+ private_constant :FileImporter
198
+
199
+ class Importer
200
+ def initialize(importer)
201
+ @importer = importer
202
+ @importer_results = {}
203
+ end
204
+
205
+ def canonicalize(url, **)
206
+ path = Util.file_url_to_path(url)
207
+ canonical_url = Util.path_to_file_url(File.absolute_path(path))
208
+
209
+ if @importer_results.key?(canonical_url)
210
+ return if @importer_results[canonical_url].nil?
211
+
212
+ return canonical_url
213
+ end
214
+
215
+ canonical_url = "sass-importer-shim:#{canonical_url}"
216
+
217
+ imports = @importer.imports path, @importer.options[:filename]
218
+ unless imports.is_a? Array
219
+ return if imports.path == path
220
+
221
+ imports = [imports]
222
+ end
223
+
224
+ contents = imports.map do |import|
225
+ import_path = File.absolute_path(import.path)
226
+ import_url = Util.path_to_file_url(import_path)
227
+ @importer_results[import_url] = if import.source
228
+ {
229
+ contents: import.source,
230
+ syntax: case import.path
231
+ when /\.scss$/i
232
+ :scss
233
+ when /\.sass$/i
234
+ :indented
235
+ when /\.css$/i
236
+ :css
237
+ else
238
+ raise ArgumentError
239
+ end,
240
+ source_map_url: if import.source_map_path
241
+ Util.path_to_file_url(
242
+ File.absolute_path(import.source_map_path, path)
243
+ )
244
+ end
245
+ }
246
+ end
247
+ "@import #{import_url.inspect};"
248
+ end.join("\n")
249
+
250
+ @importer_results[canonical_url] = {
251
+ contents: contents,
252
+ syntax: :scss
253
+ }
254
+
255
+ canonical_url
256
+ end
257
+
258
+ def load(canonical_url)
259
+ @importer_results[canonical_url]
260
+ end
261
+ end
262
+
263
+ private_constant :Importer
264
+ end
265
+
266
+ module Script
267
+ module ValueConversion
268
+ def self.to_native(value)
269
+ case value
270
+ when nil
271
+ ::Sass::Value::Null::NULL
272
+ when ::SassC::Script::Value::Bool
273
+ ::Sass::Value::Boolean.new(value.to_bool)
274
+ when ::SassC::Script::Value::Color
275
+ if value.rgba?
276
+ ::Sass::Value::Color.new(
277
+ red: value.red,
278
+ green: value.green,
279
+ blue: value.blue,
280
+ alpha: value.alpha
281
+ )
282
+ elsif value.hlsa?
283
+ ::Sass::Value::Color.new(
284
+ hue: value.hue,
285
+ saturation: value.saturation,
286
+ lightness: value.lightness,
287
+ alpha: value.alpha
288
+ )
289
+ else
290
+ raise ArgumentError
291
+ end
292
+ when ::SassC::Script::Value::List
293
+ ::Sass::Value::List.new(
294
+ value.to_a.map { |element| to_native(element) },
295
+ separator: case value.separator
296
+ when :comma
297
+ ','
298
+ when :space
299
+ ' '
300
+ else
301
+ raise ArgumentError
302
+ end,
303
+ bracketed: value.bracketed
304
+ )
305
+ when ::SassC::Script::Value::Map
306
+ ::Sass::Value::Map.new(
307
+ value.value.to_a.to_h { |k, v| [to_native(k), to_native(v)] }
308
+ )
309
+ when ::SassC::Script::Value::Number
310
+ ::Sass::Value::Number.new(
311
+ value.value, {
312
+ numerator_units: value.numerator_units,
313
+ denominator_units: value.denominator_units
314
+ }
315
+ )
316
+ when ::SassC::Script::Value::String
317
+ ::Sass::Value::String.new(
318
+ value.value,
319
+ quoted: value.type != :identifier
320
+ )
321
+ else
322
+ raise ArgumentError
323
+ end
324
+ end
325
+
326
+ def self.from_native(value)
327
+ case value
328
+ when ::Sass::Value::Null::NULL
329
+ nil
330
+ when ::Sass::Value::Boolean
331
+ ::SassC::Script::Value::Bool.new(value.to_bool)
332
+ when ::Sass::Value::Color
333
+ if value.instance_eval { defined? @hue }
334
+ ::SassC::Script::Value::Color.new(
335
+ hue: value.hue,
336
+ saturation: value.saturation,
337
+ lightness: value.lightness,
338
+ alpha: value.alpha
339
+ )
340
+ else
341
+ ::SassC::Script::Value::Color.new(
342
+ red: value.red,
343
+ green: value.green,
344
+ blue: value.blue,
345
+ alpha: value.alpha
346
+ )
347
+ end
348
+ when ::Sass::Value::List
349
+ ::SassC::Script::Value::List.new(
350
+ value.to_a.map { |element| from_native(element) },
351
+ separator: case value.separator
352
+ when ','
353
+ :comma
354
+ when ' '
355
+ :space
356
+ else
357
+ raise ArgumentError
358
+ end,
359
+ bracketed: value.bracketed?
360
+ )
361
+ when ::Sass::Value::Map
362
+ ::SassC::Script::Value::Map.new(
363
+ value.contents.to_a.to_h { |k, v| [from_native(k), from_native(v)] }
364
+ )
365
+ when ::Sass::Value::Number
366
+ ::SassC::Script::Value::Number.new(
367
+ value.value,
368
+ value.numerator_units,
369
+ value.denominator_units
370
+ )
371
+ when ::Sass::Value::String
372
+ ::SassC::Script::Value::String.new(
373
+ value.text,
374
+ value.quoted? ? :string : :identifier
375
+ )
376
+ else
377
+ raise ArgumentError
378
+ end
379
+ end
380
+ end
381
+ end
382
+
383
+ module Util
384
+ module_function
385
+
386
+ def file_url_to_path(url)
387
+ return if url.nil?
388
+
389
+ path = URI::DEFAULT_PARSER.unescape(URI.parse(url).path)
390
+ path = path[1..] if Gem.win_platform? && path[0].chr == '/' && path[1].chr =~ /[a-z]/i && path[2].chr == ':'
391
+ path
392
+ end
393
+
394
+ def path_to_file_url(path)
395
+ return if path.nil?
396
+
397
+ path = File.absolute_path(path)
398
+ path = "/#{path}" unless path.start_with? '/'
399
+ URI::File.build([nil, URI::DEFAULT_PARSER.escape(path)]).to_s
400
+ end
401
+ end
402
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'sassc/embedded'
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sassc-embedded
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - なつき
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-03-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sassc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sass-embedded
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 5.15.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 5.15.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-around
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.5.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.26.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.26.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.18.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.18.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-performance
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.13.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.13.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.6.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.6.0
125
+ description: An embedded sass polyfill for SassC.
126
+ email:
127
+ - i@ntk.me
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - LICENSE
133
+ - README.md
134
+ - lib/sassc-embedded.rb
135
+ - lib/sassc/embedded.rb
136
+ - lib/sassc/embedded/version.rb
137
+ homepage: https://github.com/ntkme/sassc-embedded-polyfill-ruby
138
+ licenses:
139
+ - MIT
140
+ metadata:
141
+ documentation_uri: https://rubydoc.info/gems/sassc-embedded/0.1.0
142
+ source_code_uri: https://github.com/ntkme/sassc-embedded-polyfill-ruby/tree/v0.1.0
143
+ funding_uri: https://github.com/sponsors/ntkme
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 2.6.0
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubygems_version: 3.3.7
160
+ signing_key:
161
+ specification_version: 4
162
+ summary: Use dart-sass with SassC!
163
+ test_files: []