@ttsc/banner 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@ttsc/banner`
2
2
 
3
- ![banner of @ttsc/banner](https://raw.githubusercontent.com/samchon/ttsc/refs/heads/master/assets/og.jpg)
3
+ ![banner of @ttsc/banner](https://ttsc.dev/og.jpg)
4
4
 
5
5
  [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/samchon/ttsc/blob/master/LICENSE)
6
6
  [![NPM Version](https://img.shields.io/npm/v/@ttsc/banner.svg)](https://www.npmjs.com/package/@ttsc/banner)
@@ -20,7 +20,20 @@ npm install -D ttsc @typescript/native-preview
20
20
  npm install -D @ttsc/banner
21
21
  ```
22
22
 
23
- Add `banner.config.ts` next to your project config:
23
+ Pass the banner text inline on the `compilerOptions.plugins[]` entry:
24
+
25
+ ```jsonc
26
+ // tsconfig.json
27
+ {
28
+ "compilerOptions": {
29
+ "plugins": [
30
+ { "transform": "@ttsc/banner", "text": "License MIT (c) 2026 Acme" }
31
+ ]
32
+ }
33
+ }
34
+ ```
35
+
36
+ Or keep the text in a separate file `banner.config.ts` next to your tsconfig:
24
37
 
25
38
  ```ts
26
39
  // banner.config.ts
@@ -37,45 +50,19 @@ Run your normal `ttsc` command:
37
50
  npx ttsc
38
51
  ```
39
52
 
40
- If `@ttsc/banner` is installed and no banner config file can be found, the compile fails.
53
+ If `@ttsc/banner` is installed and none of the three text sources (inline `text:`, `config:` path, or an auto-discovered `banner.config.*`) yields a banner, the compile fails.
41
54
 
42
55
  ## Configuration
43
56
 
44
- Use `banner.config.ts` for ordinary projects.
57
+ `@ttsc/banner` resolves its text in this order:
45
58
 
46
- Use `compilerOptions.plugins` only when the project needs a different config file path or inline text:
59
+ 1. the entry's inline `text` string;
60
+ 2. the entry's `config: "./path/to/banner.config.ts"` path;
61
+ 3. an upward walk for any `banner.config.{js,cjs,mjs,ts,mts,cts}` starting from the tsconfig directory.
47
62
 
48
- ```jsonc
49
- {
50
- "compilerOptions": {
51
- "plugins": [
52
- {
53
- "transform": "@ttsc/banner",
54
- "config": "./config/banner.config.ts",
55
- },
56
- ],
57
- },
58
- }
59
- ```
60
-
61
- The explicit `config` path resolves from the selected `tsconfig.json` directory.
62
-
63
- Existing inline text config remains supported:
64
-
65
- ```jsonc
66
- {
67
- "compilerOptions": {
68
- "plugins": [
69
- {
70
- "transform": "@ttsc/banner",
71
- "text": "License MIT (c) 2026 Acme",
72
- },
73
- ],
74
- },
75
- }
76
- ```
63
+ The plugin formats every line of the resolved text inside a JSDoc block and appends `@packageDocumentation`.
77
64
 
78
- The plugin formats every banner line inside a JSDoc block and adds `@packageDocumentation`. The banner follows TypeScript's normal comment emit policy, so `removeComments: true` removes it.
65
+ The banner follows TypeScript's normal comment emit policy, so `removeComments: true` removes it.
79
66
 
80
67
  ## Sponsors
81
68
 
