Namespace with autoloading files.
One object = one file.
Script is define global functions and object.
Object provides base methods to change behavior.
Change script debug status. If debug enabled script will log in console each operation with debug
level.
namespace.debug(true); // prefix defaults is '[namespace.js]'
Change default document event which indicates that script it's ready to run. Default event is DOMContentLoaded
.
namespace.listen('app.ready'); // Now will listen `app.ready` event and not run on `DOMContentLoaded`
Previous global alias for this method is listen
, but it's deprecated and will remove in future releases.
Register new autoloader paths, return path for specified name or return all paths.
namespace.autoload({ 'app': '/app' }); // This is register new autoloader path for `app.*` objects
namespace.autoload({ 'app': '/app' }, 'module'); // Will attach all scripts with type = 'module' (default is 'text/javascript')
console.log(namespace.autoload('app')); // Will return path for `app` - '/app'
console.log(namespace.autoload()); // Will return all registered paths - { 'app': '/app' }
Previous global alias for this method is autoload
, but it's deprecated and will remove in future releases.
Return filename by passed name. If filename is not resolved return null.
namespace.autoload({ 'app': '/app' });
console.log(namespace.resolve('app.App')); // Output - /app/App.js
Modify global require
function and allow it resolve filename by registered namespace. Available only for NodeJS.
namespace.autoload({ 'app': __dirname + '/app' }).resolveForRequire();
let app = require('app.App'); // Will require file by path __dirname + '/app/App.js'
let [ user, config ] = require([ 'app.model.User', 'app.Config' ]); // Will return array and unpack it to variables
Register global alias for internal object storage.
namespace.app('example'); // This will register global.example with all defined objects
// after this you can get all defined objects using global link
console.log(window.example); // Outputs internal storage
Define new namespace object.
namespace(
'app.components.Base',
[is('name.extend.object1', ['name.extend.object2'])],
[use('name.of.use.object1', ['name.of.use.object2'])],
['name.of.use.object3', ['name.of.use.object4']],
class | function() | { }
);
Function must contains two required arguments:
- name of the object (first argument -- arguments[0])
- object, function or class - factory of defined name (last argument -- arguments[arguments.length - 1])
namespace('app.components.Base', {
prop: "value"
});
namespace('app.components.Base', function() {
// This is constructor
});
namespace('app.model.Base', class {
db = 'main';
});
namespace('app.model.User', 'app.model.Base', (Base) => {
return class extends Base {
table = 'user';
}
});
Arguments between first and last will be used as extend or use definitions. If you call namespace
with use definitions, then last argument must be a function that takes arguments likes your set uses.
namespace(
'app.components.Component',
is('app.components.Base'),
function() {
// Prototype of this function will be extended by Base object
// NOT working with classes because class.prototype is read-only in strict mode
console.log(this.prop);
}
);
namespace(
'app.components.Component',
use('app.components.Base'),
(Base) => { // This is required function because use definition not empty
// In this function you can get defined object earlier just call this.{namespace}
// Now, Base == this.app.components.Base
return { // Here you must return object or function
prop: Base.prop
}
}
);
namespace(
'app.components.Component',
'app.components.Base', // This is simple usage definition
(Base) => {
return () => {
console.log(Base.prop);
}
}
);
Also you can use definition object. When you pass just a single argument in namespace method - it returns definition object that has 3 methods: use
, is
, define
. define
method works like factory (you need to pass object or function as this method argument).
namespace('app.Config').define({
name: 'Application'
});
namespace('app.Router')
.use('app.Config', 'app.Path')
.define((Config, Path) => {
// You need to return object here because usage list not empty
return {};
}
);
namespace('app.model.User')
.is('app.model.Base')
.use('app.components.Api')
.define((Api) => {
return {};
}
);
If you define async
method as factory namespace
will run and await this factory before save in storage.
namespace('app.view.Template', async () => { // This method will run immedeatly before storage saving
let html = await fetch('/assets/view.html').then(response => { return response.text(); });
html = (new DOMParser()).parseFromString(html, 'text/html');
return { // This is app.view.Template factory
$get(query) {
let template = html.querySelector(query);
if (template === null) { throw new Error('Template with selector `' + query + '` not found'); }
return template;
}
}
});
use('app.view.Template', (Template) => { // This will wait until template not loaded
console.log(Template); // Outputs - { $get: () }
})
Globally defined function that allow run script and autoload required objects.
use('app.App', (App) => { // Will try to autoload 'app.App' from '/app/App.js' file
App.start();
});
Special globally defined function that returns array of passed arguments with special extends
prefix.
namespace('app.model.Base', {
db: 'main'
});
namespace('app.model.User', is('app.model.Base'), {
table: 'user',
}); // Extend `User` object with `Base` properties
namespace('app.components.Base', {
prop: "value",
func: function() {
}
});
namespace('app.components.Component', function() {
console.log('This is component constructor');
});
namespace('app.components.User', class User {
});
namespace('app.Config').define({
name: 'Application'
});
namespace('app.Template', async() => {
// here you can load some templates (as example) or other stuff
return {}; // must return factory
});
namespace('app.components.Component', is('app.components.Base'), function() {
// Prototype of this function will be extended by Base object
});
namespace('app.components.Component', is('app.components.Base'), {
// This object will be extended by Base object
});
namespace('app.components.Component', use('app.components.Base'), function(Base) {
// Here you must return something (object|function) to define new object for `app.components.Component`
return function() { // Constructor
console.log(Base.prop);
}
});
namespace('app.components.Component', 'app.components.Base', function(Base) {
return {
prop: Base.prop
}
});
namespace('app.model.Base', class {
db = 'main';
});
namespace('app.model.User', 'app.model.Base', (Base) => {
return class extends Base {
table = 'user';
}
});
namespace('app.App')
.use('app.Config', 'app.Router')
.define(function(Config, Router) {
return {
start: function() {}
}
});
use('app.components.Component', function(Component) {
// This is {main} method in your application
});
For usage namespace with simple http applications you need to attach script file to body
<script type="text/javascript" src="/vendor/namespace.min.js"></script>
Then imagine - you have one main
file which attached to body
<script type="text/javascript" src="/app/main.js"></script>
In this file you need to define autoloader paths and just run application with use
function
namespace.autoload({ 'app': '/app' }); // This define autoload paths
use(
'app.App',
function(App) {
App.start();
}
);
// This call of use function will automatically attach file 'app/App.js' to body
When you pass use
definitions in namespace, script will automatically attach js file to body and only after it loaded will execute method.
If defined namespace was already loaded - just return it.
namespace(
'app.App',
use(
'app.Config',
'app.Page',
'app.Layout',
),
function(config, page, layout) {
// This method will run only when all files is attached and loaded
// You need to return some object
return {
config: config,
page: page,
layout: layout,
start: function() {
alert('Application start!');
}
}
}
);
This usage will attach files like this
<script type="text/javascript" src="/app/Config.js"></script>
<script type="text/javascript" src="/app/Page.js"></script>
<script type="text/javascript" src="/app/Layout.js"></script>
Of course! If you pack files in single - namespace will check all definitions and not attach defined files.
npm install unamespace
Then in main
file you need to require unamespace
module, which will define global functions.
require('unamespace');
After this you need to define application autoloads paths
namespace.autoload({ 'app': __dirname + '/app' });
// This will allow to load all 'app.*' definitions from specified directory
You can use namespace to load installed node modules like this
use(
'express', // This will auto-require module `express` and pass it to the function
function(express) {
}
);
or this
// ./app/App.js
namespace('app.App', use('express.request'), function(request) {
// This will load `request` object from `express` module
});
Definition of namespace in file will exports node module
// ./app/model/User.js
namespace('app.model.User', function(id) {
this.id = id;
});
var User = require('./app/model/User.js');
var andrew = new User(1);
console.log(andrew.id);
When you modify global require
function by resolveForRequire
calling, you can define classes like this
// ./app/model/Base.js
namespace('app.model.Base', class {
db = 'main';
});
// ./app/model/User.js
namespace('app.model.User', class extends require('app.model.Base') {
table = 'user';
});