@skspwork/config-doc 2.0.2 → 2.0.4

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.
Files changed (37) hide show
  1. package/package.json +3 -2
  2. package/packages/web/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  3. package/packages/web/.next/standalone/.next/server/app/_not-found.html +1 -1
  4. package/packages/web/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  5. package/packages/web/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  6. package/packages/web/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  7. package/packages/web/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  8. package/packages/web/.next/standalone/.next/server/app/api/export/route.js.nft.json +1 -1
  9. package/packages/web/.next/standalone/.next/server/app/index.html +1 -1
  10. package/packages/web/.next/standalone/.next/server/app/index.rsc +3 -3
  11. package/packages/web/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  12. package/packages/web/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  13. package/packages/web/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  14. package/packages/web/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  15. package/packages/web/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  16. package/packages/web/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_d09de205.js +84 -24
  17. package/packages/web/.next/standalone/.next/server/chunks/ssr/app_page_tsx_55b2e5ee._.js +1 -1
  18. package/packages/web/.next/standalone/.next/server/pages/404.html +1 -1
  19. package/packages/web/.next/standalone/.next/static/chunks/9726c2cde77e0916.js +1 -0
  20. package/packages/web/.next/standalone/.next/static/chunks/cd878566fda12635.css +3 -0
  21. package/packages/web/.next/standalone/hooks/useConfigManager.ts +72 -52
  22. package/packages/web/.next/standalone/lib/configManagerUtils.ts +84 -0
  23. package/packages/web/.next/standalone/lib/configParser.ts +44 -0
  24. package/packages/web/.next/standalone/lib/htmlGenerator.ts +73 -8
  25. package/packages/web/.next/standalone/lib/markdownGenerator.ts +58 -13
  26. package/packages/web/.next/standalone/lib/markdownTableGenerator.ts +31 -28
  27. package/packages/web/.next/standalone/lib/utils.ts +19 -2
  28. package/packages/web/.next/standalone/package-lock.json +239 -0
  29. package/packages/web/.next/standalone/package.json +2 -0
  30. package/packages/web/.next/standalone/playwright-report/index.html +1 -1
  31. package/packages/web/.next/static/chunks/9726c2cde77e0916.js +1 -0
  32. package/packages/web/.next/static/chunks/cd878566fda12635.css +3 -0
  33. package/packages/web/package.json +2 -0
  34. package/packages/web/.next/standalone/.next/static/chunks/1747faf69b71cf6d.js +0 -1
  35. package/packages/web/.next/standalone/.next/static/chunks/4bbca8cd642026de.css +0 -3
  36. package/packages/web/.next/static/chunks/1747faf69b71cf6d.js +0 -1
  37. package/packages/web/.next/static/chunks/4bbca8cd642026de.css +0 -3
@@ -2,6 +2,7 @@ import { FileSystemService } from './fileSystem';
2
2
  import { StorageService } from './storage';
3
3
  import { escapeHtml } from './utils';
4
4
  import { ProjectConfigFiles, ConfigDocs } from '@/types';
5
+ import { sortTagsByOrder } from './configManagerUtils';
5
6
 
