Access parent class code in custom ESLint rule - javascript

Scenario:
I want to check that a child class method calls a super class method using super keyword if parent class has such a method.
Example:
// parent.ts
class Parent {
a {
// super class method
}
}
// child.ts
class Child extends Parent {
a {
// I want to check if parent class has method a
// then the child class should call super.a(). else show a warning
super.a();
}
}
This felt like a use case for writing a custom ESLint rule. I am not able to check if the parent class has a method with name a so far.
Is this possible with ESLint rules? Is custom ESLint rule a good thing to do this or should i use a different approach?

Related

JS: How to create child class from a parent class in Javascript?

How to avoid circular references at the same time create some child classes from the parent class? And keep the constrain that each class need to reside in a different file.
//Parent.mjs:
import Sub from "/.Sub.mjs"
export default class Parent {
static createSomething(){
new Sub();
}
}
//Sub.mjs:
import Parent from "/.Parent.mjs"
export default class Sub extends Parent {
contructor(){}
}
This question was originally posted here. But there is no solution under that question. If I really want to create a subclass from the superclass what code should I write?
The parent class should not need to know anything about subclass(es).
I don't see why the parent class would need a static method for creating a subclass,
but if you feel you really, really need that, then extend the Parent class object from within the Sub.mjs file:
Parent.mjs:
export default class Parent {
}
Sub.mjs:
import Parent from "/.Parent.mjs"
Parent.createSomething = function () {
return new Sub();
}
export default class Sub extends Parent {
constructor(){} // fixed typo here
}
Still, I think it is a bad idea to define such a function on the parent class. This looks like an XY problem. The original reason that made you look for such a function in the first place, certainly has a better way to be solved that doesn't involve a parent class that needs to know about a subclass.

JavaScript - Create elements using web component class

I have a web component that only works when some properties are set, when I create the component with Document.createElement() I can't pass properties then an error happens in my component.
Is it possible to create the component by creating an instance of the component class or something similar and be able to pass parameters to it's constructor?
customElements.define('x-card', class extends HTMLDivElement {
//...
}, { extends: 'div' });
You can create a new instance using new WCard. This requires having access to the class though.
Please note that custom element names preferrably should not start with x-.
So change your code:
export class WCard extends HTMLDivElement {
//...
}
customElements.define('w-card', WCard, { extends: 'div' });
window.WCard = WCard;
This allows you to call new on the class globally, or if your code imports the class.
const wcard = new WCard(...args);

Wrapping a constructor with javascript method decorator

Referenced:
Override constructor with an class decorator?
http://blog.wolksoftware.com/decorators-metadata-reflection-in-typescript-from-novice-to-expert-part-ii
I'd like to wrap a classes constructor with a custom one when applying a method decorator (ie in the same way you could do with a class decorator). I require this as I have another component that will call into the class, and will execute the method that was decorated. Its not hard to have the component execute the method that was decorated, however because the decorator is run before the class is instantiated the decorated method will not be associated with a class instance and therefore will not have access to any of the classes state (ie this == undefined). So I want to be able to provide the method reference to the component during class instantiation (ie constructor) so that it is bound to the current instance.
So I'd like to do this (typescript):
class Foo {
constructor(private value) { }
#execute
bar() {
return this.value;
}
}
Which would have the same affect as doing this:
class Foo {
constructor(private value) {
StaticComponent.AddReference(this.bar().bind(this));
}
bar() {
return this.value;
}
}
If my other component has a reference to bar() it should be able to execute it with bar having full access to its instance.
I've tried to override the prototype of the target etc in a similar way you might do so for a class decorator, but couldn't get that to work.

Applying Behaviors with JS Mixins in Polymer 2

