Infusion Core API

This file documents some low-level APIs which are provided by Infusion at the JavaScript level. Note that since Infusion's more overarching aim is to enable declarative programming based on JSON structures, by means of its IoC system, the documentation in this file doesn't cover very much of Infusion's real function. Please consult pages on Component Grades, Component Configuration Options, the Infusion Event System, etc. for coverage of these wider topics.

Type checking

fluid.isValue(value)

  • value {Any}
  • Returns: {Boolean}

Returns true if the supplied value is other than null or undefined.

fluid.isPrimitive(value)

  • value {Any}
  • Returns: {Boolean}

Returns true if the supplied value is of a primitive JavaScript type (recognized: String, Boolean, Number, Function, and falsy values)

fluid.isArrayable(totest)

  • totest {Any}
  • Returns: {Boolean}

Returns true if the supplied value can be treated as an array. The strategy used is an optimised approach taken from an earlier version of jQuery - detecting whether the toString() version of the object agrees with the textual form [object Array], or else whether the object is a jQuery object (the most common source of "fake arrays").

fluid.isPlainObject(totest[, strict])

  • totest {Any}
  • strict {Boolean} [optional] If true, only accepts plain Objects
  • Returns: {Boolean}

Returns true if the supplied object is a plain JSON-forming container - that is, it is either a plain Object or a plain Array. If the strict argument holds true, only returns true if the supplied object is a plain Object. This method will accept as plain objects coming from other contexts (e.g. iframes or V8 contexts) if they were plain in that context.

fluid.typeCode(totest)

  • totest {Any}
  • Returns: {String}

Returns primitive, array or object depending on whether the supplied object has one of those types, by use of the fluid.isPrimitive, fluid.isPlainObject and fluid.isArrayable utilities

fluid.isDOMNode(totest)

  • totest {Any}
  • Returns: {Boolean}

Returns true if the supplied object is a DOM node.

fluid.isDOMish(totest)

  • totest {Any}
  • Returns: {Boolean}

Returns true if the supplied object is a DOM node or a jQuery object.

fluid.isUncopyable(totest)

  • totest {Any}
  • Returns: {Boolean}

Returns true if it would be unwise to copy the supplied object. The framework will not attempt to copy any material which fails this test. An object which passes fluid.isPrimitive, fluid.isDOMish or fails fluid.isPlainObject will pass this test.

fluid.isComponent(totest)

  • totest {Any}
  • Returns: {Boolean}

Returns true if the supplied object is an Infusion component.

fluid.isDestroyed(component)

  • component {Component}
  • Returns: {Boolean}

Returns true if the supplied Infusion component has been destroyed.

fluid.hasGrade(options, gradeName)

  • options {Object}
  • gradeName {String}
  • Returns: {Boolean}

Returns true if the supplied options (defaults) are the top-level options of a component which has the supplied grade. These must be options which have already been through options merging, since the test is a simpleminded one that simply checks whether the gradeNames entry in the options contains the supplied gradeName.

fluid.componentHasGrade(component, gradeName)

  • component {Component}
  • gradeName {String}
  • Returns: {Boolean}

Returns true if the supplied component has the supplied gradeName as a parent grade. This is a rapid check which uses the framework's internal data structures for the lookup.

Basic implementation atoms

fluid.identity(arg)

  • arg {Any}
  • Returns: {Any}

fluid.notImplemented()

A function which raises a failure if executed. This function name can also be used as a placeholder in Invokers and namespaced Listener to create abstract (noninstantiable) Component Grades.

fluid.each(source, func)

  • source {Array|Object} A container to be iterated over (may be null)
  • func {Function} (element {Any}, index {Number|String}) → Any. This function will be invoked once on each member of source and will receive the member and its key (either an integer for an array source, or a string for an object source)
  • Returns: none

Iterates over a supplied array or hash, invoking a function once for each member. Similar to jQuery.each only the arguments to func are the right way round and the function does not explode on nonvalues. fluid.each on null or undefined is a no-op.

fluid.invokeLater(func)

  • func {Function} A function accepting zero arguments which is to be invoked later
  • Returns: none

A standard utility to schedule the invocation of a function after the current function call stack returns. On browsers this defaults to setTimeout(func, 1) but in other environments can be customised - e.g. to process.nextTick in node.js. In future, this could be optimised in the browser to not dispatch into the event queue.

