Define template strings as const to evaluate later - javascript

Is there a way to accomplish something like this:
const API_URL = `https://api.my-data-provider.com/items/${id}`
// [...]
// and later on or in another file, use it with something like
const result = await fetch(API_URL(id)) // or API_URL.apply(id), API_URL.apply({ id: 23}), etc...
I want to save template literals in a constants / configuration file, to use them later
Or is there any other standard or well established way to do this kind of thing?

You could use a function for this:
const generateApiUrl = (id) => `https://api.my-data-provider.com/items/${id}`;
const result = await fetch(generateApiUrl(id))

Related

How do I get JSON data and load it in a JavaScript file? (node.js)

Oh? Hi there!
So, I had a little problem recently.
I'm probably too dumb to realize how to do this, but here it is. I need some sort of way to actually read JSON files. I am requiring them, but I have no idea how to actually use them.
Here is my JSON file:
{
"help": "Displays this message"
}
And my code here:
const cmdh = require("../cmdhandle");
const Discord = require("discord.js");
const util = require("../../util");
const json = require("../help.json");
module.exports = {
aliases: ["?"],
execute:function(msg, cmd) {
// Insert code here so that "def" is a list of elements and definitions in the json file
msg.channel.send(util.genEmbed("Help", def, "#ff5c5c"));
}
}
Edit: ;p i was an idiot back then, looks like this was wayyy easier than i thought lol
You've already loaded the JSON with const json = require("../help.json"), now all you have to do to use the stuff in it is to type json.help or json["help"].
If you want a list of the definitions and elements, you can use the Object.keys and Object.values functions, or Object.entries for key-value pairs.
const cmdh = require("../cmdhandle");
const Discord = require("discord.js");
const util = require("../../util");
const json = require("../help.json");
module.exports = {
aliases: ["?"],
execute:function(msg, cmd) {
// Get all entires
Object.entries(json).forEach(([key, msg]) => {
msg.channel.send(util.genEmbed(key, msg, "#ff5c5c"));
})
}
}

Importing locators in puppeteer tests using const

I have an object repository file where I store all the locators. However to improve maintainability and readability, I am now grouping the locators using const. For example:
const delivery = {
DELIVERY_HEADING: "xpath=//div[OOtext()='Delivery']",
DELIVERY_COUNT: '.bit-deliverylistrow'
};
const operations = {
SAVE_AUD: '.bit-save-btn',
SAVE_AUDNAME: "xpath=//*[text()='Audience name']/../input"
};
module.exports = { delivery, operations }
In the tests, I am using importing and using them as:
const or = require('../TestData/OR');
await page.focus(or.delivery.DELIVERY_HEADING);
await page.type(or.operations.SAVE_AUDNAME,'hello');
Is there a way I don't have to refer to the const and directly call the object locators in the test as it is difficult to identify which const has which locator ?
I would like to do await page.focus(or.DELIVERY_HEADING)
Any pointers will be helpful.
You can use the spread ... to create a single object.
module.exports = { ...delivery, ...operations }
Now you can do,
await page.focus(or.DELIVERY_HEADING)

How can I minimize duplication of code that sometimes needs a callback?

In my gulpfile, I have a task that processes all of my pages and another task that watches my pages for changes and processes just the changed page. It looks like this:
const buildPages = path => cb => {
gulp.src(path)
// some lines of piping
.pipe(gulp.dest(pages.dist));
cb();
}
const watchPages = () =>
gulp.watch(pages.src).on('change', path =>
gulp.src(path)
// the same piping as above
.pipe(gulp.dest(pages.dist))
);
The .on() method of the chokidar watcher object returned by gulp.watch() does not receive a callback function, while the gulp task above it requires one. So to remove code duplication, I can do this:
const buildPages = path =>
gulp.src(path)
// some lines of piping
.pipe(gulp.dest(pages.dist));
const buildPagesWithCallback = path => cb => {
buildPages(path)
cb();
}
const watchPages = () =>
gulp.watch(pages.src).on('change', path =>
buildPages(path)
);
Is this the right way to go about it, or is there a way to remove duplication without creating an extra function (perhaps by making the watcher receive a callback)?
Not sure what's your other requirements/needs, but given your description, I would usually have a setup like this (assuming you're using gulp 4):
const src = [ './src/pageA/**/*.js', ...others ];
const dist = './dist';
const buildPages = () => gulp.src(src).pipe(...).pipe(gulp.dest(dist));
const callback = () => { /* do stuff */ };
exports.buildPageWithCallback = gulp.series(buildPages, callback);
exports.watchPages = () => gulp.watch(src, gulp.series(buildPages));
exports.watchPageWithCallback = () => gulp.watch(src, gulp.series(buildPages, callback));
I would use gulp.series to run callback without explicitly passing a callback to a task maker function, and pass a task directly to gulp.watch.
If your requirements demand buildPages to take in a path, then I think the way you're doing it is right, sorry if I misunderstand the question

