Get path of required module in NodeJS - node.js

I have 2 classes, one that extends from the other. I need to have a method that can be called from extending classes but resolves the path to reflect whatever directory the extending class module is in.
/main.js
class Main {
getTemplate () {
return readFileSync(__dirname + './template.ejs')
}
}
/some/path/module.js (also contains /some/path/template.ejs)
class Module extends Main {
}
In main code
const m = new Module()
m.getTemplate() // /some/path/template.ejs
The above doesn't work since __dirname doesn't reflect the 'module.js' path.
I've played around with require.resolve but I am not sure how I can use this from within the module.

/main.js
class Main {
constructor(dirname) {
this.dirname = dirname;
}
getTemplate () {
return readFileSync(this.dirname + './template.ejs')
}
}
/some/path/module.js (also contains /some/path/template.ejs)
class Module extends Main {
constructor() {
super(__dirname);
}
}

Ok. I've got a working alas hokey solution.
class Main {
constructor () {
try {
throw new Error()
} catch(e) {
const m = e.stack.match(/at new \w+ \(([^:]+)/)
this.dirname = path.dirname(m[1])
}
}
getTemplate () {
return readFileSync(this.dirname + '/template.ejs')
}
}
class Module extends Main {
}

Related

Get filename of derived class from base class in typescript running on node.js?

I'm looking for a way to get the filename of a derived class from a base class in typescript running on node.js. An example of this would be:
Foo.ts
export abstract class Foo {
constructor() { }
name() { return (__filename); }
print() { console.log(this.name()); }
}
Bar.ts
import { Foo } from './Foo';
export class Bar extends Foo {
constructor() { super(); }
}
main.ts
import { Bar } from './Bar';
let bar = new Bar();
bar.print(); // should yield the location of Bar.ts
Due to the number of files involved and just cleanliness I'd like this to be confined to the Foo class rather than having an override of the name() function in each derived class.
I was able to sort-of solve this with the code:
private getDerivedFilePath(): string {
let errorStack: string[] = new Error().stack.split('\n');
let ret: string = __filename;
let baseClass: any = ThreadPoolThreadBase;
for (let i: number = 3; i < errorStack.length; i++) {
let filename: string = errorStack[i].slice(
errorStack[i].lastIndexOf('(') + 1,
Math.max(errorStack[i].lastIndexOf('.js'), errorStack[i].lastIndexOf('.ts')) + 3
);
let other: any = require(filename);
if (other.__proto__ === baseClass) {
ret = filename;
baseClass = other;
} else {
break;
}
}
return (ret || '');
}
Added to Foo, which will work when called from the constructor to set a private _filename property, for inheritance chains beyond the example above so long as the files are structured with a default export of the class being used. There may also be a caveat that if a base class from which a derived object is inheriting directly is initialized as a separate instance within the constructor of any member of the inheritance chain it could get confused and jump to another independent derived class - so it's a bit of a hacky work-around and I'd be interested if someone comes up with something better, but wanted to post this in case someone stumbles across this question and it works for them.
You can use require.cache to get all cached NodeModule objects and filter it to find your module.
https://nodejs.org/api/modules.html#requirecache
class ClassA {
public static getFilePath():string{
const nodeModule = this.getNodeModule();
return (nodeModule) ? nodeModule.filename : "";
}
public static getNodeModule(): NodeModule | undefined{
const nodeModule = Object.values(require.cache)
.filter((chl) => chl?.children.includes(module))
.filter((mn)=> mn?.filename.includes(this.name))
.shift();
return nodeModule;
}
}
class ClassB extends ClassA {
constructor(){}
}
const pathA = ClassA.getFilePath(); //Must return the absolute path of ClassA
const pathB = ClassB.getFilePath(); //Must return the absolute path of ClassB

Non type type parameters

What if I have classes that are different only by some constant used in code. Is it possible to have one generic implementation without runtime cost?
Here is the example (it's a little bit too long...)
#:enum abstract Param(Int) {
var foo = 0;
var bar = 1;
}
class WorkBase {
public function new() {}
private inline function work_impl(p: Param): Void {
if(p == foo) {
trace('foo');
}
else {
trace('bar');
}
}
public function work(): Void {
}
}
class WorkFoo extends WorkBase{
override public function work(): Void {
work_impl(foo);
}
}
class WorkBar extends WorkBase {
override public function work(): Void {
work_impl(bar);
}
}
class Test {
public static function main() {
var workFoo = new WorkFoo();
var workBar = new WorkBar();
workFoo.work();
workBar.work();
}
}
After compilation with -D analyzer-optimize we will see that WorkFoo.work() and WorkBar.work() functions were optimized and contain only one branch of code that matches one of the Param values. In real life there are lot of such comparisons in work_impl(), and they all are optimized out. That's good.
But what if I do not want to create WorkFoo and WorkBar by hand. Is it possible to do something like this:
#:generic
class WorkBase<PARAM> {
private inline function work_impl(p: Param): Void {
...
}
public function work(): Void {
work_impl(PARAM);
}
}
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
The closest thing I know is const-type-parameter. But I do not feel generic build is a good choice here.
Const type parameters can be used without #:genericBuild - a const type parameter in combination with #:generic is enough to get the desired optimization:
#:enum abstract Param(Int) from Int {
var foo = 0;
var bar = 1;
}
#:generic class Work<#:const PARAM:Int> {
public function new() {}
public function work():Void {
if (PARAM == foo) {
trace('foo');
} else {
trace('bar');
}
}
}
class Main {
public static function main() {
var workFoo = new Work<0>();
var workBar = new Work<1>();
workFoo.work();
workBar.work();
}
}
Due to #:generic, one class is generated for each constant value, for instance on JS the output looks like this:
var Work_$0 = function() {
};
Work_$0.prototype = {
work: function() {
console.log("source/Main.hx:11:","foo");
}
};
var Work_$1 = function() {
};
Work_$1.prototype = {
work: function() {
console.log("source/Main.hx:13:","bar");
}
};
Note that this example fails with a "constraint check failure" in Haxe 3.4.7 for some reason, but works fine with Haxe 4 preview 4 and later. Another limitation is that neither new Work<Param.foo>() nor new Work<foo>() work - you need to pass the actual constant value.

