Class: ImportJS::JSModule

Inherits:
Object
  • Object
show all
Defined in:
lib/import_js/js_module.rb

Overview

Class that represents a js module found in the file system

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(import_path: nil) ⇒ JSModule

Returns a new instance of JSModule.

Parameters:

  • import_path (String) (defaults to: nil)


97
98
99
# File 'lib/import_js/js_module.rb', line 97

def initialize(import_path: nil)
  self.import_path = import_path
end

Instance Attribute Details

#file_pathObject

Returns the value of attribute file_path.



8
9
10
# File 'lib/import_js/js_module.rb', line 8

def file_path
  @file_path
end

#has_named_exportsObject

Returns the value of attribute has_named_exports.



10
11
12
# File 'lib/import_js/js_module.rb', line 10

def has_named_exports
  @has_named_exports
end

#import_pathObject

Returns the value of attribute import_path.



6
7
8
# File 'lib/import_js/js_module.rb', line 6

def import_path
  @import_path
end

#lookup_pathObject

Returns the value of attribute lookup_path.



7
8
9
# File 'lib/import_js/js_module.rb', line 7

def lookup_path
  @lookup_path
end

#main_fileObject

Returns the value of attribute main_file.



9
10
11
# File 'lib/import_js/js_module.rb', line 9

def main_file
  @main_file
end

Class Method Details

.construct(lookup_path: nil, relative_file_path: nil, strip_file_extensions: nil, make_relative_to: nil, strip_from_path: nil) ⇒ Object

Parameters:

  • lookup_path (String) (defaults to: nil)

    the lookup path in which this module was found

  • relative_file_path (String) (defaults to: nil)

    a full path to the file, relative to the project root.

  • strip_file_extensions (Array) (defaults to: nil)

    a list of file extensions to strip, e.g. [‘.js’, ‘.jsx’]

  • make_relative_to (String|nil) (defaults to: nil)

    a path to a different file which the resulting import path should be relative to.

  • strip_from_path (String) (defaults to: nil)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/import_js/js_module.rb', line 20

