Is JScript/WindowsScriptHost missing Array.forEach()? - jscript

I write JSCript and run it with the WindowsScriptHost.However, it seems to be missing Array.forEach().
['a', 'b'].forEach(function(e) {
WSH.Echo(e);
});
Fails with "test.js(66, 2) Microsoft JScript runtime error: Object doesn't support this property or method".
That can't be right? Does it really lack Array.forEach()? Do I really have to use one of the for-loop-variants?

JScript uses the JavaScript feature set as it existed in IE8. Even in Windows 10, the Windows Script Host is limited to JScript 5.7. This MSDN documentation explains:
Starting with JScript 5.8, by default, the JScript scripting engine supports the language feature set as it existed in version 5.7. This is to maintain compatibility with the earlier versions of the engine. To use the complete language feature set of version 5.8, the Windows Script interface host has to invoke IActiveScriptProperty::SetProperty.
... which ultimately means, since cscript.exe and wscript.exe have no switches allowing you to invoke that method, Microsoft advises you to write your own script host to unlock the Chakra engine.
There is a workaround, though. You can invoke the htmlfile COM object, force it to IE9 (or 10 or 11 or Edge) compatibility, then import whatever methods you wish -- including Array.forEach(), JSON methods, and so on. Here's a brief example:
var htmlfile = WSH.CreateObject('htmlfile');
htmlfile.write('<meta http-equiv="x-ua-compatible" content="IE=9" />');
// And now you can use htmlfile.parentWindow to expose methods not
// natively supported by JScript 5.7.
Array.prototype.forEach = htmlfile.parentWindow.Array.prototype.forEach;
Object.keys = htmlfile.parentWindow.Object.keys;
htmlfile.close(); // no longer needed
// test object
var obj = {
"line1" : "The quick brown fox",
"line2" : "jumps over the lazy dog."
}
// test methods exposed from htmlfile
Object.keys(obj).forEach(function(key) {
WSH.Echo(obj[key]);
});
Output:
The quick brown fox
jumps over the lazy dog.
There are a few other methods demonstrated in this answer -- JSON.parse(), String.trim(), and Array.indexOf().

Related

GraalVM + Nashorn Cannot extend classes

I'm attempting to use graal + nashorn interop to write nodejs that interacts with Java. I'm starting graal with node --jvm --jvm.Xss2m --jvm.Dtruffle.js.NashornJavaInterop=true --jvm.classpath=libs/ --polyglot app.js. I cannot extend a class though. The javascript code is
const GraaljsgrpcServiceImpl = Java.type('com.thing.GraaljsgrpcServiceImpl');
const HelloReply = Java.type('com.thing.HelloReply');
var GrpcImpl = Java.extend(GraaljsgrpcServiceImpl, {
sayHello: function(request, responseObserver) {
responseObserver.onNext(HelloReply.newBuilder().setMessage("Hello " + request.getName()).build());
responseObserver.onCompleted();
}
});
and my error is
TypeError: Could not determine a class loader with access to the JS engine and class com.thing.GraaljsgrpcServiceImpl This seems to point to a classloader issue with the java code I'm referencing and where the javascript is running(i.e. 2 different classloaders). Is there a way to pull this off when using graal/nodejs?
Thanks for reporting this classloader problem. We are looking into that and should be able to fix that with our next release (0.32 expected early March).
Regarding the --jvm.Dtruffle.js.NashornJavaInterop=true flag: we strongly encourage not using that, but depending on the built-in interoperability of GraalVM. However, in this mode Graal.js is not 100% compatible with Nashorn/Rhino; for instance, we are not supporting Java.extend in that mode. Is Java.extend the only reason why you set the NashornJavaInterop flag?
Thanks,
Christian

WebStorm compatibility with exporting of classes

