<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://clearscript.clearfoundry.net/feed.xml" rel="self" type="application/atom+xml" /><link href="https://clearscript.clearfoundry.net/" rel="alternate" type="text/html" /><updated>2026-03-23T21:02:07+00:00</updated><id>https://clearscript.clearfoundry.net/feed.xml</id><title type="html">ClearScript</title><subtitle>Add scripting to your .NET applications quickly and easily.</subtitle><author><name>ClearScript Library</name><email>clearscript@clearfoundry.net</email></author><entry><title type="html">Performance API in ClearScript 7.4.5</title><link href="https://clearscript.clearfoundry.net/2024/03/21/performance-api.html" rel="alternate" type="text/html" title="Performance API in ClearScript 7.4.5" /><published>2024-03-21T00:00:00+00:00</published><updated>2024-03-21T00:00:00+00:00</updated><id>https://clearscript.clearfoundry.net/2024/03/21/performance-api</id><content type="html" xml:base="https://clearscript.clearfoundry.net/2024/03/21/performance-api.html"><![CDATA[<p>High-resolution timing facilities are now available for JavaScript code.</p>

<h1 id="introduction">Introduction</h1>

<p>By default, ClearScript provides a <em>bare</em> scripting environment. Unless the host takes explicit steps to expose .NET objects or types, scripts can access only their core language facilities, such as the standard JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects">built-in objects</a>.</p>

<p>Although ClearScript makes it easy to expose managed resources, high-resolution timing is something that benefits from a native implementation – not because .NET doesn’t support it, but because the expensive transition to managed code and back can reduce its effectiveness.</p>

<p>ClearScript 7.4.5 introduces the <code class="language-plaintext highlighter-rouge">Performance</code> object – an optional JavaScript API for high-resolution timing, available for ClearScript’s V8-based JavaScript engine.</p>

<h1 id="setting-up">Setting Up</h1>

<p>To enable the <code class="language-plaintext highlighter-rouge">Performance</code> object, specify <a href="https://clearscript.clearfoundry.net/Reference/html/T_Microsoft_ClearScript_V8_V8ScriptEngineFlags.htm"><code class="language-plaintext highlighter-rouge">V8ScriptEngineFlags.AddPerformanceObject</code></a> when constructing a <a href="https://clearscript.clearfoundry.net/Reference/html/T_Microsoft_ClearScript_V8_V8ScriptEngine.htm"><code class="language-plaintext highlighter-rouge">V8ScriptEngine</code></a> instance:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">engine</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">V8ScriptEngine</span><span class="p">(</span><span class="n">V8ScriptEngineFlags</span><span class="p">.</span><span class="n">AddPerformanceObject</span><span class="p">);</span></code></pre></figure>

<h1 id="the-api">The API</h1>

<p>The <code class="language-plaintext highlighter-rouge">Performance</code> object has the following members:</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Performance.timeOrigin</code>: This property gets the script engine’s creation time. It is a double-precision floating-point value that represents the number of milliseconds since the Unix epoch (00:00:00 UTC on Thursday, January 1, 1970).</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Performance.now()</code>: This method returns a high-resolution timestamp in milliseconds. It represents the time elapsed since <code class="language-plaintext highlighter-rouge">Performance.timeOrigin</code>.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Performance.sleep(delay, precise)</code>: This method suspends script execution for at least the millisecond duration specified by <code class="language-plaintext highlighter-rouge">delay</code>. If <code class="language-plaintext highlighter-rouge">precise</code> is falsy or unspecified, the method calls an operating system sleep function. A truthy argument directs it to perform a “cooperative spin wait” instead, providing enhanced precision at the cost of mild CPU load.</p>
  </li>
</ul>

<h1 id="timer-resolution">Timer Resolution</h1>

<p>The precision of native timing facilities differs across operating systems and can in some cases be adjusted at runtime. In addition to the <code class="language-plaintext highlighter-rouge">Performance</code> object, ClearScript 7.4.5 supports a new option that sets native timers to the highest available resolution while the script engine is active:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">var</span> <span class="n">flags</span> <span class="p">=</span> <span class="n">V8ScriptEngineFlags</span><span class="p">.</span><span class="n">AddPerformanceObject</span> <span class="p">|</span> <span class="n">V8ScriptEngineFlags</span><span class="p">.</span><span class="n">SetTimerResolution</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">engine</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">V8ScriptEngine</span><span class="p">(</span><span class="n">flags</span><span class="p">);</span></code></pre></figure>

