face-up 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.
Files changed (46) hide show
  1. package/.gitmodules +3 -0
  2. package/.kiro/steering/project-context.md +17 -0
  3. package/.vscode/settings.json +3 -0
  4. package/FaceUp.js +305 -0
  5. package/README.md +165 -2
  6. package/imports.html +8 -0
  7. package/package.json +30 -20
  8. package/tests/test1.html +130 -0
  9. package/types/.kiro/specs/conversion-template/README.md +128 -0
  10. package/types/.kiro/specs/conversion-template/design.md +360 -0
  11. package/types/.kiro/specs/conversion-template/requirements.md +191 -0
  12. package/types/.kiro/specs/conversion-template/tasks.md +174 -0
  13. package/types/.kiro/steering/coding-standards.md +17 -0
  14. package/types/.kiro/steering/conversion-guide.md +103 -0
  15. package/types/.kiro/steering/declarative-configuration.md +108 -0
  16. package/types/.kiro/steering/emc-json-serializability.md +306 -0
  17. package/types/EnhancementConversionInstructions.md +1626 -0
  18. package/types/LICENSE +21 -0
  19. package/types/NewCustomElementFeature.md +672 -0
  20. package/types/NewEnhancementInstructions.md +395 -0
  21. package/types/README.md +2 -0
  22. package/types/agrace/types.d.ts +11 -0
  23. package/types/assign-gingerly/types.d.ts +328 -0
  24. package/types/be-a-beacon/types.d.ts +17 -0
  25. package/types/be-bound/types.d.ts +61 -0
  26. package/types/be-buttoned-up/types.d.ts +19 -0
  27. package/types/be-clonable/types.d.ts +36 -0
  28. package/types/be-committed/types.d.ts +22 -0
  29. package/types/be-decked-with/types.d.ts +26 -0
  30. package/types/be-delible/types.d.ts +25 -0
  31. package/types/be-reflective/types.d.ts +80 -0
  32. package/types/be-render-neutral/types.d.ts +29 -0
  33. package/types/be-typed/types.d.ts +31 -0
  34. package/types/do-inc/types.d.ts +56 -0
  35. package/types/do-invoke/types.d.ts +38 -0
  36. package/types/do-merge/types.d.ts +28 -0
  37. package/types/do-toggle/types.d.ts +31 -0
  38. package/types/face-up/types.d.ts +104 -0
  39. package/types/global.d.ts +29 -0
  40. package/types/id-generation/types.d.ts +26 -0
  41. package/types/inferencer/types.d.ts +46 -0
  42. package/types/mount-observer/types.d.ts +363 -0
  43. package/types/nested-regex-groups/types.d.ts +101 -0
  44. package/types/roundabout/types.d.ts +255 -0
  45. package/types/time-ticker/types.d.ts +66 -0
  46. package/types/truth-sourcer/types.d.ts +46 -0
