WARNING: The following solution is based on knowledge of the internal implementation of the story format, and may stop working if the implementation changes in a future release of Harlowe 2.
The following Javascript prototype creates a custom Namespace and Function which will return an Array of datanames in their Natural order, the code needs to be placed within your story's Story Javascript area.
if (! window.GE) {
window.GE = {};
}
/* Returns an Array of datanames in Natural order. */
window.GE.datanamesNatural = function (value) {
var map = null;
if (value === null || typeof value !== "object") {
throw new TypeError('value is not an object');
} else if (value instanceof Map) {
map = value;
} else if (value.get) {
map = value.get();
} else {
throw new TypeError('value is not a VarRef or a Map');
}
return Array.from(map.keys());
}
The following test example shows how to use the new GE.datanamesNatural() function in a standard Passage.:
(set: $map to (datamap: "C", 1, "A", 2, "B", 3))
(set: $namesAtoZ to (datanames: $map))
(set: $namesNatural to GE.datanamesNatural($map))
A-Z: (print: $namesAtoZ)
Natural: (print: $namesNatural)
Within print: (print: GE.datanamesNatural($map))
NOTES:
a. For some reason Harlowe passes the story variable to the Javascript function as a VarRef object when reference within a (set:) macro, and passes the same value as Map when referenced within a (print:) macro.
b. I was not able to think of a better method for checking if the value passed was a VarRef, other than checking for the existence of the get function, because VarRef is not a known class so instanceof did not work.
c. I suggest you change the GE Namespace name to another unique name that makes sense to your particular project, just remember to also change every usage of the GE namespace in your TwineScript to the new unique name.
A more experienced Javascript programmer may be able to create a better implementation of this function.