Skip to content

Commit

Permalink
refactor: finalize loader api
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Mar 26, 2020
1 parent cca6487 commit 17747a4
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 74 deletions.
49 changes: 9 additions & 40 deletions src/Loader/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
*/

import { readFileSync } from 'fs'
import requireUncached from 'import-fresh'
import { join, isAbsolute, extname, sep } from 'path'
import { Exception, esmResolver } from '@poppinss/utils'
import { Exception } from '@poppinss/utils'
import { join, isAbsolute, sep } from 'path'
import { LoaderContract, LoaderTemplate } from '../Contracts'

/**
* The job of a loader is to load the template and it's presenter for a given path.
* The base loader (shipped with edge) looks for files on the file-system and
* reads them synchronously.
* The job of a loader is to load the template from a given path.
* The base loader (shipped with edge) looks for files on the
* file-system and reads them synchronously.
*
* You are free to define your own loaders that implements the [[LoaderContract]] interface.
*/
Expand All @@ -31,27 +30,6 @@ export class Loader implements LoaderContract {
*/
private preRegistered: Map<string, LoaderTemplate> = new Map()

/**
* Attempts to load the presenter for a given template. If presenter doesn't exists, it
* will swallow the error.
*
* Also this method will **bypass the `require` cache**, since in production compiled templates
* and their presenters are cached anyways.
*/
private getPresenterForTemplate (templatePath: string): LoaderTemplate['Presenter'] | undefined {
const presenterPath = templatePath
.replace(/^\w/, c => c.toUpperCase())
.replace(extname(templatePath), '.presenter.js')

try {
return esmResolver(requireUncached(presenterPath)) as LoaderTemplate['Presenter']
} catch (error) {
if (['ENOENT', 'MODULE_NOT_FOUND'].indexOf(error.code) === -1) {
throw error
}
}
}

/**
* Reads the content of a template from the disk. An exception is raised
* when file is missing or if `readFileSync` returns an error.
Expand Down Expand Up @@ -191,31 +169,23 @@ export class Loader implements LoaderContract {
}

/**
* Resolves the template from the disk, optionally loads the presenter too. The presenter
* resolution is based on the convention and resolved from the same directory
* as the template.
*
* ## Presenter convention
* - View name - welcome.edge
* - Presenter name - Welcome.presenter.js
* Resolves the template by reading its contents from the disk
*
* ```js
* loader.resolve('welcome', true)
*
* // output
* {
* template: `<h1> Template content </h1>`,
* Presenter: class Presenter | undefined
* }
* ```
*/
public resolve (templatePath: string, withPresenter: boolean): LoaderTemplate {
public resolve (templatePath: string): LoaderTemplate {
/**
* Return from pre-registered one's if exists
*/
if (this.preRegistered.has(templatePath)) {
const contents = this.preRegistered.get(templatePath)
return withPresenter ? contents! : { template: contents!.template }
return this.preRegistered.get(templatePath)!
}

/**
Expand All @@ -225,12 +195,11 @@ export class Loader implements LoaderContract {

return {
template: this.readTemplateContents(templatePath),
Presenter: withPresenter ? this.getPresenterForTemplate(templatePath) : undefined,
}
}

/**
* Register in memory template and Presenter for a given path. This is super helpful
* Register in memory template for a given path. This is super helpful
* when distributing components.
*
* ```js
Expand Down
40 changes: 6 additions & 34 deletions test/loader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,12 @@ test.group('Loader', (group) => {
const loader = new Loader()
loader.mount('default', fs.basePath)
loader.unmount('default')

assert.deepEqual(loader.mounted, {})
})

test('throw exception when resolving path from undefined location', (assert) => {
const loader = new Loader()
const fn = () => loader.resolve('foo', true)
const fn = () => loader.resolve('foo')
assert.throw(fn, 'E_UNMOUNTED_DISK_NAME: "default" namespace is not mounted')
})

Expand All @@ -46,15 +45,15 @@ test.group('Loader', (group) => {
const loader = new Loader()
loader.mount('default', fs.basePath)

const { template } = loader.resolve('foo', false)
const { template } = loader.resolve('foo')
assert.equal(template.trim(), 'Hello world')
})

test('raise error when template is missing', async (assert) => {
const loader = new Loader()
loader.mount('default', fs.basePath)

const fn = () => loader.resolve('foo', false)
const fn = () => loader.resolve('foo')
assert.throw(fn, `Cannot resolve "${join(fs.basePath, 'foo.edge')}". Make sure the file exists`)
})

Expand All @@ -64,7 +63,7 @@ test.group('Loader', (group) => {
const loader = new Loader()
loader.mount('default', fs.basePath)

const { template } = loader.resolve('foo.edge', false)
const { template } = loader.resolve('foo.edge')
assert.equal(template.trim(), 'Hello world')
})

Expand All @@ -74,7 +73,7 @@ test.group('Loader', (group) => {
const loader = new Loader()
loader.mount('users', fs.basePath)

const { template } = loader.resolve('users::foo.edge', false)
const { template } = loader.resolve('users::foo.edge')
assert.equal(template.trim(), 'Hello world')
})

Expand Down Expand Up @@ -110,41 +109,14 @@ test.group('Loader', (group) => {
assert.equal(templatePath, join(fs.basePath, 'partial/edge.edge'))
})

test('resolve presenter if exists', async (assert) => {
await fs.add('foo.edge', 'Hello world')
await fs.add('foo.presenter.js', `module.exports = class Foo {
}`)

const loader = new Loader()
loader.mount('users', fs.basePath)

const { template, Presenter } = loader.resolve('users::foo.edge', true)
assert.equal(template.trim(), 'Hello world')
assert.equal(Presenter!['name'], 'Foo')
})

test('do not resolve presenter if withPresenter is set to false', async (assert) => {
await fs.add('foo.edge', 'Hello world')
await fs.add('foo.presenter.js', `module.exports = class Foo {
}`)

const loader = new Loader()
loader.mount('users', fs.basePath)

const { template, Presenter } = loader.resolve('users::foo.edge', false)
assert.equal(template.trim(), 'Hello world')
assert.isUndefined(Presenter)
})

test('pre register templates with a key', async (assert) => {
const loader = new Loader()
loader.register('my-view', {
template: 'Hello world',
})

const { template, Presenter } = loader.resolve('my-view', true)
const { template } = loader.resolve('my-view')
assert.equal(template.trim(), 'Hello world')
assert.isUndefined(Presenter)
})

test('pre registering duplicate templates must raise an error', async (assert) => {
Expand Down

0 comments on commit 17747a4

Please sign in to comment.