ts_assets 0.0.0 → 0.1.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 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