import_js 0.4.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a2a0036427b0f66373fcbc6fda702570d501f281
4
- data.tar.gz: 9c798047e26eb9189e169c5395ed1bd41b03e2fc
3
+ metadata.gz: 3808c953be3c8a47d0212d952f35b4329774cba8
4
+ data.tar.gz: f1929ccab0f99004521babc2dbbf8d35347c7313
5
5
  SHA512:
6
- metadata.gz: 4eaed3ab7c8204e62a7b19bdad9cf002384f6797cd15fe6f6615763ebcda6f8cf607cbb3127f8c494082a53f84684c17e383544f897cd368ae0074101676dc5d
7
- data.tar.gz: 43c8abdad3178c4df5c6f04a7030737daa9d2cb4e83cb777e6dbde088a5a43dffa2690ae13e1b1950ce915dc01f5252a75d4747883a9d0777124cf7353541e64
6
+ metadata.gz: 9380c3f44a4306a0e9d843496bf846c47200e696649a88348135e9c7f1d928e04ad5520d67a7c15beb3306e02af1ad7aa2fd2aaaef983c0eec2463e6ca9fd288
7
+ data.tar.gz: cc46051020022e9e7ba9db5b4c8750b104ad372bb72442f5fb7712867084f8bfff92f9dcba06826ca77d87a42d4897dfe72b5b96b7fb89f7dcb61d804e684f75
@@ -57,7 +57,7 @@ module ImportJS
57
57
  path = path.sub(/\{filename\}/,
58
58
  File.basename(path_to_current_file, '.*'))
59
59
  end
60
- ImportJS::JSModule.new(import_path: path)
60
+ JSModule.new(import_path: path)
61
61
  end
62
62
 
63
63
  # @param variable_name [String]
@@ -66,7 +66,7 @@ module ImportJS
66
66
  get('named_exports').each do |import_path, named_exports|
67
67
  next unless named_exports.include?(variable_name)
68
68
 
69
- js_module = ImportJS::JSModule.new(import_path: import_path)
69
+ js_module = JSModule.new(import_path: import_path)
70
70
  js_module.has_named_exports = true
71
71
  return js_module
72
72
  end
@@ -108,11 +108,11 @@ module ImportJS
108
108
  def check_current_version!
109
109
  minimum_version = get('minimum_version')
110
110
  return if Gem::Dependency.new('', ">= #{minimum_version}")
111
- .match?('', ImportJS::VERSION)
111
+ .match?('', VERSION)
112
112
 
113
- fail ImportJS::ClientTooOldError,
113
+ fail ClientTooOldError,
114
114
  'The .importjs.json file you are using requires version ' \
115
- "#{get('minimum_version')}. You are using #{ImportJS::VERSION}."
115
+ "#{get('minimum_version')}. You are using #{VERSION}."
116
116
  end
117
117
  end
118
118
  end
@@ -16,13 +16,13 @@ module ImportJS
16
16
 
17
17
  case command
18
18
  when 'import'
19
- ImportJS::Importer.new(self).import
19
+ Importer.new(self).import
20
20
  write_file
21
21
  puts 'import:success'
22
22
  when 'goto'
23
- ImportJS::Importer.new(self).goto
23
+ Importer.new(self).goto
24
24
  when 'fix'
25
- ImportJS::Importer.new(self).fix_imports
25
+ Importer.new(self).fix_imports
26
26
  write_file
27
27
  puts 'import:success'
28
28
  else
@@ -1,7 +1,7 @@
1
1
  module ImportJS
2
2
  # Class that represents an import statement, e.g.
3
3
  # `const foo = require('foo');`
4
- # `let foo = myCustomRequire('foo');`
4
+ # `var foo = myCustomRequire('foo');`
5
5
  # `import foo from 'foo';`
6
6
  class ImportStatement
7
7
  REGEX_CONST_LET_VAR = /
@@ -50,7 +50,7 @@ module ImportJS
50
50
 
51
51
  # @param string [String] a possible import statement, e.g.
