@ttsc/banner 0.30.3 → 0.31.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.
@@ -0,0 +1,100 @@
1
+ import type { ITtscBannerPluginConfig } from "./structures";
2
+ /**
3
+ * The shape returned by a ttsc plugin factory function.
4
+ *
5
+ * Mirrors the ttsc plugin descriptor contract. The `source` field points to the
6
+ * Go source directory that the host will compile and cache as either an
7
+ * executable sidecar or linked native source.
8
+ */
9
+ type TtscPluginDescriptor = {
10
+ /** The bundled driver host records actual writes and their physical sources. */
11
+ capabilities: {
12
+ emitProvenance: true;
13
+ };
14
+ /** Universal config-discovery inputs consumed by the native transform. */
15
+ hostInputs?: string[];
16
+ /** Evaluation-time fingerprints paired with {@link hostInputs}. */
17
+ hostInputHashes?: Record<string, string | null>;
18
+ /** Evaluation-time physical targets paired with {@link hostInputs}. */
19
+ hostInputRealpaths?: Record<string, string | null>;
20
+ /** Human-readable plugin name used in logs and error messages. */
21
+ name: string;
22
+ /** Absolute path to the Go source directory for this plugin. */
23
+ source: string;
24
+ /**
25
+ * Pipeline stage. `"transform"` plugins may rewrite source files; `"check"`
26
+ * plugins only produce diagnostics. The framework default is `"transform"`.
27
+ */
28
+ stage?: "check" | "transform";
29
+ };
30
+ /**
31
+ * Context object passed by the ttsc host to every plugin factory function.
32
+ *
33
+ * Module anchors locate shipped Go source. Project anchors locate user
34
+ * configuration, including when the host uses a generated wrapper tsconfig.
35
+ */
36
+ type TtscPluginFactoryContext<TConfig> = {
37
+ /** Absolute path to the selected ttsc native helper, not a plugin binary. */
38
+ binary: string;
39
+ /** Working directory of the ttsc invocation. */
40
+ cwd: string;
41
+ /**
42
+ * Absolute path to the directory holding this descriptor module, the
43
+ * load-mode-independent replacement for `__dirname`.
44
+ */
45
+ dirname: string;
46
+ /**
47
+ * Absolute path to this descriptor module, the load-mode-independent
48
+ * replacement for `__filename`.
49
+ */
50
+ filename: string;
51
+ /** Host-declared anchor for implicit plugin config discovery. */
52
+ pluginConfigDir?: string;
53
+ /** The raw plugin entry from `compilerOptions.plugins[]`. */
54
+ plugin: TConfig;
55
+ /** Absolute path to the project root (directory containing tsconfig). */
56
+ projectRoot: string;
57
+ /** Absolute path to the resolved tsconfig. */
58
+ tsconfig: string;
59
+ };
60
+ /**
61
+ * Plugin factory called by the ttsc host to obtain the `@ttsc/banner`
62
+ * descriptor.
63
+ *
64
+ * The only banner-specific key accepted in the tsconfig plugin entry is
65
+ * `configFile`. Any other key that is not a known framework key is rejected
66
+ * with a specific error so users discover the correct configuration surface
67
+ * (the dedicated config file) rather than silently receiving no banner.
68
+ *
69
+ * @evidence contracts/common.md#principled-implementation
70
+ * The default-export factory maps host module anchors to the shipped driver
71
+ * and project anchors to config candidates. Discovery records all seven
72
+ * candidate names in every directory from the anchor through the first one
73
+ * holding a non-directory match, including absent paths and directory markers,
74
+ * so creating a nearer config or a second file beside the match changes the
75
+ * descriptor inputs. Native evaluation validates ambiguous or invalid config;
76
+ * this factory supplies observations rather than treating existence as a
77
+ * valid banner. SHA-256 covers candidate bytes and a distinct directory marker.
78
+ *
79
+ * @evidence contracts/common.md#clear-and-simple-design
80
+ * Registration validation, discovery observations and descriptor construction
81
+ * have separate responsibilities. Private helpers isolate path discovery and
82
+ * filesystem observations; they do not implement another config evaluator.
83
+ * The driver path follows the installed package layout, while config anchors
84
+ * follow the project because those two directories have different owners.
85
+ *
86
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
87
+ * Framework keys, candidate filenames, package identity and stage encode the
88
+ * supported registration contract. The descriptor neither evaluates user
89
+ * JavaScript nor changes a foreign loader; it records a failed probe (an absent
90
+ * or unreadable candidate) as a null hash or physical target, and native
91
+ * evaluation reports the actual error.
92
+ *
93
+ * @evidence contracts/common.md#meaningful-documentation
94
+ * JSDoc separates registration from config evaluation and explains why
95
+ * unknown inline keys are rejected. Context and descriptor fields document
96
+ * host anchoring and observed inputs. Paragraphs and reasons follow the
97
+ * documentation skill; the exported factory is documented as a host entry.
98
+ */
99
+ export default function createTtscBanner(context: TtscPluginFactoryContext<ITtscBannerPluginConfig>): TtscPluginDescriptor;
100
+ export {};
@@ -0,0 +1,167 @@
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 = createTtscBanner;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ /**
11
+ * Keys that the ttsc plugin host injects into every plugin entry and are not
12
+ * owned by `@ttsc/banner`. The host validates registration; this factory
13
+ * rejects unknown banner options without rejecting those registration keys.
14
+ */
15
+ const FRAMEWORK_KEYS = new Set([
16
+ "enabled",
17
+ "name",
18
+ "stage",
19
+ "transform",
20
+ ]);
21
+ /**
22
+ * Plugin factory called by the ttsc host to obtain the `@ttsc/banner`
23
+ * descriptor.
24
+ *
25
+ * The only banner-specific key accepted in the tsconfig plugin entry is
26
+ * `configFile`. Any other key that is not a known framework key is rejected
27
+ * with a specific error so users discover the correct configuration surface
28
+ * (the dedicated config file) rather than silently receiving no banner.
29
+ *
30
+ * @evidence contracts/common.md#principled-implementation
31
+ * The default-export factory maps host module anchors to the shipped driver
32
+ * and project anchors to config candidates. Discovery records all seven
33
+ * candidate names in every directory from the anchor through the first one
34
+ * holding a non-directory match, including absent paths and directory markers,
35
+ * so creating a nearer config or a second file beside the match changes the
36
+ * descriptor inputs. Native evaluation validates ambiguous or invalid config;
37
+ * this factory supplies observations rather than treating existence as a
38
+ * valid banner. SHA-256 covers candidate bytes and a distinct directory marker.
39
+ *
40
+ * @evidence contracts/common.md#clear-and-simple-design
41
+ * Registration validation, discovery observations and descriptor construction
42
+ * have separate responsibilities. Private helpers isolate path discovery and
43
+ * filesystem observations; they do not implement another config evaluator.
44
+ * The driver path follows the installed package layout, while config anchors
45
+ * follow the project because those two directories have different owners.
46
+ *
47
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
48
+ * Framework keys, candidate filenames, package identity and stage encode the
49
+ * supported registration contract. The descriptor neither evaluates user
50
+ * JavaScript nor changes a foreign loader; it records a failed probe (an absent
51
+ * or unreadable candidate) as a null hash or physical target, and native
52
+ * evaluation reports the actual error.
53
+ *
54
+ * @evidence contracts/common.md#meaningful-documentation
55
+ * JSDoc separates registration from config evaluation and explains why
56
+ * unknown inline keys are rejected. Context and descriptor fields document
57
+ * host anchoring and observed inputs. Paragraphs and reasons follow the
58
+ * documentation skill; the exported factory is documented as a host entry.
59
+ */
60
+ function createTtscBanner(context) {
61
+ const entry = context.plugin;
62
+ for (const key of Object.keys(entry)) {
63
+ if (!FRAMEWORK_KEYS.has(key) && key !== "configFile") {
64
+ throw new Error(`@ttsc/banner: tsconfig plugin entry contains unsupported key ${JSON.stringify(key)}. ` +
65
+ `Banner options must be placed in a banner.config.{ts,cts,mts,js,cjs,mjs,json} file. ` +
66
+ `The only accepted key in the tsconfig entry is "configFile" (optional path to the config file).`);
67
+ }
68
+ }
69
+ const configInputs = bannerConfigInputs(context);
70
+ return {
71
+ capabilities: { emitProvenance: true },
72
+ hostInputHashes: configInputs.hashes,
73
+ hostInputRealpaths: configInputs.realpaths,
74
+ hostInputs: configInputs.inputs,
75
+ name: "@ttsc/banner",
76
+ // Point at the `driver/` directory one level above `lib/` in the
77
+ // installed package tree (where the Go sources live). `context.dirname`
78
+ // is this descriptor's own directory in every load mode, unlike the
79
+ // CommonJS `__dirname`, which is undefined under a `.ts`-source or ESM load.
80
+ source: node_path_1.default.resolve(context.dirname, "..", "driver"),
81
+ stage: "transform",
82
+ };
83
+ }
84
+ const BANNER_CONFIG_FILENAMES = [
85
+ "banner.config.json",
86
+ "banner.config.js",
87
+ "banner.config.cjs",
88
+ "banner.config.mjs",
89
+ "banner.config.ts",
90
+ "banner.config.cts",
91
+ "banner.config.mts",
92
+ ];
93
+ /**
94
+ * Mirror native config resolution for a nonblank string `configFile` or for
95
+ * upward discovery, retaining the absent candidates that could supersede or
96
+ * make ambiguous the match. Native evaluation rejects any other `configFile`.
97
+ */
98
+ function bannerConfigInputs(context) {
99
+ const configFile = context.plugin.configFile;
100
+ const base = node_path_1.default.resolve(context.pluginConfigDir ?? node_path_1.default.dirname(context.tsconfig));
101
+ if (typeof configFile === "string" && configFile.trim() !== "") {
102
+ const file = node_path_1.default.isAbsolute(configFile)
103
+ ? node_path_1.default.resolve(configFile)
104
+ : node_path_1.default.resolve(base, configFile);
105
+ return {
106
+ hashes: { [file]: hostInputHash(file) },
107
+ inputs: [file],
108
+ realpaths: { [file]: hostInputRealpath(file) },
109
+ };
110
+ }
111
+ return configDiscoveryInputs(base, BANNER_CONFIG_FILENAMES);
112
+ }
113
+ function configDiscoveryInputs(base, names) {
114
+ const inputs = [];
115
+ const hashes = {};
116
+ const realpaths = {};
117
+ for (let directory = base;; directory = node_path_1.default.dirname(directory)) {
118
+ const candidates = names.map((name) => node_path_1.default.join(directory, name));
119
+ inputs.push(...candidates);
120
+ for (const candidate of candidates) {
121
+ hashes[candidate] = hostInputHash(candidate);
122
+ realpaths[candidate] = hostInputRealpath(candidate);
123
+ }
124
+ if (candidates.some(configCandidateExists))
125
+ break;
126
+ const parent = node_path_1.default.dirname(directory);
127
+ if (parent === directory)
128
+ break;
129
+ }
130
+ return { hashes, inputs, realpaths };
131
+ }
132
+ function hostInputRealpath(file) {
133
+ try {
134
+ return node_fs_1.default.realpathSync.native(file);
135
+ }
136
+ catch {
137
+ return null;
138
+ }
139
+ }
140
+ /** Hash the exact candidate state observed before discovery selects a file. */
141
+ function hostInputHash(file) {
142
+ try {
143
+ if (node_fs_1.default.statSync(file).isDirectory()) {
144
+ return node_crypto_1.default
145
+ .createHash("sha256")
146
+ .update("ttsc:host-input:directory\0")
147
+ .digest("hex");
148
+ }
149
+ return node_crypto_1.default
150
+ .createHash("sha256")
151
+ .update(node_fs_1.default.readFileSync(file))
152
+ .digest("hex");
153
+ }
154
+ catch {
155
+ return null;
156
+ }
157
+ }
158
+ /** Match the native discovery rule: a directory is never a config file. */
159
+ function configCandidateExists(file) {
160
+ try {
161
+ return !node_fs_1.default.statSync(file).isDirectory();
162
+ }
163
+ catch {
164
+ return false;
165
+ }
166
+ }
167
+ //# sourceMappingURL=createTtscBanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTtscBanner.js","sourceRoot":"","sources":["../src/createTtscBanner.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from "./structures/index";
2
+ export { default } from "./createTtscBanner";
package/lib/index.js CHANGED
@@ -17,133 +17,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.default = createTtscBanner;
21
- const node_crypto_1 = __importDefault(require("node:crypto"));
22
- const node_fs_1 = __importDefault(require("node:fs"));
23
- const node_path_1 = __importDefault(require("node:path"));
20
+ exports.default = void 0;
24
21
  __exportStar(require("./structures/index"), exports);
