yesod-static-angular 0.1.7 → 0.1.8
raw patch · 7 files changed
+124/−112 lines, 7 filesdep ~language-javascript
Dependency ranges changed: language-javascript
Files
- Yesod/EmbeddedStatic/AngularJavascript.hs +1/−2
- Yesod/EmbeddedStatic/AngularJsMangle.hs +81/−59
- test/RunGenerator.hs +3/−2
- test/angular/mod1-and-templ.js.expected +17/−21
- test/angular/mod1.js.expected +17/−21
- test/angular/mod2.js.expected +3/−5
- yesod-static-angular.cabal +2/−2
Yesod/EmbeddedStatic/AngularJavascript.hs view
@@ -59,12 +59,11 @@ , hamletTestTemplate ) where -import Control.Applicative import Control.Monad (forM, unless) import Data.Aeson (encode, decode, toJSON, Value) import Data.Default (def) import Data.List (isPrefixOf, sort)-import Data.Monoid ((<>), mconcat)+import Data.Monoid ((<>)) import Language.Haskell.TH import Network.Mime (MimeType) import System.Directory (getDirectoryContents, doesDirectoryExist, doesFileExist)
Yesod/EmbeddedStatic/AngularJsMangle.hs view
@@ -6,9 +6,10 @@ ) where import Blaze.ByteString.Builder (toLazyByteString)-import Control.Applicative+import Data.List (intersperse) import Data.Maybe (catMaybes) import Language.JavaScript.Parser+import Language.JavaScript.Parser.AST import System.Directory (doesFileExist) import System.FilePath @@ -23,67 +24,76 @@ cleanupDIFile :: FilePath -> IO BL.ByteString cleanupDIFile f = toLazyByteString . renderJS . cleanupDI <$> parseFile f -cleanupDI :: JSNode -> JSNode-cleanupDI (NN (JSSourceElementsTop exprs)) = NN $ JSSourceElementsTop $ map diTopExpr exprs+cleanupDI :: JSAST -> JSAST+cleanupDI (JSAstProgram exprs _) = JSAstProgram (map diTopExpr exprs) JSNoAnnot cleanupDI x = x -diTopExpr :: JSNode -> JSNode-diTopExpr (NN (JSExpression- [ call@(NN (JSMemberDot- [NT (JSIdentifier "module") _ _]- _ -- Literal .- (NT (JSIdentifier func) _ _))) -- function like controller/directive/etc.- , NN (JSArguments open args close)- ])) = NN $ JSExpression [call, NN $ JSArguments open (map (diFuncExpr directive) args) close]- where directive = func == "directive"+diTopExpr :: JSStatement -> JSStatement+diTopExpr (JSMethodCall+ call@(JSMemberDot+ (JSIdentifier _ "module")+ _+ (JSIdentifier _ func))+ _+ argsCommaList+ _+ semi)+ = JSMethodCall call JSNoAnnot (diCommaList (func == "directive") argsCommaList) JSNoAnnot semi diTopExpr x = x +diCommaList :: Bool -> JSCommaList JSExpression -> JSCommaList JSExpression+diCommaList _ JSLNil = JSLNil+diCommaList isDir (JSLOne x) = JSLOne $ diFuncExpr isDir x+diCommaList isDir (JSLCons h _ x) = JSLCons (diCommaList isDir h) JSNoAnnot (diFuncExpr isDir x)+ -- | DI a single argument which is a function expression-diFuncExpr :: Bool -> JSNode -> JSNode-diFuncExpr isDir (NN (JSFunctionExpression a b c params d body)) =+diFuncExpr :: Bool -> JSExpression -> JSExpression+diFuncExpr isDir (JSFunctionExpression _ ident _ params _ body) = case params of- [] -> func- _ -> NN $ JSArrayLiteral aopen elems aclose+ JSLNil -> func+ _ -> JSArrayLiteral JSNoAnnot elems JSNoAnnot where- aopen = NT (JSLiteral "[") tokenPosnEmpty [NoComment]- aclose = NT (JSLiteral "]") tokenPosnEmpty [NoComment]- comma = NN (JSElision (NT (JSLiteral ",") tokenPosnEmpty [NoComment]))- body' = if isDir then diBody body else body- func = NN $ JSFunctionExpression a b c params d body'+ func = JSFunctionExpression JSNoAnnot ident JSNoAnnot params JSNoAnnot body' - elems = map diParam params ++ [comma, func]+ elems :: [JSArrayElement]+ elems = intersperse (JSArrayComma JSNoAnnot) $ map diParam (jsToList params) ++ [JSArrayElement func] diFuncExpr _ x = x --- | Convert a function parameter to a string literal and convert comma to elision-diParam :: JSNode -> JSNode-diParam (NT (JSIdentifier name) _ _) = NT (JSStringLiteral '"' name) tokenPosnEmpty [NoComment]-diParam (NT (JSLiteral ",") _ _) = NN $ JSElision $ NT (JSLiteral ",") tokenPosnEmpty [NoComment]-diParam x = x+-- | Convert a function parameter to a string literal+diParam :: JSIdent -> JSArrayElement+diParam (JSIdentName _ name) = JSArrayElement $ JSStringLiteral JSNoAnnot ("\"" ++ name ++ "\"")+diParam JSIdentNone = JSArrayElement (JSDecimal JSNoAnnot "0") -- | Check a directive body to see if we need to DI cleanup a controller.-diBody :: JSNode -> JSNode-diBody (NN (JSBlock begin statements end)) = NN $ JSBlock begin (map diReturn statements) end-diBody x = x+diBody :: JSBlock -> JSBlock+diBody (JSBlock _ statements _) = JSBlock JSNoAnnot (map diReturn statements) JSNoAnnot -- | Check if a statement is a return of an object literal-diReturn :: JSNode -> JSNode-diReturn (NN (JSReturn ret [NN (JSExpression [NN (JSObjectLiteral begin props end)])] colon))- = NN $ JSReturn ret [NN (JSExpression [NN (JSObjectLiteral begin (map diProperty props) end)])] colon+diReturn :: JSStatement -> JSStatement+diReturn (JSReturn _ (Just (JSObjectLiteral _ props _)) semi)+ = JSReturn JSNoAnnot (Just (JSObjectLiteral JSNoAnnot (diPropertyList props) JSNoAnnot)) semi diReturn x = x -testPropName :: String -> JSNode -> Bool-testPropName n (NT (JSIdentifier n') _ _) = n == n'-testPropName n (NT (JSStringLiteral _ n') _ _) = n == n'+diPropertyList :: JSObjectPropertyList -> JSObjectPropertyList+diPropertyList (JSCTLComma x _) = JSCTLNone $ diPropertyList' x+diPropertyList (JSCTLNone x) = JSCTLNone $ diPropertyList' x++diPropertyList' :: JSCommaList JSObjectProperty -> JSCommaList JSObjectProperty+diPropertyList' (JSLCons h _ x) = JSLCons (diPropertyList' h) JSNoAnnot (diProperty x)+diPropertyList' (JSLOne x) = JSLOne $ diProperty x+diPropertyList' JSLNil = JSLNil++testPropName :: String -> JSPropertyName -> Bool+testPropName n (JSPropertyIdent _ n') = n == n'+testPropName n (JSPropertyString _ n') = "'" ++ n ++ "'" == n' || "\"" ++ n ++ "\"" == n' testPropName _ _ = False -- | Check a property of an object for controller-diProperty :: JSNode -> JSNode-diProperty (NN (JSPropertyNameandValue prop _ args)) - | testPropName "controller" prop = NN $ JSPropertyNameandValue ctrl colon args'+diProperty :: JSObjectProperty -> JSObjectProperty+diProperty (JSPropertyNameandValue prop _ args)+ | testPropName "controller" prop = JSPropertyNameandValue prop JSNoAnnot args' where- ctrl = NT (JSStringLiteral '"' "controller") tokenPosnEmpty [NoComment]- colon = NT (JSLiteral ":") tokenPosnEmpty [NoComment] args' = map (diFuncExpr False) args diProperty x = x @@ -116,34 +126,46 @@ firstJust (Nothing:xs) = firstJust xs -- | Search for the directive ID -parseDirId :: JSNode -> Maybe String-parseDirId (NN (JSSourceElementsTop es)) = firstJust $ map parseDirectiveCall es+parseDirId :: JSAST -> Maybe String+parseDirId (JSAstProgram es _) = firstJust $ map parseDirectiveCall es parseDirId _ = Nothing +jsToList :: JSCommaList a -> [a]+jsToList JSLNil = []+jsToList (JSLOne x) = [x]+jsToList (JSLCons h _ x) = jsToList h ++ [x]+ -- | Parse module.directive(... function(..) {-parseDirectiveCall :: JSNode -> Maybe String-parseDirectiveCall (NN (JSExpression- [NN (JSMemberDot- [NT (JSIdentifier "module") _ _]- _ -- Literal .- (NT (JSIdentifier "directive") _ _)),- NN (JSArguments _ args _)])) = firstJust $ map parseDirArg args+parseDirectiveCall :: JSStatement -> Maybe String+parseDirectiveCall (JSMethodCall+ (JSMemberDot+ (JSIdentifier _ "module")+ _+ (JSIdentifier _ "directive"))+ _ -- annotation+ argsCommalist+ _ --annotation+ _) -- semi colon+ = firstJust $ map parseDirArg $ jsToList argsCommalist parseDirectiveCall _ = Nothing -- | check the function argument to the directive call-parseDirArg :: JSNode -> Maybe String-parseDirArg (NN (JSFunctionExpression _ _ _ _ _ (NN (JSBlock _ statements _))))- = firstJust $ map parseDirSt statements+parseDirArg :: JSExpression -> Maybe String+parseDirArg (JSFunctionExpression _ _ _ _ _ (JSBlock _ statements _)) = firstJust $ map parseDirSt statements parseDirArg _ = Nothing -- | Check a statement inside the factory function for return { .. };-parseDirSt :: JSNode -> Maybe String-parseDirSt (NN (JSReturn _ [NN (JSExpression [NN (JSObjectLiteral _ props _)])] _))- = firstJust $ map parseDirTUrl props+parseDirSt :: JSStatement -> Maybe String+parseDirSt (JSReturn _ (Just (JSObjectLiteral _ props _)) _) = result+ where+ propsLst = case props of+ (JSCTLComma x _) -> jsToList x+ (JSCTLNone x) -> jsToList x+ result = firstJust $ map parseDirTUrl propsLst parseDirSt _ = Nothing -- | Check a property in the object literal-parseDirTUrl :: JSNode -> Maybe String-parseDirTUrl (NN (JSPropertyNameandValue prop _ [NT (JSStringLiteral _ tUrl) _ _])) - | testPropName "templateUrl" prop = Just tUrl+parseDirTUrl :: JSObjectProperty -> Maybe String+parseDirTUrl (JSPropertyNameandValue prop _ [JSStringLiteral _ tUrl])+ | testPropName "templateUrl" prop = Just (drop 1 $ take (length tUrl - 1) tUrl) -- the string literal has quotes around it parseDirTUrl _ = Nothing
test/RunGenerator.hs view
@@ -5,7 +5,7 @@ import Data.List (sortBy) import Data.Ord (comparing) import Language.Haskell.TH-import Test.HUnit+import Test.HUnit hiding (Location) import Yesod.EmbeddedStatic import Yesod.EmbeddedStatic.Types @@ -36,8 +36,9 @@ testEntry :: Entry -> (Location, B.ByteString, FilePath) -> ExpQ testEntry e (loc, mime, f) = do- eCt <- runIO $ BL.readFile f gCt <- runIO $ ebProductionContent e+ --runIO $ BL.writeFile f gCt+ eCt <- runIO $ BL.readFile f case (loc == ebLocation e, mime == ebMimeType e, eCt == gCt, ebDevelExtraFiles e) of (False,_,_,_) -> [| GeneratorTestResult (Just $ "Locations don't match for " ++ $(litE $ stringL loc)) undefined undefined |]
test/angular/mod1-and-templ.js.expected view
@@ -1,19 +1,16 @@-(function(module) {module.controller("myctrl",["$scope", function($scope) {+(function(module) {module.controller("myctrl",["$scope",function($scope) { console.log("A"); $scope.A = "A";-}]);-module.factory("thefactory",["$http","xyz", function($http, xyz) {+}]);module.factory("thefactory",["$http","xyz",function($http, xyz) { console.log("B");-}]);-module.directive("my-directive", function() {- return { template: "<h1>Hello World</h1>" };-});-module.directive("myPane", function() {- return {+}]);module.directive("my-directive",function(){return{+ template: "<h1>Hello World</h1>"} ;})+ ;module.directive("myPane",function(){return{+ require: '^myTabs', restrict: 'E',- transclude: true,"controller":["$scope","ttt",- function($scope, ttt) {+ transclude: true,+ controller:["$scope","ttt",function($scope, ttt) { console.log("hah"); }], scope: {@@ -22,14 +19,14 @@ link: function(scope, element, attrs, tabsCtrl) { tabsCtrl.addPane(scope); },- templateUrl: 'paneid',- };-});module.directive("myTabs", function() {- return {+ templateUrl: 'paneid'}+ ;})+ ;module.directive("myTabs",function(){return{+ restrict: "E", transclude: true,- scope: {},"controller":["$scope",- function($scope) {+ scope: {},+ "controller":["$scope",function($scope) { var panes = $scope.panes = []; $scope.select = function(pane) {@@ -46,10 +43,9 @@ panes.push(pane); }; }],- "templateUrl": 'tabstemplateurl',- };-});-module.run(['$templateCache', function($templateCache) {+ "templateUrl": 'tabstemplateurl'}+ ;})+ ;module.run(['$templateCache', function($templateCache) { $templateCache.put("paneid","<div class=\"tab-pane\" ng-show=\"selected\" ng-transclude></div>\n<br>\n"); $templateCache.put("tabstemplateurl","<div class=\"tabbable\"><ul class=\"nav nav-tabs\"><br>\n<li ng-repeat=\"pane in panes\" ng-class=\"{active:pane.selected}\"><a href=\"\" ng-click=\"select(pane)\">{{pane.title}}</a>\n</li>\n</ul>\n<div class=\"tab-content\" ng-transclude></div>\n</div>\n"); }]);
test/angular/mod1.js.expected view
@@ -1,19 +1,16 @@-(function(module) {module.controller("myctrl",["$scope", function($scope) {+(function(module) {module.controller("myctrl",["$scope",function($scope) { console.log("A"); $scope.A = "A";-}]);-module.factory("thefactory",["$http","xyz", function($http, xyz) {+}]);module.factory("thefactory",["$http","xyz",function($http, xyz) { console.log("B");-}]);-module.directive("my-directive", function() {- return { template: "<h1>Hello World</h1>" };-});-module.directive("myPane", function() {- return {+}]);module.directive("my-directive",function(){return{+ template: "<h1>Hello World</h1>"} ;})+ ;module.directive("myPane",function(){return{+ require: '^myTabs', restrict: 'E',- transclude: true,"controller":["$scope","ttt",- function($scope, ttt) {+ transclude: true,+ controller:["$scope","ttt",function($scope, ttt) { console.log("hah"); }], scope: {@@ -22,14 +19,14 @@ link: function(scope, element, attrs, tabsCtrl) { tabsCtrl.addPane(scope); },- templateUrl: 'paneid',- };-});module.directive("myTabs", function() {- return {+ templateUrl: 'paneid'}+ ;})+ ;module.directive("myTabs",function(){return{+ restrict: "E", transclude: true,- scope: {},"controller":["$scope",- function($scope) {+ scope: {},+ "controller":["$scope",function($scope) { var panes = $scope.panes = []; $scope.select = function(pane) {@@ -46,8 +43,7 @@ panes.push(pane); }; }],- "templateUrl": 'tabstemplateurl',- };-});-})(angular.module("mod1",[]));+ "templateUrl": 'tabstemplateurl'}+ ;})+ ;})(angular.module("mod1",[])); Added by mini
test/angular/mod2.js.expected view
@@ -1,9 +1,7 @@-(function(module) {module.controller("thectrl", function() {+(function(module) {module.controller("thectrl",function() { console.log("ABC");-});-module.factory("a factory", function() {+});module.factory("a factory",function() { console.log("Factory!"); return {};-});-})(angular.module("mod2",["mod1"]));+});})(angular.module("mod2",["mod1"])); Added by mini
yesod-static-angular.cabal view
@@ -1,5 +1,5 @@ name: yesod-static-angular-version: 0.1.7+version: 0.1.8 cabal-version: >= 1.8 build-type: Simple synopsis: Yesod generators for embedding AngularJs code into yesod-static at compile time@@ -69,7 +69,7 @@ , directory >= 1.2 , filepath >= 1.3 , hamlet >= 1.1- , language-javascript >= 0.5+ , language-javascript >= 0.6 && < 0.7 , mime-types >= 0.1 , shakespeare >= 1.2 , template-haskell