diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e79e21f..bececfe2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,8 +46,7 @@ jobs: - name: Run tests env: RAILS_ENV: test - # REDIS_URL: redis://localhost:6379/0 - run: bin/rails db:test:prepare test + run: bin/rails db:test:prepare && bin/rails test - name: Keep screenshots from failed system tests uses: actions/upload-artifact@v4 diff --git a/.gitignore b/.gitignore index a3ee5aad..f78a40c4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ /test/dummy/log/*.log /test/dummy/storage/ /test/dummy/tmp/ +/node_modules/ + diff --git a/Gemfile b/Gemfile index 0d0185ff..f00cf07e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,16 +1,18 @@ source "https://rubygems.org" -# Specify your gem's dependencies in pulse_wire.gemspec. +# Specify your gem's dependencies in hotwire_spark.gemspec. gemspec gem "puma" gem "sqlite3" -gem "propshaft" - # Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/] gem "rubocop-rails-omakase", require: false # Start debugger with binding.b [https://github.com/ruby/debug] # gem "debug", ">= 1.0.0" + +gem "propshaft" +gem "importmap-rails" +gem "stimulus-rails" diff --git a/Gemfile.lock b/Gemfile.lock index 1f745848..6d496a79 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,8 +1,10 @@ PATH remote: . specs: - pulse_wire (0.1.0) + hotwire-spark (0.1.0) + listen rails (>= 8.0.0) + zeitwerk GEM remote: https://rubygems.org/ @@ -78,28 +80,55 @@ GEM securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) uri (>= 0.13.1) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) ast (2.4.2) base64 (0.2.0) benchmark (0.4.0) bigdecimal (3.1.8) builder (3.3.0) + capybara (3.40.0) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.11) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) concurrent-ruby (1.3.4) connection_pool (2.4.1) crass (1.0.6) + cuprite (0.15.1) + capybara (~> 3.0) + ferrum (~> 0.15.0) date (3.4.0) drb (2.2.1) erubi (1.13.0) + ferrum (0.15) + addressable (~> 2.5) + concurrent-ruby (~> 1.1) + webrick (~> 1.7) + websocket-driver (~> 0.7) + ffi (1.17.0-arm64-darwin) + ffi (1.17.0-x86_64-linux-gnu) globalid (1.2.1) activesupport (>= 6.1) i18n (1.14.6) concurrent-ruby (~> 1.0) - io-console (0.7.2) + importmap-rails (2.0.3) + actionpack (>= 6.0.0) + activesupport (>= 6.0.0) + railties (>= 6.0.0) + io-console (0.8.0) irb (1.14.1) rdoc (>= 4.0.0) reline (>= 0.4.2) json (2.8.2) - language_server-protocol (3.17.0.3) - logger (1.6.1) + listen (3.9.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.2) loofah (2.23.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -109,9 +138,10 @@ GEM net-pop net-smtp marcel (1.0.4) + matrix (0.4.2) mini_mime (1.1.5) - minitest (5.25.1) - net-imap (0.5.1) + minitest (5.25.4) + net-imap (0.5.2) date net-protocol net-pop (0.1.2) @@ -121,9 +151,9 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.4) - nokogiri (1.16.7-arm64-darwin) + nokogiri (1.17.0-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.7-x86_64-linux) + nokogiri (1.17.0-x86_64-linux) racc (~> 1.4) parallel (1.26.3) parser (3.3.6.0) @@ -134,8 +164,10 @@ GEM activesupport (>= 7.0.0) rack railties (>= 7.0.0) - psych (5.2.0) + psych (5.2.1) + date stringio + public_suffix (6.0.1) puma (6.4.3) nio4r (~> 2.0) racc (1.8.1) @@ -164,9 +196,9 @@ GEM activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.1) loofah (~> 2.21) - nokogiri (~> 1.14) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) railties (8.0.0) actionpack (= 8.0.0) activesupport (= 8.0.0) @@ -177,26 +209,30 @@ GEM zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) rdoc (6.8.1) psych (>= 4.0.0) regexp_parser (2.9.2) - reline (0.5.11) + reline (0.5.12) io-console (~> 0.5) - rubocop (1.68.0) + rexml (3.3.9) + rubocop (1.52.1) json (~> 2.3) - language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.3.0.2) + parser (>= 3.2.2.3) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rubocop-ast (>= 1.32.2, < 2.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.28.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.36.1) parser (>= 3.3.1.0) - rubocop-minitest (0.36.0) - rubocop (>= 1.61, < 2.0) - rubocop-ast (>= 1.31.1, < 2.0) + rubocop-minitest (0.34.5) + rubocop (>= 1.39, < 2.0) + rubocop-ast (>= 1.30.0, < 2.0) rubocop-performance (1.23.0) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) @@ -211,20 +247,25 @@ GEM rubocop-performance rubocop-rails ruby-progressbar (1.13.0) - securerandom (0.3.2) + securerandom (0.4.0) sqlite3 (2.2.0-arm64-darwin) sqlite3 (2.2.0-x86_64-linux-gnu) + stimulus-rails (1.3.4) + railties (>= 6.0.0) stringio (3.1.2) thor (1.3.2) - timeout (0.4.2) + timeout (0.4.3) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.6.0) uri (1.0.2) - useragent (0.16.10) + useragent (0.16.11) + webrick (1.9.1) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) zeitwerk (2.7.1) PLATFORMS @@ -232,11 +273,16 @@ PLATFORMS x86_64-linux DEPENDENCIES + capybara + cuprite + hotwire-spark! + importmap-rails propshaft - pulse_wire! puma + rubocop rubocop-rails-omakase sqlite3 + stimulus-rails BUNDLED WITH 2.5.23 diff --git a/README.md b/README.md index 5e9fa60c..1d0aa909 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,49 @@ -# PulseWire -Short description and motivation. +# Hotwire Spark -## Usage -How to use my plugin. +**Hotwire Spark** is a live-reloading system for Hotwire applications. It enhances your development feedback loop by detecting source code changes and updating the page *smoothly* without requiring a manual reload. ## Installation -Add this line to your application's Gemfile: + +Add the gem to the group `development`: ```ruby -gem "pulse_wire" +group :development do + gem "hotwire_spark" +end ``` And then execute: + ```bash $ bundle ``` -Or install it yourself as: -```bash -$ gem install pulse_wire +That's it! + +## Hot it works + +The system will listen for three kinds of changes and will take action depending on each: + +* **HTML change:** it fetches the new document body and updates the current body with morphing. It uses [`idiomorph`](https://github.com/bigskysoftware/idiomorph) under the hood. +* **CSS change:** it fetches and reloads the stylesheet that changed. +* **Stimulus controller change:** it fetches the Stimulus controller that changed and reloads all the controllers in the page. + +## Configuration + +You can set configuration options on your `development.rb`. For example: + +```ruby +config.hotwire.spark.html_paths += %w[ lib ] ``` -## Contributing -Contribution directions go here. +| Name | Description | +|------------------|------------------------------------------------------------------------------------------------------------------------------| +| `html_paths` | Paths where file changes trigger a content refresh. By default: `app/controllers`, `app/helpers`, `app/models`, `app/views`. | +| `css_paths` | Paths where file changes trigger a CSS refresh. By default: `app/assets/stylesheets`. | +| `stimulus_paths` | Paths where file changes trigger a Stimulus controller refresh. By default: `app/javascript/controllers`. | +| `enabled` | Enable or disable live reloading. By default, it's only enabled in `development`. | +| `logging` | Show logs in the browser console when reloading happens. It's false by default. | ## License + The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/app/assets/images/pulse_wire/.keep b/app/assets/images/hotwire_spark/.keep similarity index 100% rename from app/assets/images/pulse_wire/.keep rename to app/assets/images/hotwire_spark/.keep diff --git a/app/assets/javascripts/hotwire_spark.js b/app/assets/javascripts/hotwire_spark.js new file mode 100644 index 00000000..892e916d --- /dev/null +++ b/app/assets/javascripts/hotwire_spark.js @@ -0,0 +1,3705 @@ +var HotwireSpark = (function () { + 'use strict'; + + var adapters = { + logger: typeof console !== "undefined" ? console : undefined, + WebSocket: typeof WebSocket !== "undefined" ? WebSocket : undefined + }; + + var logger = { + log(...messages) { + if (this.enabled) { + messages.push(Date.now()); + adapters.logger.log("[ActionCable]", ...messages); + } + } + }; + + const now = () => (new Date).getTime(); + + const secondsSince = time => (now() - time) / 1e3; + + class ConnectionMonitor { + constructor(connection) { + this.visibilityDidChange = this.visibilityDidChange.bind(this); + this.connection = connection; + this.reconnectAttempts = 0; + } + start() { + if (!this.isRunning()) { + this.startedAt = now(); + delete this.stoppedAt; + this.startPolling(); + addEventListener("visibilitychange", this.visibilityDidChange); + logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`); + } + } + stop() { + if (this.isRunning()) { + this.stoppedAt = now(); + this.stopPolling(); + removeEventListener("visibilitychange", this.visibilityDidChange); + logger.log("ConnectionMonitor stopped"); + } + } + isRunning() { + return this.startedAt && !this.stoppedAt; + } + recordMessage() { + this.pingedAt = now(); + } + recordConnect() { + this.reconnectAttempts = 0; + delete this.disconnectedAt; + logger.log("ConnectionMonitor recorded connect"); + } + recordDisconnect() { + this.disconnectedAt = now(); + logger.log("ConnectionMonitor recorded disconnect"); + } + startPolling() { + this.stopPolling(); + this.poll(); + } + stopPolling() { + clearTimeout(this.pollTimeout); + } + poll() { + this.pollTimeout = setTimeout((() => { + this.reconnectIfStale(); + this.poll(); + }), this.getPollInterval()); + } + getPollInterval() { + const {staleThreshold: staleThreshold, reconnectionBackoffRate: reconnectionBackoffRate} = this.constructor; + const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10)); + const jitterMax = this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate; + const jitter = jitterMax * Math.random(); + return staleThreshold * 1e3 * backoff * (1 + jitter); + } + reconnectIfStale() { + if (this.connectionIsStale()) { + logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`); + this.reconnectAttempts++; + if (this.disconnectedRecently()) { + logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`); + } else { + logger.log("ConnectionMonitor reopening"); + this.connection.reopen(); + } + } + } + get refreshedAt() { + return this.pingedAt ? this.pingedAt : this.startedAt; + } + connectionIsStale() { + return secondsSince(this.refreshedAt) > this.constructor.staleThreshold; + } + disconnectedRecently() { + return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; + } + visibilityDidChange() { + if (document.visibilityState === "visible") { + setTimeout((() => { + if (this.connectionIsStale() || !this.connection.isOpen()) { + logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`); + this.connection.reopen(); + } + }), 200); + } + } + } + + ConnectionMonitor.staleThreshold = 6; + + ConnectionMonitor.reconnectionBackoffRate = .15; + + var INTERNAL = { + message_types: { + welcome: "welcome", + disconnect: "disconnect", + ping: "ping", + confirmation: "confirm_subscription", + rejection: "reject_subscription" + }, + disconnect_reasons: { + unauthorized: "unauthorized", + invalid_request: "invalid_request", + server_restart: "server_restart", + remote: "remote" + }, + default_mount_path: "/cable", + protocols: [ "actioncable-v1-json", "actioncable-unsupported" ] + }; + + const {message_types: message_types, protocols: protocols} = INTERNAL; + + const supportedProtocols = protocols.slice(0, protocols.length - 1); + + const indexOf = [].indexOf; + + class Connection { + constructor(consumer) { + this.open = this.open.bind(this); + this.consumer = consumer; + this.subscriptions = this.consumer.subscriptions; + this.monitor = new ConnectionMonitor(this); + this.disconnected = true; + } + send(data) { + if (this.isOpen()) { + this.webSocket.send(JSON.stringify(data)); + return true; + } else { + return false; + } + } + open() { + if (this.isActive()) { + logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`); + return false; + } else { + const socketProtocols = [ ...protocols, ...this.consumer.subprotocols || [] ]; + logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`); + if (this.webSocket) { + this.uninstallEventHandlers(); + } + this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols); + this.installEventHandlers(); + this.monitor.start(); + return true; + } + } + close({allowReconnect: allowReconnect} = { + allowReconnect: true + }) { + if (!allowReconnect) { + this.monitor.stop(); + } + if (this.isOpen()) { + return this.webSocket.close(); + } + } + reopen() { + logger.log(`Reopening WebSocket, current state is ${this.getState()}`); + if (this.isActive()) { + try { + return this.close(); + } catch (error) { + logger.log("Failed to reopen WebSocket", error); + } finally { + logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`); + setTimeout(this.open, this.constructor.reopenDelay); + } + } else { + return this.open(); + } + } + getProtocol() { + if (this.webSocket) { + return this.webSocket.protocol; + } + } + isOpen() { + return this.isState("open"); + } + isActive() { + return this.isState("open", "connecting"); + } + triedToReconnect() { + return this.monitor.reconnectAttempts > 0; + } + isProtocolSupported() { + return indexOf.call(supportedProtocols, this.getProtocol()) >= 0; + } + isState(...states) { + return indexOf.call(states, this.getState()) >= 0; + } + getState() { + if (this.webSocket) { + for (let state in adapters.WebSocket) { + if (adapters.WebSocket[state] === this.webSocket.readyState) { + return state.toLowerCase(); + } + } + } + return null; + } + installEventHandlers() { + for (let eventName in this.events) { + const handler = this.events[eventName].bind(this); + this.webSocket[`on${eventName}`] = handler; + } + } + uninstallEventHandlers() { + for (let eventName in this.events) { + this.webSocket[`on${eventName}`] = function() {}; + } + } + } + + Connection.reopenDelay = 500; + + Connection.prototype.events = { + message(event) { + if (!this.isProtocolSupported()) { + return; + } + const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data); + this.monitor.recordMessage(); + switch (type) { + case message_types.welcome: + if (this.triedToReconnect()) { + this.reconnectAttempted = true; + } + this.monitor.recordConnect(); + return this.subscriptions.reload(); + + case message_types.disconnect: + logger.log(`Disconnecting. Reason: ${reason}`); + return this.close({ + allowReconnect: reconnect + }); + + case message_types.ping: + return null; + + case message_types.confirmation: + this.subscriptions.confirmSubscription(identifier); + if (this.reconnectAttempted) { + this.reconnectAttempted = false; + return this.subscriptions.notify(identifier, "connected", { + reconnected: true + }); + } else { + return this.subscriptions.notify(identifier, "connected", { + reconnected: false + }); + } + + case message_types.rejection: + return this.subscriptions.reject(identifier); + + default: + return this.subscriptions.notify(identifier, "received", message); + } + }, + open() { + logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`); + this.disconnected = false; + if (!this.isProtocolSupported()) { + logger.log("Protocol is unsupported. Stopping monitor and disconnecting."); + return this.close({ + allowReconnect: false + }); + } + }, + close(event) { + logger.log("WebSocket onclose event"); + if (this.disconnected) { + return; + } + this.disconnected = true; + this.monitor.recordDisconnect(); + return this.subscriptions.notifyAll("disconnected", { + willAttemptReconnect: this.monitor.isRunning() + }); + }, + error() { + logger.log("WebSocket onerror event"); + } + }; + + const extend$1 = function(object, properties) { + if (properties != null) { + for (let key in properties) { + const value = properties[key]; + object[key] = value; + } + } + return object; + }; + + class Subscription { + constructor(consumer, params = {}, mixin) { + this.consumer = consumer; + this.identifier = JSON.stringify(params); + extend$1(this, mixin); + } + perform(action, data = {}) { + data.action = action; + return this.send(data); + } + send(data) { + return this.consumer.send({ + command: "message", + identifier: this.identifier, + data: JSON.stringify(data) + }); + } + unsubscribe() { + return this.consumer.subscriptions.remove(this); + } + } + + class SubscriptionGuarantor { + constructor(subscriptions) { + this.subscriptions = subscriptions; + this.pendingSubscriptions = []; + } + guarantee(subscription) { + if (this.pendingSubscriptions.indexOf(subscription) == -1) { + logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`); + this.pendingSubscriptions.push(subscription); + } else { + logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`); + } + this.startGuaranteeing(); + } + forget(subscription) { + logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`); + this.pendingSubscriptions = this.pendingSubscriptions.filter((s => s !== subscription)); + } + startGuaranteeing() { + this.stopGuaranteeing(); + this.retrySubscribing(); + } + stopGuaranteeing() { + clearTimeout(this.retryTimeout); + } + retrySubscribing() { + this.retryTimeout = setTimeout((() => { + if (this.subscriptions && typeof this.subscriptions.subscribe === "function") { + this.pendingSubscriptions.map((subscription => { + logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`); + this.subscriptions.subscribe(subscription); + })); + } + }), 500); + } + } + + class Subscriptions { + constructor(consumer) { + this.consumer = consumer; + this.guarantor = new SubscriptionGuarantor(this); + this.subscriptions = []; + } + create(channelName, mixin) { + const channel = channelName; + const params = typeof channel === "object" ? channel : { + channel: channel + }; + const subscription = new Subscription(this.consumer, params, mixin); + return this.add(subscription); + } + add(subscription) { + this.subscriptions.push(subscription); + this.consumer.ensureActiveConnection(); + this.notify(subscription, "initialized"); + this.subscribe(subscription); + return subscription; + } + remove(subscription) { + this.forget(subscription); + if (!this.findAll(subscription.identifier).length) { + this.sendCommand(subscription, "unsubscribe"); + } + return subscription; + } + reject(identifier) { + return this.findAll(identifier).map((subscription => { + this.forget(subscription); + this.notify(subscription, "rejected"); + return subscription; + })); + } + forget(subscription) { + this.guarantor.forget(subscription); + this.subscriptions = this.subscriptions.filter((s => s !== subscription)); + return subscription; + } + findAll(identifier) { + return this.subscriptions.filter((s => s.identifier === identifier)); + } + reload() { + return this.subscriptions.map((subscription => this.subscribe(subscription))); + } + notifyAll(callbackName, ...args) { + return this.subscriptions.map((subscription => this.notify(subscription, callbackName, ...args))); + } + notify(subscription, callbackName, ...args) { + let subscriptions; + if (typeof subscription === "string") { + subscriptions = this.findAll(subscription); + } else { + subscriptions = [ subscription ]; + } + return subscriptions.map((subscription => typeof subscription[callbackName] === "function" ? subscription[callbackName](...args) : undefined)); + } + subscribe(subscription) { + if (this.sendCommand(subscription, "subscribe")) { + this.guarantor.guarantee(subscription); + } + } + confirmSubscription(identifier) { + logger.log(`Subscription confirmed ${identifier}`); + this.findAll(identifier).map((subscription => this.guarantor.forget(subscription))); + } + sendCommand(subscription, command) { + const {identifier: identifier} = subscription; + return this.consumer.send({ + command: command, + identifier: identifier + }); + } + } + + class Consumer { + constructor(url) { + this._url = url; + this.subscriptions = new Subscriptions(this); + this.connection = new Connection(this); + this.subprotocols = []; + } + get url() { + return createWebSocketURL(this._url); + } + send(data) { + return this.connection.send(data); + } + connect() { + return this.connection.open(); + } + disconnect() { + return this.connection.close({ + allowReconnect: false + }); + } + ensureActiveConnection() { + if (!this.connection.isActive()) { + return this.connection.open(); + } + } + addSubProtocol(subprotocol) { + this.subprotocols = [ ...this.subprotocols, subprotocol ]; + } + } + + function createWebSocketURL(url) { + if (typeof url === "function") { + url = url(); + } + if (url && !/^wss?:/i.test(url)) { + const a = document.createElement("a"); + a.href = url; + a.href = a.href; + a.protocol = a.protocol.replace("http", "ws"); + return a.href; + } else { + return url; + } + } + + function createConsumer(url = getConfig("url") || INTERNAL.default_mount_path) { + return new Consumer(url); + } + + function getConfig(name) { + const element = document.head.querySelector(`meta[name='action-cable-${name}']`); + if (element) { + return element.getAttribute("content"); + } + } + + var consumer = createConsumer(); + + function assetNameFromPath(path) { + return path.split("/").pop().split(".")[0]; + } + function pathWithoutAssetDigest(path) { + return path.replace(/-[a-z0-9]+\.(\w+)(\?.*)?$/, ".$1"); + } + function urlWithParams(urlString, params) { + const url = new URL(urlString, window.location.origin); + Object.entries(params).forEach(_ref => { + let [key, value] = _ref; + url.searchParams.set(key, value); + }); + return url.toString(); + } + function cacheBustedUrl(urlString) { + return urlWithParams(urlString, { + reload: Date.now() + }); + } + async function reloadHtmlDocument() { + let currentUrl = cacheBustedUrl(urlWithParams(window.location.href, { + hotwire_spark: "true" + })); + const response = await fetch(currentUrl); + if (!response.ok) { + throw new Error(`${response.status} when fetching ${currentUrl}`); + } + const fetchedHTML = await response.text(); + const parser = new DOMParser(); + return parser.parseFromString(fetchedHTML, "text/html"); + } + function getConfigurationProperty(name) { + return document.querySelector(`meta[name="hotwire-spark:${name}"]`)?.content; + } + + // base IIFE to define idiomorph + var Idiomorph = (function () { + + //============================================================================= + // AND NOW IT BEGINS... + //============================================================================= + let EMPTY_SET = new Set(); + + // default configuration values, updatable by users now + let defaults = { + morphStyle: "outerHTML", + callbacks : { + beforeNodeAdded: noOp, + afterNodeAdded: noOp, + beforeNodeMorphed: noOp, + afterNodeMorphed: noOp, + beforeNodeRemoved: noOp, + afterNodeRemoved: noOp, + beforeAttributeUpdated: noOp, + + }, + head: { + style: 'merge', + shouldPreserve: function (elt) { + return elt.getAttribute("im-preserve") === "true"; + }, + shouldReAppend: function (elt) { + return elt.getAttribute("im-re-append") === "true"; + }, + shouldRemove: noOp, + afterHeadMorphed: noOp, + } + }; + + //============================================================================= + // Core Morphing Algorithm - morph, morphNormalizedContent, morphOldNodeTo, morphChildren + //============================================================================= + function morph(oldNode, newContent, config = {}) { + + if (oldNode instanceof Document) { + oldNode = oldNode.documentElement; + } + + if (typeof newContent === 'string') { + newContent = parseContent(newContent); + } + + let normalizedContent = normalizeContent(newContent); + + let ctx = createMorphContext(oldNode, normalizedContent, config); + + return morphNormalizedContent(oldNode, normalizedContent, ctx); + } + + function morphNormalizedContent(oldNode, normalizedNewContent, ctx) { + if (ctx.head.block) { + let oldHead = oldNode.querySelector('head'); + let newHead = normalizedNewContent.querySelector('head'); + if (oldHead && newHead) { + let promises = handleHeadElement(newHead, oldHead, ctx); + // when head promises resolve, call morph again, ignoring the head tag + Promise.all(promises).then(function () { + morphNormalizedContent(oldNode, normalizedNewContent, Object.assign(ctx, { + head: { + block: false, + ignore: true + } + })); + }); + return; + } + } + + if (ctx.morphStyle === "innerHTML") { + + // innerHTML, so we are only updating the children + morphChildren(normalizedNewContent, oldNode, ctx); + return oldNode.children; + + } else if (ctx.morphStyle === "outerHTML" || ctx.morphStyle == null) { + // otherwise find the best element match in the new content, morph that, and merge its siblings + // into either side of the best match + let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx); + + // stash the siblings that will need to be inserted on either side of the best match + let previousSibling = bestMatch?.previousSibling; + let nextSibling = bestMatch?.nextSibling; + + // morph it + let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx); + + if (bestMatch) { + // if there was a best match, merge the siblings in too and return the + // whole bunch + return insertSiblings(previousSibling, morphedNode, nextSibling); + } else { + // otherwise nothing was added to the DOM + return [] + } + } else { + throw "Do not understand how to morph style " + ctx.morphStyle; + } + } + + + /** + * @param possibleActiveElement + * @param ctx + * @returns {boolean} + */ + function ignoreValueOfActiveElement(possibleActiveElement, ctx) { + return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement; + } + + /** + * @param oldNode root node to merge content into + * @param newContent new content to merge + * @param ctx the merge context + * @returns {Element} the element that ended up in the DOM + */ + function morphOldNodeTo(oldNode, newContent, ctx) { + if (ctx.ignoreActive && oldNode === document.activeElement) ; else if (newContent == null) { + if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode; + + oldNode.remove(); + ctx.callbacks.afterNodeRemoved(oldNode); + return null; + } else if (!isSoftMatch(oldNode, newContent)) { + if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode; + if (ctx.callbacks.beforeNodeAdded(newContent) === false) return oldNode; + + oldNode.parentElement.replaceChild(newContent, oldNode); + ctx.callbacks.afterNodeAdded(newContent); + ctx.callbacks.afterNodeRemoved(oldNode); + return newContent; + } else { + if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) return oldNode; + + if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) ; else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== "morph") { + handleHeadElement(newContent, oldNode, ctx); + } else { + syncNodeFrom(newContent, oldNode, ctx); + if (!ignoreValueOfActiveElement(oldNode, ctx)) { + morphChildren(newContent, oldNode, ctx); + } + } + ctx.callbacks.afterNodeMorphed(oldNode, newContent); + return oldNode; + } + } + + /** + * This is the core algorithm for matching up children. The idea is to use id sets to try to match up + * nodes as faithfully as possible. We greedily match, which allows us to keep the algorithm fast, but + * by using id sets, we are able to better match up with content deeper in the DOM. + * + * Basic algorithm is, for each node in the new content: + * + * - if we have reached the end of the old parent, append the new content + * - if the new content has an id set match with the current insertion point, morph + * - search for an id set match + * - if id set match found, morph + * - otherwise search for a "soft" match + * - if a soft match is found, morph + * - otherwise, prepend the new node before the current insertion point + * + * The two search algorithms terminate if competing node matches appear to outweigh what can be achieved + * with the current node. See findIdSetMatch() and findSoftMatch() for details. + * + * @param {Element} newParent the parent element of the new content + * @param {Element } oldParent the old content that we are merging the new content into + * @param ctx the merge context + */ + function morphChildren(newParent, oldParent, ctx) { + + let nextNewChild = newParent.firstChild; + let insertionPoint = oldParent.firstChild; + let newChild; + + // run through all the new content + while (nextNewChild) { + + newChild = nextNewChild; + nextNewChild = newChild.nextSibling; + + // if we are at the end of the exiting parent's children, just append + if (insertionPoint == null) { + if (ctx.callbacks.beforeNodeAdded(newChild) === false) return; + + oldParent.appendChild(newChild); + ctx.callbacks.afterNodeAdded(newChild); + removeIdsFromConsideration(ctx, newChild); + continue; + } + + // if the current node has an id set match then morph + if (isIdSetMatch(newChild, insertionPoint, ctx)) { + morphOldNodeTo(insertionPoint, newChild, ctx); + insertionPoint = insertionPoint.nextSibling; + removeIdsFromConsideration(ctx, newChild); + continue; + } + + // otherwise search forward in the existing old children for an id set match + let idSetMatch = findIdSetMatch(newParent, oldParent, newChild, insertionPoint, ctx); + + // if we found a potential match, remove the nodes until that point and morph + if (idSetMatch) { + insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx); + morphOldNodeTo(idSetMatch, newChild, ctx); + removeIdsFromConsideration(ctx, newChild); + continue; + } + + // no id set match found, so scan forward for a soft match for the current node + let softMatch = findSoftMatch(newParent, oldParent, newChild, insertionPoint, ctx); + + // if we found a soft match for the current node, morph + if (softMatch) { + insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx); + morphOldNodeTo(softMatch, newChild, ctx); + removeIdsFromConsideration(ctx, newChild); + continue; + } + + // abandon all hope of morphing, just insert the new child before the insertion point + // and move on + if (ctx.callbacks.beforeNodeAdded(newChild) === false) return; + + oldParent.insertBefore(newChild, insertionPoint); + ctx.callbacks.afterNodeAdded(newChild); + removeIdsFromConsideration(ctx, newChild); + } + + // remove any remaining old nodes that didn't match up with new content + while (insertionPoint !== null) { + + let tempNode = insertionPoint; + insertionPoint = insertionPoint.nextSibling; + removeNode(tempNode, ctx); + } + } + + //============================================================================= + // Attribute Syncing Code + //============================================================================= + + /** + * @param attr {String} the attribute to be mutated + * @param to {Element} the element that is going to be updated + * @param updateType {("update"|"remove")} + * @param ctx the merge context + * @returns {boolean} true if the attribute should be ignored, false otherwise + */ + function ignoreAttribute(attr, to, updateType, ctx) { + if(attr === 'value' && ctx.ignoreActiveValue && to === document.activeElement){ + return true; + } + return ctx.callbacks.beforeAttributeUpdated(attr, to, updateType) === false; + } + + /** + * syncs a given node with another node, copying over all attributes and + * inner element state from the 'from' node to the 'to' node + * + * @param {Element} from the element to copy attributes & state from + * @param {Element} to the element to copy attributes & state to + * @param ctx the merge context + */ + function syncNodeFrom(from, to, ctx) { + let type = from.nodeType; + + // if is an element type, sync the attributes from the + // new node into the new node + if (type === 1 /* element type */) { + const fromAttributes = from.attributes; + const toAttributes = to.attributes; + for (const fromAttribute of fromAttributes) { + if (ignoreAttribute(fromAttribute.name, to, 'update', ctx)) { + continue; + } + if (to.getAttribute(fromAttribute.name) !== fromAttribute.value) { + to.setAttribute(fromAttribute.name, fromAttribute.value); + } + } + // iterate backwards to avoid skipping over items when a delete occurs + for (let i = toAttributes.length - 1; 0 <= i; i--) { + const toAttribute = toAttributes[i]; + if (ignoreAttribute(toAttribute.name, to, 'remove', ctx)) { + continue; + } + if (!from.hasAttribute(toAttribute.name)) { + to.removeAttribute(toAttribute.name); + } + } + } + + // sync text nodes + if (type === 8 /* comment */ || type === 3 /* text */) { + if (to.nodeValue !== from.nodeValue) { + to.nodeValue = from.nodeValue; + } + } + + if (!ignoreValueOfActiveElement(to, ctx)) { + // sync input values + syncInputValue(from, to, ctx); + } + } + + /** + * @param from {Element} element to sync the value from + * @param to {Element} element to sync the value to + * @param attributeName {String} the attribute name + * @param ctx the merge context + */ + function syncBooleanAttribute(from, to, attributeName, ctx) { + if (from[attributeName] !== to[attributeName]) { + let ignoreUpdate = ignoreAttribute(attributeName, to, 'update', ctx); + if (!ignoreUpdate) { + to[attributeName] = from[attributeName]; + } + if (from[attributeName]) { + if (!ignoreUpdate) { + to.setAttribute(attributeName, from[attributeName]); + } + } else { + if (!ignoreAttribute(attributeName, to, 'remove', ctx)) { + to.removeAttribute(attributeName); + } + } + } + } + + /** + * NB: many bothans died to bring us information: + * + * https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js + * https://github.com/choojs/nanomorph/blob/master/lib/morph.jsL113 + * + * @param from {Element} the element to sync the input value from + * @param to {Element} the element to sync the input value to + * @param ctx the merge context + */ + function syncInputValue(from, to, ctx) { + if (from instanceof HTMLInputElement && + to instanceof HTMLInputElement && + from.type !== 'file') { + + let fromValue = from.value; + let toValue = to.value; + + // sync boolean attributes + syncBooleanAttribute(from, to, 'checked', ctx); + syncBooleanAttribute(from, to, 'disabled', ctx); + + if (!from.hasAttribute('value')) { + if (!ignoreAttribute('value', to, 'remove', ctx)) { + to.value = ''; + to.removeAttribute('value'); + } + } else if (fromValue !== toValue) { + if (!ignoreAttribute('value', to, 'update', ctx)) { + to.setAttribute('value', fromValue); + to.value = fromValue; + } + } + } else if (from instanceof HTMLOptionElement) { + syncBooleanAttribute(from, to, 'selected', ctx); + } else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) { + let fromValue = from.value; + let toValue = to.value; + if (ignoreAttribute('value', to, 'update', ctx)) { + return; + } + if (fromValue !== toValue) { + to.value = fromValue; + } + if (to.firstChild && to.firstChild.nodeValue !== fromValue) { + to.firstChild.nodeValue = fromValue; + } + } + } + + //============================================================================= + // the HEAD tag can be handled specially, either w/ a 'merge' or 'append' style + //============================================================================= + function handleHeadElement(newHeadTag, currentHead, ctx) { + + let added = []; + let removed = []; + let preserved = []; + let nodesToAppend = []; + + let headMergeStyle = ctx.head.style; + + // put all new head elements into a Map, by their outerHTML + let srcToNewHeadNodes = new Map(); + for (const newHeadChild of newHeadTag.children) { + srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild); + } + + // for each elt in the current head + for (const currentHeadElt of currentHead.children) { + + // If the current head element is in the map + let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML); + let isReAppended = ctx.head.shouldReAppend(currentHeadElt); + let isPreserved = ctx.head.shouldPreserve(currentHeadElt); + if (inNewContent || isPreserved) { + if (isReAppended) { + // remove the current version and let the new version replace it and re-execute + removed.push(currentHeadElt); + } else { + // this element already exists and should not be re-appended, so remove it from + // the new content map, preserving it in the DOM + srcToNewHeadNodes.delete(currentHeadElt.outerHTML); + preserved.push(currentHeadElt); + } + } else { + if (headMergeStyle === "append") { + // we are appending and this existing element is not new content + // so if and only if it is marked for re-append do we do anything + if (isReAppended) { + removed.push(currentHeadElt); + nodesToAppend.push(currentHeadElt); + } + } else { + // if this is a merge, we remove this content since it is not in the new head + if (ctx.head.shouldRemove(currentHeadElt) !== false) { + removed.push(currentHeadElt); + } + } + } + } + + // Push the remaining new head elements in the Map into the + // nodes to append to the head tag + nodesToAppend.push(...srcToNewHeadNodes.values()); + + let promises = []; + for (const newNode of nodesToAppend) { + let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild; + if (ctx.callbacks.beforeNodeAdded(newElt) !== false) { + if (newElt.href || newElt.src) { + let resolve = null; + let promise = new Promise(function (_resolve) { + resolve = _resolve; + }); + newElt.addEventListener('load', function () { + resolve(); + }); + promises.push(promise); + } + currentHead.appendChild(newElt); + ctx.callbacks.afterNodeAdded(newElt); + added.push(newElt); + } + } + + // remove all removed elements, after we have appended the new elements to avoid + // additional network requests for things like style sheets + for (const removedElement of removed) { + if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) { + currentHead.removeChild(removedElement); + ctx.callbacks.afterNodeRemoved(removedElement); + } + } + + ctx.head.afterHeadMorphed(currentHead, {added: added, kept: preserved, removed: removed}); + return promises; + } + + function noOp() { + } + + /* + Deep merges the config object and the Idiomoroph.defaults object to + produce a final configuration object + */ + function mergeDefaults(config) { + let finalConfig = {}; + // copy top level stuff into final config + Object.assign(finalConfig, defaults); + Object.assign(finalConfig, config); + + // copy callbacks into final config (do this to deep merge the callbacks) + finalConfig.callbacks = {}; + Object.assign(finalConfig.callbacks, defaults.callbacks); + Object.assign(finalConfig.callbacks, config.callbacks); + + // copy head config into final config (do this to deep merge the head) + finalConfig.head = {}; + Object.assign(finalConfig.head, defaults.head); + Object.assign(finalConfig.head, config.head); + return finalConfig; + } + + function createMorphContext(oldNode, newContent, config) { + config = mergeDefaults(config); + return { + target: oldNode, + newContent: newContent, + config: config, + morphStyle: config.morphStyle, + ignoreActive: config.ignoreActive, + ignoreActiveValue: config.ignoreActiveValue, + idMap: createIdMap(oldNode, newContent), + deadIds: new Set(), + callbacks: config.callbacks, + head: config.head + } + } + + function isIdSetMatch(node1, node2, ctx) { + if (node1 == null || node2 == null) { + return false; + } + if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) { + if (node1.id !== "" && node1.id === node2.id) { + return true; + } else { + return getIdIntersectionCount(ctx, node1, node2) > 0; + } + } + return false; + } + + function isSoftMatch(node1, node2) { + if (node1 == null || node2 == null) { + return false; + } + return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName + } + + function removeNodesBetween(startInclusive, endExclusive, ctx) { + while (startInclusive !== endExclusive) { + let tempNode = startInclusive; + startInclusive = startInclusive.nextSibling; + removeNode(tempNode, ctx); + } + removeIdsFromConsideration(ctx, endExclusive); + return endExclusive.nextSibling; + } + + //============================================================================= + // Scans forward from the insertionPoint in the old parent looking for a potential id match + // for the newChild. We stop if we find a potential id match for the new child OR + // if the number of potential id matches we are discarding is greater than the + // potential id matches for the new child + //============================================================================= + function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) { + + // max id matches we are willing to discard in our search + let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent); + + let potentialMatch = null; + + // only search forward if there is a possibility of an id match + if (newChildPotentialIdCount > 0) { + let potentialMatch = insertionPoint; + // if there is a possibility of an id match, scan forward + // keep track of the potential id match count we are discarding (the + // newChildPotentialIdCount must be greater than this to make it likely + // worth it) + let otherMatchCount = 0; + while (potentialMatch != null) { + + // If we have an id match, return the current potential match + if (isIdSetMatch(newChild, potentialMatch, ctx)) { + return potentialMatch; + } + + // computer the other potential matches of this new content + otherMatchCount += getIdIntersectionCount(ctx, potentialMatch, newContent); + if (otherMatchCount > newChildPotentialIdCount) { + // if we have more potential id matches in _other_ content, we + // do not have a good candidate for an id match, so return null + return null; + } + + // advanced to the next old content child + potentialMatch = potentialMatch.nextSibling; + } + } + return potentialMatch; + } + + //============================================================================= + // Scans forward from the insertionPoint in the old parent looking for a potential soft match + // for the newChild. We stop if we find a potential soft match for the new child OR + // if we find a potential id match in the old parents children OR if we find two + // potential soft matches for the next two pieces of new content + //============================================================================= + function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) { + + let potentialSoftMatch = insertionPoint; + let nextSibling = newChild.nextSibling; + let siblingSoftMatchCount = 0; + + while (potentialSoftMatch != null) { + + if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) { + // the current potential soft match has a potential id set match with the remaining new + // content so bail out of looking + return null; + } + + // if we have a soft match with the current node, return it + if (isSoftMatch(newChild, potentialSoftMatch)) { + return potentialSoftMatch; + } + + if (isSoftMatch(nextSibling, potentialSoftMatch)) { + // the next new node has a soft match with this node, so + // increment the count of future soft matches + siblingSoftMatchCount++; + nextSibling = nextSibling.nextSibling; + + // If there are two future soft matches, bail to allow the siblings to soft match + // so that we don't consume future soft matches for the sake of the current node + if (siblingSoftMatchCount >= 2) { + return null; + } + } + + // advanced to the next old content child + potentialSoftMatch = potentialSoftMatch.nextSibling; + } + + return potentialSoftMatch; + } + + function parseContent(newContent) { + let parser = new DOMParser(); + + // remove svgs to avoid false-positive matches on head, etc. + let contentWithSvgsRemoved = newContent.replace(/]*>|>)([\s\S]*?)<\/svg>/gim, ''); + + // if the newContent contains a html, head or body tag, we can simply parse it w/o wrapping + if (contentWithSvgsRemoved.match(/<\/html>/) || contentWithSvgsRemoved.match(/<\/head>/) || contentWithSvgsRemoved.match(/<\/body>/)) { + let content = parser.parseFromString(newContent, "text/html"); + // if it is a full HTML document, return the document itself as the parent container + if (contentWithSvgsRemoved.match(/<\/html>/)) { + content.generatedByIdiomorph = true; + return content; + } else { + // otherwise return the html element as the parent container + let htmlElement = content.firstChild; + if (htmlElement) { + htmlElement.generatedByIdiomorph = true; + return htmlElement; + } else { + return null; + } + } + } else { + // if it is partial HTML, wrap it in a template tag to provide a parent element and also to help + // deal with touchy tags like tr, tbody, etc. + let responseDoc = parser.parseFromString("", "text/html"); + let content = responseDoc.body.querySelector('template').content; + content.generatedByIdiomorph = true; + return content + } + } + + function normalizeContent(newContent) { + if (newContent == null) { + // noinspection UnnecessaryLocalVariableJS + const dummyParent = document.createElement('div'); + return dummyParent; + } else if (newContent.generatedByIdiomorph) { + // the template tag created by idiomorph parsing can serve as a dummy parent + return newContent; + } else if (newContent instanceof Node) { + // a single node is added as a child to a dummy parent + const dummyParent = document.createElement('div'); + dummyParent.append(newContent); + return dummyParent; + } else { + // all nodes in the array or HTMLElement collection are consolidated under + // a single dummy parent element + const dummyParent = document.createElement('div'); + for (const elt of [...newContent]) { + dummyParent.append(elt); + } + return dummyParent; + } + } + + function insertSiblings(previousSibling, morphedNode, nextSibling) { + let stack = []; + let added = []; + while (previousSibling != null) { + stack.push(previousSibling); + previousSibling = previousSibling.previousSibling; + } + while (stack.length > 0) { + let node = stack.pop(); + added.push(node); // push added preceding siblings on in order and insert + morphedNode.parentElement.insertBefore(node, morphedNode); + } + added.push(morphedNode); + while (nextSibling != null) { + stack.push(nextSibling); + added.push(nextSibling); // here we are going in order, so push on as we scan, rather than add + nextSibling = nextSibling.nextSibling; + } + while (stack.length > 0) { + morphedNode.parentElement.insertBefore(stack.pop(), morphedNode.nextSibling); + } + return added; + } + + function findBestNodeMatch(newContent, oldNode, ctx) { + let currentElement; + currentElement = newContent.firstChild; + let bestElement = currentElement; + let score = 0; + while (currentElement) { + let newScore = scoreElement(currentElement, oldNode, ctx); + if (newScore > score) { + bestElement = currentElement; + score = newScore; + } + currentElement = currentElement.nextSibling; + } + return bestElement; + } + + function scoreElement(node1, node2, ctx) { + if (isSoftMatch(node1, node2)) { + return .5 + getIdIntersectionCount(ctx, node1, node2); + } + return 0; + } + + function removeNode(tempNode, ctx) { + removeIdsFromConsideration(ctx, tempNode); + if (ctx.callbacks.beforeNodeRemoved(tempNode) === false) return; + + tempNode.remove(); + ctx.callbacks.afterNodeRemoved(tempNode); + } + + //============================================================================= + // ID Set Functions + //============================================================================= + + function isIdInConsideration(ctx, id) { + return !ctx.deadIds.has(id); + } + + function idIsWithinNode(ctx, id, targetNode) { + let idSet = ctx.idMap.get(targetNode) || EMPTY_SET; + return idSet.has(id); + } + + function removeIdsFromConsideration(ctx, node) { + let idSet = ctx.idMap.get(node) || EMPTY_SET; + for (const id of idSet) { + ctx.deadIds.add(id); + } + } + + function getIdIntersectionCount(ctx, node1, node2) { + let sourceSet = ctx.idMap.get(node1) || EMPTY_SET; + let matchCount = 0; + for (const id of sourceSet) { + // a potential match is an id in the source and potentialIdsSet, but + // that has not already been merged into the DOM + if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) { + ++matchCount; + } + } + return matchCount; + } + + /** + * A bottom up algorithm that finds all elements with ids inside of the node + * argument and populates id sets for those nodes and all their parents, generating + * a set of ids contained within all nodes for the entire hierarchy in the DOM + * + * @param node {Element} + * @param {Map>} idMap + */ + function populateIdMapForNode(node, idMap) { + let nodeParent = node.parentElement; + // find all elements with an id property + let idElements = node.querySelectorAll('[id]'); + for (const elt of idElements) { + let current = elt; + // walk up the parent hierarchy of that element, adding the id + // of element to the parent's id set + while (current !== nodeParent && current != null) { + let idSet = idMap.get(current); + // if the id set doesn't exist, create it and insert it in the map + if (idSet == null) { + idSet = new Set(); + idMap.set(current, idSet); + } + idSet.add(elt.id); + current = current.parentElement; + } + } + } + + /** + * This function computes a map of nodes to all ids contained within that node (inclusive of the + * node). This map can be used to ask if two nodes have intersecting sets of ids, which allows + * for a looser definition of "matching" than tradition id matching, and allows child nodes + * to contribute to a parent nodes matching. + * + * @param {Element} oldContent the old content that will be morphed + * @param {Element} newContent the new content to morph to + * @returns {Map>} a map of nodes to id sets for the + */ + function createIdMap(oldContent, newContent) { + let idMap = new Map(); + populateIdMapForNode(oldContent, idMap); + populateIdMapForNode(newContent, idMap); + return idMap; + } + + //============================================================================= + // This is what ends up becoming the Idiomorph global object + //============================================================================= + return { + morph, + defaults + } + })(); + + function log() { + if (HotwireSpark.config.loggingEnabled) { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + console.log(`[hotwire_spark]`, ...args); + } + } + + /* + Stimulus 3.2.1 + Copyright © 2023 Basecamp, LLC + */ + class EventListener { + constructor(eventTarget, eventName, eventOptions) { + this.eventTarget = eventTarget; + this.eventName = eventName; + this.eventOptions = eventOptions; + this.unorderedBindings = new Set(); + } + connect() { + this.eventTarget.addEventListener(this.eventName, this, this.eventOptions); + } + disconnect() { + this.eventTarget.removeEventListener(this.eventName, this, this.eventOptions); + } + bindingConnected(binding) { + this.unorderedBindings.add(binding); + } + bindingDisconnected(binding) { + this.unorderedBindings.delete(binding); + } + handleEvent(event) { + const extendedEvent = extendEvent(event); + for (const binding of this.bindings) { + if (extendedEvent.immediatePropagationStopped) { + break; + } + else { + binding.handleEvent(extendedEvent); + } + } + } + hasBindings() { + return this.unorderedBindings.size > 0; + } + get bindings() { + return Array.from(this.unorderedBindings).sort((left, right) => { + const leftIndex = left.index, rightIndex = right.index; + return leftIndex < rightIndex ? -1 : leftIndex > rightIndex ? 1 : 0; + }); + } + } + function extendEvent(event) { + if ("immediatePropagationStopped" in event) { + return event; + } + else { + const { stopImmediatePropagation } = event; + return Object.assign(event, { + immediatePropagationStopped: false, + stopImmediatePropagation() { + this.immediatePropagationStopped = true; + stopImmediatePropagation.call(this); + }, + }); + } + } + + class Dispatcher { + constructor(application) { + this.application = application; + this.eventListenerMaps = new Map(); + this.started = false; + } + start() { + if (!this.started) { + this.started = true; + this.eventListeners.forEach((eventListener) => eventListener.connect()); + } + } + stop() { + if (this.started) { + this.started = false; + this.eventListeners.forEach((eventListener) => eventListener.disconnect()); + } + } + get eventListeners() { + return Array.from(this.eventListenerMaps.values()).reduce((listeners, map) => listeners.concat(Array.from(map.values())), []); + } + bindingConnected(binding) { + this.fetchEventListenerForBinding(binding).bindingConnected(binding); + } + bindingDisconnected(binding, clearEventListeners = false) { + this.fetchEventListenerForBinding(binding).bindingDisconnected(binding); + if (clearEventListeners) + this.clearEventListenersForBinding(binding); + } + handleError(error, message, detail = {}) { + this.application.handleError(error, `Error ${message}`, detail); + } + clearEventListenersForBinding(binding) { + const eventListener = this.fetchEventListenerForBinding(binding); + if (!eventListener.hasBindings()) { + eventListener.disconnect(); + this.removeMappedEventListenerFor(binding); + } + } + removeMappedEventListenerFor(binding) { + const { eventTarget, eventName, eventOptions } = binding; + const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget); + const cacheKey = this.cacheKey(eventName, eventOptions); + eventListenerMap.delete(cacheKey); + if (eventListenerMap.size == 0) + this.eventListenerMaps.delete(eventTarget); + } + fetchEventListenerForBinding(binding) { + const { eventTarget, eventName, eventOptions } = binding; + return this.fetchEventListener(eventTarget, eventName, eventOptions); + } + fetchEventListener(eventTarget, eventName, eventOptions) { + const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget); + const cacheKey = this.cacheKey(eventName, eventOptions); + let eventListener = eventListenerMap.get(cacheKey); + if (!eventListener) { + eventListener = this.createEventListener(eventTarget, eventName, eventOptions); + eventListenerMap.set(cacheKey, eventListener); + } + return eventListener; + } + createEventListener(eventTarget, eventName, eventOptions) { + const eventListener = new EventListener(eventTarget, eventName, eventOptions); + if (this.started) { + eventListener.connect(); + } + return eventListener; + } + fetchEventListenerMapForEventTarget(eventTarget) { + let eventListenerMap = this.eventListenerMaps.get(eventTarget); + if (!eventListenerMap) { + eventListenerMap = new Map(); + this.eventListenerMaps.set(eventTarget, eventListenerMap); + } + return eventListenerMap; + } + cacheKey(eventName, eventOptions) { + const parts = [eventName]; + Object.keys(eventOptions) + .sort() + .forEach((key) => { + parts.push(`${eventOptions[key] ? "" : "!"}${key}`); + }); + return parts.join(":"); + } + } + + const defaultActionDescriptorFilters = { + stop({ event, value }) { + if (value) + event.stopPropagation(); + return true; + }, + prevent({ event, value }) { + if (value) + event.preventDefault(); + return true; + }, + self({ event, value, element }) { + if (value) { + return element === event.target; + } + else { + return true; + } + }, + }; + const descriptorPattern = /^(?:(?:([^.]+?)\+)?(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/; + function parseActionDescriptorString(descriptorString) { + const source = descriptorString.trim(); + const matches = source.match(descriptorPattern) || []; + let eventName = matches[2]; + let keyFilter = matches[3]; + if (keyFilter && !["keydown", "keyup", "keypress"].includes(eventName)) { + eventName += `.${keyFilter}`; + keyFilter = ""; + } + return { + eventTarget: parseEventTarget(matches[4]), + eventName, + eventOptions: matches[7] ? parseEventOptions(matches[7]) : {}, + identifier: matches[5], + methodName: matches[6], + keyFilter: matches[1] || keyFilter, + }; + } + function parseEventTarget(eventTargetName) { + if (eventTargetName == "window") { + return window; + } + else if (eventTargetName == "document") { + return document; + } + } + function parseEventOptions(eventOptions) { + return eventOptions + .split(":") + .reduce((options, token) => Object.assign(options, { [token.replace(/^!/, "")]: !/^!/.test(token) }), {}); + } + function stringifyEventTarget(eventTarget) { + if (eventTarget == window) { + return "window"; + } + else if (eventTarget == document) { + return "document"; + } + } + + function camelize(value) { + return value.replace(/(?:[_-])([a-z0-9])/g, (_, char) => char.toUpperCase()); + } + function namespaceCamelize(value) { + return camelize(value.replace(/--/g, "-").replace(/__/g, "_")); + } + function capitalize(value) { + return value.charAt(0).toUpperCase() + value.slice(1); + } + function dasherize(value) { + return value.replace(/([A-Z])/g, (_, char) => `-${char.toLowerCase()}`); + } + function tokenize(value) { + return value.match(/[^\s]+/g) || []; + } + function hasProperty(object, property) { + return Object.prototype.hasOwnProperty.call(object, property); + } + + const allModifiers = ["meta", "ctrl", "alt", "shift"]; + class Action { + constructor(element, index, descriptor, schema) { + this.element = element; + this.index = index; + this.eventTarget = descriptor.eventTarget || element; + this.eventName = descriptor.eventName || getDefaultEventNameForElement(element) || error("missing event name"); + this.eventOptions = descriptor.eventOptions || {}; + this.identifier = descriptor.identifier || error("missing identifier"); + this.methodName = descriptor.methodName || error("missing method name"); + this.keyFilter = descriptor.keyFilter || ""; + this.schema = schema; + } + static forToken(token, schema) { + return new this(token.element, token.index, parseActionDescriptorString(token.content), schema); + } + toString() { + const eventFilter = this.keyFilter ? `.${this.keyFilter}` : ""; + const eventTarget = this.eventTargetName ? `@${this.eventTargetName}` : ""; + return `${this.eventName}${eventFilter}${eventTarget}->${this.identifier}#${this.methodName}`; + } + shouldIgnoreKeyboardEvent(event) { + if (!this.keyFilter) { + return false; + } + const filters = this.keyFilter.split("+"); + if (this.keyFilterDissatisfied(event, filters)) { + return true; + } + const standardFilter = filters.filter((key) => !allModifiers.includes(key))[0]; + if (!standardFilter) { + return false; + } + if (!hasProperty(this.keyMappings, standardFilter)) { + error(`contains unknown key filter: ${this.keyFilter}`); + } + return this.keyMappings[standardFilter].toLowerCase() !== event.key.toLowerCase(); + } + shouldIgnoreMouseEvent(event) { + if (!this.keyFilter) { + return false; + } + const filters = [this.keyFilter]; + if (this.keyFilterDissatisfied(event, filters)) { + return true; + } + return false; + } + get params() { + const params = {}; + const pattern = new RegExp(`^data-${this.identifier}-(.+)-param$`, "i"); + for (const { name, value } of Array.from(this.element.attributes)) { + const match = name.match(pattern); + const key = match && match[1]; + if (key) { + params[camelize(key)] = typecast(value); + } + } + return params; + } + get eventTargetName() { + return stringifyEventTarget(this.eventTarget); + } + get keyMappings() { + return this.schema.keyMappings; + } + keyFilterDissatisfied(event, filters) { + const [meta, ctrl, alt, shift] = allModifiers.map((modifier) => filters.includes(modifier)); + return event.metaKey !== meta || event.ctrlKey !== ctrl || event.altKey !== alt || event.shiftKey !== shift; + } + } + const defaultEventNames = { + a: () => "click", + button: () => "click", + form: () => "submit", + details: () => "toggle", + input: (e) => (e.getAttribute("type") == "submit" ? "click" : "input"), + select: () => "change", + textarea: () => "input", + }; + function getDefaultEventNameForElement(element) { + const tagName = element.tagName.toLowerCase(); + if (tagName in defaultEventNames) { + return defaultEventNames[tagName](element); + } + } + function error(message) { + throw new Error(message); + } + function typecast(value) { + try { + return JSON.parse(value); + } + catch (o_O) { + return value; + } + } + + class Binding { + constructor(context, action) { + this.context = context; + this.action = action; + } + get index() { + return this.action.index; + } + get eventTarget() { + return this.action.eventTarget; + } + get eventOptions() { + return this.action.eventOptions; + } + get identifier() { + return this.context.identifier; + } + handleEvent(event) { + const actionEvent = this.prepareActionEvent(event); + if (this.willBeInvokedByEvent(event) && this.applyEventModifiers(actionEvent)) { + this.invokeWithEvent(actionEvent); + } + } + get eventName() { + return this.action.eventName; + } + get method() { + const method = this.controller[this.methodName]; + if (typeof method == "function") { + return method; + } + throw new Error(`Action "${this.action}" references undefined method "${this.methodName}"`); + } + applyEventModifiers(event) { + const { element } = this.action; + const { actionDescriptorFilters } = this.context.application; + const { controller } = this.context; + let passes = true; + for (const [name, value] of Object.entries(this.eventOptions)) { + if (name in actionDescriptorFilters) { + const filter = actionDescriptorFilters[name]; + passes = passes && filter({ name, value, event, element, controller }); + } + else { + continue; + } + } + return passes; + } + prepareActionEvent(event) { + return Object.assign(event, { params: this.action.params }); + } + invokeWithEvent(event) { + const { target, currentTarget } = event; + try { + this.method.call(this.controller, event); + this.context.logDebugActivity(this.methodName, { event, target, currentTarget, action: this.methodName }); + } + catch (error) { + const { identifier, controller, element, index } = this; + const detail = { identifier, controller, element, index, event }; + this.context.handleError(error, `invoking action "${this.action}"`, detail); + } + } + willBeInvokedByEvent(event) { + const eventTarget = event.target; + if (event instanceof KeyboardEvent && this.action.shouldIgnoreKeyboardEvent(event)) { + return false; + } + if (event instanceof MouseEvent && this.action.shouldIgnoreMouseEvent(event)) { + return false; + } + if (this.element === eventTarget) { + return true; + } + else if (eventTarget instanceof Element && this.element.contains(eventTarget)) { + return this.scope.containsElement(eventTarget); + } + else { + return this.scope.containsElement(this.action.element); + } + } + get controller() { + return this.context.controller; + } + get methodName() { + return this.action.methodName; + } + get element() { + return this.scope.element; + } + get scope() { + return this.context.scope; + } + } + + class ElementObserver { + constructor(element, delegate) { + this.mutationObserverInit = { attributes: true, childList: true, subtree: true }; + this.element = element; + this.started = false; + this.delegate = delegate; + this.elements = new Set(); + this.mutationObserver = new MutationObserver((mutations) => this.processMutations(mutations)); + } + start() { + if (!this.started) { + this.started = true; + this.mutationObserver.observe(this.element, this.mutationObserverInit); + this.refresh(); + } + } + pause(callback) { + if (this.started) { + this.mutationObserver.disconnect(); + this.started = false; + } + callback(); + if (!this.started) { + this.mutationObserver.observe(this.element, this.mutationObserverInit); + this.started = true; + } + } + stop() { + if (this.started) { + this.mutationObserver.takeRecords(); + this.mutationObserver.disconnect(); + this.started = false; + } + } + refresh() { + if (this.started) { + const matches = new Set(this.matchElementsInTree()); + for (const element of Array.from(this.elements)) { + if (!matches.has(element)) { + this.removeElement(element); + } + } + for (const element of Array.from(matches)) { + this.addElement(element); + } + } + } + processMutations(mutations) { + if (this.started) { + for (const mutation of mutations) { + this.processMutation(mutation); + } + } + } + processMutation(mutation) { + if (mutation.type == "attributes") { + this.processAttributeChange(mutation.target, mutation.attributeName); + } + else if (mutation.type == "childList") { + this.processRemovedNodes(mutation.removedNodes); + this.processAddedNodes(mutation.addedNodes); + } + } + processAttributeChange(element, attributeName) { + if (this.elements.has(element)) { + if (this.delegate.elementAttributeChanged && this.matchElement(element)) { + this.delegate.elementAttributeChanged(element, attributeName); + } + else { + this.removeElement(element); + } + } + else if (this.matchElement(element)) { + this.addElement(element); + } + } + processRemovedNodes(nodes) { + for (const node of Array.from(nodes)) { + const element = this.elementFromNode(node); + if (element) { + this.processTree(element, this.removeElement); + } + } + } + processAddedNodes(nodes) { + for (const node of Array.from(nodes)) { + const element = this.elementFromNode(node); + if (element && this.elementIsActive(element)) { + this.processTree(element, this.addElement); + } + } + } + matchElement(element) { + return this.delegate.matchElement(element); + } + matchElementsInTree(tree = this.element) { + return this.delegate.matchElementsInTree(tree); + } + processTree(tree, processor) { + for (const element of this.matchElementsInTree(tree)) { + processor.call(this, element); + } + } + elementFromNode(node) { + if (node.nodeType == Node.ELEMENT_NODE) { + return node; + } + } + elementIsActive(element) { + if (element.isConnected != this.element.isConnected) { + return false; + } + else { + return this.element.contains(element); + } + } + addElement(element) { + if (!this.elements.has(element)) { + if (this.elementIsActive(element)) { + this.elements.add(element); + if (this.delegate.elementMatched) { + this.delegate.elementMatched(element); + } + } + } + } + removeElement(element) { + if (this.elements.has(element)) { + this.elements.delete(element); + if (this.delegate.elementUnmatched) { + this.delegate.elementUnmatched(element); + } + } + } + } + + class AttributeObserver { + constructor(element, attributeName, delegate) { + this.attributeName = attributeName; + this.delegate = delegate; + this.elementObserver = new ElementObserver(element, this); + } + get element() { + return this.elementObserver.element; + } + get selector() { + return `[${this.attributeName}]`; + } + start() { + this.elementObserver.start(); + } + pause(callback) { + this.elementObserver.pause(callback); + } + stop() { + this.elementObserver.stop(); + } + refresh() { + this.elementObserver.refresh(); + } + get started() { + return this.elementObserver.started; + } + matchElement(element) { + return element.hasAttribute(this.attributeName); + } + matchElementsInTree(tree) { + const match = this.matchElement(tree) ? [tree] : []; + const matches = Array.from(tree.querySelectorAll(this.selector)); + return match.concat(matches); + } + elementMatched(element) { + if (this.delegate.elementMatchedAttribute) { + this.delegate.elementMatchedAttribute(element, this.attributeName); + } + } + elementUnmatched(element) { + if (this.delegate.elementUnmatchedAttribute) { + this.delegate.elementUnmatchedAttribute(element, this.attributeName); + } + } + elementAttributeChanged(element, attributeName) { + if (this.delegate.elementAttributeValueChanged && this.attributeName == attributeName) { + this.delegate.elementAttributeValueChanged(element, attributeName); + } + } + } + + function add(map, key, value) { + fetch$1(map, key).add(value); + } + function del(map, key, value) { + fetch$1(map, key).delete(value); + prune(map, key); + } + function fetch$1(map, key) { + let values = map.get(key); + if (!values) { + values = new Set(); + map.set(key, values); + } + return values; + } + function prune(map, key) { + const values = map.get(key); + if (values != null && values.size == 0) { + map.delete(key); + } + } + + class Multimap { + constructor() { + this.valuesByKey = new Map(); + } + get keys() { + return Array.from(this.valuesByKey.keys()); + } + get values() { + const sets = Array.from(this.valuesByKey.values()); + return sets.reduce((values, set) => values.concat(Array.from(set)), []); + } + get size() { + const sets = Array.from(this.valuesByKey.values()); + return sets.reduce((size, set) => size + set.size, 0); + } + add(key, value) { + add(this.valuesByKey, key, value); + } + delete(key, value) { + del(this.valuesByKey, key, value); + } + has(key, value) { + const values = this.valuesByKey.get(key); + return values != null && values.has(value); + } + hasKey(key) { + return this.valuesByKey.has(key); + } + hasValue(value) { + const sets = Array.from(this.valuesByKey.values()); + return sets.some((set) => set.has(value)); + } + getValuesForKey(key) { + const values = this.valuesByKey.get(key); + return values ? Array.from(values) : []; + } + getKeysForValue(value) { + return Array.from(this.valuesByKey) + .filter(([_key, values]) => values.has(value)) + .map(([key, _values]) => key); + } + } + + class SelectorObserver { + constructor(element, selector, delegate, details) { + this._selector = selector; + this.details = details; + this.elementObserver = new ElementObserver(element, this); + this.delegate = delegate; + this.matchesByElement = new Multimap(); + } + get started() { + return this.elementObserver.started; + } + get selector() { + return this._selector; + } + set selector(selector) { + this._selector = selector; + this.refresh(); + } + start() { + this.elementObserver.start(); + } + pause(callback) { + this.elementObserver.pause(callback); + } + stop() { + this.elementObserver.stop(); + } + refresh() { + this.elementObserver.refresh(); + } + get element() { + return this.elementObserver.element; + } + matchElement(element) { + const { selector } = this; + if (selector) { + const matches = element.matches(selector); + if (this.delegate.selectorMatchElement) { + return matches && this.delegate.selectorMatchElement(element, this.details); + } + return matches; + } + else { + return false; + } + } + matchElementsInTree(tree) { + const { selector } = this; + if (selector) { + const match = this.matchElement(tree) ? [tree] : []; + const matches = Array.from(tree.querySelectorAll(selector)).filter((match) => this.matchElement(match)); + return match.concat(matches); + } + else { + return []; + } + } + elementMatched(element) { + const { selector } = this; + if (selector) { + this.selectorMatched(element, selector); + } + } + elementUnmatched(element) { + const selectors = this.matchesByElement.getKeysForValue(element); + for (const selector of selectors) { + this.selectorUnmatched(element, selector); + } + } + elementAttributeChanged(element, _attributeName) { + const { selector } = this; + if (selector) { + const matches = this.matchElement(element); + const matchedBefore = this.matchesByElement.has(selector, element); + if (matches && !matchedBefore) { + this.selectorMatched(element, selector); + } + else if (!matches && matchedBefore) { + this.selectorUnmatched(element, selector); + } + } + } + selectorMatched(element, selector) { + this.delegate.selectorMatched(element, selector, this.details); + this.matchesByElement.add(selector, element); + } + selectorUnmatched(element, selector) { + this.delegate.selectorUnmatched(element, selector, this.details); + this.matchesByElement.delete(selector, element); + } + } + + class StringMapObserver { + constructor(element, delegate) { + this.element = element; + this.delegate = delegate; + this.started = false; + this.stringMap = new Map(); + this.mutationObserver = new MutationObserver((mutations) => this.processMutations(mutations)); + } + start() { + if (!this.started) { + this.started = true; + this.mutationObserver.observe(this.element, { attributes: true, attributeOldValue: true }); + this.refresh(); + } + } + stop() { + if (this.started) { + this.mutationObserver.takeRecords(); + this.mutationObserver.disconnect(); + this.started = false; + } + } + refresh() { + if (this.started) { + for (const attributeName of this.knownAttributeNames) { + this.refreshAttribute(attributeName, null); + } + } + } + processMutations(mutations) { + if (this.started) { + for (const mutation of mutations) { + this.processMutation(mutation); + } + } + } + processMutation(mutation) { + const attributeName = mutation.attributeName; + if (attributeName) { + this.refreshAttribute(attributeName, mutation.oldValue); + } + } + refreshAttribute(attributeName, oldValue) { + const key = this.delegate.getStringMapKeyForAttribute(attributeName); + if (key != null) { + if (!this.stringMap.has(attributeName)) { + this.stringMapKeyAdded(key, attributeName); + } + const value = this.element.getAttribute(attributeName); + if (this.stringMap.get(attributeName) != value) { + this.stringMapValueChanged(value, key, oldValue); + } + if (value == null) { + const oldValue = this.stringMap.get(attributeName); + this.stringMap.delete(attributeName); + if (oldValue) + this.stringMapKeyRemoved(key, attributeName, oldValue); + } + else { + this.stringMap.set(attributeName, value); + } + } + } + stringMapKeyAdded(key, attributeName) { + if (this.delegate.stringMapKeyAdded) { + this.delegate.stringMapKeyAdded(key, attributeName); + } + } + stringMapValueChanged(value, key, oldValue) { + if (this.delegate.stringMapValueChanged) { + this.delegate.stringMapValueChanged(value, key, oldValue); + } + } + stringMapKeyRemoved(key, attributeName, oldValue) { + if (this.delegate.stringMapKeyRemoved) { + this.delegate.stringMapKeyRemoved(key, attributeName, oldValue); + } + } + get knownAttributeNames() { + return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames))); + } + get currentAttributeNames() { + return Array.from(this.element.attributes).map((attribute) => attribute.name); + } + get recordedAttributeNames() { + return Array.from(this.stringMap.keys()); + } + } + + class TokenListObserver { + constructor(element, attributeName, delegate) { + this.attributeObserver = new AttributeObserver(element, attributeName, this); + this.delegate = delegate; + this.tokensByElement = new Multimap(); + } + get started() { + return this.attributeObserver.started; + } + start() { + this.attributeObserver.start(); + } + pause(callback) { + this.attributeObserver.pause(callback); + } + stop() { + this.attributeObserver.stop(); + } + refresh() { + this.attributeObserver.refresh(); + } + get element() { + return this.attributeObserver.element; + } + get attributeName() { + return this.attributeObserver.attributeName; + } + elementMatchedAttribute(element) { + this.tokensMatched(this.readTokensForElement(element)); + } + elementAttributeValueChanged(element) { + const [unmatchedTokens, matchedTokens] = this.refreshTokensForElement(element); + this.tokensUnmatched(unmatchedTokens); + this.tokensMatched(matchedTokens); + } + elementUnmatchedAttribute(element) { + this.tokensUnmatched(this.tokensByElement.getValuesForKey(element)); + } + tokensMatched(tokens) { + tokens.forEach((token) => this.tokenMatched(token)); + } + tokensUnmatched(tokens) { + tokens.forEach((token) => this.tokenUnmatched(token)); + } + tokenMatched(token) { + this.delegate.tokenMatched(token); + this.tokensByElement.add(token.element, token); + } + tokenUnmatched(token) { + this.delegate.tokenUnmatched(token); + this.tokensByElement.delete(token.element, token); + } + refreshTokensForElement(element) { + const previousTokens = this.tokensByElement.getValuesForKey(element); + const currentTokens = this.readTokensForElement(element); + const firstDifferingIndex = zip(previousTokens, currentTokens).findIndex(([previousToken, currentToken]) => !tokensAreEqual(previousToken, currentToken)); + if (firstDifferingIndex == -1) { + return [[], []]; + } + else { + return [previousTokens.slice(firstDifferingIndex), currentTokens.slice(firstDifferingIndex)]; + } + } + readTokensForElement(element) { + const attributeName = this.attributeName; + const tokenString = element.getAttribute(attributeName) || ""; + return parseTokenString(tokenString, element, attributeName); + } + } + function parseTokenString(tokenString, element, attributeName) { + return tokenString + .trim() + .split(/\s+/) + .filter((content) => content.length) + .map((content, index) => ({ element, attributeName, content, index })); + } + function zip(left, right) { + const length = Math.max(left.length, right.length); + return Array.from({ length }, (_, index) => [left[index], right[index]]); + } + function tokensAreEqual(left, right) { + return left && right && left.index == right.index && left.content == right.content; + } + + class ValueListObserver { + constructor(element, attributeName, delegate) { + this.tokenListObserver = new TokenListObserver(element, attributeName, this); + this.delegate = delegate; + this.parseResultsByToken = new WeakMap(); + this.valuesByTokenByElement = new WeakMap(); + } + get started() { + return this.tokenListObserver.started; + } + start() { + this.tokenListObserver.start(); + } + stop() { + this.tokenListObserver.stop(); + } + refresh() { + this.tokenListObserver.refresh(); + } + get element() { + return this.tokenListObserver.element; + } + get attributeName() { + return this.tokenListObserver.attributeName; + } + tokenMatched(token) { + const { element } = token; + const { value } = this.fetchParseResultForToken(token); + if (value) { + this.fetchValuesByTokenForElement(element).set(token, value); + this.delegate.elementMatchedValue(element, value); + } + } + tokenUnmatched(token) { + const { element } = token; + const { value } = this.fetchParseResultForToken(token); + if (value) { + this.fetchValuesByTokenForElement(element).delete(token); + this.delegate.elementUnmatchedValue(element, value); + } + } + fetchParseResultForToken(token) { + let parseResult = this.parseResultsByToken.get(token); + if (!parseResult) { + parseResult = this.parseToken(token); + this.parseResultsByToken.set(token, parseResult); + } + return parseResult; + } + fetchValuesByTokenForElement(element) { + let valuesByToken = this.valuesByTokenByElement.get(element); + if (!valuesByToken) { + valuesByToken = new Map(); + this.valuesByTokenByElement.set(element, valuesByToken); + } + return valuesByToken; + } + parseToken(token) { + try { + const value = this.delegate.parseValueForToken(token); + return { value }; + } + catch (error) { + return { error }; + } + } + } + + class BindingObserver { + constructor(context, delegate) { + this.context = context; + this.delegate = delegate; + this.bindingsByAction = new Map(); + } + start() { + if (!this.valueListObserver) { + this.valueListObserver = new ValueListObserver(this.element, this.actionAttribute, this); + this.valueListObserver.start(); + } + } + stop() { + if (this.valueListObserver) { + this.valueListObserver.stop(); + delete this.valueListObserver; + this.disconnectAllActions(); + } + } + get element() { + return this.context.element; + } + get identifier() { + return this.context.identifier; + } + get actionAttribute() { + return this.schema.actionAttribute; + } + get schema() { + return this.context.schema; + } + get bindings() { + return Array.from(this.bindingsByAction.values()); + } + connectAction(action) { + const binding = new Binding(this.context, action); + this.bindingsByAction.set(action, binding); + this.delegate.bindingConnected(binding); + } + disconnectAction(action) { + const binding = this.bindingsByAction.get(action); + if (binding) { + this.bindingsByAction.delete(action); + this.delegate.bindingDisconnected(binding); + } + } + disconnectAllActions() { + this.bindings.forEach((binding) => this.delegate.bindingDisconnected(binding, true)); + this.bindingsByAction.clear(); + } + parseValueForToken(token) { + const action = Action.forToken(token, this.schema); + if (action.identifier == this.identifier) { + return action; + } + } + elementMatchedValue(element, action) { + this.connectAction(action); + } + elementUnmatchedValue(element, action) { + this.disconnectAction(action); + } + } + + class ValueObserver { + constructor(context, receiver) { + this.context = context; + this.receiver = receiver; + this.stringMapObserver = new StringMapObserver(this.element, this); + this.valueDescriptorMap = this.controller.valueDescriptorMap; + } + start() { + this.stringMapObserver.start(); + this.invokeChangedCallbacksForDefaultValues(); + } + stop() { + this.stringMapObserver.stop(); + } + get element() { + return this.context.element; + } + get controller() { + return this.context.controller; + } + getStringMapKeyForAttribute(attributeName) { + if (attributeName in this.valueDescriptorMap) { + return this.valueDescriptorMap[attributeName].name; + } + } + stringMapKeyAdded(key, attributeName) { + const descriptor = this.valueDescriptorMap[attributeName]; + if (!this.hasValue(key)) { + this.invokeChangedCallback(key, descriptor.writer(this.receiver[key]), descriptor.writer(descriptor.defaultValue)); + } + } + stringMapValueChanged(value, name, oldValue) { + const descriptor = this.valueDescriptorNameMap[name]; + if (value === null) + return; + if (oldValue === null) { + oldValue = descriptor.writer(descriptor.defaultValue); + } + this.invokeChangedCallback(name, value, oldValue); + } + stringMapKeyRemoved(key, attributeName, oldValue) { + const descriptor = this.valueDescriptorNameMap[key]; + if (this.hasValue(key)) { + this.invokeChangedCallback(key, descriptor.writer(this.receiver[key]), oldValue); + } + else { + this.invokeChangedCallback(key, descriptor.writer(descriptor.defaultValue), oldValue); + } + } + invokeChangedCallbacksForDefaultValues() { + for (const { key, name, defaultValue, writer } of this.valueDescriptors) { + if (defaultValue != undefined && !this.controller.data.has(key)) { + this.invokeChangedCallback(name, writer(defaultValue), undefined); + } + } + } + invokeChangedCallback(name, rawValue, rawOldValue) { + const changedMethodName = `${name}Changed`; + const changedMethod = this.receiver[changedMethodName]; + if (typeof changedMethod == "function") { + const descriptor = this.valueDescriptorNameMap[name]; + try { + const value = descriptor.reader(rawValue); + let oldValue = rawOldValue; + if (rawOldValue) { + oldValue = descriptor.reader(rawOldValue); + } + changedMethod.call(this.receiver, value, oldValue); + } + catch (error) { + if (error instanceof TypeError) { + error.message = `Stimulus Value "${this.context.identifier}.${descriptor.name}" - ${error.message}`; + } + throw error; + } + } + } + get valueDescriptors() { + const { valueDescriptorMap } = this; + return Object.keys(valueDescriptorMap).map((key) => valueDescriptorMap[key]); + } + get valueDescriptorNameMap() { + const descriptors = {}; + Object.keys(this.valueDescriptorMap).forEach((key) => { + const descriptor = this.valueDescriptorMap[key]; + descriptors[descriptor.name] = descriptor; + }); + return descriptors; + } + hasValue(attributeName) { + const descriptor = this.valueDescriptorNameMap[attributeName]; + const hasMethodName = `has${capitalize(descriptor.name)}`; + return this.receiver[hasMethodName]; + } + } + + class TargetObserver { + constructor(context, delegate) { + this.context = context; + this.delegate = delegate; + this.targetsByName = new Multimap(); + } + start() { + if (!this.tokenListObserver) { + this.tokenListObserver = new TokenListObserver(this.element, this.attributeName, this); + this.tokenListObserver.start(); + } + } + stop() { + if (this.tokenListObserver) { + this.disconnectAllTargets(); + this.tokenListObserver.stop(); + delete this.tokenListObserver; + } + } + tokenMatched({ element, content: name }) { + if (this.scope.containsElement(element)) { + this.connectTarget(element, name); + } + } + tokenUnmatched({ element, content: name }) { + this.disconnectTarget(element, name); + } + connectTarget(element, name) { + var _a; + if (!this.targetsByName.has(name, element)) { + this.targetsByName.add(name, element); + (_a = this.tokenListObserver) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.targetConnected(element, name)); + } + } + disconnectTarget(element, name) { + var _a; + if (this.targetsByName.has(name, element)) { + this.targetsByName.delete(name, element); + (_a = this.tokenListObserver) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.targetDisconnected(element, name)); + } + } + disconnectAllTargets() { + for (const name of this.targetsByName.keys) { + for (const element of this.targetsByName.getValuesForKey(name)) { + this.disconnectTarget(element, name); + } + } + } + get attributeName() { + return `data-${this.context.identifier}-target`; + } + get element() { + return this.context.element; + } + get scope() { + return this.context.scope; + } + } + + function readInheritableStaticArrayValues(constructor, propertyName) { + const ancestors = getAncestorsForConstructor(constructor); + return Array.from(ancestors.reduce((values, constructor) => { + getOwnStaticArrayValues(constructor, propertyName).forEach((name) => values.add(name)); + return values; + }, new Set())); + } + function getAncestorsForConstructor(constructor) { + const ancestors = []; + while (constructor) { + ancestors.push(constructor); + constructor = Object.getPrototypeOf(constructor); + } + return ancestors.reverse(); + } + function getOwnStaticArrayValues(constructor, propertyName) { + const definition = constructor[propertyName]; + return Array.isArray(definition) ? definition : []; + } + + class OutletObserver { + constructor(context, delegate) { + this.started = false; + this.context = context; + this.delegate = delegate; + this.outletsByName = new Multimap(); + this.outletElementsByName = new Multimap(); + this.selectorObserverMap = new Map(); + this.attributeObserverMap = new Map(); + } + start() { + if (!this.started) { + this.outletDefinitions.forEach((outletName) => { + this.setupSelectorObserverForOutlet(outletName); + this.setupAttributeObserverForOutlet(outletName); + }); + this.started = true; + this.dependentContexts.forEach((context) => context.refresh()); + } + } + refresh() { + this.selectorObserverMap.forEach((observer) => observer.refresh()); + this.attributeObserverMap.forEach((observer) => observer.refresh()); + } + stop() { + if (this.started) { + this.started = false; + this.disconnectAllOutlets(); + this.stopSelectorObservers(); + this.stopAttributeObservers(); + } + } + stopSelectorObservers() { + if (this.selectorObserverMap.size > 0) { + this.selectorObserverMap.forEach((observer) => observer.stop()); + this.selectorObserverMap.clear(); + } + } + stopAttributeObservers() { + if (this.attributeObserverMap.size > 0) { + this.attributeObserverMap.forEach((observer) => observer.stop()); + this.attributeObserverMap.clear(); + } + } + selectorMatched(element, _selector, { outletName }) { + const outlet = this.getOutlet(element, outletName); + if (outlet) { + this.connectOutlet(outlet, element, outletName); + } + } + selectorUnmatched(element, _selector, { outletName }) { + const outlet = this.getOutletFromMap(element, outletName); + if (outlet) { + this.disconnectOutlet(outlet, element, outletName); + } + } + selectorMatchElement(element, { outletName }) { + const selector = this.selector(outletName); + const hasOutlet = this.hasOutlet(element, outletName); + const hasOutletController = element.matches(`[${this.schema.controllerAttribute}~=${outletName}]`); + if (selector) { + return hasOutlet && hasOutletController && element.matches(selector); + } + else { + return false; + } + } + elementMatchedAttribute(_element, attributeName) { + const outletName = this.getOutletNameFromOutletAttributeName(attributeName); + if (outletName) { + this.updateSelectorObserverForOutlet(outletName); + } + } + elementAttributeValueChanged(_element, attributeName) { + const outletName = this.getOutletNameFromOutletAttributeName(attributeName); + if (outletName) { + this.updateSelectorObserverForOutlet(outletName); + } + } + elementUnmatchedAttribute(_element, attributeName) { + const outletName = this.getOutletNameFromOutletAttributeName(attributeName); + if (outletName) { + this.updateSelectorObserverForOutlet(outletName); + } + } + connectOutlet(outlet, element, outletName) { + var _a; + if (!this.outletElementsByName.has(outletName, element)) { + this.outletsByName.add(outletName, outlet); + this.outletElementsByName.add(outletName, element); + (_a = this.selectorObserverMap.get(outletName)) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.outletConnected(outlet, element, outletName)); + } + } + disconnectOutlet(outlet, element, outletName) { + var _a; + if (this.outletElementsByName.has(outletName, element)) { + this.outletsByName.delete(outletName, outlet); + this.outletElementsByName.delete(outletName, element); + (_a = this.selectorObserverMap + .get(outletName)) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.outletDisconnected(outlet, element, outletName)); + } + } + disconnectAllOutlets() { + for (const outletName of this.outletElementsByName.keys) { + for (const element of this.outletElementsByName.getValuesForKey(outletName)) { + for (const outlet of this.outletsByName.getValuesForKey(outletName)) { + this.disconnectOutlet(outlet, element, outletName); + } + } + } + } + updateSelectorObserverForOutlet(outletName) { + const observer = this.selectorObserverMap.get(outletName); + if (observer) { + observer.selector = this.selector(outletName); + } + } + setupSelectorObserverForOutlet(outletName) { + const selector = this.selector(outletName); + const selectorObserver = new SelectorObserver(document.body, selector, this, { outletName }); + this.selectorObserverMap.set(outletName, selectorObserver); + selectorObserver.start(); + } + setupAttributeObserverForOutlet(outletName) { + const attributeName = this.attributeNameForOutletName(outletName); + const attributeObserver = new AttributeObserver(this.scope.element, attributeName, this); + this.attributeObserverMap.set(outletName, attributeObserver); + attributeObserver.start(); + } + selector(outletName) { + return this.scope.outlets.getSelectorForOutletName(outletName); + } + attributeNameForOutletName(outletName) { + return this.scope.schema.outletAttributeForScope(this.identifier, outletName); + } + getOutletNameFromOutletAttributeName(attributeName) { + return this.outletDefinitions.find((outletName) => this.attributeNameForOutletName(outletName) === attributeName); + } + get outletDependencies() { + const dependencies = new Multimap(); + this.router.modules.forEach((module) => { + const constructor = module.definition.controllerConstructor; + const outlets = readInheritableStaticArrayValues(constructor, "outlets"); + outlets.forEach((outlet) => dependencies.add(outlet, module.identifier)); + }); + return dependencies; + } + get outletDefinitions() { + return this.outletDependencies.getKeysForValue(this.identifier); + } + get dependentControllerIdentifiers() { + return this.outletDependencies.getValuesForKey(this.identifier); + } + get dependentContexts() { + const identifiers = this.dependentControllerIdentifiers; + return this.router.contexts.filter((context) => identifiers.includes(context.identifier)); + } + hasOutlet(element, outletName) { + return !!this.getOutlet(element, outletName) || !!this.getOutletFromMap(element, outletName); + } + getOutlet(element, outletName) { + return this.application.getControllerForElementAndIdentifier(element, outletName); + } + getOutletFromMap(element, outletName) { + return this.outletsByName.getValuesForKey(outletName).find((outlet) => outlet.element === element); + } + get scope() { + return this.context.scope; + } + get schema() { + return this.context.schema; + } + get identifier() { + return this.context.identifier; + } + get application() { + return this.context.application; + } + get router() { + return this.application.router; + } + } + + class Context { + constructor(module, scope) { + this.logDebugActivity = (functionName, detail = {}) => { + const { identifier, controller, element } = this; + detail = Object.assign({ identifier, controller, element }, detail); + this.application.logDebugActivity(this.identifier, functionName, detail); + }; + this.module = module; + this.scope = scope; + this.controller = new module.controllerConstructor(this); + this.bindingObserver = new BindingObserver(this, this.dispatcher); + this.valueObserver = new ValueObserver(this, this.controller); + this.targetObserver = new TargetObserver(this, this); + this.outletObserver = new OutletObserver(this, this); + try { + this.controller.initialize(); + this.logDebugActivity("initialize"); + } + catch (error) { + this.handleError(error, "initializing controller"); + } + } + connect() { + this.bindingObserver.start(); + this.valueObserver.start(); + this.targetObserver.start(); + this.outletObserver.start(); + try { + this.controller.connect(); + this.logDebugActivity("connect"); + } + catch (error) { + this.handleError(error, "connecting controller"); + } + } + refresh() { + this.outletObserver.refresh(); + } + disconnect() { + try { + this.controller.disconnect(); + this.logDebugActivity("disconnect"); + } + catch (error) { + this.handleError(error, "disconnecting controller"); + } + this.outletObserver.stop(); + this.targetObserver.stop(); + this.valueObserver.stop(); + this.bindingObserver.stop(); + } + get application() { + return this.module.application; + } + get identifier() { + return this.module.identifier; + } + get schema() { + return this.application.schema; + } + get dispatcher() { + return this.application.dispatcher; + } + get element() { + return this.scope.element; + } + get parentElement() { + return this.element.parentElement; + } + handleError(error, message, detail = {}) { + const { identifier, controller, element } = this; + detail = Object.assign({ identifier, controller, element }, detail); + this.application.handleError(error, `Error ${message}`, detail); + } + targetConnected(element, name) { + this.invokeControllerMethod(`${name}TargetConnected`, element); + } + targetDisconnected(element, name) { + this.invokeControllerMethod(`${name}TargetDisconnected`, element); + } + outletConnected(outlet, element, name) { + this.invokeControllerMethod(`${namespaceCamelize(name)}OutletConnected`, outlet, element); + } + outletDisconnected(outlet, element, name) { + this.invokeControllerMethod(`${namespaceCamelize(name)}OutletDisconnected`, outlet, element); + } + invokeControllerMethod(methodName, ...args) { + const controller = this.controller; + if (typeof controller[methodName] == "function") { + controller[methodName](...args); + } + } + } + + function bless(constructor) { + return shadow(constructor, getBlessedProperties(constructor)); + } + function shadow(constructor, properties) { + const shadowConstructor = extend(constructor); + const shadowProperties = getShadowProperties(constructor.prototype, properties); + Object.defineProperties(shadowConstructor.prototype, shadowProperties); + return shadowConstructor; + } + function getBlessedProperties(constructor) { + const blessings = readInheritableStaticArrayValues(constructor, "blessings"); + return blessings.reduce((blessedProperties, blessing) => { + const properties = blessing(constructor); + for (const key in properties) { + const descriptor = blessedProperties[key] || {}; + blessedProperties[key] = Object.assign(descriptor, properties[key]); + } + return blessedProperties; + }, {}); + } + function getShadowProperties(prototype, properties) { + return getOwnKeys(properties).reduce((shadowProperties, key) => { + const descriptor = getShadowedDescriptor(prototype, properties, key); + if (descriptor) { + Object.assign(shadowProperties, { [key]: descriptor }); + } + return shadowProperties; + }, {}); + } + function getShadowedDescriptor(prototype, properties, key) { + const shadowingDescriptor = Object.getOwnPropertyDescriptor(prototype, key); + const shadowedByValue = shadowingDescriptor && "value" in shadowingDescriptor; + if (!shadowedByValue) { + const descriptor = Object.getOwnPropertyDescriptor(properties, key).value; + if (shadowingDescriptor) { + descriptor.get = shadowingDescriptor.get || descriptor.get; + descriptor.set = shadowingDescriptor.set || descriptor.set; + } + return descriptor; + } + } + const getOwnKeys = (() => { + if (typeof Object.getOwnPropertySymbols == "function") { + return (object) => [...Object.getOwnPropertyNames(object), ...Object.getOwnPropertySymbols(object)]; + } + else { + return Object.getOwnPropertyNames; + } + })(); + const extend = (() => { + function extendWithReflect(constructor) { + function extended() { + return Reflect.construct(constructor, arguments, new.target); + } + extended.prototype = Object.create(constructor.prototype, { + constructor: { value: extended }, + }); + Reflect.setPrototypeOf(extended, constructor); + return extended; + } + function testReflectExtension() { + const a = function () { + this.a.call(this); + }; + const b = extendWithReflect(a); + b.prototype.a = function () { }; + return new b(); + } + try { + testReflectExtension(); + return extendWithReflect; + } + catch (error) { + return (constructor) => class extended extends constructor { + }; + } + })(); + + function blessDefinition(definition) { + return { + identifier: definition.identifier, + controllerConstructor: bless(definition.controllerConstructor), + }; + } + + class Module { + constructor(application, definition) { + this.application = application; + this.definition = blessDefinition(definition); + this.contextsByScope = new WeakMap(); + this.connectedContexts = new Set(); + } + get identifier() { + return this.definition.identifier; + } + get controllerConstructor() { + return this.definition.controllerConstructor; + } + get contexts() { + return Array.from(this.connectedContexts); + } + connectContextForScope(scope) { + const context = this.fetchContextForScope(scope); + this.connectedContexts.add(context); + context.connect(); + } + disconnectContextForScope(scope) { + const context = this.contextsByScope.get(scope); + if (context) { + this.connectedContexts.delete(context); + context.disconnect(); + } + } + fetchContextForScope(scope) { + let context = this.contextsByScope.get(scope); + if (!context) { + context = new Context(this, scope); + this.contextsByScope.set(scope, context); + } + return context; + } + } + + class ClassMap { + constructor(scope) { + this.scope = scope; + } + has(name) { + return this.data.has(this.getDataKey(name)); + } + get(name) { + return this.getAll(name)[0]; + } + getAll(name) { + const tokenString = this.data.get(this.getDataKey(name)) || ""; + return tokenize(tokenString); + } + getAttributeName(name) { + return this.data.getAttributeNameForKey(this.getDataKey(name)); + } + getDataKey(name) { + return `${name}-class`; + } + get data() { + return this.scope.data; + } + } + + class DataMap { + constructor(scope) { + this.scope = scope; + } + get element() { + return this.scope.element; + } + get identifier() { + return this.scope.identifier; + } + get(key) { + const name = this.getAttributeNameForKey(key); + return this.element.getAttribute(name); + } + set(key, value) { + const name = this.getAttributeNameForKey(key); + this.element.setAttribute(name, value); + return this.get(key); + } + has(key) { + const name = this.getAttributeNameForKey(key); + return this.element.hasAttribute(name); + } + delete(key) { + if (this.has(key)) { + const name = this.getAttributeNameForKey(key); + this.element.removeAttribute(name); + return true; + } + else { + return false; + } + } + getAttributeNameForKey(key) { + return `data-${this.identifier}-${dasherize(key)}`; + } + } + + class Guide { + constructor(logger) { + this.warnedKeysByObject = new WeakMap(); + this.logger = logger; + } + warn(object, key, message) { + let warnedKeys = this.warnedKeysByObject.get(object); + if (!warnedKeys) { + warnedKeys = new Set(); + this.warnedKeysByObject.set(object, warnedKeys); + } + if (!warnedKeys.has(key)) { + warnedKeys.add(key); + this.logger.warn(message, object); + } + } + } + + function attributeValueContainsToken(attributeName, token) { + return `[${attributeName}~="${token}"]`; + } + + class TargetSet { + constructor(scope) { + this.scope = scope; + } + get element() { + return this.scope.element; + } + get identifier() { + return this.scope.identifier; + } + get schema() { + return this.scope.schema; + } + has(targetName) { + return this.find(targetName) != null; + } + find(...targetNames) { + return targetNames.reduce((target, targetName) => target || this.findTarget(targetName) || this.findLegacyTarget(targetName), undefined); + } + findAll(...targetNames) { + return targetNames.reduce((targets, targetName) => [ + ...targets, + ...this.findAllTargets(targetName), + ...this.findAllLegacyTargets(targetName), + ], []); + } + findTarget(targetName) { + const selector = this.getSelectorForTargetName(targetName); + return this.scope.findElement(selector); + } + findAllTargets(targetName) { + const selector = this.getSelectorForTargetName(targetName); + return this.scope.findAllElements(selector); + } + getSelectorForTargetName(targetName) { + const attributeName = this.schema.targetAttributeForScope(this.identifier); + return attributeValueContainsToken(attributeName, targetName); + } + findLegacyTarget(targetName) { + const selector = this.getLegacySelectorForTargetName(targetName); + return this.deprecate(this.scope.findElement(selector), targetName); + } + findAllLegacyTargets(targetName) { + const selector = this.getLegacySelectorForTargetName(targetName); + return this.scope.findAllElements(selector).map((element) => this.deprecate(element, targetName)); + } + getLegacySelectorForTargetName(targetName) { + const targetDescriptor = `${this.identifier}.${targetName}`; + return attributeValueContainsToken(this.schema.targetAttribute, targetDescriptor); + } + deprecate(element, targetName) { + if (element) { + const { identifier } = this; + const attributeName = this.schema.targetAttribute; + const revisedAttributeName = this.schema.targetAttributeForScope(identifier); + this.guide.warn(element, `target:${targetName}`, `Please replace ${attributeName}="${identifier}.${targetName}" with ${revisedAttributeName}="${targetName}". ` + + `The ${attributeName} attribute is deprecated and will be removed in a future version of Stimulus.`); + } + return element; + } + get guide() { + return this.scope.guide; + } + } + + class OutletSet { + constructor(scope, controllerElement) { + this.scope = scope; + this.controllerElement = controllerElement; + } + get element() { + return this.scope.element; + } + get identifier() { + return this.scope.identifier; + } + get schema() { + return this.scope.schema; + } + has(outletName) { + return this.find(outletName) != null; + } + find(...outletNames) { + return outletNames.reduce((outlet, outletName) => outlet || this.findOutlet(outletName), undefined); + } + findAll(...outletNames) { + return outletNames.reduce((outlets, outletName) => [...outlets, ...this.findAllOutlets(outletName)], []); + } + getSelectorForOutletName(outletName) { + const attributeName = this.schema.outletAttributeForScope(this.identifier, outletName); + return this.controllerElement.getAttribute(attributeName); + } + findOutlet(outletName) { + const selector = this.getSelectorForOutletName(outletName); + if (selector) + return this.findElement(selector, outletName); + } + findAllOutlets(outletName) { + const selector = this.getSelectorForOutletName(outletName); + return selector ? this.findAllElements(selector, outletName) : []; + } + findElement(selector, outletName) { + const elements = this.scope.queryElements(selector); + return elements.filter((element) => this.matchesElement(element, selector, outletName))[0]; + } + findAllElements(selector, outletName) { + const elements = this.scope.queryElements(selector); + return elements.filter((element) => this.matchesElement(element, selector, outletName)); + } + matchesElement(element, selector, outletName) { + const controllerAttribute = element.getAttribute(this.scope.schema.controllerAttribute) || ""; + return element.matches(selector) && controllerAttribute.split(" ").includes(outletName); + } + } + + class Scope { + constructor(schema, element, identifier, logger) { + this.targets = new TargetSet(this); + this.classes = new ClassMap(this); + this.data = new DataMap(this); + this.containsElement = (element) => { + return element.closest(this.controllerSelector) === this.element; + }; + this.schema = schema; + this.element = element; + this.identifier = identifier; + this.guide = new Guide(logger); + this.outlets = new OutletSet(this.documentScope, element); + } + findElement(selector) { + return this.element.matches(selector) ? this.element : this.queryElements(selector).find(this.containsElement); + } + findAllElements(selector) { + return [ + ...(this.element.matches(selector) ? [this.element] : []), + ...this.queryElements(selector).filter(this.containsElement), + ]; + } + queryElements(selector) { + return Array.from(this.element.querySelectorAll(selector)); + } + get controllerSelector() { + return attributeValueContainsToken(this.schema.controllerAttribute, this.identifier); + } + get isDocumentScope() { + return this.element === document.documentElement; + } + get documentScope() { + return this.isDocumentScope + ? this + : new Scope(this.schema, document.documentElement, this.identifier, this.guide.logger); + } + } + + class ScopeObserver { + constructor(element, schema, delegate) { + this.element = element; + this.schema = schema; + this.delegate = delegate; + this.valueListObserver = new ValueListObserver(this.element, this.controllerAttribute, this); + this.scopesByIdentifierByElement = new WeakMap(); + this.scopeReferenceCounts = new WeakMap(); + } + start() { + this.valueListObserver.start(); + } + stop() { + this.valueListObserver.stop(); + } + get controllerAttribute() { + return this.schema.controllerAttribute; + } + parseValueForToken(token) { + const { element, content: identifier } = token; + return this.parseValueForElementAndIdentifier(element, identifier); + } + parseValueForElementAndIdentifier(element, identifier) { + const scopesByIdentifier = this.fetchScopesByIdentifierForElement(element); + let scope = scopesByIdentifier.get(identifier); + if (!scope) { + scope = this.delegate.createScopeForElementAndIdentifier(element, identifier); + scopesByIdentifier.set(identifier, scope); + } + return scope; + } + elementMatchedValue(element, value) { + const referenceCount = (this.scopeReferenceCounts.get(value) || 0) + 1; + this.scopeReferenceCounts.set(value, referenceCount); + if (referenceCount == 1) { + this.delegate.scopeConnected(value); + } + } + elementUnmatchedValue(element, value) { + const referenceCount = this.scopeReferenceCounts.get(value); + if (referenceCount) { + this.scopeReferenceCounts.set(value, referenceCount - 1); + if (referenceCount == 1) { + this.delegate.scopeDisconnected(value); + } + } + } + fetchScopesByIdentifierForElement(element) { + let scopesByIdentifier = this.scopesByIdentifierByElement.get(element); + if (!scopesByIdentifier) { + scopesByIdentifier = new Map(); + this.scopesByIdentifierByElement.set(element, scopesByIdentifier); + } + return scopesByIdentifier; + } + } + + class Router { + constructor(application) { + this.application = application; + this.scopeObserver = new ScopeObserver(this.element, this.schema, this); + this.scopesByIdentifier = new Multimap(); + this.modulesByIdentifier = new Map(); + } + get element() { + return this.application.element; + } + get schema() { + return this.application.schema; + } + get logger() { + return this.application.logger; + } + get controllerAttribute() { + return this.schema.controllerAttribute; + } + get modules() { + return Array.from(this.modulesByIdentifier.values()); + } + get contexts() { + return this.modules.reduce((contexts, module) => contexts.concat(module.contexts), []); + } + start() { + this.scopeObserver.start(); + } + stop() { + this.scopeObserver.stop(); + } + loadDefinition(definition) { + this.unloadIdentifier(definition.identifier); + const module = new Module(this.application, definition); + this.connectModule(module); + const afterLoad = definition.controllerConstructor.afterLoad; + if (afterLoad) { + afterLoad.call(definition.controllerConstructor, definition.identifier, this.application); + } + } + unloadIdentifier(identifier) { + const module = this.modulesByIdentifier.get(identifier); + if (module) { + this.disconnectModule(module); + } + } + getContextForElementAndIdentifier(element, identifier) { + const module = this.modulesByIdentifier.get(identifier); + if (module) { + return module.contexts.find((context) => context.element == element); + } + } + proposeToConnectScopeForElementAndIdentifier(element, identifier) { + const scope = this.scopeObserver.parseValueForElementAndIdentifier(element, identifier); + if (scope) { + this.scopeObserver.elementMatchedValue(scope.element, scope); + } + else { + console.error(`Couldn't find or create scope for identifier: "${identifier}" and element:`, element); + } + } + handleError(error, message, detail) { + this.application.handleError(error, message, detail); + } + createScopeForElementAndIdentifier(element, identifier) { + return new Scope(this.schema, element, identifier, this.logger); + } + scopeConnected(scope) { + this.scopesByIdentifier.add(scope.identifier, scope); + const module = this.modulesByIdentifier.get(scope.identifier); + if (module) { + module.connectContextForScope(scope); + } + } + scopeDisconnected(scope) { + this.scopesByIdentifier.delete(scope.identifier, scope); + const module = this.modulesByIdentifier.get(scope.identifier); + if (module) { + module.disconnectContextForScope(scope); + } + } + connectModule(module) { + this.modulesByIdentifier.set(module.identifier, module); + const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier); + scopes.forEach((scope) => module.connectContextForScope(scope)); + } + disconnectModule(module) { + this.modulesByIdentifier.delete(module.identifier); + const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier); + scopes.forEach((scope) => module.disconnectContextForScope(scope)); + } + } + + const defaultSchema = { + controllerAttribute: "data-controller", + actionAttribute: "data-action", + targetAttribute: "data-target", + targetAttributeForScope: (identifier) => `data-${identifier}-target`, + outletAttributeForScope: (identifier, outlet) => `data-${identifier}-${outlet}-outlet`, + keyMappings: Object.assign(Object.assign({ enter: "Enter", tab: "Tab", esc: "Escape", space: " ", up: "ArrowUp", down: "ArrowDown", left: "ArrowLeft", right: "ArrowRight", home: "Home", end: "End", page_up: "PageUp", page_down: "PageDown" }, objectFromEntries("abcdefghijklmnopqrstuvwxyz".split("").map((c) => [c, c]))), objectFromEntries("0123456789".split("").map((n) => [n, n]))), + }; + function objectFromEntries(array) { + return array.reduce((memo, [k, v]) => (Object.assign(Object.assign({}, memo), { [k]: v })), {}); + } + + class Application { + constructor(element = document.documentElement, schema = defaultSchema) { + this.logger = console; + this.debug = false; + this.logDebugActivity = (identifier, functionName, detail = {}) => { + if (this.debug) { + this.logFormattedMessage(identifier, functionName, detail); + } + }; + this.element = element; + this.schema = schema; + this.dispatcher = new Dispatcher(this); + this.router = new Router(this); + this.actionDescriptorFilters = Object.assign({}, defaultActionDescriptorFilters); + } + static start(element, schema) { + const application = new this(element, schema); + application.start(); + return application; + } + async start() { + await domReady(); + this.logDebugActivity("application", "starting"); + this.dispatcher.start(); + this.router.start(); + this.logDebugActivity("application", "start"); + } + stop() { + this.logDebugActivity("application", "stopping"); + this.dispatcher.stop(); + this.router.stop(); + this.logDebugActivity("application", "stop"); + } + register(identifier, controllerConstructor) { + this.load({ identifier, controllerConstructor }); + } + registerActionOption(name, filter) { + this.actionDescriptorFilters[name] = filter; + } + load(head, ...rest) { + const definitions = Array.isArray(head) ? head : [head, ...rest]; + definitions.forEach((definition) => { + if (definition.controllerConstructor.shouldLoad) { + this.router.loadDefinition(definition); + } + }); + } + unload(head, ...rest) { + const identifiers = Array.isArray(head) ? head : [head, ...rest]; + identifiers.forEach((identifier) => this.router.unloadIdentifier(identifier)); + } + get controllers() { + return this.router.contexts.map((context) => context.controller); + } + getControllerForElementAndIdentifier(element, identifier) { + const context = this.router.getContextForElementAndIdentifier(element, identifier); + return context ? context.controller : null; + } + handleError(error, message, detail) { + var _a; + this.logger.error(`%s\n\n%o\n\n%o`, message, error, detail); + (_a = window.onerror) === null || _a === void 0 ? void 0 : _a.call(window, message, "", 0, 0, error); + } + logFormattedMessage(identifier, functionName, detail = {}) { + detail = Object.assign({ application: this }, detail); + this.logger.groupCollapsed(`${identifier} #${functionName}`); + this.logger.log("details:", Object.assign({}, detail)); + this.logger.groupEnd(); + } + } + function domReady() { + return new Promise((resolve) => { + if (document.readyState == "loading") { + document.addEventListener("DOMContentLoaded", () => resolve()); + } + else { + resolve(); + } + }); + } + + class StimulusReloader { + static async reload(filePattern) { + const document = await reloadHtmlDocument(); + return new StimulusReloader(document, filePattern).reload(); + } + constructor(document) { + let filePattern = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : /./; + this.document = document; + this.filePattern = filePattern; + this.application = window.Stimulus || Application.start(); + } + async reload() { + log("Reload Stimulus controllers..."); + this.application.stop(); + await this.#reloadStimulusControllers(); + this.application.start(); + } + async #reloadStimulusControllers() { + await Promise.all(this.#stimulusControllerPaths.map(async moduleName => this.#reloadStimulusController(moduleName))); + } + get #stimulusControllerPaths() { + return Object.keys(this.#stimulusPathsByModule).filter(path => path.endsWith("_controller") && this.#shouldReloadController(path)); + } + #shouldReloadController(path) { + return this.filePattern.test(path); + } + get #stimulusPathsByModule() { + this.pathsByModule = this.pathsByModule || this.#parseImportmapJson(); + return this.pathsByModule; + } + #parseImportmapJson() { + const importmapScript = this.document.querySelector("script[type=importmap]"); + return JSON.parse(importmapScript.text).imports; + } + async #reloadStimulusController(moduleName) { + log(`\t${moduleName}`); + const controllerName = this.#extractControllerName(moduleName); + const path = cacheBustedUrl(this.#pathForModuleName(moduleName)); + const module = await import(path); + this.#registerController(controllerName, module); + } + #pathForModuleName(moduleName) { + return this.#stimulusPathsByModule[moduleName]; + } + #extractControllerName(path) { + return path.replace(/^.*\//, "").replace("_controller", "").replace(/\//g, "--").replace(/_/g, "-"); + } + #registerController(name, module) { + this.application.unload(name); + this.application.register(name, module.default); + } + } + + class HtmlReloader { + static async reload() { + return new HtmlReloader().reload(); + } + async reload() { + const reloadedDocument = await this.#reloadHtml(); + await this.#reloadStimulus(reloadedDocument); + } + async #reloadHtml() { + log("Reload html..."); + const reloadedDocument = await reloadHtmlDocument(); + this.#updateBody(reloadedDocument.body); + return reloadedDocument; + } + #updateBody(newBody) { + Idiomorph.morph(document.body, newBody); + } + async #reloadStimulus(reloadedDocument) { + return new StimulusReloader(reloadedDocument).reload(); + } + } + + class CssReloader { + static async reload() { + for (var _len = arguments.length, params = new Array(_len), _key = 0; _key < _len; _key++) { + params[_key] = arguments[_key]; + } + return new CssReloader(...params).reload(); + } + constructor() { + let filePattern = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : /./; + this.filePattern = filePattern; + } + async reload() { + log("Reload css..."); + await Promise.all(await this.#reloadAllLinks()); + } + async #reloadAllLinks() { + const cssLinks = await this.#loadNewCssLinks(); + return cssLinks.map(link => this.#reloadLinkIfNeeded(link)); + } + async #loadNewCssLinks() { + const reloadedDocument = await reloadHtmlDocument(); + return Array.from(reloadedDocument.head.querySelectorAll("link[rel='stylesheet']")); + } + #reloadLinkIfNeeded(link) { + if (this.#shouldReloadLink(link)) { + return this.#reloadLink(link); + } else { + return Promise.resolve(); + } + } + #shouldReloadLink(link) { + return this.filePattern.test(link.getAttribute("href")); + } + async #reloadLink(link) { + return new Promise(resolve => { + const href = link.getAttribute("href"); + const newLink = this.#findExistingLinkFor(link) || this.#appendNewLink(link); + newLink.setAttribute("href", cacheBustedUrl(link.getAttribute("href"))); + newLink.onload = () => { + log(`\t${href}`); + resolve(); + }; + }); + } + #findExistingLinkFor(link) { + return this.#cssLinks.find(newLink => pathWithoutAssetDigest(link.href) === pathWithoutAssetDigest(newLink.href)); + } + get #cssLinks() { + return Array.from(document.querySelectorAll("link[rel='stylesheet']")); + } + #appendNewLink(link) { + document.head.append(link); + return link; + } + } + + consumer.subscriptions.create({ + channel: "Hotwire::Spark::Channel" + }, { + connected() { + document.body.setAttribute("data-hotwire-spark-ready", ""); + }, + async received(message) { + try { + await this.dispatch(message); + } catch (error) { + console.log(`Error on ${message.action}`, error); + } + }, + dispatch(_ref) { + let { + action, + path + } = _ref; + const fileName = assetNameFromPath(path); + switch (action) { + case "reload_html": + return this.reloadHtml(); + case "reload_css": + return this.reloadCss(fileName); + case "reload_stimulus": + return this.reloadStimulus(fileName); + default: + throw new Error(`Unknown action: ${action}`); + } + }, + reloadHtml() { + return HtmlReloader.reload(); + }, + reloadCss(fileName) { + return CssReloader.reload(new RegExp(fileName)); + }, + reloadStimulus(fileName) { + return StimulusReloader.reload(new RegExp(fileName)); + } + }); + + const HotwireSpark = { + config: { + loggingEnabled: false + } + }; + document.addEventListener("DOMContentLoaded", function () { + HotwireSpark.config.loggingEnabled = getConfigurationProperty("logging"); + }); + + return HotwireSpark; + +})(); diff --git a/app/assets/javascripts/hotwire_spark.js.map b/app/assets/javascripts/hotwire_spark.js.map new file mode 100644 index 00000000..eebc587b --- /dev/null +++ b/app/assets/javascripts/hotwire_spark.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hotwire_spark.js","sources":["../../javascript/hotwire_spark/index.js"],"sourcesContent":["import \"stream_actions/reload_css\"\nimport \"stream_actions/reload_html\"\n\nconsole.debug(\"HOLA!\")\n"],"names":["console","debug"],"mappings":";;;CAGAA,OAAO,CAACC,KAAK,CAAC,OAAO,CAAC;;;;;;"} diff --git a/app/assets/javascripts/hotwire_spark.min.js b/app/assets/javascripts/hotwire_spark.min.js new file mode 100644 index 00000000..3fda26ca --- /dev/null +++ b/app/assets/javascripts/hotwire_spark.min.js @@ -0,0 +1,2 @@ +var HotwireSpark=function(){"use strict";var e={logger:"undefined"!=typeof console?console:void 0,WebSocket:"undefined"!=typeof WebSocket?WebSocket:void 0},t={log(...t){this.enabled&&(t.push(Date.now()),e.logger.log("[ActionCable]",...t))}};const n=()=>(new Date).getTime(),s=e=>(n()-e)/1e3;class r{constructor(e){this.visibilityDidChange=this.visibilityDidChange.bind(this),this.connection=e,this.reconnectAttempts=0}start(){this.isRunning()||(this.startedAt=n(),delete this.stoppedAt,this.startPolling(),addEventListener("visibilitychange",this.visibilityDidChange),t.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`))}stop(){this.isRunning()&&(this.stoppedAt=n(),this.stopPolling(),removeEventListener("visibilitychange",this.visibilityDidChange),t.log("ConnectionMonitor stopped"))}isRunning(){return this.startedAt&&!this.stoppedAt}recordMessage(){this.pingedAt=n()}recordConnect(){this.reconnectAttempts=0,delete this.disconnectedAt,t.log("ConnectionMonitor recorded connect")}recordDisconnect(){this.disconnectedAt=n(),t.log("ConnectionMonitor recorded disconnect")}startPolling(){this.stopPolling(),this.poll()}stopPolling(){clearTimeout(this.pollTimeout)}poll(){this.pollTimeout=setTimeout((()=>{this.reconnectIfStale(),this.poll()}),this.getPollInterval())}getPollInterval(){const{staleThreshold:e,reconnectionBackoffRate:t}=this.constructor;return 1e3*e*Math.pow(1+t,Math.min(this.reconnectAttempts,10))*(1+(0===this.reconnectAttempts?1:t)*Math.random())}reconnectIfStale(){this.connectionIsStale()&&(t.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${s(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`),this.reconnectAttempts++,this.disconnectedRecently()?t.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${s(this.disconnectedAt)} s`):(t.log("ConnectionMonitor reopening"),this.connection.reopen()))}get refreshedAt(){return this.pingedAt?this.pingedAt:this.startedAt}connectionIsStale(){return s(this.refreshedAt)>this.constructor.staleThreshold}disconnectedRecently(){return this.disconnectedAt&&s(this.disconnectedAt){!this.connectionIsStale()&&this.connection.isOpen()||(t.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`),this.connection.reopen())}),200)}}r.staleThreshold=6,r.reconnectionBackoffRate=.15;var i={message_types:{welcome:"welcome",disconnect:"disconnect",ping:"ping",confirmation:"confirm_subscription",rejection:"reject_subscription"},disconnect_reasons:{unauthorized:"unauthorized",invalid_request:"invalid_request",server_restart:"server_restart",remote:"remote"},default_mount_path:"/cable",protocols:["actioncable-v1-json","actioncable-unsupported"]};const{message_types:o,protocols:a}=i,c=a.slice(0,a.length-1),l=[].indexOf;class h{constructor(e){this.open=this.open.bind(this),this.consumer=e,this.subscriptions=this.consumer.subscriptions,this.monitor=new r(this),this.disconnected=!0}send(e){return!!this.isOpen()&&(this.webSocket.send(JSON.stringify(e)),!0)}open(){if(this.isActive())return t.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`),!1;{const n=[...a,...this.consumer.subprotocols||[]];return t.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${n}`),this.webSocket&&this.uninstallEventHandlers(),this.webSocket=new e.WebSocket(this.consumer.url,n),this.installEventHandlers(),this.monitor.start(),!0}}close({allowReconnect:e}={allowReconnect:!0}){if(e||this.monitor.stop(),this.isOpen())return this.webSocket.close()}reopen(){if(t.log(`Reopening WebSocket, current state is ${this.getState()}`),!this.isActive())return this.open();try{return this.close()}catch(e){t.log("Failed to reopen WebSocket",e)}finally{t.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`),setTimeout(this.open,this.constructor.reopenDelay)}}getProtocol(){if(this.webSocket)return this.webSocket.protocol}isOpen(){return this.isState("open")}isActive(){return this.isState("open","connecting")}triedToReconnect(){return this.monitor.reconnectAttempts>0}isProtocolSupported(){return l.call(c,this.getProtocol())>=0}isState(...e){return l.call(e,this.getState())>=0}getState(){if(this.webSocket)for(let t in e.WebSocket)if(e.WebSocket[t]===this.webSocket.readyState)return t.toLowerCase();return null}installEventHandlers(){for(let e in this.events){const t=this.events[e].bind(this);this.webSocket[`on${e}`]=t}}uninstallEventHandlers(){for(let e in this.events)this.webSocket[`on${e}`]=function(){}}}h.reopenDelay=500,h.prototype.events={message(e){if(!this.isProtocolSupported())return;const{identifier:n,message:s,reason:r,reconnect:i,type:a}=JSON.parse(e.data);switch(this.monitor.recordMessage(),a){case o.welcome:return this.triedToReconnect()&&(this.reconnectAttempted=!0),this.monitor.recordConnect(),this.subscriptions.reload();case o.disconnect:return t.log(`Disconnecting. Reason: ${r}`),this.close({allowReconnect:i});case o.ping:return null;case o.confirmation:return this.subscriptions.confirmSubscription(n),this.reconnectAttempted?(this.reconnectAttempted=!1,this.subscriptions.notify(n,"connected",{reconnected:!0})):this.subscriptions.notify(n,"connected",{reconnected:!1});case o.rejection:return this.subscriptions.reject(n);default:return this.subscriptions.notify(n,"received",s)}},open(){if(t.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`),this.disconnected=!1,!this.isProtocolSupported())return t.log("Protocol is unsupported. Stopping monitor and disconnecting."),this.close({allowReconnect:!1})},close(e){if(t.log("WebSocket onclose event"),!this.disconnected)return this.disconnected=!0,this.monitor.recordDisconnect(),this.subscriptions.notifyAll("disconnected",{willAttemptReconnect:this.monitor.isRunning()})},error(){t.log("WebSocket onerror event")}};class u{constructor(e,t={},n){this.consumer=e,this.identifier=JSON.stringify(t),function(e,t){if(null!=t)for(let n in t){const s=t[n];e[n]=s}}(this,n)}perform(e,t={}){return t.action=e,this.send(t)}send(e){return this.consumer.send({command:"message",identifier:this.identifier,data:JSON.stringify(e)})}unsubscribe(){return this.consumer.subscriptions.remove(this)}}class d{constructor(e){this.subscriptions=e,this.pendingSubscriptions=[]}guarantee(e){-1==this.pendingSubscriptions.indexOf(e)?(t.log(`SubscriptionGuarantor guaranteeing ${e.identifier}`),this.pendingSubscriptions.push(e)):t.log(`SubscriptionGuarantor already guaranteeing ${e.identifier}`),this.startGuaranteeing()}forget(e){t.log(`SubscriptionGuarantor forgetting ${e.identifier}`),this.pendingSubscriptions=this.pendingSubscriptions.filter((t=>t!==e))}startGuaranteeing(){this.stopGuaranteeing(),this.retrySubscribing()}stopGuaranteeing(){clearTimeout(this.retryTimeout)}retrySubscribing(){this.retryTimeout=setTimeout((()=>{this.subscriptions&&"function"==typeof this.subscriptions.subscribe&&this.pendingSubscriptions.map((e=>{t.log(`SubscriptionGuarantor resubscribing ${e.identifier}`),this.subscriptions.subscribe(e)}))}),500)}}class m{constructor(e){this.consumer=e,this.guarantor=new d(this),this.subscriptions=[]}create(e,t){const n="object"==typeof e?e:{channel:e},s=new u(this.consumer,n,t);return this.add(s)}add(e){return this.subscriptions.push(e),this.consumer.ensureActiveConnection(),this.notify(e,"initialized"),this.subscribe(e),e}remove(e){return this.forget(e),this.findAll(e.identifier).length||this.sendCommand(e,"unsubscribe"),e}reject(e){return this.findAll(e).map((e=>(this.forget(e),this.notify(e,"rejected"),e)))}forget(e){return this.guarantor.forget(e),this.subscriptions=this.subscriptions.filter((t=>t!==e)),e}findAll(e){return this.subscriptions.filter((t=>t.identifier===e))}reload(){return this.subscriptions.map((e=>this.subscribe(e)))}notifyAll(e,...t){return this.subscriptions.map((n=>this.notify(n,e,...t)))}notify(e,t,...n){let s;return s="string"==typeof e?this.findAll(e):[e],s.map((e=>"function"==typeof e[t]?e[t](...n):void 0))}subscribe(e){this.sendCommand(e,"subscribe")&&this.guarantor.guarantee(e)}confirmSubscription(e){t.log(`Subscription confirmed ${e}`),this.findAll(e).map((e=>this.guarantor.forget(e)))}sendCommand(e,t){const{identifier:n}=e;return this.consumer.send({command:t,identifier:n})}}class p{constructor(e){this._url=e,this.subscriptions=new m(this),this.connection=new h(this),this.subprotocols=[]}get url(){return function(e){"function"==typeof e&&(e=e());if(e&&!/^wss?:/i.test(e)){const t=document.createElement("a");return t.href=e,t.href=t.href,t.protocol=t.protocol.replace("http","ws"),t.href}return e}(this._url)}send(e){return this.connection.send(e)}connect(){return this.connection.open()}disconnect(){return this.connection.close({allowReconnect:!1})}ensureActiveConnection(){if(!this.connection.isActive())return this.connection.open()}addSubProtocol(e){this.subprotocols=[...this.subprotocols,e]}}var g=function(e=function(e){const t=document.head.querySelector(`meta[name='action-cable-${e}']`);if(t)return t.getAttribute("content")}("url")||i.default_mount_path){return new p(e)}();function f(e){return e.replace(/-[a-z0-9]+\.(\w+)(\?.*)?$/,".$1")}function b(e,t){const n=new URL(e,window.location.origin);return Object.entries(t).forEach((e=>{let[t,s]=e;n.searchParams.set(t,s)})),n.toString()}function v(e){return b(e,{reload:Date.now()})}async function y(){let e=v(b(window.location.href,{hotwire_spark:"true"}));const t=await fetch(e);if(!t.ok)throw new Error(`${t.status} when fetching ${e}`);const n=await t.text();return(new DOMParser).parseFromString(n,"text/html")}var A=function(){let e=new Set,t={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:l,afterNodeAdded:l,beforeNodeMorphed:l,afterNodeMorphed:l,beforeNodeRemoved:l,afterNodeRemoved:l,beforeAttributeUpdated:l},head:{style:"merge",shouldPreserve:function(e){return"true"===e.getAttribute("im-preserve")},shouldReAppend:function(e){return"true"===e.getAttribute("im-re-append")},shouldRemove:l,afterHeadMorphed:l}};function n(e,t,s){if(s.head.block){let r=e.querySelector("head"),i=t.querySelector("head");if(r&&i){let o=c(i,r,s);return void Promise.all(o).then((function(){n(e,t,Object.assign(s,{head:{block:!1,ignore:!0}}))}))}}if("innerHTML"===s.morphStyle)return i(t,e,s),e.children;if("outerHTML"===s.morphStyle||null==s.morphStyle){let n=function(e,t,n){let s;s=e.firstChild;let r=s,i=0;for(;s;){let e=g(s,t,n);e>i&&(r=s,i=e),s=s.nextSibling}return r}(t,e,s),i=n?.previousSibling,o=n?.nextSibling,a=r(e,n,s);return n?function(e,t,n){let s=[],r=[];for(;null!=e;)s.push(e),e=e.previousSibling;for(;s.length>0;){let e=s.pop();r.push(e),t.parentElement.insertBefore(e,t)}r.push(t);for(;null!=n;)s.push(n),r.push(n),n=n.nextSibling;for(;s.length>0;)t.parentElement.insertBefore(s.pop(),t.nextSibling);return r}(i,a,o):[]}throw"Do not understand how to morph style "+s.morphStyle}function s(e,t){return t.ignoreActiveValue&&e===document.activeElement}function r(e,t,n){if(!n.ignoreActive||e!==document.activeElement)return null==t?!1===n.callbacks.beforeNodeRemoved(e)?e:(e.remove(),n.callbacks.afterNodeRemoved(e),null):u(e,t)?(!1===n.callbacks.beforeNodeMorphed(e,t)||(e instanceof HTMLHeadElement&&n.head.ignore||(e instanceof HTMLHeadElement&&"morph"!==n.head.style?c(t,e,n):(!function(e,t,n){let r=e.nodeType;if(1===r){const s=e.attributes,r=t.attributes;for(const e of s)o(e.name,t,"update",n)||t.getAttribute(e.name)!==e.value&&t.setAttribute(e.name,e.value);for(let s=r.length-1;0<=s;s--){const i=r[s];o(i.name,t,"remove",n)||(e.hasAttribute(i.name)||t.removeAttribute(i.name))}}8!==r&&3!==r||t.nodeValue!==e.nodeValue&&(t.nodeValue=e.nodeValue);s(t,n)||function(e,t,n){if(e instanceof HTMLInputElement&&t instanceof HTMLInputElement&&"file"!==e.type){let s=e.value,r=t.value;a(e,t,"checked",n),a(e,t,"disabled",n),e.hasAttribute("value")?s!==r&&(o("value",t,"update",n)||(t.setAttribute("value",s),t.value=s)):o("value",t,"remove",n)||(t.value="",t.removeAttribute("value"))}else if(e instanceof HTMLOptionElement)a(e,t,"selected",n);else if(e instanceof HTMLTextAreaElement&&t instanceof HTMLTextAreaElement){let s=e.value,r=t.value;if(o("value",t,"update",n))return;s!==r&&(t.value=s),t.firstChild&&t.firstChild.nodeValue!==s&&(t.firstChild.nodeValue=s)}}(e,t,n)}(t,e,n),s(e,n)||i(t,e,n))),n.callbacks.afterNodeMorphed(e,t)),e):!1===n.callbacks.beforeNodeRemoved(e)||!1===n.callbacks.beforeNodeAdded(t)?e:(e.parentElement.replaceChild(t,e),n.callbacks.afterNodeAdded(t),n.callbacks.afterNodeRemoved(e),t)}function i(e,t,n){let s,i=e.firstChild,o=t.firstChild;for(;i;){if(s=i,i=s.nextSibling,null==o){if(!1===n.callbacks.beforeNodeAdded(s))return;t.appendChild(s),n.callbacks.afterNodeAdded(s),y(n,s);continue}if(h(s,o,n)){r(o,s,n),o=o.nextSibling,y(n,s);continue}let a=m(e,t,s,o,n);if(a){o=d(o,a,n),r(a,s,n),y(n,s);continue}let c=p(e,t,s,o,n);if(c)o=d(o,c,n),r(c,s,n),y(n,s);else{if(!1===n.callbacks.beforeNodeAdded(s))return;t.insertBefore(s,o),n.callbacks.afterNodeAdded(s),y(n,s)}}for(;null!==o;){let e=o;o=o.nextSibling,f(e,n)}}function o(e,t,n,s){return!("value"!==e||!s.ignoreActiveValue||t!==document.activeElement)||!1===s.callbacks.beforeAttributeUpdated(e,t,n)}function a(e,t,n,s){if(e[n]!==t[n]){let r=o(n,t,"update",s);r||(t[n]=e[n]),e[n]?r||t.setAttribute(n,e[n]):o(n,t,"remove",s)||t.removeAttribute(n)}}function c(e,t,n){let s=[],r=[],i=[],o=[],a=n.head.style,c=new Map;for(const t of e.children)c.set(t.outerHTML,t);for(const e of t.children){let t=c.has(e.outerHTML),s=n.head.shouldReAppend(e),l=n.head.shouldPreserve(e);t||l?s?r.push(e):(c.delete(e.outerHTML),i.push(e)):"append"===a?s&&(r.push(e),o.push(e)):!1!==n.head.shouldRemove(e)&&r.push(e)}o.push(...c.values());let l=[];for(const e of o){let r=document.createRange().createContextualFragment(e.outerHTML).firstChild;if(!1!==n.callbacks.beforeNodeAdded(r)){if(r.href||r.src){let e=null,t=new Promise((function(t){e=t}));r.addEventListener("load",(function(){e()})),l.push(t)}t.appendChild(r),n.callbacks.afterNodeAdded(r),s.push(r)}}for(const e of r)!1!==n.callbacks.beforeNodeRemoved(e)&&(t.removeChild(e),n.callbacks.afterNodeRemoved(e));return n.head.afterHeadMorphed(t,{added:s,kept:i,removed:r}),l}function l(){}function h(e,t,n){return null!=e&&null!=t&&(e.nodeType===t.nodeType&&e.tagName===t.tagName&&(""!==e.id&&e.id===t.id||A(n,e,t)>0))}function u(e,t){return null!=e&&null!=t&&(e.nodeType===t.nodeType&&e.tagName===t.tagName)}function d(e,t,n){for(;e!==t;){let t=e;e=e.nextSibling,f(t,n)}return y(n,t),t.nextSibling}function m(e,t,n,s,r){let i=A(r,n,t);if(i>0){let t=s,o=0;for(;null!=t;){if(h(n,t,r))return t;if(o+=A(r,t,e),o>i)return null;t=t.nextSibling}}return null}function p(e,t,n,s,r){let i=s,o=n.nextSibling,a=0;for(;null!=i;){if(A(r,i,e)>0)return null;if(u(n,i))return i;if(u(o,i)&&(a++,o=o.nextSibling,a>=2))return null;i=i.nextSibling}return i}function g(e,t,n){return u(e,t)?.5+A(n,e,t):0}function f(e,t){y(t,e),!1!==t.callbacks.beforeNodeRemoved(e)&&(e.remove(),t.callbacks.afterNodeRemoved(e))}function b(e,t){return!e.deadIds.has(t)}function v(t,n,s){return(t.idMap.get(s)||e).has(n)}function y(t,n){let s=t.idMap.get(n)||e;for(const e of s)t.deadIds.add(e)}function A(t,n,s){let r=t.idMap.get(n)||e,i=0;for(const e of r)b(t,e)&&v(t,e,s)&&++i;return i}function O(e,t){let n=e.parentElement,s=e.querySelectorAll("[id]");for(const e of s){let s=e;for(;s!==n&&null!=s;){let n=t.get(s);null==n&&(n=new Set,t.set(s,n)),n.add(e.id),s=s.parentElement}}}function E(e,t){let n=new Map;return O(e,n),O(t,n),n}return{morph:function(e,s,r={}){e instanceof Document&&(e=e.documentElement),"string"==typeof s&&(s=function(e){let t=new DOMParser,n=e.replace(/]*>|>)([\s\S]*?)<\/svg>/gim,"");if(n.match(/<\/html>/)||n.match(/<\/head>/)||n.match(/<\/body>/)){let s=t.parseFromString(e,"text/html");if(n.match(/<\/html>/))return s.generatedByIdiomorph=!0,s;{let e=s.firstChild;return e?(e.generatedByIdiomorph=!0,e):null}}{let n=t.parseFromString("","text/html").body.querySelector("template").content;return n.generatedByIdiomorph=!0,n}}(s));let i=function(e){if(null==e){return document.createElement("div")}if(e.generatedByIdiomorph)return e;if(e instanceof Node){const t=document.createElement("div");return t.append(e),t}{const t=document.createElement("div");for(const n of[...e])t.append(n);return t}}(s),o=function(e,n,s){return s=function(e){let n={};return Object.assign(n,t),Object.assign(n,e),n.callbacks={},Object.assign(n.callbacks,t.callbacks),Object.assign(n.callbacks,e.callbacks),n.head={},Object.assign(n.head,t.head),Object.assign(n.head,e.head),n}(s),{target:e,newContent:n,config:s,morphStyle:s.morphStyle,ignoreActive:s.ignoreActive,ignoreActiveValue:s.ignoreActiveValue,idMap:E(e,n),deadIds:new Set,callbacks:s.callbacks,head:s.head}}(e,i,r);return n(e,i,o)},defaults:t}}();function O(){if(pe.config.loggingEnabled){for(var e=arguments.length,t=new Array(e),n=0;n0}get bindings(){return Array.from(this.unorderedBindings).sort(((e,t)=>{const n=e.index,s=t.index;return ns?1:0}))}}class w{constructor(e){this.application=e,this.eventListenerMaps=new Map,this.started=!1}start(){this.started||(this.started=!0,this.eventListeners.forEach((e=>e.connect())))}stop(){this.started&&(this.started=!1,this.eventListeners.forEach((e=>e.disconnect())))}get eventListeners(){return Array.from(this.eventListenerMaps.values()).reduce(((e,t)=>e.concat(Array.from(t.values()))),[])}bindingConnected(e){this.fetchEventListenerForBinding(e).bindingConnected(e)}bindingDisconnected(e,t=!1){this.fetchEventListenerForBinding(e).bindingDisconnected(e),t&&this.clearEventListenersForBinding(e)}handleError(e,t,n={}){this.application.handleError(e,`Error ${t}`,n)}clearEventListenersForBinding(e){const t=this.fetchEventListenerForBinding(e);t.hasBindings()||(t.disconnect(),this.removeMappedEventListenerFor(e))}removeMappedEventListenerFor(e){const{eventTarget:t,eventName:n,eventOptions:s}=e,r=this.fetchEventListenerMapForEventTarget(t),i=this.cacheKey(n,s);r.delete(i),0==r.size&&this.eventListenerMaps.delete(t)}fetchEventListenerForBinding(e){const{eventTarget:t,eventName:n,eventOptions:s}=e;return this.fetchEventListener(t,n,s)}fetchEventListener(e,t,n){const s=this.fetchEventListenerMapForEventTarget(e),r=this.cacheKey(t,n);let i=s.get(r);return i||(i=this.createEventListener(e,t,n),s.set(r,i)),i}createEventListener(e,t,n){const s=new E(e,t,n);return this.started&&s.connect(),s}fetchEventListenerMapForEventTarget(e){let t=this.eventListenerMaps.get(e);return t||(t=new Map,this.eventListenerMaps.set(e,t)),t}cacheKey(e,t){const n=[e];return Object.keys(t).sort().forEach((e=>{n.push(`${t[e]?"":"!"}${e}`)})),n.join(":")}}const k={stop:({event:e,value:t})=>(t&&e.stopPropagation(),!0),prevent:({event:e,value:t})=>(t&&e.preventDefault(),!0),self:({event:e,value:t,element:n})=>!t||n===e.target},M=/^(?:(?:([^.]+?)\+)?(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/;function S(e){return"window"==e?window:"document"==e?document:void 0}function N(e){return e.replace(/(?:[_-])([a-z0-9])/g,((e,t)=>t.toUpperCase()))}function C(e){return N(e.replace(/--/g,"-").replace(/__/g,"_"))}const F=["meta","ctrl","alt","shift"];class T{constructor(e,t,n,s){this.element=e,this.index=t,this.eventTarget=n.eventTarget||e,this.eventName=n.eventName||function(e){const t=e.tagName.toLowerCase();if(t in B)return B[t](e)}(e)||L("missing event name"),this.eventOptions=n.eventOptions||{},this.identifier=n.identifier||L("missing identifier"),this.methodName=n.methodName||L("missing method name"),this.keyFilter=n.keyFilter||"",this.schema=s}static forToken(e,t){return new this(e.element,e.index,function(e){const t=e.trim().match(M)||[];let n=t[2],s=t[3];return s&&!["keydown","keyup","keypress"].includes(n)&&(n+=`.${s}`,s=""),{eventTarget:S(t[4]),eventName:n,eventOptions:t[7]?(r=t[7],r.split(":").reduce(((e,t)=>Object.assign(e,{[t.replace(/^!/,"")]:!/^!/.test(t)})),{})):{},identifier:t[5],methodName:t[6],keyFilter:t[1]||s};var r}(e.content),t)}toString(){const e=this.keyFilter?`.${this.keyFilter}`:"",t=this.eventTargetName?`@${this.eventTargetName}`:"";return`${this.eventName}${e}${t}->${this.identifier}#${this.methodName}`}shouldIgnoreKeyboardEvent(e){if(!this.keyFilter)return!1;const t=this.keyFilter.split("+");if(this.keyFilterDissatisfied(e,t))return!0;const n=t.filter((e=>!F.includes(e)))[0];return!!n&&(s=this.keyMappings,r=n,Object.prototype.hasOwnProperty.call(s,r)||L(`contains unknown key filter: ${this.keyFilter}`),this.keyMappings[n].toLowerCase()!==e.key.toLowerCase());var s,r}shouldIgnoreMouseEvent(e){if(!this.keyFilter)return!1;const t=[this.keyFilter];return!!this.keyFilterDissatisfied(e,t)}get params(){const e={},t=new RegExp(`^data-${this.identifier}-(.+)-param$`,"i");for(const{name:n,value:s}of Array.from(this.element.attributes)){const r=n.match(t),i=r&&r[1];i&&(e[N(i)]=x(s))}return e}get eventTargetName(){return(e=this.eventTarget)==window?"window":e==document?"document":void 0;var e}get keyMappings(){return this.schema.keyMappings}keyFilterDissatisfied(e,t){const[n,s,r,i]=F.map((e=>t.includes(e)));return e.metaKey!==n||e.ctrlKey!==s||e.altKey!==r||e.shiftKey!==i}}const B={a:()=>"click",button:()=>"click",form:()=>"submit",details:()=>"toggle",input:e=>"submit"==e.getAttribute("type")?"click":"input",select:()=>"change",textarea:()=>"input"};function L(e){throw new Error(e)}function x(e){try{return JSON.parse(e)}catch(t){return e}}class D{constructor(e,t){this.context=e,this.action=t}get index(){return this.action.index}get eventTarget(){return this.action.eventTarget}get eventOptions(){return this.action.eventOptions}get identifier(){return this.context.identifier}handleEvent(e){const t=this.prepareActionEvent(e);this.willBeInvokedByEvent(e)&&this.applyEventModifiers(t)&&this.invokeWithEvent(t)}get eventName(){return this.action.eventName}get method(){const e=this.controller[this.methodName];if("function"==typeof e)return e;throw new Error(`Action "${this.action}" references undefined method "${this.methodName}"`)}applyEventModifiers(e){const{element:t}=this.action,{actionDescriptorFilters:n}=this.context.application,{controller:s}=this.context;let r=!0;for(const[i,o]of Object.entries(this.eventOptions))if(i in n){const a=n[i];r=r&&a({name:i,value:o,event:e,element:t,controller:s})}return r}prepareActionEvent(e){return Object.assign(e,{params:this.action.params})}invokeWithEvent(e){const{target:t,currentTarget:n}=e;try{this.method.call(this.controller,e),this.context.logDebugActivity(this.methodName,{event:e,target:t,currentTarget:n,action:this.methodName})}catch(t){const{identifier:n,controller:s,element:r,index:i}=this,o={identifier:n,controller:s,element:r,index:i,event:e};this.context.handleError(t,`invoking action "${this.action}"`,o)}}willBeInvokedByEvent(e){const t=e.target;return!(e instanceof KeyboardEvent&&this.action.shouldIgnoreKeyboardEvent(e))&&(!(e instanceof MouseEvent&&this.action.shouldIgnoreMouseEvent(e))&&(this.element===t||(t instanceof Element&&this.element.contains(t)?this.scope.containsElement(t):this.scope.containsElement(this.action.element))))}get controller(){return this.context.controller}get methodName(){return this.action.methodName}get element(){return this.scope.element}get scope(){return this.context.scope}}class ${constructor(e,t){this.mutationObserverInit={attributes:!0,childList:!0,subtree:!0},this.element=e,this.started=!1,this.delegate=t,this.elements=new Set,this.mutationObserver=new MutationObserver((e=>this.processMutations(e)))}start(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,this.mutationObserverInit),this.refresh())}pause(e){this.started&&(this.mutationObserver.disconnect(),this.started=!1),e(),this.started||(this.mutationObserver.observe(this.element,this.mutationObserverInit),this.started=!0)}stop(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}refresh(){if(this.started){const e=new Set(this.matchElementsInTree());for(const t of Array.from(this.elements))e.has(t)||this.removeElement(t);for(const t of Array.from(e))this.addElement(t)}}processMutations(e){if(this.started)for(const t of e)this.processMutation(t)}processMutation(e){"attributes"==e.type?this.processAttributeChange(e.target,e.attributeName):"childList"==e.type&&(this.processRemovedNodes(e.removedNodes),this.processAddedNodes(e.addedNodes))}processAttributeChange(e,t){this.elements.has(e)?this.delegate.elementAttributeChanged&&this.matchElement(e)?this.delegate.elementAttributeChanged(e,t):this.removeElement(e):this.matchElement(e)&&this.addElement(e)}processRemovedNodes(e){for(const t of Array.from(e)){const e=this.elementFromNode(t);e&&this.processTree(e,this.removeElement)}}processAddedNodes(e){for(const t of Array.from(e)){const e=this.elementFromNode(t);e&&this.elementIsActive(e)&&this.processTree(e,this.addElement)}}matchElement(e){return this.delegate.matchElement(e)}matchElementsInTree(e=this.element){return this.delegate.matchElementsInTree(e)}processTree(e,t){for(const n of this.matchElementsInTree(e))t.call(this,n)}elementFromNode(e){if(e.nodeType==Node.ELEMENT_NODE)return e}elementIsActive(e){return e.isConnected==this.element.isConnected&&this.element.contains(e)}addElement(e){this.elements.has(e)||this.elementIsActive(e)&&(this.elements.add(e),this.delegate.elementMatched&&this.delegate.elementMatched(e))}removeElement(e){this.elements.has(e)&&(this.elements.delete(e),this.delegate.elementUnmatched&&this.delegate.elementUnmatched(e))}}class I{constructor(e,t,n){this.attributeName=t,this.delegate=n,this.elementObserver=new $(e,this)}get element(){return this.elementObserver.element}get selector(){return`[${this.attributeName}]`}start(){this.elementObserver.start()}pause(e){this.elementObserver.pause(e)}stop(){this.elementObserver.stop()}refresh(){this.elementObserver.refresh()}get started(){return this.elementObserver.started}matchElement(e){return e.hasAttribute(this.attributeName)}matchElementsInTree(e){const t=this.matchElement(e)?[e]:[],n=Array.from(e.querySelectorAll(this.selector));return t.concat(n)}elementMatched(e){this.delegate.elementMatchedAttribute&&this.delegate.elementMatchedAttribute(e,this.attributeName)}elementUnmatched(e){this.delegate.elementUnmatchedAttribute&&this.delegate.elementUnmatchedAttribute(e,this.attributeName)}elementAttributeChanged(e,t){this.delegate.elementAttributeValueChanged&&this.attributeName==t&&this.delegate.elementAttributeValueChanged(e,t)}}function R(e,t){let n=e.get(t);return n||(n=new Set,e.set(t,n)),n}class V{constructor(){this.valuesByKey=new Map}get keys(){return Array.from(this.valuesByKey.keys())}get values(){return Array.from(this.valuesByKey.values()).reduce(((e,t)=>e.concat(Array.from(t))),[])}get size(){return Array.from(this.valuesByKey.values()).reduce(((e,t)=>e+t.size),0)}add(e,t){!function(e,t,n){R(e,t).add(n)}(this.valuesByKey,e,t)}delete(e,t){!function(e,t,n){R(e,t).delete(n),function(e,t){const n=e.get(t);null!=n&&0==n.size&&e.delete(t)}(e,t)}(this.valuesByKey,e,t)}has(e,t){const n=this.valuesByKey.get(e);return null!=n&&n.has(t)}hasKey(e){return this.valuesByKey.has(e)}hasValue(e){return Array.from(this.valuesByKey.values()).some((t=>t.has(e)))}getValuesForKey(e){const t=this.valuesByKey.get(e);return t?Array.from(t):[]}getKeysForValue(e){return Array.from(this.valuesByKey).filter((([t,n])=>n.has(e))).map((([e,t])=>e))}}class K{constructor(e,t,n,s){this._selector=t,this.details=s,this.elementObserver=new $(e,this),this.delegate=n,this.matchesByElement=new V}get started(){return this.elementObserver.started}get selector(){return this._selector}set selector(e){this._selector=e,this.refresh()}start(){this.elementObserver.start()}pause(e){this.elementObserver.pause(e)}stop(){this.elementObserver.stop()}refresh(){this.elementObserver.refresh()}get element(){return this.elementObserver.element}matchElement(e){const{selector:t}=this;if(t){const n=e.matches(t);return this.delegate.selectorMatchElement?n&&this.delegate.selectorMatchElement(e,this.details):n}return!1}matchElementsInTree(e){const{selector:t}=this;if(t){const n=this.matchElement(e)?[e]:[],s=Array.from(e.querySelectorAll(t)).filter((e=>this.matchElement(e)));return n.concat(s)}return[]}elementMatched(e){const{selector:t}=this;t&&this.selectorMatched(e,t)}elementUnmatched(e){const t=this.matchesByElement.getKeysForValue(e);for(const n of t)this.selectorUnmatched(e,n)}elementAttributeChanged(e,t){const{selector:n}=this;if(n){const t=this.matchElement(e),s=this.matchesByElement.has(n,e);t&&!s?this.selectorMatched(e,n):!t&&s&&this.selectorUnmatched(e,n)}}selectorMatched(e,t){this.delegate.selectorMatched(e,t,this.details),this.matchesByElement.add(t,e)}selectorUnmatched(e,t){this.delegate.selectorUnmatched(e,t,this.details),this.matchesByElement.delete(t,e)}}class P{constructor(e,t){this.element=e,this.delegate=t,this.started=!1,this.stringMap=new Map,this.mutationObserver=new MutationObserver((e=>this.processMutations(e)))}start(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,{attributes:!0,attributeOldValue:!0}),this.refresh())}stop(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}refresh(){if(this.started)for(const e of this.knownAttributeNames)this.refreshAttribute(e,null)}processMutations(e){if(this.started)for(const t of e)this.processMutation(t)}processMutation(e){const t=e.attributeName;t&&this.refreshAttribute(t,e.oldValue)}refreshAttribute(e,t){const n=this.delegate.getStringMapKeyForAttribute(e);if(null!=n){this.stringMap.has(e)||this.stringMapKeyAdded(n,e);const s=this.element.getAttribute(e);if(this.stringMap.get(e)!=s&&this.stringMapValueChanged(s,n,t),null==s){const t=this.stringMap.get(e);this.stringMap.delete(e),t&&this.stringMapKeyRemoved(n,e,t)}else this.stringMap.set(e,s)}}stringMapKeyAdded(e,t){this.delegate.stringMapKeyAdded&&this.delegate.stringMapKeyAdded(e,t)}stringMapValueChanged(e,t,n){this.delegate.stringMapValueChanged&&this.delegate.stringMapValueChanged(e,t,n)}stringMapKeyRemoved(e,t,n){this.delegate.stringMapKeyRemoved&&this.delegate.stringMapKeyRemoved(e,t,n)}get knownAttributeNames(){return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)))}get currentAttributeNames(){return Array.from(this.element.attributes).map((e=>e.name))}get recordedAttributeNames(){return Array.from(this.stringMap.keys())}}class j{constructor(e,t,n){this.attributeObserver=new I(e,t,this),this.delegate=n,this.tokensByElement=new V}get started(){return this.attributeObserver.started}start(){this.attributeObserver.start()}pause(e){this.attributeObserver.pause(e)}stop(){this.attributeObserver.stop()}refresh(){this.attributeObserver.refresh()}get element(){return this.attributeObserver.element}get attributeName(){return this.attributeObserver.attributeName}elementMatchedAttribute(e){this.tokensMatched(this.readTokensForElement(e))}elementAttributeValueChanged(e){const[t,n]=this.refreshTokensForElement(e);this.tokensUnmatched(t),this.tokensMatched(n)}elementUnmatchedAttribute(e){this.tokensUnmatched(this.tokensByElement.getValuesForKey(e))}tokensMatched(e){e.forEach((e=>this.tokenMatched(e)))}tokensUnmatched(e){e.forEach((e=>this.tokenUnmatched(e)))}tokenMatched(e){this.delegate.tokenMatched(e),this.tokensByElement.add(e.element,e)}tokenUnmatched(e){this.delegate.tokenUnmatched(e),this.tokensByElement.delete(e.element,e)}refreshTokensForElement(e){const t=this.tokensByElement.getValuesForKey(e),n=this.readTokensForElement(e),s=function(e,t){const n=Math.max(e.length,t.length);return Array.from({length:n},((n,s)=>[e[s],t[s]]))}(t,n).findIndex((([e,t])=>{return s=t,!((n=e)&&s&&n.index==s.index&&n.content==s.content);var n,s}));return-1==s?[[],[]]:[t.slice(s),n.slice(s)]}readTokensForElement(e){const t=this.attributeName;return function(e,t,n){return e.trim().split(/\s+/).filter((e=>e.length)).map(((e,s)=>({element:t,attributeName:n,content:e,index:s})))}(e.getAttribute(t)||"",e,t)}}class _{constructor(e,t,n){this.tokenListObserver=new j(e,t,this),this.delegate=n,this.parseResultsByToken=new WeakMap,this.valuesByTokenByElement=new WeakMap}get started(){return this.tokenListObserver.started}start(){this.tokenListObserver.start()}stop(){this.tokenListObserver.stop()}refresh(){this.tokenListObserver.refresh()}get element(){return this.tokenListObserver.element}get attributeName(){return this.tokenListObserver.attributeName}tokenMatched(e){const{element:t}=e,{value:n}=this.fetchParseResultForToken(e);n&&(this.fetchValuesByTokenForElement(t).set(e,n),this.delegate.elementMatchedValue(t,n))}tokenUnmatched(e){const{element:t}=e,{value:n}=this.fetchParseResultForToken(e);n&&(this.fetchValuesByTokenForElement(t).delete(e),this.delegate.elementUnmatchedValue(t,n))}fetchParseResultForToken(e){let t=this.parseResultsByToken.get(e);return t||(t=this.parseToken(e),this.parseResultsByToken.set(e,t)),t}fetchValuesByTokenForElement(e){let t=this.valuesByTokenByElement.get(e);return t||(t=new Map,this.valuesByTokenByElement.set(e,t)),t}parseToken(e){try{return{value:this.delegate.parseValueForToken(e)}}catch(e){return{error:e}}}}class U{constructor(e,t){this.context=e,this.delegate=t,this.bindingsByAction=new Map}start(){this.valueListObserver||(this.valueListObserver=new _(this.element,this.actionAttribute,this),this.valueListObserver.start())}stop(){this.valueListObserver&&(this.valueListObserver.stop(),delete this.valueListObserver,this.disconnectAllActions())}get element(){return this.context.element}get identifier(){return this.context.identifier}get actionAttribute(){return this.schema.actionAttribute}get schema(){return this.context.schema}get bindings(){return Array.from(this.bindingsByAction.values())}connectAction(e){const t=new D(this.context,e);this.bindingsByAction.set(e,t),this.delegate.bindingConnected(t)}disconnectAction(e){const t=this.bindingsByAction.get(e);t&&(this.bindingsByAction.delete(e),this.delegate.bindingDisconnected(t))}disconnectAllActions(){this.bindings.forEach((e=>this.delegate.bindingDisconnected(e,!0))),this.bindingsByAction.clear()}parseValueForToken(e){const t=T.forToken(e,this.schema);if(t.identifier==this.identifier)return t}elementMatchedValue(e,t){this.connectAction(t)}elementUnmatchedValue(e,t){this.disconnectAction(t)}}class H{constructor(e,t){this.context=e,this.receiver=t,this.stringMapObserver=new P(this.element,this),this.valueDescriptorMap=this.controller.valueDescriptorMap}start(){this.stringMapObserver.start(),this.invokeChangedCallbacksForDefaultValues()}stop(){this.stringMapObserver.stop()}get element(){return this.context.element}get controller(){return this.context.controller}getStringMapKeyForAttribute(e){if(e in this.valueDescriptorMap)return this.valueDescriptorMap[e].name}stringMapKeyAdded(e,t){const n=this.valueDescriptorMap[t];this.hasValue(e)||this.invokeChangedCallback(e,n.writer(this.receiver[e]),n.writer(n.defaultValue))}stringMapValueChanged(e,t,n){const s=this.valueDescriptorNameMap[t];null!==e&&(null===n&&(n=s.writer(s.defaultValue)),this.invokeChangedCallback(t,e,n))}stringMapKeyRemoved(e,t,n){const s=this.valueDescriptorNameMap[e];this.hasValue(e)?this.invokeChangedCallback(e,s.writer(this.receiver[e]),n):this.invokeChangedCallback(e,s.writer(s.defaultValue),n)}invokeChangedCallbacksForDefaultValues(){for(const{key:e,name:t,defaultValue:n,writer:s}of this.valueDescriptors)null==n||this.controller.data.has(e)||this.invokeChangedCallback(t,s(n),void 0)}invokeChangedCallback(e,t,n){const s=`${e}Changed`,r=this.receiver[s];if("function"==typeof r){const s=this.valueDescriptorNameMap[e];try{const e=s.reader(t);let i=n;n&&(i=s.reader(n)),r.call(this.receiver,e,i)}catch(e){throw e instanceof TypeError&&(e.message=`Stimulus Value "${this.context.identifier}.${s.name}" - ${e.message}`),e}}}get valueDescriptors(){const{valueDescriptorMap:e}=this;return Object.keys(e).map((t=>e[t]))}get valueDescriptorNameMap(){const e={};return Object.keys(this.valueDescriptorMap).forEach((t=>{const n=this.valueDescriptorMap[t];e[n.name]=n})),e}hasValue(e){const t=this.valueDescriptorNameMap[e],n=`has${s=t.name,s.charAt(0).toUpperCase()+s.slice(1)}`;var s;return this.receiver[n]}}class W{constructor(e,t){this.context=e,this.delegate=t,this.targetsByName=new V}start(){this.tokenListObserver||(this.tokenListObserver=new j(this.element,this.attributeName,this),this.tokenListObserver.start())}stop(){this.tokenListObserver&&(this.disconnectAllTargets(),this.tokenListObserver.stop(),delete this.tokenListObserver)}tokenMatched({element:e,content:t}){this.scope.containsElement(e)&&this.connectTarget(e,t)}tokenUnmatched({element:e,content:t}){this.disconnectTarget(e,t)}connectTarget(e,t){var n;this.targetsByName.has(t,e)||(this.targetsByName.add(t,e),null===(n=this.tokenListObserver)||void 0===n||n.pause((()=>this.delegate.targetConnected(e,t))))}disconnectTarget(e,t){var n;this.targetsByName.has(t,e)&&(this.targetsByName.delete(t,e),null===(n=this.tokenListObserver)||void 0===n||n.pause((()=>this.delegate.targetDisconnected(e,t))))}disconnectAllTargets(){for(const e of this.targetsByName.keys)for(const t of this.targetsByName.getValuesForKey(e))this.disconnectTarget(t,e)}get attributeName(){return`data-${this.context.identifier}-target`}get element(){return this.context.element}get scope(){return this.context.scope}}function q(e,t){const n=function(e){const t=[];for(;e;)t.push(e),e=Object.getPrototypeOf(e);return t.reverse()}(e);return Array.from(n.reduce(((e,n)=>(function(e,t){const n=e[t];return Array.isArray(n)?n:[]}(n,t).forEach((t=>e.add(t))),e)),new Set))}class z{constructor(e,t){this.started=!1,this.context=e,this.delegate=t,this.outletsByName=new V,this.outletElementsByName=new V,this.selectorObserverMap=new Map,this.attributeObserverMap=new Map}start(){this.started||(this.outletDefinitions.forEach((e=>{this.setupSelectorObserverForOutlet(e),this.setupAttributeObserverForOutlet(e)})),this.started=!0,this.dependentContexts.forEach((e=>e.refresh())))}refresh(){this.selectorObserverMap.forEach((e=>e.refresh())),this.attributeObserverMap.forEach((e=>e.refresh()))}stop(){this.started&&(this.started=!1,this.disconnectAllOutlets(),this.stopSelectorObservers(),this.stopAttributeObservers())}stopSelectorObservers(){this.selectorObserverMap.size>0&&(this.selectorObserverMap.forEach((e=>e.stop())),this.selectorObserverMap.clear())}stopAttributeObservers(){this.attributeObserverMap.size>0&&(this.attributeObserverMap.forEach((e=>e.stop())),this.attributeObserverMap.clear())}selectorMatched(e,t,{outletName:n}){const s=this.getOutlet(e,n);s&&this.connectOutlet(s,e,n)}selectorUnmatched(e,t,{outletName:n}){const s=this.getOutletFromMap(e,n);s&&this.disconnectOutlet(s,e,n)}selectorMatchElement(e,{outletName:t}){const n=this.selector(t),s=this.hasOutlet(e,t),r=e.matches(`[${this.schema.controllerAttribute}~=${t}]`);return!!n&&(s&&r&&e.matches(n))}elementMatchedAttribute(e,t){const n=this.getOutletNameFromOutletAttributeName(t);n&&this.updateSelectorObserverForOutlet(n)}elementAttributeValueChanged(e,t){const n=this.getOutletNameFromOutletAttributeName(t);n&&this.updateSelectorObserverForOutlet(n)}elementUnmatchedAttribute(e,t){const n=this.getOutletNameFromOutletAttributeName(t);n&&this.updateSelectorObserverForOutlet(n)}connectOutlet(e,t,n){var s;this.outletElementsByName.has(n,t)||(this.outletsByName.add(n,e),this.outletElementsByName.add(n,t),null===(s=this.selectorObserverMap.get(n))||void 0===s||s.pause((()=>this.delegate.outletConnected(e,t,n))))}disconnectOutlet(e,t,n){var s;this.outletElementsByName.has(n,t)&&(this.outletsByName.delete(n,e),this.outletElementsByName.delete(n,t),null===(s=this.selectorObserverMap.get(n))||void 0===s||s.pause((()=>this.delegate.outletDisconnected(e,t,n))))}disconnectAllOutlets(){for(const e of this.outletElementsByName.keys)for(const t of this.outletElementsByName.getValuesForKey(e))for(const n of this.outletsByName.getValuesForKey(e))this.disconnectOutlet(n,t,e)}updateSelectorObserverForOutlet(e){const t=this.selectorObserverMap.get(e);t&&(t.selector=this.selector(e))}setupSelectorObserverForOutlet(e){const t=this.selector(e),n=new K(document.body,t,this,{outletName:e});this.selectorObserverMap.set(e,n),n.start()}setupAttributeObserverForOutlet(e){const t=this.attributeNameForOutletName(e),n=new I(this.scope.element,t,this);this.attributeObserverMap.set(e,n),n.start()}selector(e){return this.scope.outlets.getSelectorForOutletName(e)}attributeNameForOutletName(e){return this.scope.schema.outletAttributeForScope(this.identifier,e)}getOutletNameFromOutletAttributeName(e){return this.outletDefinitions.find((t=>this.attributeNameForOutletName(t)===e))}get outletDependencies(){const e=new V;return this.router.modules.forEach((t=>{q(t.definition.controllerConstructor,"outlets").forEach((n=>e.add(n,t.identifier)))})),e}get outletDefinitions(){return this.outletDependencies.getKeysForValue(this.identifier)}get dependentControllerIdentifiers(){return this.outletDependencies.getValuesForKey(this.identifier)}get dependentContexts(){const e=this.dependentControllerIdentifiers;return this.router.contexts.filter((t=>e.includes(t.identifier)))}hasOutlet(e,t){return!!this.getOutlet(e,t)||!!this.getOutletFromMap(e,t)}getOutlet(e,t){return this.application.getControllerForElementAndIdentifier(e,t)}getOutletFromMap(e,t){return this.outletsByName.getValuesForKey(t).find((t=>t.element===e))}get scope(){return this.context.scope}get schema(){return this.context.schema}get identifier(){return this.context.identifier}get application(){return this.context.application}get router(){return this.application.router}}class G{constructor(e,t){this.logDebugActivity=(e,t={})=>{const{identifier:n,controller:s,element:r}=this;t=Object.assign({identifier:n,controller:s,element:r},t),this.application.logDebugActivity(this.identifier,e,t)},this.module=e,this.scope=t,this.controller=new e.controllerConstructor(this),this.bindingObserver=new U(this,this.dispatcher),this.valueObserver=new H(this,this.controller),this.targetObserver=new W(this,this),this.outletObserver=new z(this,this);try{this.controller.initialize(),this.logDebugActivity("initialize")}catch(e){this.handleError(e,"initializing controller")}}connect(){this.bindingObserver.start(),this.valueObserver.start(),this.targetObserver.start(),this.outletObserver.start();try{this.controller.connect(),this.logDebugActivity("connect")}catch(e){this.handleError(e,"connecting controller")}}refresh(){this.outletObserver.refresh()}disconnect(){try{this.controller.disconnect(),this.logDebugActivity("disconnect")}catch(e){this.handleError(e,"disconnecting controller")}this.outletObserver.stop(),this.targetObserver.stop(),this.valueObserver.stop(),this.bindingObserver.stop()}get application(){return this.module.application}get identifier(){return this.module.identifier}get schema(){return this.application.schema}get dispatcher(){return this.application.dispatcher}get element(){return this.scope.element}get parentElement(){return this.element.parentElement}handleError(e,t,n={}){const{identifier:s,controller:r,element:i}=this;n=Object.assign({identifier:s,controller:r,element:i},n),this.application.handleError(e,`Error ${t}`,n)}targetConnected(e,t){this.invokeControllerMethod(`${t}TargetConnected`,e)}targetDisconnected(e,t){this.invokeControllerMethod(`${t}TargetDisconnected`,e)}outletConnected(e,t,n){this.invokeControllerMethod(`${C(n)}OutletConnected`,e,t)}outletDisconnected(e,t,n){this.invokeControllerMethod(`${C(n)}OutletDisconnected`,e,t)}invokeControllerMethod(e,...t){const n=this.controller;"function"==typeof n[e]&&n[e](...t)}}function J(e){return function(e,t){const n=Q(e),s=function(e,t){return Z(t).reduce(((n,s)=>{const r=function(e,t,n){const s=Object.getOwnPropertyDescriptor(e,n);if(!s||!("value"in s)){const e=Object.getOwnPropertyDescriptor(t,n).value;return s&&(e.get=s.get||e.get,e.set=s.set||e.set),e}}(e,t,s);return r&&Object.assign(n,{[s]:r}),n}),{})}(e.prototype,t);return Object.defineProperties(n.prototype,s),n}(e,function(e){const t=q(e,"blessings");return t.reduce(((t,n)=>{const s=n(e);for(const e in s){const n=t[e]||{};t[e]=Object.assign(n,s[e])}return t}),{})}(e))}const Z="function"==typeof Object.getOwnPropertySymbols?e=>[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)]:Object.getOwnPropertyNames,Q=(()=>{function e(e){function t(){return Reflect.construct(e,arguments,new.target)}return t.prototype=Object.create(e.prototype,{constructor:{value:t}}),Reflect.setPrototypeOf(t,e),t}try{return function(){const t=e((function(){this.a.call(this)}));t.prototype.a=function(){},new t}(),e}catch(e){return e=>class extends e{}}})();class X{constructor(e,t){this.application=e,this.definition=function(e){return{identifier:e.identifier,controllerConstructor:J(e.controllerConstructor)}}(t),this.contextsByScope=new WeakMap,this.connectedContexts=new Set}get identifier(){return this.definition.identifier}get controllerConstructor(){return this.definition.controllerConstructor}get contexts(){return Array.from(this.connectedContexts)}connectContextForScope(e){const t=this.fetchContextForScope(e);this.connectedContexts.add(t),t.connect()}disconnectContextForScope(e){const t=this.contextsByScope.get(e);t&&(this.connectedContexts.delete(t),t.disconnect())}fetchContextForScope(e){let t=this.contextsByScope.get(e);return t||(t=new G(this,e),this.contextsByScope.set(e,t)),t}}class Y{constructor(e){this.scope=e}has(e){return this.data.has(this.getDataKey(e))}get(e){return this.getAll(e)[0]}getAll(e){const t=this.data.get(this.getDataKey(e))||"";return t.match(/[^\s]+/g)||[]}getAttributeName(e){return this.data.getAttributeNameForKey(this.getDataKey(e))}getDataKey(e){return`${e}-class`}get data(){return this.scope.data}}class ee{constructor(e){this.scope=e}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get(e){const t=this.getAttributeNameForKey(e);return this.element.getAttribute(t)}set(e,t){const n=this.getAttributeNameForKey(e);return this.element.setAttribute(n,t),this.get(e)}has(e){const t=this.getAttributeNameForKey(e);return this.element.hasAttribute(t)}delete(e){if(this.has(e)){const t=this.getAttributeNameForKey(e);return this.element.removeAttribute(t),!0}return!1}getAttributeNameForKey(e){return`data-${this.identifier}-${t=e,t.replace(/([A-Z])/g,((e,t)=>`-${t.toLowerCase()}`))}`;var t}}class te{constructor(e){this.warnedKeysByObject=new WeakMap,this.logger=e}warn(e,t,n){let s=this.warnedKeysByObject.get(e);s||(s=new Set,this.warnedKeysByObject.set(e,s)),s.has(t)||(s.add(t),this.logger.warn(n,e))}}function ne(e,t){return`[${e}~="${t}"]`}class se{constructor(e){this.scope=e}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get schema(){return this.scope.schema}has(e){return null!=this.find(e)}find(...e){return e.reduce(((e,t)=>e||this.findTarget(t)||this.findLegacyTarget(t)),void 0)}findAll(...e){return e.reduce(((e,t)=>[...e,...this.findAllTargets(t),...this.findAllLegacyTargets(t)]),[])}findTarget(e){const t=this.getSelectorForTargetName(e);return this.scope.findElement(t)}findAllTargets(e){const t=this.getSelectorForTargetName(e);return this.scope.findAllElements(t)}getSelectorForTargetName(e){return ne(this.schema.targetAttributeForScope(this.identifier),e)}findLegacyTarget(e){const t=this.getLegacySelectorForTargetName(e);return this.deprecate(this.scope.findElement(t),e)}findAllLegacyTargets(e){const t=this.getLegacySelectorForTargetName(e);return this.scope.findAllElements(t).map((t=>this.deprecate(t,e)))}getLegacySelectorForTargetName(e){const t=`${this.identifier}.${e}`;return ne(this.schema.targetAttribute,t)}deprecate(e,t){if(e){const{identifier:n}=this,s=this.schema.targetAttribute,r=this.schema.targetAttributeForScope(n);this.guide.warn(e,`target:${t}`,`Please replace ${s}="${n}.${t}" with ${r}="${t}". The ${s} attribute is deprecated and will be removed in a future version of Stimulus.`)}return e}get guide(){return this.scope.guide}}class re{constructor(e,t){this.scope=e,this.controllerElement=t}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get schema(){return this.scope.schema}has(e){return null!=this.find(e)}find(...e){return e.reduce(((e,t)=>e||this.findOutlet(t)),void 0)}findAll(...e){return e.reduce(((e,t)=>[...e,...this.findAllOutlets(t)]),[])}getSelectorForOutletName(e){const t=this.schema.outletAttributeForScope(this.identifier,e);return this.controllerElement.getAttribute(t)}findOutlet(e){const t=this.getSelectorForOutletName(e);if(t)return this.findElement(t,e)}findAllOutlets(e){const t=this.getSelectorForOutletName(e);return t?this.findAllElements(t,e):[]}findElement(e,t){return this.scope.queryElements(e).filter((n=>this.matchesElement(n,e,t)))[0]}findAllElements(e,t){return this.scope.queryElements(e).filter((n=>this.matchesElement(n,e,t)))}matchesElement(e,t,n){const s=e.getAttribute(this.scope.schema.controllerAttribute)||"";return e.matches(t)&&s.split(" ").includes(n)}}class ie{constructor(e,t,n,s){this.targets=new se(this),this.classes=new Y(this),this.data=new ee(this),this.containsElement=e=>e.closest(this.controllerSelector)===this.element,this.schema=e,this.element=t,this.identifier=n,this.guide=new te(s),this.outlets=new re(this.documentScope,t)}findElement(e){return this.element.matches(e)?this.element:this.queryElements(e).find(this.containsElement)}findAllElements(e){return[...this.element.matches(e)?[this.element]:[],...this.queryElements(e).filter(this.containsElement)]}queryElements(e){return Array.from(this.element.querySelectorAll(e))}get controllerSelector(){return ne(this.schema.controllerAttribute,this.identifier)}get isDocumentScope(){return this.element===document.documentElement}get documentScope(){return this.isDocumentScope?this:new ie(this.schema,document.documentElement,this.identifier,this.guide.logger)}}class oe{constructor(e,t,n){this.element=e,this.schema=t,this.delegate=n,this.valueListObserver=new _(this.element,this.controllerAttribute,this),this.scopesByIdentifierByElement=new WeakMap,this.scopeReferenceCounts=new WeakMap}start(){this.valueListObserver.start()}stop(){this.valueListObserver.stop()}get controllerAttribute(){return this.schema.controllerAttribute}parseValueForToken(e){const{element:t,content:n}=e;return this.parseValueForElementAndIdentifier(t,n)}parseValueForElementAndIdentifier(e,t){const n=this.fetchScopesByIdentifierForElement(e);let s=n.get(t);return s||(s=this.delegate.createScopeForElementAndIdentifier(e,t),n.set(t,s)),s}elementMatchedValue(e,t){const n=(this.scopeReferenceCounts.get(t)||0)+1;this.scopeReferenceCounts.set(t,n),1==n&&this.delegate.scopeConnected(t)}elementUnmatchedValue(e,t){const n=this.scopeReferenceCounts.get(t);n&&(this.scopeReferenceCounts.set(t,n-1),1==n&&this.delegate.scopeDisconnected(t))}fetchScopesByIdentifierForElement(e){let t=this.scopesByIdentifierByElement.get(e);return t||(t=new Map,this.scopesByIdentifierByElement.set(e,t)),t}}class ae{constructor(e){this.application=e,this.scopeObserver=new oe(this.element,this.schema,this),this.scopesByIdentifier=new V,this.modulesByIdentifier=new Map}get element(){return this.application.element}get schema(){return this.application.schema}get logger(){return this.application.logger}get controllerAttribute(){return this.schema.controllerAttribute}get modules(){return Array.from(this.modulesByIdentifier.values())}get contexts(){return this.modules.reduce(((e,t)=>e.concat(t.contexts)),[])}start(){this.scopeObserver.start()}stop(){this.scopeObserver.stop()}loadDefinition(e){this.unloadIdentifier(e.identifier);const t=new X(this.application,e);this.connectModule(t);const n=e.controllerConstructor.afterLoad;n&&n.call(e.controllerConstructor,e.identifier,this.application)}unloadIdentifier(e){const t=this.modulesByIdentifier.get(e);t&&this.disconnectModule(t)}getContextForElementAndIdentifier(e,t){const n=this.modulesByIdentifier.get(t);if(n)return n.contexts.find((t=>t.element==e))}proposeToConnectScopeForElementAndIdentifier(e,t){const n=this.scopeObserver.parseValueForElementAndIdentifier(e,t);n?this.scopeObserver.elementMatchedValue(n.element,n):console.error(`Couldn't find or create scope for identifier: "${t}" and element:`,e)}handleError(e,t,n){this.application.handleError(e,t,n)}createScopeForElementAndIdentifier(e,t){return new ie(this.schema,e,t,this.logger)}scopeConnected(e){this.scopesByIdentifier.add(e.identifier,e);const t=this.modulesByIdentifier.get(e.identifier);t&&t.connectContextForScope(e)}scopeDisconnected(e){this.scopesByIdentifier.delete(e.identifier,e);const t=this.modulesByIdentifier.get(e.identifier);t&&t.disconnectContextForScope(e)}connectModule(e){this.modulesByIdentifier.set(e.identifier,e);this.scopesByIdentifier.getValuesForKey(e.identifier).forEach((t=>e.connectContextForScope(t)))}disconnectModule(e){this.modulesByIdentifier.delete(e.identifier);this.scopesByIdentifier.getValuesForKey(e.identifier).forEach((t=>e.disconnectContextForScope(t)))}}const ce={controllerAttribute:"data-controller",actionAttribute:"data-action",targetAttribute:"data-target",targetAttributeForScope:e=>`data-${e}-target`,outletAttributeForScope:(e,t)=>`data-${e}-${t}-outlet`,keyMappings:Object.assign(Object.assign({enter:"Enter",tab:"Tab",esc:"Escape",space:" ",up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",page_up:"PageUp",page_down:"PageDown"},le("abcdefghijklmnopqrstuvwxyz".split("").map((e=>[e,e])))),le("0123456789".split("").map((e=>[e,e]))))};function le(e){return e.reduce(((e,[t,n])=>Object.assign(Object.assign({},e),{[t]:n})),{})}class he{constructor(e=document.documentElement,t=ce){this.logger=console,this.debug=!1,this.logDebugActivity=(e,t,n={})=>{this.debug&&this.logFormattedMessage(e,t,n)},this.element=e,this.schema=t,this.dispatcher=new w(this),this.router=new ae(this),this.actionDescriptorFilters=Object.assign({},k)}static start(e,t){const n=new this(e,t);return n.start(),n}async start(){await new Promise((e=>{"loading"==document.readyState?document.addEventListener("DOMContentLoaded",(()=>e())):e()})),this.logDebugActivity("application","starting"),this.dispatcher.start(),this.router.start(),this.logDebugActivity("application","start")}stop(){this.logDebugActivity("application","stopping"),this.dispatcher.stop(),this.router.stop(),this.logDebugActivity("application","stop")}register(e,t){this.load({identifier:e,controllerConstructor:t})}registerActionOption(e,t){this.actionDescriptorFilters[e]=t}load(e,...t){(Array.isArray(e)?e:[e,...t]).forEach((e=>{e.controllerConstructor.shouldLoad&&this.router.loadDefinition(e)}))}unload(e,...t){(Array.isArray(e)?e:[e,...t]).forEach((e=>this.router.unloadIdentifier(e)))}get controllers(){return this.router.contexts.map((e=>e.controller))}getControllerForElementAndIdentifier(e,t){const n=this.router.getContextForElementAndIdentifier(e,t);return n?n.controller:null}handleError(e,t,n){var s;this.logger.error("%s\n\n%o\n\n%o",t,e,n),null===(s=window.onerror)||void 0===s||s.call(window,t,"",0,0,e)}logFormattedMessage(e,t,n={}){n=Object.assign({application:this},n),this.logger.groupCollapsed(`${e} #${t}`),this.logger.log("details:",Object.assign({},n)),this.logger.groupEnd()}}class ue{static async reload(e){const t=await y();return new ue(t,e).reload()}constructor(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:/./;this.document=e,this.filePattern=t,this.application=window.Stimulus||he.start()}async reload(){O("Reload Stimulus controllers..."),this.application.stop(),await this.#e(),this.application.start()}async#e(){await Promise.all(this.#t.map((async e=>this.#n(e))))}get#t(){return Object.keys(this.#s).filter((e=>e.endsWith("_controller")&&this.#r(e)))}#r(e){return this.filePattern.test(e)}get#s(){return this.pathsByModule=this.pathsByModule||this.#i(),this.pathsByModule}#i(){const e=this.document.querySelector("script[type=importmap]");return JSON.parse(e.text).imports}async#n(e){O(`\t${e}`);const t=this.#o(e),n=v(this.#a(e)),s=await import(n);this.#c(t,s)}#a(e){return this.#s[e]}#o(e){return e.replace(/^.*\//,"").replace("_controller","").replace(/\//g,"--").replace(/_/g,"-")}#c(e,t){this.application.unload(e),this.application.register(e,t.default)}}class de{static async reload(){return(new de).reload()}async reload(){const e=await this.#l();await this.#h(e)}async#l(){O("Reload html...");const e=await y();return this.#u(e.body),e}#u(e){A.morph(document.body,e)}async#h(e){return new ue(e).reload()}}class me{static async reload(){for(var e=arguments.length,t=new Array(e),n=0;n0&&void 0!==arguments[0]?arguments[0]:/./;this.filePattern=e}async reload(){O("Reload css..."),await Promise.all(await this.#d())}async#d(){return(await this.#m()).map((e=>this.#p(e)))}async#m(){const e=await y();return Array.from(e.head.querySelectorAll("link[rel='stylesheet']"))}#p(e){return this.#g(e)?this.#f(e):Promise.resolve()}#g(e){return this.filePattern.test(e.getAttribute("href"))}async#f(e){return new Promise((t=>{const n=e.getAttribute("href"),s=this.#b(e)||this.#v(e);s.setAttribute("href",v(e.getAttribute("href"))),s.onload=()=>{O(`\t${n}`),t()}}))}#b(e){return this.#y.find((t=>f(e.href)===f(t.href)))}get#y(){return Array.from(document.querySelectorAll("link[rel='stylesheet']"))}#v(e){return document.head.append(e),e}}g.subscriptions.create({channel:"Hotwire::Spark::Channel"},{connected(){document.body.setAttribute("data-hotwire-spark-ready","")},async received(e){try{await this.dispatch(e)}catch(t){console.log(`Error on ${e.action}`,t)}},dispatch(e){let{action:t,path:n}=e;const s=function(e){return e.split("/").pop().split(".")[0]}(n);switch(t){case"reload_html":return this.reloadHtml();case"reload_css":return this.reloadCss(s);case"reload_stimulus":return this.reloadStimulus(s);default:throw new Error(`Unknown action: ${t}`)}},reloadHtml:()=>de.reload(),reloadCss:e=>me.reload(new RegExp(e)),reloadStimulus:e=>ue.reload(new RegExp(e))});const pe={config:{loggingEnabled:!1}};return document.addEventListener("DOMContentLoaded",(function(){var e;pe.config.loggingEnabled=(e="logging",document.querySelector(`meta[name="hotwire-spark:${e}"]`)?.content)})),pe}(); +//# sourceMappingURL=hotwire_spark.min.js.map diff --git a/app/assets/javascripts/hotwire_spark.min.js.map b/app/assets/javascripts/hotwire_spark.min.js.map new file mode 100644 index 00000000..3ae97723 --- /dev/null +++ b/app/assets/javascripts/hotwire_spark.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hotwire_spark.min.js","sources":["../../../node_modules/@rails/actioncable/app/assets/javascripts/actioncable.esm.js","../../javascript/hotwire/spark/channels/consumer.js","../../javascript/hotwire/spark/helpers.js","../../../node_modules/idiomorph/dist/idiomorph.esm.js","../../javascript/hotwire/spark/logger.js","../../../node_modules/@hotwired/stimulus/dist/stimulus.js","../../javascript/hotwire/spark/reloaders/stimulus_reloader.js","../../javascript/hotwire/spark/reloaders/html_reloader.js","../../javascript/hotwire/spark/reloaders/css_reloader.js","../../javascript/hotwire/spark/channels/monitoring_channel.js","../../javascript/hotwire/spark/index.js"],"sourcesContent":["var adapters = {\n logger: typeof console !== \"undefined\" ? console : undefined,\n WebSocket: typeof WebSocket !== \"undefined\" ? WebSocket : undefined\n};\n\nvar logger = {\n log(...messages) {\n if (this.enabled) {\n messages.push(Date.now());\n adapters.logger.log(\"[ActionCable]\", ...messages);\n }\n }\n};\n\nconst now = () => (new Date).getTime();\n\nconst secondsSince = time => (now() - time) / 1e3;\n\nclass ConnectionMonitor {\n constructor(connection) {\n this.visibilityDidChange = this.visibilityDidChange.bind(this);\n this.connection = connection;\n this.reconnectAttempts = 0;\n }\n start() {\n if (!this.isRunning()) {\n this.startedAt = now();\n delete this.stoppedAt;\n this.startPolling();\n addEventListener(\"visibilitychange\", this.visibilityDidChange);\n logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`);\n }\n }\n stop() {\n if (this.isRunning()) {\n this.stoppedAt = now();\n this.stopPolling();\n removeEventListener(\"visibilitychange\", this.visibilityDidChange);\n logger.log(\"ConnectionMonitor stopped\");\n }\n }\n isRunning() {\n return this.startedAt && !this.stoppedAt;\n }\n recordMessage() {\n this.pingedAt = now();\n }\n recordConnect() {\n this.reconnectAttempts = 0;\n delete this.disconnectedAt;\n logger.log(\"ConnectionMonitor recorded connect\");\n }\n recordDisconnect() {\n this.disconnectedAt = now();\n logger.log(\"ConnectionMonitor recorded disconnect\");\n }\n startPolling() {\n this.stopPolling();\n this.poll();\n }\n stopPolling() {\n clearTimeout(this.pollTimeout);\n }\n poll() {\n this.pollTimeout = setTimeout((() => {\n this.reconnectIfStale();\n this.poll();\n }), this.getPollInterval());\n }\n getPollInterval() {\n const {staleThreshold: staleThreshold, reconnectionBackoffRate: reconnectionBackoffRate} = this.constructor;\n const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10));\n const jitterMax = this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate;\n const jitter = jitterMax * Math.random();\n return staleThreshold * 1e3 * backoff * (1 + jitter);\n }\n reconnectIfStale() {\n if (this.connectionIsStale()) {\n logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`);\n this.reconnectAttempts++;\n if (this.disconnectedRecently()) {\n logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`);\n } else {\n logger.log(\"ConnectionMonitor reopening\");\n this.connection.reopen();\n }\n }\n }\n get refreshedAt() {\n return this.pingedAt ? this.pingedAt : this.startedAt;\n }\n connectionIsStale() {\n return secondsSince(this.refreshedAt) > this.constructor.staleThreshold;\n }\n disconnectedRecently() {\n return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;\n }\n visibilityDidChange() {\n if (document.visibilityState === \"visible\") {\n setTimeout((() => {\n if (this.connectionIsStale() || !this.connection.isOpen()) {\n logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`);\n this.connection.reopen();\n }\n }), 200);\n }\n }\n}\n\nConnectionMonitor.staleThreshold = 6;\n\nConnectionMonitor.reconnectionBackoffRate = .15;\n\nvar INTERNAL = {\n message_types: {\n welcome: \"welcome\",\n disconnect: \"disconnect\",\n ping: \"ping\",\n confirmation: \"confirm_subscription\",\n rejection: \"reject_subscription\"\n },\n disconnect_reasons: {\n unauthorized: \"unauthorized\",\n invalid_request: \"invalid_request\",\n server_restart: \"server_restart\",\n remote: \"remote\"\n },\n default_mount_path: \"/cable\",\n protocols: [ \"actioncable-v1-json\", \"actioncable-unsupported\" ]\n};\n\nconst {message_types: message_types, protocols: protocols} = INTERNAL;\n\nconst supportedProtocols = protocols.slice(0, protocols.length - 1);\n\nconst indexOf = [].indexOf;\n\nclass Connection {\n constructor(consumer) {\n this.open = this.open.bind(this);\n this.consumer = consumer;\n this.subscriptions = this.consumer.subscriptions;\n this.monitor = new ConnectionMonitor(this);\n this.disconnected = true;\n }\n send(data) {\n if (this.isOpen()) {\n this.webSocket.send(JSON.stringify(data));\n return true;\n } else {\n return false;\n }\n }\n open() {\n if (this.isActive()) {\n logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);\n return false;\n } else {\n const socketProtocols = [ ...protocols, ...this.consumer.subprotocols || [] ];\n logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`);\n if (this.webSocket) {\n this.uninstallEventHandlers();\n }\n this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols);\n this.installEventHandlers();\n this.monitor.start();\n return true;\n }\n }\n close({allowReconnect: allowReconnect} = {\n allowReconnect: true\n }) {\n if (!allowReconnect) {\n this.monitor.stop();\n }\n if (this.isOpen()) {\n return this.webSocket.close();\n }\n }\n reopen() {\n logger.log(`Reopening WebSocket, current state is ${this.getState()}`);\n if (this.isActive()) {\n try {\n return this.close();\n } catch (error) {\n logger.log(\"Failed to reopen WebSocket\", error);\n } finally {\n logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`);\n setTimeout(this.open, this.constructor.reopenDelay);\n }\n } else {\n return this.open();\n }\n }\n getProtocol() {\n if (this.webSocket) {\n return this.webSocket.protocol;\n }\n }\n isOpen() {\n return this.isState(\"open\");\n }\n isActive() {\n return this.isState(\"open\", \"connecting\");\n }\n triedToReconnect() {\n return this.monitor.reconnectAttempts > 0;\n }\n isProtocolSupported() {\n return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;\n }\n isState(...states) {\n return indexOf.call(states, this.getState()) >= 0;\n }\n getState() {\n if (this.webSocket) {\n for (let state in adapters.WebSocket) {\n if (adapters.WebSocket[state] === this.webSocket.readyState) {\n return state.toLowerCase();\n }\n }\n }\n return null;\n }\n installEventHandlers() {\n for (let eventName in this.events) {\n const handler = this.events[eventName].bind(this);\n this.webSocket[`on${eventName}`] = handler;\n }\n }\n uninstallEventHandlers() {\n for (let eventName in this.events) {\n this.webSocket[`on${eventName}`] = function() {};\n }\n }\n}\n\nConnection.reopenDelay = 500;\n\nConnection.prototype.events = {\n message(event) {\n if (!this.isProtocolSupported()) {\n return;\n }\n const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);\n this.monitor.recordMessage();\n switch (type) {\n case message_types.welcome:\n if (this.triedToReconnect()) {\n this.reconnectAttempted = true;\n }\n this.monitor.recordConnect();\n return this.subscriptions.reload();\n\n case message_types.disconnect:\n logger.log(`Disconnecting. Reason: ${reason}`);\n return this.close({\n allowReconnect: reconnect\n });\n\n case message_types.ping:\n return null;\n\n case message_types.confirmation:\n this.subscriptions.confirmSubscription(identifier);\n if (this.reconnectAttempted) {\n this.reconnectAttempted = false;\n return this.subscriptions.notify(identifier, \"connected\", {\n reconnected: true\n });\n } else {\n return this.subscriptions.notify(identifier, \"connected\", {\n reconnected: false\n });\n }\n\n case message_types.rejection:\n return this.subscriptions.reject(identifier);\n\n default:\n return this.subscriptions.notify(identifier, \"received\", message);\n }\n },\n open() {\n logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`);\n this.disconnected = false;\n if (!this.isProtocolSupported()) {\n logger.log(\"Protocol is unsupported. Stopping monitor and disconnecting.\");\n return this.close({\n allowReconnect: false\n });\n }\n },\n close(event) {\n logger.log(\"WebSocket onclose event\");\n if (this.disconnected) {\n return;\n }\n this.disconnected = true;\n this.monitor.recordDisconnect();\n return this.subscriptions.notifyAll(\"disconnected\", {\n willAttemptReconnect: this.monitor.isRunning()\n });\n },\n error() {\n logger.log(\"WebSocket onerror event\");\n }\n};\n\nconst extend = function(object, properties) {\n if (properties != null) {\n for (let key in properties) {\n const value = properties[key];\n object[key] = value;\n }\n }\n return object;\n};\n\nclass Subscription {\n constructor(consumer, params = {}, mixin) {\n this.consumer = consumer;\n this.identifier = JSON.stringify(params);\n extend(this, mixin);\n }\n perform(action, data = {}) {\n data.action = action;\n return this.send(data);\n }\n send(data) {\n return this.consumer.send({\n command: \"message\",\n identifier: this.identifier,\n data: JSON.stringify(data)\n });\n }\n unsubscribe() {\n return this.consumer.subscriptions.remove(this);\n }\n}\n\nclass SubscriptionGuarantor {\n constructor(subscriptions) {\n this.subscriptions = subscriptions;\n this.pendingSubscriptions = [];\n }\n guarantee(subscription) {\n if (this.pendingSubscriptions.indexOf(subscription) == -1) {\n logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`);\n this.pendingSubscriptions.push(subscription);\n } else {\n logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`);\n }\n this.startGuaranteeing();\n }\n forget(subscription) {\n logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`);\n this.pendingSubscriptions = this.pendingSubscriptions.filter((s => s !== subscription));\n }\n startGuaranteeing() {\n this.stopGuaranteeing();\n this.retrySubscribing();\n }\n stopGuaranteeing() {\n clearTimeout(this.retryTimeout);\n }\n retrySubscribing() {\n this.retryTimeout = setTimeout((() => {\n if (this.subscriptions && typeof this.subscriptions.subscribe === \"function\") {\n this.pendingSubscriptions.map((subscription => {\n logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`);\n this.subscriptions.subscribe(subscription);\n }));\n }\n }), 500);\n }\n}\n\nclass Subscriptions {\n constructor(consumer) {\n this.consumer = consumer;\n this.guarantor = new SubscriptionGuarantor(this);\n this.subscriptions = [];\n }\n create(channelName, mixin) {\n const channel = channelName;\n const params = typeof channel === \"object\" ? channel : {\n channel: channel\n };\n const subscription = new Subscription(this.consumer, params, mixin);\n return this.add(subscription);\n }\n add(subscription) {\n this.subscriptions.push(subscription);\n this.consumer.ensureActiveConnection();\n this.notify(subscription, \"initialized\");\n this.subscribe(subscription);\n return subscription;\n }\n remove(subscription) {\n this.forget(subscription);\n if (!this.findAll(subscription.identifier).length) {\n this.sendCommand(subscription, \"unsubscribe\");\n }\n return subscription;\n }\n reject(identifier) {\n return this.findAll(identifier).map((subscription => {\n this.forget(subscription);\n this.notify(subscription, \"rejected\");\n return subscription;\n }));\n }\n forget(subscription) {\n this.guarantor.forget(subscription);\n this.subscriptions = this.subscriptions.filter((s => s !== subscription));\n return subscription;\n }\n findAll(identifier) {\n return this.subscriptions.filter((s => s.identifier === identifier));\n }\n reload() {\n return this.subscriptions.map((subscription => this.subscribe(subscription)));\n }\n notifyAll(callbackName, ...args) {\n return this.subscriptions.map((subscription => this.notify(subscription, callbackName, ...args)));\n }\n notify(subscription, callbackName, ...args) {\n let subscriptions;\n if (typeof subscription === \"string\") {\n subscriptions = this.findAll(subscription);\n } else {\n subscriptions = [ subscription ];\n }\n return subscriptions.map((subscription => typeof subscription[callbackName] === \"function\" ? subscription[callbackName](...args) : undefined));\n }\n subscribe(subscription) {\n if (this.sendCommand(subscription, \"subscribe\")) {\n this.guarantor.guarantee(subscription);\n }\n }\n confirmSubscription(identifier) {\n logger.log(`Subscription confirmed ${identifier}`);\n this.findAll(identifier).map((subscription => this.guarantor.forget(subscription)));\n }\n sendCommand(subscription, command) {\n const {identifier: identifier} = subscription;\n return this.consumer.send({\n command: command,\n identifier: identifier\n });\n }\n}\n\nclass Consumer {\n constructor(url) {\n this._url = url;\n this.subscriptions = new Subscriptions(this);\n this.connection = new Connection(this);\n this.subprotocols = [];\n }\n get url() {\n return createWebSocketURL(this._url);\n }\n send(data) {\n return this.connection.send(data);\n }\n connect() {\n return this.connection.open();\n }\n disconnect() {\n return this.connection.close({\n allowReconnect: false\n });\n }\n ensureActiveConnection() {\n if (!this.connection.isActive()) {\n return this.connection.open();\n }\n }\n addSubProtocol(subprotocol) {\n this.subprotocols = [ ...this.subprotocols, subprotocol ];\n }\n}\n\nfunction createWebSocketURL(url) {\n if (typeof url === \"function\") {\n url = url();\n }\n if (url && !/^wss?:/i.test(url)) {\n const a = document.createElement(\"a\");\n a.href = url;\n a.href = a.href;\n a.protocol = a.protocol.replace(\"http\", \"ws\");\n return a.href;\n } else {\n return url;\n }\n}\n\nfunction createConsumer(url = getConfig(\"url\") || INTERNAL.default_mount_path) {\n return new Consumer(url);\n}\n\nfunction getConfig(name) {\n const element = document.head.querySelector(`meta[name='action-cable-${name}']`);\n if (element) {\n return element.getAttribute(\"content\");\n }\n}\n\nexport { Connection, ConnectionMonitor, Consumer, INTERNAL, Subscription, SubscriptionGuarantor, Subscriptions, adapters, createConsumer, createWebSocketURL, getConfig, logger };\n","import { createConsumer } from \"@rails/actioncable\"\n\nexport default createConsumer()\n","export function assetNameFromPath(path) {\n return path.split(\"/\").pop().split(\".\")[0]\n}\n\nexport function pathWithoutAssetDigest(path) {\n return path.replace(/-[a-z0-9]+\\.(\\w+)(\\?.*)?$/, \".$1\")\n}\n\nexport function urlWithParams(urlString, params) {\n const url = new URL(urlString, window.location.origin)\n Object.entries(params).forEach(([ key, value ]) => {\n url.searchParams.set(key, value)\n })\n return url.toString()\n}\n\nexport function cacheBustedUrl(urlString) {\n return urlWithParams(urlString, { reload: Date.now() })\n}\n\nexport async function reloadHtmlDocument() {\n let currentUrl = cacheBustedUrl(urlWithParams(window.location.href, { hotwire_spark: \"true\" }))\n const response = await fetch(currentUrl)\n\n if (!response.ok) {\n throw new Error(`${response.status} when fetching ${currentUrl}`)\n }\n\n const fetchedHTML = await response.text()\n const parser = new DOMParser()\n return parser.parseFromString(fetchedHTML, \"text/html\")\n}\n\nexport function getConfigurationProperty(name) {\n return document.querySelector(`meta[name=\"hotwire-spark:${name}\"]`)?.content\n}\n\n","// base IIFE to define idiomorph\nvar Idiomorph = (function () {\n 'use strict';\n\n //=============================================================================\n // AND NOW IT BEGINS...\n //=============================================================================\n let EMPTY_SET = new Set();\n\n // default configuration values, updatable by users now\n let defaults = {\n morphStyle: \"outerHTML\",\n callbacks : {\n beforeNodeAdded: noOp,\n afterNodeAdded: noOp,\n beforeNodeMorphed: noOp,\n afterNodeMorphed: noOp,\n beforeNodeRemoved: noOp,\n afterNodeRemoved: noOp,\n beforeAttributeUpdated: noOp,\n\n },\n head: {\n style: 'merge',\n shouldPreserve: function (elt) {\n return elt.getAttribute(\"im-preserve\") === \"true\";\n },\n shouldReAppend: function (elt) {\n return elt.getAttribute(\"im-re-append\") === \"true\";\n },\n shouldRemove: noOp,\n afterHeadMorphed: noOp,\n }\n };\n\n //=============================================================================\n // Core Morphing Algorithm - morph, morphNormalizedContent, morphOldNodeTo, morphChildren\n //=============================================================================\n function morph(oldNode, newContent, config = {}) {\n\n if (oldNode instanceof Document) {\n oldNode = oldNode.documentElement;\n }\n\n if (typeof newContent === 'string') {\n newContent = parseContent(newContent);\n }\n\n let normalizedContent = normalizeContent(newContent);\n\n let ctx = createMorphContext(oldNode, normalizedContent, config);\n\n return morphNormalizedContent(oldNode, normalizedContent, ctx);\n }\n\n function morphNormalizedContent(oldNode, normalizedNewContent, ctx) {\n if (ctx.head.block) {\n let oldHead = oldNode.querySelector('head');\n let newHead = normalizedNewContent.querySelector('head');\n if (oldHead && newHead) {\n let promises = handleHeadElement(newHead, oldHead, ctx);\n // when head promises resolve, call morph again, ignoring the head tag\n Promise.all(promises).then(function () {\n morphNormalizedContent(oldNode, normalizedNewContent, Object.assign(ctx, {\n head: {\n block: false,\n ignore: true\n }\n }));\n });\n return;\n }\n }\n\n if (ctx.morphStyle === \"innerHTML\") {\n\n // innerHTML, so we are only updating the children\n morphChildren(normalizedNewContent, oldNode, ctx);\n return oldNode.children;\n\n } else if (ctx.morphStyle === \"outerHTML\" || ctx.morphStyle == null) {\n // otherwise find the best element match in the new content, morph that, and merge its siblings\n // into either side of the best match\n let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx);\n\n // stash the siblings that will need to be inserted on either side of the best match\n let previousSibling = bestMatch?.previousSibling;\n let nextSibling = bestMatch?.nextSibling;\n\n // morph it\n let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx);\n\n if (bestMatch) {\n // if there was a best match, merge the siblings in too and return the\n // whole bunch\n return insertSiblings(previousSibling, morphedNode, nextSibling);\n } else {\n // otherwise nothing was added to the DOM\n return []\n }\n } else {\n throw \"Do not understand how to morph style \" + ctx.morphStyle;\n }\n }\n\n\n /**\n * @param possibleActiveElement\n * @param ctx\n * @returns {boolean}\n */\n function ignoreValueOfActiveElement(possibleActiveElement, ctx) {\n return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement;\n }\n\n /**\n * @param oldNode root node to merge content into\n * @param newContent new content to merge\n * @param ctx the merge context\n * @returns {Element} the element that ended up in the DOM\n */\n function morphOldNodeTo(oldNode, newContent, ctx) {\n if (ctx.ignoreActive && oldNode === document.activeElement) {\n // don't morph focused element\n } else if (newContent == null) {\n if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;\n\n oldNode.remove();\n ctx.callbacks.afterNodeRemoved(oldNode);\n return null;\n } else if (!isSoftMatch(oldNode, newContent)) {\n if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;\n if (ctx.callbacks.beforeNodeAdded(newContent) === false) return oldNode;\n\n oldNode.parentElement.replaceChild(newContent, oldNode);\n ctx.callbacks.afterNodeAdded(newContent);\n ctx.callbacks.afterNodeRemoved(oldNode);\n return newContent;\n } else {\n if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) return oldNode;\n\n if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) {\n // ignore the head element\n } else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== \"morph\") {\n handleHeadElement(newContent, oldNode, ctx);\n } else {\n syncNodeFrom(newContent, oldNode, ctx);\n if (!ignoreValueOfActiveElement(oldNode, ctx)) {\n morphChildren(newContent, oldNode, ctx);\n }\n }\n ctx.callbacks.afterNodeMorphed(oldNode, newContent);\n return oldNode;\n }\n }\n\n /**\n * This is the core algorithm for matching up children. The idea is to use id sets to try to match up\n * nodes as faithfully as possible. We greedily match, which allows us to keep the algorithm fast, but\n * by using id sets, we are able to better match up with content deeper in the DOM.\n *\n * Basic algorithm is, for each node in the new content:\n *\n * - if we have reached the end of the old parent, append the new content\n * - if the new content has an id set match with the current insertion point, morph\n * - search for an id set match\n * - if id set match found, morph\n * - otherwise search for a \"soft\" match\n * - if a soft match is found, morph\n * - otherwise, prepend the new node before the current insertion point\n *\n * The two search algorithms terminate if competing node matches appear to outweigh what can be achieved\n * with the current node. See findIdSetMatch() and findSoftMatch() for details.\n *\n * @param {Element} newParent the parent element of the new content\n * @param {Element } oldParent the old content that we are merging the new content into\n * @param ctx the merge context\n */\n function morphChildren(newParent, oldParent, ctx) {\n\n let nextNewChild = newParent.firstChild;\n let insertionPoint = oldParent.firstChild;\n let newChild;\n\n // run through all the new content\n while (nextNewChild) {\n\n newChild = nextNewChild;\n nextNewChild = newChild.nextSibling;\n\n // if we are at the end of the exiting parent's children, just append\n if (insertionPoint == null) {\n if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;\n\n oldParent.appendChild(newChild);\n ctx.callbacks.afterNodeAdded(newChild);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // if the current node has an id set match then morph\n if (isIdSetMatch(newChild, insertionPoint, ctx)) {\n morphOldNodeTo(insertionPoint, newChild, ctx);\n insertionPoint = insertionPoint.nextSibling;\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // otherwise search forward in the existing old children for an id set match\n let idSetMatch = findIdSetMatch(newParent, oldParent, newChild, insertionPoint, ctx);\n\n // if we found a potential match, remove the nodes until that point and morph\n if (idSetMatch) {\n insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx);\n morphOldNodeTo(idSetMatch, newChild, ctx);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // no id set match found, so scan forward for a soft match for the current node\n let softMatch = findSoftMatch(newParent, oldParent, newChild, insertionPoint, ctx);\n\n // if we found a soft match for the current node, morph\n if (softMatch) {\n insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx);\n morphOldNodeTo(softMatch, newChild, ctx);\n removeIdsFromConsideration(ctx, newChild);\n continue;\n }\n\n // abandon all hope of morphing, just insert the new child before the insertion point\n // and move on\n if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;\n\n oldParent.insertBefore(newChild, insertionPoint);\n ctx.callbacks.afterNodeAdded(newChild);\n removeIdsFromConsideration(ctx, newChild);\n }\n\n // remove any remaining old nodes that didn't match up with new content\n while (insertionPoint !== null) {\n\n let tempNode = insertionPoint;\n insertionPoint = insertionPoint.nextSibling;\n removeNode(tempNode, ctx);\n }\n }\n\n //=============================================================================\n // Attribute Syncing Code\n //=============================================================================\n\n /**\n * @param attr {String} the attribute to be mutated\n * @param to {Element} the element that is going to be updated\n * @param updateType {(\"update\"|\"remove\")}\n * @param ctx the merge context\n * @returns {boolean} true if the attribute should be ignored, false otherwise\n */\n function ignoreAttribute(attr, to, updateType, ctx) {\n if(attr === 'value' && ctx.ignoreActiveValue && to === document.activeElement){\n return true;\n }\n return ctx.callbacks.beforeAttributeUpdated(attr, to, updateType) === false;\n }\n\n /**\n * syncs a given node with another node, copying over all attributes and\n * inner element state from the 'from' node to the 'to' node\n *\n * @param {Element} from the element to copy attributes & state from\n * @param {Element} to the element to copy attributes & state to\n * @param ctx the merge context\n */\n function syncNodeFrom(from, to, ctx) {\n let type = from.nodeType\n\n // if is an element type, sync the attributes from the\n // new node into the new node\n if (type === 1 /* element type */) {\n const fromAttributes = from.attributes;\n const toAttributes = to.attributes;\n for (const fromAttribute of fromAttributes) {\n if (ignoreAttribute(fromAttribute.name, to, 'update', ctx)) {\n continue;\n }\n if (to.getAttribute(fromAttribute.name) !== fromAttribute.value) {\n to.setAttribute(fromAttribute.name, fromAttribute.value);\n }\n }\n // iterate backwards to avoid skipping over items when a delete occurs\n for (let i = toAttributes.length - 1; 0 <= i; i--) {\n const toAttribute = toAttributes[i];\n if (ignoreAttribute(toAttribute.name, to, 'remove', ctx)) {\n continue;\n }\n if (!from.hasAttribute(toAttribute.name)) {\n to.removeAttribute(toAttribute.name);\n }\n }\n }\n\n // sync text nodes\n if (type === 8 /* comment */ || type === 3 /* text */) {\n if (to.nodeValue !== from.nodeValue) {\n to.nodeValue = from.nodeValue;\n }\n }\n\n if (!ignoreValueOfActiveElement(to, ctx)) {\n // sync input values\n syncInputValue(from, to, ctx);\n }\n }\n\n /**\n * @param from {Element} element to sync the value from\n * @param to {Element} element to sync the value to\n * @param attributeName {String} the attribute name\n * @param ctx the merge context\n */\n function syncBooleanAttribute(from, to, attributeName, ctx) {\n if (from[attributeName] !== to[attributeName]) {\n let ignoreUpdate = ignoreAttribute(attributeName, to, 'update', ctx);\n if (!ignoreUpdate) {\n to[attributeName] = from[attributeName];\n }\n if (from[attributeName]) {\n if (!ignoreUpdate) {\n to.setAttribute(attributeName, from[attributeName]);\n }\n } else {\n if (!ignoreAttribute(attributeName, to, 'remove', ctx)) {\n to.removeAttribute(attributeName);\n }\n }\n }\n }\n\n /**\n * NB: many bothans died to bring us information:\n *\n * https://github.com/patrick-steele-idem/morphdom/blob/master/src/specialElHandlers.js\n * https://github.com/choojs/nanomorph/blob/master/lib/morph.jsL113\n *\n * @param from {Element} the element to sync the input value from\n * @param to {Element} the element to sync the input value to\n * @param ctx the merge context\n */\n function syncInputValue(from, to, ctx) {\n if (from instanceof HTMLInputElement &&\n to instanceof HTMLInputElement &&\n from.type !== 'file') {\n\n let fromValue = from.value;\n let toValue = to.value;\n\n // sync boolean attributes\n syncBooleanAttribute(from, to, 'checked', ctx);\n syncBooleanAttribute(from, to, 'disabled', ctx);\n\n if (!from.hasAttribute('value')) {\n if (!ignoreAttribute('value', to, 'remove', ctx)) {\n to.value = '';\n to.removeAttribute('value');\n }\n } else if (fromValue !== toValue) {\n if (!ignoreAttribute('value', to, 'update', ctx)) {\n to.setAttribute('value', fromValue);\n to.value = fromValue;\n }\n }\n } else if (from instanceof HTMLOptionElement) {\n syncBooleanAttribute(from, to, 'selected', ctx)\n } else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) {\n let fromValue = from.value;\n let toValue = to.value;\n if (ignoreAttribute('value', to, 'update', ctx)) {\n return;\n }\n if (fromValue !== toValue) {\n to.value = fromValue;\n }\n if (to.firstChild && to.firstChild.nodeValue !== fromValue) {\n to.firstChild.nodeValue = fromValue\n }\n }\n }\n\n //=============================================================================\n // the HEAD tag can be handled specially, either w/ a 'merge' or 'append' style\n //=============================================================================\n function handleHeadElement(newHeadTag, currentHead, ctx) {\n\n let added = []\n let removed = []\n let preserved = []\n let nodesToAppend = []\n\n let headMergeStyle = ctx.head.style;\n\n // put all new head elements into a Map, by their outerHTML\n let srcToNewHeadNodes = new Map();\n for (const newHeadChild of newHeadTag.children) {\n srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);\n }\n\n // for each elt in the current head\n for (const currentHeadElt of currentHead.children) {\n\n // If the current head element is in the map\n let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);\n let isReAppended = ctx.head.shouldReAppend(currentHeadElt);\n let isPreserved = ctx.head.shouldPreserve(currentHeadElt);\n if (inNewContent || isPreserved) {\n if (isReAppended) {\n // remove the current version and let the new version replace it and re-execute\n removed.push(currentHeadElt);\n } else {\n // this element already exists and should not be re-appended, so remove it from\n // the new content map, preserving it in the DOM\n srcToNewHeadNodes.delete(currentHeadElt.outerHTML);\n preserved.push(currentHeadElt);\n }\n } else {\n if (headMergeStyle === \"append\") {\n // we are appending and this existing element is not new content\n // so if and only if it is marked for re-append do we do anything\n if (isReAppended) {\n removed.push(currentHeadElt);\n nodesToAppend.push(currentHeadElt);\n }\n } else {\n // if this is a merge, we remove this content since it is not in the new head\n if (ctx.head.shouldRemove(currentHeadElt) !== false) {\n removed.push(currentHeadElt);\n }\n }\n }\n }\n\n // Push the remaining new head elements in the Map into the\n // nodes to append to the head tag\n nodesToAppend.push(...srcToNewHeadNodes.values());\n log(\"to append: \", nodesToAppend);\n\n let promises = [];\n for (const newNode of nodesToAppend) {\n log(\"adding: \", newNode);\n let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild;\n log(newElt);\n if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {\n if (newElt.href || newElt.src) {\n let resolve = null;\n let promise = new Promise(function (_resolve) {\n resolve = _resolve;\n });\n newElt.addEventListener('load', function () {\n resolve();\n });\n promises.push(promise);\n }\n currentHead.appendChild(newElt);\n ctx.callbacks.afterNodeAdded(newElt);\n added.push(newElt);\n }\n }\n\n // remove all removed elements, after we have appended the new elements to avoid\n // additional network requests for things like style sheets\n for (const removedElement of removed) {\n if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {\n currentHead.removeChild(removedElement);\n ctx.callbacks.afterNodeRemoved(removedElement);\n }\n }\n\n ctx.head.afterHeadMorphed(currentHead, {added: added, kept: preserved, removed: removed});\n return promises;\n }\n\n //=============================================================================\n // Misc\n //=============================================================================\n\n function log() {\n //console.log(arguments);\n }\n\n function noOp() {\n }\n\n /*\n Deep merges the config object and the Idiomoroph.defaults object to\n produce a final configuration object\n */\n function mergeDefaults(config) {\n let finalConfig = {};\n // copy top level stuff into final config\n Object.assign(finalConfig, defaults);\n Object.assign(finalConfig, config);\n\n // copy callbacks into final config (do this to deep merge the callbacks)\n finalConfig.callbacks = {};\n Object.assign(finalConfig.callbacks, defaults.callbacks);\n Object.assign(finalConfig.callbacks, config.callbacks);\n\n // copy head config into final config (do this to deep merge the head)\n finalConfig.head = {};\n Object.assign(finalConfig.head, defaults.head);\n Object.assign(finalConfig.head, config.head);\n return finalConfig;\n }\n\n function createMorphContext(oldNode, newContent, config) {\n config = mergeDefaults(config);\n return {\n target: oldNode,\n newContent: newContent,\n config: config,\n morphStyle: config.morphStyle,\n ignoreActive: config.ignoreActive,\n ignoreActiveValue: config.ignoreActiveValue,\n idMap: createIdMap(oldNode, newContent),\n deadIds: new Set(),\n callbacks: config.callbacks,\n head: config.head\n }\n }\n\n function isIdSetMatch(node1, node2, ctx) {\n if (node1 == null || node2 == null) {\n return false;\n }\n if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) {\n if (node1.id !== \"\" && node1.id === node2.id) {\n return true;\n } else {\n return getIdIntersectionCount(ctx, node1, node2) > 0;\n }\n }\n return false;\n }\n\n function isSoftMatch(node1, node2) {\n if (node1 == null || node2 == null) {\n return false;\n }\n return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName\n }\n\n function removeNodesBetween(startInclusive, endExclusive, ctx) {\n while (startInclusive !== endExclusive) {\n let tempNode = startInclusive;\n startInclusive = startInclusive.nextSibling;\n removeNode(tempNode, ctx);\n }\n removeIdsFromConsideration(ctx, endExclusive);\n return endExclusive.nextSibling;\n }\n\n //=============================================================================\n // Scans forward from the insertionPoint in the old parent looking for a potential id match\n // for the newChild. We stop if we find a potential id match for the new child OR\n // if the number of potential id matches we are discarding is greater than the\n // potential id matches for the new child\n //=============================================================================\n function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {\n\n // max id matches we are willing to discard in our search\n let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent);\n\n let potentialMatch = null;\n\n // only search forward if there is a possibility of an id match\n if (newChildPotentialIdCount > 0) {\n let potentialMatch = insertionPoint;\n // if there is a possibility of an id match, scan forward\n // keep track of the potential id match count we are discarding (the\n // newChildPotentialIdCount must be greater than this to make it likely\n // worth it)\n let otherMatchCount = 0;\n while (potentialMatch != null) {\n\n // If we have an id match, return the current potential match\n if (isIdSetMatch(newChild, potentialMatch, ctx)) {\n return potentialMatch;\n }\n\n // computer the other potential matches of this new content\n otherMatchCount += getIdIntersectionCount(ctx, potentialMatch, newContent);\n if (otherMatchCount > newChildPotentialIdCount) {\n // if we have more potential id matches in _other_ content, we\n // do not have a good candidate for an id match, so return null\n return null;\n }\n\n // advanced to the next old content child\n potentialMatch = potentialMatch.nextSibling;\n }\n }\n return potentialMatch;\n }\n\n //=============================================================================\n // Scans forward from the insertionPoint in the old parent looking for a potential soft match\n // for the newChild. We stop if we find a potential soft match for the new child OR\n // if we find a potential id match in the old parents children OR if we find two\n // potential soft matches for the next two pieces of new content\n //=============================================================================\n function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {\n\n let potentialSoftMatch = insertionPoint;\n let nextSibling = newChild.nextSibling;\n let siblingSoftMatchCount = 0;\n\n while (potentialSoftMatch != null) {\n\n if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) {\n // the current potential soft match has a potential id set match with the remaining new\n // content so bail out of looking\n return null;\n }\n\n // if we have a soft match with the current node, return it\n if (isSoftMatch(newChild, potentialSoftMatch)) {\n return potentialSoftMatch;\n }\n\n if (isSoftMatch(nextSibling, potentialSoftMatch)) {\n // the next new node has a soft match with this node, so\n // increment the count of future soft matches\n siblingSoftMatchCount++;\n nextSibling = nextSibling.nextSibling;\n\n // If there are two future soft matches, bail to allow the siblings to soft match\n // so that we don't consume future soft matches for the sake of the current node\n if (siblingSoftMatchCount >= 2) {\n return null;\n }\n }\n\n // advanced to the next old content child\n potentialSoftMatch = potentialSoftMatch.nextSibling;\n }\n\n return potentialSoftMatch;\n }\n\n function parseContent(newContent) {\n let parser = new DOMParser();\n\n // remove svgs to avoid false-positive matches on head, etc.\n let contentWithSvgsRemoved = newContent.replace(/]*>|>)([\\s\\S]*?)<\\/svg>/gim, '');\n\n // if the newContent contains a html, head or body tag, we can simply parse it w/o wrapping\n if (contentWithSvgsRemoved.match(/<\\/html>/) || contentWithSvgsRemoved.match(/<\\/head>/) || contentWithSvgsRemoved.match(/<\\/body>/)) {\n let content = parser.parseFromString(newContent, \"text/html\");\n // if it is a full HTML document, return the document itself as the parent container\n if (contentWithSvgsRemoved.match(/<\\/html>/)) {\n content.generatedByIdiomorph = true;\n return content;\n } else {\n // otherwise return the html element as the parent container\n let htmlElement = content.firstChild;\n if (htmlElement) {\n htmlElement.generatedByIdiomorph = true;\n return htmlElement;\n } else {\n return null;\n }\n }\n } else {\n // if it is partial HTML, wrap it in a template tag to provide a parent element and also to help\n // deal with touchy tags like tr, tbody, etc.\n let responseDoc = parser.parseFromString(\"\", \"text/html\");\n let content = responseDoc.body.querySelector('template').content;\n content.generatedByIdiomorph = true;\n return content\n }\n }\n\n function normalizeContent(newContent) {\n if (newContent == null) {\n // noinspection UnnecessaryLocalVariableJS\n const dummyParent = document.createElement('div');\n return dummyParent;\n } else if (newContent.generatedByIdiomorph) {\n // the template tag created by idiomorph parsing can serve as a dummy parent\n return newContent;\n } else if (newContent instanceof Node) {\n // a single node is added as a child to a dummy parent\n const dummyParent = document.createElement('div');\n dummyParent.append(newContent);\n return dummyParent;\n } else {\n // all nodes in the array or HTMLElement collection are consolidated under\n // a single dummy parent element\n const dummyParent = document.createElement('div');\n for (const elt of [...newContent]) {\n dummyParent.append(elt);\n }\n return dummyParent;\n }\n }\n\n function insertSiblings(previousSibling, morphedNode, nextSibling) {\n let stack = []\n let added = []\n while (previousSibling != null) {\n stack.push(previousSibling);\n previousSibling = previousSibling.previousSibling;\n }\n while (stack.length > 0) {\n let node = stack.pop();\n added.push(node); // push added preceding siblings on in order and insert\n morphedNode.parentElement.insertBefore(node, morphedNode);\n }\n added.push(morphedNode);\n while (nextSibling != null) {\n stack.push(nextSibling);\n added.push(nextSibling); // here we are going in order, so push on as we scan, rather than add\n nextSibling = nextSibling.nextSibling;\n }\n while (stack.length > 0) {\n morphedNode.parentElement.insertBefore(stack.pop(), morphedNode.nextSibling);\n }\n return added;\n }\n\n function findBestNodeMatch(newContent, oldNode, ctx) {\n let currentElement;\n currentElement = newContent.firstChild;\n let bestElement = currentElement;\n let score = 0;\n while (currentElement) {\n let newScore = scoreElement(currentElement, oldNode, ctx);\n if (newScore > score) {\n bestElement = currentElement;\n score = newScore;\n }\n currentElement = currentElement.nextSibling;\n }\n return bestElement;\n }\n\n function scoreElement(node1, node2, ctx) {\n if (isSoftMatch(node1, node2)) {\n return .5 + getIdIntersectionCount(ctx, node1, node2);\n }\n return 0;\n }\n\n function removeNode(tempNode, ctx) {\n removeIdsFromConsideration(ctx, tempNode)\n if (ctx.callbacks.beforeNodeRemoved(tempNode) === false) return;\n\n tempNode.remove();\n ctx.callbacks.afterNodeRemoved(tempNode);\n }\n\n //=============================================================================\n // ID Set Functions\n //=============================================================================\n\n function isIdInConsideration(ctx, id) {\n return !ctx.deadIds.has(id);\n }\n\n function idIsWithinNode(ctx, id, targetNode) {\n let idSet = ctx.idMap.get(targetNode) || EMPTY_SET;\n return idSet.has(id);\n }\n\n function removeIdsFromConsideration(ctx, node) {\n let idSet = ctx.idMap.get(node) || EMPTY_SET;\n for (const id of idSet) {\n ctx.deadIds.add(id);\n }\n }\n\n function getIdIntersectionCount(ctx, node1, node2) {\n let sourceSet = ctx.idMap.get(node1) || EMPTY_SET;\n let matchCount = 0;\n for (const id of sourceSet) {\n // a potential match is an id in the source and potentialIdsSet, but\n // that has not already been merged into the DOM\n if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) {\n ++matchCount;\n }\n }\n return matchCount;\n }\n\n /**\n * A bottom up algorithm that finds all elements with ids inside of the node\n * argument and populates id sets for those nodes and all their parents, generating\n * a set of ids contained within all nodes for the entire hierarchy in the DOM\n *\n * @param node {Element}\n * @param {Map>} idMap\n */\n function populateIdMapForNode(node, idMap) {\n let nodeParent = node.parentElement;\n // find all elements with an id property\n let idElements = node.querySelectorAll('[id]');\n for (const elt of idElements) {\n let current = elt;\n // walk up the parent hierarchy of that element, adding the id\n // of element to the parent's id set\n while (current !== nodeParent && current != null) {\n let idSet = idMap.get(current);\n // if the id set doesn't exist, create it and insert it in the map\n if (idSet == null) {\n idSet = new Set();\n idMap.set(current, idSet);\n }\n idSet.add(elt.id);\n current = current.parentElement;\n }\n }\n }\n\n /**\n * This function computes a map of nodes to all ids contained within that node (inclusive of the\n * node). This map can be used to ask if two nodes have intersecting sets of ids, which allows\n * for a looser definition of \"matching\" than tradition id matching, and allows child nodes\n * to contribute to a parent nodes matching.\n *\n * @param {Element} oldContent the old content that will be morphed\n * @param {Element} newContent the new content to morph to\n * @returns {Map>} a map of nodes to id sets for the\n */\n function createIdMap(oldContent, newContent) {\n let idMap = new Map();\n populateIdMapForNode(oldContent, idMap);\n populateIdMapForNode(newContent, idMap);\n return idMap;\n }\n\n //=============================================================================\n // This is what ends up becoming the Idiomorph global object\n //=============================================================================\n return {\n morph,\n defaults\n }\n })();\n\nexport {Idiomorph};\n","import HotwireSpark from \"./index.js\"\n\nexport function log(...args) {\n if (HotwireSpark.config.loggingEnabled) {\n console.log(`[hotwire_spark]`, ...args)\n }\n}\n\n","/*\nStimulus 3.2.1\nCopyright © 2023 Basecamp, LLC\n */\nclass EventListener {\n constructor(eventTarget, eventName, eventOptions) {\n this.eventTarget = eventTarget;\n this.eventName = eventName;\n this.eventOptions = eventOptions;\n this.unorderedBindings = new Set();\n }\n connect() {\n this.eventTarget.addEventListener(this.eventName, this, this.eventOptions);\n }\n disconnect() {\n this.eventTarget.removeEventListener(this.eventName, this, this.eventOptions);\n }\n bindingConnected(binding) {\n this.unorderedBindings.add(binding);\n }\n bindingDisconnected(binding) {\n this.unorderedBindings.delete(binding);\n }\n handleEvent(event) {\n const extendedEvent = extendEvent(event);\n for (const binding of this.bindings) {\n if (extendedEvent.immediatePropagationStopped) {\n break;\n }\n else {\n binding.handleEvent(extendedEvent);\n }\n }\n }\n hasBindings() {\n return this.unorderedBindings.size > 0;\n }\n get bindings() {\n return Array.from(this.unorderedBindings).sort((left, right) => {\n const leftIndex = left.index, rightIndex = right.index;\n return leftIndex < rightIndex ? -1 : leftIndex > rightIndex ? 1 : 0;\n });\n }\n}\nfunction extendEvent(event) {\n if (\"immediatePropagationStopped\" in event) {\n return event;\n }\n else {\n const { stopImmediatePropagation } = event;\n return Object.assign(event, {\n immediatePropagationStopped: false,\n stopImmediatePropagation() {\n this.immediatePropagationStopped = true;\n stopImmediatePropagation.call(this);\n },\n });\n }\n}\n\nclass Dispatcher {\n constructor(application) {\n this.application = application;\n this.eventListenerMaps = new Map();\n this.started = false;\n }\n start() {\n if (!this.started) {\n this.started = true;\n this.eventListeners.forEach((eventListener) => eventListener.connect());\n }\n }\n stop() {\n if (this.started) {\n this.started = false;\n this.eventListeners.forEach((eventListener) => eventListener.disconnect());\n }\n }\n get eventListeners() {\n return Array.from(this.eventListenerMaps.values()).reduce((listeners, map) => listeners.concat(Array.from(map.values())), []);\n }\n bindingConnected(binding) {\n this.fetchEventListenerForBinding(binding).bindingConnected(binding);\n }\n bindingDisconnected(binding, clearEventListeners = false) {\n this.fetchEventListenerForBinding(binding).bindingDisconnected(binding);\n if (clearEventListeners)\n this.clearEventListenersForBinding(binding);\n }\n handleError(error, message, detail = {}) {\n this.application.handleError(error, `Error ${message}`, detail);\n }\n clearEventListenersForBinding(binding) {\n const eventListener = this.fetchEventListenerForBinding(binding);\n if (!eventListener.hasBindings()) {\n eventListener.disconnect();\n this.removeMappedEventListenerFor(binding);\n }\n }\n removeMappedEventListenerFor(binding) {\n const { eventTarget, eventName, eventOptions } = binding;\n const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget);\n const cacheKey = this.cacheKey(eventName, eventOptions);\n eventListenerMap.delete(cacheKey);\n if (eventListenerMap.size == 0)\n this.eventListenerMaps.delete(eventTarget);\n }\n fetchEventListenerForBinding(binding) {\n const { eventTarget, eventName, eventOptions } = binding;\n return this.fetchEventListener(eventTarget, eventName, eventOptions);\n }\n fetchEventListener(eventTarget, eventName, eventOptions) {\n const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget);\n const cacheKey = this.cacheKey(eventName, eventOptions);\n let eventListener = eventListenerMap.get(cacheKey);\n if (!eventListener) {\n eventListener = this.createEventListener(eventTarget, eventName, eventOptions);\n eventListenerMap.set(cacheKey, eventListener);\n }\n return eventListener;\n }\n createEventListener(eventTarget, eventName, eventOptions) {\n const eventListener = new EventListener(eventTarget, eventName, eventOptions);\n if (this.started) {\n eventListener.connect();\n }\n return eventListener;\n }\n fetchEventListenerMapForEventTarget(eventTarget) {\n let eventListenerMap = this.eventListenerMaps.get(eventTarget);\n if (!eventListenerMap) {\n eventListenerMap = new Map();\n this.eventListenerMaps.set(eventTarget, eventListenerMap);\n }\n return eventListenerMap;\n }\n cacheKey(eventName, eventOptions) {\n const parts = [eventName];\n Object.keys(eventOptions)\n .sort()\n .forEach((key) => {\n parts.push(`${eventOptions[key] ? \"\" : \"!\"}${key}`);\n });\n return parts.join(\":\");\n }\n}\n\nconst defaultActionDescriptorFilters = {\n stop({ event, value }) {\n if (value)\n event.stopPropagation();\n return true;\n },\n prevent({ event, value }) {\n if (value)\n event.preventDefault();\n return true;\n },\n self({ event, value, element }) {\n if (value) {\n return element === event.target;\n }\n else {\n return true;\n }\n },\n};\nconst descriptorPattern = /^(?:(?:([^.]+?)\\+)?(.+?)(?:\\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/;\nfunction parseActionDescriptorString(descriptorString) {\n const source = descriptorString.trim();\n const matches = source.match(descriptorPattern) || [];\n let eventName = matches[2];\n let keyFilter = matches[3];\n if (keyFilter && ![\"keydown\", \"keyup\", \"keypress\"].includes(eventName)) {\n eventName += `.${keyFilter}`;\n keyFilter = \"\";\n }\n return {\n eventTarget: parseEventTarget(matches[4]),\n eventName,\n eventOptions: matches[7] ? parseEventOptions(matches[7]) : {},\n identifier: matches[5],\n methodName: matches[6],\n keyFilter: matches[1] || keyFilter,\n };\n}\nfunction parseEventTarget(eventTargetName) {\n if (eventTargetName == \"window\") {\n return window;\n }\n else if (eventTargetName == \"document\") {\n return document;\n }\n}\nfunction parseEventOptions(eventOptions) {\n return eventOptions\n .split(\":\")\n .reduce((options, token) => Object.assign(options, { [token.replace(/^!/, \"\")]: !/^!/.test(token) }), {});\n}\nfunction stringifyEventTarget(eventTarget) {\n if (eventTarget == window) {\n return \"window\";\n }\n else if (eventTarget == document) {\n return \"document\";\n }\n}\n\nfunction camelize(value) {\n return value.replace(/(?:[_-])([a-z0-9])/g, (_, char) => char.toUpperCase());\n}\nfunction namespaceCamelize(value) {\n return camelize(value.replace(/--/g, \"-\").replace(/__/g, \"_\"));\n}\nfunction capitalize(value) {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\nfunction dasherize(value) {\n return value.replace(/([A-Z])/g, (_, char) => `-${char.toLowerCase()}`);\n}\nfunction tokenize(value) {\n return value.match(/[^\\s]+/g) || [];\n}\n\nfunction isSomething(object) {\n return object !== null && object !== undefined;\n}\nfunction hasProperty(object, property) {\n return Object.prototype.hasOwnProperty.call(object, property);\n}\n\nconst allModifiers = [\"meta\", \"ctrl\", \"alt\", \"shift\"];\nclass Action {\n constructor(element, index, descriptor, schema) {\n this.element = element;\n this.index = index;\n this.eventTarget = descriptor.eventTarget || element;\n this.eventName = descriptor.eventName || getDefaultEventNameForElement(element) || error(\"missing event name\");\n this.eventOptions = descriptor.eventOptions || {};\n this.identifier = descriptor.identifier || error(\"missing identifier\");\n this.methodName = descriptor.methodName || error(\"missing method name\");\n this.keyFilter = descriptor.keyFilter || \"\";\n this.schema = schema;\n }\n static forToken(token, schema) {\n return new this(token.element, token.index, parseActionDescriptorString(token.content), schema);\n }\n toString() {\n const eventFilter = this.keyFilter ? `.${this.keyFilter}` : \"\";\n const eventTarget = this.eventTargetName ? `@${this.eventTargetName}` : \"\";\n return `${this.eventName}${eventFilter}${eventTarget}->${this.identifier}#${this.methodName}`;\n }\n shouldIgnoreKeyboardEvent(event) {\n if (!this.keyFilter) {\n return false;\n }\n const filters = this.keyFilter.split(\"+\");\n if (this.keyFilterDissatisfied(event, filters)) {\n return true;\n }\n const standardFilter = filters.filter((key) => !allModifiers.includes(key))[0];\n if (!standardFilter) {\n return false;\n }\n if (!hasProperty(this.keyMappings, standardFilter)) {\n error(`contains unknown key filter: ${this.keyFilter}`);\n }\n return this.keyMappings[standardFilter].toLowerCase() !== event.key.toLowerCase();\n }\n shouldIgnoreMouseEvent(event) {\n if (!this.keyFilter) {\n return false;\n }\n const filters = [this.keyFilter];\n if (this.keyFilterDissatisfied(event, filters)) {\n return true;\n }\n return false;\n }\n get params() {\n const params = {};\n const pattern = new RegExp(`^data-${this.identifier}-(.+)-param$`, \"i\");\n for (const { name, value } of Array.from(this.element.attributes)) {\n const match = name.match(pattern);\n const key = match && match[1];\n if (key) {\n params[camelize(key)] = typecast(value);\n }\n }\n return params;\n }\n get eventTargetName() {\n return stringifyEventTarget(this.eventTarget);\n }\n get keyMappings() {\n return this.schema.keyMappings;\n }\n keyFilterDissatisfied(event, filters) {\n const [meta, ctrl, alt, shift] = allModifiers.map((modifier) => filters.includes(modifier));\n return event.metaKey !== meta || event.ctrlKey !== ctrl || event.altKey !== alt || event.shiftKey !== shift;\n }\n}\nconst defaultEventNames = {\n a: () => \"click\",\n button: () => \"click\",\n form: () => \"submit\",\n details: () => \"toggle\",\n input: (e) => (e.getAttribute(\"type\") == \"submit\" ? \"click\" : \"input\"),\n select: () => \"change\",\n textarea: () => \"input\",\n};\nfunction getDefaultEventNameForElement(element) {\n const tagName = element.tagName.toLowerCase();\n if (tagName in defaultEventNames) {\n return defaultEventNames[tagName](element);\n }\n}\nfunction error(message) {\n throw new Error(message);\n}\nfunction typecast(value) {\n try {\n return JSON.parse(value);\n }\n catch (o_O) {\n return value;\n }\n}\n\nclass Binding {\n constructor(context, action) {\n this.context = context;\n this.action = action;\n }\n get index() {\n return this.action.index;\n }\n get eventTarget() {\n return this.action.eventTarget;\n }\n get eventOptions() {\n return this.action.eventOptions;\n }\n get identifier() {\n return this.context.identifier;\n }\n handleEvent(event) {\n const actionEvent = this.prepareActionEvent(event);\n if (this.willBeInvokedByEvent(event) && this.applyEventModifiers(actionEvent)) {\n this.invokeWithEvent(actionEvent);\n }\n }\n get eventName() {\n return this.action.eventName;\n }\n get method() {\n const method = this.controller[this.methodName];\n if (typeof method == \"function\") {\n return method;\n }\n throw new Error(`Action \"${this.action}\" references undefined method \"${this.methodName}\"`);\n }\n applyEventModifiers(event) {\n const { element } = this.action;\n const { actionDescriptorFilters } = this.context.application;\n const { controller } = this.context;\n let passes = true;\n for (const [name, value] of Object.entries(this.eventOptions)) {\n if (name in actionDescriptorFilters) {\n const filter = actionDescriptorFilters[name];\n passes = passes && filter({ name, value, event, element, controller });\n }\n else {\n continue;\n }\n }\n return passes;\n }\n prepareActionEvent(event) {\n return Object.assign(event, { params: this.action.params });\n }\n invokeWithEvent(event) {\n const { target, currentTarget } = event;\n try {\n this.method.call(this.controller, event);\n this.context.logDebugActivity(this.methodName, { event, target, currentTarget, action: this.methodName });\n }\n catch (error) {\n const { identifier, controller, element, index } = this;\n const detail = { identifier, controller, element, index, event };\n this.context.handleError(error, `invoking action \"${this.action}\"`, detail);\n }\n }\n willBeInvokedByEvent(event) {\n const eventTarget = event.target;\n if (event instanceof KeyboardEvent && this.action.shouldIgnoreKeyboardEvent(event)) {\n return false;\n }\n if (event instanceof MouseEvent && this.action.shouldIgnoreMouseEvent(event)) {\n return false;\n }\n if (this.element === eventTarget) {\n return true;\n }\n else if (eventTarget instanceof Element && this.element.contains(eventTarget)) {\n return this.scope.containsElement(eventTarget);\n }\n else {\n return this.scope.containsElement(this.action.element);\n }\n }\n get controller() {\n return this.context.controller;\n }\n get methodName() {\n return this.action.methodName;\n }\n get element() {\n return this.scope.element;\n }\n get scope() {\n return this.context.scope;\n }\n}\n\nclass ElementObserver {\n constructor(element, delegate) {\n this.mutationObserverInit = { attributes: true, childList: true, subtree: true };\n this.element = element;\n this.started = false;\n this.delegate = delegate;\n this.elements = new Set();\n this.mutationObserver = new MutationObserver((mutations) => this.processMutations(mutations));\n }\n start() {\n if (!this.started) {\n this.started = true;\n this.mutationObserver.observe(this.element, this.mutationObserverInit);\n this.refresh();\n }\n }\n pause(callback) {\n if (this.started) {\n this.mutationObserver.disconnect();\n this.started = false;\n }\n callback();\n if (!this.started) {\n this.mutationObserver.observe(this.element, this.mutationObserverInit);\n this.started = true;\n }\n }\n stop() {\n if (this.started) {\n this.mutationObserver.takeRecords();\n this.mutationObserver.disconnect();\n this.started = false;\n }\n }\n refresh() {\n if (this.started) {\n const matches = new Set(this.matchElementsInTree());\n for (const element of Array.from(this.elements)) {\n if (!matches.has(element)) {\n this.removeElement(element);\n }\n }\n for (const element of Array.from(matches)) {\n this.addElement(element);\n }\n }\n }\n processMutations(mutations) {\n if (this.started) {\n for (const mutation of mutations) {\n this.processMutation(mutation);\n }\n }\n }\n processMutation(mutation) {\n if (mutation.type == \"attributes\") {\n this.processAttributeChange(mutation.target, mutation.attributeName);\n }\n else if (mutation.type == \"childList\") {\n this.processRemovedNodes(mutation.removedNodes);\n this.processAddedNodes(mutation.addedNodes);\n }\n }\n processAttributeChange(element, attributeName) {\n if (this.elements.has(element)) {\n if (this.delegate.elementAttributeChanged && this.matchElement(element)) {\n this.delegate.elementAttributeChanged(element, attributeName);\n }\n else {\n this.removeElement(element);\n }\n }\n else if (this.matchElement(element)) {\n this.addElement(element);\n }\n }\n processRemovedNodes(nodes) {\n for (const node of Array.from(nodes)) {\n const element = this.elementFromNode(node);\n if (element) {\n this.processTree(element, this.removeElement);\n }\n }\n }\n processAddedNodes(nodes) {\n for (const node of Array.from(nodes)) {\n const element = this.elementFromNode(node);\n if (element && this.elementIsActive(element)) {\n this.processTree(element, this.addElement);\n }\n }\n }\n matchElement(element) {\n return this.delegate.matchElement(element);\n }\n matchElementsInTree(tree = this.element) {\n return this.delegate.matchElementsInTree(tree);\n }\n processTree(tree, processor) {\n for (const element of this.matchElementsInTree(tree)) {\n processor.call(this, element);\n }\n }\n elementFromNode(node) {\n if (node.nodeType == Node.ELEMENT_NODE) {\n return node;\n }\n }\n elementIsActive(element) {\n if (element.isConnected != this.element.isConnected) {\n return false;\n }\n else {\n return this.element.contains(element);\n }\n }\n addElement(element) {\n if (!this.elements.has(element)) {\n if (this.elementIsActive(element)) {\n this.elements.add(element);\n if (this.delegate.elementMatched) {\n this.delegate.elementMatched(element);\n }\n }\n }\n }\n removeElement(element) {\n if (this.elements.has(element)) {\n this.elements.delete(element);\n if (this.delegate.elementUnmatched) {\n this.delegate.elementUnmatched(element);\n }\n }\n }\n}\n\nclass AttributeObserver {\n constructor(element, attributeName, delegate) {\n this.attributeName = attributeName;\n this.delegate = delegate;\n this.elementObserver = new ElementObserver(element, this);\n }\n get element() {\n return this.elementObserver.element;\n }\n get selector() {\n return `[${this.attributeName}]`;\n }\n start() {\n this.elementObserver.start();\n }\n pause(callback) {\n this.elementObserver.pause(callback);\n }\n stop() {\n this.elementObserver.stop();\n }\n refresh() {\n this.elementObserver.refresh();\n }\n get started() {\n return this.elementObserver.started;\n }\n matchElement(element) {\n return element.hasAttribute(this.attributeName);\n }\n matchElementsInTree(tree) {\n const match = this.matchElement(tree) ? [tree] : [];\n const matches = Array.from(tree.querySelectorAll(this.selector));\n return match.concat(matches);\n }\n elementMatched(element) {\n if (this.delegate.elementMatchedAttribute) {\n this.delegate.elementMatchedAttribute(element, this.attributeName);\n }\n }\n elementUnmatched(element) {\n if (this.delegate.elementUnmatchedAttribute) {\n this.delegate.elementUnmatchedAttribute(element, this.attributeName);\n }\n }\n elementAttributeChanged(element, attributeName) {\n if (this.delegate.elementAttributeValueChanged && this.attributeName == attributeName) {\n this.delegate.elementAttributeValueChanged(element, attributeName);\n }\n }\n}\n\nfunction add(map, key, value) {\n fetch(map, key).add(value);\n}\nfunction del(map, key, value) {\n fetch(map, key).delete(value);\n prune(map, key);\n}\nfunction fetch(map, key) {\n let values = map.get(key);\n if (!values) {\n values = new Set();\n map.set(key, values);\n }\n return values;\n}\nfunction prune(map, key) {\n const values = map.get(key);\n if (values != null && values.size == 0) {\n map.delete(key);\n }\n}\n\nclass Multimap {\n constructor() {\n this.valuesByKey = new Map();\n }\n get keys() {\n return Array.from(this.valuesByKey.keys());\n }\n get values() {\n const sets = Array.from(this.valuesByKey.values());\n return sets.reduce((values, set) => values.concat(Array.from(set)), []);\n }\n get size() {\n const sets = Array.from(this.valuesByKey.values());\n return sets.reduce((size, set) => size + set.size, 0);\n }\n add(key, value) {\n add(this.valuesByKey, key, value);\n }\n delete(key, value) {\n del(this.valuesByKey, key, value);\n }\n has(key, value) {\n const values = this.valuesByKey.get(key);\n return values != null && values.has(value);\n }\n hasKey(key) {\n return this.valuesByKey.has(key);\n }\n hasValue(value) {\n const sets = Array.from(this.valuesByKey.values());\n return sets.some((set) => set.has(value));\n }\n getValuesForKey(key) {\n const values = this.valuesByKey.get(key);\n return values ? Array.from(values) : [];\n }\n getKeysForValue(value) {\n return Array.from(this.valuesByKey)\n .filter(([_key, values]) => values.has(value))\n .map(([key, _values]) => key);\n }\n}\n\nclass IndexedMultimap extends Multimap {\n constructor() {\n super();\n this.keysByValue = new Map();\n }\n get values() {\n return Array.from(this.keysByValue.keys());\n }\n add(key, value) {\n super.add(key, value);\n add(this.keysByValue, value, key);\n }\n delete(key, value) {\n super.delete(key, value);\n del(this.keysByValue, value, key);\n }\n hasValue(value) {\n return this.keysByValue.has(value);\n }\n getKeysForValue(value) {\n const set = this.keysByValue.get(value);\n return set ? Array.from(set) : [];\n }\n}\n\nclass SelectorObserver {\n constructor(element, selector, delegate, details) {\n this._selector = selector;\n this.details = details;\n this.elementObserver = new ElementObserver(element, this);\n this.delegate = delegate;\n this.matchesByElement = new Multimap();\n }\n get started() {\n return this.elementObserver.started;\n }\n get selector() {\n return this._selector;\n }\n set selector(selector) {\n this._selector = selector;\n this.refresh();\n }\n start() {\n this.elementObserver.start();\n }\n pause(callback) {\n this.elementObserver.pause(callback);\n }\n stop() {\n this.elementObserver.stop();\n }\n refresh() {\n this.elementObserver.refresh();\n }\n get element() {\n return this.elementObserver.element;\n }\n matchElement(element) {\n const { selector } = this;\n if (selector) {\n const matches = element.matches(selector);\n if (this.delegate.selectorMatchElement) {\n return matches && this.delegate.selectorMatchElement(element, this.details);\n }\n return matches;\n }\n else {\n return false;\n }\n }\n matchElementsInTree(tree) {\n const { selector } = this;\n if (selector) {\n const match = this.matchElement(tree) ? [tree] : [];\n const matches = Array.from(tree.querySelectorAll(selector)).filter((match) => this.matchElement(match));\n return match.concat(matches);\n }\n else {\n return [];\n }\n }\n elementMatched(element) {\n const { selector } = this;\n if (selector) {\n this.selectorMatched(element, selector);\n }\n }\n elementUnmatched(element) {\n const selectors = this.matchesByElement.getKeysForValue(element);\n for (const selector of selectors) {\n this.selectorUnmatched(element, selector);\n }\n }\n elementAttributeChanged(element, _attributeName) {\n const { selector } = this;\n if (selector) {\n const matches = this.matchElement(element);\n const matchedBefore = this.matchesByElement.has(selector, element);\n if (matches && !matchedBefore) {\n this.selectorMatched(element, selector);\n }\n else if (!matches && matchedBefore) {\n this.selectorUnmatched(element, selector);\n }\n }\n }\n selectorMatched(element, selector) {\n this.delegate.selectorMatched(element, selector, this.details);\n this.matchesByElement.add(selector, element);\n }\n selectorUnmatched(element, selector) {\n this.delegate.selectorUnmatched(element, selector, this.details);\n this.matchesByElement.delete(selector, element);\n }\n}\n\nclass StringMapObserver {\n constructor(element, delegate) {\n this.element = element;\n this.delegate = delegate;\n this.started = false;\n this.stringMap = new Map();\n this.mutationObserver = new MutationObserver((mutations) => this.processMutations(mutations));\n }\n start() {\n if (!this.started) {\n this.started = true;\n this.mutationObserver.observe(this.element, { attributes: true, attributeOldValue: true });\n this.refresh();\n }\n }\n stop() {\n if (this.started) {\n this.mutationObserver.takeRecords();\n this.mutationObserver.disconnect();\n this.started = false;\n }\n }\n refresh() {\n if (this.started) {\n for (const attributeName of this.knownAttributeNames) {\n this.refreshAttribute(attributeName, null);\n }\n }\n }\n processMutations(mutations) {\n if (this.started) {\n for (const mutation of mutations) {\n this.processMutation(mutation);\n }\n }\n }\n processMutation(mutation) {\n const attributeName = mutation.attributeName;\n if (attributeName) {\n this.refreshAttribute(attributeName, mutation.oldValue);\n }\n }\n refreshAttribute(attributeName, oldValue) {\n const key = this.delegate.getStringMapKeyForAttribute(attributeName);\n if (key != null) {\n if (!this.stringMap.has(attributeName)) {\n this.stringMapKeyAdded(key, attributeName);\n }\n const value = this.element.getAttribute(attributeName);\n if (this.stringMap.get(attributeName) != value) {\n this.stringMapValueChanged(value, key, oldValue);\n }\n if (value == null) {\n const oldValue = this.stringMap.get(attributeName);\n this.stringMap.delete(attributeName);\n if (oldValue)\n this.stringMapKeyRemoved(key, attributeName, oldValue);\n }\n else {\n this.stringMap.set(attributeName, value);\n }\n }\n }\n stringMapKeyAdded(key, attributeName) {\n if (this.delegate.stringMapKeyAdded) {\n this.delegate.stringMapKeyAdded(key, attributeName);\n }\n }\n stringMapValueChanged(value, key, oldValue) {\n if (this.delegate.stringMapValueChanged) {\n this.delegate.stringMapValueChanged(value, key, oldValue);\n }\n }\n stringMapKeyRemoved(key, attributeName, oldValue) {\n if (this.delegate.stringMapKeyRemoved) {\n this.delegate.stringMapKeyRemoved(key, attributeName, oldValue);\n }\n }\n get knownAttributeNames() {\n return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)));\n }\n get currentAttributeNames() {\n return Array.from(this.element.attributes).map((attribute) => attribute.name);\n }\n get recordedAttributeNames() {\n return Array.from(this.stringMap.keys());\n }\n}\n\nclass TokenListObserver {\n constructor(element, attributeName, delegate) {\n this.attributeObserver = new AttributeObserver(element, attributeName, this);\n this.delegate = delegate;\n this.tokensByElement = new Multimap();\n }\n get started() {\n return this.attributeObserver.started;\n }\n start() {\n this.attributeObserver.start();\n }\n pause(callback) {\n this.attributeObserver.pause(callback);\n }\n stop() {\n this.attributeObserver.stop();\n }\n refresh() {\n this.attributeObserver.refresh();\n }\n get element() {\n return this.attributeObserver.element;\n }\n get attributeName() {\n return this.attributeObserver.attributeName;\n }\n elementMatchedAttribute(element) {\n this.tokensMatched(this.readTokensForElement(element));\n }\n elementAttributeValueChanged(element) {\n const [unmatchedTokens, matchedTokens] = this.refreshTokensForElement(element);\n this.tokensUnmatched(unmatchedTokens);\n this.tokensMatched(matchedTokens);\n }\n elementUnmatchedAttribute(element) {\n this.tokensUnmatched(this.tokensByElement.getValuesForKey(element));\n }\n tokensMatched(tokens) {\n tokens.forEach((token) => this.tokenMatched(token));\n }\n tokensUnmatched(tokens) {\n tokens.forEach((token) => this.tokenUnmatched(token));\n }\n tokenMatched(token) {\n this.delegate.tokenMatched(token);\n this.tokensByElement.add(token.element, token);\n }\n tokenUnmatched(token) {\n this.delegate.tokenUnmatched(token);\n this.tokensByElement.delete(token.element, token);\n }\n refreshTokensForElement(element) {\n const previousTokens = this.tokensByElement.getValuesForKey(element);\n const currentTokens = this.readTokensForElement(element);\n const firstDifferingIndex = zip(previousTokens, currentTokens).findIndex(([previousToken, currentToken]) => !tokensAreEqual(previousToken, currentToken));\n if (firstDifferingIndex == -1) {\n return [[], []];\n }\n else {\n return [previousTokens.slice(firstDifferingIndex), currentTokens.slice(firstDifferingIndex)];\n }\n }\n readTokensForElement(element) {\n const attributeName = this.attributeName;\n const tokenString = element.getAttribute(attributeName) || \"\";\n return parseTokenString(tokenString, element, attributeName);\n }\n}\nfunction parseTokenString(tokenString, element, attributeName) {\n return tokenString\n .trim()\n .split(/\\s+/)\n .filter((content) => content.length)\n .map((content, index) => ({ element, attributeName, content, index }));\n}\nfunction zip(left, right) {\n const length = Math.max(left.length, right.length);\n return Array.from({ length }, (_, index) => [left[index], right[index]]);\n}\nfunction tokensAreEqual(left, right) {\n return left && right && left.index == right.index && left.content == right.content;\n}\n\nclass ValueListObserver {\n constructor(element, attributeName, delegate) {\n this.tokenListObserver = new TokenListObserver(element, attributeName, this);\n this.delegate = delegate;\n this.parseResultsByToken = new WeakMap();\n this.valuesByTokenByElement = new WeakMap();\n }\n get started() {\n return this.tokenListObserver.started;\n }\n start() {\n this.tokenListObserver.start();\n }\n stop() {\n this.tokenListObserver.stop();\n }\n refresh() {\n this.tokenListObserver.refresh();\n }\n get element() {\n return this.tokenListObserver.element;\n }\n get attributeName() {\n return this.tokenListObserver.attributeName;\n }\n tokenMatched(token) {\n const { element } = token;\n const { value } = this.fetchParseResultForToken(token);\n if (value) {\n this.fetchValuesByTokenForElement(element).set(token, value);\n this.delegate.elementMatchedValue(element, value);\n }\n }\n tokenUnmatched(token) {\n const { element } = token;\n const { value } = this.fetchParseResultForToken(token);\n if (value) {\n this.fetchValuesByTokenForElement(element).delete(token);\n this.delegate.elementUnmatchedValue(element, value);\n }\n }\n fetchParseResultForToken(token) {\n let parseResult = this.parseResultsByToken.get(token);\n if (!parseResult) {\n parseResult = this.parseToken(token);\n this.parseResultsByToken.set(token, parseResult);\n }\n return parseResult;\n }\n fetchValuesByTokenForElement(element) {\n let valuesByToken = this.valuesByTokenByElement.get(element);\n if (!valuesByToken) {\n valuesByToken = new Map();\n this.valuesByTokenByElement.set(element, valuesByToken);\n }\n return valuesByToken;\n }\n parseToken(token) {\n try {\n const value = this.delegate.parseValueForToken(token);\n return { value };\n }\n catch (error) {\n return { error };\n }\n }\n}\n\nclass BindingObserver {\n constructor(context, delegate) {\n this.context = context;\n this.delegate = delegate;\n this.bindingsByAction = new Map();\n }\n start() {\n if (!this.valueListObserver) {\n this.valueListObserver = new ValueListObserver(this.element, this.actionAttribute, this);\n this.valueListObserver.start();\n }\n }\n stop() {\n if (this.valueListObserver) {\n this.valueListObserver.stop();\n delete this.valueListObserver;\n this.disconnectAllActions();\n }\n }\n get element() {\n return this.context.element;\n }\n get identifier() {\n return this.context.identifier;\n }\n get actionAttribute() {\n return this.schema.actionAttribute;\n }\n get schema() {\n return this.context.schema;\n }\n get bindings() {\n return Array.from(this.bindingsByAction.values());\n }\n connectAction(action) {\n const binding = new Binding(this.context, action);\n this.bindingsByAction.set(action, binding);\n this.delegate.bindingConnected(binding);\n }\n disconnectAction(action) {\n const binding = this.bindingsByAction.get(action);\n if (binding) {\n this.bindingsByAction.delete(action);\n this.delegate.bindingDisconnected(binding);\n }\n }\n disconnectAllActions() {\n this.bindings.forEach((binding) => this.delegate.bindingDisconnected(binding, true));\n this.bindingsByAction.clear();\n }\n parseValueForToken(token) {\n const action = Action.forToken(token, this.schema);\n if (action.identifier == this.identifier) {\n return action;\n }\n }\n elementMatchedValue(element, action) {\n this.connectAction(action);\n }\n elementUnmatchedValue(element, action) {\n this.disconnectAction(action);\n }\n}\n\nclass ValueObserver {\n constructor(context, receiver) {\n this.context = context;\n this.receiver = receiver;\n this.stringMapObserver = new StringMapObserver(this.element, this);\n this.valueDescriptorMap = this.controller.valueDescriptorMap;\n }\n start() {\n this.stringMapObserver.start();\n this.invokeChangedCallbacksForDefaultValues();\n }\n stop() {\n this.stringMapObserver.stop();\n }\n get element() {\n return this.context.element;\n }\n get controller() {\n return this.context.controller;\n }\n getStringMapKeyForAttribute(attributeName) {\n if (attributeName in this.valueDescriptorMap) {\n return this.valueDescriptorMap[attributeName].name;\n }\n }\n stringMapKeyAdded(key, attributeName) {\n const descriptor = this.valueDescriptorMap[attributeName];\n if (!this.hasValue(key)) {\n this.invokeChangedCallback(key, descriptor.writer(this.receiver[key]), descriptor.writer(descriptor.defaultValue));\n }\n }\n stringMapValueChanged(value, name, oldValue) {\n const descriptor = this.valueDescriptorNameMap[name];\n if (value === null)\n return;\n if (oldValue === null) {\n oldValue = descriptor.writer(descriptor.defaultValue);\n }\n this.invokeChangedCallback(name, value, oldValue);\n }\n stringMapKeyRemoved(key, attributeName, oldValue) {\n const descriptor = this.valueDescriptorNameMap[key];\n if (this.hasValue(key)) {\n this.invokeChangedCallback(key, descriptor.writer(this.receiver[key]), oldValue);\n }\n else {\n this.invokeChangedCallback(key, descriptor.writer(descriptor.defaultValue), oldValue);\n }\n }\n invokeChangedCallbacksForDefaultValues() {\n for (const { key, name, defaultValue, writer } of this.valueDescriptors) {\n if (defaultValue != undefined && !this.controller.data.has(key)) {\n this.invokeChangedCallback(name, writer(defaultValue), undefined);\n }\n }\n }\n invokeChangedCallback(name, rawValue, rawOldValue) {\n const changedMethodName = `${name}Changed`;\n const changedMethod = this.receiver[changedMethodName];\n if (typeof changedMethod == \"function\") {\n const descriptor = this.valueDescriptorNameMap[name];\n try {\n const value = descriptor.reader(rawValue);\n let oldValue = rawOldValue;\n if (rawOldValue) {\n oldValue = descriptor.reader(rawOldValue);\n }\n changedMethod.call(this.receiver, value, oldValue);\n }\n catch (error) {\n if (error instanceof TypeError) {\n error.message = `Stimulus Value \"${this.context.identifier}.${descriptor.name}\" - ${error.message}`;\n }\n throw error;\n }\n }\n }\n get valueDescriptors() {\n const { valueDescriptorMap } = this;\n return Object.keys(valueDescriptorMap).map((key) => valueDescriptorMap[key]);\n }\n get valueDescriptorNameMap() {\n const descriptors = {};\n Object.keys(this.valueDescriptorMap).forEach((key) => {\n const descriptor = this.valueDescriptorMap[key];\n descriptors[descriptor.name] = descriptor;\n });\n return descriptors;\n }\n hasValue(attributeName) {\n const descriptor = this.valueDescriptorNameMap[attributeName];\n const hasMethodName = `has${capitalize(descriptor.name)}`;\n return this.receiver[hasMethodName];\n }\n}\n\nclass TargetObserver {\n constructor(context, delegate) {\n this.context = context;\n this.delegate = delegate;\n this.targetsByName = new Multimap();\n }\n start() {\n if (!this.tokenListObserver) {\n this.tokenListObserver = new TokenListObserver(this.element, this.attributeName, this);\n this.tokenListObserver.start();\n }\n }\n stop() {\n if (this.tokenListObserver) {\n this.disconnectAllTargets();\n this.tokenListObserver.stop();\n delete this.tokenListObserver;\n }\n }\n tokenMatched({ element, content: name }) {\n if (this.scope.containsElement(element)) {\n this.connectTarget(element, name);\n }\n }\n tokenUnmatched({ element, content: name }) {\n this.disconnectTarget(element, name);\n }\n connectTarget(element, name) {\n var _a;\n if (!this.targetsByName.has(name, element)) {\n this.targetsByName.add(name, element);\n (_a = this.tokenListObserver) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.targetConnected(element, name));\n }\n }\n disconnectTarget(element, name) {\n var _a;\n if (this.targetsByName.has(name, element)) {\n this.targetsByName.delete(name, element);\n (_a = this.tokenListObserver) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.targetDisconnected(element, name));\n }\n }\n disconnectAllTargets() {\n for (const name of this.targetsByName.keys) {\n for (const element of this.targetsByName.getValuesForKey(name)) {\n this.disconnectTarget(element, name);\n }\n }\n }\n get attributeName() {\n return `data-${this.context.identifier}-target`;\n }\n get element() {\n return this.context.element;\n }\n get scope() {\n return this.context.scope;\n }\n}\n\nfunction readInheritableStaticArrayValues(constructor, propertyName) {\n const ancestors = getAncestorsForConstructor(constructor);\n return Array.from(ancestors.reduce((values, constructor) => {\n getOwnStaticArrayValues(constructor, propertyName).forEach((name) => values.add(name));\n return values;\n }, new Set()));\n}\nfunction readInheritableStaticObjectPairs(constructor, propertyName) {\n const ancestors = getAncestorsForConstructor(constructor);\n return ancestors.reduce((pairs, constructor) => {\n pairs.push(...getOwnStaticObjectPairs(constructor, propertyName));\n return pairs;\n }, []);\n}\nfunction getAncestorsForConstructor(constructor) {\n const ancestors = [];\n while (constructor) {\n ancestors.push(constructor);\n constructor = Object.getPrototypeOf(constructor);\n }\n return ancestors.reverse();\n}\nfunction getOwnStaticArrayValues(constructor, propertyName) {\n const definition = constructor[propertyName];\n return Array.isArray(definition) ? definition : [];\n}\nfunction getOwnStaticObjectPairs(constructor, propertyName) {\n const definition = constructor[propertyName];\n return definition ? Object.keys(definition).map((key) => [key, definition[key]]) : [];\n}\n\nclass OutletObserver {\n constructor(context, delegate) {\n this.started = false;\n this.context = context;\n this.delegate = delegate;\n this.outletsByName = new Multimap();\n this.outletElementsByName = new Multimap();\n this.selectorObserverMap = new Map();\n this.attributeObserverMap = new Map();\n }\n start() {\n if (!this.started) {\n this.outletDefinitions.forEach((outletName) => {\n this.setupSelectorObserverForOutlet(outletName);\n this.setupAttributeObserverForOutlet(outletName);\n });\n this.started = true;\n this.dependentContexts.forEach((context) => context.refresh());\n }\n }\n refresh() {\n this.selectorObserverMap.forEach((observer) => observer.refresh());\n this.attributeObserverMap.forEach((observer) => observer.refresh());\n }\n stop() {\n if (this.started) {\n this.started = false;\n this.disconnectAllOutlets();\n this.stopSelectorObservers();\n this.stopAttributeObservers();\n }\n }\n stopSelectorObservers() {\n if (this.selectorObserverMap.size > 0) {\n this.selectorObserverMap.forEach((observer) => observer.stop());\n this.selectorObserverMap.clear();\n }\n }\n stopAttributeObservers() {\n if (this.attributeObserverMap.size > 0) {\n this.attributeObserverMap.forEach((observer) => observer.stop());\n this.attributeObserverMap.clear();\n }\n }\n selectorMatched(element, _selector, { outletName }) {\n const outlet = this.getOutlet(element, outletName);\n if (outlet) {\n this.connectOutlet(outlet, element, outletName);\n }\n }\n selectorUnmatched(element, _selector, { outletName }) {\n const outlet = this.getOutletFromMap(element, outletName);\n if (outlet) {\n this.disconnectOutlet(outlet, element, outletName);\n }\n }\n selectorMatchElement(element, { outletName }) {\n const selector = this.selector(outletName);\n const hasOutlet = this.hasOutlet(element, outletName);\n const hasOutletController = element.matches(`[${this.schema.controllerAttribute}~=${outletName}]`);\n if (selector) {\n return hasOutlet && hasOutletController && element.matches(selector);\n }\n else {\n return false;\n }\n }\n elementMatchedAttribute(_element, attributeName) {\n const outletName = this.getOutletNameFromOutletAttributeName(attributeName);\n if (outletName) {\n this.updateSelectorObserverForOutlet(outletName);\n }\n }\n elementAttributeValueChanged(_element, attributeName) {\n const outletName = this.getOutletNameFromOutletAttributeName(attributeName);\n if (outletName) {\n this.updateSelectorObserverForOutlet(outletName);\n }\n }\n elementUnmatchedAttribute(_element, attributeName) {\n const outletName = this.getOutletNameFromOutletAttributeName(attributeName);\n if (outletName) {\n this.updateSelectorObserverForOutlet(outletName);\n }\n }\n connectOutlet(outlet, element, outletName) {\n var _a;\n if (!this.outletElementsByName.has(outletName, element)) {\n this.outletsByName.add(outletName, outlet);\n this.outletElementsByName.add(outletName, element);\n (_a = this.selectorObserverMap.get(outletName)) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.outletConnected(outlet, element, outletName));\n }\n }\n disconnectOutlet(outlet, element, outletName) {\n var _a;\n if (this.outletElementsByName.has(outletName, element)) {\n this.outletsByName.delete(outletName, outlet);\n this.outletElementsByName.delete(outletName, element);\n (_a = this.selectorObserverMap\n .get(outletName)) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.outletDisconnected(outlet, element, outletName));\n }\n }\n disconnectAllOutlets() {\n for (const outletName of this.outletElementsByName.keys) {\n for (const element of this.outletElementsByName.getValuesForKey(outletName)) {\n for (const outlet of this.outletsByName.getValuesForKey(outletName)) {\n this.disconnectOutlet(outlet, element, outletName);\n }\n }\n }\n }\n updateSelectorObserverForOutlet(outletName) {\n const observer = this.selectorObserverMap.get(outletName);\n if (observer) {\n observer.selector = this.selector(outletName);\n }\n }\n setupSelectorObserverForOutlet(outletName) {\n const selector = this.selector(outletName);\n const selectorObserver = new SelectorObserver(document.body, selector, this, { outletName });\n this.selectorObserverMap.set(outletName, selectorObserver);\n selectorObserver.start();\n }\n setupAttributeObserverForOutlet(outletName) {\n const attributeName = this.attributeNameForOutletName(outletName);\n const attributeObserver = new AttributeObserver(this.scope.element, attributeName, this);\n this.attributeObserverMap.set(outletName, attributeObserver);\n attributeObserver.start();\n }\n selector(outletName) {\n return this.scope.outlets.getSelectorForOutletName(outletName);\n }\n attributeNameForOutletName(outletName) {\n return this.scope.schema.outletAttributeForScope(this.identifier, outletName);\n }\n getOutletNameFromOutletAttributeName(attributeName) {\n return this.outletDefinitions.find((outletName) => this.attributeNameForOutletName(outletName) === attributeName);\n }\n get outletDependencies() {\n const dependencies = new Multimap();\n this.router.modules.forEach((module) => {\n const constructor = module.definition.controllerConstructor;\n const outlets = readInheritableStaticArrayValues(constructor, \"outlets\");\n outlets.forEach((outlet) => dependencies.add(outlet, module.identifier));\n });\n return dependencies;\n }\n get outletDefinitions() {\n return this.outletDependencies.getKeysForValue(this.identifier);\n }\n get dependentControllerIdentifiers() {\n return this.outletDependencies.getValuesForKey(this.identifier);\n }\n get dependentContexts() {\n const identifiers = this.dependentControllerIdentifiers;\n return this.router.contexts.filter((context) => identifiers.includes(context.identifier));\n }\n hasOutlet(element, outletName) {\n return !!this.getOutlet(element, outletName) || !!this.getOutletFromMap(element, outletName);\n }\n getOutlet(element, outletName) {\n return this.application.getControllerForElementAndIdentifier(element, outletName);\n }\n getOutletFromMap(element, outletName) {\n return this.outletsByName.getValuesForKey(outletName).find((outlet) => outlet.element === element);\n }\n get scope() {\n return this.context.scope;\n }\n get schema() {\n return this.context.schema;\n }\n get identifier() {\n return this.context.identifier;\n }\n get application() {\n return this.context.application;\n }\n get router() {\n return this.application.router;\n }\n}\n\nclass Context {\n constructor(module, scope) {\n this.logDebugActivity = (functionName, detail = {}) => {\n const { identifier, controller, element } = this;\n detail = Object.assign({ identifier, controller, element }, detail);\n this.application.logDebugActivity(this.identifier, functionName, detail);\n };\n this.module = module;\n this.scope = scope;\n this.controller = new module.controllerConstructor(this);\n this.bindingObserver = new BindingObserver(this, this.dispatcher);\n this.valueObserver = new ValueObserver(this, this.controller);\n this.targetObserver = new TargetObserver(this, this);\n this.outletObserver = new OutletObserver(this, this);\n try {\n this.controller.initialize();\n this.logDebugActivity(\"initialize\");\n }\n catch (error) {\n this.handleError(error, \"initializing controller\");\n }\n }\n connect() {\n this.bindingObserver.start();\n this.valueObserver.start();\n this.targetObserver.start();\n this.outletObserver.start();\n try {\n this.controller.connect();\n this.logDebugActivity(\"connect\");\n }\n catch (error) {\n this.handleError(error, \"connecting controller\");\n }\n }\n refresh() {\n this.outletObserver.refresh();\n }\n disconnect() {\n try {\n this.controller.disconnect();\n this.logDebugActivity(\"disconnect\");\n }\n catch (error) {\n this.handleError(error, \"disconnecting controller\");\n }\n this.outletObserver.stop();\n this.targetObserver.stop();\n this.valueObserver.stop();\n this.bindingObserver.stop();\n }\n get application() {\n return this.module.application;\n }\n get identifier() {\n return this.module.identifier;\n }\n get schema() {\n return this.application.schema;\n }\n get dispatcher() {\n return this.application.dispatcher;\n }\n get element() {\n return this.scope.element;\n }\n get parentElement() {\n return this.element.parentElement;\n }\n handleError(error, message, detail = {}) {\n const { identifier, controller, element } = this;\n detail = Object.assign({ identifier, controller, element }, detail);\n this.application.handleError(error, `Error ${message}`, detail);\n }\n targetConnected(element, name) {\n this.invokeControllerMethod(`${name}TargetConnected`, element);\n }\n targetDisconnected(element, name) {\n this.invokeControllerMethod(`${name}TargetDisconnected`, element);\n }\n outletConnected(outlet, element, name) {\n this.invokeControllerMethod(`${namespaceCamelize(name)}OutletConnected`, outlet, element);\n }\n outletDisconnected(outlet, element, name) {\n this.invokeControllerMethod(`${namespaceCamelize(name)}OutletDisconnected`, outlet, element);\n }\n invokeControllerMethod(methodName, ...args) {\n const controller = this.controller;\n if (typeof controller[methodName] == \"function\") {\n controller[methodName](...args);\n }\n }\n}\n\nfunction bless(constructor) {\n return shadow(constructor, getBlessedProperties(constructor));\n}\nfunction shadow(constructor, properties) {\n const shadowConstructor = extend(constructor);\n const shadowProperties = getShadowProperties(constructor.prototype, properties);\n Object.defineProperties(shadowConstructor.prototype, shadowProperties);\n return shadowConstructor;\n}\nfunction getBlessedProperties(constructor) {\n const blessings = readInheritableStaticArrayValues(constructor, \"blessings\");\n return blessings.reduce((blessedProperties, blessing) => {\n const properties = blessing(constructor);\n for (const key in properties) {\n const descriptor = blessedProperties[key] || {};\n blessedProperties[key] = Object.assign(descriptor, properties[key]);\n }\n return blessedProperties;\n }, {});\n}\nfunction getShadowProperties(prototype, properties) {\n return getOwnKeys(properties).reduce((shadowProperties, key) => {\n const descriptor = getShadowedDescriptor(prototype, properties, key);\n if (descriptor) {\n Object.assign(shadowProperties, { [key]: descriptor });\n }\n return shadowProperties;\n }, {});\n}\nfunction getShadowedDescriptor(prototype, properties, key) {\n const shadowingDescriptor = Object.getOwnPropertyDescriptor(prototype, key);\n const shadowedByValue = shadowingDescriptor && \"value\" in shadowingDescriptor;\n if (!shadowedByValue) {\n const descriptor = Object.getOwnPropertyDescriptor(properties, key).value;\n if (shadowingDescriptor) {\n descriptor.get = shadowingDescriptor.get || descriptor.get;\n descriptor.set = shadowingDescriptor.set || descriptor.set;\n }\n return descriptor;\n }\n}\nconst getOwnKeys = (() => {\n if (typeof Object.getOwnPropertySymbols == \"function\") {\n return (object) => [...Object.getOwnPropertyNames(object), ...Object.getOwnPropertySymbols(object)];\n }\n else {\n return Object.getOwnPropertyNames;\n }\n})();\nconst extend = (() => {\n function extendWithReflect(constructor) {\n function extended() {\n return Reflect.construct(constructor, arguments, new.target);\n }\n extended.prototype = Object.create(constructor.prototype, {\n constructor: { value: extended },\n });\n Reflect.setPrototypeOf(extended, constructor);\n return extended;\n }\n function testReflectExtension() {\n const a = function () {\n this.a.call(this);\n };\n const b = extendWithReflect(a);\n b.prototype.a = function () { };\n return new b();\n }\n try {\n testReflectExtension();\n return extendWithReflect;\n }\n catch (error) {\n return (constructor) => class extended extends constructor {\n };\n }\n})();\n\nfunction blessDefinition(definition) {\n return {\n identifier: definition.identifier,\n controllerConstructor: bless(definition.controllerConstructor),\n };\n}\n\nclass Module {\n constructor(application, definition) {\n this.application = application;\n this.definition = blessDefinition(definition);\n this.contextsByScope = new WeakMap();\n this.connectedContexts = new Set();\n }\n get identifier() {\n return this.definition.identifier;\n }\n get controllerConstructor() {\n return this.definition.controllerConstructor;\n }\n get contexts() {\n return Array.from(this.connectedContexts);\n }\n connectContextForScope(scope) {\n const context = this.fetchContextForScope(scope);\n this.connectedContexts.add(context);\n context.connect();\n }\n disconnectContextForScope(scope) {\n const context = this.contextsByScope.get(scope);\n if (context) {\n this.connectedContexts.delete(context);\n context.disconnect();\n }\n }\n fetchContextForScope(scope) {\n let context = this.contextsByScope.get(scope);\n if (!context) {\n context = new Context(this, scope);\n this.contextsByScope.set(scope, context);\n }\n return context;\n }\n}\n\nclass ClassMap {\n constructor(scope) {\n this.scope = scope;\n }\n has(name) {\n return this.data.has(this.getDataKey(name));\n }\n get(name) {\n return this.getAll(name)[0];\n }\n getAll(name) {\n const tokenString = this.data.get(this.getDataKey(name)) || \"\";\n return tokenize(tokenString);\n }\n getAttributeName(name) {\n return this.data.getAttributeNameForKey(this.getDataKey(name));\n }\n getDataKey(name) {\n return `${name}-class`;\n }\n get data() {\n return this.scope.data;\n }\n}\n\nclass DataMap {\n constructor(scope) {\n this.scope = scope;\n }\n get element() {\n return this.scope.element;\n }\n get identifier() {\n return this.scope.identifier;\n }\n get(key) {\n const name = this.getAttributeNameForKey(key);\n return this.element.getAttribute(name);\n }\n set(key, value) {\n const name = this.getAttributeNameForKey(key);\n this.element.setAttribute(name, value);\n return this.get(key);\n }\n has(key) {\n const name = this.getAttributeNameForKey(key);\n return this.element.hasAttribute(name);\n }\n delete(key) {\n if (this.has(key)) {\n const name = this.getAttributeNameForKey(key);\n this.element.removeAttribute(name);\n return true;\n }\n else {\n return false;\n }\n }\n getAttributeNameForKey(key) {\n return `data-${this.identifier}-${dasherize(key)}`;\n }\n}\n\nclass Guide {\n constructor(logger) {\n this.warnedKeysByObject = new WeakMap();\n this.logger = logger;\n }\n warn(object, key, message) {\n let warnedKeys = this.warnedKeysByObject.get(object);\n if (!warnedKeys) {\n warnedKeys = new Set();\n this.warnedKeysByObject.set(object, warnedKeys);\n }\n if (!warnedKeys.has(key)) {\n warnedKeys.add(key);\n this.logger.warn(message, object);\n }\n }\n}\n\nfunction attributeValueContainsToken(attributeName, token) {\n return `[${attributeName}~=\"${token}\"]`;\n}\n\nclass TargetSet {\n constructor(scope) {\n this.scope = scope;\n }\n get element() {\n return this.scope.element;\n }\n get identifier() {\n return this.scope.identifier;\n }\n get schema() {\n return this.scope.schema;\n }\n has(targetName) {\n return this.find(targetName) != null;\n }\n find(...targetNames) {\n return targetNames.reduce((target, targetName) => target || this.findTarget(targetName) || this.findLegacyTarget(targetName), undefined);\n }\n findAll(...targetNames) {\n return targetNames.reduce((targets, targetName) => [\n ...targets,\n ...this.findAllTargets(targetName),\n ...this.findAllLegacyTargets(targetName),\n ], []);\n }\n findTarget(targetName) {\n const selector = this.getSelectorForTargetName(targetName);\n return this.scope.findElement(selector);\n }\n findAllTargets(targetName) {\n const selector = this.getSelectorForTargetName(targetName);\n return this.scope.findAllElements(selector);\n }\n getSelectorForTargetName(targetName) {\n const attributeName = this.schema.targetAttributeForScope(this.identifier);\n return attributeValueContainsToken(attributeName, targetName);\n }\n findLegacyTarget(targetName) {\n const selector = this.getLegacySelectorForTargetName(targetName);\n return this.deprecate(this.scope.findElement(selector), targetName);\n }\n findAllLegacyTargets(targetName) {\n const selector = this.getLegacySelectorForTargetName(targetName);\n return this.scope.findAllElements(selector).map((element) => this.deprecate(element, targetName));\n }\n getLegacySelectorForTargetName(targetName) {\n const targetDescriptor = `${this.identifier}.${targetName}`;\n return attributeValueContainsToken(this.schema.targetAttribute, targetDescriptor);\n }\n deprecate(element, targetName) {\n if (element) {\n const { identifier } = this;\n const attributeName = this.schema.targetAttribute;\n const revisedAttributeName = this.schema.targetAttributeForScope(identifier);\n this.guide.warn(element, `target:${targetName}`, `Please replace ${attributeName}=\"${identifier}.${targetName}\" with ${revisedAttributeName}=\"${targetName}\". ` +\n `The ${attributeName} attribute is deprecated and will be removed in a future version of Stimulus.`);\n }\n return element;\n }\n get guide() {\n return this.scope.guide;\n }\n}\n\nclass OutletSet {\n constructor(scope, controllerElement) {\n this.scope = scope;\n this.controllerElement = controllerElement;\n }\n get element() {\n return this.scope.element;\n }\n get identifier() {\n return this.scope.identifier;\n }\n get schema() {\n return this.scope.schema;\n }\n has(outletName) {\n return this.find(outletName) != null;\n }\n find(...outletNames) {\n return outletNames.reduce((outlet, outletName) => outlet || this.findOutlet(outletName), undefined);\n }\n findAll(...outletNames) {\n return outletNames.reduce((outlets, outletName) => [...outlets, ...this.findAllOutlets(outletName)], []);\n }\n getSelectorForOutletName(outletName) {\n const attributeName = this.schema.outletAttributeForScope(this.identifier, outletName);\n return this.controllerElement.getAttribute(attributeName);\n }\n findOutlet(outletName) {\n const selector = this.getSelectorForOutletName(outletName);\n if (selector)\n return this.findElement(selector, outletName);\n }\n findAllOutlets(outletName) {\n const selector = this.getSelectorForOutletName(outletName);\n return selector ? this.findAllElements(selector, outletName) : [];\n }\n findElement(selector, outletName) {\n const elements = this.scope.queryElements(selector);\n return elements.filter((element) => this.matchesElement(element, selector, outletName))[0];\n }\n findAllElements(selector, outletName) {\n const elements = this.scope.queryElements(selector);\n return elements.filter((element) => this.matchesElement(element, selector, outletName));\n }\n matchesElement(element, selector, outletName) {\n const controllerAttribute = element.getAttribute(this.scope.schema.controllerAttribute) || \"\";\n return element.matches(selector) && controllerAttribute.split(\" \").includes(outletName);\n }\n}\n\nclass Scope {\n constructor(schema, element, identifier, logger) {\n this.targets = new TargetSet(this);\n this.classes = new ClassMap(this);\n this.data = new DataMap(this);\n this.containsElement = (element) => {\n return element.closest(this.controllerSelector) === this.element;\n };\n this.schema = schema;\n this.element = element;\n this.identifier = identifier;\n this.guide = new Guide(logger);\n this.outlets = new OutletSet(this.documentScope, element);\n }\n findElement(selector) {\n return this.element.matches(selector) ? this.element : this.queryElements(selector).find(this.containsElement);\n }\n findAllElements(selector) {\n return [\n ...(this.element.matches(selector) ? [this.element] : []),\n ...this.queryElements(selector).filter(this.containsElement),\n ];\n }\n queryElements(selector) {\n return Array.from(this.element.querySelectorAll(selector));\n }\n get controllerSelector() {\n return attributeValueContainsToken(this.schema.controllerAttribute, this.identifier);\n }\n get isDocumentScope() {\n return this.element === document.documentElement;\n }\n get documentScope() {\n return this.isDocumentScope\n ? this\n : new Scope(this.schema, document.documentElement, this.identifier, this.guide.logger);\n }\n}\n\nclass ScopeObserver {\n constructor(element, schema, delegate) {\n this.element = element;\n this.schema = schema;\n this.delegate = delegate;\n this.valueListObserver = new ValueListObserver(this.element, this.controllerAttribute, this);\n this.scopesByIdentifierByElement = new WeakMap();\n this.scopeReferenceCounts = new WeakMap();\n }\n start() {\n this.valueListObserver.start();\n }\n stop() {\n this.valueListObserver.stop();\n }\n get controllerAttribute() {\n return this.schema.controllerAttribute;\n }\n parseValueForToken(token) {\n const { element, content: identifier } = token;\n return this.parseValueForElementAndIdentifier(element, identifier);\n }\n parseValueForElementAndIdentifier(element, identifier) {\n const scopesByIdentifier = this.fetchScopesByIdentifierForElement(element);\n let scope = scopesByIdentifier.get(identifier);\n if (!scope) {\n scope = this.delegate.createScopeForElementAndIdentifier(element, identifier);\n scopesByIdentifier.set(identifier, scope);\n }\n return scope;\n }\n elementMatchedValue(element, value) {\n const referenceCount = (this.scopeReferenceCounts.get(value) || 0) + 1;\n this.scopeReferenceCounts.set(value, referenceCount);\n if (referenceCount == 1) {\n this.delegate.scopeConnected(value);\n }\n }\n elementUnmatchedValue(element, value) {\n const referenceCount = this.scopeReferenceCounts.get(value);\n if (referenceCount) {\n this.scopeReferenceCounts.set(value, referenceCount - 1);\n if (referenceCount == 1) {\n this.delegate.scopeDisconnected(value);\n }\n }\n }\n fetchScopesByIdentifierForElement(element) {\n let scopesByIdentifier = this.scopesByIdentifierByElement.get(element);\n if (!scopesByIdentifier) {\n scopesByIdentifier = new Map();\n this.scopesByIdentifierByElement.set(element, scopesByIdentifier);\n }\n return scopesByIdentifier;\n }\n}\n\nclass Router {\n constructor(application) {\n this.application = application;\n this.scopeObserver = new ScopeObserver(this.element, this.schema, this);\n this.scopesByIdentifier = new Multimap();\n this.modulesByIdentifier = new Map();\n }\n get element() {\n return this.application.element;\n }\n get schema() {\n return this.application.schema;\n }\n get logger() {\n return this.application.logger;\n }\n get controllerAttribute() {\n return this.schema.controllerAttribute;\n }\n get modules() {\n return Array.from(this.modulesByIdentifier.values());\n }\n get contexts() {\n return this.modules.reduce((contexts, module) => contexts.concat(module.contexts), []);\n }\n start() {\n this.scopeObserver.start();\n }\n stop() {\n this.scopeObserver.stop();\n }\n loadDefinition(definition) {\n this.unloadIdentifier(definition.identifier);\n const module = new Module(this.application, definition);\n this.connectModule(module);\n const afterLoad = definition.controllerConstructor.afterLoad;\n if (afterLoad) {\n afterLoad.call(definition.controllerConstructor, definition.identifier, this.application);\n }\n }\n unloadIdentifier(identifier) {\n const module = this.modulesByIdentifier.get(identifier);\n if (module) {\n this.disconnectModule(module);\n }\n }\n getContextForElementAndIdentifier(element, identifier) {\n const module = this.modulesByIdentifier.get(identifier);\n if (module) {\n return module.contexts.find((context) => context.element == element);\n }\n }\n proposeToConnectScopeForElementAndIdentifier(element, identifier) {\n const scope = this.scopeObserver.parseValueForElementAndIdentifier(element, identifier);\n if (scope) {\n this.scopeObserver.elementMatchedValue(scope.element, scope);\n }\n else {\n console.error(`Couldn't find or create scope for identifier: \"${identifier}\" and element:`, element);\n }\n }\n handleError(error, message, detail) {\n this.application.handleError(error, message, detail);\n }\n createScopeForElementAndIdentifier(element, identifier) {\n return new Scope(this.schema, element, identifier, this.logger);\n }\n scopeConnected(scope) {\n this.scopesByIdentifier.add(scope.identifier, scope);\n const module = this.modulesByIdentifier.get(scope.identifier);\n if (module) {\n module.connectContextForScope(scope);\n }\n }\n scopeDisconnected(scope) {\n this.scopesByIdentifier.delete(scope.identifier, scope);\n const module = this.modulesByIdentifier.get(scope.identifier);\n if (module) {\n module.disconnectContextForScope(scope);\n }\n }\n connectModule(module) {\n this.modulesByIdentifier.set(module.identifier, module);\n const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier);\n scopes.forEach((scope) => module.connectContextForScope(scope));\n }\n disconnectModule(module) {\n this.modulesByIdentifier.delete(module.identifier);\n const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier);\n scopes.forEach((scope) => module.disconnectContextForScope(scope));\n }\n}\n\nconst defaultSchema = {\n controllerAttribute: \"data-controller\",\n actionAttribute: \"data-action\",\n targetAttribute: \"data-target\",\n targetAttributeForScope: (identifier) => `data-${identifier}-target`,\n outletAttributeForScope: (identifier, outlet) => `data-${identifier}-${outlet}-outlet`,\n keyMappings: Object.assign(Object.assign({ enter: \"Enter\", tab: \"Tab\", esc: \"Escape\", space: \" \", up: \"ArrowUp\", down: \"ArrowDown\", left: \"ArrowLeft\", right: \"ArrowRight\", home: \"Home\", end: \"End\", page_up: \"PageUp\", page_down: \"PageDown\" }, objectFromEntries(\"abcdefghijklmnopqrstuvwxyz\".split(\"\").map((c) => [c, c]))), objectFromEntries(\"0123456789\".split(\"\").map((n) => [n, n]))),\n};\nfunction objectFromEntries(array) {\n return array.reduce((memo, [k, v]) => (Object.assign(Object.assign({}, memo), { [k]: v })), {});\n}\n\nclass Application {\n constructor(element = document.documentElement, schema = defaultSchema) {\n this.logger = console;\n this.debug = false;\n this.logDebugActivity = (identifier, functionName, detail = {}) => {\n if (this.debug) {\n this.logFormattedMessage(identifier, functionName, detail);\n }\n };\n this.element = element;\n this.schema = schema;\n this.dispatcher = new Dispatcher(this);\n this.router = new Router(this);\n this.actionDescriptorFilters = Object.assign({}, defaultActionDescriptorFilters);\n }\n static start(element, schema) {\n const application = new this(element, schema);\n application.start();\n return application;\n }\n async start() {\n await domReady();\n this.logDebugActivity(\"application\", \"starting\");\n this.dispatcher.start();\n this.router.start();\n this.logDebugActivity(\"application\", \"start\");\n }\n stop() {\n this.logDebugActivity(\"application\", \"stopping\");\n this.dispatcher.stop();\n this.router.stop();\n this.logDebugActivity(\"application\", \"stop\");\n }\n register(identifier, controllerConstructor) {\n this.load({ identifier, controllerConstructor });\n }\n registerActionOption(name, filter) {\n this.actionDescriptorFilters[name] = filter;\n }\n load(head, ...rest) {\n const definitions = Array.isArray(head) ? head : [head, ...rest];\n definitions.forEach((definition) => {\n if (definition.controllerConstructor.shouldLoad) {\n this.router.loadDefinition(definition);\n }\n });\n }\n unload(head, ...rest) {\n const identifiers = Array.isArray(head) ? head : [head, ...rest];\n identifiers.forEach((identifier) => this.router.unloadIdentifier(identifier));\n }\n get controllers() {\n return this.router.contexts.map((context) => context.controller);\n }\n getControllerForElementAndIdentifier(element, identifier) {\n const context = this.router.getContextForElementAndIdentifier(element, identifier);\n return context ? context.controller : null;\n }\n handleError(error, message, detail) {\n var _a;\n this.logger.error(`%s\\n\\n%o\\n\\n%o`, message, error, detail);\n (_a = window.onerror) === null || _a === void 0 ? void 0 : _a.call(window, message, \"\", 0, 0, error);\n }\n logFormattedMessage(identifier, functionName, detail = {}) {\n detail = Object.assign({ application: this }, detail);\n this.logger.groupCollapsed(`${identifier} #${functionName}`);\n this.logger.log(\"details:\", Object.assign({}, detail));\n this.logger.groupEnd();\n }\n}\nfunction domReady() {\n return new Promise((resolve) => {\n if (document.readyState == \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", () => resolve());\n }\n else {\n resolve();\n }\n });\n}\n\nfunction ClassPropertiesBlessing(constructor) {\n const classes = readInheritableStaticArrayValues(constructor, \"classes\");\n return classes.reduce((properties, classDefinition) => {\n return Object.assign(properties, propertiesForClassDefinition(classDefinition));\n }, {});\n}\nfunction propertiesForClassDefinition(key) {\n return {\n [`${key}Class`]: {\n get() {\n const { classes } = this;\n if (classes.has(key)) {\n return classes.get(key);\n }\n else {\n const attribute = classes.getAttributeName(key);\n throw new Error(`Missing attribute \"${attribute}\"`);\n }\n },\n },\n [`${key}Classes`]: {\n get() {\n return this.classes.getAll(key);\n },\n },\n [`has${capitalize(key)}Class`]: {\n get() {\n return this.classes.has(key);\n },\n },\n };\n}\n\nfunction OutletPropertiesBlessing(constructor) {\n const outlets = readInheritableStaticArrayValues(constructor, \"outlets\");\n return outlets.reduce((properties, outletDefinition) => {\n return Object.assign(properties, propertiesForOutletDefinition(outletDefinition));\n }, {});\n}\nfunction getOutletController(controller, element, identifier) {\n return controller.application.getControllerForElementAndIdentifier(element, identifier);\n}\nfunction getControllerAndEnsureConnectedScope(controller, element, outletName) {\n let outletController = getOutletController(controller, element, outletName);\n if (outletController)\n return outletController;\n controller.application.router.proposeToConnectScopeForElementAndIdentifier(element, outletName);\n outletController = getOutletController(controller, element, outletName);\n if (outletController)\n return outletController;\n}\nfunction propertiesForOutletDefinition(name) {\n const camelizedName = namespaceCamelize(name);\n return {\n [`${camelizedName}Outlet`]: {\n get() {\n const outletElement = this.outlets.find(name);\n const selector = this.outlets.getSelectorForOutletName(name);\n if (outletElement) {\n const outletController = getControllerAndEnsureConnectedScope(this, outletElement, name);\n if (outletController)\n return outletController;\n throw new Error(`The provided outlet element is missing an outlet controller \"${name}\" instance for host controller \"${this.identifier}\"`);\n }\n throw new Error(`Missing outlet element \"${name}\" for host controller \"${this.identifier}\". Stimulus couldn't find a matching outlet element using selector \"${selector}\".`);\n },\n },\n [`${camelizedName}Outlets`]: {\n get() {\n const outlets = this.outlets.findAll(name);\n if (outlets.length > 0) {\n return outlets\n .map((outletElement) => {\n const outletController = getControllerAndEnsureConnectedScope(this, outletElement, name);\n if (outletController)\n return outletController;\n console.warn(`The provided outlet element is missing an outlet controller \"${name}\" instance for host controller \"${this.identifier}\"`, outletElement);\n })\n .filter((controller) => controller);\n }\n return [];\n },\n },\n [`${camelizedName}OutletElement`]: {\n get() {\n const outletElement = this.outlets.find(name);\n const selector = this.outlets.getSelectorForOutletName(name);\n if (outletElement) {\n return outletElement;\n }\n else {\n throw new Error(`Missing outlet element \"${name}\" for host controller \"${this.identifier}\". Stimulus couldn't find a matching outlet element using selector \"${selector}\".`);\n }\n },\n },\n [`${camelizedName}OutletElements`]: {\n get() {\n return this.outlets.findAll(name);\n },\n },\n [`has${capitalize(camelizedName)}Outlet`]: {\n get() {\n return this.outlets.has(name);\n },\n },\n };\n}\n\nfunction TargetPropertiesBlessing(constructor) {\n const targets = readInheritableStaticArrayValues(constructor, \"targets\");\n return targets.reduce((properties, targetDefinition) => {\n return Object.assign(properties, propertiesForTargetDefinition(targetDefinition));\n }, {});\n}\nfunction propertiesForTargetDefinition(name) {\n return {\n [`${name}Target`]: {\n get() {\n const target = this.targets.find(name);\n if (target) {\n return target;\n }\n else {\n throw new Error(`Missing target element \"${name}\" for \"${this.identifier}\" controller`);\n }\n },\n },\n [`${name}Targets`]: {\n get() {\n return this.targets.findAll(name);\n },\n },\n [`has${capitalize(name)}Target`]: {\n get() {\n return this.targets.has(name);\n },\n },\n };\n}\n\nfunction ValuePropertiesBlessing(constructor) {\n const valueDefinitionPairs = readInheritableStaticObjectPairs(constructor, \"values\");\n const propertyDescriptorMap = {\n valueDescriptorMap: {\n get() {\n return valueDefinitionPairs.reduce((result, valueDefinitionPair) => {\n const valueDescriptor = parseValueDefinitionPair(valueDefinitionPair, this.identifier);\n const attributeName = this.data.getAttributeNameForKey(valueDescriptor.key);\n return Object.assign(result, { [attributeName]: valueDescriptor });\n }, {});\n },\n },\n };\n return valueDefinitionPairs.reduce((properties, valueDefinitionPair) => {\n return Object.assign(properties, propertiesForValueDefinitionPair(valueDefinitionPair));\n }, propertyDescriptorMap);\n}\nfunction propertiesForValueDefinitionPair(valueDefinitionPair, controller) {\n const definition = parseValueDefinitionPair(valueDefinitionPair, controller);\n const { key, name, reader: read, writer: write } = definition;\n return {\n [name]: {\n get() {\n const value = this.data.get(key);\n if (value !== null) {\n return read(value);\n }\n else {\n return definition.defaultValue;\n }\n },\n set(value) {\n if (value === undefined) {\n this.data.delete(key);\n }\n else {\n this.data.set(key, write(value));\n }\n },\n },\n [`has${capitalize(name)}`]: {\n get() {\n return this.data.has(key) || definition.hasCustomDefaultValue;\n },\n },\n };\n}\nfunction parseValueDefinitionPair([token, typeDefinition], controller) {\n return valueDescriptorForTokenAndTypeDefinition({\n controller,\n token,\n typeDefinition,\n });\n}\nfunction parseValueTypeConstant(constant) {\n switch (constant) {\n case Array:\n return \"array\";\n case Boolean:\n return \"boolean\";\n case Number:\n return \"number\";\n case Object:\n return \"object\";\n case String:\n return \"string\";\n }\n}\nfunction parseValueTypeDefault(defaultValue) {\n switch (typeof defaultValue) {\n case \"boolean\":\n return \"boolean\";\n case \"number\":\n return \"number\";\n case \"string\":\n return \"string\";\n }\n if (Array.isArray(defaultValue))\n return \"array\";\n if (Object.prototype.toString.call(defaultValue) === \"[object Object]\")\n return \"object\";\n}\nfunction parseValueTypeObject(payload) {\n const { controller, token, typeObject } = payload;\n const hasType = isSomething(typeObject.type);\n const hasDefault = isSomething(typeObject.default);\n const fullObject = hasType && hasDefault;\n const onlyType = hasType && !hasDefault;\n const onlyDefault = !hasType && hasDefault;\n const typeFromObject = parseValueTypeConstant(typeObject.type);\n const typeFromDefaultValue = parseValueTypeDefault(payload.typeObject.default);\n if (onlyType)\n return typeFromObject;\n if (onlyDefault)\n return typeFromDefaultValue;\n if (typeFromObject !== typeFromDefaultValue) {\n const propertyPath = controller ? `${controller}.${token}` : token;\n throw new Error(`The specified default value for the Stimulus Value \"${propertyPath}\" must match the defined type \"${typeFromObject}\". The provided default value of \"${typeObject.default}\" is of type \"${typeFromDefaultValue}\".`);\n }\n if (fullObject)\n return typeFromObject;\n}\nfunction parseValueTypeDefinition(payload) {\n const { controller, token, typeDefinition } = payload;\n const typeObject = { controller, token, typeObject: typeDefinition };\n const typeFromObject = parseValueTypeObject(typeObject);\n const typeFromDefaultValue = parseValueTypeDefault(typeDefinition);\n const typeFromConstant = parseValueTypeConstant(typeDefinition);\n const type = typeFromObject || typeFromDefaultValue || typeFromConstant;\n if (type)\n return type;\n const propertyPath = controller ? `${controller}.${typeDefinition}` : token;\n throw new Error(`Unknown value type \"${propertyPath}\" for \"${token}\" value`);\n}\nfunction defaultValueForDefinition(typeDefinition) {\n const constant = parseValueTypeConstant(typeDefinition);\n if (constant)\n return defaultValuesByType[constant];\n const hasDefault = hasProperty(typeDefinition, \"default\");\n const hasType = hasProperty(typeDefinition, \"type\");\n const typeObject = typeDefinition;\n if (hasDefault)\n return typeObject.default;\n if (hasType) {\n const { type } = typeObject;\n const constantFromType = parseValueTypeConstant(type);\n if (constantFromType)\n return defaultValuesByType[constantFromType];\n }\n return typeDefinition;\n}\nfunction valueDescriptorForTokenAndTypeDefinition(payload) {\n const { token, typeDefinition } = payload;\n const key = `${dasherize(token)}-value`;\n const type = parseValueTypeDefinition(payload);\n return {\n type,\n key,\n name: camelize(key),\n get defaultValue() {\n return defaultValueForDefinition(typeDefinition);\n },\n get hasCustomDefaultValue() {\n return parseValueTypeDefault(typeDefinition) !== undefined;\n },\n reader: readers[type],\n writer: writers[type] || writers.default,\n };\n}\nconst defaultValuesByType = {\n get array() {\n return [];\n },\n boolean: false,\n number: 0,\n get object() {\n return {};\n },\n string: \"\",\n};\nconst readers = {\n array(value) {\n const array = JSON.parse(value);\n if (!Array.isArray(array)) {\n throw new TypeError(`expected value of type \"array\" but instead got value \"${value}\" of type \"${parseValueTypeDefault(array)}\"`);\n }\n return array;\n },\n boolean(value) {\n return !(value == \"0\" || String(value).toLowerCase() == \"false\");\n },\n number(value) {\n return Number(value.replace(/_/g, \"\"));\n },\n object(value) {\n const object = JSON.parse(value);\n if (object === null || typeof object != \"object\" || Array.isArray(object)) {\n throw new TypeError(`expected value of type \"object\" but instead got value \"${value}\" of type \"${parseValueTypeDefault(object)}\"`);\n }\n return object;\n },\n string(value) {\n return value;\n },\n};\nconst writers = {\n default: writeString,\n array: writeJSON,\n object: writeJSON,\n};\nfunction writeJSON(value) {\n return JSON.stringify(value);\n}\nfunction writeString(value) {\n return `${value}`;\n}\n\nclass Controller {\n constructor(context) {\n this.context = context;\n }\n static get shouldLoad() {\n return true;\n }\n static afterLoad(_identifier, _application) {\n return;\n }\n get application() {\n return this.context.application;\n }\n get scope() {\n return this.context.scope;\n }\n get element() {\n return this.scope.element;\n }\n get identifier() {\n return this.scope.identifier;\n }\n get targets() {\n return this.scope.targets;\n }\n get outlets() {\n return this.scope.outlets;\n }\n get classes() {\n return this.scope.classes;\n }\n get data() {\n return this.scope.data;\n }\n initialize() {\n }\n connect() {\n }\n disconnect() {\n }\n dispatch(eventName, { target = this.element, detail = {}, prefix = this.identifier, bubbles = true, cancelable = true, } = {}) {\n const type = prefix ? `${prefix}:${eventName}` : eventName;\n const event = new CustomEvent(type, { detail, bubbles, cancelable });\n target.dispatchEvent(event);\n return event;\n }\n}\nController.blessings = [\n ClassPropertiesBlessing,\n TargetPropertiesBlessing,\n ValuePropertiesBlessing,\n OutletPropertiesBlessing,\n];\nController.targets = [];\nController.outlets = [];\nController.values = {};\n\nexport { Application, AttributeObserver, Context, Controller, ElementObserver, IndexedMultimap, Multimap, SelectorObserver, StringMapObserver, TokenListObserver, ValueListObserver, add, defaultSchema, del, fetch, prune };\n","import { Application } from \"@hotwired/stimulus\"\nimport { log } from \"../logger.js\"\nimport { cacheBustedUrl, reloadHtmlDocument } from \"../helpers.js\"\n\nexport class StimulusReloader {\n static async reload(filePattern) {\n const document = await reloadHtmlDocument()\n return new StimulusReloader(document, filePattern).reload()\n }\n\n constructor(document, filePattern = /./) {\n this.document = document\n this.filePattern = filePattern\n this.application = window.Stimulus || Application.start()\n }\n\n async reload() {\n log(\"Reload Stimulus controllers...\")\n\n this.application.stop()\n await this.#reloadStimulusControllers()\n this.application.start()\n }\n\n async #reloadStimulusControllers() {\n await Promise.all(\n this.#stimulusControllerPaths.map(async moduleName => this.#reloadStimulusController(moduleName))\n )\n }\n\n get #stimulusControllerPaths() {\n return Object.keys(this.#stimulusPathsByModule).filter(path => path.endsWith(\"_controller\") && this.#shouldReloadController(path))\n }\n\n #shouldReloadController(path) {\n return this.filePattern.test(path)\n }\n\n get #stimulusPathsByModule() {\n this.pathsByModule = this.pathsByModule || this.#parseImportmapJson()\n return this.pathsByModule\n }\n\n #parseImportmapJson() {\n const importmapScript = this.document.querySelector(\"script[type=importmap]\")\n return JSON.parse(importmapScript.text).imports\n }\n\n async #reloadStimulusController(moduleName) {\n log(`\\t${moduleName}`)\n\n const controllerName = this.#extractControllerName(moduleName)\n const path = cacheBustedUrl(this.#pathForModuleName(moduleName))\n\n const module = await import(path)\n\n this.#registerController(controllerName, module)\n }\n\n #pathForModuleName(moduleName) {\n return this.#stimulusPathsByModule[moduleName]\n }\n\n #extractControllerName(path) {\n return path\n .replace(/^.*\\//, \"\")\n .replace(\"_controller\", \"\")\n .replace(/\\//g, \"--\")\n .replace(/_/g, \"-\")\n }\n\n #registerController(name, module) {\n this.application.unload(name)\n this.application.register(name, module.default)\n }\n}\n","import { Idiomorph } from \"idiomorph/dist/idiomorph.esm.js\"\nimport { log } from \"../logger.js\"\nimport { reloadHtmlDocument } from \"../helpers.js\"\nimport { StimulusReloader } from \"./stimulus_reloader.js\"\n\nexport class HtmlReloader {\n static async reload() {\n return new HtmlReloader().reload()\n }\n\n async reload() {\n const reloadedDocument = await this.#reloadHtml()\n await this.#reloadStimulus(reloadedDocument)\n }\n\n async #reloadHtml() {\n log(\"Reload html...\")\n\n const reloadedDocument = await reloadHtmlDocument()\n this.#updateBody(reloadedDocument.body)\n return reloadedDocument\n }\n\n #updateBody(newBody) {\n Idiomorph.morph(document.body, newBody)\n }\n\n async #reloadStimulus(reloadedDocument) {\n return new StimulusReloader(reloadedDocument).reload()\n }\n}\n","import { log } from \"../logger.js\"\nimport { cacheBustedUrl, reloadHtmlDocument, pathWithoutAssetDigest } from \"../helpers.js\"\n\nexport class CssReloader {\n static async reload(...params) {\n return new CssReloader(...params).reload()\n }\n\n constructor(filePattern = /./) {\n this.filePattern = filePattern\n }\n\n async reload() {\n log(\"Reload css...\")\n await Promise.all(await this.#reloadAllLinks())\n }\n\n async #reloadAllLinks() {\n const cssLinks = await this.#loadNewCssLinks();\n return cssLinks.map(link => this.#reloadLinkIfNeeded(link))\n }\n\n async #loadNewCssLinks() {\n const reloadedDocument = await reloadHtmlDocument()\n return Array.from(reloadedDocument.head.querySelectorAll(\"link[rel='stylesheet']\"))\n }\n\n #reloadLinkIfNeeded(link) {\n if (this.#shouldReloadLink(link)) {\n return this.#reloadLink(link)\n } else {\n return Promise.resolve()\n }\n }\n\n #shouldReloadLink(link) {\n return this.filePattern.test(link.getAttribute(\"href\"))\n }\n\n async #reloadLink(link) {\n return new Promise(resolve => {\n const href = link.getAttribute(\"href\")\n const newLink = this.#findExistingLinkFor(link) || this.#appendNewLink(link)\n\n newLink.setAttribute(\"href\", cacheBustedUrl(link.getAttribute(\"href\")))\n newLink.onload = () => {\n log(`\\t${href}`)\n resolve()\n }\n })\n }\n\n #findExistingLinkFor(link) {\n return this.#cssLinks.find(newLink => pathWithoutAssetDigest(link.href) === pathWithoutAssetDigest(newLink.href))\n }\n\n get #cssLinks() {\n return Array.from(document.querySelectorAll(\"link[rel='stylesheet']\"))\n }\n\n #appendNewLink(link) {\n document.head.append(link)\n return link\n }\n}\n","import consumer from \"./consumer\"\nimport { assetNameFromPath } from \"../helpers.js\";\nimport { HtmlReloader } from \"../reloaders/html_reloader.js\";\nimport { CssReloader } from \"../reloaders/css_reloader.js\";\nimport { StimulusReloader } from \"../reloaders/stimulus_reloader.js\";\n\nconsumer.subscriptions.create({ channel: \"Hotwire::Spark::Channel\" }, {\n connected() {\n document.body.setAttribute(\"data-hotwire-spark-ready\", \"\")\n },\n\n async received(message) {\n try {\n await this.dispatch(message)\n } catch(error) {\n console.log(`Error on ${message.action}`, error)\n }\n },\n\n dispatch({ action, path }) {\n const fileName = assetNameFromPath(path)\n\n switch(action) {\n case \"reload_html\":\n return this.reloadHtml()\n case \"reload_css\":\n return this.reloadCss(fileName)\n case \"reload_stimulus\":\n return this.reloadStimulus(fileName)\n default:\n throw new Error(`Unknown action: ${action}`)\n }\n },\n\n reloadHtml() {\n return HtmlReloader.reload()\n },\n\n reloadCss(fileName) {\n return CssReloader.reload(new RegExp(fileName))\n },\n\n reloadStimulus(fileName) {\n return StimulusReloader.reload(new RegExp(fileName))\n }\n})\n\n","import \"./channels/monitoring_channel.js\"\nimport { getConfigurationProperty } from \"./helpers.js\";\n\nconst HotwireSpark = {\n config: {\n loggingEnabled: false \n }\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", function() {\n HotwireSpark.config.loggingEnabled = getConfigurationProperty(\"logging\");\n})\n\nexport default HotwireSpark\n"],"names":["adapters","logger","console","undefined","WebSocket","log","messages","this","enabled","push","Date","now","getTime","secondsSince","time","ConnectionMonitor","constructor","connection","visibilityDidChange","bind","reconnectAttempts","start","isRunning","startedAt","stoppedAt","startPolling","addEventListener","staleThreshold","stop","stopPolling","removeEventListener","recordMessage","pingedAt","recordConnect","disconnectedAt","recordDisconnect","poll","clearTimeout","pollTimeout","setTimeout","reconnectIfStale","getPollInterval","reconnectionBackoffRate","Math","pow","min","random","connectionIsStale","refreshedAt","disconnectedRecently","reopen","document","visibilityState","isOpen","INTERNAL","message_types","welcome","disconnect","ping","confirmation","rejection","disconnect_reasons","unauthorized","invalid_request","server_restart","remote","default_mount_path","protocols","supportedProtocols","slice","length","indexOf","Connection","consumer","open","subscriptions","monitor","disconnected","send","data","webSocket","JSON","stringify","isActive","getState","socketProtocols","subprotocols","uninstallEventHandlers","url","installEventHandlers","close","allowReconnect","error","reopenDelay","getProtocol","protocol","isState","triedToReconnect","isProtocolSupported","call","states","state","readyState","toLowerCase","eventName","events","handler","prototype","message","event","identifier","reason","reconnect","type","parse","reconnectAttempted","reload","confirmSubscription","notify","reconnected","reject","notifyAll","willAttemptReconnect","Subscription","params","mixin","object","properties","key","value","extend","perform","action","command","unsubscribe","remove","SubscriptionGuarantor","pendingSubscriptions","guarantee","subscription","startGuaranteeing","forget","filter","s","stopGuaranteeing","retrySubscribing","retryTimeout","subscribe","map","Subscriptions","guarantor","create","channelName","channel","add","ensureActiveConnection","findAll","sendCommand","callbackName","args","Consumer","_url","test","a","createElement","href","replace","createWebSocketURL","connect","addSubProtocol","subprotocol","name","element","head","querySelector","getAttribute","getConfig","createConsumer","pathWithoutAssetDigest","path","urlWithParams","urlString","URL","window","location","origin","Object","entries","forEach","_ref","searchParams","set","toString","cacheBustedUrl","async","reloadHtmlDocument","currentUrl","hotwire_spark","response","fetch","ok","Error","status","fetchedHTML","text","DOMParser","parseFromString","Idiomorph","EMPTY_SET","Set","defaults","morphStyle","callbacks","beforeNodeAdded","noOp","afterNodeAdded","beforeNodeMorphed","afterNodeMorphed","beforeNodeRemoved","afterNodeRemoved","beforeAttributeUpdated","style","shouldPreserve","elt","shouldReAppend","shouldRemove","afterHeadMorphed","morphNormalizedContent","oldNode","normalizedNewContent","ctx","block","oldHead","newHead","promises","handleHeadElement","Promise","all","then","assign","ignore","morphChildren","children","bestMatch","newContent","currentElement","firstChild","bestElement","score","newScore","scoreElement","nextSibling","findBestNodeMatch","previousSibling","morphedNode","morphOldNodeTo","stack","added","node","pop","parentElement","insertBefore","insertSiblings","ignoreValueOfActiveElement","possibleActiveElement","ignoreActiveValue","activeElement","ignoreActive","isSoftMatch","HTMLHeadElement","from","to","nodeType","fromAttributes","attributes","toAttributes","fromAttribute","ignoreAttribute","setAttribute","i","toAttribute","hasAttribute","removeAttribute","nodeValue","HTMLInputElement","fromValue","toValue","syncBooleanAttribute","HTMLOptionElement","HTMLTextAreaElement","syncInputValue","syncNodeFrom","replaceChild","newParent","oldParent","newChild","nextNewChild","insertionPoint","appendChild","removeIdsFromConsideration","isIdSetMatch","idSetMatch","findIdSetMatch","removeNodesBetween","softMatch","findSoftMatch","tempNode","removeNode","attr","updateType","attributeName","ignoreUpdate","newHeadTag","currentHead","removed","preserved","nodesToAppend","headMergeStyle","srcToNewHeadNodes","Map","newHeadChild","outerHTML","currentHeadElt","inNewContent","has","isReAppended","isPreserved","delete","values","newNode","newElt","createRange","createContextualFragment","src","resolve","promise","_resolve","removedElement","removeChild","kept","node1","node2","tagName","id","getIdIntersectionCount","startInclusive","endExclusive","newChildPotentialIdCount","potentialMatch","otherMatchCount","potentialSoftMatch","siblingSoftMatchCount","isIdInConsideration","deadIds","idIsWithinNode","targetNode","idMap","get","idSet","sourceSet","matchCount","populateIdMapForNode","nodeParent","idElements","querySelectorAll","current","createIdMap","oldContent","morph","config","Document","documentElement","parser","contentWithSvgsRemoved","match","content","generatedByIdiomorph","htmlElement","body","parseContent","normalizedContent","Node","dummyParent","append","normalizeContent","finalConfig","mergeDefaults","target","createMorphContext","HotwireSpark","loggingEnabled","_len","arguments","Array","_key","EventListener","eventTarget","eventOptions","unorderedBindings","bindingConnected","binding","bindingDisconnected","handleEvent","extendedEvent","stopImmediatePropagation","immediatePropagationStopped","extendEvent","bindings","hasBindings","size","sort","left","right","leftIndex","index","rightIndex","Dispatcher","application","eventListenerMaps","started","eventListeners","eventListener","reduce","listeners","concat","fetchEventListenerForBinding","clearEventListeners","clearEventListenersForBinding","handleError","detail","removeMappedEventListenerFor","eventListenerMap","fetchEventListenerMapForEventTarget","cacheKey","fetchEventListener","createEventListener","parts","keys","join","defaultActionDescriptorFilters","stopPropagation","prevent","preventDefault","self","descriptorPattern","parseEventTarget","eventTargetName","camelize","_","char","toUpperCase","namespaceCamelize","allModifiers","Action","descriptor","schema","defaultEventNames","getDefaultEventNameForElement","methodName","keyFilter","forToken","token","descriptorString","matches","trim","includes","split","options","parseActionDescriptorString","eventFilter","shouldIgnoreKeyboardEvent","filters","keyFilterDissatisfied","standardFilter","keyMappings","property","hasOwnProperty","shouldIgnoreMouseEvent","pattern","RegExp","typecast","meta","ctrl","alt","shift","modifier","metaKey","ctrlKey","altKey","shiftKey","button","form","details","input","e","select","textarea","o_O","Binding","context","actionEvent","prepareActionEvent","willBeInvokedByEvent","applyEventModifiers","invokeWithEvent","method","controller","actionDescriptorFilters","passes","currentTarget","logDebugActivity","KeyboardEvent","MouseEvent","Element","contains","scope","containsElement","ElementObserver","delegate","mutationObserverInit","childList","subtree","elements","mutationObserver","MutationObserver","mutations","processMutations","observe","refresh","pause","callback","takeRecords","matchElementsInTree","removeElement","addElement","mutation","processMutation","processAttributeChange","processRemovedNodes","removedNodes","processAddedNodes","addedNodes","elementAttributeChanged","matchElement","nodes","elementFromNode","processTree","elementIsActive","tree","processor","ELEMENT_NODE","isConnected","elementMatched","elementUnmatched","AttributeObserver","elementObserver","selector","elementMatchedAttribute","elementUnmatchedAttribute","elementAttributeValueChanged","Multimap","valuesByKey","prune","del","hasKey","hasValue","some","getValuesForKey","getKeysForValue","_values","SelectorObserver","_selector","matchesByElement","selectorMatchElement","selectorMatched","selectors","selectorUnmatched","_attributeName","matchedBefore","StringMapObserver","stringMap","attributeOldValue","knownAttributeNames","refreshAttribute","oldValue","getStringMapKeyForAttribute","stringMapKeyAdded","stringMapValueChanged","stringMapKeyRemoved","currentAttributeNames","recordedAttributeNames","attribute","TokenListObserver","attributeObserver","tokensByElement","tokensMatched","readTokensForElement","unmatchedTokens","matchedTokens","refreshTokensForElement","tokensUnmatched","tokens","tokenMatched","tokenUnmatched","previousTokens","currentTokens","firstDifferingIndex","max","zip","findIndex","previousToken","currentToken","tokenString","parseTokenString","ValueListObserver","tokenListObserver","parseResultsByToken","WeakMap","valuesByTokenByElement","fetchParseResultForToken","fetchValuesByTokenForElement","elementMatchedValue","elementUnmatchedValue","parseResult","parseToken","valuesByToken","parseValueForToken","BindingObserver","bindingsByAction","valueListObserver","actionAttribute","disconnectAllActions","connectAction","disconnectAction","clear","ValueObserver","receiver","stringMapObserver","valueDescriptorMap","invokeChangedCallbacksForDefaultValues","invokeChangedCallback","writer","defaultValue","valueDescriptorNameMap","valueDescriptors","rawValue","rawOldValue","changedMethodName","changedMethod","reader","TypeError","descriptors","hasMethodName","charAt","TargetObserver","targetsByName","disconnectAllTargets","connectTarget","disconnectTarget","_a","targetConnected","targetDisconnected","readInheritableStaticArrayValues","propertyName","ancestors","getPrototypeOf","reverse","getAncestorsForConstructor","definition","isArray","getOwnStaticArrayValues","OutletObserver","outletsByName","outletElementsByName","selectorObserverMap","attributeObserverMap","outletDefinitions","outletName","setupSelectorObserverForOutlet","setupAttributeObserverForOutlet","dependentContexts","observer","disconnectAllOutlets","stopSelectorObservers","stopAttributeObservers","outlet","getOutlet","connectOutlet","getOutletFromMap","disconnectOutlet","hasOutlet","hasOutletController","controllerAttribute","_element","getOutletNameFromOutletAttributeName","updateSelectorObserverForOutlet","outletConnected","outletDisconnected","selectorObserver","attributeNameForOutletName","outlets","getSelectorForOutletName","outletAttributeForScope","find","outletDependencies","dependencies","router","modules","module","controllerConstructor","dependentControllerIdentifiers","identifiers","contexts","getControllerForElementAndIdentifier","Context","functionName","bindingObserver","dispatcher","valueObserver","targetObserver","outletObserver","initialize","invokeControllerMethod","bless","shadowConstructor","shadowProperties","getOwnKeys","shadowingDescriptor","getOwnPropertyDescriptor","getShadowedDescriptor","getShadowProperties","defineProperties","shadow","blessings","blessedProperties","blessing","getBlessedProperties","getOwnPropertySymbols","getOwnPropertyNames","extendWithReflect","extended","Reflect","construct","setPrototypeOf","b","testReflectExtension","Module","blessDefinition","contextsByScope","connectedContexts","connectContextForScope","fetchContextForScope","disconnectContextForScope","ClassMap","getDataKey","getAll","getAttributeName","getAttributeNameForKey","DataMap","Guide","warnedKeysByObject","warn","warnedKeys","attributeValueContainsToken","TargetSet","targetName","targetNames","findTarget","findLegacyTarget","targets","findAllTargets","findAllLegacyTargets","getSelectorForTargetName","findElement","findAllElements","targetAttributeForScope","getLegacySelectorForTargetName","deprecate","targetDescriptor","targetAttribute","revisedAttributeName","guide","OutletSet","controllerElement","outletNames","findOutlet","findAllOutlets","queryElements","matchesElement","Scope","classes","closest","controllerSelector","documentScope","isDocumentScope","ScopeObserver","scopesByIdentifierByElement","scopeReferenceCounts","parseValueForElementAndIdentifier","scopesByIdentifier","fetchScopesByIdentifierForElement","createScopeForElementAndIdentifier","referenceCount","scopeConnected","scopeDisconnected","Router","scopeObserver","modulesByIdentifier","loadDefinition","unloadIdentifier","connectModule","afterLoad","disconnectModule","getContextForElementAndIdentifier","proposeToConnectScopeForElementAndIdentifier","defaultSchema","enter","tab","esc","space","up","down","home","end","page_up","page_down","objectFromEntries","c","n","array","memo","k","v","Application","debug","logFormattedMessage","register","load","registerActionOption","rest","shouldLoad","unload","controllers","onerror","groupCollapsed","groupEnd","StimulusReloader","filePattern","Stimulus","reloadStimulusControllers","stimulusControllerPaths","reloadStimulusController","moduleName","stimulusPathsByModule","endsWith","shouldReloadController","pathsByModule","parseImportmapJson","importmapScript","imports","controllerName","extractControllerName","pathForModuleName","import","registerController","default","HtmlReloader","reloadedDocument","reloadHtml","reloadStimulus","updateBody","newBody","CssReloader","reloadAllLinks","loadNewCssLinks","link","reloadLinkIfNeeded","shouldReloadLink","reloadLink","newLink","findExistingLinkFor","appendNewLink","onload","cssLinks","connected","received","dispatch","fileName","assetNameFromPath","reloadCss"],"mappings":"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","x_google_ignoreList":[0,3,5]} \ No newline at end of file diff --git a/app/assets/stylesheets/pulse_wire/application.css b/app/assets/stylesheets/hotwire_spark/application.css similarity index 100% rename from app/assets/stylesheets/pulse_wire/application.css rename to app/assets/stylesheets/hotwire_spark/application.css diff --git a/app/channels/hotwire/spark/channel.rb b/app/channels/hotwire/spark/channel.rb new file mode 100644 index 00000000..c7da8cc2 --- /dev/null +++ b/app/channels/hotwire/spark/channel.rb @@ -0,0 +1,5 @@ +class Hotwire::Spark::Channel < ActionCable::Channel::Base + def subscribed + stream_from "hotwire_spark" + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/controllers/pulse_wire/application_controller.rb b/app/controllers/pulse_wire/application_controller.rb deleted file mode 100644 index 5d3f73b9..00000000 --- a/app/controllers/pulse_wire/application_controller.rb +++ /dev/null @@ -1,4 +0,0 @@ -module PulseWire - class ApplicationController < ActionController::Base - end -end diff --git a/app/helpers/pulse_wire/application_helper.rb b/app/helpers/pulse_wire/application_helper.rb deleted file mode 100644 index 45746ed7..00000000 --- a/app/helpers/pulse_wire/application_helper.rb +++ /dev/null @@ -1,4 +0,0 @@ -module PulseWire - module ApplicationHelper - end -end diff --git a/app/javascript/hotwire/spark/channels/consumer.js b/app/javascript/hotwire/spark/channels/consumer.js new file mode 100644 index 00000000..71213f88 --- /dev/null +++ b/app/javascript/hotwire/spark/channels/consumer.js @@ -0,0 +1,3 @@ +import { createConsumer } from "@rails/actioncable" + +export default createConsumer() diff --git a/app/javascript/hotwire/spark/channels/monitoring_channel.js b/app/javascript/hotwire/spark/channels/monitoring_channel.js new file mode 100644 index 00000000..98cfcc67 --- /dev/null +++ b/app/javascript/hotwire/spark/channels/monitoring_channel.js @@ -0,0 +1,47 @@ +import consumer from "./consumer" +import { assetNameFromPath } from "../helpers.js"; +import { HtmlReloader } from "../reloaders/html_reloader.js"; +import { CssReloader } from "../reloaders/css_reloader.js"; +import { StimulusReloader } from "../reloaders/stimulus_reloader.js"; + +consumer.subscriptions.create({ channel: "Hotwire::Spark::Channel" }, { + connected() { + document.body.setAttribute("data-hotwire-spark-ready", "") + }, + + async received(message) { + try { + await this.dispatch(message) + } catch(error) { + console.log(`Error on ${message.action}`, error) + } + }, + + dispatch({ action, path }) { + const fileName = assetNameFromPath(path) + + switch(action) { + case "reload_html": + return this.reloadHtml() + case "reload_css": + return this.reloadCss(fileName) + case "reload_stimulus": + return this.reloadStimulus(fileName) + default: + throw new Error(`Unknown action: ${action}`) + } + }, + + reloadHtml() { + return HtmlReloader.reload() + }, + + reloadCss(fileName) { + return CssReloader.reload(new RegExp(fileName)) + }, + + reloadStimulus(fileName) { + return StimulusReloader.reload(new RegExp(fileName)) + } +}) + diff --git a/app/javascript/hotwire/spark/helpers.js b/app/javascript/hotwire/spark/helpers.js new file mode 100644 index 00000000..e689b66d --- /dev/null +++ b/app/javascript/hotwire/spark/helpers.js @@ -0,0 +1,37 @@ +export function assetNameFromPath(path) { + return path.split("/").pop().split(".")[0] +} + +export function pathWithoutAssetDigest(path) { + return path.replace(/-[a-z0-9]+\.(\w+)(\?.*)?$/, ".$1") +} + +export function urlWithParams(urlString, params) { + const url = new URL(urlString, window.location.origin) + Object.entries(params).forEach(([ key, value ]) => { + url.searchParams.set(key, value) + }) + return url.toString() +} + +export function cacheBustedUrl(urlString) { + return urlWithParams(urlString, { reload: Date.now() }) +} + +export async function reloadHtmlDocument() { + let currentUrl = cacheBustedUrl(urlWithParams(window.location.href, { hotwire_spark: "true" })) + const response = await fetch(currentUrl) + + if (!response.ok) { + throw new Error(`${response.status} when fetching ${currentUrl}`) + } + + const fetchedHTML = await response.text() + const parser = new DOMParser() + return parser.parseFromString(fetchedHTML, "text/html") +} + +export function getConfigurationProperty(name) { + return document.querySelector(`meta[name="hotwire-spark:${name}"]`)?.content +} + diff --git a/app/javascript/hotwire/spark/index.js b/app/javascript/hotwire/spark/index.js new file mode 100644 index 00000000..eb4442e1 --- /dev/null +++ b/app/javascript/hotwire/spark/index.js @@ -0,0 +1,14 @@ +import "./channels/monitoring_channel.js" +import { getConfigurationProperty } from "./helpers.js"; + +const HotwireSpark = { + config: { + loggingEnabled: false + } +} + +document.addEventListener("DOMContentLoaded", function() { + HotwireSpark.config.loggingEnabled = getConfigurationProperty("logging"); +}) + +export default HotwireSpark diff --git a/app/javascript/hotwire/spark/logger.js b/app/javascript/hotwire/spark/logger.js new file mode 100644 index 00000000..b8ad8571 --- /dev/null +++ b/app/javascript/hotwire/spark/logger.js @@ -0,0 +1,8 @@ +import HotwireSpark from "./index.js" + +export function log(...args) { + if (HotwireSpark.config.loggingEnabled) { + console.log(`[hotwire_spark]`, ...args) + } +} + diff --git a/app/javascript/hotwire/spark/reloaders/css_reloader.js b/app/javascript/hotwire/spark/reloaders/css_reloader.js new file mode 100644 index 00000000..88fb598d --- /dev/null +++ b/app/javascript/hotwire/spark/reloaders/css_reloader.js @@ -0,0 +1,65 @@ +import { log } from "../logger.js" +import { cacheBustedUrl, reloadHtmlDocument, pathWithoutAssetDigest } from "../helpers.js" + +export class CssReloader { + static async reload(...params) { + return new CssReloader(...params).reload() + } + + constructor(filePattern = /./) { + this.filePattern = filePattern + } + + async reload() { + log("Reload css...") + await Promise.all(await this.#reloadAllLinks()) + } + + async #reloadAllLinks() { + const cssLinks = await this.#loadNewCssLinks(); + return cssLinks.map(link => this.#reloadLinkIfNeeded(link)) + } + + async #loadNewCssLinks() { + const reloadedDocument = await reloadHtmlDocument() + return Array.from(reloadedDocument.head.querySelectorAll("link[rel='stylesheet']")) + } + + #reloadLinkIfNeeded(link) { + if (this.#shouldReloadLink(link)) { + return this.#reloadLink(link) + } else { + return Promise.resolve() + } + } + + #shouldReloadLink(link) { + return this.filePattern.test(link.getAttribute("href")) + } + + async #reloadLink(link) { + return new Promise(resolve => { + const href = link.getAttribute("href") + const newLink = this.#findExistingLinkFor(link) || this.#appendNewLink(link) + + newLink.setAttribute("href", cacheBustedUrl(link.getAttribute("href"))) + newLink.onload = () => { + log(`\t${href}`) + resolve() + } + }) + } + + #findExistingLinkFor(link) { + return this.#cssLinks.find(newLink => pathWithoutAssetDigest(link.href) === pathWithoutAssetDigest(newLink.href)) + } + + get #cssLinks() { + return Array.from(document.querySelectorAll("link[rel='stylesheet']")) + } + + #appendNewLink(link) { + document.head.append(link) + return link + } +} diff --git a/app/javascript/hotwire/spark/reloaders/html_reloader.js b/app/javascript/hotwire/spark/reloaders/html_reloader.js new file mode 100644 index 00000000..64f7ef3d --- /dev/null +++ b/app/javascript/hotwire/spark/reloaders/html_reloader.js @@ -0,0 +1,31 @@ +import { Idiomorph } from "idiomorph/dist/idiomorph.esm.js" +import { log } from "../logger.js" +import { reloadHtmlDocument } from "../helpers.js" +import { StimulusReloader } from "./stimulus_reloader.js" + +export class HtmlReloader { + static async reload() { + return new HtmlReloader().reload() + } + + async reload() { + const reloadedDocument = await this.#reloadHtml() + await this.#reloadStimulus(reloadedDocument) + } + + async #reloadHtml() { + log("Reload html...") + + const reloadedDocument = await reloadHtmlDocument() + this.#updateBody(reloadedDocument.body) + return reloadedDocument + } + + #updateBody(newBody) { + Idiomorph.morph(document.body, newBody) + } + + async #reloadStimulus(reloadedDocument) { + return new StimulusReloader(reloadedDocument).reload() + } +} diff --git a/app/javascript/hotwire/spark/reloaders/stimulus_reloader.js b/app/javascript/hotwire/spark/reloaders/stimulus_reloader.js new file mode 100644 index 00000000..d00508b5 --- /dev/null +++ b/app/javascript/hotwire/spark/reloaders/stimulus_reloader.js @@ -0,0 +1,76 @@ +import { Application } from "@hotwired/stimulus" +import { log } from "../logger.js" +import { cacheBustedUrl, reloadHtmlDocument } from "../helpers.js" + +export class StimulusReloader { + static async reload(filePattern) { + const document = await reloadHtmlDocument() + return new StimulusReloader(document, filePattern).reload() + } + + constructor(document, filePattern = /./) { + this.document = document + this.filePattern = filePattern + this.application = window.Stimulus || Application.start() + } + + async reload() { + log("Reload Stimulus controllers...") + + this.application.stop() + await this.#reloadStimulusControllers() + this.application.start() + } + + async #reloadStimulusControllers() { + await Promise.all( + this.#stimulusControllerPaths.map(async moduleName => this.#reloadStimulusController(moduleName)) + ) + } + + get #stimulusControllerPaths() { + return Object.keys(this.#stimulusPathsByModule).filter(path => path.endsWith("_controller") && this.#shouldReloadController(path)) + } + + #shouldReloadController(path) { + return this.filePattern.test(path) + } + + get #stimulusPathsByModule() { + this.pathsByModule = this.pathsByModule || this.#parseImportmapJson() + return this.pathsByModule + } + + #parseImportmapJson() { + const importmapScript = this.document.querySelector("script[type=importmap]") + return JSON.parse(importmapScript.text).imports + } + + async #reloadStimulusController(moduleName) { + log(`\t${moduleName}`) + + const controllerName = this.#extractControllerName(moduleName) + const path = cacheBustedUrl(this.#pathForModuleName(moduleName)) + + const module = await import(path) + + this.#registerController(controllerName, module) + } + + #pathForModuleName(moduleName) { + return this.#stimulusPathsByModule[moduleName] + } + + #extractControllerName(path) { + return path + .replace(/^.*\//, "") + .replace("_controller", "") + .replace(/\//g, "--") + .replace(/_/g, "-") + } + + #registerController(name, module) { + this.application.unload(name) + this.application.register(name, module.default) + } +} diff --git a/app/jobs/pulse_wire/application_job.rb b/app/jobs/pulse_wire/application_job.rb deleted file mode 100644 index aabef83e..00000000 --- a/app/jobs/pulse_wire/application_job.rb +++ /dev/null @@ -1,4 +0,0 @@ -module PulseWire - class ApplicationJob < ActiveJob::Base - end -end diff --git a/app/mailers/pulse_wire/application_mailer.rb b/app/mailers/pulse_wire/application_mailer.rb deleted file mode 100644 index 4c8ed6ba..00000000 --- a/app/mailers/pulse_wire/application_mailer.rb +++ /dev/null @@ -1,6 +0,0 @@ -module PulseWire - class ApplicationMailer < ActionMailer::Base - default from: "from@example.com" - layout "mailer" - end -end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/app/models/pulse_wire/application_record.rb b/app/models/pulse_wire/application_record.rb deleted file mode 100644 index 8cf97dd9..00000000 --- a/app/models/pulse_wire/application_record.rb +++ /dev/null @@ -1,5 +0,0 @@ -module PulseWire - class ApplicationRecord < ActiveRecord::Base - self.abstract_class = true - end -end diff --git a/app/views/layouts/pulse_wire/application.html.erb b/app/views/layouts/pulse_wire/application.html.erb deleted file mode 100644 index 4b8d918a..00000000 --- a/app/views/layouts/pulse_wire/application.html.erb +++ /dev/null @@ -1,17 +0,0 @@ - - - - Pulse wire - <%= csrf_meta_tags %> - <%= csp_meta_tag %> - - <%= yield :head %> - - <%= stylesheet_link_tag "pulse_wire/application", media: "all" %> - - - -<%= yield %> - - - diff --git a/bin/rails b/bin/rails index d16a204a..fbae5309 100755 --- a/bin/rails +++ b/bin/rails @@ -3,7 +3,7 @@ # installed from the root of your application. ENGINE_ROOT = File.expand_path("..", __dir__) -ENGINE_PATH = File.expand_path("../lib/pulse_wire/engine", __dir__) +ENGINE_PATH = File.expand_path("../lib/hotwire_spark/engine", __dir__) APP_PATH = File.expand_path("../test/dummy/config/application", __dir__) # Set up gems listed in the Gemfile. diff --git a/config/routes.rb b/config/routes.rb index cfa9a1fc..0ade7920 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,2 +1,2 @@ -PulseWire::Engine.routes.draw do +Hotwire::Spark::Engine.routes.draw do end diff --git a/hotwire-spark.gemspec b/hotwire-spark.gemspec new file mode 100644 index 00000000..960312c3 --- /dev/null +++ b/hotwire-spark.gemspec @@ -0,0 +1,29 @@ +require_relative "lib/hotwire/spark/version" + +Gem::Specification.new do |spec| + spec.name = "hotwire-spark" + spec.version = Hotwire::Spark::VERSION + spec.authors = [ "Jorge Manrubia" ] + spec.email = [ "jorge@37signals.com" ] + spec.homepage = "https://github.com/basecamp/hotwire_spark" + spec.summary = "Smooth live reloading for your Rails apps" + spec.description = "A live reloading system that updates just what's needed to offer a smooth experience." + spec.license = "MIT" + + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = "https://github.com/basecamp/hotwire_spark" + spec.metadata["changelog_uri"] = "https://github.com/basecamp/hotwire_spark" + + spec.files = Dir.chdir(File.expand_path(__dir__)) do + Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] + end + + spec.add_dependency "rails", ">= 8.0.0" + spec.add_dependency "zeitwerk" + spec.add_dependency "listen" + + spec.add_development_dependency "rubocop" + spec.add_development_dependency "rubocop-rails-omakase" + spec.add_development_dependency "capybara" + spec.add_development_dependency "cuprite" +end diff --git a/lib/hotwire-spark.rb b/lib/hotwire-spark.rb new file mode 100644 index 00000000..6031c72f --- /dev/null +++ b/lib/hotwire-spark.rb @@ -0,0 +1,26 @@ +require "hotwire/spark/version" +require "hotwire/spark/engine" + +require "zeitwerk" +loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false) +loader.ignore("#{__dir__}/hotwire-spark.rb") +loader.setup + +module Hotwire::Spark + mattr_accessor :css_paths, default: [] + mattr_accessor :html_paths, default: [] + mattr_accessor :stimulus_paths, default: [] + mattr_accessor :logging, default: false + + mattr_accessor :enabled, default: Rails.env.development? + + class << self + def install_into(application) + Installer.new(application).install + end + + def enabled? + enabled + end + end +end diff --git a/lib/hotwire/spark/action_cable/persistent_cable_middleware.rb b/lib/hotwire/spark/action_cable/persistent_cable_middleware.rb new file mode 100644 index 00000000..3ae8cc4e --- /dev/null +++ b/lib/hotwire/spark/action_cable/persistent_cable_middleware.rb @@ -0,0 +1,43 @@ +class Hotwire::Spark::ActionCable::PersistentCableMiddleware + def initialize(app) + @app = app + end + + def call(env) + request = Rack::Request.new(env) + + if supress_action_cable_restarts?(request) + respond_suppressing_action_cable_restarts(env) + else + @app.call(env) + end + end + + private + COOKIE_NAME = "hotwire_spark_disable_cable_restarts" + RESTARTS_SUPPRESSED_GRACE_PERIOD = 10.seconds + + def supress_action_cable_restarts?(request) + request.params["hotwire_spark"] || request.cookies[COOKIE_NAME] + end + + def respond_suppressing_action_cable_restarts(env) + status, headers, body = suppressing_action_cable_restarts { @app.call(env) } + headers["Set-Cookie"] = append_cookie_to_disable_cable_restarts(headers["Set-Cookie"]) + + [ status, headers, body ] + end + + def suppressing_action_cable_restarts(&block) + ActionCable.server.without_restarting(&block) + end + + def append_cookie_to_disable_cable_restarts(existing_cookies) + [ existing_cookies, cookie_to_disable_cable_restarts ].compact + end + + def cookie_to_disable_cable_restarts + expiration = RESTARTS_SUPPRESSED_GRACE_PERIOD.from_now.utc + "#{COOKIE_NAME}=true; Path=/; Expires=#{expiration.httpdate}; HttpOnly" + end +end diff --git a/lib/hotwire/spark/action_cable/persistent_cable_server.rb b/lib/hotwire/spark/action_cable/persistent_cable_server.rb new file mode 100644 index 00000000..7cefdecc --- /dev/null +++ b/lib/hotwire/spark/action_cable/persistent_cable_server.rb @@ -0,0 +1,25 @@ +module Hotwire::Spark::ActionCable::PersistentCableServer + def self.prepended(base) + base.class_eval do + thread_mattr_accessor :suppress_restarts + end + end + + def restart + return if restarts_suppressed? + + super + end + + def without_restarting + old_suppress_restarts, self.suppress_restarts = self.suppress_restarts, true + yield + ensure + self.suppress_restarts = old_suppress_restarts + end + + private + def restarts_suppressed? + suppress_restarts + end +end diff --git a/lib/hotwire/spark/action_cable/solid_cable_listener_with_safe_reloads.rb b/lib/hotwire/spark/action_cable/solid_cable_listener_with_safe_reloads.rb new file mode 100644 index 00000000..27fe9b39 --- /dev/null +++ b/lib/hotwire/spark/action_cable/solid_cable_listener_with_safe_reloads.rb @@ -0,0 +1,8 @@ +module Hotwire::Spark::ActionCable::SolidCableListenerWithSafeReloads + private + def broadcast_messages + Rails.application.executor.wrap do + super + end + end +end diff --git a/lib/hotwire/spark/engine.rb b/lib/hotwire/spark/engine.rb new file mode 100644 index 00000000..e48b272f --- /dev/null +++ b/lib/hotwire/spark/engine.rb @@ -0,0 +1,25 @@ +require "action_cable/server/base" + +module Hotwire::Spark + class Engine < ::Rails::Engine + isolate_namespace Hotwire::Spark + + config.hotwire = ActiveSupport::OrderedOptions.new unless config.respond_to?(:hotwire) + config.hotwire.spark = ActiveSupport::OrderedOptions.new + config.hotwire.spark.merge! \ + enabled: Rails.env.development?, + css_paths: %w[ app/assets/stylesheets ], + html_paths: %w[ app/controllers app/helpers app/models app/views ], + stimulus_paths: %w[ app/javascript/controllers ] + + initializer "hotwire_spark.config" do |app| + config.hotwire.spark.each do |key, value| + Hotwire::Spark.send("#{key}=", value) + end + end + + initializer "hotwire_spark.install" do |application| + Hotwire::Spark.install_into application if Hotwire::Spark.enabled? + end + end +end diff --git a/lib/hotwire/spark/file_watcher.rb b/lib/hotwire/spark/file_watcher.rb new file mode 100644 index 00000000..04be3fc7 --- /dev/null +++ b/lib/hotwire/spark/file_watcher.rb @@ -0,0 +1,40 @@ +require "listen" + +class Hotwire::Spark::FileWatcher + def initialize + @callbacks_by_path = Hash.new { |hash, key| hash[key] = [] } + end + + def monitor(paths, &callback) + Array(paths).each do |path| + @callbacks_by_path[expand_path(path)] << callback + end + end + + def start + listener = Listen.to(*paths) do |modified, added, removed| + process_changed_files modified + added + removed + end + + listener.start + end + + private + def expand_path(path) + Rails.application.root.join(path) + end + + def paths + @callbacks_by_path.keys + end + + def process_changed_files(changed_files) + changed_files.each do |file| + @callbacks_by_path.each do |path, callbacks| + if file.to_s.start_with?(path.to_s) + callbacks.each { |callback| callback.call(file) } + end + end + end + end +end diff --git a/lib/hotwire/spark/installer.rb b/lib/hotwire/spark/installer.rb new file mode 100644 index 00000000..b8fd2eda --- /dev/null +++ b/lib/hotwire/spark/installer.rb @@ -0,0 +1,52 @@ +class Hotwire::Spark::Installer + attr_reader :file_watcher + + def initialize(application) + @application = application + end + + def install + configure_middleware + monitor_paths + end + + def configure_middleware + ::ActionCable::Server::Base.prepend(Hotwire::Spark::ActionCable::PersistentCableServer) + + middleware.insert_before ActionDispatch::Executor, Hotwire::Spark::ActionCable::PersistentCableMiddleware + middleware.use Hotwire::Spark::Middleware + end + + private + attr_reader :application + delegate :middleware, to: :application + + def monitor_paths + register_monitored_paths + file_watcher.start + end + + def register_monitored_paths + monitor :css_paths, action: :reload_css + monitor :html_paths, action: :reload_html + monitor :stimulus_paths, action: :reload_stimulus + end + + def monitor(paths_name, action:) + file_watcher.monitor Hotwire::Spark.public_send(paths_name) do |file_path| + broadcast_reload_action(action, file_path) + end + end + + def broadcast_reload_action(action, file_path) + ActionCable.server.broadcast "hotwire_spark", reload_message_for(action, file_path) + end + + def reload_message_for(action, file_path) + { action: action, path: file_path } + end + + def file_watcher + @file_watches ||= Hotwire::Spark::FileWatcher.new + end +end diff --git a/lib/hotwire/spark/middleware.rb b/lib/hotwire/spark/middleware.rb new file mode 100644 index 00000000..f8ea94d9 --- /dev/null +++ b/lib/hotwire/spark/middleware.rb @@ -0,0 +1,55 @@ +class Hotwire::Spark::Middleware + def initialize(app) + @app = app + end + + def call(env) + status, headers, response = @app.call(env) + + if html_response?(headers) + html = html_from(response) + html = inject_javascript(html) + html = inject_options(html) + headers["Content-Length"] = html.bytesize.to_s if html + response = [ html ] + end + + [ status, headers, response ] + end + + private + def html_response?(headers) + headers["Content-Type"]&.include?("text/html") + end + + def html_from(response) + response_body = [] + response.each { |part| response_body << part } + response_body.join + end + + def inject_javascript(html) + html.sub("", "#{script_tag}") + end + + def script_tag + script_path = view_helpers.asset_path("hotwire_spark.js") + view_helpers.javascript_include_tag(script_path) + end + + def view_helpers + ActionController::Base.helpers + end + + def inject_options(html) + if Hotwire::Spark.logging + html.sub("", "#{logging_option}") + else + html + end + end + + def logging_option + view_helpers.tag.meta(name: "hotwire-spark:logging", content: "true") + end +end diff --git a/lib/hotwire/spark/version.rb b/lib/hotwire/spark/version.rb new file mode 100644 index 00000000..518cc415 --- /dev/null +++ b/lib/hotwire/spark/version.rb @@ -0,0 +1,5 @@ +module Hotwire + module Spark + VERSION = "0.1.0" + end +end diff --git a/lib/pulse_wire.rb b/lib/pulse_wire.rb deleted file mode 100644 index 1e0c2742..00000000 --- a/lib/pulse_wire.rb +++ /dev/null @@ -1,6 +0,0 @@ -require "pulse_wire/version" -require "pulse_wire/engine" - -module PulseWire - # Your code goes here... -end diff --git a/lib/pulse_wire/engine.rb b/lib/pulse_wire/engine.rb deleted file mode 100644 index 8e163398..00000000 --- a/lib/pulse_wire/engine.rb +++ /dev/null @@ -1,5 +0,0 @@ -module PulseWire - class Engine < ::Rails::Engine - isolate_namespace PulseWire - end -end diff --git a/lib/pulse_wire/version.rb b/lib/pulse_wire/version.rb deleted file mode 100644 index a4a0cc76..00000000 --- a/lib/pulse_wire/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module PulseWire - VERSION = "0.1.0" -end diff --git a/lib/tasks/pulse_wire_tasks.rake b/lib/tasks/hotwire_spark_tasks.rake similarity index 72% rename from lib/tasks/pulse_wire_tasks.rake rename to lib/tasks/hotwire_spark_tasks.rake index b11cdf22..e8bdea05 100644 --- a/lib/tasks/pulse_wire_tasks.rake +++ b/lib/tasks/hotwire_spark_tasks.rake @@ -1,4 +1,4 @@ # desc "Explaining what the task does" -# task :pulse_wire do +# task :hotwire_spark do # # Task goes here # end diff --git a/package.json b/package.json new file mode 100644 index 00000000..132b8cd3 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "hotwire_spark", + "version": "1.0.0", + "main": "index.js", + "repository": "https://github.com/jorgemanrubia/hotwire_spark.git", + "author": "Jorge Manrubia ", + "license": "MIT", + "type": "module", + "scripts": { + "build": "rollup -c", + "watch": "rollup -c --watch" + }, + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/preset-env": "^7.26.0", + "@hotwired/stimulus": "^3.2.2", + "@rails/actioncable": "^8.0.0", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^28.0.1", + "@rollup/plugin-node-resolve": "^15.3.0", + "idiomorph": "^0.3.0", + "rollup": "^4.27.4", + "rollup-plugin-terser": "^7.0.2" + } +} diff --git a/pulse_wire.gemspec b/pulse_wire.gemspec deleted file mode 100644 index b3cec7e9..00000000 --- a/pulse_wire.gemspec +++ /dev/null @@ -1,26 +0,0 @@ -require_relative "lib/pulse_wire/version" - -Gem::Specification.new do |spec| - spec.name = "pulse_wire" - spec.version = PulseWire::VERSION - spec.authors = [ "Jorge Manrubia" ] - spec.email = [ "jorge@37signals.com" ] - spec.homepage = "TODO" - spec.summary = "TODO: Summary of PulseWire." - spec.description = "TODO: Description of PulseWire." - spec.license = "MIT" - - # Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host" - # to allow pushing to a single host or delete this section to allow pushing to any host. - spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" - - spec.metadata["homepage_uri"] = spec.homepage - spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." - spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." - - spec.files = Dir.chdir(File.expand_path(__dir__)) do - Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - end - - spec.add_dependency "rails", ">= 8.0.0" -end diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 00000000..179c463c --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,45 @@ +import { terser } from "rollup-plugin-terser" +import resolve from "@rollup/plugin-node-resolve" +import commonjs from "@rollup/plugin-commonjs" +import babel from "@rollup/plugin-babel" + +const inputFile = "app/javascript/hotwire/spark/index.js" +const outputDir = "app/assets/javascripts" + +export default { + input: inputFile, + output: [ + { + file: `${outputDir}/hotwire_spark.js`, + name: "HotwireSpark", + format: "iife", + inlineDynamicImports: true + }, + { + file: `${outputDir}/hotwire_spark.min.js`, + format: "iife", + name: "HotwireSpark", + sourcemap: true, + inlineDynamicImports: true, + plugins: [ terser() ] + }, + ], + plugins: [ + resolve(), + commonjs(), + babel({ + babelHelpers: "bundled", + presets: [ + [ + "@babel/preset-env", + { + targets: "> 0.25%, not dead", + exclude: [ "transform-template-literals" ], + modules: false, + }, + ], + ], + exclude: "node_modules/**", + }), + ] +} diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb new file mode 100644 index 00000000..57c5f471 --- /dev/null +++ b/test/application_system_test_case.rb @@ -0,0 +1,21 @@ +require "test_helper" +require "capybara/cuprite" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :cuprite, screen_size: [ 1440, 900 ], options: { headless: "new" } + + include Hotwire::Spark::Engine.routes.url_helpers + + def visit(...) + super.tap do + wait_for_hotwire_spark + end + end + + private + def wait_for_hotwire_spark + assert_css "[data-hotwire-spark-ready]" + end +end + +Capybara.server = :puma, { Silent: true } diff --git a/test/controllers/.keep b/test/controllers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/test/css_reload_test.rb b/test/css_reload_test.rb new file mode 100644 index 00000000..5fe2f824 --- /dev/null +++ b/test/css_reload_test.rb @@ -0,0 +1,23 @@ +require "application_system_test_case" + +class CssReloadTest < ApplicationSystemTestCase + test "reload CSS changes" do + visit root_path + assert_text "This is pretty cool" + + edit_file "app/assets/stylesheets/base.css", replace: "visible", with: "hidden" + + assert_no_text "This is pretty cool" + end + + test "load new CSS stylesheets" do + visit root_path + assert_text "This is pretty cool" + + add_file "app/assets/stylesheets/other_stylesheet.css", <<~CSS + body { visibility: hidden!important; } + CSS + + assert_no_text "This is pretty cool" + end +end diff --git a/test/dummy/app/assets/stylesheets/base.css b/test/dummy/app/assets/stylesheets/base.css new file mode 100644 index 00000000..1f4e1499 --- /dev/null +++ b/test/dummy/app/assets/stylesheets/base.css @@ -0,0 +1,3 @@ +body { + visibility: visible; +} diff --git a/test/dummy/app/controllers/home_controller.rb b/test/dummy/app/controllers/home_controller.rb new file mode 100644 index 00000000..89ff5b16 --- /dev/null +++ b/test/dummy/app/controllers/home_controller.rb @@ -0,0 +1,4 @@ +class HomeController < ApplicationController + def show + end +end diff --git a/test/dummy/app/javascript/application.js b/test/dummy/app/javascript/application.js new file mode 100644 index 00000000..c275ea83 --- /dev/null +++ b/test/dummy/app/javascript/application.js @@ -0,0 +1,2 @@ +// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails +import "controllers" diff --git a/test/dummy/app/javascript/controllers/application.js b/test/dummy/app/javascript/controllers/application.js new file mode 100644 index 00000000..e5fa6742 --- /dev/null +++ b/test/dummy/app/javascript/controllers/application.js @@ -0,0 +1,9 @@ +import { Application } from "@hotwired/stimulus" + +const application = Application.start() + +// Configure Stimulus development experience +application.debug = false +window.Stimulus = application + +export { application } diff --git a/test/dummy/app/javascript/controllers/dummy_controller.js b/test/dummy/app/javascript/controllers/dummy_controller.js new file mode 100644 index 00000000..fb763a11 --- /dev/null +++ b/test/dummy/app/javascript/controllers/dummy_controller.js @@ -0,0 +1,16 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + initialize() { + this.version = 1 + } + + connect() { + console.debug("Dummy controller connected ", this.version) + this.element.querySelector("#replace").textContent = "_REPLACE_" + } + + disconnect() { + console.debug("Dummy controller disconnected", this.version) + } +} diff --git a/test/dummy/app/javascript/controllers/index.js b/test/dummy/app/javascript/controllers/index.js new file mode 100644 index 00000000..fc8ab4a9 --- /dev/null +++ b/test/dummy/app/javascript/controllers/index.js @@ -0,0 +1,5 @@ + +import { application } from "controllers/application" + +import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" +eagerLoadControllersFrom("controllers", application) diff --git a/test/dummy/app/views/home/show.html.erb b/test/dummy/app/views/home/show.html.erb new file mode 100644 index 00000000..3528c124 --- /dev/null +++ b/test/dummy/app/views/home/show.html.erb @@ -0,0 +1,4 @@ +
+

This is pretty cool, isn't it?

+

_REPLACE_

+
diff --git a/test/dummy/app/views/layouts/application.html.erb b/test/dummy/app/views/layouts/application.html.erb index f25ae92d..f7edb32f 100644 --- a/test/dummy/app/views/layouts/application.html.erb +++ b/test/dummy/app/views/layouts/application.html.erb @@ -1,27 +1,28 @@ - - <%= content_for(:title) || "Dummy" %> - - - - <%= csrf_meta_tags %> - <%= csp_meta_tag %> + + <%= content_for(:title) || "Dummy" %> + + + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> - <%= yield :head %> + <%= yield :head %> - <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> - <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> + <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> + <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> - - - + + + - <%# Includes all stylesheet files in app/assets/stylesheets %> - <%= stylesheet_link_tag :app %> - + <%# Includes all stylesheet files in app/assets/stylesheets %> + <%= stylesheet_link_tag :app %> + <%= javascript_importmap_tags %> + - - <%= yield %> - + +<%= yield %> + diff --git a/test/dummy/bin/importmap b/test/dummy/bin/importmap new file mode 100755 index 00000000..36502ab1 --- /dev/null +++ b/test/dummy/bin/importmap @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require_relative "../config/application" +require "importmap/commands" diff --git a/test/dummy/config/cable.yml b/test/dummy/config/cable.yml index 98367f89..b9adc5aa 100644 --- a/test/dummy/config/cable.yml +++ b/test/dummy/config/cable.yml @@ -1,3 +1,7 @@ +# Async adapter only works within the same process, so for manually triggering cable updates from a console, +# and seeing results in the browser, you must do so from the web console (running inside the dev process), +# not a terminal started via bin/rails console! Add "console" to any action or any ERB template view +# to make the web console appear. development: adapter: async @@ -5,6 +9,9 @@ test: adapter: test production: - adapter: redis - url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> - channel_prefix: dummy_production + adapter: solid_cable + connects_to: + database: + writing: cable + polling_interval: 0.1.seconds + message_retention: 1.day diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb index c2095b11..b753cfdc 100644 --- a/test/dummy/config/environments/test.rb +++ b/test/dummy/config/environments/test.rb @@ -7,13 +7,15 @@ # Settings specified here will take precedence over those in config/application.rb. # While tests run files are not watched, reloading is not necessary. - config.enable_reloading = false + config.enable_reloading = true + config.cache_classes = false + config.assets.sweep_cache = true # Eager loading loads your entire application. When running a single test locally, # this is usually not necessary, and can slow down your test suite. However, it's # recommended that you enable it in continuous integration systems to ensure eager # loading is working properly before deploying your code. - config.eager_load = ENV["CI"].present? + config.eager_load = false # Configure public file server for tests with cache-control for performance. config.public_file_server.headers = { "cache-control" => "public, max-age=3600" } @@ -50,4 +52,7 @@ # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true + + config.middleware.use Hotwire::Spark::Middleware + config.hotwire.spark.enabled = true end diff --git a/test/dummy/config/importmap.rb b/test/dummy/config/importmap.rb new file mode 100644 index 00000000..0a3aa472 --- /dev/null +++ b/test/dummy/config/importmap.rb @@ -0,0 +1,7 @@ +# Pin npm packages by running ./bin/importmap + +pin "application" + +pin "@hotwired/stimulus", to: "stimulus.min.js" +pin "@hotwired/stimulus-loading", to: "stimulus-loading.js" +pin_all_from "app/javascript/controllers", under: "controllers" diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index ad123fe4..ff52b395 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -1,3 +1,5 @@ Rails.application.routes.draw do - mount PulseWire::Engine => "/pulse_wire" + mount Hotwire::Spark::Engine => "/hotwire_spark" + + root to: "home#show" end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb new file mode 100644 index 00000000..0f651a43 --- /dev/null +++ b/test/dummy/db/schema.rb @@ -0,0 +1,14 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[8.0].define(version: 0) do +end diff --git a/test/helpers/.keep b/test/helpers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/test/helpers/files_helper.rb b/test/helpers/files_helper.rb new file mode 100644 index 00000000..7a0563e0 --- /dev/null +++ b/test/helpers/files_helper.rb @@ -0,0 +1,69 @@ +module FilesHelper + extend ActiveSupport::Concern + + included do + teardown do + restore_original_files + delete_added_files + end + end + + ORIGINAL_EXTENSION = ".original" + + def edit_file(path, replace:, with:) + path = Rails.application.root.join(path).to_s + + raise ArgumentError, "File at '#{path}' does not exist." unless File.exist?(path) + + original_path = "#{path}#{ORIGINAL_EXTENSION}" + remember_path_to_restore original_path + system "cp", path, original_path + + content = File.read(path) + updated_content = content.gsub(replace, with) + File.write(path, updated_content) + + reload_rails_reloader + end + + def add_file(path, content) + path = Rails.application.root.join(path).to_s + + raise ArgumentError, "File at '#{path}' already exists." if File.exist?(path) + + remember_path_to_delete path + File.write path, content + + reload_rails_reloader + end + + private + def remember_path_to_restore(path) + paths_to_restore << path + end + + def paths_to_restore + @paths_to_restore ||= [] + end + + def remember_path_to_delete(path) + paths_to_delete << path + end + + def paths_to_delete + @paths_to_delete ||= [] + end + + def restore_original_files + paths_to_restore.each do |path| + FileUtils.cp(path, path.gsub(/#{ORIGINAL_EXTENSION}$/, "")) + FileUtils.rm(path) + end + end + + def delete_added_files + paths_to_delete.each do |path| + FileUtils.rm(path) + end + end +end diff --git a/test/html_reload_test.rb b/test/html_reload_test.rb new file mode 100644 index 00000000..f0e89368 --- /dev/null +++ b/test/html_reload_test.rb @@ -0,0 +1,12 @@ +require "application_system_test_case" + +class HtmlReloadTest < ApplicationSystemTestCase + test "reload HTML changes" do + visit root_path + assert_no_text "This was replaced" + + edit_file "app/views/home/show.html.erb", replace: "_REPLACE_", with: "This was replaced!" + + assert_text "This was replaced" + end +end diff --git a/test/integration/.keep b/test/integration/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/test/integration/navigation_test.rb b/test/integration/navigation_test.rb deleted file mode 100644 index ebbc098a..00000000 --- a/test/integration/navigation_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class NavigationTest < ActionDispatch::IntegrationTest - # test "the truth" do - # assert true - # end -end diff --git a/test/mailers/.keep b/test/mailers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/test/models/.keep b/test/models/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/test/pulse_wire_test.rb b/test/pulse_wire_test.rb deleted file mode 100644 index 351f8350..00000000 --- a/test/pulse_wire_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "test_helper" - -class PulseWireTest < ActiveSupport::TestCase - test "it has a version number" do - assert PulseWire::VERSION - end -end diff --git a/test/stimulus_reload_test.rb b/test/stimulus_reload_test.rb new file mode 100644 index 00000000..88bfa216 --- /dev/null +++ b/test/stimulus_reload_test.rb @@ -0,0 +1,32 @@ +require "application_system_test_case" + +class StimulusReloadTest < ApplicationSystemTestCase + test "reload Stimulus controller changes" do + visit root_path + assert_no_text "This was replaced!" + + edit_file "app/javascript/controllers/dummy_controller.js", replace: "_REPLACE_", with: "This was replaced!" + + assert_text "This was replaced!" + end + + test "load new Stimulus controllers" do + visit root_path + assert_no_text "This was replaced!" + + edit_file "app/views/home/show.html.erb", replace: "_REPLACE_CONTROLLER_", with: "other-dummy" + sleep 2 # Broadcasting many jobs in a row sometimes makes the test fail + + add_file "app/javascript/controllers/other_dummy_controller.js", <<~JS + import { Controller } from "@hotwired/stimulus" + + export default class extends Controller { + connect() { + this.element.querySelector("p").textContent = "This was replaced!" + } + } + JS + + assert_text "This was replaced!" + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index cf669c89..7952c8e2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -13,3 +13,23 @@ ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files" ActiveSupport::TestCase.fixtures :all end + +require "helpers/files_helper" + +class ActiveSupport::TestCase + include FilesHelper + + setup do + reload_rails_reloader + ActionCable.server.suppress_restarts = true + end + + teardown do + ActionCable.server.suppress_restarts = false + end + + private + def reload_rails_reloader + Rails.application.reloader.reload! + end +end diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..f2ba5ac7 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1431 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.9", "@babel/compat-data@^7.26.0": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.2.tgz#278b6b13664557de95b8f35b90d96785850bb56e" + integrity sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg== + +"@babel/core@^7.23.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" + integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.26.0" + "@babel/generator" "^7.26.0" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.0" + "@babel/parser" "^7.26.0" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.26.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.25.9", "@babel/generator@^7.26.0": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.2.tgz#87b75813bec87916210e5e01939a4c823d6bb74f" + integrity sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw== + dependencies: + "@babel/parser" "^7.26.2" + "@babel/types" "^7.26.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-annotate-as-pure@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4" + integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g== + dependencies: + "@babel/types" "^7.25.9" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz#f41752fe772a578e67286e6779a68a5a92de1ee9" + integrity sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875" + integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ== + dependencies: + "@babel/compat-data" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz#7644147706bb90ff613297d49ed5266bde729f83" + integrity sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-member-expression-to-functions" "^7.25.9" + "@babel/helper-optimise-call-expression" "^7.25.9" + "@babel/helper-replace-supers" "^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/traverse" "^7.25.9" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz#3e8999db94728ad2b2458d7a470e7770b7764e26" + integrity sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + regexpu-core "^6.1.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.2", "@babel/helper-define-polyfill-provider@^0.6.3": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz#f4f2792fae2ef382074bc2d713522cf24e6ddb21" + integrity sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + +"@babel/helper-member-expression-to-functions@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz#9dfffe46f727005a5ea29051ac835fb735e4c1a3" + integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-module-transforms@^7.25.9", "@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-optimise-call-expression@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e" + integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ== + dependencies: + "@babel/types" "^7.25.9" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz#9cbdd63a9443a2c92a725cca7ebca12cc8dd9f46" + integrity sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw== + +"@babel/helper-remap-async-to-generator@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz#e53956ab3d5b9fb88be04b3e2f31b523afd34b92" + integrity sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-wrap-function" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-replace-supers@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz#ba447224798c3da3f8713fc272b145e33da6a5c5" + integrity sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.25.9" + "@babel/helper-optimise-call-expression" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-simple-access@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz#6d51783299884a2c74618d6ef0f86820ec2e7739" + integrity sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-skip-transparent-expression-wrappers@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9" + integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + +"@babel/helper-wrap-function@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz#d99dfd595312e6c894bd7d237470025c85eea9d0" + integrity sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g== + dependencies: + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helpers@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" + integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== + dependencies: + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.0" + +"@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.2.tgz#fd7b6f487cfea09889557ef5d4eeb9ff9a5abd11" + integrity sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ== + dependencies: + "@babel/types" "^7.26.0" + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe" + integrity sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz#af9e4fb63ccb8abcb92375b2fcfe36b60c774d30" + integrity sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz#e8dc26fcd616e6c5bf2bd0d5a2c151d4f92a9137" + integrity sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz#807a667f9158acac6f6164b4beb85ad9ebc9e1d1" + integrity sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/plugin-transform-optional-chaining" "^7.25.9" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz#de7093f1e7deaf68eadd7cc6b07f2ab82543269e" + integrity sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-syntax-import-assertions@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz#620412405058efa56e4a564903b79355020f445f" + integrity sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-import-attributes@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz#3b1412847699eea739b4f2602c74ce36f6b0b0f7" + integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz#7821d4410bee5daaadbb4cdd9a6649704e176845" + integrity sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-async-generator-functions@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz#1b18530b077d18a407c494eb3d1d72da505283a2" + integrity sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-remap-async-to-generator" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-transform-async-to-generator@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz#c80008dacae51482793e5a9c08b39a5be7e12d71" + integrity sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-remap-async-to-generator" "^7.25.9" + +"@babel/plugin-transform-block-scoped-functions@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz#5700691dbd7abb93de300ca7be94203764fce458" + integrity sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-block-scoping@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz#c33665e46b06759c93687ca0f84395b80c0473a1" + integrity sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-class-properties@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz#a8ce84fedb9ad512549984101fa84080a9f5f51f" + integrity sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-class-static-block@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz#6c8da219f4eb15cae9834ec4348ff8e9e09664a0" + integrity sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-classes@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz#7152457f7880b593a63ade8a861e6e26a4469f52" + integrity sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-replace-supers" "^7.25.9" + "@babel/traverse" "^7.25.9" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz#db36492c78460e534b8852b1d5befe3c923ef10b" + integrity sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/template" "^7.25.9" + +"@babel/plugin-transform-destructuring@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz#966ea2595c498224340883602d3cfd7a0c79cea1" + integrity sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-dotall-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz#bad7945dd07734ca52fe3ad4e872b40ed09bb09a" + integrity sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-duplicate-keys@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz#8850ddf57dce2aebb4394bb434a7598031059e6d" + integrity sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz#6f7259b4de127721a08f1e5165b852fcaa696d31" + integrity sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-dynamic-import@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz#23e917de63ed23c6600c5dd06d94669dce79f7b8" + integrity sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-exponentiation-operator@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz#ece47b70d236c1d99c263a1e22b62dc20a4c8b0f" + integrity sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-export-namespace-from@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz#90745fe55053394f554e40584cda81f2c8a402a2" + integrity sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-for-of@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz#4bdc7d42a213397905d89f02350c5267866d5755" + integrity sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + +"@babel/plugin-transform-function-name@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz#939d956e68a606661005bfd550c4fc2ef95f7b97" + integrity sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA== + dependencies: + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-transform-json-strings@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz#c86db407cb827cded902a90c707d2781aaa89660" + integrity sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-literals@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz#1a1c6b4d4aa59bc4cad5b6b3a223a0abd685c9de" + integrity sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-logical-assignment-operators@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz#b19441a8c39a2fda0902900b306ea05ae1055db7" + integrity sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-member-expression-literals@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz#63dff19763ea64a31f5e6c20957e6a25e41ed5de" + integrity sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-modules-amd@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz#49ba478f2295101544abd794486cd3088dddb6c5" + integrity sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw== + dependencies: + "@babel/helper-module-transforms" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-modules-commonjs@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz#d165c8c569a080baf5467bda88df6425fc060686" + integrity sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg== + dependencies: + "@babel/helper-module-transforms" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-simple-access" "^7.25.9" + +"@babel/plugin-transform-modules-systemjs@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz#8bd1b43836269e3d33307151a114bcf3ba6793f8" + integrity sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA== + dependencies: + "@babel/helper-module-transforms" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/plugin-transform-modules-umd@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz#6710079cdd7c694db36529a1e8411e49fcbf14c9" + integrity sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw== + dependencies: + "@babel/helper-module-transforms" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz#454990ae6cc22fd2a0fa60b3a2c6f63a38064e6a" + integrity sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-new-target@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz#42e61711294b105c248336dcb04b77054ea8becd" + integrity sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz#bcb1b0d9e948168102d5f7104375ca21c3266949" + integrity sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-numeric-separator@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz#bfed75866261a8b643468b0ccfd275f2033214a1" + integrity sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-object-rest-spread@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz#0203725025074164808bcf1a2cfa90c652c99f18" + integrity sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg== + dependencies: + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/plugin-transform-parameters" "^7.25.9" + +"@babel/plugin-transform-object-super@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz#385d5de135162933beb4a3d227a2b7e52bb4cf03" + integrity sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-replace-supers" "^7.25.9" + +"@babel/plugin-transform-optional-catch-binding@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz#10e70d96d52bb1f10c5caaac59ac545ea2ba7ff3" + integrity sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-optional-chaining@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz#e142eb899d26ef715435f201ab6e139541eee7dd" + integrity sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + +"@babel/plugin-transform-parameters@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz#b856842205b3e77e18b7a7a1b94958069c7ba257" + integrity sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-private-methods@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz#847f4139263577526455d7d3223cd8bda51e3b57" + integrity sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-private-property-in-object@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz#9c8b73e64e6cc3cbb2743633885a7dd2c385fe33" + integrity sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-create-class-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-property-literals@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz#d72d588bd88b0dec8b62e36f6fda91cedfe28e3f" + integrity sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-regenerator@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz#03a8a4670d6cebae95305ac6defac81ece77740b" + integrity sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + regenerator-transform "^0.15.2" + +"@babel/plugin-transform-regexp-modifiers@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz#2f5837a5b5cd3842a919d8147e9903cc7455b850" + integrity sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-reserved-words@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz#0398aed2f1f10ba3f78a93db219b27ef417fb9ce" + integrity sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-shorthand-properties@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz#bb785e6091f99f826a95f9894fc16fde61c163f2" + integrity sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-spread@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz#24a35153931b4ba3d13cec4a7748c21ab5514ef9" + integrity sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + +"@babel/plugin-transform-sticky-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz#c7f02b944e986a417817b20ba2c504dfc1453d32" + integrity sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-template-literals@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz#6dbd4a24e8fad024df76d1fac6a03cf413f60fe1" + integrity sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-typeof-symbol@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz#224ba48a92869ddbf81f9b4a5f1204bbf5a2bc4b" + integrity sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-unicode-escapes@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz#a75ef3947ce15363fccaa38e2dd9bc70b2788b82" + integrity sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-unicode-property-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz#a901e96f2c1d071b0d1bb5dc0d3c880ce8f53dd3" + integrity sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-unicode-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz#5eae747fe39eacf13a8bd006a4fb0b5d1fa5e9b1" + integrity sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-transform-unicode-sets-regex@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz#65114c17b4ffc20fa5b163c63c70c0d25621fabe" + integrity sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/preset-env@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.26.0.tgz#30e5c6bc1bcc54865bff0c5a30f6d4ccdc7fa8b1" + integrity sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw== + dependencies: + "@babel/compat-data" "^7.26.0" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.9" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.9" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.9" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.25.9" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.9" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-import-assertions" "^7.26.0" + "@babel/plugin-syntax-import-attributes" "^7.26.0" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.25.9" + "@babel/plugin-transform-async-generator-functions" "^7.25.9" + "@babel/plugin-transform-async-to-generator" "^7.25.9" + "@babel/plugin-transform-block-scoped-functions" "^7.25.9" + "@babel/plugin-transform-block-scoping" "^7.25.9" + "@babel/plugin-transform-class-properties" "^7.25.9" + "@babel/plugin-transform-class-static-block" "^7.26.0" + "@babel/plugin-transform-classes" "^7.25.9" + "@babel/plugin-transform-computed-properties" "^7.25.9" + "@babel/plugin-transform-destructuring" "^7.25.9" + "@babel/plugin-transform-dotall-regex" "^7.25.9" + "@babel/plugin-transform-duplicate-keys" "^7.25.9" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.9" + "@babel/plugin-transform-dynamic-import" "^7.25.9" + "@babel/plugin-transform-exponentiation-operator" "^7.25.9" + "@babel/plugin-transform-export-namespace-from" "^7.25.9" + "@babel/plugin-transform-for-of" "^7.25.9" + "@babel/plugin-transform-function-name" "^7.25.9" + "@babel/plugin-transform-json-strings" "^7.25.9" + "@babel/plugin-transform-literals" "^7.25.9" + "@babel/plugin-transform-logical-assignment-operators" "^7.25.9" + "@babel/plugin-transform-member-expression-literals" "^7.25.9" + "@babel/plugin-transform-modules-amd" "^7.25.9" + "@babel/plugin-transform-modules-commonjs" "^7.25.9" + "@babel/plugin-transform-modules-systemjs" "^7.25.9" + "@babel/plugin-transform-modules-umd" "^7.25.9" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.25.9" + "@babel/plugin-transform-new-target" "^7.25.9" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.25.9" + "@babel/plugin-transform-numeric-separator" "^7.25.9" + "@babel/plugin-transform-object-rest-spread" "^7.25.9" + "@babel/plugin-transform-object-super" "^7.25.9" + "@babel/plugin-transform-optional-catch-binding" "^7.25.9" + "@babel/plugin-transform-optional-chaining" "^7.25.9" + "@babel/plugin-transform-parameters" "^7.25.9" + "@babel/plugin-transform-private-methods" "^7.25.9" + "@babel/plugin-transform-private-property-in-object" "^7.25.9" + "@babel/plugin-transform-property-literals" "^7.25.9" + "@babel/plugin-transform-regenerator" "^7.25.9" + "@babel/plugin-transform-regexp-modifiers" "^7.26.0" + "@babel/plugin-transform-reserved-words" "^7.25.9" + "@babel/plugin-transform-shorthand-properties" "^7.25.9" + "@babel/plugin-transform-spread" "^7.25.9" + "@babel/plugin-transform-sticky-regex" "^7.25.9" + "@babel/plugin-transform-template-literals" "^7.25.9" + "@babel/plugin-transform-typeof-symbol" "^7.25.9" + "@babel/plugin-transform-unicode-escapes" "^7.25.9" + "@babel/plugin-transform-unicode-property-regex" "^7.25.9" + "@babel/plugin-transform-unicode-regex" "^7.25.9" + "@babel/plugin-transform-unicode-sets-regex" "^7.25.9" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.10" + babel-plugin-polyfill-corejs3 "^0.10.6" + babel-plugin-polyfill-regenerator "^0.6.1" + core-js-compat "^3.38.1" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@^7.8.4": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" + integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/traverse@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84" + integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/generator" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/template" "^7.25.9" + "@babel/types" "^7.25.9" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.4.4": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.0.tgz#deabd08d6b753bc8e0f198f8709fb575e31774ff" + integrity sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + +"@hotwired/stimulus@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.2.tgz#071aab59c600fed95b97939e605ff261a4251608" + integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@rails/actioncable@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-8.0.0.tgz#b12d87d4c2bb152c4445e2c168df93b585068e7c" + integrity sha512-9IXyJeaBggOzlD3pF4/yWELdyUWZm/KTyKBRqxNf9laLBXPqxJt3t6fO+X4s0WajMR8cIhzkxvq1gxsXVbn3LA== + +"@rollup/plugin-babel@^6.0.4": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz#bd698e351fa9aa9619fcae780aea2a603d98e4c4" + integrity sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@rollup/pluginutils" "^5.0.1" + +"@rollup/plugin-commonjs@^28.0.1": + version "28.0.1" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.1.tgz#e2138e31cc0637676dc3d5cae7739131f7cd565e" + integrity sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA== + dependencies: + "@rollup/pluginutils" "^5.0.1" + commondir "^1.0.1" + estree-walker "^2.0.2" + fdir "^6.2.0" + is-reference "1.2.1" + magic-string "^0.30.3" + picomatch "^4.0.2" + +"@rollup/plugin-node-resolve@^15.3.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz#efbb35515c9672e541c08d59caba2eff492a55d5" + integrity sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag== + dependencies: + "@rollup/pluginutils" "^5.0.1" + "@types/resolve" "1.20.2" + deepmerge "^4.2.2" + is-module "^1.0.0" + resolve "^1.22.1" + +"@rollup/pluginutils@^5.0.1": + version "5.1.3" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.3.tgz#3001bf1a03f3ad24457591f2c259c8e514e0dbdf" + integrity sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + +"@rollup/rollup-android-arm-eabi@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz#e3c9cc13f144ba033df4d2c3130a214dc8e3473e" + integrity sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw== + +"@rollup/rollup-android-arm64@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz#0474250fcb5871aca952e249a0c3270fc4310b55" + integrity sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA== + +"@rollup/rollup-darwin-arm64@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz#77c29b4f9c430c1624f1a6835f2a7e82be3d16f2" + integrity sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q== + +"@rollup/rollup-darwin-x64@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz#7d87711f641a458868758cbf110fb32eabd6a25a" + integrity sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ== + +"@rollup/rollup-freebsd-arm64@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz#662f808d2780e4e91021ac9ee7ed800862bb9a57" + integrity sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw== + +"@rollup/rollup-freebsd-x64@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz#71e5a7bcfcbe51d8b65d158675acec1307edea79" + integrity sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA== + +"@rollup/rollup-linux-arm-gnueabihf@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz#08f67fcec61ee18f8b33b3f403a834ab8f3aa75d" + integrity sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w== + +"@rollup/rollup-linux-arm-musleabihf@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz#2e1ad4607f86475b1731556359c6070eb8f4b109" + integrity sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A== + +"@rollup/rollup-linux-arm64-gnu@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz#c65d559dcb0d3dabea500cf7b8215959ae6cccf8" + integrity sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg== + +"@rollup/rollup-linux-arm64-musl@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz#6739f7eb33e20466bb88748519c98ce8dee23922" + integrity sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz#8d9fe9471c256e55278cb1f7b1c977cd8fe6df20" + integrity sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ== + +"@rollup/rollup-linux-riscv64-gnu@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz#9a467f7ad5b61c9d66b24e79a3c57cb755d02c35" + integrity sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw== + +"@rollup/rollup-linux-s390x-gnu@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz#efaddf22df27b87a267a731fbeb9539e92cd4527" + integrity sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg== + +"@rollup/rollup-linux-x64-gnu@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz#a959eccb04b07fd1591d7ff745a6865faa7042cd" + integrity sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q== + +"@rollup/rollup-linux-x64-musl@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz#927764f1da1f2dd50943716dec93796d10cb6e99" + integrity sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw== + +"@rollup/rollup-win32-arm64-msvc@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz#030b6cc607d845da23dced624e47fb45de105840" + integrity sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A== + +"@rollup/rollup-win32-ia32-msvc@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz#3457a3f44a84f51d8097c3606429e01f0d2d0ec2" + integrity sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ== + +"@rollup/rollup-win32-x64-msvc@4.27.4": + version "4.27.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz#67d516613c9f2fe42e2d8b78e252d0003179d92c" + integrity sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug== + +"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/node@*": + version "22.9.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.9.3.tgz#08f3d64b3bc6d74b162d36f60213e8a6704ef2b4" + integrity sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw== + dependencies: + undici-types "~6.19.8" + +"@types/resolve@1.20.2": + version "1.20.2" + resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" + integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== + +acorn@^8.8.2: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + +babel-plugin-polyfill-corejs2@^0.4.10: + version "0.4.12" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz#ca55bbec8ab0edeeef3d7b8ffd75322e210879a9" + integrity sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.6.3" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.10.6: + version "0.10.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7" + integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.2" + core-js-compat "^3.38.0" + +babel-plugin-polyfill-regenerator@^0.6.1: + version "0.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz#abeb1f3f1c762eace37587f42548b08b57789bc8" + integrity sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.3" + +browserslist@^4.24.0, browserslist@^4.24.2: + version "4.24.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" + integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== + dependencies: + caniuse-lite "^1.0.30001669" + electron-to-chromium "^1.5.41" + node-releases "^2.0.18" + update-browserslist-db "^1.1.1" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +caniuse-lite@^1.0.30001669: + version "1.0.30001684" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz#0eca437bab7d5f03452ff0ef9de8299be6b08e16" + integrity sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +core-js-compat@^3.38.0, core-js-compat@^3.38.1: + version "3.39.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.39.0.tgz#b12dccb495f2601dc860bdbe7b4e3ffa8ba63f61" + integrity sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw== + dependencies: + browserslist "^4.24.2" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +electron-to-chromium@^1.5.41: + version "1.5.64" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz#ac8c4c89075d35a1514b620f47dfe48a71ec3697" + integrity sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ== + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fdir@^6.2.0: + version "6.4.2" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689" + integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +idiomorph@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/idiomorph/-/idiomorph-0.3.0.tgz#f6675bc5bef1a72c94021e43141a3f605d2d6288" + integrity sha512-UhV1Ey5xCxIwR9B+OgIjQa+1Jx99XQ1vQHUsKBU1RpQzCx1u+b+N6SOXgf5mEJDqemUI/ffccu6+71l2mJUsRA== + +is-core-module@^2.13.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + +is-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== + +is-reference@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" + integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== + dependencies: + "@types/estree" "*" + +jest-worker@^26.2.1: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^3.0.2, jsesc@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +magic-string@^0.30.3: + version "0.30.13" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.13.tgz#92438e3ff4946cf54f18247c981e5c161c46683c" + integrity sha512-8rYBO+MsWkgjDSOvLomYnzhdwEG51olQ4zL5KXnNJWV5MNmrb4rTZdrtkhxjnD/QyZUqR/Z/XDsUs/4ej2nx0g== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +regenerate-unicode-properties@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" + integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regenerator-transform@^0.15.2: + version "0.15.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexpu-core@^6.1.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.2.0.tgz#0e5190d79e542bf294955dccabae04d3c7d53826" + integrity sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.2.0" + regjsgen "^0.8.0" + regjsparser "^0.12.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsgen@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" + integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== + +regjsparser@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.12.0.tgz#0e846df6c6530586429377de56e0475583b088dc" + integrity sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ== + dependencies: + jsesc "~3.0.2" + +resolve@^1.14.2, resolve@^1.22.1: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rollup-plugin-terser@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" + integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== + dependencies: + "@babel/code-frame" "^7.10.4" + jest-worker "^26.2.1" + serialize-javascript "^4.0.0" + terser "^5.0.0" + +rollup@^4.27.4: + version "4.27.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.27.4.tgz#b23e4ef4fe4d0d87f5237dacf63f95a499503897" + integrity sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw== + dependencies: + "@types/estree" "1.0.6" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.27.4" + "@rollup/rollup-android-arm64" "4.27.4" + "@rollup/rollup-darwin-arm64" "4.27.4" + "@rollup/rollup-darwin-x64" "4.27.4" + "@rollup/rollup-freebsd-arm64" "4.27.4" + "@rollup/rollup-freebsd-x64" "4.27.4" + "@rollup/rollup-linux-arm-gnueabihf" "4.27.4" + "@rollup/rollup-linux-arm-musleabihf" "4.27.4" + "@rollup/rollup-linux-arm64-gnu" "4.27.4" + "@rollup/rollup-linux-arm64-musl" "4.27.4" + "@rollup/rollup-linux-powerpc64le-gnu" "4.27.4" + "@rollup/rollup-linux-riscv64-gnu" "4.27.4" + "@rollup/rollup-linux-s390x-gnu" "4.27.4" + "@rollup/rollup-linux-x64-gnu" "4.27.4" + "@rollup/rollup-linux-x64-musl" "4.27.4" + "@rollup/rollup-win32-arm64-msvc" "4.27.4" + "@rollup/rollup-win32-ia32-msvc" "4.27.4" + "@rollup/rollup-win32-x64-msvc" "4.27.4" + fsevents "~2.3.2" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +supports-color@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +terser@^5.0.0: + version "5.36.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.36.0.tgz#8b0dbed459ac40ff7b4c9fd5a3a2029de105180e" + integrity sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +undici-types@~6.19.8: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" + integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz#a0401aee72714598f739b68b104e4fe3a0cb3c71" + integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==