juisy 2.0.0-beta.0
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 +211 -0
- package/bin/cli/cli.js +23 -0
- package/bin/cli/cmds/changelog.js +41 -0
- package/bin/cli/cmds/docs/generate-api.js +22 -0
- package/bin/cli/cmds/docs/generate-cli.js +11 -0
- package/bin/cli/cmds/docs/generate-readme.js +11 -0
- package/bin/cli/cmds/docs/index.js +22 -0
- package/bin/cli/cmds/docs/lint.js +42 -0
- package/bin/cli/cmds/eject.js +28 -0
- package/bin/cli/cmds/git-hooks/index.js +20 -0
- package/bin/cli/cmds/git-hooks/reset.js +48 -0
- package/bin/cli/cmds/git-hooks/sync.js +19 -0
- package/bin/cli/cmds/index.js +15 -0
- package/bin/cli/cmds/print-globals.js +28 -0
- package/bin/cli/cmds/release.js +231 -0
- package/bin/cli/cmds/squeeze.js +269 -0
- package/bin/cli/cmds/test.js +33 -0
- package/bin/cli/index.js +9 -0
- package/bin/cli/lib/docs/generate-api-doc.js +78 -0
- package/bin/cli/lib/version/update-version.js +52 -0
- package/bin/scripts/commit-msg.js +32 -0
- package/bin/scripts/pre-commit.js +24 -0
- package/dist/DataExporter.d.ts +67 -0
- package/dist/cli/CLIFactory.d.ts +19 -0
- package/dist/cli/Command.d.ts +44 -0
- package/dist/cli/InterfaceUtils.d.ts +53 -0
- package/dist/cli/OutputUtils.d.ts +123 -0
- package/dist/cli/command-visitors/command-handler-injections.d.ts +10 -0
- package/dist/cli/command-visitors/get-command-meta.d.ts +10 -0
- package/dist/cli/command-visitors/index.d.ts +9 -0
- package/dist/cli/command-visitors/private-command.d.ts +16 -0
- package/dist/cli/create-engine.d.ts +7 -0
- package/dist/cli/extract-usage.d.ts +72 -0
- package/dist/cli/index.d.ts +20 -0
- package/dist/cli/index.js +559 -0
- package/dist/cli/types.d.ts +112 -0
- package/dist/cli/utils.d.ts +19 -0
- package/dist/eject.d.ts +22 -0
- package/dist/get-package-info.d.ts +6 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +244 -0
- package/dist/project-globals.d.ts +63 -0
- package/dist/templater/Templater.d.ts +23 -0
- package/dist/templater/index.d.ts +6 -0
- package/dist/templater/index.js +330 -0
- package/dist/templater/markdown-templater/ReadmeTemplater.d.ts +154 -0
- package/dist/templater/markdown-templater/index.d.ts +25 -0
- package/dist/templater/types.d.ts +10 -0
- package/dist/utils/misc.d.ts +21 -0
- package/package.json +179 -0
- package/src/index.js +507 -0
- package/template/CHANGELOG.md +0 -0
- package/template/bin/cli/cli.js +27 -0
- package/template/bin/cli/cmds/changelog.js +71 -0
- package/template/bin/cli/cmds/docs.js +30 -0
- package/template/bin/cli/cmds/docs_cmds/generate-api.js +75 -0
- package/template/bin/cli/cmds/docs_cmds/generate-readme.js +51 -0
- package/template/bin/cli/cmds/git-hooks.js +30 -0
- package/template/bin/cli/cmds/git_hooks_cmds/reset.js +76 -0
- package/template/bin/cli/cmds/git_hooks_cmds/sync.js +44 -0
- package/template/bin/cli/cmds/release.js +219 -0
- package/template/bin/cli/index.js +7 -0
- package/template/bin/cli/lib/docs/generate-api-doc.js +33 -0
- package/template/bin/cli/lib/release/generate-release-note.js +3 -0
- package/template/bin/cli/lib/version/update-version.js +51 -0
- package/template/bin/scripts/commit-msg.js +42 -0
- package/template/bin/scripts/pre-commit.js +32 -0
- package/template/docs/api/docs.config.js +10 -0
- package/template/docs/readme/config.js +22 -0
- package/template/docs/readme/readme.js +70 -0
- package/template/docs/readme/template.md +53 -0
package/dist/eject.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LogLevelDesc } from 'loglevel';
|
|
2
|
+
type EjectOptions = {
|
|
3
|
+
force?: boolean;
|
|
4
|
+
targetDir?: string;
|
|
5
|
+
logLevel?: LogLevelDesc;
|
|
6
|
+
processor?: (content: string, identifier: string) => string | Promise<string>;
|
|
7
|
+
onError?: (identifier: string, fromPath: string, toPath: string, err: Error) => void | Promise<void>;
|
|
8
|
+
onSuccess?: (identifier: string, fromPath: string, toPath: string) => void | Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Eject from file from template to user project
|
|
12
|
+
* @param identifier - The identifier of the file to eject (relative to juisy/template folder). Can be a glob pattern (ex: `bin\/**\/*`).
|
|
13
|
+
* @param options - The options object
|
|
14
|
+
* @param options.force - If true, the target files will be overwritten
|
|
15
|
+
* @param options.targetDir - The target directory absolute path
|
|
16
|
+
* @param options.processor - The template file content processor function.
|
|
17
|
+
* Takes content as unique argument and must return string or a Promise that resolves a string
|
|
18
|
+
* @param options.onError - The callback if an error occurs
|
|
19
|
+
* @param options.onSuccess - The callback in of success
|
|
20
|
+
*/
|
|
21
|
+
export default function eject(identifier: string, options?: EjectOptions): Promise<void>;
|
|
22
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API of juisy library
|
|
3
|
+
* @module juisy
|
|
4
|
+
* @author Hervé Perchec
|
|
5
|
+
*/
|
|
6
|
+
import * as utils from './utils/misc';
|
|
7
|
+
export { default as eject } from './eject';
|
|
8
|
+
export * from './DataExporter';
|
|
9
|
+
export { default as getPackageInfo } from './get-package-info';
|
|
10
|
+
export * from './project-globals';
|
|
11
|
+
export { utils };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* juisy v1.4.0
|
|
3
|
+
* Copyright © 2022-Present Hervé Perchec
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import path, { dirname } from 'node:path';
|
|
7
|
+
import { readdir, readFileSync } from 'node:fs';
|
|
8
|
+
import { glob } from 'glob';
|
|
9
|
+
import fs from 'fs-extra';
|
|
10
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
11
|
+
import { packageDirectorySync } from 'pkg-dir';
|
|
12
|
+
import log from 'loglevel';
|
|
13
|
+
import { Templater } from 'juisy/templater';
|
|
14
|
+
import yaml from 'yaml';
|
|
15
|
+
import { json2csv } from 'json-2-csv';
|
|
16
|
+
import jstoxml from 'jstoxml';
|
|
17
|
+
import dotenv from '@dotenvx/dotenvx';
|
|
18
|
+
import deepmerge from 'deepmerge';
|
|
19
|
+
|
|
20
|
+
function getFileUrls(pattern, options) {
|
|
21
|
+
const files = glob.sync(pattern, options || {});
|
|
22
|
+
return files;
|
|
23
|
+
}
|
|
24
|
+
async function* getFiles(dir) {
|
|
25
|
+
const dirents = await readdir(dir, { withFileTypes: true });
|
|
26
|
+
for (const dirent of dirents) {
|
|
27
|
+
const res = path.resolve(dir, dirent.name);
|
|
28
|
+
if (dirent.isDirectory()) {
|
|
29
|
+
yield* getFiles(res);
|
|
30
|
+
} else {
|
|
31
|
+
yield res;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const misc = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
37
|
+
__proto__: null,
|
|
38
|
+
getFileUrls,
|
|
39
|
+
getFiles
|
|
40
|
+
}, Symbol.toStringTag, { value: 'Module' }));
|
|
41
|
+
|
|
42
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
43
|
+
const __dirname = dirname(__filename);
|
|
44
|
+
const templater = new Templater("ejs", {
|
|
45
|
+
engineOptions: {
|
|
46
|
+
// ...
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
async function isDirectory(filePath) {
|
|
50
|
+
try {
|
|
51
|
+
const stats = await fs.stat(filePath);
|
|
52
|
+
return stats.isDirectory();
|
|
53
|
+
} catch (err) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function isFile(filePath) {
|
|
58
|
+
try {
|
|
59
|
+
const stats = await fs.stat(filePath);
|
|
60
|
+
return stats.isFile();
|
|
61
|
+
} catch (err) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function ejectFile(from, to, identifier = null, options) {
|
|
66
|
+
identifier = identifier || path.basename(from);
|
|
67
|
+
const force = options?.force || false;
|
|
68
|
+
const processor = options?.processor || (async (str, _identifier) => str);
|
|
69
|
+
const onError = options?.onError || (async (_identifier, fromPath, toPath, err) => {
|
|
70
|
+
throw err;
|
|
71
|
+
});
|
|
72
|
+
const onSuccess = options?.onSuccess || (async (_identifier, fromPath, toPath) => {
|
|
73
|
+
log.info(`File ${_identifier} successfuly ejected!`);
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
const write = await fs.exists(to) ? force : true;
|
|
77
|
+
if (write) {
|
|
78
|
+
const template = await fs.readFile(from, { encoding: "utf8" });
|
|
79
|
+
const content = await templater.render(template);
|
|
80
|
+
const processedContent = await processor(content, identifier);
|
|
81
|
+
await fs.ensureFile(to);
|
|
82
|
+
await fs.writeFile(to, processedContent);
|
|
83
|
+
await onSuccess(identifier, from, to);
|
|
84
|
+
} else {
|
|
85
|
+
log.warn(`Target "${to}" already exists. Skipped... Use "force" option to overwrite`);
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
await onError(identifier, from, to, err);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function eject(identifier, options) {
|
|
92
|
+
const targetDir = options?.targetDir || packageDirectorySync() || process.cwd();
|
|
93
|
+
const logLevel = options?.logLevel || "trace";
|
|
94
|
+
const originalLogLevel = log.getLevel();
|
|
95
|
+
log.setLevel(logLevel);
|
|
96
|
+
if (!identifier) {
|
|
97
|
+
throw new Error("eject: identifier is required");
|
|
98
|
+
} else {
|
|
99
|
+
try {
|
|
100
|
+
const localTemplatePath = path.resolve(__dirname, "../template");
|
|
101
|
+
const fullPath = path.resolve(localTemplatePath, identifier);
|
|
102
|
+
if (await isFile(fullPath)) {
|
|
103
|
+
await ejectFile(fullPath, path.resolve(targetDir, identifier), identifier, {
|
|
104
|
+
processor: options?.processor,
|
|
105
|
+
onSuccess: options?.onSuccess,
|
|
106
|
+
onError: options?.onError
|
|
107
|
+
});
|
|
108
|
+
} else {
|
|
109
|
+
const globPattern = await isDirectory(fullPath) ? identifier + "/**/*" : identifier;
|
|
110
|
+
for (const fileRelativePath of getFileUrls(globPattern, { cwd: localTemplatePath, nodir: true, posix: true })) {
|
|
111
|
+
const fullTemplateFilePath = path.resolve(localTemplatePath, fileRelativePath);
|
|
112
|
+
await ejectFile(fullTemplateFilePath, path.resolve(targetDir, fileRelativePath), fileRelativePath, {
|
|
113
|
+
processor: options?.processor,
|
|
114
|
+
onSuccess: options?.onSuccess,
|
|
115
|
+
onError: options?.onError
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
log.info(`Successfully ejected "${identifier}"`);
|
|
120
|
+
} finally {
|
|
121
|
+
log.setLevel(originalLogLevel);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const xml = jstoxml.toXML;
|
|
127
|
+
const SUPPORTED_FORMATS = [
|
|
128
|
+
"json",
|
|
129
|
+
"yaml",
|
|
130
|
+
"csv",
|
|
131
|
+
"xml"
|
|
132
|
+
// 'bson',
|
|
133
|
+
// 'msgpack',
|
|
134
|
+
// 'protobuf',
|
|
135
|
+
// 'avro'
|
|
136
|
+
];
|
|
137
|
+
const jsonExporter = function(data, options = {}) {
|
|
138
|
+
return JSON.stringify(data, options.replacer, options.space);
|
|
139
|
+
};
|
|
140
|
+
const yamlExporter = function(data, options = {}) {
|
|
141
|
+
return yaml.stringify(data, options.replacer, options.exporter);
|
|
142
|
+
};
|
|
143
|
+
const csvExporter = function(data, options) {
|
|
144
|
+
return json2csv(data, options);
|
|
145
|
+
};
|
|
146
|
+
const xmlExporter = function(data, options) {
|
|
147
|
+
return xml(data, options);
|
|
148
|
+
};
|
|
149
|
+
class DataExporter {
|
|
150
|
+
/**
|
|
151
|
+
* The target format
|
|
152
|
+
*/
|
|
153
|
+
format;
|
|
154
|
+
/**
|
|
155
|
+
* Creates new instance of Costume
|
|
156
|
+
* @param options - Costume options
|
|
157
|
+
*/
|
|
158
|
+
constructor(format) {
|
|
159
|
+
if (SUPPORTED_FORMATS.includes(format)) {
|
|
160
|
+
this.format = format;
|
|
161
|
+
} else {
|
|
162
|
+
throw new Error(`DataConverter: Unsupported "${format}" format`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exportSync(data, options) {
|
|
166
|
+
switch (this.format) {
|
|
167
|
+
case "json":
|
|
168
|
+
return jsonExporter(data, options);
|
|
169
|
+
case "yaml":
|
|
170
|
+
return yamlExporter(data, options);
|
|
171
|
+
case "csv":
|
|
172
|
+
return csvExporter(data, options);
|
|
173
|
+
case "xml":
|
|
174
|
+
return xmlExporter(data, options);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
export(...args) {
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
resolve(this.exportSync(...args));
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function getPackageInfo() {
|
|
185
|
+
const pkgPath = path.resolve(packageDirectorySync(), "./package.json");
|
|
186
|
+
return JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function defineGlobals(config, builder) {
|
|
190
|
+
const env = {
|
|
191
|
+
...process.env
|
|
192
|
+
};
|
|
193
|
+
let pkg = {};
|
|
194
|
+
try {
|
|
195
|
+
pkg = getPackageInfo();
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.warn("Unable to find or parse package.json:", error.message);
|
|
198
|
+
}
|
|
199
|
+
const GLOBALS = {
|
|
200
|
+
ENV: {},
|
|
201
|
+
PACKAGE: {
|
|
202
|
+
NAME: pkg.name,
|
|
203
|
+
URL: `https://www.npmjs.com/package/${pkg.name}`
|
|
204
|
+
},
|
|
205
|
+
VERSION: pkg.version,
|
|
206
|
+
AUTHOR: {
|
|
207
|
+
EMAIL: pkg.author?.email,
|
|
208
|
+
NAME: pkg.author?.name,
|
|
209
|
+
URL: pkg.author?.url
|
|
210
|
+
},
|
|
211
|
+
REPOSITORY: {
|
|
212
|
+
TYPE: pkg.repository?.type,
|
|
213
|
+
URL: pkg.repository?.url
|
|
214
|
+
},
|
|
215
|
+
ISSUES_URL: pkg.bugs?.url,
|
|
216
|
+
HOMEPAGE: pkg.homepage
|
|
217
|
+
};
|
|
218
|
+
if (config.env?.map?.length) {
|
|
219
|
+
dotenv.config({
|
|
220
|
+
// Default to not verbose, can be overridden
|
|
221
|
+
debug: false,
|
|
222
|
+
verbose: false,
|
|
223
|
+
quiet: true,
|
|
224
|
+
// Spread user options
|
|
225
|
+
...config.env.dotenvOptions || {},
|
|
226
|
+
// DON'T write to process.env.
|
|
227
|
+
// We pass custom local temporary object
|
|
228
|
+
processEnv: env
|
|
229
|
+
});
|
|
230
|
+
for (const envVar of config.env.map) {
|
|
231
|
+
GLOBALS.ENV[envVar] = env[envVar];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const ctx = {
|
|
235
|
+
env,
|
|
236
|
+
pkg
|
|
237
|
+
};
|
|
238
|
+
return deepmerge(GLOBALS, JSON.parse(JSON.stringify(builder(ctx))));
|
|
239
|
+
}
|
|
240
|
+
async function getProjectGlobals(filePath = "./globals.config.js") {
|
|
241
|
+
return (await import(pathToFileURL(path.resolve(filePath)))).default;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export { DataExporter, defineGlobals, eject, getPackageInfo, getProjectGlobals, misc as utils };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { DotenvConfigOptions } from '@dotenvx/dotenvx';
|
|
2
|
+
import { IPackageJson as PackageJson, IAuthor as PackageJsonAuthor, IRepository as PackageJsonRepository, IBugs as PackageJsonBugs } from 'package-json-type';
|
|
3
|
+
export type ProjectGlobals = Record<string, string | Record<string, unknown> | undefined> & {
|
|
4
|
+
ENV: NodeJS.ProcessEnv;
|
|
5
|
+
PACKAGE: {
|
|
6
|
+
NAME: PackageJson['name'];
|
|
7
|
+
URL: PackageJson['url'];
|
|
8
|
+
};
|
|
9
|
+
VERSION: PackageJson['version'];
|
|
10
|
+
AUTHOR: {
|
|
11
|
+
EMAIL: PackageJsonAuthor['email'];
|
|
12
|
+
NAME: PackageJsonAuthor['name'];
|
|
13
|
+
URL: PackageJsonAuthor['url'];
|
|
14
|
+
};
|
|
15
|
+
REPOSITORY: {
|
|
16
|
+
TYPE: PackageJsonRepository['type'];
|
|
17
|
+
URL: PackageJsonRepository['url'];
|
|
18
|
+
};
|
|
19
|
+
ISSUES_URL: PackageJsonBugs['url'];
|
|
20
|
+
HOMEPAGE: PackageJson['homepage'];
|
|
21
|
+
};
|
|
22
|
+
export type DotenvOptions = Omit<DotenvConfigOptions, 'processEnv'>;
|
|
23
|
+
export type DefineGlobalsBuilder = (ctx: {
|
|
24
|
+
env: NodeJS.ProcessEnv;
|
|
25
|
+
pkg: PackageJson;
|
|
26
|
+
}) => ProjectGlobals;
|
|
27
|
+
/**
|
|
28
|
+
* Define project globals
|
|
29
|
+
* @param config - The config object
|
|
30
|
+
* @param builder - The builder function
|
|
31
|
+
* @returns The computed globals object
|
|
32
|
+
*/
|
|
33
|
+
export declare function defineGlobals(config: {
|
|
34
|
+
env?: {
|
|
35
|
+
map?: string[];
|
|
36
|
+
dotenvOptions?: DotenvOptions;
|
|
37
|
+
};
|
|
38
|
+
}, builder: DefineGlobalsBuilder): {
|
|
39
|
+
[x: string]: /*elided*/ any;
|
|
40
|
+
ENV: NodeJS.ProcessEnv;
|
|
41
|
+
PACKAGE: {
|
|
42
|
+
NAME: PackageJson["name"];
|
|
43
|
+
URL: PackageJson["url"];
|
|
44
|
+
};
|
|
45
|
+
VERSION: string;
|
|
46
|
+
AUTHOR: {
|
|
47
|
+
EMAIL: PackageJsonAuthor["email"];
|
|
48
|
+
NAME: PackageJsonAuthor["name"];
|
|
49
|
+
URL: PackageJsonAuthor["url"];
|
|
50
|
+
};
|
|
51
|
+
REPOSITORY: {
|
|
52
|
+
TYPE: PackageJsonRepository["type"];
|
|
53
|
+
URL: PackageJsonRepository["url"];
|
|
54
|
+
};
|
|
55
|
+
ISSUES_URL: string;
|
|
56
|
+
HOMEPAGE: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Get project globals
|
|
60
|
+
* @param filePath - The filePath. Default is `'./globals.config.js'`
|
|
61
|
+
* @returns The resolved project globals object
|
|
62
|
+
*/
|
|
63
|
+
export declare function getProjectGlobals(filePath?: string): Promise<ProjectGlobals>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SupportedEngines, TemplaterOptions } from './types';
|
|
2
|
+
export declare class Templater {
|
|
3
|
+
constructor(engine: 'handlebars', options?: TemplaterOptions<'handlebars'>);
|
|
4
|
+
constructor(engine: 'ejs', options?: TemplaterOptions<'ejs'>);
|
|
5
|
+
constructor(engine: 'pug', options?: TemplaterOptions<'pug'>);
|
|
6
|
+
constructor(engine: SupportedEngines[number], options?: TemplaterOptions<SupportedEngines[number]>);
|
|
7
|
+
private engine;
|
|
8
|
+
private defaultData;
|
|
9
|
+
private methodsMap;
|
|
10
|
+
/**
|
|
11
|
+
* @returns Get the engine
|
|
12
|
+
*/
|
|
13
|
+
getEngine(): unknown;
|
|
14
|
+
/**
|
|
15
|
+
* Renders a template with the given context.
|
|
16
|
+
*/
|
|
17
|
+
render(template: string, data?: undefined, options?: any): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Renders a template file with the given context.
|
|
20
|
+
* @todo not yet implemented
|
|
21
|
+
*/
|
|
22
|
+
renderFile(filePath: string, context?: Record<string, any>): string;
|
|
23
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Templater } from './Templater';
|
|
2
|
+
export { MarkdownTemplater } from './markdown-templater';
|
|
3
|
+
export { ReadmeTemplater } from './markdown-templater/ReadmeTemplater';
|
|
4
|
+
export type * from './types';
|
|
5
|
+
export type { MarkdownTemplaterOptions } from './markdown-templater';
|
|
6
|
+
export type { UserConfiguration as ReadmeTemplaterUserConfiguration } from './markdown-templater/ReadmeTemplater';
|