Copernicus.js Documentation

Introduction

Copernicus.js is a powerful JavaScript framework designed for creating data-driven single-page applications (SPAs) with a focus on simplicity and ease of use for non-programmers. Formulas are the 'connective tissue' that form all of the application's components. Formulas interact with the Copernicus.js libraries and are used to perform calculations or data transformations.

Copernicus.js is a framework or operating system 'lite' engineered to power iteration, transparency, extensibility, and connectedness. It addresses common constraints of legacy systems by providing a robust platform for developing single-page applications (SPAs). This enables traditional industries like banking, healthcare, and insurance to break free from monolithic systems and embrace a more agile development environment where humans and AI can transparently build useful software applications.

Installation and Basic Setup Instructions

Download the Repository

Extract the ZIP File

Run the Application

Edit the JavaScript Files (if desired)

For more detailed instructions, refer to the FI.js GitHub repository.

Core Concepts

Working Ingredients of a Copernicus.js App or SPA

Formulas govern the underlying logic, and functions, attributes, and dictionaries power the formulas:

Formula Syntax

Copernicus.js allows you to define and evaluate formulas using a human-readable syntax. Here are some examples:

The syntax supports:

Example Implementation

Attribute Example


attributes: {
    loanServicingFactor: {
        description: "The factor used to calculate loan servicing costs",
        value: 0.0025
    }
}
    

Dictionary Example


dictionaries: {
    loanTypeID: {
        description: "Mappings of loan types to the respective identifiers",
        values: {
            "Agriculture": [],
            "Commercial": ["31", "32", "33", "34"],
            "Commercial Real Estate": ["4"],
            // Add more mappings as needed
        }
    }
}
    

Function Example


functions: {
    loanPayment: {
        description: "Calculates the monthly loan payment",
        implementation: function(principal, annualRate, amortizationMonths) {
            const monthlyRate = annualRate < 1 ? parseFloat(annualRate) / 12 : parseFloat(annualRate / 100) / 12;
            if (monthlyRate === 0) {
                return (principal / amortizationMonths).toFixed(2);
            }
            const monthlyPayment = principal * (monthlyRate / (1 - Math.pow(1 + monthlyRate, -amortizationMonths)));
            return monthlyPayment.toFixed(2);
        }
    }
}
    

Functions, Attributes & Dictionaries

Functions

Functions in Copernicus.js are JavaScript functions used for calculations or data manipulation. Each function has a description and an implementation.

A function in Copernicus.js consists of the following components:

Function Syntax Example:


loanPayment: {
    description: "Calculates the monthly loan payment based on principal, annual rate, and amortization months",
    implementation: function(principal, annualRate, amortizationMonths) {
        const monthlyRate = annualRate < 1 ? parseFloat(annualRate) / 12 : parseFloat(annualRate / 100) / 12;
        if (monthlyRate === 0) {
            return (principal / amortizationMonths).toFixed(2);
        }
        const monthlyPayment = principal * (monthlyRate / (1 - Math.pow(1 + monthlyRate, -amortizationMonths)));
        return monthlyPayment.toFixed(2);
    }
}
                

Detailed Breakdown:

AI Prompt for Function Creation

To help the AI understand how to build its own Copernicus.js functions, you can use the following prompt template:


Create a Copernicus.js function with the following details:

- Function Name: [Function Name]
- Description: [Brief Description]
- Parameters: [Parameter1, Parameter2, ...]
- Implementation: [JavaScript Code]

Example:
Function Name: calculateBMI
Description: "Calculates Body Mass Index (BMI) based on weight in kilograms and height in meters"
Parameters: weight, height
Implementation:
function(weight, height) {
    const bmi = weight / (height * height);
    return bmi.toFixed(2);
}
                

AI Output:


calculateBMI: {
    description: "Calculates Body Mass Index (BMI) based on weight in kilograms and height in meters",
    implementation: function(weight, height) {
        const bmi = weight / (height * height);
        return bmi.toFixed(2);
    }
}
            

Attributes

Attributes in Copernicus.js are values or constants used throughout the application. They are defined within the attributes section of a library and include a description and a value.

Example of Attribute Definition


attributes: {
    loanServicingFactor: {
        description: "The factor used to calculate loan servicing costs",
        value: 0.0025
    }
}
            