Pointfree-Style with template-string in ramda.js

I've problems writing a pointfree-style function in ramda.js and wondered if anybody can help me with that. The getEnv function reads an env-variable and logs to console if it couldn't be found.
Here is my code
const env = name => R.path(['env', name], process);
const getEnv = name => R.pipe(
env,
R.when(R.isNil, () => log(`Missing env "${name}"`))
)(name);
console.log(getEnv('myenv'))
I'd want to drop the name parameter of the getEnv function (and if possible also on the env function) but don't know how to do this.
The function getEnv does more than it should. It actualy returns the content of the path or logs a validation message.
Split it into two separate functions. In my example below, I call it findPath andvalidatePath, which works generically for all paths. I've wrapped validatePath into another function calledvalidateEnvPath, which searches directly for "env"
To get rid of env you can do the following: R.flip (R.curry (R.path)). This will turn the function curry and then the arguments around, so you can tell the function where you want to query first
const process = {env: {myenv: ':)'}}
const path = R.flip(R.curry(R.path))
const findPathInProcess = R.pipe(
path (process),
R.ifElse(
R.isNil,
R.always(undefined),
R.identity
)
)
const validatePath = path =>
validationPathResponse (findPathInProcess( path )) (`can't find something under [${path}]`)
const validateEnvPath = path =>
validatePath (buildPath (['env']) (path))
const buildPath = xs => x =>
xs.concat(x)
const validationPathResponse = response => errorMessage =>
response
? response
: errorMessage
console.log(validatePath(['env', 'myenv']))
console.log(validateEnvPath('myenv'))
console.log(validateEnvPath('yourenv'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
Consider using Either monad. Sanctuary has it already implemented and plays nice with its brother ramda:
const viewEnv = S.pipe ([
S.flip (R.append) (['env']),
R.lensPath,
R.view,
S.T (process),
S.toEither ('Given variable could not be retrieved')
])
const log = R.tap (console.log)
const eitherSomeVar = viewEnv ('someVar')
const eitherWhatever = S.bimap (log) (doSomeOtherStuff)
In addition one could also write the following
const path = R.flip(R.path) // already curried
const findPathInProcess = R.pipe(
path(process),
R.when(
R.isNil,
R.always(undefined)
)
)

How to update json entry in node.js

How can I update json value with node.js? I found in internet couple examples but my is a little bit more complicated
I can open value I want to change
var contents = fs.readFileSync("./../../skill.json");
var jsonContent = JSON.parse(contents);
console.log("Address", jsonContent['manifest']['apis']['custom']['endpoint']['uri']);
but how to edit it with my value?
var contents = fs.readFileSync("./../../skill.json");
var jsonContent = JSON.parse(contents);
console.log("Address", jsonContent['manifest']['apis']['custom']['endpoint']['uri']);
// modify your value
jsonContent['manifest']['apis']['custom']['endpoint']['uri'] = 'new value';
// stringify it and write to file
fs.writeFileSync("./../../skill.json", JSON.stringify(jsonContent));
Assignment in JavaScript is done via the assignment operator (=).
Accessing values of an object can be done via the property accessors (. and []).
Hence, modifying the content is as straightforward as
jsonContent['manifest']['apis']['custom']['endpoint']['uri'] = 'value';
Or even:
jsonContent.manifest.apis.custom.endpoint.uri = 'value';
That being said, I would suggest to at least wrap the assignment in a try catch block so that you are not exposed to a crash if the object does not deeply match the structure you expect to receive.
A more robust and versatile solution would be to leverage Lodash.set. For example:
_.set(jsonContent, ['manifest', 'apis', 'custom', 'endpoint', 'uri'], 'value');
As noted by #Patrick Roberts, modern JavaScript will allow leveraging the optional chaining operator ?.. This is currently only available in stage 1.
jsonContent?.manifest?.apis?.custom?.endpoint?.uri = 'value';
const {promisify} = require('util');
const fs = require('fs');
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
(async (){
try {
var contents = await readFile("./../../skill.json");
var jsonContent = JSON.parse(contents);
console.log("Address", jsonContent.manifest.apis.custom.endpoint.uri);
// modify your value
jsonContent.manifest.apis.custom.endpoint.uri = 'new value';
// stringify it and write to file
await writeFile("./../../skill.json", JSON.stringify(jsonContent));
} catch (e){
console.error(e);
}
})();

Categories