@@ -0,0 +1,479 @@
1
+ package banner
2
+
3
+ import (
4
+ "encoding/json"
5
+ "fmt"
6
+ "os"
7
+ "os/exec"
8
+ "path/filepath"
9
+ "strings"
10
+
11
+ "github.com/samchon/ttsc/packages/ttsc/driver"
12
+ )
13
+
14
+ func init() {
15
+ driver.RegisterPlugin(plugin{})
16
+ }
17
+
18
+ type plugin struct{}
19
+
20
+ var (
21
+ linkConfigNodeModules = linkNearestNodeModules
22
+ writeConfigLoaderFile = os.WriteFile
23
+ )
24
+
25
+ func (plugin) SourcePreamble(ctx driver.PluginContext) (string, error) {
26
+ return parseBanner(ctx.Entry.Config, ctx.Cwd, ctx.Tsconfig)
27
+ }
28
+
29
+ func parseBanner(config map[string]any, cwd, tsconfigPath string) (string, error) {
30
+ text, err := resolveBannerText(config, cwd, tsconfigPath)
31
+ if err != nil {
32
+ return "", err
33
+ }
34
+ lines := strings.Split(strings.ReplaceAll(text, "\r\n", "\n"), "\n")
35
+ for len(lines) > 0 && strings.TrimSpace(lines[len(lines)-1]) == "" {
36
+ lines = lines[:len(lines)-1]
37
+ }
38
+ var b strings.Builder
39
+ sep := strings.Repeat("-", 64)
40
+ b.WriteString("/**\n")
41
+ b.WriteString(" * ")
42
+ b.WriteString(sep)
43
+ b.WriteByte('\n')
44
+ for _, line := range lines {
45
+ b.WriteString(" * ")
46
+ b.WriteString(sanitizeJSDocLine(line))
47
+ b.WriteByte('\n')
48
+ }
49
+ b.WriteString(" *\n")
50
+ b.WriteString(" * @packageDocumentation\n ")
51
+ b.WriteString("*/\n")
52
+ return b.String(), nil
53
+ }
54
+
55
+ func resolveBannerText(config map[string]any, cwd, tsconfigPath string) (string, error) {
56
+ if text, ok, err := bannerTextFromConfigValue(config["text"], `"text"`); ok || err != nil {
57
+ return text, err
58
+ }
59
+ if rawConfigPath, ok := config["config"]; ok {
60
+ configPath, ok := rawConfigPath.(string)
61
+ if !ok || strings.TrimSpace(configPath) == "" {
62
+ return "", fmt.Errorf("@ttsc/banner: \"config\" must be a non-empty string path")
63
+ }
64
+ location := resolveBannerConfigPath(configPath, cwd, tsconfigPath)
65
+ raw, err := loadBannerConfigFile(location)
66
+ if err != nil {
67
+ return "", err
68
+ }
69
+ text, ok, err := bannerTextFromConfigValue(raw, filepath.Base(location))
70
+ if err != nil {
71
+ return "", err
72
+ }
73
+ if !ok {
74
+ return "", fmt.Errorf("@ttsc/banner: %s must export a non-empty string or an object with a non-empty \"text\" string", location)
75
+ }
76
+ return text, nil
77
+ }
78
+ location, err := findBannerConfigFile(cwd, tsconfigPath)
79
+ if err != nil {
80
+ return "", err
81
+ }
82
+ if location == "" {
83
+ return "", fmt.Errorf("@ttsc/banner: \"text\" must be a non-empty string or a banner.config.{js,cjs,mjs,ts,mts,cts} file must exist")
84
+ }
85
+ raw, err := loadBannerConfigFile(location)
86
+ if err != nil {
87
+ return "", err
88
+ }
89
+ text, ok, err := bannerTextFromConfigValue(raw, filepath.Base(location))
90
+ if err != nil {
91
+ return "", err
92
+ }
93
+ if !ok {
94
+ return "", fmt.Errorf("@ttsc/banner: %s must export a non-empty string or an object with a non-empty \"text\" string", location)
95
+ }
96
+ return text, nil
97
+ }
98
+
99
+ func bannerTextFromConfigValue(raw any, label string) (string, bool, error) {
100
+ if raw == nil {
101
+ return "", false, nil
102
+ }
103
+ text, ok := raw.(string)
104
+ if ok {
105
+ if strings.TrimSpace(text) == "" {
106
+ return "", true, fmt.Errorf("@ttsc/banner: %s must be a non-empty string", label)
107
+ }
108
+ return text, true, nil
109
+ }
110
+ object, ok := raw.(map[string]any)
111
+ if !ok {
112
+ return "", true, fmt.Errorf("@ttsc/banner: %s must be a string or an object with a non-empty \"text\" string", label)
113
+ }
114
+ rawText, ok := object["text"]
115
+ if !ok {
116
+ return "", false, nil
117
+ }
118
+ text, ok = rawText.(string)
119
+ if !ok || strings.TrimSpace(text) == "" {
120
+ return "", true, fmt.Errorf("@ttsc/banner: %s.text must be a non-empty string", label)
121
+ }
122
+ return text, true, nil
123
+ }
124
+
125
+ func findBannerConfigFile(cwd, tsconfigPath string) (string, error) {
126
+ dir := discoveryConfigBaseDir(cwd, tsconfigPath)
127
+ for {
128
+ matches := make([]string, 0, 1)
129
+ for _, name := range []string{
130
+ "banner.config.js",
131
+ "banner.config.cjs",
132
+ "banner.config.mjs",
133
+ "banner.config.ts",
134
+ "banner.config.cts",
135
+ "banner.config.mts",
136
+ } {
137
+ candidate := filepath.Join(dir, name)
138
+ if stat, err := os.Stat(candidate); err == nil && !stat.IsDir() {
139
+ matches = append(matches, candidate)
140
+ }
141
+ }
142
+ if len(matches) > 1 {
143
+ return "", fmt.Errorf("@ttsc/banner: multiple banner.config.* files found in %s", dir)
144
+ }
145
+ if len(matches) == 1 {
146
+ return matches[0], nil
147
+ }
148
+ parent := filepath.Dir(dir)
149
+ if parent == dir {
150
+ return "", nil
151
+ }
152
+ dir = parent
153
+ }
154
+ }
155
+
156
+ func resolveBannerConfigPath(configPath, cwd, tsconfigPath string) string {
157
+ if filepath.IsAbs(configPath) {
158
+ return configPath
159
+ }
160
+ return filepath.Join(tsconfigBaseDir(cwd, tsconfigPath), configPath)
161
+ }
162
+
163
+ func tsconfigBaseDir(cwd, tsconfigPath string) string {
164
+ if tsconfigPath == "" {
165
+ return cwd
166
+ }
167
+ resolvedTsconfig := tsconfigPath
168
+ if !filepath.IsAbs(resolvedTsconfig) {
169
+ resolvedTsconfig = filepath.Join(cwd, resolvedTsconfig)
170
+ }
171
+ return filepath.Dir(resolvedTsconfig)
172
+ }
173
+
174
+ func discoveryConfigBaseDir(cwd, tsconfigPath string) string {
175
+ if tsconfigPath != "" {
176
+ resolvedTsconfig := tsconfigPath
177
+ if !filepath.IsAbs(resolvedTsconfig) {
178
+ resolvedTsconfig = filepath.Join(cwd, resolvedTsconfig)
179
+ }
180
+ return filepath.Dir(resolvedTsconfig)
181
+ }
182
+ return cwd
183
+ }
184
+
185
+ func loadBannerConfigFile(location string) (any, error) {
186
+ if !isBannerConfigFileName(filepath.Base(location)) {
187
+ return nil, fmt.Errorf("@ttsc/banner: config file must be named banner.config.{js,cjs,mjs,ts,mts,cts}: %s", location)
188
+ }
189
+ ext := strings.ToLower(filepath.Ext(location))
190
+ switch ext {
191
+ case ".js", ".cjs", ".mjs":
192
+ return loadBannerScriptConfigFile(location)
193
+ }
194
+ return loadBannerTypeScriptConfigFile(location)
195
+ }
196
+
197
+ func isBannerConfigFileName(name string) bool {
198
+ switch name {
199
+ case "banner.config.js",
200
+ "banner.config.cjs",
201
+ "banner.config.mjs",
202
+ "banner.config.ts",
203
+ "banner.config.cts",
204
+ "banner.config.mts":
205
+ return true
206
+ default:
207
+ return false
208
+ }
209
+ }
210
+
211
+ func loadBannerScriptConfigFile(location string) (any, error) {
212
+ const script = `
213
+ const { pathToFileURL } = require("node:url");
214
+
215
+ (async () => {
216
+ const mod = await import(pathToFileURL(process.argv[1]).href);
217
+ const candidate = Object.prototype.hasOwnProperty.call(mod, "default") ? mod.default : mod;
218
+ const value = typeof candidate === "function" ? await candidate() : candidate;
219
+ process.stdout.write(JSON.stringify(toSerializableBanner(value)));
220
+ })().catch((error) => {
221
+ process.stderr.write(error && error.stack ? error.stack : String(error));
222
+ process.exit(1);
223
+ });
224
+
225
+ function toSerializableBanner(value) {
226
+ if (typeof value === "string") {
227
+ return value;
228
+ }
229
+ if (value !== null && typeof value === "object" && typeof value.text === "string") {
230
+ return { text: value.text };
231
+ }
232
+ throw new Error("config file must export a string or an object with a text string");
233
+ }
234
+ `
235
+ node := os.Getenv("TTSC_NODE_BINARY")
236
+ if node == "" {
237
+ node = "node"
238
+ }
239
+ cmd := exec.Command(node, "-e", script, location)
240
+ cmd.Env = nodeConfigLoaderEnv(location)
241
+ output, err := cmd.Output()
242
+ if err != nil {
243
+ stderr := ""
244
+ if exit, ok := err.(*exec.ExitError); ok {
245
+ stderr = strings.TrimSpace(string(exit.Stderr))
246
+ }
247
+ if stderr != "" {
248
+ return nil, fmt.Errorf("@ttsc/banner: load config file %s: %s", location, stderr)
249
+ }
250
+ return nil, fmt.Errorf("@ttsc/banner: load config file %s: %w", location, err)
251
+ }
252
+ var out any
253
+ if err := json.Unmarshal(output, &out); err != nil {
254
+ return nil, fmt.Errorf("@ttsc/banner: parse config file %s output: %w", location, err)
255
+ }
256
+ return out, nil
257
+ }
258
+
259
+ func loadBannerTypeScriptConfigFile(location string) (any, error) {
260
+ tempDir, err := os.MkdirTemp("", "ttsc-banner-config-")
261
+ if err != nil {
262
+ return nil, fmt.Errorf("@ttsc/banner: create config loader tempdir: %w", err)
263
+ }
264
+ defer os.RemoveAll(tempDir)
265
+
266
+ if err := linkConfigNodeModules(tempDir, filepath.Dir(location)); err != nil {
267
+ return nil, err
268
+ }
269
+
270
+ loader := filepath.Join(tempDir, "loader.mts")
271
+ tsconfig := filepath.Join(tempDir, "tsconfig.json")
272
+ importSpecifier, err := relativeImportSpecifier(tempDir, location)
273
+ if err != nil {
274
+ return nil, err
275
+ }
276
+ importLiteral, _ := json.Marshal(importSpecifier)
277
+ if err := writeConfigLoaderFile(loader, []byte(bannerTypeScriptConfigLoaderSource(string(importLiteral))), 0o644); err != nil {
278
+ return nil, fmt.Errorf("@ttsc/banner: write config loader: %w", err)
279
+ }
280
+ if err := writeConfigLoaderFile(tsconfig, []byte(typeScriptConfigLoaderTsconfig(loader, location, tempDir)), 0o644); err != nil {
281
+ return nil, fmt.Errorf("@ttsc/banner: write config loader tsconfig: %w", err)
282
+ }
283
+
284
+ args := []string{
285
+ "--project", tsconfig,
286
+ "--cwd", tempDir,
287
+ "--cache-dir", filepath.Join(tempDir, "cache"),
288
+ }
289
+ if tsgo := os.Getenv("TTSC_TSGO_BINARY"); tsgo != "" {
290
+ args = append(args, "--binary", tsgo)
291
+ }
292
+ args = append(args, loader)
293
+
294
+ cmd := ttsxCommand(args...)
295
+ cmd.Env = nodeConfigLoaderEnv(location)
296
+ output, err := cmd.Output()
297
+ if err != nil {
298
+ stderr := ""
299
+ if exit, ok := err.(*exec.ExitError); ok {
300
+ stderr = strings.TrimSpace(string(exit.Stderr))
301
+ }
302
+ if stderr != "" {
303
+ return nil, fmt.Errorf("@ttsc/banner: load TypeScript config file %s: %s", location, stderr)
304
+ }
305
+ return nil, fmt.Errorf("@ttsc/banner: load TypeScript config file %s: %w", location, err)
306
+ }
307
+ var out any
308
+ if err := json.Unmarshal(output, &out); err != nil {
309
+ return nil, fmt.Errorf("@ttsc/banner: parse TypeScript config file %s output: %w", location, err)
310
+ }
311
+ return out, nil
312
+ }
313
+
314
+ func relativeImportSpecifier(fromDir, location string) (string, error) {
315
+ relative, err := filepath.Rel(fromDir, location)
316
+ if err != nil {
317
+ return "", fmt.Errorf("@ttsc/banner: resolve relative config import %s: %w", location, err)
318
+ }
319
+ relative = filepath.ToSlash(relative)
320
+ if strings.HasPrefix(relative, "../") || strings.HasPrefix(relative, "./") {
321
+ return relative, nil
322
+ }
323
+ return "./" + relative, nil
324
+ }
325
+
326
+ func bannerTypeScriptConfigLoaderSource(importLiteral string) string {
327
+ return fmt.Sprintf(`import * as importedConfig from %s;
328
+
329
+ declare const process: {
330
+ stdout: { write(value: string): void };
331
+ stderr: { write(value: string): void };
332
+ exit(code?: number): never;
333
+ };
334
+
335
+ try {
336
+ const value = await resolveConfig(importedConfig);
337
+ process.stdout.write(JSON.stringify(toSerializableBanner(value)));
338
+ } catch (error) {
339
+ process.stderr.write(error instanceof Error && error.stack ? error.stack : String(error));
340
+ process.exit(1);
341
+ }
342
+
343
+ async function resolveConfig(value: unknown): Promise<unknown> {
344
+ let current = value;
345
+ for (let i = 0; i < 8; i++) {
346
+ if (isObject(current) && hasOwn(current, "default")) {
347
+ current = current.default;
348
+ continue;
349
+ }
350
+ break;
351
+ }
352
+ if (typeof current === "function") {
353
+ return await (current as () => unknown | Promise<unknown>)();
354
+ }
355
+ return current;
356
+ }
357
+
358
+ function isObject(value: unknown): value is Record<string, unknown> {
359
+ return value !== null && typeof value === "object";
360
+ }
361
+
362
+ function hasOwn(value: Record<string, unknown>, key: string): boolean {
363
+ return Object.prototype.hasOwnProperty.call(value, key);
364
+ }
365
+
366
+ function toSerializableBanner(value: unknown): unknown {
367
+ if (typeof value === "string") {
368
+ return value;
369
+ }
370
+ if (isObject(value) && typeof value.text === "string") {
371
+ return { text: value.text };
372
+ }
373
+ throw new Error("config file must export a string or an object with a text string");
374
+ }
375
+ `, importLiteral)
376
+ }
377
+
378
+ func typeScriptConfigLoaderTsconfig(loader, location, outDir string) string {
379
+ content := map[string]any{
380
+ "compilerOptions": map[string]any{
381
+ "allowImportingTsExtensions": true,
382
+ "module": "ESNext",
383
+ "moduleResolution": "bundler",
384
+ "outDir": filepath.ToSlash(filepath.Join(outDir, "out")),
385
+ "rewriteRelativeImportExtensions": true,
386
+ "rootDir": "/",
387
+ "skipLibCheck": true,
388
+ "strict": true,
389
+ "target": "ES2022",
390
+ },
391
+ "files": []string{
392
+ filepath.ToSlash(loader),
393
+ filepath.ToSlash(location),
394
+ },
395
+ }
396
+ body, _ := json.MarshalIndent(content, "", " ")
397
+ return string(body)
398
+ }
399
+
400
+ func ttsxCommand(args ...string) *exec.Cmd {
401
+ ttsx := os.Getenv("TTSC_TTSX_BINARY")
402
+ if ttsx == "" {
403
+ ttsx = "ttsx"
404
+ }
405
+ if shouldRunTtsxThroughNode(ttsx) {
406
+ node := os.Getenv("TTSC_NODE_BINARY")
407
+ if node == "" {
408
+ node = "node"
409
+ }
410
+ return exec.Command(node, append([]string{ttsx}, args...)...)
411
+ }
412
+ return exec.Command(ttsx, args...)
413
+ }
414
+
415
+ func shouldRunTtsxThroughNode(binary string) bool {
416
+ switch strings.ToLower(filepath.Ext(binary)) {
417
+ case ".js", ".cjs", ".mjs", ".ts", ".cts", ".mts":
418
+ return true
419
+ default:
420
+ return false
421
+ }
422
+ }
423
+
424
+ func nodeConfigLoaderEnv(location string) []string {
425
+ env := os.Environ()
426
+ parts := make([]string, 0, 2)
427
+ if nodeModules := findNearestNodeModules(filepath.Dir(location)); nodeModules != "" {
428
+ parts = append(parts, nodeModules)
429
+ }
430
+ if existing := os.Getenv("NODE_PATH"); existing != "" {
431
+ parts = append(parts, existing)
432
+ }
433
+ if len(parts) == 0 {
434
+ return env
435
+ }
436
+ return setEnv(env, "NODE_PATH", strings.Join(parts, string(os.PathListSeparator)))
437
+ }
438
+
439
+ func linkNearestNodeModules(tempDir, sourceDir string) error {
440
+ nodeModules := findNearestNodeModules(sourceDir)
441
+ if nodeModules == "" {
442
+ return nil
443
+ }
444
+ link := filepath.Join(tempDir, "node_modules")
445
+ if err := os.Symlink(nodeModules, link); err != nil {
446
+ return fmt.Errorf("@ttsc/banner: link config node_modules %s: %w", nodeModules, err)
447
+ }
448
+ return nil
449
+ }
450
+
451
+ func findNearestNodeModules(start string) string {
452
+ dir := filepath.Clean(start)
453
+ for {
454
+ candidate := filepath.Join(dir, "node_modules")
455
+ if stat, err := os.Stat(candidate); err == nil && stat.IsDir() {
456
+ return candidate
457
+ }
458
+ parent := filepath.Dir(dir)
459
+ if parent == dir {
460
+ return ""
461
+ }
462
+ dir = parent
463
+ }
464
+ }
465
+
466
+ func setEnv(env []string, key, value string) []string {
467
+ prefix := key + "="
468
+ for i, entry := range env {
469
+ if strings.HasPrefix(entry, prefix) {
470
+ env[i] = prefix + value
471
+ return env
472
+ }
473
+ }
474
+ return append(env, prefix+value)
475
+ }
476
+
477
+ func sanitizeJSDocLine(line string) string {
478
+ return strings.ReplaceAll(line, "*/", "* /")
479
+ }
package/lib/index.d.ts CHANGED
@@ -1,15 +1 @@
1
- import type { ITtscBannerPluginConfig } from "./structures";
2
1
  export * from "./structures/index";
