konpeito 0.2.4 → 0.3.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.
@@ -0,0 +1,298 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Konpeito
4
+ module Commands
5
+ # Completion command - generates shell completion scripts
6
+ class CompletionCommand < BaseCommand
7
+ def self.command_name
8
+ "completion"
9
+ end
10
+
11
+ def self.description
12
+ "Generate shell completion scripts (bash, zsh, fish)"
13
+ end
14
+
15
+ def run
16
+ parse_options!
17
+
18
+ shell = args.first
19
+ unless shell
20
+ error("No shell specified. Usage: konpeito completion <bash|zsh|fish>")
21
+ end
22
+
23
+ case shell.downcase
24
+ when "bash"
25
+ puts bash_completion
26
+ when "zsh"
27
+ puts zsh_completion
28
+ when "fish"
29
+ puts fish_completion
30
+ else
31
+ error("Unsupported shell: #{shell}. Supported: bash, zsh, fish")
32
+ end
33
+ end
34
+
35
+ protected
36
+
37
+ def banner
38
+ <<~BANNER.chomp
39
+ Usage: konpeito completion <shell>
40
+
41
+ Generate shell completion scripts.
42
+
43
+ Supported shells: bash, zsh, fish
44
+
45
+ Examples:
46
+ eval "$(konpeito completion bash)" # Add to .bashrc
47
+ eval "$(konpeito completion zsh)" # Add to .zshrc
48
+ konpeito completion fish | source # Add to config.fish
49
+ BANNER
50
+ end
51
+
52
+ private
53
+
54
+ SUBCOMMANDS = %w[build run check init test fmt watch deps doctor completion].freeze
55
+
56
+ BUILD_OPTIONS = %w[
57
+ -o --output -f --format -g --debug -p --profile -v --verbose
58
+ -I --require-path --rbs --incremental --clean-cache --inline
59
+ --target --run --emit-ir --classpath --lib --stats -q --quiet
60
+ --no-color -h --help
61
+ ].freeze
62
+
63
+ TARGET_VALUES = %w[native jvm].freeze
64
+
65
+ def bash_completion
66
+ <<~'BASH'
67
+ _konpeito() {
68
+ local cur prev commands
69
+ COMPREPLY=()
70
+ cur="${COMP_WORDS[COMP_CWORD]}"
71
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
72
+ commands="build run check init test fmt watch deps doctor completion"
73
+
74
+ # Complete subcommand
75
+ if [[ ${COMP_CWORD} -eq 1 ]]; then
76
+ COMPREPLY=( $(compgen -W "${commands} --help --version" -- "${cur}") )
77
+ return 0
78
+ fi
79
+
80
+ local subcmd="${COMP_WORDS[1]}"
81
+
82
+ # Complete --target values
83
+ if [[ "${prev}" == "--target" ]]; then
84
+ COMPREPLY=( $(compgen -W "native jvm" -- "${cur}") )
85
+ return 0
86
+ fi
87
+
88
+ # Complete shell names for completion command
89
+ if [[ "${subcmd}" == "completion" && ${COMP_CWORD} -eq 2 ]]; then
90
+ COMPREPLY=( $(compgen -W "bash zsh fish" -- "${cur}") )
91
+ return 0
92
+ fi
93
+
94
+ # Complete options per subcommand
95
+ case "${subcmd}" in
96
+ build)
97
+ if [[ "${cur}" == -* ]]; then
98
+ COMPREPLY=( $(compgen -W "-o --output -f --format -g --debug -p --profile -v --verbose -I --require-path --rbs --incremental --clean-cache --inline --target --run --emit-ir --classpath --lib --stats -q --quiet --no-color -h --help" -- "${cur}") )
99
+ else
100
+ COMPREPLY=( $(compgen -f -X '!*.rb' -- "${cur}") )
101
+ fi
102
+ ;;
103
+ run)
104
+ if [[ "${cur}" == -* ]]; then
105
+ COMPREPLY=( $(compgen -W "--target --classpath --rbs -I --require-path --inline -v --verbose --no-color -h --help" -- "${cur}") )
106
+ else
107
+ COMPREPLY=( $(compgen -f -X '!*.rb' -- "${cur}") )
108
+ fi
109
+ ;;
110
+ check)
111
+ if [[ "${cur}" == -* ]]; then
112
+ COMPREPLY=( $(compgen -W "-v --verbose --rbs -I --require-path --no-color -h --help" -- "${cur}") )
113
+ else
114
+ COMPREPLY=( $(compgen -f -X '!*.rb' -- "${cur}") )
115
+ fi
116
+ ;;
117
+ init)
118
+ COMPREPLY=( $(compgen -W "-h --help" -- "${cur}") )
119
+ ;;
120
+ test|fmt|watch|deps|doctor)
121
+ COMPREPLY=( $(compgen -W "-v --verbose --no-color -h --help" -- "${cur}") )
122
+ ;;
123
+ esac
124
+ return 0
125
+ }
126
+ complete -F _konpeito konpeito
127
+ BASH
128
+ end
129
+
130
+ def zsh_completion
131
+ <<~'ZSH'
132
+ #compdef konpeito
133
+
134
+ _konpeito() {
135
+ local -a commands
136
+ commands=(
137
+ 'build:Compile Ruby source to native code'
138
+ 'run:Build and run a Konpeito program'
139
+ 'check:Type check only (no code generation)'
140
+ 'init:Initialize a new Konpeito project'
141
+ 'test:Run tests'
142
+ 'fmt:Format source files'
143
+ 'watch:Watch files and recompile on changes'
144
+ 'deps:Analyze dependencies'
145
+ 'doctor:Check environment setup'
146
+ 'completion:Generate shell completion scripts'
147
+ )
148
+
149
+ if (( CURRENT == 2 )); then
150
+ _describe 'command' commands
151
+ return
152
+ fi
153
+
154
+ case "${words[2]}" in
155
+ build)
156
+ _arguments \
157
+ '-o[Output file name]:file:_files' \
158
+ '--output[Output file name]:file:_files' \
159
+ '-f[Output format]:format:(cruby_ext standalone)' \
160
+ '--format[Output format]:format:(cruby_ext standalone)' \
161
+ '-g[Generate debug info (DWARF)]' \
162
+ '--debug[Generate debug info (DWARF)]' \
163
+ '-p[Enable profiling]' \
164
+ '--profile[Enable profiling]' \
165
+ '-v[Verbose output]' \
166
+ '--verbose[Verbose output]' \
167
+ '-I[Add require search path]:path:_directories' \
168
+ '--require-path[Add require search path]:path:_directories' \
169
+ '--rbs[RBS type definition file]:file:_files -g "*.rbs"' \
170
+ '--incremental[Enable incremental compilation]' \
171
+ '--clean-cache[Clear compilation cache]' \
172
+ '--inline[Use inline RBS annotations]' \
173
+ '--target[Target platform]:target:(native jvm)' \
174
+ '--run[Run after building]' \
175
+ '--emit-ir[Emit intermediate representation]' \
176
+ '--classpath[JVM classpath]:path:_files' \
177
+ '--lib[Build as library JAR]' \
178
+ '--stats[Show optimization statistics]' \
179
+ '-q[Suppress non-error output]' \
180
+ '--quiet[Suppress non-error output]' \
181
+ '--no-color[Disable colored output]' \
182
+ '-h[Show help]' \
183
+ '--help[Show help]' \
184
+ '*:source file:_files -g "*.rb"'
185
+ ;;
186
+ run)
187
+ _arguments \
188
+ '--target[Target platform]:target:(native jvm)' \
189
+ '--classpath[JVM classpath]:path:_files' \
190
+ '--rbs[RBS type definition file]:file:_files -g "*.rbs"' \
191
+ '-I[Add require search path]:path:_directories' \
192
+ '--require-path[Add require search path]:path:_directories' \
193
+ '--inline[Use inline RBS annotations]' \
194
+ '-v[Verbose output]' \
195
+ '--verbose[Verbose output]' \
196
+ '--no-color[Disable colored output]' \
197
+ '-h[Show help]' \
198
+ '--help[Show help]' \
199
+ '*:source file:_files -g "*.rb"'
200
+ ;;
201
+ check)
202
+ _arguments \
203
+ '-v[Verbose output]' \
204
+ '--verbose[Verbose output]' \
205
+ '--rbs[RBS type definition file]:file:_files -g "*.rbs"' \
206
+ '-I[Add require search path]:path:_directories' \
207
+ '--require-path[Add require search path]:path:_directories' \
208
+ '--no-color[Disable colored output]' \
209
+ '-h[Show help]' \
210
+ '--help[Show help]' \
211
+ '*:source file:_files -g "*.rb"'
212
+ ;;
213
+ completion)
214
+ _arguments \
215
+ '1:shell:(bash zsh fish)'
216
+ ;;
217
+ *)
218
+ _arguments \
219
+ '-v[Verbose output]' \
220
+ '--verbose[Verbose output]' \
221
+ '--no-color[Disable colored output]' \
222
+ '-h[Show help]' \
223
+ '--help[Show help]'
224
+ ;;
225
+ esac
226
+ }
227
+
228
+ _konpeito "$@"
229
+ ZSH
230
+ end
231
+
232
+ def fish_completion
233
+ <<~'FISH'
234
+ # konpeito completions for fish shell
235
+
236
+ # Disable file completions by default
237
+ complete -c konpeito -f
238
+
239
+ # Subcommands
240
+ complete -c konpeito -n '__fish_use_subcommand' -a 'build' -d 'Compile Ruby source to native code'
241
+ complete -c konpeito -n '__fish_use_subcommand' -a 'run' -d 'Build and run a Konpeito program'
242
+ complete -c konpeito -n '__fish_use_subcommand' -a 'check' -d 'Type check only'
243
+ complete -c konpeito -n '__fish_use_subcommand' -a 'init' -d 'Initialize a new project'
244
+ complete -c konpeito -n '__fish_use_subcommand' -a 'test' -d 'Run tests'
245
+ complete -c konpeito -n '__fish_use_subcommand' -a 'fmt' -d 'Format source files'
246
+ complete -c konpeito -n '__fish_use_subcommand' -a 'watch' -d 'Watch and recompile'
247
+ complete -c konpeito -n '__fish_use_subcommand' -a 'deps' -d 'Analyze dependencies'
248
+ complete -c konpeito -n '__fish_use_subcommand' -a 'doctor' -d 'Check environment'
249
+ complete -c konpeito -n '__fish_use_subcommand' -a 'completion' -d 'Generate shell completions'
250
+
251
+ # Global options
252
+ complete -c konpeito -n '__fish_use_subcommand' -l help -s h -d 'Show help'
253
+ complete -c konpeito -n '__fish_use_subcommand' -l version -s V -d 'Show version'
254
+
255
+ # build options
256
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -s o -l output -r -d 'Output file name'
257
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -s f -l format -r -a 'cruby_ext standalone' -d 'Output format'
258
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -s g -l debug -d 'Generate debug info'
259
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -s p -l profile -d 'Enable profiling'
260
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -s v -l verbose -d 'Verbose output'
261
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -s I -l require-path -r -d 'Add require search path'
262
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l rbs -r -d 'RBS type definition file'
263
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l incremental -d 'Incremental compilation'
264
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l clean-cache -d 'Clear compilation cache'
265
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l inline -d 'Use inline RBS annotations'
266
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l target -r -a 'native jvm' -d 'Target platform'
267
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l run -d 'Run after building'
268
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l emit-ir -d 'Emit intermediate representation'
269
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l classpath -r -d 'JVM classpath'
270
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l lib -d 'Build as library JAR'
271
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l stats -d 'Show optimization statistics'
272
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -s q -l quiet -d 'Suppress non-error output'
273
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -l no-color -d 'Disable colored output'
274
+ complete -c konpeito -n '__fish_seen_subcommand_from build' -F -d 'Ruby source file'
275
+
276
+ # run options
277
+ complete -c konpeito -n '__fish_seen_subcommand_from run' -l target -r -a 'native jvm' -d 'Target platform'
278
+ complete -c konpeito -n '__fish_seen_subcommand_from run' -l classpath -r -d 'JVM classpath'
279
+ complete -c konpeito -n '__fish_seen_subcommand_from run' -l rbs -r -d 'RBS type definition file'
280
+ complete -c konpeito -n '__fish_seen_subcommand_from run' -s I -l require-path -r -d 'Add require search path'
281
+ complete -c konpeito -n '__fish_seen_subcommand_from run' -s v -l verbose -d 'Verbose output'
282
+ complete -c konpeito -n '__fish_seen_subcommand_from run' -l no-color -d 'Disable colored output'
283
+ complete -c konpeito -n '__fish_seen_subcommand_from run' -F -d 'Ruby source file'
284
+
285
+ # check options
286
+ complete -c konpeito -n '__fish_seen_subcommand_from check' -s v -l verbose -d 'Verbose output'
287
+ complete -c konpeito -n '__fish_seen_subcommand_from check' -l rbs -r -d 'RBS type definition file'
288
+ complete -c konpeito -n '__fish_seen_subcommand_from check' -s I -l require-path -r -d 'Add require search path'
289
+ complete -c konpeito -n '__fish_seen_subcommand_from check' -l no-color -d 'Disable colored output'
290
+ complete -c konpeito -n '__fish_seen_subcommand_from check' -F -d 'Ruby source file'
291
+
292
+ # completion options
293
+ complete -c konpeito -n '__fish_seen_subcommand_from completion' -a 'bash zsh fish' -d 'Shell type'
294
+ FISH
295
+ end
296
+ end
297
+ end
298
+ end
@@ -5,7 +5,7 @@ require "fileutils"
5
5
 