<p>Note that <code class="language-plaintext highlighter-rouge">V8ScriptEngineFlags.SetTimerResolution</code> is only a hint and may be ignored on some systems. Where supported, it can degrade overall system performance or power efficiency, so caution is recommended.</p>

<p>Good luck!</p>]]></content><author><name>ClearScript Library</name><email>clearscript@clearfoundry.net</email></author><summary type="html"><![CDATA[High-resolution timing facilities are now available for JavaScript code.]]></summary></entry><entry><title type="html">Module Interoperability in ClearScript 7.3.7</title><link href="https://clearscript.clearfoundry.net/2023/01/24/module-interop.html" rel="alternate" type="text/html" title="Module Interoperability in ClearScript 7.3.7" /><published>2023-01-24T00:00:00+00:00</published><updated>2023-01-24T00:00:00+00:00</updated><id>https://clearscript.clearfoundry.net/2023/01/24/module-interop</id><content type="html" xml:base="https://clearscript.clearfoundry.net/2023/01/24/module-interop.html"><![CDATA[<p>Standard (ES6) modules can now import CommonJS modules.</p>

<h1 id="introduction">Introduction</h1>

<p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules">JavaScript modules</a> offer a way to split complex scripts into independent functional units with well-defined interfaces. The <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import"><code class="language-plaintext highlighter-rouge">import</code></a> and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export"><code class="language-plaintext highlighter-rouge">export</code></a> declarations, as well as the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import"><code class="language-plaintext highlighter-rouge">import</code></a> operator, were introduced in ECMAScript 2015 (ES6) as a standard way for modules to share code and data.</p>

<p>This facility supersedes earlier module specifications such as <a href="https://commonjs.org/">CommonJS</a>. However, the latter remains in heavy use, and many popular libraries aren’t available in any other form.</p>

<p>ClearScript 7.3.7 allows JavaScript modules to import resources from CommonJS libraries. In this post we’ll walk through an example.</p>

<h1 id="basic-setup">Basic Setup</h1>

<p>For this example, let’s allow scripts to load documents and use the console:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">engine</span><span class="p">.</span><span class="n">DocumentSettings</span><span class="p">.</span><span class="n">AccessFlags</span> <span class="p">=</span> <span class="n">DocumentAccessFlags</span><span class="p">.</span><span class="n">EnableFileLoading</span><span class="p">;</span>
<span class="n">engine</span><span class="p">.</span><span class="nf">AddHostType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Console</span><span class="p">));</span></code></pre></figure>

<h1 id="document-categories">Document Categories</h1>

<p>ClearScript uses <a href="https://clearscript.clearfoundry.net/Reference/html/T_Microsoft_ClearScript_DocumentCategory.htm"><em>document categories</em></a> to distinguish between the following document types:</p>
<ul>
  <li>JavaScript 
module – <a href="https://clearscript.clearfoundry.net/Reference/html/P_Microsoft_ClearScript_JavaScript_ModuleCategory_Standard.htm"><code class="language-plaintext highlighter-rouge">ModuleCategory.Standard</code></a></li>
  <li>CommonJS module – <a href="https://clearscript.clearfoundry.net/Reference/html/P_Microsoft_ClearScript_JavaScript_ModuleCategory_CommonJS.htm"><code class="language-plaintext highlighter-rouge">ModuleCategory.CommonJS</code></a></li>
  <li>Normal script – <a href="https://clearscript.clearfoundry.net/Reference/html/P_Microsoft_ClearScript_DocumentCategory_Script.htm"><code class="language-plaintext highlighter-rouge">DocumentCategory.Script</code></a></li>
</ul>

<p>However, it has no way to <em>detect</em> the category of a document. Instead, the host must specify the category when it initiates script execution:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">engine</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="k">new</span> <span class="n">DocumentInfo</span> <span class="p">{</span> <span class="n">Category</span> <span class="p">=</span> <span class="n">ModuleCategory</span><span class="p">.</span><span class="n">Standard</span> <span class="p">},</span> <span class="s">@"
    import { Rectangle } from 'Geometry';
    Console.WriteLine('The area is {0}.', new Rectangle(3, 4).Area);
"</span><span class="p">);</span></code></pre></figure>

<p>If the host doesn’t provide a category, ClearScript assumes <code class="language-plaintext highlighter-rouge">DocumentCategory.Script</code>.</p>

<p>On the other hand, if a module is loaded on behalf of another module, it <em>inherits</em> its category from the requesting module. In our example, <strong>Geometry</strong> inherits <code class="language-plaintext highlighter-rouge">ModuleCategory.Standard</code>.</p>

<h1 id="overriding-the-category">Overriding the Category</h1>