Using Attributes in Functions

Attributes can be accessed and used directly within formulas or functions. Here is an example of how an attribute is used within a function. Note that the function requires at least one of the parameters termMonths or maturityDate to be provided.


servicingExpense: {
    description: "Calculates the loan servicing expense based on principal and term",
    implementation: function(principal, termMonths = null, maturityDate = null) {
        if (libraries.attributes.loanServicingFactor.value) {
            const months = maturityDate ? libraries.functions.remainingMonths.implementation(maturityDate) : termMonths;
            let expense = principal * libraries.attributes.loanServicingFactor.value / months * 12;
            return expense.toFixed(2);
        } else {
            console.log('libraries are missing loanServicingFactor see library docs');
        }
    }
}
            

Detailed Breakdown


attributes: {
    loanServicingFactor: {
        description: "The factor used to calculate loan servicing costs",
        value: 0.0025
    }
}
            

servicingExpense: {
    description: "Calculates the loan servicing expense based on principal and term",
    implementation: function(principal, termMonths = null, maturityDate = null) {
        if (libraries.attributes.loanServicingFactor.value) {
            const months = maturityDate ? libraries.functions.remainingMonths.implementation(maturityDate) : termMonths;
            let expense = principal * libraries.attributes.loanServicingFactor.value / months * 12;
            return expense.toFixed(2);
        } else {
            console.log('libraries are missing loanServicingFactor see library docs');
        }
    }
}
            

AI Prompt for Attribute Usage

To help the AI understand how to use attributes within Copernicus.js, you can use the following prompt template:


Create a Copernicus.js function that uses an attribute from the attribute library. 

- Function Name: [Function Name]
- Description: [Brief Description]
- Parameters: [Parameter1, Parameter2, ...]
- Attribute: [Attribute Name]
- Implementation: [JavaScript Code]

Example:
Function Name: calculateServicingExpense
Description: "Calculates the loan servicing expense based on principal and term"
Parameters: principal, termMonths = null, maturityDate = null
Attribute: loanServicingFactor
Implementation:
function(principal, termMonths = null, maturityDate = null) {
    if (libraries.attributes.loanServicingFactor.value) {
        const months = maturityDate ? libraries.functions.remainingMonths.implementation(maturityDate) : termMonths;
        let expense = principal * libraries.attributes.loanServicingFactor.value / months * 12;
        return expense.toFixed(2);
    } else {
        console.log('libraries are missing loanServicingFactor see library docs');
    }
}
            

AI Output:


calculateServicingExpense: {
    description: "Calculates the loan servicing expense based on principal and term",
    implementation: function(principal, termMonths = null, maturityDate = null) {
        if (libraries.attributes.loanServicingFactor.value) {
            const months = maturityDate ? libraries.functions.remainingMonths.implementation(maturityDate) : termMonths;
            let expense = principal * libraries.attributes.loanServicingFactor.value / months * 12;
            return expense.toFixed(2);
        } else {
            console.log('libraries are missing loanServicingFactor see library docs');
        }
    }
}
            

Dictionaries

Dictionaries in Copernicus.js are key-value pairs used for lookups throughout the application. They are defined within the dictionaries section of a library and include a description and a set of values.

Example of Dictionary Definition


dictionaries: {
    loanRiskFactors: {
        description: "Risk factors representing the risk associated with different loan types",
        values: {
            "0": 1,
            "1": 0,
            "2": 0.5,
            "3": 1,
            "3W": 2,
            "4": 10,
            "5": 100,
            "NULL": 1
        }
    },
    loanTypeID: {
        description: "Mappings of loan types to the respective identifiers",
        values: {
            "Agriculture": [],
            "Commercial": ["30", "31", "32", "33"], 
            "Commercial Real Estate": ["4"],
            "Residential Real Estate": ["1"],
            "Consumer": ["20", "21", "22", "23", "24"], 
            "Equipment": [], 
            "Home Equity": ["24", "25", "46"], 
            "Letter of Credit": ["35"],
            "Commercial Line": ["36", "63", "65"], 
            "Home Equity Line of Credit": ["9", "10"],
            "Municipal": ["7"],
        }
    }
}
            

Using Dictionaries in Functions

Dictionaries can be accessed and used within functions. Here is an example function that utilizes such dictionaries. Note that the function requires at least one of the parameters termMonths or maturityDate to be provided.


