-
Notifications
You must be signed in to change notification settings - Fork 236
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Java script engine switcher and highlight js (#452)
* Adds server-side code block formatting This applies the highlight.js highlighting on the server allowing the client side script to be dropped. It does this using the MsieJavaScriptEngine to execute the script. The script itself is actually the node version, but I applied browserify to it so that it wouldn't require node anymore. Kind of a hack, but it works. I included the steps I took to build the file in regenerating-highlight-all.js so that it could be updated in the future with a newer version. * Uses ThreadLocal<MsieJsEngine> to reuse JS engine MsieJsEngine is certainly not thread safe so I was rebuildingi t from scratch within the loop. No sense in doing that, so switch the code to use a ThreadLocal instance to pool the JS instances between threads. Not a huge win for small sites, but for a 1000 document test run it went from 15s to 1s on my machine. * Adds test for auto-highlighting Adds a test where the code block doesn't have a language and highlightAuto must be called. This not only covers that scenario but is an important test case for javascript execution engines. Because highlight.js doesn't know the language it must iterate through the languages it is configured with and check them one by one using regular expressions. These have a wide variety of implementations so it actually provides a good test case for a javascript languages regex support. It seems anything doing JS -> IL starts to fall short here due to the differences in supported Regex escaping and language features. And with regex being a huge part of linting and text manipulation supporting regex is a vital part of evaluating a JS engine. * Adds JavaScriptEngineSwitcher for javascript processing Adds the following packages to Core * JavaScriptEngineSwitcher - an abstraction around common JS processing libraries * JsPool - a pool around the engine switcher. We'll be creating these a lot potentially so good pooling is a must * Jint - managed implementation of a javascript processor. We'll make this the default. * JavaScriptEngineSwitcher.Jint - allows Jint to be plugged into the JavaScriptEngineSwitcher For a module that wants to use the javascript engine it's pretty simple. They just need to call GetJsEngineFromPool off of the context. When they are done then must call ReturnJsEngineToPool, This exposes more or less the same interface as IJsEngine from the JavaScriptEngineSwitcher so it should be easy to find help and examples for devs to work with. The implementation is just a wrapper of the default implementation plus a couple of helpers around ensuring libraries only get loaded once per engine. Things get tricky in two spots 1. Testing. With this being exposed off of IExecutionContext the TestContext project needed some implementation. Rather than bring in a JS engine here too I made it a Func<> that could be set to a factory for building up the JsEngine by the test. I added a Wyam.Tests.JavaScript with an implementation of an engine that could be used for testing. It's just a copy and paste from Wyam.Core but it does allow test projects to be able to avoid needing to reference Core just to get some JS processing to work 2. Reloading the configuration. Because the configuration could potentially change the JS engine it needed the ability to wipe the singleton that JavaScriptEngineSwitcher uses. Had to add a couple static methods off of Engine and ExecutionContext to get those settings cleared out properly. * Marks CanHighlightAutoCodeBlocks as Ignored Test is failing due to Jint's regex implementation, but is still valuable to keep around for testing those fixes in the future * Removes escaping of @ in code blocks This was escaping ALL @ signs in the document instead of just the ones in the code blocks. Not good for things like actual javascript and the such. I tried to get AngularSharp to be nice and let me escape it via the InnerHtml but they insisted on changing it back. Taking a step back I realized all of this is foolish. This should really only be called after Razor is invoked. Added a test to make sure the highlighting is cool with the escaped html in a code block razor will generate. * Tweaks highlight.js to have more .net compliant regex The ADA and Lisp languages used some regex syntax that .Net couldn't handle. By changing this it allows Jint to run successfully.
- Loading branch information
1 parent
ac03425
commit 6ab96dc
Showing
29 changed files
with
17,064 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
using System; | ||
using System.Reflection; | ||
using System.Text; | ||
|
||
namespace Wyam.Common.JavaScript | ||
{ | ||
/// <summary> | ||
/// Defines a interface of JS engine | ||
/// </summary> | ||
public interface IJsEngine : IDisposable | ||
{ | ||
/// <summary> | ||
/// Gets the name of JS engine | ||
/// </summary> | ||
string Name | ||
{ | ||
get; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the version of original JS engine | ||
/// </summary> | ||
string Version | ||
{ | ||
get; | ||
} | ||
|
||
/// <summary> | ||
/// Evaluates an expression | ||
/// </summary> | ||
/// <param name="expression">JS-expression</param> | ||
/// <returns>Result of the expression</returns> | ||
object Evaluate(string expression); | ||
|
||
/// <summary> | ||
/// Evaluates an expression | ||
/// </summary> | ||
/// <typeparam name="T">Type of result</typeparam> | ||
/// <param name="expression">JS-expression</param> | ||
/// <returns>Result of the expression</returns> | ||
T Evaluate<T>(string expression); | ||
|
||
/// <summary> | ||
/// Executes code | ||
/// </summary> | ||
/// <param name="code">Code</param> | ||
void Execute(string code); | ||
|
||
/// <summary> | ||
/// Executes code from JS-file. If the file should only be loaded once per lifetime of the | ||
/// JsEngine, see <see cref="RequireFile"/> | ||
/// </summary> | ||
/// <param name="path">Path to the JS-file</param> | ||
/// <param name="encoding">Text encoding</param> | ||
void ExecuteFile(string path, Encoding encoding = null); | ||
|
||
/// <summary> | ||
/// Executes code from embedded JS-resource. If the resource should only be loaded once per lifetime of the | ||
/// JsEngine, see <see cref="RequireResource"/> | ||
/// </summary> | ||
/// <param name="resourceName">The case-sensitive resource name without the namespace of the specified type</param> | ||
/// <param name="type">The type, that determines the assembly and whose namespace is used to scope | ||
/// the resource name</param> | ||
void ExecuteResource(string resourceName, Type type); | ||
|
||
/// <summary> | ||
/// Executes code from embedded JS-resource. If the resource should only be loaded once per lifetime of the | ||
/// JsEngine, see <see cref="RequireResource"/> | ||
/// </summary> | ||
/// <param name="resourceName">The case-sensitive resource name</param> | ||
/// <param name="assembly">The assembly, which contains the embedded resource</param> | ||
void ExecuteResource(string resourceName, Assembly assembly); | ||
|
||
/// <summary> | ||
/// Calls a function | ||
/// </summary> | ||
/// <param name="functionName">Function name</param> | ||
/// <param name="args">Function arguments</param> | ||
/// <returns>Result of the function execution</returns> | ||
object CallFunction(string functionName, params object[] args); | ||
|
||
/// <summary> | ||
/// Calls a function | ||
/// </summary> | ||
/// <typeparam name="T">Type of function result</typeparam> | ||
/// <param name="functionName">Function name</param> | ||
/// <param name="args">Function arguments</param> | ||
/// <returns>Result of the function execution</returns> | ||
T CallFunction<T>(string functionName, params object[] args); | ||
|
||
/// <summary> | ||
/// Сhecks for the existence of a variable | ||
/// </summary> | ||
/// <param name="variableName">Variable name</param> | ||
/// <returns>Result of check (true - exists; false - not exists</returns> | ||
bool HasVariable(string variableName); | ||
|
||
/// <summary> | ||
/// Gets the value of variable | ||
/// </summary> | ||
/// <param name="variableName">Variable name</param> | ||
/// <returns>Value of variable</returns> | ||
object GetVariableValue(string variableName); | ||
|
||
/// <summary> | ||
/// Gets the value of variable | ||
/// </summary> | ||
/// <typeparam name="T">Type of variable</typeparam> | ||
/// <param name="variableName">Variable name</param> | ||
/// <returns>Value of variable</returns> | ||
T GetVariableValue<T>(string variableName); | ||
|
||
/// <summary> | ||
/// Sets the value of variable | ||
/// </summary> | ||
/// <param name="variableName">Variable name</param> | ||
/// <param name="value">Value of variable</param> | ||
void SetVariableValue(string variableName, object value); | ||
|
||
/// <summary> | ||
/// Removes a variable | ||
/// </summary> | ||
/// <param name="variableName">Variable name</param> | ||
void RemoveVariable(string variableName); | ||
|
||
/// <summary> | ||
/// Embeds a host object to script code | ||
/// </summary> | ||
/// <param name="itemName">The name for the new global variable or function that will represent the object</param> | ||
/// <param name="value">The object to expose</param> | ||
/// <remarks>Allows to embed instances of simple classes (or structures) and delegates.</remarks> | ||
void EmbedHostObject(string itemName, object value); | ||
|
||
/// <summary> | ||
/// Embeds a host type to script code | ||
/// </summary> | ||
/// <param name="itemName">The name for the new global variable that will represent the type</param> | ||
/// <param name="type">The type to expose</param> | ||
/// <remarks> | ||
/// Host types are exposed to script code in the form of objects whose properties and | ||
/// methods are bound to the type's static members. | ||
/// </remarks> | ||
void EmbedHostType(string itemName, Type type); | ||
|
||
/// <summary> | ||
/// Ensures a resource is loaded for this engine. If it is already | ||
/// loaded then nothing is executed. | ||
/// </summary> | ||
/// <param name="resourceName">Name of the resource.</param> | ||
/// <param name="type">The type.</param> | ||
void RequireResource(string resourceName, Type type); | ||
|
||
/// <summary> | ||
/// Ensures a resource is loaded for this engine. If it is already | ||
/// loaded then nothing is executed. | ||
/// </summary> | ||
/// <param name="path">The path is load.</param> | ||
void RequireFile(string path); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.