rbs 1.5.1 → 1.7.0.beta.1

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +10 -0
  3. data/.github/workflows/ruby.yml +0 -4
  4. data/.gitignore +1 -0
  5. data/CHANGELOG.md +51 -0
  6. data/Gemfile +2 -0
  7. data/Rakefile +7 -22
  8. data/Steepfile +9 -1
  9. data/core/enumerator.rbs +1 -0
  10. data/core/io.rbs +3 -1
  11. data/core/kernel.rbs +4 -4
  12. data/core/trace_point.rbs +1 -1
  13. data/docs/collection.md +116 -0
  14. data/ext/rbs/extension/constants.c +140 -0
  15. data/ext/rbs/extension/constants.h +72 -0
  16. data/ext/rbs/extension/extconf.rb +3 -0
  17. data/ext/rbs/extension/lexer.c +1070 -0
  18. data/ext/rbs/extension/lexer.h +145 -0
  19. data/ext/rbs/extension/location.c +295 -0
  20. data/ext/rbs/extension/location.h +59 -0
  21. data/ext/rbs/extension/main.c +9 -0
  22. data/ext/rbs/extension/parser.c +2418 -0
  23. data/ext/rbs/extension/parser.h +23 -0
  24. data/ext/rbs/extension/parserstate.c +313 -0
  25. data/ext/rbs/extension/parserstate.h +141 -0
  26. data/ext/rbs/extension/rbs_extension.h +40 -0
  27. data/ext/rbs/extension/ruby_objs.c +585 -0
  28. data/ext/rbs/extension/ruby_objs.h +46 -0
  29. data/ext/rbs/extension/unescape.c +65 -0
  30. data/goodcheck.yml +1 -1
  31. data/lib/rbs/ast/comment.rb +0 -12
  32. data/lib/rbs/buffer.rb +4 -0
  33. data/lib/rbs/builtin_names.rb +1 -0
  34. data/lib/rbs/cli.rb +98 -10
  35. data/lib/rbs/collection/cleaner.rb +29 -0
  36. data/lib/rbs/collection/config/lockfile_generator.rb +95 -0
  37. data/lib/rbs/collection/config.rb +85 -0
  38. data/lib/rbs/collection/installer.rb +27 -0
  39. data/lib/rbs/collection/sources/git.rb +162 -0
  40. data/lib/rbs/collection/sources/rubygems.rb +40 -0
  41. data/lib/rbs/collection/sources/stdlib.rb +38 -0
  42. data/lib/rbs/collection/sources.rb +22 -0
  43. data/lib/rbs/collection.rb +13 -0
  44. data/lib/rbs/environment_loader.rb +12 -0
  45. data/lib/rbs/errors.rb +16 -1
  46. data/lib/rbs/location.rb +221 -217
  47. data/lib/rbs/location_aux.rb +108 -0
  48. data/lib/rbs/locator.rb +10 -7
  49. data/lib/rbs/parser_aux.rb +24 -0
  50. data/lib/rbs/repository.rb +13 -7
  51. data/lib/rbs/types.rb +2 -3
  52. data/lib/rbs/validator.rb +4 -1
  53. data/lib/rbs/version.rb +1 -1
  54. data/lib/rbs/writer.rb +4 -2
  55. data/lib/rbs.rb +4 -7
  56. data/rbs.gemspec +2 -1
  57. data/sig/ancestor_builder.rbs +2 -2
  58. data/sig/annotation.rbs +2 -2
  59. data/sig/builtin_names.rbs +1 -0
  60. data/sig/cli.rbs +5 -0
  61. data/sig/collection/cleaner.rbs +13 -0
  62. data/sig/collection/collections.rbs +112 -0
  63. data/sig/collection/config.rbs +69 -0
  64. data/sig/collection/installer.rbs +15 -0
  65. data/sig/collection.rbs +4 -0
  66. data/sig/comment.rbs +7 -7
  67. data/sig/constant_table.rbs +1 -1
  68. data/sig/declarations.rbs +9 -9
  69. data/sig/definition.rbs +1 -1
  70. data/sig/definition_builder.rbs +2 -2
  71. data/sig/environment_loader.rbs +3 -0
  72. data/sig/errors.rbs +30 -25
  73. data/sig/location.rbs +42 -79
  74. data/sig/locator.rbs +2 -2
  75. data/sig/members.rbs +7 -7
  76. data/sig/method_types.rbs +3 -3
  77. data/sig/parser.rbs +11 -21
  78. data/sig/polyfill.rbs +12 -3
  79. data/sig/repository.rbs +4 -0
  80. data/sig/types.rbs +45 -27
  81. data/sig/writer.rbs +1 -1
  82. data/stdlib/json/0/json.rbs +3 -3
  83. data/stdlib/objspace/0/objspace.rbs +406 -0
  84. data/stdlib/openssl/0/openssl.rbs +1 -1
  85. data/stdlib/tempfile/0/tempfile.rbs +270 -0
  86. data/steep/Gemfile.lock +10 -10
  87. metadata +43 -7
  88. data/lib/rbs/parser.rb +0 -3614
@@ -0,0 +1,85 @@
1
+ module RBS
2
+ module Collection
3
+
4
+ # This class represent the configration file.
5
+ class Config
6
+ class CollectionNotAvailable < StandardError
7
+ def initialize
8
+ super <<~MSG
9
+ rbs collection is not initialized.
10
+ Run `rbs collection install` to install RBSs from collection.
11
+ MSG
12
+ end
13
+ end
14
+
15
+ PATH = Pathname('rbs_collection.yaml')
16
+
17
+ # Generate a rbs lockfile from Gemfile.lock to `config_path`.
18
+ # If `with_lockfile` is true, it respects existing rbs lockfile.
19
+ def self.generate_lockfile(config_path:, gemfile_lock_path:, with_lockfile: true)
20
+ LockfileGenerator.generate(config_path: config_path, gemfile_lock_path: gemfile_lock_path, with_lockfile: with_lockfile)
21
+ end
22
+
23
+ def self.from_path(path)
24
+ new(YAML.load(path.read), config_path: path)
25
+ end
26
+
27
+ def self.lockfile_of(config_path)
28
+ lock_path = to_lockfile_path(config_path)
29
+ from_path lock_path if lock_path.exist?
30
+ end
31
+
32
+ def self.to_lockfile_path(config_path)
33
+ config_path.sub_ext('.lock' + config_path.extname)
34
+ end
35
+
36
+ def initialize(data, config_path:)
37
+ @data = data
38
+ @config_path = config_path
39
+ end
40
+
41
+ def add_gem(gem)
42
+ gems << gem
43
+ end
44
+
45
+ def gem(gem_name)
46
+ gems.find { |gem| gem['name'] == gem_name }
47
+ end
48
+
49
+ def repo_path
50
+ @config_path.dirname.join @data['path']
51
+ end
52
+
53
+ def sources
54
+ @sources ||= (
55
+ @data['sources']
56
+ .map { |c| Sources.from_config_entry(c) }
57
+ .push(Sources::Stdlib.instance)
58
+ .push(Sources::Rubygems.instance)
59
+ )
60
+ end
61
+
62
+ def dump_to(io)
63
+ YAML.dump(@data, io)
64
+ end
65
+
66
+ def gems
67
+ @data['gems'] ||= []
68
+ end
69
+
70
+ # It raises an error when there are non-available libraries
71
+ def check_rbs_availability!
72
+ raise CollectionNotAvailable unless repo_path.exist?
73
+
74
+ gems.each do |gem|
75
+ case gem['source']['type']
76
+ when 'git'
77
+ meta_path = repo_path.join(gem['name'], gem['version'], Sources::Git::METADATA_FILENAME)
78
+ raise CollectionNotAvailable unless meta_path.exist?
79
+ raise CollectionNotAvailable unless gem == YAML.load(meta_path.read)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,27 @@
1
+ module RBS
2
+ module Collection
3
+ class Installer
4
+ attr_reader :lockfile
5
+ attr_reader :stdout
6
+
7
+ def initialize(lockfile_path:, stdout: $stdout)
8
+ @lockfile = Config.from_path(lockfile_path)
9
+ @stdout = stdout
10
+ end
11
+
12
+ def install_from_lockfile
13
+ install_to = lockfile.repo_path
14
+ lockfile.gems.each do |config_entry|
15
+ source_for(config_entry).install(dest: install_to, config_entry: config_entry, stdout: stdout)
16
+ end
17
+ stdout.puts "It's done! #{lockfile.gems.size} gems' RBSs now installed."
18
+ end
19
+
20
+ private def source_for(config_entry)
21
+ @source_for ||= {}
22
+ key = config_entry['source'] or raise
23
+ @source_for[key] ||= Sources.from_config_entry(key)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,162 @@
1
+ require 'digest/sha2'
2
+ require 'open3'
3
+ require 'find'
4
+
5
+ module RBS
6
+ module Collection
7
+ module Sources
8
+ class Git
9
+ METADATA_FILENAME = '.rbs_meta.yaml'
10
+
11
+ class CommandError < StandardError; end
12
+
13
+ attr_reader :name, :remote, :repo_dir
14
+
15
+ def initialize(name:, revision:, remote:, repo_dir:)
16
+ @name = name
17
+ @remote = remote
18
+ @repo_dir = repo_dir || 'gems'
19
+
20
+ setup!(revision: revision)
21
+ end
22
+
23
+ def has?(config_entry)
24
+ gem_name = config_entry['name']
25
+ gem_repo_dir.join(gem_name).directory?
26
+ end
27
+
28
+ def versions(config_entry)
29
+ gem_name = config_entry['name']
30
+ gem_repo_dir.join(gem_name).glob('*/').map { |path| path.basename.to_s }
31
+ end
32
+
33
+ def install(dest:, config_entry:, stdout:)
34
+ gem_name = config_entry['name']
35
+ version = config_entry['version'] or raise
36
+ gem_dir = dest.join(gem_name, version)
37
+
38
+ if gem_dir.directory?
39
+ if (prev = YAML.load_file(gem_dir.join(METADATA_FILENAME))) == config_entry
40
+ stdout.puts "Using #{format_config_entry(config_entry)}"
41
+ else
42
+ # @type var prev: RBS::Collection::Config::gem_entry
43
+ stdout.puts "Updating to #{format_config_entry(config_entry)} from #{format_config_entry(prev)}"
44
+ FileUtils.remove_entry_secure(gem_dir.to_s)
45
+ _install(dest: dest, config_entry: config_entry)
46
+ end
47
+ else
48
+ stdout.puts "Installing #{format_config_entry(config_entry)}"
49
+ _install(dest: dest, config_entry: config_entry)
50
+ end
51
+ end
52
+
53
+ private def _install(dest:, config_entry:)
54
+ gem_name = config_entry['name']
55
+ version = config_entry['version'] or raise
56
+ dest = dest.join(gem_name, version)
57
+ dest.mkpath
58
+ src = gem_repo_dir.join(gem_name, version)
59
+
60
+ cp_r(src, dest)
61
+ dest.join(METADATA_FILENAME).write(YAML.dump(config_entry))
62
+ end
63
+
64
+ private def cp_r(src, dest)
65
+ Find.find(src) do |file_src|
66
+ file_src = Pathname(file_src)
67
+
68
+ # Skip file if it starts with _, such as _test/
69
+ Find.prune if file_src.basename.to_s.start_with?('_')
70
+
71
+ file_src_relative = file_src.relative_path_from(src)
72
+ file_dest = dest.join(file_src_relative)
73
+ file_dest.dirname.mkpath
74
+ FileUtils.copy_entry(file_src, file_dest, false, true) unless file_src.directory?
75
+ end
76
+ end
77
+
78
+ def to_lockfile
79
+ {
80
+ 'type' => 'git',
81
+ 'name' => name,
82
+ 'revision' => resolved_revision,
83
+ 'remote' => remote,
84
+ 'repo_dir' => repo_dir,
85
+ }
86
+ end
87
+
88
+ private def format_config_entry(config_entry)
89
+ name = config_entry['name']
90
+ v = config_entry['version']
91
+
92
+ rev = resolved_revision[0..10]
93
+ desc = "#{name}@#{rev}"
94
+
95
+ "#{name}:#{v} (#{desc})"
96
+ end
97
+
98
+ private def setup!(revision:)
99
+ git_dir.mkpath
100
+ if git_dir.join('.git').directory?
101
+ if need_to_fetch?(revision)
102
+ git 'fetch', 'origin'
103
+ end
104
+ else
105
+ git 'clone', remote, git_dir.to_s
106
+ end
107
+
108
+ begin
109
+ git 'checkout', "origin/#{revision}" # for branch name as `revision`
110
+ rescue CommandError
111
+ git 'checkout', revision
112
+ end
113
+ end
114
+
115
+ private def need_to_fetch?(revision)
116
+ return true unless revision.match?(/\A[a-f0-9]{40}\z/)
117
+
118
+ begin
119
+ git('cat-file', '-e', revision)
120
+ false
121
+ rescue CommandError
122
+ true
123
+ end
124
+ end
125
+
126
+ private def git_dir
127
+ @git_dir ||= (
128
+ base = Pathname(ENV['XDG_CACHE_HOME'] || File.expand_path("~/.cache"))
129
+ dir = base.join('rbs', Digest::SHA256.hexdigest(remote))
130
+ dir.mkpath
131
+ dir
132
+ )
133
+ end
134
+
135
+ private def gem_repo_dir
136
+ git_dir.join @repo_dir
137
+ end
138
+
139
+ private def resolved_revision
140
+ @resolved_revision ||= resolve_revision
141
+ end
142
+
143
+ private def resolve_revision
144
+ git('rev-parse', 'HEAD').chomp
145
+ end
146
+
147
+ private def git(*cmd)
148
+ sh! 'git', *cmd
149
+ end
150
+
151
+ private def sh!(*cmd)
152
+ RBS.logger.debug "$ #{cmd.join(' ')}"
153
+ (__skip__ = Open3.capture3(*cmd, chdir: git_dir)).then do |out, err, status|
154
+ raise CommandError, "Unexpected status #{status.exitstatus}\n\n#{err}" unless status.success?
155
+
156
+ out
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,40 @@
1
+ require 'singleton'
2
+
3
+ module RBS
4
+ module Collection
5
+ module Sources
6
+ # Signatures that are inclduded in gem package as sig/ directory.
7
+ class Rubygems
8
+ include Singleton
9
+
10
+ def has?(config_entry)
11
+ gem_sig_path(config_entry)
12
+ end
13
+
14
+ def versions(config_entry)
15
+ spec, _ = gem_sig_path(config_entry)
16
+ spec or raise
17
+ [spec.version.to_s]
18
+ end
19
+
20
+ def install(dest:, config_entry:, stdout:)
21
+ # Do nothing because stdlib RBS is available by default
22
+ name = config_entry['name']
23
+ version = config_entry['version'] or raise
24
+ _, from = gem_sig_path(config_entry)
25
+ stdout.puts "Using #{name}:#{version} (#{from})"
26
+ end
27
+
28
+ def to_lockfile
29
+ {
30
+ 'type' => 'rubygems',
31
+ }
32
+ end
33
+
34
+ private def gem_sig_path(config_entry)
35
+ RBS::EnvironmentLoader.gem_sig_path(config_entry['name'], config_entry['version'])
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ require 'singleton'
2
+
3
+ module RBS
4
+ module Collection
5
+ module Sources
6
+ # signatures that are bundled in rbs gem under the stdlib/ directory
7
+ class Stdlib
8
+ include Singleton
9
+
10
+ def has?(config_entry)
11
+ gem_dir(config_entry).exist?
12
+ end
13
+
14
+ def versions(config_entry)
15
+ gem_dir(config_entry).glob('*/').map { |path| path.basename.to_s }
16
+ end
17
+
18
+ def install(dest:, config_entry:, stdout:)
19
+ # Do nothing because stdlib RBS is available by default
20
+ name = config_entry['name']
21
+ version = config_entry['version'] or raise
22
+ from = gem_dir(config_entry) / version
23
+ stdout.puts "Using #{name}:#{version} (#{from})"
24
+ end
25
+
26
+ def to_lockfile
27
+ {
28
+ 'type' => 'stdlib',
29
+ }
30
+ end
31
+
32
+ private def gem_dir(config_entry)
33
+ Repository::DEFAULT_STDLIB_ROOT.join(config_entry['name'])
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ require_relative './sources/git'
2
+ require_relative './sources/stdlib'
3
+ require_relative './sources/rubygems'
4
+
5
+ module RBS
6
+ module Collection
7
+ module Sources
8
+ def self.from_config_entry(source_entry)
9
+ case source_entry['type']
10
+ when 'git', nil # git source by default
11
+ __skip__ = Git.new(**source_entry.slice('name', 'revision', 'remote', 'repo_dir').transform_keys(&:to_sym))
12
+ when 'stdlib'
13
+ Stdlib.instance
14
+ when 'rubygems'
15
+ Rubygems.instance
16
+ else
17
+ raise
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ require 'yaml'
2
+ require 'bundler'
3
+
4
+ require_relative './collection/sources'
5
+ require_relative './collection/config'
6
+ require_relative './collection/config/lockfile_generator'
7
+ require_relative './collection/installer'
8
+ require_relative './collection/cleaner'
9
+
10
+ module RBS
11
+ module Collection
12
+ end
13
+ end
@@ -47,6 +47,18 @@ module RBS
47
47
  end
48
48
  end
49
49
 
50
+ def add_collection(collection_config)
51
+ warn "warning: rbs collection is experimental, and the behavior may change until RBS v2.0"
52
+
53
+ collection_config.check_rbs_availability!
54
+
55
+ repository.add(collection_config.repo_path)
56
+
57
+ collection_config.gems.each do |gem|
58
+ add(library: gem['name'], version: gem['version'])
59
+ end
60
+ end
61
+
50
62
  def has_library?(library:, version:)
51
63
  if self.class.gem_sig_path(library, version) || repository.lookup(library, version)
52
64
  true
data/lib/rbs/errors.rb CHANGED
@@ -15,10 +15,23 @@ module RBS
15
15
  end
16
16
 
17
17
  class ErrorBase < StandardError; end
18
- class ParsingError < ErrorBase; end
19
18
  class LoadingError < ErrorBase; end
20
19
  class DefinitionError < ErrorBase; end
21
20
 
21
+ class ParsingError < ErrorBase
22
+ attr_reader :location
23
+ attr_reader :error_message
24
+ attr_reader :token_type
25
+
26
+ def initialize(location, error_message, token_type)
27
+ @location = location
28
+ @error_message = error_message
29
+ @token_type = token_type
30
+
31
+ super "#{Location.to_string location}: Syntax error: #{error_message}, token=`#{location.source}` (#{token_type})"
32
+ end
33
+ end
34
+
22
35
  class InvalidTypeApplicationError < DefinitionError
23
36
  attr_reader :type_name
24
37
  attr_reader :args
@@ -383,6 +396,8 @@ module RBS
383
396
  "include"
384
397
  when AST::Members::Extend
385
398
  "extend"
399
+ else
400
+ raise
386
401
  end
387
402
  end
388
403
  end