fluid.allocateGuid()

  • Returns: {String} A string of about a dozen characters that has made moderate efforts to be globally unique.

Allocate a string value that will be unique within this Infusion instance (frame or process), and globally unique with high probability (50% chance of collision after a million trials). This has the structure prefix-id where prefix is the value of fluid.fluidInstance identifying this Infusion instance, and id is a increasing integer initialised at 1 when this infusion instance starts up.

fluid.add(a, b)

  • a {Number} The first operand to be added
  • b {Number} The second operand to be added
  • Returns: {Number} The value of a + b

Returns the result of invoking the JavaScript operator + on its two arguments. This is a function convenient to supply, for example, to fluid.accumulate to sum a list of numbers.

Creation, copying and destroying

fluid.freshContainer(tocopy)

  • tocopy {Object|Array}
  • Returns: {Object|Array}

Return an empty container as the same type as the argument (either an array or hash). To be wise, the supplied argument should pass the fluid.isPlainObject test.

fluid.copy(tocopy)

  • tocopy {Any}
  • Returns: {Any}

Performs a deep copy (clone) of its argument. This will guard against cloning a circular object by terminating if it reaches a path depth greater than fluid.strategyRecursionBailout. fluid.copy will not copy an object which passes fluid.isUncopyable.

fluid.makeArray(arg)

  • arg {Any}
  • Returns: {Array}

Converts the supplied argument to an array (or copies it if it is already an array), by a variety of strategies:

  • If it is even slightly arrayable (has a numeric length property), its elements will be copied into a fresh array
  • If it is not slightly arrayable, it will be placed into a 1-element array
  • If it is undefined, a 0-element array will be returned

fluid.generate(n, generator[, applyFunc])

  • n {Integer} The size of the array to be filled
  • generator {Object|Function} Either a value to be replicated or function to be called (if the applyFunc argument holds true). In case of a function, the signature is (i {Integer}) → Any, accepting the index position and returning the generated element.
  • applyFunc {Boolean} If true, the generator value is to be treated as a function
  • Returns: {Array} An array of length n holding the generated elements

Fills an array of given size with copies of a value or result of a function invocation

fluid.iota(n[, first])

  • n {Integer} Size of the filled array to be returned
  • first {Number} [optional, defaults to 0] First element to appear in the array
  • Returns: {Array} An array of length n holding the generated elements

Returns an array of size n, filled with increasing integers, starting at 0 or at the value specified by first. The name iota originally stems from the APL programming language.

fluid.clear(target)

  • target {Object|Array} The target to be cleared
  • Returns: {Undefined}

Clears an object or array of its contents. For objects, each property is deleted. The input argument will be destructively modified.

Transforming and filtering

fluid.transform(source, [fn1, fn2, ...])

  • source {Array|Object} The initial container of objects to be transformed. If the source is neither an array nor an object, it will be returned untransformed
  • fn_i {Function} (element {Any}, index {Number|String})→Any (arbitrary number accepted) An arbitrary number of optional further arguments, all of type Function, accepting the signature (element, index), where element is the list member to be transformed, and index is its index. Each function will be applied in turn to each member, which will be replaced by the return value from the function.
  • Returns: {Array|Object} The finally transformed structure, where each member has been replaced by the original member acted on by the function or functions.

Return a list or hash of objects, transformed by one or more functions. Similar to jQuery.map, but accepts an arbitrary list of transformation functions and does not explode on null sources. fluid.transform on a non-array and non-object (e.g. null) is a no-op.

fluid.accumulate(list, fn, initial)

  • list {Array} The list of objects to be accumulated over.
  • fn {Function: (object {Any}, total {Any-Total}, index {Integer}) → Any-Total} An "accumulation function" accepting the signature (object, total, index) where object is the list member, total is the "running total" object (which is the return value from the previous invocation of fn or else initial), and index is the index number.
  • arg {Any-Total} The initial value for the "running total" object.
  • Returns: {Any-Total} The final running total object as returned from the final invocation of the function on the last list member.

Scan through a list of objects, "accumulating" a value over them (may be a straightforward "sum" or some other chained computation). "accumulate" is the name derived from the C++ STL, other names for this algorithm are "reduce" or "fold". Example:

var numbers = fluid.iota(4, 1); // numbers now holds [1, 2, 3, 4]
var sum = fluid.accumulate(numbers, fluid.add, 0); // sum now holds 10

