@ts-ioc-container/bundler 2.0.0 → 2.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/AGENTS.md +13 -2
- package/cjm/app.js +39 -0
- package/cjm/bin.js +2 -2
- package/cjm/cli/Application.js +58 -0
- package/cjm/cli/IErrorHandler.js +5 -0
- package/cjm/cli/decorators.js +9 -0
- package/cjm/cli/index.js +17 -0
- package/cjm/cli/options.js +25 -0
- package/cjm/cli/usage.js +19 -0
- package/cjm/domain/CliIo.js +7 -0
- package/cjm/domain/GlobalConfig.js +7 -0
- package/cjm/exceptions/DomainException.js +54 -0
- package/cjm/exceptions/ExceptionHandler.js +38 -0
- package/cjm/features/build/BuildConfig.js +183 -0
- package/cjm/features/build/BuildController.js +91 -0
- package/cjm/features/build/BuildModule.js +16 -0
- package/cjm/{ImportPaths.js → features/build/domain/ImportPaths.js} +2 -2
- package/cjm/features/build/domain/configFiles.js +35 -0
- package/cjm/{emit.js → features/build/domain/emit.js} +9 -11
- package/cjm/features/build/domain/tokenCollisions.js +29 -0
- package/cjm/{tsconfig.js → features/build/domain/tsconfig.js} +3 -3
- package/cjm/features/build/services/BundleBuilder.js +116 -0
- package/cjm/features/build/services/TicConfigService.js +68 -0
- package/cjm/features/help/HelpController.js +39 -0
- package/cjm/features/help/HelpModule.js +12 -0
- package/cjm/features/help/VersionController.js +45 -0
- package/cjm/index.js +84 -25
- package/cjm/modules/CommonModule.js +28 -0
- package/cjm/schema/ticConfigSchema.js +24 -0
- package/cjm/services/ConsoleLogger.js +36 -0
- package/cjm/services/HandlebarsRenderService.js +33 -0
- package/cjm/services/NodeFileSystemService.js +32 -0
- package/cjm/services/OutputService.js +33 -0
- package/package.json +9 -7
- package/tic.schema.json +48 -53
- package/typings/app.d.ts +24 -0
- package/typings/cli/Application.d.ts +16 -0
- package/typings/cli/Application.d.ts.map +1 -0
- package/typings/cli/IErrorHandler.d.ts +7 -0
- package/typings/cli/IErrorHandler.d.ts.map +1 -0
- package/typings/cli/decorators.d.ts +10 -0
- package/typings/cli/decorators.d.ts.map +1 -0
- package/typings/cli/index.d.ts +6 -0
- package/typings/cli/index.d.ts.map +1 -0
- package/typings/cli/options.d.ts +23 -0
- package/typings/cli/options.d.ts.map +1 -0
- package/typings/cli/usage.d.ts +2 -0
- package/typings/cli/usage.d.ts.map +1 -0
- package/typings/domain/CliIo.d.ts +10 -0
- package/typings/domain/CliIo.d.ts.map +1 -0
- package/typings/domain/GlobalConfig.d.ts +10 -0
- package/typings/domain/GlobalConfig.d.ts.map +1 -0
- package/typings/exceptions/DomainException.d.ts +37 -0
- package/typings/exceptions/DomainException.d.ts.map +1 -0
- package/typings/exceptions/ExceptionHandler.d.ts +12 -0
- package/typings/exceptions/ExceptionHandler.d.ts.map +1 -0
- package/typings/{config.d.ts → features/build/BuildConfig.d.ts} +42 -25
- package/typings/features/build/BuildConfig.d.ts.map +1 -0
- package/typings/features/build/BuildController.d.ts +32 -0
- package/typings/features/build/BuildController.d.ts.map +1 -0
- package/typings/features/build/BuildModule.d.ts +5 -0
- package/typings/features/build/BuildModule.d.ts.map +1 -0
- package/typings/features/build/domain/ImportPaths.d.ts.map +1 -0
- package/typings/features/build/domain/configFiles.d.ts +13 -0
- package/typings/features/build/domain/configFiles.d.ts.map +1 -0
- package/typings/{emit.d.ts → features/build/domain/emit.d.ts} +22 -3
- package/typings/features/build/domain/emit.d.ts.map +1 -0
- package/typings/features/build/domain/glob.d.ts.map +1 -0
- package/typings/{scan.d.ts → features/build/domain/scan.d.ts} +1 -1
- package/typings/features/build/domain/scan.d.ts.map +1 -0
- package/typings/features/build/domain/tokenCollisions.d.ts +14 -0
- package/typings/features/build/domain/tokenCollisions.d.ts.map +1 -0
- package/typings/features/build/domain/tsconfig.d.ts.map +1 -0
- package/typings/features/build/services/BundleBuilder.d.ts +68 -0
- package/typings/features/build/services/BundleBuilder.d.ts.map +1 -0
- package/typings/features/build/services/TicConfigService.d.ts +37 -0
- package/typings/features/build/services/TicConfigService.d.ts.map +1 -0
- package/typings/features/help/HelpController.d.ts +8 -0
- package/typings/features/help/HelpController.d.ts.map +1 -0
- package/typings/features/help/HelpModule.d.ts +5 -0
- package/typings/features/help/HelpModule.d.ts.map +1 -0
- package/typings/features/help/VersionController.d.ts +8 -0
- package/typings/features/help/VersionController.d.ts.map +1 -0
- package/typings/index.d.ts +25 -9
- package/typings/modules/CommonModule.d.ts +9 -0
- package/typings/modules/CommonModule.d.ts.map +1 -0
- package/typings/schema/ticConfigSchema.d.ts +7 -0
- package/typings/schema/ticConfigSchema.d.ts.map +1 -0
- package/typings/services/ConsoleLogger.d.ts +20 -0
- package/typings/services/ConsoleLogger.d.ts.map +1 -0
- package/typings/services/HandlebarsRenderService.d.ts +23 -0
- package/typings/services/HandlebarsRenderService.d.ts.map +1 -0
- package/typings/services/NodeFileSystemService.d.ts +21 -0
- package/typings/services/NodeFileSystemService.d.ts.map +1 -0
- package/typings/services/OutputService.d.ts +13 -0
- package/typings/services/OutputService.d.ts.map +1 -0
- package/cjm/build.js +0 -106
- package/cjm/cli.js +0 -109
- package/cjm/config.js +0 -199
- package/cjm/errors.js +0 -15
- package/cjm/render.js +0 -15
- package/typings/build.d.ts +0 -42
- package/typings/cli.d.ts +0 -8
- package/typings/errors.d.ts +0 -13
- package/typings/render.d.ts +0 -8
- /package/cjm/{glob.js → features/build/domain/glob.js} +0 -0
- /package/cjm/{scan.js → features/build/domain/scan.js} +0 -0
- /package/typings/{ImportPaths.d.ts → features/build/domain/ImportPaths.d.ts} +0 -0
- /package/typings/{glob.d.ts → features/build/domain/glob.d.ts} +0 -0
- /package/typings/{tsconfig.d.ts → features/build/domain/tsconfig.d.ts} +0 -0
package/cjm/build.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.TSCONFIG_FILE = void 0;
|
|
7
|
-
exports.build = build;
|
|
8
|
-
const node_fs_1 = require("node:fs");
|
|
9
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
-
const config_1 = require("./config");
|
|
11
|
-
const emit_1 = require("./emit");
|
|
12
|
-
const glob_1 = require("./glob");
|
|
13
|
-
const errors_1 = require("./errors");
|
|
14
|
-
const scan_1 = require("./scan");
|
|
15
|
-
const tsconfig_1 = require("./tsconfig");
|
|
16
|
-
exports.TSCONFIG_FILE = 'tsconfig.json';
|
|
17
|
-
function build({ config, cwd = process.cwd(), check = false } = {}) {
|
|
18
|
-
const resolved = config === undefined
|
|
19
|
-
? (0, config_1.resolveConfig)({ extends: config_1.DEFAULT_EXTENDS }, node_path_1.default.join((0, config_1.findPackageRoot)(cwd), exports.TSCONFIG_FILE))
|
|
20
|
-
: (0, config_1.loadConfig)(node_path_1.default.resolve(cwd, config));
|
|
21
|
-
const { output, content, registrations, warnings } = generate(resolved);
|
|
22
|
-
const current = (0, node_fs_1.existsSync)(output) ? (0, node_fs_1.readFileSync)(output, 'utf8') : undefined;
|
|
23
|
-
const status = current === content ? 'unchanged' : check ? 'stale' : 'written';
|
|
24
|
-
if (status === 'written') {
|
|
25
|
-
(0, node_fs_1.mkdirSync)(node_path_1.default.dirname(output), { recursive: true });
|
|
26
|
-
(0, node_fs_1.writeFileSync)(output, content);
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
config: resolved.file,
|
|
30
|
-
output: { file: output, bundle: resolved.className, status, registrations, content },
|
|
31
|
-
warnings: [...resolved.warnings, ...warnings],
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function generate(config) {
|
|
35
|
-
const { importPaths: paths, fileNames, rootDir } = (0, tsconfig_1.loadTsconfig)(config.tsconfig, config.importExtension);
|
|
36
|
-
const output = config.output ?? (rootDir && node_path_1.default.join(rootDir, `${config.name}.bundle.ts`));
|
|
37
|
-
if (output === undefined)
|
|
38
|
-
throw new errors_1.TicConfigError('output: required when there is no tsconfig to extend');
|
|
39
|
-
const relative = (file) => (0, glob_1.toPosix)(node_path_1.default.relative(config.dir, file));
|
|
40
|
-
const { include, exclude } = config.files;
|
|
41
|
-
const isExcluded = (file) => {
|
|
42
|
-
if (file === output)
|
|
43
|
-
return true;
|
|
44
|
-
const filename = relative(file);
|
|
45
|
-
if (include && !include.some((glob) => glob.test(filename)))
|
|
46
|
-
return true;
|
|
47
|
-
return exclude.some((glob) => glob.test(filename));
|
|
48
|
-
};
|
|
49
|
-
const files = new Set();
|
|
50
|
-
if (config.files.paths) {
|
|
51
|
-
for (const entry of config.files.paths) {
|
|
52
|
-
const dir = paths.resolveNamespace(entry.path, config.dir);
|
|
53
|
-
for (const file of (0, scan_1.listSourceFiles)(dir, entry.recursive, isExcluded))
|
|
54
|
-
files.add(file);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else if (fileNames) {
|
|
58
|
-
for (const file of fileNames)
|
|
59
|
-
if ((0, scan_1.isSourceFile)(file) && !isExcluded(file))
|
|
60
|
-
files.add(file);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
throw new errors_1.TicConfigError(`files.paths: required when there is no tsconfig to extend (${config.tsconfig.file} not found)`);
|
|
64
|
-
}
|
|
65
|
-
const classes = [...files]
|
|
66
|
-
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
67
|
-
.flatMap((file) => {
|
|
68
|
-
const text = (0, node_fs_1.readFileSync)(file, 'utf8');
|
|
69
|
-
return text.startsWith(emit_1.GENERATED_HEADER) ? [] : (0, scan_1.findClasses)(file, config.classes, text);
|
|
70
|
-
})
|
|
71
|
-
.map((cls) => ({ ...cls, specifier: paths.specifier(output, cls.file) }));
|
|
72
|
-
const content = (0, emit_1.emitBundle)({
|
|
73
|
-
name: config.className,
|
|
74
|
-
configPath: (0, glob_1.toPosix)(node_path_1.default.relative(node_path_1.default.dirname(output), config.file)),
|
|
75
|
-
paths: config.files.paths?.map((entry) => entry.path),
|
|
76
|
-
tsconfigPath: (0, glob_1.toPosix)(node_path_1.default.relative(node_path_1.default.dirname(output), config.tsconfig.file)),
|
|
77
|
-
classes,
|
|
78
|
-
});
|
|
79
|
-
return { output, content, registrations: classes.length, warnings: tokenCollisions(classes) };
|
|
80
|
-
}
|
|
81
|
-
function tokenCollisions(classes) {
|
|
82
|
-
const owners = new Map();
|
|
83
|
-
for (const cls of classes) {
|
|
84
|
-
for (const token of cls.tokens) {
|
|
85
|
-
const group = owners.get(token) ?? [];
|
|
86
|
-
if (!group.some((owner) => owner.className === cls.className))
|
|
87
|
-
group.push(cls);
|
|
88
|
-
owners.set(token, group);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return [...owners]
|
|
92
|
-
.filter(([, group]) => group.length > 1 && !scopeDisjoint(group))
|
|
93
|
-
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
94
|
-
.map(([token, group]) => {
|
|
95
|
-
const names = group.map((cls) => cls.className);
|
|
96
|
-
return (`decorator token "${token}" is passed by ${names.join(', ')}; ` +
|
|
97
|
-
`registration is last-wins, exclude one with classes.excludeClasses`);
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
function scopeDisjoint(group) {
|
|
101
|
-
const [first, ...rest] = group;
|
|
102
|
-
return first.decoratorCalls.some(({ name, args }) => rest.every((cls) => {
|
|
103
|
-
const same = cls.decoratorCalls.find((call) => call.name === name);
|
|
104
|
-
return same !== undefined && same.args.join('\u0000') !== args.join('\u0000');
|
|
105
|
-
}));
|
|
106
|
-
}
|
package/cjm/cli.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.run = run;
|
|
7
|
-
const node_fs_1 = require("node:fs");
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const build_1 = require("./build");
|
|
10
|
-
const config_1 = require("./config");
|
|
11
|
-
const errors_1 = require("./errors");
|
|
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 one bundle per *.bundle.{json,yaml,yml} config',
|
|
18
|
-
' (none: one bundle from tsconfig.json, all defaults)',
|
|
19
|
-
'',
|
|
20
|
-
'Options:',
|
|
21
|
-
' -c, --config <path> build only this config; repeatable (default: every *.bundle.{json,yaml,yml} of the package, else tsconfig.json)',
|
|
22
|
-
' --check write nothing; exit 1 when a generated bundle is out of date',
|
|
23
|
-
' -h, --help show this help',
|
|
24
|
-
' -v, --version show the version',
|
|
25
|
-
].join('\n');
|
|
26
|
-
const VERB = { written: 'wrote', unchanged: 'unchanged', stale: 'stale' };
|
|
27
|
-
const plural = (n) => `${n} registration${n === 1 ? '' : 's'}`;
|
|
28
|
-
function version() {
|
|
29
|
-
return JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.join(__dirname, '..', 'package.json'), 'utf8')).version;
|
|
30
|
-
}
|
|
31
|
-
class UsageError extends errors_1.TicError {
|
|
32
|
-
}
|
|
33
|
-
function parseBuildArgs(args) {
|
|
34
|
-
const options = { configs: [], check: false };
|
|
35
|
-
for (let i = 0; i < args.length; i++) {
|
|
36
|
-
const arg = args[i];
|
|
37
|
-
if (arg === '--check')
|
|
38
|
-
options.check = true;
|
|
39
|
-
else if (arg === '--config' || arg === '-c') {
|
|
40
|
-
const config = args[++i];
|
|
41
|
-
if (!config)
|
|
42
|
-
throw new UsageError(`${arg} needs a path`);
|
|
43
|
-
options.configs.push(config);
|
|
44
|
-
}
|
|
45
|
-
else if (arg.startsWith('--config='))
|
|
46
|
-
options.configs.push(arg.slice('--config='.length));
|
|
47
|
-
else
|
|
48
|
-
throw new UsageError(`unknown option "${arg}"`);
|
|
49
|
-
}
|
|
50
|
-
return options;
|
|
51
|
-
}
|
|
52
|
-
function configsToBuild(named, cwd) {
|
|
53
|
-
if (named.length > 0)
|
|
54
|
-
return named.map((config) => node_path_1.default.resolve(cwd, config));
|
|
55
|
-
const root = (0, config_1.findPackageRoot)(cwd);
|
|
56
|
-
const found = (0, config_1.findConfigFiles)(root);
|
|
57
|
-
if (found.length > 0)
|
|
58
|
-
return found;
|
|
59
|
-
if ((0, node_fs_1.existsSync)(node_path_1.default.join(root, build_1.TSCONFIG_FILE)))
|
|
60
|
-
return [undefined];
|
|
61
|
-
throw new errors_1.TicConfigError(`no *.bundle.{json,yaml,yml} or ${build_1.TSCONFIG_FILE} in ${root}; name a config with --config`);
|
|
62
|
-
}
|
|
63
|
-
function run(argv, io = { cwd: process.cwd(), stdout: console.log, stderr: console.error }) {
|
|
64
|
-
const [command, ...rest] = argv;
|
|
65
|
-
if (command === '--help' || command === '-h' || command === 'help') {
|
|
66
|
-
io.stdout(USAGE);
|
|
67
|
-
return 0;
|
|
68
|
-
}
|
|
69
|
-
if (command === '--version' || command === '-v') {
|
|
70
|
-
io.stdout(version());
|
|
71
|
-
return 0;
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
if (command !== 'build') {
|
|
75
|
-
io.stderr(command ? `tic: unknown command "${command}"` : USAGE);
|
|
76
|
-
return 1;
|
|
77
|
-
}
|
|
78
|
-
const { configs, check } = parseBuildArgs(rest);
|
|
79
|
-
let stale = 0;
|
|
80
|
-
for (const config of configsToBuild(configs, io.cwd)) {
|
|
81
|
-
const name = config === undefined ? build_1.TSCONFIG_FILE : node_path_1.default.relative(io.cwd, config);
|
|
82
|
-
try {
|
|
83
|
-
const { output, warnings } = (0, build_1.build)({ config, check, cwd: io.cwd });
|
|
84
|
-
for (const warning of warnings)
|
|
85
|
-
io.stderr(`tic: warning: ${name}: ${warning}`);
|
|
86
|
-
const { status, file, registrations } = output;
|
|
87
|
-
io.stdout(`${VERB[status].padEnd(10)}${node_path_1.default.relative(io.cwd, file)} (${plural(registrations)})`);
|
|
88
|
-
if (status === 'stale')
|
|
89
|
-
stale++;
|
|
90
|
-
}
|
|
91
|
-
catch (e) {
|
|
92
|
-
if (e instanceof errors_1.TicError)
|
|
93
|
-
e.message = `${name}: ${e.message}`;
|
|
94
|
-
throw e;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (stale > 0) {
|
|
98
|
-
io.stderr(`tic: ${stale} generated bundle${stale === 1 ? ' is' : 's are'} out of date — run \`tic build\``);
|
|
99
|
-
return 1;
|
|
100
|
-
}
|
|
101
|
-
return 0;
|
|
102
|
-
}
|
|
103
|
-
catch (e) {
|
|
104
|
-
if (!(e instanceof errors_1.TicError))
|
|
105
|
-
throw e;
|
|
106
|
-
io.stderr(`tic: ${e.message}`);
|
|
107
|
-
return 1;
|
|
108
|
-
}
|
|
109
|
-
}
|
package/cjm/config.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.DEFAULT_EXCLUDE = exports.DEFAULT_DECORATORS = exports.DEFAULT_BUNDLE_NAME = exports.DEFAULT_EXTENDS = exports.CONFIG_FILE_SUFFIXES = void 0;
|
|
7
|
-
exports.resolveConfig = resolveConfig;
|
|
8
|
-
exports.toClassName = toClassName;
|
|
9
|
-
exports.findPackageRoot = findPackageRoot;
|
|
10
|
-
exports.findConfigFiles = findConfigFiles;
|
|
11
|
-
exports.loadConfig = loadConfig;
|
|
12
|
-
const node_fs_1 = require("node:fs");
|
|
13
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
14
|
-
const yaml_1 = require("yaml");
|
|
15
|
-
const errors_1 = require("./errors");
|
|
16
|
-
const glob_1 = require("./glob");
|
|
17
|
-
exports.CONFIG_FILE_SUFFIXES = ['.bundle.json', '.bundle.yaml', '.bundle.yml'];
|
|
18
|
-
const configSuffix = (file) => exports.CONFIG_FILE_SUFFIXES.find((suffix) => file.endsWith(suffix));
|
|
19
|
-
exports.DEFAULT_EXTENDS = './tsconfig.json';
|
|
20
|
-
exports.DEFAULT_BUNDLE_NAME = 'base';
|
|
21
|
-
exports.DEFAULT_DECORATORS = ['register'];
|
|
22
|
-
exports.DEFAULT_EXCLUDE = [
|
|
23
|
-
'**/*.spec.ts',
|
|
24
|
-
'**/*.test.ts',
|
|
25
|
-
'**/*.spec.tsx',
|
|
26
|
-
'**/*.test.tsx',
|
|
27
|
-
'**/__tests__/**',
|
|
28
|
-
'**/node_modules/**',
|
|
29
|
-
];
|
|
30
|
-
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
31
|
-
const isNonEmptyString = (value) => typeof value === 'string' && value.length > 0;
|
|
32
|
-
const isStringArray = (value) => Array.isArray(value) && value.every(isNonEmptyString);
|
|
33
|
-
const isBundleName = (value) => typeof value === 'string' && /^[A-Za-z][\w-]*$/.test(value);
|
|
34
|
-
const fail = (field, expected) => {
|
|
35
|
-
throw new errors_1.TicConfigError(`${field}: expected ${expected}`);
|
|
36
|
-
};
|
|
37
|
-
function toPath(value, field) {
|
|
38
|
-
if (isNonEmptyString(value))
|
|
39
|
-
return { path: value, recursive: true };
|
|
40
|
-
if (!isObject(value))
|
|
41
|
-
return fail(field, 'a string or an object with "path"');
|
|
42
|
-
if (!isNonEmptyString(value.path))
|
|
43
|
-
return fail(`${field}.path`, 'a non-empty string');
|
|
44
|
-
if (value.recursive !== undefined && typeof value.recursive !== 'boolean')
|
|
45
|
-
return fail(`${field}.recursive`, 'a boolean');
|
|
46
|
-
return { path: value.path, recursive: value.recursive ?? true };
|
|
47
|
-
}
|
|
48
|
-
const FILE_SELECTOR_FIELDS = new Set(['paths', 'include', 'exclude']);
|
|
49
|
-
function toFileSelector(value, field) {
|
|
50
|
-
if (value === undefined)
|
|
51
|
-
return { exclude: exports.DEFAULT_EXCLUDE.map(glob_1.globToRegExp) };
|
|
52
|
-
if (!isObject(value))
|
|
53
|
-
return fail(field, 'an object');
|
|
54
|
-
const unknown = Object.keys(value).find((key) => !FILE_SELECTOR_FIELDS.has(key));
|
|
55
|
-
if (unknown)
|
|
56
|
-
throw new errors_1.TicConfigError(`${field}.${unknown}: unknown field`);
|
|
57
|
-
const { paths, include, exclude } = value;
|
|
58
|
-
if (paths !== undefined && !(Array.isArray(paths) && paths.length > 0)) {
|
|
59
|
-
return fail(`${field}.paths`, 'a non-empty array');
|
|
60
|
-
}
|
|
61
|
-
if (include !== undefined && !(isStringArray(include) && include.length > 0)) {
|
|
62
|
-
return fail(`${field}.include`, 'a non-empty array of strings');
|
|
63
|
-
}
|
|
64
|
-
if (exclude !== undefined && !isStringArray(exclude))
|
|
65
|
-
return fail(`${field}.exclude`, 'an array of strings');
|
|
66
|
-
return {
|
|
67
|
-
paths: paths?.map((entry, i) => toPath(entry, `${field}.paths[${i}]`)),
|
|
68
|
-
include: include?.map(glob_1.globToRegExp),
|
|
69
|
-
exclude: (exclude ?? exports.DEFAULT_EXCLUDE).map(glob_1.globToRegExp),
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
const CLASS_SELECTOR_FIELDS = new Set(['export', 'decorators', 'name', 'excludeClasses', 'excludeName']);
|
|
73
|
-
function toClassSelector(value, field) {
|
|
74
|
-
if (value === undefined)
|
|
75
|
-
return { export: 'any', decorators: exports.DEFAULT_DECORATORS };
|
|
76
|
-
if (!isObject(value))
|
|
77
|
-
return fail(field, 'an object');
|
|
78
|
-
const unknown = Object.keys(value).find((key) => !CLASS_SELECTOR_FIELDS.has(key));
|
|
79
|
-
if (unknown)
|
|
80
|
-
throw new errors_1.TicConfigError(`${field}.${unknown}: unknown field`);
|
|
81
|
-
const { export: kind, decorators, name, excludeClasses, excludeName } = value;
|
|
82
|
-
if (kind !== undefined && kind !== 'any' && kind !== 'named' && kind !== 'default') {
|
|
83
|
-
return fail(`${field}.export`, '"any", "named" or "default"');
|
|
84
|
-
}
|
|
85
|
-
if (decorators !== undefined && !isStringArray(decorators))
|
|
86
|
-
return fail(`${field}.decorators`, 'an array of strings');
|
|
87
|
-
if (name !== undefined && !isNonEmptyString(name))
|
|
88
|
-
return fail(`${field}.name`, 'a non-empty string');
|
|
89
|
-
if (excludeClasses !== undefined && !(isStringArray(excludeClasses) && excludeClasses.length > 0)) {
|
|
90
|
-
return fail(`${field}.excludeClasses`, 'a non-empty array of strings');
|
|
91
|
-
}
|
|
92
|
-
if (excludeName !== undefined && !isNonEmptyString(excludeName)) {
|
|
93
|
-
return fail(`${field}.excludeName`, 'a non-empty string');
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
export: kind ?? 'any',
|
|
97
|
-
decorators: decorators === undefined ? exports.DEFAULT_DECORATORS : decorators.length > 0 ? decorators : undefined,
|
|
98
|
-
name: name === undefined ? undefined : (0, glob_1.globToRegExp)(name),
|
|
99
|
-
excludeClasses,
|
|
100
|
-
excludeName: excludeName === undefined ? undefined : (0, glob_1.globToRegExp)(excludeName),
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
function excludeWarnings(files) {
|
|
104
|
-
if (!isObject(files))
|
|
105
|
-
return [];
|
|
106
|
-
const exclude = files.exclude;
|
|
107
|
-
if (!isStringArray(exclude) || exclude.length === 0)
|
|
108
|
-
return [];
|
|
109
|
-
const missing = exports.DEFAULT_EXCLUDE.filter((glob) => !exclude.includes(glob));
|
|
110
|
-
if (missing.length === 0)
|
|
111
|
-
return [];
|
|
112
|
-
return [
|
|
113
|
-
`files.exclude replaces the default excludes and omits ${missing.map((glob) => `"${glob}"`).join(', ')}; ` +
|
|
114
|
-
`add them back`,
|
|
115
|
-
];
|
|
116
|
-
}
|
|
117
|
-
const CONFIG_FIELDS = new Set(['$schema', 'output', 'name', 'tags', 'extends', 'importExtension', 'files', 'classes']);
|
|
118
|
-
function resolveConfig(content, file) {
|
|
119
|
-
const dir = node_path_1.default.dirname(file);
|
|
120
|
-
if (!isObject(content))
|
|
121
|
-
return fail('config', 'an object');
|
|
122
|
-
const unknown = Object.keys(content).find((key) => !CONFIG_FIELDS.has(key));
|
|
123
|
-
if (unknown)
|
|
124
|
-
throw new errors_1.TicConfigError(`${unknown}: unknown field`);
|
|
125
|
-
const { output, name, tags, extends: tsconfig, importExtension, files, classes } = content;
|
|
126
|
-
if (output !== undefined && !isNonEmptyString(output))
|
|
127
|
-
return fail('output', 'a non-empty string');
|
|
128
|
-
if (name !== undefined && !isBundleName(name)) {
|
|
129
|
-
return fail('name', 'letters, digits, "-" or "_", starting with a letter');
|
|
130
|
-
}
|
|
131
|
-
const bundleName = name ?? configStem(file) ?? exports.DEFAULT_BUNDLE_NAME;
|
|
132
|
-
if (tags !== undefined && !isStringArray(tags))
|
|
133
|
-
return fail('tags', 'an array of strings');
|
|
134
|
-
if (tsconfig !== undefined && !isNonEmptyString(tsconfig))
|
|
135
|
-
return fail('extends', 'a non-empty string');
|
|
136
|
-
if (importExtension !== undefined && typeof importExtension !== 'string')
|
|
137
|
-
return fail('importExtension', 'a string');
|
|
138
|
-
return {
|
|
139
|
-
file,
|
|
140
|
-
dir,
|
|
141
|
-
output: output === undefined ? undefined : node_path_1.default.resolve(dir, output),
|
|
142
|
-
name: bundleName,
|
|
143
|
-
className: toClassName(bundleName),
|
|
144
|
-
tags: tags ?? [],
|
|
145
|
-
tsconfig: { file: node_path_1.default.resolve(dir, tsconfig ?? exports.DEFAULT_EXTENDS), required: tsconfig !== undefined },
|
|
146
|
-
importExtension,
|
|
147
|
-
files: toFileSelector(files, 'files'),
|
|
148
|
-
classes: toClassSelector(classes, 'classes'),
|
|
149
|
-
warnings: excludeWarnings(files),
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
function configStem(file) {
|
|
153
|
-
const base = node_path_1.default.basename(file);
|
|
154
|
-
const suffix = configSuffix(base);
|
|
155
|
-
const stem = suffix ? base.slice(0, -suffix.length) : '';
|
|
156
|
-
return isBundleName(stem) ? stem : undefined;
|
|
157
|
-
}
|
|
158
|
-
function toClassName(name) {
|
|
159
|
-
const words = name.split(/[-_]+/).filter(Boolean);
|
|
160
|
-
return `${words.map((word) => word[0].toUpperCase() + word.slice(1)).join('')}Bundle`;
|
|
161
|
-
}
|
|
162
|
-
function findPackageRoot(dir) {
|
|
163
|
-
const start = node_path_1.default.resolve(dir);
|
|
164
|
-
for (let current = start;; current = node_path_1.default.dirname(current)) {
|
|
165
|
-
if ((0, node_fs_1.existsSync)(node_path_1.default.join(current, 'package.json')))
|
|
166
|
-
return current;
|
|
167
|
-
if (node_path_1.default.dirname(current) === current)
|
|
168
|
-
return start;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
function findConfigFiles(dir) {
|
|
172
|
-
const files = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true })
|
|
173
|
-
.filter((entry) => entry.isFile() && configSuffix(entry.name) !== undefined)
|
|
174
|
-
.map((entry) => entry.name)
|
|
175
|
-
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
176
|
-
const byStem = new Map();
|
|
177
|
-
for (const file of files) {
|
|
178
|
-
const stem = file.slice(0, -configSuffix(file).length);
|
|
179
|
-
const other = byStem.get(stem);
|
|
180
|
-
if (other)
|
|
181
|
-
throw new errors_1.TicConfigError(`${other} and ${file} describe the same bundle; keep one`);
|
|
182
|
-
byStem.set(stem, file);
|
|
183
|
-
}
|
|
184
|
-
return files.map((file) => node_path_1.default.join(dir, file));
|
|
185
|
-
}
|
|
186
|
-
function parseConfig(file, text) {
|
|
187
|
-
const yaml = file.endsWith('.yaml') || file.endsWith('.yml');
|
|
188
|
-
try {
|
|
189
|
-
return yaml ? ((0, yaml_1.parse)(text) ?? {}) : JSON.parse(text);
|
|
190
|
-
}
|
|
191
|
-
catch (e) {
|
|
192
|
-
throw new errors_1.TicConfigError(`${file} is not valid ${yaml ? 'YAML' : 'JSON'}: ${e.message}`);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
function loadConfig(file) {
|
|
196
|
-
if (!(0, node_fs_1.existsSync)(file))
|
|
197
|
-
throw new errors_1.TicConfigError(`config file not found: ${file}`);
|
|
198
|
-
return resolveConfig(parseConfig(file, (0, node_fs_1.readFileSync)(file, 'utf8')), file);
|
|
199
|
-
}
|
package/cjm/errors.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NamespaceNotFoundError = exports.TicConfigError = exports.TicError = void 0;
|
|
4
|
-
class TicError extends Error {
|
|
5
|
-
name = 'TicError';
|
|
6
|
-
}
|
|
7
|
-
exports.TicError = TicError;
|
|
8
|
-
class TicConfigError extends TicError {
|
|
9
|
-
name = 'TicConfigError';
|
|
10
|
-
}
|
|
11
|
-
exports.TicConfigError = TicConfigError;
|
|
12
|
-
class NamespaceNotFoundError extends TicError {
|
|
13
|
-
name = 'NamespaceNotFoundError';
|
|
14
|
-
}
|
|
15
|
-
exports.NamespaceNotFoundError = NamespaceNotFoundError;
|
package/cjm/render.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.renderProtocol = renderProtocol;
|
|
7
|
-
require("../tpl/index.cjs");
|
|
8
|
-
const handlebars_1 = __importDefault(require("handlebars"));
|
|
9
|
-
handlebars_1.default.registerHelper('join', (items, separator) => items.join(separator));
|
|
10
|
-
function renderProtocol(name, data) {
|
|
11
|
-
const protocol = handlebars_1.default.templates?.[name];
|
|
12
|
-
if (!protocol)
|
|
13
|
-
throw new Error(`Protocol not found: ${name}`);
|
|
14
|
-
return protocol(data);
|
|
15
|
-
}
|
package/typings/build.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/** The tsconfig a build without a config file extends. */
|
|
2
|
-
export declare const TSCONFIG_FILE = "tsconfig.json";
|
|
3
|
-
export interface BuildOptions {
|
|
4
|
-
/**
|
|
5
|
-
* Path of the `*.bundle.json` to build, relative to `cwd`. Omitted: build from the
|
|
6
|
-
* `tsconfig.json` of the package `cwd` is in (see `findPackageRoot`), every setting at its default.
|
|
7
|
-
*/
|
|
8
|
-
config?: string;
|
|
9
|
-
/** Default `process.cwd()`. */
|
|
10
|
-
cwd?: string;
|
|
11
|
-
/** Compare instead of writing: outputs that would change are reported `stale`. */
|
|
12
|
-
check?: boolean;
|
|
13
|
-
}
|
|
14
|
-
/** `written` / `unchanged` after a build; `stale` / `unchanged` after a check. */
|
|
15
|
-
export type OutputStatus = 'written' | 'unchanged' | 'stale';
|
|
16
|
-
export interface OutputResult {
|
|
17
|
-
/** Absolute path of the generated file. */
|
|
18
|
-
file: string;
|
|
19
|
-
/** Name of the generated class. */
|
|
20
|
-
bundle: string;
|
|
21
|
-
status: OutputStatus;
|
|
22
|
-
registrations: number;
|
|
23
|
-
content: string;
|
|
24
|
-
}
|
|
25
|
-
export interface BuildResult {
|
|
26
|
-
/** Absolute path of the config that was built. */
|
|
27
|
-
config: string;
|
|
28
|
-
output: OutputResult;
|
|
29
|
-
/**
|
|
30
|
-
* Non-fatal problems found while building, e.g. a `files.exclude` that drops a default
|
|
31
|
-
* test glob or two selected classes passing the same decorator token.
|
|
32
|
-
*/
|
|
33
|
-
warnings: string[];
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Generates the bundle a config describes. Nothing is written unless generation succeeds.
|
|
37
|
-
*
|
|
38
|
-
* @throws {TicConfigError} when the config or its tsconfig is missing or invalid, or the config has neither `files.paths` nor a tsconfig.
|
|
39
|
-
* @throws {NamespaceNotFoundError} when a path is neither a folder nor a tsconfig paths alias of one.
|
|
40
|
-
*/
|
|
41
|
-
export declare function build({ config, cwd, check }?: BuildOptions): BuildResult;
|
|
42
|
-
//# sourceMappingURL=build.d.ts.map
|
package/typings/cli.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export interface CliIo {
|
|
2
|
-
cwd: string;
|
|
3
|
-
stdout: (line: string) => void;
|
|
4
|
-
stderr: (line: string) => void;
|
|
5
|
-
}
|
|
6
|
-
/** Runs the `tic` CLI and returns its exit code; output goes through `io`. */
|
|
7
|
-
export declare function run(argv: string[], io?: CliIo): number;
|
|
8
|
-
//# sourceMappingURL=cli.d.ts.map
|
package/typings/errors.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/** Base class of every error the bundler raises on purpose; the CLI prints its message without a stack. */
|
|
2
|
-
export declare class TicError extends Error {
|
|
3
|
-
name: string;
|
|
4
|
-
}
|
|
5
|
-
/** The config file is missing, is not JSON, or does not match the `.bundles.json` shape. */
|
|
6
|
-
export declare class TicConfigError extends TicError {
|
|
7
|
-
name: string;
|
|
8
|
-
}
|
|
9
|
-
/** A namespace is neither an existing folder nor a `tsconfig.json` `paths` alias of one. */
|
|
10
|
-
export declare class NamespaceNotFoundError extends TicError {
|
|
11
|
-
name: string;
|
|
12
|
-
}
|
|
13
|
-
//# sourceMappingURL=errors.d.ts.map
|
package/typings/render.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import '../tpl/index.cjs';
|
|
2
|
-
/**
|
|
3
|
-
* Renders a precompiled protocol, looked up by its file basename (`Bundle.ts.hbs`).
|
|
4
|
-
*
|
|
5
|
-
* @throws {Error} when no protocol is registered under `name`.
|
|
6
|
-
*/
|
|
7
|
-
export declare function renderProtocol(name: string, data: unknown): string;
|
|
8
|
-
//# sourceMappingURL=render.d.ts.map
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|