ts_assets 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2390acea17cbc05b4c9b38d9878fda3fda7e9ec3
4
- data.tar.gz: 44b3f059cc5d795775238800657eb9bc65d3a87e
3
+ metadata.gz: 5aa69bcfd907932ff761f68dbc57fe6ab753a5ac
4
+ data.tar.gz: bfc02d04c4a26c84ef4c6fce8e3d5431a157255c
5
5
  SHA512:
6
- metadata.gz: e80e205dc7df6e00d412aff691d3386068e00a54507729eab00a294b53a3635310b9557c85873bdc1e026c2507f54c2970c79d3d49cd6136a808a58e3be3f21a
7
- data.tar.gz: ef305593178177c9b138acbc3f8a55ab3a7b28d64523b57a367d0f6b6a26c6ad93ac96753aadfc874a83c5cb1c31f4a48d27cdfaf66788851ea4f7952b4d9b27
6
+ metadata.gz: 2725a42259d3752423beda929cb291ac0fcfa9cc27bd34e9ec2b7b19e94886d370988f08adbc24c5365a62df6dd6c7dff468466b09ed241245b14e0410e64a44
7
+ data.tar.gz: d019fc93f82c95b4b860c78474d0b65fd2153fbb103249fa4ff8c3a90fd49ed308c4dfd58c4d1645fdf747132ad8aa52b98c32a7b54a9957756b481bfcc16b7d
@@ -0,0 +1,74 @@
1
+ version: 2
2
+ jobs:
3
+ build:
4
+ docker:
5
+ - image: ruby:latest
6
+ environment:
7
+ BUNDLE_DIR: vendor/bundle
8
+
9
+ working_directory: src
10
+
11
+ steps:
12
+ - checkout
13
+
14
+ - restore_cache:
15
+ name: "[Node.js] Restore Cache"
16
+ keys:
17
+ - nodejs-6.10.2
18
+ - nodejs-
19
+
20
+ - run:
21
+ name: "[Node.js] Install"
22
+ command: |
23
+ if [[ ! -e /usr/local/bin/node || $(node --version) != "v${NODEJS_VERSION}" ]]; then
24
+ # https://nodejs.org/ja/download/package-manager/#debian-and-ubuntu-based-linux-distributions-debian-ubuntu-linux
25
+ curl -sL https://deb.nodesource.com/setup_6.x | bash -
26
+ apt-get update -qq
27
+ apt-get install -y nodejs
28
+ ln -s /usr/local/bin/node /usr/local/bin/nodejs
29
+ fi
30
+
31
+ - save_cache:
32
+ name: "[Node.js] Save Cache"
33
+ key: nodejs-6.10.2
34
+ paths:
35
+ - /usr/local/bin/node
36
+
37
+ - run:
38
+ name: Check Runtime Information
39
+ command: |
40
+ cat << EOF
41
+ bundler : `bundle -v`
42
+ Node.js : `node -v`
43
+ EOF
44
+
45
+ - restore_cache:
46
+ name: "[Ruby] Restore Cache"
47
+ keys:
48
+ - gems-{{ checksum "ts_assets.gemspec" }}
49
+ - gems-
50
+
51
+ - run: bundle check --path=$BUNDLE_DIR || bundle install --path=$BUNDLE_DIR --jobs=4 --retry=3 --without=production
52
+
53
+ - save_cache:
54
+ name: "[Ruby] Save Cache"
55
+ key: gems-{{ checksum "ts_assets.gemspec" }}
56
+ paths:
57
+ - vendor/bundle/
58
+
59
+ - restore_cache:
60
+ name: "[JavaScript] Restore Cache"
61
+ keys:
62
+ - js-packages-{{ checksum "package-lock.json" }}
63
+ - js-packages-
64
+
65
+ - run: npm install
66
+
67
+ - save_cache:
68
+ name: "[JavaScript] Save Cache"
69
+ key: js-packages-{{ checksum "package-lock.json" }}
70
+ paths:
71
+ - node_modules/
72
+
73
+ - run: npm test
74
+ - run: npm run lint
data/.gitignore CHANGED
@@ -1,44 +1,16 @@
1
- *.rbc
2
- capybara-*.html
3
- .rspec
4
- /log
5
- /tmp
6
- /db/*.sqlite3
7
- /db/*.sqlite3-journal
8
- /public/system
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
9
5
  /coverage/
10
- /spec/tmp
11
- *.orig
12
- rerun.txt
13
- pickle-email-*.html
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
14
10
 
15
- # TODO Comment out this rule if you are OK with secrets being uploaded to the repo
16
- config/initializers/secret_token.rb
11
+ # rspec failure tracking
12
+ .rspec_status
17
13
 
18
- # Only include if you have production secrets in this file, which is no longer a Rails default
19
- # config/secrets.yml
14
+ */build/assets.tsx
20
15
 
