Skip to content

⬅️ Back to Table of Contents

📄 scripts/utils

📊 Analysis Summary

Metric Count
🔧 Functions 13
📦 Imports 12
📊 Variables & Constants 1
⚡ Async/Await Patterns 10

📚 Table of Contents

🛠️ File Location:

📂 scripts/utils.ts

📦 Imports

Name Source
PackageIndexes @vueuse/metadata
VueUseFunction @vueuse/metadata
existsSync node:fs
join node:path
resolve node:path
fileURLToPath node:url
matter gray-matter
$fetch ofetch
Git simple-git
yaml yaml
packages ../meta/packages
getCategories ../packages/metadata/utils

Variables & Constants

Name Type Kind Value Exported
DOCS_URL "https://vueuse.org" const 'https://vueuse.org'

Async/Await Patterns

Type Function Await Expressions Promise Chains
async-function getTypeDefinition fs.readFile(typingFilepath, 'utf-8'), import('prettier'), prettier .format( t... none
async-function updateImport fs.writeFile(join(dir, 'index.ts'), ${imports.join('\n')}\n), fs.rm(join(di... none
async-function updatePackageREADME fs.readFile(readmePath, 'utf-8'), fs.writeFile(readmePath, ${readme}\n, 'ut... none
async-function updateIndexREADME fs.readFile('README.md', 'utf-8'), fs.writeFile('README.md', ${readme}\n, '... none
async-function updateFunctionsMD fs.readFile('packages/add-ons.md', 'utf-8'), fs.writeFile('packages/add-ons.m... none
async-function updateFunctionREADME fs.readFile(mdPath, 'utf-8'), fs.writeFile(mdPath, ${readme}\n, 'utf-8') none
async-function updateCountBadge $fetch(url, { responseType: 'text' }), fs.writeFile(join(DIR_ROOT, 'packages/... none
async-function updatePackageJSON fs.readFile('package.json', { encoding: 'utf8' }), fs.readFile(packageJSONPat... none
async-function fetchContributors $fetch<{ login: string }[]>(`https://api.github.com/repos/vueuse/vueuse/contr... none
async-function updateContributors fetchContributors(), fs.writeFile(join(DIR_SRC, './contributors.json'), `${JS... none

Functions

getTypeDefinition(pkg: string, name: string): Promise<string | undefined>

Parameters:

  • pkg string
  • name string

Returns: Promise<string | undefined>

Calls:

  • join (from node:path)
  • existsSync (from node:fs)
  • fs.readFile
  • types .replace(/import\(.*?\)\./g, '') .replace(/import[\s\S]+?from ?["'][\s\S]+?["']/g, '') .replace
  • complex_call_1243
  • (await prettier .format( types, { semi: false, parser: 'typescript', }, )) .trim
  • prettier .format

Internal Comments:

// clean up types (x3)

Code
export async function getTypeDefinition(pkg: string, name: string): Promise<string | undefined> {
  const typingFilepath = join(DIR_TYPES, `${pkg}/${name}/index.d.ts`)

  if (!existsSync(typingFilepath))
    return

  let types = await fs.readFile(typingFilepath, 'utf-8')

  if (!types)
    return

  // clean up types
  types = types
    .replace(/import\(.*?\)\./g, '')
    .replace(/import[\s\S]+?from ?["'][\s\S]+?["']/g, '')
    .replace(/export \{\}/g, '')

  const prettier = await import('prettier')
  return (await prettier
    .format(
      types,
      {
        semi: false,
        parser: 'typescript',
      },
    ))
    .trim()
}

updateImport({ packages, functions }: PackageIndexes): Promise<void>

Parameters:

  • { packages, functions } PackageIndexes

Returns: Promise<void>

Calls:

  • Object.values
  • functions .sort((a, b) => a.name.localeCompare(b.name)) .flatMap
  • arr.push
  • functions .filter(i => i.package === name) .map(f => f.name) .sort() .map
  • imports.push
  • fs.writeFile
  • join (from node:path)
  • imports.join
  • fs.rm

Internal Comments:

// don't include integration components
// temporary file for export-size (x2)

Code
export async function updateImport({ packages, functions }: PackageIndexes) {
  for (const { name, dir, manualImport } of Object.values(packages)) {
    if (manualImport)
      continue

    let imports: string[]
    if (name === 'components') {
      imports = functions
        .sort((a, b) => a.name.localeCompare(b.name))
        .flatMap((fn) => {
          const arr: string[] = []

          // don't include integration components
          if (fn.package === 'integrations')
            return arr

          if (fn.component)
            arr.push(`export * from '../${fn.package}/${fn.name}/component'`)
          if (fn.directive)
            arr.push(`export * from '../${fn.package}/${fn.name}/directive'`)
          return arr
        })
    }
    else {
      imports = functions
        .filter(i => i.package === name)
        .map(f => f.name)
        .sort()
        .map(name => `export * from './${name}'`)
    }

    if (name === 'core') {
      imports.push(
        'export * from \'./types\'',
        'export * from \'@vueuse/shared\'',
        'export * from \'./ssr-handlers\'',
      )
    }

    if (name === 'nuxt') {
      imports.push(
        'export * from \'@vueuse/core\'',
      )
    }

    await fs.writeFile(join(dir, 'index.ts'), `${imports.join('\n')}\n`)

    // temporary file for export-size
    await fs.rm(join(dir, 'index.mjs'), { force: true })
  }
}

uniq(a: T): any[]

Parameters:

  • a T

Returns: any[]

Calls:

  • Array.from
Code
export function uniq<T extends any[]>(a: T) {
  return Array.from(new Set(a))
}

stringifyFunctions(functions: VueUseFunction[], title: boolean): string

Parameters:

  • functions VueUseFunction[]
  • title boolean

Returns: string

Calls:

  • getCategories (from ../packages/metadata/utils)
  • category.startsWith
  • functions .filter(i => i.category === category) .sort
  • a.name.localeCompare
Code
export function stringifyFunctions(functions: VueUseFunction[], title = true) {
  let list = ''

  const categories = getCategories(functions)

  for (const category of categories) {
    if (category.startsWith('_'))
      continue

    if (title)
      list += `### ${category}\n`

    const categoryFunctions = functions
      .filter(i => i.category === category)
      .sort((a, b) => a.name.localeCompare(b.name))

    for (const { name, docs, description, deprecated } of categoryFunctions) {
      if (deprecated)
        continue

      const desc = description ? ` — ${description}` : ''
      list += `- [\`${name}\`](${docs})${desc}\n`
    }
    list += '\n'
  }
  return list
}

replacer(code: string, value: string, key: string, insert: 'head' | 'tail' | 'none'): string

Parameters:

  • code string
  • value string
  • key string
  • insert 'head' | 'tail' | 'none'

Returns: string

Calls:

  • value.trim
  • regex.test
  • code.replace
Code
export function replacer(code: string, value: string, key: string, insert: 'head' | 'tail' | 'none' = 'none') {
  const START = `<!--${key}_STARTS-->`
  const END = `<!--${key}_ENDS-->`
  const regex = new RegExp(`${START}[\\s\\S]*?${END}`, 'im')

  const target = value ? `${START}\n\n${value.trim()}\n\n${END}` : `${START}${END}`

  if (!regex.test(code)) {
    if (insert === 'none')
      return code
    else if (insert === 'head')
      return `${target}\n\n${code}`
    else
      return `${code}\n\n${target}`
  }

  return code.replace(regex, target)
}

updatePackageREADME({ packages, functions }: PackageIndexes): Promise<void>

Parameters:

  • { packages, functions } PackageIndexes

Returns: Promise<void>

Calls:

  • Object.values
  • join (from node:path)
  • existsSync (from node:fs)
  • stringifyFunctions
  • functions.filter
  • fs.readFile
  • replacer(readme, functionMD, 'FUNCTIONS_LIST').trim().replace
  • fs.writeFile
Code
export async function updatePackageREADME({ packages, functions }: PackageIndexes) {
  for (const { name, dir } of Object.values(packages)) {
    const readmePath = join(dir, 'README.md')

    if (!existsSync(readmePath))
      continue

    const functionMD = stringifyFunctions(functions.filter(i => i.package === name), false)
    let readme = await fs.readFile(readmePath, 'utf-8')
    readme = replacer(readme, functionMD, 'FUNCTIONS_LIST').trim().replace(/\r\n/g, '\n')

    await fs.writeFile(readmePath, `${readme}\n`, 'utf-8')
  }
}

updateIndexREADME({ packages, functions }: PackageIndexes): Promise<void>

Parameters:

  • { packages, functions } PackageIndexes

Returns: Promise<void>

Calls:

  • fs.readFile
  • functions.filter
  • readme.replace( /img\.shields\.io\/badge\/-(.+?)%20functions/,img.shields.io/badge/-${functionsCount}%20functions, ).trim().replace
  • fs.writeFile
Code
export async function updateIndexREADME({ packages, functions }: PackageIndexes) {
  let readme = await fs.readFile('README.md', 'utf-8')

  const functionsCount = functions.filter(i => !i.internal).length

  readme = readme.replace(
    /img\.shields\.io\/badge\/-(.+?)%20functions/,
    `img.shields.io/badge/-${functionsCount}%20functions`,
  ).trim().replace(/\r\n/g, '\n')

  await fs.writeFile('README.md', `${readme}\n`, 'utf-8')
}

updateFunctionsMD({ packages, functions }: PackageIndexes): Promise<void>

Parameters:

  • { packages, functions } PackageIndexes

Returns: Promise<void>

Calls:

  • fs.readFile
  • Object.values(packages) .filter(i => i.addon && !i.deprecated) .map(({ docs, name, display, description }) => { return## ${display} - `@vueuse/${name}`\n\n${description?.trim()}\n\n${ stringifyFunctions(functions.filter(i => i.package === name), false)}.trim() }) .join
  • replacer(mdAddons, addons, 'ADDONS_LIST').replace
  • fs.writeFile
Code
export async function updateFunctionsMD({ packages, functions }: PackageIndexes) {
  let mdAddons = await fs.readFile('packages/add-ons.md', 'utf-8')

  const addons = Object.values(packages)
    .filter(i => i.addon && !i.deprecated)
    .map(({ docs, name, display, description }) => {
      return `## ${display} - [\`@vueuse/${name}\`](${docs})\n\n${description?.trim()}\n\n${
        stringifyFunctions(functions.filter(i => i.package === name), false)}`.trim()
    })
    .join('\n\n')

  mdAddons = replacer(mdAddons, addons, 'ADDONS_LIST').replace(/\r\n/g, '\n')

  await fs.writeFile('packages/add-ons.md', mdAddons, 'utf-8')
}

updateFunctionREADME(indexes: PackageIndexes): Promise<void>

Parameters:

  • indexes PackageIndexes

Returns: Promise<void>

Calls:

  • existsSync (from node:fs)
  • console.warn
  • fs.readFile
  • matter (from gray-matter)
  • yaml.stringify
  • `---\n${yamlData}---\n\n${content.trim()}.trim().replace`
  • fs.writeFile
Code
export async function updateFunctionREADME(indexes: PackageIndexes) {
  const hasTypes = existsSync(DIR_TYPES)

  if (!hasTypes)
    console.warn('No types dist found, run `npm run build:types` first.')

  for (const fn of indexes.functions) {
    const mdPath = `packages/${fn.package}/${fn.name}/index.md`
    if (!existsSync(mdPath))
      continue

    let readme = await fs.readFile(mdPath, 'utf-8')

    const { content, data = {} } = matter(readme)
    const yamlData = yaml.stringify(data, {
      singleQuote: true,
    })

    data.category = fn.category || 'Unknown'

    readme = `---\n${yamlData}---\n\n${content.trim()}`.trim().replace(/\r\n/g, '\n')

    await fs.writeFile(mdPath, `${readme}\n`, 'utf-8')
  }
}

updateCountBadge(indexes: PackageIndexes): Promise<void>

Parameters:

  • indexes PackageIndexes

Returns: Promise<void>

Calls:

  • indexes.functions.filter
  • $fetch (from ofetch)
  • fs.writeFile
  • join (from node:path)
Code
export async function updateCountBadge(indexes: PackageIndexes) {
  const functionsCount = indexes.functions.filter(i => !i.internal).length
  const url = `https://img.shields.io/badge/-${functionsCount}%20functions-13708a`
  const data = await $fetch(url, { responseType: 'text' })
  await fs.writeFile(join(DIR_ROOT, 'packages/public/badge-function-count.svg'), data, 'utf-8')
}

updatePackageJSON(indexes: PackageIndexes): Promise<void>

Parameters:

  • indexes PackageIndexes

Returns: Promise<void>

Calls:

  • JSON.parse
  • fs.readFile
  • join (from node:path)
  • indexes.functions .filter(i => i.package === name) .forEach
  • fs.writeFile
  • JSON.stringify
Code
export async function updatePackageJSON(indexes: PackageIndexes) {
  const { version } = JSON.parse(await fs.readFile('package.json', { encoding: 'utf8' }))

  for (const { name, description, author, submodules, iife, manualEntryPoints } of packages) {
    const packageDir = join(DIR_SRC, name)
    const packageJSONPath = join(packageDir, 'package.json')
    const packageJSON = JSON.parse(await fs.readFile(packageJSONPath, { encoding: 'utf8' }))

    packageJSON.version = version
    packageJSON.description = description || packageJSON.description
    packageJSON.author = author || 'Anthony Fu <https://github.com/antfu>'
    packageJSON.bugs = {
      url: 'https://github.com/vueuse/vueuse/issues',
    }
    packageJSON.type = 'module'
    packageJSON.homepage = name === 'core'
      ? 'https://github.com/vueuse/vueuse#readme'
      : `https://github.com/vueuse/vueuse/tree/main/packages/${name}#readme`
    packageJSON.repository = {
      type: 'git',
      url: 'git+https://github.com/vueuse/vueuse.git',
      directory: `packages/${name}`,
    }
    packageJSON.files = [
      'dist',
    ]

    if (!manualEntryPoints) {
      packageJSON.main = './dist/index.js'
      packageJSON.types = './dist/index.d.ts'
      packageJSON.module = './dist/index.js'
      if (iife !== false) {
        packageJSON.unpkg = './dist/index.iife.min.js'
        packageJSON.jsdelivr = './dist/index.iife.min.js'
      }

      packageJSON.exports = {
        '.': './dist/index.js',
        ...packageJSON.exports,
        './*': './dist/*',
      }

      if (submodules) {
        indexes.functions
          .filter(i => i.package === name)
          .forEach((i) => {
            packageJSON.exports[`./${i.name}`] = `./dist/${i.name}.js`
            if (i.component) {
              packageJSON.exports[`./${i.name}/component`] = `./dist/${i.name}/component.js`
            }
          })
      }
    }

    await fs.writeFile(packageJSONPath, `${JSON.stringify(packageJSON, null, 2)}\n`)
  }
}

updateContributors(): Promise<void>

Returns: Promise<void>

Calls:

  • fetchContributors
  • fs.writeFile
  • join (from node:path)
  • JSON.stringify
Code
export async function updateContributors() {
  const collaborators = await fetchContributors()
  await fs.writeFile(join(DIR_SRC, './contributors.json'), `${JSON.stringify(collaborators, null, 2)}\n`, 'utf8')
}

fetchContributors(page: number): Promise<string[]>

Parameters:

  • page number

Returns: Promise<string[]>

Calls:

  • $fetch (from ofetch)
  • collaborators.push
  • data.map
  • fetchContributors
  • Array.from
  • collaborators.filter
  • ['renovate[bot]', 'dependabot[bot]', 'renovate-bot'].includes

Internal Comments:

// contributors that contribute to repos other than `vueuse/vueuse`, required for contributor avatar to work (x2)

Code
async function fetchContributors(page = 1) {
  // contributors that contribute to repos other than `vueuse/vueuse`, required for contributor avatar to work
  const additional = ['egoist', 'Tahul', 'BobbieGoede']

  const collaborators: string[] = []
  const data = await $fetch<{ login: string }[]>(`https://api.github.com/repos/vueuse/vueuse/contributors?per_page=100&page=${page}`, {
    method: 'get',
    headers: {
      'content-type': 'application/json',
    },
  }) || []
  collaborators.push(...data.map(i => i.login))
  if (data.length === 100)
    collaborators.push(...(await fetchContributors(page + 1)))

  return Array.from(new Set([
    ...collaborators.filter(collaborator => !['renovate[bot]', 'dependabot[bot]', 'renovate-bot'].includes(collaborator)),
    ...additional,
  ]))
}

Generated by Syntax Scribe