upload_d_n_d 0.9.3 → 0.9.4

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
  SHA256:
3
- metadata.gz: 5c93f26a694496d5e6582aaeb7d7d2f723b58fd1684de65da9e6870f099d04b0
4
- data.tar.gz: e23c03f1241c7f9488696230c73ebe56e0cf90cebebadaff5c4b76c40d9b77f3
3
+ metadata.gz: 2bc35467ae9c71f396f1168a6c900f8a828e87ad9491b99abd0f07c3ebfe49ab
4
+ data.tar.gz: 477cb07d1fda946dfccea4181327a4a5c8ce978998c2183a7fd7b38f1fd1ff6d
5
5
  SHA512:
6
- metadata.gz: 5f0b4d1593e58c8f0ebec99a3828f5f5754bf38bf3f3e0d8540b6b1f0b3034a23e6667a68a4f0dbb6a37f074bc258764af46c60a3232c19056bd4dc9333edc2f
7
- data.tar.gz: 2fe89e1d9d7d865a309d90e3ec4b80e9bbdb68d12edc0b2848de55c61d58d7a663d0cdc1b87de600242d5ece0e62cc16b2c27a775123efdd4ae102e10b4360fb
6
+ metadata.gz: '09adbe224dd2403b21da5e590e667686dea3c514f9c6c5a11f8cd2b528cf2506883cc283e99b916795afaf9a3278b7ff31c8aa9de41cb8a2ff3b403c5c947d29'
7
+ data.tar.gz: b5427eda02e120647c435f27df467126cbe24faa060260cd71833b02c57f4aa5adca316db0f6354606b20e632113eb1a48edeba72b8c5928aa94270ee44818fa
data/README.md CHANGED
@@ -55,6 +55,8 @@ The installer adds `view_component` and `stimulus-rails` if missing, creates the
55
55
 
56
56
  Everything else (JS, CSS, components, concerns) is served from the gem: upgrading is a `bundle update`.
57
57
 
58
+ With **jsbundling-rails** (bun/esbuild), the `upload_d_n_d:link_js` task copies the gem's JS/CSS into `node_modules/upload_d_n_d` so your bundler can resolve `import "upload_d_n_d"` and `@import "upload_d_n_d/styles"`. It is a real directory (not a symlink), so the gem's own imports of `@hotwired/stimulus` and `@rails/activestorage` resolve against your app's `node_modules`. The task runs automatically on `javascript:build` (so `assets:precompile` at deploy is always up to date). Note: a watch-mode dev server such as `bin/dev` calls the bundler directly and does **not** run the task, so after upgrading the gem run `bin/rails javascript:build` once locally to refresh the copy.
59
+
58
60
  ActiveStorage must be installed (`bin/rails active_storage:install`). With an external S3-like bucket and a strict CSP, serve files same-origin:
59
61
 