Note that other common uses of fluid.accumulate (maximum and minimum) can be achieved through the multi-arg versions of Math.max and Math.min, e.g.

var max = Math.max.apply(null, numbers);

fluid.roundToDecimal(num, scale, method)

  • num {Number} The number to be rounded
  • scale {Number} The maximum number of decimal places to round to. If the scale is invalid (i.e falsey, not a number, negative value), it is treated as 0. If the scale is a floating point number, it is rounded to an integer.
  • method {String} (optional) Request a rounding method to use ("round", "ceil", "floor"). If nothing or an invalid method is provided, it will default to "round".

Derived from Sindre Sorhus's round-to node module. (License: MIT)

Rounds the supplied number to at most the number of decimal places indicated by the scale, omitting any trailing 0s. There are three possible rounding methods described below: "round", "ceil", "floor".

  • "round": Numbers are rounded away from 0 (i.e 0.5 -> 1, -0.5 -> -1).
  • "ceil": Numbers are rounded up
  • "floor": Numbers are rounded down
var rounded = fluid.roundToDecimal(1.555, 2); // rounded now holds 1.56
var ceil = fluid.roundToDecimal(1.555, 2, "ceil"); // rounded now holds 1.56
var floor = fluid.roundToDecimal(1.555, 2, "floor"); // rounded now holds 1.55

fluid.remove_if(source, fn[, target])

  • source {Array|Object} The array or hash of objects to be scanned over. This structure will be modified in place. Note that in the case this is an array, iteration will run from the end of the array towards the front, so that the index of elements yet to be removed will remain stable.
  • fn {Function: (object {Any}, index {Number|String}) → Booleanish } A predicate function determining whether an element should be removed. This accepts the standard signature (object, index). If the predicate returns a "truthy" value, the corresponding object will be removed from the source structure.
  • target {Array|Object} [optional] A target object of the same type as source, which will receive any objects removed from it.
  • Returns: {Array|Object} Either target, containing the removed elements, if it was supplied, or else source modified by the operation of removing the matched elements.

Scan through a list or hash of objects, removing those which match a predicate. The source structure will be modified in place.

fluid.getMembers(holder, path)

  • holder {Array|Object} The container to be filtered
  • path {String|Array of String} An EL path to be fetched from each top-level member
  • Returns: {Array|Object} A container of the same type as holder, with the members of holder dereferenced by path.

Extracts a particular member from each top-level member of a container, returning a new container of the same type. Example:

var cattes = [
    { name: "Huggoe" },
    { name: "Arthur" },
    { name: "THER CATTE" }
];
var names = fluid.getMembers(cattes, "name");
// names now holds ["Huggoe", "Arthur", "THER CATTE"];

fluid.filterKeys(toFilter, keys[, exclude])

  • toFilter {Object} The object to be filtered - this will be NOT modified by the operation
  • keys {String[]} The list of keys to operate with
  • exclude {Boolean} [optional] If true, the keys listed are removed rather than included
  • Returns: {Object} the filtered object

Accepts an object to be filtered, and a list of keys. Either all keys not present in the list are removed (the default), or all keys present in the list are removed (exclude: true). The supplied object is not modified but will be shallow cloned by this operation.

fluid.censorKeys(toCensor, keys)

  • toFilter {Object} The object to be filtered - this will be NOT modified by the operation
  • keys {String[]} The list of keys to be excluded
  • Returns: {Object} A shallow clone of toFilter with the supplied keys removed

A convenience wrapper for fluid.filterKeys with the argument exclude set to true. Returns a shallow clone of the supplied object with listed keys removed.

fluid.keys(object)

  • object {Object} The object to have its keys listed
  • Returns: {Array} An array holding the keys of this object.

Return the keys in the supplied object as an array. Note that this will return keys found in the prototype chain as well as "own properties", unlike the builtin Object.keys()

fluid.values(object)

  • object {Object} The object to have its values listed
  • Returns: {Array} An array holding the values of this object.

Return the values in the supplied object as an array. This will return values found in the prototype chain as well as those attached to "own properties".

fluid.arrayToHash(array)

  • array {Array of String} The array to be converted to a hash
  • Returns: {Object} An object with value true for each key taken from a member of array

Converts an array into an object whose keys are the elements of the array, each with the value true