<p>Now let’s suppose that <strong>Geometry</strong> is actually a CommonJS module and looks something like this:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// Geometry.js</span>
<span class="nx">exports</span><span class="p">.</span><span class="nx">Rectangle</span> <span class="o">=</span> <span class="kd">class</span> <span class="p">{</span>
    <span class="kd">constructor</span><span class="p">(</span><span class="nx">width</span><span class="p">,</span> <span class="nx">height</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">width</span> <span class="o">=</span> <span class="nx">width</span><span class="p">;</span>
        <span class="k">this</span><span class="p">.</span><span class="nx">height</span> <span class="o">=</span> <span class="nx">height</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kd">get</span> <span class="nx">Area</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">width</span> <span class="o">*</span> <span class="k">this</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>Normally, the sample code above would result in a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError"><code class="language-plaintext highlighter-rouge">SyntaxError</code></a> with a message such as “The requested module ‘Geometry’ does not provide an export named ‘Rectangle’”.</p>

<p>To allow our example to work, we must <em>override</em> <strong>Geometry</strong>’s document category. To do that, we can use a <a href="https://clearscript.clearfoundry.net/Reference/html/P_Microsoft_ClearScript_DocumentSettings_LoadCallback.htm">document load callback</a>:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">engine</span><span class="p">.</span><span class="n">DocumentSettings</span><span class="p">.</span><span class="n">LoadCallback</span> <span class="p">=</span> <span class="p">(</span><span class="k">ref</span> <span class="n">DocumentInfo</span> <span class="n">info</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">Path</span><span class="p">.</span><span class="nf">GetFileNameWithoutExtension</span><span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">Uri</span><span class="p">.</span><span class="n">AbsolutePath</span><span class="p">)</span> <span class="p">==</span> <span class="s">"Geometry"</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">info</span><span class="p">.</span><span class="n">Category</span> <span class="p">=</span> <span class="n">ModuleCategory</span><span class="p">.</span><span class="n">CommonJS</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span></code></pre></figure>

<p>Note that we’re using a simple file name comparison to assign the document category. A real-world host might use a more generic algorithm, basing the assignment on the document’s location, its file name extension, an external manifest, or even the document’s contents.</p>

<h1 id="a-final-hurdle">A Final Hurdle</h1>

<p>In ClearScript 7.3.7, <code class="language-plaintext highlighter-rouge">V8ScriptEngine</code> is capable of importing CommonJS resources via the standard <code class="language-plaintext highlighter-rouge">import</code> declaration and operator. However, by default, the document loader throws an exception if a newly loaded document is of an unexpected category.</p>

<p>In other words, simply overriding the category would make our example fail even earlier – at the document loading stage. ClearScript 7.3.7 retains that behavior for compatibility and safety reasons. In many cases, blocking unexpected document categories is the prudent option.</p>

<p>In <em>this</em> case, however, we can use a new flag to relax that requirement:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">engine</span><span class="p">.</span><span class="n">DocumentSettings</span><span class="p">.</span><span class="n">AccessFlags</span> <span class="p">|=</span> <span class="n">DocumentAccessFlags</span><span class="p">.</span><span class="n">AllowCategoryMismatch</span><span class="p">;</span></code></pre></figure>

<p>With this flag in place, the document loader allows <strong>Geometry</strong> to pass on to the script engine, which now supports the CommonJS module category and safely imports the requested resources.</p>

<h1 id="putting-it-all-together">Putting It All Together</h1>

<p>Here’s the complete, working sample code:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">engine</span><span class="p">.</span><span class="n">DocumentSettings</span><span class="p">.</span><span class="n">AccessFlags</span> <span class="p">=</span> <span class="n">DocumentAccessFlags</span><span class="p">.</span><span class="n">EnableFileLoading</span> <span class="p">|</span> <span class="n">DocumentAccessFlags</span><span class="p">.</span><span class="n">AllowCategoryMismatch</span><span class="p">;</span>
<span class="n">engine</span><span class="p">.</span><span class="n">DocumentSettings</span><span class="p">.</span><span class="n">LoadCallback</span> <span class="p">=</span> <span class="p">(</span><span class="k">ref</span> <span class="n">DocumentInfo</span> <span class="n">info</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">Path</span><span class="p">.</span><span class="nf">GetFileNameWithoutExtension</span><span class="p">(</span><span class="n">info</span><span class="p">.</span><span class="n">Uri</span><span class="p">.</span><span class="n">AbsolutePath</span><span class="p">)</span> <span class="p">==</span> <span class="s">"Geometry"</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">info</span><span class="p">.</span><span class="n">Category</span> <span class="p">=</span> <span class="n">ModuleCategory</span><span class="p">.</span><span class="n">CommonJS</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
<span class="n">engine</span><span class="p">.</span><span class="nf">AddHostType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Console</span><span class="p">));</span>
<span class="n">engine</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="k">new</span> <span class="n">DocumentInfo</span> <span class="p">{</span> <span class="n">Category</span> <span class="p">=</span> <span class="n">ModuleCategory</span><span class="p">.</span><span class="n">Standard</span> <span class="p">},</span> <span class="s">@"
    import { Rectangle } from 'Geometry';
    Console.WriteLine('The area is {0}.', new Rectangle(3, 4).Area);
"</span><span class="p">);</span></code></pre></figure>

<p>Module interoperability allows newer scripts to use the standard JavaScript module facility while consuming existing CommonJS libraries.</p>

<h1 id="how-about-reverse-interoperability">How About Reverse Interoperability?</h1>

<p>Unfortunately, importing standard modules from CommonJS modules is <em>not</em> possible. The problem has to do with synchronous vs. asynchronous execution modes.</p>

<p>Specifically, standard modules can be <a href="https://github.com/tc39/proposal-top-level-await">asynchronous</a>, so they can invoke both synchronous and asynchronous code at the top level. Even if a module doesn’t use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await"><code class="language-plaintext highlighter-rouge">await</code></a>, its top-level code can be effectively asynchronous if it imports any asynchronous modules.</p>

<p>The top-level code of a CommonJS module is executed as a normal (synchronous) function, so it cannot interoperate with asynchronous code.</p>

<p>Good luck!</p>]]></content><author><name>ClearScript Library</name><email>clearscript@clearfoundry.net</email></author><summary type="html"><![CDATA[Standard (ES6) modules can now import CommonJS modules.]]></summary></entry><entry><title type="html">Using .NET Playgrounds with ClearScript 7.3</title><link href="https://clearscript.clearfoundry.net/2022/06/15/playground-environments.html" rel="alternate" type="text/html" title="Using .NET Playgrounds with ClearScript 7.3" /><published>2022-06-15T00:00:00+00:00</published><updated>2022-06-15T00:00:00+00:00</updated><id>https://clearscript.clearfoundry.net/2022/06/15/playground-environments</id><content type="html" xml:base="https://clearscript.clearfoundry.net/2022/06/15/playground-environments.html"><![CDATA[<p>ClearScript is now easier to use with LINQPad and .NET Fiddle.</p>

