@fluffjs/cli 0.3.1 → 0.3.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.
@@ -86,7 +86,7 @@ export class ComponentCompiler {
86
86
  const componentDir = path.dirname(filePath);
87
87
  const parser = this.createTemplateParser(filePath);
88
88
  reactivePropertiesMap.delete(filePath);
89
- if (source.includes('@Reactive') || source.includes('@Input')) {
89
+ if (source.includes('@Reactive') || source.includes('@Input') || source.includes('@HostListener') || source.includes('@HostBinding') || source.includes('@Watch') || source.includes('@ViewChild') || source.includes('@LinkedProperty')) {
90
90
  source = await this.transformReactiveProperties(source, filePath, production);
91
91
  }
92
92
  const metadata = await this.extractComponentMetadata(source, filePath);
@@ -190,8 +190,16 @@ export default function reactivePlugin() {
190
190
  t.variableDeclaration('const', [t.variableDeclarator(t.identifier('__v'), t.memberExpression(t.thisExpression(), t.identifier(getterName)))]),
191
191
  updateStatement
192
192
  ]));
193
+ const watchedProps = [];
194
+ memberPath.traverse({
195
+ MemberExpression(mePath) {
196
+ if (t.isThisExpression(mePath.node.object) && t.isIdentifier(mePath.node.property)) {
197
+ watchedProps.push(mePath.node.property.name);
198
+ }
199
+ }
200
+ });
193
201
  newMembers.push(updateMethod);
194
- getterHostBindingUpdates.push(`__updateHostBinding_${getterName}`);
202
+ getterHostBindingUpdates.push({ updateMethodName: `__updateHostBinding_${getterName}`, watchedProps });
195
203
  }
196
204
  }
197
205
  decorators.splice(hostBindingIndex, 1);
@@ -287,9 +295,19 @@ export default function reactivePlugin() {
287
295
  if (args.length === 0)
288
296
  continue;
289
297
  const [optionsArg] = args;
290
- if (!t.isObjectExpression(optionsArg))
298
+ let optionsObject = t.isObjectExpression(optionsArg) ? optionsArg : undefined;
299
+ if (t.isIdentifier(optionsArg)) {
300
+ const binding = path.scope.getBinding(optionsArg.name);
301
+ if (binding?.path.isVariableDeclarator()) {
302
+ const { init } = binding.path.node;
303
+ if (t.isObjectExpression(init)) {
304
+ optionsObject = init;
305
+ }
306
+ }
307
+ }
308
+ if (!optionsObject)
291
309
  continue;
292
- for (const prop of optionsArg.properties) {
310
+ for (const prop of optionsObject.properties) {
293
311
  if (!t.isObjectProperty(prop))
294
312
  continue;
295
313
  if (prop.computed || !t.isIdentifier(prop.key))
@@ -383,8 +401,13 @@ export default function reactivePlugin() {
383
401
  for (const { propName, className, privateName } of classHostBindingDefs) {
384
402
  constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('__defineClassHostBinding')), [t.stringLiteral(propName), t.stringLiteral(className), t.stringLiteral(privateName)])));
385
403
  }
386
- for (const updateMethodName of getterHostBindingUpdates) {
404
+ for (const { updateMethodName, watchedProps } of getterHostBindingUpdates) {
387
405
  constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier(updateMethodName)), [])));
406
+ for (const prop of watchedProps) {
407
+ if (reactiveProps.has(prop)) {
408
+ constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('__baseSubscriptions')), t.identifier('push')), [t.callExpression(t.memberExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier(`__${prop}`)), t.identifier('onChange')), t.identifier('subscribe')), [t.arrowFunctionExpression([], t.callExpression(t.memberExpression(t.thisExpression(), t.identifier(updateMethodName)), []))])])));
409
+ }
410
+ }
388
411
  }
389
412
  for (const { propName, privateName } of propertyHostBindingInits) {
390
413
  constructorStatements.push(t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier(propName)), t.memberExpression(t.thisExpression(), t.identifier(privateName)))));
@@ -420,8 +443,19 @@ export default function reactivePlugin() {
420
443
  const watchClassProp = t.classProperty(t.identifier(propName), t.callExpression(t.arrowFunctionExpression([], t.blockStatement(iife)), []));
421
444
  path.pushContainer('body', watchClassProp);
422
445
  }
446
+ const globalListenerCleanups = [];
423
447
  for (const { methodName, eventName } of hostListeners) {
424
- const [baseEvent, ...modifiers] = eventName.split('.');
448
+ let target = 'this';
449
+ let eventPart = eventName;
450
+ if (eventName.startsWith('document:')) {
451
+ target = 'document';
452
+ eventPart = eventName.slice('document:'.length);
453
+ }
454
+ else if (eventName.startsWith('window:')) {
455
+ target = 'window';
456
+ eventPart = eventName.slice('window:'.length);
457
+ }
458
+ const [baseEvent, ...modifiers] = eventPart.split('.');
425
459
  let handlerBody = t.emptyStatement();
426
460
  if (modifiers.length > 0) {
427
461
  const conditions = modifiers.map(mod => {
@@ -439,10 +473,23 @@ export default function reactivePlugin() {
439
473
  else {
440
474
  handlerBody = t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier(methodName)), [t.identifier('__ev')]));
441
475
  }
442
- constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('addEventListener')), [
443
- t.stringLiteral(baseEvent),
444
- t.arrowFunctionExpression([t.identifier('__ev')], t.blockStatement([handlerBody]))
445
- ])));
476
+ const handlerFn = t.arrowFunctionExpression([t.identifier('__ev')], t.blockStatement([handlerBody]));
477
+ if (target === 'this') {
478
+ constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('addEventListener')), [
479
+ t.stringLiteral(baseEvent),
480
+ handlerFn
481
+ ])));
482
+ }
483
+ else {
484
+ const handlerPropName = `__${methodName}Handler`;
485
+ const targetExpr = target === 'document' ? t.identifier('document') : t.identifier('window');
486
+ constructorStatements.push(t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier(handlerPropName)), handlerFn)));
487
+ constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(targetExpr, t.identifier('addEventListener')), [
488
+ t.stringLiteral(baseEvent),
489
+ t.memberExpression(t.thisExpression(), t.identifier(handlerPropName))
490
+ ])));
491
+ globalListenerCleanups.push(t.expressionStatement(t.callExpression(t.memberExpression(target === 'document' ? t.identifier('document') : t.identifier('window'), t.identifier('removeEventListener')), [t.stringLiteral(baseEvent), t.memberExpression(t.thisExpression(), t.identifier(handlerPropName))])));
492
+ }
446
493
  }
447
494
  if (constructorStatements.length > 0) {
448
495
  const constructor = path.node.body.find((m) => t.isClassMethod(m) && m.kind === 'constructor');
@@ -456,6 +503,15 @@ export default function reactivePlugin() {
456
503
  ])));
457
504
  }
458
505
  }
506
+ if (globalListenerCleanups.length > 0) {
507
+ const disconnectedCallback = path.node.body.find((m) => t.isClassMethod(m) && t.isIdentifier(m.key) && m.key.name === 'disconnectedCallback');
508
+ if (disconnectedCallback) {
509
+ disconnectedCallback.body.body.unshift(...globalListenerCleanups);
510
+ }
511
+ else {
512
+ path.pushContainer('body', t.classMethod('method', t.identifier('disconnectedCallback'), [], t.blockStatement(globalListenerCleanups)));
513
+ }
514
+ }
459
515
  },
460
516
  ClassDeclaration(path, state) {
461
517
  const decorators = path.node.decorators ?? [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluffjs/cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",