fluid.hashToArray(hash, keyName[, func])

  • hash {Array} The hash to be transformed into an array
  • keyName {String} The name within the resulting array elements which will receive the string which used to form the element's key in hash
  • func {Function (newElement {Object), oldElement {Object}, key {String}) → Object } [optional] receives (newElement, oldElement, key) where newElement is the freshly cloned element (a fresh Object obj which just has obj[keyName] = key), oldElement is the original hash's element, and key is the key of the element in the hash. The function returns the final element that will be added to the array - it may ignore newElement if it pleases and make an unrelated return. If the function makes no return, newElement will be used. If the function is not supplied, the old element is simply deep-cloned onto the new element (same effect as transform fluid.transforms.objectToArray).

Converts a hash into an array by hoisting out the object's keys into an array element via the supplied String key, and then transforming the elements via an optional further function func. Note that without some further means of sorting the resulting array elements, the order of elements in the array will not be defined. Example:

var hash = {
    "Proailurus":     25000000,
    "Pseudaelurus":   18500000,
    "Felis attica":   12000000,
    "Felis lunensis":  2500000,
    "CATT":              50000
};
var CATTyears = fluid.hashToArray(hash, "species", function (newElement, oldElement) {
    newElement.yearsAgo = oldElement;
});

// CATTyears now contains [ {
//    species: "Proailurus",
//    yearsAgo: 25000000
//}, { // etc.

fluid.flatten(array)

  • array {Array} The array to be flattened
  • Returns: {Array} The flattened array.

Converts an array consisting of a mixture of arrays and non-arrays into the concatenation of any inner arrays with the non-array elements. The original array will not be modified. See description of mapcat or flat-map.

fluid.freezeRecursive(tofreeze)

  • tofreeze {Array|Object} The object to be frozen recursively
  • Returns: {Array|Object} The supplied argument, recursively frozen

Calls Object.freeze at each level of containment of the supplied object. This function is a no-op if a primitive value is supplied.

fluid.pushArray(holder, member, topush)

  • holder {Array|Object} The holding object whose member is to receive the pushed element(s).
  • member {String} The member of the holder onto which the element(s) are to be pushed
  • topush {Array|Object} If an array, these elements will be added to the end of the array using Array.push.apply. If an object, it will be pushed to the end of the array using Array.push.

Pushes an element or elements onto an array, initialising the array as a member of a holding object if it is not already allocated. The member of the holding object should either be undefined or hold an array at the time of the call. Example:

var holder = {};
fluid.pushArray(holder, "array", 3); // holder.array now holds [3]
fluid.pushArray(holder, "array", [4, 5]); // holder.array now holds [3, 4, 5]

Sorting and searching

fluid.find(source, func[, deflt])

  • source {Arrayable|Object} The list or hash of objects to be searched.
  • func {Function: (element {Any}, index {Number|String}) → Any} A predicate function, acting on a member. A predicate which returns any value which is not undefined will terminate the search.
  • deflt {Any} [optional] A value to be returned in the case the predicate is not satisfied on any element a member. The default will be the natural value of undefined
  • Returns: The first return value from the predicate function which is not undefined

Scan through a list or hash of objects, terminating on the first member which satisfies a predicate function. The return is the return value from the predicate.

fluid.find_if(source, func[, deflt])

  • source {Arrayable|Object} The list or hash of objects to be searched.
  • func {Function: (element {Any}, index {Number|String}) → Boolean} A predicate function, acting on a member. A predicate which returns any value which is not false will terminate the search.
  • deflt {Any} [optional] A value to be returned in the case no predicate function matches a member. The default will be the natural value of undefined
  • Returns: The first element for which the value of the predicate function is not false

Scan through a list or hash of objects, terminating on the first member which matches a predicate function. The return value is the first element itself for which the predicate returns other than false.

fluid.contains(tosearch, value)

  • tosearch {Object|Array} The structure to be searched for the supplied value,
  • value {Any} The value to be searched for
  • Returns: {Boolean|Undefined} Returns true if the value was found in the container

Searches through the supplied structure, and returns true if the supplied value can be found, using === equality

