import { assign } from 'ember-utils';
import { assert, deprecate } from 'ember-metal';
/**
@module ember
@submodule ember-routing
*/
function DSL(name, options) {
this.parent = name;
this.enableLoadingSubstates = options && options.enableLoadingSubstates;
this.matches = [];
this.explicitIndex = undefined;
this.options = options;
}
export default DSL;
DSL.prototype = {
route(name, options, callback) {
let dummyErrorRoute = `/_unused_dummy_error_path_route_${name}/:error`;
if (arguments.length === 2 && typeof options === 'function') {
callback = options;
options = {};
}
if (arguments.length === 1) {
options = {};
}
assert(
`'${name}' cannot be used as a route name.`,
(function() {
if (options.overrideNameAssertion === true) { return true; }
return ['array', 'basic', 'object', 'application'].indexOf(name) === -1;
})()
);
if (this.enableLoadingSubstates) {
createRoute(this, `${name}_loading`, { resetNamespace: options.resetNamespace });
createRoute(this, `${name}_error`, { resetNamespace: options.resetNamespace, path: dummyErrorRoute });
}
if (callback) {
let fullName = getFullName(this, name, options.resetNamespace);
let dsl = new DSL(fullName, this.options);
createRoute(dsl, 'loading');
createRoute(dsl, 'error', { path: dummyErrorRoute });
callback.call(dsl);
createRoute(this, name, options, dsl.generate());
} else {
createRoute(this, name, options);
}
},
push(url, name, callback, serialize) {
let parts = name.split('.');
if (this.options.engineInfo) {
let localFullName = name.slice(this.options.engineInfo.fullName.length + 1);
let routeInfo = assign({ localFullName }, this.options.engineInfo);
if (serialize) {
routeInfo.serializeMethod = serialize;
}
this.options.addRouteForEngine(name, routeInfo);
} else if (serialize) {
throw new Error(`Defining a route serializer on route '${name}' outside an Engine is not allowed.`);
}
if (url === '' || url === '/' || parts[parts.length - 1] === 'index') { this.explicitIndex = true; }
this.matches.push([url, name, callback]);
},
resource(name, options, callback) {
if (arguments.length === 2 && typeof options === 'function') {
callback = options;
options = {};
}
if (arguments.length === 1) {
options = {};
}
options.resetNamespace = true;
deprecate('this.resource() is deprecated. Use this.route(\'name\', { resetNamespace: true }, function () {}) instead.', false, { id: 'ember-routing.router-resource', until: '3.0.0' });
this.route(name, options, callback);
},
generate() {
let dslMatches = this.matches;
if (!this.explicitIndex) {
this.route('index', { path: '/' });
}
return match => {
for (let i = 0; i < dslMatches.length; i++) {
let dslMatch = dslMatches[i];
match(dslMatch[0]).to(dslMatch[1], dslMatch[2]);
}
};
}
};
function canNest(dsl) {
return dsl.parent && dsl.parent !== 'application';
}
function getFullName(dsl, name, resetNamespace) {
if (canNest(dsl) && resetNamespace !== true) {
return `${dsl.parent}.${name}`;
} else {
return name;
}
}
function createRoute(dsl, name, options, callback) {
options = options || {};
let fullName = getFullName(dsl, name, options.resetNamespace);
if (typeof options.path !== 'string') {
options.path = `/${name}`;
}
dsl.push(options.path, fullName, callback, options.serialize);
}
DSL.map = function(callback) {
let dsl = new DSL();
callback.call(dsl);
return dsl;
};
let uuid = 0;
DSL.prototype.mount = function(_name, _options) {
let options = _options || {};
let engineRouteMap = this.options.resolveRouteMap(_name);
let name = _name;
if (options.as) {
name = options.as;
}
var fullName = getFullName(this, name, options.resetNamespace);
let engineInfo = {
name: _name,
instanceId: uuid++,
mountPoint: fullName,
fullName
};
let path = options.path;
if (typeof path !== 'string') {
path = `/${name}`;
}
let callback;
let dummyErrorRoute = `/_unused_dummy_error_path_route_${name}/:error`;
if (engineRouteMap) {
let shouldResetEngineInfo = false;
let oldEngineInfo = this.options.engineInfo;
if (oldEngineInfo) {
shouldResetEngineInfo = true;
this.options.engineInfo = engineInfo;
}
let optionsForChild = assign({ engineInfo }, this.options);
let childDSL = new DSL(fullName, optionsForChild);
createRoute(childDSL, 'loading');
createRoute(childDSL, 'error', { path: dummyErrorRoute });
engineRouteMap.call(childDSL);
callback = childDSL.generate();
if (shouldResetEngineInfo) {
this.options.engineInfo = oldEngineInfo;
}
}
let localFullName = 'application';
let routeInfo = assign({ localFullName }, engineInfo);
if (this.enableLoadingSubstates) {
// These values are important to register the loading routes under their
// proper names for the Router and within the Engine's registry.
let substateName = `${name}_loading`;
let localFullName = `application_loading`;
let routeInfo = assign({ localFullName }, engineInfo);
createRoute(this, substateName, { resetNamespace: options.resetNamespace });
this.options.addRouteForEngine(substateName, routeInfo);
substateName = `${name}_error`;
localFullName = `application_error`;
routeInfo = assign({ localFullName }, engineInfo);
createRoute(this, substateName, { resetNamespace: options.resetNamespace, path: dummyErrorRoute });
this.options.addRouteForEngine(substateName, routeInfo);
}
this.options.addRouteForEngine(fullName, routeInfo);
this.push(path, fullName, callback);
};