def self.construct(lookup_path: nil,
                   relative_file_path: nil,
                   strip_file_extensions: nil,
                   make_relative_to: nil,
                   strip_from_path: nil)
  js_module = new
  js_module.lookup_path = normalize_path(lookup_path)
  js_module.file_path = normalize_path(relative_file_path)

  import_path, main_file = resolve_import_path_and_main(
    js_module.file_path, strip_file_extensions)

  return unless import_path

  import_path.sub!(%r{^#{Regexp.escape(js_module.lookup_path)}/}, '')

  js_module.import_path = import_path
  js_module.main_file = main_file
  js_module.make_relative_to(make_relative_to) if make_relative_to
  js_module.strip_from_path!(strip_from_path) unless make_relative_to
  js_module
end

.find_index(directory) ⇒ String?

Parameters:

  • directory (String)

Returns:

  • (String, nil)


89
90
91
92
93
94
# File 'lib/import_js/js_module.rb', line 89

def self.find_index(directory)
  %w[index.js index.jsx].each do |index_file|
    return index_file if File.exist? "#{directory}/#{index_file}"
  end
  nil
end

.normalize_path(path) ⇒ String

Parameters:

  • path (String)

Returns:

  • (String)


45
46
47
48
# File 'lib/import_js/js_module.rb', line 45

def self.normalize_path(path)
  return unless path
  path.sub(%r{^\./?}, '')
end

.resolve_import_path_and_main(file_path, strip_file_extensions) ⇒ String

Parameters:

  • file_path (String)
  • strip_file_extensions (Array)

Returns:

  • (String, String)


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/import_js/js_module.rb', line 53

def self.resolve_import_path_and_main(file_path, strip_file_extensions)
  if file_path.end_with? '/package.json'
    return [nil, nil] unless File.exist?(file_path)

    file_contents = File.read(file_path)
    return [nil, nil] if file_contents.strip.empty?

    main_file = JSON.parse(file_contents)['main']
    match = file_path.match(%r{(?<package>.*)/package\.json})

    unless main_file
      index_file = find_index(match[:package])
      return [nil, nil] unless index_file
      main_file = index_file
    end

    if File.directory?("#{match[:package]}/#{main_file}")
      # The main in package.json refers to a directory, so we want to
      # resolve it to an index file.
      index_file = find_index("#{match[:package]}/#{main_file}")
      main_file += "/#{index_file}" if index_file
    end

    return match[:package], main_file
  end

  match = file_path.match(%r{(.*)/(index\.js[^/]*)$})
  return match[1], match[2] if match

  extensions = strip_file_extensions.map { |str| Regexp.escape(str) }
  import_path = file_path.sub(/(?:#{extensions.join('|')})$/, '')
  [import_path, nil]
end

Instance Method Details

#display_nameString

Returns a readable description of the module.

Returns:

  • (String)

    a readable description of the module



134
135
136
137
138
# File 'lib/import_js/js_module.rb', line 134

def display_name
  parts = [import_path]
  parts << " (main: #{@main_file})" if @main_file
  parts.join('')
end

#make_relative_to(make_relative_to) ⇒ Object

Parameters:

  • make_relative_to (String)


102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/import_js/js_module.rb', line 102

def make_relative_to(make_relative_to)
  return unless lookup_path

  # Prevent mutating the argument that was passed in
  make_relative_to = make_relative_to.dup

  # First, strip out any absolute path up until the current directory
  make_relative_to.sub!("#{Dir.pwd}/", '')

  # Ignore if the file to relate to is part of a different lookup_path
  return unless make_relative_to.start_with? lookup_path

  # Strip out the lookup_path
  make_relative_to.sub!(%r{^#{Regexp.escape(lookup_path)}/}, '')

  path = Pathname.new(import_path).relative_path_from(
    Pathname.new(File.dirname(make_relative_to))
  ).to_s

  # `Pathname.relative_path_from` will not add "./" automatically
  path = './' + path unless path.start_with?('.')

  self.import_path = path
end

#open_file_path(path_to_current_file) ⇒ String

Parameters:

  • path_to_current_file (String)

Returns:

  • (String)


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/import_js/js_module.rb', line 142

def open_file_path(path_to_current_file)
  if @file_path
    # There is a file_path. This happens for JSModules that are not aliases.
    return @file_path unless @file_path.end_with?('/package.json')

    # The file_path points to a package.json file, so we want to look in
    # that package.json file for a `main` configuration value and open that
    # file instead.
    return @file_path.sub(/package\.json$/, main_file)
  end

  # There is no file_path. This likely means that we are working with an
  # alias, so we want to expand it to a full path if we can.

  if @import_path.start_with?('.')
    # The import path in the alias starts with a ".", which means that it is
    # relative to the current file. In order to open this file, we need to
    # expand it to a full path.
    return File.expand_path(
      @import_path, File.dirname(path_to_current_file))
  end

  # This is likely an alias that points to a package, so let's try to find
  # its main file from its package.json file.
  file_path = "node_modules/#{@import_path}/package.json"
  _, main = self.class.resolve_import_path_and_main(file_path, [])
  return "node_modules/#{@import_path}/#{main}" if main

  @import_path
end

#strip_from_path!(prefix) ⇒ Object

Parameters:

  • prefix (String)


128
129
130
131
# File 'lib/import_js/js_module.rb', line 128

def strip_from_path!(prefix)
  return unless prefix
  import_path.sub!(/^#{Regexp.escape(prefix)}/, '')
end

#to_import_statement(variable_name, config) ⇒ ImportJS::ImportStatement

Parameters:

Returns:



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/import_js/js_module.rb', line 176

def to_import_statement(variable_name, config)
  if has_named_exports
    named_imports = [variable_name]
  else
    default_import = variable_name
  end

  ImportStatement.new(
    declaration_keyword:
      config.get('declaration_keyword', from_file: file_path),
    default_import: default_import,
    import_function: config.get('import_function', from_file: file_path),
    named_imports: named_imports,
    path: import_path
  )
end