<h1 id="background">Background</h1>

<p>.NET playgrounds such as <a href="https://www.linqpad.net/">LINQPad</a> and <a href="https://dotnetfiddle.net/">.NET Fiddle</a> offer a great way to create small programs and explore the .NET platform.</p>

<p>In the past, ClearScript was difficult to use with these environments due to its reliance on native V8 assemblies and the Windows-only .NET Framework. Now that it supports newer .NET runtimes as well as several popular operating systems and machine architectures, ClearScript is much easier to incorporate into LINQPad and .NET Fiddle.</p>

<p>ClearScript 7.3 includes additional changes that make it almost as easy to use in these environments as a pure .NET library.</p>

<h1 id="linqpad">LINQPad</h1>

<p><a href="https://www.linqpad.net/">LINQPad</a> is a powerful .NET playground for Windows. We’ve tested ClearScript 7.3 with LINQPad 7 (x86/x64 and arm64) and LINQPad 5 (x86/x64).</p>

<p>Use the LINQPad NuGet Manager to add the appropriate package to your query:</p>

<ul>
  <li>
    <p>For LINQPad 7 (x86/x64) and LINQPad 5, use <strong>ClearScript Library for Windows (x86/x64)</strong> (Package ID: <a href="https://www.nuget.org/packages/Microsoft.ClearScript/">Microsoft.ClearScript</a>).<br />
<img src="/images/LINQPad-7-NuGet-Manager-x86-x64.png" alt="LINQPad 7 NuGet Manager (x86/x64)" /></p>
  </li>
  <li>
    <p>For LINQPad 7 (arm64), use <strong>ClearScript Library for Windows (arm64)</strong> (Package ID: <a href="https://www.nuget.org/packages/Microsoft.ClearScript.win-arm64/">Microsoft.ClearScript.win-arm64</a>).<br />
<img src="/images/LINQPad-7-NuGet-Manager-arm64.png" alt="LINQPad 7 NuGet Manager (arm64)" /></p>
  </li>
</ul>