21
- # dotenv
22
- # TODO Comment out this rule if environment variables can be committed
23
- .env
24
-
25
- ## Environment normalization:
26
- /.bundle
27
- /vendor/bundle
28
-
29
- # these should all be checked in to normalize the environment:
30
- # Gemfile.lock, .ruby-version, .ruby-gemset
31
-
32
- # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
33
- .rvmrc
34
-
35
- # if using bower-rails ignore default bower_components path bower.json files
36
- /vendor/assets/bower_components
37
- *.bowerrc
38
- bower.json
39
-
40
- # Ignore pow environment settings
41
- .powenv
42
-
43
- # Ignore Byebug command history file.
44
- .byebug_history
16
+ node_modules/
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # The Revision History
2
+
3
+ ## v0.1.0 - 2017/7/6
4
+
5
+ * Add `TsAssets.generate` to generate assets in TypeScript
6
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ts_assets.gemspec
4
+ gemspec
data/LICENSE CHANGED
@@ -1,3 +1,4 @@
1
+
1
2
  Apache License
2
3
  Version 2.0, January 2004
3
4
  http://www.apache.org/licenses/
@@ -175,27 +176,3 @@
175
176
 
176
177
  END OF TERMS AND CONDITIONS
177
178
 
178
- APPENDIX: How to apply the Apache License to your work.
179
-
180
- To apply the Apache License to your work, attach the following
181
- boilerplate notice, with the fields enclosed by brackets "{}"
182
- replaced with your own identifying information. (Don't include
183
- the brackets!) The text should be enclosed in the appropriate
184
- comment syntax for the file format. We also recommend that a
185
- file or class name and description of purpose be included on the
186
- same "printed page" as the copyright notice for easier
187
- identification within third-party archives.
188
-
189
- Copyright {yyyy} {name of copyright owner}
190
-
191
- Licensed under the Apache License, Version 2.0 (the "License");
192
- you may not use this file except in compliance with the License.
193
- You may obtain a copy of the License at
194
-
195
- http://www.apache.org/licenses/LICENSE-2.0
196
-
197
- Unless required by applicable law or agreed to in writing, software
198
- distributed under the License is distributed on an "AS IS" BASIS,
199
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
- See the License for the specific language governing permissions and
201
- limitations under the License.
data/README.md CHANGED
@@ -1 +1,134 @@
1
- # ts_assets-rails
1
+ # TsAssets
2
+
3
+ [![CircleCI](https://circleci.com/gh/bitjourney/ts_assets-rails.svg?style=svg)](https://circleci.com/gh/bitjourney/ts_assets-rails)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'ts_assets'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install ts_assets
20
+
21
+ ## Usage
22
+
23
+ ### Rake
24
+
25
+ Here is an example to generate an asset file via rake.
26
+
27
+ `lib/tasks/ts_assets.rake`:
28
+
29
+ ```ruby
30
+ # rake ts_assets:generate
31
+ namespace :ts_assets do
32
+ task generate: :environment do
33
+ TS_ASSETS_FILENAME = "client/generated/assets.tsx"
34
+ File.write TS_ASSETS_FILENAME, TsAssets.generate(include: "app/assets/images")
35
+ end
36
+ end
37
+ ```
38
+
39
+ For example, if you have `app/assets/images/svg/ruby-icon.svg` in your asset path, the generated source would be like this:
40
+
41
+ `client/generated/assets.tsx`:
42
+
43
+ ```typescript
44
+ /** svg/ruby-icon.svg */
45
+ const PATH_SVG_RUBY_ICON = "/assets/svg/ruby-icon-486fbe77b2fa535451a48ccd48587f8a1359fb373b7843e14fb5a84cb2697160.svg";
46
+
47
+ /** svg/ruby-icon */
48
+ export function ImageSvgRubyIcon(props: React.HTMLProps<HTMLImageElement>) {
49
+ return <img alt="ruby-icon"
50
+ width={128}
51
+ height={128}
52
+ src={PATH_SVG_RUBY_ICON}
53
+ srcSet={`${PATH_SVG_RUBY_ICON} 1x`}
54
+ {...props}
55
+ />;
56
+ }
57
+ ```
58
+
59
+ Then you can import `client/generated/assets.tsx` and use the imported components.
60
+
61
+ `client/components/MyComponent.tsx`:
62
+
63
+ ```typescript
64
+ import * as React from 'react';
65
+ import * as Assets from '../../generated/assets';
66
+
67
+ class MyComponent extend React.Component<any, any> {
68
+ render() {
69
+ return (
70
+ <Assets.ImageSvgRubyIcon
71
+ alt='ruby'
72
+ className='svg icon'
73
+ />
74
+ );
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### Options
80
+
81
+ All you need to do is to call `TsAssets.generate` class method with supported options.
82
+
83
+ Currently supported options are:
84
+
85
+ - `include`: the path to the assets. e.g.) "app/assets/images"
86
+
87
+ ### React Components
88
+
89
+ #### `width`, `height`
90
+
91
+ The `width` and `height` attribute is automatically set via https://github.com/sdsykes/fastimage gem.
92
+
93
+ #### `srcSet`
94
+
95
+ If you have files named like `*@1x.png` or `*@2x.png`, the `srcSet` attribute will be automatically set.
96
+
97
+ For example, if there are those images in your `include` path:
98
+
99
+ ```
100
+ app/assets/images
101
+ /webhook
102
+ slack_icon@1x.png
103
+ slack_icon@2x.png
104
+ ```
105
+
106
+ Then the generated components looks like:
107
+
108
+ ```typescript
109
+ /** webhook/slack_icon@1x.png */
110
+ const PATH_WEBHOOK_SLACK_ICON_1X = "/assets/webhook/slack_icon@1x-dd316f78fb005e28fb960482d5972fc58ab33da6836c684c1b61e7cb1b60d1e0.png";
111
+
112
+ /** webhook/slack_icon@2x.png */
113
+ const PATH_WEBHOOK_SLACK_ICON_2X = "/assets/webhook/slack_icon@2x-4f5daeae796f89bb5590bae233226cacd092c1c4e911a12061bfe12c597cc885.png";
114
+
115
+ /** webhook/slack_icon */
116
+ export function ImageWebhookSlackIcon(props: React.HTMLProps<HTMLImageElement>) {
117
+ return <img alt="slack_icon"
118
+ width={20}
119
+ src={PATH_WEBHOOK_SLACK_ICON_1X}
120
+ srcSet={`${PATH_WEBHOOK_SLACK_ICON_1X} 1x,${PATH_WEBHOOK_SLACK_ICON_2X} 2x`}
121
+ {...props}
122
+ />;
123
+ }
124
+ ```
125
+
126
+ ## Development
127
+
128
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
129
+
130
+ 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).
131
+
132
+ ## Contributing
133
+
134
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bitjourney/ts_assets-rails.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "ts_assets"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :generate do
8
+ TS_ASSETS_FILENAME = "__tests__/build/assets.tsx"
9
+ source = TsAssets.generate(include: "__tests__/assets/images")
10
+ File.write TS_ASSETS_FILENAME, source
11
+ end
12
+
13
+ task :default => :spec
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill-rule="evenodd" clip-rule="evenodd" fill="#D91404" d="M35.971 111.33c27.466 3.75 54.444 7.433 81.958 11.188-9.374-15.606-18.507-30.813-27.713-46.144l-54.245 34.956zM125.681 24.947c-2.421 3.636-4.847 7.269-7.265 10.907-8.304 12.493-16.607 24.986-24.903 37.485-.462.696-1.061 1.248-.41 2.321 8.016 13.237 15.969 26.513 23.942 39.777 1.258 2.095 2.53 4.182 4.157 6.192 1.612-32.193 3.223-64.387 4.834-96.58l-.355-.102zM16.252 66.22c.375.355 1.311.562 1.747.347 7.689-3.779 15.427-7.474 22.948-11.564 2.453-1.333 4.339-3.723 6.452-5.661 6.997-6.417 13.983-12.847 20.966-19.278.427-.395.933-.777 1.188-1.275 2.508-4.902 4.973-9.829 7.525-14.898-3.043-1.144-5.928-2.263-8.849-3.281-.396-.138-1.02.136-1.449.375-6.761 3.777-13.649 7.353-20.195 11.472-3.275 2.061-5.943 5.098-8.843 7.743-4.674 4.266-9.342 8.542-13.948 12.882-1.222 1.152-2.336 2.468-3.288 3.854-3.15 4.587-6.206 9.24-9.402 14.025 1.786 1.847 3.41 3.613 5.148 5.259zM44.354 59.949c-3.825 16.159-7.627 32.227-11.556 48.823 18.423-11.871 36.421-23.468 54.3-34.987-14.228-4.605-28.41-9.196-42.744-13.836zM120.985 25.103c-15.566 2.601-30.76 5.139-46.15 7.71 5.242 12.751 10.379 25.246 15.662 38.096 10.221-15.359 20.24-30.41 30.488-45.806zM44.996 56.644c14.017 4.55 27.755 9.01 41.892 13.6-5.25-12.79-10.32-25.133-15.495-37.737-8.815 8.059-17.498 15.999-26.397 24.137zM16.831 75.643c-4.971 11.883-9.773 23.362-14.662 35.048 9.396-.278 18.504-.547 27.925-.825-4.423-11.412-8.759-22.6-13.263-34.223zM30.424 101.739l.346-.076c3.353-13.941 6.754-27.786 10.177-42.272-7.636 3.969-14.92 7.754-22.403 11.644 3.819 9.926 7.891 20.397 11.88 30.704zM115.351 22.842c-4.459-1.181-8.918-2.366-13.379-3.539-6.412-1.686-12.829-3.351-19.237-5.052-.801-.213-1.38-.352-1.851.613-2.265 4.64-4.6 9.245-6.901 13.868-.071.143-.056.328-.111.687 13.886-2.104 27.679-4.195 41.47-6.285l.009-.292zM89.482 12.288l36.343 10.054c-2.084-5.939-4.017-11.446-6.005-17.11l-30.285 6.715-.053.341zM33.505 114.007c-4.501-.519-9.122-.042-13.687.037-3.75.063-7.5.206-11.25.323-.386.012-.771.09-1.156.506 31.003 2.866 62.005 5.732 93.007 8.6l.063-.414c-9.938-1.357-19.877-2.714-29.815-4.07-12.384-1.691-24.747-3.551-37.162-4.982zM2.782 99.994c3.995-9.27 7.973-18.546 11.984-27.809.401-.929.37-1.56-.415-2.308-1.678-1.597-3.237-3.318-5.071-5.226-2.479 12.24-4.897 24.177-7.317 36.113l.271.127c.185-.297.411-.578.548-.897zM81.522 9.841c6.737-1.738 13.572-3.097 20.367-4.613.44-.099.87-.244 1.303-.368l-.067-.332c-9.571 1.287-19.141 2.575-29.194 3.928 2.741 1.197 4.853 2.091 7.591 1.385z"/></svg>
File without changes
@@ -0,0 +1,39 @@
1
+ import { shallow } from "enzyme";
2
+ import * as React from "react";
3
+ import { renderToString } from "react-dom/server";
4
+
5
+ import * as Assets from "./build/assets";
6
+
7
+ describe("TsAssets Components", () => {
8
+ describe("with Server-Side Rendering", () => {
9
+ test("renders something", () => {
10
+ expect(renderToString(Assets.ImageSvgRubyIcon())).toBeTruthy();
11
+ expect(renderToString(Assets.ImageWebhookSlackIcon())).toBeTruthy();
12
+ });
13
+ });
14
+
15
+ describe("with Client-Side Rendering", () => {
16
+ test("renders something", () => {
17
+ const rubyIcon = shallow(
18
+ <Assets.ImageSvgRubyIcon
19
+ className="svg"
20
+ />,
21
+ );
22
+ const slackIcon = shallow(
23
+ <Assets.ImageWebhookSlackIcon
24
+ className="webhook classname"
25
+ />,
26
+ );
27
+
28
+ expect(rubyIcon.props().alt).toEqual("ruby-icon");
29
+ expect(rubyIcon.props().className).toEqual("svg");
30
+ expect(rubyIcon.props().src).toBeTruthy();
31
+ expect(rubyIcon.props().srcSet).toBeTruthy();
32
+
33
+ expect(slackIcon.props().alt).toEqual("slack_icon");
34
+ expect(slackIcon.props().className).toEqual("webhook classname");
35
+ expect(slackIcon.props().src).toBeTruthy();
36
+ expect(slackIcon.props().srcSet).toBeTruthy();
37
+ });
38
+ });
39
+ });
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ts_assets"
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(__FILE__)
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,58 @@
1
+ require 'sprockets'
2
+
3
+ module TsAssets
4
+ class ApplicationGenerator
5
+ # @return [Hash] mapping
6
+ attr_reader :mapping
7
+
8
+ # @param [String] include
9
+ def initialize(include:)
10
+ @mapping = build_mapping(include)
11
+
12
+ environment.append_path(include)
13
+ end
14
+
15
+ # @return [Sprockets::Environment]
16
+ def environment
17
+ @environment ||= Sprockets::Environment.new
18
+ end
19
+
20
+ # @return [String]
21
+ def generate
22
+ [ # header
23
+ react_content.header,
24
+
25
+ # body
26
+ const_content.body,
27
+ react_content.body,
28
+
29
+ ].join("\n")
30
+ end
31
+
32
+ # @return [TsAssets::Models::Content]
33
+ def const_content
34
+ @const_content ||= TsAssets::Generators::ConstGenerator.new(mapping).generate
35
+ end
36
+
37
+ # @return [TsAssets::Models::Content]
38
+ def react_content
39
+ @react_content ||= TsAssets::Generators::ReactGenerator.new(mapping).generate
40
+ end
41
+
42
+ # @param [String] include_path
43
+ # @return [Hash]
44
+ def build_mapping(include_path)
45
+ mapping = {}
46
+
47
+ Dir.glob("#{include_path}/**/*.*").each do |full_path|
48
+ mapping[full_path] = TsAssets::Models::AssetMetaInfo.new(
49
+ full_path: full_path,
50
+ include_path: include_path,
51
+ environment: environment,
52
+ )
53
+ end
54
+
55
+ mapping
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,29 @@
1
+ module TsAssets
2
+ module Generators
3
+ class ConstGenerator < TsAssets::ApplicationGenerator
4
+
5
+ # @return [Hash]
6
+ attr_reader :mapping
7
+
8
+ # @param [Hash] mapping
9
+ def initialize(mapping)
10
+ @mapping = mapping
11
+ end
12
+
13
+ # @return [TsAssets::Models::Content]
14
+ def generate
15
+ ts_paths = mapping.map { |full_path, asset_meta_info| constify(asset_meta_info) }
16
+ TsAssets::Models::Content.new(header: nil, body: ts_paths.join("\n"))
17
+ end
18
+
19
+ # @param [TsAssets::Models::AssetMetaInfo] meta_info
20
+ # @return [String]
21
+ def constify(meta_info)
22
+ <<~TS
23
+ /** #{meta_info.asset_path} */
24
+ const #{meta_info.normalised_path} = "/assets/#{meta_info.digest_path}";
25
+ TS
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,88 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ module TsAssets
4
+ module Generators
5
+ class ReactGenerator < TsAssets::ApplicationGenerator
6
+
7
+ # @return [Hash]
8
+ attr_reader :mapping
9
+
10
+ # @param [Hash] mapping
11
+ def initialize(mapping)
12
+ @mapping = merge_mapping_with_same_descriptors(mapping)
13
+ end
14
+
15
+ # @return [TsAssets::Models::Content]
16
+ def generate
17
+ components = mapping.map { |path, asset_meta_infos| reactify(path, asset_meta_infos) }
18
+ TsAssets::Models::Content.new(header: header, body: components.join("\n"))
19
+ end
20
+
21
+ private
22
+
23
+ # @param [Hash<String, TsAssets::Models::AssetMetaInfo>] mapping
24
+ # @return [Hash<String, [TsAssets::Models::AssetMetaInfo]>]
25
+ def merge_mapping_with_same_descriptors(mapping)
26
+ new_mapping = {}
27
+
28
+ mapping.map do |full_path, asset_meta_info|
29
+ path = asset_meta_info.asset_path_without_descriptor
30
+
31
+ if new_mapping[path].nil?
32
+ new_mapping[path] = [asset_meta_info]
33
+ else
34
+ new_mapping[path] << asset_meta_info
35
+ end
36
+ end
37
+
38
+ new_mapping
39
+ end
40
+
41
+ # @return [String]
42
+ def header
43
+ "import * as React from \"react\";\n"
44
+ end
45
+
46
+ # @param [String] path
47
+ # @param [Array<AssetMetaInfo>] asset_meta_infos
48
+ # @return [String]
49
+ def reactify(path, asset_meta_infos)
50
+ component_name = build_component_name(path)
51
+
52
+ alt = File.basename(path)
53
+ width = asset_meta_infos.first.width
54
+ height = asset_meta_infos.first.height
55
+ src = asset_meta_infos.first.normalised_path
56
+ src_set = build_src_set(asset_meta_infos)
57
+
58
+ <<~TS
59
+ /** #{path} */
60
+ export function #{component_name}(props?: React.HTMLProps<HTMLImageElement>) {
61
+ return <img alt="#{alt}"
62
+ width={#{width}}
63
+ height={#{height}}
64
+ src={#{src}}
65
+ srcSet={#{src_set}}
66
+ {...props}
67
+ />;
68
+ }
69
+ TS
70
+ end
71
+
72
+ # @param [String] asset_path
73
+ # @return [String]
74
+ def build_component_name(asset_path)
75
+ "Image#{asset_path.gsub(/[^a-zA-Z0-9_]/, '_').camelize}"
76
+ end
77
+
78
+ # @param [Array<AssetMetaInfo>] asset_meta_infos
79
+ # @return [String]
80
+ def build_src_set(asset_meta_infos)
81
+ src_set = asset_meta_infos.map do |meta_info|
82
+ "${#{meta_info.normalised_path}} #{meta_info.descriptor}"
83
+ end.join(',')
84
+ "`#{src_set}`"
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,85 @@
1
+ require 'fastimage'
2
+
3
+ module TsAssets
4
+ module Models
5
+ class AssetMetaInfo
6
+ # [String]
7
+ DESCRIPTOR_REGEX = /(.+?)@(\dx)./
8
+
9
+ # full_path is a path from the app root.
10
+ # ex) "app/assets/images/path/to/the/image.png"
11
+ # @return [String]
12
+ attr_reader :full_path
13
+
14
+ # include_path is the app asset path root.
15
+ # ex) "app/assets/images"
16
+ # @return [String]
17
+ attr_reader :include_path
18
+
19
+ # @return [Sprockets::Environment]
20
+ attr_reader :environment
21
+
22
+ # @return [String]
23
+ attr_reader :asset_path_without_descriptor
24
+
25
+ # @return [String]
26
+ attr_reader :descriptor
27
+
28
+ # @return [Numeric]
29
+ attr_reader :width
30
+
31
+ # @return [Numeric]
32
+ attr_reader :height
33
+
34
+ # @param [String] full_path
35
+ # @param [String] include_path
36
+ # @param [Sprockets::Environment] environment
37
+ def initialize(full_path:,
38
+ include_path:,
39
+ environment:)
40
+
41
+ @full_path = full_path
42
+ @include_path = include_path
43
+ @environment = environment
44
+
45
+ @width, @height = FastImage.size(full_path)
46
+
47
+ if has_descriptor?
48
+ # ex)
49
+ # dir/blog_feed.png -> #<MatchData "dir/blog_feed." 1:"dir/blog_feed">
50
+ # dir/blog_feed@2x.png -> #<MatchData "dir/blog_feed@2x." 1:"dir/blog_feed" 2:"2x">
51
+ match_data = asset_path.match(DESCRIPTOR_REGEX)
52
+ @asset_path_without_descriptor, @descriptor = match_data.captures
53
+ else
54
+ @asset_path_without_descriptor = asset_path_without_ext
55
+ @descriptor = '1x' # 1x as a default descriptor
56
+ end
57
+ end
58
+
59
+ # @return [Boolean]
60
+ def has_descriptor?
61
+ !asset_path.match(DESCRIPTOR_REGEX).nil?
62
+ end
63
+
64
+ # @return [String]
65
+ def asset_path
66
+ full_path.gsub(%r{^#{include_path}/}, '')
67
+ end
68
+
69
+ # @return [String]
70
+ def asset_path_without_ext
71
+ asset_path.chomp(File.extname(asset_path))
72
+ end
73
+
74
+ # @return [String]
75
+ def digest_path
76
+ environment.find_asset(asset_path).digest_path
77
+ end
78
+
79
+ # @return [String]
80
+ def normalised_path
81
+ "PATH_#{asset_path_without_ext.gsub(/[^a-zA-Z0-9_]/, '_').upcase}"
82
+ end
83
+ end
84
+ end
85
+ end