I want a custom element I'm defining to have the Polymer.IronScrollTargetBehavior in Polymer 2.
In Polymer 1, this can be done by adding it to the behaviors array:
Polymer({
is: 'my-element',
behaviors: [Polymer.IronScrollTargetBehavior]
});
In the Polymer 2 upgrade guide, it says that you should:
Implement "behaviors" as mixins that return class expressions.
In the linked article, it explains how you can use the following syntax for mixins:
let MyMixin = (superclass) => class extends superclass {
foo() {
console.log('foo from MyMixin');
}
};
class MyClass extends MyMixin(MyBaseClass) {
/* ... */
}
I mostly get what's going on here (although I find the mixin syntax difficult to wrap my mind around), and I can get sample code to work.
What I haven't been able to do is apply this concept to Polymer.IronScrollTargetBehavior, and create a mixin for it. Since that behavior is already defined as an object, I don't know where to fit it in.
So, how do I implement the proper mixin in this scenario, or if I'm on the wrong path, how to I apply one of the defined Polymer behaviors to my custom element in Polymer 2?
You can use the Polymer 2 hybrid behaviours as mixins by extending
Polymer.mixinBehaviors(behaviors, klass) where
- behaviors is the Behavior object or array of behaviors
- klass is the Element class.
i.e.
<dom-module id="element-name">
<template><!-- ... --></template>
<script>
class MyElement extends Polymer.mixinBehaviors([MyBehavior, MyBehavior2], Polymer.Element) {
static get is() { return 'element-name' }
/* ... */
}
customElements.define('element-name', MyElement);
</script>
</dom-module>
For more detailed information search the Polymer source code for mixinBehaviors method: polymer/lib/legacy/class.html
worth reading: https://www.polymer-project.org/2.0/docs/upgrade#mixins
Polymer 2.0 has a compatibility layer that still supports the old Polymer function syntax. Most of the 2.0 preview elements, if not all, still retain the old syntax. The breaking changes are mostly in the dom-module markup.
If you are composing new elements, it is recommended you switch over to the class based syntax. If however you are porting 1.0 elements to 2.0 and those elements rely on Polymer behaviors, I don't think you much choice at this juncture but to retain the old syntax.
In the class-based syntax you can fluently simulate Element multiple inheritance of class mixins with something like this
let Mixin = (superclass) => new MixinBuilder(superclass);
class MixinBuilder {
constructor(superclass) {
this.superclass = superclass;
}
with(...mixins) {
return mixins.reduce((c, mixin) => mixin(c), this.superclass);
}
}
const MyMixin = subclass => class extends subclass {
_test(){
}
}
const MyMixinTwo = subclass => class extends subclass {
_testTwo(){
}
}
class MyElement extends Mixin(Polymer.Element).with(MyMixin,MyMixin2) {
static get is() { return 'my-element' }
}
You can separate the MixinBuilder into its own file and then reference it as an Html Import dependency whenever composing elements that use mixins.

Custom element's Binding Context - what is it exactly, how to access parent VM

I couldn't find the answer in the docs, so I'm asking here. What exactly is the binding context passed to the bind method of custom element. Is it simply equal to router's currently active ViewModel? At least, that's what I've found out so far.
Why isn't it the element's parent (in the terms of DOM) VM?
with this code
#customElement("myelem")
#inlineView("<template><content></content></template>")
export class MyElem{
bind(ctx){
console.log(ctx);
}
}
// welcome.html
<myelem>
<h3>inside myelem</h3>
<myelem>
<h4>inside inside ... </h4>
</myelem>
</myelem>
the output in the console is just current viewmodel (Welcome) printed twice.
I'd expect it to be Welcome for the first (outer) myelem, but MyElem for the second (inner) occurance...
Please explain why am I wrong here, and how can the inner custom element be aware of it's actual context (by which I mean the outer one in the case above), without using ugly hacks like creating secret property in the "shared" context (the one which actually gets passed to both of them)
In terms of data-binding, both elements are bound to the same binding context. Consider this example:
<div foo.bind="bar">
<div foo.bind="bar"></div>
</div>
You would expect both <div> elements to have the same binding context right? Both element's foo property should be bound to the same model's bar property. The same holds true in this scenario:
<myelem foo.bind="bar">
<myelem foo.bind="bar"></myelem>
</myelem>
Both instances of <myelem> are bound to the same binding context / model.
If I understand the question correctly, you would like an elegant way to give the inner MyElem class instance a reference to the outer MyElem class instance. Luckily, you're using Aurelia so there is a very nice way to do this... declare it as a dependency using the inject decorator:
import {inject, Parent} from 'aurelia-dependency-injection';
import {customElement} from 'aurelia-framework';
#customElement("myelem")
#inject(Parent.of(MyElem))
export class MyElem {
constructor(parent) {
this.parent = parent;
}
...
}
There's one caveat however...
The Aurelia dependency-injection container's default behavior is to create an instance of the requested item if an instance is not found in the container. This means that #inject(Parent.of(MyElem)) is not quite what we want. In situations where there is no parent MyElem instance the container will create one for us instead of returning null. Normally we'd use #inject(Optional.of(MyElem)) to tell the container to give us the instance, only when it exists in the container. I don't know of a way to combine Parent.of and Optional.of. I'll create an issue in the aurelia dependency-injection repository so we can get this feature added.
In the meantime, we can easily create our own Resolver that combines the behavior of Parent.of and Optional.of:
import {resolver} from 'aurelia-dependency-injection';
#resolver()
export class OptionalParent {
constructor(key) {
this.key = key;
}
get(container) {
if (container.parent && container.parent.hasResolver(this.key, false)) {
return container.parent.get(this.key)
}
return null;
}
static of(key) {
return new OptionalParent(key);
}
}
So the new version of our MyElem class would look like this:
import {inject} from 'aurelia-dependency-injection';
import {customElement} from 'aurelia-framework';
import {OptionalParent} from './optional-parent';
#customElement("myelem")
#inject(OptionalParent.of(MyElem))
export class MyElem {
constructor(parent) {
this.parent = parent;
}
...
}
Here's a working example. Check the console for log messages showing the result:
https://gist.run/?id=1a84e0a466fb928aa075

Categories