import_js 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|