6
6
  module Konpeito
7
7
  module Commands
8
- # Deps command - download Maven dependencies
8
+ # Deps command - analyze source file dependencies or download Maven JARs
9
9
  class DepsCommand < BaseCommand
10
10
  MAVEN_CENTRAL_BASE = "https://repo1.maven.org/maven2"
11
11
 
@@ -14,32 +14,32 @@ module Konpeito
14
14
  end
15
15
 
16
16
  def self.description
17
- "Download JAR dependencies from Maven Central"
17
+ "Analyze source file dependencies"
18
18
  end
19
19
 
20
20
  def run
21
21
  parse_options!
22
22
 
23
- jars = config.deps_jars
24
-
25
- if jars.empty?
26
- puts "No dependencies configured in konpeito.toml [deps] section."
27
- puts ""
28
- puts "Example:"
29
- puts ' [deps]'
30
- puts ' jars = ["com.google.code.gson:gson:2.10.1"]'
23
+ if options[:fetch]
24
+ fetch_jars
31
25
  return
32
26
  end
33
27
 
34
- lib_dir = options[:output_dir]
35
- FileUtils.mkdir_p(lib_dir)
28
+ if args.empty?
29
+ source_file = find_default_source
30
+ unless source_file
31
+ puts option_parser_help
32
+ return
33
+ end
34
+ else
35
+ source_file = args.first
36
+ end
36
37
 
