1
0
Fork 0
mirror of synced 2024-10-02 10:08:09 +13:00
This commit is contained in:
Adria Navarro 2024-02-22 11:16:09 +01:00
parent 9e0e9297f5
commit c3531ac8ba
6 changed files with 118 additions and 86 deletions

View file

@ -1,11 +1,11 @@
import { getJsHelperList } from "../helpers"
function getLayers(fullBlock) {
function getLayers(fullBlock: string): string[] {
let layers = []
while (fullBlock.length) {
const start = fullBlock.lastIndexOf("("),
end = fullBlock.indexOf(")")
let layer
let layer: string
if (start === -1 || end === -1) {
layer = fullBlock.trim()
fullBlock = ""
@ -21,7 +21,7 @@ function getLayers(fullBlock) {
return layers
}
function getVariable(variableName) {
function getVariable(variableName: string) {
if (!variableName || typeof variableName !== "string") {
return variableName
}
@ -47,10 +47,12 @@ function getVariable(variableName) {
return `$("${variableName}")`
}
function buildList(parts, value) {
function buildList(parts: any[], value: any) {
function build() {
return parts
.map(part => (part.startsWith("helper") ? part : getVariable(part)))
.map((part: string) =>
part.startsWith("helper") ? part : getVariable(part)
)
.join(", ")
}
if (!value) {
@ -60,12 +62,12 @@ function buildList(parts, value) {
}
}
function splitBySpace(layer) {
function splitBySpace(layer: string) {
const parts = []
let started = null,
endChar = null,
last = 0
function add(str) {
function add(str: string) {
const startsWith = ["]"]
while (startsWith.indexOf(str.substring(0, 1)) !== -1) {
str = str.substring(1, str.length)
@ -103,7 +105,7 @@ function splitBySpace(layer) {
return parts
}
export function convertHBSBlock(block, blockNumber) {
export function convertHBSBlock(block: string, blockNumber: number) {
const braceLength = block[2] === "{" ? 3 : 2
block = block.substring(braceLength, block.length - braceLength).trim()
const layers = getLayers(block)

View file

@ -1,4 +1,4 @@
import { createContext, runInNewContext } from "vm"
import { Context, createContext, runInNewContext } from "vm"
import { create } from "handlebars"
import { registerAll, registerMinimum } from "./helpers/index"
import { preprocess, postprocess } from "./processors"
@ -15,6 +15,7 @@ import { setJSRunner, removeJSRunner } from "./helpers/javascript"
import { helpersToRemoveForJs } from "./helpers/list"
import manifest from "../manifest.json"
import { ProcessOptions } from "./types"
export { setJSRunner, setOnErrorLog } from "./helpers/javascript"
@ -22,7 +23,7 @@ const hbsInstance = create()
registerAll(hbsInstance)
const hbsInstanceNoHelpers = create()
registerMinimum(hbsInstanceNoHelpers)
const defaultOpts = {
const defaultOpts: ProcessOptions = {
noHelpers: false,
cacheTemplates: false,
noEscaping: false,
@ -33,7 +34,7 @@ const defaultOpts = {
/**
* Utility function to check if the object is valid.
*/
function testObject(object) {
function testObject(object: any) {
// JSON stringify will fail if there are any cycles, stops infinite recursion
try {
JSON.stringify(object)
@ -46,7 +47,7 @@ function testObject(object) {
* Creates a HBS template function for a given string, and optionally caches it.
*/
let templateCache = {}
function createTemplate(string, opts) {
function createTemplate(string: string, opts: ProcessOptions) {
opts = { ...defaultOpts, ...opts }
// Finalising adds a helper, can't do this with no helpers
@ -82,7 +83,11 @@ function createTemplate(string, opts) {
* @param {object|undefined} [opts] optional - specify some options for processing.
* @returns {Promise<object|array>} The structure input, as fully updated as possible.
*/
export async function processObject(object, context, opts?) {
export async function processObject(
object: { [x: string]: any },
context: object,
opts?: { noHelpers?: boolean; escapeNewlines?: boolean; onlyFound?: boolean }
) {
testObject(object)
for (let key of Object.keys(object || {})) {
if (object[key] != null) {
@ -123,7 +128,11 @@ export async function processString(
* @param {object|undefined} [opts] optional - specify some options for processing.
* @returns {object|array} The structure input, as fully updated as possible.
*/
export function processObjectSync(object, context, opts) {
export function processObjectSync(
object: { [x: string]: any },
context: any,
opts: any
) {
testObject(object)
for (let key of Object.keys(object || {})) {
let val = object[key]
@ -144,13 +153,17 @@ export function processObjectSync(object, context, opts) {
* @param {object|undefined} [opts] optional - specify some options for processing.
* @returns {string} The enriched string, all templates should have been replaced if they can be.
*/
export function processStringSync(string, context, opts?) {
export function processStringSync(
string: string,
context: object,
opts?: { noHelpers?: boolean; escapeNewlines?: boolean; onlyFound: any }
) {
// Take a copy of input in case of error
const input = string
if (typeof string !== "string") {
throw "Cannot process non-string types."
}
function process(stringPart) {
function process(stringPart: string) {
const template = createTemplate(stringPart, opts)
const now = Math.floor(Date.now() / 1000) * 1000
return postprocess(
@ -186,7 +199,7 @@ export function processStringSync(string, context, opts?) {
* this function will find any double braces and switch to triple.
* @param string the string to have double HBS statements converted to triple.
*/
export function disableEscaping(string) {
export function disableEscaping(string: string) {
const matches = findDoubleHbsInstances(string)
if (matches == null) {
return string
@ -207,7 +220,7 @@ export function disableEscaping(string) {
* @param {string} property The property which is to be wrapped.
* @returns {string} The wrapped property ready to be added to a templating string.
*/
export function makePropSafe(property) {
export function makePropSafe(property: any) {
return `[${property}]`.replace("[[", "[").replace("]]", "]")
}
@ -217,7 +230,7 @@ export function makePropSafe(property) {
* @param [opts] optional - specify some options for processing.
* @returns {boolean} Whether or not the input string is valid.
*/
export function isValid(string, opts?) {
export function isValid(string: any, opts?: any) {
const validCases = [
"string",
"number",
@ -268,7 +281,7 @@ export function getManifest() {
* @param handlebars the HBS expression to check
* @returns {boolean} whether the expression is JS or not
*/
export function isJSBinding(handlebars) {
export function isJSBinding(handlebars: any) {
return decodeJSBinding(handlebars) != null
}
@ -277,7 +290,7 @@ export function isJSBinding(handlebars) {
* @param javascript the JS code to encode
* @returns {string} the JS HBS expression
*/
export function encodeJSBinding(javascript) {
export function encodeJSBinding(javascript: string) {
return `{{ js "${btoa(javascript)}" }}`
}
@ -286,7 +299,7 @@ export function encodeJSBinding(javascript) {
* @param handlebars the JS HBS expression
* @returns {string|null} the raw JS code
*/
export function decodeJSBinding(handlebars) {
export function decodeJSBinding(handlebars: string) {
if (!handlebars || typeof handlebars !== "string") {
return null
}
@ -311,7 +324,7 @@ export function decodeJSBinding(handlebars) {
* @param {string[]} strings The strings to look for.
* @returns {boolean} Will return true if all strings found in HBS statement.
*/
export function doesContainStrings(template, strings) {
export function doesContainStrings(template: string, strings: any[]) {
let regexp = new RegExp(FIND_HBS_REGEX)
let matches = template.match(regexp)
if (matches == null) {
@ -341,7 +354,7 @@ export function doesContainStrings(template, strings) {
* @param {string} string The string to search within.
* @return {string[]} The found HBS blocks.
*/
export function findHBSBlocks(string) {
export function findHBSBlocks(string: string) {
if (!string || typeof string !== "string") {
return []
}
@ -362,11 +375,11 @@ export function findHBSBlocks(string) {
* @param {string} string The word or sentence to search for.
* @returns {boolean} The this return true if the string is found, false if not.
*/
export function doesContainString(template, string) {
export function doesContainString(template: any, string: any) {
return doesContainStrings(template, [string])
}
export function convertToJS(hbs) {
export function convertToJS(hbs: string) {
const blocks = findHBSBlocks(hbs)
let js = "return `",
prevBlock: string | null = null
@ -407,7 +420,7 @@ function defaultJSSetup() {
/**
* Use polyfilled vm to run JS scripts in a browser Env
*/
setJSRunner((js, context) => {
setJSRunner((js: string, context: Context) => {
context = {
...context,
alert: undefined,

View file

@ -1,8 +1,9 @@
import { FIND_HBS_REGEX } from "../utilities"
import * as preprocessor from "./preprocessor"
import * as postprocessor from "./postprocessor"
import { ProcessOptions } from "../types"
function process(output, processors, opts?) {
function process(output: string, processors: any[], opts?: ProcessOptions) {
for (let processor of processors) {
// if a literal statement has occurred stop
if (typeof output !== "string") {
@ -21,7 +22,7 @@ function process(output, processors, opts?) {
return output
}
export function preprocess(string, opts) {
export function preprocess(string: string, opts: ProcessOptions) {
let processors = preprocessor.processors
if (opts.noFinalise) {
processors = processors.filter(
@ -30,7 +31,7 @@ export function preprocess(string, opts) {
}
return process(string, processors, opts)
}
export function postprocess(string) {
export function postprocess(string: string) {
let processors = postprocessor.processors
return process(string, processors)
}

View file

@ -6,45 +6,51 @@ export const PostProcessorNames = {
/* eslint-disable no-unused-vars */
class Postprocessor {
name
private fn
name: string
private fn: any
constructor(name, fn) {
constructor(name: string, fn: any) {
this.name = name
this.fn = fn
}
process(statement) {
process(statement: any) {
return this.fn(statement)
}
}
export const processors = [
new Postprocessor(PostProcessorNames.CONVERT_LITERALS, statement => {
if (typeof statement !== "string" || !statement.includes(LITERAL_MARKER)) {
return statement
new Postprocessor(
PostProcessorNames.CONVERT_LITERALS,
(statement: string) => {
if (
typeof statement !== "string" ||
!statement.includes(LITERAL_MARKER)
) {
return statement
}
const splitMarkerIndex = statement.indexOf("-")
const type = statement.substring(12, splitMarkerIndex)
const value = statement.substring(
splitMarkerIndex + 1,
statement.length - 2
)
switch (type) {
case "string":
return value
case "number":
return parseFloat(value)
case "boolean":
return value === "true"
case "object":
return JSON.parse(value)
case "js_result":
// We use the literal helper to process the result of JS expressions
// as we want to be able to return any types.
// We wrap the value in an abject to be able to use undefined properly.
return JSON.parse(value).data
}
return value
}
const splitMarkerIndex = statement.indexOf("-")
const type = statement.substring(12, splitMarkerIndex)
const value = statement.substring(
splitMarkerIndex + 1,
statement.length - 2
)
switch (type) {
case "string":
return value
case "number":
return parseFloat(value)
case "boolean":
return value === "true"
case "object":
return JSON.parse(value)
case "js_result":
// We use the literal helper to process the result of JS expressions
// as we want to be able to return any types.
// We wrap the value in an abject to be able to use undefined properly.
return JSON.parse(value).data
}
return value
}),
),
]

View file

@ -14,7 +14,7 @@ class Preprocessor {
name: string
private fn: any
constructor(name, fn) {
constructor(name: string, fn: any) {
this.name = name
this.fn = fn
}
@ -27,7 +27,7 @@ class Preprocessor {
}
export const processors = [
new Preprocessor(PreprocessorNames.SWAP_TO_DOT, statement => {
new Preprocessor(PreprocessorNames.SWAP_TO_DOT, (statement: string) => {
let startBraceIdx = statement.indexOf("[")
let lastIdx = 0
while (startBraceIdx !== -1) {
@ -42,7 +42,7 @@ export const processors = [
return statement
}),
new Preprocessor(PreprocessorNames.FIX_FUNCTIONS, statement => {
new Preprocessor(PreprocessorNames.FIX_FUNCTIONS, (statement: string) => {
for (let specialCase of FUNCTION_CASES) {
const toFind = `{ ${specialCase}`,
replacement = `{${specialCase}`
@ -51,29 +51,32 @@ export const processors = [
return statement
}),
new Preprocessor(PreprocessorNames.FINALISE, (statement, opts) => {
const noHelpers = opts && opts.noHelpers
let insideStatement = statement.slice(2, statement.length - 2)
if (insideStatement.charAt(0) === " ") {
insideStatement = insideStatement.slice(1)
}
if (insideStatement.charAt(insideStatement.length - 1) === " ") {
insideStatement = insideStatement.slice(0, insideStatement.length - 1)
}
const possibleHelper = insideStatement.split(" ")[0]
// function helpers can't be wrapped
for (let specialCase of FUNCTION_CASES) {
if (possibleHelper.includes(specialCase)) {
return statement
new Preprocessor(
PreprocessorNames.FINALISE,
(statement: string, opts: { noHelpers: any }) => {
const noHelpers = opts && opts.noHelpers
let insideStatement = statement.slice(2, statement.length - 2)
if (insideStatement.charAt(0) === " ") {
insideStatement = insideStatement.slice(1)
}
if (insideStatement.charAt(insideStatement.length - 1) === " ") {
insideStatement = insideStatement.slice(0, insideStatement.length - 1)
}
const possibleHelper = insideStatement.split(" ")[0]
// function helpers can't be wrapped
for (let specialCase of FUNCTION_CASES) {
if (possibleHelper.includes(specialCase)) {
return statement
}
}
const testHelper = possibleHelper.trim().toLowerCase()
if (
!noHelpers &&
HelperNames().some(option => testHelper === option.toLowerCase())
) {
insideStatement = `(${insideStatement})`
}
return `{{ all ${insideStatement} }}`
}
const testHelper = possibleHelper.trim().toLowerCase()
if (
!noHelpers &&
HelperNames().some(option => testHelper === option.toLowerCase())
) {
insideStatement = `(${insideStatement})`
}
return `{{ all ${insideStatement} }}`
}),
),
]

View file

@ -0,0 +1,7 @@
export interface ProcessOptions {
cacheTemplates?: boolean
noEscaping?: boolean
noHelpers?: boolean
noFinalise?: boolean
escapeNewlines?: boolean
}