JSON.stringify() a string which is actual NodeJS code - node.js

I'm working with the Readline module in NodeJS and would like to parse the content of what the user wrote as code. Meaning if someone writes:
{
name: "David",
age: 34
}
I should be able to JSON.stringify(content) and get:
{
"name": "David",
"age": "34"
}
How can I convert a string in to actual code, so it can be interpreted as a JavaScript object, thus be converted in to JSON using JSON.stringify()?

It's not entirely clear what you're asking, but, would JSON.parse() help you here? You'll want to wrap it in a try catch in case the input is not valid JSON.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

The trick to make this work is to use the VM module in a undocumented way as seen below.
let vm = require('vm');
let script = new vm.Script('x = ' + full_content);
let sandbox = script.runInThisContext();
converted = JSON.stringify(sandbox);
Basically you have to create a variable that will hold your string (JavaScript), which will be then converted in to proper JavaScript code thanks to .runInThisContext().
In this case the x variable will "disappear" and you don't have to think about that. But if you were to follow the NodeJS documentation example, and use .runInNewContext() then the x variable wouldn't go away, a you would have your object (in my case at least) assigned to the x variable.
Hope this helps :)

Related

Jest fails for same string

I'm trying unit testing for the first time with Jest on a personal project, and some of my tests failed even though the data received was the exact same as expected, here's an example:
test("decrypt method works correctly", () =>{
const myAES = new rijndael("", "0bdfa595235c307a105d593fb78fbb13", { key: "SOME 128 BIT KEY", bits: 128, rounds: 9 })
expect(myAES.decrypt()).toStrictEqual({
"c": "0bdfa595235c307a105d593fb78fbb13",
"p": "ATTACK AT DAWN!",
"errors": []
})
}
So then I tried to check if it's a problem with Jest or my code:
const r = myAES.decrypt()
console.log(typeof r.p) // string
console.log(r.p === "ATTACK AT DAWN!") // false
Which just made me even more confused as the strings look the same. The code that I'm testing is an AES encryption function (Don't worry it's just a personal project for fun won't be used in production) that processes text as nodeJS Buffers, and in the end uses the toString() method to convert it back to a string. I'm thinking that may be why I'm having issues, but can't seem to find exactly why. Would love it if someone could point me in the right direction so I can get rid of this error. Thank you in advance.
P.S. I'll save everyone the pain of reading my AES implementation for now as I don't think it's a problem with the encryption but let me know if that's necessary
Ok, so turns out it was a stupid mistake where I overlooked the series of null bytes that tend to end up in the end of the buffer after decryption. While toString() will turn the buffer into the string I want the computer will not recognise it as the same string. So all I had to do was strip the null bytes that follow. Assuming that the null bytes should only appear at the end of the string as they normally do:
const i = buffer.indexOf(0x00)
const result = buffer.slice(0, i).toString() //solves the problem

How to generate a warning/error when using non-string-variables inside string interpolation?

