Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ The project uses [recast](https://github.com/benjamn/recast) (which uses Esprima
- App.Router = Ember.Router.extend(); placed at beginning of router file

# TODOS
- [ ] helpers
- [ ] articles-controller-mixin
- [ ] export undefined
- [ ] use new visitor syntax
- [ ] App.Something = App.SomethingElse = Ember.Object.extend();
60 changes: 28 additions & 32 deletions lib/ember-migrator.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ function EmberMigrator(options){
// Map from class name to export path in ember-cli
// E.g., App.MyClassView -> /app/views/my-class.js
// Also, window.App -> app/app.js
// We handle the difference between main app space and window simply with isWindowVar flag
this.classesFilepathMap = Object.create(null);
// Some things are stored on the window directly, e.g., the main application
// E.g., window.App -> /app/app.js
this.windowFilepathMap = Object.create(null);
}

var Visitor = recast.Visitor;
Expand All @@ -43,6 +39,7 @@ var MigratorVisitor = Visitor.extend({
init: function(options) {
this.rootAppName = options.rootAppName;
this.classesFilepathMap = options.classesFilepathMap;
this.filePath = options.filePath;
// This is what we will construct our import strings from
this.imports = {};
},
Expand All @@ -58,11 +55,15 @@ var MigratorVisitor = Visitor.extend({
this.imports.DS = 'ember-data';
} else if (isExpression && node.object.object.name === this.rootAppName){
// We are using the global App namespace so we need to import something from our ember-cli structure
var name = node.object.property.name;
if (this.classesFilepathMap[name].moduleName) {
this.imports[name] = this.classesFilepathMap[name].moduleName;
if (node.object.property.type === 'Identifier') {
var name = node.object.property.name;
if (this.classesFilepathMap[name].moduleName) {
this.imports[name] = this.classesFilepathMap[name].moduleName;
} else {
console.log("Do not know how to import", name);
}
} else {
console.log("Do not know how to import", name);
console.log("Warning: Don't know how to import line in " + this.filePath);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for us to get the line number or put more information here?

}
}
return node;
Expand All @@ -75,7 +76,7 @@ var MigratorVisitor = Visitor.extend({
var rightNode = node.right;
if (namedTypes.MemberExpression.check(node.left) &&
(leftNode.object.name === this.rootAppName ||
leftNode.object.name === 'window') ){
isAppDefinition(leftNode, this.rootAppName)) ) {
this._exportName = leftNode.property.name;
var newNode = builders.variableDeclaration("var", [builders.variableDeclarator(builders.identifier(leftNode.property.name), rightNode)]);
// Recursively check this node to see if it is a member expression and we need an import
Expand Down Expand Up @@ -132,7 +133,6 @@ EmberMigrator.prototype.run = function EmberMigrator_run(){
var fullPath = path.join(self.inputDirectory, filePath);
var outputFile = path.join(self.outputDirectory, self.appName, 'nonjs', filePath);
var outputFolder = path.dirname(outputFile);
console.log('copying nonjs file', outputFile);
mkdirp.sync(outputFolder);
fs.writeFileSync(outputFile, fs.readFileSync(fullPath));
});
Expand All @@ -147,7 +147,6 @@ EmberMigrator.prototype.run = function EmberMigrator_run(){
var outputFile = dirs.join('/');
outputFile = path.join(self.outputDirectory, self.appName, outputFile);
var outputFolder = path.dirname(outputFile);
console.log('copying nonjs file', outputFile);
mkdirp.sync(outputFolder);
fs.writeFileSync(outputFile, fs.readFileSync(fullPath));
});
Expand All @@ -166,7 +165,7 @@ EmberMigrator.prototype.splitFile = function(filePath) {
var typedExports = [];

var that = this;
var addTypedNode = function(node, filePath, className, isWindow) {
var addTypedNode = function(node, filePath, className) {
var newType = TypedExport.determineType(filePath, className);
var fileName = TypedExport.filePathForClassname(className, newType, filePath, that.splitFiles);

Expand All @@ -180,11 +179,13 @@ EmberMigrator.prototype.splitFile = function(filePath) {
exportName: className
});
that.splitFiles[fileName] = typedExport;
// Every typed export needs to be able to be looked up on this map
that.classesFilepathMap[typedExport.exportName] = {
moduleName: typedExport.exportPath(that.appName),
isWindow: isWindow
};
if (typedExport.exportName) {
// Every module we export needs to be looked up on this map for imports
that.classesFilepathMap[typedExport.exportName] = {
moduleName: typedExport.exportPath(that.appName)
};
}
// Keep track of all exports so far
typedExports.push(typedExport);
}
that.splitFiles[fileName].astNodes.push(node);
Expand All @@ -197,15 +198,14 @@ EmberMigrator.prototype.splitFile = function(filePath) {
if (namedTypes.ExpressionStatement.check(node)) {
// We know we are an assignment
var expression = node.expression;
// Special case app definition to export, all other window exports
// should not be handled this way
if (namedTypes.AssignmentExpression.check(expression) &&
namedTypes.MemberExpression.check(expression.left) &&
(expression.left.object.name === this.rootAppName ||
expression.left.object.name === "window")) {

// See if we are assigning the class on the App or window
var isWindow = expression.left.object.name === "window";
isAppDefinition(expression.left, this.rootAppName))) {
className = expression.left.property.name;
addTypedNode(node, filePath, className, isWindow);
addTypedNode(node, filePath, className);
isNodeStored = true;
assignmentCount++;
}
Expand Down Expand Up @@ -237,7 +237,8 @@ EmberMigrator.prototype.processFile = function(typedExport){
EmberMigrator.prototype.convertFile = function(typedExport){
var visitor = new MigratorVisitor({
rootAppName: this.rootAppName,
classesFilepathMap: this.classesFilepathMap
classesFilepathMap: this.classesFilepathMap,
filePath: typedExport.fileName
});
visitor.visit(typedExport.astNodes);
var imports = Object.keys(visitor.imports)
Expand All @@ -263,15 +264,6 @@ EmberMigrator.prototype.convertFile = function(typedExport){
code = code.replace(/;;\n+/g, ';\n'); // for some reason recast print will add another semicolon if there is already one
code = code.replace(new RegExp(this.rootAppName + "\\.", 'g'), '');
code = code.replace(/Em\./g, 'Ember.');
// For any module imported that used to be a window global
Object.keys(this.classesFilepathMap).forEach(function(name) {
var module = this.classesFilepathMap[name];
if (module.isWindow) {
code = code.replace("window." + name, name);
}
}, this);


code = code + "\n" + "export default " + typedExport.exportName + ";\n";

return code;
Expand All @@ -288,6 +280,10 @@ EmberMigrator.prototype.flushConvertedFiles = function(splitFiles){
};


function isAppDefinition(leftNode, appName) {
return leftNode.object.name === "window" && leftNode.property.name === appName;
}

function capitalize(string){
return string.charAt(0).toUpperCase() + string.slice(1);
}
Expand Down
10 changes: 7 additions & 3 deletions lib/typed-export.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ TypedExport.knownTypes = ['model', 'serializer', 'controller', 'view', 'mixin',

TypedExport.pluralizeType = function(type) {
return type + 's';
}
};

TypedExport.determineType = function(filePath, className) {
// First check to see if any class matches
Expand All @@ -46,7 +46,7 @@ TypedExport.determineType = function(filePath, className) {
}, this);
}
return type;
}
};

// TODO(Tony) handle path and name
TypedExport.prototype.exportPath = function(appName) {
Expand Down Expand Up @@ -79,7 +79,11 @@ TypedExport.convertToOutputFilename = function(stringInput) {

TypedExport.filePathForClassname = function(className, type, filePath, exportFiles) {
var newFilePath;
if (type === 'unknown') {
if (!className) {
// className = null means we are not exporting anything for this filepath
// so we should send it to special globals folder
newFilePath = path.join('globals', filePath);
} else if (type === 'unknown') {
newFilePath = filePath;
} else {
var filename = TypedExport.convertToOutputFilename(className);
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/vanilla/input/analytics/global_analytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(function() {
window.global_analytics = 'inject thorough analytics solution';
})();
3 changes: 3 additions & 0 deletions test/fixtures/vanilla/input/window_var.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
window.vip_global = function() {
console.log('the coolest');
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(function() {
window.global_analytics = 'inject thorough analytics solution';
})();

export default undefined;
5 changes: 5 additions & 0 deletions test/fixtures/vanilla/output/globals/window-var.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
window.vip_global = function() {
console.log('the coolest');
};

export default undefined;
17 changes: 17 additions & 0 deletions test/models-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,21 @@ describe('migrating models', function(){
});
});

describe('Moves window var definition into globals directory', function(){

it('migrates the files correctly', function(){
var expectedModel = fixture('globals/window-var.js').split('\n');
var actualModel = result('globals/window-var.js').split('\n');
assert.deepEqual(actualModel, expectedModel);
});
});

describe('Moves self executing anonymous functions to globals', function(){

it('migrates the files correctly', function(){
var expectedModel = fixture('globals/analytics/global-analytics.js').split('\n');
var actualModel = result('globals/analytics/global-analytics.js').split('\n');
assert.deepEqual(actualModel, expectedModel);
});
});
});