52
52
  # `const foo = require('foo');`
53
- # `let foo = myCustomRequire('foo');`
53
+ # `var foo = myCustomRequire('foo');`
54
54
  # `import foo from 'foo';`
55
55
  # @return [ImportJS::ImportStatement?] a parsed statement, or nil if the
56
56
  # string can't be parsed
@@ -138,7 +138,7 @@ module ImportJS
138
138
  else
139
139
  [default_import_string(max_line_length, tab)]
140
140
  end
141
- else # const/let/var
141
+ else # const/var
142
142
  strings = []
143
143
 
144
144
  if default_import
@@ -9,14 +9,14 @@ module ImportJS
9
9
  REGEX_MULTI_LINE_COMMENT_END = %r{\*/}
10
10
  REGEX_WHITESPACE_ONLY = /\A\s*\Z/
11
11
 
12
- def initialize(editor = ImportJS::VIMEditor.new)
12
+ def initialize(editor = VIMEditor.new)
13
13
  @editor = editor
14
14
  end
15
15
 
16
16
  # Finds variable under the cursor to import. By default, this is bound to
17
17
  # `<Leader>j`.
18
18
  def import
19
- @config = ImportJS::Configuration.new(@editor.path_to_current_file)
19
+ reload_config
20
20
  variable_name = @editor.current_word
21
21
  if variable_name.empty?
22
22
  message(<<-EOS.split.join(' '))
@@ -39,17 +39,29 @@ module ImportJS
39
39
  end
40
40
 
41
41
  def goto
42
- @config = ImportJS::Configuration.new(@editor.path_to_current_file)
42
+ reload_config
43
43
  js_modules = []
44
44
  variable_name = @editor.current_word
45
45
  time do
46
46
  js_modules = find_js_modules(variable_name)
47
47
  end
48
- return if js_modules.empty?
49
- js_module = resolve_one_js_module(js_modules, variable_name)
50
- if js_module
51
- @editor.open_file(js_module.open_file_path(@editor.path_to_current_file))
48
+
49
+ if js_modules.empty?
50
+ # No JS modules are found for the variable, so there is nothing to go to
51
+ # and we return early.
52
+ return message("No modules were found for `#{variable_name}`")
53
+ end
54
+
55
+ js_module = resolve_goto_module(js_modules, variable_name)
56
+
57
+ unless js_module
58
+ # The current word is not mappable to one of the JS modules that we
59
+ # found. This can happen if the user does not select one from the list.
60
+ # We have nothing to go to, so we return early.
61
+ return message("Could not resolve a module for `#{variable_name}`")
52
62
  end
63
+
64
+ @editor.open_file(js_module.open_file_path(@editor.path_to_current_file))
53
65
  end
54
66
 
55
67
  REGEX_ESLINT_RESULT = /
@@ -68,7 +80,7 @@ module ImportJS
68
80
 
69
81
  # Removes unused imports and adds imports for undefined variables
70
82
  def fix_imports
71
- @config = ImportJS::Configuration.new(@editor.path_to_current_file)
83
+ reload_config
72
84
  eslint_result = run_eslint_command
73
85
 
74
86
  unused_variables = []
@@ -107,6 +119,13 @@ module ImportJS
107
119
 
108
120
  private
109
121
 
122
+ # The configuration is relative to the current file, so we need to make sure
123
+ # that we are operating with the appropriate configuration when we perform
124
+ # certain actions.
125
+ def reload_config
126
+ @config = Configuration.new(@editor.path_to_current_file)
127
+ end
128
+
110
129
  def message(str)
111
130
  @editor.message("ImportJS: #{str}")
112
131
  end
@@ -139,11 +158,11 @@ module ImportJS
139
158
  stdin_data: @editor.current_file_content)
140
159
 
141
160
  if ESLINT_STDOUT_ERROR_REGEXES.any? { |regex| out =~ regex }
142
- fail ImportJS::ParseError.new, out
161
+ fail ParseError.new, out
143
162
  end
144
163
 
