@esphome/compose 0.1.2 → 0.1.3

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/dist/index.js CHANGED
@@ -174,10 +174,16 @@ function useScript(metadata) {
174
174
  return [{ "script.execute": metadata.id }];
175
175
  }
176
176
 
177
- // src/runtime.ts
177
+ // src/serialize.ts
178
178
  function camelToSnake(key) {
179
179
  return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
180
180
  }
181
+ function toYamlKey(type) {
182
+ if (type.startsWith("lvgl-")) {
183
+ return type.slice(5).replace(/-/g, "_");
184
+ }
185
+ return type;
186
+ }
181
187
  function keysToSnakeCase(obj) {
182
188
  const out = {};
183
189
  for (const [k, v] of Object.entries(obj)) {
@@ -193,6 +199,95 @@ function serializeValue(v) {
193
199
  }
194
200
  return v;
195
201
  }
202
+ function stripUndefined(obj) {
203
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0));
204
+ }
205
+ function extractElementProps(el) {
206
+ const { children, ref, "x:custom": xCustom, ...ownProps } = el.props;
207
+ const propsWithId = ref != null ? { id: isRef(ref) ? ref.toString() : String(ref), ...ownProps } : ownProps;
208
+ const allProps = xCustom != null ? { ...propsWithId, ...xCustom } : propsWithId;
209
+ return { allProps, children };
210
+ }
211
+ function Fragment(props) {
212
+ const { children } = props;
213
+ if (children == null) return null;
214
+ return Array.isArray(children) ? children : [children];
215
+ }
216
+ function flattenFragments(elements) {
217
+ const out = [];
218
+ for (const el of elements) {
219
+ if (el.type === Fragment) {
220
+ const result = Fragment(el.props);
221
+ if (result != null) {
222
+ const nested = Array.isArray(result) ? result : [result];
223
+ out.push(...flattenFragments(nested));
224
+ }
225
+ } else {
226
+ out.push(el);
227
+ }
228
+ }
229
+ return out;
230
+ }
231
+
232
+ // src/lvgl.ts
233
+ function isLvglElement(type) {
234
+ return typeof type === "string" && type.startsWith("lvgl-");
235
+ }
236
+ function resolveLvglChildren(children) {
237
+ if (!children) return [];
238
+ const arr = Array.isArray(children) ? children : [children];
239
+ const flat = flattenFragments(arr);
240
+ const resolved = [];
241
+ for (const el of flat) {
242
+ if (typeof el.type === "function") {
243
+ const result = el.type(el.props);
244
+ if (result == null) continue;
245
+ const rendered = Array.isArray(result) ? result : [result];
246
+ resolved.push(...resolveLvglChildren(rendered));
247
+ } else {
248
+ resolved.push(el);
249
+ }
250
+ }
251
+ return resolved;
252
+ }
253
+ function lvglWidgetToPlain(el) {
254
+ const { allProps, children } = extractElementProps(el);
255
+ const widgetChildren = resolveLvglChildren(children);
256
+ const lvglChildren = widgetChildren.filter((c) => isLvglElement(c.type));
257
+ const nestedWidgets = lvglChildren.map(lvglWidgetToPlain);
258
+ const data = { ...allProps };
259
+ if (nestedWidgets.length > 0) {
260
+ data.widgets = nestedWidgets;
261
+ }
262
+ const yamlKey = toYamlKey(el.type);
263
+ return { [yamlKey]: stripUndefined(keysToSnakeCase(data)) };
264
+ }
265
+ function buildLvglSection(el) {
266
+ const { allProps, children } = extractElementProps(el);
267
+ const resolved = resolveLvglChildren(children);
268
+ const pages = [];
269
+ const topWidgets = [];
270
+ for (const child of resolved) {
271
+ if (child.type === "lvgl-page") {
272
+ const { allProps: pageProps, children: pageChildren } = extractElementProps(child);
273
+ const pageResolved = resolveLvglChildren(pageChildren);
274
+ const pageWidgets = pageResolved.filter((c) => isLvglElement(c.type)).map(lvglWidgetToPlain);
275
+ const pageData = { ...pageProps };
276
+ if (pageWidgets.length > 0) {
277
+ pageData.widgets = pageWidgets;
278
+ }
279
+ pages.push(stripUndefined(keysToSnakeCase(pageData)));
280
+ } else if (isLvglElement(child.type)) {
281
+ topWidgets.push(lvglWidgetToPlain(child));
282
+ }
283
+ }
284
+ const data = { ...allProps };
285
+ if (pages.length > 0) data.pages = pages;
286
+ if (topWidgets.length > 0) data.widgets = topWidgets;
287
+ return stripUndefined(keysToSnakeCase(data));
288
+ }
289
+
290
+ // src/runtime.ts
196
291
  function createElement(type, props, ...children) {
197
292
  const flatChildren = children.flat().filter((c) => c != null);
198
293
  return {
@@ -203,11 +298,6 @@ function createElement(type, props, ...children) {
203
298
  }
204
299
  };
205
300
  }
