I'm writing a nodeJs application that uses google flat buffer.
I installed flatc on my macbook pro and compiled the following schema:
namespace MyAlcoholist;
table Drink {
drink_type_name: string;
drink_company_name: string;
drink_brand_name: string;
drink_flavor_type_name : string;
liquid_color_type_name : string;
liquid_color_is_transparent : bool;
alcohol_vol : float;
calories_for_100g : uint;
global_image_id: ulong;
drink_flavor_id: ulong;
}
table Drinks { drinks:[Drink]; }
root_type Drinks;
the schema file is called drink.fbs and it generated a javascript file called drink_generated.js
I include this file in my nodejs application and add data to it using the following code.. this is my flatBufferUtil.js utility file.
var flatbuffers = require('../js/flatbuffers').flatbuffers;
var builder = new flatbuffers.Builder();
var drinks = require('../fbs/drinks_generated').MyAlcoholist; // Generated by `flatc`.
function drinkArrayToBuffer(drinkArray) {
var drinksVectArray = [];
drinkArray.forEach(function (element, index, array) {
var drinkObj = element;
var drinkBrandName = builder.createString(drinkObj.drink_brand_name);
var drinkCompanyName = builder.createString(drinkObj.drink_company_name);
var drinkflavorTypeName = builder.createString(drinkObj.drink_flavor_type_name);
var drinkTypeName = builder.createString(drinkObj.drink_type_name);
var liquidColorTypeName = builder.createString(drinkObj.liquid_color_type_name);
drinks.Drink.startDrink(builder);
drinks.Drink.addAlcoholVol(builder, drinkObj.alcohol_vol);
drinks.Drink.addCaloriesFor100g(builder,drinkObj.calories_for_100g);
drinks.Drink.addDrinkBrandName(builder,drinkBrandName);
drinks.Drink.addDrinkCompanyName(builder,drinkCompanyName);
drinks.Drink.addDrinkFlavorId(builder,drinkObj.drink_flavor_id);
drinks.Drink.addDrinkFlavorTypeName(builder, drinkflavorTypeName);
drinks.Drink.addDrinkTypeName(builder,drinkTypeName);
drinks.Drink.addGlobalImageId(builder,drinkObj.global_image_id);
drinks.Drink.addLiquidColorIsTransparent(builder,drinkObj.is_transparent);
drinks.Drink.addLiquidColorTypeName(builder,liquidColorTypeName);
var drink = drinks.Drink.endDrink(builder);
drinksVectArray.push(drink);
})
var drinksVect = drinks.createDrinksVector(builder,drinksVectArray);
builder.finish(drinksVect);
var buf = builder.dataBuffer();
return buf;
}
module.exports.drinkArrayToBuffer=drinkArrayToBuffer;
now when I execute this function it fails with the error flatbuffers is not defined.
I debugged my code and I saw that it files on the following line of code:
drinks.Drink.addDrinkFlavorId(builder,drinkObj.drink_flavor_id);
if i get inside addDrinkFlavorId function i see this code in drinks_generted.js:
MyAlcoholist.Drink.addDrinkFlavorId = function(builder, drinkFlavorId) {
builder.addFieldInt64(9, drinkFlavorId, flatbuffers.Long.ZERO);
};
as you can see it uses flatbuffers.Long.ZERO but flatbuffers is not defined in that file at all. the compilation did not provide any errors so what do I miss?
It seems to me like it is a bug... The generated file appears to be meant to exist autonomously from the flatbuffers require. However for the custom flatbuffers.Long class, the default of flatbuffers.Long.ZERO bleeds into the generated file.
While this isn't a solution per-say, one workaround is to manually add the flatbuffers require to the generated file; it's ugly, but it might be better than being blocked until a more appropriate answer (or fix) comes around.
// In `drinks_generated.js`
var flatbuffers = require('../js/flatbuffers').flatbuffers;
Note:
The drinks.Drink.addDrinkFlavorId() and drinks.Drink.addGlobalImageId() functions expect flatbuffers.Long values to be passed into them, because they were specified as ulong in the schema (fbs file). So you will need to ensure that you are not trying to pass in a simple number type.
For example:
var my_long = flatbuffers.Long(100, 0); // low = 100, high = 0
drinks.Drink.addDrinkFlavorId(builder, my_long);
As a result, another possible workaround is to change the datatype of those fields in the schema to avoid using ulong until it becomes more clear what is going on here.
P.S. I am pretty sure drinks.createDrinksVector on line 30 of that snippet should be drinks.Drinks.createDrinksVector.
Related
I have some code in a web worker that is working perfectly locally, but as soon as I build and deploy (which minifies the code) it no longer works.
The unminified code looks like this:
const mapSourceCode = (treeNode, mfi, {objectType, types, fileType, templateType}) => {
let sourceCodeMap = new Map();
let ownerMap = new Map();
let sourceCodeList = [];
let ownerList = [];
let mfiMap = new Map();
mfi.forEach(row => mfiMap.set(row.uuid, row));
let sourceCodeObjects = mfi.filter(row => types.includes(row.objectTypeUuid));
if(sourceCodeObjects.length < 1)
return {sourceCodeMap, sourceCodeTree: undefined};
try {
sourceCodeObjects.forEach(sourceObj => {
let owner = findOwner(sourceObj, sourceObj, mfiMap, {...treeNode.data}, objectType);
The minified code is this:
i = function(e, t, n) {
var c = n.objectType
, o = n.types
, i = n.fileType
, u = n.templateType
, l = new Map
, s = new Map
, f = []
, p = []
, m = new Map;
t.forEach((function(e) {
return m.set(e.uuid, e)
}
));
var h = t.filter((function(e) {
return o.includes(e.objectTypeUuid)
}
));
if (h.length < 1)
return {
sourceCodeMap: l,
sourceCodeTree: void 0
};
try {
if (h.forEach((function(n) {
var r = a(n, n, m, Object(d.a)({}, e.data), c);
The line it's erroring out on is {...treeNode.data} on the last line.
The error is ReferenceError: d is not defined
I can't figure out what the issue could be? Like I said everything runs great on locally. Any help is greatly appreciated
I found the issue, in case anybody runs into this same thing.
Normally when using web workers you need to tell your builder (webpack) to build / compile workers separately. I'm using the default create-react-app configuration which doesn't give access to that part of webpack. unless you eject from create-react-app completely (which I'm currently not ready to do)
I'm using the react hook called useWorker, where I pass the function I want to allocate to the worker.
When your code is optimized and minified variable names are replaced with smaller names (mostly 1 or 2 letters from what I've seen). Because I didn't have any custom loaders to load my worker code, it used variables from the global scope assuming it would have access. When the code was extracted to a separate thread outside the main thread it no longer had access to those variables and thus didn't work.
The fix is to
Add a loader (you can either eject from create-react-app, or there may be some npm libraries that will give you access to that particular part of webpack)
Or my solution was to create the function in a string and create a function using the Function constructor like so
const generateFunction = new Function('treeNode', 'mfi', 'types', 'action', generateFunctionString);
Where the generateFunctionString was a string like: "return a + b"
I then passed that function into my useWorker hook:
const [generatorWorker] = useWorker(generateFunction);
I need to build a js file from sjsir files at runtime to implement a system of plugins, so that it can't be done at compile time with the rest of my compilation. I used to implement the same process in 0.6.3 with the following code, but it seems to be deprecated. What algorithm do you recommand to achieve the same action with 0.6.13 ?
Thanks
val scalajsLib = copyJar("scalajs-library_2.11-0.6.3")
val semantics = org.scalajs.core.tools.sem.Semantics.Defaults
val partialClasspath =
PartialClasspathBuilder.build(collection.immutable.Seq(scalajsLib, src))
val completeClasspath = partialClasspath.resolve()
val optimizer = new ScalaJSOptimizer(semantics)
val logger = new ScalaConsoleLogger
val out = WritableFileVirtualJSFile(
new java.io.File(target, JS_FILE))
if (optimized) {
val sems = semantics.optimized
new ScalaJSClosureOptimizer(sems).optimizeCP(
new ScalaJSOptimizer(sems),
completeClasspath,
ScalaJSClosureOptimizer.Config(out),
logger
)
} else {
optimizer.optimizeCP(
completeClasspath,
ScalaJSOptimizer.Config(out, checkIR = false, wantSourceMap = !optimized),
logger
)
}
The Tools API has dramatically changed in 0.6.5, indeed. It became much simpler and more able to evolve in non-breaking ways in the future.
Your code above can be written with the new API as follows:
import java.io.File
import org.scalajs.core.tools.io._
import org.scalajs.core.tools.sem._
import org.scalajs.core.tools.linker.backend.{OutputMode, ModuleKind}
import org.scalajs.core.tools.linker.Linker
import org.scalajs.core.tools.logging.ScalaConsoleLogger
def link(inputClasspath: Seq[File], outputJSFile: File): Unit = {
// Obtain VirtualScalaJSIRFile's from the input classpath
val irCache = new IRFileCache().newCache
val irContainers = IRFileCache.IRContainer.fromClasspath(inputClasspath)
val sjsirFiles = irCache.cached(irContainers)
// A bunch of options. Here we use all the defaults
val semantics = Semantics.Defaults
val outputMode = OutputMode.Default
val moduleKind = ModuleKind.NoModule
val linkerConfig = Linker.Config()
// Actual linking
val linker = Linker(semantics, outputMode, moduleKind, linkerConfig)
val logger = new ScalaConsoleLogger
linker.link(sjsirFiles, WritableFileVirtualJSFile(outputJSFile), logger)
}
And you can call that link function with the following arguments, to exactly match your above snippet:
link(Seq(scalajsLib, src), new java.io.File(target, JS_FILE))
If you intend to call this method several times on the same classpath within the same process, it is advised to cache and reuse the instances irCache and linker across runs, as this will considerably speed up the process.
See also the Scaladoc of the Tools API.
Is there a way to prevent from errors about class repetition in the batch of sjsir (which generates the message: XXX already seen) at link time ? I guess it is, since this error does not occur when the build is done at compile time from the build.sbt.
Has anyone deduced syntax which successfully loads XML from file/string and gives access to the data in OS X Yosemite (10.10) Javascript for Automation ?
Documentation and code samples are still fairly thin (as of Nov 2014), and my inductive skills are running dry on three separate approaches to reading an XML (OPML) file at the moment:
Most promising: $.NSXMLDocument
Getting hold of the string data in various ways goes well,
function readTextFromFile(strPath) {
return $.NSString.stringWithContentsOfFile(strPath);
}
function readDataFromFile(strPath) {
return $.NSData.alloc.initWithContentsOfFile(strPath);
}
function filePath(strPath) { return Path(strPath); }
But no permutations on this theme have borne fruit:
var strPath='/Users/houthakker/Desktop/notes-2014-11-04.opml',
dataXML = readData(strPath),
strXML = readTextFile(strPath),
oXMLDoc1, oXMLDoc2;
oXMLDoc1 = $.NSXMLDocument.alloc.initWithXMLString(strXML,0,null);
oXMLDoc2 = $.NSXMLDocument.alloc.initWithData(dataXML,0,null);
(the 'function undefined' error messages suggest that those two init functions may not be exposed, though initWithRootElement() does seem to be)
Most progress: $.NSXMLParser
var oParser = $.NSXMLParser.alloc.initWithData(dataXML);
return oParser.parse; //true
But event-driven parsing seems to require some further complexities which remain opaque to me, and which may not match my simple needs (reading and converting modestly sized local OPML files).
Most familiar: Application("System Events")
In Applescript this can be done with System Events code:
set fOPML to (POSIX file "/Users/houthakker/Desktop/notes-2014-11-04.opml" as alias) as string
tell application "System Events"
tell XML file fOPML
-- now access XML Elements by name or index
end tell
but I haven't found a successful javascript idiom for initializing the XMLFile object with any permutation of a unix Path(), string, or colon-delimited mac path string.
Any thoughts or more successful experience here ?
This turns out to work for the (very slow executing) Application("System Events") route:
var app = Application("System Events"),
strPath = '~/Desktop/summarise.opml';
var oFile = app.xmlFiles[strPath],
oRoot = oFile.xmlElements[0],
oHead = oRoot.xmlElements.head,
oBody = oRoot.xmlElements.body,
lstOutlineXML = oBody.xmlElements.whose({
name: 'outline'
});
And the function for initialising an NSXMLDocument from an XML string is, according to the JSExport convention (in which the letter following each ":" is capitalized, and then the ":"s are removed) .initWithXMLStringOptionsError()
Thus, to choose a local OPML file and parse it to a simple JSON outline:
function run() {
var app = Application.currentApplication();
app.includeStandardAdditions = true;
function readTextFromFile(strPath) {
return $.NSString.stringWithContentsOfFile(strPath);
}
var strPath = (
app.chooseFile({withPrompt: "Choose OPML file:"})
).toString(), // Path → String
strXML = strPath ? readTextFromFile(strPath) : '';
if (!strXML) return;
var oXMLDoc1 = $.NSXMLDocument.alloc.initWithXMLStringOptionsError(strXML, 0, null),
oRoot = oXMLDoc1.rootElement,
oBody = ObjC.unwrap(oRoot.children)[1],
lstOutline = ObjC.unwrap(oBody.children),
lstParse, strJSON;
function parseOPML(lst) {
var lstParse=[], oNode, dctNode, lstChiln;
for (var i = 0, lng=lst.length; i<lng; i++) {
oNode = lst[i];
dctNode = {};
dctNode.txt = ObjC.unwrap(oNode.attributeForName('text').stringValue);
lstChiln = ObjC.unwrap(oNode.children);
if (lstChiln && lstChiln.length)
dctNode.chiln = parseOPML(lstChiln);
lstParse.push(dctNode);
}
return lstParse;
}
lstParse = parseOPML(lstOutline);
strJSON = JSON.stringify(lstParse,null, 2);
app.setTheClipboardTo(strJSON);
return strJSON;
}
I'm trying to save an Entity that was loaded using a classic WEBAPI ODATA service.
When saveChanges is called on the client side, the modified entity is found and then the code goes into ´createChangeRequests´ and because the entityState is modified it goes into the function :
function updateDeleteMergeRequest(request, aspect, prefix) {
var extraMetadata = aspect.extraMetadata;
var uri = extraMetadata.uri;
if (__stringStartsWith(uri, prefix)) {
uri = uri.substring(prefix.length);
}
request.requestUri = uri;
if (extraMetadata.etag) {
request.headers["If-Match"] = extraMetadata.etag;
}
}
However it raises an exception on the second line because extraMetadata is null. Where is this supposed to come from ? The property extraMetadata does not even exist on 'aspect'....
breeze does have metadata of my model since I can load entities. It's just that I cannot save.
line 13318(breeze.debug.js):
function mergeEntity(node, mappingContext, meta) {
node._$meta = meta;
meta.extra = node.__metadata;//added
var em = mappingContext.entityManager;
I just stumpled across the same problem with Breeze 1.4.13. I resolved the problem by adding meta.extraMetadata = node.__metadata in line 14396
function mergeEntity(mc, node, meta) {
node._$meta = meta;
meta.extraMetadata = node.__metadata;
var em = mc.entityManager;
Our application currently shares messages between the Java and Javascript side. They are stored as resource bundles in the class path, and we have a custom controller that returns all the messages as Json. The client side code look like this:
// This calls the controller to get all the messages
var messages = MessageBundle();
var text = messages.get('my.message', 1);
This is great because we can mock "messages" in our unit tests.
I want to start using JAWR for this, since we already use it for other things. The problem is JAWR generates the following Javascript object:
var text = messages.my.message(1);
This means the code cannot be unit tested anymore unless the unit tests also define a global "messages" variable with the right nested objects. Is there a way around this? Any idea how to extend JAWR to make this unit-testable?
Currently my work around is:
function messages() {
var args = Array.prototype.slice.call(arguments);
var messageId = args.shift();
var messageFunc = window.messages;
messageId.split('.').forEach(function(part) {
messageFunc = messageFunc[part];
});
return messageFunc(args);
}
// Same syntax as the old one, but uses the JAWR object behind the scenes
// This function is easy to mock for a unit test
var text = messages('my.message', 1);
Thanks for any ideas!
Maybe next samples can help you.
1)
function messagesTester(funcPath,id) {
var args=funcPath.split('.'),root=window.messages;
for(var i=0;i<args.length;i++)root=root[args[i]];
return root(id);
// or if more that one parameter for *func*, then, for example:
// return root.apply(null,Array.prototype.slice(arguments,1));
}
var text = messagesTester('my.message',1);
2)
function messagesTester(funcPath) {
var args=funcPath.split('.'),root=window.messages;
for(var i=0;i<args.length;i++)root=root[args[i]];
return root;
}
// var text = messagesTester('my.message')( /*arguments list*/ );
var text = messagesTester('my.message')(1);