String.matchAll is undefined - javascript

I am creating a package in node to parse and manipulate csv and needed to use String.matchAll() and I got an error saying str.matchAll is not a function. I tried switching to str.match() and got the same error. I tried to console.log each and both returned undefined. I typed node -v into the visual studio code powershell and it spat out v10.16.3
my code
fs = require('fs');
class Table {
//the function I needed it for
removeRow(header, value){
let regLine = "";
for(let i=0; i<this.colArr.length; i++){
if (this.colArr[i][0]==header){
regLine+=value+",";
}else{
regLine+=".*,"
}
}
regLine = "\n"+regLine.substring(0,regLine.length-2)+"\n";
let regex = new RegExp(regLine);
let removed = this.text.matchAll(regex);//this line
let newText = this.text.replace(regex,"\n");
fs.writeFile(this.link, newText);
this.update();
return removed;
}
}
At the line marked it throws the error this.text is not a function I console.logged typeof(this.text) and it gave string so I don't know whats going on

String.matchAll is only available from Node.js 12.0 onwards (see compatibility here: string.matchAll).
String.match however should be available from early versions of Node.js.
Here's an example I've created of it in action (Node v10.16.0): https://repl.it/repls/PunctualRareHypotenuse
I'd suggest also ensuring that the object in question is a string just to be sure!
Also if it's easy for you to upgrade, try installing Node.js 12.
Code:
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var regexp = /[A-E]/g;
var matches_array = str.match(regexp);
console.log(matches_array);

Related

Alternative to eval() in node script

I am working on a script that runs during our build process in Jenkins right before npm install. My issue is that I need to download a JavaScript file from an external resource and read a variable from it.
unzipper.on('extract', () => {
const content = fs.readFileSync(`${outputDir}/js/en.js`, 'utf8');
eval(content); // Less smellier alternative?
if (obj) {
const str = JSON.stringify(obj);
fs.writeFileSync(`${outputDir}/public/data.json`, str);
} else {
throw 'Variable `obj` not found';
}
});
I know that "eval is evil", but any suggested alternatives I've found online don't seem to work.
I have tried different variations of new Function(obj)(), but Node seems to exit the script after (the if-case never runs).
Ideas?
Since node.js provides the API to talk to the V8 runner directly, it might be a good idea to use it. Basically, it's the API used by node's require under the hood.
Assuming the js file in question contains the variable obj we're interested in, we do the following:
read the code from the file
append ; obj to the code to make sure it's the last expression it evaluates
pass the code to V8 for evaluation
grab the return value (which is our obj):
const fs = require('fs'),
vm = require('vm');
const code = fs.readFileSync('path-to-js-file', 'utf8');
const obj = vm.runInNewContext(code + ';obj');
This answer is heavily based on #georg's comments, but since it helped me I'll provide it as an alternative answer.
Explanation in the comments.
let content = fs.readFileSync(`${outputDir}/js/en.js`, 'utf8');
content += '; module.exports=obj'; // Export "obj" variable
fs.writeFileSync(`${outputDir}/temp`, content); // Create a temporary file
const obj = require(`${outputDir}/temp`); // Import the variable from the temporary file
fs.unlinkSync(`${outputDir}/temp`); // Remove the temporary file

How to track down a ReferenceError in Nashorn

