importmap-plus 2.0.1 → 2.0.2
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/CHANGELOG.md +34 -0
- data/lib/importmap/doctor.rb +15 -3
- data/lib/importmap/packager.rb +54 -5
- data/lib/importmap/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '068b0fd351d34f6741037740731f5545ec5e98530ddd935abc45d18ac92b30e1'
|
|
4
|
+
data.tar.gz: 6482173bb6db3322fa43711fce8ccf0c9ac48d7b35c0b572e5b68d45f11d0445
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 22b1de80057a17f315ab8230d5537400985c9f67c1c50faa184336856de9e3e1d8f06ea815392c78a0fef30bffa3373bd25b206ab638cf056c8447faa674fe44
|
|
7
|
+
data.tar.gz: 444fca5f51ec92e43ab7163bb14ce92791727b3a93242298e776a753cc243e218f17fdf3acb6c873842012bf38867862fa37bf4eb99e0464ed8e72061254c33f
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,40 @@
|
|
|
4
4
|
|
|
5
5
|
### Fixed
|
|
6
6
|
|
|
7
|
+
- **`doctor` leaves a bundle installed inside the app alone.** A file an engine
|
|
8
|
+
serves out of its gem is skipped, because no `bin/importmap` command can fix
|
|
9
|
+
it — but "out of its gem" was read as "outside the app root". With
|
|
10
|
+
`bundle config set path vendor/bundle`, as a CI caching its gems has, the
|
|
11
|
+
gems are under the root, so an engine's controller importing a package the
|
|
12
|
+
app never pinned failed `doctor` in CI and nowhere else. Files under
|
|
13
|
+
`Gem.path` or `Bundler.bundle_path` are now skipped wherever they sit.
|
|
14
|
+
|
|
15
|
+
- **A `preload: %w[...]` survives a rewrite.** `pin`, `update` and `pristine`
|
|
16
|
+
carried over `preload: ["admin", "app"]` but not the same list written as a
|
|
17
|
+
word array, which RuboCop and Standard prefer (`Style/WordArray`). The option
|
|
18
|
+
was dropped without a word, so an updated package quietly stopped being
|
|
19
|
+
preloaded on the pages that named it. It is now read — backslash escapes and
|
|
20
|
+
nested brackets included, so `%w[my\ app]` is the one entry point Ruby sees and
|
|
21
|
+
`%w[foo [bar]]` keeps its `[bar]` — and written back in the form the app chose:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
pin "tailwindcss-stimulus-components", preload: %w[application webcad] # @6.1.3
|
|
25
|
+
# after bin/importmap update
|
|
26
|
+
pin "tailwindcss-stimulus-components", preload: %w[application webcad] # @6.1.4
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- **A quoted preload keeps a bracket or quote inside it.** `preload: ["a]", "b"]`
|
|
30
|
+
was cut at the first `]` and `preload: "it's"` at the `'`, so a rewrite wrote
|
|
31
|
+
back a shorter list or a different entry point. Quoted strings are now read
|
|
32
|
+
whole, and a quoted preload — one entry point or a bracketed list — is written
|
|
33
|
+
back exactly as the app wrote it, quotes included, so `"\u0061pp"` stays the
|
|
34
|
+
`app` entry point and `"#{prefix}app"` still interpolates (both used to come
|
|
35
|
+
back as a different name). `preload: 'say "hi"'` no longer becomes `"say "hi""`.
|
|
36
|
+
|
|
37
|
+
## 2.0.1
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
7
41
|
- **`bin/importmap doctor` no longer reports comments and prose as unpinned
|
|
8
42
|
imports.** The import scanner read `from "…"` and `import "…"` wherever the
|
|
9
43
|
text appeared, so a line comment such as `// e.g. 'en' from 'en-US'` and
|
data/lib/importmap/doctor.rb
CHANGED
|
@@ -59,11 +59,18 @@ class Importmap::Doctor
|
|
|
59
59
|
# against the importing file's own URL, or fetches outright, is not one.
|
|
60
60
|
SCHEME_REGEXP = %r{\A[a-zA-Z][a-zA-Z0-9+\-.]*:}.freeze # :nodoc:
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
# Where installed gems live: the default +gem_paths+. A bundle installed
|
|
63
|
+
# with `path: vendor/bundle` puts Bundler's under the app root.
|
|
64
|
+
def self.gem_paths
|
|
65
|
+
[ *Gem.path, (Bundler.bundle_path.to_s if defined?(Bundler)) ].compact.uniq
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def initialize(importmap:, resolver:, root:, asset_paths: [], gem_paths: self.class.gem_paths, online: false)
|
|
63
69
|
@importmap = importmap
|
|
64
70
|
@resolver = resolver
|
|
65
71
|
@root = Pathname.new(root)
|
|
66
72
|
@asset_paths = Array(asset_paths).map { |path| Pathname.new(path) }
|
|
73
|
+
@gem_paths = Array(gem_paths).map { |path| Pathname.new(path) }
|
|
67
74
|
@online = online
|
|
68
75
|
end
|
|
69
76
|
|
|
@@ -188,9 +195,14 @@ class Importmap::Doctor
|
|
|
188
195
|
|
|
189
196
|
# The files this gem may read: the app's own, not a file an engine serves
|
|
190
197
|
# out of its gem, which no `bin/importmap` command can do anything about.
|
|
191
|
-
#
|
|
198
|
+
# Being under the root isn't enough to be the app's: a bundle installed
|
|
199
|
+
# into vendor/bundle is too. One file serving two keys is scanned once.
|
|
192
200
|
def scannable
|
|
193
|
-
@scannable ||= entries.select { |entry| entry.file &&
|
|
201
|
+
@scannable ||= entries.select { |entry| entry.file && app_file?(entry.file) }.uniq(&:file)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def app_file?(file)
|
|
205
|
+
under?(file, @root) && @gem_paths.none? { |gem_path| under?(file, gem_path) }
|
|
194
206
|
end
|
|
195
207
|
|
|
196
208
|
def vendored
|
data/lib/importmap/packager.rb
CHANGED
|
@@ -13,10 +13,47 @@ class Importmap::Packager
|
|
|
13
13
|
include Importmap::HttpRetries
|
|
14
14
|
|
|
15
15
|
PIN_REGEX = /#{Importmap::Map::PIN_REGEX}(.*)/.freeze # :nodoc:
|
|
16
|
+
# A Ruby string literal, escapes included, so a quote or bracket inside one
|
|
17
|
+
# doesn't end the match early (`"it's"`, `["a]"]`).
|
|
18
|
+
QUOTED_STRING_REGEXP = /"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'/m.freeze # :nodoc:
|
|
16
19
|
# The bracketed form matches an empty array too: `preload: []` is a pin an
|
|
17
20
|
# app wrote, and a rewrite that dropped it would start preloading the package
|
|
18
|
-
# on every page.
|
|
19
|
-
|
|
21
|
+
# on every page. A word array nests its own delimiter the way Ruby does
|
|
22
|
+
# (`%w[foo [bar]]` is "foo" and "[bar]"), hence the recursive groups; with
|
|
23
|
+
# named groups in the pattern, the value has to be named too to stay [1].
|
|
24
|
+
PRELOAD_OPTION_REGEXP = /preload:\s*(?<value>\[(?:#{QUOTED_STRING_REGEXP}|[^\]"'])*\]|%w(?<brackets>\[(?:\\.|[^\[\]\\]|\g<brackets>)*\])|%w(?<parens>\((?:\\.|[^()\\]|\g<parens>)*\))|true|false|#{QUOTED_STRING_REGEXP})/.freeze # :nodoc:
|
|
25
|
+
# A `preload: %w[...]` read from a pin, so a rewrite writes it back in the
|
|
26
|
+
# form the app chose (RuboCop's Style/WordArray flags `["a", "b"]`). Read
|
|
27
|
+
# with Ruby's escapes rather than split on whitespace: `%w[my\ app]` is one
|
|
28
|
+
# word, and a backslash before anything but whitespace, a backslash or the
|
|
29
|
+
# literal's own delimiter stays in it.
|
|
30
|
+
class WordArray < Array # :nodoc:
|
|
31
|
+
LITERAL_REGEXP = /\A%w([\[(])(.*)[\])]\z/m.freeze
|
|
32
|
+
|
|
33
|
+
def self.parse(literal)
|
|
34
|
+
open, body = literal.match(LITERAL_REGEXP)&.captures
|
|
35
|
+
return unless open
|
|
36
|
+
|
|
37
|
+
escapable = /\\([\s\\#{Regexp.escape(open == "[" ? "[]" : "()")}])/
|
|
38
|
+
new(body.scan(/(?:\\.|[^\s\\])+/m).map { |word| word.gsub(escapable, '\1') })
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_s
|
|
42
|
+
"%w[#{map { |word| word.gsub(/[\s\\\[\]]/) { "\\#{$&}" } }.join(" ")}]"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
# A quoted preload read from a pin — a string or a bracketed array — keeps
|
|
46
|
+
# the literal it was read from, and a rewrite writes that back untouched.
|
|
47
|
+
# The names are read with only the simple escapes; the rest of Ruby's string
|
|
48
|
+
# semantics ("\u0061pp", "#{prefix}app") is Ruby's to evaluate, so writing
|
|
49
|
+
# the value read back through inspect would change the entry point.
|
|
50
|
+
module Literal # :nodoc:
|
|
51
|
+
attr_accessor :source
|
|
52
|
+
|
|
53
|
+
def self.of(value, source)
|
|
54
|
+
value.extend(self).tap { |literal| literal.source = source }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
20
57
|
TO_OPTION_REGEXP = /to:\s*["']([^"']*)["']/.freeze # :nodoc:
|
|
21
58
|
# Only the booleans: a hash string is tied to the file it was computed for,
|
|
22
59
|
# so a rewrite that changes the URL has to drop it.
|
|
@@ -537,21 +574,33 @@ class Importmap::Packager
|
|
|
537
574
|
true
|
|
538
575
|
when "false"
|
|
539
576
|
false
|
|
577
|
+
when WordArray::LITERAL_REGEXP
|
|
578
|
+
WordArray.parse(value)
|
|
540
579
|
when /^\[.*\]$/
|
|
541
580
|
# config/importmap.rb is Ruby, not JSON, and a single-quoted pin is a
|
|
542
581
|
# supported shape here, so the entry points are scanned out of the
|
|
543
582
|
# literal rather than parsed. JSON.parse raised on every one of them.
|
|
544
|
-
value.scan(
|
|
583
|
+
Literal.of(value.scan(QUOTED_STRING_REGEXP).map { |double, single| unquote(double, single) }, value)
|
|
545
584
|
else
|
|
546
|
-
value.
|
|
585
|
+
Literal.of(unquote(*value.match(/\A#{QUOTED_STRING_REGEXP}\z/).captures), value)
|
|
547
586
|
end
|
|
548
587
|
end
|
|
549
588
|
|
|
589
|
+
# A single-quoted string unescapes only \\ and \'. In a double-quoted one
|
|
590
|
+
# a backslash before any character an entry point would hold is that
|
|
591
|
+
# character, which is all a preload name needs. The value is only read;
|
|
592
|
+
# a rewrite writes the Literal's source.
|
|
593
|
+
def unquote(double, single)
|
|
594
|
+
double ? double.gsub(/\\(.)/m, '\1') : single.gsub(/\\([\\'])/, '\1')
|
|
595
|
+
end
|
|
596
|
+
|
|
550
597
|
def preload(preloads)
|
|
551
598
|
# nil is "the pin carries no preload:"; [] is the pin carrying one that
|
|
552
599
|
# names no entry point. Array() flattens both to [], so the difference
|
|
553
600
|
# has to be read before it.
|
|
554
601
|
return "" if preloads.nil?
|
|
602
|
+
return %(, preload: #{preloads}) if preloads.is_a?(WordArray)
|
|
603
|
+
return %(, preload: #{preloads.source}) if preloads.is_a?(Literal)
|
|
555
604
|
|
|
556
605
|
case Array(preloads)
|
|
557
606
|
in []
|
|
@@ -561,7 +610,7 @@ class Importmap::Packager
|
|
|
561
610
|
in ["false"] | [false]
|
|
562
611
|
%(, preload: false)
|
|
563
612
|
in [string]
|
|
564
|
-
%(, preload:
|
|
613
|
+
%(, preload: #{string.to_s.inspect})
|
|
565
614
|
else
|
|
566
615
|
%(, preload: #{preloads})
|
|
567
616
|
end
|
data/lib/importmap/version.rb
CHANGED