<p>Be sure to select Version 7.3.0 or later. As soon as LINQPad completes the package import procedure, ClearScript is ready to go:</p>

<p><img src="/images/LINQPad-7-QuickTest.png" alt="LINQPad 7 QuickTest" /></p>

<h1 id="net-fiddle">.NET Fiddle</h1>

<p><a href="https://dotnetfiddle.net/">.NET Fiddle</a> is a convenient online .NET playground that enables easy sharing of code snippets. ClearScript 7.3 works seamlessly with its .NET 6 compiler.</p>

<p>Here’s how to enable ClearScript in your fiddle:</p>

<ol>
  <li>
    <p>Select “.NET 6” in the Compiler drop-down menu:<br />
<img src="/images/DotNetFiddle-Compiler-Dropdown.png" alt=".NET Fiddle Compiler Dropdown" /></p>
  </li>
  <li>
    <p>Add the NuGet package <strong>ClearScript Library for Linux (x64)</strong> (Package ID: <a href="https://www.nuget.org/packages/Microsoft.ClearScript.linux-x64/">Microsoft.ClearScript.linux-x64</a>). Be sure to select Version 7.3.0 or later:<br />
<img src="/images/DotNetFiddle-NuGet-Packages.png" alt=".NET Fiddle NuGet Packages" /></p>
  </li>
</ol>

<p>You are now ready to use ClearScript:</p>

<p><img src="/images/DotNetFiddle-QuickTest.png" alt=".NET Fiddle QuickTest" /></p>

<p>You can find this fiddle <a href="https://dotnetfiddle.net/3daJda">here</a>. Click <a href="https://dotnetfiddle.net/GdGvZ5">here</a> to see the full set of <a href="https://clearscript.clearfoundry.net/Examples/Examples.html">ClearScript examples</a> in action.</p>

<p>Good luck!</p>]]></content><author><name>ClearScript Library</name><email>clearscript@clearfoundry.net</email></author><summary type="html"><![CDATA[ClearScript is now easier to use with LINQPad and .NET Fiddle.]]></summary></entry><entry><title type="html">Custom Attribute Loaders in ClearScript 7.2.4</title><link href="https://clearscript.clearfoundry.net/2022/03/20/custom-attribute-loaders.html" rel="alternate" type="text/html" title="Custom Attribute Loaders in ClearScript 7.2.4" /><published>2022-03-20T00:00:00+00:00</published><updated>2022-03-20T00:00:00+00:00</updated><id>https://clearscript.clearfoundry.net/2022/03/20/custom-attribute-loaders</id><content type="html" xml:base="https://clearscript.clearfoundry.net/2022/03/20/custom-attribute-loaders.html"><![CDATA[<p>You can now add ClearScript attributes to platform and external resources, and more.</p>

<h1 id="background">Background</h1>

<p>ClearScript offers several <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/">attributes</a> for controlling how .NET resources are exposed for scripting. They allow hosts to expose type members under substitute names, restrict or block script access to individual resources, and adjust marshaling behavior. An example is <a href="https://clearscript.clearfoundry.net/Reference/html/T_Microsoft_ClearScript_ScriptMemberAttribute.htm"><code class="language-plaintext highlighter-rouge">ScriptMemberAttribute</code></a>.</p>

<p>.NET languages typically provide dedicated syntax for declaring attributes in source code, enabling fine-grained customization. However, that approach has some disadvantages:</p>

<ol>
  <li>
    <p>New attributes can’t be added to code developed elsewhere, such as .NET platform components and external libraries.</p>
  </li>
  <li>
    <p>There’s no convenient and efficient way to apply attributes broadly – e.g., for automatic renaming of all exposed type members.</p>
  </li>
</ol>

<h1 id="custom-attribute-loaders">Custom Attribute Loaders</h1>

<p>ClearScript now funnels all attribute access through a global facility, the <a href="https://clearscript.clearfoundry.net/Reference/html/P_Microsoft_ClearScript_HostSettings_CustomAttributeLoader.htm"><em>custom attribute loader</em></a>. The host can override that facility to <em>virtualize</em> attribute retrieval, gaining the ability to add new attributes to <em>any</em> .NET resource – as well as modify or hide conventionally declared attributes – all by overriding a single class method.</p>

<h1 id="example-expose-net-type-members-as-lower-camel-case">Example: Expose .NET Type Members as Lower Camel Case</h1>

<p>By convention, the names of public .NET type members are usually upper-camel-cased (a.k.a. Pascal-cased), whereas Javascript property names are often lower-camel-cased.</p>

