lib/config-parser.js
function processNode(attrNode, context) {
    const isMainResource = context.attrPath.length === 0;

    // identify/handle options-contexts: resource/sub-resource, nested-attribute, attribute:
    if (attrNode.dataSources || attrNode.resource || isMainResource) {
        context.errorContext = getErrorContext(isMainResource ? 'resource' : 'sub-resource', context);
        context.subAttrPath = [];
        context.dataSourceAttributes = {};

        if (isMainResource) {
            parseNode(
                attrNode,
                {
                    dataSources: null,
                    subFilters: parseSubFilters,
                    resource: checkResourceName,
                    primaryKey: parsePrimaryKey,
                    depends: parseDepends,
                    deprecated: parseBoolean,
                    permission: null,
                    attributes: null,
                    defaultLimit: parseInteger,
                    maxLimit: parseInteger,
                    defaultOrder: requestParser.order
                },
                context
            );
        } else {
            parseNode(
                attrNode,
                {
                    dataSources: null,
                    subFilters: parseSubFilters,
                    resource: checkResourceName,
                    primaryKey: parsePrimaryKey,
                    parentKey: parseRelationKey,
                    childKey: parseRelationKey,
                    many: parseBoolean,
                    depends: parseDepends,
                    hidden: parseBoolean,
                    deprecated: parseBoolean,
                    permission: null,
                    joinVia: checkIdentifier,
                    attributes: null,
                    defaultLimit: parseInteger,
                    maxLimit: parseInteger,
                    defaultOrder: requestParser.order
                },
                context
            );
        }

        handleResourceContext(attrNode, context);
    } else if (attrNode.attributes) {
        context.errorContext = getErrorContext('nested-attribute', context);

        parseNode(
            attrNode,
            {
                depends: parseDepends,
                hidden: parseBoolean,
                deprecated: parseBoolean,
                permission: null,
                attributes: null
            },
            context
        );

        // no context-specific special-cases for nested-attributes
    } else {
        context.errorContext = getErrorContext('attribute', context);

        // prepare standard-mapping - except for fixed values and inherited attributes:
        if (!attrNode.map && !('value' in attrNode) && attrNode.inherit !== 'inherit') {
            attrNode.map = null; // "null" means "set standard-mapping in parseMap()"
        }

        parseNode(
            attrNode,
            {
                type: parseType,
                multiValued: parseBoolean,
                storedType: parseStoredType,
                delimiter: null,
                map: parseMap,
                filter: parseFilter,
                order: parseOrder,
                value: parseStaticValue,
                depends: parseDepends,
                hidden: parseBoolean,
                deprecated: parseBoolean,
                permission: null,
                inherit: parseInherit
            },
            context
        );

        handleAttributeContext(attrNode, context);
    }

    // recursion:
    if (attrNode.attributes) {
        Object.keys(attrNode.attributes).forEach(subAttrName => {
            const subAttrNode = attrNode.attributes[subAttrName];

            const subContext = Object.assign({}, context);
            subContext.attrPath = context.attrPath.concat([subAttrName]);
            subContext.subAttrPath = context.subAttrPath.concat([subAttrName]);

            processNode(subAttrNode, subContext);
        });
    }

    if (attrNode.dataSources) {
        if (attrNode.primaryKey) resolvePrimaryKey(attrNode, context);
        prepareDataSources(attrNode, context);
    }
}
function processNode(attrNode, context) {
    const isMainResource = context.attrPath.length === 0;

    // identify/handle options-contexts: resource/sub-resource, nested-attribute, attribute:
    if (attrNode.dataSources || attrNode.resource || isMainResource) {
        context.errorContext = getErrorContext(isMainResource ? 'resource' : 'sub-resource', context);
        context.subAttrPath = [];
        context.dataSourceAttributes = {};

        if (isMainResource) {
            parseNode(
                attrNode,
                {
                    dataSources: null,
                    subFilters: parseSubFilters,
                    resource: checkResourceName,
                    primaryKey: parsePrimaryKey,
                    depends: parseDepends,
                    deprecated: parseBoolean,
                    permission: null,
                    attributes: null,
                    defaultLimit: parseInteger,
                    maxLimit: parseInteger,
                    defaultOrder: requestParser.order
                },
                context
            );
        } else {
            parseNode(
                attrNode,
                {
                    dataSources: null,
                    subFilters: parseSubFilters,
                    resource: checkResourceName,
                    primaryKey: parsePrimaryKey,
                    parentKey: parseRelationKey,
                    childKey: parseRelationKey,
                    many: parseBoolean,
                    depends: parseDepends,
                    hidden: parseBoolean,
                    deprecated: parseBoolean,
                    permission: null,
                    joinVia: checkIdentifier,
                    attributes: null,
                    defaultLimit: parseInteger,
                    maxLimit: parseInteger,
                    defaultOrder: requestParser.order
                },
                context
            );
        }

        handleResourceContext(attrNode, context);
    } else if (attrNode.attributes) {
        context.errorContext = getErrorContext('nested-attribute', context);

        parseNode(
            attrNode,
            {
                depends: parseDepends,
                hidden: parseBoolean,
                deprecated: parseBoolean,
                permission: null,
                attributes: null
            },
            context
        );

        // no context-specific special-cases for nested-attributes
    } else {
        context.errorContext = getErrorContext('attribute', context);

        // prepare standard-mapping - except for fixed values and inherited attributes:
        if (!attrNode.map && !('value' in attrNode) && attrNode.inherit !== 'inherit') {
            attrNode.map = null; // "null" means "set standard-mapping in parseMap()"
        }

        parseNode(
            attrNode,
            {
                type: parseType,
                multiValued: parseBoolean,
                storedType: parseStoredType,
                delimiter: null,
                map: parseMap,
                filter: parseFilter,
                order: parseOrder,
                value: parseStaticValue,
                depends: parseDepends,
                hidden: parseBoolean,
                deprecated: parseBoolean,
                permission: null,
                inherit: parseInherit
            },
            context
        );

        handleAttributeContext(attrNode, context);
    }

    // recursion:
    if (attrNode.attributes) {
        Object.keys(attrNode.attributes).forEach(subAttrName => {
            const subAttrNode = attrNode.attributes[subAttrName];

            const subContext = Object.assign({}, context);
            subContext.attrPath = context.attrPath.concat([subAttrName]);
            subContext.subAttrPath = context.subAttrPath.concat([subAttrName]);

            processNode(subAttrNode, subContext);
        });
    }

    if (attrNode.dataSources) {
        if (attrNode.primaryKey) resolvePrimaryKey(attrNode, context);
        prepareDataSources(attrNode, context);
    }
}
function processNode ( attrNode , context ) { const isMainResource = context . attrPath . length === 0 ; // identify/handle options-contexts: resource/sub-resource, nested-attribute, attribute: if ( attrNode . dataSources || attrNode . resource || isMainResource ) { context . errorContext = getErrorContext ( isMainResource ? 'resource' : 'sub-resource' , context ) ; context . subAttrPath = [ ] ; context . dataSourceAttributes = { } ; if ( isMainResource ) { parseNode ( attrNode , { dataSources : null , subFilters : parseSubFilters , resource : checkResourceName , primaryKey : parsePrimaryKey , depends : parseDepends , deprecated : parseBoolean , permission : null , attributes : null , defaultLimit : parseInteger , maxLimit : parseInteger , defaultOrder : requestParser . order } , context ) ; } else { parseNode ( attrNode , { dataSources : null , subFilters : parseSubFilters , resource : checkResourceName , primaryKey : parsePrimaryKey , parentKey : parseRelationKey , childKey : parseRelationKey , many : parseBoolean , depends : parseDepends , hidden : parseBoolean , deprecated : parseBoolean , permission : null , joinVia : checkIdentifier , attributes : null , defaultLimit : parseInteger , maxLimit : parseInteger , defaultOrder : requestParser . order } , context ) ; } handleResourceContext ( attrNode , context ) ; } else if ( attrNode . attributes ) { context . errorContext = getErrorContext ( 'nested-attribute' , context ) ; parseNode ( attrNode , { depends : parseDepends , hidden : parseBoolean , deprecated : parseBoolean , permission : null , attributes : null } , context ) ; // no context-specific special-cases for nested-attributes } else { context . errorContext = getErrorContext ( 'attribute' , context ) ; // prepare standard-mapping - except for fixed values and inherited attributes: if ( ! attrNode . map && ! ( 'value' in attrNode ) && attrNode . inherit !== 'inherit' ) { attrNode . map = null ; // "null" means "set standard-mapping in parseMap()" } parseNode ( attrNode , { type : parseType , multiValued : parseBoolean , storedType : parseStoredType , delimiter : null , map : parseMap , filter : parseFilter , order : parseOrder , value : parseStaticValue , depends : parseDepends , hidden : parseBoolean , deprecated : parseBoolean , permission : null , inherit : parseInherit } , context ) ; handleAttributeContext ( attrNode , context ) ; } // recursion: if ( attrNode . attributes ) { Object . keys ( attrNode . attributes ) . forEach ( subAttrName => { const subAttrNode = attrNode . attributes [ subAttrName ] ; const subContext = Object . assign ( { } , context ) ; subContext . attrPath = context . attrPath . concat ( [ subAttrName ] ) ; subContext . subAttrPath = context . subAttrPath . concat ( [ subAttrName ] ) ; processNode ( subAttrNode , subContext ) ; } ) ; } if ( attrNode . dataSources ) { if ( attrNode . primaryKey ) resolvePrimaryKey ( attrNode , context ) ; prepareDataSources ( attrNode , context ) ; } }
Recursive iteration over one resource.

@param {Object} attrNode
@param {Object} context
@private
Recursive iteration over one resource .