I write a package wrapper for Meteorjs.
package.js have this line:
api.addFiles('my-package.js', 'client');
that successfully adds global property MyPackage to window object.
MyPackage property is a function.
If I add api.export(['MyPackage'], 'client'); though, MyPackage on window object becomes undefined instead. Any hints?
related to https://github.com/meteor/meteor/issues/4105
It is work as intended at the moment, as was explained by meteor team.
Reason was I was using this to initialize and assign lib variables, but you don't permitted to do this and assign like MyLib = {} (globally without any objects) instead.
Related
I'm writing a ts transformer that finds named class decorator then replace decorator's call and passes a map with names and types of all props of decorated class, e.g.:
source file:
import BigNumber from "bignumber.js";
#decorator()
class AClass {
aProp: BigNumber;
}
output:
import BigNumber from "bignumber.js";
#decorator({"aProp": BigNumber})
class AClass {
aProp: BigNumber;
}
I'm getting prop name and type from PropertyDeclaration:
const clazzProps = [];
for (const childNode of clazz.members) {
if (ts.isPropertyDeclaration(childNode)) {
const type = typeChecker.getTypeAtLocation(childNode);
if (type.isClass()) {
clazzProps.push(ts.createPropertyAssignment(
ts.createIdentifier(childNode.name.getText()),
childNode.type.typeName
);
}
}
}
So far so good, however after compilation import statement is removed from output js file, cause in the source file BigNumber was only referenced as a type, not as a value. My question is, how to properly check if BigNumber is not a type only and make sure that import will not be stripped ?
I know it's a bit late, but still.
Typescript compiler has four main phases—parsing, binding, type checking, and emitting. Binding is where the relationships between identifiers are resolved, but transformation happens during the "emitting" phase.
That means on a moment when transform happened typescript already know that BigNumber is used only as type in this context and following it's own rules all imports which point only to type is not emitted to js.
Unfortunately, there is no simple solution and you probably will be needed to add this imports by yourself during the transform.
The same use-case and problem was solved here https://github.com/nestjs/graphql/blob/master/lib/plugin/visitors/model-class.visitor.ts
It's resolving types of property using type checker and finding the file this type pointint to and store this paths in importsToAddPerFile, than in updateImports the are added to the source file.
I'm generally not recommending using a TypeChecker (it's slower, might not be available in some context and can produce weird results if you have few transform relying on it) in transforms and probably for simple cases you can just read what imports you already have and re-create them manually.
In my custom module, I would like to call uc_quote_request_quotes() (for testing purposes). The module has obviously not been loaded yet because when I try to call it, I get an error:
Fatal error: Call to undefined function uc_quote_request_quotes()...
tf_common.module
function tf_common_test()
{
module_load_include('module', 'uc_quote');
uc_quote_request_quotes();
}
In uc_quotes.pages.inc I have the function defined
function uc_quote_request_quotes() {
//code
}
EDIT:
I had to change the module_load_include line to be module_load_include('inc', 'uc_quote', 'uc_quote.pages');
but that makes me question:
Is there a way to load the entire module or do I have to load each file individually like this?
I don't really want to change the info file to make the other module a dependency because this is only needed as a test function.
The reason uc_quote_request_quotes() isn't available to the tf_common module is because the uc_quote module is loaded after tf_common is. Look into changing the weight of the tf_common module to be loaded after or change uc_quote to be loaded before.
I'm developing a test frameword where I want to reset all collections on each run.
I'm having problems doing this with Meteor.users, since it's undefined on the package environment.
Is there any workaround to clean the Meteor.users collection from within a package?
The package load order and exported variables matter when it comes to symbol availability in packages.
In order to get a symbol created in a package, it has to be loaded prior to your package. This can be achieved by depending on it or on some other package that depends on it.
Examples of such symbols are methods added to the Meteor object, and this is what is happening in your case.
api.use('some-package'); // some-package is the desired package or depends on it
In order to get a symbol that is exported by a package, you should either directly depend on it, or depend on a package that implies this package (or explicitly exports the symbol on its own as well).
api.use('some-package'); // some-package exports the symbol directly or by implying
You can make this dependency weak if you don't want the package to be added to the bundle if your package is the only one that depends on it (i.e, there are no other packages that strongly depend on it, and the user did not add it as a top-level dependency).
api.use(['some-package'], ['client', 'server'], {weak: true});
If you need to do something after all of the packages have loaded, you can do so with Meteor.startup():
Meteor.startup(function() {
//do stuff after all packages and code were loaded
});
You can put some 'reset logic' on users collection,
Meteor.users.allow({
remove:function() {
resetLogic(); });
please check http://docs.meteor.com/#/full/allow for the reference
I have some tinytests, simple server unit tests.
Separately they run fine, but if i run them together I get errors on my collections.
What else might cause an error like the below?
I think its related to defining the exports in a JS file and the other classes in coffeescript and some scoping issue is complicating things. "Told you not to use coffeescript" i hear. But then again, it maybe something else!
os.osx.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:245
W20150418-17:39:20.312(-7)? (STDERR) throw(ex);
^
Error: A method named '/Profiles/insert' is already defined
at packages/ddp/livedata_server.js:1461:1
at Function._.each._.forEach (packages/underscore/underscore.js:113:1)
at [object Object]._.extend.methods (packages/ddp/livedata_server.js:1459:1)
at [object Object].Mongo.Collection._defineMutationMethods (packages/mongo/collection.js:90
at new Mongo.Collection (packages/mongo/collection.js:209:1)
at [object Object].Meteor.Collection (packages/dburles:collection-helpers/collection-helper
at __coffeescriptShare (packages/local-test:dcsan:mpgames/lib/exports.js:2:1)
at /private/var/folders/lw/6kdr1_9j3q1ggldr_c798qy80000gn/T/meteor-test-run126tw73/.meteor/
FWIW the app has no problems running, its just the tests that fail.
This error means you defined the Profiles collection more than once. My strategy in dealing with this problem has been to:
Use a global definition via api.export for any collections which actually should be defined by a package (e.g. if the posts package defined a Posts collection).
Define all other collections needed by the test with a null collection name (unmanaged) and use a reset like the following before each test:
var resetCollection = function(name) {
var Collection = this[name];
if (Collection)
// if the collection is already defined, remove its documents
Collection.remove({});
else
// define a new unmanaged collection
this[name] = new Mongo.Collection(null);
};
So if you call resetCollection('Posts') it would only define a new collection if needed and ensure its documents were removed. This way, you'll avoid multiple definitions and you'll start with a clean DB each time.
From what I have seen using a debugger, calling:
require(["menu/main-menu"], function(util) {
Will load the main-menu.js file, but the function is called before the global code in the required .js file is executed? Is this correct?
If so, what is the best way to have all that code executed before my function is called?
The problem I am trying to solve is I want the code in mani-menu.js to all be in a module. But I can't call any method in that module until the global code in there is executed which creates the module.
I can call a global method in there which then creates everything, but that then requires a global init() method in every .js file (each with a unique name).
What's the best way to handle all this?
Update: There's a more basic question here (maybe). In writing javascript (and I use Sencha Ext JS & TypeScript), I need to create my objects. So when I go to create say my main menu, I want to call a method in my main-menu.js file to get that Ext JS derived menu object I created.
I think all the code in main-menu.js should be in a namespace, including the method I call to get the menu object. Is that correct? In addition, the way most Ext JS code is set up is you have several Ext.define() calls as well as other variable instantiations, and then the function that takes all that, builds the full menu, and returns it. But that requires all that code has executed in main-menu.js before I call it.
Am I approaching this correctly? My experience to date is Java & C# and I may be trying to fit that model incorrectly to javascript.
Let's suppose menu/main-menu.js contains this:
define(function () {
// Module factory function
return [... whatever you want to expose...];
});
And your application does this:
require(["menu/main-menu"], function (util) {
// Require callback.
});
What happens is:
The require call loads menu/main-menu.js.
The define in menu/main-menu.js is executed.
The module factory function (the function passed to define) is executed.
The require callback is executed with the symbol util set to
what the factory function in menu/main-menu.js returned.
As for simulating namespaces, there are multiple ways to do it. For
instance, you can do it like this:
define(function () {
return {
foo: function () {},
bar: function () {},
[...]
};
});
This exports an object with two functions in it. You can then use it
like this:
require(["menu/main-menu"], function (util) {
util.foo();
util.bar();
});
RequireJS also supports a CommonJS-style of defining modules:
define(function (require, exports, module) {
exports.foo = function () {};
exports.bar = function () {};
[...]
});
This is functionally equivalent to the first way I defined the module
earlier: you get the same two functions and you use them in the same
way as I've shown above.
Unfortunately, I can't speak about Ext JS specifically because I don't
use it.