originationExpense: {
    description: "Calculates the origination expense based on loan type, principal, and term",
    implementation: function(type, principal, termMonths = null, maturityDate = null) {
        const identifiedType = libraries.functions.identifyType(type, libraries.dictionaries.loanTypeID.values);
        if (identifiedType !== null) {
            const months = maturityDate ? libraries.functions.remainingMonths.implementation(maturityDate) : termMonths;
            const originationFactor = libraries.dictionaries.originationFactor.values[identifiedType];
            const principalCostMax = libraries.dictionaries.principalCostMax.values[identifiedType];
            const principalCostMin = principalCostMax / 10;
            let expense = Math.max(principalCostMin, Math.min(principalCostMax, principal)) * originationFactor / Math.max(months, 60) * 12;
            return expense.toFixed(2);
        } else {
            console.error(`type not found in libraries.dictionaries.loanTypeID.values:${type}.`);
        }
    }
}
            

Detailed Breakdown


originationExpense: {
    description: "Calculates the origination expense based on loan type, principal, and term",
    implementation: function(type, principal, termMonths = null, maturityDate = null) {
        const identifiedType = libraries.functions.identifyType(type, libraries.dictionaries.loanTypeID.values);
        if (identifiedType !== null) {
            const months = maturityDate ? libraries.functions.remainingMonths.implementation(maturityDate) : termMonths;
            const originationFactor = libraries.dictionaries.originationFactor.values[identifiedType];
            const principalCostMax = libraries.dictionaries.principalCostMax.values[identifiedType];
            const principalCostMin = principalCostMax / 10;
            let expense = Math.max(principalCostMin, Math.min(principalCostMax, principal)) * originationFactor / Math.max(months, 60) * 12;
            return expense.toFixed(2);
        } else {
            console.error(`type not found in libraries.dictionaries.loanTypeID.values:${type}.`);
        }
    }
}
            

AI Prompt for Flexible Dictionary Usage

To help the AI understand how to use flexible dictionaries within Copernicus.js, you can use the following prompt template:


Create a Copernicus.js function that uses dictionaries from the library, where dictionary values can be arrays.

- Function Name: [Function Name]
- Description: [Brief Description]
- Parameters: [Parameter1, Parameter2, ...]
- Dictionaries: [Dictionary Names]
- Implementation: [JavaScript Code]

Example:
Function Name: calculateOriginationExpense
Description: "Calculates the origination expense based on loan type, principal, and term"
Parameters: type, principal, termMonths = null, maturityDate = null
Dictionaries: loanTypeID, originationFactor, principalCostMax
Implementation:
function(type, principal, termMonths = null, maturityDate = null) {
    const identifiedType = libraries.functions.identifyType(type, libraries.dictionaries.loanTypeID.values);
    if (identifiedType !== null) {
        const months = maturityDate ? libraries.functions.remainingMonths.implementation(maturityDate) : termMonths;
        const originationFactor = libraries.dictionaries.originationFactor.values[identifiedType];
        const principalCostMax = libraries.dictionaries.principalCostMax.values[identifiedType];
        const principalCostMin = principalCostMax / 10;
        let expense = Math.max(principalCostMin, Math.min(principalCostMax, principal)) * originationFactor / Math.max(months, 60) * 12;
        return expense.toFixed(2);
    } else {
        console.error(`type not found in libraries.dictionaries.loanTypeID.values:${type}.`);
    }
}
            

AI Output:


calculateOriginationExpense: {
    description: "Calculates the origination expense based on loan type, principal, and term",
    implementation: function(type, principal, termMonths = null, maturityDate = null) {
        const identifiedType = libraries.functions.identifyType(type, libraries.dictionaries.loanTypeID.values);
        if (identifiedType !== null) {
            const months = maturityDate ? libraries.functions.remainingMonths.implementation(maturityDate) : termMonths;
            const originationFactor = libraries.dictionaries.originationFactor.values[identifiedType];
            const principalCostMax = libraries.dictionaries.principalCostMax.values[identifiedType];
            const principalCostMin = principalCostMax / 10;
            let expense = Math.max(principalCostMin, Math.min(principalCostMax, principal)) * originationFactor / Math.max(months, 60) * 12;
            return expense.toFixed(2);
        } else {
            console.error(`type not found in libraries.dictionaries.loanTypeID.values:${type}.`);
        }
    }
}
            

