JavaScript for loop not working with VS Code extension API - javascript

I'm writing a VS Code extension in JavaScript. It requires a loop to open several text files so I used a for loop. Here's my a sample of the code for the loop:
const allFiles = vscode.workspace.findFiles('**/*.*', '**/node_modules/**');
for (let i = 0; i < allFiles.length; i++) {
vscode.workspace.openTextDocument(allFiles[i])
}
Here's the whole extension.js file:
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');
const path = require('path')
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
/**
* #param {vscode.ExtensionContext} context
*/
function activate(context) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "code-runner-from-the-web" is now active!');
const allFiles = vscode.workspace.findFiles('**/*.*', '**/node_modules/**');
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('code-runner-from-the-web.helloWorld', function () {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
vscode.window.showInformationMessage('Hello World from Code Runner From The Web!');
});
for (let i = 0; i < allFiles.legnth; i++) {
console.log (vscode.workspace.openTextDocument(allFiles[i]))
vscode.commands.executeCommand('code-runner.run', null)
}
context.subscriptions.push(disposable);
}
// This method is called when your extension is deactivated
function deactivate() {}
module.exports = {
activate,
deactivate
}
Where am I going wrong here?

The solution was to use an async function.
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');
const path = require('path')
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
/**
* #param {vscode.ExtensionContext} context
*/
async function activate(context) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "code-runner-from-the-web" is now active!');
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('code-runner-from-the-web.helloWorld', function () {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
vscode.window.showInformationMessage('Hello World from Code Runner From The Web!');
const getAllFiles = vscode.workspace.findFiles('**/*.*', '**/node_modules/**');
const findFile = async () => {
const allFiles = await getAllFiles
console.log(allFiles)
for (let i = 0; i < allFiles.length; i++) {
vscode.workspace.openTextDocument(allFiles[i])
//vscode.commands.executeCommand('code-runner.run', null)
console.log("Hello!!!!")
}
}
findFile()
});
context.subscriptions.push(disposable);
}
// This method is called when your extension is deactivated
function deactivate() { }
module.exports = {
activate,
deactivate
}

You have a typo in the for loop. Instead of allFiles.legnth, it should be allFiles.length. The corrected code should be:
for (let i = 0; i < allFiles.length; i++) {
console.log (vscode.workspace.openTextDocument(allFiles[i]))
vscode.commands.executeCommand('code-runner.run', null)
}

Related

Netlify Serverless Function returning 404