<p>Suppose you’d like to make all exposed .NET type members accessible to script code via lower-camel-cased names. Until now, if your script API included types developed elsewhere, there was no way to achieve this without writing wrappers whose member names were under your control.</p>

<p>Now, by overriding ClearScript’s custom attribute loader, you can write a small method to implement a <em>global</em> transformation to lower camel case:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">class</span> <span class="nc">MyAttributeLoader</span> <span class="p">:</span> <span class="n">CustomAttributeLoader</span> <span class="p">{</span>
    <span class="k">public</span> <span class="k">override</span> <span class="n">T</span><span class="p">[]</span> <span class="n">LoadCustomAttributes</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">ICustomAttributeProvider</span> <span class="n">resource</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">inherit</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">var</span> <span class="n">declaredAttributes</span> <span class="p">=</span> <span class="k">base</span><span class="p">.</span><span class="n">LoadCustomAttributes</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">resource</span><span class="p">,</span> <span class="n">inherit</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(!</span><span class="n">declaredAttributes</span><span class="p">.</span><span class="nf">Any</span><span class="p">()</span> <span class="p">&amp;&amp;</span> <span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="p">==</span> <span class="k">typeof</span><span class="p">(</span><span class="n">ScriptMemberAttribute</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="n">resource</span> <span class="k">is</span> <span class="n">MemberInfo</span> <span class="n">member</span><span class="p">)</span> <span class="p">{</span>
            <span class="kt">var</span> <span class="n">lowerCamelCaseName</span> <span class="p">=</span> <span class="kt">char</span><span class="p">.</span><span class="nf">ToLowerInvariant</span><span class="p">(</span><span class="n">member</span><span class="p">.</span><span class="n">Name</span><span class="p">[</span><span class="m">0</span><span class="p">])</span> <span class="p">+</span> <span class="n">member</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="nf">Substring</span><span class="p">(</span><span class="m">1</span><span class="p">);</span>
            <span class="k">return</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="k">new</span> <span class="nf">ScriptMemberAttribute</span><span class="p">(</span><span class="n">lowerCamelCaseName</span><span class="p">)</span> <span class="p">}</span> <span class="k">as</span> <span class="n">T</span><span class="p">[];</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">declaredAttributes</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span></code></pre></figure>

<p>And then:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">HostSettings</span><span class="p">.</span><span class="n">CustomAttributeLoader</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">MyAttributeLoader</span><span class="p">();</span>
<span class="n">engine</span><span class="p">.</span><span class="nf">AddHostType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Console</span><span class="p">));</span>
<span class="n">engine</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="s">"Console.writeLine('Hello, world!');"</span><span class="p">);</span></code></pre></figure>

<p>You can also use this technique to centralize script access control and extend other ClearScript attribute capabilities to platform and external resources.</p>

<p>Good luck!</p>]]></content><author><name>ClearScript Library</name><email>clearscript@clearfoundry.net</email></author><summary type="html"><![CDATA[You can now add ClearScript attributes to platform and external resources, and more.]]></summary></entry><entry><title type="html">Top-Level Await in ClearScript 7.2.2</title><link href="https://clearscript.clearfoundry.net/2022/02/04/top-level-await.html" rel="alternate" type="text/html" title="Top-Level Await in ClearScript 7.2.2" /><published>2022-02-04T00:00:00+00:00</published><updated>2022-02-04T00:00:00+00:00</updated><id>https://clearscript.clearfoundry.net/2022/02/04/top-level-await</id><content type="html" xml:base="https://clearscript.clearfoundry.net/2022/02/04/top-level-await.html"><![CDATA[<p>ClearScript 7.2.2 is paired with V8 9.8, which no longer supports Top-Level Await control.</p>

<h1 id="background">Background</h1>

<p><a href="https://github.com/tc39/proposal-top-level-await">Top-Level Await</a> is a feature that enables code at the outermost scope of an <a href="https://262.ecma-international.org/6.0/#sec-modules">ECMAScript 6</a> module to be executed as an <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async function</a>.</p>

<p>ClearScript 7.1.3 added an <a href="https://clearscript.clearfoundry.net/Reference/html/P_Microsoft_ClearScript_V8_V8Settings_EnableTopLevelAwait.htm">API</a> for controlling Top-Level Await. When enabled, it caused module evaluation to return a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a>, eventually to be resolved with the module’s evaluation result.</p>

<p>Unfortunately, due to a <a href="https://bugs.chromium.org/p/v8/issues/detail?id=11715">V8 bug</a>, the promise resolution value is always <a href="https://developer.mozilla.org/en-US/docs/Glossary/undefined">undefined</a>. For that reason, and to maintain compatibility with hosts that rely on <em>immediate</em> module evaluation results, ClearScript left Top-Level Await disabled by default.</p>