206
- function Fragment(props) {
207
- const { children } = props;
208
- if (children == null) return null;
209
- return Array.isArray(children) ? children : [children];
210
- }
211
301
  function toPlainObject(el) {
212
302
  if (el == null) return void 0;
213
303
  if (Array.isArray(el)) {
@@ -231,11 +321,18 @@ function toPlainObject(el) {
231
321
  ...childSections
232
322
  };
233
323
  }
324
+ if (el.type === "lvgl") {
325
+ const lvglData = buildLvglSection(el);
326
+ return { lvgl: Object.keys(lvglData).length > 0 ? lvglData : null };
327
+ }
328
+ if (isLvglElement(el.type)) {
329
+ return lvglWidgetToPlain(el);
330
+ }
234
331
  const childData = buildChildData(
235
332
  children
236
333
  );
237
334
  const data = stripUndefined(keysToSnakeCase({ ...allProps, ...childData }));
238
- return { [el.type]: Object.keys(data).length > 0 ? data : null };
335
+ return { [toYamlKey(el.type)]: Object.keys(data).length > 0 ? data : null };
239
336
  }
240
337
  function childrenToTopLevelSections(children) {
241
338
  if (!children) return {};
@@ -261,6 +358,12 @@ function childrenToTopLevelSections(children) {
261
358
  return out;
262
359
  }
263
360
  function mergeSection(sections, child) {
361
+ if (child.type === "lvgl") {
362
+ const lvglData = buildLvglSection(child);
363
+ if (!sections["lvgl"]) sections["lvgl"] = [];
364
+ sections["lvgl"].push(Object.keys(lvglData).length > 0 ? lvglData : null);
365
+ return;
366
+ }
264
367
  const { children: grandchildren, ref, "x:custom": xCustom, ...ownProps } = child.props;
265
368
  const propsWithId = ref != null ? { id: isRef(ref) ? ref.toString() : String(ref), ...ownProps } : ownProps;
266
369
  const allProps = xCustom != null ? { ...propsWithId, ...xCustom } : propsWithId;
@@ -268,8 +371,9 @@ function mergeSection(sections, child) {
268
371
  grandchildren
269
372
  );
270
373
  const data = stripUndefined(keysToSnakeCase({ ...allProps, ...childData }));
271
- if (!sections[child.type]) sections[child.type] = [];
272
- sections[child.type].push(Object.keys(data).length > 0 ? data : null);
374
+ const yamlKey = toYamlKey(child.type);
375
+ if (!sections[yamlKey]) sections[yamlKey] = [];
376
+ sections[yamlKey].push(Object.keys(data).length > 0 ? data : null);
273
377
  }
274
378
  function buildChildData(children) {
275
379
  if (!children) return {};
@@ -283,24 +387,6 @@ function buildChildData(children) {
283
387
  }
284
388
  return out;
285
389
  }
286
- function flattenFragments(elements) {
287
- const out = [];
288
- for (const el of elements) {
289
- if (el.type === Fragment) {
290
- const result = Fragment(el.props);
291
- if (result != null) {
292
- const nested = Array.isArray(result) ? result : [result];
293
- out.push(...flattenFragments(nested));
294
- }
295
- } else {
296
- out.push(el);
297
- }
298
- }
299
- return out;
300
- }
301
- function stripUndefined(obj) {
302
- return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0));
303
- }
304
390
  function render(element) {
305
391
  return toPlainObject(Array.isArray(element) ? element : element);
306
392
  }
package/dist/index.mjs CHANGED
@@ -114,10 +114,16 @@ function useScript(metadata) {
114
114
  return [{ "script.execute": metadata.id }];
115
115
  }
116
116
 
