achilles 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/CONTRIBUTING.md +122 -0
- data/MAINTAINERS.md +53 -0
- data/README.md +248 -14
- data/SECURITY.md +50 -0
- data/app/javascript/achilles/application/application.js +40 -3
- data/app/javascript/achilles/application/dom-mutation-observer/observer.js +11 -1
- data/app/javascript/achilles/application/hooks-manager/turbo.js +28 -7
- data/app/javascript/achilles/components/component_base.js +19 -2
- data/app/javascript/achilles/components/component_parser.js +22 -2
- data/app/javascript/achilles/components/components_registry.js +34 -14
- data/docs/core-js-gaps.md +26 -0
- data/docs/release-checklist.md +42 -23
- data/docs/releases/v1.1.0.md +74 -0
- data/docs/releases/v1.1.1.md +46 -0
- data/docs/upgrading-to-1.1.0.md +144 -0
- data/docs/upgrading.md +31 -0
- data/lib/achilles/version.rb +1 -1
- data/lib/achilles.rb +1 -0
- metadata +10 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d860cd0be6faa8af39117c4dc6feadb2445f48ccfd687963a3a8eeddbe1c3b95
|
|
4
|
+
data.tar.gz: '09cdfabdfa0895b1a3c7a92726baf49cb234a9a716b8a1e3a65c7eb6e578904e'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7899f56529ad2a867a289b546241023e235a1d848d3a22ceb1a396fb92a515c9edeb3b50decdec7d37e952f9c5fc524326c8d1fc3456e78f5e1c7db5be53c10d
|
|
7
|
+
data.tar.gz: 7d43d1c196f608be65a27d42840cdd0a3f3bac7bb86870dec876b89bdbfdf63408465dabd265986322638300ab0d8287c3a747e2b2830ccc3c824bf74217318e
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Achilles will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 1.1.1
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed Turbo browser history restoration so components restored from cached DOM
|
|
10
|
+
are registered and set up again when their registry entries were already
|
|
11
|
+
removed.
|
|
12
|
+
- Fixed component subtree deregistration so child components are removed with
|
|
13
|
+
their parent and cannot block later re-registration.
|
|
14
|
+
- Added browser system coverage for back, forward, restored nested components,
|
|
15
|
+
restored form-field listeners, Turbo-replaced form restoration, and duplicate
|
|
16
|
+
listener prevention.
|
|
17
|
+
|
|
18
|
+
## 1.1.0
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Added explicit `Application#start` and `Application#stop` lifecycle methods.
|
|
23
|
+
- Added opt-in `Application#strictLifecycleErrors` handling for tests and
|
|
24
|
+
development.
|
|
25
|
+
- Added browser system coverage for nested components inside Turbo form
|
|
26
|
+
replacement and Turbo Drive navigation.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- `Application` no longer starts automatically from the constructor. Applications
|
|
31
|
+
should register component classes, then call `achilles.start()`. See
|
|
32
|
+
[docs/upgrading-to-1.1.0.md](docs/upgrading-to-1.1.0.md).
|
|
33
|
+
- Elements with `data-component-class` must now have a non-empty `id`; invalid
|
|
34
|
+
component roots are skipped with a console error.
|
|
35
|
+
- Component teardown now runs from child components to parent components.
|
|
36
|
+
- Component parentage now follows DOM ancestry under the synthetic `Page` root.
|
|
37
|
+
- Turbo lifecycle hooks are now attached by `start()` and removed by `stop()`.
|
|
38
|
+
- Achilles now requires `turbo-rails` so Turbo importmap assets are available to
|
|
39
|
+
host applications.
|
|
40
|
+
|
|
5
41
|
## 1.0.0
|
|
6
42
|
|
|
7
43
|
### Added
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Code Of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We want Achilles to be a respectful, useful, and practical open source project.
|
|
6
|
+
|
|
7
|
+
Everyone participating in the project is expected to communicate with clarity,
|
|
8
|
+
patience, and respect. Disagreement is fine. Harassment, personal attacks, and
|
|
9
|
+
abusive behavior are not.
|
|
10
|
+
|
|
11
|
+
## Expected Behavior
|
|
12
|
+
|
|
13
|
+
- Be respectful of differing experience levels and viewpoints.
|
|
14
|
+
- Keep technical criticism focused on the code, design, or documentation.
|
|
15
|
+
- Assume good intent, but be direct when something is unclear or risky.
|
|
16
|
+
- Help keep issues and pull requests actionable.
|
|
17
|
+
- Respect maintainers' time and project scope.
|
|
18
|
+
|
|
19
|
+
## Unacceptable Behavior
|
|
20
|
+
|
|
21
|
+
- Harassment, threats, or personal attacks.
|
|
22
|
+
- Insults, slurs, or discriminatory language.
|
|
23
|
+
- Public or private abuse of contributors or maintainers.
|
|
24
|
+
- Publishing someone's private information without permission.
|
|
25
|
+
- Repeated off-topic disruption after maintainers ask for the discussion to
|
|
26
|
+
stop or move elsewhere.
|
|
27
|
+
|
|
28
|
+
## Enforcement
|
|
29
|
+
|
|
30
|
+
Maintainers may remove comments, close issues, reject pull requests, or block
|
|
31
|
+
participants who violate this code of conduct.
|
|
32
|
+
|
|
33
|
+
To report a concern, email:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
jey@jeygeethan.com
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Reports will be reviewed privately. Please include relevant links, screenshots,
|
|
40
|
+
or context when possible.
|
|
41
|
+
|
|
42
|
+
## Scope
|
|
43
|
+
|
|
44
|
+
This code of conduct applies to Achilles project spaces, including GitHub
|
|
45
|
+
issues, pull requests, discussions, release comments, and private project
|
|
46
|
+
communication with maintainers.
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for taking the time to improve Achilles.
|
|
4
|
+
|
|
5
|
+
Achilles is intentionally small. Contributions should keep the public API clear,
|
|
6
|
+
the Rails + Turbo integration reliable, and the documentation practical for
|
|
7
|
+
applications that already use the gem.
|
|
8
|
+
|
|
9
|
+
## Local Setup
|
|
10
|
+
|
|
11
|
+
Install dependencies:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bundle install
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Run the dummy Rails app:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bin/rails server
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Open:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
http://localhost:3000/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The dummy app includes a working counter component that exercises the basic
|
|
30
|
+
Achilles flow.
|
|
31
|
+
|
|
32
|
+
## Test Commands
|
|
33
|
+
|
|
34
|
+
Run the Rails and JavaScript lifecycle tests:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bin/rails test
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Run the browser system test:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bin/rails test:system
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Run JavaScript syntax checks:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
for file in $(find app/javascript/achilles test/dummy/app/javascript -name '*.js' -print); do node --input-type=module --check < "$file" || exit 1; done
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Run the dummy app asset precompile check:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
RAILS_ENV=test bin/rails app:assets:precompile
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Run the full local verification set:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bin/rails test
|
|
62
|
+
bin/rails test:system
|
|
63
|
+
for file in $(find app/javascript/achilles test/dummy/app/javascript -name '*.js' -print); do node --input-type=module --check < "$file" || exit 1; done
|
|
64
|
+
RAILS_ENV=test bin/rails app:assets:precompile
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## System Test Browser Requirements
|
|
68
|
+
|
|
69
|
+
System tests use Selenium with headless Chrome.
|
|
70
|
+
|
|
71
|
+
On CI, GitHub's Ubuntu runner provides Chrome. Locally, set these environment
|
|
72
|
+
variables if Chrome or chromedriver are installed in non-standard locations:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
CHROME_BIN=/path/to/chrome CHROMEDRIVER_PATH=/path/to/chromedriver bin/rails test:system
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
If Chrome is not available, the system test base skips browser tests cleanly.
|
|
79
|
+
|
|
80
|
+
## Pull Request Guidelines
|
|
81
|
+
|
|
82
|
+
- Keep changes scoped.
|
|
83
|
+
- Add or update tests for behavior changes.
|
|
84
|
+
- Update the README or docs for public API changes.
|
|
85
|
+
- Add or update an upgrade guide for changes existing applications must make.
|
|
86
|
+
- Mention breaking changes clearly in the pull request.
|
|
87
|
+
- Do not introduce a new runtime dependency without explaining why it belongs in
|
|
88
|
+
a small lifecycle gem.
|
|
89
|
+
- Prefer browser DOM APIs in Achilles internals.
|
|
90
|
+
- Keep jQuery usage out of Achilles internals. Applications may still use jQuery
|
|
91
|
+
explicitly in their own components.
|
|
92
|
+
|
|
93
|
+
## Public API Expectations
|
|
94
|
+
|
|
95
|
+
Treat these as public API:
|
|
96
|
+
|
|
97
|
+
- `Application`
|
|
98
|
+
- `ComponentBase`
|
|
99
|
+
- `ComponentsClassMapper`
|
|
100
|
+
- `data-component-class`
|
|
101
|
+
- `setup()`
|
|
102
|
+
- `teardown()`
|
|
103
|
+
- `rootElement()`
|
|
104
|
+
- `rootNode()`
|
|
105
|
+
- `rootElementSelector()`
|
|
106
|
+
|
|
107
|
+
Changes to these APIs need tests, documentation, and changelog notes.
|
|
108
|
+
|
|
109
|
+
## Release Process
|
|
110
|
+
|
|
111
|
+
Use [docs/release-checklist.md](docs/release-checklist.md) for prereleases and
|
|
112
|
+
final releases.
|
|
113
|
+
|
|
114
|
+
Maintainer release ownership and project decision guidelines are documented in
|
|
115
|
+
[MAINTAINERS.md](MAINTAINERS.md).
|
|
116
|
+
|
|
117
|
+
Before releasing:
|
|
118
|
+
|
|
119
|
+
- confirm CI is green
|
|
120
|
+
- run the full local verification set
|
|
121
|
+
- build the gem with `gem build achilles.gemspec`
|
|
122
|
+
- test release candidates in at least one real application
|
data/MAINTAINERS.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Maintainers
|
|
2
|
+
|
|
3
|
+
Achilles is maintained as a small, stable Rails + Turbo lifecycle gem.
|
|
4
|
+
|
|
5
|
+
The maintainer goal is to keep the public API easy to understand, the runtime
|
|
6
|
+
surface small, and releases safe for applications that already depend on the
|
|
7
|
+
gem.
|
|
8
|
+
|
|
9
|
+
## Decision Making
|
|
10
|
+
|
|
11
|
+
Maintainers should prefer changes that:
|
|
12
|
+
|
|
13
|
+
- preserve the small public API
|
|
14
|
+
- improve reliability across Rails, Turbo, and importmap applications
|
|
15
|
+
- reduce hidden runtime dependencies
|
|
16
|
+
- make migration or debugging easier for existing applications
|
|
17
|
+
- include tests for changed behavior
|
|
18
|
+
|
|
19
|
+
Breaking changes are acceptable when they make the project simpler, safer, or
|
|
20
|
+
more predictable. They should be documented in `CHANGELOG.md`, covered by tests,
|
|
21
|
+
and called out in migration notes when existing applications need code changes.
|
|
22
|
+
|
|
23
|
+
## Release Ownership
|
|
24
|
+
|
|
25
|
+
Before publishing a release, a maintainer should:
|
|
26
|
+
|
|
27
|
+
- confirm CI is green
|
|
28
|
+
- run the local verification set in `CONTRIBUTING.md`
|
|
29
|
+
- follow `docs/release-checklist.md`
|
|
30
|
+
- test release candidates in at least one real Rails application when behavior
|
|
31
|
+
changes affect runtime integration
|
|
32
|
+
|
|
33
|
+
Patch releases should be narrow and low risk. Minor releases can add compatible
|
|
34
|
+
APIs or documentation improvements. Major releases may remove deprecated
|
|
35
|
+
behavior or tighten public contracts.
|
|
36
|
+
|
|
37
|
+
## Security Reports
|
|
38
|
+
|
|
39
|
+
Security reports should follow `SECURITY.md`. Reports are handled privately
|
|
40
|
+
until there is a fix or a clear public response.
|
|
41
|
+
|
|
42
|
+
## Community Standards
|
|
43
|
+
|
|
44
|
+
Project participation is covered by `CODE_OF_CONDUCT.md`. Maintainers may close
|
|
45
|
+
issues, reject pull requests, edit discussions, or block participants when
|
|
46
|
+
needed to keep the project focused and respectful.
|
|
47
|
+
|
|
48
|
+
## Adding Maintainers
|
|
49
|
+
|
|
50
|
+
New maintainers should already have a history of useful issues, documentation,
|
|
51
|
+
or code contributions. They should understand the project scope, support the
|
|
52
|
+
public API expectations in `CONTRIBUTING.md`, and be comfortable reviewing
|
|
53
|
+
changes conservatively.
|
data/README.md
CHANGED
|
@@ -1,12 +1,53 @@
|
|
|
1
1
|
# Achilles
|
|
2
2
|
|
|
3
3
|
Achilles is a small JavaScript lifecycle layer for Rails + Turbo applications.
|
|
4
|
-
It is
|
|
5
|
-
|
|
4
|
+
It is an explicit component-class alternative to Stimulus for teams that prefer
|
|
5
|
+
plain JavaScript classes mapped directly to DOM nodes.
|
|
6
6
|
|
|
7
7
|
Achilles scans the page for elements with `data-component-class`, instantiates
|
|
8
8
|
the matching JavaScript class, and calls `setup` and `teardown` as Turbo renders
|
|
9
|
-
new pages.
|
|
9
|
+
new pages or new component markup is inserted.
|
|
10
|
+
|
|
11
|
+
Current applications should use Achilles `1.1.1`. If you are upgrading an
|
|
12
|
+
existing app, start with the [1.1.0 upgrade guide](docs/upgrading-to-1.1.0.md)
|
|
13
|
+
and then read the [1.1.1 release note](docs/releases/v1.1.1.md).
|
|
14
|
+
|
|
15
|
+
## Why Achilles?
|
|
16
|
+
|
|
17
|
+
Rails and Turbo make server-rendered interfaces productive, but many apps still
|
|
18
|
+
need page-specific JavaScript for menus, forms, filters, widgets, charts, and
|
|
19
|
+
small interaction islands.
|
|
20
|
+
|
|
21
|
+
Achilles keeps that JavaScript close to the DOM without requiring controller
|
|
22
|
+
naming conventions or a build step. You register classes explicitly, mark the
|
|
23
|
+
HTML root node, and implement lifecycle methods.
|
|
24
|
+
|
|
25
|
+
Use Achilles when you want:
|
|
26
|
+
|
|
27
|
+
- explicit JavaScript classes instead of controller naming conventions
|
|
28
|
+
- lifecycle hooks that match Turbo navigation
|
|
29
|
+
- no internal jQuery dependency
|
|
30
|
+
- no JavaScript build step
|
|
31
|
+
- predictable setup and teardown for server-rendered UI
|
|
32
|
+
- simple dynamic DOM registration through `MutationObserver`
|
|
33
|
+
|
|
34
|
+
## Achilles vs Stimulus
|
|
35
|
+
|
|
36
|
+
Stimulus is a strong default for many Rails apps. Achilles is intentionally
|
|
37
|
+
smaller and more explicit.
|
|
38
|
+
|
|
39
|
+
| Concern | Achilles | Stimulus |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| Class registration | Explicit mapper registration | File and identifier conventions |
|
|
42
|
+
| DOM marker | `data-component-class` | `data-controller` |
|
|
43
|
+
| Root element API | `this.rootElement()` | `this.element` |
|
|
44
|
+
| Lifecycle | `setup()` and `teardown()` | `connect()` and `disconnect()` |
|
|
45
|
+
| Targets/actions | Use standard DOM APIs | Built-in targets/actions |
|
|
46
|
+
| Dependency | Rails, Turbo, Importmap | Hotwire Stimulus |
|
|
47
|
+
|
|
48
|
+
Choose Achilles if you want a tiny lifecycle layer with explicit class mapping.
|
|
49
|
+
Choose Stimulus if you want its controller ecosystem, targets, values, actions,
|
|
50
|
+
and conventions.
|
|
10
51
|
|
|
11
52
|
## Requirements
|
|
12
53
|
|
|
@@ -39,8 +80,12 @@ import { CounterComponent } from "components/counter_component";
|
|
|
39
80
|
|
|
40
81
|
const achilles = new Application();
|
|
41
82
|
achilles.componentsClassMapper.addComponentClass("CounterComponent", CounterComponent);
|
|
83
|
+
achilles.start();
|
|
42
84
|
```
|
|
43
85
|
|
|
86
|
+
Call `start()` after registering component classes. Achilles parses the current
|
|
87
|
+
page and attaches Turbo lifecycle hooks when the application starts.
|
|
88
|
+
|
|
44
89
|
Create components by extending `ComponentBase`:
|
|
45
90
|
|
|
46
91
|
```js
|
|
@@ -70,17 +115,151 @@ Mark the component root in your view:
|
|
|
70
115
|
<button id="counter" data-component-class="CounterComponent">0</button>
|
|
71
116
|
```
|
|
72
117
|
|
|
73
|
-
Every component root must have a unique `id`. Achilles uses that id to
|
|
74
|
-
the component, find its root element, and avoid running setup twice for
|
|
75
|
-
DOM node.
|
|
118
|
+
Every component root must have a non-empty unique `id`. Achilles uses that id to
|
|
119
|
+
register the component, find its root element, and avoid running setup twice for
|
|
120
|
+
the same DOM node. Components without ids are skipped and reported in the browser
|
|
121
|
+
console.
|
|
122
|
+
|
|
123
|
+
## Dynamic Components
|
|
124
|
+
|
|
125
|
+
Achilles watches the document for inserted component markup. If Turbo Streams,
|
|
126
|
+
custom JavaScript, or another UI flow adds a matching element, Achilles parses
|
|
127
|
+
and sets it up automatically.
|
|
128
|
+
|
|
129
|
+
```erb
|
|
130
|
+
<div id="notification-42" data-component-class="NotificationComponent">
|
|
131
|
+
Saved successfully
|
|
132
|
+
</div>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
import { ComponentBase } from "achilles/components/component_base";
|
|
137
|
+
|
|
138
|
+
class NotificationComponent extends ComponentBase {
|
|
139
|
+
setup() {
|
|
140
|
+
this.timeout = window.setTimeout(() => {
|
|
141
|
+
this.rootElement().remove();
|
|
142
|
+
}, 3000);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
teardown() {
|
|
146
|
+
window.clearTimeout(this.timeout);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { NotificationComponent };
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Register the component class once:
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
achilles.componentsClassMapper.addComponentClass("NotificationComponent", NotificationComponent);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Nested Components
|
|
160
|
+
|
|
161
|
+
Achilles keeps a component tree rooted at a single synthetic `Page` component.
|
|
162
|
+
A component's parent is its nearest ancestor element with `data-component-class`.
|
|
163
|
+
If there is no component ancestor, its parent is `Page`.
|
|
164
|
+
|
|
165
|
+
```erb
|
|
166
|
+
<div id="dashboard" data-component-class="DashboardComponent">
|
|
167
|
+
<div id="filters" data-component-class="FiltersComponent"></div>
|
|
168
|
+
</div>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
This creates the following component tree:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
Page
|
|
175
|
+
dashboard
|
|
176
|
+
filters
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Example App
|
|
180
|
+
|
|
181
|
+
The dummy Rails app includes a working counter component. See
|
|
182
|
+
[examples/README.md](examples/README.md) for the files and local run command.
|
|
76
183
|
|
|
77
184
|
## Lifecycle
|
|
78
185
|
|
|
79
|
-
- `setup` runs after `turbo:load` and after new matching DOM nodes are inserted.
|
|
80
|
-
- `teardown` runs before Turbo renders a new page.
|
|
81
|
-
- `
|
|
82
|
-
-
|
|
83
|
-
-
|
|
186
|
+
- `setup()` runs after `turbo:load` and after new matching DOM nodes are inserted.
|
|
187
|
+
- `teardown()` runs before Turbo renders a new page.
|
|
188
|
+
- `setup()` and `teardown()` are called once per registered component instance.
|
|
189
|
+
- Parent components are set up before their children.
|
|
190
|
+
- Child components are torn down before their parents.
|
|
191
|
+
- Components that attach listeners, timers, observers, subscriptions, or widgets
|
|
192
|
+
should clean them up in `teardown()`.
|
|
193
|
+
- Lifecycle errors are logged and swallowed by default so one broken component
|
|
194
|
+
does not stop the page. Enable strict mode in tests or development when errors
|
|
195
|
+
should be re-raised:
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
achilles.strictLifecycleErrors = true;
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## API Reference
|
|
202
|
+
|
|
203
|
+
### `Application`
|
|
204
|
+
|
|
205
|
+
The top-level Achilles application object.
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
import { Application } from "achilles/application/application";
|
|
209
|
+
|
|
210
|
+
const achilles = new Application();
|
|
211
|
+
achilles.start();
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Useful properties:
|
|
215
|
+
|
|
216
|
+
- `componentsClassMapper`: register component classes by name.
|
|
217
|
+
- `componentRegistry`: inspect or manage registered component instances.
|
|
218
|
+
- `strictLifecycleErrors`: re-raise lifecycle errors after logging them.
|
|
219
|
+
- `timezone`: access the configured app timezone.
|
|
220
|
+
|
|
221
|
+
Call `start()` after registering component classes. Call `stop()` when an
|
|
222
|
+
application instance should remove its Turbo hooks and stop observing the DOM.
|
|
223
|
+
|
|
224
|
+
### `ComponentsClassMapper`
|
|
225
|
+
|
|
226
|
+
Maps `data-component-class` values to JavaScript classes.
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
achilles.componentsClassMapper.addComponentClass("MenuComponent", MenuComponent);
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### `ComponentBase`
|
|
233
|
+
|
|
234
|
+
Base class for application components.
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
import { ComponentBase } from "achilles/components/component_base";
|
|
238
|
+
|
|
239
|
+
class MenuComponent extends ComponentBase {
|
|
240
|
+
setup() {}
|
|
241
|
+
teardown() {}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Useful methods:
|
|
246
|
+
|
|
247
|
+
- `setup()`: override to initialize behavior.
|
|
248
|
+
- `teardown()`: override to clean up behavior before Turbo renders a new page.
|
|
249
|
+
- `rootElement()`: returns the component root DOM element.
|
|
250
|
+
- `rootNode()`: alias for `rootElement()`.
|
|
251
|
+
- `rootElementSelector()`: returns a CSS selector for the component id.
|
|
252
|
+
|
|
253
|
+
### Component Markup
|
|
254
|
+
|
|
255
|
+
```erb
|
|
256
|
+
<div id="account-menu" data-component-class="MenuComponent"></div>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The `data-component-class` value must match a class registered with
|
|
260
|
+
`componentsClassMapper`. The element must also have a non-empty unique `id`.
|
|
261
|
+
Nested components are parented by DOM ancestry, with top-level components
|
|
262
|
+
parented by the synthetic `Page` component.
|
|
84
263
|
|
|
85
264
|
## Timezone
|
|
86
265
|
|
|
@@ -93,18 +272,73 @@ value through `achilles.timezone.timezoneString`.
|
|
|
93
272
|
|
|
94
273
|
If no timezone is present, Achilles falls back to `Etc/UTC`.
|
|
95
274
|
|
|
275
|
+
## Upgrading
|
|
276
|
+
|
|
277
|
+
Applications upgrading to `1.1.0` should read the
|
|
278
|
+
[1.1.0 upgrade guide](docs/upgrading-to-1.1.0.md). The complete upgrade index
|
|
279
|
+
lives in [docs/upgrading.md](docs/upgrading.md), and the GitHub release draft is
|
|
280
|
+
available at [docs/releases/v1.1.1.md](docs/releases/v1.1.1.md).
|
|
281
|
+
|
|
282
|
+
## Upgrading From 0.1.3
|
|
283
|
+
|
|
284
|
+
Achilles `1.0.0` changes `rootElement()` to return a DOM element. It no longer
|
|
285
|
+
returns a jQuery object when `window.$` is present.
|
|
286
|
+
|
|
287
|
+
Old jQuery-style code:
|
|
288
|
+
|
|
289
|
+
```js
|
|
290
|
+
this.rootElement().addClass("is-open");
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Use DOM APIs:
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
this.rootElement().classList.add("is-open");
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Or wrap explicitly if the application still uses jQuery:
|
|
300
|
+
|
|
301
|
+
```js
|
|
302
|
+
$(this.rootElement()).addClass("is-open");
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Applications upgrading from `0.1.3` should also read the
|
|
306
|
+
[v1 migration guide](docs/migrating-from-0.1.3-to-v1.md).
|
|
307
|
+
|
|
96
308
|
## Contributing
|
|
97
309
|
|
|
310
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, test commands, pull request
|
|
311
|
+
guidelines, and release notes. Project participation is covered by the
|
|
312
|
+
[code of conduct](CODE_OF_CONDUCT.md). Maintainer responsibilities are described
|
|
313
|
+
in [MAINTAINERS.md](MAINTAINERS.md).
|
|
314
|
+
|
|
98
315
|
Run the test suite with:
|
|
99
316
|
|
|
100
317
|
```bash
|
|
101
318
|
bin/rails test
|
|
102
319
|
```
|
|
103
320
|
|
|
104
|
-
|
|
321
|
+
Run the browser system test with:
|
|
105
322
|
|
|
106
|
-
|
|
107
|
-
|
|
323
|
+
```bash
|
|
324
|
+
bin/rails test:system
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Run the JavaScript syntax check with:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
for file in $(find app/javascript/achilles -name '*.js' -print); do node --input-type=module --check < "$file" || exit 1; done
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Run the dummy app asset precompile check with:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
RAILS_ENV=test bin/rails app:assets:precompile
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Security
|
|
340
|
+
|
|
341
|
+
Report security issues privately. See [SECURITY.md](SECURITY.md).
|
|
108
342
|
|
|
109
343
|
## License
|
|
110
344
|
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
Only the latest minor release of Achilles `1.x` receives security fixes.
|
|
6
|
+
|
|
7
|
+
| Version | Supported |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `1.x` | Yes |
|
|
10
|
+
| `< 1.0` | No |
|
|
11
|
+
|
|
12
|
+
## Reporting A Vulnerability
|
|
13
|
+
|
|
14
|
+
Please do not open a public GitHub issue for security vulnerabilities.
|
|
15
|
+
|
|
16
|
+
Report security issues by email:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
jey@jeygeethan.com
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Include:
|
|
23
|
+
|
|
24
|
+
- affected Achilles version
|
|
25
|
+
- Rails version
|
|
26
|
+
- Ruby version
|
|
27
|
+
- a description of the vulnerability
|
|
28
|
+
- reproduction steps or proof of concept
|
|
29
|
+
- whether the issue is already public
|
|
30
|
+
|
|
31
|
+
## Response Expectations
|
|
32
|
+
|
|
33
|
+
You should receive an acknowledgement within 7 days.
|
|
34
|
+
|
|
35
|
+
If the issue is confirmed, the fix will be prepared privately when practical and
|
|
36
|
+
released with a changelog entry that gives users enough information to upgrade
|
|
37
|
+
without exposing unnecessary exploit details before a fix is available.
|
|
38
|
+
|
|
39
|
+
## Scope
|
|
40
|
+
|
|
41
|
+
Security reports are most useful when they involve Achilles behavior directly,
|
|
42
|
+
including:
|
|
43
|
+
|
|
44
|
+
- unsafe DOM lifecycle behavior
|
|
45
|
+
- asset/importmap packaging issues
|
|
46
|
+
- Rails engine integration issues
|
|
47
|
+
- behavior that could cause applications to execute unintended JavaScript
|
|
48
|
+
|
|
49
|
+
General application security issues in apps that use Achilles should be reported
|
|
50
|
+
to those applications instead.
|