Necessary Templates
Necessary Templates is a Visual Studio Code plugin that enables users to create files faster by using templates. It works by selecting a template, writing a name, and then creating a file with the template content. If you have selected text, it will be used as the file name instead of asking the user for input.
Installation
To install Necessary Templates, follow these steps:
- Open Visual Studio Code
- Press
Cmd+Shift+X
(Mac) or Ctrl+Shift+X
(Windows/Linux) to open the Extensions view
- Search for "Necessary Templates"
- Click "Install"
Usage
To use Necessary Templates, follow these steps:
- Open the Command Palette (
Cmd+Shift+P
or Ctrl+Shift+P
)
- Search for "Necessary Templates: Create File"
- Select a template from the list
- Write a name for the file (if you have selected text, it will be used as the file name)
- Press Enter
Alternatively, you can use the keybinding Alt+Cmd+N
(Mac) or Alt+Ctrl+N
(Windows/Linux) to run the command directly.
The templates.js
interface TemplatesConfig {
inputs?(ctx: TemplatesAPIContext): TemplateInputRequest[]
getDirectories?(
ctx: TemplatesAPIContext,
utils: Utils,
): DirectoriesResponse | Promise<DirectoriesResponse>
replaces?: ReplacesRecord
formatName?(name: string, ctx: TemplatesAPIContext): string
formatFileName?(
name: string,
ctx: TemplatesAPIContext,
utils: TemplatesAPIUtils,
): string
formatContent?(
content: string,
ctx: TemplatesAPIContext,
utils: TemplatesAPIUtils,
): string
onApply?(ctx: AfterContext, utils: Utils): void
}
This function allows you to define input prompts for the user when creating a file with a specific template. For example, you could prompt the user to enter a description for a custom hook or to choose a storybook section for a component. The function receives an object with the current template and target directory and should return an array of objects with the input properties.
{
inputs: ({ template, targetDir }) => {
if (template.name === 'Hook') {
return [
{
type: 'text',
name: 'description',
placeholder: 'A hook to ...',
prompt: 'Choose a description for your hook',
},
]
}
if (template.name === 'Component' && targetDir.includes('www/')) {
return [
{
type: 'text',
name: '__storybook_dir__',
placeholder: 'Think like auth, group, user, etc..',
prompt: 'Choose storybook section for this component',
},
]
}
return []
}
}
replaces
object
This object defines the dynamic replacements that should be made in the template content before creating the file. You can define custom replacement functions that receive an object with the current inputs and target directory and return the replacement value. For example, you could replace __description__
in the template content with the value entered by the user in the description
input.
{
replaces: {
__description__: ({ inputs }) => inputs.description,
__verbose_name__: ({ inputs }) =>
capitalize(inputs.selectedText.split('.').pop()),
__procedure_name__: ({ inputs, targetDir }) =>
`${path.basename(path.dirname(targetDir))}.${inputs.selectedText
.split('.')
.pop()}`,
__storybook_dir__: ({ inputs, targetDir }) =>
!targetDir.includes('packages/kit')
? inputs.__storybook_dir__?.trim() || 'UNDEFINED'
: '@sass/ui',
},
}
getDirectories
function
This function allows you to define the list of directories where a specific template can be created. You can define custom logic based on the template and inputs to return an array of objects with the directory label
and path
properties. For example, you could define a list of possible directories for a component template, such as www/components
and acme/kit/components
, and return them based on the user input.
getDirectories: async ({ template, inputs }, { listDir }) => {
if (template.name === 'Component') {
return [
{
label: 'www',
path: 'apps/www/components',
},
{
label: 'acme/kit',
path: 'packages/kit/components',
},
{
label: 'page',
path: 'apps/www/pages',
},
]
}
if (template.name === 'Hook') {
return [
{
label: 'www',
path: 'apps/www/hooks',
},
{
label: 'acme/kit',
path: 'packages/kit/hooks',
},
]
}
if (template.name === 'Query') {
let routers = await listDir(
path.resolve(template.workspacePath, 'apps/api/router/*'),
)
routers = routers
.filter((r) => !r.includes('.'))
.map((r) => path.basename(r))
if (inputs.selectedText.includes('.')) {
const [router] = inputs.selectedText.split('.')
if (routers.includes(router)) {
routers = [router, ...routers.filter((r) => r !== router)]
} else {
routers = [router, ...routers]
}
}
return routers.map((router) => ({
label: router,
path: `apps/api/router/${router}`,
}))
}
if (template.name === 'Schema') {
return 'packages/schemas'
}
}
This function allows you to format the name of the file that will be created based on the user input. You can define custom logic based on the template and inputs to return the formatted name. For example, you could remove the package name prefix from a query name input before using it as the file name.
{
formatName: (rawName, { template }) => {
if (template.name === 'Query' || template.name === 'Mutation') {
// ex.: app.findMany -> findMany
return rawName.split('.').pop()
}
return rawName
},
}
onApply
function
This function allows you to define custom actions that should be performed after a file is created with a specific template. You can define custom logic based on the template and target directory to perform any additional actions, such as updating an index file or running a script. For example, you could update the index.ts
file in a kit directory to export all kit components after creating a new component file.
{
onApply: async ({ template, targetDir }, { listDir }) => {
if (template.name === 'Component' && targetDir.includes('packages/kit')) {
const kitDir = path.join(
template.workspacePath,
'packages',
'kit',
'components',
)
const kitFiles = await listDir(path.join(kitDir, '*'))
const kitComponentDirectories = kitFiles
.filter((f) => !f.includes('.'))
.map((f) => path.basename(f))
const content = `
// export all material ui components
export * from './material'
// export acme kit components
${kitComponentDirectories.map((name) => `export * from './${name}'`).join('\n')}
`.trim()
await fs.promises.writeFile(
path.resolve(kitDir, 'index.ts'),
content,
'utf-8',
)
}
},
}
Credits
Necessary Templates was created by Vinicius Pacheco vin175pacheco@gmail.com and is licensed under the MIT license.