I know that the ES6 export/import syntax is not part of Node.JS yet, so when I write a class in Node.JS, it usually goes something like this:
class Foo {
...
}
module.exports = Foo;
However, I frequently see a slightly more compact version of this:
module.exports = class Foo { ... }
When I write this code in WebStorm it will however complain "expression expected" (it doesn't like the class keyword in an assignment). The file seems to work fine when run with Node (~6.10) though.
Is there a compatibility setting in WebStorm to allow this? The only option I found was an inspection for warning about non-ES6 draft features.
WebStorm has issues resolving members of classes exported this way (see WEB-28158), but the syntax itself is correctly accepted (WebStorm 2017.3.2):
What IDE version do you use? Did you set JavaScript Language Version to ECMAScript 6 in Settings | Languages & Frameworks | JavaScript?
If this doesn't help, try invalidating caches

Debuging es6 Proxy as property -> Internal error: illegal access

If I, in node.js 6.6, write (resp. have transpiled from TypeScript) a class like that:
class Table {
constructor(args) {
this._rows = new Proxy({ test: 42 }, {});
}
}
And instantiate it like this:
var table = new Table();
When I debug in Visual Studio Code 1.2.1 when I want to watch the var table I always have
Internal error: illegal access
written there, meaning I can not watch table or any of its properties.
The same thing works perfectly fine in Chrome.
So, why is that and what can I do about it?
Thanks!
For those coming here first. It is indeed a bug this happens however Microsoft traced it to depreciated v8 debug code inside node.js itself. The workaround is to use "type": "node2" in your launch configuration file. This tells vscode to use the new debug protocol. Node 7+ is also recommended. Support for both is considered experimental as of vscode 1.10 and should used only if needed.
As of vscode 1.10 the "node2" code is being merged with "node". "type":"node2" is depreciated in favor of the "protocol" attribute. If set to "auto" the protocol will be switched automatically based on runtime determination. Setting to attribute to "inspector" simulates the effects of "node2" forcing the new debug protocol to be used. The default setting is equivalent to using "type":"node" in vscode 1.8.x, 1.9.x.

Can't release the ID3DX11Effect pointer?

I use Effect framework in my demo.
here are my defination in header file
ID3D11Buffer* m_pVertexBuffer;
ID3D11Buffer* m_pIndexBuffer;
ID3D11InputLayout* m_pInputLayout;
ID3DX11Effect* m_pFx;
ID3DX11EffectTechnique* m_pTechnique;
ID3DX11EffectMatrixVariable* m_pFxWorldViewProj;
I release them as follow
void HillsDemo::UnLoadContent()
{
if (m_pVertexBuffer) m_pVertexBuffer->Release();
if (m_pIndexBuffer) m_pIndexBuffer->Release();
if (m_pInputLayout) m_pInputLayout->Release();
if (m_pTechnique) m_pTechnique->Release();
if (m_pFx) m_pFx->Release();
}
then I run the demo,when I close the demo window, there is an error which means HillsDemo has stopped working.Why?Then I delete the lineif (m_pFx) m_pFx->Release();,there is no error. So is releasing the m_pFx make the error?
I view the documents of Effect11 https://github.com/Microsoft/FX11/wiki/Effects-11, there are on the document:
The following types are now derived from IUnknown: ID3DX11EffectType, ID3DX11EffectVariable, I3DX11EffectPass, ID3DX11EffectTechnique, ID3DX11EffectGroup. Note that these objects do not follow standard COM reference-counting rules and they are released when the parent ID3DX11Effect is released. This is mostly to simplify use of Effects 11 from managed languages.
Does it means that I should only release the m_pFx rather than release both m_pFx and m_pTechnique? Any ideas?
I assume you are using the latest version of Effects 11 from GitHub rather than the legacy DirectX SDK copy based on your reference to the project wiki.
You should really look at using ComPtr instead of raw pointers to COM objects. In the case of Effects 11, you'd just use them for ID3DX11Effect instances. You should stick with 'raw pointers' for ID3DX11EffectType, ID3DX11EffectVariable, I3DX11EffectPass, ID3DX11EffectTechnique, and ID3DX11EffectGroup. Don't bother calling Release on these raw pointers as the lifetime controlled by the ID3DX11Effect.
Something like:
Microsoft::WRL::ComPtr<ID3D11Buffer> m_pVertexBuffer;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_pIndexBuffer;
Microsoft::WRL::ComPtr<ID3D11InputLayout> m_pInputLayout;
Microsoft::WRL::ComPtr<ID3DX11Effect> m_pFx;
ID3DX11EffectTechnique* m_pTechnique;
ID3DX11EffectMatrixVariable* m_pFxWorldViewProj;
void HillsDemo::UnLoadContent()
{
m_pVertexBuffer.Reset();
m_pIndexBuffer.Reset();
m_pInputLayout.Reset();
m_pFx.Reset();
m_pTechnique = nullptr;
pFxWorldViewProj = nullptr;
}

How to clean SSJS in Domino server after someone used javascript prototype in a nsf?

How to clean SSJS (Server Side Javascript) in Domino server after someone used javascript prototype in a nsf?
Mark Roden discovered a huge weakness in XPages SSJS: (thanks to David Leedy for tell me about this and show me the article).
If you have the following SSJS code:
var dummyObj = {}
dummyObj.prototype.NAME = "Johann"
XPages SSJS doesn't care that you uses var (var means the variable must be local) and it makes dummyObj.NAME visible in the whole server with the value Johann. So if another nsf in the same server uses a var with the same name it inherits the whole prototype:
var dummyObj = {}
println(dummyObj.NAME) /*prints "Johann" */
This is a huge bug (one that makes unreliable XPages SSJS IMO). Even if you don't use prototype at all, if someone else in his application do something like this:
String.prototype.split = function(){ return "I broke this method" }
It will broke all applications in the same server that uses the innocent split().
So, the question is: if someone "by mistake" writes the following SSJS (XPages Server Side Javascript) in a NSF:
String.prototype.split = function(){ return "I broke this method" }
How can I fix String.prototype.split() to his original value?
As Mark Roden said, restarting HTTP task doesn't fix it.
///////////////////////////////////////////////////////////
Edit 1: Why I think this is a huge bug:
I'm a Javascript fan but IMHO #MarkyRoden has discovered a huge bug in SSJS. Shims and polyfills aren't really the main problem. Eval is known to be a bad practice but the prototype object is a fundamental element of basic Javascript. It's the standard and preferred way to add methods to Javascript classes, it's also needed for inheritance and all kind of OOP stuff. So you will need some kind of namespace at server level in order to avoid collisions. All this is really bad but the huge problem is that just a line of code in one application can broke all applications in a server. Yes, you can trust in your developers but one of them can write a bad line by mistake and also a Domino server can have hundreds of applications from different software vendors. Set the responsability in code reviews is not a reliable enought procedure. Maybe it's time to have a real javascript engine in SSJS, like V8, Spidermonkey, Chakra or Rhino. As a workaround, I'm thinking in something like Tommy Valand's idea with Rhino in SSJS.
Edit 2: It's even worse. You can do things like:
prototype.importPackage = null
or
prototype.Array = null
As you can see in #SvenHasselbach's article: http://hasselba.ch/blog/?p=1371
Edit 3: IBM: you told me I could use SSJS. COME ONE! PLEASE FIX THIS, it's AWFUL. Please let's officially report this issue to IBM.
You can reset the SSJS interpreter with the following Java code:
FacesContextExImpl fc = (FacesContextExImpl) FacesContextExImpl.getCurrentInstance();
UIViewRootEx2 uiRoot = (UIViewRootEx2) fc.getViewRoot();
JSContext jsContext = uiRoot.getJSInterpreter().getJSContext();
jsContext.getRegistry().init(jsContext);
This reinitializes the registry and all prototype functions.
EDIT: Changed the declaration of fc to the correct type.
EDIT 2:
Here is the SSJS version:
var uiRoot = facesContext.getViewRoot();
var jsContext = uiRoot.getJSInterpreter().getJSContext();
var reg = jsContext.getRegistry();
reg.init( jsContext );
Does I understand you correctly, that you want to clean up the SSJS interpreter to avoid a collision with your own prototype extension?
Just to clarify the answer above: This reinitializes the SSJS interpreter once. And only once.
You have to do this over and over again, because directly after reinitializing, another application on the server can overwrite the prototype functionality again. That's why this is not a real solution, it is an answer to your initial question.
It will have interessting consequences if another application will do the same while your code tries to use your extension...
try to do a Restart Task Http instead
tell http restart will not do a full restart of the http task

Resources