@ts-ioc-container/bundler 2.0.0 → 3.0.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 +36 -23
- package/README.md +64 -84
- 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 +48 -0
- package/cjm/exceptions/ExceptionHandler.js +38 -0
- package/cjm/features/build/BuildConfig.js +146 -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} +0 -27
- package/cjm/features/build/domain/configFiles.js +35 -0
- package/cjm/{emit.js → features/build/domain/emit.js} +9 -11
- package/cjm/{scan.js → features/build/domain/scan.js} +0 -18
- package/cjm/features/build/domain/tokenCollisions.js +29 -0
- package/cjm/{tsconfig.js → features/build/domain/tsconfig.js} +17 -11
- package/cjm/features/build/services/BundleBuilder.js +93 -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 +83 -26
- package/cjm/modules/CommonModule.js +28 -0
- package/cjm/schema/ticConfigSchema.js +20 -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 +79 -113
- package/tpl/index.cjs +19 -41
- package/typings/app.d.ts +23 -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 +33 -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/features/build/BuildConfig.d.ts +159 -0
- package/typings/features/build/BuildConfig.d.ts.map +1 -0
- package/typings/features/build/BuildController.d.ts +31 -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/{ImportPaths.d.ts → features/build/domain/ImportPaths.d.ts} +2 -9
- 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/features/build/domain/emit.d.ts +36 -0
- 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 -3
- 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 +21 -0
- package/typings/features/build/domain/tsconfig.d.ts.map +1 -0
- package/typings/features/build/services/BundleBuilder.d.ts +65 -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/config.d.ts +0 -162
- package/typings/emit.d.ts +0 -23
- package/typings/errors.d.ts +0 -13
- package/typings/render.d.ts +0 -8
- package/typings/tsconfig.d.ts +0 -25
- /package/cjm/{glob.js → features/build/domain/glob.js} +0 -0
- /package/typings/{glob.d.ts → features/build/domain/glob.d.ts} +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
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.configSuffix = exports.CONFIG_FILE_SUFFIXES = exports.BUNDLE_CONFIG_SCHEMA = exports.DEFAULT_EXCLUDE = exports.DEFAULT_DECORATORS = exports.DEFAULT_BUNDLE_NAME = exports.DEFAULT_EXTENDS = void 0;
|
|
7
|
+
exports.toClassName = toClassName;
|
|
8
|
+
exports.resolveConfig = resolveConfig;
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
|
+
const DomainException_1 = require("../../exceptions/DomainException");
|
|
12
|
+
const glob_1 = require("./domain/glob");
|
|
13
|
+
exports.DEFAULT_EXTENDS = './tsconfig.json';
|
|
14
|
+
exports.DEFAULT_BUNDLE_NAME = 'base';
|
|
15
|
+
exports.DEFAULT_DECORATORS = ['register'];
|
|
16
|
+
exports.DEFAULT_EXCLUDE = [
|
|
17
|
+
'**/*.spec.ts',
|
|
18
|
+
'**/*.test.ts',
|
|
19
|
+
'**/*.spec.tsx',
|
|
20
|
+
'**/*.test.tsx',
|
|
21
|
+
'**/__tests__/**',
|
|
22
|
+
'**/node_modules/**',
|
|
23
|
+
];
|
|
24
|
+
const BUNDLE_NAME = /^[A-Za-z][\w-]*$/;
|
|
25
|
+
const expected = (what) => ({ error: `expected ${what}` });
|
|
26
|
+
const nonEmptyString = () => zod_1.z.string(expected('a non-empty string')).min(1, expected('a non-empty string'));
|
|
27
|
+
const isNonEmptyString = (value) => typeof value === 'string' && value.length > 0;
|
|
28
|
+
const strings = (what, minItems) => zod_1.z
|
|
29
|
+
.custom((value) => Array.isArray(value) && value.length >= minItems && value.every(isNonEmptyString), expected(what))
|
|
30
|
+
.meta({ type: 'array', items: { type: 'string', minLength: 1 }, ...(minItems > 0 && { minItems }) });
|
|
31
|
+
const stringList = () => strings('an array of strings', 0);
|
|
32
|
+
const nonEmptyStringList = () => strings('a non-empty array of strings', 1);
|
|
33
|
+
const CLASSES_SCHEMA = zod_1.z
|
|
34
|
+
.strictObject({
|
|
35
|
+
export: zod_1.z
|
|
36
|
+
.enum(['any', 'named', 'default'], expected('"any", "named" or "default"'))
|
|
37
|
+
.default('any')
|
|
38
|
+
.describe('Which exports count.'),
|
|
39
|
+
decorators: stringList()
|
|
40
|
+
.default(exports.DEFAULT_DECORATORS)
|
|
41
|
+
.describe('The class must carry one of these decorators, recognised by name (e.g. "register", or a composed decorator). Default ["register"]; [] requires none.'),
|
|
42
|
+
name: nonEmptyString()
|
|
43
|
+
.optional()
|
|
44
|
+
.describe('Glob the class name must match, e.g. "*Service". An anonymous default export is named after its file.'),
|
|
45
|
+
excludeClasses: nonEmptyStringList()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe('Class names to drop after selection, e.g. one test double sitting next to the real registration in the same file.'),
|
|
48
|
+
excludeName: nonEmptyString()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe('Glob the class name must NOT match, e.g. "*Mock". An anonymous default export is named after its file.'),
|
|
51
|
+
}, expected('an object'))
|
|
52
|
+
.describe('Which classes of a scanned file are registered. A class is selected when it is exported, not abstract, and meets every criterion set here; by default that is every exported class decorated with @register.');
|
|
53
|
+
const COMPILER_OPTIONS_SCHEMA = zod_1.z
|
|
54
|
+
.looseObject({
|
|
55
|
+
importExtension: zod_1.z
|
|
56
|
+
.string(expected('a string'))
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Extension of generated imports, e.g. ".js". Inferred from the tsconfig: ".js" under node16/nodenext resolution, none otherwise.'),
|
|
59
|
+
classes: CLASSES_SCHEMA.optional(),
|
|
60
|
+
paths: zod_1.z
|
|
61
|
+
.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string()))
|
|
62
|
+
.optional()
|
|
63
|
+
.describe('tsconfig `paths`: aliases the generated imports are written in.'),
|
|
64
|
+
rootDir: zod_1.z
|
|
65
|
+
.string()
|
|
66
|
+
.optional()
|
|
67
|
+
.describe('tsconfig `rootDir`: where the default output (<rootDir>/<name>.bundle.ts) goes.'),
|
|
68
|
+
}, expected('an object'))
|
|
69
|
+
.describe("tsconfig `compilerOptions`, plus the bundler's own `importExtension` and `classes`. Every other option is handed to TypeScript on top of the extended tsconfig's, which validates it.");
|
|
70
|
+
const tsconfigGlobs = (field) => stringList().optional().describe(`tsconfig \`${field}\`: replaces the extended tsconfig's. Relative to this file.`);
|
|
71
|
+
exports.BUNDLE_CONFIG_SCHEMA = zod_1.z.strictObject({
|
|
72
|
+
$schema: zod_1.z.string().optional(),
|
|
73
|
+
extends: nonEmptyString()
|
|
74
|
+
.optional()
|
|
75
|
+
.meta({ default: exports.DEFAULT_EXTENDS })
|
|
76
|
+
.describe("The tsconfig this bundle extends, as a tsconfig's own `extends`: its file set, `paths` aliases and module resolution apply unless this file overrides them. Relative to this file. The default may be absent; a tsconfig named here must exist."),
|
|
77
|
+
output: nonEmptyString()
|
|
78
|
+
.optional()
|
|
79
|
+
.describe('The bundle file (convention: *.bundle.ts). Default `<root>/<name>.bundle.ts`: <root> is the compiled rootDir, else the common folder of the files compiled.'),
|
|
80
|
+
name: zod_1.z
|
|
81
|
+
.string(expected('letters, digits, "-" or "_", starting with a letter'))
|
|
82
|
+
.regex(BUNDLE_NAME, expected('letters, digits, "-" or "_", starting with a letter'))
|
|
83
|
+
.optional()
|
|
84
|
+
.describe('The bundle\'s name: letters, digits, "-" and "_", starting with a letter. Default: this file\'s stem (production.bundle.json → production), else "base". It names the default output (production.bundle.ts) and the generated IContainerModule class (ProductionBundle).'),
|
|
85
|
+
include: tsconfigGlobs('include'),
|
|
86
|
+
exclude: tsconfigGlobs('exclude'),
|
|
87
|
+
compilerOptions: COMPILER_OPTIONS_SCHEMA.optional(),
|
|
88
|
+
}, expected('an object'));
|
|
89
|
+
function formatPath(segments) {
|
|
90
|
+
const formatted = segments
|
|
91
|
+
.map((segment) => (typeof segment === 'number' ? `[${segment}]` : `.${String(segment)}`))
|
|
92
|
+
.join('')
|
|
93
|
+
.replace(/^\./, '');
|
|
94
|
+
return formatted || 'config';
|
|
95
|
+
}
|
|
96
|
+
function formatIssue(issue) {
|
|
97
|
+
if (issue.code === 'unrecognized_keys') {
|
|
98
|
+
return issue.keys.map((key) => `${formatPath([...issue.path, key])}: unknown field`);
|
|
99
|
+
}
|
|
100
|
+
return [`${formatPath(issue.path)}: ${issue.message}`];
|
|
101
|
+
}
|
|
102
|
+
const formatIssues = (error) => error.issues.flatMap((issue) => formatIssue(issue)).join('; ');
|
|
103
|
+
function toClassSelector(classes) {
|
|
104
|
+
if (classes === undefined)
|
|
105
|
+
return { export: 'any', decorators: exports.DEFAULT_DECORATORS };
|
|
106
|
+
const { decorators, name, excludeName, ...rest } = classes;
|
|
107
|
+
return {
|
|
108
|
+
...rest,
|
|
109
|
+
decorators: decorators.length > 0 ? decorators : undefined,
|
|
110
|
+
name: name === undefined ? undefined : (0, glob_1.globToRegExp)(name),
|
|
111
|
+
excludeName: excludeName === undefined ? undefined : (0, glob_1.globToRegExp)(excludeName),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
exports.CONFIG_FILE_SUFFIXES = ['.bundle.json', '.bundle.yaml', '.bundle.yml'];
|
|
115
|
+
const configSuffix = (file) => exports.CONFIG_FILE_SUFFIXES.find((suffix) => file.endsWith(suffix));
|
|
116
|
+
exports.configSuffix = configSuffix;
|
|
117
|
+
function configStem(file) {
|
|
118
|
+
const base = node_path_1.default.basename(file);
|
|
119
|
+
const suffix = (0, exports.configSuffix)(base);
|
|
120
|
+
const stem = suffix ? base.slice(0, -suffix.length) : '';
|
|
121
|
+
return BUNDLE_NAME.test(stem) ? stem : undefined;
|
|
122
|
+
}
|
|
123
|
+
function toClassName(name) {
|
|
124
|
+
const words = name.split(/[-_]+/).filter(Boolean);
|
|
125
|
+
return `${words.map((word) => word[0].toUpperCase() + word.slice(1)).join('')}Bundle`;
|
|
126
|
+
}
|
|
127
|
+
function resolveConfig(content, file) {
|
|
128
|
+
const result = exports.BUNDLE_CONFIG_SCHEMA.safeParse(content);
|
|
129
|
+
if (!result.success)
|
|
130
|
+
throw new DomainException_1.TicConfigError(formatIssues(result.error));
|
|
131
|
+
const { output, name, extends: tsconfig, include, exclude, compilerOptions = {} } = result.data;
|
|
132
|
+
const { importExtension, classes, ...tsCompilerOptions } = compilerOptions;
|
|
133
|
+
const dir = node_path_1.default.dirname(file);
|
|
134
|
+
const bundleName = name ?? configStem(file) ?? exports.DEFAULT_BUNDLE_NAME;
|
|
135
|
+
return {
|
|
136
|
+
file,
|
|
137
|
+
dir,
|
|
138
|
+
output: output === undefined ? undefined : node_path_1.default.resolve(dir, output),
|
|
139
|
+
name: bundleName,
|
|
140
|
+
className: toClassName(bundleName),
|
|
141
|
+
tsconfig: { file: node_path_1.default.resolve(dir, tsconfig ?? exports.DEFAULT_EXTENDS), required: tsconfig !== undefined },
|
|
142
|
+
overrides: { include, exclude, compilerOptions: tsCompilerOptions },
|
|
143
|
+
importExtension,
|
|
144
|
+
classes: toClassSelector(classes),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.BuildController = exports.BUILD_OPTIONS = void 0;
|
|
19
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
20
|
+
const ts_ioc_container_1 = require("ts-ioc-container");
|
|
21
|
+
const zod_1 = require("zod");
|
|
22
|
+
const cli_1 = require("../../cli");
|
|
23
|
+
const GlobalConfig_1 = require("../../domain/GlobalConfig");
|
|
24
|
+
const DomainException_1 = require("../../exceptions/DomainException");
|
|
25
|
+
const ConsoleLogger_1 = require("../../services/ConsoleLogger");
|
|
26
|
+
const OutputService_1 = require("../../services/OutputService");
|
|
27
|
+
const BundleBuilder_1 = require("./services/BundleBuilder");
|
|
28
|
+
const TicConfigService_1 = require("./services/TicConfigService");
|
|
29
|
+
exports.BUILD_OPTIONS = zod_1.z.object({
|
|
30
|
+
config: zod_1.z.array(zod_1.z.string().min(1)).default([]),
|
|
31
|
+
check: zod_1.z.boolean().default(false),
|
|
32
|
+
});
|
|
33
|
+
const buildArgs = (0, cli_1.parseOptions)({
|
|
34
|
+
config: { type: 'string', short: 'c', multiple: true },
|
|
35
|
+
check: { type: 'boolean' },
|
|
36
|
+
});
|
|
37
|
+
const VERB = { written: 'wrote', unchanged: 'unchanged', stale: 'stale' };
|
|
38
|
+
const plural = (n) => `${n} registration${n === 1 ? '' : 's'}`;
|
|
39
|
+
let BuildController = class BuildController {
|
|
40
|
+
cwd;
|
|
41
|
+
configs;
|
|
42
|
+
builder;
|
|
43
|
+
output;
|
|
44
|
+
logger;
|
|
45
|
+
constructor(cwd, configs, builder, output, logger) {
|
|
46
|
+
this.cwd = cwd;
|
|
47
|
+
this.configs = configs;
|
|
48
|
+
this.builder = builder;
|
|
49
|
+
this.output = output;
|
|
50
|
+
this.logger = logger;
|
|
51
|
+
}
|
|
52
|
+
build(options) {
|
|
53
|
+
let stale = 0;
|
|
54
|
+
for (const config of this.configs.discover(options.config)) {
|
|
55
|
+
const name = config === undefined ? TicConfigService_1.TSCONFIG_FILE : node_path_1.default.relative(this.cwd, config);
|
|
56
|
+
try {
|
|
57
|
+
const { output, warnings } = this.builder.build({ config, check: options.check });
|
|
58
|
+
for (const warning of warnings)
|
|
59
|
+
this.logger.warn(`${name}: ${warning}`);
|
|
60
|
+
const { status, file, registrations } = output;
|
|
61
|
+
this.output.write(`${VERB[status].padEnd(10)}${node_path_1.default.relative(this.cwd, file)} (${plural(registrations)})`);
|
|
62
|
+
if (status === 'stale')
|
|
63
|
+
stale++;
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
if (e instanceof DomainException_1.TicError)
|
|
67
|
+
e.message = `${name}: ${e.message}`;
|
|
68
|
+
throw e;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (stale > 0)
|
|
72
|
+
throw new DomainException_1.StaleBundlesError(stale);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
exports.BuildController = BuildController;
|
|
76
|
+
__decorate([
|
|
77
|
+
(0, cli_1.onDefault)(ts_ioc_container_1.invoke),
|
|
78
|
+
__param(0, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.pipe)(cli_1.commandArgs, buildArgs, (0, cli_1.validate)(exports.BUILD_OPTIONS)))),
|
|
79
|
+
__metadata("design:type", Function),
|
|
80
|
+
__metadata("design:paramtypes", [Object]),
|
|
81
|
+
__metadata("design:returntype", void 0)
|
|
82
|
+
], BuildController.prototype, "build", null);
|
|
83
|
+
exports.BuildController = BuildController = __decorate([
|
|
84
|
+
(0, ts_ioc_container_1.register)('build'),
|
|
85
|
+
__param(0, (0, ts_ioc_container_1.inject)((0, GlobalConfig_1.globalConfig)('cwd'))),
|
|
86
|
+
__param(1, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.by)(TicConfigService_1.ITicConfigServiceKey))),
|
|
87
|
+
__param(2, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.by)(BundleBuilder_1.IBundleBuilderKey))),
|
|
88
|
+
__param(3, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.by)(OutputService_1.IOutputServiceKey))),
|
|
89
|
+
__param(4, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.by)(ConsoleLogger_1.ILoggerKey))),
|
|
90
|
+
__metadata("design:paramtypes", [String, Object, Object, Object, Object])
|
|
91
|
+
], BuildController);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BuildModule = void 0;
|
|
4
|
+
const ts_ioc_container_1 = require("ts-ioc-container");
|
|
5
|
+
const BuildController_1 = require("./BuildController");
|
|
6
|
+
const BundleBuilder_1 = require("./services/BundleBuilder");
|
|
7
|
+
const TicConfigService_1 = require("./services/TicConfigService");
|
|
8
|
+
class BuildModule {
|
|
9
|
+
applyTo(container) {
|
|
10
|
+
container
|
|
11
|
+
.addRegistration(ts_ioc_container_1.Registration.fromClass(BuildController_1.BuildController))
|
|
12
|
+
.addRegistration(ts_ioc_container_1.Registration.fromClass(BundleBuilder_1.BundleBuilder))
|
|
13
|
+
.addRegistration(ts_ioc_container_1.Registration.fromClass(TicConfigService_1.TicConfigService));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.BuildModule = BuildModule;
|
|
@@ -37,14 +37,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.ImportPaths = void 0;
|
|
40
|
-
const node_fs_1 = require("node:fs");
|
|
41
40
|
const node_path_1 = __importDefault(require("node:path"));
|
|
42
41
|
const ts = __importStar(require("typescript"));
|
|
43
|
-
const errors_1 = require("./errors");
|
|
44
42
|
const glob_1 = require("./glob");
|
|
45
43
|
const SOURCE_EXTENSION = /\.(tsx?|mts|cts)$/;
|
|
46
|
-
const isDirectory = (dir) => (0, node_fs_1.existsSync)(dir) && (0, node_fs_1.statSync)(dir).isDirectory();
|
|
47
|
-
const isRelative = (spec) => spec.startsWith('.') || node_path_1.default.isAbsolute(spec);
|
|
48
44
|
function splitWildcard(pattern) {
|
|
49
45
|
const star = pattern.indexOf('*');
|
|
50
46
|
return star === -1 ? undefined : [pattern.slice(0, star), pattern.slice(star + 1)];
|
|
@@ -66,17 +62,6 @@ class ImportPaths {
|
|
|
66
62
|
this.aliases = aliases;
|
|
67
63
|
this.extension = extension;
|
|
68
64
|
}
|
|
69
|
-
resolveNamespace(namespace, baseDir) {
|
|
70
|
-
const folder = node_path_1.default.resolve(baseDir, namespace);
|
|
71
|
-
if (isDirectory(folder))
|
|
72
|
-
return folder;
|
|
73
|
-
if (!isRelative(namespace)) {
|
|
74
|
-
const found = [namespace, `${namespace}/`].flatMap((spec) => this.aliasTargets(spec)).find(isDirectory);
|
|
75
|
-
if (found)
|
|
76
|
-
return node_path_1.default.normalize(found);
|
|
77
|
-
}
|
|
78
|
-
throw new errors_1.NamespaceNotFoundError(`namespace "${namespace}" is neither a folder relative to ${baseDir} nor a tsconfig paths alias of one`);
|
|
79
|
-
}
|
|
80
65
|
specifier(fromFile, toFile) {
|
|
81
66
|
const target = (0, glob_1.toPosix)(toFile);
|
|
82
67
|
const bare = target.replace(SOURCE_EXTENSION, '');
|
|
@@ -97,18 +82,6 @@ class ImportPaths {
|
|
|
97
82
|
}
|
|
98
83
|
return best;
|
|
99
84
|
}
|
|
100
|
-
aliasTargets(spec) {
|
|
101
|
-
return this.aliases.flatMap(({ pattern, targets }) => {
|
|
102
|
-
const wildcard = splitWildcard(pattern);
|
|
103
|
-
if (!wildcard)
|
|
104
|
-
return pattern === spec ? targets : [];
|
|
105
|
-
const [prefix, suffix] = wildcard;
|
|
106
|
-
if (!spec.startsWith(prefix) || !spec.endsWith(suffix) || spec.length < prefix.length + suffix.length)
|
|
107
|
-
return [];
|
|
108
|
-
const captured = spec.slice(prefix.length, spec.length - suffix.length);
|
|
109
|
-
return targets.map((target) => target.replace('*', captured));
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
85
|
matchAlias(pattern, aliasTarget, file, bare) {
|
|
113
86
|
const wildcard = splitWildcard(aliasTarget);
|
|
114
87
|
if (!wildcard) {
|
|
@@ -0,0 +1,35 @@
|
|
|
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.findPackageRoot = findPackageRoot;
|
|
7
|
+
exports.findConfigFiles = findConfigFiles;
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const DomainException_1 = require("../../../exceptions/DomainException");
|
|
11
|
+
const BuildConfig_1 = require("../BuildConfig");
|
|
12
|
+
function findPackageRoot(dir) {
|
|
13
|
+
const start = node_path_1.default.resolve(dir);
|
|
14
|
+
for (let current = start;; current = node_path_1.default.dirname(current)) {
|
|
15
|
+
if ((0, node_fs_1.existsSync)(node_path_1.default.join(current, 'package.json')))
|
|
16
|
+
return current;
|
|
17
|
+
if (node_path_1.default.dirname(current) === current)
|
|
18
|
+
return start;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function findConfigFiles(dir) {
|
|
22
|
+
const files = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true })
|
|
23
|
+
.filter((entry) => entry.isFile() && (0, BuildConfig_1.configSuffix)(entry.name) !== undefined)
|
|
24
|
+
.map((entry) => entry.name)
|
|
25
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
26
|
+
const byStem = new Map();
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
const stem = file.slice(0, -(0, BuildConfig_1.configSuffix)(file).length);
|
|
29
|
+
const other = byStem.get(stem);
|
|
30
|
+
if (other)
|
|
31
|
+
throw new DomainException_1.TicConfigError(`${other} and ${file} describe the same bundle; keep one`);
|
|
32
|
+
byStem.set(stem, file);
|
|
33
|
+
}
|
|
34
|
+
return files.map((file) => node_path_1.default.join(dir, file));
|
|
35
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GENERATED_HEADER = void 0;
|
|
3
|
+
exports.BUNDLE_PROTOCOL = exports.GENERATED_HEADER = void 0;
|
|
4
|
+
exports.bundleView = bundleView;
|
|
4
5
|
exports.emitBundle = emitBundle;
|
|
5
|
-
const
|
|
6
|
+
const HandlebarsRenderService_1 = require("../../../services/HandlebarsRenderService");
|
|
6
7
|
exports.GENERATED_HEADER = '// Generated by `tic build`';
|
|
8
|
+
exports.BUNDLE_PROTOCOL = 'Bundle.ts.hbs';
|
|
7
9
|
const RUNTIME_IMPORTS = ['IContainer', 'IContainerModule', 'IRegistration', 'Registration'];
|
|
8
|
-
function
|
|
10
|
+
function bundleView({ name, configPath, classes }) {
|
|
9
11
|
const taken = new Set([...RUNTIME_IMPORTS, 'registrations', name]);
|
|
10
12
|
const uniqueName = (wanted) => {
|
|
11
13
|
let candidate = wanted;
|
|
@@ -25,12 +27,8 @@ function emitBundle({ name, configPath, paths, tsconfigPath, classes }) {
|
|
|
25
27
|
entry.named.push(binding === cls.exportName ? binding : `${cls.exportName} as ${binding}`);
|
|
26
28
|
return binding;
|
|
27
29
|
});
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
name,
|
|
33
|
-
imports: [...byFile.values()],
|
|
34
|
-
registrations: bindings,
|
|
35
|
-
});
|
|
30
|
+
return { configPath, name, imports: [...byFile.values()], registrations: bindings };
|
|
31
|
+
}
|
|
32
|
+
function emitBundle(input) {
|
|
33
|
+
return (0, HandlebarsRenderService_1.renderProtocol)(exports.BUNDLE_PROTOCOL, bundleView(input));
|
|
36
34
|
}
|
|
@@ -37,7 +37,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.isSourceFile = void 0;
|
|
40
|
-
exports.listSourceFiles = listSourceFiles;
|
|
41
40
|
exports.findClasses = findClasses;
|
|
42
41
|
const node_fs_1 = require("node:fs");
|
|
43
42
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -46,23 +45,6 @@ const SOURCE_FILE = /\.(tsx?|mts|cts)$/;
|
|
|
46
45
|
const DECLARATION_FILE = /\.d\.[mc]?tsx?$/;
|
|
47
46
|
const isSourceFile = (file) => SOURCE_FILE.test(file) && !DECLARATION_FILE.test(file);
|
|
48
47
|
exports.isSourceFile = isSourceFile;
|
|
49
|
-
function listSourceFiles(dir, recursive, isExcluded) {
|
|
50
|
-
const files = [];
|
|
51
|
-
const walk = (current) => {
|
|
52
|
-
for (const entry of (0, node_fs_1.readdirSync)(current, { withFileTypes: true })) {
|
|
53
|
-
const full = node_path_1.default.join(current, entry.name);
|
|
54
|
-
if (entry.isDirectory()) {
|
|
55
|
-
if (recursive && entry.name !== 'node_modules')
|
|
56
|
-
walk(full);
|
|
57
|
-
}
|
|
58
|
-
else if ((0, exports.isSourceFile)(entry.name) && !isExcluded(full)) {
|
|
59
|
-
files.push(full);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
walk(dir);
|
|
64
|
-
return files.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
65
|
-
}
|
|
66
48
|
const hasModifier = (node, kind) => ts.canHaveModifiers(node) && (ts.getModifiers(node) ?? []).some((m) => m.kind === kind);
|
|
67
49
|
function decoratorName(decorator, imports) {
|
|
68
50
|
const callee = ts.isCallExpression(decorator.expression) ? decorator.expression.expression : decorator.expression;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tokenCollisions = tokenCollisions;
|
|
4
|
+
function tokenCollisions(classes) {
|
|
5
|
+
const owners = new Map();
|
|
6
|
+
for (const cls of classes) {
|
|
7
|
+
for (const token of cls.tokens) {
|
|
8
|
+
const group = owners.get(token) ?? [];
|
|
9
|
+
if (!group.some((owner) => owner.className === cls.className))
|
|
10
|
+
group.push(cls);
|
|
11
|
+
owners.set(token, group);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return [...owners]
|
|
15
|
+
.filter(([, group]) => group.length > 1 && !scopeDisjoint(group))
|
|
16
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
17
|
+
.map(([token, group]) => {
|
|
18
|
+
const names = group.map((cls) => cls.className);
|
|
19
|
+
return (`decorator token "${token}" is passed by ${names.join(', ')}; ` +
|
|
20
|
+
`registration is last-wins, exclude one with compilerOptions.classes.excludeClasses`);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function scopeDisjoint(group) {
|
|
24
|
+
const [first, ...rest] = group;
|
|
25
|
+
return first.decoratorCalls.some(({ name, args }) => rest.every((cls) => {
|
|
26
|
+
const same = cls.decoratorCalls.find((call) => call.name === name);
|
|
27
|
+
return same !== undefined && same.args.join('\u0000') !== args.join('\u0000');
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
@@ -40,7 +40,7 @@ exports.loadTsconfig = loadTsconfig;
|
|
|
40
40
|
const node_fs_1 = require("node:fs");
|
|
41
41
|
const node_path_1 = __importDefault(require("node:path"));
|
|
42
42
|
const ts = __importStar(require("typescript"));
|
|
43
|
-
const
|
|
43
|
+
const DomainException_1 = require("../../../exceptions/DomainException");
|
|
44
44
|
const ImportPaths_1 = require("./ImportPaths");
|
|
45
45
|
const scan_1 = require("./scan");
|
|
46
46
|
const NO_INPUTS = 18003;
|
|
@@ -57,22 +57,28 @@ function commonDir(files) {
|
|
|
57
57
|
}
|
|
58
58
|
return first.slice(0, length).join(node_path_1.default.sep) || node_path_1.default.sep;
|
|
59
59
|
}
|
|
60
|
-
function
|
|
61
|
-
if (!(0, node_fs_1.existsSync)(tsconfig.file)) {
|
|
62
|
-
if (tsconfig.required)
|
|
63
|
-
throw new
|
|
64
|
-
return {
|
|
60
|
+
function asTsconfig(config) {
|
|
61
|
+
if (!(0, node_fs_1.existsSync)(config.tsconfig.file)) {
|
|
62
|
+
if (config.tsconfig.required)
|
|
63
|
+
throw new DomainException_1.TicConfigError(`tsconfig not found: ${config.tsconfig.file}`);
|
|
64
|
+
return { config: config.overrides };
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
if (config.file === config.tsconfig.file)
|
|
67
|
+
return ts.readConfigFile(config.file, ts.sys.readFile);
|
|
68
|
+
return { config: { extends: config.tsconfig.file, ...config.overrides } };
|
|
69
|
+
}
|
|
70
|
+
function loadTsconfig(config) {
|
|
71
|
+
const { config: json, error } = asTsconfig(config);
|
|
72
|
+
const configFileName = config.file === config.tsconfig.file ? config.file : undefined;
|
|
73
|
+
const parsed = ts.parseJsonConfigFileContent(json ?? {}, ts.sys, config.dir, undefined, configFileName);
|
|
68
74
|
const [fatal] = [error, ...parsed.errors].filter((d) => !!d && d.code !== NO_INPUTS);
|
|
69
75
|
if (fatal) {
|
|
70
|
-
throw new
|
|
76
|
+
throw new DomainException_1.TicConfigError(`${config.file}: ${ts.flattenDiagnosticMessageText(fatal.messageText, '\n')}`);
|
|
71
77
|
}
|
|
72
78
|
const fileNames = parsed.fileNames.map((file) => node_path_1.default.resolve(file));
|
|
73
79
|
return {
|
|
74
|
-
importPaths: ImportPaths_1.ImportPaths.fromOptions(parsed.options,
|
|
80
|
+
importPaths: ImportPaths_1.ImportPaths.fromOptions(parsed.options, config.file, config.importExtension),
|
|
75
81
|
fileNames,
|
|
76
|
-
rootDir: parsed.options.rootDir ?? commonDir(fileNames.filter(scan_1.isSourceFile)) ??
|
|
82
|
+
rootDir: parsed.options.rootDir ?? commonDir(fileNames.filter(scan_1.isSourceFile)) ?? config.dir,
|
|
77
83
|
};
|
|
78
84
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.BundleBuilder = exports.IBundleBuilderKey = void 0;
|
|
19
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
20
|
+
const ts_ioc_container_1 = require("ts-ioc-container");
|
|
21
|
+
const GlobalConfig_1 = require("../../../domain/GlobalConfig");
|
|
22
|
+
const HandlebarsRenderService_1 = require("../../../services/HandlebarsRenderService");
|
|
23
|
+
const NodeFileSystemService_1 = require("../../../services/NodeFileSystemService");
|
|
24
|
+
const BuildConfig_1 = require("../BuildConfig");
|
|
25
|
+
const configFiles_1 = require("../domain/configFiles");
|
|
26
|
+
const emit_1 = require("../domain/emit");
|
|
27
|
+
const glob_1 = require("../domain/glob");
|
|
28
|
+
const scan_1 = require("../domain/scan");
|
|
29
|
+
const tokenCollisions_1 = require("../domain/tokenCollisions");
|
|
30
|
+
const tsconfig_1 = require("../domain/tsconfig");
|
|
31
|
+
const TicConfigService_1 = require("./TicConfigService");
|
|
32
|
+
const DEFAULT_EXCLUDE_GLOBS = BuildConfig_1.DEFAULT_EXCLUDE.map(glob_1.globToRegExp);
|
|
33
|
+
exports.IBundleBuilderKey = new ts_ioc_container_1.SingleToken('IBundleBuilder');
|
|
34
|
+
let BundleBuilder = class BundleBuilder {
|
|
35
|
+
cwd;
|
|
36
|
+
configs;
|
|
37
|
+
fs;
|
|
38
|
+
renderer;
|
|
39
|
+
constructor(cwd, configs, fs, renderer) {
|
|
40
|
+
this.cwd = cwd;
|
|
41
|
+
this.configs = configs;
|
|
42
|
+
this.fs = fs;
|
|
43
|
+
this.renderer = renderer;
|
|
44
|
+
}
|
|
45
|
+
build({ config, check = false } = {}) {
|
|
46
|
+
const resolved = config === undefined
|
|
47
|
+
? (0, BuildConfig_1.resolveConfig)({ extends: BuildConfig_1.DEFAULT_EXTENDS }, node_path_1.default.join((0, configFiles_1.findPackageRoot)(this.cwd), TicConfigService_1.TSCONFIG_FILE))
|
|
48
|
+
: this.configs.load(node_path_1.default.resolve(this.cwd, config));
|
|
49
|
+
const { output, content, registrations, warnings } = this.generate(resolved);
|
|
50
|
+
const current = this.fs.fileExists(output) ? this.fs.readFile(output) : undefined;
|
|
51
|
+
const status = current === content ? 'unchanged' : check ? 'stale' : 'written';
|
|
52
|
+
if (status === 'written')
|
|
53
|
+
this.fs.writeFile(output, content);
|
|
54
|
+
return {
|
|
55
|
+
config: resolved.file,
|
|
56
|
+
output: { file: output, bundle: resolved.className, status, registrations, content },
|
|
57
|
+
warnings,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
generate(config) {
|
|
61
|
+
const { importPaths: paths, fileNames, rootDir } = (0, tsconfig_1.loadTsconfig)(config);
|
|
62
|
+
const output = config.output ?? node_path_1.default.join(rootDir, `${config.name}.bundle.ts`);
|
|
63
|
+
const isExcluded = (file) => {
|
|
64
|
+
if (file === output)
|
|
65
|
+
return true;
|
|
66
|
+
const filename = (0, glob_1.toPosix)(node_path_1.default.relative(config.dir, file));
|
|
67
|
+
return DEFAULT_EXCLUDE_GLOBS.some((glob) => glob.test(filename));
|
|
68
|
+
};
|
|
69
|
+
const files = fileNames.filter((file) => (0, scan_1.isSourceFile)(file) && !isExcluded(file));
|
|
70
|
+
const classes = files
|
|
71
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
72
|
+
.flatMap((file) => {
|
|
73
|
+
const text = this.fs.readFile(file);
|
|
74
|
+
return text.startsWith(emit_1.GENERATED_HEADER) ? [] : (0, scan_1.findClasses)(file, config.classes, text);
|
|
75
|
+
})
|
|
76
|
+
.map((cls) => ({ ...cls, specifier: paths.specifier(output, cls.file) }));
|
|
77
|
+
const content = this.renderer.render(emit_1.BUNDLE_PROTOCOL, (0, emit_1.bundleView)({
|
|
78
|
+
name: config.className,
|
|
79
|
+
configPath: (0, glob_1.toPosix)(node_path_1.default.relative(node_path_1.default.dirname(output), config.file)),
|
|
80
|
+
classes,
|
|
81
|
+
}));
|
|
82
|
+
return { output, content, registrations: classes.length, warnings: (0, tokenCollisions_1.tokenCollisions)(classes) };
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
exports.BundleBuilder = BundleBuilder;
|
|
86
|
+
exports.BundleBuilder = BundleBuilder = __decorate([
|
|
87
|
+
(0, ts_ioc_container_1.register)(exports.IBundleBuilderKey),
|
|
88
|
+
__param(0, (0, ts_ioc_container_1.inject)((0, GlobalConfig_1.globalConfig)('cwd'))),
|
|
89
|
+
__param(1, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.by)(TicConfigService_1.ITicConfigServiceKey))),
|
|
90
|
+
__param(2, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.by)(NodeFileSystemService_1.IFileSystemServiceKey))),
|
|
91
|
+
__param(3, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.by)(HandlebarsRenderService_1.IRenderServiceKey))),
|
|
92
|
+
__metadata("design:paramtypes", [String, Object, Object, Object])
|
|
93
|
+
], BundleBuilder);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.TicConfigService = exports.ITicConfigServiceKey = exports.TSCONFIG_FILE = void 0;
|
|
19
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
20
|
+
const ts_ioc_container_1 = require("ts-ioc-container");
|
|
21
|
+
const yaml_1 = require("yaml");
|
|
22
|
+
const GlobalConfig_1 = require("../../../domain/GlobalConfig");
|
|
23
|
+
const DomainException_1 = require("../../../exceptions/DomainException");
|
|
24
|
+
const NodeFileSystemService_1 = require("../../../services/NodeFileSystemService");
|
|
25
|
+
const BuildConfig_1 = require("../BuildConfig");
|
|
26
|
+
const configFiles_1 = require("../domain/configFiles");
|
|
27
|
+
exports.TSCONFIG_FILE = 'tsconfig.json';
|
|
28
|
+
exports.ITicConfigServiceKey = new ts_ioc_container_1.SingleToken('ITicConfigService');
|
|
29
|
+
let TicConfigService = class TicConfigService {
|
|
30
|
+
cwd;
|
|
31
|
+
fs;
|
|
32
|
+
constructor(cwd, fs) {
|
|
33
|
+
this.cwd = cwd;
|
|
34
|
+
this.fs = fs;
|
|
35
|
+
}
|
|
36
|
+
load(file) {
|
|
37
|
+
if (!this.fs.fileExists(file))
|
|
38
|
+
throw new DomainException_1.TicConfigError(`config file not found: ${file}`);
|
|
39
|
+
return (0, BuildConfig_1.resolveConfig)(parseConfig(file, this.fs.readFile(file)), file);
|
|
40
|
+
}
|
|
41
|
+
discover(named) {
|
|
42
|
+
if (named.length > 0)
|
|
43
|
+
return named.map((config) => node_path_1.default.resolve(this.cwd, config));
|
|
44
|
+
const root = (0, configFiles_1.findPackageRoot)(this.cwd);
|
|
45
|
+
const found = (0, configFiles_1.findConfigFiles)(root);
|
|
46
|
+
if (found.length > 0)
|
|
47
|
+
return found;
|
|
48
|
+
if (this.fs.fileExists(node_path_1.default.join(root, exports.TSCONFIG_FILE)))
|
|
49
|
+
return [undefined];
|
|
50
|
+
throw new DomainException_1.TicConfigError(`no *.bundle.{json,yaml,yml} or ${exports.TSCONFIG_FILE} in ${root}; name a config with --config`);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
exports.TicConfigService = TicConfigService;
|
|
54
|
+
exports.TicConfigService = TicConfigService = __decorate([
|
|
55
|
+
(0, ts_ioc_container_1.register)(exports.ITicConfigServiceKey),
|
|
56
|
+
__param(0, (0, ts_ioc_container_1.inject)((0, GlobalConfig_1.globalConfig)('cwd'))),
|
|
57
|
+
__param(1, (0, ts_ioc_container_1.inject)((0, ts_ioc_container_1.by)(NodeFileSystemService_1.IFileSystemServiceKey))),
|
|
58
|
+
__metadata("design:paramtypes", [String, Object])
|
|
59
|
+
], TicConfigService);
|
|
60
|
+
function parseConfig(file, text) {
|
|
61
|
+
const yaml = file.endsWith('.yaml') || file.endsWith('.yml');
|
|
62
|
+
try {
|
|
63
|
+
return yaml ? ((0, yaml_1.parse)(text) ?? {}) : JSON.parse(text);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
throw new DomainException_1.TicConfigError(`${file} is not valid ${yaml ? 'YAML' : 'JSON'}: ${e.message}`);
|
|
67
|
+
}
|
|
68
|
+
}
|