sorbet_view 0.6.0 → 0.8.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/lib/sorbet_view/lsp/server.rb +38 -0
- data/lib/sorbet_view/version.rb +1 -1
- data/lib/tapioca/dsl/compilers/sorbet_view.rb +40 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1eb1f1ebb6f7bf77db79673819fc89044d6b998ea2ee1ba069700453d87cc1cd
|
|
4
|
+
data.tar.gz: 40fefcdbe8af51be0b75f3f3dee6a4f31524439424c90468b80c779422b5054f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c468a4efb4b9ed4d2965979d326d885e807b11bb4b6386d26ea08f580db59b2638dd34387f0b82e51d071fbecf9b952dd5015c4be1029e8abb6c457144c86111
|
|
7
|
+
data.tar.gz: f1ec4ae5f31c306ffc1321c7fd56a98c25730858b5fa230bfc4cb63ce221eee4a964f52e01a0e7bf838cd7107dedb6583d7228d4aa7cbb59bc2e3f7863977dcf
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
require 'listen'
|
|
4
5
|
require 'logger'
|
|
5
6
|
require 'set'
|
|
6
7
|
|
|
@@ -44,6 +45,7 @@ module SorbetView
|
|
|
44
45
|
@logger.error("Server error: #{e.message}\n#{e.backtrace&.join("\n")}")
|
|
45
46
|
ensure
|
|
46
47
|
@file_watcher&.stop
|
|
48
|
+
@ivar_json_watcher&.stop
|
|
47
49
|
@sorbet.stop
|
|
48
50
|
@logger.info('SorbetView LSP server stopped')
|
|
49
51
|
end
|
|
@@ -568,10 +570,46 @@ module SorbetView
|
|
|
568
570
|
end
|
|
569
571
|
@file_watcher.start
|
|
570
572
|
@logger.info("FileWatcher started for: #{@config.input_dirs.join(', ')}")
|
|
573
|
+
|
|
574
|
+
start_ivar_json_watcher
|
|
571
575
|
rescue => e
|
|
572
576
|
@logger.warn("Failed to start FileWatcher: #{e.message}")
|
|
573
577
|
end
|
|
574
578
|
|
|
579
|
+
sig { void }
|
|
580
|
+
def start_ivar_json_watcher
|
|
581
|
+
json_path = File.join(@config.output_dir, '.defined_ivars.json')
|
|
582
|
+
dir = File.dirname(json_path)
|
|
583
|
+
return unless Dir.exist?(dir)
|
|
584
|
+
|
|
585
|
+
@ivar_json_watcher = T.let(nil, T.untyped)
|
|
586
|
+
@ivar_json_watcher = Listen.to(dir, only: /\.defined_ivars\.json$/) do |modified, added, _removed|
|
|
587
|
+
next if (modified + added).empty?
|
|
588
|
+
|
|
589
|
+
@logger.info('.defined_ivars.json changed — recompiling all templates')
|
|
590
|
+
@compiler.invalidate_ivar_cache!
|
|
591
|
+
recompile_all_templates
|
|
592
|
+
end
|
|
593
|
+
@ivar_json_watcher.start
|
|
594
|
+
@logger.info("Watching #{json_path} for ivar mapping changes")
|
|
595
|
+
rescue => e
|
|
596
|
+
@logger.warn("Failed to start ivar JSON watcher: #{e.message}")
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
sig { void }
|
|
600
|
+
def recompile_all_templates
|
|
601
|
+
templates = FileSystem::ProjectScanner.scan(@config)
|
|
602
|
+
templates.each do |path|
|
|
603
|
+
source = File.read(path)
|
|
604
|
+
result = @compiler.compile(path, source)
|
|
605
|
+
@output_manager.write(result)
|
|
606
|
+
@position_translator.register(path, result.source_map)
|
|
607
|
+
notify_sorbet_template_changed(path, result)
|
|
608
|
+
end
|
|
609
|
+
rescue => e
|
|
610
|
+
@logger.error("recompile_all_templates error: #{e.message}")
|
|
611
|
+
end
|
|
612
|
+
|
|
575
613
|
sig { params(modified: T::Array[String], added: T::Array[String], removed: T::Array[String]).void }
|
|
576
614
|
def handle_file_changes(modified, added, removed)
|
|
577
615
|
(modified + added).each do |path|
|
data/lib/sorbet_view/version.rb
CHANGED
|
@@ -40,6 +40,7 @@ module Tapioca
|
|
|
40
40
|
|
|
41
41
|
generate_ivar_mapping(controllers)
|
|
42
42
|
process_components
|
|
43
|
+
compile_all_templates
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
private
|
|
@@ -80,17 +81,22 @@ module Tapioca
|
|
|
80
81
|
mapping_path = File.join(config.output_dir, '.defined_ivars.json')
|
|
81
82
|
FileUtils.mkdir_p(File.dirname(mapping_path))
|
|
82
83
|
File.write(mapping_path, JSON.pretty_generate(mapping))
|
|
83
|
-
rescue StandardError
|
|
84
|
-
|
|
84
|
+
rescue StandardError => e
|
|
85
|
+
$stderr.puts "[SorbetView] generate_ivar_mapping failed: #{e.class}: #{e.message}"
|
|
86
|
+
$stderr.puts e.backtrace&.first(5)&.join("\n")
|
|
85
87
|
end
|
|
86
88
|
|
|
87
89
|
# Resolve view directories from Rails, relative to project root
|
|
90
|
+
# Only include directories within the project (exclude gem paths)
|
|
88
91
|
sig { returns(T::Array[String]) }
|
|
89
92
|
def resolve_view_dirs
|
|
90
93
|
if defined?(::ActionController::Base) && ::ActionController::Base.respond_to?(:view_paths)
|
|
94
|
+
cwd = Dir.pwd
|
|
91
95
|
::ActionController::Base.view_paths.paths.filter_map do |p|
|
|
92
96
|
path_str = p.to_s
|
|
93
|
-
|
|
97
|
+
next unless path_str.start_with?(cwd)
|
|
98
|
+
|
|
99
|
+
relative = path_str.sub(%r{^#{Regexp.escape(cwd)}/?}, '')
|
|
94
100
|
relative unless relative.empty?
|
|
95
101
|
end
|
|
96
102
|
else
|
|
@@ -134,11 +140,34 @@ module Tapioca
|
|
|
134
140
|
next if name.nil? || name.empty?
|
|
135
141
|
next if type.nil? || type.empty?
|
|
136
142
|
|
|
137
|
-
result[name] = type
|
|
143
|
+
result[name] = normalize_type(type)
|
|
138
144
|
end
|
|
139
145
|
result
|
|
140
146
|
end
|
|
141
147
|
|
|
148
|
+
# Compile all templates after generating ivar mapping
|
|
149
|
+
sig { void }
|
|
150
|
+
def compile_all_templates
|
|
151
|
+
config = ::SorbetView::Configuration.load
|
|
152
|
+
compiler = ::SorbetView::Compiler::TemplateCompiler.new(config: config)
|
|
153
|
+
output_manager = ::SorbetView::FileSystem::OutputManager.new(config.output_dir)
|
|
154
|
+
|
|
155
|
+
templates = ::SorbetView::FileSystem::ProjectScanner.scan(config)
|
|
156
|
+
templates.each do |path|
|
|
157
|
+
result = compiler.compile_file(path)
|
|
158
|
+
output_manager.write(result)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
component_compiler = ::SorbetView::Compiler::ComponentCompiler.new(config: config)
|
|
162
|
+
components = ::SorbetView::FileSystem::ProjectScanner.scan_components(config)
|
|
163
|
+
components.each do |path|
|
|
164
|
+
results = component_compiler.compile_file(path)
|
|
165
|
+
results.each { |result| output_manager.write(result) }
|
|
166
|
+
end
|
|
167
|
+
rescue StandardError => e
|
|
168
|
+
$stderr.puts "[SorbetView] compile_all_templates failed: #{e.class}: #{e.message}"
|
|
169
|
+
end
|
|
170
|
+
|
|
142
171
|
sig { void }
|
|
143
172
|
def process_components
|
|
144
173
|
config = ::SorbetView::Configuration.load
|
|
@@ -287,6 +316,13 @@ module Tapioca
|
|
|
287
316
|
[]
|
|
288
317
|
end
|
|
289
318
|
|
|
319
|
+
# Normalize Sorbet literal types to their base types
|
|
320
|
+
# e.g. String("test") → String, Integer(42) → Integer, Symbol(:foo) → Symbol
|
|
321
|
+
sig { params(type: String).returns(String) }
|
|
322
|
+
def normalize_type(type)
|
|
323
|
+
type.gsub(/\b([A-Z]\w*)\(.*?\)/) { $1 }
|
|
324
|
+
end
|
|
325
|
+
|
|
290
326
|
sig { params(str: String).returns(String) }
|
|
291
327
|
def camelize(str)
|
|
292
328
|
str.split('_').map(&:capitalize).join
|