I have hit a problem that seems like it might be some sort of bug in the Nashorn engine, but I can't figure out a good way to distill a test case that will demonstrate it.
I have a block of code (that used to work!) which looks roughly like this:
'use strict';
function Dummy() {
this.val = 'I am fubar';
this.aContainer = [];
}
Dummy.prototype.toString = function() { return JSON.stringify(this);};
let obj = {};
obj.aMethod = function(arg) {
let fubar = new Dummy();
print('Okay so far');
fubar.aContainer.push({"some":"thing"});
print('Still okay');
fubar.aContainer.push({"==": [{"var": "something_else"}, fubar.val]});
return fubar;
};
print(obj.aMethod(null));
Unfortunately, running this example with jss --language=es6 -strict doesn't crash. In my real code though, I get the following:
jdk.nashorn.internal.runtime.ECMAException: ReferenceError: "fubar" is not defined
If I change the code as follows, it runs fine:
'use strict';
function Dummy() {
this.val = 'I am fubar';
this.aContainer = [];
}
Dummy.prototype.toString = function() { return JSON.stringify(this);};
let obj = {};
obj.aMethod = function(arg) {
let fubar = new Dummy();
print('Okay so far');
fubar.aContainer.push({"some":"thing"});
print('Still okay');
let x = fubar.val;
fubar.aContainer.push({"==": [{"var": "something_else"}, x]});
return fubar;
};
print(obj.aMethod(null));
Is there anything I can do to try to instrument the real code further or otherwise track this issue down? The odd thing is the error happens very early in execution. If I put a print() call anywhere in the method, the print is never reached. The last line of my code in the callstack is actually the line that calls the method.
I did just pick up a new version of Java via auto-update, but I need to see if this code is running under it or not. My current version from the console is:
➜ ~ java -version
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)
A full summary of all you can do to trace Nashorn is contained in this document:
jdk8u-dev/nashorn/file/tip/docs/DEVELOPER_README
It describes system properties that are used for internal debugging and instrumentation purposes, along with the system loggers, which are used for the same thing.

Object doesn't support property or method 'entries'

I am working with the FormData object, while my code works well on Chrome, Microsoft Edge spits out the following error message Object doesn't support property or method 'entries' – which corresponds to the following code:
for(let pair of formData.entries()) {
...
}
I've tried replacing .entries() with .getAll(), however Microsoft Edge doesn't recognize either of both methods.
Is there a way to get this functionality (iterating over FormData files) out of Microsoft Edge?
FormData Microsoft Edge Console Dump
2/10/2020 UPDATE:
Like #Monomachus said, first try adding this line to polyfill.ts:
import 'core-js/es7/object';
If this fixes it, make sure to give his answer credit! If needed, you can manually define it using the instructions below:
Original Response:
Essentially, a polyfill is a way you can manually define a function that isn't natively supported on a specific platform/browser.
In your case, there is a basic definition of the function Object.entries given here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries#Polyfill
They provide this simple, ready to deploy definition:
if (!Object.entries)
Object.entries = function( obj ){
var ownProps = Object.keys( obj ),
i = ownProps.length,
resArray = new Array(i); // preallocate the Array
while (i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];
return resArray;
};
Looking at the code above, the first thing it checks is if Object.entries exists. If it does, no worries, but if it doesn't exist, then it creates it...
As long as this function gets defined before you actually call it in your code, you should be fine.
Using something like angular-cli, they provide a polyfills.ts file (which gets executed before your app is run) where you can place code like this or import files containing definitions you'll need.
10/30/2018 UPDATE:
#apsillers correctly pointed out the answer above does not apply to FormData.entries(), but to Object.entries() instead.
Solution for FormData.entries() (this worked for me):
https://stackoverflow.com/a/49556416/3806701
Basically, import this poly-fill:
<script src="https://unpkg.com/formdata-polyfill"></script>
Then you can iterate FormData as follows:
var formDataEntries = (<any>formData).entries(), formDataEntry = formDataEntries.next(), pair;
while (!formDataEntry.done) {
pair = formDataEntry.value;
console.log(pair[0] + ', ' + pair[1]);
formDataEntry = formDataEntries.next();
}
If you're in an Angular App please add this line to your polyfills.ts file
import 'core-js/es7/object';
It will import all the new methods on Object, including entries
By importing
import 'core-js/es7/object';
if you are getting error
Module not found: Error: Can't resolve 'core-js/es7/object'
then Change all "es6" and "es7" to "es" in your imports.
import 'core-js/es/object';
I have added the below code in my polyfills.ts and it worked for me.
import 'core-js/es7/object';
import 'core-js/es7/array';
if (!Object.entries)
{ Object.entries = function(obj)
{
var ownProps = Object.keys(obj),
i = ownProps.length,
resArray = new Array(i); // preallocate the Array while (i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];
return resArray;
};
}

Typescript generated JavaScript has a function that is not a function