Can I overload method in module.export in node.js?

I have an app.js with this code:
var addnote = (title,body) => { /* enter code here */ }
module.exports = {addnote};
Can I add another addnotes function with different parameters to that file?
Function overloading in JavaScript does not exist like in other programming languages such as C# and Java.
What you should be looking to do is pass an object as a parameter that has properties attached and filter them out there..
You could call different functions from your little 'mapping function' just implement the logic there if it isn't big (to keep the code clear).
function foo(parameters){
var title = parameters.title;
var body = parameters.body;
if(parameters.extraProperty){
// oh we have extraProperty passed in too, run a different function?
bar(title, body, parameters.extraProperty); // ??
}
}
foo({title: 'Title', body: 'Body', extraProperty: 'This is extra...'});
If this is your own custom module, you can use the concept of function overriding, where each child class can have its own way to handle something and also have a default way to do things.
class Parent {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello ${this.name}`);
}
}
class Child1 extends Parent {
constructor(name) {
super(name);
}
greet() {
console.log(`Hey there ${this.name}. This is Child 1`);
}
}
class Child2 extends Parent {
constructor(name) {
super(name);
}
greet() {
console.log(`Hi there ${this.name}. This is Child 2`);
}
}
const o1 = new Child1('Foo')
const o2 = new Child2('Foo')
o1.greet();
o2.greet();
But if you are trying to override a function in an external module(You do not have access to that code, like a library), my suggestion is to create a wrapper and add functionality there.

With TypeScript: unable to refer to 'this' (class) from inside a function

I'm learning TypeScript and have the following class:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(getCertificate)
.fail(somethingWrong);
function getCertificate() {
var id = this.driver.id(); // this refers to any
return ...
}
}
}
As you can see on the above code, the first call to this refers to my class DetailDriver. That's good. The second call to this (inside getCertificate) refers to any. That's not what I need. I need to refer to my class DetailDriver.
How to proceed?
Thanks.
Well,
According to section 4.9.2 of the TypeScript Language Specification you should use fat arrow syntax to preserve the scoping for this.
return promise
.then(() => return.this.id;)
.fail(somethingWrong);
Then the this keyword is properly determined to be a Driver.
For reference, you could also just do:
class SomeClass {
public someMethod() {
// Do something
}
public anotherMethod() {
var that = this; // Reference the class instance
function someFunction () {
that.someMethod();
}
}
}
You could refactor to something like this:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(this.getCertificate.bind(this)) // <- important part
.fail(somethingWrong);
}
// new method function here
private getCertificate() {
var id = this.driver.id(); // this refers to any
return ...
}
}
Using the function keyword anywhere in your class will make any reference to this keyword refer to that function rather than the outer class. Generally, you want to avoid defining functions inside of classes, unless you use the "fat arrow" syntax. That would look like this:
class DetailDriver {
public get driver() {
return super.getEntity();
}
public activate(): breeze.Promise {
var id = this.driver.id(); // this refers to (class) DetailDriver
return promise
.then(() => { // <- important part
var id = this.driver.id(); // this refers to any
return ...
})
.fail(somethingWrong);
}
}

PreloadJS + Typescript

I have been stuck for 4 days so it is going on SO!
Please reference the PreloadJS Definitions:
https://github.com/borisyankov/DefinitelyTyped/blob/master/preloadjs/preloadjs.d.ts
From line 26.
My question is, how do you addEventListener in typescript while also binding it to the class scope?
imagine (semi psudo):
class Test
{
private _loader:createJS.AssetLoader;
constructor()
{
this._loader = new createJS.AssetLoader();
this._loader.addEventListener(???????????);
this._loader.load();
}
onLoadComplete(???): ???
{
}
}
Using TypeScript 0.9.1.0:
class Test
{
private _loader: createJS.AssetLoader;
constructor()
{
this._loader = new createJS.AssetLoader();
this._loader.addEventListenerthis.onLoadComplete);
this._loader.load();
}
onLoadComplete = () =>
{
console.log(this.whatever);
};
}
The important part here is using the member initialization syntax (member = value) for onLoadComplete and using a fat arrow lambda expression (() => { ... }) for the function. This will correctly capture the this context in the callback.

Resources