Skip to content

Commit

Permalink
Merge 6c37027 into 3e68893
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanPiercey committed Dec 3, 2018
2 parents 3e68893 + 6c37027 commit 613caf5
Show file tree
Hide file tree
Showing 27 changed files with 501 additions and 269 deletions.
4 changes: 0 additions & 4 deletions src/compiler/CompileContext.js
Expand Up @@ -460,10 +460,6 @@ class CompileContext extends EventEmitter {
elDef = { tagName, argument, attributes, openTagOnly, selfClosed };
}

if (elDef.tagName === "") {
elDef.tagName = tagName = "assign";
}

if (!attributes) {
attributes = elDef.attributes = [];
} else if (typeof attributes === "object") {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/Compiler.js
Expand Up @@ -154,7 +154,7 @@ class Compiler {
var codeGenerator = new CodeGenerator(context);

// STAGE 1: Parse the template to produce the initial AST
var ast = this.parser.parse(src, context);
var ast = this.parser.parse(src, context, { migrate: true });
context._parsingFinished = true;

if (!context.ignoreUnrecognizedTags && context.unrecognizedTags) {
Expand Down
87 changes: 87 additions & 0 deletions src/compiler/Migrator.js
@@ -0,0 +1,87 @@
"use strict";

var createError = require("raptor-util/createError");

const FLAG_MIGRATOR_APPLIED = "migratorApply";

function migrateNode(node, context) {
if (node.isDetached()) {
return; //The node might have been removed from the tree
}

if (!(node.tagName || node.tagNameExpression)) {
return;
}

context.taglibLookup.forEachTagMigrator(node, migration => {
// Check to make sure a migration of a certain type is only applied once to a node
if (node.isTransformerApplied(migration)) {
return;
}

// Mark the node as have been transformed by the current migrator
node.setTransformerApplied(migration);
// Set the flag to indicate that a node was transformed
context.setFlag(FLAG_MIGRATOR_APPLIED);
context._currentNode = node;

try {
migration(node, context);
} catch (e) {
throw createError(
new Error(
'Unable to migrate template at path "' +
context.filename +
'". Error: ' +
e.message
),
e
);
}
});
}

function migrateTreeHelper(node, context) {
migrateNode(node, context);

/*
* Now process the child nodes by looping over the child nodes
* and migrating the subtree recursively
*
* NOTE: The length of the childNodes array might change as the tree is being performed.
* The checks to prevent migrators from being applied multiple times makes
* sure that this is not a problem.
*/

node.forEachChild(function(childNode) {
migrateTreeHelper(childNode, context);
});
}

function migrateTree(ast, context) {
// TODO: Consider moving this into the loop below so that root level migrations
// are also run on new nodes.
context.taglibLookup.forEachTemplateMigrator(migration => {
migration(ast, context);
});

/*
* The tree is continuously migrated until we go through an entire pass where
* there were no new nodes that needed to be migrated. This loop makes sure that
* nodes added by migrators are also migrated.
*/
do {
context.clearFlag(FLAG_MIGRATOR_APPLIED);
//Reset the flag to indicate that no migrations were yet applied to any of the nodes for this pass
migrateTreeHelper(ast, context); //Run the migrations on the tree
} while (context.isFlagSet(FLAG_MIGRATOR_APPLIED));
}

class Migrator {
migrate(ast, context) {
migrateTree(ast, context);
return ast;
}
}

module.exports = Migrator;
11 changes: 11 additions & 0 deletions src/compiler/Parser.js
Expand Up @@ -2,6 +2,7 @@
var ok = require("assert").ok;
var extend = require("raptor-util/extend");
var Normalizer = require("./Normalizer");
var Migrator = require("./Migrator");

var COMPILER_ATTRIBUTE_HANDLERS = {
"preserve-whitespace": function(attr, context) {
Expand Down Expand Up @@ -96,13 +97,19 @@ class Parser {
var rootNode = builder.templateRoot();
var mergedOptions = Object.assign({}, this.defaultOptions, options);
var raw = mergedOptions.raw === true;
var migrate = mergedOptions.migrate === true;

this.stack.push({
node: rootNode
});

this.parserImpl.parse(src, this, context.filename, mergedOptions);

if (migrate) {
var migrator = new Migrator();
rootNode = migrator.migrate(rootNode, context);
}

if (!raw) {
var normalizer = new Normalizer();
rootNode = normalizer.normalize(rootNode, context);
Expand Down Expand Up @@ -143,6 +150,10 @@ class Parser {
argument = argument.value;
}

if (!el.tagNameExpression && !tagName) {
tagName = el.tagName = "assign";
}

if (tagName === "marko-compiler-options") {
this.parentNode.setTrimStartEnd(true);

Expand Down
6 changes: 3 additions & 3 deletions src/compiler/ast/Node.js
Expand Up @@ -40,7 +40,7 @@ class Node {
this.tagDef = null; // The tag definition associated with this Node
this._codeGeneratorFuncs = null;
this._flags = {};
this._transformersApplied = {};
this._transformersApplied = new Set();
this._preserveWhitespace = null;
this._events = null;
this._childTextNormalized = undefined;
Expand Down Expand Up @@ -191,11 +191,11 @@ class Node {
}

isTransformerApplied(transformer) {
return this._transformersApplied[transformer.id] === true;
return this._transformersApplied.has(transformer);
}

setTransformerApplied(transformer) {
this._transformersApplied[transformer.id] = true;
this._transformersApplied.add(transformer);
}

toString() {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/index.js
Expand Up @@ -273,6 +273,10 @@ var coreTaglibsRegistered = false;
function registerCoreTaglibs() {
if (!coreTaglibsRegistered) {
coreTaglibsRegistered = true;
registerTaglib(
require("../taglibs/migrate/marko.json"),
require.resolve("../taglibs/migrate/marko.json")
);
registerTaglib(
require("../taglibs/core/marko.json"),
require.resolve("../taglibs/core/marko.json")
Expand Down
12 changes: 12 additions & 0 deletions src/compiler/taglib-loader/Tag.js
Expand Up @@ -23,6 +23,8 @@ class Tag {
this.dir = path.dirname(filePath);
}

this.migrators = {};
this.migratorPaths = [];
this.attributes = {};
this.transformers = {};
this.patternAttributes = [];
Expand Down Expand Up @@ -198,6 +200,16 @@ class Tag {
hasNestedTags() {
return this.nestedTags != null;
}

forEachMigrator(callback, thisObj) {
this.migratorPaths
.map(function(path) {
return (this.migrators[path] =
this.migrators[path] || markoModules.require(path));
}, this)
.forEach(callback, thisObj);
}

getNodeFactory() {
var nodeFactory = this._nodeFactory;
if (nodeFactory !== undefined) {
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/taglib-loader/Taglib.js
Expand Up @@ -3,6 +3,7 @@ var forEachEntry = require("raptor-util/forEachEntry");
var ok = require("assert").ok;
var path = require("path");
var loaders = require("./loaders");
var markoModules = require("../modules");

function handleImport(taglib, importedTaglib) {
var importsLookup = taglib.importsLookup || (taglib.importsLookup = {});
Expand Down Expand Up @@ -65,6 +66,14 @@ class Taglib {
}
return attribute;
}
getMigrator() {
var path = this.migratorPath;

if (path) {
return (this._migrator =
this._migrator || markoModules.require(path));
}
}
addTag(tag) {
ok(arguments.length === 1, "Invalid args");
if (!tag.name) {
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/taglib-loader/loadTagFromProps.js
Expand Up @@ -389,6 +389,16 @@ class TagLoader {
);
}

/**
* A custom tag can be mapped to module that is used
* migrate deprecated features to modern features.
*/
migrator(value) {
var tag = this.tag;
var dirname = this.dirname;
tag.migratorPaths.push(markoModules.resolveFrom(dirname, value));
}

/**
* A custom tag can be mapped to module that is is used
* to generate compile-time code for the custom tag. A
Expand Down
12 changes: 12 additions & 0 deletions src/compiler/taglib-loader/loadTaglibFromProps.js
Expand Up @@ -322,6 +322,18 @@ class TaglibLoader {
}
}

/**
* A taglib can be mapped to module that is used
* migrate deprecated features to modern features across the entire template.
*/
migrator(value) {
var taglib = this.taglib;
var dirname = this.dirname;

var path = markoModules.resolveFrom(dirname, value);
taglib.migratorPath = path;
}

textTransformer(value) {
// Marko allows a "text-transformer" to be registered. The provided
// text transformer will be called for any static text found in a template.
Expand Down
53 changes: 53 additions & 0 deletions src/compiler/taglib-lookup/TaglibLookup.js
Expand Up @@ -326,6 +326,59 @@ class TaglibLookup {
return attrDef;
}

forEachTemplateMigrator(callback, thisObj) {
for (var key in this.taglibsById) {
var migration = this.taglibsById[key].getMigrator();
if (migration) {
callback.call(thisObj, migration);
}
}
}

forEachTagMigrator(element, callback, thisObj) {
if (typeof element === "string") {
element = {
tagName: element
};
}

var tagName = element.tagName;
/*
* If the node is an element node then we need to find all matching
* migrators based on the URI and the local name of the element.
*/

var migrators = [];

function addMigrator(migrator) {
if (typeof migrator !== "function") {
throw new Error("Invalid transformer");
}

migrators.push(migrator);
}

/*
* Handle all of the migrators for all possible matching migrators.
*
* Start with the least specific and end with the most specific.
*/

if (this.merged.tags) {
if (tagName) {
if (this.merged.tags[tagName]) {
this.merged.tags[tagName].forEachMigrator(addMigrator);
}
}

if (this.merged.tags["*"]) {
this.merged.tags["*"].forEachMigrator(addMigrator);
}
}

migrators.forEach(callback, thisObj);
}

forEachTemplateTransformer(callback, thisObj) {
var transformers = this.merged.transformers;
if (transformers && transformers.length) {
Expand Down
30 changes: 0 additions & 30 deletions src/taglibs/core/assign-tag.js

This file was deleted.

0 comments on commit 613caf5

Please sign in to comment.