Use user snippets inside with VS Code Extension API - javascript

"I'm developing an extension for Visual Studio Code that allows users to specify their own snippet names in the plugin's settings. The plugin can then use these names to create files.
I've successfully implemented the file creation functionality, but I'm still trying to figure out how to run snippets programmatically.
The following code is not fully tested yet but it illustrates in what context I would like to use the snippet.
// user config
"[extensionName]": [
["{folderName}.js", "snippetName1", "JavaScript"],
["{folderName}.styled.js", "snippetName2", "JavaScript"],
["{folderName}.translation.js", "snippetName3", "JavaScript"]
]
// extension.ts
async function createFolder (folderName: string) {
// Create the folder in the workspace
const config = await vscode.workspace.getConfiguration();
const options: Array<[string, string, string]> = config["[extensionName]"];
const selectedFolders = await vscode.window.showOpenDialog({
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false
});
if (!selectedFolders || selectedFolders.length === 0) {
return undefined;
}
const selectedFolderUri = selectedFolders[0];
const selectedFolderPath = selectedFolderUri.fsPath;
const folderPath = path.join(selectedFolderPath, folderName);
await fs.promises.mkdir(folderPath, { recursive: true });
// Create the files in the folder
options.forEach(async ([fileName, snippetName, snippetLanguage]: [string, string, string]) => {
// If the fileName has the variable {folderName}, it will be replaced to the name of the current folder
const filePath = path.join(folderPath, fileName.replace("{folderName}", folderName));
const body = ["hello", "world"].join("\n"); // Suppose to be created by snippet
await fs.promises.writeFile(filePath, body);
});
};

Related

Can't get random file with random type from folder

I was coding this command for my discord bot, but I tried to fix that lot of times, I already spend 2 hours trying to code but all I get is a Can't send a empty message in console
const fs = require('fs');
module.exports = {
name: 'name',
description: 'description',
aliases: ['aliase1','aliase2'],
usage: '[command]',
guildOnly: true,
execute(message) {
const fileType = ['png','jpg','gif','mp4','mov'];
const Rfile2 = fs.readdirSync(`./commands/Database`).filter(file => file.endsWith(fileType));
for (const file of Rfile2) {
const Rfile = require(`.commands/Database/${file}`)
const randomFile = Rfile(Math.floor(Math.random()*5) * Rfile.length);
}
try {
message.channel.send(randomFile);
} catch (error) {
message.channel.send(error);
}
}
}
The String.prototype.endsWith function expects a string or an array of only one item. So you're passing a whole array which will always return false, Hence filtering out an empty array.
You can split the string by all occurrences of the period . then pop the last character element and then check if the extension is included in the fileType array
const Rfile2 = fs.readdirSync('./commands/Database').filter(file => fileType.includes(file.split('.').pop())));
Consider learning Typescript that way you can catch and prevent simple bugs even before you run the code.

How to update plain .js file in Node.JS?

I have a filename.config.js file with contents like these:
module.exports = {
foo: [
{bar: "bar"},
],
};
Does the native Node.js or some lib for it have any tools that can add another item to foo without resorting to regular expressions?
Found a solution myself in some googled schematics:
const { cosmiconfigSync } = require('cosmiconfig');
export function getConfig(path?: string): MyConfig {
const explorer = cosmiconfigSync('filename');
if (path) {
path = `${process.cwd()}/${path}`;
}
const configSearch = explorer.search(path);
return configSearch ? configSearch.config : {};
}
Use a .json file for configurations. Never dynamically write to a js file.
filename.config.json
{
"foo": [
{"bar": "bar"},
],
}
Then in another js file you can read the file:
const fs = require('fs');
const path = require('path');
const config = JSON.parse(
fs.readFileSync(path.resolve(__dirname, './filename.config.json'), 'utf8')
);
console.log(config);
To edit the file, you can edit the object and write it back to the file:
config.biz = 'baz';
fs.writeFileSync(path.resolve(__dirname, './filename.config.json'), JSON.stringify(config));
JSON.parse and JSON.stringify can be used to convert JSON objects from a string to a real object and back. No regex required.

