Skip to content

在创建API的时候, Tealina 只知道最终的文件路径, 文件内的具体代码, 是通过自定义模版填充的.

模版即函数

一个接收上下文, 返回字符串的js函数. 为了更方便的定制模版, Tealina 提供了一个makeTeamplate的辅助函数,

示例代码
js
// @ts-check
import { makeTemplate } from 'tealina'
export default makeTemplate(({ Dir: Model, relative2api, dir: model }) => {
  // Feel free to change it
  const imps = [
    `import type { AuthedHandler } from '${relative2api}/../types/handler.js'`,
    `import type { Pure } from '${relative2api}/../types/pure.js'`,
    `import { convention } from '${relative2api}/convention.js'`,
    `import { db } from '${relative2api}/db/prisma.js'`,
  ]
  const codes = [
    `type ApiType = AuthedHandler<{ body: Pure.${Model}CreateInput }, Pure.${Model}>`,
    '',
    `/** Create ${Model} */`,
    `const handler: ApiType = async (req, res) => {`,
    `  const result = await db.${model}.create({`,
    '    data: req.body,',
    '  })',
    '  res.send(result)',
    '}',
    '',
    `export default convention(handler)`,
  ]
  return [...imps, '', ...codes].join('\n')
})
// @ts-check
import { makeTemplate } from 'tealina'
export default makeTemplate(({ Dir: Model, relative2api, dir: model }) => {
  // Feel free to change it
  const imps = [
    `import type { AuthedHandler } from '${relative2api}/../types/handler.js'`,
    `import type { Pure } from '${relative2api}/../types/pure.js'`,
    `import { convention } from '${relative2api}/convention.js'`,
    `import { db } from '${relative2api}/db/prisma.js'`,
  ]
  const codes = [
    `type ApiType = AuthedHandler<{ body: Pure.${Model}CreateInput }, Pure.${Model}>`,
    '',
    `/** Create ${Model} */`,
    `const handler: ApiType = async (req, res) => {`,
    `  const result = await db.${model}.create({`,
    '    data: req.body,',
    '  })',
    '  res.send(result)',
    '}',
    '',
    `export default convention(handler)`,
  ]
  return [...imps, '', ...codes].join('\n')
})

定义多个模版

可以为不同的 http-method 或按名称定义多个模版, 组成一个js数组, Tealina 也提供了 definedApiTemplates 辅助函数.

js
// @ts-check
import genCreateCode from './genCreateCode.mjs'
import genBasicCode from './genBasicCode.mjs'
import { defineApiTemplates } from 'tealina'

export default defineApiTemplates([
  {
    alias: 'c',
    name: 'create',
    method: 'post',
    generateFn: genCreateCode,
  },
  ...
  {
    alias: '*', //fallback
    name: '',
    method: 'post',
    generateFn: genBasicCode,
  },
])
// @ts-check
import genCreateCode from './genCreateCode.mjs'
import genBasicCode from './genBasicCode.mjs'
import { defineApiTemplates } from 'tealina'

export default defineApiTemplates([
  {
    alias: 'c',
    name: 'create',
    method: 'post',
    generateFn: genCreateCode,
  },
  ...
  {
    alias: '*', //fallback
    name: '',
    method: 'post',
    generateFn: genBasicCode,
  },
])

TIP

当执行 v1 user -t c, Tealina 会通过别名 c 找到对应的模版, 使用模版名称作为文件名, 调用 generateFn 获得文件内容, 写入到API文件.

注册到配置文件

js
// @ts-check
import { defineConfig } from 'tealina'
import apiTemplates from './dev-templates/handlers/index.mjs'
import { genTestSuite } from './dev-templates/test/index.mjs'

export default defineConfig({
  template: {
    handlers: apiTemplates,
    test: {
      genSuite: genTestSuite,
    },
  },
})
// @ts-check
import { defineConfig } from 'tealina'
import apiTemplates from './dev-templates/handlers/index.mjs'
import { genTestSuite } from './dev-templates/test/index.mjs'

export default defineConfig({
  template: {
    handlers: apiTemplates,
    test: {
      genSuite: genTestSuite,
    },
  },
})

类型

详细定义
ts
interface TemplateContext {
  dir?: string
  /** captialized directory name */
  Dir?: string
  filename: string
  /** captialized filename */
  Filename: string
  relative2api: string
  /** http method */
  method: string
}

type CodeGenerateFnType = (ctx: TemplateContext) => string

interface ApiTemplateType {
  /**
   * 名称缩写.\
   * 一个字符,大小写敏感.\
   * `*` 用于 当 name 和 alias 都没有匹配到的时候
   */
  alias: string
  /**
   * 用作文件名,如果为空字符,文件名是路由中的最后一段.
   */
  name: string
  /**
   * Http Method
   * @default 'post'
   */
  method?: string
  /** Code generate function */
  generateFn: CodeGenerateFnType
}
interface TemplateContext {
  dir?: string
  /** captialized directory name */
  Dir?: string
  filename: string
  /** captialized filename */
  Filename: string
  relative2api: string
  /** http method */
  method: string
}

type CodeGenerateFnType = (ctx: TemplateContext) => string

interface ApiTemplateType {
  /**
   * 名称缩写.\
   * 一个字符,大小写敏感.\
   * `*` 用于 当 name 和 alias 都没有匹配到的时候
   */
  alias: string
  /**
   * 用作文件名,如果为空字符,文件名是路由中的最后一段.
   */
  name: string
  /**
   * Http Method
   * @default 'post'
   */
  method?: string
  /** Code generate function */
  generateFn: CodeGenerateFnType
}