25
- /**
26
- * Keys that the ttsc plugin host injects into every plugin entry and are not
27
- * owned by `@ttsc/banner`. These pass through the factory without validation so
28
- * the host can freely add new framework keys in the future.
29
- */
30
- const FRAMEWORK_KEYS = new Set([
31
- "enabled",
32
- "name",
33
- "stage",
34
- "transform",
35
- ]);
36
- /**
37
- * Plugin factory for `@ttsc/banner` — called by the ttsc host to obtain the
38
- * plugin descriptor.
39
- *
40
- * The only banner-specific key accepted in the tsconfig plugin entry is
41
- * `configFile`. Any other key that is not a known framework key is rejected
42
- * with a specific error so users discover the correct configuration surface
43
- * (the dedicated config file) rather than silently receiving no banner.
44
- *
45
- * @internal
46
- */
47
- function createTtscBanner(context) {
48
- const entry = context.plugin;
49
- for (const key of Object.keys(entry)) {
50
- if (!FRAMEWORK_KEYS.has(key) && key !== "configFile") {
51
- throw new Error(`@ttsc/banner: tsconfig plugin entry contains unsupported key ${JSON.stringify(key)}. ` +
52
- `Banner options must be placed in a banner.config.{ts,cts,mts,js,cjs,mjs,json} file. ` +
53
- `The only accepted key in the tsconfig entry is "configFile" (optional path to the config file).`);
54
- }
55
- }
56
- const configInputs = bannerConfigInputs(context);
57
- return {
58
- hostInputHashes: configInputs.hashes,
59
- hostInputRealpaths: configInputs.realpaths,
60
- hostInputs: configInputs.inputs,
61
- name: "@ttsc/banner",
62
- // Point at the `driver/` directory one level above `lib/` in the
63
- // installed package tree (where the Go sources live). `context.dirname`
64
- // is this descriptor's own directory in every load mode, unlike the
65
- // CommonJS `__dirname`, which is undefined under a `.ts`-source or ESM load.
66
- source: node_path_1.default.resolve(context.dirname, "..", "driver"),
67
- stage: "transform",
68
- };
69
- }
70
- const BANNER_CONFIG_FILENAMES = [
71
- "banner.config.json",
72
- "banner.config.js",
73
- "banner.config.cjs",
74
- "banner.config.mjs",
75
- "banner.config.ts",
76
- "banner.config.cts",
77
- "banner.config.mts",
78
- ];
79
- /** Mirror native config resolution while retaining missing priority probes. */
80
- function bannerConfigInputs(context) {
81
- const configFile = context.plugin.configFile;
82
- const base = node_path_1.default.resolve(context.pluginConfigDir ?? node_path_1.default.dirname(context.tsconfig));
83
- if (typeof configFile === "string" && configFile.trim() !== "") {
84
- const file = node_path_1.default.isAbsolute(configFile)
85
- ? node_path_1.default.resolve(configFile)
86
- : node_path_1.default.resolve(base, configFile);
87
- return {
88
- hashes: { [file]: hostInputHash(file) },
89
- inputs: [file],
90
- realpaths: { [file]: hostInputRealpath(file) },
91
- };
92
- }
93
- return configDiscoveryInputs(base, BANNER_CONFIG_FILENAMES);
94
- }
95
- function configDiscoveryInputs(base, names) {
96
- const inputs = [];
97
- const hashes = {};
98
- const realpaths = {};
99
- for (let directory = base;; directory = node_path_1.default.dirname(directory)) {
100
- const candidates = names.map((name) => node_path_1.default.join(directory, name));
101
- inputs.push(...candidates);
102
- for (const candidate of candidates) {
103
- hashes[candidate] = hostInputHash(candidate);
104
- realpaths[candidate] = hostInputRealpath(candidate);
105
- }
106
- if (candidates.some(configCandidateExists))
107
- break;
108
- const parent = node_path_1.default.dirname(directory);
109
- if (parent === directory)
110
- break;
111
- }
112
- return { hashes, inputs, realpaths };
113
- }
114
- function hostInputRealpath(file) {
115
- try {
116
- return node_fs_1.default.realpathSync.native(file);
117
- }
118
- catch {
119
- return null;
120
- }
121
- }
122
- /** Hash the exact candidate state observed before discovery selects a file. */
123
- function hostInputHash(file) {
124
- try {
125
- if (node_fs_1.default.statSync(file).isDirectory()) {
126
- return node_crypto_1.default
127
- .createHash("sha256")
128
- .update("ttsc:host-input:directory\0")
129
- .digest("hex");
130
- }
131
- return node_crypto_1.default
132
- .createHash("sha256")
133
- .update(node_fs_1.default.readFileSync(file))
134
- .digest("hex");
135
- }
136
- catch {
137
- return null;
138
- }
139
- }
140
- /** Match the native discovery rule: a directory is never a config file. */
141
- function configCandidateExists(file) {
142
- try {
143
- return !node_fs_1.default.statSync(file).isDirectory();
144
- }
145
- catch {
146
- return false;
147
- }
148
- }
22
+ var createTtscBanner_1 = require("./createTtscBanner");
23
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(createTtscBanner_1).default; } });
149
24
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,qDAAmC;AAEnC,uDAA6C;AAApC,4HAAA,OAAO,OAAA"}
@@ -1,5 +1,43 @@
1
- /** Standalone `banner.config.*` file shape consumed by `@ttsc/banner`. */
1
+ /**
2
+ * Object exported by a standalone `banner.config.*` file.
3
+ *
4
+ * The native loader requires a nonblank text string. Keeping banner contents in
5
+ * this object gives JSON, JavaScript and TypeScript configuration the same
6
+ * value contract; the tsconfig plugin entry selects the file instead.
7
+ *
8
+ * @evidence contracts/common.md#principled-implementation
9
+ * A required string member expresses the loader's object payload. TypeScript
10
+ * cannot express nonblank contents through this string type, so the native
11
+ * loader validates that condition before formatting. The formatter preserves
12
+ * content lines while normalizing CRLF and escaping closing delimiters; it
13
+ * changes comment representation without treating text as executable source.
14
+ *
15
+ * @evidence contracts/common.md#clear-and-simple-design
16
+ * Banner content has one field in a dedicated config value. Registration and
17
+ * config discovery stay in ITtscBannerPluginConfig because they select the
18
+ * content's source rather than change its representation.
19
+ *
20
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
21
+ * The text is consumer content, not a fixture-selected banner or a hardcoded
22
+ * expected output. Required separators and the annotation are formatting
23
+ * constants in the driver rather than hidden options in this value.
24
+ *
25
+ * @evidence contracts/common.md#meaningful-documentation
26
+ * Interface and field JSDoc explain standalone config ownership, required
27
+ * nonblank text, CRLF and trailing-line handling, terminator escaping and
28
+ * removeComments behavior. Purpose, validation and formatting rationale are
29
+ * separated into native paragraphs under the documentation skill; the type
30
+ * acknowledgment covers its field without duplicating a checklist on that
31
+ * property.
32
+ */
2
33
  export interface ITtscBannerConfig {
3
- /** Text inserted into the generated `@packageDocumentation` block. */
34
+ /**
35
+ * Text placed before the generated `@packageDocumentation` annotation.
36
+ *
37
+ * Empty or whitespace-only values are rejected. The formatter preserves the
38
+ * supplied lines, removes trailing blank lines, normalizes CRLF and escapes
39
+ * comment terminators so the value cannot close the generated JSDoc block.
40
+ * The resulting comment follows the compiler's `removeComments` policy.
41
+ */
4
42
  text: string;
5
43
  }