Programmatically create Gatsby pages from API data

This is a similar question to this.
I'm looking for help programmatically creating pages using createPage or createPages and am having trouble - the docs give an example for creating pages from markdown files but not much explanation.
I am using a plugin in plugins\characters\gatsby-node.js to add data from the Rick & Morty API to the GraphQL data layer. My plugin is at the bottom of the question in case it is relevant.
The plugin does add the data successfully as I can see the data in http://localhost:8000/___graphql, and I have successfully managed to use the data in (static) pages.
Where I am lost is that I would like to be able to create a page for each individual character, using the url characters/<characterIdHere> for each of the pages. I am aware that I need to add some logic to my (main or plugins version of....?) gatsby-node.js file, but this is the part I am stuck on. I do not know what I need to put into the gatsby-node.js file. The examples I can find all use json or markdown files and I would like to use data that I have pulled in (from an API) to gatsby's data layer. I have obviously researched this for a few hours and played around with it before asking, but not had any luck.
The component on the pages I would like to create should look something like this:
const CharactersViewSingle = ({ character}) => {
return (
<div>
<Helmet>
<title>{character.name && character.name}</title>
</Helmet>
<NavBar />
<CharactersViewBox character={character} width={300} height={520} />
</div>
)
}
The above code is taken from what the component returned when I was using create-react-app.
The graphQL query (which obviously reflects the structure of the data I would like to use) I use to get the data on other (static) pages looks like this:
export const query = graphql`
query CharactersQuery {
allCharacters(limit: 5) {
edges {
node {
id
name
status
gender
image
}
}
}
}
`
Plugin code:
const axios = require("axios")
exports.sourceNodes = async ({
actions,
createNodeId,
createContentDigest,
}) => {
const { createNode } = actions
const integerList = (start, length) =>
Array.from({ length: length }, (v, k) => k + start)
const rickMortyURL = `https://rickandmortyapi.com/api/character/${integerList(
1,
493
)}`
const rickMorty = await axios.get(rickMortyURL)
const query = await axios.get(rickMortyURL)
rickMorty.data.forEach(character => {
const nodeContent = JSON.stringify(character)
const nodeMeta = {
id: character.id.toString(),
//id: createNodeId(`char-data-${character.id}`),
parent: null,
children: [],
internal: {
type: `Characters`,
content: nodeContent,
contentDigest: createContentDigest(character),
},
}
const node = Object.assign({}, character, nodeMeta)
createNode(node)
})
}
Gatsby's createPages API is what you might be looking for.
I used it to create multiple pages like blog1, blog2, blog3 etc...
In the same way, you can create multiple pages for your characters.
Since you mentioned you have a graphql call to get your characters using
const pages = await graphql(`
query CharactersQuery {
allCharacters(limit: 5) {
edges {
node {
id
name
status
gender
image
}
}
}
}
`)
The above graphql call returns results in pages.data.allCharacters.edges
Now you can iterate them using foreach and use createPage to create the pages.
Below is complete mock code you might need to add in your gatsby-node.js file
const path = require('path');
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const templateOfYourCharacterPage = path.resolve(`src/templates/exampleTemplateFile.jsx`)
const pages = await graphql(`
query CharactersQuery {
allCharacters(limit: 5) {
edges {
node {
id
name
status
gender
image
}
}
}
}
`)
let characters = pages.data.allCharacters.edges;
characters.forEach(edge => {
createPage({
path: `/${edge.node.id}`,
component: templateOfYourCharacterPage,
context: {id: edge.node.uid, name: edge.node.name } // This is to pass data as props to your component.
})
})
}

Write javascript code into a js using fs.writeFile

