import_js 0.3.1 → 0.4.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/bin/import-js +2 -2
- data/lib/import_js/command_line_editor.rb +4 -9
- data/lib/import_js/configuration.rb +65 -39
- data/lib/import_js/emacs_editor.rb +137 -137
- data/lib/import_js/import_statement.rb +81 -76
- data/lib/import_js/importer.rb +227 -102
- data/lib/import_js/js_module.rb +97 -54
- data/lib/import_js/version.rb +3 -1
- data/lib/import_js/vim_editor.rb +2 -2
- data/lib/import_js.rb +8 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2a0036427b0f66373fcbc6fda702570d501f281
|
4
|
+
data.tar.gz: 9c798047e26eb9189e169c5395ed1bd41b03e2fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4eaed3ab7c8204e62a7b19bdad9cf002384f6797cd15fe6f6615763ebcda6f8cf607cbb3127f8c494082a53f84684c17e383544f897cd368ae0074101676dc5d
|
7
|
+
data.tar.gz: 43c8abdad3178c4df5c6f04a7030737daa9d2cb4e83cb777e6dbde088a5a43dffa2690ae13e1b1950ce915dc01f5252a75d4747883a9d0777124cf7353541e64
|
data/bin/import-js
CHANGED
@@ -9,7 +9,7 @@ opts = Slop.parse do |o|
|
|
9
9
|
o.bool '--goto', 'instead of importing, just print the path to a module'
|
10
10
|
o.array '--selections', 'a list of resolved selections, e.g. Foo:0,Bar:1'
|
11
11
|
o.string '--filename',
|
12
|
-
|
12
|
+
'a path to the file which contents are being passed in as stdin'
|
13
13
|
o.on '-v', '--version', 'print the current version' do
|
14
14
|
puts ImportJS::VERSION
|
15
15
|
exit
|
@@ -50,7 +50,7 @@ end
|
|
50
50
|
|
51
51
|
# Print messages to stderr
|
52
52
|
meta = {
|
53
|
-
messages: editor.messages
|
53
|
+
messages: editor.messages,
|
54
54
|
}
|
55
55
|
ask = editor.ask_for_selections
|
56
56
|
meta[:ask_for_selections] = ask unless ask.empty?
|
@@ -1,4 +1,5 @@
|
|
1
1
|
module ImportJS
|
2
|
+
# This is the implementation of command line integration in Import-JS.
|
2
3
|
class CommandLineEditor
|
3
4
|
def initialize(lines, opts)
|
4
5
|
@lines = lines
|
@@ -24,20 +25,14 @@ module ImportJS
|
|
24
25
|
@goto = file_path
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
-
def goto
|
29
|
-
@goto
|
30
|
-
end
|
28
|
+
attr_reader :goto
|
31
29
|
|
32
30
|
# @param str [String]
|
33
31
|
def message(str)
|
34
32
|
@messages << str
|
35
33
|
end
|
36
34
|
|
37
|
-
|
38
|
-
def ask_for_selections
|
39
|
-
@ask_for_selections
|
40
|
-
end
|
35
|
+
attr_reader :ask_for_selections
|
41
36
|
|
42
37
|
# @return [String]
|
43
38
|
def current_file_content
|
@@ -110,7 +105,7 @@ module ImportJS
|
|
110
105
|
else
|
111
106
|
@ask_for_selections << {
|
112
107
|
word: word,
|
113
|
-
alternatives: alternatives
|
108
|
+
alternatives: alternatives,
|
114
109
|
}
|
115
110
|
nil
|
116
111
|
end
|
@@ -1,42 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'json'
|
2
3
|
require 'open3'
|
3
4
|
|
4
5
|
module ImportJS
|
5
|
-
CONFIG_FILE = '.importjs.json'
|
6
|
+
CONFIG_FILE = '.importjs.json'.freeze
|
6
7
|
|
7
8
|
DEFAULT_CONFIG = {
|
8
9
|
'aliases' => {},
|
9
10
|
'declaration_keyword' => 'import',
|
11
|
+
'named_exports' => {},
|
10
12
|
'eslint_executable' => 'eslint',
|
11
13
|
'excludes' => [],
|
12
14
|
'ignore_package_prefixes' => [],
|
15
|
+
'import_dev_dependencies' => false,
|
16
|
+
'import_function' => 'require',
|
13
17
|
'lookup_paths' => ['.'],
|
18
|
+
'minimum_version' => '0.0.0',
|
14
19
|
'strip_file_extensions' => ['.js', '.jsx'],
|
15
|
-
'
|
16
|
-
|
20
|
+
'strip_from_path' => nil,
|
21
|
+
'use_relative_paths' => false,
|
22
|
+
}.freeze
|
17
23
|
|
18
24
|
# Class that initializes configuration from a .importjs.json file
|
19
25
|
class Configuration
|
20
|
-
def initialize
|
21
|
-
@
|
22
|
-
|
26
|
+
def initialize(path_to_current_file)
|
27
|
+
@path_to_current_file = normalize_path(path_to_current_file)
|
28
|
+
@configs = []
|
29
|
+
user_config = load_config(CONFIG_FILE)
|
30
|
+
@configs.concat([user_config].flatten.reverse) if user_config
|
31
|
+
@configs << DEFAULT_CONFIG
|
23
32
|
|
24
|
-
|
25
|
-
return if @config_time == config_file_last_modified
|
26
|
-
@config = DEFAULT_CONFIG.merge(load_config)
|
33
|
+
check_current_version!
|
27
34
|
end
|
28
35
|
|
29
36
|
# @return [Object] a configuration value
|
30
|
-
def get(key)
|
31
|
-
@config
|
37
|
+
def get(key, from_file: nil)
|
38
|
+
@configs.find do |config|
|
39
|
+
applies_to = config['applies_to'] || '*'
|
40
|
+
applies_from = config['applies_from'] || '*'
|
41
|
+
next unless config.key?(key)
|
42
|
+
File.fnmatch(normalize_path(applies_to), @path_to_current_file) &&
|
43
|
+
File.fnmatch(normalize_path(applies_from), normalize_path(from_file))
|
44
|
+
end[key]
|
32
45
|
end
|
33
46
|
|
34
47
|
# @param variable_name [String]
|
35
48
|
# @param path_to_current_file [String?]
|
36
49
|
# @return [ImportJS::JSModule?]
|
37
50
|
def resolve_alias(variable_name, path_to_current_file)
|
38
|
-
path =
|
39
|
-
return
|
51
|
+
path = get('aliases')[variable_name]
|
52
|
+
return unless path
|
40
53
|
|
41
54
|
path = path['path'] if path.is_a? Hash
|
42
55
|
|
@@ -44,21 +57,18 @@ module ImportJS
|
|
44
57
|
path = path.sub(/\{filename\}/,
|
45
58
|
File.basename(path_to_current_file, '.*'))
|
46
59
|
end
|
47
|
-
ImportJS::JSModule.new(
|
48
|
-
relative_file_path: path,
|
49
|
-
strip_file_extensions: [])
|
60
|
+
ImportJS::JSModule.new(import_path: path)
|
50
61
|
end
|
51
62
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
63
|
+
# @param variable_name [String]
|
64
|
+
# @return [ImportJS::JSModule?]
|
65
|
+
def resolve_named_exports(variable_name)
|
66
|
+
get('named_exports').each do |import_path, named_exports|
|
67
|
+
next unless named_exports.include?(variable_name)
|
68
|
+
|
69
|
+
js_module = ImportJS::JSModule.new(import_path: import_path)
|
70
|
+
js_module.has_named_exports = true
|
71
|
+
return js_module
|
62
72
|
end
|
63
73
|
nil
|
64
74
|
end
|
@@ -67,26 +77,42 @@ module ImportJS
|
|
67
77
|
def package_dependencies
|
68
78
|
return [] unless File.exist?('package.json')
|
69
79
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
dependencies.concat(peer_dependencies)
|
80
|
+
keys = %w[dependencies peerDependencies]
|
81
|
+
keys << 'devDependencies' if get('import_dev_dependencies')
|
82
|
+
package_json = JSON.parse(File.read('package.json'))
|
83
|
+
keys.map do |key|
|
84
|
+
package_json[key].keys if package_json[key]
|
85
|
+
end.compact.flatten
|
77
86
|
end
|
78
87
|
|
79
88
|
private
|
80
89
|
|
90
|
+
# @param file [File]
|
81
91
|
# @return [Hash]
|
82
|
-
def load_config
|
83
|
-
|
84
|
-
|
92
|
+
def load_config(file)
|
93
|
+
return unless File.exist?(file)
|
94
|
+
JSON.parse(File.read(file))
|
95
|
+
end
|
96
|
+
|
97
|
+
# @param path [String]
|
98
|
+
# @return [String]
|
99
|
+
def normalize_path(path)
|
100
|
+
return './' unless path
|
101
|
+
path = path.sub(/^#{Regexp.escape(Dir.pwd)}/, '.')
|
102
|
+
path = "./#{path}" unless path.start_with?('.')
|
103
|
+
path
|
85
104
|
end
|
86
105
|
|
87
|
-
#
|
88
|
-
|
89
|
-
|
106
|
+
# Checks that the current version is bigger than the `minimum_version`
|
107
|
+
# defined in config. Raises an error if it doesn't match.
|
108
|
+
def check_current_version!
|
109
|
+
minimum_version = get('minimum_version')
|
110
|
+
return if Gem::Dependency.new('', ">= #{minimum_version}")
|
111
|
+
.match?('', ImportJS::VERSION)
|
112
|
+
|
113
|
+
fail ImportJS::ClientTooOldError,
|
114
|
+
'The .importjs.json file you are using requires version ' \
|
115
|
+
"#{get('minimum_version')}. You are using #{ImportJS::VERSION}."
|
90
116
|
end
|
91
117
|
end
|
92
118
|
end
|
@@ -1,159 +1,159 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module ImportJS
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
3
|
+
# This is the implementation of the emacs integration in Import-JS.
|
4
|
+
class EmacsEditor
|
5
|
+
attr_accessor :current_word
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
loop do
|
9
|
+
input = gets.chomp
|
10
|
+
command, value, path = input.split(':')
|
11
|
+
|
12
|
+
begin
|
13
|
+
@path = path
|
14
|
+
@file = File.readlines(path).map(&:chomp)
|
15
|
+
@current_word = value
|
16
|
+
|
17
|
+
case command
|
18
|
+
when 'import'
|
19
|
+
ImportJS::Importer.new(self).import
|
20
|
+
write_file
|
21
|
+
puts 'import:success'
|
22
|
+
when 'goto'
|
23
|
+
ImportJS::Importer.new(self).goto
|
24
|
+
when 'fix'
|
25
|
+
ImportJS::Importer.new(self).fix_imports
|
26
|
+
write_file
|
27
|
+
puts 'import:success'
|
28
|
+
else
|
29
|
+
puts "unknown command: #{command}"
|
30
|
+
end
|
31
|
+
rescue Exception => e
|
32
|
+
puts e.inspect
|
31
33
|
end
|
32
|
-
rescue Exception => e
|
33
|
-
puts e.inspect
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
37
|
+
def write_file
|
38
|
+
new_file = File.open(@path, 'w')
|
39
|
+
@file.each { |line| new_file.puts(line) }
|
40
|
+
new_file.close
|
41
|
+
end
|
43
42
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
43
|
+
# Open a file specified by a path.
|
44
|
+
#
|
45
|
+
# @param file_path [String]
|
46
|
+
def open_file(file_path)
|
47
|
+
puts "goto:success:#{File.expand_path(file_path)}"
|
48
|
+
end
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
# Get the path to the file currently being edited. May return `nil` if an
|
51
|
+
# anonymous file is being edited.
|
52
|
+
#
|
53
|
+
# @return [String?]
|
54
|
+
def path_to_current_file
|
55
|
+
@path
|
56
|
+
end
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
58
|
+
# Display a message to the user.
|
59
|
+
#
|
60
|
+
# @param str [String]
|
61
|
+
def message(str)
|
62
|
+
puts str
|
63
|
+
end
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
65
|
+
# Read the entire file into a string.
|
66
|
+
#
|
67
|
+
# @return [String]
|
68
|
+
def current_file_content
|
69
|
+
@file.join("\n")
|
70
|
+
end
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
72
|
+
# Reads a line from the file.
|
73
|
+
#
|
74
|
+
# Lines are one-indexed, so 1 means the first line in the file.
|
75
|
+
# @return [String]
|
76
|
+
def read_line(line_number)
|
77
|
+
@file[line_number - 1]
|
78
|
+
end
|
80
79
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
80
|
+
# Get the cursor position.
|
81
|
+
#
|
82
|
+
# @return [Array(Number, Number)]
|
83
|
+
def cursor
|
84
|
+
[0, 0]
|
85
|
+
end
|
87
86
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
87
|
+
# Place the cursor at a specified position.
|
88
|
+
#
|
89
|
+
# @param position_tuple [Array(Number, Number)] the row and column to place
|
90
|
+
# the cursor at.
|
91
|
+
def cursor=(position_tuple)
|
92
|
+
end
|
94
93
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
94
|
+
# Delete a line.
|
95
|
+
#
|
96
|
+
# @param line_number [Number] One-indexed line number.
|
97
|
+
# 1 is the first line in the file.
|
98
|
+
def delete_line(line_number)
|
99
|
+
@file.delete_at(line_number - 1)
|
100
|
+
end
|
102
101
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
102
|
+
# Append a line right after the specified line.
|
103
|
+
#
|
104
|
+
# Lines are one-indexed, but you need to support appending to line 0 (add
|
105
|
+
# content at top of file).
|
106
|
+
# @param line_number [Number]
|
107
|
+
def append_line(line_number, str)
|
108
|
+
@file.insert(line_number, str)
|
109
|
+
end
|
111
110
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
111
|
+
# Count the number of lines in the file.
|
112
|
+
#
|
113
|
+
# @return [Number] the number of lines in the file
|
114
|
+
def count_lines
|
115
|
+
@file.size
|
116
|
+
end
|
118
117
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
selected_index = VIM.evaluate("inputlist(#{escaped_list_string})")
|
139
|
-
return if selected_index < 1
|
140
|
-
selected_index - 1
|
141
|
-
end
|
118
|
+
# Ask the user to select something from a list of alternatives.
|
119
|
+
#
|
120
|
+
# @param word [String] The word/variable to import
|
121
|
+
# @param alternatives [Array<String>] A list of alternatives
|
122
|
+
# @return [Number, nil] the index of the selected alternative, or nil if
|
123
|
+
# nothing was selected.
|
124
|
+
def ask_for_selection(word, alternatives)
|
125
|
+
puts 'asking for selection'
|
126
|
+
puts "ImportJS: Pick JS module to import for '#{word}':"
|
127
|
+
puts JSON.pretty_generate(alternatives)
|
128
|
+
return
|
129
|
+
|
130
|
+
# need to implement this
|
131
|
+
escaped_list = [heading]
|
132
|
+
escaped_list << alternatives.each_with_index.map do |alternative, i|
|
133
|
+
"\"#{i + 1}: #{alternative}\""
|
134
|
+
end
|
135
|
+
escaped_list_string = '[' + escaped_list.join(',') + ']'
|
142
136
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
end
|
137
|
+
selected_index = VIM.evaluate("inputlist(#{escaped_list_string})")
|
138
|
+
return if selected_index < 1
|
139
|
+
selected_index - 1
|
140
|
+
end
|
148
141
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
142
|
+
# Get the preferred max length of a line
|
143
|
+
# @return [Number?]
|
144
|
+
def max_line_length
|
145
|
+
80
|
146
|
+
end
|
147
|
+
|
148
|
+
# @return [String] shiftwidth number of spaces if expandtab is not set,
|
149
|
+
# otherwise `\t`
|
150
|
+
def tab
|
151
|
+
' ' * shift_width || 2
|
152
|
+
end
|
154
153
|
|
155
|
-
|
156
|
-
|
157
|
-
|
154
|
+
# @return [Number?]
|
155
|
+
def shift_width
|
156
|
+
2
|
157
|
+
end
|
158
158
|
end
|
159
159
|
end
|