Presentation Layer

Copernicus.js provides a flexible and dynamic way to build Single Page Applications (SPAs) that can display data in tables, data typing, and optionally can include charting. Designers can easily define how results are presented by configuring the buildConfig object inside each app. This guide explains how to set up and customize the Copernicus.js presentation layer in an SPAs buildConfig:

Here's an example SPA, take note of presentation:



            

Here's an example of leveraging count which is a built-in primary_key instance counter. Using 'count' as 'key' for limited datasets is very a effective illustration tool.



            

Configuration Details

Example Components

Columns Configuration

Define the columns in the presentation object to control how data is displayed. Each column object includes:


columns: [
    { header: 'ID', key: 'ID', type: 'integer' },
    { header: 'Principal', key: 'principal', type: 'currency' },
    { header: 'Balance', key: 'balance', type: 'USD' },
    { header: 'Responsibility', key: 'responsibility', type: 'category' },
    { header: 'Result', key: 'result', type: 'float' }
],
            

Supported Types

Chart Configuration

Add a chart configuration to visualize data.


chart: {
    key: 'responsibility', // Grouping key
    label: 'Results by Responsibility' // Chart label
}
            

Sorting

Control the sort order of the displayed results.


sort: { key: 'result', order: 'desc' }
            

Translation Capabilities in Copernicus.js

Copernicus.js supports flexible translation capabilities to make data presentation and reporting more readable. Translations can be applied to:

Presentation Columns

Translate headers and values for better clarity.


{ header: 'Branch', key: 'branch', type: 'category' }
            

Formulas

Attributes, functions, and dictionary keys/values are replaced with universal terms, so that formulas can work across platforms.


formula: '((annualRate - trates:12) * averagePrincipal - originationExpense - servicingExpense) * (1 - taxRate) - loanLossReserve'
            

Chart Labels

Labels for charts can be translated to improve readability.


chart: { key: 'branch', label: 'Results by Branch' }
            

Example Translation Usage

Translation Definition:


const translations = {
    loans: {  //legacy platform terminology: universal terminology   
        Portfolio: 'portfolioID',
        Date_Opened: 'dateOpened',
        Maturity_Date: 'maturityDate',
        Branch_Number: 'branch',
        // More translations
    },
    branch: {
        '1': 'Main Branch',
        '2': 'Secondary Branch',
        // More translations
    }
};
            

Benefits of Using Translations

These capabilities make Copernicus.js a powerful framework for building dynamic and user-friendly SPAs, with data presented in a clear and accessible manner.

Copernicus.js Editor

Overview

The Copernicus.js Editor is designed to provide a robust environment for creating and managing Single Page Applications (SPAs) within the Copernicus.js framework. The editor includes features such as syntax highlighting, autocompletion, suggestions, multiple editor instances, and dynamic component generation based on formulas.

Features

Syntax Highlighting

  • Highlights keywords, functions, attributes, dictionaries, and pipes in different colors.
  • Highlights opening and closing parentheses with different colors for each level of nesting, and highlights unbalanced parentheses in red.

Autocompletion and Suggestions

  • Provides suggestions for Copernicus.js functions, attributes, and dictionaries.
  • Displays suggestions in a sidebar organized by category.
  • Highlights suggestions as they are inserted into the editor.

Error Detection and Linting

  • Detects and highlights syntax errors, such as unbalanced parentheses and incorrectly formatted dictionaries.

Multiple Editor Instances

  • Allows the creation of multiple editor instances, each with its own tab.
  • Each editor instance can be named and includes a close button to delete the instance.
  • Ensures unique IDs for each component based on the pipes used in the formulas.

Dynamic Component Generation

  • Splits formulas separated by semicolons into separate components.
  • Identifies used pipes in each formula and sets the appropriate component ID and pipeIDs.
  • Generates a complete HTML file with the correct configuration for Copernicus.js SPAs.

Usage

Adding an Editor Instance

  1. Click the "Add Editor" button.
  2. Enter a unique name for the new editor instance.
  3. The new editor instance will appear in the center of the screen, and a corresponding tab will be created.