fluid.keyForValue(tosearch, value) {

  • tosearch {Object|Array} The structure to be searched for the supplied value
  • value {Any} The value to be found. This will be compared against the structure's members using === equality.
  • Returns: {String|Integer|Undefined} The first key (an Integer if tosearch is an Array) whose value matches the one supplied, or undefined if no value matches

Searches through the supplied object for the first value which matches the one supplied.

fluid.stableSort(array, func)

  • array {Array of Any-Element} The array to be sorted. This input array will be modified in place.
  • func {Function: (a {Any-Element}, b {Any-Element}) → Number} A comparator returning >0, 0, or <0 on pairs of elements representing their sort order (same contract as Array.sort comparator)

Applies a stable sorting algorithm to the supplied array and comparator (note that Array.sort in JavaScript is not specified to be stable). The algorithm used will be an insertion sort, which whilst quadratic in time, will perform well on small array sizes.

fluid.compareStringLength(ascending)

  • ascending {Booleanish} true if a comparator is to be returned which sorts strings in ascending order of length
  • Returns: {Function: (a {String}, b {String}) → Number} The comparator function to be used for sorting

Produces a comparator function suitable for use with Array.sort or fluid.stableSort to sort an array of strings by length

Parsing and rendering

fluid.parseInteger(string)

  • string {String} A string to be converted to an integer
  • Returns: {Integer|NaN} The integer value, or NaN if the string does not represent an integer

Returns the converted integer if the input string can be converted to an integer. Otherwise, returns NaN.

fluid.stringTemplate(template, terms)

  • template {String} A string with embedded tokens of the form %value
  • terms {Object: String → Stringable} A hash which maps tokens to their required interpolated values

A simple string interpolation system. Accepts a template string with embedded tokens of the form %value. Returns a new string with the tokens replaced by the specified values. Keys and values can be of any data type that can be coerced into a string. Tokens are not delimited in the template with any syntax - the implementation will replace the longest token which can be sourced from terms.

Handling models and paths

fluid.get(model, path)

  • model {Any} The model object to be indirected into. This may be undefined, etc. without triggering an error.
  • path {String|Array of String} Either a period-separated EL path representing a chain of properties to be navigated, or else an array of path segments representing this
  • Returns: {Any} The result of the indirection of the path into the supplied model

Accesses an element nested within a model object at the supplied (EL) path. fluid.get can operate various special behaviour in encountering particular kinds of material - for example, any object with a function member named resolvePathSegment will hand resolution of the next path segment to that function if there is no corresponding concrete member. If fluid.get navigates off the end of the available model material, this will not trigger an error - all successive indirections will simply return undefined. fluid.get accepts various esoteric piece of configuration allowing it to operate indirection rules encoded in arbitrary JSON material - these are imperfectly supported, contact us if you are interested.

fluid.getImmediate(model, path)

  • model {Any} The model object to be indirected into. This may be undefined, etc. without triggering an error.
  • path {Array of String} An array of path segments representing representing a chain of properties to be navigated
  • Returns: {Any} The result of the indirection of the path into the supplied model

An extremely simplistic, high-performance variant of fluid.get that supports none of the same bells and whistles - it is only capable of navigating over concrete object properties that are actually present in the model, and the path must have already been parsed out into an array of segments. It still, however, operates the same semantic as fluid.get for navigating over undefined values.

fluid.set(model, path, newValue)

Writes a new value into a model at a specified path. This is performed by directly modifying the penultimately referenced model object (the one referenced by the first n-1 path segments in path) by writing the value newValue to its property named after the final path segment. Other approaches to this task are possible (see New New Notes on the ChangeApplier) but the fundamental invariant to be respected is that

fluid.get(model, fluid.set(model, path, value), path); // === value

Even a functional programmer could admit that. A slight wrinkle, however, is the behaviour of the special path "" or [], attempting to write a value at the model root. This API is not capable of this and will fail in this case - since it is hampered at the language level by being unable to rewrite the object reference model which exists in the scope of its caller. The ADD message of the ChangeApplier can be used to handle this case. Under its new semantics, the reference model is at a known address in its parent component which can be rebound.

If the path path indirects beyond the range of concrete properties in model, the implementation will fill in any intermediate path levels with fresh instances of {} (in the manner of mkdirs). There are some esoteric extra arguments for fluid.set which will allow this to be done in a schema-aware way, for example filling in path levels with [] instead - contact us if you are interested.

  • model {Object} The model object to be indirected into. This must be an Object.
  • path {String|Array of String} Either a period-separated EL path representing a chain of properties to be navigated, or else an array of path segments representing this
  • newValue: {Any} The value to be written into model at the path path

fluid.modelPairToChanges(value, oldValue, changePathPrefix)

  • value {Any} Model value to compare
  • oldValue {Any} Model value to compare
  • changePathPrefix {String|Array of String} [optional] Path prefix to prepend to change request paths
  • Returns: {Array of changeRequest} An array of changeRequest objects

Calculates the changes between the model values value and oldValue and returns an array of changeRequest objects. The optional argument changePathPrefix is prepended to the change path of each request (this is useful for generating change requests to be applied at a non-root path in a model).

The returned array of change request objects may be used with fluid.fireChanges().

For example, if we call fluid.modelPairToChanges with value of {b: 2} and oldValue of {a: 1}:

fluid.modelPairToChanges({b: 2}, {a:1});

we will receive this result:

[
    {
        path: [ "b" ],
        value: 2,
        type: "ADD"
    },
    {
        path: [ "a" ],
        value: null,
        type: "DELETE"
    }
]

Indicating that the property "b" was added with value 2 and that the property "a" was removed.

fluid.model.parseEL(EL)

  • EL {String} The EL path to be parsed
  • Returns: {Array of String} The EL path parsed as an array of path segments

Parses a EL path expression by splitting it on the character .. This is a fast, low-quality implementation which assumes that no escaping of . characters is necessary.

fluid.model.composeSegments([seg1, seg2, ...])

  • seg1 ... segn {String} The path segments to be composed
  • Returns: {String} The EL path composed by concatenating the path segments.

Compose any number of path segments, none of which may be empty. The inverse to fluid.model.parseEL - this is a fast, low-quality implementation which does no escaping.

fluid.pathUtil.parseEL(EL)

  • EL {String} The EL path to be parsed
  • Returns: {Array of String} The EL path parsed as an array of path segments

Parses a EL path expression by splitting it on the period character ".". This is an analog of fluid.model.parseEL that will escape the characters . as \. and \ as \\, allowing all possible paths to be expressed. In modern JavaScript VMs, it is not much slower than fluid.model.parseEL and should be used in all applications where paths will be accepted from external users.

fluid.pathUtil.composeSegments([seg1, seg2, ...])

  • seg1 ... segn {String} The path segments to be composed
  • Returns: {String} The EL path composed by concatenating the path segments.

Compose any number of path segments, none of which may be empty. This is an analog of fluid.pathUtil.parseEL that will escape the characters . as \. and \ as \\, allowing all possible paths to be expressed. In modern JavaScript VMs, it is not much slower than fluid.pathUtil.composeSegments and should be used in all applications where paths will be accepted from external users.

Logging and error handling

fluid.log([logLevel, arg1, ... argn])

  • logLevel {LogLevel} [optional] One of the members of the fluid.logLevel structure or in general some fluid.marker with a numeric value holding a priority
  • arg1 ... argn {Stringable} A sequence of arguments to be logged. By default these will be handed unchanged to the multiple arguments of console.log. It is wise to convert these to String yourself (e.g. by JSON.stringify) if i) this is safe, and ii) you would not be satisfied by the environment's rendering.