60
62
  ```ruby
data/docs/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.4] - 2026-10-29
11
+
12
+ `link_js` copie le JS/CSS dans `node_modules` au lieu d'un lien symbolique, pour que les imports tiers de la gem se résolvent dans l'app (jsbundling/bun/esbuild). Patch, sans changement d'API.
13
+
14
+ ### Changed
15
+ - **`upload_d_n_d:link_js` copie désormais le JS au lieu de créer un lien symbolique** — le JS de la gem importe `@hotwired/stimulus` et `@rails/activestorage`, que l'app hôte fournit dans ses propres `node_modules`. Avec un lien symbolique, le bundler (bun/esbuild) résolvait ces imports depuis le `realpath` du lien (le dossier de la gem, hors de l'app) et ne les trouvait pas — la compilation échouait (y compris à la construction de l'image de déploiement). La tâche copie maintenant `package.json` et les fichiers des `exports` dans `node_modules/upload_d_n_d` (vrai dossier), ce qui laisse la résolution remonter jusqu'aux dépendances de l'app. La copie est rafraîchie quand la version de la gem change ; un dossier ou fichier **non géré par la gem** (ex. paquet npm) n'est jamais supprimé (avertissement). Un ancien lien symbolique (gem ≤ 0.9.3) est remplacé par la copie au premier `rake upload_d_n_d:link_js` (ou `javascript:build`).
16
+
17
+ ### Migration
18
+ - Les apps qui avaient ajouté `NODE_PATH=node_modules` à leur script de build pour contourner le problème en 0.9.3 peuvent **retirer ce réglage** après passage en 0.9.4 : la copie rend la résolution correcte sans configuration côté app.
19
+
10
20
  ## [0.9.3] - 2026-10-29
11
21
 
12
22
  Correctifs d'empaquetage pour la consommation de la gem via jsbundling (bun/esbuild) et Tailwind. Patch, sans changement d'API.
@@ -1,21 +1,21 @@
1
1
  require "upload_d_n_d/js_link"
2
2
 
3
3
  namespace :upload_d_n_d do
4
- desc "Link gem JS into node_modules for jsbundling compatibility"
4
+ desc "Copy gem JS into node_modules for jsbundling compatibility"
5
5
  task :link_js do
6
6
  gem_spec = Gem.loaded_specs["upload_d_n_d"]
7
7
  next unless gem_spec
8
8
 
9
- gem_path = gem_spec.gem_dir
10
- link_path = Rails.root.join("node_modules", "upload_d_n_d")
9
+ gem_path = gem_spec.gem_dir
10
+ dest = Rails.root.join("node_modules", "upload_d_n_d")
11
11
 
12
- case UploadDND::JsLink.reconcile(link_path: link_path, target: gem_path)
13
- when :created then puts "upload_d_n_d: linked JS #{link_path} → #{gem_path}"
14
- when :updated then puts "upload_d_n_d: relinked JS #{link_path} → #{gem_path}"
12
+ case UploadDND::JsLink.sync(source: gem_path, dest: dest)
13
+ when :created then puts "upload_d_n_d: copied JS → #{dest}"
14
+ when :updated then puts "upload_d_n_d: updated JS → #{dest}"
15
15
  when :conflict
16
- warn "upload_d_n_d: #{link_path} existe et n'est pas un lien géré par la gem ; " \
16
+ warn "upload_d_n_d: #{dest} existe et n'est pas géré par la gem ; " \
17
17
  "laissé tel quel (rien supprimé). Retirez-le pour permettre à " \
18
- "`rake upload_d_n_d:link_js` de créer le lien vers #{gem_path}."
18
+ "`rake upload_d_n_d:link_js` d'y copier le JS de la gem."
19
19
  end
20
20
  end
21
21
  end
@@ -1,62 +1,114 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fileutils"
4
+ require "json"
4
5
 
5
6
  module UploadDND
6
- # Réconcilie le lien symbolique `node_modules/upload_d_n_d` utilisé par
7
- # jsbundling (bun/esbuild) et Tailwind pour résoudre `upload_d_n_d` et
8
- # `upload_d_n_d/styles` depuis le paquet de la gem.
7
+ # Synchronise `node_modules/upload_d_n_d` avec le JS/CSS de la gem
8
+ # (`package.json` + les fichiers de ses `exports`) en les **copiant**.
9
9
  #
10
- # Idempotent, et corrige deux cas que la simple présence du lien masquait :
11
- # un lien périmé pointant vers une version précédente de la gem (montée de
12
- # version), et un lien cassé dont la cible a disparu (où `ln_s` échouerait,
13
- # le lien existant déjà).
10
+ # Pourquoi une copie et non un lien symbolique : le JS de la gem importe des
11
+ # bibliothèques tierces (`@hotwired/stimulus`, `@rails/activestorage`) que
12
+ # l'app hôte fournit dans ses propres `node_modules`. Un lien symbolique est
13
+ # résolu vers son `realpath` (le dossier de la gem, hors de l'app) et la
14
+ # résolution de ces imports y échoue. Un vrai dossier sous les `node_modules`
15
+ # de l'app laisse la résolution remonter jusqu'aux dépendances de l'app.
14
16
  #
15
- # Ne gère que les liens symboliques. Un vrai dossier ou fichier à cet
16
- # emplacement (par ex. un paquet installé par npm) n'est jamais supprimé ni
17
- # écrasé : la méthode signale un conflit (`:conflict`) et laisse l'appelant
18
- # avertir.
17
+ # La copie est rafraîchie quand la version de la gem change. Un dossier ou
18
+ # fichier **non géré par la gem** (ex. paquet installé par npm) n'est jamais
19
+ # supprimé : la méthode signale un conflit et laisse l'appelant avertir.
19
20
  module JsLink
21
+ PACKAGE_NAME = "upload_d_n_d"
22
+
20
23
  module_function
21
24
 
22
- # Crée ou met à jour le lien `link_path` vers `target`.
25
+ # Copie/rafraîchit le JS de la gem depuis `source` (gem_dir) vers `dest`
26
+ # (node_modules/upload_d_n_d).
23
27
  #
24
- # @param link_path [String, Pathname] emplacement du lien (node_modules/upload_d_n_d)
25
- # @param target [String, Pathname] répertoire cible (gem_dir de la gem courante)
28
+ # @param source [String, Pathname] répertoire de la gem (gem_dir)
29
+ # @param dest [String, Pathname] destination dans node_modules
26
30
  # @return [Symbol] :created, :updated, :unchanged ou :conflict
27
- def reconcile(link_path:, target:)
28
- link = link_path.to_s
29
- target = target.to_s
31
+ def sync(source:, dest:)
32
+ source = source.to_s
33
+ dest = dest.to_s
30
34
 
31
- if File.symlink?(link)
32
- return :unchanged if resolves_to?(link, target)
35
+ if File.symlink?(dest)
36
+ replace(source, dest) # ancien lien symbolique (gem <= 0.9.3)
37
+ :updated
38
+ elsif File.directory?(dest)
39
+ return :conflict unless ours?(dest) # dossier étranger : on n'y touche jamais
40
+ return :unchanged if same_version?(source, dest)
33
41
 
34
- File.unlink(link) # lien périmé, cassé, ou pointant ailleurs
35
- link!(link, target)
42
+ replace(source, dest) # notre copie, version périmée
36
43
  :updated
37
- elsif File.exist?(link)
38
- :conflict # vrai dossier/fichier (ex. installé par npm) : on n'y touche jamais
44
+ elsif File.exist?(dest)
45
+ :conflict # fichier étranger
39
46
  else
40
- link!(link, target)
47
+ copy(source, dest)
41
48
  :created
42
49
  end
43
50
  end
44
51
 
45
- # Confronte la cible réelle du lien au dossier de la gem, après résolution
46
- # des deux chemins (chemin relatif, lien intermédiaire) : un lien qui pointe
47
- # déjà vers la bonne gem par un chemin indirect n'est pas remplacé. Un lien
48
- # cassé ne résout pas (ENOENT) et n'est donc jamais considéré comme à jour.
49
- def resolves_to?(link, target)
50
- File.realpath(link) == File.realpath(target)
51
- rescue Errno::ENOENT
52
+ # Le dossier est-il une copie gérée par la gem (et non un paquet étranger) ?
53
+ def ours?(dest)
54
+ pkg = File.join(dest, "package.json")
55
+ File.file?(pkg) && read_json(pkg)["name"] == PACKAGE_NAME
56
+ rescue JSON::ParserError
52
57
  false
53
58
  end
54
- private_class_method :resolves_to?
59
+ private_class_method :ours?
60
+
61
+ def same_version?(source, dest)
62
+ read_json(File.join(source, "package.json"))["version"] ==
63
+ read_json(File.join(dest, "package.json"))["version"]
64
+ end
65
+ private_class_method :same_version?
66
+
67
+ def replace(source, dest)
68
+ FileUtils.remove_entry(dest)
69
+ copy(source, dest)
70
+ end
71
+ private_class_method :replace
72
+
73
+ # Copie `package.json` et les fichiers référencés par ses `exports`, en
74
+ # conservant leurs chemins relatifs (les `exports` les désignent ainsi).
75
+ def copy(source, dest)
76
+ package_files(source).each do |rel|
77
+ from = File.join(source, rel)
78
+ to = File.join(dest, rel)
79
+ FileUtils.mkdir_p(File.dirname(to))
80
+ FileUtils.cp(from, to)
81
+ end
82
+ end
83
+ private_class_method :copy
84
+
85
+ def package_files(source)
86
+ exports = read_json(File.join(source, "package.json"))["exports"] || {}
87
+ targets = []
88
+ collect = lambda do |value|
89
+ case value
90
+ when String then targets << value
91
+ when Hash then value.each_value(&collect)
92
+ end
93
+ end
94
+ exports.each_value(&collect)
95
+
96
+ files = [ "package.json" ]
97
+ targets.each do |target|
98
+ rel = target.sub(%r{\A\./}, "")
99
+ if rel.include?("*")
100
+ Dir.glob(File.join(source, rel)).each { |path| files << path.sub("#{source}/", "") }
101
+ else
102
+ files << rel
103
+ end
104
+ end
105
+ files.uniq
106
+ end
107
+ private_class_method :package_files
55
108
 
56
- def link!(link, target)
57
- FileUtils.mkdir_p(File.dirname(link))
58
- FileUtils.ln_s(target, link)
109
+ def read_json(path)
110
+ JSON.parse(File.read(path))
59
111
  end
60
- private_class_method :link!
112
+ private_class_method :read_json
61
113
  end
62
114
  end
@@ -1,3 +1,3 @@
1
1
  module UploadDND
2
- VERSION = "0.9.3"
2
+ VERSION = "0.9.4"
3
3
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "upload_d_n_d",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "type": "module",
5
5
  "main": "app/javascript/upload_d_n_d/index.js",
6
6
  "exports": {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: upload_d_n_d
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pierre Cherbero