This typescript:
export enum UID {
FACTORY,
ROBOT
}
compiles to this javascript:
(function (UID) {
UID._map = [];
UID._map[0] = "FACTORY";
UID.FACTORY = 0;
UID._map[1] = "ROBOT";
UID.ROBOT = 1;
})(exports.UID || (exports.UID = {}));
var UID = exports.UID;
I have to admit that the code seems rather obscure to me but I trusted the tsc compiler to know what it's doing. Unfortunately the javascript can't be executed. nodejs complains that:
(function (UID) {
^ TypeError: object is not a function
at ...
What have I done wrong ?
UPDATE:
Matt B. has solved the problem. This is a known bug in the typescript compiler. tsc fails to insert semicolons after require statements, this can lead to strange errors. Manually adding the semicolons to my code solved the problem. Here's the link to the codeplex issue:
http://typescript.codeplex.com/workitem/364
UPDATE 2:
for those of you that experience the same error. You can insert the missing semicolons manually but that is not a very comfortable solution since you have to do this after every compilation. I noted that the problem only occurs with the enum. There are lots of other modules in the project and none of them have caused this error. Apparently a class definition is not "harmed" by the missing semicolons in front of it. Just move the definition of the enum behind one of your class definitions and the error should disappear. It's not sufficient to move the enum behind an interface since interfaces have no direct equivalent and are just deleted by the compiler
I think this is the same issue as described here -- which turned out to be due to a missing semicolon after a require() statement:
Typescript generating javascript that doesn't work
Is there a line like this in another compiled file?
var UID = require('UID')
If so, try adding a semicolon at the end:
var UID = require('UID');
This appears to be a TypeScript bug; here's the bug report (vote it up!): http://typescript.codeplex.com/workitem/364
In your Javascript you should have something like
var exports = exports || {};
Before
(function (UID) {
UID._map = [];
UID._map[0] = "FACTORY";
UID.FACTORY = 0;
UID._map[1] = "ROBOT";
UID.ROBOT = 1;
})(exports.UID || (exports.UID = {}));
var UID = exports.UID;
I tried and I have the same problem - I assume that the missing exports variables should be generated by the JavaScript code used to load the module when you do
import XXXX = module("XXXX");
that generates this JavaScript:
var XXXX = require("./XXXX")
and I think Matt B. is right and the problem there is the missing semi-colon after require(), that messes things up afterwards.
A fix is to place the enumeration declaration in a module:
module Test {
export enum UID {
FACTORY,
ROBOT
}
}
that generates:
var test;
(function (test) {
(function (UID) {
UID._map = [];
UID._map[0] = "FACTORY";
UID.FACTORY = 0;
UID._map[1] = "ROBOT";
UID.ROBOT = 1;
})(test.UID || (test.UID = {}));
var UID = test.UID;
})(test || (test = {}));
in this way the exports variable is no longer needed.

Invoking functions with `out` arguments, passing arguments by reference in JScript

I'm using following code in JScript (WSH) to connect to local registry using WMI: var registry = GetObject('winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\default:StdRegProv'); and that works.
Then I have to determine if I'm allowed to delete key without really trying to delete it (e.g. perform a non-destructive check). I looked over docs and found that I need StdRegProv.CheckAccess() method. Problem is that CheckAccess returns result as out argument and I could not find VBScript's ByRef equivalent in JScript.
Somewhere in the Internet I've found that using SWbemServices.ExecMethod would help somehow, but I hadn't figured out how can I use that yet.
Could anyone provide me with code sample in JScript performing function call with argument passed by reference?
Heh, got it working.
For anyone who will need it, CheckAccess invokation in JScript looks something like this:
function CheckAccess(defKey, subkeyName, required) {
var providerName = "StdRegProv";
var funcName = "CheckAccess";
// connect to WMI
var services = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\default");
// get provider
var registry = services.Get(providerName);
var in_params = registry.Methods_(funcName).InParameters.SpawnInstance_();
in_params.hDefKey = defKey;
in_params.sSubKeyName = subkeyName;
in_params.uRequired = required;
var outParams = services.ExecMethod(providerName, funcName, inParams);
return Boolean(outParams.bGranted);
};

Categories