Log a message to a suitable environmental console (in current implementations, console.log). If the first argument to fluid.log is one of the members of the fluid.logLevel structure, this will be taken as the priority of the logged message - else it will default to fluid.logLevel.INFO. If the logged message priority does not exceed that set by the most recent call to the fluid.setLogging function, the logging action will be suppressed.

fluid.logLevel

A hash of strings to LogLevel constants, suitable for sending as the special, optional, first argument to fluid.log. These communicate a logging priority, with lower numbers of higher priority than higher numbers. The system maintains a current "logging level" as an internal piece of state, updated by fluid.setLogging and fluid.popLogging - any fluid.log statements whose supplied priority does not exceed the logging level will be inactive.

LogLevel Priority Description
fluid.logLevel.FATAL 0 the very highest logging level, indicating that the process must now exit immediately due to a fatal error
fluid.logLevel.FAIL 5 a very high logging priority, corresponding to an assertion failure, similar to that of fluid.fail - the system will terminate shortly if not immediately
fluid.logLevel.WARN 10 a moderate logging priority, corresponding to a problem which most users would wish to be notified of, but is not sufficient to halt the system
fluid.logLevel.IMPORTANT 12 a moderate logging priority, corresponding to standard debugging messages. This is the level set by fluid.setLogging(false)
fluid.logLevel.INFO 15 a low logging level, corresponding to verbose debugging messages. This is the level set by fluid.setLogging(true).
fluid.logLevel.TRACE 20 a very low logging level, which if enabled would produce extremely voluminous output which would significantly slow execution and consume a lot of storage. This should only be enabled for short periods of time, perhaps conditional on some triggers surrounding an event of interest.

