@ts-ioc-container/bundler 0.2.0 → 1.1.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 +23 -0
- package/cjm/build.js +1 -1
- package/cjm/cli.js +3 -1
- package/cjm/config.js +20 -2
- package/package.json +2 -2
- package/tic.schema.json +8 -1
- package/typings/build.d.ts +2 -0
- package/typings/config.d.ts +9 -0
package/README.md
CHANGED
|
@@ -56,9 +56,32 @@ below use the shortcut.
|
|
|
56
56
|
| `bundles[].namespaces` | — | Folders to scan; `{ path, recursive }` to stop at the folder itself |
|
|
57
57
|
| `bundles[].select` | every exported class | Which classes of a file are registered — see [Selecting classes](#selecting-classes) |
|
|
58
58
|
| `bundles[].exclude` | test files, `__tests__/`, `node_modules/` | Globs (relative to the config) never scanned; replaces the default |
|
|
59
|
+
| `bundles[].additionalExclude`| — | Globs never scanned, added on top of `exclude` (or the defaults) — see [Excluding files](#excluding-files) |
|
|
59
60
|
| `bundles[].filterExports` | `tic.exports.*` next to the config | File exporting an `ExportPredicate` — see [Filtering classes](#filtering-classes-after-parsing) |
|
|
60
61
|
| `bundles[].include` | `tic.include.*` next to the config | File exporting an `InclusionPredicate` — see [Including files](#including-files-with-a-predicate) |
|
|
61
62
|
|
|
63
|
+
## Excluding files
|
|
64
|
+
|
|
65
|
+
By default test files, `__tests__/` and `node_modules/` are never scanned. To
|
|
66
|
+
add one exclusion without restating those defaults, use `additionalExclude`:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"bundles": [
|
|
71
|
+
{
|
|
72
|
+
"output": "src/di/app.bundle.ts",
|
|
73
|
+
"namespaces": ["@app/services"],
|
|
74
|
+
"additionalExclude": ["frontend/api/generated/**", "**/Mock*.ts"]
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
A non-empty `exclude` replaces the defaults; if it omits a default glob the
|
|
81
|
+
build warns, since test classes usually carry the same `@register` decorators as
|
|
82
|
+
production ones. `exclude: []` deliberately scans everything, including tests —
|
|
83
|
+
combine it with `include` when only some tests should join.
|
|
84
|
+
|
|
62
85
|
## Selecting classes
|
|
63
86
|
|
|
64
87
|
By default every exported, non-abstract class of a scanned file is registered.
|
package/cjm/build.js
CHANGED
|
@@ -38,7 +38,7 @@ function build({ config = config_1.DEFAULT_CONFIG_FILE, cwd = process.cwd(), che
|
|
|
38
38
|
}
|
|
39
39
|
return { file: bundle.output, bundle: bundle.name, status, registrations, content };
|
|
40
40
|
});
|
|
41
|
-
return { config: resolved.file, outputs };
|
|
41
|
+
return { config: resolved.file, outputs, warnings: resolved.warnings };
|
|
42
42
|
}
|
|
43
43
|
function predicateResolver({ override, conventional, fileOf, load, }) {
|
|
44
44
|
const loaded = new Map();
|
package/cjm/cli.js
CHANGED
|
@@ -62,7 +62,9 @@ function run(argv, io = { cwd: process.cwd(), stdout: console.log, stderr: conso
|
|
|
62
62
|
return 1;
|
|
63
63
|
}
|
|
64
64
|
const { config, check } = parseBuildArgs(rest);
|
|
65
|
-
const { outputs } = (0, build_1.build)({ config, check, cwd: io.cwd });
|
|
65
|
+
const { outputs, warnings } = (0, build_1.build)({ config, check, cwd: io.cwd });
|
|
66
|
+
for (const warning of warnings)
|
|
67
|
+
io.stderr(`tic: warning: ${warning}`);
|
|
66
68
|
for (const { status, file, registrations } of outputs) {
|
|
67
69
|
io.stdout(`${VERB[status].padEnd(10)}${node_path_1.default.relative(io.cwd, file)} (${plural(registrations)})`);
|
|
68
70
|
}
|
package/cjm/config.js
CHANGED
|
@@ -61,7 +61,7 @@ function toSelector(value, field) {
|
|
|
61
61
|
function toBundle(value, field, dir) {
|
|
62
62
|
if (!isObject(value))
|
|
63
63
|
return fail(field, 'an object');
|
|
64
|
-
const { output, name, namespaces, select, exclude, include, filterExports } = value;
|
|
64
|
+
const { output, name, namespaces, select, exclude, additionalExclude, include, filterExports } = value;
|
|
65
65
|
if (!isNonEmptyString(output))
|
|
66
66
|
return fail(`${field}.output`, 'a non-empty string');
|
|
67
67
|
if (name !== undefined && !isIdentifier(name))
|
|
@@ -70,6 +70,9 @@ function toBundle(value, field, dir) {
|
|
|
70
70
|
return fail(`${field}.namespaces`, 'a non-empty array');
|
|
71
71
|
if (exclude !== undefined && !isStringArray(exclude))
|
|
72
72
|
return fail(`${field}.exclude`, 'an array of strings');
|
|
73
|
+
if (additionalExclude !== undefined && !isStringArray(additionalExclude)) {
|
|
74
|
+
return fail(`${field}.additionalExclude`, 'an array of strings');
|
|
75
|
+
}
|
|
73
76
|
if (include !== undefined && !isNonEmptyString(include))
|
|
74
77
|
return fail(`${field}.include`, 'a non-empty string');
|
|
75
78
|
if (filterExports !== undefined && !isNonEmptyString(filterExports)) {
|
|
@@ -80,11 +83,25 @@ function toBundle(value, field, dir) {
|
|
|
80
83
|
name: name ?? exports.DEFAULT_BUNDLE_NAME,
|
|
81
84
|
namespaces: namespaces.map((ns, i) => toNamespace(ns, `${field}.namespaces[${i}]`)),
|
|
82
85
|
select: toSelector(select, `${field}.select`),
|
|
83
|
-
exclude: exclude ?? exports.DEFAULT_EXCLUDE,
|
|
86
|
+
exclude: [...(exclude ?? exports.DEFAULT_EXCLUDE), ...(additionalExclude ?? [])],
|
|
84
87
|
include: include === undefined ? undefined : node_path_1.default.resolve(dir, include),
|
|
85
88
|
filterExports: filterExports === undefined ? undefined : node_path_1.default.resolve(dir, filterExports),
|
|
86
89
|
};
|
|
87
90
|
}
|
|
91
|
+
function excludeWarnings(value, field) {
|
|
92
|
+
if (!isObject(value))
|
|
93
|
+
return [];
|
|
94
|
+
const exclude = value.exclude;
|
|
95
|
+
if (!isStringArray(exclude) || exclude.length === 0)
|
|
96
|
+
return [];
|
|
97
|
+
const missing = exports.DEFAULT_EXCLUDE.filter((glob) => !exclude.includes(glob));
|
|
98
|
+
if (missing.length === 0)
|
|
99
|
+
return [];
|
|
100
|
+
return [
|
|
101
|
+
`${field}.exclude replaces the default excludes and omits ${missing.map((glob) => `"${glob}"`).join(', ')}; ` +
|
|
102
|
+
`add them back or use ${field}.additionalExclude`,
|
|
103
|
+
];
|
|
104
|
+
}
|
|
88
105
|
function resolveConfig(content, file) {
|
|
89
106
|
const dir = node_path_1.default.dirname(file);
|
|
90
107
|
if (!isObject(content))
|
|
@@ -102,6 +119,7 @@ function resolveConfig(content, file) {
|
|
|
102
119
|
tsconfig: { file: node_path_1.default.resolve(dir, tsconfig ?? 'tsconfig.json'), required: tsconfig !== undefined },
|
|
103
120
|
importExtension,
|
|
104
121
|
bundles: bundles.map((m, i) => toBundle(m, `bundles[${i}]`, dir)),
|
|
122
|
+
warnings: bundles.flatMap((m, i) => excludeWarnings(m, `bundles[${i}]`)),
|
|
105
123
|
};
|
|
106
124
|
}
|
|
107
125
|
function loadConfig(file) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-ioc-container/bundler",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
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",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"typescript": "5.8.3",
|
|
62
62
|
"unplugin-swc": "^1.6.0",
|
|
63
63
|
"vitest": "^4.1.11",
|
|
64
|
-
"ts-ioc-container": "
|
|
64
|
+
"ts-ioc-container": "73.0.0"
|
|
65
65
|
},
|
|
66
66
|
"engines": {
|
|
67
67
|
"node": ">= 18"
|
package/tic.schema.json
CHANGED
|
@@ -115,7 +115,14 @@
|
|
|
115
115
|
"**/__tests__/**",
|
|
116
116
|
"**/node_modules/**"
|
|
117
117
|
],
|
|
118
|
-
"description": "Globs, relative to this file, of files never scanned. Replaces the default when given."
|
|
118
|
+
"description": "Globs, relative to this file, of files never scanned. Replaces the default when given; prefer additionalExclude to add one exclusion without restating the defaults. A non-empty list that omits a default glob makes `tic build` warn."
|
|
119
|
+
},
|
|
120
|
+
"additionalExclude": {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"items": {
|
|
123
|
+
"type": "string"
|
|
124
|
+
},
|
|
125
|
+
"description": "Globs, relative to this file, of files never scanned, added on top of `exclude` (or the default excludes when `exclude` is omitted)."
|
|
119
126
|
},
|
|
120
127
|
"include": {
|
|
121
128
|
"type": "string",
|
package/typings/build.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export interface BuildResult {
|
|
|
27
27
|
/** Absolute path of the config that was built. */
|
|
28
28
|
config: string;
|
|
29
29
|
outputs: OutputResult[];
|
|
30
|
+
/** Non-fatal problems found while resolving the config, e.g. an `exclude` that drops a default test glob. */
|
|
31
|
+
warnings: string[];
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
34
|
* Generates one bundle per config entry. Every bundle is generated before any
|
package/typings/config.d.ts
CHANGED
|
@@ -35,6 +35,12 @@ export interface BundleConfig {
|
|
|
35
35
|
select?: ClassSelector;
|
|
36
36
|
/** Globs, relative to the config file, of files never scanned. Replaces {@link DEFAULT_EXCLUDE} when given. */
|
|
37
37
|
exclude?: string[];
|
|
38
|
+
/**
|
|
39
|
+
* Globs, relative to the config file, of files never scanned, added on top of
|
|
40
|
+
* `exclude` (or {@link DEFAULT_EXCLUDE} when `exclude` is omitted). Use this to
|
|
41
|
+
* add one exclusion without restating the defaults.
|
|
42
|
+
*/
|
|
43
|
+
additionalExclude?: string[];
|
|
38
44
|
/**
|
|
39
45
|
* A file exporting an `InclusionPredicate`, relative to the config file. Overrides the
|
|
40
46
|
* conventional `tic.include.*` next to the config.
|
|
@@ -68,12 +74,15 @@ export interface ResolvedConfig {
|
|
|
68
74
|
};
|
|
69
75
|
importExtension?: string;
|
|
70
76
|
bundles: ResolvedBundle[];
|
|
77
|
+
/** Non-fatal problems found while resolving, e.g. an `exclude` that drops a default test glob. */
|
|
78
|
+
warnings: string[];
|
|
71
79
|
}
|
|
72
80
|
export interface ResolvedBundle {
|
|
73
81
|
output: string;
|
|
74
82
|
name: string;
|
|
75
83
|
namespaces: Required<NamespaceConfig>[];
|
|
76
84
|
select: ResolvedSelector;
|
|
85
|
+
/** The effective list: the configured `exclude` (or the defaults) followed by `additionalExclude`. */
|
|
77
86
|
exclude: string[];
|
|
78
87
|
/** Absolute path of the bundle's own predicate file, when it names one. */
|
|
79
88
|
include?: string;
|