145
164
  if ESLINT_STDERR_ERROR_REGEXES.any? { |regex| err =~ regex }
146
- fail ImportJS::ParseError.new, err
165
+ fail ParseError.new, err
147
166
  end
148
167
 
149
168
  out.split("\n")
@@ -296,7 +315,7 @@ module ImportJS
296
315
  # iterate through those and stop at anything that's not an import.
297
316
  imports = {}
298
317
  potential_imports_blob.scan(/^.*?;/m).each do |potential_import|
299
- import_statement = ImportJS::ImportStatement.parse(potential_import)
318
+ import_statement = ImportStatement.parse(potential_import)
300
319
  break unless import_statement
301
320
 
302
321
  if imports[import_statement.path]
@@ -333,7 +352,7 @@ module ImportJS
333
352
  if lookup_path == ''
334
353
  # If lookup_path is an empty string, the `find` command will not work
335
354
  # as desired so we bail early.
336
- fail ImportJS::FindError.new,
355
+ fail FindError.new,
337
356
  "lookup path cannot be empty (#{lookup_path.inspect})"
338
357
  end
339
358
 
@@ -345,14 +364,14 @@ module ImportJS
345
364
  command = "#{find_command} | #{egrep_command}"
346
365
  out, err = Open3.capture3(command)
347
366
 
348
- fail ImportJS::FindError.new, err unless err == ''
367
+ fail FindError.new, err unless err == ''
349
368
 
