From d12255d1c117500ec2a6afc08736d14245b02978 Mon Sep 17 00:00:00 2001 From: khai96_ Date: Tue, 1 Oct 2024 19:01:09 +0700 Subject: [PATCH] feat!: bundle template files as 1 json file This should allow the pnpm build script to stop copying the template files from this library to pnpm's `dist` assuming the bundle script used by pnpm can bundle JSON. BREAKING CHANGE: `getCompletionScript` no longer returns a `Promise` --- .gitignore | 1 + examples/tabtab-test-complete/index.js | 2 +- lib/filename.js | 18 ++++++------------ lib/index.js | 6 +++--- lib/installer.js | 21 ++++++--------------- lib/templates/bundle.js | 19 +++++++++++++++++++ lib/templates/index.js | 13 +++++++++++++ package.json | 3 ++- test/getCompletionScript.js | 4 ++-- tsconfig.common.json | 1 + 10 files changed, 54 insertions(+), 34 deletions(-) create mode 100755 lib/templates/bundle.js create mode 100644 lib/templates/index.js diff --git a/.gitignore b/.gitignore index c8394bb..421cba0 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ coverage/ tabtab/ test/tabtab.log /types +/lib/templates/data.json diff --git a/examples/tabtab-test-complete/index.js b/examples/tabtab-test-complete/index.js index 9fe5953..5f3278e 100644 --- a/examples/tabtab-test-complete/index.js +++ b/examples/tabtab-test-complete/index.js @@ -82,7 +82,7 @@ const init = async () => { console.error('shell argument is required'); return; } - const completion = await tabtab.getCompletionScript({ + const completion = tabtab.getCompletionScript({ name: 'tabtab-test', completer: 'tabtab-test', shell, diff --git a/lib/filename.js b/lib/filename.js index 30bee16..74c33c9 100644 --- a/lib/filename.js +++ b/lib/filename.js @@ -3,14 +3,14 @@ const { COMPLETION_FILE_EXT } = require('./constants'); /** * Get a template file name for the SHELL provided. * @param {import('./constants').SupportedShell} shell - * @returns {String} + * @returns {typeof COMPLETION_FILE_EXT[import('./constants').SupportedShell]} */ -const templateFileName = shell => { +const completionFileExt = shell => { const ext = COMPLETION_FILE_EXT[shell]; if (!ext) { throw new Error(`Unsupported shell: ${shell}`); } - return `completion.${ext}`; + return ext; }; /** @@ -20,10 +20,7 @@ const templateFileName = shell => { * @returns {String} */ const completionFileName = (name, shell) => { - const ext = COMPLETION_FILE_EXT[shell]; - if (!ext) { - throw new Error(`Unsupported shell: ${shell}`); - } + const ext = completionFileExt(shell); return `${name}.${ext}`; }; @@ -33,15 +30,12 @@ const completionFileName = (name, shell) => { * @returns {String} */ const tabtabFileName = shell => { - const ext = COMPLETION_FILE_EXT[shell]; - if (!ext) { - throw new Error(`Unsupported shell: ${shell}`); - } + const ext = completionFileExt(shell); return `__tabtab.${ext}`; }; module.exports = { - templateFileName, + completionFileExt, completionFileName, tabtabFileName, }; diff --git a/lib/index.js b/lib/index.js index 98ab169..aa0049f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -53,13 +53,13 @@ const getShellFromEnv = env => { * @param {String} options.name - The package configured for completion * @param {String} options.completer - The program the will act as the completer for the `name` program * @param {SupportedShell} options.shell - * @returns {Promise.} + * @returns {String} */ -const getCompletionScript = async ({ name, completer, shell }) => { +const getCompletionScript = ({ name, completer, shell }) => { if (!name) throw new TypeError('options.name is required'); if (!completer) throw new TypeError('options.completer is required'); if (!shell) throw new TypeError('options.shell is required'); - const completionScriptContent = await installer.getCompletionScript({ name, completer, shell }); + const completionScriptContent = installer.getCompletionScript({ name, completer, shell }); return completionScriptContent } diff --git a/lib/installer.js b/lib/installer.js index c356c94..8990288 100644 --- a/lib/installer.js +++ b/lib/installer.js @@ -3,7 +3,8 @@ const path = require('path'); const untildify = require('untildify'); const { promisify } = require('util'); const { tabtabDebug, exists } = require('./utils'); -const { SUPPORTED_SHELLS } = require('./constants') +const { SUPPORTED_SHELLS } = require('./constants'); +const { getTemplate } = require('./templates'); const debug = tabtabDebug('tabtab:installer'); @@ -18,7 +19,6 @@ const { } = require('./constants'); const { - templateFileName, completionFileName, tabtabFileName, } = require('./filename'); @@ -27,14 +27,6 @@ const { * @typedef {import('./constants').SupportedShell} SupportedShell */ -/** - * Helper to return the correct script template based on the SHELL provided - * - * @param {SupportedShell} shell - Shell to base the check on, defaults to system shell. - * @returns {String} The template script content, defaults to Bash for shell we don't know yet - */ -const scriptFromShell = shell => path.join(__dirname, 'templates', templateFileName(shell)); - /** * Helper to return the expected location for SHELL config file, based on the * provided shell value. @@ -245,11 +237,10 @@ const writeToTabtabScript = async ({ name, shell }) => { * @param {String} options.name - The package configured for completion * @param {String} options.completer - The program the will act as the completer for the `name` program * @param {SupportedShell} options.shell - * @returns {Promise.} + * @returns {String} */ -const getCompletionScript = async ({ name, completer, shell }) => { - const templatePath = scriptFromShell(shell); - const templateContent = await readFile(templatePath, 'utf8'); +const getCompletionScript = ({ name, completer, shell }) => { + const templateContent = getTemplate(shell); const scriptContent = templateContent .replaceAll('{pkgname}', name) .replaceAll('{completer}', completer) @@ -274,7 +265,7 @@ const writeToCompletionScript = async ({ name, completer, shell }) => { ); try { - const filecontent = await getCompletionScript({ name, completer, shell }) + const filecontent = getCompletionScript({ name, completer, shell }) debug('Writing completion script to', filename); await mkdir(path.dirname(filename), { recursive: true }); await writeFile(filename, filecontent); diff --git a/lib/templates/bundle.js b/lib/templates/bundle.js new file mode 100755 index 0000000..7201f35 --- /dev/null +++ b/lib/templates/bundle.js @@ -0,0 +1,19 @@ +#! /usr/bin/env node +const fs = require('fs'); +const path = require('path'); + +const templateFiles = fs.readdirSync(__dirname).filter(name => name.startsWith('completion.')); + +/** @type {Record.} */ +const jsonData = {} + +for (const templateFileName of templateFiles) { + const templateFilePath = path.join(__dirname, templateFileName); + const templateContent = fs.readFileSync(templateFilePath, 'utf-8'); + const ext = templateFileName.replace('completion.', ''); + jsonData[ext] = templateContent; +} + +const jsonFilePath = path.join(__dirname, 'data.json'); +const jsonText = JSON.stringify(jsonData); +fs.writeFileSync(jsonFilePath, jsonText); diff --git a/lib/templates/index.js b/lib/templates/index.js new file mode 100644 index 0000000..4065193 --- /dev/null +++ b/lib/templates/index.js @@ -0,0 +1,13 @@ +const { completionFileExt } = require('../filename'); +const data = require('./data.json'); + +/** + * + * @param {import('../constants').SupportedShell} shell + * @returns {String} + */ +const getTemplate = shell => data[completionFileExt(shell)]; + +module.exports = { + getTemplate, +}; diff --git a/package.json b/package.json index b3fd89d..19d5160 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "scripts": { "test": "c8 mocha --timeout 5000", "typecheck": "pnpm run build && tsc -p test --noEmit", - "build": "tsc -p lib", + "bundle-templates": "node lib/templates/bundle.js", + "build": "pnpm run bundle-templates && tsc -p lib", "prepublishOnly": "pnpm run build", "mocha": "mocha --timeout 5000", "coverage": "c8 report --reporter=text-lcov | coveralls", diff --git a/test/getCompletionScript.js b/test/getCompletionScript.js index 2691410..67b6d54 100644 --- a/test/getCompletionScript.js +++ b/test/getCompletionScript.js @@ -5,8 +5,8 @@ const { COMPLETION_FILE_EXT } = require('../lib/constants'); describe('getCompletionScript gets the right completion script for', () => { for (const shell of SUPPORTED_SHELLS) { - it(shell, async () => { - const received = await getCompletionScript({ + it(shell, () => { + const received = getCompletionScript({ name: 'foo', completer: 'foo-complete', shell diff --git a/tsconfig.common.json b/tsconfig.common.json index 0505ee4..3a3193c 100644 --- a/tsconfig.common.json +++ b/tsconfig.common.json @@ -5,5 +5,6 @@ "module": "Node16", "strictNullChecks": true, "target": "ES2022", + "resolveJsonModule": true, } }