37
- jars.each do |spec|
38
- download_jar(spec, lib_dir)
38
+ unless File.exist?(source_file)
39
+ error("File not found: #{source_file}")
39
40
  end
40
41
 
41
- puts ""
42
- puts "#{jars.size} dependency(ies) downloaded to #{lib_dir}/"
42
+ analyze(source_file)
43
43
  end
44
44
 
45
45
  protected
@@ -48,30 +48,138 @@ module Konpeito
48
48
  {
49
49
  verbose: false,
50
50
  color: $stderr.tty?,
51
- output_dir: "lib"
51
+ fetch: false,
52
+ output_dir: "lib",
53
+ require_paths: config.require_paths.dup
52
54
  }
53
55
  end
54
56
 
55
57
  def setup_option_parser(opts)
56
- opts.on("-d", "--dir DIR", "Output directory (default: lib)") do |dir|
58
+ opts.on("--fetch", "Download configured JAR dependencies (JVM)") do
59
+ options[:fetch] = true
60
+ end
61
+
62
+ opts.on("-d", "--dir DIR", "Output directory for --fetch (default: lib)") do |dir|
57
63
  options[:output_dir] = dir
58
64
  end
59
65
 
66
+ opts.on("-I", "--require-path PATH", "Add require search path") do |path|
67
+ options[:require_paths] << path
68
+ end
69
+
60
70
  super
