Importing Proto File to another ProtoFile in NodeJS - javascript

I am quite new to Protocol Buffers.
I noticed that the grpc proto-loader module requires just a single proto definition file to load, so I have loaded it in my code as below:
const PROTO_PATH = `${path.resolve(__dirname, '..')}${path.sep}protos${path.sep}index.proto`;
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
let indexProto = grpc.loadPackageDefinition(packageDefinition).index;
Now my index.proto file is referencing another proto file
as below:
syntax = "proto3";
package index;
import public "location_updater.proto";
And my location_updater.proto is defined as below
syntax = "proto3";
package location_updater;
service LocationUpdater{
rpc updateLocation(Location) returns LocationUpdateResponse{}
}
message Location{
string apiKey = 1;
string updateTarget = 2;
double longitude = 3;
double latitude = 4;
}
message LocationUpdateResponse{
int32 statusCode = 1;
}
When I do the following:
let grpcServer = new grpc.Server();
grpcServer.addService(indexProto.location_updater.LocationUpdater.service, {
});
I am getting an error TypeError: Cannot read property 'LocationUpdater' of undefined
If I move the content of the location_updater.proto into to the index.proto file it works, but I don't want that behavior as I would be working with many different proto files for different business logic.
What am I doing wrong and what is the best way to go about this?.
Thanks in anticipation for your input.

You need to use the includeDirs option to include directories in the search paths, so that the proto loader library knows how to find the imported files. Those directories should be the ones that the import paths are relative to.
In this situation, assuming that location_updater.proto is in the same directory as index.proto, the includeDirs option should be an array containing the single path __dirname/../protos. Those directories can also be used to search for the main file, so you can pass a proto path that is just index.proto.

Related

Add functions in other folder, to an object in this folder

I want to create an object that would import functions from another folder and it would look something like this:
class = {
functions: {
//All functions here
}
}
The functions would be inside of a different folder, however, I want to make some sort of importer in which it would make new classes for each new function/file it finds inside of the folder.
someFunction.js Function File:
function someFunction() {
console.log("this is some function");
}
So I would like for something to look like this:
class.functions.someFunction()
No, I do not want to have it hard coded into the object, I want to import all functions from a folder and create functions like that.
Well, first I wan't to answer your question as I think you want, even if I also think it is not the correct way to proceed.
I'll also assume that with class you are not referring to an actual ES6 Class, but we are talking about a plain object.
So this is the code:
const fs = require('fs');
const path = require('path');
function importer(dirPath) {
const absoluteDirPath = path.normalize(
path.isAbsolute(dirPath)
? dirPath
: path.resolve(process.cwd(), dirPath)
);
const output = {
functions: {}
};
const content = fs.readdirSync(path.normalize(absoluteDirPath));
content.forEach((basename) => {
const absoluteItemPath = path.join(absoluteDirPath, basename);
if (fs.statSync(absoluteItemPath).isFile() && /\.js$/i.test(basename)) {
output.functions[basename.slice(-3)] = require(path.relative(
__dirname,
absoluteItemPath
));
}
});
return output;
}
module.exports = importer;
For this to work, all your functions in your files should be exported like:
module.exports = function myFunction() {};
To use the 'importer', you just do:
const artemis = importer('/path/to/directory'); // PATH MUST BE ABSOLUTE OR RELATIVE TO CWD.
/*
SUPPOSING THAT YOUR DIRECTORY CONTAINS THE FOLLOWING FILES:
function1.js
function2.js
Then you can do:
artemis.function1();
artemis.function2();
Please note that your files must be named in a JS friendly way (a valid string for an object key).
*/
A final important note about this odd method: This will only ever work in a NodeJS environment. Even if functions could have worked in other environments (like a browser). The next method, will work for any ECMAScript environment after proper building process: transpilation (EX: Babel) and bundling (EX: Webpack).
Suggested Solution
Use ES6 Static import / export like modern JS libraries do. This comes with huge benefits, from static code analysis to tree shaking and more.
Let's suppose the following hierarchy:
// - index.js
// - internals/
// - index.js
// - module-1.js
// - module-2.js
internals/module-1.js
function module1() {}
export {module1};
internals/module-2.js
import {module1} from 'module-1.js';
function module2() {
// YOU CAN USE module1 IF YOU NEED. (AVOID CIRCULAR REFERENCES)
module1();
}
export {module2};
internals/index.js
import {module1} from './module-1.js';
import {module2} from './module-2.js';
export {module1, module2};
index.js
import * as moduleGroup from './internals/index.js';
export {moduleGroup};
Finally, where you import your moduleGroup, you can do:
moduleGroup.module1();
moduleGroup.module2();
Obviously this is a basic scenario, but this is, IMHO, the correct way to deliver a group of functions and other stuff. Please let me know if you have any doubt.