3
- type TtscPluginDescriptor = {
4
- name: string;
5
- source: string;
6
- stage?: "check" | "transform";
7
- };
8
- type TtscPluginFactoryContext<TConfig> = {
9
- binary: string;
10
- cwd: string;
11
- plugin: TConfig;
12
- projectRoot: string;
13
- tsconfig: string;
14
- };
15
- export default function createTtscBanner(_context: TtscPluginFactoryContext<ITtscBannerPluginConfig>): TtscPluginDescriptor;
package/lib/index.js CHANGED
@@ -20,10 +20,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
20
20
  exports.default = createTtscBanner;
21
21
  const node_path_1 = __importDefault(require("node:path"));
22
22
  __exportStar(require("./structures/index"), exports);
23
+ /**
24
+ * @internal
25
+ */
23
26
  function createTtscBanner(_context) {
24
27
  return {
25
28
  name: "@ttsc/banner",
26
- source: node_path_1.default.resolve(__dirname, "..", "plugin"),
29
+ source: node_path_1.default.resolve(__dirname, "..", "driver"),
27
30
  stage: "transform",
28
31
  };
29
32
  }
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,0DAA6B;AAI7B,qDAAmC;AAgBnC,0BACE,QAA2D;IAE3D,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,mBAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC;QAC/C,KAAK,EAAE,WAAW;KACnB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,0DAA6B;AAI7B,qDAAmC;AAgBnC;;GAEG;AACH,0BACE,QAA2D;IAE3D,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,mBAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC;QAC/C,KAAK,EAAE,WAAW;KACnB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttsc/banner",
3
- "version": "0.11.0",
3
+ "version": "0.12.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",
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "files": [
26
26
  "README.md",
27
+ "driver/banner.go",
27
28
  "lib",
28
29
  "src",
29
30
  "go.mod",
@@ -34,7 +35,7 @@
34
35
  "@types/node": "^25.3.0",
35
36
  "@typescript/native-preview": "7.0.0-dev.20260515.1",
36
37
  "rimraf": "^6.1.2",
37
- "ttsc": "0.11.0"
38
+ "ttsc": "0.12.0"
38
39
  },
39
40
  "repository": {
40
41
  "type": "git",
package/plugin/banner.go CHANGED
@@ -1,3 +1,3 @@
1
1
  package main
2
2
 
3
- // Banner transform logic lives in github.com/samchon/ttsc/packages/ttsc/utility.
3
+ import _ "github.com/samchon/ttsc/packages/banner/driver"
package/src/index.ts CHANGED
@@ -18,12 +18,15 @@ type TtscPluginFactoryContext<TConfig> = {
18
18
  tsconfig: string;
19
19
  };
20
20
 
21
+ /**
22
+ * @internal
23
+ */
21
24
  export default function createTtscBanner(
22
25
  _context: TtscPluginFactoryContext<ITtscBannerPluginConfig>,
23
26
  ): TtscPluginDescriptor {
24
27
  return {
25
28
  name: "@ttsc/banner",
26
- source: path.resolve(__dirname, "..", "plugin"),
29
+ source: path.resolve(__dirname, "..", "driver"),
27
30
  stage: "transform",
28
31
  };
29
32
  }