Using the Editor

  1. Type your formula into the editor. Syntax highlighting and suggestions will be automatically applied.
  2. Use the sidebar to insert functions, attributes, and dictionaries by clicking on the suggestions.
  3. Ensure each formula is separated by a semicolon if you want them to be treated as separate components.

Saving the File

  1. Enter a file name in the provided input field.
  2. Click the "Save" button.
  3. The editor will generate an HTML file with the correct Copernicus.js configuration, including all the components based on the entered formulas.

Example

Editor Content:

principal * taxRate; balance * marginTarget

Generated Components:


components: [
    {
        "id": "loans",
        "formula": "principal * taxRate",
        "pipeIDs": [
            "loans"
        ]
    },
    {
        "id": "checking",
        "formula": "balance * marginTarget",
        "pipeIDs": [
            "checking"
        ]
    }
]
                

AI Prompting Process for Creating Copernicus.js Functions

Reviewing Documentation

To create a function in Copernicus.js, start by reviewing the documentation at copernicusjs.com.\n Ensure you understand the structure and syntax for functions, attributes, and dictionaries.

Defining Dictionaries and Attributes

Identify if there are existing data structures that can be reused or if new ones need to be created. For the `marginOfSafety` function, we will create a dictionary to store stock data with keys for `intrinsicValue` and `stockPrice`.

Creating the Function

Implement the function using the intrinsic value and stock price from the dictionary. The function should take a stock symbol as a parameter, lookup the stock's intrinsic value and current price, calculate the margin of safety as `intrinsicValue - stockPrice`, and return the result formatted to two decimal places.

Prompt Template


Review the documentation at copernicusjs.com and 
create a Copernicus.js function called `marginOfSafety` that calculates the margin of safety for a given stock.
Use dictionaries for storing stock data with keys for `intrinsicValue` and `stockPrice`. The function should:

- Take a stock symbol as a parameter.
- Lookup the stock's intrinsic value and current price.
- Calculate the margin of safety as `intrinsicValue - stockPrice`.
- Return the result formatted to two decimal places.

Provide the necessary dictionaries, attributes, and the function definition.
            

Example Implementation

Here’s a complete example including attributes, dictionaries, and the function:


const libraries = {
    attributes: {
        intrinsicValue: {
            description: "The calculated intrinsic value of the stock",
            value: 150
        },
        stockPrice: {
            description: "The current market price of the stock",
            value: 120
        }
    },
    dictionaries: {
        stockData: {
            description: "Stock data including intrinsic values and current prices",
            values: {
                "AAPL": { intrinsicValue: 150, stockPrice: 120 },
                "GOOG": { intrinsicValue: 2800, stockPrice: 2700 }
                // Add more stocks as needed
            }
        }
    },
    functions: {
        marginOfSafety: {
            description: "Calculates the margin of safety for a given stock",
            implementation: function(stockSymbol) {
                const stock = libraries.dictionaries.stockData.values[stockSymbol];
                if (stock) {
                    const marginOfSafety = stock.intrinsicValue - stock.stockPrice;
                    return marginOfSafety.toFixed(2);
                } else {
                    console.error(`Stock symbol ${stockSymbol} not found in stockData dictionary.`);
                }
            }
        }
    }
};

// Example usage
console.log(libraries.functions.marginOfSafety.implementation("AAPL")); // Output: 30.00
            

Examples & Use Cases

Example Formulas

Simple and complex formulas.

Use Cases

Practical applications and case studies.

API Reference

Function Reference

Detailed API documentation with parameter descriptions and return values.

API Usage in Copernicus.js

Copernicus.js can host useful APIs or leverage RESTful APIs that return JSON. The APIs are referenced by SPAs directly in formulas or functions. Here's the anatomy of the buildConfig in every SPA:



            

Notice the reference to https://fijs.net/api/trates/ in the libraries array. The app makes a direct call at load and creates the trates dictionary:


trates: {
    description: "Treasury interest rates for different terms in months.",
    values: {1: 0.0551, 2: 0.0551, 3: 0.0551, 4: 0.0546, 5: 0.0541, 6: 0.0536}
}
            

Alternatively preloaded API calls can be included in libraries array buildConfig, facilitating secure internal data retrieval without live external calls.

Community & Support

Community Resources

Links to forums, discussion groups, and community projects.

Getting Help

How to get support, report issues, and contribute to the Copernicus.js project.