types_from_serializers 2.6.1 → 2.7.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 +4 -4
- data/CHANGELOG.md +20 -1
- data/lib/types_from_serializers/dsl.rb +1 -1
- data/lib/types_from_serializers/generator.rb +79 -55
- data/lib/types_from_serializers/version.rb +1 -1
- metadata +7 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0c7231c333c07c7cc5c16f2934c5c6cdc59b6633ad93b1a97f254d489f43af95
|
|
4
|
+
data.tar.gz: 9165a3c8fd6d7fb50ef7f4c26a3d6fb8d33c60cc6a2397657777f97fde10940a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 71add1bc036f519427612789520ddea812be40d1d2daac7ad1e6553d7d2d4c4d9981f94eff342dfbe951315b9c3cb91a7d6ca960d1e8139e247ff11a6e48a9c6
|
|
7
|
+
data.tar.gz: 8ddfa2c04c39db9ec8940c799a3c38494a69ead2ac4e656494b8784db4d2c4f418fa0a05338301f04bd6d3cd6ae11830e6e02f0a98897b5a19a969e59c14676c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
# [2.7.0](https://github.com/ElMassimo/types_from_serializers/compare/types_from_serializers@2.6.1...types_from_serializers@2.7.0) (2026-10-19)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* replace generated cache-key headers with content comparison ([#37](https://github.com/ElMassimo/types_from_serializers/issues/37)) ([1902824](https://github.com/ElMassimo/types_from_serializers/commit/19028240524cfff7007f04030b2cb968b856abec))
|
|
7
|
+
|
|
8
|
+
|
|
2
9
|
|
|
10
|
+
# [2.7.0](https://github.com/ElMassimo/types_from_serializers/compare/types_from_serializers@2.6.1...types_from_serializers@2.7.0) (2026-10-17)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* generated files no longer start with a `// TypesFromSerializers CacheKey` header. Files are compared by content and only written when they changed, which removes a frequent source of merge conflicts. Run `bin/rake types_from_serializers:generate` once after upgrading to drop the header from existing files.
|
|
16
|
+
* in development, only the serializers whose files were modified are regenerated, together with their subclasses and the serializers that flat-embed them, found by scanning the serializer files; adding or removing a serializer file still triggers a full pass.
|
|
17
|
+
* `SERIALIZER_TYPES_FORCE` now only controls whether the output dir is cleaned before generating.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## [2.6.1](https://github.com/ElMassimo/types_from_serializers/compare/types_from_serializers@2.6.0...types_from_serializers@2.6.1) (2026-07-03)
|
|
3
21
|
|
|
22
|
+
* Render nullable boolean columns with default value of false as not optional on rails 8.1 [#36](https://github.com/ElMassimo/types_from_serializers/pull/36)
|
|
4
23
|
|
|
5
24
|
# [2.6.0](https://github.com/ElMassimo/types_from_serializers/compare/types_from_serializers@2.5.0...types_from_serializers@2.6.0) (2026-05-06)
|
|
6
25
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "digest"
|
|
4
3
|
require "fileutils"
|
|
5
4
|
require "pathname"
|
|
6
5
|
|
|
@@ -152,7 +151,7 @@ module TypesFromSerializers
|
|
|
152
151
|
TS
|
|
153
152
|
end
|
|
154
153
|
|
|
155
|
-
|
|
154
|
+
protected
|
|
156
155
|
|
|
157
156
|
def pathname
|
|
158
157
|
@pathname ||= Pathname.new(filename)
|
|
@@ -249,7 +248,7 @@ module TypesFromSerializers
|
|
|
249
248
|
@modified.clear
|
|
250
249
|
end
|
|
251
250
|
|
|
252
|
-
|
|
251
|
+
private
|
|
253
252
|
|
|
254
253
|
def track_changes(dirs)
|
|
255
254
|
Listen.to(*dirs, only: %r{.rb$}) do |modified, added, removed|
|
|
@@ -263,8 +262,6 @@ module TypesFromSerializers
|
|
|
263
262
|
class << self
|
|
264
263
|
using SerializerRefinements
|
|
265
264
|
|
|
266
|
-
attr_reader :force_generation
|
|
267
|
-
|
|
268
265
|
# Public: Registry of named configurations for multi-app setups.
|
|
269
266
|
def configs
|
|
270
267
|
@configs ||= {}
|
|
@@ -283,19 +280,14 @@ module TypesFromSerializers
|
|
|
283
280
|
end
|
|
284
281
|
|
|
285
282
|
# Public: Generates code for all serializers in the app.
|
|
283
|
+
#
|
|
284
|
+
# force - Deletes the output dir first, so that files for serializers that
|
|
285
|
+
# were renamed or removed don't linger.
|
|
286
286
|
def generate(force: ENV["SERIALIZER_TYPES_FORCE"])
|
|
287
|
-
@force_generation = force
|
|
288
287
|
config.output_dir.rmtree if force && config.output_dir.exist?
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
else
|
|
293
|
-
generate_index_file
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
loaded_serializers.each do |serializer|
|
|
297
|
-
generate_interface_for(serializer)
|
|
298
|
-
end
|
|
288
|
+
load_serializers(all_serializer_files)
|
|
289
|
+
generate_index_file unless config.namespace
|
|
290
|
+
generate_interfaces
|
|
299
291
|
end
|
|
300
292
|
|
|
301
293
|
# Public: Generates types for all registered configurations (default + named).
|
|
@@ -306,28 +298,29 @@ module TypesFromSerializers
|
|
|
306
298
|
end
|
|
307
299
|
end
|
|
308
300
|
|
|
301
|
+
# Public: Generates code only for serializers whose files changed since the
|
|
302
|
+
# last run, which avoids loading every serializer on each reload.
|
|
303
|
+
#
|
|
304
|
+
# When files were only modified, the index can't have changed (it's derived
|
|
305
|
+
# from file names), so only the modified serializers and the ones that
|
|
306
|
+
# depend on them are regenerated. Added or removed files require a full pass.
|
|
309
307
|
def generate_changed
|
|
310
308
|
chg = changes_for(config)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
309
|
+
return unless chg.updated?
|
|
310
|
+
|
|
311
|
+
if chg.only_modified?
|
|
312
|
+
load_serializers_and_dependents(chg.modified_files)
|
|
313
|
+
generate_interfaces
|
|
314
|
+
else
|
|
315
|
+
generate(force: chg.any_removed?)
|
|
316
316
|
end
|
|
317
|
+
chg.clear
|
|
317
318
|
end
|
|
318
319
|
|
|
319
320
|
# Public: Like generate_changed but for all registered configurations.
|
|
320
321
|
def generate_all_changed
|
|
321
322
|
all_configs_list.each do |cfg|
|
|
322
|
-
|
|
323
|
-
if chg.updated?
|
|
324
|
-
with_active_config(cfg) do
|
|
325
|
-
config.output_dir.rmtree if chg.any_removed?
|
|
326
|
-
load_serializers(chg.modified_files)
|
|
327
|
-
generate
|
|
328
|
-
chg.clear
|
|
329
|
-
end
|
|
330
|
-
end
|
|
323
|
+
with_active_config(cfg) { generate_changed }
|
|
331
324
|
end
|
|
332
325
|
end
|
|
333
326
|
|
|
@@ -335,16 +328,14 @@ module TypesFromSerializers
|
|
|
335
328
|
def generate_interface_for(serializer)
|
|
336
329
|
interface = serializer.ts_interface
|
|
337
330
|
|
|
338
|
-
write_if_changed(filename: interface.filename,
|
|
331
|
+
write_if_changed(filename: interface.filename, extension: config.namespace ? "d.ts" : "ts") {
|
|
339
332
|
serializer_interface_content(interface)
|
|
340
333
|
}
|
|
341
334
|
end
|
|
342
335
|
|
|
343
336
|
# Internal: Allows to import all serializer types from a single file.
|
|
344
337
|
def generate_index_file
|
|
345
|
-
|
|
346
|
-
write_if_changed(filename: "index", cache_key: cache_key) {
|
|
347
|
-
load_serializers(all_serializer_files)
|
|
338
|
+
write_if_changed(filename: "index") {
|
|
348
339
|
serializers_index_content(loaded_serializers)
|
|
349
340
|
}
|
|
350
341
|
end
|
|
@@ -365,7 +356,7 @@ module TypesFromSerializers
|
|
|
365
356
|
all_configs_list.map { |cfg| changes_for(cfg) }
|
|
366
357
|
end
|
|
367
358
|
|
|
368
|
-
|
|
359
|
+
private
|
|
369
360
|
|
|
370
361
|
def root
|
|
371
362
|
defined?(Rails) ? Rails.root : Pathname.new(Dir.pwd)
|
|
@@ -390,6 +381,51 @@ module TypesFromSerializers
|
|
|
390
381
|
@config = saved
|
|
391
382
|
end
|
|
392
383
|
|
|
384
|
+
def generate_interfaces
|
|
385
|
+
loaded_serializers.each { |serializer| generate_interface_for(serializer) }
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Internal: Requires the given serializer files, plus every serializer file
|
|
389
|
+
# whose interface depends on a serializer they define, transitively. Rails
|
|
390
|
+
# unloads all classes before to_prepare, so subclasses and flat associations
|
|
391
|
+
# of a modified serializer would otherwise stay unloaded, and their files
|
|
392
|
+
# stale.
|
|
393
|
+
def load_serializers_and_dependents(files)
|
|
394
|
+
loaded = Set.new
|
|
395
|
+
pending = files.to_a
|
|
396
|
+
until pending.empty?
|
|
397
|
+
load_serializers(pending)
|
|
398
|
+
loaded.merge(pending)
|
|
399
|
+
names = serializer_names_defined_in(pending)
|
|
400
|
+
pending = names.empty? ? [] : serializer_files_depending_on(names).reject { |file| loaded.include?(file) }
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def serializer_names_defined_in(files)
|
|
405
|
+
base_serializers = config.base_serializers.filter_map(&:safe_constantize)
|
|
406
|
+
(base_serializers + base_serializers.flat_map(&:descendants))
|
|
407
|
+
.select { |serializer| files.include?(Object.const_source_location(serializer.name)&.first) }
|
|
408
|
+
.map { |serializer| serializer.name.demodulize }
|
|
409
|
+
.uniq
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
# Internal: Files whose serializers inherit from, or flat-embed, one of the
|
|
413
|
+
# named serializers: the only references that change a generated interface,
|
|
414
|
+
# since plain associations only import the other interface by name.
|
|
415
|
+
#
|
|
416
|
+
# A file is scanned as text rather than loaded, so this is cheap. Flat
|
|
417
|
+
# associations are matched loosely (a flat call anywhere plus the name
|
|
418
|
+
# anywhere) so that multi-line calls aren't missed.
|
|
419
|
+
def serializer_files_depending_on(names)
|
|
420
|
+
alternatives = names.map { |name| Regexp.escape(name) }.join("|")
|
|
421
|
+
inherits = /<\s*(?:\w+::)*(?:#{alternatives})\b/
|
|
422
|
+
mentions = /\b(?:#{alternatives})\b/
|
|
423
|
+
all_serializer_files.select { |file|
|
|
424
|
+
source = File.read(file)
|
|
425
|
+
source.match?(inherits) || (source.include?("flat") && source.match?(mentions))
|
|
426
|
+
}
|
|
427
|
+
end
|
|
428
|
+
|
|
393
429
|
def all_serializer_files
|
|
394
430
|
config.serializers_dirs.flat_map { |dir| Dir["#{dir}/**/*.rb"] }.sort
|
|
395
431
|
end
|
|
@@ -463,26 +499,21 @@ module TypesFromSerializers
|
|
|
463
499
|
)
|
|
464
500
|
end
|
|
465
501
|
|
|
466
|
-
# Internal: Writes
|
|
467
|
-
#
|
|
502
|
+
# Internal: Writes the file unless it already has the same content, which
|
|
503
|
+
# keeps mtimes stable so file watchers don't react to no-op generations.
|
|
468
504
|
#
|
|
469
|
-
# Yields to receive the rendered file content
|
|
470
|
-
def write_if_changed(filename:,
|
|
505
|
+
# Yields to receive the rendered file content.
|
|
506
|
+
def write_if_changed(filename:, extension: "ts")
|
|
471
507
|
filename = config.output_dir.join("#{filename}.#{extension}")
|
|
508
|
+
content = yield
|
|
509
|
+
return if filename.exist? && filename.read == content
|
|
510
|
+
|
|
472
511
|
FileUtils.mkdir_p(filename.dirname)
|
|
473
|
-
|
|
474
|
-
File.open(filename, "a+") { |file|
|
|
475
|
-
if stale?(file, cache_key_comment)
|
|
476
|
-
file.truncate(0)
|
|
477
|
-
file.write(cache_key_comment)
|
|
478
|
-
file.write(yield)
|
|
479
|
-
end
|
|
480
|
-
}
|
|
512
|
+
filename.write(content)
|
|
481
513
|
end
|
|
482
514
|
|
|
483
515
|
def serializers_index_content(serializers)
|
|
484
516
|
<<~TS
|
|
485
|
-
//
|
|
486
517
|
// DO NOT MODIFY: This file was automatically generated by TypesFromSerializers.
|
|
487
518
|
#{serializers.reject(&:inline_serializer?).map { |s|
|
|
488
519
|
"export type { default as #{s.ts_name} } from './#{s.ts_filename}'"
|
|
@@ -496,7 +527,6 @@ module TypesFromSerializers
|
|
|
496
527
|
|
|
497
528
|
def standard_interface_definition(interface)
|
|
498
529
|
<<~TS
|
|
499
|
-
//
|
|
500
530
|
// DO NOT MODIFY: This file was automatically generated by TypesFromSerializers.
|
|
501
531
|
#{interface.used_imports.join}
|
|
502
532
|
export default #{interface.as_typescript}
|
|
@@ -505,7 +535,6 @@ module TypesFromSerializers
|
|
|
505
535
|
|
|
506
536
|
def declaration_interface_definition(interface)
|
|
507
537
|
<<~TS
|
|
508
|
-
//
|
|
509
538
|
// DO NOT MODIFY: This file was automatically generated by TypesFromSerializers.
|
|
510
539
|
#{interface.used_imports.empty? ? "export {}\n" : interface.used_imports.join}
|
|
511
540
|
declare global {
|
|
@@ -515,10 +544,5 @@ module TypesFromSerializers
|
|
|
515
544
|
}
|
|
516
545
|
TS
|
|
517
546
|
end
|
|
518
|
-
|
|
519
|
-
# Internal: Returns true if the cache key has changed since the last codegen.
|
|
520
|
-
def stale?(file, cache_key_comment)
|
|
521
|
-
@force_generation || file.gets != cache_key_comment
|
|
522
|
-
end
|
|
523
547
|
end
|
|
524
548
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: types_from_serializers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Máximo Mussini
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: railties
|
|
@@ -84,16 +83,16 @@ dependencies:
|
|
|
84
83
|
name: simplecov
|
|
85
84
|
requirement: !ruby/object:Gem::Requirement
|
|
86
85
|
requirements:
|
|
87
|
-
- - "
|
|
86
|
+
- - "~>"
|
|
88
87
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0.
|
|
88
|
+
version: '0.22'
|
|
90
89
|
type: :development
|
|
91
90
|
prerelease: false
|
|
92
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
92
|
requirements:
|
|
94
|
-
- - "
|
|
93
|
+
- - "~>"
|
|
95
94
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '0.
|
|
95
|
+
version: '0.22'
|
|
97
96
|
- !ruby/object:Gem::Dependency
|
|
98
97
|
name: standard
|
|
99
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -228,7 +227,6 @@ homepage: https://github.com/ElMassimo/types_from_serializers
|
|
|
228
227
|
licenses:
|
|
229
228
|
- MIT
|
|
230
229
|
metadata: {}
|
|
231
|
-
post_install_message:
|
|
232
230
|
rdoc_options: []
|
|
233
231
|
require_paths:
|
|
234
232
|
- lib
|
|
@@ -243,8 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
243
241
|
- !ruby/object:Gem::Version
|
|
244
242
|
version: '0'
|
|
245
243
|
requirements: []
|
|
246
|
-
rubygems_version:
|
|
247
|
-
signing_key:
|
|
244
|
+
rubygems_version: 4.0.20
|
|
248
245
|
specification_version: 4
|
|
249
246
|
summary: Generate TypeScript interfaces from your JSON serializers.
|
|
250
247
|
test_files: []
|