gonia 0.2.1 → 0.2.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.
@@ -12,6 +12,20 @@ import { FOR_PROCESSED_ATTR, FOR_TEMPLATE_ATTR } from '../directives/for.js';
12
12
  import { IF_PROCESSED_ATTR } from '../directives/if.js';
13
13
  import { resolveDependencies as resolveInjectables } from '../inject.js';
14
14
  import { resolveContext } from '../context-registry.js';
15
+ /**
16
+ * Decode HTML entities that happy-dom doesn't decode.
17
+ *
18
+ * @internal
19
+ */
20
+ function decodeHTMLEntities(str) {
21
+ return str
22
+ .replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code)))
23
+ .replace(/"/g, '"')
24
+ .replace(/'/g, "'")
25
+ .replace(/&lt;/g, '<')
26
+ .replace(/&gt;/g, '>')
27
+ .replace(/&amp;/g, '&');
28
+ }
15
29
  /** Registered services */
16
30
  let services = new Map();
17
31
  const selectorCache = new WeakMap();
@@ -152,6 +166,27 @@ export async function render(html, state, registry) {
152
166
  });
153
167
  continue;
154
168
  }
169
+ // Handle g-scope elements that don't have other directives
170
+ // Add a placeholder entry so they get processed
171
+ if (match.hasAttribute('g-scope')) {
172
+ let hasDirective = false;
173
+ for (const [name] of registry) {
174
+ if (match.hasAttribute(`g-${name}`)) {
175
+ hasDirective = true;
176
+ break;
177
+ }
178
+ }
179
+ if (!hasDirective) {
180
+ index.push({
181
+ el: match,
182
+ name: 'scope',
183
+ directive: null,
184
+ expr: '',
185
+ priority: DirectivePriority.STRUCTURAL,
186
+ isNativeSlot: false
187
+ });
188
+ }
189
+ }
155
190
  for (const [name, directive] of registry) {
156
191
  const attr = match.getAttribute(`g-${name}`);
157
192
  if (attr !== null) {
@@ -161,7 +196,7 @@ export async function render(html, state, registry) {
161
196
  el: match,
162
197
  name,
163
198
  directive,
164
- expr: attr,
199
+ expr: decodeHTMLEntities(attr),
165
200
  priority: directive.priority ?? DirectivePriority.NORMAL,
166
201
  using: registration?.options.using
167
202
  });
@@ -227,7 +262,7 @@ export async function render(html, state, registry) {
227
262
  // Process g-scope first (inline scope initialization)
228
263
  const scopeAttr = el.getAttribute('g-scope');
229
264
  if (scopeAttr) {
230
- const scopeValues = ctx.eval(scopeAttr);
265
+ const scopeValues = ctx.eval(decodeHTMLEntities(scopeAttr));
231
266
  if (scopeValues && typeof scopeValues === 'object') {
232
267
  Object.assign(state, scopeValues);
233
268
  }
@@ -236,7 +271,7 @@ export async function render(html, state, registry) {
236
271
  for (const attr of [...el.attributes]) {
237
272
  if (attr.name.startsWith('g-bind:')) {
238
273
  const targetAttr = attr.name.slice('g-bind:'.length);
239
- const value = ctx.eval(attr.value);
274
+ const value = ctx.eval(decodeHTMLEntities(attr.value));
240
275
  if (value === null || value === undefined) {
241
276
  el.removeAttribute(targetAttr);
242
277
  }
@@ -253,6 +288,10 @@ export async function render(html, state, registry) {
253
288
  if (item.isNativeSlot) {
254
289
  processNativeSlot(item.el);
255
290
  }
291
+ else if (item.directive === null) {
292
+ // Placeholder for g-scope - already processed above
293
+ continue;
294
+ }
256
295
  else {
257
296
  const config = createServerResolverConfig(item.el, state);
258
297
  const args = resolveInjectables(item.directive, item.expr, item.el, ctx.eval.bind(ctx), config, item.using);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gonia",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "A lightweight, SSR-first reactive UI library with declarative directives",
5
5
  "type": "module",
6
6
  "license": "MIT",