How to handle external modules when writing unit tests for server-side Javascript

I am unit testing a JS file that has a require that points to an external module. How do I handle the external module when running UT if it keeps on looking for that external module locally?
I already tried mocking a function from the script, but I do not think that is the proper way to test its components. What I really want is for my test file to point to the script file, and that script file will either skip the call for the require part that calls the external modules OR find a way to override or ignore that line so that I can start referencing the functions and components I need in the script file for unit testing.
Deal.js
var cordra = require('cordra');
var util = require('util');
exports.beforeSchemaValidation = beforeSchemaValidation;
function beforeSchemaValidation(deal, context) {
...
return deal;
}
DealTest.js
var assert = require('chai').assert;
const beforeSchemaValidation = require('../rules/Deal').beforeSchemaValidation;
describe('Deal', function() {
it('beforeSchemaValidation should return object', function() {
let result = beforeSchemaValidation();
assert.typeOf(result, Object);
});
});
I want my test file to run through ../rules/Deal without getting a thrown error of Error: Cannot find module 'cordra' and/or 'util' so I can test the rest of its components.
You need to do it in following way :
var cordra = require('cordra');
var util = require('util');
function beforeSchemaValidation(deal, context) {
...
return deal;
}
module.exports = {
beforeSchemaValidation: beforeSchemaValidation }

TypeScript: Handling import from external libraries

I just started using Famo.us and wanted to use it as an opportunity to learn typescript at the same time to leverage on its awesomeness. So I did the following
Used yo famous to create the Famo.us project as per the documentation
I was not sure how to include typescript so I created a typeScriptHTML project, copies the .csproj file over and manually edited it. I tried using the NVTS and specified that it should create it from an existing folder but I always got an error saying that the file path was too long. It checked and some of the modules have very long path. Couldn't even delete them and the system was saying the same thing. In the end I discarded the idea and used the typescript html application. It generated no errors.
I added a file app.ts, wrote some sample code in it and it generated the js file as expected.
Now I wanted to translate main.js to main.ts and I'm stuck with the following issues
i. var Engine = require('famous/core/Engine'); gives the error could not find symbol 'require'.
ii. import Engine = require('famous/core/Engine') gives the error: Unable to resolve external module "famous/core/Engine". Changing the path to "../lib/famous/core/Engine" gives a similar error with a different file name.
iii. Created a file Famous.d.ts but I don't think I'm getting it I'm not doing something right
declare module "famous/core/Engine" {
class Engine{
public createContext(): Engine
}
export = Engine
}
In the end, my confusion is how to I translate the sample code to typescript:
/*globals define*/
define(function(require, exports, module) {
'use strict';
///first
var Engine = require('famous/core/Engine');
var DeviceView = require('./DeviceView');
var mainContext = Engine.createContext();
var device;
createDevice();
function createDevice() {
var deviceOptions = {
type: 'iphone',
height: window.innerHeight - 100
};
device = new DeviceView(deviceOptions);
mainContext.add(device);
}
});
Any assistance appreciated.
It turned out to be a lot easier than I thought. One way was to declare the class and export it as a module
declare class Engine{
...
}
export module 'famous/core/Engine'{ export = Engine; }
Manage to get a tiny definition of famous running using this.

How do I create a typescript object in javascript?

My worker-api.ts file is:
export class WorkerApi {
private worker:Worker;
constructor() {
this.worker = new Worker("layout-worker.js");
}
// more ...
}
And I am trying to create the in javascript as follows:
require(["../common/events.js", "worker-api.js"], function (events, worker) {
// worker is null so worker.WorkerApi() won't work either.
var api = new WorkerApi();
I also tried with internal modules so it was named MyModule.WorkerApi() - that also failed (we are using external modules for our .ts files).
What am I missing? I'm guessing I need to set something in the .ts file so the requires passes an object in function (events, worker) but can't find what it is.
thanks - dave
Remove the .js file extension I.e.
require(["../common/events", "./worker-api"]

use a typescript module/class in the browser and in the server (Node.Js)

How would I use the same typescript class or module in a client side javascript file and in a server side node.js file?
I found a solution here where you manually create the exports variable instead of using TypeScript's export keyword but then you lose the type information for the class when you include it in node.js with the require keyword.
You can cast what comes out of the require function since you know what it's going to be.
module Lib {
export class Alpha {
bravo: number = 1;
}
}
// meanwhile back at the ranch
var _lib = <Lib> require("Lib");
var a = new _lib.Alpha();

Categories

Resources