I'm trying to write JavaScript code into a js with Nodejs fs module. I managed to write a json file but could wrap my head around on how to write JavaScript to it.
fs.writeFile("config.json", JSON.stringify({name: 'adman'tag: 'batsman',age: 25}), 'utf8',{ flag: "wx" }, function(err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
I need to create a .js file with the following data
const cricketers = [
{
name: 'adman',
tag: 'batsman',
age: 25
},
// other objects
]
module.exports = cricketers ;
Two things:
If all you want to do is to be able to do let someData = require('someFile.json'); Nodejs already supports requiring json files and treats them like Js objects.
Otherwise I don't know of a library that will do exactly this for you, BUT...
You can do this yourself. The fs.writeFile function takes a string, so you just have to generate the string you want to write to the file.
let someData = [{name: 'adman', tag: 'batsman', age: 25}];
let jsonData = JSON.stringify(someData);
let codeStr = `const cricketers = ${jsonData}; module.exports = cricketers;`;
fs.writeFile("someFile.js", codeStr, 'utf8',{ flag: "wx" }, function(err) {
if (err) {
return console.log(err);
}
console.log("The file was saved!");
});
Obviously this only works for a very specific use case, but the point is it can be done with simple (or complicated...) string manipulation.
use string templating
const data = `const cricketers = ${JSON.stringify(yourArray)};
module.exports = cricketers;
`
Where yourArray is an array of objects

How to clone a node to another path based on a reference value from the initial path on Google Cloud Functions?

I am trying clone an "original" node's data (as soon as I create the data) to a path that is based on the original node's path.
This is my data structure:
root: {
doors: {
111111111111: {
MACaddress: "111111111111",
inRoom: "-LBMH_8KHf_N9CvLqhzU", // I will need this value for the clone's path
ins: {
// I am creating several "key: pair"s here, something like:
1525104151100: true,
1525104151183: true,
}
}
},
rooms: {
-LBMH_8KHf_N9CvLqhzU: {
ins: {
// I want the function to clone the same data here:
1525104151100: true,
1525104151183: true,
}
}
}
My cloud function is now like this:
exports.updateRoom = functions.database.ref('/doors/{MACaddress}/ins').onWrite((change, context) => {
const beforeData = change.before.val(); // data before the write
const afterData = change.after.val(); // data after the write
const roomPushKey = change.before.ref.parent.child('/inRoom');
console.log(roomPushKey); // this is retrieving all the info about the ref "inRoom" but not its value...
Question 1) How can I get to this ref/node's value?
My code goes on by trying to get the value like this.
roomPushKey.once('child_added').then(function(dataSnapshot) {
let snapVal = dataSnapshot.val();
console.log(snapVal);
});
Question 2 (which I think is basically question 1 rephrased): How can I get the snapVal outside the then. method's scope?
return change.after.ref.parent.parent.parent.child('/rooms')
.child(snapVal).child('/ins').set(afterData);
// snapVal should go above
});
Error message: ReferenceError: snapVal is not defined
The following should work.
const admin = require("firebase-admin");
....
....
exports.updateRoom = functions.database.ref('/doors/{MACaddress}').onWrite((change, context) => {
const afterData = change.after.val(); // data after the write
const roomPushKey = afterData.inRoom;
const ins = afterData.ins;
const updates = {};
updates['/rooms/' + roomPushKey] = ins;
return admin.database().ref().update(updates);
}).catch(error => {
console.log(error);
//+ other rerror treatment if necessary
});
Here are some explanations:
You get the roomPushKey by reading the "data after the write" as an object: roomPushKey = afterData.inRoom. You don't need to do roomPushKey.once('child_added').then()
Once you have the roomPushKey, you create a new child node in the rooms node by using update() and creating an object with square brackets notation which allow you to assign the id of the node (i.e. roomPushKey).
Note that you could also do:
return admin.database().ref('/rooms/' + roomPushKey).set(ins);
Note also that you have to import firebase-admin in order to be able to do return admin.database().ref()...
Finally, I would suggest that you have a look at the three following videos from the Firebase team: youtube.com/watch?v=7IkUgCLr5oA&t=517s & youtube.com/watch?v=652XeeKNHSk&t=27s & youtube.com/watch?v=d9GrysWH1Lc. A must for anyone starting coding for Cloud Functions.

Categories

Resources