TypeScript does not produce any errors for the following code:
const maybe_a_string: undefined | string = undefined;
const false_or_string: false | string = false;
// I'd like the following to produce an error/warning...
const message_string = `Some readable string info should be here: ${maybe_a_string} ${false_or_string}`;
Is there some kind of setting I can turn on, or simple alternative ways to write the last line that will warn me about trying to use non-string variables inside strings like this? (but without needing to add extra lines of code for every sub-string to be asserted individually)
I guess it treats them as fine because some types like bools, numbers and misc objects have a .toString() method...
But especially in the case of undefined (which actually doesn't have a .toString() method) - it's quite common for you to have a bug there, as the only time you really want to see the string "undefined" inside another string is for debugging purposes. But there's a lot of these bugs out there in the wild where end users are seeing stuff like "hello undefined" unintentionally.
Personally I would handle this by making the string template into a function. That way you can specify that the arguments must be strings.
const createMessageString = (first: string, second: string): string => {
return `Some readable string info should be here: ${first} ${second}`;
}
const message_string = createMessageString( maybe_a_string, false_or_string );
// will give an error unless types are refined
Vote for https://github.com/microsoft/TypeScript/issues/30239 [Restrict template literal interpolation expressions to strings]
Additionally, you can try workarounds from the issue comments.

NodeJS why is object[0] returning '{' instead of the first property from this json object?

So I have to go through a bunch of code to get some data from an iframe. the iframe has a lot of data but in there is an object called '_name'. the first key of name is 'extension_id' and its value is a big long string. the json object is enclosed in apostrophes. I have tried removing the apostrophes but still instead of 'extension_id_output' I get a single curly bracket. the json object looks something like this
Frame {
...
...
_name: '{"extension_id":"a big huge string that I need"} "a bunch of other stuff":"this is a valid json object as confirmed by jsonlint", "globalOptions":{"crev":"1.2.50"}}}'
}
it's a whole big ugly paragraph but I really just need the extension_id. so this is the code I'm currently using after attempt 100 or whatever.
var frames = await page.frames();
// I'm using puppeteer for this part but I don't think that's relevant overall.
var thing = frames[1]._name;
console.log(frames[1])
// console.log(thing)
thing.replace(/'/g, '"')
// this is to remove the apostrophes from the outside of the object. I thought that would change things before. it does not. still outputs a single {
JSON.parse(thing)
console.log(thing[0])
instead of getting a big huge string that I need or whatever is written in extension_id. I get a {. that's it. I think that is because the whole object starts with a curly bracket. this is confirmed to me because console.log(thing[2]) prints e. so what's going on? jsonlint says this is a valid json object but maybe it's just a big string and I should be doing some kind of split to grab whaat's between the first : and the first ,. I'm really not sure.
For two reasons:
object[0] doesn't return the value an object's "first property", it returns the value of the property with the name "0", if any (there probably isn't in your object); and
Because it's JSON, and when you're dealing with JSON in JavaScript code, you are by definition dealing with a string. (More here.) If you want to deal with the object that the JSON describes, parse it.
Here's an example of parsing it and getting the value of the extension_id property from it:
const parsed = JSON.parse(frames[1]._name);
console.log(parsed.extension_id); // The ID

Converting match object to string in perl6

I was trying to convert a match object to a string in perl6. The method Str on a match object is defined as:
method Str(Match:D: --> Str:D)
I would think I could use Str($match) to accomplish this. And it seems to convert it to a string, but I'm getting an error using the string with the following code:
my $searchme = "rudolph";
my $match = $searchme ~~ /.*dol.*/;
say $match.WHAT;
my $test1 = Str($match);
say $test1.WHAT;
say $test1;
With the output:
(Match)
(Str)
With the error:
Cannot find method 'gist': no method cache and no .^find_method in
block at .code.tio line 6
However, if I run:
my $searchme = "rudolph";
my $match = $searchme ~~ /.*dol.*/;
say $match.WHAT;
my $test1 = $match.Str;
say $test1.WHAT;
say $test1;
I get no error and the result:
(Match)
(Str)
rudolph
Is this a bug or me misunderstanding how it works?
Thanks for reading.
I'm writing this up as an answer even though it's actually an incomplete discussion of a bug, so not at all normal SO fare. The alternative of lots of comments doesn't seem better.
It's a bug. Perhaps you just golfed this.
dd $test1; instead of say $test1; is helpful in that it displays BOOTStr $test1 = (BOOTStr without .perl method).
Based on that I searched the rakudo repo for BOOTStr and that led to the above issue.
Golfing it further leads to:
say $ = Str(Match.new);
Note that these are all fine:
say Str(Match.new);
say $ = Int(Match.new);
say $ = Str(Date.new: '2015-12-31');
It appears to be a combination of leaking some implementation details regarding how Rakudo/NQP/MoarVM bootstrap; Match being an NQP object; Str() on that being wonky; and assigning it to a Scalar container (the $ is an anonymous one) making that wonkiness visible.
I'll add more when/if I figure it out.

Start and stop parsing of a string

I grab a url and I want to parse and store two sections of the url
User/Confirmation?=QVNERkFTREY=&code=MTAvMjMvMjAxMyAxMjowMDowMCBBTQ==
So I want to start at (Confirmation?=) and stop at (&) and store the results
string = QVNERkFTREY
then for the second one I want to start at (&code=) and go to the end of the string and store that result
string = MTAvMjMvMjAxMyAxMjowMDowMCBBTQ==
I was have tried a few different things
Uri myUri = new Uri(Request.Url.AbsoluteUri);
string param1 = HttpUtility.ParseQueryString(myUri.Query).Get("Confirmation?=");
string param2 = myUri.Query.Split();
Pretty sure I should be going a different route here but any help would be appreciate. I am going to continue to google search for now. I appreciate the help.
EDIT: I feel as though LINQ should be able to help me here..hmm
I would use HttpUtility.ParseQueryString rather than try to parse the URL myself.
String val = "User/Confirmation?=QVNERkFTREY=&code=MTAvMjMvMjAxMyAxMjowMDowMCBBTQ==";
System.Collections.Specialized.NameValueCollection parameters = System.Web.HttpUtility.ParseQueryString(val);
Console.Out.WriteLine(parameters[0]); // QVNERkFTREY=
Console.Out.WriteLine(parameters.Get("code"); // MTAvMjMvMjAxMyAxMjowMDowMCBBTQ==
You will need to add System.Web.dll, which you can read about here: Cannot add System.Web.dll reference

Resources