@@ -0,0 +1,395 @@
1
+ # New Enhancement Instructions
2
+
3
+ ## Introduction
4
+
5
+ This document provides step-by-step instructions for creating a **brand new** "be-*" or "do-*" enhancement project using the modern architecture. Unlike the [Enhancement Conversion Instructions](./EnhancementConversionInstructions.md) (which covers migrating legacy projects), this guide starts from scratch.
6
+
7
+ **Note:** This guide is specifically for **enhancements** (declarative behaviors added to existing HTML elements via attributes). It does NOT apply to custom elements. Enhancements use `be-hive` and `mount-observer` to attach behavior to elements without requiring custom element registration.
8
+
9
+ ## Reference Implementations
10
+
11
+ - **[do-invoke](https://github.com/bahrus/do-invoke)** — Custom parser with nested paths and default values
12
+ - **[do-toggle](https://github.com/bahrus/do-toggle)** — Parser with infer pattern
13
+ - **[do-inc](https://github.com/bahrus/do-inc)** — Increment enhancement with parser
14
+ - **[be-clonable](https://github.com/bahrus/be-clonable)** — Most up-to-date conversion example (useful for architecture patterns)
15
+
16
+ ## Prerequisites
17
+
18
+ - Node.js installed
19
+ - npm installed
20
+ - `ncu` (npm-check-updates) installed globally: `npm install -g npm-check-updates`
21
+
22
+ ## Step 1: Initialize the Project
23
+
24
+ 1. Create a new repository (e.g., `do-merge` or `be-fancy`)
25
+ 2. Run `npm init` or create a `package.json` manually
26
+ 3. Add the `types` submodule:
27
+ ```bash
28
+ git submodule add https://github.com/bahrus/types.git types
29
+ ```
30
+
31
+ ## Step 2: Configure package.json
32
+
33
+ Set up the standard scripts and dependencies:
34
+
35
+ ```json
36
+ {
37
+ "name": "do-my-enhancement",
38
+ "version": "0.0.0",
39
+ "description": "Description of what the enhancement does",
40
+ "type": "module",
41
+ "main": "do-my-enhancement.js",
42
+ "scripts": {
43
+ "build": "node emc.mjs > emc.json && node [emoji].mjs > [emoji].json",
44
+ "serve": "node ./node_modules/spa-ssi/serve.js",
45
+ "test": "playwright test",
46
+ "safari": "npx playwright wk http://localhost:8000",
47
+ "update": "ncu -u && npm install"
48
+ },
49
+ "dependencies": {
50
+ "assign-gingerly": "0.0.5",
51
+ "be-hive": "0.1.9",
52
+ "inferencer": "0.0.1",
53
+ "mount-observer": "0.0.16",
54
+ "roundabout-lib": "0.0.2"
55
+ },
56
+ "devDependencies": {
57
+ "spa-ssi": "0.0.27",
58
+ "@playwright/test": "1.59.1"
59
+ }
60
+ }
61
+ ```
62
+
63
+ **Notes:**
64
+ - Replace `[emoji]` with your emoji shorthand (or remove that part of the build script if no emoji)
65
+ - Use exact versions, not ranges (no `^` or `~`)
66
+ - Add `nested-regex-groups` if you need custom attribute parsing
67
+ - Run `npm run update` after creating package.json to install dependencies
68
+
69
+ ## Step 3: Create Type Definitions
70
+
71
+ Create `types/[project-name]/types.d.ts` with the standard structure:
72
+
73
+ ```typescript
74
+ import { ElementEnhancementGateway, SpawnContext } from "../assign-gingerly/types";
75
+
76
+ export interface EndUserProps {
77
+ // Properties that end users configure via attributes
78
+ myProp: string;
79
+ }
80
+
81
+ export interface AllProps extends EndUserProps {
82
+ enhancedElement: Element & ElementEnhancementGateway;
83
+ resolved: boolean;
84
+ }
85
+
86
+ export type AP = AllProps;
87
+ export type PAP = Partial<AP>;
88
+ export type ProPAP = Promise<PAP>;
89
+
90
+ export interface Actions {
91
+ init(self: AP, enhancedElement: Element, ctx: SpawnContext, initVals: PAP): Promise<void>;
92
+ hydrate(self: AP): ProPAP;
93
+ }
94
+ ```
95
+
96
+ **Key points:**
97
+ - `EndUserProps` — what the user configures via HTML attributes
98
+ - `AllProps` — includes `enhancedElement` and any internal state like `resolved`
99
+ - `Actions` — methods the enhancement exposes; `init` always has the 4-parameter signature
100
+ - If using a custom parser, import `StatementsResult` from `../nested-regex-groups/types`
101
+
102
+ ## Step 4: Create emc.mjs (Build Configuration)
103
+
104
+ Create `emc.mjs` in the project root:
105
+
106
+ ```javascript
107
+ //@ts-check
108
+
109
+ /** @import {EMC} from './types/mount-observer/types' */;
110
+ /** @import {AllProps, Actions} from './types/[project-name]/types' */
111
+ /** @import {RAConfig} from './types/roundabout/types' */
112
+
113
+ /**
114
+ * @type {EMC<any, AllProps, Element, RAConfig<AllProps, Actions> >}
115
+ */
116
+ export const emc = {
117
+ enhConfig: {
118
+ enhKey: 'DoMyEnhancement',
119
+ spawn: '[project-name]/[project-name].js',
120
+ withAttrs: {
121
+ base: '[project-name]',
122
+ // For simple string/number properties:
123
+ // myProp: '${base}-my-prop',
124
+ // For the base attribute itself (JSON object):
125
+ // _base: { mapsTo: 'myProp', instanceOf: 'Object' }
126
+ // For boolean properties:
127
+ // _nudge: { instanceOf: 'Boolean' }
128
+ }
129
+ },
130
+ customData: {
131
+ weakRef: {
132
+ properties: ['enhancedElement']
133
+ },
134
+ actions: {
135
+ hydrate: {
136
+ ifAllOf: ['myProp', 'enhancedElement']
137
+ }
138
+ }
139
+ }
140
+ };
141
+
142
+ export function render(){
143
+ return JSON.stringify(emc, null, 4);
144
+ }
145
+
146
+ console.log(render());
147
+ ```
148
+
149
+ ### Attribute Parsing Options
150
+
151
+ **JSON attribute (parsed by browser):**
152
+ ```javascript
153
+ _base: { mapsTo: 'mergeParamSets', instanceOf: 'Object' }
154
+ ```
155
+ Use when the attribute value is valid JSON. The browser's JSON parser handles it.
156
+
157
+ **Custom parser (for string DSL syntax):**
158
+ ```javascript
159
+ _base: {
160
+ mapsTo: 'invokeParamSet',
161
+ parser: 'parse-pattern-statements',
162
+ instanceOf: 'Array',
163
+ parserConfig: parsePatterns
164
+ }
165
+ ```
166
+ Use when you need to parse a custom string syntax. See [Enhancement Conversion Instructions](./EnhancementConversionInstructions.md) Step 7a for details.
167
+
168
+ ## Step 5: Create Emoji Shorthand (Optional)
169
+
170
+ If your enhancement has an emoji shorthand, create `[emoji].mjs`:
171
+
172
+ ```javascript
173
+ import myJSON from './emc.json' with {type: 'json'};
174
+
175
+ /** @import {EMC} from './types/mount-observer/types' */;
176
+ /** @import {AllProps} from './types/[project-name]/types' */
177
+
178
+ /**
179
+ * @type {EMC<any, AllProps> }
180
+ */
181
+ const emc = {
182
+ ...myJSON,
183
+ enhConfig: {
184
+ ...myJSON.enhConfig,
185
+ enhKey: '[emoji]',
186
+ withAttrs: {
187
+ ...myJSON.enhConfig.withAttrs,
188
+ base: '[emoji]'
189
+ }
190
+ }
191
+ };
192
+
193
+ export function render(){
194
+ return JSON.stringify(emc, null, 4);
195
+ }
196
+
197
+ console.log(render());
198
+ ```
199
+
200
+ **Critical:** The `...myJSON` spread at the top level ensures `customData` is carried over.
201
+
202
+ ## Step 6: Create the Enhancement Class
203
+
204
+ Create `[project-name].js`:
205
+
206
+ ```javascript
207
+ // @ts-check
208
+ /** @import {Actions, PAP, AllProps, AP} from './types/[project-name]/types' */;
209
+ /** @import {RoundaboutOptions} from './types/roundabout/types' */;
210
+ /** @import {ElementEnhancementGateway, SpawnContext} from './types/assign-gingerly/types' */;
211
+ /** @import {EMC} from './types/mount-observer/types' */;
212
+ /** @import {RAConfig} from './types/roundabout/types' */;
213
+
214
+ /**
215
+ * @implements {Actions}
216
+ */
217
+ class DoMyEnhancement {
218
+
219
+ /**
220
+ * @this {AllProps & Actions}
221
+ * @param {Element & ElementEnhancementGateway} enhancedElement
222
+ * @param {SpawnContext} ctx
223
+ * @param {PAP} initVals
224
+ */
225
+ constructor(enhancedElement, ctx, initVals){
226
+ this.init(this, enhancedElement, ctx, initVals);
227
+ }
228
+
229
+ /**
230
+ * @param {AllProps} self
231
+ * @param {Element & ElementEnhancementGateway} enhancedElement
232
+ * @param {SpawnContext} ctx
233
+ * @param {PAP} initVals
234
+ */
235
+ async init(self, enhancedElement, ctx, initVals){
236
+ const {customData} = /** @type {EMC<any, AllProps, Element, RAConfig<AllProps, Actions>>} */ (ctx.emc);
237
+ /**
238
+ * @type {RoundaboutOptions}
239
+ */
240
+ const raOptions = {
241
+ ...customData,
242
+ vm: self,
243
+ initialPropVals: {
244
+ enhancedElement,
245
+ ...customData?.defaultPropVals,
246
+ ...initVals
247
+ }
248
+ };
249
+ (await import('roundabout-lib/roundabout.js')).roundabout(raOptions);
250
+ }
251
+
252
+ /**
253
+ * @param {AP} self
254
+ */
255
+ async hydrate(self){
256
+ // Your enhancement logic here
257
+ return /** @type {PAP} */ ({resolved: true});
258
+ }
259
+ }
260
+
261
+ export {DoMyEnhancement};
262
+ ```
263
+
264
+ **Key patterns:**
265
+ - No base class — plain JavaScript class
266
+ - Constructor delegates to `init` with 4 parameters
267
+ - `init` extracts `customData` from `ctx.emc` (no JSON import needed)
268
+ - Action methods receive `self` (the reactive proxy) as first parameter
269
+ - Return partial props from actions to trigger reactive updates
270
+
271
+ ## Step 7: Create imports.html
272
+
273
+ ```html
274
+ <script type=importmap >
275
+ {
276
+ "imports": {
277
+ "assign-gingerly/": "/node_modules/assign-gingerly/",
278
+ "[project-name]/": "/",
279
+ "be-hive/": "/node_modules/be-hive/",
280
+ "inferencer/": "/node_modules/inferencer/",
281
+ "mount-observer/": "/node_modules/mount-observer/",
282
+ "roundabout-lib/": "/node_modules/roundabout-lib/",
283
+ "id-generation/": "/node_modules/id-generation/"
284
+ }
285
+ }
286
+ </script>
287
+ ```
288
+
289
+ ## Step 8: Configure VS Code
290
+
291
+ Create `.vscode/settings.json`:
292
+
293
+ ```json
294
+ {
295
+ "explorer.fileNesting.patterns": {
296
+ "*.mjs": "${capture}.json"
297
+ },
298
+ "explorer.fileNesting.enabled": true
299
+ }
300
+ ```
301
+
302
+ ## Step 9: Set Up Auto-Build Hook
303
+
304
+ Create `.kiro/hooks/auto-build-config.kiro.hook`:
305
+
306
+ ```json
307
+ {
308
+ "name": "Auto-build Configuration",
309
+ "version": "1.0.0",
310
+ "description": "Automatically runs npm run build when emc.mjs or emoji .mjs files are saved",
311
+ "when": {
312
+ "type": "fileEdited",
313
+ "patterns": ["emc.mjs", "[emoji].mjs"]
314
+ },
315
+ "then": {
316
+ "type": "runCommand",
317
+ "command": "npm run build",
318
+ "timeout": 10000
319
+ }
320
+ }
321
+ ```
322
+
323
+ ## Step 10: Build and Verify
324
+
325
+ ```bash
326
+ npm run update # Install/update dependencies
327
+ npm run build # Generate emc.json and emoji.json
328
+ ```
329
+
330
+ Verify that `emc.json` (and `[emoji].json`) are generated with the expected structure.
331
+
332
+ ## Step 11: Create Test HTML
333
+
334
+ Create a test file (e.g., `tests/test1.html`):
335
+
336
+ ```html
337
+ <!DOCTYPE html>
338
+ <html lang="en">
339
+ <head>
340
+ <meta charset="UTF-8">
341
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
342
+ <title>Test</title>
343
+ <!-- #include virtual="/imports.html" -->
344
+ <be-hive>
345
+ <script type=emc src="[project-name]/emc.json"></script>
346
+ </be-hive>
347
+ <script type=module>
348
+ import 'be-hive/be-hive.js';
349
+ </script>
350
+ </head>
351
+ <body>
352
+ <!-- Your test markup here -->
353
+ </body>
354
+ </html>
355
+ ```
356
+
357
+ ## Architecture Overview
358
+
359
+ ```
360
+ [project-name]/
361
+ ├── .kiro/
362
+ │ └── hooks/
363
+ │ └── auto-build-config.kiro.hook
364
+ ├── .vscode/
365
+ │ └── settings.json
366
+ ├── types/ (git submodule)
367
+ │ └── [project-name]/
368
+ │ └── types.d.ts
369
+ ├── [project-name].js (enhancement class - browser code)
370
+ ├── emc.mjs (build script → emc.json)
371
+ ├── emc.json (generated - runtime config)
372
+ ├── [emoji].mjs (build script → [emoji].json)
373
+ ├── [emoji].json (generated - emoji variant config)
374
+ ├── imports.html (import map for browser)
375
+ ├── package.json
376
+ └── README.md
377
+ ```
378
+
379
+ ## Key Differences from Conversion
380
+
381
+ | Aspect | Conversion | New Enhancement |
382
+ |--------|-----------|-----------------|
383
+ | Legacy code | Move to `legacy/` folder | N/A — no legacy code |
384
+ | ts-refs | Remove and migrate to `types/` | Start directly in `types/` |
385
+ | Type cleanup | Remove IEnhancement extends, BAP | Write clean types from scratch |
386
+ | Static config | Migrate to emc.mjs customData | Write customData directly |
387
+ | Class refactor | Remove BE extends, bootUp | Write plain class from start |
388
+
389
+ ## Tips
390
+
391
+ - **Start simple**: Get the basic case working before adding complexity
392
+ - **Test incrementally**: Build one example at a time
393
+ - **Check generated JSON**: Run `node emc.mjs` to see the output
394
+ - **Use `@ts-check`**: Catches type errors early in `.js` files
395
+ - **Don't import emc.json in the class**: The config comes through `ctx.emc`
@@ -0,0 +1,2 @@
1
+ # types
2
+ Common Shared Type Definitions
@@ -0,0 +1,11 @@
1
+ import {RAConfig} from '../roundabout/types';
2
+ import {AttrPatterns} from '../assign-gingerly/types';
3
+
4
+ /**
5
+ * Assign Gingerly Roundabout Config
6
+ */
7
+ export interface AgraceConfig<TProps = unknown, TActions = TProps, ETProps = TProps, TCustomData = unknown> {
8
+ raConfig: RAConfig<TProps, TActions, ETProps, TCustomData>,
9
+ withAttrs?: AttrPatterns<TProps>,
10
+ template?: string | HTMLTemplateElement,
11
+ }