I am trying to set up a simple serverless function on Netlify just to test out usage of environment variables. I have defined the following two environment variables in Netlify for my site:
Variable Name
Value
ALPHABET_SEPARATION
2
CHARS_BETWEEN
3
I have also updated my functions directory as follows:
Functions directory: myfunctions
I am using continuous deployment from github. As I do not know the use of npm at present and finding it convenient to directly test the production deploy, I have defined a subdirectory called myfunctions inside my root directory and have placed my javascript file containing the "serverless" function inside it on my local machine. I have built in logic so that the "serverless" function gets called only when a "netlify" flag is set, otherwise, an alternate function gets executed client-side. Basically it works as follows:
const deploy = "netlify" //Possible valid values are "local" and "netlify"
async function postRandomString() {
const stringToUpdate = "THISISATESTSTRING"
var stringToPost = "DUMMYINITIALVALUE";
if (deploy === "local") {
stringToPost = updateString(stringToUpdate); //updateString is a function defined elsewhere and executes client-side;
}
else if (deploy === "netlify") {
const config = {
method: 'GET',
headers: {
'Accept': 'application/json',
}
};
const res = await fetch(`myfunctions/serverUpdateString?input=${stringToUpdate}`, config);
const data = await res.json();
stringToPost = data.retVal;
console.log(data.retVal);
}
else {
stringToPost = "##ERROR##";
}
postString(stringToPost); //postString is a function defined elsewhere and executes client-side;
}
The serverless function file serverUpdateString.js is coded as follows (it basically sets a character at a certain position (determined by CHARS_BETWEEN) in the string to an alphabetical character which is a certain number (determined by ALPHABET_SEPARATION) of places in the alphabet after the first character of the string (don't ask why - the point is that it never even receives/handles the request):
exports.handler = async function (event) {
const { CHARS_BETWEEN, ALPHABET_SEPARATION } = process.env;
const charsBetween = CHARS_BETWEEN;
const alphabetSeparation = ALPHABET_SEPARATION;
const initString = event.queryStringParameters.input;
const rootUnicode = initString.charCodeAt(0);
const finalUnicode = "A".charCodeAt(0) + (rootUnicode - "A".charCodeAt(0) + alphabetSeparation) % 26;
const finalChar = String.fromCharCode(finalUnicode);
const stringArray = initString.split("");
stringArray[charsBetween + 1] = finalChar;
const stringToReturn = stringArray.join("");
const response = {
statusCode: 200,
retVal: stringToReturn,
}
return JSON.stringify(response);
}
When I run it, I get a 404 error for the GET request:
In the above image, script.js:43 is the line const res = await fetch(myfunctions/serverUpdateString?input=ATESTSTRIN, config); in the calling file, as shown in the first code block above.
What am I doing incorrectly? Surely Netlify should be able to pick up the serverless function file given that I have specified the folder alright and have placed it at the right place in the directory structure? I have given the whole code for completeness but the problem seems quite elementary. Look forward to your help, thanks.
I got assistance from Netlify forums. Basically the following changes needed to be made:
The fetch request -- line 43 in the calling code (script.js) -- needed to be changed to
const res = await fetch(`https://netlifytestserverless.netlify.app/.netlify/functions/serverUpdateString?input=${stringToUpdate}`, config);
The return statement in the lambda function needed to be changed to:
const response = {
statusCode: 200,
body: JSON.stringify(stringToReturn),
}
Other minor changes such as using parseInt with the environment variables.
The code works now.

Run separate functions in node.js file from terminal

I have a javascript file the that I'm running some node tasks in, and would like to be able to run them separately based on the terminal command I trigger.
For instance, my nodejs file myFile code could look like this:
const mysql = require('mysql');
const fs = require('fs');
const getDbData = () => {
...
...
}
const fileTransform = () => {
file transformation functionality
}
I'd like to be able to run each function separately, so that I can say node myFile.js getDbData in terminal. Do I need to export each of the functions to be able to do this?
You can supply command-line arguments to your script on the node command line. You receive them in the process.argv array. Your arguments start at index 2 (0 is the full path to node, 1 is the full path to your script).
So for instance:
switch (process.argv[2]) {
case "getData":
getData();
break;
case "etlData":
etlData();
break;
// ...
}
Note that it's true that your arguments start at index 2 even if a Node argument precedes your script on the actual command line. For instance:
node --use-strict your-script.js
...will still have the full path to node in process.argv[0] and the full path to your script in process.argv[1]. The --use-strict argument isn't in the array at all.
Or you can put your functions on an object and use the argument as a key:
function getData() {
// ...
}
function getData() {
// ...
}
const functions = {
getData,
etlData
};
const fn = functions[process.argv[2]] || () => { console.log("Invalid option"); };
fn();
Try using process.argv.
https://stackabuse.com/command-line-arguments-in-node-js/
parse the command line arguments and, for example, evaluate them with eval()

How can I start a REPL that can access local variables in node.js?

Just like from IPython import embed; embed() but for node.
I want to open a REPL shell programmatically and be able to at least read the local variables. Being able to change them as well is a plus.
As far I know, the closest you can get is by using the repl built-in module (which is used by node inspect itself):
// ... your code you want to debug
const repl = require("repl");
const replServer = repl.start({
prompt: "Your Own Repl > ",
useGlobal: true
});
// Expose variables
const localVar = 42
replServer.context.localVar = localVar;
By running node index.js (assuming you saved the above content in index.js) we get access to this custom repl:
$ node index.js
Your Own Repl > localVar
42
Your Own Repl >
(To exit, press Ctrl+C again or Ctrl+D or type .exit)
Your Own Repl >
However, this does not work like a debugger tool, but really, it's only a REPL.
You can build a REPL similar to the built-in Deno REPL and and evaluate expressions using the dangerous eval function. Through it you'll be able to access local variables and other things (e.g. window).
repl.ts
import { readLines, writeAll } from "https://deno.land/std#0.106.0/io/mod.ts";
export default async function repl(evaluate: (x: string) => unknown) {
await writeOutput("exit using ctrl+d or close()\n");
await writeOutput("> ");
for await (const input of readInputs()) {
try {
const value = evaluate(input);
const output = `${Deno.inspect(value, { colors: !Deno.noColor })}\n`;
await writeOutput(output);
await writeOutput("> ");
} catch (error) {
await writeError(error);
}
}
}
async function* readInputs(): AsyncIterableIterator<string> {
yield* readLines(Deno.stdin);
}
async function writeOutput(output: string) {
await writeAll(Deno.stdout, new TextEncoder().encode(output));
}
async function writeError(error: unknown) {
await writeAll(Deno.stderr, new TextEncoder().encode(`Uncaught ${error}\n`));
}
repl_demo.ts
import repl from "./repl.ts";
let a = 1;
let b = 2;
let c = 3;
await repl((x) => eval(x));
example usage
% deno run repl_demo.ts
exit using ctrl+d or close()
> a
1
> a = 40
40
> a + b
42
For deno (Title says Node.js, tag deno) you can use Deno.run to execute deno and write to stdin and read from stdout.
The following will do:
const p = Deno.run({
cmd: ["deno"],
stdin: "piped",
stdout: "piped",
stderr: "piped"
});
async function read(waitForMessage) {
const reader = Deno.iter(p.stdout)
let res = '';
for await(const chunk of reader) {
res += new TextDecoder().decode(chunk);
console.log('Chunk', res, '---')
// improve this, you should wait until the last chunk
// is read in case of a command resulting in a big output
if(!waitForMessage)
return res;
else if(res.includes(waitForMessage))
return res;
}
}
async function writeCommand(command) {
const msg = new TextEncoder().encode(command + '\n');
console.log('Command: ', command)
const readPromise = read();
// write command
await p.stdin.write(msg);
// Wait for output
const value = await readPromise
return value;
}
// Wait for initial output:
// Deno 1.0.0
// exit using ctrl+d or close()
await read('ctrl+d or close()');
await writeCommand('let x = 5;')
let value = await writeCommand('x') // read x
console.log('Value: ', value)
await writeCommand('x = 6;')
value = await writeCommand('x') // read x
console.log('Value: ', value)
If you run that snippet, the output will be:
Command: let x = 5;
Command: x
Value: 5
Command: x = 6;
Command: x
Value: 6
There are some improvements to be made, such as handling stderr but you get the idea.
This feature doesn't currently exist but is being proposed in https://github.com/denoland/deno/issues/7938.
The vision being something along the lines of
Deno.eval("Deno.repl()")
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
//to be sure this context is here
const ev = eval.bind(this);
function ask() {
rl.question('>', (code) => {
console.log(ev(code));
ask();
});
}
ask();
this code ask a input with readLine module and every time a reponse is provided the code is executed and a new input is askef

why is node just printing out what is in the file?

I'm having issues with node.js, I'm not that familiar with it.
I have a JavaScript file that I need to load the file into node.js by using .load "filename.js".
when I run the command I just get a print out of the code that is in the file.
here is my code for the file I'm trying to load. I have made the changes suggested to me. but I'm still getting an entire print out of code.
class ArithmeticTaskRunner
{
constructor()
{
this.tasks = [];
}
addNegationTask()
{
const negationTask = (x) => -x;
this.tasks.push(negationTask)
return this;
}
addAdditionTask(y)
{
const additionByY = (x) => x + y;
this.tasks.push(additionByY)
return this;
}
addMultiplicationTask(y)
{
const multiplyByY = (x) => x * y;
this.tasks.push(multiplyByY)
return this;
}
taskCount()
{
return this.tasks.length;
}
execute(n)
{
let currentResult = n;
for(let task of this.tasks)
{
currentResult = task(currentResult)
}
return currentResult;
}
}
let taskRunner = new ArithmeticTaskRunner()
taskRunner.addAdditionTask(10)
taskRunner.addNegationTask()
taskRunner.addMultiplicationTask()
taskRunner.execute(2)
here are examples of the output and the input that is needed on this task
1.
let taskRunner = new ArithmeticTaskRunner()
undefined
taskRunner.addAdditionTask(2)
undefined
taskRunner.addMultiplicationTask(4)
undefined
taskRunner.addAdditionTask(10)
undefined
taskRunner.execute(2)
26
taskRunner.execute(-2)
10
2.
taskRunner.execute()
-5
taskRunner.execute(10)
-10
taskRunner.taskCount
3
If you want to have a REPL session and run the commands in command line you can use repl module.
const repl = require('repl');
class ArithmeticTaskRunner {
... // Your class definition
}
// This starts the REPL session with the ArithmeticTaskRunner defined
repl.start().context.ArithmeticTaskRunner = ArithmeticTaskRunner;
Then in terminal:
node filename.js
And when you have node running:
let taskRunner = new ArithmeticTaskRunner()
taskRunner.addAdditionTask(2)
taskRunner.addMultiplicationTask(4)
taskRunner.addAdditionTask(10)
taskRunner.execute(2)
taskRunner.execute(-2)
If you want to run the code completely and output the result use console.log in the code and run node filename.js:
class ArithmeticTaskRunner {
... // Your class definition
}
let taskRunner = new ArithmeticTaskRunner()
taskRunner.addAdditionTask(2)
taskRunner.addMultiplicationTask(4)
taskRunner.addAdditionTask(10)
console.log(taskRunner.execute(2))
console.log(taskRunner.execute(-2))
In terminal:
node filename.js
I'm assuming you've done basically the following on the command line:
node
.load ArithmeticTaskRunner.js
The reason you're only seeing the code printed out is because you just have a class definition. You don't have an instance of TaskRunner. If that's your intent, at the bottom of your code add something like this:
const taskRunner = new TaskRunner();
console.log(taskRunner);
Then when you try those command line steps again, it will print out an instance of TaskRunner with your methods on it.
However, the entire purpose of the .load command is to put your script into the Node.js REPL. Alternatively you can instead do the following in the command line:
node
.load ArithmeticTaskRunner.js
const taskRunner = new TaskRunner();
console.log(taskRunner);
This will let you do work on the command line without hard-coding it into your script.
Update
If your intent is to execute the code without printing it out, you can do the following:
node ArithmeticTaskRunner.js
But you won't be making your code available to the global instance. You'd have to add code into that script that creates a 'TaskRunner` instance and make use of it, like I did initially and save it into that file.
class ArithmeticTaskRunner
{
constructor()
{
this.tasks = [];
}
addNegationTask()
{
const negationTask = (x) => -x;
this.tasks.push(negationTask)
return this;
}
addAdditionTask(y)
{
const additionByY = (x) => x + y;
this.tasks.push(additionByY)
return this;
}
addMultiplicationTask(y)
{
const multiplyByY = (x) => x * y;
this.tasks.push(multiplyByY)
return this;
}
taskCount()
{
return this.tasks.length;
}
execute(n)
{
let currentResult = n;
for(let task of this.tasks)
{
currentResult = task(currentResult)
}
return currentResult;
}
}
const arithmeticTaskRunner = new ArithmeticTaskRunner ();
console.log(arithmeticTaskRunner );
After this then try doing the steps on the command line:
node
.load ArithmeticTaskRunner.js
Update 2
This should open the Node REPL (leading '>` should appear). Afterwards do these commands one line at a time:
let taskRunner = new ArithmeticTaskRunner()
taskRunner.addAdditionTask(2)
taskRunner.addMultiplicationTask(4)
taskRunner.addAdditionTask(10)
taskRunner.execute(2)
This should print 26.
taskRunner.execute(-2)
This should print 10.

How do I implement tab completion in node.js shell?

I was looking for this feature in node.js and I haven't found it.
Can I implement it myself? As far as I know, node.js doesn't load any file at it's startup (like Bash does with .bashrc) and I haven't noticed any way to somehow override shell prompt.
Is there a way to implement it without writing custom shell?
You could monkey-patch the REPL. Note that you must use the callback version of the completer, otherwise it won't work correctly:
var repl = require('repl').start()
var _completer = repl.completer.bind(repl)
repl.completer = function(line, cb) {
// ...
_completer(line, cb)
}
Just as a reference.
readline module has readline.createInterface(options) method that accepts an optional completer function that makes a tab completion.
function completer(line) {
var completions = '.help .error .exit .quit .q'.split(' ')
var hits = completions.filter(function(c) { return c.indexOf(line) == 0 })
// show all completions if none found
return [hits.length ? hits : completions, line]
}
and
function completer(linePartial, callback) {
callback(null, [['123'], linePartial]);
}
link to the api docs: http://nodejs.org/api/readline.html#readline_readline_createinterface_options
You can implement tab functionality using completer function like below.
const readline = require('readline');
/*
* This function returns an array of matched strings that starts with given
* line, if there is not matched string then it return all the options
*/
var autoComplete = function completer(line) {
const completions = 'var const readline console globalObject'.split(' ');
const hits = completions.filter((c) => c.startsWith(line));
// show all completions if none found
return [hits.length ? hits : completions, line];
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
completer: autoComplete
});
rl.setPrompt("Type some character and press Tab key for auto completion....\n");
rl.prompt();
rl.on('line', (data) => {
console.log(`Received: ${data}`);
});
Reference :
https://self-learning-java-tutorial.blogspot.com/2018/10/nodejs-readlinecreateinterfaceoptions_2.html

Categories

Resources