@ts-ioc-container/bundler 0.0.0 → 0.2.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/LICENSE +16 -0
- package/README.md +1 -1
- package/cjm/bin.js +0 -0
- package/package.json +19 -21
- package/lib/ImportPaths.ts +0 -127
- package/lib/bin.ts +0 -4
- package/lib/build.ts +0 -157
- package/lib/cli.ts +0 -88
- package/lib/config.ts +0 -206
- package/lib/emit.ts +0 -47
- package/lib/errors.ts +0 -14
- package/lib/exportPredicate.ts +0 -45
- package/lib/glob.ts +0 -24
- package/lib/inclusion.ts +0 -61
- package/lib/index.ts +0 -40
- package/lib/predicateFile.ts +0 -36
- package/lib/render.ts +0 -19
- package/lib/scan.ts +0 -133
- package/lib/utils.ts +0 -2
- package/typings/ImportPaths.d.ts.map +0 -1
- package/typings/bin.d.ts.map +0 -1
- package/typings/build.d.ts.map +0 -1
- package/typings/cli.d.ts.map +0 -1
- package/typings/config.d.ts.map +0 -1
- package/typings/emit.d.ts.map +0 -1
- package/typings/errors.d.ts.map +0 -1
- package/typings/exportPredicate.d.ts.map +0 -1
- package/typings/glob.d.ts.map +0 -1
- package/typings/inclusion.d.ts.map +0 -1
- package/typings/index.d.ts.map +0 -1
- package/typings/predicateFile.d.ts.map +0 -1
- package/typings/render.d.ts.map +0 -1
- package/typings/scan.d.ts.map +0 -1
- package/typings/utils.d.ts.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, Igor Babkin
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Bundles your dependencies into a single container module.** `tic build` scans
|
|
4
4
|
your folders — by path or tsconfig alias — and generates one typed bundle that
|
|
5
5
|
registers every class in them, ready for
|
|
6
|
-
[`ts-ioc-container`](
|
|
6
|
+
[`ts-ioc-container`](https://www.npmjs.com/package/ts-ioc-container):
|
|
7
7
|
|
|
8
8
|
```ts
|
|
9
9
|
const container = new Container().useModule(new AppBundle());
|
package/cjm/bin.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-ioc-container/bundler",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Bundles your dependencies into a single container module for ts-ioc-container: the `tic` CLI scans folders (by path or tsconfig alias) and generates one typed bundle that registers every class
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Bundles your dependencies into a single container module for ts-ioc-container: the `tic` CLI scans folders (by path or tsconfig alias) and generates one typed bundle that registers every class — `container.useModule(new AppBundle())`.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -38,9 +38,8 @@
|
|
|
38
38
|
"files": [
|
|
39
39
|
"cjm/**/*",
|
|
40
40
|
"typings/**/*",
|
|
41
|
+
"!typings/**/*.d.ts.map",
|
|
41
42
|
"tpl/**/*",
|
|
42
|
-
"lib/**/*",
|
|
43
|
-
"!lib/**/*.hbs",
|
|
44
43
|
"tic.schema.json",
|
|
45
44
|
"AGENTS.md"
|
|
46
45
|
],
|
|
@@ -49,20 +48,6 @@
|
|
|
49
48
|
"url": "git+https://github.com/IgorBabkin/ts-ioc-container",
|
|
50
49
|
"directory": "packages/bundler"
|
|
51
50
|
},
|
|
52
|
-
"scripts": {
|
|
53
|
-
"hbs:compile": "mkdir -p tpl && handlebars lib/protocols/*.hbs -f tpl/index.cjs -c handlebars",
|
|
54
|
-
"build:cjm": "node ../scripts/build.mjs cjm",
|
|
55
|
-
"build:types": "node ../scripts/build.mjs types",
|
|
56
|
-
"build": "pnpm run hbs:compile && pnpm run build:cjm && pnpm run build:types",
|
|
57
|
-
"prepack": "pnpm run hbs:compile",
|
|
58
|
-
"test": "pnpm run hbs:compile && pnpm run build:cjm && vitest run",
|
|
59
|
-
"test:coverage": "pnpm run hbs:compile && pnpm run build:cjm && vitest run --coverage --coverage.reporter=lcov",
|
|
60
|
-
"type-check": "pnpm run hbs:compile && tsc --noEmit",
|
|
61
|
-
"lint": "eslint lib/**/*.ts __tests__/**/*.ts",
|
|
62
|
-
"lint:fix": "pnpm run lint --fix",
|
|
63
|
-
"format": "prettier --write \"lib/**/*.ts\" \"__tests__/**/*.ts\"",
|
|
64
|
-
"format:check": "prettier --check \"lib/**/*.ts\" \"__tests__/**/*.ts\""
|
|
65
|
-
},
|
|
66
51
|
"dependencies": {
|
|
67
52
|
"handlebars": "^4.7.9"
|
|
68
53
|
},
|
|
@@ -73,12 +58,25 @@
|
|
|
73
58
|
"@types/node": "^25.5.2",
|
|
74
59
|
"@vitest/coverage-v8": "^4.1.2",
|
|
75
60
|
"reflect-metadata": "^0.2.2",
|
|
76
|
-
"ts-ioc-container": "workspace:*",
|
|
77
61
|
"typescript": "5.8.3",
|
|
78
62
|
"unplugin-swc": "^1.6.0",
|
|
79
|
-
"vitest": "^4.1.11"
|
|
63
|
+
"vitest": "^4.1.11",
|
|
64
|
+
"ts-ioc-container": "72.3.2"
|
|
80
65
|
},
|
|
81
66
|
"engines": {
|
|
82
67
|
"node": ">= 18"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"hbs:compile": "mkdir -p tpl && handlebars lib/protocols/*.hbs -f tpl/index.cjs -c handlebars",
|
|
71
|
+
"build:cjm": "node ../scripts/build.mjs cjm",
|
|
72
|
+
"build:types": "node ../scripts/build.mjs types",
|
|
73
|
+
"build": "pnpm run hbs:compile && pnpm run build:cjm && pnpm run build:types",
|
|
74
|
+
"test": "pnpm run hbs:compile && pnpm run build:cjm && vitest run",
|
|
75
|
+
"test:coverage": "pnpm run hbs:compile && pnpm run build:cjm && vitest run --coverage --coverage.reporter=lcov",
|
|
76
|
+
"type-check": "pnpm run hbs:compile && tsc --noEmit",
|
|
77
|
+
"lint": "eslint lib/**/*.ts __tests__/**/*.ts",
|
|
78
|
+
"lint:fix": "pnpm run lint --fix",
|
|
79
|
+
"format": "prettier --write \"lib/**/*.ts\" \"__tests__/**/*.ts\"",
|
|
80
|
+
"format:check": "prettier --check \"lib/**/*.ts\" \"__tests__/**/*.ts\""
|
|
83
81
|
}
|
|
84
|
-
}
|
|
82
|
+
}
|
package/lib/ImportPaths.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { existsSync, statSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import * as ts from 'typescript';
|
|
4
|
-
import { NamespaceNotFoundError, TicConfigError } from './errors';
|
|
5
|
-
import { toPosix } from './glob';
|
|
6
|
-
|
|
7
|
-
interface Alias {
|
|
8
|
-
pattern: string;
|
|
9
|
-
/** Absolute, `/`-separated. */
|
|
10
|
-
targets: string[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const SOURCE_EXTENSION = /\.(tsx?|mts|cts)$/;
|
|
14
|
-
/** tsconfig "No inputs were found": irrelevant here, the bundler scans its own folders. */
|
|
15
|
-
const NO_INPUTS = 18003;
|
|
16
|
-
|
|
17
|
-
const isDirectory = (dir: string) => existsSync(dir) && statSync(dir).isDirectory();
|
|
18
|
-
const isRelative = (spec: string) => spec.startsWith('.') || path.isAbsolute(spec);
|
|
19
|
-
|
|
20
|
-
/** Splits a `paths` pattern at its `*`, if it has one. */
|
|
21
|
-
function splitWildcard(pattern: string): [string, string] | undefined {
|
|
22
|
-
const star = pattern.indexOf('*');
|
|
23
|
-
return star === -1 ? undefined : [pattern.slice(0, star), pattern.slice(star + 1)];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Import paths as a project's `tsconfig.json` sees them: resolves namespaces
|
|
28
|
-
* written as `paths` aliases to folders, and writes imports back in alias form.
|
|
29
|
-
*/
|
|
30
|
-
export class ImportPaths {
|
|
31
|
-
/**
|
|
32
|
-
* Reads `paths` (following `extends`) and the extension imports need under the
|
|
33
|
-
* tsconfig's `moduleResolution`; `importExtension` overrides the latter.
|
|
34
|
-
*
|
|
35
|
-
* @throws {TicConfigError} when a required tsconfig is missing or cannot be parsed.
|
|
36
|
-
*/
|
|
37
|
-
static load(tsconfig: { file: string; required: boolean }, importExtension?: string): ImportPaths {
|
|
38
|
-
if (!existsSync(tsconfig.file)) {
|
|
39
|
-
if (tsconfig.required) throw new TicConfigError(`tsconfig not found: ${tsconfig.file}`);
|
|
40
|
-
return new ImportPaths([], importExtension ?? '');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const { config, error } = ts.readConfigFile(tsconfig.file, ts.sys.readFile);
|
|
44
|
-
const parsed = ts.parseJsonConfigFileContent(config, ts.sys, path.dirname(tsconfig.file), undefined, tsconfig.file);
|
|
45
|
-
const [fatal] = [error, ...parsed.errors].filter((d): d is ts.Diagnostic => !!d && d.code !== NO_INPUTS);
|
|
46
|
-
if (fatal) {
|
|
47
|
-
throw new TicConfigError(`${tsconfig.file}: ${ts.flattenDiagnosticMessageText(fatal.messageText, '\n')}`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const { paths = {}, baseUrl, pathsBasePath, moduleResolution } = parsed.options;
|
|
51
|
-
// Without baseUrl, paths resolve against the tsconfig that declared them (which `extends` may make another file).
|
|
52
|
-
const base = baseUrl ?? (typeof pathsBasePath === 'string' ? pathsBasePath : path.dirname(tsconfig.file));
|
|
53
|
-
const aliases = Object.entries(paths).map(([pattern, targets]) => ({
|
|
54
|
-
pattern,
|
|
55
|
-
targets: targets.map((target) => toPosix(path.resolve(base, target))),
|
|
56
|
-
}));
|
|
57
|
-
const nodeEsm =
|
|
58
|
-
moduleResolution === ts.ModuleResolutionKind.Node16 || moduleResolution === ts.ModuleResolutionKind.NodeNext;
|
|
59
|
-
return new ImportPaths(aliases, importExtension ?? (nodeEsm ? '.js' : ''));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
constructor(
|
|
63
|
-
private readonly aliases: Alias[],
|
|
64
|
-
readonly extension: string,
|
|
65
|
-
) {}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* The folder a namespace names: a path relative to `baseDir`, or a `paths` alias.
|
|
69
|
-
*
|
|
70
|
-
* @throws {NamespaceNotFoundError} when the namespace is neither an existing folder nor an alias of one.
|
|
71
|
-
*/
|
|
72
|
-
resolveNamespace(namespace: string, baseDir: string): string {
|
|
73
|
-
const folder = path.resolve(baseDir, namespace);
|
|
74
|
-
if (isDirectory(folder)) return folder;
|
|
75
|
-
if (!isRelative(namespace)) {
|
|
76
|
-
// `@app` also matches an `@app/*` pattern, naming the alias root itself.
|
|
77
|
-
const found = [namespace, `${namespace}/`].flatMap((spec) => this.aliasTargets(spec)).find(isDirectory);
|
|
78
|
-
if (found) return path.normalize(found);
|
|
79
|
-
}
|
|
80
|
-
throw new NamespaceNotFoundError(
|
|
81
|
-
`namespace "${namespace}" is neither a folder relative to ${baseDir} nor a tsconfig paths alias of one`,
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** The specifier `fromFile` imports `toFile` by: its most specific alias, else a relative path. */
|
|
86
|
-
specifier(fromFile: string, toFile: string): string {
|
|
87
|
-
const target = toPosix(toFile);
|
|
88
|
-
const bare = target.replace(SOURCE_EXTENSION, '');
|
|
89
|
-
let best: { spec: string; score: number } | undefined;
|
|
90
|
-
for (const { pattern, targets } of this.aliases) {
|
|
91
|
-
for (const aliasTarget of targets) {
|
|
92
|
-
const match = this.matchAlias(pattern, aliasTarget, target, bare);
|
|
93
|
-
if (match && (!best || match.score > best.score)) best = match;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (best) return best.spec;
|
|
97
|
-
|
|
98
|
-
const relative = toPosix(path.relative(path.dirname(fromFile), bare));
|
|
99
|
-
return `${relative.startsWith('.') ? relative : `./${relative}`}${this.extension}`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private aliasTargets(spec: string): string[] {
|
|
103
|
-
return this.aliases.flatMap(({ pattern, targets }) => {
|
|
104
|
-
const wildcard = splitWildcard(pattern);
|
|
105
|
-
if (!wildcard) return pattern === spec ? targets : [];
|
|
106
|
-
const [prefix, suffix] = wildcard;
|
|
107
|
-
if (!spec.startsWith(prefix) || !spec.endsWith(suffix) || spec.length < prefix.length + suffix.length) return [];
|
|
108
|
-
const captured = spec.slice(prefix.length, spec.length - suffix.length);
|
|
109
|
-
return targets.map((target) => target.replace('*', captured));
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** A longer matched target prefix is a more specific alias; an exact file alias beats every wildcard. */
|
|
114
|
-
private matchAlias(pattern: string, aliasTarget: string, file: string, bare: string) {
|
|
115
|
-
const wildcard = splitWildcard(aliasTarget);
|
|
116
|
-
if (!wildcard) {
|
|
117
|
-
const exact = aliasTarget === file || aliasTarget.replace(SOURCE_EXTENSION, '') === bare;
|
|
118
|
-
return exact && !splitWildcard(pattern) ? { spec: pattern, score: Infinity } : undefined;
|
|
119
|
-
}
|
|
120
|
-
const [prefix, suffix] = wildcard;
|
|
121
|
-
if (!bare.startsWith(prefix) || !bare.endsWith(suffix) || bare.length < prefix.length + suffix.length) {
|
|
122
|
-
return undefined;
|
|
123
|
-
}
|
|
124
|
-
const captured = bare.slice(prefix.length, bare.length - suffix.length);
|
|
125
|
-
return { spec: `${pattern.replace('*', captured)}${this.extension}`, score: prefix.length };
|
|
126
|
-
}
|
|
127
|
-
}
|
package/lib/bin.ts
DELETED
package/lib/build.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { DEFAULT_CONFIG_FILE, loadConfig, type ResolvedConfig, type ResolvedBundle } from './config';
|
|
4
|
-
import { emitBundle } from './emit';
|
|
5
|
-
import { globToRegExp, toPosix } from './glob';
|
|
6
|
-
import { ImportPaths } from './ImportPaths';
|
|
7
|
-
import { type ExportPredicate, findConventionalExportPredicate, loadExportPredicate } from './exportPredicate';
|
|
8
|
-
import { fileTags, findConventionalPredicate, type InclusionPredicate, loadInclusionPredicate } from './inclusion';
|
|
9
|
-
import { findClasses, listSourceFiles } from './scan';
|
|
10
|
-
|
|
11
|
-
export interface BuildOptions {
|
|
12
|
-
/** Path of `tic.config.json`, relative to `cwd`. Default `tic.config.json`. */
|
|
13
|
-
config?: string;
|
|
14
|
-
/** Default `process.cwd()`. */
|
|
15
|
-
cwd?: string;
|
|
16
|
-
/** Compare instead of writing: outputs that would change are reported `stale`. */
|
|
17
|
-
check?: boolean;
|
|
18
|
-
/** Decides which scanned files take part; overrides every inclusion predicate file. */
|
|
19
|
-
include?: InclusionPredicate;
|
|
20
|
-
/** Decides which parsed classes become registrations; overrides every export predicate file. */
|
|
21
|
-
filterExports?: ExportPredicate;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** `written` / `unchanged` after a build; `stale` / `unchanged` after a check. */
|
|
25
|
-
export type OutputStatus = 'written' | 'unchanged' | 'stale';
|
|
26
|
-
|
|
27
|
-
export interface OutputResult {
|
|
28
|
-
/** Absolute path of the generated file. */
|
|
29
|
-
file: string;
|
|
30
|
-
/** Name of the generated class. */
|
|
31
|
-
bundle: string;
|
|
32
|
-
status: OutputStatus;
|
|
33
|
-
registrations: number;
|
|
34
|
-
content: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface BuildResult {
|
|
38
|
-
/** Absolute path of the config that was built. */
|
|
39
|
-
config: string;
|
|
40
|
-
outputs: OutputResult[];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Generates one bundle per config entry. Every bundle is generated before any
|
|
45
|
-
* file is written, so a failing namespace leaves the previous outputs intact.
|
|
46
|
-
*
|
|
47
|
-
* @throws {TicConfigError} when the config, the tsconfig or a predicate file it names is missing or invalid.
|
|
48
|
-
* @throws {NamespaceNotFoundError} when a namespace is neither a folder nor a tsconfig paths alias of one.
|
|
49
|
-
*/
|
|
50
|
-
export function build({
|
|
51
|
-
config = DEFAULT_CONFIG_FILE,
|
|
52
|
-
cwd = process.cwd(),
|
|
53
|
-
check = false,
|
|
54
|
-
include,
|
|
55
|
-
filterExports,
|
|
56
|
-
}: BuildOptions = {}): BuildResult {
|
|
57
|
-
const resolved = loadConfig(path.resolve(cwd, config));
|
|
58
|
-
const paths = ImportPaths.load(resolved.tsconfig, resolved.importExtension);
|
|
59
|
-
const includeFor = predicateResolver({
|
|
60
|
-
override: include,
|
|
61
|
-
conventional: findConventionalPredicate(resolved.dir),
|
|
62
|
-
fileOf: (bundle) => bundle.include,
|
|
63
|
-
load: loadInclusionPredicate,
|
|
64
|
-
});
|
|
65
|
-
const filterExportsFor = predicateResolver({
|
|
66
|
-
override: filterExports,
|
|
67
|
-
conventional: findConventionalExportPredicate(resolved.dir),
|
|
68
|
-
fileOf: (bundle) => bundle.filterExports,
|
|
69
|
-
load: loadExportPredicate,
|
|
70
|
-
});
|
|
71
|
-
const generated = resolved.bundles.map((bundle) =>
|
|
72
|
-
generate(resolved, bundle, paths, { include: includeFor(bundle), filterExports: filterExportsFor(bundle) }),
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const outputs = generated.map(({ bundle, content, registrations }): OutputResult => {
|
|
76
|
-
const current = existsSync(bundle.output) ? readFileSync(bundle.output, 'utf8') : undefined;
|
|
77
|
-
const status: OutputStatus = current === content ? 'unchanged' : check ? 'stale' : 'written';
|
|
78
|
-
if (status === 'written') {
|
|
79
|
-
mkdirSync(path.dirname(bundle.output), { recursive: true });
|
|
80
|
-
writeFileSync(bundle.output, content);
|
|
81
|
-
}
|
|
82
|
-
return { file: bundle.output, bundle: bundle.name, status, registrations, content };
|
|
83
|
-
});
|
|
84
|
-
return { config: resolved.file, outputs };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Which predicate of one kind a bundle uses: the one passed to `build`, else the bundle's own file,
|
|
89
|
-
* else the conventional file next to the config, else none. Each file is loaded once, and only when
|
|
90
|
-
* a bundle needs it.
|
|
91
|
-
*
|
|
92
|
-
* @throws {TicConfigError} when a predicate file a bundle needs is missing or does not export a function.
|
|
93
|
-
*/
|
|
94
|
-
function predicateResolver<P>({
|
|
95
|
-
override,
|
|
96
|
-
conventional,
|
|
97
|
-
fileOf,
|
|
98
|
-
load,
|
|
99
|
-
}: {
|
|
100
|
-
override?: P;
|
|
101
|
-
conventional?: string;
|
|
102
|
-
fileOf: (bundle: ResolvedBundle) => string | undefined;
|
|
103
|
-
load: (file: string) => P;
|
|
104
|
-
}) {
|
|
105
|
-
const loaded = new Map<string, P>();
|
|
106
|
-
return (bundle: ResolvedBundle): P | undefined => {
|
|
107
|
-
if (override) return override;
|
|
108
|
-
const file = fileOf(bundle) ?? conventional;
|
|
109
|
-
if (file === undefined) return undefined;
|
|
110
|
-
if (!loaded.has(file)) loaded.set(file, load(file));
|
|
111
|
-
return loaded.get(file);
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* @throws {NamespaceNotFoundError} when a namespace is neither a folder nor a tsconfig paths alias of one.
|
|
117
|
-
*/
|
|
118
|
-
function generate(
|
|
119
|
-
config: ResolvedConfig,
|
|
120
|
-
bundle: ResolvedBundle,
|
|
121
|
-
paths: ImportPaths,
|
|
122
|
-
{ include, filterExports }: { include?: InclusionPredicate; filterExports?: ExportPredicate },
|
|
123
|
-
) {
|
|
124
|
-
const relative = (file: string) => toPosix(path.relative(config.dir, file));
|
|
125
|
-
const outputs = new Set(config.bundles.map((m) => m.output));
|
|
126
|
-
const excludes = bundle.exclude.map(globToRegExp);
|
|
127
|
-
const isExcluded = (file: string) => {
|
|
128
|
-
if (outputs.has(file)) return true;
|
|
129
|
-
const filename = relative(file);
|
|
130
|
-
return excludes.some((glob) => glob.test(filename)) || (include !== undefined && !include({ filename }));
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const files = new Set<string>();
|
|
134
|
-
for (const namespace of bundle.namespaces) {
|
|
135
|
-
const dir = paths.resolveNamespace(namespace.path, config.dir);
|
|
136
|
-
for (const file of listSourceFiles(dir, namespace.recursive, isExcluded)) files.add(file);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const classes = [...files]
|
|
140
|
-
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
141
|
-
.flatMap((file) => findClasses(file, bundle.select))
|
|
142
|
-
.filter((cls) => {
|
|
143
|
-
if (!filterExports) return true;
|
|
144
|
-
const filename = relative(cls.file);
|
|
145
|
-
const { exportName, className, isDefault, decorators } = cls;
|
|
146
|
-
return filterExports({ filename, exportName, className, isDefault, decorators, tags: fileTags(filename) });
|
|
147
|
-
})
|
|
148
|
-
.map((cls) => ({ ...cls, specifier: paths.specifier(bundle.output, cls.file) }));
|
|
149
|
-
|
|
150
|
-
const content = emitBundle({
|
|
151
|
-
name: bundle.name,
|
|
152
|
-
configPath: toPosix(path.relative(path.dirname(bundle.output), config.file)),
|
|
153
|
-
namespaces: bundle.namespaces.map((ns) => ns.path),
|
|
154
|
-
classes,
|
|
155
|
-
});
|
|
156
|
-
return { bundle, content, registrations: classes.length };
|
|
157
|
-
}
|
package/lib/cli.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { build, type OutputStatus } from './build';
|
|
4
|
-
import { TicError } from './errors';
|
|
5
|
-
|
|
6
|
-
export interface CliIo {
|
|
7
|
-
cwd: string;
|
|
8
|
-
stdout: (line: string) => void;
|
|
9
|
-
stderr: (line: string) => void;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const USAGE = [
|
|
13
|
-
'Usage: ts-ioc-container <command> [options]',
|
|
14
|
-
' tic is a shortcut for ts-ioc-container',
|
|
15
|
-
'',
|
|
16
|
-
'Commands:',
|
|
17
|
-
' ts-ioc-container build [--config <path>] [--check] generate the bundles described by tic.config.json',
|
|
18
|
-
'',
|
|
19
|
-
'Options:',
|
|
20
|
-
' -c, --config <path> config file (default: tic.config.json)',
|
|
21
|
-
' --check write nothing; exit 1 when a generated bundle is out of date',
|
|
22
|
-
' -h, --help show this help',
|
|
23
|
-
' -v, --version show the version',
|
|
24
|
-
].join('\n');
|
|
25
|
-
|
|
26
|
-
const VERB: Record<OutputStatus, string> = { written: 'wrote', unchanged: 'unchanged', stale: 'stale' };
|
|
27
|
-
|
|
28
|
-
const plural = (n: number) => `${n} registration${n === 1 ? '' : 's'}`;
|
|
29
|
-
|
|
30
|
-
function version(): string {
|
|
31
|
-
return JSON.parse(readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')).version;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
class UsageError extends TicError {}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @throws {UsageError} when an option is unknown or `--config` has no value.
|
|
38
|
-
*/
|
|
39
|
-
function parseBuildArgs(args: string[]) {
|
|
40
|
-
const options: { config?: string; check: boolean } = { check: false };
|
|
41
|
-
for (let i = 0; i < args.length; i++) {
|
|
42
|
-
const arg = args[i];
|
|
43
|
-
if (arg === '--check') options.check = true;
|
|
44
|
-
else if (arg === '--config' || arg === '-c') {
|
|
45
|
-
options.config = args[++i];
|
|
46
|
-
if (!options.config) throw new UsageError(`${arg} needs a path`);
|
|
47
|
-
} else if (arg.startsWith('--config=')) options.config = arg.slice('--config='.length);
|
|
48
|
-
else throw new UsageError(`unknown option "${arg}"`);
|
|
49
|
-
}
|
|
50
|
-
return options;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Runs the `tic` CLI and returns its exit code; output goes through `io`. */
|
|
54
|
-
export function run(
|
|
55
|
-
argv: string[],
|
|
56
|
-
io: CliIo = { cwd: process.cwd(), stdout: console.log, stderr: console.error },
|
|
57
|
-
): number {
|
|
58
|
-
const [command, ...rest] = argv;
|
|
59
|
-
if (command === '--help' || command === '-h' || command === 'help') {
|
|
60
|
-
io.stdout(USAGE);
|
|
61
|
-
return 0;
|
|
62
|
-
}
|
|
63
|
-
if (command === '--version' || command === '-v') {
|
|
64
|
-
io.stdout(version());
|
|
65
|
-
return 0;
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
if (command !== 'build') {
|
|
69
|
-
io.stderr(command ? `tic: unknown command "${command}"` : USAGE);
|
|
70
|
-
return 1;
|
|
71
|
-
}
|
|
72
|
-
const { config, check } = parseBuildArgs(rest);
|
|
73
|
-
const { outputs } = build({ config, check, cwd: io.cwd });
|
|
74
|
-
for (const { status, file, registrations } of outputs) {
|
|
75
|
-
io.stdout(`${VERB[status].padEnd(10)}${path.relative(io.cwd, file)} (${plural(registrations)})`);
|
|
76
|
-
}
|
|
77
|
-
const stale = outputs.filter((o) => o.status === 'stale').length;
|
|
78
|
-
if (stale > 0) {
|
|
79
|
-
io.stderr(`tic: ${stale} generated bundle${stale === 1 ? ' is' : 's are'} out of date — run \`tic build\``);
|
|
80
|
-
return 1;
|
|
81
|
-
}
|
|
82
|
-
return 0;
|
|
83
|
-
} catch (e) {
|
|
84
|
-
if (!(e instanceof TicError)) throw e;
|
|
85
|
-
io.stderr(`tic: ${e.message}`);
|
|
86
|
-
return 1;
|
|
87
|
-
}
|
|
88
|
-
}
|
package/lib/config.ts
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { TicConfigError } from './errors';
|
|
4
|
-
import { globToRegExp } from './glob';
|
|
5
|
-
|
|
6
|
-
/** Which exports of a file count: both kinds, only named exports, or only the default export. */
|
|
7
|
-
export type ExportKind = 'any' | 'named' | 'default';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* How the bundler picks target classes out of a file. A class is selected when
|
|
11
|
-
* it is exported, not abstract, and meets every criterion set here; an empty
|
|
12
|
-
* rule selects every exported class.
|
|
13
|
-
*/
|
|
14
|
-
export interface ClassSelector {
|
|
15
|
-
/** Default `any`. */
|
|
16
|
-
export?: ExportKind;
|
|
17
|
-
/** The class must carry one of these decorators, recognised by name (`register`, or a composed one). */
|
|
18
|
-
decorators?: string[];
|
|
19
|
-
/** A glob the class name must match, e.g. `*Service`. An anonymous default export is named after its file. */
|
|
20
|
-
nameGlob?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** A {@link ClassSelector} with its defaults filled in and its `nameGlob` compiled. */
|
|
24
|
-
export interface ResolvedSelector {
|
|
25
|
-
export: ExportKind;
|
|
26
|
-
decorators?: string[];
|
|
27
|
-
nameGlob?: RegExp;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface NamespaceConfig {
|
|
31
|
-
/** A folder relative to the config file (`./src/services`) or a tsconfig `paths` alias (`@app/services`). */
|
|
32
|
-
path: string;
|
|
33
|
-
/** Scan sub-folders too. Default `true`. */
|
|
34
|
-
recursive?: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface BundleConfig {
|
|
38
|
-
/** The generated file, relative to the config file. */
|
|
39
|
-
output: string;
|
|
40
|
-
/** Name of the generated class, an `IContainerModule`. Default `Bundle`. */
|
|
41
|
-
name?: string;
|
|
42
|
-
namespaces: (string | NamespaceConfig)[];
|
|
43
|
-
/** Which classes of a scanned file are registered. Default: every exported class. */
|
|
44
|
-
select?: ClassSelector;
|
|
45
|
-
/** Globs, relative to the config file, of files never scanned. Replaces {@link DEFAULT_EXCLUDE} when given. */
|
|
46
|
-
exclude?: string[];
|
|
47
|
-
/**
|
|
48
|
-
* A file exporting an `InclusionPredicate`, relative to the config file. Overrides the
|
|
49
|
-
* conventional `tic.include.*` next to the config.
|
|
50
|
-
*/
|
|
51
|
-
include?: string;
|
|
52
|
-
/**
|
|
53
|
-
* A file exporting an `ExportPredicate`, relative to the config file. Overrides the
|
|
54
|
-
* conventional `tic.exports.*` next to the config.
|
|
55
|
-
*/
|
|
56
|
-
filterExports?: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** The shape of `tic.config.json`. */
|
|
60
|
-
export interface TicConfig {
|
|
61
|
-
$schema?: string;
|
|
62
|
-
/** Relative to the config file. Default `tsconfig.json`, which may be absent. */
|
|
63
|
-
tsconfig?: string;
|
|
64
|
-
/** Extension of generated imports. Inferred from the tsconfig's `moduleResolution` when omitted. */
|
|
65
|
-
importExtension?: string;
|
|
66
|
-
bundles: BundleConfig[];
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const DEFAULT_CONFIG_FILE = 'tic.config.json';
|
|
70
|
-
export const DEFAULT_BUNDLE_NAME = 'Bundle';
|
|
71
|
-
export const DEFAULT_EXCLUDE = [
|
|
72
|
-
'**/*.spec.ts',
|
|
73
|
-
'**/*.test.ts',
|
|
74
|
-
'**/*.spec.tsx',
|
|
75
|
-
'**/*.test.tsx',
|
|
76
|
-
'**/__tests__/**',
|
|
77
|
-
'**/node_modules/**',
|
|
78
|
-
];
|
|
79
|
-
|
|
80
|
-
/** A config whose defaults are filled in and whose paths are absolute. */
|
|
81
|
-
export interface ResolvedConfig {
|
|
82
|
-
file: string;
|
|
83
|
-
dir: string;
|
|
84
|
-
tsconfig: { file: string; required: boolean };
|
|
85
|
-
importExtension?: string;
|
|
86
|
-
bundles: ResolvedBundle[];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export interface ResolvedBundle {
|
|
90
|
-
output: string;
|
|
91
|
-
name: string;
|
|
92
|
-
namespaces: Required<NamespaceConfig>[];
|
|
93
|
-
select: ResolvedSelector;
|
|
94
|
-
exclude: string[];
|
|
95
|
-
/** Absolute path of the bundle's own predicate file, when it names one. */
|
|
96
|
-
include?: string;
|
|
97
|
-
/** Absolute path of the bundle's own export predicate file, when it names one. */
|
|
98
|
-
filterExports?: string;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
type Json = Record<string, unknown>;
|
|
102
|
-
|
|
103
|
-
const isObject = (value: unknown): value is Json =>
|
|
104
|
-
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
105
|
-
const isNonEmptyString = (value: unknown): value is string => typeof value === 'string' && value.length > 0;
|
|
106
|
-
const isStringArray = (value: unknown): value is string[] => Array.isArray(value) && value.every(isNonEmptyString);
|
|
107
|
-
const isIdentifier = (value: unknown): value is string => typeof value === 'string' && /^[A-Za-z_$][\w$]*$/.test(value);
|
|
108
|
-
|
|
109
|
-
const fail = (field: string, expected: string): never => {
|
|
110
|
-
throw new TicConfigError(`${field}: expected ${expected}`);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* @throws {TicConfigError} when a namespace entry is neither a non-empty string nor an object with a `path`.
|
|
115
|
-
*/
|
|
116
|
-
function toNamespace(value: unknown, field: string): Required<NamespaceConfig> {
|
|
117
|
-
if (isNonEmptyString(value)) return { path: value, recursive: true };
|
|
118
|
-
if (!isObject(value)) return fail(field, 'a string or an object with "path"');
|
|
119
|
-
if (!isNonEmptyString(value.path)) return fail(`${field}.path`, 'a non-empty string');
|
|
120
|
-
if (value.recursive !== undefined && typeof value.recursive !== 'boolean')
|
|
121
|
-
return fail(`${field}.recursive`, 'a boolean');
|
|
122
|
-
return { path: value.path, recursive: value.recursive ?? true };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const SELECTOR_FIELDS = new Set(['export', 'decorators', 'nameGlob']);
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* @throws {TicConfigError} when the rule is not an object, has an unknown field, or a field has the wrong type.
|
|
129
|
-
*/
|
|
130
|
-
function toSelector(value: unknown, field: string): ResolvedSelector {
|
|
131
|
-
if (value === undefined) return { export: 'any' };
|
|
132
|
-
if (!isObject(value)) return fail(field, 'an object');
|
|
133
|
-
const unknown = Object.keys(value).find((key) => !SELECTOR_FIELDS.has(key));
|
|
134
|
-
if (unknown) throw new TicConfigError(`${field}.${unknown}: unknown field`);
|
|
135
|
-
const { export: kind, decorators, nameGlob } = value;
|
|
136
|
-
if (kind !== undefined && kind !== 'any' && kind !== 'named' && kind !== 'default') {
|
|
137
|
-
return fail(`${field}.export`, '"any", "named" or "default"');
|
|
138
|
-
}
|
|
139
|
-
if (decorators !== undefined && !(isStringArray(decorators) && decorators.length > 0)) {
|
|
140
|
-
return fail(`${field}.decorators`, 'a non-empty array of strings');
|
|
141
|
-
}
|
|
142
|
-
if (nameGlob !== undefined && !isNonEmptyString(nameGlob)) return fail(`${field}.nameGlob`, 'a non-empty string');
|
|
143
|
-
return { export: kind ?? 'any', decorators, nameGlob: nameGlob === undefined ? undefined : globToRegExp(nameGlob) };
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* @throws {TicConfigError} when a bundle field is missing or has the wrong type.
|
|
148
|
-
*/
|
|
149
|
-
function toBundle(value: unknown, field: string, dir: string): ResolvedBundle {
|
|
150
|
-
if (!isObject(value)) return fail(field, 'an object');
|
|
151
|
-
const { output, name, namespaces, select, exclude, include, filterExports } = value;
|
|
152
|
-
if (!isNonEmptyString(output)) return fail(`${field}.output`, 'a non-empty string');
|
|
153
|
-
if (name !== undefined && !isIdentifier(name)) return fail(`${field}.name`, 'a valid identifier');
|
|
154
|
-
if (!Array.isArray(namespaces) || namespaces.length === 0) return fail(`${field}.namespaces`, 'a non-empty array');
|
|
155
|
-
if (exclude !== undefined && !isStringArray(exclude)) return fail(`${field}.exclude`, 'an array of strings');
|
|
156
|
-
if (include !== undefined && !isNonEmptyString(include)) return fail(`${field}.include`, 'a non-empty string');
|
|
157
|
-
if (filterExports !== undefined && !isNonEmptyString(filterExports)) {
|
|
158
|
-
return fail(`${field}.filterExports`, 'a non-empty string');
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
output: path.resolve(dir, output),
|
|
162
|
-
name: name ?? DEFAULT_BUNDLE_NAME,
|
|
163
|
-
namespaces: namespaces.map((ns, i) => toNamespace(ns, `${field}.namespaces[${i}]`)),
|
|
164
|
-
select: toSelector(select, `${field}.select`),
|
|
165
|
-
exclude: exclude ?? DEFAULT_EXCLUDE,
|
|
166
|
-
include: include === undefined ? undefined : path.resolve(dir, include),
|
|
167
|
-
filterExports: filterExports === undefined ? undefined : path.resolve(dir, filterExports),
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Validates parsed `tic.config.json` content and resolves its paths against `file`'s directory.
|
|
173
|
-
*
|
|
174
|
-
* @throws {TicConfigError} when the content does not match the config shape; the message names the field.
|
|
175
|
-
*/
|
|
176
|
-
export function resolveConfig(content: unknown, file: string): ResolvedConfig {
|
|
177
|
-
const dir = path.dirname(file);
|
|
178
|
-
if (!isObject(content)) return fail('config', 'a JSON object');
|
|
179
|
-
const { tsconfig, importExtension, bundles } = content;
|
|
180
|
-
if (tsconfig !== undefined && !isNonEmptyString(tsconfig)) return fail('tsconfig', 'a non-empty string');
|
|
181
|
-
if (importExtension !== undefined && typeof importExtension !== 'string') return fail('importExtension', 'a string');
|
|
182
|
-
if (!Array.isArray(bundles) || bundles.length === 0) return fail('bundles', 'a non-empty array');
|
|
183
|
-
return {
|
|
184
|
-
file,
|
|
185
|
-
dir,
|
|
186
|
-
tsconfig: { file: path.resolve(dir, tsconfig ?? 'tsconfig.json'), required: tsconfig !== undefined },
|
|
187
|
-
importExtension,
|
|
188
|
-
bundles: bundles.map((m, i) => toBundle(m, `bundles[${i}]`, dir)),
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Reads and validates a `tic.config.json`.
|
|
194
|
-
*
|
|
195
|
-
* @throws {TicConfigError} when the file is missing, is not valid JSON, or does not match the config shape.
|
|
196
|
-
*/
|
|
197
|
-
export function loadConfig(file: string): ResolvedConfig {
|
|
198
|
-
if (!existsSync(file)) throw new TicConfigError(`config file not found: ${file}`);
|
|
199
|
-
let content: unknown;
|
|
200
|
-
try {
|
|
201
|
-
content = JSON.parse(readFileSync(file, 'utf8'));
|
|
202
|
-
} catch (e) {
|
|
203
|
-
throw new TicConfigError(`${file} is not valid JSON: ${(e as Error).message}`);
|
|
204
|
-
}
|
|
205
|
-
return resolveConfig(content, file);
|
|
206
|
-
}
|
package/lib/emit.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { renderProtocol } from './render';
|
|
2
|
-
import type { DiscoveredClass } from './scan';
|
|
3
|
-
|
|
4
|
-
export interface EmitInput {
|
|
5
|
-
/** Name of the generated class. */
|
|
6
|
-
name: string;
|
|
7
|
-
/** Shown in the header: where the output came from. */
|
|
8
|
-
configPath: string;
|
|
9
|
-
namespaces: string[];
|
|
10
|
-
classes: (DiscoveredClass & { specifier: string })[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const RUNTIME_IMPORTS = ['IContainer', 'IContainerModule', 'IRegistration', 'Registration'];
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Renders the generated bundle — static imports, `registrations`, and the bundle applying them —
|
|
17
|
-
* from its protocol, `protocols/Bundle.ts.hbs`. This function only prepares the data: unique local
|
|
18
|
-
* names, and one import per file in file order.
|
|
19
|
-
*/
|
|
20
|
-
export function emitBundle({ name, configPath, namespaces, classes }: EmitInput): string {
|
|
21
|
-
const taken = new Set([...RUNTIME_IMPORTS, 'registrations', name]);
|
|
22
|
-
const uniqueName = (wanted: string) => {
|
|
23
|
-
let candidate = wanted;
|
|
24
|
-
for (let n = 2; taken.has(candidate); n++) candidate = `${wanted}_${n}`;
|
|
25
|
-
taken.add(candidate);
|
|
26
|
-
return candidate;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// One import statement per file, in file order.
|
|
30
|
-
const byFile = new Map<string, { specifier: string; defaultName?: string; named: string[] }>();
|
|
31
|
-
const bindings = classes.map((cls) => {
|
|
32
|
-
const binding = uniqueName(cls.localName);
|
|
33
|
-
const entry = byFile.get(cls.file) ?? { specifier: cls.specifier, named: [] };
|
|
34
|
-
byFile.set(cls.file, entry);
|
|
35
|
-
if (cls.exportName === 'default') entry.defaultName = binding;
|
|
36
|
-
else entry.named.push(binding === cls.exportName ? binding : `${cls.exportName} as ${binding}`);
|
|
37
|
-
return binding;
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return renderProtocol('Bundle.ts.hbs', {
|
|
41
|
-
configPath,
|
|
42
|
-
namespaces,
|
|
43
|
-
name,
|
|
44
|
-
imports: [...byFile.values()],
|
|
45
|
-
registrations: bindings,
|
|
46
|
-
});
|
|
47
|
-
}
|
package/lib/errors.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/** Base class of every error the bundler raises on purpose; the CLI prints its message without a stack. */
|
|
2
|
-
export class TicError extends Error {
|
|
3
|
-
name = 'TicError';
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
/** The config file is missing, is not JSON, or does not match the `tic.config.json` shape. */
|
|
7
|
-
export class TicConfigError extends TicError {
|
|
8
|
-
name = 'TicConfigError';
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** A namespace is neither an existing folder nor a `tsconfig.json` `paths` alias of one. */
|
|
12
|
-
export class NamespaceNotFoundError extends TicError {
|
|
13
|
-
name = 'NamespaceNotFoundError';
|
|
14
|
-
}
|
package/lib/exportPredicate.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { conventionalNames, findConventionalFile, loadPredicateFile } from './predicateFile';
|
|
2
|
-
import type { FilterPredicate } from './utils';
|
|
3
|
-
|
|
4
|
-
/** What an {@link ExportPredicate} decides on: one exported class of a parsed file. */
|
|
5
|
-
export interface ExportContext {
|
|
6
|
-
/** The file's path relative to the config file, `/`-separated: `src/services/Logger.ts`. */
|
|
7
|
-
filename: string;
|
|
8
|
-
/** The name the class is exported under; `'default'` for a default export. */
|
|
9
|
-
exportName: string;
|
|
10
|
-
/** The declared class name; an anonymous default export is named after its file. */
|
|
11
|
-
className: string;
|
|
12
|
-
isDefault: boolean;
|
|
13
|
-
/** Names of the class's decorators, renamed imports resolved (`register as reg` -> `'register'`). */
|
|
14
|
-
decorators: string[];
|
|
15
|
-
/** The file-name tags `byTags` reads: `Report.production.eu.ts` -> `['production', 'eu']`. */
|
|
16
|
-
tags: string[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Decides, right after a file is parsed, whether one of its exported classes becomes a
|
|
21
|
-
* registration. It runs on every exported, non-abstract class that passes `select`.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* // tic.exports.ts, next to tic.config.json - picked up by convention
|
|
25
|
-
* const filterExports: ExportPredicate = ({ exportName }) => !/(Stub|Mock|Fake)$/.test(exportName);
|
|
26
|
-
* export default filterExports;
|
|
27
|
-
*/
|
|
28
|
-
export type ExportPredicate = FilterPredicate<ExportContext>;
|
|
29
|
-
|
|
30
|
-
/** Export predicate files looked up next to the config, in this order, when no bundle names one. */
|
|
31
|
-
export const EXPORTS_CONVENTION = conventionalNames('tic.exports');
|
|
32
|
-
|
|
33
|
-
/** The conventional export predicate file in `dir`, if there is one. */
|
|
34
|
-
export function findConventionalExportPredicate(dir: string): string | undefined {
|
|
35
|
-
return findConventionalFile(dir, 'tic.exports');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Loads an {@link ExportPredicate} file (see `loadPredicateFile` for formats and caching).
|
|
40
|
-
*
|
|
41
|
-
* @throws {TicConfigError} when the file is missing or does not export a function.
|
|
42
|
-
*/
|
|
43
|
-
export function loadExportPredicate(file: string): ExportPredicate {
|
|
44
|
-
return loadPredicateFile<ExportPredicate>(file, 'ExportPredicate');
|
|
45
|
-
}
|
package/lib/glob.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Converts a glob to an anchored RegExp over `/`-separated paths: `**` spans
|
|
3
|
-
* folders (`**\/` also matches none), `*` and `?` stay within one segment.
|
|
4
|
-
*/
|
|
5
|
-
export function globToRegExp(glob: string): RegExp {
|
|
6
|
-
let source = '';
|
|
7
|
-
for (let i = 0; i < glob.length; i++) {
|
|
8
|
-
const char = glob[i];
|
|
9
|
-
if (char === '*' && glob[i + 1] === '*') {
|
|
10
|
-
const slash = glob[i + 2] === '/';
|
|
11
|
-
source += slash ? '(?:.*/)?' : '.*';
|
|
12
|
-
i += slash ? 2 : 1;
|
|
13
|
-
} else if (char === '*') {
|
|
14
|
-
source += '[^/]*';
|
|
15
|
-
} else if (char === '?') {
|
|
16
|
-
source += '[^/]';
|
|
17
|
-
} else {
|
|
18
|
-
source += char.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return new RegExp(`^${source}$`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const toPosix = (file: string): string => file.split('\\').join('/');
|
package/lib/inclusion.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { conventionalNames, findConventionalFile, loadPredicateFile } from './predicateFile';
|
|
2
|
-
import type { FilterPredicate } from './utils';
|
|
3
|
-
|
|
4
|
-
/** What an {@link InclusionPredicate} decides on. */
|
|
5
|
-
export interface InclusionContext {
|
|
6
|
-
/** The file's path relative to the config file, `/`-separated: `src/services/Logger.ts`. */
|
|
7
|
-
filename: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Decides whether a scanned file takes part in code generation. A file takes
|
|
12
|
-
* part only when it matches no `exclude` glob and the predicate returns `true`.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* // tic.include.ts, next to tic.config.json - picked up by convention
|
|
16
|
-
* const include: InclusionPredicate = ({ filename }) => !filename.includes('/legacy/');
|
|
17
|
-
* export default include;
|
|
18
|
-
*/
|
|
19
|
-
export type InclusionPredicate = FilterPredicate<InclusionContext>;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* An {@link InclusionPredicate} over a file's tags, the dot-separated parts of its name between
|
|
23
|
-
* the base name and the extension. Wrap it with {@link byTags} to use it anywhere an
|
|
24
|
-
* `InclusionPredicate` goes.
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* // StripeGateway.production.ts joins production only; Shared.ts joins every environment
|
|
28
|
-
* const ENVS = ['development', 'production', 'test'];
|
|
29
|
-
* export default byTags((tags) => tags.filter((t) => ENVS.includes(t)).every((t) => t === process.env.TIC_ENV));
|
|
30
|
-
*/
|
|
31
|
-
export type TagInclusionPredicate = (tags: string[], context: InclusionContext) => boolean;
|
|
32
|
-
|
|
33
|
-
/** `src/Report.production.eu.ts` -> `['production', 'eu']`; `src/Shared.ts` -> `[]`. */
|
|
34
|
-
export function fileTags(filename: string): string[] {
|
|
35
|
-
return filename
|
|
36
|
-
.slice(filename.lastIndexOf('/') + 1)
|
|
37
|
-
.split('.')
|
|
38
|
-
.slice(1, -1);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** Wraps a {@link TagInclusionPredicate} into the {@link InclusionPredicate} the bundler calls. */
|
|
42
|
-
export function byTags(predicate: TagInclusionPredicate): InclusionPredicate {
|
|
43
|
-
return (context) => predicate(fileTags(context.filename), context);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Predicate files looked up next to the config, in this order, when no bundle names one. */
|
|
47
|
-
export const INCLUSION_CONVENTION = conventionalNames('tic.include');
|
|
48
|
-
|
|
49
|
-
/** The conventional inclusion predicate file in `dir`, if there is one. */
|
|
50
|
-
export function findConventionalPredicate(dir: string): string | undefined {
|
|
51
|
-
return findConventionalFile(dir, 'tic.include');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Loads an {@link InclusionPredicate} file (see `loadPredicateFile` for formats and caching).
|
|
56
|
-
*
|
|
57
|
-
* @throws {TicConfigError} when the file is missing or does not export a function.
|
|
58
|
-
*/
|
|
59
|
-
export function loadInclusionPredicate(file: string): InclusionPredicate {
|
|
60
|
-
return loadPredicateFile<InclusionPredicate>(file, 'InclusionPredicate');
|
|
61
|
-
}
|
package/lib/index.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
export { build, type BuildOptions, type BuildResult, type OutputResult, type OutputStatus } from './build';
|
|
2
|
-
export { run, type CliIo } from './cli';
|
|
3
|
-
export {
|
|
4
|
-
loadConfig,
|
|
5
|
-
resolveConfig,
|
|
6
|
-
DEFAULT_CONFIG_FILE,
|
|
7
|
-
DEFAULT_EXCLUDE,
|
|
8
|
-
DEFAULT_BUNDLE_NAME,
|
|
9
|
-
type TicConfig,
|
|
10
|
-
type BundleConfig,
|
|
11
|
-
type NamespaceConfig,
|
|
12
|
-
type ClassSelector,
|
|
13
|
-
type ExportKind,
|
|
14
|
-
type ResolvedSelector,
|
|
15
|
-
type ResolvedConfig,
|
|
16
|
-
type ResolvedBundle,
|
|
17
|
-
} from './config';
|
|
18
|
-
export { ImportPaths } from './ImportPaths';
|
|
19
|
-
export { type FilterPredicate } from './utils';
|
|
20
|
-
export {
|
|
21
|
-
type ExportPredicate,
|
|
22
|
-
type ExportContext,
|
|
23
|
-
EXPORTS_CONVENTION,
|
|
24
|
-
findConventionalExportPredicate,
|
|
25
|
-
loadExportPredicate,
|
|
26
|
-
} from './exportPredicate';
|
|
27
|
-
export {
|
|
28
|
-
type InclusionPredicate,
|
|
29
|
-
type InclusionContext,
|
|
30
|
-
type TagInclusionPredicate,
|
|
31
|
-
byTags,
|
|
32
|
-
fileTags,
|
|
33
|
-
INCLUSION_CONVENTION,
|
|
34
|
-
findConventionalPredicate,
|
|
35
|
-
loadInclusionPredicate,
|
|
36
|
-
} from './inclusion';
|
|
37
|
-
export { findClasses, listSourceFiles, type DiscoveredClass } from './scan';
|
|
38
|
-
export { emitBundle, type EmitInput } from './emit';
|
|
39
|
-
export { globToRegExp } from './glob';
|
|
40
|
-
export { TicError, TicConfigError, NamespaceNotFoundError } from './errors';
|
package/lib/predicateFile.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { TicConfigError } from './errors';
|
|
5
|
-
import type { FilterPredicate } from './utils';
|
|
6
|
-
|
|
7
|
-
const EXTENSIONS = ['cjs', 'js', 'mjs', 'ts', 'cts', 'mts'];
|
|
8
|
-
|
|
9
|
-
/** `tic.include` -> `tic.include.cjs`, `tic.include.js`, ... in lookup order. */
|
|
10
|
-
export const conventionalNames = (base: string): string[] => EXTENSIONS.map((ext) => `${base}.${ext}`);
|
|
11
|
-
|
|
12
|
-
/** The first conventional file for `base` that exists in `dir`, if any. */
|
|
13
|
-
export function findConventionalFile(dir: string, base: string): string | undefined {
|
|
14
|
-
return conventionalNames(base)
|
|
15
|
-
.map((name) => path.join(dir, name))
|
|
16
|
-
.find((file) => existsSync(file));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Loads a predicate file synchronously with `require` - `.cjs` / `.js`, ES modules
|
|
21
|
-
* (Node 22.12+) and `.ts` (Node with type stripping). Its default export, or
|
|
22
|
-
* `module.exports` itself, is the predicate. Like any `require`d module it is loaded
|
|
23
|
-
* once per process, so a predicate that depends on the environment should read it
|
|
24
|
-
* when called, not when loaded.
|
|
25
|
-
*
|
|
26
|
-
* @throws {TicConfigError} when the file is missing or does not export a function.
|
|
27
|
-
*/
|
|
28
|
-
export function loadPredicateFile<T extends FilterPredicate<never>>(file: string, typeName: string): T {
|
|
29
|
-
if (!existsSync(file)) throw new TicConfigError(`predicate file not found: ${file}`);
|
|
30
|
-
const loaded: unknown = createRequire(file)(file);
|
|
31
|
-
const predicate = typeof loaded === 'function' ? loaded : (loaded as { default?: unknown } | undefined)?.default;
|
|
32
|
-
if (typeof predicate !== 'function') {
|
|
33
|
-
throw new TicConfigError(`${file} must export an ${typeName} function (default export or module.exports)`);
|
|
34
|
-
}
|
|
35
|
-
return predicate as T;
|
|
36
|
-
}
|
package/lib/render.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import '../tpl/index.cjs';
|
|
2
|
-
import Handlebars from 'handlebars';
|
|
3
|
-
|
|
4
|
-
// A protocol is the declarative definition (schema) of a generated file, written as a Handlebars
|
|
5
|
-
// template in lib/protocols/. `hbs:compile` precompiles them into tpl/index.cjs, which registers each
|
|
6
|
-
// one in the process-global `Handlebars.templates` under its file basename. Output is TypeScript,
|
|
7
|
-
// not HTML, so protocols interpolate with `{{{ }}}` and helpers return plain strings.
|
|
8
|
-
Handlebars.registerHelper('join', (items: string[], separator: string) => items.join(separator));
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Renders a precompiled protocol, looked up by its file basename (`Bundle.ts.hbs`).
|
|
12
|
-
*
|
|
13
|
-
* @throws {Error} when no protocol is registered under `name`.
|
|
14
|
-
*/
|
|
15
|
-
export function renderProtocol(name: string, data: unknown): string {
|
|
16
|
-
const protocol = Handlebars.templates?.[name];
|
|
17
|
-
if (!protocol) throw new Error(`Protocol not found: ${name}`);
|
|
18
|
-
return protocol(data);
|
|
19
|
-
}
|
package/lib/scan.ts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import * as ts from 'typescript';
|
|
4
|
-
import type { ResolvedSelector } from './config';
|
|
5
|
-
|
|
6
|
-
/** An exported class the generated bundle registers. */
|
|
7
|
-
export interface DiscoveredClass {
|
|
8
|
-
file: string;
|
|
9
|
-
/** The name it is exported under; `default` for a default export. */
|
|
10
|
-
exportName: string;
|
|
11
|
-
/** The local name the generated bundle would like to import it under. */
|
|
12
|
-
localName: string;
|
|
13
|
-
/** The declared class name; an anonymous default export is named after its file. */
|
|
14
|
-
className: string;
|
|
15
|
-
isDefault: boolean;
|
|
16
|
-
/** Names of the class's decorators, renamed imports resolved. */
|
|
17
|
-
decorators: string[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const SOURCE_FILE = /\.(tsx?|mts|cts)$/;
|
|
21
|
-
const DECLARATION_FILE = /\.d\.[mc]?tsx?$/;
|
|
22
|
-
|
|
23
|
-
/** Source files of `dir`, sorted by path so the generated output is stable across machines. */
|
|
24
|
-
export function listSourceFiles(dir: string, recursive: boolean, isExcluded: (file: string) => boolean): string[] {
|
|
25
|
-
const files: string[] = [];
|
|
26
|
-
const walk = (current: string) => {
|
|
27
|
-
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
28
|
-
const full = path.join(current, entry.name);
|
|
29
|
-
if (entry.isDirectory()) {
|
|
30
|
-
if (recursive && entry.name !== 'node_modules') walk(full);
|
|
31
|
-
} else if (SOURCE_FILE.test(entry.name) && !DECLARATION_FILE.test(entry.name) && !isExcluded(full)) {
|
|
32
|
-
files.push(full);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
walk(dir);
|
|
37
|
-
return files.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const hasModifier = (node: ts.Node, kind: ts.SyntaxKind) =>
|
|
41
|
-
ts.canHaveModifiers(node) && (ts.getModifiers(node) ?? []).some((m) => m.kind === kind);
|
|
42
|
-
|
|
43
|
-
/** `@register`, `@register(...)`, `@ioc.register(...)` -> `register`; renamed imports map back to the imported name. */
|
|
44
|
-
function decoratorName(decorator: ts.Decorator, imports: Map<string, string>): string | undefined {
|
|
45
|
-
const callee = ts.isCallExpression(decorator.expression) ? decorator.expression.expression : decorator.expression;
|
|
46
|
-
if (ts.isIdentifier(callee)) return imports.get(callee.text) ?? callee.text;
|
|
47
|
-
if (ts.isPropertyAccessExpression(callee)) return callee.name.text;
|
|
48
|
-
return undefined;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* `user-service.ts` -> `UserService`: the import name of an anonymous default-exported class.
|
|
53
|
-
* File-name tags are not part of it: `user-service.production.ts` -> `UserService`.
|
|
54
|
-
*/
|
|
55
|
-
function nameFromFile(file: string): string {
|
|
56
|
-
const words = path
|
|
57
|
-
.basename(file)
|
|
58
|
-
.split('.')[0]
|
|
59
|
-
.split(/[^A-Za-z0-9_$]+/)
|
|
60
|
-
.filter(Boolean);
|
|
61
|
-
const name = words.map((w: string) => w[0].toUpperCase() + w.slice(1)).join('');
|
|
62
|
-
return /^[A-Za-z_$]/.test(name) ? name : `_${name}`;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* The exported, non-abstract classes of one file that `selector` selects, in
|
|
67
|
-
* declaration order. Syntax only: decorators are recognised by name, not by type.
|
|
68
|
-
*/
|
|
69
|
-
export function findClasses(
|
|
70
|
-
file: string,
|
|
71
|
-
selector: ResolvedSelector,
|
|
72
|
-
text = readFileSync(file, 'utf8'),
|
|
73
|
-
): DiscoveredClass[] {
|
|
74
|
-
const kind = file.endsWith('x') ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
75
|
-
const source = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, false, kind);
|
|
76
|
-
|
|
77
|
-
const imports = new Map<string, string>(); // local name -> imported name
|
|
78
|
-
const classes = new Map<string, ts.ClassDeclaration>();
|
|
79
|
-
const exported: { node: ts.ClassDeclaration | undefined; local?: string; exportName: string }[] = [];
|
|
80
|
-
|
|
81
|
-
for (const statement of source.statements) {
|
|
82
|
-
if (ts.isImportDeclaration(statement)) {
|
|
83
|
-
const bindings = statement.importClause?.namedBindings;
|
|
84
|
-
if (bindings && ts.isNamedImports(bindings)) {
|
|
85
|
-
for (const el of bindings.elements) imports.set(el.name.text, (el.propertyName ?? el.name).text);
|
|
86
|
-
}
|
|
87
|
-
} else if (ts.isClassDeclaration(statement)) {
|
|
88
|
-
if (statement.name) classes.set(statement.name.text, statement);
|
|
89
|
-
if (hasModifier(statement, ts.SyntaxKind.ExportKeyword)) {
|
|
90
|
-
const isDefault = hasModifier(statement, ts.SyntaxKind.DefaultKeyword);
|
|
91
|
-
exported.push({ node: statement, exportName: isDefault ? 'default' : statement.name!.text });
|
|
92
|
-
}
|
|
93
|
-
} else if (ts.isExportDeclaration(statement) && !statement.moduleSpecifier && !statement.isTypeOnly) {
|
|
94
|
-
const clause = statement.exportClause;
|
|
95
|
-
if (clause && ts.isNamedExports(clause)) {
|
|
96
|
-
for (const el of clause.elements) {
|
|
97
|
-
if (!el.isTypeOnly)
|
|
98
|
-
exported.push({ node: undefined, local: (el.propertyName ?? el.name).text, exportName: el.name.text });
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
} else if (ts.isExportAssignment(statement) && !statement.isExportEquals && ts.isIdentifier(statement.expression)) {
|
|
102
|
-
exported.push({ node: undefined, local: statement.expression.text, exportName: 'default' });
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const decoratorsOf = (node: ts.ClassDeclaration) =>
|
|
107
|
-
(ts.getDecorators(node) ?? []).map((d) => decoratorName(d, imports)).filter((n): n is string => !!n);
|
|
108
|
-
|
|
109
|
-
return exported
|
|
110
|
-
.map(({ node, local, exportName }) => ({ node: node ?? (local ? classes.get(local) : undefined), exportName }))
|
|
111
|
-
.filter((e): e is { node: ts.ClassDeclaration; exportName: string } => !!e.node)
|
|
112
|
-
.map(({ node, exportName }) => ({
|
|
113
|
-
node,
|
|
114
|
-
exportName,
|
|
115
|
-
className: node.name?.text ?? nameFromFile(file),
|
|
116
|
-
decorators: decoratorsOf(node),
|
|
117
|
-
}))
|
|
118
|
-
.filter(({ node, exportName, className, decorators }) => {
|
|
119
|
-
if (hasModifier(node, ts.SyntaxKind.AbstractKeyword)) return false;
|
|
120
|
-
if (selector.export !== 'any' && (exportName === 'default') !== (selector.export === 'default')) return false;
|
|
121
|
-
if (selector.decorators && !selector.decorators.some((name) => decorators.includes(name))) return false;
|
|
122
|
-
return !selector.nameGlob || selector.nameGlob.test(className);
|
|
123
|
-
})
|
|
124
|
-
.sort((a, b) => a.node.pos - b.node.pos)
|
|
125
|
-
.map(({ exportName, className, decorators }) => ({
|
|
126
|
-
file,
|
|
127
|
-
exportName,
|
|
128
|
-
localName: exportName === 'default' ? className : exportName,
|
|
129
|
-
className,
|
|
130
|
-
isDefault: exportName === 'default',
|
|
131
|
-
decorators,
|
|
132
|
-
}));
|
|
133
|
-
}
|
package/lib/utils.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ImportPaths.d.ts","sourceRoot":"","sources":["../lib/ImportPaths.ts"],"names":[],"mappings":"AAMA,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAeD;;;GAGG;AACH,qBAAa,WAAW;IAiCpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM;IAjC5B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,WAAW;gBA0B9E,OAAO,EAAE,KAAK,EAAE,EACxB,SAAS,EAAE,MAAM;IAG5B;;;;OAIG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAa5D,mGAAmG;IACnG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAgBnD,OAAO,CAAC,YAAY;IAWpB,yGAAyG;IACzG,OAAO,CAAC,UAAU;CAanB"}
|
package/typings/bin.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../lib/bin.ts"],"names":[],"mappings":""}
|
package/typings/build.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../lib/build.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,eAAe,EAAwD,MAAM,mBAAmB,CAAC;AAC/G,OAAO,EAAuC,KAAK,kBAAkB,EAA0B,MAAM,aAAa,CAAC;AAGnH,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uFAAuF;IACvF,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,gGAAgG;IAChG,aAAa,CAAC,EAAE,eAAe,CAAC;CACjC;AAED,kFAAkF;AAClF,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,EACpB,MAA4B,EAC5B,GAAmB,EACnB,KAAa,EACb,OAAO,EACP,aAAa,GACd,GAAE,YAAiB,GAAG,WAAW,CA6BjC"}
|
package/typings/cli.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../lib/cli.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AA2CD,8EAA8E;AAC9E,wBAAgB,GAAG,CACjB,IAAI,EAAE,MAAM,EAAE,EACd,EAAE,GAAE,KAA0E,GAC7E,MAAM,CA+BR"}
|
package/typings/config.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../lib/config.ts"],"names":[],"mappings":"AAKA,iGAAiG;AACjG,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,wGAAwG;IACxG,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,8GAA8G;IAC9G,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,uFAAuF;AACvF,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,6GAA6G;IAC7G,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,CAAC,MAAM,GAAG,eAAe,CAAC,EAAE,CAAC;IACzC,qFAAqF;IACrF,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,+GAA+G;IAC/G,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,sCAAsC;AACtC,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AACrD,eAAO,MAAM,mBAAmB,WAAW,CAAC;AAC5C,eAAO,MAAM,eAAe,UAO3B,CAAC;AAEF,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;IACxC,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,CAc5E;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CASvD"}
|
package/typings/emit.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../lib/emit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,CAAC,eAAe,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;CACtD;AAID;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,SAAS,GAAG,MAAM,CA2BvF"}
|
package/typings/errors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../lib/errors.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,qBAAa,QAAS,SAAQ,KAAK;IACjC,IAAI,SAAc;CACnB;AAED,8FAA8F;AAC9F,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,IAAI,SAAoB;CACzB;AAED,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,QAAQ;IAClD,IAAI,SAA4B;CACjC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"exportPredicate.d.ts","sourceRoot":"","sources":["../lib/exportPredicate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,uFAAuF;AACvF,MAAM,WAAW,aAAa;IAC5B,4FAA4F;IAC5F,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,qGAAqG;IACrG,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,8FAA8F;IAC9F,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;AAE7D,oGAAoG;AACpG,eAAO,MAAM,kBAAkB,UAAmC,CAAC;AAEnE,wEAAwE;AACxE,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE/E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAEjE"}
|
package/typings/glob.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../lib/glob.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBjD;AAED,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,MAAoC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inclusion.d.ts","sourceRoot":"","sources":["../lib/inclusion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,4FAA4F;IAC5F,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC;AAE3F,wFAAwF;AACxF,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAKnD;AAED,mGAAmG;AACnG,wBAAgB,MAAM,CAAC,SAAS,EAAE,qBAAqB,GAAG,kBAAkB,CAE3E;AAED,6FAA6F;AAC7F,eAAO,MAAM,oBAAoB,UAAmC,CAAC;AAErE,2EAA2E;AAC3E,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAEvE"}
|
package/typings/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAC3G,OAAO,EAAE,GAAG,EAAE,KAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EACL,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,kBAAkB,EAClB,+BAA+B,EAC/B,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,MAAM,EACN,QAAQ,EACR,oBAAoB,EACpB,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"predicateFile.d.ts","sourceRoot":"","sources":["../lib/predicateFile.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,iFAAiF;AACjF,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MAAM,EAA+C,CAAC;AAEvG,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIlF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,eAAe,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,CAQrG"}
|
package/typings/render.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../lib/render.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAS1B;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAIlE"}
|
package/typings/scan.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../lib/scan.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAKD,+FAA+F;AAC/F,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,EAAE,CAchH;AA2BD;;;GAGG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,SAA6B,GAChC,eAAe,EAAE,CA4DnB"}
|
package/typings/utils.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../lib/utils.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,MAAM,MAAM,eAAe,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC"}
|