@@ -1,14 +1,64 @@
1
- /** `compilerOptions.plugins[]` entry shape consumed by `@ttsc/banner`. */
1
+ /**
2
+ * Host registration and config-file selection for `@ttsc/banner`.
3
+ *
4
+ * This entry belongs in `compilerOptions.plugins[]`. Banner text belongs in the
5
+ * separate `ITtscBannerConfig` value so discovery and config evaluation have
6
+ * one supported home instead of an additional inline option surface.
7
+ *
8
+ * @evidence contracts/common.md#principled-implementation
9
+ * Optional enabled distinguishes omission from an explicit false host switch;
10
+ * transform carries the module specifier and configFile carries a separate
11
+ * filesystem path. Those values belong to different resolution contracts, so
12
+ * a binary path or inline text is not represented as banner configuration.
13
+ * String typing does not establish path existence or nonblankness; the loader
14
+ * validates an explicitly supplied configFile before evaluation.
15
+ *
16
+ * @evidence contracts/common.md#clear-and-simple-design
17
+ * The type separates two host registration fields from one banner-owned file
18
+ * selector. Text belongs to the loaded ITtscBannerConfig object, leaving one
19
+ * evaluation path instead of parallel inline and file configuration policies.
20
+ *
21
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts
22
+ * Host switches and configFile represent the supported registration
23
+ * contract. Banner text has one typed config-file home, preventing a second
24
+ * inline option shape from bypassing that loader's validation.
25
+ *
26
+ * @evidence contracts/common.md#meaningful-documentation
27
+ * Interface and member JSDoc distinguish host registration from banner
28
+ * text, disabled and omitted enabled states, module specifiers from config
29
+ * or binary paths, and configFile anchoring, discovery, validation and
30
+ * failure behavior. Separate paragraphs explain why generated wrapper
31
+ * directories cannot become the discovery base, applying the documentation
32
+ * skill's clear prose and rationale guidance to the complete type contract.
33
+ */
2
34
  export interface ITtscBannerPluginConfig {
3
- /** Set to `false` to keep the entry while disabling this plugin. */
35
+ /**
36
+ * Set to `false` to retain the entry without running the plugin.
37
+ *
38
+ * Omission leaves the entry enabled. The ttsc host owns this switch; it is
39
+ * not a banner option passed through the standalone config file.
40
+ */
4
41
  enabled?: boolean;
5
- /** Plugin module specifier. */
42
+ /**
43
+ * Module specifier the host resolves to the plugin factory.
44
+ *
45
+ * Use `@ttsc/banner` to register this package through the transform key. This
46
+ * names the factory module, not the banner config file or Go binary.
47
+ */
6
48
  transform?: string;
7
49
  /**
8
- * Path to a `banner.config.*` file, resolved from the directory that contains
9
- * the tsconfig. When omitted, `@ttsc/banner` walks up from that directory and
10
- * uses the first `banner.config.{ts,cts,mts,js,cjs,mjs,json}` file it finds.
11
- * Any other key in this entry is rejected with an error.
50
+ * Explicit banner config path, absolute or relative to the host's plugin
51
+ * config directory. Without that explicit anchor, resolution uses the
52
+ * tsconfig directory, or the invocation directory when no tsconfig is set.
53
+ *
54
+ * Omission searches upward from the same anchor for `banner.config.*`.
55
+ * Missing or ambiguous discovery is an error. An explicit value must be a
56
+ * nonblank string naming a supported config file. Banner-specific inline
57
+ * options such as text are rejected; host-owned registration keys remain
58
+ * permitted.
59
+ *
60
+ * The host anchor matters when the tsconfig is a generated wrapper: its
61
+ * temporary directory must not become the user's config-resolution base.
12
62
  */
13
63
  configFile?: string;
14
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttsc/banner",
3
- "version": "0.30.3",
3
+ "version": "0.31.0",
4
4
  "description": "First-party ttsc plugin that adds package-documentation JSDoc banners during emit.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -32,10 +32,11 @@
32
32
  "plugin/main.go"
33
33
  ],
