forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[8.6] [@kbn/handlebars] Split index.ts into several files (elastic#15…
…0230) (elastic#150422) # Backport This will backport the following commits from `main` to `8.6`: - [[@kbn/handlebars] Split index.ts into several files (elastic#150230)](elastic#150230) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Thomas Watson","email":"[email protected]"},"sourceCommit":{"committedDate":"2023-02-07T09:39:10Z","message":"[@kbn/handlebars] Split index.ts into several files (elastic#150230)\n\nAn attempt to make the code a little bit easier to parse","sha":"eafa5e7f0536715e26d71c3e104525ddd7551a14","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport:prev-minor","v8.7.0"],"number":150230,"url":"https://github.com/elastic/kibana/pull/150230","mergeCommit":{"message":"[@kbn/handlebars] Split index.ts into several files (elastic#150230)\n\nAn attempt to make the code a little bit easier to parse","sha":"eafa5e7f0536715e26d71c3e104525ddd7551a14"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/150230","number":150230,"mergeCommit":{"message":"[@kbn/handlebars] Split index.ts into several files (elastic#150230)\n\nAn attempt to make the code a little bit easier to parse","sha":"eafa5e7f0536715e26d71c3e104525ddd7551a14"}}]}] BACKPORT-->
- Loading branch information
Thomas Watson
authored
Feb 7, 2023
1 parent
3f3846c
commit b8d278c
Showing
8 changed files
with
1,081 additions
and
1,011 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Elasticsearch B.V licenses this file to you under the MIT License. | ||
* See `packages/kbn-handlebars/LICENSE` for more information. | ||
*/ | ||
|
||
// The handlebars module uses `export =`, so we should technically use `import Handlebars = require('handlebars')`, but Babel will not allow this: | ||
// https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require | ||
import Handlebars from 'handlebars'; | ||
|
||
import type { DecoratorsHash, ExtendedCompileOptions, ExtendedRuntimeOptions } from './types'; | ||
import { ElasticHandlebarsVisitor } from './visitor'; | ||
|
||
const originalCreate = Handlebars.create; | ||
|
||
export { Handlebars }; | ||
|
||
/** | ||
* Creates an isolated Handlebars environment. | ||
* | ||
* Each environment has its own helpers. | ||
* This is only necessary for use cases that demand distinct helpers. | ||
* Most use cases can use the root Handlebars environment directly. | ||
* | ||
* @returns A sandboxed/scoped version of the @kbn/handlebars module | ||
*/ | ||
Handlebars.create = function (): typeof Handlebars { | ||
const SandboxedHandlebars = originalCreate.call(Handlebars) as typeof Handlebars; | ||
// When creating new Handlebars environments, ensure the custom compileAST function is present in the new environment as well | ||
SandboxedHandlebars.compileAST = Handlebars.compileAST; | ||
return SandboxedHandlebars; | ||
}; | ||
|
||
/** | ||
* Compiles the given Handlbars template without the use of `eval`. | ||
* | ||
* @returns A render function with the same API as the return value from the regular Handlebars `compile` function. | ||
*/ | ||
Handlebars.compileAST = function ( | ||
input: string | hbs.AST.Program, | ||
options?: ExtendedCompileOptions | ||
) { | ||
if (input == null || (typeof input !== 'string' && input.type !== 'Program')) { | ||
throw new Handlebars.Exception( | ||
`You must pass a string or Handlebars AST to Handlebars.compileAST. You passed ${input}` | ||
); | ||
} | ||
|
||
// If `Handlebars.compileAST` is reassigned, `this` will be undefined. | ||
const helpers = (this ?? Handlebars).helpers; | ||
const partials = (this ?? Handlebars).partials; | ||
const decorators = (this ?? Handlebars).decorators as DecoratorsHash; | ||
|
||
const visitor = new ElasticHandlebarsVisitor(this, input, options, helpers, partials, decorators); | ||
return (context: any, runtimeOptions?: ExtendedRuntimeOptions) => | ||
visitor.render(context, runtimeOptions); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
* Elasticsearch B.V licenses this file to you under the MIT License. | ||
* See `packages/kbn-handlebars/LICENSE` for more information. | ||
*/ | ||
|
||
export const kHelper = Symbol('helper'); | ||
export const kAmbiguous = Symbol('ambiguous'); | ||
export const kSimple = Symbol('simple'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/* | ||
* Elasticsearch B.V licenses this file to you under the MIT License. | ||
* See `packages/kbn-handlebars/LICENSE` for more information. | ||
*/ | ||
|
||
import { kHelper, kAmbiguous, kSimple } from './symbols'; | ||
|
||
/** | ||
* A custom version of the Handlesbars module with an extra `compileAST` function and fixed typings. | ||
*/ | ||
declare module 'handlebars' { | ||
export function compileAST( | ||
input: string | hbs.AST.Program, | ||
options?: ExtendedCompileOptions | ||
): (context?: any, options?: ExtendedRuntimeOptions) => string; | ||
|
||
// -------------------------------------------------------- | ||
// Override/Extend inherited types below that are incorrect | ||
// -------------------------------------------------------- | ||
|
||
export interface TemplateDelegate<T = any> { | ||
(context?: T, options?: RuntimeOptions): string; // Override to ensure `context` is optional | ||
blockParams?: number; // TODO: Can this really be optional? | ||
partials?: any; // TODO: Narrow type to something better than any? | ||
} | ||
|
||
export interface HelperOptions { | ||
name: string; | ||
loc: { start: hbs.AST.SourceLocation['start']; end: hbs.AST.SourceLocation['end'] }; | ||
lookupProperty: LookupProperty; | ||
} | ||
|
||
export interface HelperDelegate { | ||
// eslint-disable-next-line @typescript-eslint/prefer-function-type | ||
(...params: any[]): any; | ||
} | ||
|
||
export function registerPartial(spec: { [name: string]: Handlebars.Template }): void; // Ensure `spec` object values can be strings | ||
} | ||
|
||
export type NodeType = typeof kHelper | typeof kAmbiguous | typeof kSimple; | ||
|
||
type LookupProperty = <T = any>(parent: { [name: string]: any }, propertyName: string) => T; | ||
|
||
export type ProcessableStatementNode = | ||
| hbs.AST.MustacheStatement | ||
| hbs.AST.PartialStatement | ||
| hbs.AST.SubExpression; | ||
export type ProcessableBlockStatementNode = hbs.AST.BlockStatement | hbs.AST.PartialBlockStatement; | ||
export type ProcessableNode = ProcessableStatementNode | ProcessableBlockStatementNode; | ||
export type ProcessableNodeWithPathParts = ProcessableNode & { path: hbs.AST.PathExpression }; | ||
export type ProcessableNodeWithPathPartsOrLiteral = ProcessableNode & { | ||
path: hbs.AST.PathExpression | hbs.AST.Literal; | ||
}; | ||
|
||
export interface Helper { | ||
fn?: Handlebars.HelperDelegate; | ||
context: any[]; | ||
params: any[]; | ||
options: AmbiguousHelperOptions; | ||
} | ||
|
||
export type NonBlockHelperOptions = Omit<Handlebars.HelperOptions, 'fn' | 'inverse'>; | ||
export type AmbiguousHelperOptions = Handlebars.HelperOptions | NonBlockHelperOptions; | ||
|
||
export interface DecoratorOptions extends Omit<Handlebars.HelperOptions, 'lookupProperties'> { | ||
args?: any[]; | ||
} | ||
|
||
/** | ||
* Supported Handlebars compile options. | ||
* | ||
* This is a subset of all the compile options supported by the upstream | ||
* Handlebars module. | ||
*/ | ||
export type ExtendedCompileOptions = Pick< | ||
CompileOptions, | ||
| 'data' | ||
| 'knownHelpers' | ||
| 'knownHelpersOnly' | ||
| 'noEscape' | ||
| 'strict' | ||
| 'assumeObjects' | ||
| 'preventIndent' | ||
| 'explicitPartialContext' | ||
>; | ||
|
||
/** | ||
* Supported Handlebars runtime options | ||
* | ||
* This is a subset of all the runtime options supported by the upstream | ||
* Handlebars module. | ||
*/ | ||
export type ExtendedRuntimeOptions = Pick< | ||
RuntimeOptions, | ||
'data' | 'helpers' | 'partials' | 'decorators' | 'blockParams' | ||
>; | ||
|
||
/** | ||
* According to the [decorator docs]{@link https://github.com/handlebars-lang/handlebars.js/blob/4.x/docs/decorators-api.md}, | ||
* a decorator will be called with a different set of arugments than what's actually happening in the upstream code. | ||
* So here I assume that the docs are wrong and that the upstream code is correct. In reality, `context` is the last 4 | ||
* documented arguments rolled into one object. | ||
*/ | ||
export type DecoratorFunction = ( | ||
prog: Handlebars.TemplateDelegate, | ||
props: Record<string, any>, | ||
container: Container, | ||
options: any | ||
) => any; | ||
|
||
export interface HelpersHash { | ||
[name: string]: Handlebars.HelperDelegate; | ||
} | ||
|
||
export interface PartialsHash { | ||
[name: string]: HandlebarsTemplateDelegate; | ||
} | ||
|
||
export interface DecoratorsHash { | ||
[name: string]: DecoratorFunction; | ||
} | ||
|
||
export interface Container { | ||
helpers: HelpersHash; | ||
partials: PartialsHash; | ||
decorators: DecoratorsHash; | ||
strict: (obj: { [name: string]: any }, name: string, loc: hbs.AST.SourceLocation) => any; | ||
lookupProperty: LookupProperty; | ||
lambda: (current: any, context: any) => any; | ||
data: (value: any, depth: number) => any; | ||
hooks: { | ||
helperMissing?: Handlebars.HelperDelegate; | ||
blockHelperMissing?: Handlebars.HelperDelegate; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Elasticsearch B.V licenses this file to you under the MIT License. | ||
* See `packages/kbn-handlebars/LICENSE` for more information. | ||
*/ | ||
|
||
// @ts-expect-error: Could not find a declaration file for module | ||
import { createFrame } from 'handlebars/dist/cjs/handlebars/utils'; | ||
|
||
import type { AmbiguousHelperOptions, DecoratorOptions } from './types'; | ||
|
||
export function isBlock(node: hbs.AST.Node): node is hbs.AST.BlockStatement { | ||
return 'program' in node || 'inverse' in node; | ||
} | ||
|
||
export function isDecorator( | ||
node: hbs.AST.Node | ||
): node is hbs.AST.Decorator | hbs.AST.DecoratorBlock { | ||
return node.type === 'Decorator' || node.type === 'DecoratorBlock'; | ||
} | ||
|
||
export function toDecoratorOptions(options: AmbiguousHelperOptions) { | ||
// There's really no tests/documentation on this, but to match the upstream codebase we'll remove `lookupProperty` from the decorator context | ||
delete (options as any).lookupProperty; | ||
|
||
return options as DecoratorOptions; | ||
} | ||
|
||
export function noop() { | ||
return ''; | ||
} | ||
|
||
// liftet from handlebars lib/handlebars/runtime.js | ||
export function initData(context: any, data: any) { | ||
if (!data || !('root' in data)) { | ||
data = data ? createFrame(data) : {}; | ||
data.root = context; | ||
} | ||
return data; | ||
} | ||
|
||
// liftet from handlebars lib/handlebars/compiler/compiler.js | ||
export function transformLiteralToPath(node: { path: hbs.AST.PathExpression | hbs.AST.Literal }) { | ||
const pathIsLiteral = 'parts' in node.path === false; | ||
|
||
if (pathIsLiteral) { | ||
const literal = node.path; | ||
// @ts-expect-error: Not all `hbs.AST.Literal` sub-types has an `original` property, but that's ok, in that case we just want `undefined` | ||
const original = literal.original; | ||
// Casting to string here to make false and 0 literal values play nicely with the rest | ||
// of the system. | ||
node.path = { | ||
type: 'PathExpression', | ||
data: false, | ||
depth: 0, | ||
parts: [original + ''], | ||
original: original + '', | ||
loc: literal.loc, | ||
}; | ||
} | ||
} | ||
|
||
export function allowUnsafeEval() { | ||
try { | ||
new Function(); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
} |
Oops, something went wrong.