Skip to content

Commit

Permalink
refactor: cleanup entire project API
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Jul 23, 2019
1 parent a0d5502 commit c2382bc
Show file tree
Hide file tree
Showing 24 changed files with 982 additions and 584 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"@poppinss/utils": "^1.0.3",
"debug": "^4.1.1",
"edge-error": "^1.0.2",
"edge-parser": "^2.0.6",
"edge-parser": "^2.0.7",
"he": "^1.2.0",
"import-fresh": "^3.1.0",
"lodash": "^4.17.15",
Expand Down
97 changes: 92 additions & 5 deletions src/Compiler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@
* file that was distributed with this source code.
*/

import { Token } from 'edge-lexer'
import { Parser } from 'edge-parser'
import { EdgeError } from 'edge-error'
import { Token, TagToken } from 'edge-lexer'

import { LoaderContract, Tags, LoaderTemplate } from '../Contracts'
import { mergeSections, isBlock } from '../utils'
import { CacheManager } from '../CacheManager'
import { isBlock, getLineAndColumn } from '../utils'
import { LoaderContract, TagsContract, LoaderTemplate } from '../Contracts'

/**
* Compiler compiles the template to a function, which can be invoked at a later
Expand All @@ -31,10 +32,96 @@ export class Compiler {

constructor (
private _loader: LoaderContract,
private _tags: Tags,
private _tags: TagsContract,
private _cache: boolean = true,
) {}

/**
* Merges sections of base template and parent template tokens
*/
private _mergeSections (base: Token[], extended: Token[], filename: string): Token[] {
/**
* Collection of all sections from the extended tokens
*/
const extendedSections: { [key: string]: TagToken } = {}

/**
* Collection of extended set calls as top level nodes. Now since they are hanging
* up in the air, they will be hoisted like `var` statements in Javascript
*/
const extendedSetCalls: TagToken[] = []

extended
.forEach((node) => {
/**
* Ignore new lines, layout tag and empty raw nodes inside the parent
* template
*/
if (
isBlock(node, 'layout') ||
node.type === 'newline' ||
(node.type === 'raw' && !node.value.trim())
) {
return
}

/**
* Collect parent template sections
*/
if (isBlock(node, 'section')) {
extendedSections[node.properties.jsArg.trim()] = node
return
}

/**
* Collect set calls inside parent templates
*/
if (isBlock(node, 'set')) {
extendedSetCalls.push(node)
return
}

/**
* Everything else if not allowed as top level nodes
*/
const [line, col] = getLineAndColumn(node)
throw new EdgeError(
`Template extending the layout can only define @sections as top level nodes`,
'E_UNALLOWED_EXPRESSION',
{ line, col, filename },
)
})

/**
* Replace/extend sections inside base tokens list
*/
const finalNodes = base
.map((node) => {
if (!isBlock(node, 'section')) {
return node
}

const extendedNode = extendedSections[node.properties.jsArg.trim()]
if (!extendedNode) {
return node
}

/**
* Concat children when super was called
*/
if (extendedNode.children.length && isBlock(extendedNode.children[0], 'super')) {
extendedNode.children = node.children.concat(extendedNode.children)
}

return extendedNode
})

/**
* Set calls are hoisted to the top
*/
return ([] as Token[]).concat(extendedSetCalls).concat(finalNodes)
}

/**
* Generates an array of lexer tokens from the template string. Further tokens
* are checked for layouts and if layouts are used, their sections will be
Expand All @@ -51,7 +138,7 @@ export class Compiler {
*/
if (isBlock(firstToken, 'layout')) {
const layoutTokens = this.generateTokens(firstToken.properties.jsArg.replace(/'/g, ''))
templateTokens = mergeSections(layoutTokens, templateTokens)
templateTokens = this._mergeSections(layoutTokens, templateTokens, parser.options.filename)
}

return templateTokens
Expand Down
3 changes: 2 additions & 1 deletion src/Context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import * as he from 'he'
import { set } from 'lodash'
import { Macroable } from 'macroable'
import { ContextContract } from '../Contracts'

/**
* Context is used at runtime to resolve values for a given
Expand All @@ -22,7 +23,7 @@ import { Macroable } from 'macroable'
* Also the context can be extended to add `getters` and `methods`. Checkout
* [macroable](https://github.com/poppinss/macroable) for same.
*/
export class Context extends Macroable {
export class Context extends Macroable implements ContextContract {
protected static _macros = {}
protected static _getters = {}

Expand Down
25 changes: 23 additions & 2 deletions src/Contracts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* file that was distributed with this source code.
*/

import { MacroableConstructorContract } from 'macroable'
import { ParseTagDefininationContract } from 'edge-parser'

/**
Expand Down Expand Up @@ -58,17 +59,37 @@ export interface LoaderContract {
register (templatePath: string, contents: LoaderTemplate): void
}

/**
* Shape of runtime context
*/
export interface ContextContract {
newFrame (): void,
setOnFrame (key: string, value: any): void,
removeFrame (): void,
escape <T> (input: T): T,
resolve (key: string): any,
set (key: string, value: any): void,
}

/**
* Shape of context constructor
*/
export interface ContextConstructorContract extends MacroableConstructorContract {
new (presenter: any, sharedState: any): ContextContract,
}

/**
* The final tag must have a tagName along with other properties
* required by lexer and parser
*/
export interface TagContract extends ParseTagDefininationContract {
tagName: string
tagName: string,
run? (context: ContextConstructorContract): void,
}

/**
* Shape of required tags
*/
export type Tags = {
export type TagsContract = {
[tagName: string]: TagContract,
}
49 changes: 49 additions & 0 deletions src/StringifiedObject/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @module edge
*/

/*
* edge
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/**
* This class generates a valid object as a string, which is written to the template
* output. The reason we need a string like object, since we don't want it's
* properties to be evaluated during the object creation, instead it must
* be evaluated when the compiled output is invoked.
*/
export class StringifiedObject {
private obj: string = ''

/**
* Add key/value pair to the object.
*
* ```js
* stringifiedObject.add('username', `'virk'`)
* ```
*/
public add (key: any, value: any) {
this.obj += this.obj.length ? `, ${key}: ${value}` : `${key}: ${value}`
}

/**
* Returns the object alike string back.
*
* ```js
* stringifiedObject.flush()
*
* // returns
* `{ username: 'virk' }`
* ```
*/
public flush (): string {
const obj = `{ ${this.obj} }`
this.obj = ''
return obj
}
}
Loading

0 comments on commit c2382bc

Please sign in to comment.