Last active
March 14, 2025 07:14
-
-
Save drobune/642da67627d7ff0bc23ac2eb88603697 to your computer and use it in GitHub Desktop.
cosense_to_google_docs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 代表的なページタイプを取得して、最終的な移行計画を作成 | |
const fileContent = await window.fs.readFile('tdwda.json', { encoding: 'utf8' }); | |
// ページタイトルとIDのマッピングを作成(後でディレクトリ構造に使用) | |
const titleToIdMap = {}; | |
const pagePattern = /"title":"([^"]+)","created":(\d+),"updated":(\d+),"id":"([^"]+)","views":(\d+)/g; | |
let match; | |
while ((match = pagePattern.exec(fileContent))) { | |
const title = match[1]; | |
const id = match[4]; | |
titleToIdMap[title] = id; | |
} | |
// サンプルページのIDを取得 | |
const samplePageIds = [ | |
"IDRアンケート", | |
"IDRアプリデザイン仕様", | |
"過ごし方の提案のJSON", | |
"IDR ユーザーレベルとバッジについて" | |
]; | |
const samplePageIdMap = {}; | |
samplePageIds.forEach(title => { | |
if (titleToIdMap[title]) { | |
samplePageIdMap[title] = titleToIdMap[title]; | |
} | |
}); | |
// 改良した変換関数 | |
function convertToMarkdown(lines) { | |
const markdown = []; | |
let inCodeBlock = false; | |
let codeLanguage = ""; | |
lines.forEach(line => { | |
// 空行はそのまま | |
if (line === "") { | |
markdown.push(""); | |
return; | |
} | |
// コードブロック処理 | |
if (line.startsWith("code:")) { | |
inCodeBlock = true; | |
codeLanguage = line.substring(5).trim() || ""; | |
markdown.push("```" + codeLanguage); | |
return; | |
} | |
if (inCodeBlock) { | |
// コードブロック終了判定(空白行またはコードブロック以外の開始) | |
if (line === " " || line.trim() === "") { | |
inCodeBlock = false; | |
markdown.push("```"); | |
return; | |
} | |
// コードブロック内はそのまま | |
markdown.push(line); | |
return; | |
} | |
// 見出し変換 | |
if (/^\[(\*{1,6}) (.+)\]$/.test(line)) { | |
const match = line.match(/^\[(\*{1,6}) (.+)\]$/); | |
const level = Math.min(match[1].length, 6); // Markdownの見出しは6段階まで | |
const text = match[2]; | |
markdown.push("#".repeat(level) + " " + text); | |
return; | |
} | |
// リンク変換 | |
let processedLine = line; | |
// 名前付きリンク: [テキスト https://example.com] | |
processedLine = processedLine.replace(/\[([^\]]+) (https?:\/\/[^\]]+)\]/g, "[$1]($2)"); | |
// シンプルリンク: [https://example.com] | |
processedLine = processedLine.replace(/\[(https?:\/\/[^\]]+)\]/g, "[$1]($1)"); | |
// ユーザーアイコン: [user.icon] | |
processedLine = processedLine.replace(/\[([^\.]+)\.icon\]/g, "**@$1**"); | |
// タグ: #タグ | |
processedLine = processedLine.replace(/#([A-Za-z0-9_\-]+)/g, "**#$1**"); | |
// インデント処理 | |
const indentMatch = processedLine.match(/^( +)/); | |
if (indentMatch) { | |
const indentLevel = indentMatch[1].length; | |
// レベルに応じてリストや引用に変換 | |
if (indentLevel === 1) { | |
processedLine = "- " + processedLine.substring(indentMatch[1].length); | |
} else { | |
processedLine = " ".repeat(indentLevel - 1) + "- " + processedLine.substring(indentMatch[1].length); | |
} | |
} | |
markdown.push(processedLine); | |
}); | |
// コードブロックが閉じられていない場合 | |
if (inCodeBlock) { | |
markdown.push("```"); | |
} | |
return markdown.join("\n"); | |
} | |
// 最初のサンプルページの抽出と変換 | |
console.log("サンプルページの変換例:"); | |
// サンプルページIDを使用して内容を抽出 | |
const pageExtracts = {}; | |
for (const title in samplePageIdMap) { | |
const id = samplePageIdMap[title]; | |
const pagePattern = new RegExp(`"title":"${title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"[^}]*"lines":\\[(.*?)\\]`, 's'); | |
const pageMatch = pagePattern.exec(fileContent); | |
if (pageMatch) { | |
const linesJson = pageMatch[1]; | |
const linePattern = /"([^"]*)"/g; | |
const lines = []; | |
let lineMatch; | |
while ((lineMatch = linePattern.exec(linesJson))) { | |
lines.push(lineMatch[1]); | |
} | |
pageExtracts[title] = lines; | |
} | |
} | |
// サンプルページの変換を表示 | |
for (const title in pageExtracts) { | |
const lines = pageExtracts[title]; | |
const markdown = convertToMarkdown(lines); | |
console.log(`\n=== ${title} ===`); | |
console.log(markdown.substring(0, 500) + "..."); | |
} | |
// 最終的な移行プラン | |
console.log("\n\n==== cosenseからGoogle Docsへの移行計画 ===="); | |
// 1. ディレクトリ構造の提案 | |
console.log("\n1. ディレクトリ構造の提案:"); | |
console.log(` | |
Google Driveに以下のようなフォルダ構造を作成することをお勧めします: | |
- tdwda/ | |
- IDR/ | |
- アンケート/ | |
- 実装計画/ | |
- デザイン/ | |
- 要件定義/ | |
- マーケティング/ | |
- メンバー/ | |
- その他/ | |
`); | |
// 2. 変換プロセス | |
console.log("\n2. 変換プロセス:"); | |
console.log(` | |
各ページをMarkdownに変換し、Google Docsにインポートする手順: | |
1. Cosenseデータからページデータを抽出 | |
2. 各ページをMarkdown形式に変換 | |
3. Google Docsへのインポート方法: | |
a. Markdownを直接Google Docsにペースト | |
b. Google DocsアドオンのDocs to Markdownを使用 | |
c. Google DocsへのMarkdownインポート機能を持つ外部ツールを使用 | |
`); | |
// 3. テンプレート | |
console.log("\n3. Google Docsテンプレート:"); | |
console.log(` | |
各ドキュメントには以下のテンプレートを使用することをお勧めします: | |
--- | |
タイトル: [ページタイトル] | |
作成日: [日付] | |
更新日: [日付] | |
タグ: [関連タグ] | |
--- | |
# [ページタイトル] | |
[本文内容] | |
--- | |
関連ドキュメント: | |
- [関連ドキュメント1](リンク) | |
- [関連ドキュメント2](リンク) | |
`); | |
// 4. スタイリングガイドライン | |
console.log("\n4. スタイリングガイドライン:"); | |
console.log(` | |
Google Docsでのページレスデザインの実現方法: | |
1. ドキュメントの余白を最小限に設定する | |
2. シンプルなフォントを使用(Google Fonts から Roboto または Noto Sans JP を推奨) | |
3. 見出しスタイルを適切に使用 | |
4. ドキュメント全体で一貫したカラースキームを使用 | |
`); | |
// 5. 自動化ツール | |
console.log("\n5. 自動化ツール:"); | |
console.log(` | |
以下のツールを使用して移行プロセスを自動化できます: | |
1. Node.jsスクリプト: JSONからMarkdownへの変換 | |
2. Google Apps Script: Google Driveへのファイル自動作成 | |
3. Markdownエディタ: VS Code + Markdown Preview Enhanced | |
`); | |
// 6. 付録: 変換ルール | |
console.log("\n6. 付録: 記法変換ルール一覧:"); | |
console.log(` | |
| Cosense記法 | Markdown記法 | 備考 | | |
|------------|-------------|------| | |
| [*** 見出し] | ### 見出し | * の数に応じてレベル変更 | | |
| [リンク] | [リンク](URL) | 内部リンクの場合はドキュメント名を参照 | | |
| [テキスト https://...] | [テキスト](https://...) | 名前付きリンク | | |
| [[ページ名]] | [ページ名](ページ名.md) | 内部リンク | | |
| code:言語名 | \`\`\`言語名 | コードブロック | | |
| [user.icon] | **@user** | ユーザーアイコン | | |
| #タグ | **#タグ** | タグ | | |
| インデント | - インデント | インデントをリストに変換 | | |
`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment