checkoff 0.256.0 → 0.257.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6f30a4354aedf2688699c3c460f2495445ce9cc647e0da109586f9be561caf4
4
- data.tar.gz: 159ce5f7020c4ed9d0c3bd2f6841e3da1c5e5fc3009a2efefc04af8ccc3b97b1
3
+ metadata.gz: 1896715fc41d51e76c6c1381eed1a4b3cd72ee304a75b36d1a26bfe42d0ee158
4
+ data.tar.gz: 07f5cc66320360ebc668d21adc062585fb6927b029872b99f0416f30b7986387
5
5
  SHA512:
6
- metadata.gz: 473fa677a861c4d4d8d2d6b9c93feeaa4d3a3cd6d029298a3a8ac98bf1ec443316c08860e20f64406aa3775642cf8b08115163513b8b634fe6ddf9dddb8ae78e
7
- data.tar.gz: c50cd2149b2465e59e6a84b7ab53ca5027c8fb24aceb1e01731a39dfa52e5e52964f8ee2a38bb3b69ded267a9f989c7a9cc806bbcd2b24ad2b75be70c6d25ad6
6
+ metadata.gz: 161d6849b466f214b62ee2c04d2188bd672323560ff37fd99709166efb920aea03aec8f5255835b2b938ee6c0036c847e40d57a509ccaeded3f03b5bda98d603
7
+ data.tar.gz: 16acaccaea9884fbfe513ac8dfe6f9bb30f72342deba8d88a335a3f391d8fb18fd61d8034731346b5e6015ef9c0fb125e3153599dfe2eeb76dfd4ed6ff0ccfe3
@@ -54,7 +54,7 @@ module Checkoff
54
54
  end
55
55
 
56
56
  # @param url [String]
57
- # @param resource [Asana::Resources::Resource]
57
+ # @param resource [Asana::Resources::Task]
58
58
  # @param attachment_name [String,nil]
59
59
  # @param just_the_url [Boolean]
60
60
  # @param verify_mode [Integer] - e.g., OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER
@@ -79,15 +79,15 @@ module Checkoff
79
79
  # extension as the URL using Net::HTTP, raising an exception if
80
80
  # not succesful
81
81
  #
82
- # @param uri [URI]
82
+ # @param uri [URI::Generic]
83
83
  # @param verify_mode [Integer] - e.g., OpenSSL::SSL::VERIFY_NONE,OpenSSL::SSL::VERIFY_PEER
84
84
  #
85
85
  # @return [Object]
86
86
  def download_uri(uri, verify_mode: OpenSSL::SSL::VERIFY_PEER, &block)
87
87
  out = nil
88
- # @sg-ignore
89
88
  Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https', verify_mode:) do |http|
90
- # @sg-ignore
89
+ # @sg-ignore Unresolved constant Net::HTTP::Get / Unresolved call to request —
90
+ # stdlib RBS gap on Net::HTTP block param types
91
91
  http.request(Net::HTTP::Get.new(uri)) do |response|
92
92
  raise("Unexpected response code: #{response.code}") unless response.code == '200'
93
93
 
@@ -120,7 +120,7 @@ module Checkoff
120
120
  end
121
121
 
122
122
  # @param url [String]
123
- # @param resource [Asana::Resources::Resource]
123
+ # @param resource [Asana::Resources::Task]
124
124
  # @param attachment_name [String,nil]
125
125
  # @param verify_mode [Integer] - e.g., OpenSSL::SSL::VERIFY_NONE,OpenSSL::SSL::VERIFY_PEER
126
126
  #
@@ -130,25 +130,25 @@ module Checkoff
130
130
  uri = URI(url)
131
131
  attachment_name ||= File.basename(uri.path)
132
132
  download_uri(uri, verify_mode:) do |tempfile|
133
- # @sg-ignore
133
+ # @sg-ignore attachment_name reassignment above isn't narrowed from the declared
134
+ # [String, nil] param type — needs a fresh typed local, deferred to a follow-up code PR
134
135
  content_type ||= content_type_from_filename(attachment_name)
135
- # @sg-ignore
136
+ # @sg-ignore URI::Generic#path can be nil
136
137
  content_type ||= content_type_from_filename(uri.path)
137
138
 
138
- # @sg-ignore
139
+ # @sg-ignore same attachment_name/content_type narrowing gap as above
139
140
  resource.attach(filename: attachment_name, mime: content_type,
140
141
  io: tempfile)
141
142
  end
142
143
  end
143
144
 
144
145
  # @param url [String]
145
- # @param resource [Asana::Resources::Resource]
146
+ # @param resource [Asana::Resources::Task]
146
147
  # @param attachment_name [String,nil]
147
148
  #
148
149
  # @return [Asana::Resources::Attachment]
149
150
  def create_attachment_from_url_alone!(url, resource, attachment_name:)
150
151
  with_params = {
151
- # @sg-ignore
152
152
  'parent' => resource.gid,
153
153
  'url' => url,
154
154
  'resource_subtype' => 'external',
@@ -196,7 +196,8 @@ module Checkoff
196
196
  tasks = Checkoff::Tasks.new
197
197
  attachments = Checkoff::Attachments.new
198
198
  task = tasks.task_by_gid(gid)
199
- # @sg-ignore
199
+ # @sg-ignore task_by_gid can return nil; needs a raise-if-nil guard, deferred to a
200
+ # follow-up code PR
200
201
  attachment = attachments.create_attachment_from_url!(url, task)
201
202
  puts "Results: #{attachment.inspect}"
202
203
  end
data/lib/checkoff/cli.rb CHANGED
@@ -29,7 +29,6 @@ module Checkoff
29
29
  end
30
30
 
31
31
  @from_workspace_name = from_workspace_arg
32
- # @sg-ignore
33
32
  @from_project_name = project_arg_to_name(from_project_arg)
34
33
  @from_section_name = from_section_arg
35
34
  end
@@ -41,7 +40,6 @@ module Checkoff
41
40
  if to_project_arg == :source_project
42
41
  from_project_name
43
42
  else
44
- # @sg-ignore
45
43
  project_arg_to_name(to_project_arg)
46
44
  end
47
45
  end
@@ -146,7 +144,7 @@ module Checkoff
146
144
  :to_workspace_name, :to_project_name, :to_section_name,
147
145
  :projects, :sections
148
146
 
149
- # @param project_arg [String]
147
+ # @param project_arg [Symbol, String]
150
148
  # @return [Symbol, String]
151
149
  def project_arg_to_name(project_arg)
152
150
  arg = project_arg.to_s
@@ -218,7 +216,6 @@ module Checkoff
218
216
  # @return [String]
219
217
  def run_on_project(workspace, project)
220
218
  tasks_by_section =
221
- # @sg-ignore
222
219
  sections.tasks_by_section(workspace, project)
223
220
  tasks_by_section.update(tasks_by_section) do |_key, tasks|
224
221
  tasks_to_hash(tasks)
@@ -30,9 +30,9 @@ module Checkoff
30
30
  # @return [Asana::Client]
31
31
  def client
32
32
  @client ||= @asana_client_class.new do |c|
33
- # @sg-ignore
33
+ # @sg-ignore Unresolved call to authentication — gem config DSL block, not covered by annotations
34
34
  c.authentication :access_token, @config.fetch(:personal_access_token)
35
- # @sg-ignore
35
+ # @sg-ignore Unresolved call to default_headers — gem config DSL block, not covered by annotations
36
36
  c.default_headers 'asana-enable' =>
37
37
  'new_project_templates,new_user_task_lists,new_memberships,new_goal_memberships'
38
38
  end
@@ -41,7 +41,7 @@ module Checkoff
41
41
  # @param custom_field_name [String]
42
42
  #
43
43
  # @return [Asana::Resources::CustomField]
44
- # @sg-ignore
44
+ # @sg-ignore nil check above is not flow-sensitive
45
45
  def custom_field_or_raise(workspace_name, custom_field_name)
46
46
  cf = custom_field(workspace_name, custom_field_name)
47
47
  raise "Could not find custom_field #{custom_field_name} under workspace #{workspace_name}." if cf.nil?
@@ -78,8 +78,10 @@ module Checkoff
78
78
 
79
79
  # @param resource [Asana::Resources::Project,Asana::Resources::Task]
80
80
  # @param custom_field_name [String]
81
- # @sg-ignore
82
81
  # @return [Array<String>]
82
+ # @sg-ignore Declared return type Array<String> does not match inferred type Array,Array<Array> —
83
+ # fixing cleanly needs binding enum_value.fetch('name') to a typed local; leaving for a
84
+ # follow-up code PR to keep this one annotation-only.
83
85
  def resource_custom_field_values_names_by_name(resource, custom_field_name)
84
86
  custom_field = resource_custom_field_by_name(resource, custom_field_name)
85
87
  return [] if custom_field.nil?
@@ -108,9 +110,9 @@ module Checkoff
108
110
  end
109
111
 
110
112
  # @param resource [Asana::Resources::Task,Asana::Resources::Project]
111
- # @sg-ignore
112
113
  # @param custom_field_name [String]
113
114
  # @return [Hash]
115
+ # @sg-ignore nil check above is not flow-sensitive
114
116
  def resource_custom_field_by_name_or_raise(resource, custom_field_name)
115
117
  custom_field = resource_custom_field_by_name(resource, custom_field_name)
116
118
  if custom_field.nil?
@@ -120,10 +122,10 @@ module Checkoff
120
122
  custom_field
121
123
  end
122
124
 
123
- # @sg-ignore
124
125
  # @param resource [Asana::Resources::Project,Asana::Resources::Task]
125
126
  # @param custom_field_gid [String]
126
127
  # @return [Hash]
128
+ # @sg-ignore nil check above is not flow-sensitive
127
129
  def resource_custom_field_by_gid_or_raise(resource, custom_field_gid)
128
130
  # @type [Array<Hash>]
129
131
  custom_fields = resource.custom_fields
@@ -146,7 +148,9 @@ module Checkoff
146
148
  # @param custom_field [Hash{String => Hash,Array<Hash>}]
147
149
  #
148
150
  # @return [Array<Hash>]
149
- # @sg-ignore
151
+ # @sg-ignore Declared return type Array<Hash> does not match inferred type Array,Hash,Array<Hash> —
152
+ # fixing cleanly needs restructuring the case/when to bind each branch to a typed local; leaving
153
+ # for a follow-up code PR to keep this one annotation-only.
150
154
  def resource_custom_field_enum_values(custom_field)
151
155
  resource_subtype = custom_field.fetch('resource_subtype')
152
156
  case resource_subtype
@@ -74,9 +74,11 @@ module Checkoff
74
74
  end
75
75
  resource = webhook_subscription&.fetch('resource', nil)
76
76
  name, resource_type = enrich_gid(resource) if resource
77
- # @sg-ignore
77
+ # @sg-ignore webhook_subscription is declared [Hash, nil] but this line assumes non-nil
78
+ # without the &. used elsewhere in this method — looks like a real nil-safety gap, not
79
+ # just a typing gap; flagging for the follow-up code PR rather than silently widening
78
80
  webhook_subscription['checkoff:enriched:name'] = name if name
79
- # @sg-ignore
81
+ # @sg-ignore same nil-safety gap as above
80
82
  webhook_subscription['checkoff:enriched:resource_type'] = resource_type if resource_type
81
83
  end
82
84
 
@@ -96,13 +98,11 @@ module Checkoff
96
98
 
97
99
  # @param filter [Hash{String => String, Array<String>}]
98
100
  #
99
- # @sg-ignore
100
- # @return [String, nil]
101
+ # @return [void]
101
102
  def enrich_filter_parent_gid!(filter)
102
- parent_gid = filter['checkoff:parent.gid']
103
+ parent_gid = T.cast(filter['checkoff:parent.gid'], T.nilable(String))
103
104
  return unless parent_gid
104
105
 
105
- # @sg-ignore
106
106
  name, resource_type = enrich_gid(parent_gid)
107
107
  filter['checkoff:enriched:parent.name'] = name if name
108
108
  filter['checkoff:enriched:parent.resource_type'] = resource_type if resource_type
@@ -112,11 +112,10 @@ module Checkoff
112
112
  #
113
113
  # @return [void]
114
114
  def enrich_filter_resource!(filter)
115
- resource_gid = filter['checkoff:resource.gid']
115
+ resource_gid = T.cast(filter['checkoff:resource.gid'], T.nilable(String))
116
116
 
117
117
  return unless resource_gid
118
118
 
119
- # @sg-ignore
120
119
  task = tasks.task_by_gid(resource_gid)
121
120
  task_name = task&.name
122
121
  filter['checkoff:enriched:resource.name'] = task_name if task_name
@@ -134,12 +133,11 @@ module Checkoff
134
133
  filter['checkoff:enriched:fetched.section.name'] = name if name
135
134
  end
136
135
 
137
- # @param asana_event [Hash{'resource' => Hash}]
136
+ # @param asana_event [Hash]
138
137
  #
139
138
  # @return [void]
140
139
  def enrich_event_parent!(asana_event)
141
140
  # @type [Hash{String => String }]
142
- # @sg-ignore
143
141
  parent = asana_event['parent']
144
142
 
145
143
  return unless parent
@@ -154,7 +152,7 @@ module Checkoff
154
152
  nil
155
153
  end
156
154
 
157
- # @param asana_event [Hash{'resource' => Hash}]
155
+ # @param asana_event [Hash]
158
156
  #
159
157
  # @return [void]
160
158
  def enrich_event_resource!(asana_event)
@@ -20,12 +20,12 @@ module Checkoff
20
20
 
21
21
  # @param key [Symbol]
22
22
  # @return [Object]
23
- # @sg-ignore
23
+ # @sg-ignore return type could not be inferred — cascades from the ENV.fetch RBS gap below
24
24
  def [](key)
25
25
  config_value = @config[key]
26
26
  return config_value unless config_value.nil?
27
27
 
28
- # @sg-ignore
28
+ # @sg-ignore Unresolved call to fetch on RBS::Unnamed::ENVClass, Class<ENV>
29
29
  ENV.fetch(envvar_name(key), nil)
30
30
  end
31
31
 
@@ -57,10 +57,10 @@ module Logging
57
57
  private
58
58
 
59
59
  # @return [Symbol]
60
- # @sg-ignore
60
+ # @sg-ignore return type could not be inferred — cascades from the ENV.fetch RBS gap below
61
61
  def log_level
62
- # @sg-ignore
63
62
  # rubocop:disable Style/RedundantFetchBlock
63
+ # @sg-ignore Unresolved call to fetch on RBS::Unnamed::ENVClass, Class<ENV>
64
64
  ENV.fetch('LOG_LEVEL') { 'INFO' }.downcase.to_sym
65
65
  # rubocop:enable Style/RedundantFetchBlock
66
66
  end
@@ -24,9 +24,10 @@ module Checkoff
24
24
  # @param url [String]
25
25
  # @return [Array(Hash{String => String}, Array)]
26
26
  def convert_params(url)
27
- # @sg-ignore
27
+ # @sg-ignore URI#query can be nil for a URL with no query string; CGI.parse expects
28
+ # String — looks like a real gap (unhandled no-query-string case), not just a typing
29
+ # gap, flagging for the follow-up code PR rather than silently asserting non-nil
28
30
  url_params = CGI.parse(URI.parse(url).query)
29
- # @sg-ignore
30
31
  custom_field_params, date_url_params, simple_url_params = partition_url_params(url_params)
31
32
  custom_field_args, custom_field_task_selector = convert_custom_field_params(custom_field_params)
32
33
  date_url_args, date_task_selector = convert_date_params(date_url_params)
@@ -56,14 +57,15 @@ module Checkoff
56
57
  CustomFieldParamConverter.new(custom_field_params:).convert
57
58
  end
58
59
 
59
- # @param url_params [Hash{String => String}]
60
+ # @param url_params [Hash{String => Array<String>}]
60
61
  # @return [Array(Hash{String => Array<String>}, Hash{String => Array<String>}, Hash{String => Array<String>})]
61
62
  def partition_url_params(url_params)
62
63
  groups = T.let(url_params.to_a.group_by do |key, _values|
63
- # @sg-ignore
64
+ # @sg-ignore Unresolved call to start_with? — T.let wrapping this
65
+ # chained group_by block seems to block block-param inference
64
66
  if key.start_with? 'custom_field_'
65
67
  :custom_field
66
- # @sg-ignore
68
+ # @sg-ignore Unresolved call to include? — same T.let/block-param gap
67
69
  elsif key.include? '_date'
68
70
  :date
69
71
  else
@@ -17,8 +17,7 @@ module Checkoff
17
17
  end
18
18
 
19
19
  # @param task_selectors [Array<Symbol, Array>]
20
- # @return [Array(Symbol, Array, Array)]
21
- # @sg-ignore
20
+ # @return [Symbol, Array, Array(Symbol, Array, Array)]
22
21
  def self.merge_task_selectors(*task_selectors)
23
22
  return [] if task_selectors.empty?
24
23
 
@@ -238,9 +238,10 @@ module Checkoff
238
238
  end
239
239
 
240
240
  # @param resource [Asana::Resources::Task, Asana::Resources::Project]
241
- # @sg-ignore
242
241
  # @param prefix [String]
243
242
  # @return [boolish]
243
+ # @sg-ignore Checkoff::SelectorClasses::Common::NameStartsWithPFunctionEvaluator#evaluate
244
+ # return type could not be inferred
244
245
  def evaluate(resource, prefix)
245
246
  resource.name&.start_with?(prefix)
246
247
  end
@@ -15,15 +15,15 @@ module Checkoff
15
15
  end
16
16
 
17
17
  # @return [Boolean]
18
- # @sg-ignore
18
+ # @sg-ignore return type could not be inferred — abstract method body is only `raise`
19
19
  def matches?
20
20
  raise 'Override me!'
21
21
  end
22
22
 
23
23
  # @param _task [Asana::Resources::Task]
24
24
  # @param _args [Array<Object>]
25
- # @sg-ignore
26
25
  # @return [Object]
26
+ # @sg-ignore return type could not be inferred — abstract method body is only `raise`
27
27
  def evaluate(_task, *_args)
28
28
  raise 'Implement me!'
29
29
  end
@@ -362,7 +362,8 @@ module Checkoff
362
362
  # @param task [Asana::Resources::Task]
363
363
  #
364
364
  # @return [Boolean]
365
- # @sg-ignore
365
+ # @sg-ignore Checkoff::SelectorClasses::Task::MilestonePFunctionEvaluator#evaluate
366
+ # return type could not be inferred
366
367
  def evaluate(task)
367
368
  raise 'Please add resource_subtype to extra_fields' if task.resource_subtype.nil?
368
369
 
@@ -19,14 +19,16 @@ module Checkoff
19
19
 
20
20
  # @param task [Asana::Resources::Task]
21
21
  # @return [Time, nil]
22
- # @sg-ignore
22
+ # @sg-ignore return type could not be inferred — #to_time called via &. on a Date|Time
23
+ # union receiver
23
24
  def start_time(task)
24
25
  date_or_time_field_by_name(task, :start)&.to_time
25
26
  end
26
27
 
27
28
  # @param task [Asana::Resources::Task]
28
- # @sg-ignore
29
29
  # @return [Time, nil]
30
+ # @sg-ignore return type could not be inferred — #to_time called via &. on a Date|Time
31
+ # union receiver
30
32
  def due_time(task)
31
33
  date_or_time_field_by_name(task, :due)&.to_time
32
34
  end
@@ -35,8 +37,7 @@ module Checkoff
35
37
  #
36
38
  # @return [Date, Time, nil]
37
39
  def start_date_or_time(task)
38
- # @sg-ignore
39
- return @time_class.parse(task.start_at).localtime unless task.start_at.nil?
40
+ return @time_class.parse(T.must(task.start_at)).localtime unless task.start_at.nil?
40
41
 
41
42
  return @date_class.parse(task.start_on) unless task.start_on.nil?
42
43
 
@@ -58,7 +59,7 @@ module Checkoff
58
59
  #
59
60
  # @return [Time, nil]
60
61
  def modified_time(task)
61
- @time_class.parse(task.modified_at).localtime unless task.modified_at.nil?
62
+ @time_class.parse(T.must(task.modified_at)).localtime unless task.modified_at.nil?
62
63
  end
63
64
 
64
65
  # @param task [Asana::Resources::Task]
@@ -10,7 +10,8 @@ module Checkoff
10
10
  # @param value [Object,Boolean]
11
11
  # @yieldreturn [generic<T>]
12
12
  # @return [generic<T>]
13
- # @sg-ignore
13
+ # @sg-ignore return type could not be inferred — Solargraph's generic/yield-return
14
+ # inference gap for #with_thread_local_variable
14
15
  def with_thread_local_variable(name, value, &block)
15
16
  old_value = Thread.current[name]
16
17
  Thread.current[name] = value
@@ -67,7 +67,9 @@ module Checkoff
67
67
  sections.each_entry { |section| by_section[section_key(section.name)] = [] }
68
68
  tasks.each do |task|
69
69
  assignee_section = task.assignee_section
70
- # @sg-ignore
70
+ # @sg-ignore assignee_section can be nil (task has no My Tasks section) but is
71
+ # dereferenced without a nil guard — looks like a real gap, flagging for the
72
+ # follow-up code PR
71
73
  current_section = section_key(assignee_section.name)
72
74
  by_section[current_section] ||= []
73
75
  by_section[current_section] << task
@@ -47,7 +47,7 @@ module Checkoff
47
47
  # @param portfolio_name [String]
48
48
  #
49
49
  # @return [Asana::Resources::Portfolio]
50
- # @sg-ignore
50
+ # @sg-ignore nil check above is not flow-sensitive
51
51
  def portfolio_or_raise(workspace_name, portfolio_name)
52
52
  portfolio_obj = portfolio(workspace_name, portfolio_name)
53
53
  raise "Could not find portfolio #{portfolio_name} under workspace #{workspace_name}." if portfolio_obj.nil?
@@ -108,8 +108,9 @@ module Checkoff
108
108
  else
109
109
  # @type [Enumerable<Asana::Resources::Project>]
110
110
  ps = projects_by_workspace_name(workspace_name, extra_fields:)
111
- # @type <Asana::Resources::Project,nil>
112
- # @sg-ignore
111
+ # @type [Asana::Resources::Project,nil]
112
+ # @sg-ignore Variable type could not be inferred / Unresolved call to _1 — Solargraph
113
+ # doesn't fully support numbered block parameters
113
114
  project = ps.find { _1.name == project_name }
114
115
  project_by_gid(project.gid, extra_fields:) unless project.nil?
115
116
  end
@@ -120,8 +121,8 @@ module Checkoff
120
121
  # @param project_name [String,Symbol] - :my_tasks or a project name
121
122
  # @param [Array<String>] extra_fields
122
123
  #
123
- # @sg-ignore
124
124
  # @return [Asana::Resources::Project]
125
+ # @sg-ignore nil check above is not flow-sensitive
125
126
  def project_or_raise(workspace_name, project_name, extra_fields: [])
126
127
  p = project(workspace_name, project_name, extra_fields:)
127
128
  raise "Could not find project #{project_name.inspect} under workspace #{workspace_name}." if p.nil?
@@ -80,7 +80,7 @@ module Checkoff
80
80
 
81
81
  # Given a workspace name and project name, then provide a Hash of
82
82
  # tasks with section name -> task list of the uncompleted tasks
83
- # @param workspace_name [String]
83
+ # @param workspace_name [String, Symbol]
84
84
  # @param project_name [String, Symbol]
85
85
  # @param only_uncompleted [Boolean]
86
86
  # @param extra_fields [Array<String>]
@@ -295,7 +295,9 @@ module Checkoff
295
295
  # @type [String, nil]
296
296
  current_section = section_key(section_name)
297
297
 
298
- # @sg-ignore
298
+ # @sg-ignore Hash#fetch arg0 expected String,NilClass received String,nil — Solargraph
299
+ # treats the nil literal in a Hash{K,nil=>V} declaration and an inferred `nil` union
300
+ # member as distinct types; no comment-only fix found
299
301
  by_section.fetch(current_section) << task
300
302
  end
301
303
 
@@ -89,7 +89,8 @@ module Checkoff
89
89
  # as memberships with a separate API within a task.
90
90
  #
91
91
  # @param subtask [Asana::Resources::Task]
92
- # @sg-ignore
92
+ # @return [Boolean, nil]
93
+ # @sg-ignore Checkoff::Subtasks#subtask_section? return type could not be inferred
93
94
  def subtask_section?(subtask)
94
95
  subtask.is_rendered_as_separator
95
96
  end
data/lib/checkoff/tags.rb CHANGED
@@ -79,7 +79,7 @@ module Checkoff
79
79
  # @param tag_name [String]
80
80
  #
81
81
  # @return [Asana::Resources::Tag]
82
- # @sg-ignore
82
+ # @sg-ignore nil check above is not flow-sensitive
83
83
  def tag_or_raise(workspace_name, tag_name)
84
84
  t = tag(workspace_name, tag_name)
85
85
 
@@ -114,7 +114,8 @@ module Checkoff
114
114
  # @return [Hash{Symbol => Object}]
115
115
  def build_params(options)
116
116
  { limit: options[:per_page], completed_since: options[:completed_since] }.reject do |_, v|
117
- # @sg-ignore
117
+ # @sg-ignore Unresolved call to nil? on Object — Solargraph doesn't treat a Hash's
118
+ # declared `Object` value type as full Object here
118
119
  v.nil? || Array(v).empty?
119
120
  end
120
121
  end
@@ -73,7 +73,9 @@ module Checkoff
73
73
  workspace = workspaces.workspace_or_raise(workspace_name)
74
74
  api_params, task_selector = @search_url_parser.convert_params(url)
75
75
  debug { "Task search params: api_params=#{api_params}, task_selector=#{task_selector}" }
76
- # @sg-ignore
76
+ # @sg-ignore task_selector expected Symbol,Array<Symbol,Integer,Array> received
77
+ # Hash{String=>String} — Solargraph mis-assigns tuple-destructured types from
78
+ # `api_params, task_selector = @search_url_parser.convert_params(url)` above
77
79
  raw_task_search(api_params, workspace_gid: workspace.gid, task_selector:,
78
80
  extra_fields:)
79
81
  end
@@ -186,8 +188,9 @@ module Checkoff
186
188
  end
187
189
 
188
190
  # @param [Array<String>] extra_fields
189
- # @sg-ignore
190
- # @return [Hash{Symbol => undefined}]
191
+ # @return [Hash{Symbol => Array<String>}]
192
+ # @sg-ignore return type could not be inferred — bracket access on a Hash{Symbol=>undefined}
193
+ # local doesn't narrow even with a T.cast on the return expression
191
194
  def calculate_api_options(extra_fields)
192
195
  # @type [Hash{Symbol => undefined}]
193
196
  all_options = projects.task_options(extra_fields: ['custom_fields'] + extra_fields)
@@ -122,8 +122,7 @@ module Checkoff
122
122
  only_uncompleted: true,
123
123
  extra_fields: [])
124
124
  thread_local = Checkoff::Internal::ThreadLocal.new
125
- # @type [String]
126
- # @sg-ignore
125
+ # @type [String, nil]
127
126
  task_gid = thread_local.with_thread_local_variable(:suppress_asana_webhook_watch_creation,
128
127
  true) do
129
128
  gid_for_task(workspace_name, project_name, section_name, task_name)
@@ -179,9 +178,10 @@ module Checkoff
179
178
  # @param name [String]
180
179
  # @param workspace_gid [String]
181
180
  # @param assignee_gid [String]
182
- # @sg-ignore
183
181
  #
184
182
  # @return [Asana::Resources::Task]
183
+ # @sg-ignore @asana_task.create return type could not be inferred — calling a class method
184
+ # through a Class<T>-typed ivar is a known Solargraph dispatch limitation
185
185
  def add_task(name,
186
186
  workspace_gid: @workspaces.default_workspace_gid,
187
187
  assignee_gid: default_assignee_gid)
@@ -201,10 +201,10 @@ module Checkoff
201
201
 
202
202
  # True if any of the task's dependencies are marked incomplete
203
203
  #
204
- # @sg-ignore
205
204
  # Include 'dependencies.gid' in extra_fields of task passed in.
206
205
  #
207
206
  # @param task [Asana::Resources::Task]
207
+ # @return [Boolean]
208
208
  def incomplete_dependencies?(task)
209
209
  # Avoid a redundant fetch. Unfortunately, Ruby SDK allows
210
210
  # dependencies to be fetched along with other attributes--but
@@ -214,14 +214,13 @@ module Checkoff
214
214
  #
215
215
  # https://github.com/Asana/ruby-asana/issues/125
216
216
 
217
- # @type [Enumerable<Asana::Resources::Task>, nil]
217
+ # @type [Array<Hash>]
218
218
  dependencies = task.instance_variable_get(:@dependencies) || []
219
219
 
220
220
  dependencies.any? do |parent_task_info|
221
221
  # the real bummer though is that asana doesn't let you fetch
222
222
  # the completion status of dependencies, so we need to do this
223
223
  # regardless:
224
- # @sg-ignore
225
224
  parent_task_gid = parent_task_info.fetch('gid')
226
225
 
227
226
  parent_task = task_by_gid(parent_task_gid, only_uncompleted: false)
@@ -387,7 +386,9 @@ module Checkoff
387
386
  end
388
387
 
389
388
  # @return [String]
390
- # @sg-ignore
389
+ # @sg-ignore @config.fetch return type could not be inferred — @config is intentionally
390
+ # dual-typed [Hash, EnvFallbackConfigLoader] throughout this codebase; Solargraph can't
391
+ # unify #fetch across that union
391
392
  def default_assignee_gid
392
393
  @config.fetch(:default_assignee_gid)
393
394
  end
@@ -57,7 +57,9 @@ module Checkoff
57
57
  section_data = membership_data.fetch('section')
58
58
  section_gid = section_data.fetch('gid')
59
59
  section = @sections.section_by_gid(section_gid)
60
- # @sg-ignore
60
+ # @sg-ignore section_by_gid can return nil on a gid lookup miss, and
61
+ # task_data_dependent_on_previous_section_last_milestone? dereferences it immediately
62
+ # without a nil guard — looks like a real gap, flagging for the follow-up code PR
61
63
  task_data_dependent_on_previous_section_last_milestone?(task_data, section)
62
64
  end
63
65
  end
@@ -95,7 +97,8 @@ module Checkoff
95
97
 
96
98
  all_dependent_task_gids ||= @tasks.all_dependent_tasks(task).map(&:gid)
97
99
 
98
- # @sg-ignore
100
+ # @sg-ignore all_dependent_task_gids is nil-initialized then set via ||= above, but
101
+ # Solargraph doesn't narrow it back to non-nil after the reassignment
99
102
  all_dependent_task_gids.include? last_milestone.gid
100
103
  end
101
104
  end
@@ -131,7 +134,8 @@ module Checkoff
131
134
  dependent_task.resource_subtype == 'milestone'
132
135
  end
133
136
 
134
- # @sg-ignore
137
+ # @sg-ignore all_dependent_milestones is nil-initialized then set via ||= above, but
138
+ # Solargraph doesn't narrow it back to non-nil after the reassignment
135
139
  all_dependent_milestones.any? do |milestone|
136
140
  milestone.memberships.any? do |milestone_membership_data|
137
141
  milestone_membership_data.fetch('project').fetch('gid') == project_gid