6
7
  interface ConfigWithDocs {
7
8
  filePath: string;
@@ -26,6 +27,12 @@ export class HtmlGenerator {
26
27
  return this.generateEmptyHtml();
27
28
  }
28
29
 
30
+ // フィールドの順序を取得
31
+ const fieldKeys = settings.fields ? Object.keys(settings.fields) : [];
32
+
33
+ // タグの順序を取得
34
+ const availableTags = settings.availableTags || [];
35
+
29
36
  // 各設定ファイルとそのドキュメントを読み込む
30
37
  const configs: ConfigWithDocs[] = [];
31
38
  for (const filePath of settings.configFiles) {
@@ -59,7 +66,7 @@ export class HtmlGenerator {
59
66
  configFiles: []
60
67
  };
61
68
 
62
- return this.generateFullHtml(metadata, configs);
69
+ return this.generateFullHtml(metadata, configs, fieldKeys, availableTags);
63
70
  }
64
71
 
65
72
  private generateEmptyHtml(): string {
@@ -85,8 +92,10 @@ export class HtmlGenerator {
85
92
  </html>`;
86
93
  }
87
94
 
88
- private generateFullHtml(metadata: ProjectConfigFiles, configs: ConfigWithDocs[]): string {
95
+ private generateFullHtml(metadata: ProjectConfigFiles, configs: ConfigWithDocs[], fieldKeys: string[], availableTags: string[]): string {
89
96
  const configsJson = JSON.stringify(configs, null, 2);
97
+ const fieldKeysJson = JSON.stringify(fieldKeys);
98
+ const availableTagsJson = JSON.stringify(availableTags);
90
99
 
91
100
  return `<!DOCTYPE html>
92
101
  <html lang="ja">
@@ -123,10 +132,25 @@ export class HtmlGenerator {
123
132
 
124
133
  <script>
125
134
  const configs = ${configsJson};
135
+ const fieldKeys = ${fieldKeysJson};
136
+ const availableTags = ${availableTagsJson};
126
137
  let activeConfigIndex = 0;
127
138
  let selectedPath = '';
128
139
  let currentSearchQuery = '';
129
140
 
141
+ // タグをavailableTagsの順序でソート
142
+ function sortTagsByOrder(tags) {
143
+ if (!tags || tags.length === 0) return [];
144
+ return [...tags].sort((a, b) => {
145
+ const indexA = availableTags.indexOf(a);
146
+ const indexB = availableTags.indexOf(b);
147
+ if (indexA !== -1 && indexB !== -1) return indexA - indexB;
148
+ if (indexA === -1) return 1;
149
+ if (indexB === -1) return -1;
150
+ return 0;
151
+ });
152
+ }
153
+
130
154
  ${this.getScripts()}
131
155
  </script>
132
156
  </body>
@@ -223,13 +247,15 @@ export class HtmlGenerator {
223
247
  }
224
248
 
225
249
  .config-tab {
226
- padding: 10px 15px;
250
+ display: flex;
251
+ flex-direction: column;
252
+ gap: 2px;
253
+ padding: 10px 12px;
227
254
  background: #f9fafb;
228
255
  border: 1px solid #e5e7eb;
229
256
  border-radius: 4px;
230
257
  cursor: pointer;
231
258
  transition: all 0.2s;
232
- font-size: 0.9rem;
233
259
  }
234
260
 
235
261
  .config-tab:hover {
@@ -242,10 +268,28 @@ export class HtmlGenerator {
242
268
  border-color: #2563eb;
243
269
  }
244
270
 
271
+ .config-tab.active .config-tab-path {
272
+ color: rgba(255, 255, 255, 0.8);
273
+ }
274
+
245
275
  .config-tab.hidden {
246
276
  display: none;
247
277
  }
248
278
 
279
+ .config-tab-filename {
280
+ font-weight: 500;
281
+ font-size: 0.9rem;
282
+ }
283
+
284
+ .config-tab-path {
285
+ font-size: 0.75rem;
286
+ color: #9ca3af;
287
+ overflow: hidden;
288
+ text-overflow: ellipsis;
289
+ white-space: nowrap;
290
+ max-width: 100%;
291
+ }
292
+
249
293
  .tree-container {
250
294
  padding: 10px;
251
295
  max-height: 600px;
@@ -363,6 +407,20 @@ export class HtmlGenerator {
363
407
  border-bottom: 2px solid #e5e7eb;
364
408
  }
365
409
 
410
+ .property-file {
411
+ font-size: 0.85rem;
412
+ color: #6b7280;
413
+ background: #f9fafb;
414
+ padding: 6px 10px;
415
+ border-radius: 4px;
416
+ margin-bottom: 12px;
417
+ font-family: 'Courier New', monospace;
418
+ overflow: hidden;
419
+ text-overflow: ellipsis;
420
+ white-space: nowrap;
421
+ cursor: help;
422
+ }
423
+
366
424
  .property-path {
367
425
  background: #f3f4f6;
368
426
  padding: 10px 15px;
@@ -585,23 +643,26 @@ export class HtmlGenerator {
585
643
  const doc = config.docs.properties && config.docs.properties[node.path];
586
644
 
587
645
  let html = \`<h2>\${escapeHtml(node.key)}</h2>\`;
646
+ html += \`<div class="property-file" title="\${escapeHtml(config.filePath)}">ファイル: \${escapeHtml(config.filePath)}</div>\`;
588
647
  html += \`<div class="property-path">パス: \${escapeHtml(node.path)}</div>\`;
589
648
  html += \`<div class="property-value">値: \${escapeHtml(JSON.stringify(node.value, null, 2))}</div>\`;
590
649
 
591
650
  if (doc) {
592
651
  if (doc.tags && doc.tags.length > 0) {
652
+ const sortedTags = sortTagsByOrder(doc.tags);
593
653
  html += \`<div class="doc-section">
594
654
  <h3>タグ</h3>
595
655
  <div class="tag-list">\`;
596
- doc.tags.forEach(tag => {
656
+ sortedTags.forEach(tag => {
597
657
  html += \`<span class="tag">\${escapeHtml(tag)}</span>\`;
598
658
  });
599
659
  html += \`</div>
600
660
  </div>\`;
601
661
  }
602
662
 
603
- // フィールドを表示
604
- Object.entries(doc.fields).forEach(([label, value]) => {
663
+ // フィールドをprojectFieldsの順序で表示
664
+ fieldKeys.forEach(label => {
665
+ const value = doc.fields[label];
605
666
  if (value) {
606
667
  html += \`<div class="doc-section">
607
668
  <h3>\${escapeHtml(label)}</h3>
@@ -645,7 +706,10 @@ export class HtmlGenerator {
645
706
  }
646
707
 
647
708
  tab.className = className;
648
- tab.textContent = config.fileName;
709
+ tab.innerHTML = \`
710
+ <div class="config-tab-filename">\${escapeHtml(config.fileName)}</div>
711
+ <div class="config-tab-path" title="\${escapeHtml(config.filePath)}">\${escapeHtml(config.filePath)}</div>
712
+ \`;
649
713
  tab.addEventListener('click', () => {
650
714
  activeConfigIndex = index;
651
715
  renderConfigTabs(matchedConfigIndexes);
@@ -657,6 +721,7 @@ export class HtmlGenerator {
657
721
  });
658
722
  tabsEl.appendChild(tab);
659
723
  });
724
+
660
725
  }
661
726
 
662
727
  // 現在の設定を描画
@@ -1,6 +1,8 @@
1
1
  import { FileSystemService } from './fileSystem';
2
2
  import { StorageService } from './storage';
3
- import path from 'path';
3
+ import { ConfigParser } from './configParser';
4
+ import { sortTagsByOrder } from './configManagerUtils';
5
+ import { getPropertyByPath } from './utils';
4
6
 
5
7
  export class MarkdownGenerator {
6
8
  private rootPath: string;
@@ -19,6 +21,12 @@ export class MarkdownGenerator {
19
21
  return '# 設定ファイルドキュメント\n\nドキュメント化された設定ファイルがありません。\n';
20
22
  }
21
23
 
24
+ // フィールドの順序を取得
25
+ const fieldKeys = settings.fields ? Object.keys(settings.fields) : [];
26
+
27
+ // タグの順序を取得
28
+ const availableTags = settings.availableTags || [];
29
+
22
30
  let markdown = '# 設定ファイルドキュメント\n\n';
23
31
  markdown += `プロジェクト: **${settings.projectName}**\n\n`;
24
32
  markdown += `最終更新: ${new Date().toLocaleString('ja-JP')}\n\n`;
@@ -28,37 +36,74 @@ export class MarkdownGenerator {
28
36
  for (const filePath of settings.configFiles) {
29
37
  const fileName = filePath.split(/[/\\]/).pop() || 'config.json';
30
38
  const docs = await storageService.loadAllDocs(filePath);
39
+ const configData = await fsService.loadConfigFile(filePath);
31
40
 
32
41
  markdown += `## ${fileName}\n\n`;
33
42
  markdown += `**ファイルパス:** \`${filePath}\`\n\n`;
34
43
 
35
- const propertyEntries = Object.entries(docs.properties);
36
- if (propertyEntries.length === 0) {
37
- markdown += '*ドキュメントが登録されていません。*\n\n';
44
+ // 設定ファイルから全プロパティを取得(オブジェクト型も含む)
45
+ // ツリー構造の順序を保持するためソートしない
46
+ const allPropertyPaths = ConfigParser.getAllPropertyPaths(configData);
47
+
48
+ if (allPropertyPaths.length === 0) {
49
+ markdown += '*プロパティがありません。*\n\n';
38
50
  continue;
39
51
  }
40
52
 
41
53
  markdown += '### プロパティ一覧\n\n';
42
54
 
43
- for (const [propertyPath, doc] of propertyEntries) {
55
+ for (const propertyPath of allPropertyPaths) {
56
+ const doc = docs.properties[propertyPath];
57
+ const value = getPropertyByPath(configData, propertyPath);
58
+
44
59
  markdown += `#### \`${propertyPath}\`\n\n`;
45
60
 
46
- if (doc.tags && doc.tags.length > 0) {
47
- markdown += `**タグ:** ${doc.tags.map(tag => `\`${tag}\``).join(', ')}\n\n`;
61
+ // 値を表示(プリミティブ値とプリミティブ配列)
62
+ if (value !== undefined && value !== null) {
63
+ const valueType = typeof value;
64
+ const isArray = Array.isArray(value);
65
+ const isObject = valueType === 'object' && !isArray;
66
+
67
+ if (isArray) {
68
+ // 配列の場合:要素がプリミティブならば表示
69
+ const hasPrimitiveElements = value.length > 0 && value.every((item: any) =>
70
+ typeof item !== 'object' || item === null
71
+ );
72
+ if (hasPrimitiveElements) {
73
+ markdown += `**値:** \`${JSON.stringify(value)}\`\n\n`;
74
+ }
75
+ } else if (!isObject) {
76
+ // プリミティブ値を表示
77
+ markdown += `**値:** \`${String(value)}\`\n\n`;
78
+ }
48
79
  }
49
80
 
50
- // フィールドを表示
51
- Object.entries(doc.fields).forEach(([label, value]) => {
52
- if (value) {
53
- markdown += `**${label}:**\n\n${value}\n\n`;
81
+ // ドキュメントがある場合
82
+ if (doc) {
83
+ if (doc.tags && doc.tags.length > 0) {
84
+ const sortedTags = sortTagsByOrder(doc.tags, availableTags);
85
+ markdown += `**タグ:** ${sortedTags.map(tag => `\`${tag}\``).join(', ')}\n\n`;
86
+ }
87
+
88
+ // フィールドをprojectFieldsの順序で表示
89
+ if (doc.fields) {
90
+ for (const fieldKey of fieldKeys) {
91
+ const fieldValue = doc.fields[fieldKey];
92
+ if (fieldValue) {
93
+ markdown += `**${fieldKey}:**\n\n${fieldValue}\n\n`;
94
+ }
95
+ }
54
96
  }
55
- });
97
+ } else {
98
+ // ドキュメントがない場合
99
+ markdown += '*ドキュメントなし*\n\n';
100
+ }
56
101
 
57
102
  markdown += '---\n\n';
58
103
  }
59
104
  }
60
105
 
61
- markdown += `\n*このドキュメントは [ConfigDoc](https://github.com/your-repo/configdoc) により自動生成されました。*\n`;
106
+ markdown += `\n*このドキュメントは ConfigDoc により自動生成されました。*\n`;
62
107
 
63
108
  return markdown;
64
109
  }
@@ -1,6 +1,8 @@
1
1
  import { FileSystemService } from './fileSystem';
2
2
  import { StorageService } from './storage';
3
3
  import { escapeTableCell, getPropertyByPath, formatValue } from './utils';
4
+ import { ConfigParser } from './configParser';
5
+ import { sortTagsByOrder } from './configManagerUtils';
4
6
 
5
7
  export class MarkdownTableGenerator {
6
8
  private rootPath: string;
@@ -19,6 +21,12 @@ export class MarkdownTableGenerator {
19
21
  return '# 設定ファイルドキュメント\n\nドキュメント化された設定ファイルがありません。\n';
20
22
  }
21
23
 
24
+ // フィールドの順序を取得(すべてのフィールドをテーブルの列として使用)
25
+ const fieldKeys = settings.fields ? Object.keys(settings.fields) : [];
26
+
27
+ // タグの順序を取得
28
+ const availableTags = settings.availableTags || [];
29
+
22
30
  let markdown = '# 設定ファイルドキュメント\n\n';
23
31
  markdown += `プロジェクト: **${settings.projectName}**\n\n`;
24
32
  markdown += `最終更新: ${new Date().toLocaleString('ja-JP')}\n\n`;
@@ -33,52 +41,47 @@ export class MarkdownTableGenerator {
33
41
  markdown += `## ${fileName}\n\n`;
34
42
  markdown += `**ファイルパス:** \`${filePath}\`\n\n`;
35
43
 
36
- const propertyEntries = Object.entries(docs.properties);
37
- if (propertyEntries.length === 0) {
38
- markdown += '*ドキュメントが登録されていません。*\n\n';
44
+ // 設定ファイルから全プロパティを取得(オブジェクト型も含む)
45
+ // ツリー構造の順序を保持するためソートしない
46
+ const allPropertyPaths = ConfigParser.getAllPropertyPaths(configData);
47
+
48
+ if (allPropertyPaths.length === 0) {
49
+ markdown += '*プロパティがありません。*\n\n';
39
50
  continue;
40
51
  }
41
52
 
42
- // すべてのフィールドラベルを収集(説明以外)
43
- const fieldLabels = new Set<string>();
44
- propertyEntries.forEach(([_, doc]) => {
45
- Object.keys(doc.fields).forEach(label => {
46
- if (label !== '説明') {
47
- fieldLabels.add(label);
48
- }
49
- });
50
- });
51
- const sortedLabels = Array.from(fieldLabels).sort();
52
-
53
- // テーブルヘッダー
54
- markdown += '| プロパティ名 | タグ | 説明 | 値 |';
55
- sortedLabels.forEach(label => {
53
+ // テーブルヘッダー(projectFieldsの順序で表示)
54
+ markdown += '| プロパティ名 | タグ | 値 |';
55
+ fieldKeys.forEach(label => {
56
56
  markdown += ` ${label} |`;
57
57
  });
58
58
  markdown += '\n';
59
59
 
60
- markdown += '|-------------|------|------|-----|';
61
- sortedLabels.forEach(() => {
60
+ markdown += '|-------------|------|-----|';
61
+ fieldKeys.forEach(() => {
62
62
  markdown += '------|';
63
63
  });
64
64
  markdown += '\n';
65
65
 
66
66
  // 各プロパティの行を追加
67
- for (const [propertyPath, doc] of propertyEntries) {
67
+ for (const propertyPath of allPropertyPaths) {
68
+ const doc = docs.properties[propertyPath];
68
69
  const propertyName = escapeTableCell(propertyPath);
69
- const tags = doc.tags && doc.tags.length > 0
70
- ? escapeTableCell(doc.tags.map(tag => `\`${tag}\``).join(', '))
70
+ const sortedTags = doc && doc.tags && doc.tags.length > 0
71
+ ? sortTagsByOrder(doc.tags, availableTags)
72
+ : [];
73
+ const tags = sortedTags.length > 0
74
+ ? escapeTableCell(sortedTags.map(tag => `\`${tag}\``).join(', '))
71
75
  : '-';
72
76
 
73
- const description = escapeTableCell(doc.fields['説明'] || '-');
74
77
  const value = this.getPropertyValue(configData, propertyPath);
75
78
  const valueStr = escapeTableCell(value);
76
79
 
77
- markdown += `| ${propertyName} | ${tags} | ${description} | ${valueStr} |`;
80
+ markdown += `| ${propertyName} | ${tags} | ${valueStr} |`;
78
81
 
79
- // フィールドの値を追加(説明以外)
80
- sortedLabels.forEach(label => {
81
- const fieldValue = doc.fields[label] || '-';
82
+ // フィールドの値をprojectFieldsの順序で追加
83
+ fieldKeys.forEach(label => {
84
+ const fieldValue = (doc && doc.fields && doc.fields[label]) || '-';
82
85
  markdown += ` ${escapeTableCell(fieldValue)} |`;
83
86
  });
84
87
 
@@ -88,7 +91,7 @@ export class MarkdownTableGenerator {
88
91
  markdown += '\n';
89
92
  }
90
93
 
91
- markdown += `\n*このドキュメントは [ConfigDoc](https://github.com/your-repo/configdoc) により自動生成されました。*\n`;
94
+ markdown += `\n*このドキュメントは ConfigDoc により自動生成されました。*\n`;
92
95
 
93
96
  return markdown;
94
97
  }
@@ -58,15 +58,32 @@ export function getPropertyByPath(obj: unknown, propertyPath: string): unknown {
58
58
 
59
59
  /**
60
60
  * 値を表示用の文字列に変換
61
+ * プリミティブ値とプリミティブ配列のみ表示し、オブジェクトとオブジェクト配列は'-'を返す
61
62
  */
62
63
  export function formatValue(value: unknown): string {
63
64
  if (value === null || value === undefined) {
64
65
  return '-';
65
66
  }
66
67
 
67
- if (typeof value === 'object') {
68
- return JSON.stringify(value);
68
+ const valueType = typeof value;
69
+ const isArray = Array.isArray(value);
70
+ const isObject = valueType === 'object' && !isArray;
71
+
72
+ if (isArray) {
73
+ // 配列の場合:要素がプリミティブならば表示
74
+ const hasPrimitiveElements = value.length > 0 && value.every((item: any) =>
75
+ typeof item !== 'object' || item === null
76
+ );
77
+ if (hasPrimitiveElements) {
78
+ return JSON.stringify(value);
79
+ }
80
+ // オブジェクト配列の場合は表示しない
81
+ return '-';
82
+ } else if (isObject) {
83
+ // オブジェクトの場合は表示しない
84
+ return '-';
69
85
  }
70
86
 
87
+ // プリミティブ値を表示
71
88
  return String(value);
72
89
  }