@skspwork/config-doc 2.0.3 → 2.0.5
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/package.json +3 -2
- package/packages/web/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/packages/web/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/packages/web/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/packages/web/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/packages/web/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/packages/web/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/packages/web/.next/standalone/.next/server/app/api/config/save/route.js +1 -1
- package/packages/web/.next/standalone/.next/server/app/api/config/save/route.js.nft.json +1 -1
- package/packages/web/.next/standalone/.next/server/app/api/export/route.js +3 -3
- package/packages/web/.next/standalone/.next/server/app/api/export/route.js.nft.json +1 -1
- package/packages/web/.next/standalone/.next/server/app/index.html +1 -1
- package/packages/web/.next/standalone/.next/server/app/index.rsc +3 -3
- package/packages/web/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/packages/web/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/packages/web/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/packages/web/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/packages/web/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/packages/web/.next/standalone/.next/server/chunks/[root-of-the-server]__40e87302._.js +3 -0
- package/packages/web/.next/standalone/.next/server/chunks/[root-of-the-server]__93da9fce._.js +1 -1
- package/packages/web/.next/standalone/.next/server/chunks/[root-of-the-server]__c9655ac8._.js +3 -0
- package/packages/web/.next/standalone/.next/server/chunks/[root-of-the-server]__e19366f6._.js +1 -1
- package/packages/web/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_d09de205.js +368 -29
- package/packages/web/.next/standalone/.next/server/chunks/ssr/app_page_tsx_55b2e5ee._.js +1 -1
- package/packages/web/.next/standalone/.next/server/pages/404.html +1 -1
- package/packages/web/.next/standalone/.next/static/chunks/02de70e4c30afe2f.js +1 -0
- package/packages/web/.next/standalone/.next/static/chunks/862e384b52cfebf3.css +3 -0
- package/packages/web/.next/standalone/app/api/config/metadata/route.ts +5 -3
- package/packages/web/.next/standalone/package.json +2 -0
- package/packages/web/.next/standalone/playwright-report/index.html +1 -1
- package/packages/web/.next/static/chunks/02de70e4c30afe2f.js +1 -0
- package/packages/web/.next/static/chunks/862e384b52cfebf3.css +3 -0
- package/packages/web/package.json +2 -0
- package/packages/web/.next/standalone/.next/server/chunks/[root-of-the-server]__1a68b1f3._.js +0 -3
- package/packages/web/.next/standalone/.next/server/chunks/[root-of-the-server]__2c94dfea._.js +0 -3
- package/packages/web/.next/standalone/.next/static/chunks/4bbca8cd642026de.css +0 -3
- package/packages/web/.next/standalone/.next/static/chunks/54e2bd8f072e7d4e.js +0 -1
- package/packages/web/.next/standalone/app/api/config/load/route.ts +0 -57
- package/packages/web/.next/standalone/app/api/config/save/route.ts +0 -73
- package/packages/web/.next/standalone/app/api/export/route.ts +0 -75
- package/packages/web/.next/standalone/app/api/export/settings/route.ts +0 -144
- package/packages/web/.next/standalone/app/api/files/browse/route.ts +0 -46
- package/packages/web/.next/standalone/app/api/project/route.ts +0 -41
- package/packages/web/.next/standalone/app/globals.css +0 -26
- package/packages/web/.next/standalone/app/icon.svg +0 -41
- package/packages/web/.next/standalone/app/layout.tsx +0 -34
- package/packages/web/.next/standalone/app/page.tsx +0 -135
- package/packages/web/.next/standalone/components/ConfigFileTabs.tsx +0 -188
- package/packages/web/.next/standalone/components/ConfigTree.tsx +0 -176
- package/packages/web/.next/standalone/components/EditableList.tsx +0 -337
- package/packages/web/.next/standalone/components/ExportDialog.tsx +0 -234
- package/packages/web/.next/standalone/components/FieldsEditor.tsx +0 -92
- package/packages/web/.next/standalone/components/FileBrowser.tsx +0 -290
- package/packages/web/.next/standalone/components/Header.tsx +0 -37
- package/packages/web/.next/standalone/components/PropertyEditor.tsx +0 -102
- package/packages/web/.next/standalone/components/TagEditor.tsx +0 -86
- package/packages/web/.next/standalone/components/Toast.tsx +0 -91
- package/packages/web/.next/standalone/eslint.config.mjs +0 -18
- package/packages/web/.next/standalone/hooks/useConfigManager.ts +0 -633
- package/packages/web/.next/standalone/lib/configParser.ts +0 -155
- package/packages/web/.next/standalone/lib/fileSystem.ts +0 -186
- package/packages/web/.next/standalone/lib/getRootPath.ts +0 -45
- package/packages/web/.next/standalone/lib/htmlGenerator.ts +0 -839
- package/packages/web/.next/standalone/lib/jsonUtils.ts +0 -26
- package/packages/web/.next/standalone/lib/markdownGenerator.ts +0 -79
- package/packages/web/.next/standalone/lib/markdownTableGenerator.ts +0 -107
- package/packages/web/.next/standalone/lib/storage.ts +0 -104
- package/packages/web/.next/standalone/lib/utils.ts +0 -72
- package/packages/web/.next/standalone/next.config.ts +0 -10
- package/packages/web/.next/standalone/package-lock.json +0 -7977
- package/packages/web/.next/standalone/playwright.config.ts +0 -27
- package/packages/web/.next/standalone/postcss.config.mjs +0 -7
- package/packages/web/.next/standalone/test-results/.last-run.json +0 -4
- package/packages/web/.next/standalone/tsconfig.json +0 -34
- package/packages/web/.next/standalone/tsconfig.tsbuildinfo +0 -1
- package/packages/web/.next/standalone/types/index.ts +0 -74
- package/packages/web/.next/standalone/vitest.config.ts +0 -14
- package/packages/web/.next/static/chunks/4bbca8cd642026de.css +0 -3
- package/packages/web/.next/static/chunks/54e2bd8f072e7d4e.js +0 -1
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { parse } from 'jsonc-parser';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* BOM(Byte Order Mark)を除去してJSONをパースする
|
|
5
|
-
* UTF-8 BOM (0xFEFF) が含まれているJSONファイルをパースする際に使用
|
|
6
|
-
* JSONC形式(コメント、末尾カンマ)にも対応
|
|
7
|
-
*/
|
|
8
|
-
export function parseJSON<T = unknown>(content: string): T {
|
|
9
|
-
// UTF-8 BOM (EF BB BF) を除去
|
|
10
|
-
const cleanContent = content.charCodeAt(0) === 0xFEFF
|
|
11
|
-
? content.slice(1)
|
|
12
|
-
: content;
|
|
13
|
-
|
|
14
|
-
return parse(cleanContent) as T;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* BOM(Byte Order Mark)を除去する
|
|
19
|
-
* UTF-8 BOM (0xFEFF) が含まれている文字列をクリーンアップ
|
|
20
|
-
*/
|
|
21
|
-
export function removeBOM(content: string): string {
|
|
22
|
-
if (content.charCodeAt(0) === 0xFEFF) {
|
|
23
|
-
return content.slice(1);
|
|
24
|
-
}
|
|
25
|
-
return content;
|
|
26
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { FileSystemService } from './fileSystem';
|
|
2
|
-
import { StorageService } from './storage';
|
|
3
|
-
import { ConfigParser } from './configParser';
|
|
4
|
-
|
|
5
|
-
export class MarkdownGenerator {
|
|
6
|
-
private rootPath: string;
|
|
7
|
-
|
|
8
|
-
constructor(rootPath: string) {
|
|
9
|
-
this.rootPath = rootPath;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async generateMarkdown(): Promise<string> {
|
|
13
|
-
const fsService = new FileSystemService(this.rootPath);
|
|
14
|
-
const storageService = new StorageService(fsService);
|
|
15
|
-
|
|
16
|
-
// プロジェクト設定を読み込む
|
|
17
|
-
const settings = await fsService.loadProjectSettings();
|
|
18
|
-
if (!settings || settings.configFiles.length === 0) {
|
|
19
|
-
return '# 設定ファイルドキュメント\n\nドキュメント化された設定ファイルがありません。\n';
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let markdown = '# 設定ファイルドキュメント\n\n';
|
|
23
|
-
markdown += `プロジェクト: **${settings.projectName}**\n\n`;
|
|
24
|
-
markdown += `最終更新: ${new Date().toLocaleString('ja-JP')}\n\n`;
|
|
25
|
-
markdown += '---\n\n';
|
|
26
|
-
|
|
27
|
-
// 各設定ファイルのドキュメントを生成
|
|
28
|
-
for (const filePath of settings.configFiles) {
|
|
29
|
-
const fileName = filePath.split(/[/\\]/).pop() || 'config.json';
|
|
30
|
-
const docs = await storageService.loadAllDocs(filePath);
|
|
31
|
-
const configData = await fsService.loadConfigFile(filePath);
|
|
32
|
-
|
|
33
|
-
markdown += `## ${fileName}\n\n`;
|
|
34
|
-
markdown += `**ファイルパス:** \`${filePath}\`\n\n`;
|
|
35
|
-
|
|
36
|
-
// 設定ファイルから全プロパティを取得(オブジェクト型も含む)
|
|
37
|
-
// ツリー構造の順序を保持するためソートしない
|
|
38
|
-
const allPropertyPaths = ConfigParser.getAllPropertyPaths(configData);
|
|
39
|
-
|
|
40
|
-
if (allPropertyPaths.length === 0) {
|
|
41
|
-
markdown += '*プロパティがありません。*\n\n';
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
markdown += '### プロパティ一覧\n\n';
|
|
46
|
-
|
|
47
|
-
for (const propertyPath of allPropertyPaths) {
|
|
48
|
-
const doc = docs.properties[propertyPath];
|
|
49
|
-
|
|
50
|
-
markdown += `#### \`${propertyPath}\`\n\n`;
|
|
51
|
-
|
|
52
|
-
// ドキュメントがある場合
|
|
53
|
-
if (doc) {
|
|
54
|
-
if (doc.tags && doc.tags.length > 0) {
|
|
55
|
-
markdown += `**タグ:** ${doc.tags.map(tag => `\`${tag}\``).join(', ')}\n\n`;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// フィールドを表示
|
|
59
|
-
if (doc.fields) {
|
|
60
|
-
Object.entries(doc.fields).forEach(([label, value]) => {
|
|
61
|
-
if (value) {
|
|
62
|
-
markdown += `**${label}:**\n\n${value}\n\n`;
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
// ドキュメントがない場合
|
|
68
|
-
markdown += '*ドキュメントなし*\n\n';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
markdown += '---\n\n';
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
markdown += `\n*このドキュメントは ConfigDoc により自動生成されました。*\n`;
|
|
76
|
-
|
|
77
|
-
return markdown;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { FileSystemService } from './fileSystem';
|
|
2
|
-
import { StorageService } from './storage';
|
|
3
|
-
import { escapeTableCell, getPropertyByPath, formatValue } from './utils';
|
|
4
|
-
import { ConfigParser } from './configParser';
|
|
5
|
-
|
|
6
|
-
export class MarkdownTableGenerator {
|
|
7
|
-
private rootPath: string;
|
|
8
|
-
|
|
9
|
-
constructor(rootPath: string) {
|
|
10
|
-
this.rootPath = rootPath;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async generateMarkdownTable(): Promise<string> {
|
|
14
|
-
const fsService = new FileSystemService(this.rootPath);
|
|
15
|
-
const storageService = new StorageService(fsService);
|
|
16
|
-
|
|
17
|
-
// プロジェクト設定を読み込む
|
|
18
|
-
const settings = await fsService.loadProjectSettings();
|
|
19
|
-
if (!settings || settings.configFiles.length === 0) {
|
|
20
|
-
return '# 設定ファイルドキュメント\n\nドキュメント化された設定ファイルがありません。\n';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let markdown = '# 設定ファイルドキュメント\n\n';
|
|
24
|
-
markdown += `プロジェクト: **${settings.projectName}**\n\n`;
|
|
25
|
-
markdown += `最終更新: ${new Date().toLocaleString('ja-JP')}\n\n`;
|
|
26
|
-
markdown += '---\n\n';
|
|
27
|
-
|
|
28
|
-
// 各設定ファイルのドキュメントを生成
|
|
29
|
-
for (const filePath of settings.configFiles) {
|
|
30
|
-
const fileName = filePath.split(/[/\\]/).pop() || 'config.json';
|
|
31
|
-
const docs = await storageService.loadAllDocs(filePath);
|
|
32
|
-
const configData = await fsService.loadConfigFile(filePath);
|
|
33
|
-
|
|
34
|
-
markdown += `## ${fileName}\n\n`;
|
|
35
|
-
markdown += `**ファイルパス:** \`${filePath}\`\n\n`;
|
|
36
|
-
|
|
37
|
-
// 設定ファイルから全プロパティを取得(オブジェクト型も含む)
|
|
38
|
-
// ツリー構造の順序を保持するためソートしない
|
|
39
|
-
const allPropertyPaths = ConfigParser.getAllPropertyPaths(configData);
|
|
40
|
-
|
|
41
|
-
if (allPropertyPaths.length === 0) {
|
|
42
|
-
markdown += '*プロパティがありません。*\n\n';
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// すべてのフィールドラベルを収集(説明以外)
|
|
47
|
-
const fieldLabels = new Set<string>();
|
|
48
|
-
allPropertyPaths.forEach(propertyPath => {
|
|
49
|
-
const doc = docs.properties[propertyPath];
|
|
50
|
-
if (doc && doc.fields) {
|
|
51
|
-
Object.keys(doc.fields).forEach(label => {
|
|
52
|
-
if (label !== '説明') {
|
|
53
|
-
fieldLabels.add(label);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
const sortedLabels = Array.from(fieldLabels).sort();
|
|
59
|
-
|
|
60
|
-
// テーブルヘッダー
|
|
61
|
-
markdown += '| プロパティ名 | タグ | 値 |';
|
|
62
|
-
sortedLabels.forEach(label => {
|
|
63
|
-
markdown += ` ${label} |`;
|
|
64
|
-
});
|
|
65
|
-
markdown += '\n';
|
|
66
|
-
|
|
67
|
-
markdown += '|-------------|------|-----|';
|
|
68
|
-
sortedLabels.forEach(() => {
|
|
69
|
-
markdown += '------|';
|
|
70
|
-
});
|
|
71
|
-
markdown += '\n';
|
|
72
|
-
|
|
73
|
-
// 各プロパティの行を追加
|
|
74
|
-
for (const propertyPath of allPropertyPaths) {
|
|
75
|
-
const doc = docs.properties[propertyPath];
|
|
76
|
-
const propertyName = escapeTableCell(propertyPath);
|
|
77
|
-
const tags = doc && doc.tags && doc.tags.length > 0
|
|
78
|
-
? escapeTableCell(doc.tags.map(tag => `\`${tag}\``).join(', '))
|
|
79
|
-
: '-';
|
|
80
|
-
|
|
81
|
-
const value = this.getPropertyValue(configData, propertyPath);
|
|
82
|
-
const valueStr = escapeTableCell(value);
|
|
83
|
-
|
|
84
|
-
markdown += `| ${propertyName} | ${tags} | ${valueStr} |`;
|
|
85
|
-
|
|
86
|
-
// フィールドの値を追加(説明以外)
|
|
87
|
-
sortedLabels.forEach(label => {
|
|
88
|
-
const fieldValue = (doc && doc.fields && doc.fields[label]) || '-';
|
|
89
|
-
markdown += ` ${escapeTableCell(fieldValue)} |`;
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
markdown += '\n';
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
markdown += '\n';
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
markdown += `\n*このドキュメントは ConfigDoc により自動生成されました。*\n`;
|
|
99
|
-
|
|
100
|
-
return markdown;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private getPropertyValue(configData: unknown, propertyPath: string): string {
|
|
104
|
-
const value = getPropertyByPath(configData, propertyPath);
|
|
105
|
-
return formatValue(value);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { FileSystemService } from './fileSystem';
|
|
2
|
-
import { ConfigDocs, PropertyDoc } from '@/types';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
|
|
5
|
-
export class StorageService {
|
|
6
|
-
constructor(private fs: FileSystemService) {}
|
|
7
|
-
|
|
8
|
-
async savePropertyDoc(
|
|
9
|
-
configFilePath: string,
|
|
10
|
-
propertyPath: string,
|
|
11
|
-
propertyDoc: PropertyDoc
|
|
12
|
-
): Promise<void> {
|
|
13
|
-
const docsFileName = this.getDocsFileName(configFilePath);
|
|
14
|
-
|
|
15
|
-
// 絶対パスを相対パスに変換
|
|
16
|
-
const relativeConfigPath = this.toRelativePath(configFilePath);
|
|
17
|
-
|
|
18
|
-
let docs = await this.fs.loadConfigDocs(docsFileName);
|
|
19
|
-
if (!docs) {
|
|
20
|
-
docs = {
|
|
21
|
-
configFilePath: relativeConfigPath,
|
|
22
|
-
lastModified: new Date().toISOString(),
|
|
23
|
-
properties: {}
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
docs.properties[propertyPath] = propertyDoc;
|
|
28
|
-
docs.lastModified = new Date().toISOString();
|
|
29
|
-
docs.configFilePath = relativeConfigPath; // 常に相対パスを保存
|
|
30
|
-
|
|
31
|
-
await this.fs.saveConfigDocs(docsFileName, docs);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async updateAllProperties(
|
|
35
|
-
configFilePath: string,
|
|
36
|
-
properties: Record<string, PropertyDoc>
|
|
37
|
-
): Promise<void> {
|
|
38
|
-
const docsFileName = this.getDocsFileName(configFilePath);
|
|
39
|
-
|
|
40
|
-
// 絶対パスを相対パスに変換
|
|
41
|
-
const relativeConfigPath = this.toRelativePath(configFilePath);
|
|
42
|
-
|
|
43
|
-
let docs = await this.fs.loadConfigDocs(docsFileName);
|
|
44
|
-
if (!docs) {
|
|
45
|
-
docs = {
|
|
46
|
-
configFilePath: relativeConfigPath,
|
|
47
|
-
lastModified: new Date().toISOString(),
|
|
48
|
-
properties: {}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
docs.properties = properties;
|
|
53
|
-
docs.lastModified = new Date().toISOString();
|
|
54
|
-
docs.configFilePath = relativeConfigPath;
|
|
55
|
-
|
|
56
|
-
await this.fs.saveConfigDocs(docsFileName, docs);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async loadAllDocs(configFilePath: string): Promise<ConfigDocs> {
|
|
60
|
-
const docsFileName = this.getDocsFileName(configFilePath);
|
|
61
|
-
const docs = await this.fs.loadConfigDocs(docsFileName);
|
|
62
|
-
|
|
63
|
-
// 絶対パスを相対パスに変換
|
|
64
|
-
const relativeConfigPath = this.toRelativePath(configFilePath);
|
|
65
|
-
|
|
66
|
-
return docs || {
|
|
67
|
-
configFilePath: relativeConfigPath,
|
|
68
|
-
lastModified: new Date().toISOString(),
|
|
69
|
-
properties: {}
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// 公開メソッド: docsファイル名を取得
|
|
74
|
-
public getDocsFileName(configFilePath: string): string {
|
|
75
|
-
// 相対パスに変換してから処理
|
|
76
|
-
const relativePath = this.toRelativePath(configFilePath);
|
|
77
|
-
|
|
78
|
-
// パスの深さが1以下(ルート直下のファイル)の場合は、シンプルなファイル名
|
|
79
|
-
const pathParts = relativePath.split(/[/\\]/).filter(p => p && p !== '.');
|
|
80
|
-
|
|
81
|
-
if (pathParts.length <= 1) {
|
|
82
|
-
// ルート直下のファイル: components.json → components.docs.json
|
|
83
|
-
const fileName = pathParts[0] || 'config.json';
|
|
84
|
-
return fileName.replace('.json', '.docs.json');
|
|
85
|
-
} else {
|
|
86
|
-
// サブディレクトリのファイル: 相対パスを含めて一意にする
|
|
87
|
-
// 例: ../SimMoney/components.json → __SimMoney_components.docs.json
|
|
88
|
-
// 例: sample/appsettings.json → sample_appsettings.docs.json
|
|
89
|
-
const normalized = relativePath
|
|
90
|
-
.replace(/\.\./g, '__') // .. を __ に変換
|
|
91
|
-
.replace(/[/\\]/g, '_') // / と \ を _ に変換
|
|
92
|
-
.replace(/:/g, ''); // : を削除
|
|
93
|
-
return normalized.replace('.json', '.docs.json');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private toRelativePath(filePath: string): string {
|
|
98
|
-
// 絶対パスの場合は相対パスに変換
|
|
99
|
-
if (path.isAbsolute(filePath)) {
|
|
100
|
-
return path.relative(this.fs['rootPath'], filePath);
|
|
101
|
-
}
|
|
102
|
-
return filePath;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 共通ユーティリティ関数
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Markdownテーブルのセル内で特殊文字をエスケープ
|
|
7
|
-
*/
|
|
8
|
-
export function escapeTableCell(text: string): string {
|
|
9
|
-
return text
|
|
10
|
-
.replace(/\|/g, '\\|') // パイプをエスケープ
|
|
11
|
-
.replace(/\n/g, '<br>') // 改行をHTMLのbrタグに変換
|
|
12
|
-
.replace(/\r/g, ''); // キャリッジリターンを削除
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* HTMLの特殊文字をエスケープ
|
|
17
|
-
*/
|
|
18
|
-
export function escapeHtml(text: string): string {
|
|
19
|
-
return text
|
|
20
|
-
.replace(/&/g, '&')
|
|
21
|
-
.replace(/</g, '<')
|
|
22
|
-
.replace(/>/g, '>')
|
|
23
|
-
.replace(/"/g, '"')
|
|
24
|
-
.replace(/'/g, ''');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* ネストしたオブジェクトからプロパティパスで値を取得
|
|
29
|
-
* @param obj 対象オブジェクト
|
|
30
|
-
* @param propertyPath コロン区切りのプロパティパス(例: "Database:ConnectionString" または "Servers[0]:Name")
|
|
31
|
-
* @returns 見つかった値、または undefined
|
|
32
|
-
*/
|
|
33
|
-
export function getPropertyByPath(obj: unknown, propertyPath: string): unknown {
|
|
34
|
-
// "Servers[0]:Name" -> ["Servers", "[0]", "Name"]
|
|
35
|
-
const keys = propertyPath.split(/(?=\[)|:/);
|
|
36
|
-
let value: unknown = obj;
|
|
37
|
-
|
|
38
|
-
for (const key of keys) {
|
|
39
|
-
if (value === undefined || value === null) return undefined;
|
|
40
|
-
|
|
41
|
-
if (key.startsWith('[') && key.endsWith(']')) {
|
|
42
|
-
// 配列インデックス
|
|
43
|
-
const index = parseInt(key.slice(1, -1), 10);
|
|
44
|
-
if (Array.isArray(value)) {
|
|
45
|
-
value = value[index];
|
|
46
|
-
} else {
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
} else if (key && typeof value === 'object' && key in value) {
|
|
50
|
-
value = (value as Record<string, unknown>)[key];
|
|
51
|
-
} else if (key) {
|
|
52
|
-
return undefined;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return value;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 値を表示用の文字列に変換
|
|
61
|
-
*/
|
|
62
|
-
export function formatValue(value: unknown): string {
|
|
63
|
-
if (value === null || value === undefined) {
|
|
64
|
-
return '-';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (typeof value === 'object') {
|
|
68
|
-
return JSON.stringify(value);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return String(value);
|
|
72
|
-
}
|