js_from_routes 2.0.0 → 2.0.6

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
  SHA256:
3
- metadata.gz: 120fa96855c034323a664b851019f5d1df7bd418de5578af5fa074b80451ca3e
4
- data.tar.gz: 7a39747149294d21f74568296c4cab44f2e93ea172c85bad0d721e686c16ce74
3
+ metadata.gz: 9053499de4df17e1ef042b1b54e4c172ab8ab94b2c0c353e6b8035efa8d3c0e5
4
+ data.tar.gz: 6fc5926dfcf3b0f94bde9c7176af31522c36bf206d6636563415143655414c3e
5
5
  SHA512:
6
- metadata.gz: 77d1b1b6bef1a59d68bc1452dcb8ade3de38123ae907687bab9017347897a440b6f8b57ce6874f46d8873c6fcddf0e0480e38aa46a02fd91c39600c5c9980eca
7
- data.tar.gz: 993bf91cfd887d1c645313b305f2f5d1c095ed31f3232d34b7dcbf575eefafdbadaeb3fb6948e00f1b1614e8f38e86217dd6c5bb2c55c508df771584441bde53
6
+ metadata.gz: 30c30f206f148dcb9ca5dac38f4f5eb07d0b6d49f5ca4c87dd4e358a3b7af12ce1fe0750cb0554c91c0655c2cadcaf6ad47438a35b9ee9678eaf3cf4945ba2d5
7
+ data.tar.gz: 2515d4737e9202d93e99b3f573f43667d2beea1dc61a2fafdabf2a3752478e36289fd742649fe55396185604b3ff8b04d0742048e6d8ec7ef7530627107e0931
data/CHANGELOG.md CHANGED
@@ -1,3 +1,54 @@
1
+ ## [2.0.6](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.5...js_from_routes@2.0.6) (2022-05-25)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * should not attempt to export routes without controllers ([47f8f70](https://github.com/ElMassimo/js_from_routes/commit/47f8f70b0db98baa240470f8b2b891a730499518))
7
+
8
+
9
+
10
+ ## [2.0.5](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.4...js_from_routes@2.0.5) (2021-09-02)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * ensure :export is not added as a required default in routes ([40126ac](https://github.com/ElMassimo/js_from_routes/commit/40126ac27caeee33abef1c7067ba1db88ea03660))
16
+
17
+
18
+
19
+ ## [2.0.4](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.3...js_from_routes@2.0.4) (2021-03-16)
20
+
21
+ ### Features
22
+
23
+ * Allow importing individual helpers from "~/api" by adding exports ([2dfb8a2](https://github.com/ElMassimo/js_from_routes/commit/2dfb8a27d182376d75f0b037258bc772553e43f3)). Thanks @matias-capeletto!
24
+
25
+
26
+ ## [2.0.3](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.2...js_from_routes@2.0.3) (2021-03-16)
27
+
28
+
29
+ ### Bug Fixes
30
+
31
+ * Ensure changing the client library triggers code generation ([6cf2bdf](https://github.com/ElMassimo/js_from_routes/commit/6cf2bdf4896dafe0d1e80668551665c46bfcadc6))
32
+
33
+
34
+ ### Features
35
+
36
+ * Allow passing JS_FROM_ROUTES_FORCE=true to ignore cache keys ([8a6d2a8](https://github.com/ElMassimo/js_from_routes/commit/8a6d2a807e0a9926c6b24e1fc9127f917ec0ed5d))
37
+
38
+
39
+
40
+ ## [2.0.2](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.1...js_from_routes@2.0.2) (2021-03-14)
41
+
42
+ ### Improvements
43
+
44
+ - Remove underscores from namespaced controllers in global file ([90fdcc2](https://github.com/ElMassimo/js_from_routes/commit/90fdcc2))
45
+
46
+ ## [2.0.1](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.0...js_from_routes@2.0.1) (2021-03-14)
47
+
48
+ ### Features ⚡️
49
+
50
+ - Enable generation of index combining and exporting all helpers (#9)
51
+
1
52
  # [2.0.0](https://github.com/ElMassimo/js_from_routes/compare/v1.0.3...js_from_routes@2.0.0) (2021-03-13)
2
53
 
3
54
  ### Features ⚡️
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2021 Máximo Mussini
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -9,11 +9,11 @@ require "pathname"
9
9
  # Generates one file per controller, and one function per route.
10
10
  module JsFromRoutes
11
11
  # Internal: Helper class used as a presenter for the routes template.
12
- class Routes
12
+ class ControllerRoutes
13
13
  attr_reader :routes
14
14
 
15
- def initialize(routes, config)
16
- @config = config
15
+ def initialize(controller, routes, config)
16
+ @controller, @config = controller, config
17
17
  @routes = routes
18
18
  .uniq { |route| route.requirements.fetch(:action) }
19
19
  .map { |route| Route.new(route, config.helper_mappings) }
@@ -22,7 +22,7 @@ module JsFromRoutes
22
22
  # Public: Used to check whether the file should be generated again, changes
23
23
  # based on the configuration, and route definition.
24
24
  def cache_key
25
- Digest::MD5.hexdigest(routes.map(&:inspect).join + [File.read(@config.template_path), @config.helper_mappings.inspect].join)
25
+ routes.map(&:inspect).join + [File.read(@config.template_path), @config.helper_mappings.inspect, @config.client_library].join
26
26
  end
27
27
 
28
28
  # Public: Exposes the preferred import library to the generator.
@@ -30,10 +30,24 @@ module JsFromRoutes
30
30
  @config.client_library
31
31
  end
32
32
 
33
- # Internal: By performing the evaluation here, we ensure only "routes" is
34
- # exposed to the ERB template as a local variable.
35
- def evaluate(compiled_template)
36
- instance_eval(compiled_template)
33
+ # Internal: Name of the JS file with helpers for the the given controller.
34
+ def filename
35
+ @config.output_folder.join(basename)
36
+ end
37
+
38
+ # Public: Name of the JS file with helpers for the the given controller.
39
+ def import_filename
40
+ @config.output_folder.basename.join((basename.split(".")[0]).to_s)
41
+ end
42
+
43
+ # Public: Name of the file as a valid JS variable.
44
+ def js_name
45
+ @controller.camelize(:lower).tr(":", "")
46
+ end
47
+
48
+ # Internal: The base name of the JS file to be written.
49
+ def basename
50
+ "#{@controller.camelize}#{@config.file_suffix}".tr_s(":", "/")
37
51
  end
38
52
  end
39
53
 
@@ -70,6 +84,48 @@ module JsFromRoutes
70
84
  end
71
85
  end
72
86
 
87
+ # Internal: Represents a compiled template that can write itself to a file.
88
+ class Template
89
+ def initialize(template_path)
90
+ # NOTE: The compiled ERB template, used to generate JS code.
91
+ @compiled_template = Erubi::Engine.new(File.read(template_path), filename: template_path).src
92
+ end
93
+
94
+ # Public: Checks if the cache is fresh, or renders the template with the
95
+ # specified variables, and writes the updated result to a file.
96
+ def write_if_changed(object)
97
+ write_file_if_changed(object.filename, object.cache_key) { render_template(object) }
98
+ end
99
+
100
+ private
101
+
102
+ # Internal: Returns a String with the generated JS code.
103
+ def render_template(object)
104
+ object.instance_eval(@compiled_template)
105
+ end
106
+
107
+ # Internal: Returns true if the cache key has changed since the last codegen.
108
+ def stale?(file, cache_key_comment)
109
+ ENV["JS_FROM_ROUTES_FORCE"] || file.gets != cache_key_comment
110
+ end
111
+
112
+ # Internal: Writes if the file does not exist or the cache key has changed.
113
+ # The cache strategy consists of a comment on the first line of the file.
114
+ #
115
+ # Yields to receive the rendered file content when it needs to.
116
+ def write_file_if_changed(name, cache_key)
117
+ FileUtils.mkdir_p(name.dirname)
118
+ cache_key_comment = "// JsFromRoutes CacheKey #{Digest::MD5.hexdigest(cache_key)}\n"
119
+ File.open(name, "a+") { |file|
120
+ if stale?(file, cache_key_comment)
121
+ file.truncate(0)
122
+ file.write(cache_key_comment)
123
+ file.write(yield)
124
+ end
125
+ }
126
+ end
127
+ end
128
+
73
129
  class << self
74
130
  # Public: Configuration of the code generator.
75
131
  def config
@@ -82,67 +138,58 @@ module JsFromRoutes
82
138
  def generate!(app_or_routes = Rails.application)
83
139
  raise ArgumentError, "A Rails app must be defined, or you must specify a custom `output_folder`" if config.output_folder.blank?
84
140
  rails_routes = app_or_routes.is_a?(::Rails::Engine) ? app_or_routes.routes.routes : app_or_routes
85
- @compiled_template = nil # Clear on every code reload in case the template changed.
86
- exported_routes_by_controller(rails_routes).each do |controller, controller_routes|
87
- routes = Routes.new(controller_routes, config)
88
- write_if_changed(filename_for(controller), routes.cache_key) { render_template(routes) }
89
- end
141
+ generate_files exported_routes_by_controller(rails_routes)
90
142
  end
91
143
 
92
144
  private
93
145
 
146
+ def generate_files(exported_routes)
147
+ template = Template.new(config.template_path)
148
+ generate_file_for_all exported_routes.map { |controller, routes|
149
+ ControllerRoutes.new(controller, routes, config).tap do |routes|
150
+ template.write_if_changed routes
151
+ end
152
+ }
153
+ end
154
+
155
+ def generate_file_for_all(routes)
156
+ return unless config.all_helpers_file && !routes.empty?
157
+
158
+ preferred_extension = File.extname(config.file_suffix)
159
+ index_file = config.all_helpers_file == true ? "index#{preferred_extension}" : config.all_helpers_file
160
+
161
+ Template.new(config.template_all_path).write_if_changed OpenStruct.new(
162
+ cache_key: routes.map(&:import_filename).join + File.read(config.template_all_path),
163
+ filename: config.output_folder.join("all#{preferred_extension}"),
164
+ helpers: routes,
165
+ )
166
+ Template.new(config.template_index_path).write_if_changed OpenStruct.new(
167
+ cache_key: File.read(config.template_index_path),
168
+ filename: config.output_folder.join(index_file),
169
+ )
170
+ end
171
+
94
172
  def default_config(root)
95
173
  dir = %w[frontend packs javascript assets].find { |dir| root.join("app", dir).exist? }
96
174
  {
175
+ all_helpers_file: true,
97
176
  client_library: "@js-from-routes/client",
98
177
  file_suffix: "Api.js",
99
178
  helper_mappings: {"index" => "list", "show" => "get"},
100
179
  output_folder: root.join("app", dir, "api"),
101
180
  template_path: File.expand_path("template.js.erb", __dir__),
181
+ template_all_path: File.expand_path("template_all.js.erb", __dir__),
182
+ template_index_path: File.expand_path("template_index.js.erb", __dir__),
102
183
  }
103
184
  end
104
185
 
105
186
  # Internal: Returns exported routes grouped by controller name.
106
187
  def exported_routes_by_controller(routes)
107
188
  routes.select { |route|
108
- route.defaults.fetch(:export, false)
189
+ route.defaults.fetch(:export, false) && route.requirements[:controller]
109
190
  }.group_by { |route|
110
191
  route.requirements.fetch(:controller)
111
192
  }
112
193
  end
113
-
114
- # Internal: Name of the JS file with helpers for the the given controller.
115
- def filename_for(controller)
116
- config.output_folder.join("#{controller.camelize}#{config.file_suffix}".tr_s(":", "/"))
117
- end
118
-
119
- # Internal: Returns a String with the JS generated for a controller's routes.
120
- def render_template(routes)
121
- routes.evaluate(compiled_template)
122
- end
123
-
124
- # Internal: Returns the compiled ERB to generate JS from a set of routes.
125
- def compiled_template
126
- @compiled_template ||= begin
127
- template = File.read(config.template_path)
128
- Erubi::Engine.new(template, filename: config.template_path).src
129
- end
130
- end
131
-
132
- # Internal: Writes if the file does not exist or the cache key has changed.
133
- # The cache strategy consists of a comment on the first line of the file.
134
- #
135
- # Yields to receive the rendered file content when it needs to.
136
- def write_if_changed(name, cache_key)
137
- FileUtils.mkdir_p(name.dirname)
138
- cache_key_comment = "// JsFromRoutes CacheKey #{cache_key}\n"
139
- File.open(name, "a+") { |file|
140
- if file.gets != cache_key_comment
141
- file.truncate(0)
142
- file.write(cache_key_comment)
143
- file.write(yield)
144
- end
145
- }
146
- end
147
194
  end
148
195
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rails/railtie"
4
+
3
5
  # NOTE: Not strictly required, but it helps to simplify the setup.
4
6
  class JsFromRoutes::Railtie < Rails::Railtie
5
7
  railtie_name :js_from_routes
@@ -22,4 +24,14 @@ class JsFromRoutes::Railtie < Rails::Railtie
22
24
  end
23
25
  end
24
26
  end
27
+
28
+ # Prevents Rails from interpreting the :export option as a required default,
29
+ # which would cause controller tests to fail.
30
+ initializer "js_from_routes.required_defaults" do |app|
31
+ ActionDispatch::Journey::Route.prepend Module.new {
32
+ def required_default?(key)
33
+ key == :export ? false : super
34
+ end
35
+ }
36
+ end
25
37
  end
@@ -3,7 +3,7 @@
3
3
  import { definePathHelper } from '<%= client_library %>'
4
4
 
5
5
  export default {
6
- <% routes.each_with_index do |route, index| %>
6
+ <% routes.each do |route| %>
7
7
  <%= route.helper %>: definePathHelper('<%= route.verb %>', '<%= route.path %>'),
8
8
  <% end %>
9
9
  }
@@ -0,0 +1,5 @@
1
+ //
2
+ // DO NOT MODIFY: This file was automatically generated by JsFromRoutes.
3
+ <% helpers.each do |helper| %>
4
+ export { default as <%= helper.js_name %> } from '~/<%= helper.import_filename %>'
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ //
2
+ // DO NOT MODIFY: This file was automatically generated by JsFromRoutes.
3
+ import * as helpers from '~/api/all'
4
+ export * from '~/api/all'
5
+ export default helpers
@@ -4,5 +4,5 @@
4
4
  # Generates one file per controller, and one function per route.
5
5
  module JsFromRoutes
6
6
  # Public: This library adheres to semantic versioning.
7
- VERSION = "2.0.0"
7
+ VERSION = "2.0.6"
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: js_from_routes
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Máximo Mussini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-13 00:00:00.000000000 Z
11
+ date: 2022-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -139,11 +139,14 @@ extra_rdoc_files:
139
139
  - README.md
140
140
  files:
141
141
  - CHANGELOG.md
142
+ - LICENSE.txt
142
143
  - README.md
143
144
  - lib/js_from_routes.rb
144
145
  - lib/js_from_routes/generator.rb
145
146
  - lib/js_from_routes/railtie.rb
146
147
  - lib/js_from_routes/template.js.erb
148
+ - lib/js_from_routes/template_all.js.erb
149
+ - lib/js_from_routes/template_index.js.erb
147
150
  - lib/js_from_routes/version.rb
148
151
  homepage: https://github.com/ElMassimo/js_from_routes
149
152
  licenses:
@@ -164,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
167
  - !ruby/object:Gem::Version
165
168
  version: '0'
166
169
  requirements: []
167
- rubygems_version: 3.1.4
170
+ rubygems_version: 3.2.32
168
171
  signing_key:
169
172
  specification_version: 4
170
173
  summary: Generate JS automatically from Rails routes.