New File Template
Effortlessly create new files or folders from custom templates with this versatile tool. 🎉 It supports multiple template folders, user input prompts, JavaScript expressions, dynamic file inclusion/exclusion, and various case conversion methods to streamline your template generation process. 🚀
Features
- Effortlessly create custom template files and folders. 📁
- Support for multiple custom template folders and config paths.
- Generate templates multiple times with the same or new contexts.
- Generate multiple output files from a single template file.
- Prompt user input on demand or on load. 📝
- Example:
${input.componentName}
prompts the user for the componentName
.
- Configure user input prompts based on conditions. For more details, refer to the template configuration section.
- Simplify logic within templates using JavaScript expressions.
- Example:
${new Date()}
, ${process.env.HOME}
, or ${Math.random()}
.
- Set predefined variables and user input values for seamless template generation.
- Configure user input as plain text, single select, or multiple choice, with validation and transformation capabilities.
- Utilize hook functions for enhanced control. For more details, refer to the Hooks section.
- Utilize hooks to do a find and replace data text manually.
- Add cursors at specific positions by generating the template as a snippet.
- Dynamically include and exclude template files based on user inputs.
- Utilize helper case conversion methods:
- Example 1:
${input.componentName_toPascalCase}
prompts input and converts it to PascalCase.
- Example 2:
${_toPascalCase(componentName, { startWithAlpha: true })}
converts an existing variable value to PascalCase.
- Configure settings to open specific template files after generation.
- Configure custom patterns to identify variables and prompt users.
- Add logs for debugging. 🐛
Preview
This demonstration uses sample React component templates. However, this extension is not limited to React; it is a versatile tool that can create any template to meet various business needs.

