face-up 0.0.0 → 0.0.2
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/.kiro/steering/project-context.md +17 -0
- package/.vscode/settings.json +3 -0
- package/FaceUp.js +305 -0
- package/README.md +162 -2
- package/imports.html +8 -0
- package/package.json +30 -20
- package/tests/test1.html +115 -0
- 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 +673 -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 +328 -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 +80 -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 +104 -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/time-ticker/types.d.ts +66 -0
- package/types/truth-sourcer/types.d.ts +46 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# EMC Configuration JSON Serializability
|
|
2
|
+
|
|
3
|
+
## Core Principle
|
|
4
|
+
|
|
5
|
+
**All content in `emc.mjs` files MUST be JSON-serializable without loss of information.**
|
|
6
|
+
|
|
7
|
+
The `render()` function at the bottom of every `emc.mjs` file exports the configuration as JSON via `JSON.stringify()`. This JSON is what gets loaded at runtime by enhancement classes and the be-hive system.
|
|
8
|
+
|
|
9
|
+
## Why This Matters
|
|
10
|
+
|
|
11
|
+
1. **Runtime Loading**: Enhancement classes import `emc.json` (not `emc.mjs`) using JSON import assertions
|
|
12
|
+
2. **Declarative Configuration**: The JSON file is the source of truth for how enhancements are configured
|
|
13
|
+
3. **Portability**: JSON files can be loaded by any JavaScript environment without executing code
|
|
14
|
+
4. **Security**: JSON is safer than executing arbitrary JavaScript
|
|
15
|
+
5. **Tooling**: JSON can be validated, transformed, and analyzed by standard tools
|
|
16
|
+
|
|
17
|
+
## What IS JSON-Serializable
|
|
18
|
+
|
|
19
|
+
✅ **Allowed in emc.mjs:**
|
|
20
|
+
- Strings: `"hello"`
|
|
21
|
+
- Numbers: `42`, `3.14`
|
|
22
|
+
- Booleans: `true`, `false`
|
|
23
|
+
- null: `null`
|
|
24
|
+
- Arrays: `[1, 2, 3]`
|
|
25
|
+
- Plain objects: `{ key: "value" }`
|
|
26
|
+
- Nested structures: `{ items: [{ id: 1 }, { id: 2 }] }`
|
|
27
|
+
|
|
28
|
+
## What is NOT JSON-Serializable
|
|
29
|
+
|
|
30
|
+
❌ **NOT allowed in emc.mjs:**
|
|
31
|
+
- **Functions**: `parser: (v) => v.split(',')` ❌
|
|
32
|
+
- **Class constructors**: `spawn: MyClass` ❌
|
|
33
|
+
- **Symbols**: `Symbol('key')` ❌
|
|
34
|
+
- **undefined**: `value: undefined` ❌ (becomes `null` or omitted)
|
|
35
|
+
- **Regular expressions**: `/pattern/` ❌ (becomes `{}`)
|
|
36
|
+
- **Dates**: `new Date()` ❌ (becomes string)
|
|
37
|
+
- **WeakMap/WeakSet**: Not serializable
|
|
38
|
+
- **Circular references**: Will throw error
|
|
39
|
+
|
|
40
|
+
## How to Handle Non-Serializable Values
|
|
41
|
+
|
|
42
|
+
### Functions (Parsers, Handlers)
|
|
43
|
+
|
|
44
|
+
**❌ WRONG:**
|
|
45
|
+
```javascript
|
|
46
|
+
// emc.mjs
|
|
47
|
+
function myParser(value) {
|
|
48
|
+
return value.split(',');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const emc = {
|
|
52
|
+
enhConfig: {
|
|
53
|
+
withAttrs: {
|
|
54
|
+
_base: {
|
|
55
|
+
parser: myParser // ❌ Function reference - not JSON serializable
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**✅ CORRECT:**
|
|
63
|
+
```javascript
|
|
64
|
+
// emc.mjs
|
|
65
|
+
export const emc = {
|
|
66
|
+
enhConfig: {
|
|
67
|
+
withAttrs: {
|
|
68
|
+
_base: {
|
|
69
|
+
parser: 'myParser' // ✅ String reference - JSON serializable
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Separate parser file: parser.js
|
|
76
|
+
export default function myParser(value) {
|
|
77
|
+
return value.split(',');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// HTML: Load parser separately
|
|
81
|
+
<script type="emc-parser" src="./parser.js" parser-name="myParser"></script>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Class Constructors (spawn)
|
|
85
|
+
|
|
86
|
+
**❌ WRONG:**
|
|
87
|
+
```javascript
|
|
88
|
+
// emc.mjs
|
|
89
|
+
import { MyEnhancement } from './my-enhancement.js';
|
|
90
|
+
|
|
91
|
+
export const emc = {
|
|
92
|
+
enhConfig: {
|
|
93
|
+
spawn: MyEnhancement // ❌ Class reference - not JSON serializable
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**✅ CORRECT:**
|
|
99
|
+
```javascript
|
|
100
|
+
// emc.mjs
|
|
101
|
+
export const emc = {
|
|
102
|
+
enhConfig: {
|
|
103
|
+
spawn: 'my-enhancement/my-enhancement.js' // ✅ Module path string
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Regular Expressions
|
|
109
|
+
|
|
110
|
+
**❌ WRONG:**
|
|
111
|
+
```javascript
|
|
112
|
+
export const emc = {
|
|
113
|
+
enhConfig: {
|
|
114
|
+
withAttrs: {
|
|
115
|
+
pattern: /^test-/ // ❌ RegExp - becomes {}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**✅ CORRECT:**
|
|
122
|
+
```javascript
|
|
123
|
+
export const emc = {
|
|
124
|
+
enhConfig: {
|
|
125
|
+
withAttrs: {
|
|
126
|
+
pattern: '^test-' // ✅ String - can be converted to RegExp at runtime
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Validation
|
|
133
|
+
|
|
134
|
+
Every `emc.mjs` file should end with:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
export function render() {
|
|
138
|
+
return JSON.stringify(emc, null, 4);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(render());
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Test your configuration:**
|
|
145
|
+
```bash
|
|
146
|
+
node emc.mjs
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
If this command:
|
|
150
|
+
- ✅ Outputs valid JSON → Configuration is serializable
|
|
151
|
+
- ❌ Throws an error → You have non-serializable values
|
|
152
|
+
- ❌ Outputs `{}` or `null` for a property → You have a non-serializable value that was silently dropped
|
|
153
|
+
|
|
154
|
+
## Common Mistakes
|
|
155
|
+
|
|
156
|
+
### Mistake 1: Inline Parser Functions
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
// ❌ WRONG
|
|
160
|
+
export const emc = {
|
|
161
|
+
enhConfig: {
|
|
162
|
+
withAttrs: {
|
|
163
|
+
_base: {
|
|
164
|
+
parser: (v) => v.split(',') // Lost in JSON.stringify()
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Result:** The `parser` property becomes `{}` in the JSON output.
|
|
172
|
+
|
|
173
|
+
### Mistake 2: Importing Classes
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
// ❌ WRONG
|
|
177
|
+
import { MyClass } from './my-class.js';
|
|
178
|
+
|
|
179
|
+
export const emc = {
|
|
180
|
+
customData: {
|
|
181
|
+
helperClass: MyClass // Lost in JSON.stringify()
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Result:** The `helperClass` property becomes `{}` in the JSON output.
|
|
187
|
+
|
|
188
|
+
### Mistake 3: Using undefined
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
// ❌ WRONG
|
|
192
|
+
export const emc = {
|
|
193
|
+
customData: {
|
|
194
|
+
optionalValue: undefined // Omitted in JSON.stringify()
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Result:** The `optionalValue` property is completely omitted from the JSON output.
|
|
200
|
+
|
|
201
|
+
## Best Practices
|
|
202
|
+
|
|
203
|
+
1. **Always test serialization**: Run `node emc.mjs` to verify output
|
|
204
|
+
2. **Use string references**: For parsers, use string names that resolve at runtime
|
|
205
|
+
3. **Use module paths**: For `spawn`, use string paths to modules
|
|
206
|
+
4. **Document external dependencies**: If your config references parsers by name, document which parser files are required
|
|
207
|
+
5. **Avoid undefined**: Use `null` instead if you need to represent "no value"
|
|
208
|
+
6. **Keep it simple**: The simpler your config, the easier it is to serialize
|
|
209
|
+
|
|
210
|
+
## Example: Complete Valid emc.mjs
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
// @ts-check
|
|
214
|
+
|
|
215
|
+
/** @import {EMC} from './types/mount-observer/types' */;
|
|
216
|
+
/** @import {AllProps, Actions} from './types/my-enhancement/types' */
|
|
217
|
+
/** @import {RAConfig} from './types/roundabout/types' */
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* @type {EMC<any, AllProps, Element, RAConfig<AllProps, Actions> >}
|
|
221
|
+
*/
|
|
222
|
+
export const emc = {
|
|
223
|
+
enhConfig: {
|
|
224
|
+
enhKey: 'MyEnhancement',
|
|
225
|
+
spawn: 'my-enhancement/my-enhancement.js', // ✅ String path
|
|
226
|
+
withAttrs: {
|
|
227
|
+
base: 'my-enhancement',
|
|
228
|
+
value: '${base}-value',
|
|
229
|
+
_value: {
|
|
230
|
+
parser: 'myParser' // ✅ String reference
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
customData: {
|
|
235
|
+
weakRef: {
|
|
236
|
+
properties: ['enhancedElement']
|
|
237
|
+
},
|
|
238
|
+
actions: {
|
|
239
|
+
hydrate: {
|
|
240
|
+
ifAllOf: ['value', 'enhancedElement']
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
defaultPropVals: {
|
|
244
|
+
enabled: true,
|
|
245
|
+
count: 0
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export function render() {
|
|
251
|
+
return JSON.stringify(emc, null, 4);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
console.log(render());
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Enforcement
|
|
258
|
+
|
|
259
|
+
This principle should be enforced by:
|
|
260
|
+
|
|
261
|
+
1. **Code review**: Check that all `emc.mjs` files only contain JSON-serializable values
|
|
262
|
+
2. **Testing**: Run `node emc.mjs` as part of the build process
|
|
263
|
+
3. **Documentation**: Reference this principle in conversion guides
|
|
264
|
+
4. **Linting**: Consider adding a custom lint rule to detect non-serializable values
|
|
265
|
+
|
|
266
|
+
## Dependency Version Management
|
|
267
|
+
|
|
268
|
+
**Always use specific point versions** in `package.json`, not version ranges:
|
|
269
|
+
|
|
270
|
+
✅ **CORRECT:**
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"dependencies": {
|
|
274
|
+
"be-hive": "0.1.9",
|
|
275
|
+
"mount-observer": "0.0.16",
|
|
276
|
+
"roundabout-lib": "0.0.2"
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
❌ **WRONG:**
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"dependencies": {
|
|
285
|
+
"be-hive": "^0.1.9", // ❌ Caret allows minor/patch updates
|
|
286
|
+
"mount-observer": "~0.0.16", // ❌ Tilde allows patch updates
|
|
287
|
+
"roundabout-lib": "*" // ❌ Wildcard allows any version
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Why specific versions?**
|
|
293
|
+
- **Reproducible builds**: Same versions across all environments
|
|
294
|
+
- **No surprises**: Prevents automatic breaking changes
|
|
295
|
+
- **Explicit control**: You decide when to update
|
|
296
|
+
- **Easier debugging**: Know exactly which version caused an issue
|
|
297
|
+
- **Consistent testing**: CI/CD uses same versions as development
|
|
298
|
+
|
|
299
|
+
**When to update:**
|
|
300
|
+
Use `npm run update` (which runs `ncu -u && npm install`) to explicitly update all dependencies to their latest versions. Review the changes and test thoroughly before committing.
|
|
301
|
+
|
|
302
|
+
## Related Documentation
|
|
303
|
+
|
|
304
|
+
- [Scoped Parser Registry](https://github.com/bahrus/mount-observer#scoped-parser-registry-for-emc-scripts)
|
|
305
|
+
- [EMC Scripts](https://github.com/bahrus/mount-observer#element-mount-configuration-emc-scripts)
|
|
306
|
+
- [Conversion Instructions](../ConversionInstructions.md)
|