{"action":"created","issue":{"url":"https://api.github.com/repos/wycats/javascript-decorators/issues/40","repository_url":"https://api.github.com/repos/wycats/javascript-decorators","labels_url":"https://api.github.com/repos/wycats/javascript-decorators/issues/40/labels{/name}","comments_url":"https://api.github.com/repos/wycats/javascript-decorators/issues/40/comments","events_url":"https://api.github.com/repos/wycats/javascript-decorators/issues/40/events","html_url":"https://github.com/wycats/javascript-decorators/issues/40","id":108786483,"number":40,"title":"Declaring a decorator so it is context aware","user":{"login":"lukescott","id":486224,"avatar_url":"https://avatars.githubusercontent.com/u/486224?v=3","gravatar_id":"","url":"https://api.github.com/users/lukescott","html_url":"https://github.com/lukescott","followers_url":"https://api.github.com/users/lukescott/followers","following_url":"https://api.github.com/users/lukescott/following{/other_user}","gists_url":"https://api.github.com/users/lukescott/gists{/gist_id}","starred_url":"https://api.github.com/users/lukescott/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lukescott/subscriptions","organizations_url":"https://api.github.com/users/lukescott/orgs","repos_url":"https://api.github.com/users/lukescott/repos","events_url":"https://api.github.com/users/lukescott/events{/privacy}","received_events_url":"https://api.github.com/users/lukescott/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":9,"created_at":"2015-09-29T03:15:01Z","updated_at":"2016-03-02T20:14:15Z","closed_at":null,"body":"I have a case where I want to use the same decorator, but do something slightly different depending on the context. For example:\r\n```javascript\r\n@attribute(\"value\", {\"default\": \"foo\"}) // Adds a default get/set for value and registers it as an attribute\r\nclass Foo {\r\n  @attribute({\"default\": 0}) // registers size as an attribute and adds a default value\r\n  get size() {\r\n    return this._size\r\n  }\r\n\r\n  set size(size) {\r\n    this._size = size;\r\n  }\r\n\r\n  get name() {\r\n      return this._name;\r\n  }\r\n\r\n  @attribute // registers name as an attribute\r\n  set name(name) {\r\n    this._name = name;\r\n  }\r\n}\r\n```\r\nThe problem is in order to make all three work I need to use 3 different decorator syntaxes:\r\n```javascript\r\n// class Foo case\r\nfunction attribute(name, options = {}) {\r\n  return function(constructor) {\r\n    ///...\r\n  }\r\n}\r\n// get size() case\r\nfunction attribute(name, options = {}) {\r\n  return function(prototype, name, descriptor) {\r\n    ///...\r\n  }\r\n}\r\n// get name() case\r\nfunction attribute(prototype, name, descriptor) {\r\n  // ...\r\n}\r\n```\r\nDetecting the context and using the proper declaration is a bit difficult and cumbersome. There are two issues:\r\n\r\n1 - `@attribute` and `@attribute()` have two different decorator signatures. First is the decorator the second returns a decorator. They both should be the same. And `@attribute(name, options)` should also work with the same definition.\r\n2 - There is no indication of context, unless you check the argument types, which can be messy considering that the prototype is an `Object`. If you wanted the first argument to be an `Object` how do you know it is a prototype or an argument?\r\n\r\nA alternate for creating a decorator like this could work:\r\n\r\n```javascript\r\nfunction attribute(...args) {\r\n  return {\r\n    class(constructor) {\r\n      let [name, options] = args;\r\n      // ...\r\n    },\r\n    get(prototype, name, descriptor) {\r\n      let options = args[0];\r\n      // ...\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nThe decorator method would return an object containing functions for each context. Keys of the object could be \"class\", \"get\", \"set\", \"method\", \"function\", \"var\".\r\n\r\nThe reserved words actually work in babel when used in that way. If that doesn't work you could do something like `\"class\": function(constructor){...}` instead."},"comment":{"url":"https://api.github.com/repos/wycats/javascript-decorators/issues/comments/191406879","html_url":"https://github.com/wycats/javascript-decorators/issues/40#issuecomment-191406879","issue_url":"https://api.github.com/repos/wycats/javascript-decorators/issues/40","id":191406879,"user":{"login":"lukescott","id":486224,"avatar_url":"https://avatars.githubusercontent.com/u/486224?v=3","gravatar_id":"","url":"https://api.github.com/users/lukescott","html_url":"https://github.com/lukescott","followers_url":"https://api.github.com/users/lukescott/followers","following_url":"https://api.github.com/users/lukescott/following{/other_user}","gists_url":"https://api.github.com/users/lukescott/gists{/gist_id}","starred_url":"https://api.github.com/users/lukescott/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lukescott/subscriptions","organizations_url":"https://api.github.com/users/lukescott/orgs","repos_url":"https://api.github.com/users/lukescott/repos","events_url":"https://api.github.com/users/lukescott/events{/privacy}","received_events_url":"https://api.github.com/users/lukescott/received_events","type":"User","site_admin":false},"created_at":"2016-03-02T20:14:15Z","updated_at":"2016-03-02T20:14:15Z","body":"The original use-case of using the same decorator in both class and method context may not be the best approach. However, the current implementing does not stop someone from trying to use a class method decorator class or vise versa. The decorator has to somehow check for that.\r\n\r\nIf a decorator was defined via an `Object.createDecorator({...})` or `new Decorator({...})` you could define handlers for the different cases. And if you don't specify a case for the decorator the engine can throw an error. You don't have to pollute your decorator handler at that point. And on top of that you can distinguish a decorator from a regular function, which at the moment you can't."}}