Usage
- Create a folder inside
./vscode/Templates
, for example: ./vscode/Templates/MyTemplate
(the folder name will be the template name).
- Create a new file, folder, or subfolder inside the
./vscode/Templates/MyTemplate
folder, for example: ./vscode/Templates/MyTemplate/${input.componentName}/${input.fileName}.ts
.
- Right-click on any file or folder where you want to generate the file from the template and select
New File From Template
.
- You will be prompted to pick a template name and provide the necessary variables such as
${input.componentName}
and ${input.fileName}
.
- Once all inputs are provided, a new file will be generated from the selected template.
Simple File
Interpolation occurs for the entire file content. If an error is encountered, the file content is returned without any interpolation.
To enable partial interpolation, set the new-file-template.settings.interpolateByLine
setting to true
. This will interpolate the content line by line.
If an error occurs, only the problematic line will be returned without interpolation, while the remaining lines will still be interpolated.
Set the new-file-template.settings.disableInterpolationErrorMessage
setting to true
to suppress error messages of interpolation.
- Example:
./vscode/Templates/MyTemplate/package.json
- This will prompt inputs with the pattern
${input.<variable name without spaces>}
{
"displayName": "${input.extensionName}", // this will prompt extensionName from the user
"name": "${extensionName_toKebabCase}", // this will convert the extensionName to kebab case
"description": "${input.description_toSentenceCase}", // this prompts the description and then converts into a sentence case
"version": "${input.version}",
"publisher": "Thinker",
"license": "MIT",
"author": {
"name": "r35007",
"email": "sendmsg2siva@gmail.com"
},
"repository": {
"type": "git",
"url": "https://github.com/R35007/${_toKebabCase(extensionName)}" // can use helper methods to convert any variable values
}
}
Template File
Any file within the templates folder that ends with .template.js
is considered a template module file.
These files are expected to export a function that will be called with a context
object.
When generating the output file, the .template.js
suffix will be removed from the file name. This allows for dynamic script logic to generate a template file.
Ensure that the function returns a template string to generate the template data.
Note: Template contents will not be interpolated for files ending with *.template.js
.
Basic Usage
- File: `./vscode/Templates/MyTemplate/${input.componentName}.tsx.template.js`
- File names ending with `*.template.js` should always expose a method and will be called with a `context` object as an argument.
module.exports = async ({ componentName, _toCamelCase }) => `import styled from 'styled-components';
export interface ${componentName}Props {};
export const ${componentName} = (${_toCamelCase(componentName)}Props: ${componentName}Props) => {
// your component logic goes here 👇
return <Styled${componentName} {...${_toCamelCase(componentName)}Props} />
};
`;
Example Templates
We've added more example templates to this repository to help you get started quickly and efficiently with various use cases. These templates are designed to simplify your workflow and showcase the flexibility of this extension.
For detailed examples, please refer to the following link:
Example Templates
Case Conversions
{
"exampleVariablesFoobar": "@foo1Bar2 3jaz4Qux$",
"caseConverters": {
"_toNumericCase": "1 1 2 3 4",
"_toAlphaCase": "foo Bar jaz Qux",
"_toAlphaNumericCase": "1 foo1Bar2 3jaz4Qux",
"_toSpaceCase": "1 foo1 Bar2 3jaz4 Qux",
"_toTitleCase": "1 Foo1 Bar2 3jaz4 Qux",
"_toCamelCase": "1Foo1Bar23jaz4Qux",
"_toPascalCase": "1Foo1Bar23jaz4Qux",
"_toComponentNameCase": "Foo1Bar23jaz4Qux",
"_toSnakeCase": "1_foo1_bar2_3jaz4_qux",
"_toSnakeUpperCase": "1_FOO1_BAR2_3JAZ4_QUX",
"_toConstantCase": "alias of _toSnakeUpperCase",
"_toSnakeTitleCase": "1_Foo1_Bar2_3jaz4_Qux",
"_toKebabCase": "1-foo1-bar2-3jaz4-qux",
"_toKebabUpperCase": "1-FOO1-BAR2-3JAZ4-QUX",
"_toKebabTitleCase": "1-Foo1-Bar2-3jaz4-Qux",
"_toHeaderCase": "alias of _toKebabTitleCase",
"_toTrainCase": "alias of _toKebabTitleCase",
"_toDotCase": "1.foo1.bar2.3jaz4.qux",
"_toDotUpperCase": "1.FOO1.BAR2.3JAZ4.QUX",
"_toDotTitleCase": "1.Foo1.Bar2.3jaz4.Qux",
"_toSentenceCase": "1 foo1Bar2 3jaz4Qux",
"_toCapitalCase": "1 Foo1Bar2 3jaz4Qux",
"_toStudlyCaps": "1 FoO1BaR2 3JaZ4QuX",
"_toUpperCase": "1 FOO1BAR2 3JAZ4QUX",
"_toLowerCase": "1 foo1bar2 3jaz4qux",
"_toPathCase": "/foo1bar2/3jaz4qux"
},
"_split": "1,foo1Bar2,3jaz4Qux",
"Custom PathCase": "foo/Bar/jaz/Qux"
}
Template Configuration
By default, the extension searches for configuration files named _config.json
, _config.js
, or _config/index.js
within the template folder. Alternatively, you can specify a custom configuration file path using the new-file-template.settings.configPath
setting in the extension.
export type Hooks = {
beforeAll?: (context: Context) => Promise<Context | false | void>; // Executes before generating all template files. return new context
beforeEach?: (context: Context) => Promise<Context | false | void>; // Executes before generating each template file. return new context
processBeforeEach?: ({ data, context }: { data: string; context: Context }) => Promise<{ data: string; context: Context } | false | void>; // Executes before interpolating template data for each file. Return new data string or context
processAfterEach?: ({ data, context }: { data: string; context: Context }) => Promise<{ data: string; context: Context } | false | void>; // Executes after interpolating template data for each file. Return new data string or context
afterEach?: (context: Context) => Promise<Context | false | void>; // Executes after generating each template file. return new context
afterAll?: (context: Context) => Promise<Context | false | void>; // Executes after generating all template files. return new context
};
export type UserConfig = Hooks & {
times: number | ((context: Context) => Promise<false | number | Array<false | Context | ((context: Context) => Promise<Partial<Context>>)>>); // define number of times to generate template multiple times
out: string; // Output directory for generated files.
variables: Record<string, unknown>; // Additional variables for template generation.
input: Record<string, unknown>; // Predefined input values for template generation.
inputConfig: Record<string, InputConfig | ((context: Context) => InputConfig | unknown) | unknown>; // Configuration for user input prompts.
overwriteExistingFile?: 'prompt' | 'never' | 'always' | ((context: Context) => Promise<'prompt' | 'never' | 'always'>); // Behavior for overwriting existing files.
promptTemplateFiles?: boolean | ((context: Context) => Promise<boolean>); // Whether to prompt for template files.
enableSnippetGeneration?: boolean | ((context: Context) => Promise<boolean>); // Whether to enable snippet generation.
interpolateByLine?: boolean | ((context: Context) => Promise<boolean>); // interpolates line by line
disableInterpolation?: boolean | ((context: Context) => Promise<boolean>); // disables interpolation
disableInterpolationErrorMessage?: boolean | ((context: Context) => Promise<boolean>); // disables interpolation error messages
openAfterGeneration?: boolean | string[] | ((context: Context) => Promise<string[]>); // Files to open after generation.
include: string[] | ((context: Context) => Promise<string[]>); // Files to include in the template.
exclude: string[] | ((context: Context) => Promise<string[]>); // Files to exclude from the template.
};
export interface InputConfig {
prePrompt?: boolean | ((context: Context) => boolean); // Whether to prompt before generating the template.
value?: any; // Default value for the input.
title?: string; // Title for the input prompt.
placeHolder?: string; // Placeholder text for the input prompt.
options?: string[] | QuickPickItem[]; // Options for single select or multiple choice inputs.
validateInput?: string | ((value: unknown, context: Context) => string | undefined); // Validation function for the input.
transform?: string | ((value: unknown, context: Context) => unknown); // Transformation function for the input.
canPickMany?: boolean; // Whether multiple options can be selected.
matchOnDescription?: boolean; // Whether to match on description in the input prompt.
matchOnDetail?: boolean; // Whether to match on detail in the input prompt.
ignoreFocusOut?: boolean; // Whether to ignore focus out in the input prompt.
password?: boolean; // Whether the input is a password.
}
Hooks
Hooks are used to execute custom code before or after generating template files. They provide flexibility and control over the template generation process, allowing you to modify data or context as needed.
- beforeAll(context): Executes before generating all template files. Return
false
to skip the template or return a new context
to modify the existing context.
- beforeEach(context): Executes before generating each template file. Return
false
to skip the template file or return a new context
to modify the existing context.
- processBeforeEach({ data, context }): Executes before interpolating template data for each file. Return
false
to skip the template file or return new data
and context
to modify the existing data and context.
- processAfterEach({ data, context }): Executes after interpolating template data for each file. Return
false
to skip the template file or return new data
and context
to modify the existing data and context.
- afterEach(context): Executes after generating each template file. Return
false
to skip the template file or return a new context
to modify the existing context.
- afterAll(context): Executes after generating all template files. Return
false
to skip the template file or return a new context
to modify the existing context.
Extension Configuration Settings
The extension can be configured using the following settings in your settings.json
file:
new-file-template.settings.configPath
: Provide template config path. Set to empty to automatically pick _config{.js|.json}
from the template folder.
new-file-template.settings.templatePaths
: Specify the paths to the custom templates folders.
new-file-template.settings.overwriteExistingFile
: Should overwrite existing file? (prompt
, never
, always
).
new-file-template.settings.promptMultipleTemplates
: If true, prompts a multiple-choice picker to select multiple template folders to generate.
new-file-template.settings.useSeparateInstance
: If new-file-template.settings.promptMultipleTemplates
is true, it uses the same instance to create multiple templates. Set to true to generate each template at a separate instance.
new-file-template.settings.promptTemplateFiles
: If true, prompts a multiple-choice picker to select the template files to generate.
new-file-template.settings.interpolateByLine
: If true, interpolates each line individually. On error, returns the original line without interpolation.
new-file-template.settings.disableInterpolationErrorMessage
: If true, It ignores interpolation error messages
new-file-template.settings.promptVariablePatterns
: Provide list of patterns to recognize and prmpt the user input variables. Defaults to ["\\${input\\.([a-zA-Z0-9_]+)}"]
new-file-template.settings.enableSnippetGeneration
: If true, it enables snippet generation for template files. Snippets help with cursor placement using placeholders like $<number>
.
new-file-template.settings.openAfterGeneration
: If true, opens all generated files. This will always be true
if new-file-template.settings.enableSnippetGeneration
is set to true
.
new-file-template.settings.variables
: Define custom variables for template generation.
new-file-template.settings.input
: Define custom input variables. These variables can be accessed using ${input.<Your variable name>}
or ${<Your variable name>}
.
Sample Settings
Add the following configuration to your settings.json
file:
{
"new-file-template.settings.configPath": "",
"new-file-template.settings.templatePaths": [ "./.vscode/templates" ],
"new-file-template.settings.overwriteExistingFile": "prompt",
"new-file-template.settings.promptMultipleTemplates": false,
"new-file-template.settings.useSeparateInstance": false,
"new-file-template.settings.promptTemplateFiles": false,
"new-file-template.settings.interpolateByLine": false,
"new-file-template.settings.disableInterpolationErrorMessage": false,
"new-file-template.settings.promptVariablePatterns": ["\\${input\\.([a-zA-Z0-9_]+)}"],
"new-file-template.settings.enableSnippetGeneration": false,
"new-file-template.settings.openAfterGeneration": true,
"new-file-template.settings.variables": {
"foobar": "@foo1Bar2 3jaz4Qux$",
"lorem": "Lorem ipsum dolor sit amet consectetur adipisicing elit.",
"user": { "name": "r35007" }
},
"new-file-template.settings.input": {
"fileName": "index",
"ext": {[".tsx", ".ts", ".jsx", ".js", ".json", ".java", ".txt", ".md" ]},
"componentName": {
"prePrompt": true,
"value": "AppComponent",
"placeHolder": "Please provide a component name in PascalCase",
"validateInput": "${value?.trim().length >= 5 ? '' : 'Please enter a minimum of 5 characters'}",
"transform": "${value?.trim().length ? _toPascalCase(value) : ''}"
}
}
}
Extension Context Utils
The context
object contains many utility methods to create a template explicitly. These are the following methods:
export type Case = {
_toNumericCase: (input?: string, options?: { preserve?: string }) => string;
_toAlphaCase: (input?: string, options?: { preserve?: string }) => string;
_toAlphaNumericCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_split: (input?: string, options?: { numeric?: boolean; alpha?: boolean; preserve?: string; startWithAlpha?: boolean }) => string[];
_toSpaceCase: (input?: string, options?: { numeric?: boolean; alpha?: boolean; preserve?: string; startWithAlpha?: boolean }) => string;
_toTitleCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toCamelCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toPascalCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toComponentNameCase: (input?: string) => string;
_toSnakeCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toSnakeUpperCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toConstantCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toSnakeTitleCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toKebabCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toKebabUpperCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toKebabTitleCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toHeaderCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toTrainCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toDotCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toDotUpperCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toDotTitleCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toSentenceCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toCapitalizedWords: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toCapitalCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toStudlyCaps: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toUpperCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toLowerCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
_toPathCase: (input?: string, options?: { preserve?: string; startWithAlpha?: boolean }) => string;
};
export type Utils = typeof Case & {
log: (message: string, newLine?: string, noDate?: boolean) => void;
clearLog: () => void;
setContext: (context?: Context) => void;
promptInput: (inputName: string, inputConfig: InputConfig) => unknown;
readFile: (templateFile: string, context: Partial<Context>) => Promise<string>;
getTemplateFileData: (templateFile: string, context?: Partial<Context>) => Promise<string | false>;
createOutputFile: (data: string, contextOrOutputFile?: Partial<Context> | string) => Promise<void>;
generateTemplateFile: (templateFile: string, contextOrOutputFile?: Partial<Context>) => Promise<void>;
generateTemplateFiles: (templateFiles: string[], context?: Partial<Context>) => Promise<void>;
generateTemplate: (template: string, context?: Partial<Context>) => Promise<void>;
interpolate: (template: string, context: Context, hideError?: boolean, interpolateByLine?: boolean) => string;
showInformationMessage: typeof window.showInformationMessage;
showErrorMessage: typeof window.showErrorMessage;
showWarningMessage: typeof window.showWarningMessage;
Case: typeof Case;
/*
@example
```js
const newFileTemplate = new FileTemplate(fsPath, allTemplates, selectedTemplates, newContext);
newFileTemplate.log(messageString);
newFileTemplate.clearLog();
newFileTemplate.setContext(context);
const input = await newFileTemplate.promptInput('inputName', inputConfig);
const fileData = await newFileTemplate.readFile(templateFile, context);
const templateFileData = await newFileTemplate.getTemplateFileData(templateFile, context);
await newFileTemplate.createOutputFile(data, contextOrOutputFile);
await newFileTemplate.generateTemplateFile(templateFile, contextOrOutputFile);
await newFileTemplate.generateTemplateFiles(templateFiles, context);
await newFileTemplate.generateTemplate(template, context);
const interpolatedData = newFileTemplate.interpolate(template, context, hideError, interpolateByLine);
```
*/
FileTemplate: typeof FileTemplate;
};
``;