Skip to content

Commit

Permalink
Handle shorthand actions (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssutar authored and pzuraq committed Nov 30, 2018
1 parent 6f0b1af commit f690999
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 54 deletions.
1 change: 1 addition & 0 deletions transforms/ember-object/__testfixtures__/basic.input.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const Foo = Test.extend(MyMixin, {
numProp: 123,
[MY_VAL]: "val",
queryParams: {},
someVal,

/**
* Method comments
Expand Down
1 change: 1 addition & 0 deletions transforms/ember-object/__testfixtures__/basic.output.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class Foo extends Test.extend(MyMixin) {
numProp = 123;
[MY_VAL] = "val";
queryParams = {};
someVal = someVal;

/**
* Method comments
Expand Down
2 changes: 2 additions & 0 deletions transforms/ember-object/__testfixtures__/decorators.input.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { inject as controller } from "@ember/controller";
import { inject as service } from "@ember/service";
import { on } from "@ember/object/evented";
import layout from "components/templates/foo";
import { someActionUtil } from "some/action/util";

const Foo = EmberObject.extend({
tagName: "div",
Expand All @@ -25,6 +26,7 @@ const Foo = EmberObject.extend({
}),

actions: {
someActionUtil,
/**
Comments
*/
Expand Down
6 changes: 6 additions & 0 deletions transforms/ember-object/__testfixtures__/decorators.output.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { controller } from "@ember-decorators/controller";
import { service } from "@ember-decorators/service";
import { on } from "@ember-decorators/object/evented";
import templateLayout from "components/templates/foo";
import { someActionUtil } from "some/action/util";

@tagName("div")
@classNames("test-class", "custom-class")
Expand All @@ -28,6 +29,11 @@ class Foo extends EmberObject {
return "abc";
}

@action
someActionUtil() {
return someActionUtil.call(this, ...arguments);
}

/**
Comments
*/
Expand Down
4 changes: 3 additions & 1 deletion transforms/ember-object/__testfixtures__/runtime.input.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import RuntimeInput from "common/runtime/input";

/**
* Program comments
*/
const Foo = Test.extend(MyMixin, {
export default RuntimeInput.extend(MyMixin, {
/**
* Property comments
*/
Expand Down
3 changes: 2 additions & 1 deletion transforms/ember-object/__testfixtures__/runtime.output.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { action, off, unobserves } from "@ember-decorators/object";
import RuntimeInput from "common/runtime/input";

/**
* Program comments
*/
class Foo extends Test.extend(MyMixin) {
export default class RuntimeInputEmberObject extends RuntimeInput.extend(MyMixin) {
/**
* Property comments
*/
Expand Down
9 changes: 0 additions & 9 deletions transforms/ember-object/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
const { getOptions } = require("codemod-cli");
const { replaceEmberObjectExpressions } = require("../helpers/parse-helper");
const { getRuntimeData } = require("../helpers/util");

module.exports = function transformer(file, api, opts) {
const j = api.jscodeshift;
const options = Object.assign({}, opts, getOptions());
let { source, path } = file;
const runtimeConfigPath = options["runtime-config-path"];

if (runtimeConfigPath) {
options.runtimeData = getRuntimeData(runtimeConfigPath, path);
if (!options.runtimeData) {
return;
}
}

const root = j(source);

Expand Down
16 changes: 10 additions & 6 deletions transforms/helpers/decorator-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ function createCallExpressionDecorators(j, decoratorName, instanceProp) {
);
}

/**
* Create decorators which need arguments
*
* @param {Object} j - jscodeshift lib reference
* @param {String} identifier
* @param {String[]} args
* @returns {Decorator[]}
*/
function createDecoratorsWithArgs(j, identifier, args) {
return [
j.decorator(
Expand All @@ -80,6 +88,7 @@ function createDecoratorsWithArgs(j, identifier, args) {
* Create `@action` decorator
*
* @param {Object} j - jscodeshift lib reference
* @param {String} identifier
* @returns {Decorator[]}
*/
function createIdentifierDecorators(j, identifier = "action") {
Expand Down Expand Up @@ -132,12 +141,7 @@ function createInstancePropDecorators(j, instanceProp) {
);
}
return decorators.concat(
createCallExpressionDecorators(
j,
decorator,
instanceProp,
instanceProp.decoratorArgs[decorator]
)
createCallExpressionDecorators(j, decorator, instanceProp)
);
}, []);
}
Expand Down
85 changes: 62 additions & 23 deletions transforms/helpers/parse-helper.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
const path = require("path");
const camelCase = require("camelcase");
const {
get,
getOptions,
capitalizeFirstLetter,
startsWithUpperCaseLetter,
DECORATOR_PATHS,
EMBER_DECORATOR_SPECIFIERS,
get,
getOptions,
getRuntimeData,
LAYOUT_IMPORT_SPECIFIER,
METHOD_DECORATORS,
META_DECORATORS,
EMBER_DECORATOR_SPECIFIERS
METHOD_DECORATORS,
startsWithUpperCaseLetter
} = require("./util");
const { hasValidProps, isFileOfType } = require("./validation-helper");
const {
withComments,
hasValidProps,
isFileOfType,
isTestFile
} = require("./validation-helper");
const {
createClass,
createEmberDecoratorSpecifiers,
createImportDeclaration,
createEmberDecoratorSpecifiers
withComments
} = require("./transform-helper");
const EOProp = require("./EOProp");
const logger = require("./log-helper");
Expand Down Expand Up @@ -131,11 +136,11 @@ function getDecoratorInfo(specifier, importPropDecoratorMap) {
const isMethodDecorator = METHOD_DECORATORS.includes(importedName);
return {
decoratorName,
localName,
importedName,
isImportedAs,
isMetaDecorator,
isMethodDecorator
isMethodDecorator,
localName
};
}

Expand Down Expand Up @@ -223,15 +228,15 @@ function getDecoratorImports(j, root) {
function getDecoratorsToImport(instanceProps, decoratorsMap = {}) {
return instanceProps.reduce((specs, prop) => {
return {
attribute: specs.attribute || prop.hasAttributeDecorator,
readOnly: specs.readOnly || prop.hasReadOnly,
action: specs.action || prop.isAction,
layout: specs.layout || prop.isLayout,
tagName: specs.tagName || prop.isTagName,
attribute: specs.attribute || prop.hasAttributeDecorator,
className: specs.className || prop.hasClassNameDecorator,
classNames: specs.classNames || prop.isClassNames,
unobserves: specs.unobserves || prop.hasUnobservesDecorator,
layout: specs.layout || prop.isLayout,
off: specs.off || prop.hasOffDecorator,
readOnly: specs.readOnly || prop.hasReadOnly,
tagName: specs.tagName || prop.isTagName,
unobserves: specs.unobserves || prop.hasUnobservesDecorator,
volatile: specs.volatile || prop.hasVolatile
};
}, decoratorsMap);
Expand Down Expand Up @@ -460,11 +465,21 @@ function getExpressionToReplace(j, eoCallExpression) {
* @param {String} filePath
* @return {String}
*/
function getClassName(j, eoCallExpression, filePath) {
function getClassName(
j,
eoCallExpression,
filePath,
superClassName,
type = "EmberObject"
) {
const varDeclaration = getClosetVariableDeclaration(j, eoCallExpression);
const className =
getVariableName(varDeclaration) || camelCase(path.basename(filePath, "js"));
return capitalizeFirstLetter(className);
let capitalizedClassName = capitalizeFirstLetter(className);
if (capitalizedClassName === superClassName) {
capitalizedClassName += capitalizeFirstLetter(type);
}
return capitalizedClassName;
}

/**
Expand Down Expand Up @@ -499,6 +514,24 @@ function parseEmberObjectCallExpression(eoCallExpression) {
*/
function replaceEmberObjectExpressions(j, root, filePath, options = {}) {
logger.info(`[${filePath}]: BEGIN`);

const runtimeConfigPath = options["runtime-config-path"];

if (runtimeConfigPath) {
options.runtimeData = getRuntimeData(runtimeConfigPath, filePath);
if (!options.runtimeData) {
logger.warn(
`${filePath} SKIPPED Cound not find runtime data NO_RUNTIME_DATA`
);
return;
}
}

if (isTestFile(filePath)) {
logger.warn(`[${filePath}]: Skipping test file`);
return;
}

if (options.type && !isFileOfType(filePath, options.type)) {
logger.warn(
`[${filePath}]: FAILURE Type mismatch, expected type '${
Expand Down Expand Up @@ -536,7 +569,13 @@ function replaceEmberObjectExpressions(j, root, filePath, options = {}) {
const superClassName = get(eoCallExpression, "value.callee.object.name");
const es6ClassDeclaration = createClass(
j,
getClassName(j, eoCallExpression, filePath),
getClassName(
j,
eoCallExpression,
filePath,
superClassName,
get(options, "runtimeData.type")
),
eoProps,
superClassName,
mixins
Expand Down Expand Up @@ -568,11 +607,11 @@ function replaceEmberObjectExpressions(j, root, filePath, options = {}) {
}

module.exports = {
getVariableName,
getEmberObjectProps,
getEmberObjectCallExpressions,
getClassName,
getClosetVariableDeclaration,
getEmberObjectCallExpressions,
getEmberObjectProps,
getExpressionToReplace,
replaceEmberObjectExpressions,
getClassName
getVariableName,
replaceEmberObjectExpressions
};
Loading

0 comments on commit f690999

Please sign in to comment.