how to read ts file and update code dynamically using fs? - javascript

i am scaffolding new project using yeoman generator it is creating all the directories and running dependencies , now once files are generated i want to update js class same as appName,
first i am trying to read the ts file which i failed to do it throws error TypeError: Cannot read property 'toString' of undefined then i would update the file with appName if there is any better approach to achieve this task i will apprecaite the help.
index.js
updateTsFile () {
const npmdir = `${process.cwd()}/${this.props.appName}`;
const dirPath = `${npmdir}/${"./api.ts"}`;
console.log("path", dirPath);
let response;
_fs.readFile(dirPath, (_err, res) => {
if (_err) {
console.error(_err);
}
let file = res.toString("utf-8");
console.log(file);
response = file;
let lines = file.split("\n");
for (let i = 0; i < lines.length; i++) {
console.log(lines[i]);
}
});
return response;
}
api.ts
export class CAPIClass extends Wrapper {
public after = after;
constructor() {
super({
configFileName: "package-name-v1.json"
});
}
}
expected output
export class CMyAppNameClass extends Wrapper {
public after = after;
constructor() {
super({
configFileName: "package-name-v1.json"
});
}
}

In case of an error you're just logging the error but continuing with the logic. So it seems like you're running into an error resulting in res being undefined. Since fs exposes a promise-based api nowadays, I would rewrite this as follows instead of using callbacks (also note that you were using utf-8 for the encoding but it should be utf8):
async updateTsFile() {
const npmdir = `${process.cwd()}/${this.props.appName}`;
const dirPath = `${npmdir}/${"./api.ts"}`;
console.log("path", dirPath);
try {
const fileData = await _fs.promises.readFile(dirPath);
const fileAsStr = fileData.toString("utf8");
// replace class-name
fileAsStr = fileAsStr.replace(/CAPIClass/g, "CMyAppNameClass");
// (over)write file: setting 'utf8' is not actually needed as it's the default
await _fs.promises.writeFile(dirPath, fileAsStr, 'utf8');
} catch (err) {
console.log(err);
// handle error here
}
}

Related

NodeJS: My jest spyOn function is not being called

I don't understand why my spy is not being used. I have used this code elsewhere and it has worked fine.
Here is my test:
const {DocumentEngine} = require('../documentEngine')
const fileUtils = require('../utils/fileUtils')
const request = {...}
const fieldConfig = {...}
test('If the Carbone addons file is not found, context is built with the carboneAddons property as an empty object', async () => {
const expectedResult = {
carboneAddons: {},
}
const fileExistSpy = jest
.spyOn(fileUtils, 'checkFileExists')
.mockResolvedValue(false)
const result = await docEngine.buildContext(request, fieldConfig)
expect(fileExistSpy).toHaveBeenCalledTimes(1)
})
Here is the code that it is being tested:
async function buildContextForLocalResources(request, fieldConfig) {
/* other code */
const addonFormatters = await getCarboneAddonFormatters()
const context = {
sourceJson,
addonFormatters,
documentFormat,
documentTemplateId,
documentTemplateFile,
responseType,
jsonTransformContext
}
return context
}
async function getCarboneAddonFormatters() {
const addOnPath = path.resolve(
docConfig.DOC_GEN_RESOURCE_LOCATION,
'library/addon-formatters.js'
)
if (await checkFileExists(addOnPath)) {
logger.info('Formatters found and are being used')
const {formatters} = require(addOnPath)
return formatters
}
logger.info('No formatters were found')
return {}
}
This is the code from my fileUtils file:
const fs = require('fs/promises')
async function checkFileExists(filePath) {
try {
await fs.stat(filePath)
return true
} catch (e) {
return false
}
}
My DocumentEngine class calls the buildContext function which in turn calls the its method getCarboneAddonFormatters. The fileUtils is outside of DocumentEngine class in a utilities folder. The original code I had this working on was TypeScript as opposed to this which is just NodeJS Javascript. The config files for both are the same. When I try to step through the code (VSCode debugger), as soon as I hit the line with await fs.stat(filePath) in the checkFileExists function, it kicks me out of the test and moves on to the next test - no error messages or warnings.
I've spent most of the day trying to figure this out. I don't think I need to do an instance wrapper for the documentEngine, because checkFileExists is not a class member, and that looks like a React thing...
Any help in getting this to work would be appreciated.

Custom module Nodejs - Set Property To arguments of anonymous inner function

This module is minimal module that can be used to create server-side code in Nodejs.
Please read the comment in the code to undersrtand what is going on.
I have the following code :
import http from 'http';
class Application {
constructor(name) {
this.name = name;
}
listen(...args) {
const server = http.createServer(this.contextBody()).listen(...args)
}
contextBody () {
// Is this ok?
let req = Object.create(http.IncomingMessage.prototype);
let res = Object.create(http.ServerResponse.prototype);
return function(request, response) {
// What should I put here?
res.statusCode = response['status']
res.end(response['body'])
}
}
}
export const Maki = new Application();
How should the logic in anonymous function (request, response) like ?
I have call this module like so :
The logic should used like this below
import { Maki } from "../lib/application.js";
Maki.contextBody((req, res) => {
// How can i have the following code to work.
// this will thrown an error because res was undefined
// res.status = 200;
// res.body = "Hello World!"
})
Maki.listen(3000, () => console.log("Server runnig!"))
Any help to make this possible please?