117
- // src/runtime.ts
117
+ // src/serialize.ts
118
118
  function camelToSnake(key) {
119
119
  return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
120
120
  }
121
+ function toYamlKey(type) {
122
+ if (type.startsWith("lvgl-")) {
123
+ return type.slice(5).replace(/-/g, "_");
124
+ }
125
+ return type;
126
+ }
121
127
  function keysToSnakeCase(obj) {
122
128
  const out = {};
123
129
  for (const [k, v] of Object.entries(obj)) {
@@ -133,6 +139,95 @@ function serializeValue(v) {
133
139
  }
134
140
  return v;
135
141
  }
142
+ function stripUndefined(obj) {
143
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0));
144
+ }
145
+ function extractElementProps(el) {
146
+ const { children, ref, "x:custom": xCustom, ...ownProps } = el.props;
147
+ const propsWithId = ref != null ? { id: isRef(ref) ? ref.toString() : String(ref), ...ownProps } : ownProps;
148
+ const allProps = xCustom != null ? { ...propsWithId, ...xCustom } : propsWithId;
149
+ return { allProps, children };
150
+ }
151
+ function Fragment(props) {
152
+ const { children } = props;
153
+ if (children == null) return null;
154
+ return Array.isArray(children) ? children : [children];
155
+ }
156
+ function flattenFragments(elements) {
157
+ const out = [];
158
+ for (const el of elements) {
159
+ if (el.type === Fragment) {
160
+ const result = Fragment(el.props);
161
+ if (result != null) {
162
+ const nested = Array.isArray(result) ? result : [result];
163
+ out.push(...flattenFragments(nested));
164
+ }
165
+ } else {
166
+ out.push(el);
167
+ }
168
+ }
169
+ return out;
170
+ }
171
+
172
+ // src/lvgl.ts
173
+ function isLvglElement(type) {
174
+ return typeof type === "string" && type.startsWith("lvgl-");
175
+ }
176
+ function resolveLvglChildren(children) {
177
+ if (!children) return [];
178
+ const arr = Array.isArray(children) ? children : [children];
179
+ const flat = flattenFragments(arr);
180
+ const resolved = [];
181
+ for (const el of flat) {
182
+ if (typeof el.type === "function") {
183
+ const result = el.type(el.props);
184
+ if (result == null) continue;
185
+ const rendered = Array.isArray(result) ? result : [result];
186
+ resolved.push(...resolveLvglChildren(rendered));
187
+ } else {
188
+ resolved.push(el);
189
+ }
190
+ }
191
+ return resolved;
192
+ }
193
+ function lvglWidgetToPlain(el) {
194
+ const { allProps, children } = extractElementProps(el);
195
+ const widgetChildren = resolveLvglChildren(children);
196
+ const lvglChildren = widgetChildren.filter((c) => isLvglElement(c.type));
197
+ const nestedWidgets = lvglChildren.map(lvglWidgetToPlain);
198
+ const data = { ...allProps };
199
+ if (nestedWidgets.length > 0) {
200
+ data.widgets = nestedWidgets;
201
+ }
202
+ const yamlKey = toYamlKey(el.type);
203
+ return { [yamlKey]: stripUndefined(keysToSnakeCase(data)) };
204
+ }
205
+ function buildLvglSection(el) {
206
+ const { allProps, children } = extractElementProps(el);
207
+ const resolved = resolveLvglChildren(children);
208
+ const pages = [];
209
+ const topWidgets = [];
210
+ for (const child of resolved) {
211
+ if (child.type === "lvgl-page") {
212
+ const { allProps: pageProps, children: pageChildren } = extractElementProps(child);
213
+ const pageResolved = resolveLvglChildren(pageChildren);
214
+ const pageWidgets = pageResolved.filter((c) => isLvglElement(c.type)).map(lvglWidgetToPlain);
215
+ const pageData = { ...pageProps };
216
+ if (pageWidgets.length > 0) {
217
+ pageData.widgets = pageWidgets;
218
+ }
219
+ pages.push(stripUndefined(keysToSnakeCase(pageData)));
220
+ } else if (isLvglElement(child.type)) {
221
+ topWidgets.push(lvglWidgetToPlain(child));
222
+ }
223
+ }
224
+ const data = { ...allProps };
225
+ if (pages.length > 0) data.pages = pages;
226
+ if (topWidgets.length > 0) data.widgets = topWidgets;
227
+ return stripUndefined(keysToSnakeCase(data));
228
+ }
229
+
230
+ // src/runtime.ts
136
231
  function createElement(type, props, ...children) {
137
232
  const flatChildren = children.flat().filter((c) => c != null);
138
233
  return {
@@ -143,11 +238,6 @@ function createElement(type, props, ...children) {
143
238
  }
144
239
  };
145
240
  }
