artisans 2.0.6

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f866e3e8c8b4527ba12f809994af9d52f27cf784cac9bd2f3b9041b2819c11da
4
+ data.tar.gz: 0520a752f5b37d10f6dc58d453f0645bfa6f6c557a0ada819dc82c325dde9f88
5
+ SHA512:
6
+ metadata.gz: 5f19344a38c395334092753e73af630474b4085a4f15c0a1e482eaa05c10d966981c7accdf7f2792688c4cc30574e310a301d61e8074b770a5d2ce468b577ad9
7
+ data.tar.gz: 5393ad558dde18e70442ddeaabde0b66f16a60857b01d710b9f97062ec7a2b15962acbcd02b056f340b25014981b590118a77ea563a5ca5e993f508ab3c54f6b
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in artisans.gemspec
4
+ gemspec
5
+
6
+ gem 'sass'
7
+ gem 'sprockets'
8
+ gem 'liquid', git: 'https://github.com/Shopify/liquid.git'
9
+ gem 'haml'
10
+ gem 'rubyzip'
11
+ gem 'pry'
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Myroslava Stavnycha
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # Artisans
2
+
3
+ Artisans is a gem that helps to compile stylesheets assets in a format of scss.liquid, which might contain settings.
4
+ The main job of this gem is:
5
+ - To help existing sprocket FileImporter to locate scss files (@import directive), which has scss.liquid extension
6
+ - To make existing Sass compiler keep inline comments, which include pattern 'settings.xxx'
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'artisans'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install artisans
23
+
24
+ ## Usage
25
+
26
+ The gem can be used for compiling single assets (used directly in shoperb during theme editing) and compiling (and packing to .zip) the whole theme.
27
+
28
+ Single asset compiling generally looks as following:
29
+
30
+ ```ruby
31
+ compiler = Artisans::ThemeCompiler.new(theme_sources_path, theme_assets_url, drops: liquid_drops_hash)
32
+
33
+ compiled_output = compiler.compiled_source('source/file/path')
34
+
35
+ # compiling whole theme. ThemeCompiler#compiled_file_with_derivatives yields every result file one by one
36
+ compiler.compiled_files do |file_path, content, type: :file|
37
+ # type might be :symlink. type = :file is default
38
+ end
39
+
40
+ # compilation of only 1 file with its derivatives is also possible:
41
+ # in this case compilation of sources/emails.liquid.haml will result in:
42
+ # - sources/emails/xxx.liquid.haml -> just returns source itself
43
+ # - emails/xxx.liquid -> compiled version
44
+ #
45
+ # Compilation of 'sources/translations/en.json' will result in:
46
+ # - sources/translations/en.json -> the source itself
47
+ # - translations/en.json -> a symlink to the source
48
+ #
49
+ # Compilation of sources/stylesheets/application.sass.liquid will result in:
50
+ # - sources/stylesheets/application.sass.liquid
51
+ # - stylesheets/application.css
52
+
53
+ compiler.compiled_file_with_derivatives('path/to/source') do |file_path, content, type: :file|
54
+ # type might be :symlink. type = :file is default
55
+ end
56
+
57
+ ```
58
+
59
+ Artisans gem have could of configs as well:
60
+
61
+ ```ruby
62
+ Artisans.configure do |c|
63
+ c.verbose = false # by default
64
+ c.logger = MyCustomLogger # which should implement #notify method
65
+ end
66
+ ```
67
+
68
+
69
+ ## Development
70
+
71
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
72
+
73
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
74
+
75
+ ## Contributing
76
+
77
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/artisans.
78
+
79
+
80
+ ## License
81
+
82
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
83
+
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => :spec
data/artisans.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'artisans/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "artisans"
8
+ spec.version = Artisans::VERSION
9
+ spec.required_ruby_version = ">= 3.2.0"
10
+ spec.authors = ["Shoperb"]
11
+ spec.email = ["engineering@shoperb.com"]
12
+
13
+ spec.summary = 'Tool for compiling scss+liquid assets'
14
+ spec.description = 'Artisans compiles SCSS + Liquid assets for Shoperb themes, bundling templates and styles into deployable packages.'
15
+ spec.homepage = "https://www.shoperb.dev"
16
+ spec.license = "MIT"
17
+
18
+ spec.metadata = {
19
+ "rubygems_mfa_required" => "true",
20
+ "homepage_uri" => "https://www.shoperb.com",
21
+ "documentation_uri" => "https://www.shoperb.dev",
22
+ "source_code_uri" => "https://github.com/shoperb/artisans",
23
+ "bug_tracker_uri" => "https://github.com/shoperb/artisans/issues"
24
+ }
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_development_dependency "bundler", "~> 2.0"
32
+ spec.add_development_dependency "rake", "~> 13.0"
33
+
34
+ spec.add_dependency "liquid", "~> 4.0"
35
+ spec.add_dependency "sass", "~> 3"
36
+ spec.add_dependency "haml", "~> 6"
37
+ spec.add_dependency "rubyzip", "~> 2.3"
38
+ spec.add_dependency "sprockets", "3.7.2"
39
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "artisans"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,79 @@
1
+ module Artisans
2
+ class CachedEnvironment < ::Sprockets::CachedEnvironment
3
+ attr_accessor :assets_url, :environment, :file_reader, :drops
4
+
5
+ def initialize(environment, options={})
6
+ @assets_url = environment.assets_url
7
+ @environment = environment
8
+ @file_reader = environment.file_reader
9
+ @drops = environment.drops
10
+ super(environment)
11
+ end
12
+
13
+ def stat(filename)
14
+ if file_reader.respond_to?(:stat)
15
+ file_reader.stat(filename)
16
+ else
17
+ super(filename)
18
+ end
19
+ end
20
+
21
+ def read_file(filename, content_type = nil)
22
+ @file_reader.read(filename)
23
+ end
24
+
25
+ def load_from_unloaded(unloaded, force_native = false)
26
+ if file_reader.respond_to?(:load_from_unloaded) && !force_native
27
+ file_reader.load_from_unloaded(unloaded, self)
28
+ else
29
+ super(unloaded)
30
+ end
31
+ end
32
+
33
+ # def resolve_absolute_path(paths, filename, accept)
34
+ # if file_reader.respond_to?(:resolve_absolute_path)
35
+ # file_reader.resolve_absolute_path(paths, filename, accept, self)
36
+ # else
37
+ # super(paths, filename, accept)
38
+ # end
39
+ # end
40
+
41
+ def load(uri, force_native = false)
42
+ if file_reader.respond_to?(:load) && !force_native
43
+ file_reader.load(uri, self)
44
+ else
45
+ super(uri)
46
+ end
47
+ end
48
+
49
+ def file?(uri)
50
+ if file_reader.respond_to?(:file?)
51
+ file_reader.file?(uri)
52
+ else
53
+ super(uri)
54
+ end
55
+ end
56
+
57
+ # Overrides resolver path_matches in sprockets 3.5
58
+ def path_matches(load_path, logical_name, logical_basename)
59
+ if file_reader && file_reader.respond_to?(:path_matches)
60
+ file_reader.path_matches(load_path, logical_name, logical_basename)
61
+ else
62
+ super(load_path, logical_name, logical_basename)
63
+ end
64
+ end
65
+
66
+ # Overrides resolver for sprockets 4.0 to reuse path_matches
67
+ def resolve_alts_under_path(load_path, logical_name, mime_exts)
68
+ logical_basename = File.basename(logical_name)
69
+
70
+ candidates,deps = path_matches(load_path, logical_name, logical_basename) if method(:path_matches).super_method
71
+ if candidates.present?
72
+ c = candidates.first
73
+ return [{ filename: c[0], type: c[1] }], deps
74
+ end
75
+
76
+ super
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,16 @@
1
+ module Artisans
2
+ class Configuration
3
+
4
+ attr_accessor :verbose, :logger
5
+
6
+ def initialize(*)
7
+ @verbose = false
8
+ @logger = Logger.new(STDOUT).tap do |logger|
9
+ logger.define_singleton_method(:notify) do |msg, &block|
10
+ info msg
11
+ block.call
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,106 @@
1
+ require_relative 'cached_environment'
2
+ require_relative 'liquid/drops/settings_drop'
3
+
4
+ require_relative 'sass/sass_liquid_importer'
5
+ require_relative 'sass/settings_processor'
6
+ require_relative 'sass/script/lexer'
7
+
8
+ module Artisans
9
+ #
10
+ # Supplying sprockets environment with correct assets paths, custom file importer for Sass::Engine
11
+ # and custom SassProcessor
12
+ #
13
+ class Environment < ::Sprockets::Environment
14
+ attr_reader :sources_path, :settings, :assets_url, :file_reader
15
+
16
+ def initialize **options, &block
17
+ @sources_path = options[:sources_path]
18
+ @settings = options[:settings]
19
+
20
+ @assets_url = Pathname.new(options[:assets_url])
21
+ @file_reader = options[:file_reader]
22
+
23
+ super(&block)
24
+
25
+ # either calculating digest from file content
26
+ # or already existing digests are taken
27
+ context_class.class_eval %Q{
28
+ def asset_path(path, options = {})
29
+ full_path = File.join('#{assets_path}', path)
30
+ reader = environment.file_reader
31
+
32
+ digest = reader.try(:find_digest, full_path)
33
+ digest ||= Digest::MD5.hexdigest(File.read(full_path)) if File.exist?(full_path)
34
+
35
+ separator = reader.try(:find_separator, full_path)
36
+ separator ||= ''
37
+
38
+ ext = File.extname(path)
39
+ filename = [path.gsub(/\#{Regexp.quote(ext)}\\z/, ''), separator, digest, ext].map(&:presence).compact.join
40
+
41
+ # if is fixing after_processor AssetUrlProcessor
42
+ filename.start_with?('#{assets_url}') ? filename : File.join('#{assets_url}', filename)
43
+ end
44
+ }
45
+
46
+ # cant use 'append_path' with objects importers, so:
47
+ self.config = hash_reassoc(config, :paths) do |paths|
48
+ paths.push(assets_path.to_s)
49
+ paths.push(stylesheets_path)
50
+ paths.push(javascripts_path)
51
+
52
+ paths.push(sass_liquid_importer)
53
+ end
54
+
55
+ register_mime_type 'application/font-woff', extensions: ['.woff2'] # not registered by default
56
+ register_mime_type 'application/pdf', extensions: ['.pdf'] # not registered by default
57
+ register_mime_type 'application/liquid', extensions: ['.liquid'] # not registered by default
58
+ register_mime_type 'text/scss', extensions: ['.scss'], charset: :unicode
59
+ register_transformer 'text/scss', 'text/css', Artisans::Sass::SettingsProcessor
60
+ register_transformer 'application/liquid', 'text/css', Artisans::Sass::SettingsProcessor
61
+ register_transformer 'application/liquid', 'text/scss', Artisans::Sass::SettingsProcessor
62
+
63
+ register_preprocessor 'application/liquid', Sprockets::DirectiveProcessor.new(comments: ["//", ["/*", "*/"]])
64
+
65
+ # register_transformer is not working on current rails if engine is set,
66
+ # so add manually to engine to rewrite Sprockets::ScssProcessor transformer
67
+ self.config = hash_reassoc(config, :engines) do |engines|
68
+ engines.merge(".scss" => Artisans::Sass::SettingsProcessor)
69
+ end if config[:engines] # only for sprockets up to 3.7
70
+
71
+ Artisans::Sass::SassLiquidImporter.environment = self
72
+ end
73
+
74
+ def drops
75
+ @drops ||= {
76
+ settings: Artisans::SettingsDrop.new(settings)
77
+ }.stringify_keys
78
+ end
79
+
80
+ def read_file(filename)
81
+ cached.read_file(filename)
82
+ end
83
+
84
+ private
85
+
86
+ def sass_liquid_importer
87
+ Artisans::Sass::SassLiquidImporter.new(stylesheets_path, self)
88
+ end
89
+
90
+ def assets_path
91
+ @assets_path ||= sources_path.join('assets')
92
+ end
93
+
94
+ def stylesheets_path
95
+ @stylesheets_path ||= assets_path.join('stylesheets').to_s
96
+ end
97
+
98
+ def javascripts_path
99
+ @javascripts_path ||= assets_path.join('javascripts').to_s
100
+ end
101
+
102
+ def cached
103
+ Artisans::CachedEnvironment.new(self)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,5 @@
1
+ module Artisans
2
+ class Error < StandardError; end
3
+ class ArgumentsError < Error; end
4
+ class CompilationError < Error; end
5
+ end
@@ -0,0 +1,33 @@
1
+ module Artisans
2
+ class SettingsDrop < Liquid::Drop
3
+
4
+ attr_reader :settings
5
+
6
+ def initialize(settings = {})
7
+ @settings = settings || {}
8
+
9
+ @settings.each do |key, value|
10
+ define_singleton_method key do
11
+ format_value(key, value)
12
+ end
13
+ end
14
+ end
15
+
16
+ def self.invokable?(method_name)
17
+ true
18
+ end
19
+
20
+ def method_missing *args
21
+ nil
22
+ end
23
+
24
+ private
25
+
26
+ #
27
+ # adding a setting key around value in a comment
28
+ #
29
+ def format_value(key, value)
30
+ "'/*settings.#{key}[*/#{value}/*]*/'"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,67 @@
1
+ #
2
+ # Artisans::Sass::SassLiquidImporter can read .scss.liquid files, and at the same time
3
+ # using custom 'file_reader' provided along with the environment
4
+ #
5
+ module Artisans
6
+ module Sass
7
+ class SassLiquidImporter < ::Sass::Importers::Filesystem
8
+ def self.environment= env
9
+ @environment = env
10
+ end
11
+
12
+ def self.environment
13
+ @environment
14
+ end
15
+
16
+
17
+ def initialize(root, environment = nil)
18
+ @environment = environment||self.class.environment
19
+ root = @environment.send(:stylesheets_path)
20
+
21
+ super(root)
22
+
23
+ @root = root.to_s
24
+ @real_root = ::Sass::Util.realpath(@root).to_s
25
+ end
26
+
27
+ alias_method :to_str, :to_s
28
+ protected
29
+
30
+ def extensions
31
+ super.merge(
32
+ 'sass.liquid' => :sass,
33
+ 'scss.liquid' => :scss
34
+ )
35
+ end
36
+
37
+ def _find(dir, name, options)
38
+ return unless @environment
39
+
40
+ if @environment.file_reader.respond_to?(:find_real_file)
41
+ full_filename, syntax = @environment.file_reader.find_real_file(dir, name, options, extensions)
42
+ else
43
+ full_filename, syntax = ::Sass::Util.destructure(find_real_file(dir, name, options))
44
+ end
45
+ return unless full_filename
46
+
47
+ full_filename = full_filename.tr("\\", "/") if ::Sass::Util.windows?
48
+
49
+ options[:syntax] = syntax
50
+ options[:filename] = full_filename
51
+ options[:importer] = self
52
+
53
+ #
54
+ # below goes the modification of original function
55
+ #
56
+ file_content = @environment.read_file(full_filename)
57
+
58
+ if File.extname(full_filename) == '.liquid'
59
+ liquid_compiled = Liquid::Template.parse(file_content).render(@environment.drops)
60
+ ::Sass::Engine.new(liquid_compiled, options)
61
+ else
62
+ ::Sass::Engine.new(file_content, options)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,81 @@
1
+ #
2
+ # Extending Sass Lexer to understand colors,
3
+ # surrounded with settings comments
4
+ #
5
+ module Artisans
6
+ module SettingsLexer
7
+
8
+ def self.prepended(base)
9
+ base.class_eval do
10
+ class << self
11
+ def settings_re(re)
12
+ Regexp::new("(\\'?/\\*settings\\.[a-z_]+\\[\\*/)(" + re.source + ")(/\\*\\]\\*/\\'?)")
13
+ end
14
+ end
15
+
16
+ self::REGULAR_EXPRESSIONS[:settings_color] = settings_re(self::REGULAR_EXPRESSIONS[:color])
17
+ self::REGULAR_EXPRESSIONS[:settings_rgb_color] = settings_re(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*(\d+.?\d*))?\s*\)/)
18
+ self::REGULAR_EXPRESSIONS[:settings_number] = settings_re(self::REGULAR_EXPRESSIONS[:number])
19
+
20
+ private
21
+
22
+ #
23
+ # taken from ::Sass::Script::Lexer
24
+ #
25
+ def token
26
+ if after_interpolation? && (interp = @interpolation_stack.pop)
27
+ interp_type, interp_value = interp
28
+ if interp_type == :special_fun
29
+ return special_fun_body(interp_value)
30
+ else
31
+ raise "[BUG]: Unknown interp_type #{interp_type}" unless interp_type == :string
32
+ return string(interp_value, true)
33
+ end
34
+ end
35
+
36
+ #
37
+ # Injecting 'settings_color'
38
+ # lexer check in here
39
+ #
40
+ variable || settings_color || settings_rgb_color || string(:double, false) || string(:single, false) || color || number || id ||
41
+ selector || string(:uri, false) || raw(self.class::UNICODERANGE) || special_fun || special_val ||
42
+ ident_op || ident || op
43
+ end
44
+
45
+ #
46
+ # Modified "color" lexer: parses value as valid color.
47
+ # Stores 'representation' along with comments
48
+ #
49
+ def settings_color
50
+ return unless @scanner.match?(self.class::REGULAR_EXPRESSIONS[:settings_color])
51
+ return unless @scanner[2].length == 4 || @scanner[2].length == 7
52
+ scanned_color = scan(self.class::REGULAR_EXPRESSIONS[:settings_color])
53
+ script_color = ::Sass::Script::Value::Color.from_hex(@scanner[2])
54
+ script_color.instance_variable_set("@representation", @scanner[0].gsub(/^'/, '').gsub(/'$/, ''))
55
+ [:color, script_color]
56
+ end
57
+
58
+ def settings_rgb_color
59
+ return unless @scanner.match?(self.class::REGULAR_EXPRESSIONS[:settings_rgb_color])
60
+ scanned_color = scan(self.class::REGULAR_EXPRESSIONS[:settings_rgb_color])
61
+ script_color = ::Sass::Script::Value::Color.new([@scanner[3].to_f, @scanner[4].to_f, @scanner[5].to_f, @scanner[7].to_f || 1])
62
+ script_color.instance_variable_set("@representation", @scanner[0].gsub(/^'/, '').gsub(/'$/, ''))
63
+ [:color, script_color]
64
+ end
65
+
66
+ # def settings_number
67
+ # return unless scan(self.class::REGULAR_EXPRESSIONS[:settings_number])
68
+
69
+ # value = (@scanner[2] ? @scanner[2].to_f : @scanner[3].to_i)
70
+ # value *= 10**@scanner[4].to_i if @scanner[4]
71
+ # script_number = ::Sass::Script::Value::Number.new(value, Array(@scanner[4]))
72
+ # script_number.original = @scanner[1]
73
+
74
+ # [:number, script_number]
75
+ # end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ ::Sass::Script::Lexer.send(:prepend, Artisans::SettingsLexer)
@@ -0,0 +1,31 @@
1
+ #
2
+ # Artisans::Sass::SettingsProcessor inherits all functionality of built-it
3
+ # sprockets scss processors class.
4
+ #
5
+ # Artisans::Sass::SettingsProcessor is intended to integerate custom file importer (Artisans::Sass::FileImporter),
6
+ # which is able to @import liquid files. In addition, ScssProcessor processed correctly
7
+ # inline comments in scss file.
8
+ #
9
+ require "sprockets/sass_processor.rb"
10
+ module Artisans
11
+ module Sass
12
+ class SettingsProcessor < Sprockets::ScssProcessor
13
+
14
+ def initialize(options={}, &block)
15
+ options[:importer] ||= Artisans::Sass::SassLiquidImporter
16
+ super(options, &block)
17
+ end
18
+ #
19
+ # Inherits default scss compiling.
20
+ # + Removes quates, which were artificially places around settings comments so the processor leaves them.
21
+ # "/*setting.setting_name[*/setting_value/*]*/" => /*setting.setting_name[*/setting_value/*]*/
22
+ #
23
+ def call(input)
24
+ super.tap do |hash|
25
+ hash[:data] = hash[:data].gsub(/["'](\/\*settings\..+\[.+\]\*\/)["']/, '\1')
26
+ hash[:data] = hash[:data].gsub(/(" (.*?) ")/, '"\2"') # if value has quotes, then some redundant spaces are added. we remove them here
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,129 @@
1
+ require 'artisans/environment'
2
+
3
+ module Artisans
4
+ class ThemeCompiler
5
+
6
+ module DefaultFileReader
7
+ extend self
8
+
9
+ def read(file)
10
+ File.read(file) if File.file?(file)
11
+ end
12
+ end
13
+
14
+ attr_reader :sources_path, :assets_url, :compile, :settings
15
+
16
+ def initialize(sources_path, assets_url, **options)
17
+ @sources_path = sources_path.is_a?(String) ? Pathname.new(sources_path) : sources_path
18
+ @assets_url = assets_url
19
+ @compile = options[:compile] || default_compilation_assets
20
+ @settings = options[:settings] || {}
21
+ @file_reader = options[:file_reader] || Artisans::ThemeCompiler::DefaultFileReader
22
+
23
+ @compile.symbolize_keys!
24
+ @compiled_assets = {}
25
+ end
26
+
27
+ def compiled_files(&block)
28
+ Pathname.glob(sources_path.join("**/*")) do |file|
29
+ process_file file do |*args|
30
+ logger.notify("Packing #{file}"){ block.call(*args) }
31
+ end
32
+ end
33
+ end
34
+
35
+ def compiled_file_with_derivatives(filename, &block)
36
+ process_file Pathname.new(filename), &block
37
+ end
38
+
39
+ def compiled_source(asset_path)
40
+ asset = compiled_asset(asset_path)
41
+ asset ? asset.source : (raise "Asset not found: #{asset_path} in #{sources_path.join('assets')}")
42
+ end
43
+
44
+ def rack_response env
45
+ sprockets_env.call(env)
46
+ end
47
+
48
+ protected
49
+ attr_accessor :compiled_assets
50
+
51
+ def default_compilation_assets
52
+ {
53
+ javascripts: ['application.js'],
54
+ stylesheets: ['application.css']
55
+ }
56
+ end
57
+
58
+ def compile_without_ext
59
+ compile.each_with_object({}) do |(type, files), collection|
60
+ collection[type] = files.map{ |f| File.basename(f, '.*') }
61
+ end
62
+ end
63
+
64
+ def process_file(file)
65
+ relative_path = file.relative_path_from(sources_path)
66
+ source_path = Pathname.new('sources').join(relative_path)
67
+
68
+ file_content = @file_reader.read(file)
69
+
70
+ case relative_path.to_s
71
+ when /\A(assets\/(stylesheets\/((?:#{compile_without_ext[:stylesheets].join("|")})\.(css(|\.sass|\.scss)|sass|scss)(\.liquid)?)))\z/
72
+ yield source_path, file_content
73
+
74
+ compiled = compiled_source($~[2])
75
+ filename = "#{$~[1].gsub(".#{$~[4]}", "")}.css"
76
+ yield Pathname.new(filename), compiled
77
+ when /\A(assets\/(javascripts\/((?:#{compile_without_ext[:javascripts].join("|")})\.(js|coffee|js\.coffee))))\z/
78
+ yield source_path, file_content
79
+
80
+ compiled = compiled_source($~[2])
81
+ filename = "#{$~[1].gsub(".#{$~[4]}", "")}.js"
82
+ yield Pathname.new(filename), compiled
83
+ when /\A((layouts|templates|emails|sections)\/(.*\.liquid))\z/,
84
+ /\A(assets\/((images|icons)\/(.*\.(png|jpg|jpeg|gif|swf|ico|svg|pdf|json))))\z/,
85
+ /\A(assets\/(fonts\/(.*\.(eot|woff|ttf|woff2|svg))))\z/
86
+ yield relative_path, file_content
87
+ yield source_path, relative_path, :symlink
88
+ when /\A((layouts|templates|emails|sections)\/(.*\.liquid))\.haml\z/
89
+ content_compiled = Haml::Engine.new(file_content).render
90
+ yield Pathname.new($1.dup), content_compiled
91
+
92
+ if file_content == content_compiled
93
+ yield source_path, Pathname.new($1.dup), :symlink
94
+ else
95
+ yield source_path, file_content
96
+ end
97
+ when /\A((presets|config|translations)\/(.*\.json))\z/
98
+ yield relative_path, file_content
99
+ yield source_path, relative_path, :symlink
100
+ when /\A(assets\/(javascripts\/(.*\.(js|coffee|js\.coffee))))\z/, /\A(assets\/(stylesheets\/(.*\.(css(|\.sass|\.scss)|sass|scss)(\.liquid)?)))\z/
101
+ yield source_path, file_content
102
+ end
103
+ end
104
+
105
+ def compiled_asset(asset_path)
106
+ compiled_assets[asset_path] ||= begin
107
+ sprockets_env[asset_path]
108
+ rescue StandardError => e
109
+ puts e.message
110
+ puts e.backtrace
111
+
112
+ raise Artisans::CompilationError.new(e)
113
+ end
114
+ end
115
+
116
+ def logger
117
+ Artisans.configuration.logger
118
+ end
119
+
120
+ def sprockets_env
121
+ @sprockets_env ||= Artisans::Environment.new(
122
+ sources_path: sources_path,
123
+ assets_url: assets_url,
124
+ settings: settings,
125
+ file_reader: @file_reader
126
+ )
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,3 @@
1
+ module Artisans
2
+ VERSION = "2.0.6"
3
+ end
data/lib/artisans.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'sass'
2
+ require 'sprockets'
3
+ require 'liquid'
4
+ require 'haml'
5
+ require 'zip'
6
+
7
+ require 'artisans/version'
8
+ require 'artisans/errors'
9
+ require 'artisans/configuration'
10
+
11
+ require 'artisans/theme_compiler'
12
+
13
+ module Artisans
14
+ def self.configure
15
+ yield(configuration)
16
+ end
17
+
18
+ def self.configuration
19
+ @configuration ||= Artisans::Configuration.new
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: artisans
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Shoperb
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bundler
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: liquid
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '4.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '4.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: sass
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3'
68
+ - !ruby/object:Gem::Dependency
69
+ name: haml
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '6'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '6'
82
+ - !ruby/object:Gem::Dependency
83
+ name: rubyzip
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.3'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '2.3'
96
+ - !ruby/object:Gem::Dependency
97
+ name: sprockets
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '='
101
+ - !ruby/object:Gem::Version
102
+ version: 3.7.2
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - '='
108
+ - !ruby/object:Gem::Version
109
+ version: 3.7.2
110
+ description: Artisans compiles SCSS + Liquid assets for Shoperb themes, bundling templates
111
+ and styles into deployable packages.
112
+ email:
113
+ - engineering@shoperb.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".travis.yml"
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - artisans.gemspec
125
+ - bin/console
126
+ - bin/setup
127
+ - lib/artisans.rb
128
+ - lib/artisans/cached_environment.rb
129
+ - lib/artisans/configuration.rb
130
+ - lib/artisans/environment.rb
131
+ - lib/artisans/errors.rb
132
+ - lib/artisans/liquid/drops/settings_drop.rb
133
+ - lib/artisans/sass/sass_liquid_importer.rb
134
+ - lib/artisans/sass/script/lexer.rb
135
+ - lib/artisans/sass/settings_processor.rb
136
+ - lib/artisans/theme_compiler.rb
137
+ - lib/artisans/version.rb
138
+ homepage: https://www.shoperb.dev
139
+ licenses:
140
+ - MIT
141
+ metadata:
142
+ rubygems_mfa_required: 'true'
143
+ homepage_uri: https://www.shoperb.com
144
+ documentation_uri: https://www.shoperb.dev
145
+ source_code_uri: https://github.com/shoperb/artisans
146
+ bug_tracker_uri: https://github.com/shoperb/artisans/issues
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 3.2.0
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubygems_version: 3.6.7
162
+ specification_version: 4
163
+ summary: Tool for compiling scss+liquid assets
164
+ test_files: []