350
369
  matched_modules.concat(
351
370
  out.split("\n").map do |f|
352
371
  next if @config.get('excludes').any? do |glob_pattern|
353
372
  File.fnmatch(glob_pattern, f)
354
373
  end
355
- ImportJS::JSModule.construct(
374
+ JSModule.construct(
356
375
  lookup_path: lookup_path,
357
376
  relative_file_path: f,
358
377
  strip_file_extensions:
@@ -376,7 +395,7 @@ module ImportJS
376
395
  @config.package_dependencies.each do |dep|
377
396
  next unless dep =~ dep_regex
378
397
 
379
- js_module = ImportJS::JSModule.construct(
398
+ js_module = JSModule.construct(
380
399
  lookup_path: 'node_modules',
381
400
  relative_file_path: "node_modules/#{dep}/package.json",
382
401
  strip_file_extensions: [])
@@ -399,7 +418,7 @@ module ImportJS
399
418
 
400
419
  # @param js_modules [Array]
401
420
  # @param variable_name [String]
402
- # @return [String]
421
+ # @return [ImportJS::JSModule]
403
422
  def resolve_one_js_module(js_modules, variable_name)
404
423
  if js_modules.length == 1
405
424
  js_module = js_modules.first
@@ -421,6 +440,25 @@ module ImportJS
421
440
  js_modules[selected_index]
422
441
  end
423
442
 
443
+ # @param js_modules [Array]
444
+ # @param variable_name [String]
445
+ # @return [ImportJS::JSModule]
446
+ def resolve_goto_module(js_modules, variable_name)
447
+ return js_modules.first if js_modules.length == 1
448
+
449
+ # Look for a current import matching the goto
450
+ find_current_imports[:imports].each do |ist|
451
+ js_modules.each do |js_module|
452
+ next unless variable_name == ist.default_import ||
453
+ (ist.named_imports || []).include?(variable_name)
454
+ return js_module if ist.path == js_module.import_path
455
+ end
456
+ end
457
+
458
+ # Fall back to asking the user to resolve the ambiguity
459
+ resolve_one_js_module(js_modules, variable_name)
460
+ end
461
+
424
462
  # Takes a string in any of the following four formats:
425
463
  # dash-separated
426
464
  # snake_case
@@ -52,10 +52,28 @@ module ImportJS
52
52
  # @return [String, String]
53
53
  def self.resolve_import_path_and_main(file_path, strip_file_extensions)
54
54
  if file_path.end_with? '/package.json'
55
- main_file = JSON.parse(File.read(file_path))['main']
56
- return [nil, nil] unless main_file
57
- match = file_path.match(%r{(.*)/package\.json})
58
- return match[1], main_file
55
+ return [nil, nil] unless File.exist?(file_path)
56
+
57
+ file_contents = File.read(file_path)
58
+ return [nil, nil] if file_contents.strip.empty?
59
+
60
+ main_file = JSON.parse(file_contents)['main']
61
+ match = file_path.match(%r{(?<package>.*)/package\.json})
62
+
63
+ unless main_file
64
+ index_file = find_index(match[:package])
65
+ return [nil, nil] unless index_file
66
+ main_file = index_file
67
+ end
68
+
69
+ if File.directory?("#{match[:package]}/#{main_file}")
70
+ # The main in package.json refers to a directory, so we want to
71
+ # resolve it to an index file.
72
+ index_file = find_index("#{match[:package]}/#{main_file}")
73
+ main_file += "/#{index_file}" if index_file
74
+ end
75
+
76
+ return match[:package], main_file
59
77
  end
60
78
 
61
79
  match = file_path.match(%r{(.*)/(index\.js[^/]*)$})
@@ -66,6 +84,15 @@ module ImportJS
66
84
  [import_path, nil]
67
85
  end
68
86
 
87
+ # @param directory [String]
88
+ # @return [String, nil]
89
+ def self.find_index(directory)
90
+ %w[index.js index.jsx].each do |index_file|
91
+ return index_file if File.exist? "#{directory}/#{index_file}"
92
+ end
93
+ nil
94
+ end
95
+
69
96
  # @param import_path [String]
70
97
  def initialize(import_path: nil)
71
98
  self.import_path = import_path
@@ -110,23 +137,41 @@ module ImportJS
110
137
  # @param path_to_current_file [String]
111
138
  # @return [String]
112
139
  def open_file_path(path_to_current_file)
113
- if file_path && file_path.end_with?('/package.json')
114
- return file_path.sub(/package\.json$/, main_file)
140
+ if @file_path
141
+ # There is a file_path. This happens for JSModules that are not aliases.
142
+ return @file_path unless @file_path.end_with?('/package.json')
143
+
144
+ # The file_path points to a package.json file, so we want to look in
145
+ # that package.json file for a `main` configuration value and open that
146
+ # file instead.
147
+ return @file_path.sub(/package\.json$/, main_file)
115
148
  end
116
- return file_path if file_path
117
149
 
118
- if import_path.start_with?('.')
119
- return File.expand_path(import_path, File.dirname(path_to_current_file))
150
+ # There is no file_path. This likely means that we are working with an
151
+ # alias, so we want to expand it to a full path if we can.
152
+
153
+ if @import_path.start_with?('.')
154
+ # The import path in the alias starts with a ".", which means that it is
155
+ # relative to the current file. In order to open this file, we need to
156
+ # expand it to a full path.
157
+ return File.expand_path(
158
+ @import_path, File.dirname(path_to_current_file))
120
159
  end
121
160
 
122
- import_path
161
+ # This is likely an alias that points to a package, so let's try to find
162
+ # its main file from its package.json file.
163
+ file_path = "node_modules/#{@import_path}/package.json"
164
+ _, main = self.class.resolve_import_path_and_main(file_path, [])
165
+ return "node_modules/#{@import_path}/#{main}" if main
166
+
167
+ @import_path
123
168
  end
124
169
 
125
170
  # @param variable_name [String]
126
171
  # @param config [ImportJS::Configuration]
127
172
  # @return [ImportJS::ImportStatement]
128
173
  def to_import_statement(variable_name, config)
129
- ImportJS::ImportStatement.new.tap do |statement|
174
+ ImportStatement.new.tap do |statement|
130
175
  if has_named_exports
131
176
  statement.inject_named_import(variable_name)
132
177
  else
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Defines the gem version.
4
4
  module ImportJS
5
- VERSION = '0.4.0'.freeze
5
+ VERSION = '0.4.1'.freeze
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: import_js
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henric Trotzig