<h1 id="v8-98-and-clearscript-722">V8 9.8 and ClearScript 7.2.2</h1>

<p>As of version 9.8, V8 no longer allows embedders to control Top-Level Await. Instead, the feature is always enabled.</p>

<p>However, embedders can now ask V8 whether a loaded module requires <em>async evaluation</em> – true only if the module uses <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await"><code class="language-plaintext highlighter-rouge">await</code></a> or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of"><code class="language-plaintext highlighter-rouge">for await...of</code></a>, or if any of its imported modules require async evaluation.</p>

<p>ClearScript 7.2.2 uses this information to extract the correct result from a promise tracking normal (non-async) module evaluation, and to return that result directly to the host.</p>

<p>That preserves ClearScript’s original behavior and allows async modules to work as expected. The only remaining issue, as of this blog entry, is that the evaluation result of an async module is still inaccessible due to the V8 bug mentioned above.</p>

<p>Good luck!</p>]]></content><author><name>ClearScript Library</name><email>clearscript@clearfoundry.net</email></author><summary type="html"><![CDATA[ClearScript 7.2.2 is paired with V8 9.8, which no longer supports Top-Level Await control.]]></summary></entry><entry><title type="html">Object Sharing Changes in ClearScript 7.2</title><link href="https://clearscript.clearfoundry.net/2022/01/10/object-sharing-changes.html" rel="alternate" type="text/html" title="Object Sharing Changes in ClearScript 7.2" /><published>2022-01-10T00:00:00+00:00</published><updated>2022-01-10T00:00:00+00:00</updated><id>https://clearscript.clearfoundry.net/2022/01/10/object-sharing-changes</id><content type="html" xml:base="https://clearscript.clearfoundry.net/2022/01/10/object-sharing-changes.html"><![CDATA[<p>ClearScript 7.2 includes enhancements for sharing objects across V8 script engines and runtimes.</p>

<h1 id="introduction">Introduction</h1>

<p>In ClearScript 7.1 and earlier, passing a script object from one engine to another always results in the latter holding a “proxy to a proxy” – a special object that forwards property access to a managed proxy to the original script object.</p>

<p>The overhead of that arrangement is usually unavoidable, as script engines generally can’t be given direct access to foreign script objects.</p>

<p>However, there are specific scenarios in which alternate means of sharing are not only possible but preferable. ClearScript 7.2 enables the following exceptions to the normal behavior.</p>

<h1 id="engines-that-share-a-v8-runtime">Engines That Share a V8 Runtime</h1>

<p>Consider the following C# code:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">using</span> <span class="nn">var</span> <span class="n">runtime</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">V8Runtime</span><span class="p">();</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">engine1</span> <span class="p">=</span> <span class="n">runtime</span><span class="p">.</span><span class="nf">CreateScriptEngine</span><span class="p">();</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">engine2</span> <span class="p">=</span> <span class="n">runtime</span><span class="p">.</span><span class="nf">CreateScriptEngine</span><span class="p">();</span></code></pre></figure>

<p>This creates a V8 runtime with two script engines – an arrangement that looks something like this:</p>

<p><img src="/images/Two-Engines-One-Runtime.svg" alt="Two Engines One Runtime" /></p>

<p>Now let’s create a script object in one engine and copy a reference to the other:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">engine1</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="s">"foo = { bar: 123 }"</span><span class="p">);</span>
<span class="n">engine2</span><span class="p">.</span><span class="n">Script</span><span class="p">.</span><span class="n">foo</span> <span class="p">=</span> <span class="n">engine1</span><span class="p">.</span><span class="n">Script</span><span class="p">.</span><span class="n">foo</span><span class="p">;</span></code></pre></figure>

<p>Executing this code in ClearScript 7.1 or earlier results in the following:</p>

<p><img src="/images/Two-Engines-One-Runtime-Double-Proxy.svg" alt="Two Engines One Runtime Double Proxy" /></p>

<p>With this setup, <code class="language-plaintext highlighter-rouge">foo</code> in <code class="language-plaintext highlighter-rouge">engine2</code> is very expensive to access and may be missing some functionality. For example, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols">JavaScript iteration protocols</a> can’t be routed through the managed proxy.</p>

<p>This “double proxy” construction is usually required, as different script engines generally can’t access each other’s objects directly. In this instance, however, they can do just that – safely and without ClearScript’s involvement.</p>

<p>ClearScript 7.2 detects this case and produces the following configuration for the same code:</p>