Unable to implement singleton patten in javascript

I am trying to implement a singleton pattern for the fastify instance. My code is as follows :-
const { createFastifyServer: server } = require("../app");
const getFastifyInstance = (() => {
let fastify;
return {
fastifyInstance: async () => {
if (!fastify) {
console.log("Called")
fastify = server();
await fastify.ready();
}
return fastify
}
}
})();
const { fastifyInstance } = getFastifyInstance
module.exports = fastifyInstance
Now wherever I am importing the code in a different file, the console prints "Called" each time it's imported in a new file, but shouldn't that be only once if singleton pattern was correctly implemented. Any idea what am I doing wrong?

Refactoring probot event functions into seperate file causes error: TypeError: handler is not a function

I have the vanilla probot event function from the docs that comments on new issues:
const probotApp = app => {
app.on("issues.opened", async context => {
const params = context.issue({ body: "Hello World!" });
return context.github.issues.createComment(params);
});
}
This works fine.
I refactor the code into a separate file:
index.js
const { createComment } = require("./src/event/probot.event");
const probotApp = app => {
app.on("issues.opened", createComment);
}
probot.event.js
module.exports.createComment = async context => {
const params = context.issue({ body: "Hello World!" });
return context.github.issues.createComment(params);
};
But I receive this error:
ERROR (event): handler is not a function
TypeError: handler is not a function
at C:\Users\User\probot\node_modules\#octokit\webhooks\dist-node\index.js:103:14
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Promise.all (index 0)
When I create a test as recommended in the docs with a fixture and mock the event webhook call with nock this works fine. But when I create a real issue on GitHub this error is thrown.
How can I refactor the code into a separate file without causing the error?
This was my mistake.
This is the whole probot.event.js file:
module.exports.createComment = async context => {
const params = context.issue({ body: "Hello World!" });
return context.github.issues.createComment(params);
};
module.exports = app => {
// some other event definitions
}
By defining module.exports = app I overwrote the previous module.export. The createComment function was therefore never exported.
Removing module.exports = app = { ... } fixed it!

How can I make static variable in `module.exports = class` in node.js

How can I initialize a static variable in module.exports = class in node.js.
Basically, what I'm trying to achieve is, if StaticVariable is null, Ill get data from a json file. Then store it in StaticVariable.
module.exports = class Config {
static fetch() {
if ( StaticVariable === null ) {
const fs = require('fs');
const data = fs.readFileSync('./config.json');
const config = JSON.parse(data);
StaticVariable = config;
}
return StaticVariable;
}
}
Function fetch() will be called several times so it is unnecessary to readFileSync every call.
Static-only class is an antipattern in JavaScript because a class is never instantiated.
In case there's a need to have a method that lazily loads JSON file, a plain object can be used. There's already such object in module scope, module.exports:
const fs = require('fs');
let StaticVariable;
exports.fetch = () => {
if ( StaticVariable == undefined ) { // not "=== null"
const data = fs.readFileSync('./config.json');
const config = JSON.parse(data);
StaticVariable = config;
}
return StaticVariable;
}
There may be no need to parse it manually because this could be handled by require('./config.json') one-liner and with more consistent relative paths.
In case JSON file can be eagerly loaded, this can be simplified to:
exports.config = require('./config.json');
If there's a need for Config class and it should access configuration object, it can refer to it, e.g.:
exports.Config = class Config {
constructor() {
this.config = deepClone(exports.config);
}
modify() {
// modify this.config
}
};
I can think of several ways to achieve what you are asking.
Saving it in a global variable
//initialise it here
var StaticVariable = null;
//however if you initialise it here, it makes more sense to just load it once
const fs = require('fs');
const data = fs.readFileSync('./config.json');
const config = JSON.parse(data);
StaticVariable = config;
module.exports = class Config {
static fetch() {
return StaticVariable;
}
}
Or just use require. Require will do the same thing what you want to do. It will read the file config.json, try to parse it as a valid json and it will do this only once.
module.exports = class Config {
static fetch() {
return require('./config.json');
}
}
Starting from (node 15.2.1) ES2020, static private class fields is supported. So from now on static class may not be anti pattern and you can instantiate a class using new keywords. ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static
module.exports = class Config {
static #StaticVariable = null;
static fetch() {
if ( StaticVariable === null ) {
const fs = require('fs');
const data = fs.readFileSync('./config.json');
const config = JSON.parse(data);
StaticVariable = config;
}
return StaticVariable;
}
}
Where # sign means private more reference can be found in https://node.green, but still the easiest way is described in other answers
exports.config = require('./config.json');

Categories

Resources