fluid.setLogging(logLevel)

  • logLevel {Boolean|LogLevel} The system logging level to be made current and to be pushed onto the top of the system's stack of logging levels.

Push a value onto the stack of the system's current logging levels. This will become the system's current logging level until there is a corresponding call to fluid.popLogging. The argument may either be a boolean, in which case one of the standard logging levels (true: fluid.logLevel.INFO / false: fluid.logLevel.IMPORTANT) will be selected, or else one of the members of the fluid.logLevel structure or a LogLevel marker in general. The stack is initialised with a single element of fluid.logLevel.IMPORTANT.

fluid.popLogging()

Pops one LogLevel value that was pushed onto the logging level stack by a previous call to fluid.setLogging. This will expose the previous element on top of the stack and restore the logging level that had previously been in effect. If the stack has only its one original element, this call is a no-op.

fluid.passLogLevel(testLogLevel)

  • testLogLevel {LogLevel} The log level against which the system's current logging level is to be checked.
  • Returns: {Boolean} - true if a message supplied at that log priority would be logged at the current logging level.

Accepts one of the members of the fluid.logLevel structure or a LogLevel object in general. Returns true if a message supplied at that log priority would be logged at the current logging level. Clients who issue particularly expensive log payload arguments are recommended to guard their logging statements with this

fluid.doLog([arg1, ... argn])

The actual implementation to which fluid.log messages and other logging generated by the system are dispatched. Implemented to forward to console.debug and console.log but may be monkey-patched by clients who require an alternative implementation.

fluid.fail([arg1, ... argn])

The framework and clients can call this method in order to signal a hard assertion failure. The current contract of fluid.fail is that an implementation/log error has been discovered - the typical behaviour of the system is to halt or at the very least propagate an unhandled exception to the top process level which is likely to make the system's behaviour unstable. If this failure resulted from bad user or external input, do not call this function but instead signal it in a milder, more implementation-specific way - for example by sending an HTTP status code or showing a user message. As Infusion evolves to handle a more finely graded variety of dynamic authoring scenarios, this function will be broken up into variants which can signal failures of different severities.

The current system behaviour is to throw a particular subclass of the standard Error type, of type fluid.FluidError. The behaviour of fluid.fail can be customised by contributing handlers to the standard event fluid.failureEvent

fluid.failureEvent

  • log - the namespace for the listener which logs the failure to a suitable environment. By default this fires to fluid.logFailure which forwards to fluid.log before also logging the state of the IoC system by using fluid.logActivity
  • fail - the namespace for the listener which enacts any failure behaviour. By default this calls fluid.fail but in a testing environment, for example, will react by failing any current test, or in an HTTP server by aborting the handling of any current request with a suitable HTTP status code and message.

Every call to fluid.fail triggers a firing of this global event. This is a standard Infusion Event with several handlers installed on startup to take on various functions. Extra handlers are registered, and the builtin handlers overriden, to customise error handling behaviour in various contexts - for example, when Infusion is running in node.js, is running a jqUnit test or is running in Kettle etc. There are two currently standard namespaces for listeners to this event:

fluid.strategyRecursionBailout

A positive integer (default value 50) above which depth the framework's processing of configuration will bail out, assuming that it has become circularly linked. This can be customised by the user (although this is an unlikely requirement), and is read by algorithms such as fluid.copy and during options expansion.

The global namespace

Infusion is unusual amongst modern JavaScript systems in that it maintains a single, global namespace of fully qualified implementation names. For example, builtin Infusion grades are stored in this namespace at paths fluid.* and each project will in general allocate its own top-level name. Users are assisted to operate on this global namespace with some utility functions. Any user of Infusion who has successfully resolved the fluid object can access the root object for this namespace as fluid.global. In the browser, the root of this namespace coincides directly with the real global namespace, which conventionally is addressed as window. In a Web Worker this object is conventionally known as self. In environments like node.js where a global namespace is discouraged (but not, thankfully, actively prohibited) the global object is not directly accessible and users will need to use these utilities or the helping reference fluid.global. See fluid.setGlobalValue for some guidelines on the use of global names.