<p><img src="/images/Two-Engines-One-Runtime-Shared-Object.svg" alt="Two Engines One Runtime Shared Object" /></p>

<p>All script engines in the same V8 runtime can be given direct access to each other’s objects with full functionality, performance, and safety.</p>

<h1 id="v8-shared-array-buffers-and-views">V8 Shared Array Buffers and Views</h1>

<p>Suppose you create two V8 script engines, each within its own runtime:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="k">using</span> <span class="nn">var</span> <span class="n">engine1</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">V8ScriptEngine</span><span class="p">();</span>
<span class="k">using</span> <span class="nn">var</span> <span class="n">engine2</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">V8ScriptEngine</span><span class="p">();</span></code></pre></figure>

<p>In memory, this setup looks something like this:</p>

<p><img src="/images/Two-Engines-Two-Runtimes.svg" alt="Two Engines Two Runtimes" /></p>

<p>Normally, script engines in separate runtimes can’t share objects. However, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer"><code class="language-plaintext highlighter-rouge">SharedArrayBuffer</code></a> was designed specifically for sharing memory across runtimes.</p>

<p>ClearScript 7.1 and earlier don’t support this form of sharing. Let’s say you create a shared array buffer in one script engine and copy a reference to the other:</p>

<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="n">engine1</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="s">"sab = new SharedArrayBuffer(1024)"</span><span class="p">);</span>
<span class="n">engine2</span><span class="p">.</span><span class="n">Script</span><span class="p">.</span><span class="n">sab</span> <span class="p">=</span> <span class="n">engine1</span><span class="p">.</span><span class="n">Script</span><span class="p">.</span><span class="n">sab</span><span class="p">;</span></code></pre></figure>

<p>In ClearScript 7.1 and earlier, this code results in the following:</p>

<p><img src="/images/Two-Engines-Two-Runtimes-Double-Proxy.svg" alt="Two Engines Two Runtimes Double Proxy" /></p>

<p>In this configuration, <code class="language-plaintext highlighter-rouge">sab</code> in <code class="language-plaintext highlighter-rouge">engine2</code> is a “double proxy” that really isn’t very useful. For example, you can’t create <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView">data views</a> or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray">typed arrays</a> on top of it. Additionally, it incurs a lot of overhead, as all access is routed through the host back to <code class="language-plaintext highlighter-rouge">engine1</code>.</p>

<p>However, the same code in ClearScript 7.2 results in this:</p>

<p><img src="/images/Two-Engines-Two-Runtimes-Shared-Backing-Store.svg" alt="Two Engines Two Runtimes Shared Backing Store" /></p>

<p>This arrangement supports the full functionality and performance of shared array buffers in both script engines, with independent access to the shared backing store.</p>

<p>Finally, note that shared data views and typed arrays – that is, data views and typed arrays backed by shared array buffers – are also marshaled in this manner, enabling easy memory sharing across V8 runtimes. You can use the standard <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics"><code class="language-plaintext highlighter-rouge">Atomics</code></a> object to synchronize access to these resources.</p>

<p>Good luck!</p>]]></content><author><name>ClearScript Library</name><email>clearscript@clearfoundry.net</email></author><summary type="html"><![CDATA[ClearScript 7.2 includes enhancements for sharing objects across V8 script engines and runtimes.]]></summary></entry><entry><title type="html">Welcome to the ClearScript Blog!</title><link href="https://clearscript.clearfoundry.net/2022/01/09/welcome-to-the-blog.html" rel="alternate" type="text/html" title="Welcome to the ClearScript Blog!" /><published>2022-01-09T00:00:00+00:00</published><updated>2022-01-09T00:00:00+00:00</updated><id>https://clearscript.clearfoundry.net/2022/01/09/welcome-to-the-blog</id><content type="html" xml:base="https://clearscript.clearfoundry.net/2022/01/09/welcome-to-the-blog.html"><![CDATA[<p>Sometimes release notes and API documentation aren’t enough.</p>

<p>We’d like to use this space for in-depth articles on ClearScript features, significant changes, and user-requested topics. Please feel free to suggest topics on the project’s <a href="https://github.com/ClearFoundry/ClearScript/issues">Issues</a> or <a href="https://github.com/ClearFoundry/ClearScript/discussions">Discussions</a> pages.</p>

<p>Thanks for visiting!</p>]]></content><author><name>ClearScript Library</name><email>clearscript@clearfoundry.net</email></author><summary type="html"><![CDATA[Sometimes release notes and API documentation aren’t enough.]]></summary></entry></feed>