├── .gitignore ├── testdata ├── JavaScriptGetText │ ├── name.txt │ └── index.html.template ├── transforms │ ├── buildProduction │ │ ├── GetStaticUrlFlash │ │ │ ├── swf │ │ │ │ └── foo.swf │ │ │ └── index.html │ │ ├── initialHtmlFragments │ │ │ ├── script.js │ │ │ ├── js │ │ │ │ └── script.js │ │ │ ├── myTemplate.html │ │ │ ├── foo.png │ │ │ └── index.html │ │ ├── inline │ │ │ ├── script.js │ │ │ ├── styles.css │ │ │ └── index.html │ │ ├── simple │ │ │ ├── someTextFile.txt │ │ │ ├── script1.js │ │ │ ├── script2.js │ │ │ ├── script3.js │ │ │ ├── morescripts │ │ │ │ ├── shimmed.js │ │ │ │ ├── somethingElse.js │ │ │ │ ├── amdDependency.js │ │ │ │ ├── view │ │ │ │ │ ├── styles.less │ │ │ │ │ └── template.ko │ │ │ │ └── main.js │ │ │ ├── styles1.css │ │ │ ├── styles3.css │ │ │ ├── styles2.css │ │ │ ├── myImage.gif │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── dataMainAndAlmondJs │ │ │ ├── a.js │ │ │ ├── d.js │ │ │ ├── almond.js │ │ │ ├── require.js │ │ │ └── index.html │ │ ├── bundlingInHtmlFragments │ │ │ ├── a.js │ │ │ ├── b.js │ │ │ ├── a.css │ │ │ ├── b.css │ │ │ └── index.html │ │ ├── duplicateImports │ │ │ ├── one.css │ │ │ ├── two.css │ │ │ ├── imported.css │ │ │ └── index.html │ │ ├── issue58 │ │ │ ├── templates │ │ │ │ └── header.html │ │ │ ├── js │ │ │ │ └── main.js │ │ │ └── index.html │ │ ├── lessPlugin │ │ │ ├── b.less │ │ │ ├── c.less │ │ │ ├── a.less │ │ │ ├── someModule.js │ │ │ ├── main.js │ │ │ ├── main2.js │ │ │ ├── index.html │ │ │ └── index2.html │ │ ├── htmlDataMainWithI18n │ │ │ ├── script.js │ │ │ ├── webmail.i18n │ │ │ └── index.html │ │ ├── assetsThatShouldNotBeMoved │ │ │ ├── .htaccess │ │ │ ├── robots.txt │ │ │ ├── humans.txt │ │ │ ├── favicon.ico │ │ │ └── index.html │ │ ├── implicitBaseUrl │ │ │ ├── src │ │ │ │ ├── component.js │ │ │ │ └── main.js │ │ │ └── index.html │ │ ├── requiredCssImport │ │ │ ├── other.css │ │ │ ├── foo.css │ │ │ └── index.html │ │ ├── issue60 │ │ │ ├── js │ │ │ │ ├── config.js │ │ │ │ ├── modules │ │ │ │ │ └── utils.js │ │ │ │ └── main.js │ │ │ └── index.html │ │ ├── knockoutJs │ │ │ ├── templates │ │ │ │ ├── bar.ko │ │ │ │ └── foo.ko │ │ │ ├── foo.png │ │ │ ├── someModule.js │ │ │ ├── main.js │ │ │ ├── index.html │ │ │ └── tpl.js │ │ ├── styleSheetInTemplate │ │ │ ├── style.css │ │ │ ├── component.html │ │ │ └── index.html │ │ ├── gzip │ │ │ ├── foo.js │ │ │ ├── foo.png │ │ │ ├── sockjs-0.3.4.js.gz │ │ │ └── index.html │ │ ├── requireJsConfigurationInExternalFile │ │ │ ├── theCorrectBase │ │ │ │ └── foo.js │ │ │ ├── theRequireJsConfig.js │ │ │ └── index.html │ │ ├── GetStaticUrlSingleFileWildcard │ │ │ ├── justThisOneFile.txt │ │ │ └── index.html │ │ ├── bootstrapperI18n │ │ │ ├── bootstrapper.js │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── requireJsOrphans │ │ │ ├── module1.js │ │ │ ├── module2.js │ │ │ ├── module4.js │ │ │ ├── module3.js │ │ │ ├── index.html │ │ │ └── main.js │ │ ├── GetStaticUrlSingleFileAndTwoWildcards │ │ │ ├── dir │ │ │ │ └── justThisOneFile.txt │ │ │ └── index.html │ │ ├── issue114 │ │ │ ├── a.js │ │ │ └── index.html │ │ ├── issue54 │ │ │ ├── js │ │ │ │ ├── vendor │ │ │ │ │ ├── deep-model.js │ │ │ │ │ └── backbone-amd │ │ │ │ │ │ └── backbone.js │ │ │ │ └── app.js │ │ │ └── index.html │ │ ├── multiPageRequireJs │ │ │ ├── common1.js │ │ │ ├── common2.js │ │ │ ├── main1.js │ │ │ ├── main2.js │ │ │ ├── index1.html │ │ │ └── index2.html │ │ ├── issue83 │ │ │ ├── script.js │ │ │ └── index.html │ │ ├── angularJs │ │ │ ├── index.i18n │ │ │ ├── bar.png │ │ │ ├── foo.png │ │ │ ├── partials │ │ │ │ └── 1.html │ │ │ ├── quux.png │ │ │ └── index.html │ │ ├── multipleHtmlsReferencingTheSameExternalRequireJsConfig │ │ │ ├── requireJsConfig.js │ │ │ ├── app │ │ │ │ ├── someDependency.js │ │ │ │ ├── main1.js │ │ │ │ └── main2.js │ │ │ ├── app1.html │ │ │ └── app2.html │ │ ├── rss │ │ │ ├── foo.png │ │ │ ├── index.html │ │ │ └── rssFeed.xml │ │ ├── initialAssetWithoutHtmlElement │ │ │ └── index.html │ │ ├── inkscape │ │ │ ├── index.html │ │ │ ├── styles.less │ │ │ └── image.svg │ │ ├── requireJsCdnPath │ │ │ ├── main.js │ │ │ └── index.html │ │ ├── angularJsMultipleTemplateRefs │ │ │ ├── partials │ │ │ │ └── 1.html │ │ │ └── index.html │ │ ├── fragmentWithUnpopulatedRelation │ │ │ ├── templates │ │ │ │ └── myTemplate.html │ │ │ └── index.html │ │ ├── nonInitialAssetWithIncomingHtmlAnchor │ │ │ ├── index2.html │ │ │ └── index.html │ │ ├── nonExistentFileWithoutExtension │ │ │ └── index.html │ │ ├── spriteAndProcessImages │ │ │ ├── foo.png │ │ │ └── index.html │ │ ├── faviconOutsideRoot │ │ │ ├── foo │ │ │ │ └── favicon.ico │ │ │ └── index.html │ │ ├── GetStaticUrlImageOnCdn │ │ │ ├── images │ │ │ │ └── test.png │ │ │ └── index.html │ │ ├── existingSourceMap │ │ │ └── index.html │ │ ├── imagesWithWrongExtensions │ │ │ ├── actuallyAPng.jpg │ │ │ ├── actuallyAJpeg.png │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── issue69 │ │ │ ├── index.html │ │ │ └── app │ │ │ │ └── main.js │ │ ├── JavaScriptGetStaticUrlWithProcessedImages │ │ │ ├── images │ │ │ │ ├── bar.png │ │ │ │ └── foo.png │ │ │ └── index.html │ │ ├── missingDataBind │ │ │ └── index.html │ │ ├── ssi │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── noCompress │ │ │ └── index.html │ │ ├── lessCompiler │ │ │ └── index.html │ │ ├── emptyScriptsAndStylesheetsWithAttributes │ │ │ └── index.html │ │ ├── stripDebug │ │ │ └── index.html │ │ └── svgsWithIdenticalInlineStyle │ │ │ ├── gears.svg │ │ │ └── gears2.svg │ ├── replaceDartWithJavaScript │ │ ├── app.dart │ │ ├── app.dart.js │ │ └── index.html │ ├── buildDevelopment │ │ ├── simple │ │ │ ├── script.js │ │ │ ├── styles.css │ │ │ ├── index.i18n │ │ │ └── index.html.template │ │ └── dataBindOnHtmlStyle │ │ │ └── index.html.template │ ├── autoprefixer │ │ ├── userselect.css │ │ ├── borderimage.css │ │ ├── borderimage.png │ │ └── index.html │ ├── cloneForEachLocale │ │ ├── css │ │ │ ├── doesNotNeedLocalization.css │ │ │ ├── bar.png │ │ │ ├── foo.png │ │ │ ├── index.html │ │ │ └── needsLocalization.css │ │ ├── knockoutTemplate │ │ │ ├── templateWithoutI18n.ko │ │ │ ├── index.html │ │ │ ├── index.js │ │ │ ├── templateWithI18n.ko │ │ │ └── index.i18n │ │ ├── simple │ │ │ ├── index.html.appcache │ │ │ ├── style.css │ │ │ ├── foo.png │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── localeCookieName │ │ │ ├── localeCookieName.js │ │ │ └── index.html │ │ ├── multipleHtmls │ │ │ ├── doesNotNeedLocalization.js │ │ │ ├── needsLocalization.js │ │ │ ├── index.i18n │ │ │ ├── 1.html │ │ │ └── 2.html │ │ ├── JavaScriptTrHtmlAndJavaScriptGetText │ │ │ ├── template.html │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── inlineScriptTemplateInKnockoutJsTemplate │ │ │ ├── index.js │ │ │ ├── template.ko │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── svg │ │ │ ├── index.i18n │ │ │ ├── index.html │ │ │ └── image.svg │ │ ├── trInHtmlDataBindAttributeInKoTemplate │ │ │ ├── template.ko │ │ │ ├── main.js │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── reusePlaceHolder │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── inlineCssCombo │ │ │ ├── foo.png │ │ │ └── index.html │ │ ├── JavaScriptTrHtml │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── inlineScriptTemplate │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── relationInPlaceHolder │ │ │ ├── index.i18n │ │ │ ├── foo.png │ │ │ └── index.html │ │ ├── trInHtmlDataBindAttribute │ │ │ ├── index.i18n │ │ │ └── index.html │ │ ├── globalVarUsageInJavaScript │ │ │ ├── index.html │ │ │ └── foo.js │ │ └── multipleLocales │ │ │ ├── index.html │ │ │ └── index.i18n │ ├── processImages │ │ ├── jpeg │ │ │ ├── style.css │ │ │ └── turtle.jpg │ │ ├── setFormat │ │ │ ├── index.css │ │ │ └── foo.png │ │ ├── dot.in.path │ │ │ ├── style.css │ │ │ └── redalpha24bit.png │ │ ├── html │ │ │ ├── myImage.png │ │ │ └── index.html │ │ ├── css │ │ │ ├── redalpha24bit.png │ │ │ ├── purplealpha24bit.png │ │ │ └── style.css │ │ ├── devicePixelRatio │ │ │ ├── foo.png │ │ │ ├── foo@2x.png │ │ │ ├── foo@8x.png │ │ │ └── style.css │ │ ├── pngs │ │ │ ├── redalpha24bit.png │ │ │ ├── purplealpha24bit.png │ │ │ └── style.css │ │ └── svg │ │ │ ├── addBogusElement.js │ │ │ └── index.html │ ├── duplicateFavicon │ │ ├── unreferencedFavicon │ │ │ ├── noHead.html │ │ │ ├── index.html │ │ │ └── favicon.ico │ │ └── referencedFavicon │ │ │ ├── favicon.ico │ │ │ └── index.html │ ├── checkLanguageKeys │ │ ├── duplicateLanguageKeys │ │ │ ├── external.js │ │ │ └── index.html │ │ ├── neverEndingSpaceLoop │ │ │ └── index.html │ │ ├── pluralRule │ │ │ ├── index.html │ │ │ └── index.i18n │ │ └── combo │ │ │ └── index.html │ ├── angularAnnotations │ │ └── basic.js │ └── runJavaScriptConditionalBlocks │ │ └── index.html ├── resolvers │ └── senchaJsBuilder │ │ ├── dependentPackages │ │ ├── js │ │ │ ├── A1.js │ │ │ ├── B1.js │ │ │ └── C1.js │ │ ├── index.html │ │ ├── overlappingIncludes.html │ │ └── foo.jsb2 │ │ └── rewriteBackgroundImageUrls │ │ ├── index.html │ │ ├── resources │ │ ├── images │ │ │ └── foo │ │ │ │ └── bar │ │ │ │ └── foo.png │ │ └── css │ │ │ └── subdir │ │ │ └── foo.css │ │ └── foo.jsb2 ├── bin │ ├── applyBabelJob │ │ ├── index.someother.i18n │ │ ├── translationjob │ │ │ ├── en.txt │ │ │ └── da.txt │ │ ├── index.i18n │ │ └── index.html │ ├── makeBabelJobAndApplyBabelJob │ │ ├── template.ko │ │ ├── index.html │ │ └── thething.i18n │ └── makeBabelJob │ │ ├── other.i18n │ │ ├── index.i18n │ │ └── index.html └── findParentDirectory │ ├── directory │ └── quux.png │ └── otherdirectory │ └── onemorelevel │ ├── bar.png │ └── foo.png ├── .jshintignore ├── test ├── mocha.opts ├── unexpected-with-plugins.js ├── transforms │ ├── angularAnnotations.js │ ├── replaceDartWithJavaScript.js │ ├── runJavaScriptConditionalBlocks.js │ ├── autoprefixer.js │ ├── buildDevelopment.js │ └── duplicateFavicon.js ├── JavaScriptGetText.js ├── findParentDirectory.js ├── i18nTools.js ├── resolvers │ └── senchaJsBuilder.js └── bin │ └── applyBabelJob.js ├── Dockerfile ├── lib ├── transforms │ ├── removeNobundleAttribute.js │ ├── omitFunctionCall.js │ ├── setAsyncOrDeferOnHtmlScripts.js │ ├── removeDuplicateHtmlStyles.js │ ├── injectBootstrapper.js │ ├── replaceDartWithJavaScript.js │ ├── angularAnnotations.js │ ├── autoprefixer.js │ ├── duplicateFavicon.js │ ├── addDataVersionAttributeToHtmlElement.js │ ├── stripDebug.js │ ├── gzip.js │ ├── runJavaScriptConditionalBlocks.js │ ├── buildDevelopment.js │ └── registerLabelsAsCustomProtocols.js ├── resolvers │ ├── index.js │ ├── findParentDirectory.js │ └── senchaJsBuilder.js ├── canonicalizeObject.js ├── mkpathSync.js ├── AssetGraph.js ├── loadAndInstantiateAutoprefixer.js └── PngQuantWithHistogram.js ├── .travis.yml ├── bin ├── optimizeImage ├── buildDevelopment ├── flattenOneInclude ├── findUnusedSelectors ├── copyReferencedAssets ├── checkLanguageKeys └── refreshI18n ├── LICENSE ├── package.json └── .jshintrc /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /coverage/ 3 | -------------------------------------------------------------------------------- /testdata/JavaScriptGetText/name.txt: -------------------------------------------------------------------------------- 1 | Foobar 2 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | testdata 3 | coverage 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/GetStaticUrlFlash/swf/foo.swf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/initialHtmlFragments/script.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/dependentPackages/js/A1.js: -------------------------------------------------------------------------------- 1 | A1(); 2 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/dependentPackages/js/B1.js: -------------------------------------------------------------------------------- 1 | B1(); 2 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/dependentPackages/js/C1.js: -------------------------------------------------------------------------------- 1 | C1(); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/inline/script.js: -------------------------------------------------------------------------------- 1 | alert("script"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/someTextFile.txt: -------------------------------------------------------------------------------- 1 | someText 2 | -------------------------------------------------------------------------------- /testdata/transforms/replaceDartWithJavaScript/app.dart: -------------------------------------------------------------------------------- 1 | 'I am Dart' 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildDevelopment/simple/script.js: -------------------------------------------------------------------------------- 1 | alert('script'); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/dataMainAndAlmondJs/a.js: -------------------------------------------------------------------------------- 1 | alert("a"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/dataMainAndAlmondJs/d.js: -------------------------------------------------------------------------------- 1 | alert("d"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/script1.js: -------------------------------------------------------------------------------- 1 | alert("script1"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/script2.js: -------------------------------------------------------------------------------- 1 | alert("script2"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/script3.js: -------------------------------------------------------------------------------- 1 | alert("script3"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/bundlingInHtmlFragments/a.js: -------------------------------------------------------------------------------- 1 | alert("a"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/bundlingInHtmlFragments/b.js: -------------------------------------------------------------------------------- 1 | alert("b"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/replaceDartWithJavaScript/app.dart.js: -------------------------------------------------------------------------------- 1 | 'I am JavaScript' 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/dataMainAndAlmondJs/almond.js: -------------------------------------------------------------------------------- 1 | alert("almond"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/dataMainAndAlmondJs/require.js: -------------------------------------------------------------------------------- 1 | alert("require"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/morescripts/shimmed.js: -------------------------------------------------------------------------------- 1 | alert('shimmed'); 2 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec 2 | --timeout 60000 3 | --recursive 4 | --check-leaks 5 | -------------------------------------------------------------------------------- /testdata/transforms/autoprefixer/userselect.css: -------------------------------------------------------------------------------- 1 | body { 2 | user-select: none; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildDevelopment/simple/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: beige; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/bundlingInHtmlFragments/a.css: -------------------------------------------------------------------------------- 1 | body {color: #aaa;} 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/bundlingInHtmlFragments/b.css: -------------------------------------------------------------------------------- 1 | body {color: #bbb;} 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/duplicateImports/one.css: -------------------------------------------------------------------------------- 1 | @import url("imported.css"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/duplicateImports/two.css: -------------------------------------------------------------------------------- 1 | @import url("imported.css"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue58/templates/header.html: -------------------------------------------------------------------------------- 1 |

The header

2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessPlugin/b.less: -------------------------------------------------------------------------------- 1 | body { 2 | color: tan; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/styles1.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: teal; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/styles3.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: tan; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/htmlDataMainWithI18n/script.js: -------------------------------------------------------------------------------- 1 | INCLUDE('webmail.i18n'); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/inline/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: maroon; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessPlugin/c.less: -------------------------------------------------------------------------------- 1 | body { 2 | text-indent: 10px; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/styles2.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: maroon; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/assetsThatShouldNotBeMoved/.htaccess: -------------------------------------------------------------------------------- 1 | AddType text/html .shtml 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/implicitBaseUrl/src/component.js: -------------------------------------------------------------------------------- 1 | define([], function () {}); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requiredCssImport/other.css: -------------------------------------------------------------------------------- 1 | span { 2 | color: green; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/morescripts/somethingElse.js: -------------------------------------------------------------------------------- 1 | alert('something else'); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/assetsThatShouldNotBeMoved/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/duplicateImports/imported.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: white; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/implicitBaseUrl/src/main.js: -------------------------------------------------------------------------------- 1 | require(['component'], function () {}); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue60/js/config.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | baseUrl: '/js' 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/knockoutJs/templates/bar.ko: -------------------------------------------------------------------------------- 1 |
2 |

bar.ko

3 |
4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessPlugin/a.less: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: beige; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/styleSheetInTemplate/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: red; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/gzip/foo.js: -------------------------------------------------------------------------------- 1 | alert("this is a tiny script that's not worth gzipping"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessPlugin/someModule.js: -------------------------------------------------------------------------------- 1 | define(['less!b.less'], function () { 2 | }); 3 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsConfigurationInExternalFile/theCorrectBase/foo.js: -------------------------------------------------------------------------------- 1 | alert("foo"); 2 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/css/doesNotNeedLocalization.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: red; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/knockoutTemplate/templateWithoutI18n.ko: -------------------------------------------------------------------------------- 1 |
No i18n stuff here!
2 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/simple/index.html.appcache: -------------------------------------------------------------------------------- 1 | CACHE MANIFEST 2 | style.css 3 | foo.png 4 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/jpeg/style.css: -------------------------------------------------------------------------------- 1 | #turtle { 2 | background-image: url(turtle.jpg); 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/GetStaticUrlSingleFileWildcard/justThisOneFile.txt: -------------------------------------------------------------------------------- 1 | The contents of the file. 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/bootstrapperI18n/bootstrapper.js: -------------------------------------------------------------------------------- 1 | var keys = JSON.parse(GETTEXT('index.i18n')); 2 | -------------------------------------------------------------------------------- /testdata/transforms/autoprefixer/borderimage.css: -------------------------------------------------------------------------------- 1 | body { 2 | border-image: url(borderimage.png) 30 30 repeat; 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/knockoutJs/templates/foo.ko: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsOrphans/module1.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | return 'module1'; 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsOrphans/module2.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | return 'module2'; 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsOrphans/module4.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | return 'module4'; 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requiredCssImport/foo.css: -------------------------------------------------------------------------------- 1 | @import "other.css"; 2 | body { 3 | color: red; 4 | } 5 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/localeCookieName/localeCookieName.js: -------------------------------------------------------------------------------- 1 | var bar = LOCALECOOKIENAME; 2 | alert(bar); 3 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/GetStaticUrlSingleFileAndTwoWildcards/dir/justThisOneFile.txt: -------------------------------------------------------------------------------- 1 | The contents of the file. 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/initialHtmlFragments/js/script.js: -------------------------------------------------------------------------------- 1 | var myTemplateUrl = GETSTATICURL('myTemplate.html'); 2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue114/a.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var aJS = true; 3 | console.log(aJS); 4 | }()); 5 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue54/js/vendor/deep-model.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | return "deepmodel"; 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multiPageRequireJs/common1.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | alert("common1"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multiPageRequireJs/common2.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | alert("common2"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/setFormat/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url(foo.png?setFormat=gif); 3 | } 4 | -------------------------------------------------------------------------------- /testdata/bin/applyBabelJob/index.someother.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "KeyInSomeOtherI18nFile": { 3 | "en": "Woop" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/assetsThatShouldNotBeMoved/humans.txt: -------------------------------------------------------------------------------- 1 | /* SITE */ 2 | 3 | This site was made by humans. 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue54/js/vendor/backbone-amd/backbone.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | return "backbone"; 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue60/js/modules/utils.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | alert("These are the utils!"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessPlugin/main.js: -------------------------------------------------------------------------------- 1 | require(['less!a.less', 'someModule', 'less!c.less'], function () { 2 | }); 3 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessPlugin/main2.js: -------------------------------------------------------------------------------- 1 | require(['less!a.less', 'someModule', 'less!c.less'], function () { 2 | }); 3 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/simple/style.css: -------------------------------------------------------------------------------- 1 | .bogus { 2 | color: red; 3 | background-image: url(foo.png); 4 | } 5 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue60/js/main.js: -------------------------------------------------------------------------------- 1 | require(['modules/utils'], function(Utils) { 2 | console.log('Ready.'); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue83/script.js: -------------------------------------------------------------------------------- 1 | function hey ($$super, foo, quux) { 2 | $$super.foo(); 3 | quux.baz(); 4 | } 5 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/morescripts/amdDependency.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | console.warn("here I AM(D)"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/morescripts/view/styles.less: -------------------------------------------------------------------------------- 1 | body { 2 | & div { 3 | width: 100px; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/multipleHtmls/doesNotNeedLocalization.js: -------------------------------------------------------------------------------- 1 | INCLUDE('needsLocalization.js'); 2 | 3 | alert("hello"); 4 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/multipleHtmls/needsLocalization.js: -------------------------------------------------------------------------------- 1 | INCLUDE('index.i18n'); 2 | 3 | alert(TR('languageKey', 'yup')); 4 | -------------------------------------------------------------------------------- /testdata/transforms/duplicateFavicon/unreferencedFavicon/noHead.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/dot.in.path/style.css: -------------------------------------------------------------------------------- 1 | #redalpha24bit { 2 | background-image: url(redalpha24bit.png?optipng); 3 | } 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multiPageRequireJs/main1.js: -------------------------------------------------------------------------------- 1 | require(['common1', 'common2'], function () { 2 | alert("main1"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multiPageRequireJs/main2.js: -------------------------------------------------------------------------------- 1 | require(['common1', 'common2'], function () { 2 | alert("main2"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsOrphans/module3.js: -------------------------------------------------------------------------------- 1 | define(['module4'], function (module4) { 2 | return 'module3+' + module4; 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/styleSheetInTemplate/component.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/JavaScriptTrHtmlAndJavaScriptGetText/template.html: -------------------------------------------------------------------------------- 1 | The default value 2 | -------------------------------------------------------------------------------- /testdata/bin/makeBabelJobAndApplyBabelJob/template.ko: -------------------------------------------------------------------------------- 1 |

Simple key in a Knockout.js template

2 | -------------------------------------------------------------------------------- /testdata/findParentDirectory/directory/quux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/findParentDirectory/directory/quux.png -------------------------------------------------------------------------------- /testdata/transforms/autoprefixer/borderimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/autoprefixer/borderimage.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/angularJs/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "foo": { 3 | "da": "lige direkte", 4 | "en": "directly" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/gzip/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/gzip/foo.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multipleHtmlsReferencingTheSameExternalRequireJsConfig/requireJsConfig.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | baseUrl: '/' 3 | }; 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/rss/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/rss/foo.png -------------------------------------------------------------------------------- /testdata/bin/makeBabelJob/other.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "KeyAlreadyPartiallyTranslatedInOtherI18n": { 3 | "de": "Existing translation to German" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/bootstrapperI18n/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "TheTitle": { 3 | "en": "The title", 4 | "da": "Titelen" 5 | } 6 | } -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/morescripts/view/template.ko: -------------------------------------------------------------------------------- 1 | The link text 2 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/css/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/cloneForEachLocale/css/bar.png -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/css/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/cloneForEachLocale/css/foo.png -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/inlineScriptTemplateInKnockoutJsTemplate/index.js: -------------------------------------------------------------------------------- 1 | INCLUDE('index.i18n'); 2 | 3 | var template = GETTEXT('template.ko'); 4 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/multipleHtmls/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "languageKey": { 3 | "en": "yup", 4 | "da": "jeps" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/svg/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "keyName": { 3 | "da": "Dansk nøgle", 4 | "en": "English key" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/html/myImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/html/myImage.png -------------------------------------------------------------------------------- /testdata/transforms/processImages/jpeg/turtle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/jpeg/turtle.jpg -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/angularJs/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/angularJs/bar.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/angularJs/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/angularJs/foo.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/angularJs/partials/1.html: -------------------------------------------------------------------------------- 1 |

1: External template loaded asynchronously with templateUrl: 'partials/1.html'

2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/htmlDataMainWithI18n/webmail.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "languageKey": { 3 | "da": "foo", 4 | "en": "bar" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/initialAssetWithoutHtmlElement/index.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/simple/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/cloneForEachLocale/simple/foo.png -------------------------------------------------------------------------------- /testdata/transforms/processImages/setFormat/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/setFormat/foo.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/angularJs/quux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/angularJs/quux.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/initialHtmlFragments/myTemplate.html: -------------------------------------------------------------------------------- 1 |
2 |

Template with a relative image reference:

3 |
4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/inkscape/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/knockoutJs/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/knockoutJs/foo.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsCdnPath/main.js: -------------------------------------------------------------------------------- 1 | require(['jquery'], function ($) { 2 | $(function () { 3 | alert('Ready!'); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/myImage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/simple/myImage.gif -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/trInHtmlDataBindAttributeInKoTemplate/template.ko: -------------------------------------------------------------------------------- 1 |
foo
2 | -------------------------------------------------------------------------------- /testdata/transforms/duplicateFavicon/unreferencedFavicon/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/css/redalpha24bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/css/redalpha24bit.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/knockoutJs/someModule.js: -------------------------------------------------------------------------------- 1 | define(['tpl!templates/foo.ko'], function () { 2 | alert("The module that also requires foo.ko!"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multipleHtmlsReferencingTheSameExternalRequireJsConfig/app/someDependency.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | return "some dependency"; 3 | }); -------------------------------------------------------------------------------- /testdata/transforms/checkLanguageKeys/duplicateLanguageKeys/external.js: -------------------------------------------------------------------------------- 1 | alert(TR('AnotherSimpleAndIdentical1', 'Blah')); 2 | alert(TR('AnotherSimpleAndIdentical2', 'Blah')); 3 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/css/purplealpha24bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/css/purplealpha24bit.png -------------------------------------------------------------------------------- /testdata/transforms/processImages/devicePixelRatio/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/devicePixelRatio/foo.png -------------------------------------------------------------------------------- /testdata/transforms/processImages/pngs/redalpha24bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/pngs/redalpha24bit.png -------------------------------------------------------------------------------- /testdata/transforms/angularAnnotations/basic.js: -------------------------------------------------------------------------------- 1 | /*global angular*/ 2 | angular.module('MyMod').controller('MyCtrl', function ($scope, $timeout) { return [$scope, $timeout]; }); 3 | -------------------------------------------------------------------------------- /testdata/transforms/buildDevelopment/simple/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "myLanguageKey": { 3 | "en": "The English value", 4 | "da": "Den danske værdi" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/gzip/sockjs-0.3.4.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/gzip/sockjs-0.3.4.js.gz -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/knockoutJs/main.js: -------------------------------------------------------------------------------- 1 | require(['tpl!templates/foo.ko', 'someModule', 'tpl!templates/bar.ko'], function () { 2 | alert("Alles klar!"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/reusePlaceHolder/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "foo": { 3 | "en": "Some {0} thing", 4 | "da": "Some {0} {0} thing" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/pngs/purplealpha24bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/pngs/purplealpha24bit.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/angularJsMultipleTemplateRefs/partials/1.html: -------------------------------------------------------------------------------- 1 |

1: External template loaded asynchronously with templateUrl: 'partials/1.html'

2 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/fragmentWithUnpopulatedRelation/templates/myTemplate.html: -------------------------------------------------------------------------------- 1 |
2 | Link pointing somewhere else 3 |
4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/nonInitialAssetWithIncomingHtmlAnchor/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsConfigurationInExternalFile/theRequireJsConfig.js: -------------------------------------------------------------------------------- 1 | var require = { 2 | paths: { 3 | foo: "theCorrectBase/foo" 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/inlineCssCombo/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/cloneForEachLocale/inlineCssCombo/foo.png -------------------------------------------------------------------------------- /testdata/transforms/processImages/devicePixelRatio/foo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/devicePixelRatio/foo@2x.png -------------------------------------------------------------------------------- /testdata/transforms/processImages/devicePixelRatio/foo@8x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/devicePixelRatio/foo@8x.png -------------------------------------------------------------------------------- /testdata/transforms/processImages/dot.in.path/redalpha24bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/processImages/dot.in.path/redalpha24bit.png -------------------------------------------------------------------------------- /testdata/findParentDirectory/otherdirectory/onemorelevel/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/findParentDirectory/otherdirectory/onemorelevel/bar.png -------------------------------------------------------------------------------- /testdata/findParentDirectory/otherdirectory/onemorelevel/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/findParentDirectory/otherdirectory/onemorelevel/foo.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/initialHtmlFragments/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/initialHtmlFragments/foo.png -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/JavaScriptTrHtml/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "myLanguageKey": { 3 | "da": "Den danske værdi", 4 | "en": "The English value" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/inlineScriptTemplate/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "MyLanguageKey": { 3 | "da": "Min sprognøgle", 4 | "en": "My language key" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/relationInPlaceHolder/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "foo": { 3 | "en": "Some {0} thing", 4 | "da": "Et {0} eller {0} andet" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/simple/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "the.key.name": { 3 | "en_US": "The American English text", 4 | "da": "The Danish text" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/replaceDartWithJavaScript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/initialHtmlFragments/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue58/js/main.js: -------------------------------------------------------------------------------- 1 | require([ 2 | 'text!/templates/header.html' 3 | ], function (headerHtml) { 4 | alert("Got the header HTML: " + headerHtml); 5 | }); 6 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue83/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/nonExistentFileWithoutExtension/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/spriteAndProcessImages/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/spriteAndProcessImages/foo.png -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/knockoutTemplate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/relationInPlaceHolder/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/cloneForEachLocale/relationInPlaceHolder/foo.png -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/trInHtmlDataBindAttribute/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "keyname": { 3 | "en": "The English value", 4 | "da": "Den danske værdi" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/trInHtmlDataBindAttributeInKoTemplate/main.js: -------------------------------------------------------------------------------- 1 | require(['tpl!template.ko'], function () { 2 | // Here I am with my lovely template in scope... 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/duplicateFavicon/referencedFavicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/duplicateFavicon/referencedFavicon/favicon.ico -------------------------------------------------------------------------------- /testdata/transforms/duplicateFavicon/unreferencedFavicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/duplicateFavicon/unreferencedFavicon/favicon.ico -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/faviconOutsideRoot/foo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/faviconOutsideRoot/foo/favicon.ico -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/knockoutJs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessPlugin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessPlugin/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/globalVarUsageInJavaScript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/inlineScriptTemplateInKnockoutJsTemplate/template.ko: -------------------------------------------------------------------------------- 1 | 4 |
5 |
6 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/localeCookieName/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/JavaScriptGetText/index.html.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/multipleHtmls/1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | First HTML 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/trInHtmlDataBindAttributeInKoTemplate/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "keyname": { 3 | "en": "The English value", 4 | "da": "Den danske værdi" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/svg/addBogusElement.js: -------------------------------------------------------------------------------- 1 | var g = document.createElement('g'); 2 | g.setAttribute('id', svgFilter.bogusElementId || 'blablaf'); 3 | document.documentElement.appendChild(g); 4 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/rewriteBackgroundImageUrls/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/GetStaticUrlImageOnCdn/images/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/GetStaticUrlImageOnCdn/images/test.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/assetsThatShouldNotBeMoved/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/assetsThatShouldNotBeMoved/favicon.ico -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/htmlDataMainWithI18n/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multipleHtmlsReferencingTheSameExternalRequireJsConfig/app/main1.js: -------------------------------------------------------------------------------- 1 | require(['app/someDependency'], function (someDependency) { 2 | alert("main1 ready to go"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multipleHtmlsReferencingTheSameExternalRequireJsConfig/app/main2.js: -------------------------------------------------------------------------------- 1 | require(['app/someDependency'], function (someDependency) { 2 | alert("main2 ready to go"); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/JavaScriptTrHtmlAndJavaScriptGetText/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "myLanguageKey": { 3 | "da": "Den danske værdi", 4 | "en": "The English value" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/inlineScriptTemplateInKnockoutJsTemplate/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "MyLanguageKey": { 3 | "da": "Min sprognøgle", 4 | "en": "My language key" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/multipleHtmls/2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Second HTML 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/dependentPackages/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/bundlingInHtmlFragments/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/existingSourceMap/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/imagesWithWrongExtensions/actuallyAPng.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/imagesWithWrongExtensions/actuallyAPng.jpg -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue114/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Text
8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue58/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue69/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/inlineScriptTemplateInKnockoutJsTemplate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/imagesWithWrongExtensions/actuallyAJpeg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/imagesWithWrongExtensions/actuallyAJpeg.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/imagesWithWrongExtensions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/nonInitialAssetWithIncomingHtmlAnchor/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | hello 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsOrphans/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/knockoutTemplate/index.js: -------------------------------------------------------------------------------- 1 | INCLUDE('index.i18n'); 2 | 3 | var templateWithoutI18n = GETTEXT('templateWithoutI18n.ko'), 4 | templateWithI18n = GETTEXT('templateWithI18n.ko'); 5 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsOrphans/main.js: -------------------------------------------------------------------------------- 1 | require(['module1', 'module2', 'module3'], function (module1, module2, module3) { 2 | alert("got " + module1 + ", " + module2 + ', and ' + module3); 3 | }); 4 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/globalVarUsageInJavaScript/foo.js: -------------------------------------------------------------------------------- 1 | alert(LOCALEID); 2 | alert(DEFAULTLOCALEID); 3 | alert(LOCALECOOKIENAME); 4 | alert(SUPPORTEDLOCALEIDS); 5 | LOCALEID="foo"; // Shouldn't be replaced 6 | -------------------------------------------------------------------------------- /testdata/transforms/duplicateFavicon/referencedFavicon/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/GetStaticUrlFlash/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue54/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multiPageRequireJs/index1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multiPageRequireJs/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/duplicateImports/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/GetStaticUrlImageOnCdn/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/JavaScriptGetStaticUrlWithProcessedImages/images/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/JavaScriptGetStaticUrlWithProcessedImages/images/bar.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/JavaScriptGetStaticUrlWithProcessedImages/images/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/transforms/buildProduction/JavaScriptGetStaticUrlWithProcessedImages/images/foo.png -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/rewriteBackgroundImageUrls/resources/images/foo/bar/foo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/podio/assetgraph-builder/master/testdata/resolvers/senchaJsBuilder/rewriteBackgroundImageUrls/resources/images/foo/bar/foo.png -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/rss/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/faviconOutsideRoot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/dependentPackages/overlappingIncludes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/inline/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/svg/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/missingDataBind/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/svg/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/css/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/trInHtmlDataBindAttributeInKoTemplate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/ssi/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "title": { 3 | "en": "Yes, {0} like that", 4 | "da": "Ja, {0} sådan" 5 | }, 6 | "somethingelse": { 7 | "en": "{0} is the thing", 8 | "da": "{0} er tingen" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/pngs/style.css: -------------------------------------------------------------------------------- 1 | #redalpha24bit { 2 | background-image: url(redalpha24bit.png); 3 | _background-image: url(redalpha24bit.png?pngquant=256); 4 | } 5 | 6 | #purplealpha24bit { 7 | background-image: url(purplealpha24bit.png?pngcrush); 8 | } 9 | -------------------------------------------------------------------------------- /testdata/bin/applyBabelJob/translationjob/en.txt: -------------------------------------------------------------------------------- 1 | foo=FooProofRead 2 | bar=BarProofRead 3 | placeholders=This proofread key has {0} proofread placeholders 4 | WeirdlyFormattedKey=that comes back the same in the translation job 5 | ComplexKey[that]=also comes 6 | ComplexKey[back]=the same 7 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/trInHtmlDataBindAttribute/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
foo
7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/reusePlaceHolder/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
Some foo thing
6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/GetStaticUrlSingleFileWildcard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requiredCssImport/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/styleSheetInTemplate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/relationInPlaceHolder/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
Some thing
6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/css/style.css: -------------------------------------------------------------------------------- 1 | #redalpha24bit { 2 | background-image: url(redalpha24bit.png?irrelevant); 3 | _background-image: url(redalpha24bit.png?pngquant=128); 4 | } 5 | 6 | #purplealpha24bit { 7 | background-image: url(purplealpha24bit.png?pngquant=256); 8 | } 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/fragmentWithUnpopulatedRelation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/bootstrapperI18n/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Default title 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/unexpected-with-plugins.js: -------------------------------------------------------------------------------- 1 | var expect = require('unexpected') 2 | .clone() 3 | .installPlugin(require('unexpected-sinon')) 4 | .installPlugin(require('assetgraph/test/unexpectedAssetGraph')); 5 | 6 | // expect.output.installPlugin(require('magicpen-prism')); 7 | 8 | module.exports = expect; 9 | -------------------------------------------------------------------------------- /testdata/bin/applyBabelJob/translationjob/da.txt: -------------------------------------------------------------------------------- 1 | foo=FooOversat 2 | bar=BarOversat 3 | placeholders=Denne oversatte nøgle har {0} pladsholdere 4 | WeirdlyFormattedKey=der kommer uændret retur i oversættelsesjobbet 5 | ComplexKey[that]=også kommer 6 | ComplexKey[back]=det samme 7 | KeyInSomeOtherI18nFile=Jubii 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/GetStaticUrlSingleFileAndTwoWildcards/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multipleHtmlsReferencingTheSameExternalRequireJsConfig/app1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/multipleHtmlsReferencingTheSameExternalRequireJsConfig/app2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/noCompress/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/inlineCssCombo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ... 5 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/bin/applyBabelJob/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "foo": { 3 | "en": "Foo", 4 | "da": null 5 | }, 6 | "bar": { 7 | "en": "Bar", 8 | "da": null 9 | }, 10 | "placeholders": { 11 | "en": "This key has {0} placeholders", 12 | "da": null 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/implicitBaseUrl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue69/app/main.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | baseUrl: 'app', 3 | enforceDefine: false, 4 | paths: { 5 | sockjs: '../vendor/sockjs/sockjs-0.3.4' 6 | } 7 | }); 8 | 9 | require(['sockjs'], function (sockjs) { 10 | alert("got sockjs: " + sockjs); 11 | }); 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node 2 | 3 | RUN apt-get update 4 | RUN apt-get install -y --no-install-recommends libcairo2-dev libgif-dev optipng pngcrush pngquant libpango1.0-dev graphicsmagick libjpeg-progs inkscape libvips-dev libgsf-1-dev 5 | RUN npm install -g assetgraph-builder 6 | 7 | ENTRYPOINT ["/usr/local/bin/buildProduction"] 8 | -------------------------------------------------------------------------------- /testdata/transforms/buildDevelopment/dataBindOnHtmlStyle/index.html.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 |

My Shop

8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/JavaScriptGetStaticUrlWithProcessedImages/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/JavaScriptTrHtmlAndJavaScriptGetText/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/gzip/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/JavaScriptTrHtml/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue54/js/app.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | paths: { 3 | backbone: 'vendor/backbone-amd/backbone', 4 | deepmodel: 'vendor/deep-model' 5 | } 6 | }); 7 | 8 | require(['backbone', 'deepmodel'], function (backbone, deepmodel) { 9 | alert("Yup, got " + backbone + " and " + deepmodel); 10 | }); 11 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/inlineScriptTemplate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/transforms/autoprefixer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/issue60/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/lessCompiler/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/ssi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Yes, <!--#echo "exactly" --> like that 5 | 6 | 7 |
is the thing
8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/imagesWithWrongExtensions/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url(actuallyAJpeg.png?sprite=foo); 3 | } 4 | 5 | .quux { 6 | background-image: url(actuallyAPng.jpg?sprite=foo); 7 | } 8 | 9 | .bar { 10 | background-image: url(actuallyAJpeg.png); 11 | } 12 | 13 | .baz { 14 | background-image: url(actuallyAPng.jpg); 15 | } -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "documentTitle": { 3 | "en": "The English title", 4 | "da": "Den danske titel" 5 | }, 6 | "linkText": { 7 | "en": "The English link text", 8 | "da": "Den danske linktekst" 9 | }, 10 | "greeting": { 11 | "en": "Hello!", 12 | "da": "Hej!" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsConfigurationInExternalFile/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/morescripts/main.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | shim: { 3 | shimmed: ['somethingElse'] 4 | } 5 | }); 6 | 7 | require([ 8 | 'shimmed', 9 | 'amdDependency', 10 | 'tpl!view/template.ko', 11 | 'less!view/styles.less' 12 | ], function (shimmedDependency, amdDependency) { 13 | alert(TR('greeting', 'Hello!')); 14 | }); 15 | -------------------------------------------------------------------------------- /testdata/transforms/buildDevelopment/simple/index.html.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The default title 5 | 6 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/transforms/checkLanguageKeys/neverEndingSpaceLoop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/rewriteBackgroundImageUrls/foo.jsb2: -------------------------------------------------------------------------------- 1 | { 2 | "licenseText": "Ext JS Library 3.0.0 <-- This is the trigger for fixing background-image urls", 3 | "pkgs": [{ 4 | "name": "CSS stuff", 5 | "file": "resources/css/stuff.css", 6 | "fileIncludes": [{ 7 | "text": "foo.css", 8 | "path": "resources/css/subdir/" 9 | }] 10 | }] 11 | } 12 | -------------------------------------------------------------------------------- /lib/transforms/removeNobundleAttribute.js: -------------------------------------------------------------------------------- 1 | module.exports = function (queryObj) { 2 | return function removeNobundleAttribute(assetGraph) { 3 | assetGraph.findRelations(queryObj).forEach(function (relation) { 4 | if (relation.node.hasAttribute('nobundle')) { 5 | relation.node.removeAttribute('nobundle'); 6 | relation.from.markDirty(); 7 | } 8 | }); 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/assetsThatShouldNotBeMoved/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Here's my .htaccess file, grab it if you can! 9 | If you're a robot, please refer to robots.txt. 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/transforms/runJavaScriptConditionalBlocks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/requireJsCdnPath/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/dataMainAndAlmondJs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/spriteAndProcessImages/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/inkscape/styles.less: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url("image.svg?inkscape=--export-width=70,--export-area=0:0:70:12"); 3 | background-size: 70px; 4 | background-repeat: no-repeat; 5 | background-position: center center; 6 | } 7 | @media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx), (min-resolution: 144dpi) { 8 | body { 9 | background-image: url("image.svg?inkscape=--export-width=105,--export-area=0:0:70:12"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/emptyScriptsAndStylesheetsWithAttributes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/knockoutTemplate/templateWithI18n.ko: -------------------------------------------------------------------------------- 1 |
2 |
foo
3 | bar 4 | quux 5 | baz 6 | Here is a Nice and beautiful nested i18n construct 7 |
8 | -------------------------------------------------------------------------------- /lib/resolvers/index.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | // Start with AssetGraph's built-in resolvers: 4 | 5 | _.extend(exports, require('assetgraph').resolvers); 6 | 7 | // Install getters for all resolvers in this directory: 8 | 9 | require('fs').readdirSync(__dirname).forEach(function (fileName) { 10 | if (/\.js$/.test(fileName) && fileName !== 'index.js') { 11 | exports.__defineGetter__(fileName.replace(/\.js$/, ''), function () { 12 | return require('./' + fileName); 13 | }); 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/svg/image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The default text 5 | 6 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/inkscape/image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The default text 5 | 6 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/stripDebug/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/angularJsMultipleTemplateRefs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My AngularJS App 5 | 6 | 7 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /lib/canonicalizeObject.js: -------------------------------------------------------------------------------- 1 | module.exports = function canonicalizeObject(obj, numLevels) { 2 | if (typeof numLevels !== 'number') { 3 | numLevels = Infinity; 4 | } 5 | if (Array.isArray(obj)) { 6 | return obj.map(canonicalizeObject, numLevels - 1); 7 | } else if (typeof obj === 'object' && obj !== null && numLevels > 0) { 8 | var sortedObj = {}; 9 | Object.keys(obj).sort().forEach(function (key) { 10 | sortedObj[key] = canonicalizeObject(obj[key], numLevels - 1); 11 | }); 12 | return sortedObj; 13 | } else { 14 | return obj; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/css/needsLocalization.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-weight: bold; 3 | } 4 | 5 | html[lang=da] .theThing { 6 | width: 128px; 7 | background-image: url(foo.png); 8 | } 9 | 10 | html[lang="de"].anotherClassOnHtml .theGermanThing { 11 | width: 130px; 12 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC); 13 | } 14 | 15 | html[lang="sv"] .theSwedishThing { 16 | width: 128px; 17 | background-image: url(bar.png); 18 | } 19 | -------------------------------------------------------------------------------- /lib/transforms/omitFunctionCall.js: -------------------------------------------------------------------------------- 1 | // GETSTATICURL(fileNameOrHash) => fileNameOrHash 2 | // TRHTML(htmlString) => htmlString 3 | // Saves bytes, but makes it impossible to recognize the relations again. 4 | 5 | module.exports = function (queryObj) { 6 | return function omitFunctionCall(assetGraph) { 7 | assetGraph.findRelations(queryObj).filter(function (relation) { 8 | return relation.type === 'JavaScriptTrHtml' || relation.type === 'JavaScriptGetStaticUrl'; 9 | }).forEach(function (relation) { 10 | relation.omitFunctionCall = true; 11 | relation.inline(); 12 | }); 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /testdata/transforms/checkLanguageKeys/pluralRule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib/mkpathSync.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | path = require('path'); 3 | 4 | function mkpathSync(p, permissions) { 5 | if (typeof permissions === 'undefined') { 6 | permissions = '0777'; 7 | } 8 | if (!/^\//.test(p)) { 9 | p = process.cwd() + '/' + p; 10 | } 11 | p = path.normalize(p).replace(/\/$/, ''); 12 | if (!(fs.existsSync || path.existsSync)(p)) { 13 | var fragments = p.split('/'); 14 | if (fragments.length > 1) { 15 | mkpathSync(fragments.slice(0, fragments.length - 1).join('/'), permissions); 16 | fs.mkdirSync(p, permissions); 17 | } 18 | } 19 | } 20 | 21 | module.exports = mkpathSync; 22 | -------------------------------------------------------------------------------- /testdata/transforms/processImages/devicePixelRatio/style.css: -------------------------------------------------------------------------------- 1 | .p1 { 2 | background-image: url(foo.png); 3 | } 4 | 5 | .p2 { 6 | background-image: url(foo@2x.png); 7 | } 8 | 9 | .p3 { 10 | background-image: url(foo.png?dpr=3); 11 | } 12 | 13 | .p4 { 14 | background-image: url(foo.png?resize=,200); 15 | } 16 | 17 | .p5 { 18 | background-image: url(foo.png?resize=,200&dpr=5); 19 | } 20 | 21 | .p6 { 22 | background-image: url(foo.png?dpr=6&resize=,200); 23 | } 24 | 25 | .p7 { 26 | background-image: url(foo.png?dpr=7&foo=bar); 27 | } 28 | 29 | .p8 { 30 | background-image: url(foo@8x.png?dpr=1); 31 | } 32 | 33 | .p9 { 34 | background-image: url(foo.png?setFormat=jpg&dpr=9); 35 | } 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | before_install: "sudo apt-get update && sudo apt-get install -y libcairo2-dev libjpeg8-dev libgif-dev optipng pngcrush pngquant libpango1.0-dev graphicsmagick libjpeg-turbo-progs inkscape && npm install -g npm && npm cache clean" 5 | script: "npm run-script travis" 6 | after_success: " 2 | 3 | 4 | 5 | 6 |

Bla bla

7 |

A beautiful text with lovely placeholders in it

8 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/rss/rssFeed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RSS Title 5 | This is an example of an RSS feed 6 | index.html 7 | Mon, 06 Sep 2010 00:01:00 +0000 8 | Mon, 06 Sep 2009 16:20:00 +0000 9 | 1800 10 | 11 | Example entry 12 | Here is some text containing an interesting description and an image: <img src="foo.png" />. 13 | http://www.wikipedia.org/ 14 | unique string per item 15 | Mon, 06 Sep 2009 16:20:00 +0000 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/transforms/removeDuplicateHtmlStyles.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | // https://github.com/One-com/assetgraph/issues/82 4 | 5 | module.exports = function (queryObj) { 6 | return function removeDuplicateHtmlStyles(assetGraph) { 7 | assetGraph.findAssets(_.extend({type: 'Html'}, queryObj)).forEach(function (htmlAsset) { 8 | var seenCssAssetsById = {}; 9 | assetGraph.findRelations({from: htmlAsset, type: 'HtmlStyle'}).forEach(function (htmlStyle) { 10 | if (seenCssAssetsById[htmlStyle.to.id]) { 11 | htmlStyle.detach(); 12 | } else { 13 | seenCssAssetsById[htmlStyle.to.id] = true; 14 | } 15 | }); 16 | }); 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/rewriteBackgroundImageUrls/resources/css/subdir/foo.css: -------------------------------------------------------------------------------- 1 | .x-html-editor-tb .x-edit-bold, .x-menu-item img.x-edit-bold { 2 | background-position:0 0; 3 | background-image:url(../images/foo/bar/foo.png); 4 | } 5 | 6 | .x-html-editor-tb .x-edit-italic, .x-menu-item img.x-edit-italic { 7 | background-position:-16px 0; 8 | background-image:url(../images/foo/bar/foo.png); 9 | } 10 | 11 | .x-html-editor-tb .x-edit-underline, .x-menu-item img.x-edit-underline { 12 | background-position:-32px 0; 13 | background-image:url(../images/foo/bar/foo.png); 14 | } 15 | 16 | .x-html-editor-tb .x-edit-forecolor, .x-menu-item img.x-edit-forecolor { 17 | background-position:-160px 0; 18 | background-image:url(../images/foo/bar/foo.png); 19 | } 20 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The fancy title 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /lib/AssetGraph.js: -------------------------------------------------------------------------------- 1 | var Path = require('path'), 2 | AssetGraph = module.exports = require('assetgraph'); 3 | 4 | // Get the spriteBackgroundImages transform from assetgraph-sprite if available: 5 | var spriteBackgroundImages; 6 | try { 7 | spriteBackgroundImages = require('assetgraph-sprite'); 8 | } catch (e) { 9 | spriteBackgroundImages = function () { 10 | console.warn('assetgraph-sprite is not available, skipping the spriteBackgroundImages transform'); 11 | return function spriteBackgroundImagesDisabled(assetGraph) {}; 12 | }; 13 | } 14 | AssetGraph.registerTransform(spriteBackgroundImages, 'spriteBackgroundImages'); 15 | 16 | // Register ./transforms/*: 17 | 18 | require('fs').readdirSync(Path.resolve(__dirname, 'transforms')).forEach(function (fileName) { 19 | AssetGraph.registerTransform(Path.resolve(__dirname, 'transforms', fileName)); 20 | }); 21 | -------------------------------------------------------------------------------- /bin/optimizeImage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var AssetGraph = require('../lib/AssetGraph'), 4 | urlTools = require('urltools'), 5 | commandLineOptions = require('optimist') 6 | .usage('$0 image1 image2...') 7 | .demand(1) 8 | .argv; 9 | 10 | new AssetGraph({root: commandLineOptions.root}) 11 | .logEvents({repl: commandLineOptions.repl, stopOnWarning: commandLineOptions.stoponwarning, suppressJavaScriptCommonJsRequireWarnings: true}) 12 | .loadAssets(commandLineOptions._.map(urlTools.fsFilePathToFileUrl)) 13 | .queue(function () { 14 | console.warn('BEFORE:'); 15 | }) 16 | .writeStatsToStderr() 17 | .processImages({isImage: true}, {autoLossless: true}) 18 | .writeAssetsToDisc({url: /^file:/, isImage: true, isDirty: true}) 19 | .queue(function () { 20 | console.warn('\nAFTER:'); 21 | }) 22 | .writeStatsToStderr() 23 | .run(); 24 | -------------------------------------------------------------------------------- /test/transforms/angularAnnotations.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('../unexpected-with-plugins'); 3 | var AssetGraph = require('../../lib/AssetGraph'); 4 | 5 | describe('angularAnnotations', function () { 6 | it('should annotate a basic example', function (done) { 7 | new AssetGraph({ root: __dirname + '/../../testdata/transforms/angularAnnotations' }) 8 | .loadAssets('basic.js') 9 | .populate() 10 | .angularAnnotations() 11 | .queue(function (assetGraph) { 12 | expect(assetGraph, 'to contain assets', 'JavaScript', 1); 13 | 14 | var asset = assetGraph.findAssets()[0]; 15 | 16 | expect(asset.text, 'to be', 'angular.module("MyMod").controller("MyCtrl",["$scope","$timeout",function($scope,$timeout){return[$scope,$timeout]}]);'); 17 | }) 18 | .run(done); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/knockoutTemplate/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "MyLanguageKey": { 3 | "da": "Min sprognøgle", 4 | "en": "My language key" 5 | }, 6 | "YetAnotherOne": { 7 | "da": "quux på dansk", 8 | "en": "quux in English" 9 | }, 10 | "YetYetAnotherOne": { 11 | "da": "baz på dansk", 12 | "en": "baz in English" 13 | }, 14 | "AndAnother": { 15 | "da": "blah på dansk", 16 | "en": "blah in English" 17 | }, 18 | "MyOtherLanguageKey": { 19 | "da": "Min anden sprognøgle", 20 | "en": "My other language key" 21 | }, 22 | "MyNestedLanguageKey": { 23 | "en": "Here is a {0} nested i18n construct in English", 24 | "da": "Her er en {0} dyb i18n-struktur på dansk" 25 | }, 26 | "Nice": { 27 | "en": "nice and English", 28 | "da": "rar" 29 | }, 30 | "Beautiful": { 31 | "en": "beautifully English", 32 | "da": "smuk" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/transforms/replaceDartWithJavaScript.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('../unexpected-with-plugins'), 3 | AssetGraph = require('../../lib/AssetGraph'); 4 | 5 | describe('replaceDartWithJavaScript', function (done) { 6 | it('should handle a test case with 2 Dart assets', function (done) { 7 | new AssetGraph({root: __dirname + '/../../testdata/transforms/replaceDartWithJavaScript/'}) 8 | .loadAssets('index.html') 9 | .populate() 10 | .queue(function (assetGraph) { 11 | expect(assetGraph, 'to contain relation', 'HtmlDart'); 12 | expect(assetGraph, 'to contain no relations', 'HtmlScript'); 13 | }) 14 | .replaceDartWithJavaScript() 15 | .queue(function (assetGraph) { 16 | expect(assetGraph, 'to contain no relations', 'HtmlDart'); 17 | expect(assetGraph, 'to contain relation', 'HtmlScript'); 18 | }) 19 | .run(done); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /testdata/transforms/checkLanguageKeys/duplicateLanguageKeys/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /testdata/resolvers/senchaJsBuilder/dependentPackages/foo.jsb2: -------------------------------------------------------------------------------- 1 | { 2 | "pkgs": [ 3 | { 4 | "name": "A", 5 | "file": "A.js", 6 | "fileIncludes": [ 7 | { 8 | "text": "A1.js", 9 | "path": "js/" 10 | } 11 | ] 12 | }, 13 | { 14 | "name": "B", 15 | "file": "B.js", 16 | "pkgDeps": [ 17 | "A.js" 18 | ], 19 | "fileIncludes": [ 20 | { 21 | "text": "B1.js", 22 | "path": "js/" 23 | } 24 | ] 25 | }, 26 | { 27 | "name": "C", 28 | "file": "C.js", 29 | "pkgDeps": [ 30 | "B.js" 31 | ], 32 | "fileIncludes": [ 33 | { 34 | "text": "C1.js", 35 | "path": "js/" 36 | } 37 | ] 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /testdata/transforms/cloneForEachLocale/multipleLocales/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "theTitle": { 3 | "en": "The awesome document title", 4 | "en_GB": "The most delightful document title", 5 | "da": "Dokumentets vidunderlige titel" 6 | }, 7 | "plainTr": { 8 | "en": "Plain English", 9 | "da": "Jævnt dansk" 10 | }, 11 | "callTRPAT": { 12 | "en": "Boring {0} English pattern", 13 | "da": "Kedeligt {0} dansk mønster" 14 | }, 15 | "nonInvokedTrPattern": { 16 | "en": "Welcome to an English-speaking country, Mr. {0}", 17 | "en_US": "Welcome to America, Mr. {0}", 18 | "da": "Velkommen til Danmark, hr. {0}" 19 | }, 20 | "some.text.in.body": { 21 | "en": "Some text in body", 22 | "da": "Kropstekst" 23 | }, 24 | "text.with.placeholders": { 25 | "en": "A {0} text with {1} placeholders in it", 26 | "en_GB": "A {0} text with oh so {1} placeholders in it", 27 | "da": "En {0} tekst med {1} pladsholdere i sig" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /testdata/bin/makeBabelJobAndApplyBabelJob/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

Simple key in HTML

6 |

...

7 |

Key with nice placeholders

8 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /testdata/transforms/checkLanguageKeys/pluralRule/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "EveryNWeeks": { 3 | "en": { 4 | "one": "Every week", 5 | "other": "Every {0} weeks" 6 | }, 7 | "cs": { 8 | "one": "Každý týden", 9 | "other": "Každých {0} týdnů" 10 | }, 11 | "da": { 12 | "one": "Hver uge", 13 | "other": "Hver {0}. uge", 14 | "many": "I should not be here" 15 | } 16 | }, 17 | "DeeplyStructured": { 18 | "en": { 19 | "foo": { 20 | "one": "Every week", 21 | "other": "Every {0} weeks" 22 | } 23 | }, 24 | "cs": { 25 | "foo": { 26 | "one": "Každý týden", 27 | "other": "Každých {0} týdnů" 28 | }, 29 | "bar": 123 30 | }, 31 | "da": { 32 | "foo": { 33 | "one": "Hver uge", 34 | "other": "Hver {0}. uge", 35 | "many": "I should not be here" 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/transforms/injectBootstrapper.js: -------------------------------------------------------------------------------- 1 | var bootstrapper = require('../bootstrapper'); 2 | 3 | module.exports = function (queryObj, options) { 4 | if (!queryObj) { 5 | throw new Error('transforms.injectBootstrapper: The \'queryObj\' parameter is required.'); 6 | } 7 | return function injectBootstrapper(assetGraph) { 8 | assetGraph.findAssets(queryObj).forEach(function (initialAsset) { 9 | var bootstrapAsset = new assetGraph.JavaScript({ 10 | parseTree: bootstrapper.createAst(initialAsset, assetGraph, options) 11 | }); 12 | assetGraph.addAsset(bootstrapAsset); 13 | if (initialAsset.type === 'Html') { 14 | new assetGraph.HtmlScript({to: bootstrapAsset}) 15 | .attach(initialAsset, 'first') 16 | .inline() 17 | .node.setAttribute('id', 'bootstrapper'); 18 | } else { // initialAsset.type === 'JavaScript' 19 | new assetGraph.JavaScriptInclude({to: bootstrapAsset}).attach(initialAsset, 'first'); 20 | } 21 | }); 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /test/JavaScriptGetText.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('./unexpected-with-plugins'), 3 | AssetGraph = require('../lib/AssetGraph'); 4 | 5 | describe('GETTEXT', function () { 6 | it('should handle a simple test case', function (done) { 7 | new AssetGraph({root: __dirname + '/../testdata/JavaScriptGetText/'}) 8 | .loadAssets('index.html.template') 9 | .populate() 10 | .injectBootstrapper({isInitial: true}) 11 | .queue(function (assetGraph) { 12 | expect(assetGraph, 'to contain assets', {}, 4); 13 | expect(assetGraph, 'to contain relation', 'JavaScriptGetText'); 14 | }) 15 | .inlineRelations({type: 'JavaScriptGetText'}) 16 | .removeRelations({type: 'JavaScriptGetText'}, {removeOrphan: true}) 17 | .queue(function (assetGraph) { 18 | expect(assetGraph, 'to contain assets', {}, 3); 19 | expect(assetGraph.findAssets({type: 'JavaScript'})[0].text, 'to match', /\"Hello, my name is \"\s*\+\s*\"Foobar/); 20 | }) 21 | .run(done); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /lib/transforms/replaceDartWithJavaScript.js: -------------------------------------------------------------------------------- 1 | var seq = require('seq'); 2 | 3 | module.exports = function () { 4 | return function replaceDartWithJavaScript(assetGraph, cb) { 5 | seq(assetGraph.findRelations({type: 'HtmlDart'})) 6 | .parEach(function (dartRelation) { 7 | var self = this, 8 | url = dartRelation.to.url + '.js'; 9 | 10 | assetGraph.resolveAssetConfig(url, assetGraph.root, function (err, config) { 11 | var jsAsset = assetGraph.createAsset(config), 12 | jsRelation = new assetGraph.HtmlScript({ 13 | from: dartRelation.from, 14 | to: jsAsset 15 | }); 16 | 17 | assetGraph.addAsset(jsAsset); 18 | jsRelation.attach(dartRelation.from, 'after', dartRelation); 19 | dartRelation.detach(); 20 | 21 | jsAsset.load(self); 22 | }); 23 | }) 24 | .seq(function () { 25 | cb(); 26 | }) 27 | .catch(cb); 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /lib/loadAndInstantiateAutoprefixer.js: -------------------------------------------------------------------------------- 1 | var semver = require('semver'); 2 | 3 | module.exports = function loadAndInstantiateAutoprefixer(browsersOrAutoprefixerInstance, errorMessageIfUnavailable) { 4 | if (browsersOrAutoprefixerInstance && browsersOrAutoprefixerInstance.process) { 5 | return browsersOrAutoprefixerInstance; 6 | } else if (browsersOrAutoprefixerInstance && !Array.isArray(browsersOrAutoprefixerInstance)) { 7 | browsersOrAutoprefixerInstance = String(browsersOrAutoprefixerInstance).split(/,\s*/); 8 | } 9 | 10 | var autoprefixer; 11 | try { 12 | autoprefixer = require('autoprefixer'); 13 | } catch (e) { 14 | if (errorMessageIfUnavailable) { 15 | e.message = errorMessageIfUnavailable + '\n' + e.message; 16 | throw e; 17 | } 18 | } 19 | 20 | if (semver.satisfies(require('autoprefixer/package.json').version, '>= 3.0.0')) { 21 | autoprefixer = autoprefixer(browsersOrAutoprefixerInstance ? {browsers: browsersOrAutoprefixerInstance} : {}); 22 | } else { 23 | autoprefixer = autoprefixer(browsersOrAutoprefixerInstance); 24 | } 25 | return autoprefixer; 26 | }; 27 | -------------------------------------------------------------------------------- /test/transforms/runJavaScriptConditionalBlocks.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('../unexpected-with-plugins'), 3 | AssetGraph = require('../../lib/AssetGraph'); 4 | 5 | describe('runJavaScriptConditionalBlocks', function () { 6 | it('shold handle a simple test case with some code that alters the DOM', function (done) { 7 | new AssetGraph({root: __dirname + '/../../testdata/transforms/runJavaScriptConditionalBlocks'}) 8 | .loadAssets('index.html') 9 | .populate() 10 | .queue(function (assetGraph) { 11 | expect(assetGraph, 'to contain asset', 'JavaScript'); 12 | }) 13 | .runJavaScriptConditionalBlocks({type: 'Html'}, 'THEENVIRONMENT') 14 | .queue(function (assetGraph) { 15 | var html = assetGraph.findAssets({type: 'Html'})[0], 16 | divs = html.parseTree.getElementsByTagName('div'); 17 | expect(divs, 'to have length', 2); 18 | expect(divs[0].firstChild.nodeValue, 'to equal', 'Howdy'); 19 | expect(divs[1].firstChild.nodeValue, 'to equal', 'there'); 20 | }) 21 | .run(done); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /lib/transforms/angularAnnotations.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | var annotate; 4 | 5 | module.exports = function (queryObj, annotateOptions) { 6 | queryObj = _.extend({ type: 'JavaScript', isLoaded: true }, queryObj); 7 | annotateOptions = _.extend(annotateOptions || {}, { add: true }); 8 | 9 | return function angularAnnotations(assetGraph, cb) { 10 | if (!annotate) { 11 | try { 12 | annotate = require('ng-annotate'); 13 | } catch (err) { 14 | assetGraph.emit('warn', new Error('angularAnnotations: ng-annotate not installed. Please install it to get angular annotations')); 15 | return cb(); 16 | } 17 | } 18 | 19 | assetGraph.findAssets(queryObj).forEach(function (asset) { 20 | var res = annotate(asset.text, annotateOptions); 21 | 22 | if (res.errors) { 23 | var err = new Error('ng-annotate: ' + res.errors); 24 | err.asset = asset; 25 | 26 | assetGraph.emit('warn', err); 27 | } else { 28 | asset.text = res.src; 29 | } 30 | }); 31 | 32 | return cb(); 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /testdata/bin/makeBabelJob/index.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "KeyAlreadyPartiallyTranslatedInIndexI18n": { 3 | "de": "Existing translation to German" 4 | }, 5 | "KeyAlreadyTranslatedToCzech": { 6 | "cs": { 7 | "one": "fzd", 8 | "few": "fzd", 9 | "many": "fzd", 10 | "other": "fzd" 11 | } 12 | }, 13 | "KeyAlreadyTranslatedToCzech": { 14 | "cs": { 15 | "one": "fzd", 16 | "few": "fzd", 17 | "many": "fzd", 18 | "other": "fzd" 19 | } 20 | }, 21 | "KeyAlreadyTranslatedToAllLanguages": { 22 | "cs": { 23 | "one": "fzd", 24 | "few": "fzd", 25 | "many": "fzd", 26 | "other": "fzd" 27 | }, 28 | "da": { 29 | "one": "føø", 30 | "other": "føø" 31 | }, 32 | "de": { 33 | "one": "voo", 34 | "other": "voo" 35 | }, 36 | "en": { 37 | "one": "foo", 38 | "other": "foo" 39 | }, 40 | "pl": { 41 | "one": "fzz", 42 | "few": "fzz", 43 | "many": "fzz", 44 | "other": "fzz" 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/transforms/autoprefixer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * autoprefixer transform 3 | * 4 | * - Runs autoprefixer with the supplied options on each css asset 5 | */ 6 | 7 | var loadAndInstantiateAutoprefixer = require('../loadAndInstantiateAutoprefixer'); 8 | 9 | module.exports = function (autoprefixerOrOptions) { 10 | return function autoprefixer(assetGraph) { 11 | var cssAssets = assetGraph.findAssets({type: 'Css'}); 12 | 13 | if (cssAssets.length > 0) { 14 | // See https://github.com/ai/autoprefixer#browsers 15 | var autoprefix = loadAndInstantiateAutoprefixer(autoprefixerOrOptions, 'autoprefixer transform: Found ' + cssAssets.length + ' css asset(s), but no autoprefixer module is available. Please use npm to install autoprefixer in your project so the autoprefixer transform can require it.'); 16 | 17 | cssAssets.forEach(function (cssAsset) { 18 | try { 19 | cssAsset.text = autoprefix.process(cssAsset.text).css; 20 | } catch (err) { 21 | console.log(cssAsset.urlOrDescription, err); 22 | err.asset = cssAsset; 23 | 24 | assetGraph.emit('warn', err); 25 | } 26 | }); 27 | } 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /testdata/bin/applyBabelJob/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Foo 5 | 6 | 7 | 17 | This key has some placeholders 18 | 19 | 20 | that comes back the same 21 | in the translation job 22 | 23 | data-i18n specifying that the contents of the tag should not be translated 24 | data-i18n specifying that the contents of the tag should not be translated 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /lib/transforms/duplicateFavicon.js: -------------------------------------------------------------------------------- 1 | // If the graph contains a favicon.ico at the root, make sure that all Html assets reference it explicitly so that 2 | // it can be moved to the static dir and served with a far-future expires. Still, keep a copy at /favicon.ico for 3 | // old IE versions. 4 | 5 | var _ = require('lodash'); 6 | 7 | module.exports = function (queryObj) { 8 | return function duplicateFavicon(assetGraph) { 9 | var rootFavicon = assetGraph.findAssets({url: assetGraph.root + 'favicon.ico'})[0]; 10 | assetGraph.findAssets(_.extend({type: 'Html', isInline: false, isFragment: false}, queryObj)).forEach(function (htmlAsset) { 11 | if (rootFavicon && assetGraph.findRelations({from: htmlAsset, type: 'HtmlShortcutIcon'}).length === 0) { 12 | new assetGraph.HtmlShortcutIcon({to: rootFavicon}).attach(htmlAsset); 13 | } 14 | }); 15 | if (rootFavicon) { 16 | var incomingRelations = assetGraph.findRelations({to: rootFavicon}); 17 | if (incomingRelations.length > 0) { 18 | var rootFaviconCopy = rootFavicon.clone(incomingRelations); 19 | rootFaviconCopy.fileName = 'favicon.copy.ico'; 20 | rootFaviconCopy.isInitial = false; 21 | } 22 | } 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /testdata/bin/makeBabelJob/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | data-i18n specifying that the contents of the tag should not be translated 18 | data-i18n specifying that the contents of the tag should not be translated 19 | 20 | 21 | -------------------------------------------------------------------------------- /testdata/bin/makeBabelJobAndApplyBabelJob/thething.i18n: -------------------------------------------------------------------------------- 1 | { 2 | "stringvalue": { 3 | "en": "value" 4 | }, 5 | "arrayvalue": { 6 | "en": [5, "items", "in", "an", "array"] 7 | }, 8 | "objectvalue": { 9 | "en": { 10 | "key1": "value1", 11 | "key2": "value2" 12 | } 13 | }, 14 | "objectvaluewithsomemissingkeysinthestructure": { 15 | "en": { 16 | "foo": { 17 | "bar": "baz" 18 | } 19 | }, 20 | "da": { 21 | "foo": { 22 | "bar": "baz" 23 | } 24 | } 25 | }, 26 | "withexistingkeys": { 27 | "en": "the English value", 28 | "da": "the Danish value" 29 | }, 30 | "simplekeyinhtml": { 31 | "en": "Simple key in HTML, English" 32 | }, 33 | "simplekeyinhtmlattribute": { 34 | "en": "Simple key in HTML attribute, English" 35 | }, 36 | "keywithplaceholdersinhtml": { 37 | "en": "Key with {0} placeholders in HTML, English" 38 | }, 39 | "alreadyPartiallyTranslatedKey": { 40 | "en": { 41 | "theTranslatedOne": "yep" 42 | }, 43 | "da": { 44 | "theTranslatedOne": "ja" 45 | }, 46 | "de": { 47 | "theTranslatedOne": "Ja" 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/transforms/addDataVersionAttributeToHtmlElement.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'), 2 | childProcess = require('child_process'); 3 | 4 | module.exports = function (queryObj, version) { 5 | return function addDataVersionAttributeToHtmlElement(assetGraph, cb) { 6 | function proceed() { 7 | if (version) { 8 | assetGraph.findAssets(_.extend({type: 'Html'}, queryObj)).forEach(function (htmlAsset) { 9 | var documentElement = htmlAsset.parseTree.documentElement; 10 | if (documentElement) { 11 | documentElement.setAttribute('data-version', version.replace(/\{0\}/g, documentElement.getAttribute('data-version') || '')); 12 | htmlAsset.markDirty(); 13 | } 14 | }); 15 | } 16 | cb(); 17 | } 18 | 19 | if (typeof version === 'undefined') { 20 | // Try to derive a version tag from git: 21 | childProcess.exec('git describe --long --tags --always --dirty', function (err, stdout, stderr) { 22 | if (!err) { 23 | version = stdout.replace(/^[\s\n\r]+|[\s\r\n]+$/g, ''); 24 | } 25 | proceed(); 26 | }); 27 | } else { 28 | proceed(); 29 | } 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /testdata/transforms/checkLanguageKeys/combo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | This should be translated, but there is no data-i18n attribute for the text contents 6 | 7 | This should be translated, but there is no data-i18n attribute for the text contents 8 | This is 9 | translated 10 | This should be translated, but there is no data-i18n attribute for the text contents, although there is one for the title attribute 11 | data-i18n specifying that the contents of the tag should not be translated 12 | data-i18n specifying that the contents of the tag should not be translated 13 | 14 | This is translated but with wrong content 15 | 16 | 17 | -------------------------------------------------------------------------------- /lib/transforms/stripDebug.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'), 2 | AssetGraph = require('../AssetGraph'), 3 | uglifyJs = AssetGraph.JavaScript.uglifyJs, 4 | uglifyAst = AssetGraph.JavaScript.uglifyAst; 5 | 6 | module.exports = function (queryObj) { 7 | return function stripDebug(assetGraph) { 8 | assetGraph.findAssets(_.extend({type: 'JavaScript'}, queryObj)).forEach(function (javaScript) { 9 | javaScript.parseTree.figure_out_scope(); // So that uglifyJs.AST_SymbolRef.undeclared() is available 10 | var walker = new uglifyJs.TreeWalker(function (node) { 11 | if (node instanceof uglifyJs.AST_SimpleStatement) { 12 | if (node.body instanceof uglifyJs.AST_Call && 13 | node.body.expression instanceof uglifyJs.AST_Dot && 14 | node.body.expression.expression instanceof uglifyJs.AST_SymbolRef && 15 | node.body.expression.expression.name === 'console' && 16 | node.body.expression.expression.undeclared()) { 17 | uglifyAst.replaceDescendantNode(walker.parent(), node, new uglifyJs.AST_EmptyStatement()); 18 | } else if (node instanceof uglifyJs.AST_Debugger) { 19 | uglifyAst.replaceDescendantNode(walker.parent(), node, new uglifyJs.AST_EmptyStatement()); 20 | } 21 | } 22 | }); 23 | javaScript.parseTree.walk(walker); 24 | }); 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /test/findParentDirectory.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('./unexpected-with-plugins'), 3 | passError = require('passerror'), 4 | AssetGraph = require('../lib/AssetGraph'), 5 | resolvers = require('../lib/resolvers'), 6 | Path = require('path'), 7 | assetGraphRoot = Path.resolve(__dirname, '..', 'testdata', 'findParentDirectory') + '/'; 8 | 9 | function resolveAssetConfig(assetConfig, fromUrl, cb) { 10 | var assetGraph = new AssetGraph({root: assetGraphRoot}); 11 | assetGraph.defaultResolver = resolvers.findParentDirectory(); 12 | assetGraph.resolveAssetConfig(assetConfig, fromUrl || assetGraph.root, cb); 13 | } 14 | 15 | describe('findParentDirectory', function () { 16 | it('should resolve an a url with an unknown protocol', function (done) { 17 | resolveAssetConfig('directory:quux.png', null, passError(done, function (resolvedAssetConfig) { 18 | expect(resolvedAssetConfig, 'to have properties', { 19 | url: 'file://' + assetGraphRoot + 'directory/quux.png' 20 | }); 21 | done(); 22 | })); 23 | }); 24 | 25 | it('should resolving a url with an unknown protocol and a wildcard', function (done) { 26 | resolveAssetConfig('otherdirectory:onemorelevel/*.png', 'file://' + assetGraphRoot + 'directory', passError(done, function (resolvedAssetConfigs) { 27 | expect(resolvedAssetConfigs, 'to be an array whose items satisfy', 'to have properties', {type: 'Png'}); 28 | done(); 29 | })); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /lib/transforms/gzip.js: -------------------------------------------------------------------------------- 1 | var async = require('async'), 2 | _ = require('lodash'), 3 | AssetGraph = require('../AssetGraph'); 4 | 5 | module.exports = function (queryObj) { 6 | return function gzip(assetGraph, cb) { 7 | var compress, 8 | gzipAssets = assetGraph.findAssets(_.extend({isInline: false}, queryObj)); 9 | 10 | if (gzipAssets.length > 0) { 11 | try { 12 | compress = require('node-zopfli'); 13 | } catch (e) { 14 | assetGraph.emit('info', new Error('node-zopfli is not available, using less efficient zlib compression')); 15 | compress = require('zlib'); 16 | } 17 | } 18 | 19 | async.eachLimit(gzipAssets, 4, function (asset, cb) { 20 | // http://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits 21 | if (asset.rawSrc.length <= 860) { 22 | return cb(); 23 | } 24 | 25 | compress.gzip(asset.rawSrc, function (err, gzippedRawSrc) { 26 | if (err) { 27 | assetGraph.emit('error', err); 28 | } else if (gzippedRawSrc.length < asset.rawSrc.length) { 29 | assetGraph.addAsset(new AssetGraph.Asset({ 30 | url: asset.url.replace(/(?=[\?#]|$)/, '.gz'), 31 | rawSrc: gzippedRawSrc 32 | })); 33 | } 34 | cb(); 35 | }); 36 | }, cb); 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, One.com 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of the author nor the names of contributors may 15 | be used to endorse or promote products derived from this 16 | software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /test/i18nTools.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var unexpected = require('./unexpected-with-plugins'), 3 | i18nTools = require('../lib/i18nTools'); 4 | 5 | describe('i18nTools', function () { 6 | var expect = unexpected.clone().addAssertion('to tokenize as', function (expect, subject, value) { 7 | expect(i18nTools.tokenizePattern(subject), 'to equal', value); 8 | }); 9 | 10 | describe('#tokenizePattern()', function () { 11 | it('should recognize a simple text as one text token', function () { 12 | expect('foo bar', 'to tokenize as', [{type: 'text', value: 'foo bar'}]); 13 | }); 14 | 15 | it('should allow backslash in text tokens', function () { 16 | expect('foo \\ bar', 'to tokenize as', [{type: 'text', value: 'foo \\ bar'}]); 17 | }); 18 | 19 | it('should recognize a placeholder', function () { 20 | expect('foo {1} bar', 'to tokenize as', [{type: 'text', value: 'foo '}, {type: 'placeHolder', value: 1}, {type: 'text', value: ' bar'}]); 21 | }); 22 | 23 | it('should support curly brace followed by non-number in text tokens', function () { 24 | expect('foo { bar', 'to tokenize as', [{type: 'text', value: 'foo { bar'}]); 25 | }); 26 | 27 | it('should support curly brace followed by number followed by non-curly end brace in text tokens', function () { 28 | expect('foo {5 bar', 'to tokenize as', [{type: 'text', value: 'foo {5 bar'}]); 29 | }); 30 | 31 | it('should work even with a space at the end of a string', function () { 32 | expect('foo bar ', 'to tokenize as', [{type: 'text', value: 'foo bar '}]); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/transforms/autoprefixer.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('../unexpected-with-plugins'), 3 | AssetGraph = require('../../lib/AssetGraph'); 4 | 5 | describe('transforms.autoprefixer', function () { 6 | it('should handle an unprefixed test case', function (done) { 7 | new AssetGraph({root: __dirname + '/../../testdata/transforms/autoprefixer/'}) 8 | .loadAssets('index.html') 9 | .populate() 10 | .queue(function (assetGraph) { 11 | expect(assetGraph, 'to contain relations', 'HtmlStyle', 2); 12 | expect(assetGraph, 'to contain relations', 'CssImage', 1); 13 | }) 14 | .autoprefixer('last 100 versions') 15 | .queue(function (assetGraph) { 16 | expect(assetGraph, 'to contain relations', 'HtmlStyle', 2); 17 | expect(assetGraph, 'to contain relations', 'CssImage', 4); 18 | }) 19 | .run(done); 20 | }); 21 | 22 | it('should handle a simple option case', function (done) { 23 | expect(function () { 24 | new AssetGraph({root: __dirname + '/../../testdata/transforms/autoprefixer/'}) 25 | .loadAssets('index.html') 26 | .populate() 27 | .autoprefixer('last 2 versions') 28 | .run(done); 29 | }, 'not to throw'); 30 | }); 31 | 32 | it('should handle a complex option case', function (done) { 33 | expect(function () { 34 | new AssetGraph({root: __dirname + '/../../testdata/transforms/autoprefixer/'}) 35 | .loadAssets('index.html') 36 | .populate() 37 | .autoprefixer('last 2 versions, ie > 8,ff > 28') 38 | .run(done); 39 | }, 'not to throw'); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/angularJs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My AngularJS App 5 | 6 | 7 | 8 | 14 | 15 |
16 | 17 | 18 | 51 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /bin/buildDevelopment: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'), 4 | AssetGraph = require('../lib/AssetGraph'), 5 | i18nTools = require('../lib/i18nTools'), 6 | urlTools = require('urltools'), 7 | commandLineOptions = require('optimist') 8 | .usage('$0 --root [--label = ...] [--parentdir] [--locales ,...] [--defaultlocale ] [--localecookiename ] [--cssimports] [--inline ] [--watch] [--version ] ...') 9 | .boolean('cssimports', 'parentdir') 10 | .options('stoponwarning', { 11 | describe: 'Whether to stop with a non-zero exit code when a warning is encountered', 12 | type: 'boolean', 13 | default: false 14 | }) 15 | .demand(['root']) 16 | .argv; 17 | 18 | new AssetGraph({root: commandLineOptions.root}) 19 | .logEvents({repl: commandLineOptions.repl, stopOnWarning: commandLineOptions.stoponwarning, suppressJavaScriptCommonJsRequireWarnings: true}) 20 | .if(commandLineOptions.watch) 21 | .startOverIfAssetSourceFilesChange() 22 | .endif() 23 | .registerRequireJsConfig({preventPopulationOfJavaScriptAssetsUntilConfigHasBeenFound: true}) 24 | .registerLabelsAsCustomProtocols(commandLineOptions.label, {installFindParentDirectoryAsDefault: commandLineOptions.parentdir}) 25 | .loadAssets(commandLineOptions._.map(urlTools.fsFilePathToFileUrl)) 26 | .buildDevelopment({ 27 | version: commandLineOptions.version, 28 | supportedLocaleIds: commandLineOptions.locales && _.flatten(_.flatten([commandLineOptions.locales]).map(function (localeId) { 29 | return localeId.split(','); 30 | })).map(i18nTools.normalizeLocaleId), 31 | defaultLocaleId: commandLineOptions.defaultlocale && i18nTools.normalizeLocaleId(commandLineOptions.defaultlocale), 32 | localeCookieName: commandLineOptions.localecookiename, 33 | cssImports: commandLineOptions.cssimports, 34 | inlineUrlWildCard: commandLineOptions.inline 35 | }) 36 | .writeAssetsToDisc({isInitial: true}) 37 | .run(); 38 | -------------------------------------------------------------------------------- /bin/flattenOneInclude: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'), 4 | seq = require('seq'), 5 | AssetGraph = require('../lib/AssetGraph'), 6 | urlTools = require('urltools'), 7 | commandLineOptions = require('optimist') 8 | .usage('$0 [--label = ...] [--parentdir] [--root ] [-o ] ') 9 | .boolean('parentdir') 10 | .check(function (argv) { 11 | if (argv._.length !== 1 || !/\.js$/.test(argv._[0])) { 12 | throw 'Please specify a single JavaScript file on the command line'; 13 | } 14 | }) 15 | .argv; 16 | 17 | new AssetGraph({root: commandLineOptions.root}) 18 | .logEvents({repl: commandLineOptions.repl, stopOnWarning: commandLineOptions.stoponwarning, suppressJavaScriptCommonJsRequireWarnings: true}) 19 | .registerLabelsAsCustomProtocols(commandLineOptions.label, {installFindParentDirectoryAsDefault: commandLineOptions.parentdir}) 20 | .loadAssets(commandLineOptions._.map(urlTools.fsFilePathToFileUrl)) 21 | .populate({followRelations: {type: 'JavaScriptInclude'}}) 22 | .queue(function (assetGraph) { 23 | assetGraph.findAssets({isInitial: true}).forEach(function (initialAsset) { 24 | // Get the original text including comments etc.: 25 | seq(assetGraph.collectAssetsPostOrder(initialAsset, {to: {type: 'JavaScript'}}).filter(function (asset) { 26 | return !asset.isInline; 27 | })) 28 | .parMap(function (asset) { 29 | fs.readFile(urlTools.fileUrlToFsPath(asset.url), 'utf-8', this); 30 | }) 31 | .unflatten() 32 | .seq(function (texts) { 33 | var flattenedText = texts.join('\n').replace(/INCLUDE\(([^\)]*)\);?\n?/g, ''); 34 | if ('o' in commandLineOptions) { 35 | fs.writeFileSync(commandLineOptions.o, flattenedText, AssetGraph.assets.JavaScript.prototype.encoding); 36 | } else { 37 | console.log(flattenedText); 38 | } 39 | }); 40 | }); 41 | }) 42 | .run(); 43 | -------------------------------------------------------------------------------- /bin/findUnusedSelectors: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var AssetGraph = require('../lib/AssetGraph'), 4 | _ = require('lodash'), 5 | urlTools = require('urltools'), 6 | commandLineOptions = require('optimist') 7 | .usage('$0 [--root ] ...') 8 | .demand(1) 9 | .argv; 10 | 11 | new AssetGraph({root: commandLineOptions.root}) 12 | .logEvents({repl: commandLineOptions.repl, stopOnWarning: commandLineOptions.stoponwarning, suppressJavaScriptCommonJsRequireWarnings: true}) 13 | .loadAssets(commandLineOptions._.map(urlTools.fsFilePathToFileUrl)) 14 | .populate({ 15 | followRelations: {type: ['HtmlStyle', 'CssImport'], to: {url: /^file:/}} 16 | }) 17 | .queue(function (assetGraph) { 18 | var documents = _.pluck(assetGraph.findAssets({type: 'Html'}), 'parseTree'); 19 | function isSelectorUsed(selector) { 20 | return documents.some(function (document) { 21 | return document.querySelectorAll(selector).length > 0; 22 | }); 23 | } 24 | assetGraph.findAssets({type: 'Css'}).forEach(function (cssAsset) { 25 | cssAsset.constructor.eachRuleInParseTree(cssAsset.parseTree, function (cssRule) { 26 | if (cssRule.type === 1) { // STYLE_RULE 27 | if (isSelectorUsed(cssRule.selectorText)) { 28 | //console.warn('IN USE: ' + cssRule.cssText); 29 | if (cssRule.selectorText.indexOf(',') !== -1) { 30 | cssRule.selectorText.split(',').forEach(function (subSelector) { 31 | subSelector = subSelector.replace(/^\s+|\s+$/g, ''); // Trim 32 | if (!isSelectorUsed(subSelector)) { 33 | console.warn('Unused selector fragment "' + subSelector + '" in rule: ' + cssRule.cssText); 34 | } 35 | }); 36 | } 37 | } else { 38 | console.warn('NOT IN USE: ' + cssRule.cssText); 39 | } 40 | } 41 | }); 42 | }); 43 | }) 44 | .run(); 45 | -------------------------------------------------------------------------------- /lib/transforms/runJavaScriptConditionalBlocks.js: -------------------------------------------------------------------------------- 1 | var vm = require('vm'), 2 | _ = require('lodash'), 3 | AssetGraph = require('../AssetGraph'), 4 | uglifyJs = AssetGraph.JavaScript.uglifyJs, 5 | bootstrapper = require('../bootstrapper'); 6 | 7 | module.exports = function (queryObj, environment, removeAfter) { 8 | if (!environment) { 9 | throw new Error('transforms.runJavaScriptConditionalBlocks: no \'environment\' option provided'); 10 | } 11 | return function runJavaScriptConditionalBlocks(assetGraph) { 12 | assetGraph.findAssets(_.extend({type: 'Html'}, queryObj)).forEach(function (htmlAsset) { 13 | var contextProperties = {console: console}; 14 | contextProperties[environment] = true; 15 | var context = bootstrapper.createContext(htmlAsset, assetGraph, contextProperties); 16 | 17 | assetGraph.collectAssetsPostOrder(htmlAsset, {type: ['HtmlScript', 'HtmlRequireJsMain', 'JavaScriptAmdRequire', 'JavaScriptAmdDefine', 'JavaScriptShimRequire', 'JavaScriptRequireJsCommonJsCompatibilityRequire', 'JavaScriptInclude']}).filter(function (asset) { 18 | return asset.isLoaded && asset.type === 'JavaScript'; 19 | }).forEach(function (javaScript) { 20 | // Loop through top-level statements: 21 | var topLevelStatements = javaScript.parseTree.body; 22 | for (var i = 0 ; i < topLevelStatements.length ; i += 1) { 23 | var node = topLevelStatements[i]; 24 | if (node instanceof uglifyJs.AST_If && 25 | ((node.condition instanceof uglifyJs.AST_SymbolRef && node.condition.name === environment) || 26 | (node.condition instanceof uglifyJs.AST_Dot && node.condition.property === environment && 27 | node.condition.expression instanceof uglifyJs.AST_SymbolRef && 28 | node.condition.expression.name === 'window'))) { 29 | 30 | var fileName = javaScript.url || assetGraph.findRelations({to: javaScript})[0].baseAsset.url; 31 | new vm.Script(node.body.print_to_string(), fileName).runInContext(context); 32 | if (removeAfter) { 33 | javaScript.parseTree.body.splice(i, 1); 34 | i -= 1; 35 | } 36 | } 37 | } 38 | }); 39 | }); 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /lib/transforms/buildDevelopment.js: -------------------------------------------------------------------------------- 1 | var urlTools = require('urltools'); 2 | 3 | module.exports = function (options) { 4 | options = options || {}; 5 | return function buildDevelopment(assetGraph, cb) { 6 | var query = assetGraph.query; 7 | assetGraph 8 | .populate({from: {type: 'Html'}, followRelations: {type: 'HtmlScript', to: {url: /^file:/}}}) 9 | .assumeRequireJsConfigHasBeenFound() 10 | .moveAssets({isInitial: true}, function (asset) { return asset.url.replace(/\.template$/, ''); }) 11 | .addDataVersionAttributeToHtmlElement({type: 'Html', isInitial: true}, options.version) 12 | .populate({ 13 | followRelations: query.or({ 14 | type: ['HtmlScript', 'HtmlRequireJsMain', 'JavaScriptAmdRequire', 'JavaScriptAmdDefine', 'JavaScriptShimRequire', 'JavaScriptRequireJsCommonJsCompatibilityRequire', 'JavaScriptInclude'], 15 | to: {url: assetGraph.query.not(/^https?:/)} 16 | }, 17 | { 18 | to: {type: 'I18n'} 19 | }) 20 | }) 21 | .injectBootstrapper({isInitial: true}, { 22 | defaultLocaleId: options.defaultLocaleId, 23 | supportedLocaleIds: options.supportedLocaleIds, 24 | localeCookieName: options.localeCookieName 25 | }) 26 | .flattenStaticIncludes({isInitial: true}) 27 | .removeAssets({isLoaded: true, isEmpty: true, type: 'JavaScript'}) 28 | .inlineRelations({type: 'HtmlStyle', from: {isInitial: true, type: 'Html'}, to: {fixedUpExtJS: true, isLoaded: true}}) 29 | .if(options.cssImports) 30 | .convertHtmlStylesToInlineCssImports() 31 | .endif() 32 | .inlineRelations({type: 'HtmlScript', from: {isInitial: true, type: 'Html'}, to: {fixedUpExtJS: true, isLoaded: true}}) 33 | .prettyPrintAssets({type: 'JavaScript', isLoaded: true, incoming: {type: 'HtmlScript', from: {isInitial: true, type: 'Html'}}}) 34 | .prettyPrintAssets({type: 'Css', isLoaded: true, incoming: {type: 'HtmlStyle', from: {isInitial: true, type: 'Html'}}}) 35 | .runJavaScriptConditionalBlocks({type: 'Html', isLoaded: true}, 'BUILDDEVELOPMENT') 36 | .if(options.inlineUrlWildCard) 37 | .inlineRelations({to: {isLoaded: true, url: urlTools.makeFileUrlMatcher(options.inlineUrlWildCard)}}) 38 | .endif() 39 | .run(cb); 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/svgsWithIdenticalInlineStyle/gears.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/svgsWithIdenticalInlineStyle/gears2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "assetgraph-builder", 3 | "description": "Build system for web sites and applications", 4 | "repository": "git://github.com/One-com/assetgraph-builder.git", 5 | "version": "3.0.2-podio", 6 | "keywords": [ 7 | "assetgraph", 8 | "web", 9 | "build", 10 | "build system", 11 | "single page", 12 | "web application", 13 | "static html", 14 | "cache manifest", 15 | "appcache", 16 | "spriting", 17 | "html", 18 | "css", 19 | "javascript", 20 | "jsdom", 21 | "localization", 22 | "internationalization", 23 | "i18n", 24 | "l10n" 25 | ], 26 | "maintainers": [ 27 | { 28 | "name": "Andreas Lind Petersen", 29 | "email": "andreas@one.com" 30 | }, 31 | { 32 | "name": "Peter Müller", 33 | "email": "munter@fumle.dk" 34 | } 35 | ], 36 | "main": "lib/AssetGraph.js", 37 | "files": [ 38 | "lib", 39 | "bin" 40 | ], 41 | "dependencies": { 42 | "assetgraph": "1.15.4", 43 | "async": "0.9.0", 44 | "chalk": "1.0.0", 45 | "express-processimage": "https://github.com/podio/express-processimage/archive/v2.1.1-podio.tar.gz", 46 | "extend": "1.2.1", 47 | "jpegtran": "0.1.0", 48 | "lodash": "2.4.1", 49 | "memoizesync": "0.5.0", 50 | "ng-annotate": "0.15.4", 51 | "optimist": "0.6.1", 52 | "optipng": "0.1.1", 53 | "passerror": "1.1.0", 54 | "plurals-cldr": "1.0.1", 55 | "pngcrush": "0.1.0", 56 | "pngquant": "https://github.com/podio/node-pngquant/archive/v0.4.1-podio.tar.gz", 57 | "semver": "4.3.1", 58 | "seq": "0.3.5", 59 | "temp": "0.8.1", 60 | "urltools": "0.2.0" 61 | }, 62 | "optionalDependencies": { 63 | "assetgraph-sprite": "0.7.1", 64 | "histogram": "2.0.0", 65 | "node-zopfli": "1.2.1" 66 | }, 67 | "devDependencies": { 68 | "autoprefixer": "3.1.0", 69 | "coveralls": "2.11.2", 70 | "gm": "1.17.0", 71 | "istanbul": "0.3.6", 72 | "jsdom": "0.11.0", 73 | "jshint": "2.6.0", 74 | "less": "1.6.3", 75 | "mocha": "2.1.0", 76 | "node-sass": "0.9.4", 77 | "sinon": "1.12.2", 78 | "unexpected": "5.9.3", 79 | "unexpected-jsdom": "5.1.0", 80 | "unexpected-sinon": "5.1.0" 81 | }, 82 | "engines": { 83 | "node": ">=0.8.0" 84 | }, 85 | "directories": { 86 | "lib": "./lib", 87 | "bin": "./bin" 88 | }, 89 | "publishConfig": { 90 | "registry": "http://registry.npmjs.org/" 91 | }, 92 | "scripts": { 93 | "lint": "jshint . bin/*", 94 | "test": "npm run lint && mocha", 95 | "travis": "npm run lint && npm run coverage", 96 | "coverage": "NODE_ENV=development ./node_modules/.bin/istanbul cover --include-all-sources -x '**/testdata/**' -x lib/i18nTools.js -x lib/bootstrapper.js ./node_modules/mocha/bin/_mocha -- --reporter dot" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /testdata/transforms/buildProduction/knockoutJs/tpl.js: -------------------------------------------------------------------------------- 1 | /*global define, $, ko*/ 2 | define({ 3 | load: function (url, req, load, config) { 4 | if (!ko.templateSources.externalTemplate) { 5 | ko.templateSources.externalTemplate = function (template) { 6 | this.data = {}; 7 | this.template = ko.externalTemplateEngine.templates[template]; 8 | }; 9 | 10 | ko.templateSources.externalTemplate.prototype.data = function (key, value) { 11 | if (value) { 12 | return this.data[key]; 13 | } else { 14 | this.data[key] = value; 15 | } 16 | }; 17 | 18 | ko.templateSources.externalTemplate.prototype.text = function (value) { 19 | if (value) { 20 | this.template = value; 21 | } else { 22 | return this.template; 23 | } 24 | }; 25 | 26 | ko.externalTemplateEngine = function () { 27 | var nativeTemplateEngine = new ko.nativeTemplateEngine(), 28 | nativeMakeTemplateSource = nativeTemplateEngine.makeTemplateSource; 29 | 30 | nativeTemplateEngine.makeTemplateSource = function (template) { 31 | if (typeof template === 'string' && ko.externalTemplateEngine.templates[template]) { 32 | return new ko.templateSources.externalTemplate(template); 33 | } else { 34 | return nativeMakeTemplateSource(template); 35 | } 36 | }; 37 | 38 | return nativeTemplateEngine; 39 | }; 40 | 41 | ko.externalTemplateEngine.templates = {}; 42 | 43 | ko.setTemplateEngine(new ko.externalTemplateEngine()); 44 | } 45 | 46 | $.ajax({ 47 | url: url, 48 | success: function (htmlString) { 49 | var templateId = url.split('/').pop().replace(/\.ko$/, ''); 50 | 51 | if (templateId in ko.externalTemplateEngine.templates) { 52 | throw new Error("tpl plugin for require.js: More than one of the loaded templates have the file name " + templateId + ".ko, skipped " + url + ". Please disambiguate by changing at least one of the file names."); 53 | } else { 54 | // Translate the template if AssetGraph-builder's bootstrapper script is present and we're not using the default language: 55 | if (window.TRHTML && (!window.DEFAULTLOCALEID || LOCALEID !== DEFAULTLOCALEID) && window.TRANSLATE !== false) { 56 | htmlString = TRHTML(htmlString); 57 | } 58 | ko.externalTemplateEngine.templates[templateId] = htmlString; 59 | } 60 | load(htmlString); 61 | } 62 | }); 63 | } 64 | }); 65 | -------------------------------------------------------------------------------- /lib/resolvers/findParentDirectory.js: -------------------------------------------------------------------------------- 1 | /*global setImmediate:true*/ 2 | // node 0.8 compat 3 | if (typeof setImmediate === 'undefined') { 4 | setImmediate = process.nextTick; 5 | } 6 | 7 | var urlTools = require('urltools'), 8 | passError = require('passerror'), 9 | fs = require('fs'), 10 | seq = require('seq'); 11 | 12 | // FIXME: Make flushable 13 | var dirExistsCache = {}, 14 | dirExistsWaitingQueue = {}; 15 | 16 | function dirExistsCached(fsPath, cb) { 17 | if (fsPath in dirExistsCache) { 18 | setImmediate(function () { 19 | cb(null, dirExistsCache[fsPath]); 20 | }); 21 | } else if (fsPath in dirExistsWaitingQueue) { 22 | dirExistsWaitingQueue[fsPath].push(cb); 23 | } else { 24 | dirExistsWaitingQueue[fsPath] = [cb]; 25 | fs.stat(fsPath, function (err, stats) { 26 | var isDirectory = !err && stats.isDirectory(); 27 | dirExistsCache[fsPath] = isDirectory; 28 | dirExistsWaitingQueue[fsPath].forEach(function (waitingCallback) { 29 | waitingCallback(null, isDirectory); 30 | }); 31 | delete dirExistsWaitingQueue[fsPath]; 32 | }); 33 | } 34 | } 35 | 36 | function findParentDirCached(fromPath, parentDirName, cb) { 37 | var candidatePaths = [], 38 | fromPathFragments = fromPath.replace(/\/$/, '').split('/'); 39 | 40 | seq(fromPathFragments) 41 | .parMap(function (fromPathFragment, i) { 42 | // FIXME: Stop at caller's definition of root? 43 | var candidatePath = fromPathFragments.slice(0, i + 1).concat(parentDirName).join('/'); 44 | candidatePaths.push(candidatePath); 45 | dirExistsCached(candidatePath, this); 46 | }) 47 | .unflatten() 48 | .seq(function (dirExistsResults) { 49 | var bestCandidateIndex = dirExistsResults.lastIndexOf(true); 50 | if (bestCandidateIndex === -1) { 51 | return cb(new Error('findParentDirCached: Couldn\'t find a parent dir named ' + parentDirName + ' from ' + fromPath)); 52 | } 53 | cb(null, candidatePaths[bestCandidateIndex]); 54 | })['catch'](cb); 55 | } 56 | 57 | module.exports = function () { 58 | return function findParentDirectory(assetConfig, fromUrl, cb) { 59 | if (/^file:/.test(fromUrl)) { 60 | var protocol = assetConfig.url.substr(0, assetConfig.url.indexOf(':')), 61 | pathname = assetConfig.url.replace(/^\w+:(?:\/\/)?/, ''); // Strip protocol and two leading slashes if present 62 | findParentDirCached(urlTools.fileUrlToFsPath(fromUrl), protocol, passError(cb, function (parentPath) { 63 | assetConfig.url = urlTools.fsFilePathToFileUrl(parentPath + '/' + pathname); 64 | cb(null, assetConfig); 65 | })); 66 | } else { 67 | setImmediate(function () { 68 | cb(new Error('resolvers.findParentDir: fromUrl must be file: ' + fromUrl)); 69 | }); 70 | } 71 | }; 72 | }; 73 | -------------------------------------------------------------------------------- /test/transforms/buildDevelopment.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('../unexpected-with-plugins'), 3 | passError = require('passerror'), 4 | AssetGraph = require('../../lib/AssetGraph'); 5 | 6 | describe('buildDevelopment', function () { 7 | it('should handle a simple test case', function (done) { 8 | new AssetGraph({root: __dirname + '/../../testdata/transforms/buildDevelopment/simple/'}) 9 | .registerRequireJsConfig() 10 | .loadAssets('index.html.template') 11 | .populate() 12 | .buildDevelopment({ 13 | version: 'The version number', 14 | supportedLocaleIds: ['en', 'da'], 15 | defaultLocaleId: 'en', 16 | localeCookieName: 'myLocaleCookie', 17 | cssImports: true, 18 | inlineUrlWildCard: false // Test it 19 | }) 20 | .run(passError(done, function (assetGraph) { 21 | expect(assetGraph, 'to contain asset', 'Html', 1); 22 | 23 | expect(assetGraph.findAssets({type: 'Html'})[0].parseTree.title, 'to equal', 'The default title'); 24 | 25 | expect(assetGraph, 'to contain relations', { 26 | type: 'HtmlScript', 27 | node: function (node) { 28 | return node.getAttribute('id') === 'bootstrapper'; 29 | } 30 | }, 1); 31 | 32 | var bootstrapperText = assetGraph.findRelations({type: 'HtmlScript', node: function (node) {return node.getAttribute('id') === 'bootstrapper'; }})[0].to.text; 33 | expect(bootstrapperText, 'to match', /\bwindow\.SUPPORTEDLOCALEIDS\s*=\s*\[\s*(['"])en\1\s*,\s*\1da\1\s*\]\s*;/); 34 | expect(bootstrapperText, 'to match', /\bwindow\.DEFAULTLOCALEID\s*=\s*(['"])en\1\s*;/); 35 | expect(bootstrapperText, 'to match', /\bwindow\.LOCALECOOKIENAME\s*=\s*(['"])myLocaleCookie\1\s*;/); 36 | expect(bootstrapperText, 'to match', /\bwindow\.I18NKEYS\s*=\s*\{\s*myLanguageKey:\s*\{\s*en:\s*(['"])The English value\1\s*,\s*da:\s*\1Den danske værdi\1\s*\}\s*\}\s*;/); 37 | 38 | expect(assetGraph.findAssets({type: 'Html'})[0].parseTree.querySelectorAll('html[data-version="The version number"]'), 'to have length', 1); 39 | done(); 40 | })); 41 | }); 42 | 43 | it('should not mangle an inline stylesheet with a data-bind attribute', function (done) { 44 | new AssetGraph({root: __dirname + '/../../testdata/transforms/buildDevelopment/dataBindOnHtmlStyle/'}) 45 | .registerRequireJsConfig() 46 | .loadAssets('index.html.template') 47 | .populate() 48 | .buildDevelopment({ 49 | version: 'The version number' 50 | }) 51 | .queue(function (assetGraph) { 52 | expect(assetGraph.findAssets({type: 'Html'})[0].text, 'to contain', ''); 53 | }) 54 | .run(done); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /lib/transforms/registerLabelsAsCustomProtocols.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'), 2 | resolvers = require('../resolvers'), 3 | seq = require('seq'), 4 | urlTools = require('urltools'); 5 | 6 | module.exports = function (labelDefinitions, options) { 7 | options = options || {}; 8 | if (!labelDefinitions) { 9 | labelDefinitions = []; 10 | } else if (_.isString(labelDefinitions)) { 11 | labelDefinitions = [labelDefinitions]; 12 | } 13 | if (_.isArray(labelDefinitions)) { 14 | labelDefinitions = labelDefinitions.map(function (labelDefinition) { 15 | if (_.isString(labelDefinition)) { 16 | var matchNameTypeAndUrl = labelDefinition.match(/^([^:=]+)(?::([^=]+))?=(.*)$/); 17 | if (!matchNameTypeAndUrl) { 18 | throw new Error('transforms.registerLabelsAsCustomProtocols: Invalid label definition syntax: ' + labelDefinition); 19 | } 20 | labelDefinition = { 21 | name: matchNameTypeAndUrl[1], 22 | type: matchNameTypeAndUrl[2] || null, 23 | url: matchNameTypeAndUrl[3] 24 | }; 25 | } else if (typeof labelDefinition !== 'object' || labelDefinition === null) { 26 | throw new Error('transforms.registerLabelsAsCustomProtocols: Invalid label definition: ' + labelDefinition); 27 | } 28 | if (!('url' in labelDefinition) || !('name' in labelDefinition)) { 29 | throw new Error('transforms.registerLabelsAsCustomProtocols: \'name\' and \'url\' options are mandatory.'); 30 | } 31 | if (labelDefinition.type && !(labelDefinition.type in resolvers)) { 32 | throw new Error('transforms.registerLabelsAsCustomProtocols: Unknown resolver type: ' + labelDefinition.type); 33 | } 34 | return labelDefinition; 35 | }); 36 | } else { 37 | throw new Error('transforms.registerLabelsAsCustomProtocols: Invalid label definitions: ' + labelDefinitions); 38 | } 39 | 40 | return function registerLabelsAsCustomProtocols(assetGraph, cb) { 41 | if (options.installFindParentDirectoryAsDefault) { 42 | assetGraph.defaultResolver = resolvers.findParentDirectory(); 43 | } 44 | 45 | seq(labelDefinitions) 46 | .parEach(function (labelDefinition) { 47 | var resolverName = labelDefinition.type || (/\.jsb\d+$/.test(labelDefinition.url) ? 'senchaJsBuilder' : 'fixedDirectory'); 48 | 49 | try { 50 | assetGraph.resolverByProtocol[labelDefinition.name] = resolvers[resolverName](urlTools.fsFilePathToFileUrl(labelDefinition.url)); 51 | } catch (err) { 52 | err.message = 'transforms.registerLabelsAsCustomProtocols: Error initializing resolver: ' + err.message; 53 | return this(err); 54 | } 55 | this(); 56 | }) 57 | .seq(function () { 58 | cb(); 59 | })['catch'](cb); 60 | }; 61 | }; 62 | -------------------------------------------------------------------------------- /lib/PngQuantWithHistogram.js: -------------------------------------------------------------------------------- 1 | /*global setImmediate:true*/ 2 | // node 0.8 compat 3 | if (typeof setImmediate === 'undefined') { 4 | setImmediate = process.nextTick; 5 | } 6 | 7 | var Stream = require('stream'), 8 | util = require('util'), 9 | PngQuant = require('pngquant'), 10 | histogram; 11 | 12 | try { 13 | histogram = require('histogram'); 14 | } catch (err) {} 15 | 16 | function PngQuantWithHistogram() { 17 | // Fall back to quanting to 256 colors. If you don't want this behavior, check PngQuantWithHistogram.histogramAvailable 18 | if (!histogram) { 19 | return new PngQuant([256]); 20 | } 21 | 22 | Stream.call(this); 23 | this.bufferedChunks = []; 24 | } 25 | 26 | PngQuantWithHistogram.histogramAvailable = !!histogram; 27 | 28 | util.inherits(PngQuantWithHistogram, Stream); 29 | 30 | PngQuantWithHistogram.prototype.write = function (chunk) { 31 | this.bufferedChunks.push(chunk); 32 | }; 33 | 34 | PngQuantWithHistogram.prototype.end = function (chunk) { 35 | if (chunk) { 36 | this.write(chunk); 37 | } 38 | var rawSrc = Buffer.concat(this.bufferedChunks); 39 | this.bufferedChunks = null; 40 | histogram(rawSrc, function (err, data) { 41 | if (err) { 42 | err.message = 'histogram: ' + err.message; 43 | return this.emit('error', err); 44 | } 45 | if (data.colors.rgba < 256) { 46 | // The image has fewer than 256 colors, run rawSrc through a PngQuant filter and proxy its events: 47 | this.pngQuant = new PngQuant([data.colors.rgba < 2 ? 2 : data.colors.rgba]); 48 | this.__defineGetter__('commandLine', function () { 49 | return this.pngQuant.commandLine; 50 | }.bind(this)); 51 | ['data', 'end', 'error'].forEach(function (eventName) { 52 | this.pngQuant.on(eventName, function () { // ... 53 | this.emit.apply(this, eventName.concat(arguments)); 54 | }.bind(this)); 55 | }.bind(this)); 56 | this.pngQuant.end(rawSrc); 57 | } else { 58 | // The image has too many colors. Emit all the buffered chunks at once when we aren't paused: 59 | var hasEnded = false, 60 | emitRawSrcAndEnd = function () { 61 | hasEnded = true; 62 | this.emit('data', rawSrc); 63 | this.emit('end'); 64 | }.bind(this); 65 | 66 | if (this.isPaused) { 67 | this.resume = function () { 68 | setImmediate(function () { 69 | if (!this.isPaused && !hasEnded) { 70 | emitRawSrcAndEnd(); 71 | } 72 | }); 73 | }.bind(this); 74 | } else { 75 | emitRawSrcAndEnd(); 76 | } 77 | } 78 | }.bind(this)); 79 | 80 | }; 81 | 82 | PngQuantWithHistogram.prototype.pause = function () { 83 | this.isPaused = true; 84 | if (this.pngQuant) { 85 | this.pngQuant.pause(); 86 | } 87 | }; 88 | 89 | PngQuantWithHistogram.prototype.resume = function () { 90 | this.isPaused = false; 91 | if (this.pngQuant) { 92 | this.pngQuant.resume(); 93 | } 94 | }; 95 | 96 | module.exports = PngQuantWithHistogram; 97 | -------------------------------------------------------------------------------- /test/transforms/duplicateFavicon.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('../unexpected-with-plugins'), 3 | passError = require('passerror'), 4 | AssetGraph = require('../../lib/AssetGraph'), 5 | urlTools = require('urltools'); 6 | 7 | describe('transforms.duplicateFavicon', function () { 8 | it('should handle a referenced favicon.ico', function (done) { 9 | new AssetGraph({root: __dirname + '/../../testdata/transforms/duplicateFavicon/referencedFavicon'}) 10 | .loadAssets('index.html') 11 | .populate() 12 | .queue(function (assetGraph) { 13 | expect(assetGraph, 'to contain relations', 'HtmlShortcutIcon', 1); 14 | }) 15 | .duplicateFavicon() 16 | .run(passError(done, function (assetGraph) { 17 | expect(assetGraph, 'to contain relation', 'HtmlShortcutIcon'); 18 | expect(assetGraph, 'to contain relation', {type: 'HtmlShortcutIcon', href: 'favicon.copy.ico'}); 19 | expect(assetGraph, 'to contain assets', 'Ico', 2); 20 | expect(assetGraph, 'to contain asset', {url: urlTools.resolveUrl(assetGraph.root, 'favicon.ico')}); 21 | expect(assetGraph, 'to contain asset', {url: urlTools.resolveUrl(assetGraph.root, 'favicon.copy.ico')}); 22 | expect(assetGraph.findAssets({type: 'Html'})[0].text, 'to equal', 23 | '\n' + 24 | '\n' + 25 | ' \n' + 26 | ' \n' + 27 | ' \n' + 28 | ' \n' + 29 | ' \n' + 30 | '\n'); 31 | done(); 32 | })); 33 | }); 34 | 35 | it('should handle an unreferenced favicon.ico', function (done) { 36 | new AssetGraph({root: __dirname + '/../../testdata/transforms/duplicateFavicon/unreferencedFavicon'}) 37 | .loadAssets('index.html', 'noHead.html', 'favicon.ico') 38 | .populate() 39 | .queue(function (assetGraph) { 40 | expect(assetGraph, 'to contain relations', 'HtmlShortcutIcon', 0); 41 | }) 42 | .duplicateFavicon() 43 | .run(passError(done, function (assetGraph) { 44 | expect(assetGraph, 'to contain relation', 'HtmlShortcutIcon', 2); 45 | expect(assetGraph, 'to contain assets', 'Ico', 2); 46 | expect(assetGraph, 'to contain asset', {url: urlTools.resolveUrl(assetGraph.root, 'favicon.ico'), isInitial: true}); 47 | expect(assetGraph, 'to contain asset', {url: urlTools.resolveUrl(assetGraph.root, 'favicon.copy.ico'), isInitial: function (isInitial) {return !isInitial; }}); 48 | expect(assetGraph.findAssets({type: 'Html', fileName: 'index.html'})[0].text, 'to equal', 49 | '\n' + 50 | '\n' + 51 | ' \n' + 52 | ' \n' + 53 | ' \n' + 54 | ' \n' + 55 | '\n' 56 | ); 57 | expect(assetGraph.findAssets({type: 'Html', fileName: 'noHead.html'})[0].text, 'to equal', 58 | '\n' + 59 | '\n' + 60 | ' \n' + 61 | ' \n' + 62 | '\n' 63 | ); 64 | done(); 65 | })); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/resolvers/senchaJsBuilder.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var expect = require('../unexpected-with-plugins'), 3 | _ = require('lodash'), 4 | AssetGraph = require('../../lib/AssetGraph'); 5 | 6 | describe('resolvers/senchaJsBuilder', function () { 7 | it('should handle a test case with 3 assets', function (done) { 8 | new AssetGraph({root: __dirname + '/../../testdata/resolvers/senchaJsBuilder/rewriteBackgroundImageUrls/'}) 9 | .registerLabelsAsCustomProtocols([ 10 | {name: 'mylabel', url: __dirname + '/../../testdata/resolvers/senchaJsBuilder/rewriteBackgroundImageUrls/foo.jsb2'} 11 | ]) 12 | .loadAssets('index.html') 13 | .populate() 14 | .flattenStaticIncludes({isInitial: true}) 15 | .queue(function (assetGraph) { 16 | expect(assetGraph, 'to contain asset', 'Html'); 17 | expect(assetGraph, 'to contain asset', {type: 'Css', isInline: false}); 18 | expect(assetGraph, 'to contain asset', 'Png'); 19 | 20 | var cssAsset = assetGraph.findAssets({type: 'Css'})[0], 21 | cssBackgroundImageRelations = assetGraph.findRelations({type: 'CssImage', to: assetGraph.findAssets({type: 'Png'})[0]}); 22 | expect(cssBackgroundImageRelations, 'to have length', 4); 23 | cssBackgroundImageRelations.forEach(function (cssBackgroundImageRelation) { 24 | expect(cssBackgroundImageRelation.baseAsset, 'to be', cssAsset); 25 | }); 26 | var src = assetGraph.findAssets({type: 'Css'})[0].text, 27 | matches = src.match(/url\(\.\.\/\.\.\/images\/foo\/bar\/foo\.png\)/g); 28 | expect(matches, 'to have length', 4); 29 | }) 30 | .inlineRelations({type: 'HtmlStyle'}) 31 | .queue(function (assetGraph) { 32 | // All the background-image urls should be relative to the Html 33 | assetGraph.findRelations({type: 'CssImage'}).forEach(function (relation) { 34 | expect(relation.cssRule.style[relation.propertyName], 'to equal', 'url(resources/images/foo/bar/foo.png)'); 35 | }); 36 | expect(assetGraph.findAssets({type: 'Html'})[0].text.match(/url\(resources\/images\/foo\/bar\/foo\.png\)/g), 'to have length', 4); 37 | }) 38 | .run(done); 39 | }); 40 | 41 | it('should handle an Html asset and a jsb2 describing packages that depend on each other', function (done) { 42 | new AssetGraph({root: __dirname + '/../../testdata/resolvers/senchaJsBuilder/dependentPackages/'}) 43 | .registerLabelsAsCustomProtocols([ 44 | {name: 'mylabel', url: __dirname + '/../../testdata/resolvers/senchaJsBuilder/dependentPackages/foo.jsb2'} 45 | ]) 46 | .loadAssets('index.html') 47 | .populate() 48 | .queue(function (assetGraph) { 49 | expect(assetGraph, 'to contain asset', 'Html'); 50 | expect(assetGraph, 'to contain asset', {type: 'JavaScript', isInline: true}); 51 | expect(assetGraph, 'to contain relations', 'JavaScriptInclude', 3); 52 | 53 | expect(assetGraph.findAssets({type: 'JavaScript', isInline: true})[0].text.match(/INCLUDE/g), 'to have length', 3); 54 | }) 55 | .flattenStaticIncludes({isInitial: true}) 56 | .queue(function (assetGraph) { 57 | expect(assetGraph, 'to contain relations', 'HtmlScript', 4); 58 | expect(_.pluck(assetGraph.findRelations({type: 'HtmlScript'}), 'href'), 'to equal', [ 59 | 'js/A1.js', 60 | 'js/B1.js', 61 | 'js/C1.js', 62 | undefined 63 | ]); 64 | }) 65 | .run(done); 66 | }); 67 | 68 | it('should handle overlapping jsb2 packages', function (done) { 69 | new AssetGraph({root: __dirname + '/../../testdata/resolvers/senchaJsBuilder/dependentPackages/'}) 70 | .registerLabelsAsCustomProtocols([ 71 | {name: 'mylabel', url: __dirname + '/../../testdata/resolvers/senchaJsBuilder/dependentPackages/foo.jsb2'} 72 | ]) 73 | .loadAssets('overlappingIncludes.html') 74 | .populate() 75 | .queue(function (assetGraph) { 76 | expect(assetGraph, 'to contain asset', 'Html'); 77 | expect(assetGraph, 'to contain asset', {type: 'JavaScript', isInline: true}); 78 | expect(assetGraph, 'to contain relations', 'JavaScriptInclude', 4); 79 | 80 | expect(assetGraph.findAssets({type: 'JavaScript', isInline: true})[0].text.match(/INCLUDE/g), 'to have length', 4); 81 | }) 82 | .flattenStaticIncludes({isInitial: true}) 83 | .queue(function (assetGraph) { 84 | expect(assetGraph, 'to contain relations', 'HtmlScript', 4); 85 | expect(_.pluck(assetGraph.findRelations({type: 'HtmlScript'}), 'href'), 'to equal', [ 86 | 'js/A1.js', 87 | 'js/B1.js', 88 | 'js/C1.js', 89 | undefined 90 | ]); 91 | }) 92 | .run(done); 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /bin/copyReferencedAssets: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var optimist = require('optimist'), 4 | commandLineOptions = optimist 5 | .usage('$0 --root --outroot [options] ') 6 | .options('h', { 7 | alias: 'help', 8 | describe: 'Show this help', 9 | type: 'boolean', 10 | default: false 11 | }) 12 | .options('root', { 13 | describe: 'Path to your web root (will be deduced from your input files if not specified)', 14 | type: 'string', 15 | demand: false 16 | }) 17 | .options('outroot', { 18 | describe: 'Path to the output folder. Will be generated if non-existing', 19 | type: 'string', 20 | demand: true 21 | }) 22 | .options('label', { 23 | describe: 'Registers labels as custom protocols for path resolving. You can create multiple of these: --label = --label =', 24 | type: 'string', 25 | demand: false 26 | }) 27 | .options('parentdir', { 28 | describe: 'If an unknown label (scheme) is found, look for at parent dir of that name before failing (breaks custom protocols)', 29 | type: 'boolean', 30 | demand: false 31 | }) 32 | .options('stoponwarning', { 33 | describe: 'Whether to stop with a non-zero exit code when a warning is encountered', 34 | type: 'boolean', 35 | default: false 36 | }) 37 | .options('noless', { 38 | describe: 'Keep .less files as they are instead of automatically compiling them to CSS', 39 | type: 'boolean', 40 | default: false 41 | }) 42 | .wrap(72) 43 | .argv; 44 | 45 | if (commandLineOptions.h) { 46 | optimist.showHelp(); 47 | process.exit(1); 48 | } 49 | 50 | var AssetGraph = require('../lib/AssetGraph'), 51 | query = AssetGraph.query, 52 | urlTools = require('urltools'), 53 | outRoot = urlTools.fsDirToFileUrl(commandLineOptions.outroot), 54 | rootUrl = commandLineOptions.root && urlTools.urlOrFsPathToUrl(commandLineOptions.root, true), 55 | inputUrls; 56 | 57 | if (commandLineOptions._.length > 0) { 58 | inputUrls = commandLineOptions._.map(function (urlOrFsPath) { 59 | return urlTools.urlOrFsPathToUrl(urlOrFsPath, false); 60 | }); 61 | if (!rootUrl) { 62 | rootUrl = urlTools.findCommonUrlPrefix(inputUrls.filter(function (inputUrl) { 63 | return (/^file:/).test(inputUrl); 64 | })); 65 | if (rootUrl) { 66 | console.warn('Guessing --root from input files: ' + rootUrl); 67 | } 68 | } 69 | } else if (rootUrl && /^file:/.test(rootUrl)) { 70 | inputUrls = [rootUrl + '**/*.html']; 71 | console.warn('No input files specified, defaulting to ' + inputUrls[0]); 72 | } else { 73 | throw new Error('No input files and no --root specified (or it isn\'t file:), cannot proceed'); 74 | } 75 | 76 | var followRelationsQueryObj = query.or( 77 | { 78 | to: {type: 'I18n'} 79 | }, 80 | { 81 | type: query.not(['JavaScriptInclude', 'JavaScriptExtJsRequire', 'JavaScriptCommonJsRequire', 'HtmlAnchor', 'HtmlMetaRefresh']), 82 | to: {url: query.not(/^https?:/)} 83 | } 84 | ); 85 | 86 | new AssetGraph({root: rootUrl}) 87 | .logEvents({repl: commandLineOptions.repl, stopOnWarning: commandLineOptions.stoponwarning, suppressJavaScriptCommonJsRequireWarnings: true}) 88 | .registerRequireJsConfig({preventPopulationOfJavaScriptAssetsUntilConfigHasBeenFound: true}) 89 | .registerLabelsAsCustomProtocols(commandLineOptions.label, {installFindParentDirectoryAsDefault: commandLineOptions.parentdir}) 90 | .loadAssets(inputUrls) 91 | .populate({from: {type: 'Html'}, followRelations: {type: 'HtmlScript', to: {url: /^file:/}}}) 92 | .assumeRequireJsConfigHasBeenFound() 93 | .populate({followRelations: followRelationsQueryObj}) 94 | .queue(function fixBaseAssetsOfUnresolvedOutgoingRelationsFromHtmlFragments(assetGraph) { 95 | assetGraph.findRelations({from: {type: 'Html', isFragment: true, isInitial: true}}, true).forEach(function (relation) { 96 | if (relation._baseAssetPath === null) { 97 | delete relation._baseAssetPath; 98 | } 99 | }); 100 | }) 101 | .populate({followRelations: followRelationsQueryObj, startAssets: {type: 'Html', isFragment: true, isInitial: true}}) 102 | .if(!commandLineOptions.noless) 103 | // Replace Less assets with their Css counterparts: 104 | .compileLessToCss({type: 'Less', isLoaded: true}) 105 | 106 | // Remove the in-browser less compiler and its incoming relations, 107 | // even if it's included from a CDN and thus hasn't been populated: 108 | .removeRelations({to: {url: /\/less(?:-\d+\.\d+\.\d+)?(?:\.min)?\.js$/}}, {unresolved: true, detach: true, removeOrphan: true}) 109 | 110 | // Find and populate CssImage relations from the compiled Less assets: 111 | .populate({from: {type: 'Css'}, followRelations: followRelationsQueryObj}) 112 | .endif() 113 | .writeAssetsToDisc({url: /^file:/, isLoaded: true}, outRoot) 114 | .writeStatsToStderr() 115 | .run(); 116 | -------------------------------------------------------------------------------- /bin/checkLanguageKeys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var optimist = require('optimist'), 4 | commandLineOptions = optimist 5 | .usage('$0 --root [options] ') 6 | .options('locales', { 7 | describe: 'Comma-separated list of locales to check', 8 | type: 'string', 9 | demand: true 10 | }) 11 | .options('removeunused', { 12 | describe: 'Remove unused language keys from .i18n files', 13 | type: 'boolean' 14 | }) 15 | .options('ignore', { 16 | describe: 'Type(s) of messages to suppress (supported: \'missing\', \'untranslated\', \'defaultValueMismatch\', \'whitespace\', \'unused\')', 17 | type: 'string' 18 | }) 19 | .options('warn', { 20 | descrbe: 'Type(s) of messages that should be emitted with \'warning\' status (supported: \'missing\', \'untranslated\', \'defaultValueMismatch\', \'whitespace\', \'unused\'). Intended for use with --stoponwarning', 21 | type: 'string' 22 | }) 23 | .options('stoponwarning', { 24 | describe: 'Whether to stop with a non-zero exit code when a warning is encountered', 25 | type: 'boolean', 26 | default: false 27 | }) 28 | .options('defaultlocale', { 29 | describe: 'The locale of the default value in TR statements and tags with a data-i18n attribute', 30 | type: 'string', 31 | default: 'en' 32 | }) 33 | .wrap(72) 34 | .argv; 35 | 36 | if (commandLineOptions.h) { 37 | optimist.showHelp(); 38 | process.exit(1); 39 | } 40 | 41 | var _ = require('lodash'), 42 | AssetGraph = require('../lib/AssetGraph'), 43 | i18nTools = require('../lib/i18nTools'), 44 | query = AssetGraph.query, 45 | urlTools = require('urltools'), 46 | rootUrl = commandLineOptions.root && urlTools.urlOrFsPathToUrl(commandLineOptions.root, true), 47 | localeIds = commandLineOptions.locales && _.flatten(_.flatten([commandLineOptions.locales]).map(function (localeId) { 48 | return localeId.split(','); 49 | })).map(i18nTools.normalizeLocaleId), 50 | defaultLocaleId = commandLineOptions.defaultlocale && i18nTools.normalizeLocaleId(commandLineOptions.defaultlocale), 51 | ignoreMessageTypes = commandLineOptions.ignore && _.flatten(_.flatten([commandLineOptions.ignore]).map(function (ignoreMessageType) { 52 | return ignoreMessageType.split(','); 53 | })), 54 | warnMessageTypes = commandLineOptions.warn && _.flatten(_.flatten([commandLineOptions.warn]).map(function (warnMessageType) { 55 | return warnMessageType.split(','); 56 | })), 57 | includeAttributeNames = commandLineOptions.includeattribute && _.flatten(_.flatten([commandLineOptions.includeattribute]).map(function (attributeName) { 58 | return attributeName.split(','); 59 | })), 60 | excludeAttributeNames = commandLineOptions.excludeattribute && _.flatten(_.flatten([commandLineOptions.excludeattribute]).map(function (attributeName) { 61 | return attributeName.split(','); 62 | })), 63 | inputUrls; 64 | 65 | if (commandLineOptions._.length > 0) { 66 | inputUrls = commandLineOptions._.map(function (urlOrFsPath) { 67 | return urlTools.urlOrFsPathToUrl(urlOrFsPath, false); 68 | }); 69 | if (!rootUrl) { 70 | rootUrl = urlTools.findCommonUrlPrefix(inputUrls.filter(function (inputUrl) { 71 | return /^file:/.test(inputUrl); 72 | })); 73 | if (rootUrl) { 74 | console.warn('Guessing --root from input files: ' + rootUrl); 75 | } 76 | } 77 | } else if (rootUrl && /^file:/.test(rootUrl)) { 78 | inputUrls = [rootUrl + '**/*.html']; 79 | console.warn('No input files specified, defaulting to ' + inputUrls[0]); 80 | } else { 81 | throw new Error('No input files and no --root specified (or it isn\'t file:), cannot proceed'); 82 | } 83 | 84 | new AssetGraph({root: rootUrl}) 85 | .logEvents({repl: commandLineOptions.repl, stopOnWarning: commandLineOptions.stoponwarning, suppressJavaScriptCommonJsRequireWarnings: true}) 86 | .registerRequireJsConfig({preventPopulationOfJavaScriptAssetsUntilConfigHasBeenFound: true}) 87 | .registerLabelsAsCustomProtocols(commandLineOptions.label, {installFindParentDirectoryAsDefault: commandLineOptions.parentdir}) 88 | .loadAssets(inputUrls) 89 | .populate({from: {type: 'Html'}, followRelations: {type: 'HtmlScript', to: {url: /^file:/}}}) 90 | .assumeRequireJsConfigHasBeenFound() 91 | .populate({ 92 | followRelations: query.or( 93 | { 94 | to: {type: 'I18n'} 95 | }, 96 | { 97 | type: query.not(['JavaScriptCommonJsRequire', 'HtmlAnchor', 'HtmlMetaRefresh', 'SvgAnchor', 'JavaScriptSourceMappingUrl', 'JavaScriptSourceUrl']), 98 | to: {url: query.not(/^https?:/)} 99 | } 100 | ) 101 | }) 102 | .checkLanguageKeys({ 103 | supportedLocaleIds: localeIds, 104 | defaultLocaleId: defaultLocaleId, 105 | ignoreMessageTypes: ignoreMessageTypes, 106 | warnMessageTypes: warnMessageTypes, 107 | removeUnused: commandLineOptions.removeunused, 108 | includeAttributeNames: includeAttributeNames, 109 | excludeAttributeNames: excludeAttributeNames 110 | }) 111 | .if(commandLineOptions.removeunused) 112 | .prettyPrintAssets({type: ['I18n'], isDirty: true}) 113 | .writeAssetsToDisc({type: ['I18n'], isDirty: true}) 114 | .endif() 115 | .run(); 116 | -------------------------------------------------------------------------------- /test/bin/applyBabelJob.js: -------------------------------------------------------------------------------- 1 | /*global describe, it*/ 2 | var childProcess = require('child_process'), 3 | fs = require('fs'), 4 | Path = require('path'), 5 | expect = require('unexpected'), 6 | temp = require('temp'); 7 | 8 | describe('applyBabelJob', function () { 9 | it('should handle a complex test case', function (done) { 10 | var babelDir = Path.resolve(__dirname, '..', '..', 'testdata', 'bin', 'applyBabelJob', 'translationjob'), 11 | tmpTestCaseCopyDir = temp.mkdirSync(), 12 | copyCommand = 'cp \'' + __dirname + '/../../testdata/bin/applyBabelJob\'/index.* ' + tmpTestCaseCopyDir; 13 | childProcess.exec(copyCommand, function (err, stdout, stderr) { 14 | if (err) { 15 | return done(new Error(copyCommand + ' failed: STDERR:' + stderr + '\nSTDOUT:' + stdout)); 16 | } 17 | var applyBabelJobProcess = childProcess.spawn(__dirname + '/../../bin/applyBabelJob', [ 18 | '--babeldir', babelDir, 19 | '--root', tmpTestCaseCopyDir, 20 | '--defaultlocale', 'en', 21 | '--locales', 'en,da', 22 | '--i18n', tmpTestCaseCopyDir + '/index.i18n', 23 | '--replace', 24 | tmpTestCaseCopyDir + '/index.html' 25 | ]); 26 | 27 | applyBabelJobProcess.on('exit', function (exitCode) { 28 | if (exitCode) { 29 | done(new Error('The applyBabelJob process ended with a non-zero exit code: ' + exitCode)); 30 | } else { 31 | expect(JSON.parse(fs.readFileSync(tmpTestCaseCopyDir + '/index.i18n')), 'to equal', { 32 | ComplexKey: { 33 | da: { 34 | that: 'også kommer', 35 | back: 'det samme' 36 | }, 37 | en: { 38 | that: 'also comes', 39 | back: 'the same' 40 | } 41 | }, 42 | WeirdlyFormattedKey: { 43 | da: 'der kommer uændret retur i oversættelsesjobbet', 44 | en: 'that comes back the same in the translation job' 45 | }, 46 | bar: { 47 | da: 'BarOversat', 48 | en: 'BarProofRead' 49 | }, 50 | foo: { 51 | da: 'FooOversat', 52 | en: 'FooProofRead' 53 | }, 54 | placeholders: { 55 | da: 'Denne oversatte nøgle har {0} pladsholdere', 56 | en: 'This proofread key has {0} proofread placeholders' 57 | } 58 | }); 59 | expect(JSON.parse(fs.readFileSync(tmpTestCaseCopyDir + '/index.someother.i18n')), 'to equal', { 60 | KeyInSomeOtherI18nFile: { 61 | en: 'Woop', 62 | da: 'Jubii' 63 | } 64 | }); 65 | expect(fs.readFileSync(tmpTestCaseCopyDir + '/index.html', 'utf-8'), 'to equal', 66 | '\n' + 67 | '\n' + 68 | ' \n' + 69 | ' FooProofRead\n' + 70 | ' \n' + 71 | ' \n' + 72 | ' \n' + 82 | ' This proofread key has some proofread placeholders\n' + 83 | ' \n' + 84 | ' \n' + 85 | ' that comes back the same\n' + 86 | ' in the translation job\n' + 87 | ' \n' + 88 | ' data-i18n specifying that the contents of the tag should not be translated\n' + 89 | ' data-i18n specifying that the contents of the tag should not be translated\n' + 90 | ' \n' + 91 | ' \n' + 92 | '\n' 93 | ); 94 | done(); 95 | } 96 | }); 97 | }); 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /bin/refreshI18n: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require('lodash'), 4 | AssetGraph = require('../lib/AssetGraph'), 5 | i18nTools = require('../lib/i18nTools'), 6 | uglifyAst = require('uglifyast'), 7 | urlTools = require('urltools'), 8 | fs = require('fs'), 9 | commandLineOptions = require('optimist') 10 | .usage('$0 [--label = ...] [--parentdir] --root --locales ,... ...') 11 | .boolean('parentdir') 12 | .demand(['root', 'locales']) 13 | .argv, 14 | localeIds = _.flatten(_.flatten([commandLineOptions.locales]).map(function (localeId) { 15 | return localeId.split(','); 16 | })); 17 | 18 | new AssetGraph({root: commandLineOptions.root}) 19 | .logEvents({repl: commandLineOptions.repl, stopOnWarning: commandLineOptions.stoponwarning, suppressJavaScriptCommonJsRequireWarnings: true}) 20 | .registerRequireJsConfig({preventPopulationOfJavaScriptAssetsUntilConfigHasBeenFound: true}) 21 | .registerLabelsAsCustomProtocols(commandLineOptions.label, {installFindParentDirectoryAsDefault: commandLineOptions.parentdir}) 22 | .loadAssets(commandLineOptions._.map(urlTools.fsFilePathToFileUrl)) 23 | .populate({from: {type: 'Html'}, followRelations: {type: 'HtmlScript', to: {url: /^file:/}}}) 24 | .assumeRequireJsConfigHasBeenFound() 25 | .populate({ 26 | followRelations: { 27 | type: ['HtmlScript', 'HtmlRequireJsMain', 'JavaScriptInclude', 'JavaScriptAmdDefine', 'JavaScriptAmdRequire', 'JavaScriptGetText'], 28 | to: {url: AssetGraph.query.not(/^https?:/)} 29 | } 30 | }) 31 | .queue(function (assetGraph) { 32 | // We don't want to overwrite the "initially dirty" assets, such as ext-base.js. 33 | assetGraph.findAssets({isDirty: true}).forEach(function (dirtyAsset) { 34 | dirtyAsset.isDirty = false; 35 | }); 36 | var existingI18nRelations = assetGraph.findRelations({to: {type: 'I18n'}, from: {type: 'JavaScript'}}), 37 | occurrencesByKey = i18nTools.findOccurrences(assetGraph, assetGraph.findAssets({type: 'Html', isInitial: true})); 38 | 39 | _.keys(occurrencesByKey).forEach(function (key) { 40 | var occurrences = occurrencesByKey[key]; 41 | if (occurrences.length > 1) { 42 | for (var i = 1 ; i < occurrences.length ; i += 1) { 43 | if (!_.isEqual(occurrences[0].defaultValue, occurrences[1].defaultValue)) { 44 | console.warn('Default values for ' + key + ' are different'); 45 | } 46 | } 47 | } 48 | var i18nAsset = i18nTools.getOrCreateI18nAssetForKey(assetGraph, key, occurrencesByKey); 49 | localeIds.forEach(function (localeId) { 50 | var prioritizedLocaleIds = i18nTools.expandLocaleIdToPrioritizedList(localeId); 51 | if (key in i18nAsset.parseTree) { 52 | for (var i = 0 ; i < prioritizedLocaleIds.length ; i += 1) { 53 | if (prioritizedLocaleIds[i] in i18nAsset.parseTree[key]) { 54 | return; // Already found, don't do anything 55 | } 56 | } 57 | } else { 58 | i18nAsset.parseTree[key] = {}; 59 | } 60 | var leastSpecificLocaleId = prioritizedLocaleIds[prioritizedLocaleIds.length - 1], 61 | value = null; 62 | if (leastSpecificLocaleId === 'en' && occurrences[0].defaultValue) { 63 | value = /^i18nTag/.test(occurrences[0].type) ? occurrences[0].defaultValue : uglifyAst.astToObj(occurrences[0].defaultValue); 64 | } 65 | i18nAsset.parseTree[key][leastSpecificLocaleId] = value; 66 | console.log(i18nAsset.url + ': ' + key + ' already found, added entry for ' + leastSpecificLocaleId); 67 | i18nAsset.markDirty(); 68 | }); 69 | }); 70 | 71 | // Find the JavaScript => I18n relations that didn't exist when we started: 72 | var newI18nRelationsByJavaScriptId = {}; 73 | assetGraph.findRelations({to: {type: 'I18n'}, from: {type: 'JavaScript'}}).forEach(function (i18nRelation) { 74 | if (existingI18nRelations.indexOf(i18nRelation) === -1) { 75 | (newI18nRelationsByJavaScriptId[i18nRelation.from.id] = newI18nRelationsByJavaScriptId[i18nRelation.from.id] || []).push(i18nRelation); 76 | } 77 | }); 78 | 79 | // Hack: Inject the new relations at the top of the file 80 | _.each(newI18nRelationsByJavaScriptId, function (i18nRelations, javaScriptId) { 81 | var javaScript = assetGraph.idIndex[javaScriptId], 82 | originalText = fs.readFileSync(urlTools.fileUrlToFsPath(javaScript.url), javaScript.encoding), 83 | oneIncludeStatements = i18nRelations.map(function (i18nRelation) { 84 | return 'INCLUDE(\'' + 85 | urlTools.buildRelativeUrl(i18nRelation.from.url || assetGraph.findBaseAssetForRelation(i18nRelation).url, i18nRelation.to.url) + 86 | '\');\n'; 87 | }).join(''), 88 | matchSplitAfterLastOneIncludeLine = originalText.match(/^([\s\S]*one\.include[^\n]*\n)([\s\S]*)$/), 89 | patchedText; 90 | if (matchSplitAfterLastOneIncludeLine) { 91 | patchedText = matchSplitAfterLastOneIncludeLine[1] + '\n' + oneIncludeStatements + matchSplitAfterLastOneIncludeLine[2]; 92 | } else { 93 | patchedText = oneIncludeStatements + originalText; 94 | } 95 | fs.writeFileSync(urlTools.fileUrlToFsPath(javaScript.url), patchedText, javaScript.encoding); 96 | }); 97 | }) 98 | .prettyPrintAssets({type: 'I18n', isDirty: true}) 99 | .writeStatsToStderr() 100 | .writeAssetsToDisc({type: 'I18n', isDirty: true}) 101 | .run(); 102 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // JSHint Default Configuration File (as on JSHint website) 3 | // See http://jshint.com/docs/ for more details 4 | 5 | "maxerr" : 50, // {int} Maximum error before stopping 6 | 7 | // Enforcing 8 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) 9 | "camelcase" : false, // true: Identifiers must be in camelCase 10 | "curly" : true, // true: Require {} for every new block or scope 11 | "eqeqeq" : true, // true: Require triple equals (===) for comparison 12 | "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() 13 | "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` 14 | "indent" : 4, // {int} Number of spaces to use for indentation 15 | "latedef" : true, // true: Require variables/functions to be defined before being used 16 | "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` 17 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` 18 | "noempty" : true, // true: Prohibit use of empty blocks 19 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) 20 | "plusplus" : true, // true: Prohibit use of `++` & `--` 21 | "quotmark" : "single", // Quotation mark consistency: 22 | // false : do nothing (default) 23 | // true : ensure whatever is used is consistent 24 | // "single" : require single quotes 25 | // "double" : require double quotes 26 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) 27 | "unused" : "vars", // true: Require all defined variables be used 28 | "strict" : false, // true: Requires all functions run in ES5 Strict Mode 29 | "trailing" : true, // true: Prohibit trailing whitespaces 30 | "maxparams" : false, // {int} Max number of formal params allowed per function 31 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions) 32 | "maxstatements" : false, // {int} Max number statements per function 33 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function 34 | "maxlen" : false, // {int} Max number of characters per line 35 | 36 | // Relaxing 37 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) 38 | "boss" : false, // true: Tolerate assignments where comparisons would be expected 39 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. 40 | "eqnull" : false, // true: Tolerate use of `== null` 41 | "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) 42 | "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) 43 | // (ex: `for each`, multiple try/catch, function expression…) 44 | "evil" : false, // true: Tolerate use of `eval` and `new Function()` 45 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs 46 | "funcscope" : false, // true: Tolerate defining variables inside control statements" 47 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') 48 | "iterator" : false, // true: Tolerate using the `__iterator__` property 49 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block 50 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings 51 | "laxcomma" : false, // true: Tolerate comma-first style coding 52 | "loopfunc" : true, // true: Tolerate functions being defined in loops 53 | "multistr" : false, // true: Tolerate multi-line strings 54 | "proto" : false, // true: Tolerate using the `__proto__` property 55 | "scripturl" : false, // true: Tolerate script-targeted URLs 56 | "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment 57 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` 58 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation 59 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` 60 | "validthis" : false, // true: Tolerate using this in a non-constructor function 61 | 62 | // Environments 63 | "browser" : false, // Web Browser (window, document, etc) 64 | "couch" : false, // CouchDB 65 | "devel" : true, // Development/debugging (alert, confirm, etc) 66 | "dojo" : false, // Dojo Toolkit 67 | "jquery" : true, // jQuery 68 | "mootools" : false, // MooTools 69 | "node" : true, // Node.js 70 | "nonstandard" : true, // Widely adopted globals (escape, unescape, etc) 71 | "prototypejs" : false, // Prototype and Scriptaculous 72 | "rhino" : false, // Rhino 73 | "worker" : false, // Web Workers 74 | "wsh" : false, // Windows Scripting Host 75 | "yui" : false, // Yahoo User Interface 76 | 77 | // Legacy 78 | "nomen" : false, // true: Prohibit dangling `_` in variables 79 | "onevar" : false, // true: Allow only one `var` statement per function 80 | "passfail" : false, // true: Stop on first error 81 | "white" : true, // true: Check against strict whitespace and indentation rules 82 | 83 | // Custom Globals 84 | "predef" : [ // additional predefined global variables 85 | "TR", 86 | "TRPAT", 87 | "GETTEXT", 88 | "GETSTATICURL", 89 | "INCLUDE", 90 | "define", 91 | "require" 92 | ] 93 | } 94 | -------------------------------------------------------------------------------- /lib/resolvers/senchaJsBuilder.js: -------------------------------------------------------------------------------- 1 | /*global setImmediate:true*/ 2 | // node 0.8 compat 3 | if (typeof setImmediate === 'undefined') { 4 | setImmediate = process.nextTick; 5 | } 6 | 7 | var fs = require('fs'), 8 | urlTools = require('urltools'), 9 | seq = require('seq'), 10 | _ = require('lodash'), 11 | passError = require('passerror'); 12 | 13 | module.exports = function (fileUrl) { 14 | var matchJSBUrl = fileUrl.match(/^(.*\/)[^\/]*\.jsb([23])$/); 15 | 16 | if (!matchJSBUrl) { 17 | throw new Error('resolvers.SenchaJsBuilder: Url must end in .jsb2 or .jsb3: ' + fileUrl); 18 | } 19 | var baseUrl = matchJSBUrl[1], 20 | jsbVersion = parseInt(matchJSBUrl[2], 10), 21 | jsbBody = JSON.parse(fs.readFileSync(urlTools.fileUrlToFsPath(fileUrl), 'utf-8')), 22 | pkgIndex = {}; 23 | 24 | if (jsbVersion === 2) { 25 | jsbBody.packages = jsbBody.pkgs; 26 | delete jsbBody.pkgs; 27 | } 28 | 29 | jsbBody.builds = jsbBody.builds || []; 30 | 31 | ['packages', 'builds'].forEach(function (sectionName) { 32 | if (sectionName in jsbBody) { 33 | jsbBody[sectionName].forEach(function (pkg) { 34 | if (jsbVersion === 2) { 35 | pkg.packages = pkg.pkgDeps; 36 | delete pkg.pkgDeps; 37 | pkg.target = pkg.file; 38 | delete pkg.file; 39 | pkg.files = pkg.fileIncludes.map(function (fileInclude) { 40 | return { 41 | path: fileInclude.path.replace(/^src\/ext-core/, '../ext-core'), // FIXME 42 | name: fileInclude.text 43 | }; 44 | }); 45 | delete pkg.fileIncludes; 46 | } 47 | pkgIndex[pkg.name] = pkgIndex[pkg.target] = pkg; 48 | if ('id' in pkg) { 49 | pkgIndex[pkg.id] = pkg; 50 | } 51 | }); 52 | } 53 | }); 54 | 55 | function fixupAssetConfig(assetConfig, cb) { 56 | if (/\bresources\/.*\.css$/.test(assetConfig.url) && /^Ext JS Library [23].\d.\d/.test(jsbBody.licenseText)) { 57 | // Stupid ExtJS 3 has Css url()s relative to the target paths of their 58 | // bundles, NOT the source files! 59 | // Issue reported here: http://www.extjs.com/forum/showthread.php?p=330222 60 | // Work around it by around by substituting the url()s: 61 | 62 | fs.readFile(urlTools.fileUrlToFsPath(assetConfig.url), 'utf-8', passError(cb, function (src) { 63 | assetConfig.type = 'Css'; 64 | assetConfig.text = src.replace(/\/\*[\s\S]*?\*\//g, ' ').replace(/url\s*\(\s*/g, function () { 65 | assetConfig.isDirty = true; 66 | assetConfig.fixedUpExtJS = true; 67 | return 'url(../'; 68 | }); 69 | assetConfig.isResolved = true; 70 | cb(null, assetConfig); 71 | })); 72 | } else { 73 | setImmediate(function () { 74 | cb(null, assetConfig); 75 | }); 76 | } 77 | } 78 | 79 | function resolveExtBase(pkg, fileNames, cb) { 80 | seq(fileNames) 81 | .parMap(function (url) { 82 | fs.readFile(urlTools.fileUrlToFsPath(url), 'utf-8', this); 83 | }) 84 | .unflatten() 85 | .seq(function (texts) { 86 | cb(null, { 87 | type: 'JavaScript', 88 | isResolved: true, 89 | isDirty: true, 90 | fixedUpExtJS: true, 91 | text: texts.join('\n'), 92 | outgoingRelations: [], // Save the trouble of parsing it to find zero relations 93 | url: urlTools.resolveUrl(baseUrl, pkg.target) 94 | }); 95 | })['catch'](cb); 96 | } 97 | 98 | function resolvePkg(pkg, cb) { 99 | var assetConfigs = [], 100 | fileNames = (pkg.files || []).map(function (fileDef) { 101 | return urlTools.resolveUrl(baseUrl, fileDef.path + fileDef.name); 102 | }); 103 | 104 | if (pkg.name === 'Ext Base') { 105 | // Special case for the ext-base.js package, which doesn't work when included as individual files 106 | return resolveExtBase(pkg, fileNames, cb); 107 | } 108 | 109 | seq(pkg.packages || []) 110 | .parMap(function (dependentPkgTargetFileName) { 111 | if (!pkgIndex[dependentPkgTargetFileName] && dependentPkgTargetFileName === 'ext-base.js') { 112 | dependentPkgTargetFileName = 'adapter/ext/ext-base.js'; // pkgDeps bug in ExtJS 3.2 113 | } 114 | resolvePkg(pkgIndex[dependentPkgTargetFileName], this); 115 | }) 116 | .seqEach(function (resolvedAssetConfigs) { 117 | if (_.isArray(resolvedAssetConfigs)) { 118 | Array.prototype.push.apply(assetConfigs, resolvedAssetConfigs); 119 | } else { 120 | assetConfigs.push(resolvedAssetConfigs); 121 | } 122 | this(); 123 | }) 124 | .set(fileNames) 125 | .parMap(function (url) { 126 | var assetConfig = { 127 | url: url 128 | }; 129 | if (/\.js$/.test(url)) { 130 | assetConfig.outgoingRelations = []; 131 | } 132 | fixupAssetConfig(assetConfig, this); 133 | }) 134 | .unflatten() 135 | .seq(function (fixedUpAssetConfigs) { 136 | cb(null, assetConfigs.concat(fixedUpAssetConfigs)); 137 | })['catch'](cb); 138 | } 139 | 140 | return function senchaJsBuilder(assetConfig, fromUrl, cb) { 141 | var labelRelativePath = assetConfig.url.replace(/^[^:]*:/, ''); 142 | if (labelRelativePath in pkgIndex) { 143 | resolvePkg(pkgIndex[labelRelativePath], cb); 144 | } else { 145 | fixupAssetConfig({url: urlTools.resolveUrl(baseUrl, labelRelativePath)}, cb); 146 | } 147 | }; 148 | }; 149 | --------------------------------------------------------------------------------