@vvlad1973/filler
v2.1.2
Published
TypeScript library for multilevel template string resolution with support for {{}} format and legacy @<id>:[@<element>...] format
Downloads
318
Maintainers
Readme
@vvlad1973/filler
TypeScript library for multilevel template string resolution with support for {{}} format and legacy @stringId:[@param...] format
Features
- Multilevel template resolution with {{placeholder}} syntax
- Environment variable substitution with shell-style syntax:
${VAR:-default},${VAR:?error},${VAR:+alt} - Static method
Filler.resolve()for quick one-off resolution without creating an instance - Legacy format support: text@stringId:[@param1@param2...]
- Support for async values and Promise resolution
- Context-based value resolution with nested paths (including array notation like
items[0]) - Parameter management (add, delete, clear)
- Integration with vvlad1973-strings-resources for multilingual support
- Object completion with path specification and deep mode
- Full TypeScript support with type safety
Installation
npm install @vvlad1973/fillerDocumentation
- Complete Usage Guide (USAGE_GUIDE.md) - Comprehensive guide with detailed examples
Quick Start
Static Method
For simple template resolution without creating an instance:
import { Filler } from '@vvlad1973/filler';
// Template format: {{placeholder}}
const result = await Filler.resolve({
text: 'Hello {{user.name}}, your ID is {{user.id}}',
context: { user: { name: 'Alice', id: 123 } }
});
// Result: "Hello Alice, your ID is 123"
// Legacy format: @stringId:[@param...]
const result2 = await Filler.resolve({
text: '@GREETING:[@user.name]',
strings: { GREETING: 'Hello, %s!' },
context: { user: { name: 'Bob' } }
});
// Result: "Hello, Bob!"
// Combine both formats
const result3 = await Filler.resolve({
text: 'User {{user.id}}: @MESSAGE:[@user.name]',
strings: { MESSAGE: 'Welcome, %s!' },
context: { user: { name: 'Charlie', id: 456 } }
});
// Result: "User 456: Welcome, Charlie!"Instance
For advanced features and reusable configuration:
import { Filler } from '@vvlad1973/filler';
const filler = new Filler({
params: {
userName: 'John',
asyncValue: async () => 'async result',
},
strings: {
GREETING: 'Hello, %s!',
WELCOME: 'Welcome to the app',
},
});
filler.context = {
user: {
name: 'Alice',
id: 456,
},
};
// Template resolution
const result1 = await filler.completeText('Hello {{user.name}}!');
// Result: "Hello Alice!"
// Legacy format
const result2 = await filler.completeText('@GREETING:[@userName]');
// Result: "Hello, John!"
// Nested resolution
const result3 = await filler.completeText('User: {{user.name}}, ID: {{user.id}}');
// Result: "User: Alice, ID: 456"Template Format {{}}
The library supports {{placeholder}} format for template resolution:
const filler = new Filler();
filler.context = {
user: {
name: 'Bob',
profile: {
age: 30,
},
},
};
// Simple path
await filler.completeText('{{user.name}}'); // "Bob"
// Nested path
await filler.completeText('{{user.profile.age}}'); // "30"
// Multiple placeholders
await filler.completeText('Name: {{user.name}}, Age: {{user.profile.age}}');
// "Name: Bob, Age: 30"Legacy Format
The library supports legacy format: text@stringId:[@param1@param2...]
const filler = new Filler({
strings: {
GREETING: 'Hello, %s!',
USER_INFO: 'User: %s (ID: %d)',
},
});
filler.context = {
user: { name: 'Alice', id: 123 },
};
// String with parameter from context
await filler.completeText('@GREETING:[@user.name]');
// "Hello, Alice!"
// Multiple parameters
await filler.completeText('@USER_INFO:[@[email protected]]');
// "User: Alice (ID: 123)"
// Prefix + string
await filler.completeText('Welcome! @GREETING:[@user.name]');
// "Welcome! Hello, Alice!"Async Values and Promises
The library properly handles async values and Promises:
const filler = new Filler({
params: {
asyncData: async () => {
const data = await fetchData();
return data.value;
},
},
});
filler.context = {
user: {
data: Promise.resolve({ name: 'Charlie' }),
},
};
// Async parameter
await filler.completeText('@GREETING:[@asyncData]');
// Promise in context
await filler.completeText('User: {{user.data.name}}');Environment Variables
The library supports shell-style environment variable substitution with the ${VAR} format:
// Set environment variables
process.env.APP_NAME = 'MyApp';
process.env.PORT = '3000';
const filler = new Filler();
// Simple substitution: ${VAR}
await filler.completeText('App: ${APP_NAME}');
// "App: MyApp"
// With default value: ${VAR:-default}
await filler.completeText('Port: ${PORT:-8080}');
// "Port: 3000"
await filler.completeText('Host: ${HOST:-localhost}');
// "Host: localhost" (uses default if HOST not set)
// Required variable: ${VAR:?error_message}
await filler.completeText('${API_KEY:?API_KEY is required}');
// Throws error if API_KEY not set
// Alternative value if set: ${VAR:+alternative}
await filler.completeText('${DEBUG:+debug mode enabled}');
// Returns "debug mode enabled" if DEBUG is set, empty string otherwise
// Combine with templates
filler.context = { user: { name: 'Alice' } };
await filler.completeText('${APP_NAME} - User: {{user.name}}');
// "MyApp - User: Alice"Supported formats:
${VAR}- Simple substitution (empty string if not set)${VAR:-default}- Use default value if variable not set${VAR:?error_msg}- Required variable (throws error if not set)${VAR:+alt_value}- Use alternative value if variable is set
Parameter Management
const filler = new Filler();
// Add parameter
filler.addParam('newParam', 'value');
filler.addParam('asyncParam', async () => 'async value');
filler.addParam('functionParam', () => 'function value');
// Delete parameter
filler.deleteParam('newParam');
// Clear all parameters
filler.clearParams();Object Completion
For arbitrary objects with template strings:
const data = {
title: '{{user.name}}',
items: [
{ name: '{{item1}}', desc: 'Description' },
{ name: '{{item2}}', desc: 'Another' }
],
meta: {
author: '{{user.name}}',
date: '2024-01-01'
}
};
// Process specific paths
const result = await filler.completeObject(data, {
paths: ['title', 'items[].name', 'meta.author']
});
// title and items[].name are resolved, desc and date are unchanged
// Process all string fields recursively
const result2 = await filler.completeObject(data, { deep: true });
// All string fields with templates are resolved
// For Telegram bot keyboards
const markup = {
inline_keyboard: [
[
{ text: 'User: {{user.name}}', callback_data: 'user_{{user.id}}' },
],
],
};
const completed = await filler.completeObject(markup, { deep: true });
// { inline_keyboard: [[{ text: 'User: Alice', callback_data: 'user_123' }]] }Strings from JSON
const jsonStrings = [
{ _id: 'KEY1', Text: 'Value 1' },
{ _id: 'KEY2', Text: 'Value 2' },
];
const filler = new Filler({
strings: jsonStrings,
stringsFromJson: true,
jsonOptions: {
jsonKeyId: '_id',
jsonValue: 'Text',
},
});
await filler.completeText('@KEY1'); // "Value 1"API
Constructor Options
interface FillerOptions {
params?: FillerParams;
strings?: StringsResources | Strings;
stringsFromJson?: boolean;
jsonOptions?: StringsFromJsonOptions;
logger?: ExternalLogger;
logLevel?: string;
}Static Methods
Filler.resolve(options: StaticResolveOptions): Promise<string>
Static method for simple template resolution without creating an instance.
Options:
text- Text to resolve (required)context- Context object for template resolutionstrings- String resources dictionaryparams- Parameters mapmaxDepth- Maximum depth for recursive resolution (default: 10)
Example:
const result = await Filler.resolve({
text: 'Hello {{user.name}}, your ID is {{user.id}}',
context: { user: { name: 'Alice', id: 123 } }
});
// Result: "Hello Alice, your ID is 123"Limitations compared to instance methods:
- Does NOT support loading strings from JSON (pass already loaded strings instead)
- Does NOT support custom logger configuration (uses silent mode)
- Does NOT support
completeArray()orcompleteReplyMarkup()methods - Does NOT support dynamic parameter management (
addParam,deleteParam,clearParams)
Supports:
- Both
{{placeholder}}templates and legacy format@stringId:[@param1@param2...] - Random value patterns (
/pattern/) - Async/Promise values
- Nested paths and array notation
- Multilevel recursive resolution
Use this method for one-off text resolution when creating an instance is not practical.
Instance Methods
completeText(text: string, options?: CompleteTextOptions): Promise<string>
Completes text by resolving all templates and legacy formats.
completeArray(array: unknown[]): Promise<unknown[]>
Completes text values in an array (recursive for nested arrays and objects).
completeObject<T>(obj: T, options?: CompleteObjectOptions): Promise<T>
Completes text values in an arbitrary object by resolving specified paths.
Options:
paths- Array of paths to fields that should be resolved (e.g.,['title', 'items[].name', 'user.profile.bio'])deep- If true, recursively processes all string fields in the object
Examples:
// Process specific paths
const result = await filler.completeObject(data, {
paths: ['title', 'items[].name']
});
// Process all string fields recursively
const result2 = await filler.completeObject(data, { deep: true });
// Default: process only top-level string fields
const result3 = await filler.completeObject(data);completeReplyMarkup(markup: TelegramReplyMarkup): Promise<TelegramReplyMarkup> (deprecated)
Completes text values in Telegram reply markup. Use completeObject() with deep: true instead.
addParam(key: string, value: unknown): void
Adds a parameter to the parameters map.
deleteParam(key: string): void
Deletes a parameter from the parameters map.
clearParams(): void
Clears all parameters.
License
MIT with Commercial Use
Author
Vladislav Vnukovskiy [email protected]
