lib/transforms/moveAssetsInOrder.js

lib/ AssetGraph.js errors.js index.js query.js
assets/ Asset.js Atom.js CacheManifest.js CoffeeScript.js Css.js Flash.js Gif.js Htc.js Html.js I18n.js Ico.js Image.js JavaScript.js Jpeg.js Json.js KnockoutJsTemplate.js Less.js Png.js Rss.js StaticUrlMap.js Stylus.js Text.js Xml.js index.js
relations/ CacheManifestEntry.js CssAlphaImageLoader.js CssBehavior.js CssFontFaceSrc.js CssImage.js CssImport.js CssUrlTokenRelation.js HtmlAlternateLink.js HtmlAnchor.js HtmlAppleTouchStartupImage.js HtmlApplet.js HtmlAudio.js HtmlCacheManifest.js HtmlConditionalComment.js HtmlDataBindAttribute.js HtmlEdgeSideInclude.js HtmlEmbed.js HtmlFrame.js HtmlIFrame.js HtmlIFrameSrcDoc.js HtmlImage.js HtmlInlineScriptTemplate.js HtmlKnockoutContainerless.js HtmlObject.js HtmlRelation.js HtmlRequireJsMain.js HtmlScript.js HtmlShortcutIcon.js HtmlStyle.js HtmlStyleAttribute.js HtmlVideo.js HtmlVideoPoster.js JavaScriptAmdDefine.js JavaScriptAmdRequire.js JavaScriptCommonJsRequire.js JavaScriptExtJsRequire.js JavaScriptGetStaticUrl.js JavaScriptGetText.js JavaScriptInclude.js JavaScriptShimRequire.js JavaScriptTrHtml.js Relation.js StaticUrlMapEntry.js index.js
resolvers/ data.js extJs4Dir.js file.js fixedDirectory.js http.js index.js javascript.js
transforms/ addCacheManifest.js bundleRelations.js bundleRequireJs.js compileCoffeeScriptToJavaScript.js compileLessToCss.js compileStylusToCss.js compressJavaScript.js convertCssImportsToHtmlStyles.js convertHtmlStylesToInlineCssImports.js convertStylesheetsToInlineStyles.js drawGraph.js executeJavaScriptInOrder.js externalizeRelations.js flattenStaticIncludes.js inlineCssImagesWithLegacyFallback.js inlineRelations.js loadAssets.js mergeIdenticalAssets.js minifyAssets.js moveAssets.js moveAssetsInOrder.js populate.js prettyPrintAssets.js pullGlobalsIntoVariables.js registerRequireJsConfig.js removeAssets.js removeRelations.js setAssetContentType.js setAssetEncoding.js setAssetExtension.js setHtmlImageDimensions.js startOverIfAssetSourceFilesChange.js writeAssetsToDisc.js writeAssetsToStdout.js writeStatsToStderr.js
util/ deepCopy.js extendWithGettersAndSetters.js fsTools.js getImageInfoFromBuffers.js memoizeAsyncAccessor.js uniqueId.js urlTools.js
var urlTools = require('../util/urlTools'),
    query = require('../query');

// Helper function for determining the order in which the hashes can be computed and the assets
// moved. The challenge lies in the fact that updating a relation to point at .
// will change the hash of the asset that owns the relation.
// Needless to say this will fail if the graph of assets to be moved has cycles, so be careful.
function findAssetMoveOrderBatches(assetGraph, queryObj) {
    var batches = [],
        outgoingRelationsByAssetId = {},
        assetMatcher = query.queryObjToMatcherFunction(queryObj);

    assetGraph.findAssets({isInline: false}).forEach(function (asset) {
        if (assetMatcher(asset)) {
            outgoingRelationsByAssetId[asset.id] = assetGraph.findRelations({from: assetGraph.collectAssetsPostOrder(asset, {to: {isInline: true}}), to: {isInline: false}});
        }
    });

    while (true) {
        var remainingAssetIds = Object.keys(outgoingRelationsByAssetId);
        if (remainingAssetIds.length === 0) {
            break;
        }
        var currentBatch = [];
        remainingAssetIds.forEach(function (assetId) {
            if (!outgoingRelationsByAssetId[assetId].some(function (outgoingRelation) {return outgoingRelation.to.id in outgoingRelationsByAssetId;})) {
                currentBatch.push(assetGraph.idIndex[assetId]);
            }
        });

        currentBatch.forEach(function (asset) {
            delete outgoingRelationsByAssetId[asset.id];
        });

        if (currentBatch.length === 0) {
            throw new Error("transforms.moveAssetsInOrder: Couldn't find a suitable rename order due to cycles in the selection");
        }
        batches.push(currentBatch);
    }
    return batches;
}

module.exports = function (queryObj, newUrlFunctionOrString) {
    if (!newUrlFunctionOrString) {
        throw new Error("transforms.moveAssetsInOrder: 'newUrlFunctionOrString' parameter is mandatory.");
    }
    return function moveAssetsInOrder(assetGraph) {
        findAssetMoveOrderBatches(assetGraph, queryObj).forEach(function (assetBatch) {
            assetBatch.forEach(function (asset) {
                var newUrl = typeof newUrlFunctionOrString === 'function' ? newUrlFunctionOrString(asset, assetGraph) : String(newUrlFunctionOrString);
                if (newUrl) {
                    // Keep the old file name, query string and fragment identifier if the new url ends in a slash:
                    if (asset.url && /\/$/.test(newUrl)) {
                        var matchOldFileNameQueryStringAndFragmentIdentifier = asset.url.match(/[^\/]*(?:[\?#].*)?$/);
                        if (matchOldFileNameQueryStringAndFragmentIdentifier) {
                            newUrl += matchOldFileNameQueryStringAndFragmentIdentifier[0];
                        }
                    }
                    asset.url = newUrl;
                }
            });
        });
    };
};