34
34
  "devDependencies": {
35
+ "@wrtnlabs/evidence": "^0.3.1",
35
36
  "@types/node": "^25.3.0",
36
37
  "rimraf": "^6.1.2",
37
38
  "typescript": "^7.0.2",
38
- "ttsc": "0.30.3"
39
+ "ttsc": "0.31.0"
39
40
  },
40
41
  "repository": {
41
42
  "type": "git",
@@ -48,6 +49,7 @@
48
49
  },
49
50
  "homepage": "https://ttsc.dev",
50
51
  "scripts": {
51
- "build": "rimraf lib && tsc"
52
+ "build": "rimraf lib && tsc",
53
+ "evidence": "evidence"
52
54
  }
53
55
  }
package/plugin/main.go CHANGED
@@ -2,7 +2,6 @@
2
2
  package main
3
3
 
4
4
  import (
5
- "fmt"
6
5
  "os"
7
6
 
8
7
  "github.com/samchon/ttsc/packages/ttsc/utility"
@@ -10,27 +9,28 @@ import (
10
9
 
11
10
  const version = "0.0.1"
12
11
 
12
+ // main exits the standalone process with its command dispatch status.
13
+ //
14
+ // These review grounds cover this private operation and its actual callees.
15
+ // Go Evidence does not admit private declaration acknowledgment tags.
16
+ //
17
+ // Common: Principled implementation: os.Args excludes the executable name and os.Exit propagates the actual run status to the process consumer.
18
+ // Common: Clear and simple design: The entrypoint binds process lifetime while run owns identity and stream delegation.
19
+ // Common: Prohibited implementation shortcuts: The process uses the real command return status without rewriting failures or bypassing package registration.
20
+ // Common: Meaningful documentation: The native comment names process status propagation separately from these native review grounds.
21
+ // Portability: OS-neutral implementation: Go's os package supplies native argv and process exit semantics without host-specific command quoting.
13
22
  func main() {
14
23
  os.Exit(run(os.Args[1:]))
15
24
  }
16
25
 
26
+ // run supplies this standalone plugin's identity and process streams to the
27
+ // shared production utility dispatch; linked registration remains in init.
28
+ //
29
+ // Common: Principled implementation: The package identity and unchanged version constant reach the shared actual command owner with original argv and process writers.
30
+ // Common: Clear and simple design: One delegation leaves command semantics with utility.RunCommandWithIO and package registration with the sibling init import.
31
+ // Common: Prohibited implementation shortcuts: Production execution uses the same dispatch as direct units and retains the real host for build, transform and check.
32
+ // Common: Meaningful documentation: Native prose identifies identity, process stream binding and unchanged linked registration separately from these native review grounds.
33
+ // Portability: OS-neutral implementation: os supplies the native process streams and argv values without a shell or path reconstruction.
17
34
  func run(args []string) int {
18
- if len(args) == 0 {
19
- fmt.Fprintln(os.Stderr, "@ttsc/banner: command required (expected build|transform|check|version)")
20
- return 2
21
- }
22
- switch args[0] {
23
- case "-v", "--version", "version":
24
- fmt.Fprintf(os.Stdout, "@ttsc/banner %s\n", version)
25
- return 0
26
- case "build":
27
- return utility.RunBuild(args[1:])
28
- case "transform":
29
- return utility.RunTransform(args[1:])
30
- case "check":
31
- return utility.RunCheck(args[1:])
32
- default:
33
- fmt.Fprintf(os.Stderr, "@ttsc/banner: unknown command %q\n", args[0])
34
- return 2
35
- }
35
+ return utility.RunCommandWithIO("@ttsc/banner", version, args, os.Stdout, os.Stderr)
36
36
  }