From 3502f6133aa143e181fea6764ea530c4188d1c91 Mon Sep 17 00:00:00 2001 From: Trevor DeVore Date: Fri, 18 Jan 2019 15:17:46 -0600 Subject: [PATCH] Add support for helper dependencies Helpers can now have a `name` and define `dependencies`. This is a comma delimited list of other helper names that the helper is dependent on. If a helper is dependent on another helper then the other helper will be loaded before it. --- framework/levure.livecodescript | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/framework/levure.livecodescript b/framework/levure.livecodescript index dca25db..216f164 100644 --- a/framework/levure.livecodescript +++ b/framework/levure.livecodescript @@ -1194,6 +1194,7 @@ command levureLoadAppConfig pBuildProfile put the result into tError if tError is empty then + sortHelpersBasedOnDependencies resolveHelperAssets pBuildProfile put the result into tError end if @@ -1947,6 +1948,93 @@ private function shellFormat pArg, pSwitch end shellFormat +/** +Summary: Reorders helpers so that dependencies are loaded before dependents. + +Description: +If a helper is dependent on another helper then behaviors in the dependency +must be loaded first. This handler will reorder helpers so that the load +order is correct. + +Returns: nothing +*/ +private command sortHelpersBasedOnDependencies + local tHelperA, tHelpersA, tIndexesToProcess, tIndex, tNewIndex + local tLoadedHelpersA, tSkip + + lookForCircularDependenciesInHelpers + + put the keys of sAppA["helpers"] into tIndexesToProcess + sort lines of tIndexesToProcess numeric ascending + + repeat until tIndexesToProcess is empty + put line 1 of tIndexesToProcess into tIndex + put sAppA["helpers"][tIndex] into tHelperA + + put false into tSkip + + repeat for each item tHelperName in tHelperA["dependencies"] + if tHelperName is not among the keys of tLoadedHelpersA then + + # Move this helper to the end of the list + put tIndex into line (the number of lines of tIndexesToProcess + 1) of tIndexesToProcess + + put true into tSkip + exit repeat + end if + end repeat + + if not tSkip then + add 1 to tNewIndex + put tHelperA into tHelpersA[tNewIndex] + put empty into tLoadedHelpersA[ tHelperA["name"] ] + end if + + delete line 1 of tIndexesToProcess + end repeat + + put tHelpersA into sAppA["helpers"] +end sortHelpersBasedOnDependencies + + +/** +Summary: Performs a simple check for circular dependencies. + +Description: +The check only looks for circular dependencies between A and B. +It doesn't look for circular connections between A, B, and C where +A depends on B and B depends on C but C depends on A. + +Returns: nothing +*/ +private command lookForCircularDependenciesInHelpers + local tHelperA, tDependenciesA + local tHelperName, tDependentName + + # Create lookup area of each helper's dependencies + repeat for each element tHelperA in sAppA["helpers"] + if word 1 to -1 of tHelperA["name"] is not empty then + repeat for each item tHelperName in tHelperA["dependencies"] + put tHelperA["name"] & "," after tDependenciesA[tHelperName] + end repeat + end if + end repeat + + # Now see if any of a helper depends on any of it's dependents. + repeat for each element tHelperA in sAppA["helpers"] + if word 1 to -1 of tHelperA["name"] is not empty then + repeat for each item tDependentName in tDependenciesA[ tHelperA["name"] ] + if tHelperA["name"] is among the items of tDependenciesA[tDependentName] then + throw kLevureErr & "circular dependency detected in" && \ + quote & tHelperA["name"] & quote && "and" && \ + quote & tDependentName & quote && "helpers" + end if + end repeat + end if + end repeat +end lookForCircularDependenciesInHelpers + + private command resolveHelperAssets pBuildProfile local tError, tConfigA, i local tExternalPackagesInMemory