146
- function Fragment(props) {
147
- const { children } = props;
148
- if (children == null) return null;
149
- return Array.isArray(children) ? children : [children];
150
- }
151
241
  function toPlainObject(el) {
152
242
  if (el == null) return void 0;
153
243
  if (Array.isArray(el)) {
@@ -171,11 +261,18 @@ function toPlainObject(el) {
171
261
  ...childSections
172
262
  };
173
263
  }
264
+ if (el.type === "lvgl") {
265
+ const lvglData = buildLvglSection(el);
266
+ return { lvgl: Object.keys(lvglData).length > 0 ? lvglData : null };
267
+ }
268
+ if (isLvglElement(el.type)) {
269
+ return lvglWidgetToPlain(el);
270
+ }
174
271
  const childData = buildChildData(
175
272
  children
176
273
  );
177
274
  const data = stripUndefined(keysToSnakeCase({ ...allProps, ...childData }));
178
- return { [el.type]: Object.keys(data).length > 0 ? data : null };
275
+ return { [toYamlKey(el.type)]: Object.keys(data).length > 0 ? data : null };
179
276
  }
180
277
  function childrenToTopLevelSections(children) {
181
278
  if (!children) return {};
@@ -201,6 +298,12 @@ function childrenToTopLevelSections(children) {
201
298
  return out;
202
299
  }
203
300
  function mergeSection(sections, child) {
301
+ if (child.type === "lvgl") {
302
+ const lvglData = buildLvglSection(child);
303
+ if (!sections["lvgl"]) sections["lvgl"] = [];
304
+ sections["lvgl"].push(Object.keys(lvglData).length > 0 ? lvglData : null);
305
+ return;
306
+ }
204
307
  const { children: grandchildren, ref, "x:custom": xCustom, ...ownProps } = child.props;
205
308
  const propsWithId = ref != null ? { id: isRef(ref) ? ref.toString() : String(ref), ...ownProps } : ownProps;
206
309
  const allProps = xCustom != null ? { ...propsWithId, ...xCustom } : propsWithId;
@@ -208,8 +311,9 @@ function mergeSection(sections, child) {
208
311
  grandchildren
209
312
  );
210
313
  const data = stripUndefined(keysToSnakeCase({ ...allProps, ...childData }));
211
- if (!sections[child.type]) sections[child.type] = [];
212
- sections[child.type].push(Object.keys(data).length > 0 ? data : null);
314
+ const yamlKey = toYamlKey(child.type);
315
+ if (!sections[yamlKey]) sections[yamlKey] = [];
316
+ sections[yamlKey].push(Object.keys(data).length > 0 ? data : null);
213
317
  }
214
318
  function buildChildData(children) {
215
319
  if (!children) return {};
@@ -223,24 +327,6 @@ function buildChildData(children) {
223
327
  }
224
328
  return out;
225
329
  }
226
- function flattenFragments(elements) {
227
- const out = [];
228
- for (const el of elements) {
229
- if (el.type === Fragment) {
230
- const result = Fragment(el.props);
231
- if (result != null) {
232
- const nested = Array.isArray(result) ? result : [result];
233
- out.push(...flattenFragments(nested));
234
- }
235
- } else {
236
- out.push(el);
237
- }
238
- }
239
- return out;
240
- }
241
- function stripUndefined(obj) {
242
- return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0));
243
- }
244
330
  function render(element) {
245
331
  return toPlainObject(Array.isArray(element) ? element : element);
246
332
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@esphome/compose",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "ESPHome Compose SDK - TypeScript framework for generating ESPHome YAML",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -50,7 +50,6 @@
50
50
  "scripts": {
51
51
  "build": "tsup src/index.ts --format cjs,esm --dts --tsconfig tsconfig.json",
52
52
  "clean": "rimraf dist",
53
- "codegen": "tsx tools/codegen/generate.ts",
54
53
  "lint": "eslint src",
55
54
  "test": "echo \"No tests yet\""
56
55
  }