61
71
  end
62
72
 
63
73
  def banner
64
74
  <<~BANNER.chomp
65
- Usage: konpeito deps [options]
75
+ Usage: konpeito deps [options] [source.rb]
66
76
 
67
77
  Examples:
68
- konpeito deps Download all configured JARs
69
- konpeito deps -d vendor/lib Download to custom directory
78
+ konpeito deps src/main.rb Show dependency analysis
79
+ konpeito deps --fetch Download configured JAR dependencies
70
80
  BANNER
71
81
  end
72
82
 
73
83
  private
74
84
 
85
+ def find_default_source
86
+ candidates = ["src/main.rb", "main.rb", "app.rb"]
87
+ candidates.find { |f| File.exist?(f) }
88
+ end
89
+
90
+ def option_parser_help
91
+ parser = OptionParser.new do |opts|
92
+ opts.banner = banner
93
+ opts.separator ""
94
+ opts.separator "Options:"
95
+ setup_option_parser(opts)
96
+ end
97
+ parser.to_s
98
+ end
99
+
100
+ def analyze(source_file)
101
+ emit("Analyzing", source_file)
102
+
103
+ resolver = DependencyResolver.new(
104
+ base_paths: options[:require_paths],
105
+ verbose: options[:verbose]
106
+ )
107
+
108
+ begin
109
+ _merged_ast, rbs_paths, stdlib_requires, native_extensions = resolver.resolve(source_file)
110
+ rescue Konpeito::DependencyError => e
111
+ display_dependency_error(e)
112
+ exit 1
113
+ end
114
+
115
+ resolved = resolver.resolved_files.keys
116
+ puts ""
117
+
118
+ # Source files (dependency order)
119
+ puts "Source files (#{resolved.size}):"
120
+ resolved.each_with_index do |path, i|
121
+ puts " #{i + 1}. #{abbreviate(path)}"
122
+ end
123
+
124
+ # Type definitions
125
+ puts ""
126
+ puts "Type definitions (#{rbs_paths.size}):"
127
+ if rbs_paths.empty?
128
+ puts " (none)"
129
+ else
130
+ rbs_paths.each { |p| puts " - #{abbreviate(p)}" }
131
+ end
132
+
133
+ # Runtime requires
134
+ puts ""
135
+ puts "Runtime requires (#{stdlib_requires.size}):"
136
+ if stdlib_requires.empty?
137
+ puts " (none)"
138
+ else
139
+ stdlib_requires.each { |r| puts " - #{r}" }
140
+ end
141
+
142
+ # Native extensions
143
+ puts ""
144
+ puts "Native extensions (#{native_extensions.size}):"
145
+ if native_extensions.empty?
146
+ puts " (none)"
147
+ else
148
+ native_extensions.each { |ext| puts " - #{ext[:base]}" }
149
+ end
150
+ end
151
+
152
+ # Shorten absolute paths relative to cwd for readability
153
+ def abbreviate(path)
154
+ cwd = Dir.pwd + "/"
155
+ path.start_with?(cwd) ? path.delete_prefix(cwd) : path
156
+ end
157
+
158
+ # --- JAR fetch (legacy, --fetch) ---
159
+
160
+ def fetch_jars
161
+ jars = config.deps_jars
162
+
163
+ if jars.empty?
164
+ puts "No dependencies configured in konpeito.toml [deps] section."
165
+ puts ""
166
+ puts "Example:"
167
+ puts ' [deps]'
168
+ puts ' jars = ["com.google.code.gson:gson:2.10.1"]'
169
+ return
170
+ end
171
+
172
+ lib_dir = options[:output_dir]
173
+ FileUtils.mkdir_p(lib_dir)
174
+
175
+ jars.each do |spec|
176
+ download_jar(spec, lib_dir)
177
+ end
178
+
179
+ puts ""
180
+ puts "#{jars.size} dependency(ies) downloaded to #{lib_dir}/"
181
+ end
182
+
75
183
  def download_jar(spec, lib_dir)
76
184
  parts = spec.split(":")
77
185
  unless parts.size == 3