fluid.registerNamespace(path)

  • path {String|Array of String} The global path at which the namespace is to be allocated
  • Returns: {Any} Any current value held at the supplied path - or a freshly allocated {} to be held at that path if it was previously empty

Ensures that the supplied path has an object allocated in the global namespace, and retrieves the current value. If no value is stored, a fresh {} will be assigned at the path, and to all currently empty paths leading to the global namespace root. Calls to fluid.registerNamespace are very common at the start of Infusion-aware .js files - they are analogous to require statements, only they do not cause any code to be loaded by themselves - but they can grant access to implementations which have been loaded by others, or else provide an intermediate node at which to export implementations to others.

fluid.getGlobalValue(path)

  • path {String|Array of String} The global path from which the value is to be fetched
  • Returns: {Any} The value that was stored at the path, or undefined if there is none.

Returns any value held at a particular global path. This may be an object or a function, depending on what has been stored there.

fluid.setGlobalValue(path, value)

  • path {String|Array of String} The global path at which the value is to be set.
  • value {Any} The value to be written to the global path. This should in general be a function or other immutable value, and an existing value should not be overwritten. This rule can be overlooked in a genuine architectural emergency.

Write a value to a particular global path. Users are strongly discouraged from storing any mutable information at these paths, but it is accepted that in certain integration scenarios there can be little alternative. Please choose a properly qualified global path name that identifies your project (perhaps, derived from a domain name or npm package name) that you have control over. The Java package naming conventions have proved effective at heading off such problems in the past and we intend that Infusion global names should be handled in an analogous way.

fluid.invokeGlobalFunction(functionPath, args)

  • functionPath {String|Array of String} The global path holding the function which is to be invoked
  • args {Array|Any} The array of arguments to be supplied to the function. If args is not an array, fluid.makeArray will be called on it first.
  • Returns: {Any} Any return value from the function which was invoked

Invokes a function held at a particular global path with the supplied arguments. Equivalent to fluid.getGlobalValue followed by Function.apply(null, args).

fluid.invokeGradedFunction(name, spec)

  • name {String} A global name which can be resolved to a Function. The defaults for this name must resolve onto a grade derived from fluid.function. The defaults record should also contain an entry argumentMap, a hash of argument names onto indexes.
  • spec {Object} A hash where the keys are keys of the functions argumentMap, and the values are the argument values to be sent to the function. The keys will be looked up in the argumentMap and the values resolved into a flat list of arguments.
  • Returns: {Any} The return value from the function

Invoke a global function by name and named arguments. A courtesy to allow declaratively encoded function calls to use named arguments, with names encoded in the defaults for a fluid.function, rather than bare arrays.

Storing and retrieving defaults

Infusion's component system is organised around blocks of JSON which define grades - another way of describing a grade is as a component's default options, which appeals to a slightly more old-fashioned notion of what a component is. These options are registered into the system and read back from it by using the API fluid.defaults. If the options supplied to fluid.defaults represent a component grade, the framework will automatically construct and register a component creator function in the global namespace at a path which matches the component's grade name. Note that not all defaults correspond to a component - some of them are descended from fluid.function in which case they represent a function grade and hold metadata about it. Some defaults are not descended from a framework grade at all, and are designed to be used as mixins to other grades.

fluid.defaults(gradeName[, options])

  • gradeName {String} The fully-qualified name of the grade whose defaults are to be read or written.
  • options {Object} [optional] The defaults which are to be registered for the grade. If this argument is omitted, the existing defaults are read and returned.
  • Returns: {Object} If the function was called with 1 argument, any defaults already registered for the component. These read defaults will already have gone through options merging and have the contents of any parent grades resolved in them. If you want to read exactly the raw defaults information that was registered for this grade, instead use fluid.rawDefaults

fluid.rawDefaults(gradeName[, options])

  • gradeName {String} The fully-qualified name of the grade whose defaults are to be read or written.
  • options {Object} [optional] The defaults which are to be registered for the grade. If this argument is omitted, the existing defaults are read and returned.
  • Returns: {Object} The raw defaults registered for this grade, without being resolved against parent grades by options merging.