@jakubmazanec/template 1.0.0 → 1.0.1-265acad

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ <!-- header -->
1
2
  <div align="center">
2
3
 
3
4
  # @jakubmazanec/template
@@ -5,6 +6,7 @@
5
6
  TypeScript-first library for working with templates using EJS and Zod.
6
7
 
7
8
  </div>
9
+ <!-- header -->
8
10
 
9
11
  ## Installation
10
12
 
package/dist/Template.js CHANGED
@@ -25,7 +25,12 @@ import { templateAttributesSchema } from './types.js';
25
25
  * @typeParam A A Zod schema type used to define the custom template attributes type.
26
26
  * @typeParam D A Zod schema type used to define the template datatype.
27
27
  */ export class Template {
28
- constructor({ content , attributes , attributesSchema , dataSchema }){
28
+ /** Template content. Templates are written in [EJS](https://ejs.co/). */ content;
29
+ /** Template attributes. These control how the template is rendered. Some attributes can be written in [EJS](https://ejs.co/) and are rendered before the template content is rendered. It is expected that attribute `if` renders to a string that can be parsed as YAML value; if that value is `false`, the rendering is cancelled. Attribute `to` is also rendered and it represents the path of file the resulting template render is supposed to be written into (by the user). Attribute `variables` is an object that is merged with the data object before rendering. If attribute `variables` is an array of objects, that leads to multiple renders, each with different variables object merged with the data. Each variable that is a string is also rendered. */ attributes;
30
+ /** Template function. */ fn;
31
+ /** Zod schema for custom template attributes. */ attributesSchema;
32
+ /** Zod schema for template data. */ dataSchema;
33
+ constructor({ content, attributes, attributesSchema, dataSchema }){
29
34
  this.content = content;
30
35
  this.attributes = attributes;
31
36
  this.fn = ejs.compile(this.content);
@@ -45,8 +50,9 @@ import { templateAttributesSchema } from './types.js';
45
50
  *
46
51
  * @param templateFilePath Path to the template file.
47
52
  */ static async read(templateFilePath, options) {
48
- let { data: attributes , content } = matter(await fs.readFile(templateFilePath, 'utf8'));
49
- let attributesSchema = (options === null || options === void 0 ? void 0 : options.attributesSchema) ? templateAttributesSchema.merge(options.attributesSchema) : templateAttributesSchema;
53
+ var _options, _options1, _options2;
54
+ let { data: attributes, content } = matter(await fs.readFile(templateFilePath, 'utf8'));
55
+ let attributesSchema = ((_options = options) === null || _options === void 0 ? void 0 : _options.attributesSchema) ? templateAttributesSchema.merge(options.attributesSchema) : templateAttributesSchema;
50
56
  let attributesParseResult = attributesSchema.safeParse(attributes);
51
57
  if (!attributesParseResult.success) {
52
58
  throw new TemplateError('INVALID_ATTRIBUTES', {
@@ -60,8 +66,8 @@ import { templateAttributesSchema } from './types.js';
60
66
  return new this({
61
67
  attributes,
62
68
  content,
63
- attributesSchema: options === null || options === void 0 ? void 0 : options.attributesSchema,
64
- dataSchema: options === null || options === void 0 ? void 0 : options.dataSchema
69
+ attributesSchema: (_options1 = options) === null || _options1 === void 0 ? void 0 : _options1.attributesSchema,
70
+ dataSchema: (_options2 = options) === null || _options2 === void 0 ? void 0 : _options2.dataSchema
65
71
  });
66
72
  }
67
73
  /**
@@ -72,13 +78,14 @@ import { templateAttributesSchema } from './types.js';
72
78
  * @param options Options object.
73
79
  * @return Template renders.
74
80
  */ static async readAndRender(templateFilePath, data, options) {
81
+ var _options, _options1, _options2, _options3;
75
82
  let template = await Template.read(templateFilePath, {
76
- attributesSchema: options === null || options === void 0 ? void 0 : options.attributesSchema,
77
- dataSchema: options === null || options === void 0 ? void 0 : options.dataSchema
83
+ attributesSchema: (_options = options) === null || _options === void 0 ? void 0 : _options.attributesSchema,
84
+ dataSchema: (_options1 = options) === null || _options1 === void 0 ? void 0 : _options1.dataSchema
78
85
  });
79
86
  return template.render(data, {
80
- prettierOptions: options === null || options === void 0 ? void 0 : options.prettierOptions,
81
- disablePrettier: options === null || options === void 0 ? void 0 : options.disablePrettier
87
+ prettierOptions: (_options2 = options) === null || _options2 === void 0 ? void 0 : _options2.prettierOptions,
88
+ disablePrettier: (_options3 = options) === null || _options3 === void 0 ? void 0 : _options3.disablePrettier
82
89
  });
83
90
  }
84
91
  /**
@@ -92,6 +99,7 @@ import { templateAttributesSchema } from './types.js';
92
99
  for (let variables of Array.isArray(this.attributes.variables) ? this.attributes.variables : [
93
100
  this.attributes.variables
94
101
  ]){
102
+ var _options;
95
103
  let renderedAttributes = omit(this.attributes, [
96
104
  'if'
97
105
  ]);
@@ -129,16 +137,17 @@ import { templateAttributesSchema } from './types.js';
129
137
  cause: error
130
138
  });
131
139
  }
132
- if (!(options === null || options === void 0 ? void 0 : options.disablePrettier)) {
140
+ if (!((_options = options) === null || _options === void 0 ? void 0 : _options.disablePrettier)) {
133
141
  try {
142
+ var _options1;
134
143
  content = prettier.format(content, {
135
- ...options === null || options === void 0 ? void 0 : options.prettierOptions,
144
+ ...(_options1 = options) === null || _options1 === void 0 ? void 0 : _options1.prettierOptions,
136
145
  filepath: renderedAttributes.to
137
146
  });
138
- } catch (error1) {
139
- if (!NO_INFERRED_PARSER_REGEXP.test(error1.message)) {
147
+ } catch (error) {
148
+ if (!NO_INFERRED_PARSER_REGEXP.test(error.message)) {
140
149
  throw new TemplateError('FAILED_FORMAT', {
141
- cause: error1
150
+ cause: error
142
151
  });
143
152
  }
144
153
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Template.ts"],"sourcesContent":["import ejs from 'ejs';\nimport fs from 'fs-extra';\nimport matter from 'gray-matter';\nimport omit from 'lodash.omit';\nimport prettier from 'prettier';\nimport yaml from 'yaml';\nimport {type z, type AnyZodObject} from 'zod';\n\nimport {NO_INFERRED_PARSER_REGEXP} from './constants.js';\nimport {TemplateError} from './TemplateError.js';\nimport {\n templateAttributesSchema,\n type TemplateAttributes,\n type TemplateFunction,\n type TemplateRender,\n type TemplateRenders,\n} from './types.js';\n\nexport type TemplateOptions<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n> = {\n /** Template content. */\n content: string;\n\n /** Template attributes. */\n attributes: A extends undefined\n ? TemplateAttributes\n : TemplateAttributes & z.infer<NonNullable<A>>;\n\n /** Zod schema for custom template attributes. */\n attributesSchema?: A | undefined;\n\n /** Zod schema for template data. */\n dataSchema?: D | undefined;\n};\n\nexport type TemplateReadOptions<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n> = {\n /** Zod schema for custom template attributes. */\n attributesSchema?: A | undefined;\n\n /** Zod schema for template data. */\n dataSchema?: D | undefined;\n};\n\nexport type TemplateReadAndRenderOptions<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n> = {\n /** Prettier options. */\n prettierOptions?: prettier.Options | undefined;\n\n /** Disable formatting the rendered template using Prettier. */\n disablePrettier?: boolean | undefined;\n\n /** Zod schema for custom template attributes. */\n attributesSchema?: A | undefined;\n\n /** Zod schema for template data. */\n dataSchema?: D | undefined;\n};\n\nexport type TemplateRenderOptions = {\n /** Prettier options. */\n prettierOptions?: prettier.Options | undefined;\n\n /** Disable formatting the rendered template using Prettier. */\n disablePrettier?: boolean | undefined;\n};\n\n/**\n * The `Template` object stores all information about a template and has methods for reading and rendering.\n *\n * ```TypeScript\n * let template = new Template({\n * content: '<%- value %>',\n * attributes: {\n * to: 'value.txt',\n * },\n * dataSchema: z.object({value: z.number()}),\n * });\n *\n * console.log(await template.render({value: 42})); // -> [{attributes: {to: 'value.txt'}, data: {value: 42}, content: '42'}]\n * ```\n *\n * @typeParam A A Zod schema type used to define the custom template attributes type.\n * @typeParam D A Zod schema type used to define the template datatype.\n */\nexport class Template<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n> {\n /** Template content. Templates are written in [EJS](https://ejs.co/). */\n readonly content: string;\n\n /** Template attributes. These control how the template is rendered. Some attributes can be written in [EJS](https://ejs.co/) and are rendered before the template content is rendered. It is expected that attribute `if` renders to a string that can be parsed as YAML value; if that value is `false`, the rendering is cancelled. Attribute `to` is also rendered and it represents the path of file the resulting template render is supposed to be written into (by the user). Attribute `variables` is an object that is merged with the data object before rendering. If attribute `variables` is an array of objects, that leads to multiple renders, each with different variables object merged with the data. Each variable that is a string is also rendered. */\n readonly attributes: A extends undefined\n ? TemplateAttributes\n : TemplateAttributes & z.infer<NonNullable<A>>;\n\n /** Template function. */\n private readonly fn: TemplateFunction;\n\n /** Zod schema for custom template attributes. */\n readonly attributesSchema: A extends AnyZodObject ? A : null;\n\n /** Zod schema for template data. */\n readonly dataSchema: D extends AnyZodObject ? D : null;\n\n constructor({content, attributes, attributesSchema, dataSchema}: TemplateOptions<A, D>) {\n this.content = content;\n this.attributes = attributes;\n this.fn = ejs.compile(this.content);\n\n if (attributesSchema) {\n this.attributesSchema = attributesSchema as A extends AnyZodObject ? A : null;\n } else {\n this.attributesSchema = null as A extends AnyZodObject ? A : null;\n }\n\n if (dataSchema) {\n this.dataSchema = dataSchema as D extends AnyZodObject ? D : null;\n } else {\n this.dataSchema = null as D extends AnyZodObject ? D : null;\n }\n }\n\n /**\n * Reads a template from a file.\n *\n * @param templateFilePath Path to the template file.\n */\n static async read<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n >(templateFilePath: string, options?: TemplateReadOptions<A, D>): Promise<Template<A, D>> {\n let {data: attributes, content} = matter(await fs.readFile(templateFilePath, 'utf8'));\n let attributesSchema = options?.attributesSchema\n ? templateAttributesSchema.merge(options.attributesSchema)\n : templateAttributesSchema;\n let attributesParseResult = attributesSchema.safeParse(attributes);\n\n if (!attributesParseResult.success) {\n throw new TemplateError('INVALID_ATTRIBUTES', {\n cause: attributesParseResult.error,\n data: {\n path: templateFilePath,\n zodIssues: attributesParseResult.error.issues,\n },\n });\n }\n\n return new this({\n attributes,\n content,\n attributesSchema: options?.attributesSchema,\n dataSchema: options?.dataSchema,\n } as TemplateOptions<A, D>);\n }\n\n /**\n * Reads a template from a file and then renders it.\n *\n * @param templateFilePath Path to the template file.\n * @param data Data used for rendering the template.\n * @param options Options object.\n * @return Template renders.\n */\n static async readAndRender<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n >(\n templateFilePath: string,\n data: D extends undefined ? null : z.infer<NonNullable<D>>,\n options?: TemplateReadAndRenderOptions<A, D>,\n ) {\n let template = await Template.read<A, D>(templateFilePath, {\n attributesSchema: options?.attributesSchema,\n dataSchema: options?.dataSchema,\n });\n\n return template.render(data, {\n prettierOptions: options?.prettierOptions,\n disablePrettier: options?.disablePrettier,\n });\n }\n\n /**\n * Renders the template using data.\n *\n * @param data Data used for rendering the template.\n * @param options Options object.\n * @return Template renders.\n */\n async render(\n data: D extends undefined ? null : z.infer<NonNullable<D>>,\n options?: TemplateRenderOptions,\n ): Promise<TemplateRenders<A, D>> {\n let renders: TemplateRenders<A, D> = [];\n\n for (let variables of Array.isArray(this.attributes.variables)\n ? this.attributes.variables\n : [this.attributes.variables]) {\n let renderedAttributes = omit(this.attributes, ['if']);\n let renderedVariables = variables;\n\n if (renderedVariables) {\n for (let [variableName, variableValue] of Object.entries(renderedVariables)) {\n if (typeof variableValue === 'string') {\n renderedVariables[variableName] = ejs.render(variableValue, {...data});\n } else {\n renderedVariables[variableName] = variableValue;\n }\n }\n\n renderedAttributes.variables = renderedVariables;\n }\n\n let dataWithAttributes = {...data, attributes: renderedAttributes};\n\n if (this.attributes.if) {\n let renderedIf = ejs.render(this.attributes.if, dataWithAttributes);\n let parsedIf = yaml.parse(renderedIf) as unknown;\n\n if (parsedIf === false) {\n continue;\n }\n }\n\n renderedAttributes.to = ejs.render(renderedAttributes.to, dataWithAttributes);\n dataWithAttributes.attributes = renderedAttributes;\n\n let content;\n\n try {\n content = this.fn(dataWithAttributes);\n } catch (error: unknown) {\n throw new TemplateError('FAILED_RENDER', {cause: error});\n }\n\n if (!options?.disablePrettier) {\n try {\n content = prettier.format(content, {\n ...options?.prettierOptions,\n filepath: renderedAttributes.to,\n });\n } catch (error: unknown) {\n if (!NO_INFERRED_PARSER_REGEXP.test((error as Error).message)) {\n throw new TemplateError('FAILED_FORMAT', {cause: error});\n }\n }\n }\n\n renders.push({\n attributes: renderedAttributes,\n data: data ?? null,\n content,\n } as TemplateRender<A, D>);\n }\n\n return renders;\n }\n}\n"],"names":["ejs","fs","matter","omit","prettier","yaml","NO_INFERRED_PARSER_REGEXP","TemplateError","templateAttributesSchema","Template","constructor","content","attributes","attributesSchema","dataSchema","fn","compile","read","templateFilePath","options","data","readFile","merge","attributesParseResult","safeParse","success","cause","error","path","zodIssues","issues","readAndRender","template","render","prettierOptions","disablePrettier","renders","variables","Array","isArray","renderedAttributes","renderedVariables","variableName","variableValue","Object","entries","dataWithAttributes","if","renderedIf","parsedIf","parse","to","format","filepath","test","message","push"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/Template.ts"],"sourcesContent":["import ejs from 'ejs';\nimport fs from 'fs-extra';\nimport matter from 'gray-matter';\nimport omit from 'lodash.omit';\nimport prettier from 'prettier';\nimport yaml from 'yaml';\nimport {type z, type AnyZodObject} from 'zod';\n\nimport {NO_INFERRED_PARSER_REGEXP} from './constants.js';\nimport {TemplateError} from './TemplateError.js';\nimport {\n templateAttributesSchema,\n type TemplateAttributes,\n type TemplateFunction,\n type TemplateRender,\n type TemplateRenders,\n} from './types.js';\n\nexport type TemplateOptions<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n> = {\n /** Template content. */\n content: string;\n\n /** Template attributes. */\n attributes: A extends undefined\n ? TemplateAttributes\n : TemplateAttributes & z.infer<NonNullable<A>>;\n\n /** Zod schema for custom template attributes. */\n attributesSchema?: A | undefined;\n\n /** Zod schema for template data. */\n dataSchema?: D | undefined;\n};\n\nexport type TemplateReadOptions<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n> = {\n /** Zod schema for custom template attributes. */\n attributesSchema?: A | undefined;\n\n /** Zod schema for template data. */\n dataSchema?: D | undefined;\n};\n\nexport type TemplateReadAndRenderOptions<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n> = {\n /** Prettier options. */\n prettierOptions?: prettier.Options | undefined;\n\n /** Disable formatting the rendered template using Prettier. */\n disablePrettier?: boolean | undefined;\n\n /** Zod schema for custom template attributes. */\n attributesSchema?: A | undefined;\n\n /** Zod schema for template data. */\n dataSchema?: D | undefined;\n};\n\nexport type TemplateRenderOptions = {\n /** Prettier options. */\n prettierOptions?: prettier.Options | undefined;\n\n /** Disable formatting the rendered template using Prettier. */\n disablePrettier?: boolean | undefined;\n};\n\n/**\n * The `Template` object stores all information about a template and has methods for reading and rendering.\n *\n * ```TypeScript\n * let template = new Template({\n * content: '<%- value %>',\n * attributes: {\n * to: 'value.txt',\n * },\n * dataSchema: z.object({value: z.number()}),\n * });\n *\n * console.log(await template.render({value: 42})); // -> [{attributes: {to: 'value.txt'}, data: {value: 42}, content: '42'}]\n * ```\n *\n * @typeParam A A Zod schema type used to define the custom template attributes type.\n * @typeParam D A Zod schema type used to define the template datatype.\n */\nexport class Template<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n> {\n /** Template content. Templates are written in [EJS](https://ejs.co/). */\n readonly content: string;\n\n /** Template attributes. These control how the template is rendered. Some attributes can be written in [EJS](https://ejs.co/) and are rendered before the template content is rendered. It is expected that attribute `if` renders to a string that can be parsed as YAML value; if that value is `false`, the rendering is cancelled. Attribute `to` is also rendered and it represents the path of file the resulting template render is supposed to be written into (by the user). Attribute `variables` is an object that is merged with the data object before rendering. If attribute `variables` is an array of objects, that leads to multiple renders, each with different variables object merged with the data. Each variable that is a string is also rendered. */\n readonly attributes: A extends undefined\n ? TemplateAttributes\n : TemplateAttributes & z.infer<NonNullable<A>>;\n\n /** Template function. */\n private readonly fn: TemplateFunction;\n\n /** Zod schema for custom template attributes. */\n readonly attributesSchema: A extends AnyZodObject ? A : null;\n\n /** Zod schema for template data. */\n readonly dataSchema: D extends AnyZodObject ? D : null;\n\n constructor({content, attributes, attributesSchema, dataSchema}: TemplateOptions<A, D>) {\n this.content = content;\n this.attributes = attributes;\n this.fn = ejs.compile(this.content);\n\n if (attributesSchema) {\n this.attributesSchema = attributesSchema as A extends AnyZodObject ? A : null;\n } else {\n this.attributesSchema = null as A extends AnyZodObject ? A : null;\n }\n\n if (dataSchema) {\n this.dataSchema = dataSchema as D extends AnyZodObject ? D : null;\n } else {\n this.dataSchema = null as D extends AnyZodObject ? D : null;\n }\n }\n\n /**\n * Reads a template from a file.\n *\n * @param templateFilePath Path to the template file.\n */\n static async read<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n >(templateFilePath: string, options?: TemplateReadOptions<A, D>): Promise<Template<A, D>> {\n let {data: attributes, content} = matter(await fs.readFile(templateFilePath, 'utf8'));\n let attributesSchema = options?.attributesSchema\n ? templateAttributesSchema.merge(options.attributesSchema)\n : templateAttributesSchema;\n let attributesParseResult = attributesSchema.safeParse(attributes);\n\n if (!attributesParseResult.success) {\n throw new TemplateError('INVALID_ATTRIBUTES', {\n cause: attributesParseResult.error,\n data: {\n path: templateFilePath,\n zodIssues: attributesParseResult.error.issues,\n },\n });\n }\n\n return new this({\n attributes,\n content,\n attributesSchema: options?.attributesSchema,\n dataSchema: options?.dataSchema,\n } as TemplateOptions<A, D>);\n }\n\n /**\n * Reads a template from a file and then renders it.\n *\n * @param templateFilePath Path to the template file.\n * @param data Data used for rendering the template.\n * @param options Options object.\n * @return Template renders.\n */\n static async readAndRender<\n A extends AnyZodObject | undefined = undefined,\n D extends AnyZodObject | undefined = undefined,\n >(\n templateFilePath: string,\n data: D extends undefined ? null : z.infer<NonNullable<D>>,\n options?: TemplateReadAndRenderOptions<A, D>,\n ) {\n let template = await Template.read<A, D>(templateFilePath, {\n attributesSchema: options?.attributesSchema,\n dataSchema: options?.dataSchema,\n });\n\n return template.render(data, {\n prettierOptions: options?.prettierOptions,\n disablePrettier: options?.disablePrettier,\n });\n }\n\n /**\n * Renders the template using data.\n *\n * @param data Data used for rendering the template.\n * @param options Options object.\n * @return Template renders.\n */\n async render(\n data: D extends undefined ? null : z.infer<NonNullable<D>>,\n options?: TemplateRenderOptions,\n ): Promise<TemplateRenders<A, D>> {\n let renders: TemplateRenders<A, D> = [];\n\n for (let variables of Array.isArray(this.attributes.variables)\n ? this.attributes.variables\n : [this.attributes.variables]) {\n let renderedAttributes = omit(this.attributes, ['if']);\n let renderedVariables = variables;\n\n if (renderedVariables) {\n for (let [variableName, variableValue] of Object.entries(renderedVariables)) {\n if (typeof variableValue === 'string') {\n renderedVariables[variableName] = ejs.render(variableValue, {...data});\n } else {\n renderedVariables[variableName] = variableValue;\n }\n }\n\n renderedAttributes.variables = renderedVariables;\n }\n\n let dataWithAttributes = {...data, attributes: renderedAttributes};\n\n if (this.attributes.if) {\n let renderedIf = ejs.render(this.attributes.if, dataWithAttributes);\n let parsedIf = yaml.parse(renderedIf) as unknown;\n\n if (parsedIf === false) {\n continue;\n }\n }\n\n renderedAttributes.to = ejs.render(renderedAttributes.to, dataWithAttributes);\n dataWithAttributes.attributes = renderedAttributes;\n\n let content;\n\n try {\n content = this.fn(dataWithAttributes);\n } catch (error: unknown) {\n throw new TemplateError('FAILED_RENDER', {cause: error});\n }\n\n if (!options?.disablePrettier) {\n try {\n content = prettier.format(content, {\n ...options?.prettierOptions,\n filepath: renderedAttributes.to,\n });\n } catch (error: unknown) {\n if (!NO_INFERRED_PARSER_REGEXP.test((error as Error).message)) {\n throw new TemplateError('FAILED_FORMAT', {cause: error});\n }\n }\n }\n\n renders.push({\n attributes: renderedAttributes,\n data: data ?? null,\n content,\n } as TemplateRender<A, D>);\n }\n\n return renders;\n }\n}\n"],"names":["ejs","fs","matter","omit","prettier","yaml","NO_INFERRED_PARSER_REGEXP","TemplateError","templateAttributesSchema","Template","content","attributes","fn","attributesSchema","dataSchema","constructor","compile","read","templateFilePath","options","data","readFile","merge","attributesParseResult","safeParse","success","cause","error","path","zodIssues","issues","readAndRender","template","render","prettierOptions","disablePrettier","renders","variables","Array","isArray","renderedAttributes","renderedVariables","variableName","variableValue","Object","entries","dataWithAttributes","if","renderedIf","parsedIf","parse","to","format","filepath","test","message","push"],"mappings":"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"}
@@ -6,6 +6,9 @@ import { createCustomErrorWithData } from '@jakubmazanec/error';
6
6
  FAILED_FORMAT: 'Template render formatting has failed.',
7
7
  FAILED_RENDER: 'Rendering has failed.'
8
8
  }, class TemplateErrorData {
9
+ template;
10
+ path;
11
+ zodIssues;
9
12
  });
10
13
 
11
14
  //# sourceMappingURL=TemplateError.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/TemplateError.ts"],"sourcesContent":["import {createCustomErrorWithData} from '@jakubmazanec/error';\nimport {type ZodIssue} from 'zod';\n\nimport {type Template} from './Template.js';\n\n/**\n * A subclass of `Error` that indicates a template failure.\n */\nexport const TemplateError = createCustomErrorWithData(\n 'TemplateError',\n {\n INVALID_ATTRIBUTES: 'Invalid template attributes.',\n FAILED_FORMAT: 'Template render formatting has failed.',\n FAILED_RENDER: 'Rendering has failed.',\n },\n class TemplateErrorData {\n template?: Template;\n path?: string;\n zodIssues?: ZodIssue[];\n },\n);\n"],"names":["createCustomErrorWithData","TemplateError","INVALID_ATTRIBUTES","FAILED_FORMAT","FAILED_RENDER","TemplateErrorData"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,sBAAsB;AAK9D;;CAEC,GACD,OAAO,MAAMC,gBAAgBD,0BAC3B,iBACA;IACEE,oBAAoB;IACpBC,eAAe;IACfC,eAAe;AACjB,GACA,MAAMC;AAIN,GACA"}
1
+ {"version":3,"sources":["../src/TemplateError.ts"],"sourcesContent":["import {createCustomErrorWithData} from '@jakubmazanec/error';\nimport {type ZodIssue} from 'zod';\n\nimport {type Template} from './Template.js';\n\n/**\n * A subclass of `Error` that indicates a template failure.\n */\nexport const TemplateError = createCustomErrorWithData(\n 'TemplateError',\n {\n INVALID_ATTRIBUTES: 'Invalid template attributes.',\n FAILED_FORMAT: 'Template render formatting has failed.',\n FAILED_RENDER: 'Rendering has failed.',\n },\n class TemplateErrorData {\n template?: Template;\n path?: string;\n zodIssues?: ZodIssue[];\n },\n);\n"],"names":["createCustomErrorWithData","TemplateError","INVALID_ATTRIBUTES","FAILED_FORMAT","FAILED_RENDER","TemplateErrorData","template","path","zodIssues"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,sBAAsB;AAK9D;;CAEC,GACD,OAAO,MAAMC,gBAAgBD,0BAC3B,iBACA;IACEE,oBAAoB;IACpBC,eAAe;IACfC,eAAe;AACjB,GACA,MAAMC;IACJC,SAAoB;IACpBC,KAAc;IACdC,UAAuB;AACzB,GACA"}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@jakubmazanec/template",
3
- "version": "1.0.0",
3
+ "version": "1.0.1-265acad",
4
4
  "description": "TypeScript-first library for working with templates using EJS and Zod.",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "git@github.com:jakubmazanec/js-tools.git",
7
+ "url": "https://github.com/jakubmazanec/js-tools",
8
8
  "directory": "packages/template"
9
9
  },
10
10
  "license": "LGPL-3.0-only",
@@ -26,7 +26,7 @@
26
26
  "typecheck": "tsc --project tsconfig.typecheck.json"
27
27
  },
28
28
  "dependencies": {
29
- "@jakubmazanec/error": "^2.0.0",
29
+ "@jakubmazanec/error": "2.0.1-265acad",
30
30
  "ejs": "^3.1.9",
31
31
  "fs-extra": "^11.1.1",
32
32
  "gray-matter": "^4.0.3",