el-maker 0.0.0 → 0.0.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.
- package/.gitmodules +3 -0
- package/ElementMaker.js +95 -0
- package/Instructions.md +9 -0
- package/README.md +105 -1
- package/SuggestionForExtending.md +131 -0
- package/package.json +19 -3
- package/types/.kiro/specs/conversion-template/README.md +128 -0
- package/types/.kiro/specs/conversion-template/design.md +360 -0
- package/types/.kiro/specs/conversion-template/requirements.md +191 -0
- package/types/.kiro/specs/conversion-template/tasks.md +174 -0
- package/types/.kiro/steering/coding-standards.md +17 -0
- package/types/.kiro/steering/conversion-guide.md +103 -0
- package/types/.kiro/steering/declarative-configuration.md +108 -0
- package/types/.kiro/steering/emc-json-serializability.md +306 -0
- package/types/EnhancementConversionInstructions.md +1626 -0
- package/types/LICENSE +21 -0
- package/types/NewCustomElementFeature.md +683 -0
- package/types/NewEnhancementInstructions.md +395 -0
- package/types/README.md +2 -0
- package/types/agrace/types.d.ts +11 -0
- package/types/assign-gingerly/types.d.ts +476 -0
- package/types/be-a-beacon/types.d.ts +17 -0
- package/types/be-bound/types.d.ts +61 -0
- package/types/be-buttoned-up/types.d.ts +19 -0
- package/types/be-clonable/types.d.ts +36 -0
- package/types/be-committed/types.d.ts +22 -0
- package/types/be-decked-with/types.d.ts +26 -0
- package/types/be-delible/types.d.ts +25 -0
- package/types/be-reflective/types.d.ts +78 -0
- package/types/be-render-neutral/types.d.ts +29 -0
- package/types/be-typed/types.d.ts +31 -0
- package/types/do-inc/types.d.ts +56 -0
- package/types/do-invoke/types.d.ts +38 -0
- package/types/do-merge/types.d.ts +28 -0
- package/types/do-toggle/types.d.ts +31 -0
- package/types/face-up/types.d.ts +100 -0
- package/types/global.d.ts +29 -0
- package/types/id-generation/types.d.ts +26 -0
- package/types/inferencer/types.d.ts +46 -0
- package/types/mount-observer/types.d.ts +363 -0
- package/types/nested-regex-groups/types.d.ts +101 -0
- package/types/roundabout/types.d.ts +255 -0
- package/types/templ-maker/types.d.ts +43 -0
- package/types/time-ticker/types.d.ts +62 -0
- package/types/truth-sourcer/types.d.ts +44 -0
package/.gitmodules
ADDED
package/ElementMaker.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/** @import {SupportedFeaturesMap} from './types/assign-gingerly/types' */
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ElementMaker — Abstract base custom element class that declares support
|
|
7
|
+
* for a catalog of composable features via `static supportedFeatures`.
|
|
8
|
+
*
|
|
9
|
+
* Concrete elements are defined declaratively (via `defineWithFeatures` or
|
|
10
|
+
* cede scripts) by selecting which features to activate and providing
|
|
11
|
+
* per-element configuration — without writing any JavaScript class code.
|
|
12
|
+
*
|
|
13
|
+
* Features are lazily instantiated on first property access. Async fallback
|
|
14
|
+
* spawns ensure implementations are only loaded when a derived element
|
|
15
|
+
* actually uses them.
|
|
16
|
+
*
|
|
17
|
+
* @abstract
|
|
18
|
+
*/
|
|
19
|
+
export class ElementMaker extends HTMLElement {
|
|
20
|
+
/** @type {EventTarget} */
|
|
21
|
+
propagator = new EventTarget();
|
|
22
|
+
|
|
23
|
+
/** @type {ElementInternals} */
|
|
24
|
+
#internals;
|
|
25
|
+
|
|
26
|
+
/** @type {SupportedFeaturesMap} */
|
|
27
|
+
static supportedFeatures = {
|
|
28
|
+
roundabout: {
|
|
29
|
+
fallbackSpawn: () => import('roundabout-lib/roundaboutFeature.js')
|
|
30
|
+
.then(m => m.RoundaboutFeature),
|
|
31
|
+
callbackForwarding: ['connectedCallback'],
|
|
32
|
+
/** @param {ElementMaker} instance */
|
|
33
|
+
getSharedContext(instance) {
|
|
34
|
+
return {
|
|
35
|
+
internals: instance.#internals,
|
|
36
|
+
hostPropagator: instance.propagator,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
truthSourcer: {
|
|
41
|
+
fallbackSpawn: () => import('truth-sourcer/TruthSourcer.js')
|
|
42
|
+
.then(m => m.TruthSourcer),
|
|
43
|
+
callbackForwarding: ['connectedCallback', 'attributeChangedCallback'],
|
|
44
|
+
/** @param {ElementMaker} instance */
|
|
45
|
+
getSharedContext(instance) {
|
|
46
|
+
return {
|
|
47
|
+
hostPropagator: instance.propagator,
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
faceUp: {
|
|
52
|
+
fallbackSpawn: () => import('face-up/FaceUp.js')
|
|
53
|
+
.then(m => m.FaceUp),
|
|
54
|
+
callbackForwarding: [
|
|
55
|
+
'connectedCallback',
|
|
56
|
+
'disconnectedCallback',
|
|
57
|
+
'formDisabledCallback',
|
|
58
|
+
'formResetCallback',
|
|
59
|
+
'formStateRestoreCallback',
|
|
60
|
+
],
|
|
61
|
+
/** @param {ElementMaker} instance */
|
|
62
|
+
getSharedContext(instance) {
|
|
63
|
+
return {
|
|
64
|
+
internals: instance.#internals,
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
reflector: {
|
|
69
|
+
fallbackSpawn: () => import('be-reflective/ReflectorLazy.js')
|
|
70
|
+
.then(m => m.ReflectorLazy),
|
|
71
|
+
callbackForwarding: ['connectedCallback', 'disconnectedCallback'],
|
|
72
|
+
/** @param {ElementMaker} instance */
|
|
73
|
+
getSharedContext(instance) {
|
|
74
|
+
return {
|
|
75
|
+
internals: instance.#internals,
|
|
76
|
+
hostPropagator: instance.propagator,
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
templateMaker: {
|
|
81
|
+
fallbackSpawn: () => import('templ-maker/TemplateMaker.js')
|
|
82
|
+
.then(m => m.TemplateMaker),
|
|
83
|
+
callbackForwarding: ['connectedCallback'],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
static featuresConfig = {
|
|
88
|
+
lifecycleKeys: true,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
constructor() {
|
|
92
|
+
super();
|
|
93
|
+
this.#internals = this.attachInternals();
|
|
94
|
+
}
|
|
95
|
+
}
|
package/Instructions.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Instructions
|
|
2
|
+
|
|
3
|
+
## Human ask
|
|
4
|
+
|
|
5
|
+
Please become familiar with the documentation in types/NewCustomElementFeature.md (tangentially relevant) and deeply familiar with https://raw.githubusercontent.com/bahrus/assign-gingerly/refs/heads/baseline/docs/defineWithFeatures.md.
|
|
6
|
+
|
|
7
|
+
Then take a look at the README.md.
|
|
8
|
+
|
|
9
|
+
If you then have the confidence to proceed implementing the ElementMaker.js abstract custom element class, please proceed. Otherwise, post questions below.
|
package/README.md
CHANGED
|
@@ -1 +1,105 @@
|
|
|
1
|
-
# element-maker
|
|
1
|
+
# element-maker
|
|
2
|
+
|
|
3
|
+
An abstract custom element base class (`ElementMaker`) that bundles a catalog of composable features behind async lazy-loading. Concrete elements are defined declaratively — picking which features to activate and providing per-element configuration — without writing any JavaScript class code.
|
|
4
|
+
|
|
5
|
+
## How It Works
|
|
6
|
+
|
|
7
|
+
`ElementMaker` extends `HTMLElement` and declares `static supportedFeatures` with async `fallbackSpawn` functions for each feature. Feature implementations are only imported when a derived element actually uses them, so unused features add zero overhead.
|
|
8
|
+
|
|
9
|
+
Concrete elements are created via [`defineWithFeatures`](https://github.com/bahrus/assign-gingerly/blob/baseline/docs/defineWithFeatures.md), which:
|
|
10
|
+
|
|
11
|
+
1. Waits for the base class to be defined
|
|
12
|
+
2. Resolves async fallback spawns in parallel (cached per base class)
|
|
13
|
+
3. Creates a subclass dynamically
|
|
14
|
+
4. Calls `assignFeatures` with the resolved spawns + JSON config
|
|
15
|
+
5. Registers the element
|
|
16
|
+
|
|
17
|
+
This enables fully declarative element definition from JSON — including from [mount-observer cede scripts](https://github.com/bahrus/mount-observer#custom-element-definition-cede-scripts) embedded in HTML.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### From JavaScript
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { defineWithFeatures } from 'assign-gingerly/defineWithFeatures.js';
|
|
25
|
+
|
|
26
|
+
await defineWithFeatures('time-ticker', 'el-maker', {
|
|
27
|
+
assignFeatures: {
|
|
28
|
+
roundabout: {
|
|
29
|
+
customData: { raConfig: { actions: {...}, compacts: {...} } },
|
|
30
|
+
withAttrs: { base: 'tt', duration: '${base}-duration', _duration: { instanceOf: 'Number' } },
|
|
31
|
+
callbackForwarding: ['connectedCallback']
|
|
32
|
+
},
|
|
33
|
+
truthSourcer: {
|
|
34
|
+
callbackForwarding: ['connectedCallback', 'attributeChangedCallback']
|
|
35
|
+
},
|
|
36
|
+
faceUp: {
|
|
37
|
+
customData: { integrateWithRoundabout: true },
|
|
38
|
+
callbackForwarding: ['connectedCallback', 'formDisabledCallback', 'formResetCallback', 'formStateRestoreCallback']
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### From a cede script in HTML
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<time-ticker>
|
|
48
|
+
<script type="cede" data-extends="el-maker">{
|
|
49
|
+
"assignFeatures": {
|
|
50
|
+
"roundabout": {
|
|
51
|
+
"customData": { "raConfig": { ... } },
|
|
52
|
+
"withAttrs": { "base": "tt", "duration": "${base}-duration" },
|
|
53
|
+
"callbackForwarding": ["connectedCallback"]
|
|
54
|
+
},
|
|
55
|
+
"truthSourcer": {
|
|
56
|
+
"callbackForwarding": ["connectedCallback", "attributeChangedCallback"]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}</script>
|
|
60
|
+
</time-ticker>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## What the Base Class Provides
|
|
64
|
+
|
|
65
|
+
`ElementMaker` sets up shared infrastructure that features depend on:
|
|
66
|
+
|
|
67
|
+
| Resource | Purpose |
|
|
68
|
+
|----------|---------|
|
|
69
|
+
| `propagator` (EventTarget) | Property change event bus — used by truthSourcer and reflector to observe value changes |
|
|
70
|
+
| `#internals` (ElementInternals) | Shared via `getSharedContext` with faceUp (form control), reflector (custom states), and roundabout |
|
|
71
|
+
| `static featuresConfig` | Installs `whenFeatureReady()` for awaiting async feature resolution |
|
|
72
|
+
|
|
73
|
+
Because all spawns are async, defining 10 elements that extend `el-maker` only imports each feature module once — results are cached per base class.
|
|
74
|
+
|
|
75
|
+
## Feature Catalog
|
|
76
|
+
|
|
77
|
+
| Package | Description | Source |
|
|
78
|
+
|---------|-------------|--------|
|
|
79
|
+
| [truth-sourcer](https://www.npmjs.com/package/truth-sourcer) | Attribute/property binding and truth-sourcing for custom elements | [GitHub](https://github.com/bahrus/truth-sourcer) |
|
|
80
|
+
| [be-reflective](https://www.npmjs.com/package/be-reflective) | CSS custom state reflection from computed styles | [GitHub](https://github.com/bahrus/be-reflective) |
|
|
81
|
+
| [face-up](https://www.npmjs.com/package/face-up) | Form Associated Custom Element behavior via ElementInternals | [GitHub](https://github.com/bahrus/face-up) |
|
|
82
|
+
| [roundabout-lib](https://www.npmjs.com/package/roundabout-lib) | Reactive view-model binding with template rendering and computed property orchestration | [GitHub](https://github.com/bahrus/roundabout-lib) |
|
|
83
|
+
| [templ-maker](https://www.npmjs.com/package/templ-maker) | Extracts a DOM fragment into a reusable template and clones it per instance (works with cede scripts) | [GitHub](https://github.com/bahrus/templ-maker) |
|
|
84
|
+
|
|
85
|
+
### Example: time-ticker
|
|
86
|
+
|
|
87
|
+
[time-ticker](https://github.com/bahrus/time-ticker) demonstrates a fully feature-based component with no code in the element class itself — all behavior comes from the `roundabout` and `timeTicker` features wired via `assignFeatures`.
|
|
88
|
+
|
|
89
|
+
## Viewing Demos Locally
|
|
90
|
+
|
|
91
|
+
1. Install git
|
|
92
|
+
2. Fork/clone this repo
|
|
93
|
+
3. Install node.js
|
|
94
|
+
4. Open command window to folder where you cloned this repo
|
|
95
|
+
5. > git submodule add https://github.com/bahrus/types.git types
|
|
96
|
+
6. > git submodule update --init --recursive
|
|
97
|
+
7. > npm install
|
|
98
|
+
8. > npm run serve
|
|
99
|
+
9. Open http://localhost:8000/demo/ in a modern browser
|
|
100
|
+
|
|
101
|
+
## Running Tests
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
> npm run test
|
|
105
|
+
```
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Suggestion for Extending
|
|
2
|
+
|
|
3
|
+
I like how you made a good call to treat the time-ticker feature as one that probably doesn't belong in an "abstract" class called ElementMaker that serves as general a purpose as element-maker does. But the explanation provided for separating it out was a bit fuzzy, I think.
|
|
4
|
+
|
|
5
|
+
The time-ticker package does in fact include both a [custom element feature](https://raw.githubusercontent.com/bahrus/time-ticker/refs/heads/baseline/TimeTicker.js) as well as a [custom element](https://raw.githubusercontent.com/bahrus/time-ticker/refs/heads/baseline/time-ticker-element.js).
|
|
6
|
+
|
|
7
|
+
I would like to go back to that package, and make the custom element extend ElementMaker from this package so that the static features get "inherited" somehow, and add on the time-ticker package. I guess there could be a separate file that could be referenced as an old-fashioned module that registers the custom element name, similar to [def.js](https://raw.githubusercontent.com/bahrus/time-ticker/refs/heads/baseline/def.js)
|
|
8
|
+
|
|
9
|
+
After studying these links carefully, can you spell out what to do below, and I will then copy this file into that project and ask kiro to make the necessary adjustments.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Instructions for Converting time-ticker to Extend ElementMaker
|
|
14
|
+
|
|
15
|
+
### Overview
|
|
16
|
+
|
|
17
|
+
Currently `time-ticker-element.js` is a standalone `HTMLElement` subclass that manually redeclares `propagator`, `#internals`, `attachInternals()`, and `static supportedFeatures` entries for `truthSourcer`, `faceUp`, and `roundabout`. All of that is already provided by `ElementMaker`. The goal is to:
|
|
18
|
+
|
|
19
|
+
1. Extend `ElementMaker` instead of `HTMLElement`
|
|
20
|
+
2. Inherit all of ElementMaker's features automatically
|
|
21
|
+
3. Only declare the *additional* feature (`timeTicker`) that is specific to this package
|
|
22
|
+
4. Simplify `wireFeatures.js` to only inject what's unique to this element
|
|
23
|
+
5. Keep `def.js` as the side-effect module that registers the tag name
|
|
24
|
+
|
|
25
|
+
### Step 1: Add `el-maker` as a dependency
|
|
26
|
+
|
|
27
|
+
In `package.json`, add:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"el-maker": "0.0.0"
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Also add it to `imports.html`:
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
"el-maker/": "/node_modules/el-maker/"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Step 2: Rewrite `time-ticker-element.js`
|
|
42
|
+
|
|
43
|
+
Replace the entire file with:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { ElementMaker } from 'el-maker/ElementMaker.js';
|
|
47
|
+
|
|
48
|
+
export class TimeTickerElement extends ElementMaker {
|
|
49
|
+
static supportedFeatures = {
|
|
50
|
+
...ElementMaker.supportedFeatures,
|
|
51
|
+
timeTicker: {},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Key points:
|
|
57
|
+
- Extends `ElementMaker` instead of `HTMLElement`
|
|
58
|
+
- No need to redeclare `propagator`, `#internals`, or `constructor` — inherited from `ElementMaker`
|
|
59
|
+
- No need to redeclare `truthSourcer`, `faceUp`, `roundabout`, or `reflector` — inherited via the spread of `ElementMaker.supportedFeatures`
|
|
60
|
+
- Only adds the `timeTicker` slot, which is specific to this package
|
|
61
|
+
- `static formAssociated = true` is no longer needed here — `FaceUp.onAssigned` sets it automatically when `faceUp` is wired via `assignFeatures`
|
|
62
|
+
|
|
63
|
+
### Step 3: Simplify `wireFeatures.js`
|
|
64
|
+
|
|
65
|
+
The current `wireFeatures.js` eagerly imports all feature classes (RoundaboutFeature, TruthSourcer, FaceUp) and passes them as explicit `spawn` values. Since `ElementMaker` already declares async `fallbackSpawn` for all of those, you only need to provide:
|
|
66
|
+
|
|
67
|
+
- The `timeTicker` spawn (unique to this package)
|
|
68
|
+
- The `roundabout` config (`customData`, `withAttrs`) that comes from the cef.json
|
|
69
|
+
- Any `callbackForwarding` or `customData` overrides specific to this element
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
import { TimeTicker } from './TimeTicker.js';
|
|
73
|
+
import 'assign-gingerly/assignFeatures.js';
|
|
74
|
+
|
|
75
|
+
export async function wireFeatures(ElementClass, cfg) {
|
|
76
|
+
const { roundabout } = cfg.features;
|
|
77
|
+
const { customData, withAttrs } = roundabout;
|
|
78
|
+
|
|
79
|
+
await customElements.assignFeatures(ElementClass, {
|
|
80
|
+
timeTicker: { spawn: TimeTicker },
|
|
81
|
+
truthSourcer: {
|
|
82
|
+
callbackForwarding: ['connectedCallback', 'attributeChangedCallback'],
|
|
83
|
+
},
|
|
84
|
+
faceUp: {
|
|
85
|
+
customData: { integrateWithRoundabout: true },
|
|
86
|
+
callbackForwarding: [
|
|
87
|
+
'connectedCallback', 'disconnectedCallback',
|
|
88
|
+
'formDisabledCallback', 'formResetCallback', 'formStateRestoreCallback',
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
roundabout: {
|
|
92
|
+
customData,
|
|
93
|
+
withAttrs,
|
|
94
|
+
callbackForwarding: ['connectedCallback'],
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Key changes:
|
|
101
|
+
- Removed all explicit `spawn` entries for `truthSourcer`, `faceUp`, and `roundabout` — the async `fallbackSpawn` from `ElementMaker.supportedFeatures` will be used instead
|
|
102
|
+
- Removed the eager imports of `RoundaboutFeature`, `TruthSourcer`, and `FaceUp` — they'll be lazy-loaded on first access
|
|
103
|
+
- Still pass `callbackForwarding` and `customData` since those are per-element configuration (the consumer additions get unioned with the author defaults from `supportedFeatures`)
|
|
104
|
+
|
|
105
|
+
### Step 4: `def.js` stays the same
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
import { TimeTickerElement } from './time-ticker-element.js';
|
|
109
|
+
import { wireFeatures } from './wireFeatures.js';
|
|
110
|
+
import defRef from './defRef.json' with { type: 'json' };
|
|
111
|
+
|
|
112
|
+
await wireFeatures(TimeTickerElement, defRef);
|
|
113
|
+
customElements.define('time-ticker', TimeTickerElement);
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
No changes needed.
|
|
117
|
+
|
|
118
|
+
### Step 5: Remove redundant dependencies
|
|
119
|
+
|
|
120
|
+
Since `ElementMaker` brings in `truth-sourcer`, `face-up`, `be-reflective`, and `roundabout-lib` as its own dependencies, you can remove them from time-ticker's `package.json` dependencies (they'll be available transitively). Keep only:
|
|
121
|
+
|
|
122
|
+
- `el-maker` (brings everything)
|
|
123
|
+
- `assign-gingerly` (needed for `assignFeatures.js` import)
|
|
124
|
+
- Any test/dev dependencies
|
|
125
|
+
|
|
126
|
+
### Benefits
|
|
127
|
+
|
|
128
|
+
1. **Less boilerplate** — no manual `propagator`, `#internals`, `attachInternals()`, or `getSharedContext` declarations per element
|
|
129
|
+
2. **Lazy loading** — feature implementations are only imported when actually accessed, not eagerly at module load time
|
|
130
|
+
3. **Consistency** — all elements extending `ElementMaker` get the same shared context wiring, reducing bugs from copy-paste divergence
|
|
131
|
+
4. **Extensibility** — if a new feature is added to `ElementMaker` later, all extending elements inherit it automatically
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "el-maker",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"homepage": "https://github.com/bahrus/element-maker#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -13,8 +13,24 @@
|
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"author": "Bruce B. Anderson <anderson.bruce.b@gmail.com>",
|
|
15
15
|
"type": "module",
|
|
16
|
-
"main": "
|
|
16
|
+
"main": "ElementMaker.js",
|
|
17
17
|
"scripts": {
|
|
18
|
-
"
|
|
18
|
+
"build": "node emc.mjs > emc.json && node ⏻.mjs > ⏻.json",
|
|
19
|
+
"serve": "node ./node_modules/spa-ssi/serve.js",
|
|
20
|
+
"test": "playwright test",
|
|
21
|
+
"safari": "npx playwright wk http://localhost:8000",
|
|
22
|
+
"update": "ncu -u && npm install"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"be-reflective": "0.0.3",
|
|
26
|
+
"face-up": "0.0.4",
|
|
27
|
+
"roundabout-lib": "0.0.20",
|
|
28
|
+
"templ-maker": "0.0.1",
|
|
29
|
+
"truth-sourcer": "0.0.3",
|
|
30
|
+
"time-ticker": "0.0.31"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"spa-ssi": "0.0.27",
|
|
34
|
+
"@playwright/test": "1.60.0"
|
|
19
35
|
}
|
|
20
36
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Conversion Template
|
|
2
|
+
|
|
3
|
+
This spec template provides a structured approach to converting legacy be-* enhancement projects to the modern architecture.
|
|
4
|
+
|
|
5
|
+
## When to Use This Template
|
|
6
|
+
|
|
7
|
+
Use this template when:
|
|
8
|
+
- You want to track conversion progress step-by-step
|
|
9
|
+
- You're converting a be-* project for the first time
|
|
10
|
+
- You want to review each step before proceeding
|
|
11
|
+
- Multiple people are involved in the conversion
|
|
12
|
+
- You want a record of the conversion process
|
|
13
|
+
|
|
14
|
+
## How to Use This Template
|
|
15
|
+
|
|
16
|
+
### Option 1: Copy to Project (Recommended)
|
|
17
|
+
|
|
18
|
+
1. Copy this entire folder to your project's `.kiro/specs/` directory:
|
|
19
|
+
```bash
|
|
20
|
+
cp -r types/.kiro/specs/conversion-template .kiro/specs/conversion-[project-name]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. Update placeholders in all files:
|
|
24
|
+
- Replace `[PROJECT_NAME]` with your project name (e.g., "be-clonable")
|
|
25
|
+
- Replace `[project-name]` with kebab-case name (e.g., "be-clonable")
|
|
26
|
+
- Replace `[ClassName]` with PascalCase name (e.g., "BeClonable")
|
|
27
|
+
- Replace `[emoji]` with actual emoji if applicable (e.g., "⿻")
|
|
28
|
+
|
|
29
|
+
3. Work through the tasks in `tasks.md` sequentially
|
|
30
|
+
|
|
31
|
+
4. Use Kiro to execute tasks: "execute task 1", "execute task 2", etc.
|
|
32
|
+
|
|
33
|
+
### Option 2: Use as Reference
|
|
34
|
+
|
|
35
|
+
Simply reference this template while doing a manual conversion:
|
|
36
|
+
- Follow the requirements in `requirements.md`
|
|
37
|
+
- Understand the architecture from `design.md`
|
|
38
|
+
- Use `tasks.md` as a checklist
|
|
39
|
+
|
|
40
|
+
## Template Structure
|
|
41
|
+
|
|
42
|
+
### requirements.md
|
|
43
|
+
- User stories for each conversion step
|
|
44
|
+
- Correctness properties to verify
|
|
45
|
+
- Success criteria
|
|
46
|
+
- Non-functional requirements
|
|
47
|
+
|
|
48
|
+
### design.md
|
|
49
|
+
- Architecture overview with diagrams
|
|
50
|
+
- Component design for each file type
|
|
51
|
+
- Data flow explanations
|
|
52
|
+
- Design decisions and rationale
|
|
53
|
+
- Alternatives considered
|
|
54
|
+
|
|
55
|
+
### tasks.md
|
|
56
|
+
- Detailed task breakdown (11 major tasks, 60+ subtasks)
|
|
57
|
+
- Task dependencies
|
|
58
|
+
- Execution notes for each step
|
|
59
|
+
- Reference to ConversionInstructions.md
|
|
60
|
+
|
|
61
|
+
## Key Features
|
|
62
|
+
|
|
63
|
+
### Comprehensive Coverage
|
|
64
|
+
All 10 conversion steps from ConversionInstructions.md are covered with detailed subtasks
|
|
65
|
+
|
|
66
|
+
### Verification Built-in
|
|
67
|
+
Task 11 provides comprehensive verification steps to ensure conversion success
|
|
68
|
+
|
|
69
|
+
### Reference Integration
|
|
70
|
+
All files reference ConversionInstructions.md for detailed step-by-step instructions
|
|
71
|
+
|
|
72
|
+
### Kiro-Optimized
|
|
73
|
+
- Uses file references: `#[[file:../../ConversionInstructions.md]]`
|
|
74
|
+
- Task format compatible with Kiro's task execution
|
|
75
|
+
- Structured for spec-driven development workflow
|
|
76
|
+
|
|
77
|
+
## Example Usage with Kiro
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
User: "I want to convert be-clonable to the modern architecture"
|
|
81
|
+
|
|
82
|
+
Kiro: "I can help you with that. Would you like to:
|
|
83
|
+
1. Create a tracked conversion spec (recommended for first-time conversions)
|
|
84
|
+
2. Do a direct conversion (faster, for experienced users)
|
|
85
|
+
|
|
86
|
+
User: "Create a spec"
|
|
87
|
+
|
|
88
|
+
Kiro: [Creates spec from template, updates placeholders]
|
|
89
|
+
"I've created a conversion spec at .kiro/specs/conversion-be-clonable/
|
|
90
|
+
Let's start with Task 1: Migrate Type Definitions. Ready to begin?"
|
|
91
|
+
|
|
92
|
+
User: "Yes"
|
|
93
|
+
|
|
94
|
+
Kiro: [Executes Task 1, marks subtasks complete]
|
|
95
|
+
"Task 1 complete. Type definitions migrated to types/be-clonable/.
|
|
96
|
+
Ready for Task 2: Archive Legacy Implementation?"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Success Criteria
|
|
100
|
+
|
|
101
|
+
A successful conversion using this template should result in:
|
|
102
|
+
- ✅ All tasks marked complete
|
|
103
|
+
- ✅ `npm run build` succeeds
|
|
104
|
+
- ✅ `npm test` passes
|
|
105
|
+
- ✅ No TypeScript errors
|
|
106
|
+
- ✅ Legacy code preserved in legacy/ folder
|
|
107
|
+
- ✅ Modern architecture verified
|
|
108
|
+
|
|
109
|
+
## Related Files
|
|
110
|
+
|
|
111
|
+
- `../../ConversionInstructions.md` - Detailed step-by-step instructions
|
|
112
|
+
- `../../.kiro/steering/conversion-guide.md` - Kiro steering guidance
|
|
113
|
+
- Reference implementations:
|
|
114
|
+
- [be-a-beacon](https://github.com/bahrus/be-a-beacon)
|
|
115
|
+
- [be-committed](https://github.com/bahrus/be-committed)
|
|
116
|
+
- [be-decked-with](https://github.com/bahrus/be-decked-with)
|
|
117
|
+
|
|
118
|
+
## Customization
|
|
119
|
+
|
|
120
|
+
Feel free to customize this template for your specific needs:
|
|
121
|
+
- Add project-specific tasks
|
|
122
|
+
- Modify verification steps
|
|
123
|
+
- Add additional correctness properties
|
|
124
|
+
- Extend design documentation
|
|
125
|
+
|
|
126
|
+
## Feedback
|
|
127
|
+
|
|
128
|
+
If you find issues with this template or have suggestions for improvement, please update the template in the types repository so all projects benefit.
|