From 63c6ad2d9abb470cf0a426ab83e2d8ed7e99ade8 Mon Sep 17 00:00:00 2001
From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com>
Date: Mon, 3 Aug 2026 00:40:55 +0900
Subject: [PATCH 1/6] add Dart
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- **API**: DartPad の `compileNewDDC` API エンドポイント (`https://stable.api.dartpad.dev/api/v3/compileNewDDC`) を使用。
- **実行環境**: iframe 内で RequireJS により `ddc_module_loader.js` および `dart_sdk_new.js` をロードし、`dartDevEmbedder.runMain` でコンパイル済み JS を安全に実行。
- **UI & 統合**: Ace Editor モード (`mode-dart`)、Dart SVG アイコン、テスト用サンプルコード (`main.dart`) を追加・統合。
---
app/terminal/editor.tsx | 1 +
app/terminal/icons.tsx | 10 +
app/terminal/page.tsx | 8 +
app/terminal/samples/main.dart | 3 +
packages/runtime/src/context.tsx | 8 +-
packages/runtime/src/dart/runtime.tsx | 299 ++++++++++++++++++++++++
packages/runtime/src/languages.ts | 21 +-
packages/runtime/tests/fileExecution.ts | 7 +
packages/runtime/tests/repl.ts | 5 +
packages/runtime/tests/utils.ts | 1 +
10 files changed, 358 insertions(+), 5 deletions(-)
create mode 100644 app/terminal/samples/main.dart
create mode 100644 packages/runtime/src/dart/runtime.tsx
diff --git a/app/terminal/editor.tsx b/app/terminal/editor.tsx
index 14d2547b..70e9b94e 100644
--- a/app/terminal/editor.tsx
+++ b/app/terminal/editor.tsx
@@ -26,6 +26,7 @@ const AceEditor = lazy(async () => {
await import("ace-builds/src-min-noconflict/mode-json");
await import("ace-builds/src-min-noconflict/mode-csv");
await import("ace-builds/src-min-noconflict/mode-text");
+ await import("ace-builds/src-min-noconflict/mode-dart");
return ace;
} else {
throw new Error("should not try SSR");
diff --git a/app/terminal/icons.tsx b/app/terminal/icons.tsx
index 872ae930..9c356a0f 100644
--- a/app/terminal/icons.tsx
+++ b/app/terminal/icons.tsx
@@ -113,6 +113,16 @@ export function LanguageIcon(props: Props) {
);
+ case "dart":
+ return (
+
+ );
default:
props.lang satisfies never;
console.warn("unknown lang for LanguageIcon:", props.lang);
diff --git a/app/terminal/page.tsx b/app/terminal/page.tsx
index ba9a32ec..b40bef1c 100644
--- a/app/terminal/page.tsx
+++ b/app/terminal/page.tsx
@@ -26,6 +26,7 @@ import sub_h from "./samples/sub.h?raw";
import sub_cpp from "./samples/sub.cpp?raw";
import main2_rs from "./samples/main2.rs?raw";
import sub_rs from "./samples/sub.rs?raw";
+import main_dart from "./samples/main.dart?raw";
import { DaisyInfoIcon } from "@/daisyAlertIcon";
export default function RuntimeTestPage() {
@@ -127,6 +128,13 @@ const sampleConfig: Record = {
},
exec: ["main2.rs"],
},
+ dart: {
+ repl: false,
+ editor: {
+ "main.dart": main_dart,
+ },
+ exec: ["main.dart"],
+ },
};
function RuntimeSample({
lang,
diff --git a/app/terminal/samples/main.dart b/app/terminal/samples/main.dart
new file mode 100644
index 00000000..a506f97c
--- /dev/null
+++ b/app/terminal/samples/main.dart
@@ -0,0 +1,3 @@
+void main() {
+ print("Hello, Dart!");
+}
diff --git a/packages/runtime/src/context.tsx b/packages/runtime/src/context.tsx
index 9874812e..4a7e5ac4 100644
--- a/packages/runtime/src/context.tsx
+++ b/packages/runtime/src/context.tsx
@@ -3,6 +3,7 @@
import { ReactNode, useEffect } from "react";
import { RuntimeContext } from "./interface";
import { RuntimeLang } from "./languages";
+import { DartProvider, useDart } from "./dart/runtime";
import { TypeScriptProvider, useTypeScript } from "./typescript/runtime";
import { useWandbox, WandboxProvider } from "./wandbox/runtime";
import { JSEvalContext, useJSEval } from "./worker/jsEval";
@@ -34,6 +35,7 @@ export function useRuntimeAll(): Record {
const typescript = useTypeScript(jsEval);
const wandboxCpp = useWandbox("cpp");
const wandboxRust = useWandbox("rust");
+ const dart = useDart();
// initはしない。呼び出し側でする必要がある
return {
@@ -43,6 +45,7 @@ export function useRuntimeAll(): Record {
typescript: typescript,
cpp: wandboxCpp,
rust: wandboxRust,
+ dart: dart,
};
}
export function RuntimeProvider({ children }: { children: ReactNode }) {
@@ -51,10 +54,13 @@ export function RuntimeProvider({ children }: { children: ReactNode }) {
- {children}
+
+ {children}
+
);
}
+
diff --git a/packages/runtime/src/dart/runtime.tsx b/packages/runtime/src/dart/runtime.tsx
new file mode 100644
index 00000000..dabf52fa
--- /dev/null
+++ b/packages/runtime/src/dart/runtime.tsx
@@ -0,0 +1,299 @@
+"use client";
+
+import {
+ createContext,
+ ReactNode,
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useRef,
+} from "react";
+import useSWR from "swr";
+import {
+ ReplOutput,
+ RuntimeContext,
+ RuntimeErrorHandler,
+ RuntimeInfo,
+ UpdatedFile,
+} from "../interface";
+
+const DART_PAD_API_BASE = "https://stable.api.dartpad.dev/api/v3";
+const DART_PAD_ARTIFACTS_BASE = "https://stable.api.dartpad.dev/artifacts";
+
+interface DartVersionResponse {
+ dartVersion?: string;
+ flutterVersion?: string;
+}
+
+const versionFetcher = async (url: string): Promise => {
+ const res = await fetch(url);
+ if (!res.ok) {
+ throw new Error(`Failed to fetch Dart version: ${res.statusText}`);
+ }
+ return res.json();
+};
+
+const DartContext = createContext<{
+ init: (onError?: RuntimeErrorHandler) => void;
+ ready: boolean;
+ dartVersion?: string;
+}>({
+ init: () => undefined,
+ ready: true,
+});
+
+export function DartProvider({ children }: { children: ReactNode }) {
+ const onErrorRef = useRef(undefined);
+ const init = useCallback((onError?: RuntimeErrorHandler) => {
+ onErrorRef.current = onError;
+ }, []);
+
+ const { data, error } = useSWR(
+ `${DART_PAD_API_BASE}/version`,
+ versionFetcher
+ );
+
+ useEffect(() => {
+ if (error) {
+ console.error("Failed to fetch Dart version info:", error);
+ onErrorRef.current?.(error);
+ }
+ }, [error]);
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useDart(): RuntimeContext {
+ const { init: dartInit, ready, dartVersion } = useContext(DartContext);
+ const onErrorRef = useRef(undefined);
+
+ const init = useCallback(
+ (onError?: RuntimeErrorHandler) => {
+ onErrorRef.current = onError;
+ dartInit(onError);
+ },
+ [dartInit]
+ );
+
+ const runFiles = useCallback(
+ async (
+ filenames: string[],
+ files: Readonly>,
+ onOutput: (output: ReplOutput | UpdatedFile) => void
+ ) => {
+ if (typeof window === "undefined") {
+ onOutput({
+ type: "error",
+ message: "Dart runtime requires browser environment.",
+ });
+ return;
+ }
+
+ const filename = filenames[0] ?? Object.keys(files)[0];
+ const source = files[filename] ?? Object.values(files)[0];
+
+ if (!source) {
+ onOutput({ type: "error", message: "No source code provided to run." });
+ return;
+ }
+
+ try {
+ const response = await fetch(`${DART_PAD_API_BASE}/compileNewDDC`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ source }),
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ onOutput({
+ type: "error",
+ message:
+ errorText ||
+ `Compilation failed with status ${response.status}`,
+ });
+ return;
+ }
+
+ const data = await response.json();
+ if (!data.result) {
+ onOutput({
+ type: "error",
+ message: "Compilation returned empty result.",
+ });
+ return;
+ }
+
+ const jsCode: string = data.result;
+
+ // Execute compiled JS inside a temporary iframe
+ await new Promise((resolve) => {
+ const iframe = document.createElement("iframe");
+ iframe.style.display = "none";
+ document.body.appendChild(iframe);
+
+ let resolved = false;
+ const cleanup = () => {
+ if (resolved) return;
+ resolved = true;
+ window.removeEventListener("message", handleMessage);
+ if (iframe.parentNode) {
+ iframe.parentNode.removeChild(iframe);
+ }
+ resolve();
+ };
+
+ const handleMessage = (event: MessageEvent) => {
+ if (event.source !== iframe.contentWindow) return;
+ const msgData = event.data;
+ if (!msgData || msgData.sender !== "dart_frame") return;
+
+ if (msgData.type === "stdout") {
+ onOutput({ type: "stdout", message: String(msgData.message) });
+ } else if (msgData.type === "stderr") {
+ onOutput({ type: "stderr", message: String(msgData.message) });
+ } else if (msgData.type === "done") {
+ cleanup();
+ } else if (msgData.type === "error") {
+ onOutput({ type: "error", message: String(msgData.message) });
+ cleanup();
+ }
+ };
+
+ window.addEventListener("message", handleMessage);
+
+ const iframeDoc = iframe.contentDocument;
+ if (!iframeDoc) {
+ onOutput({
+ type: "error",
+ message: "Failed to access iframe document.",
+ });
+ cleanup();
+ return;
+ }
+
+ const htmlContent = `
+
+
+
+
+
+
+
+`;
+
+ iframeDoc.open();
+ iframeDoc.write(htmlContent);
+ iframeDoc.close();
+
+ setTimeout(() => {
+ cleanup();
+ }, 15000);
+ });
+ } catch (error) {
+ onErrorRef.current?.(error);
+ onOutput({
+ type: "fatalError",
+ message: error instanceof Error ? error.message : String(error),
+ });
+ }
+ },
+ []
+ );
+
+ const runtimeInfo = useMemo(
+ () => ({
+ prettyLangName: "Dart",
+ version: dartVersion,
+ }),
+ [dartVersion]
+ );
+
+ return {
+ init,
+ ready,
+ runFiles,
+ getCommandlineStr,
+ runtimeInfo,
+ };
+}
+
+function getCommandlineStr(filenames: string[]) {
+ return `dart run ${filenames[0] ?? "main.dart"}`;
+}
diff --git a/packages/runtime/src/languages.ts b/packages/runtime/src/languages.ts
index 3c2ceb72..2b4ff665 100644
--- a/packages/runtime/src/languages.ts
+++ b/packages/runtime/src/languages.ts
@@ -22,7 +22,8 @@ export type MarkdownLang =
| "makefile"
| "cmake"
| "text"
- | "txt";
+ | "txt"
+ | "dart";
export type RuntimeLang =
| "python"
@@ -30,7 +31,8 @@ export type RuntimeLang =
| "cpp"
| "rust"
| "javascript"
- | "typescript";
+ | "typescript"
+ | "dart";
export type LangConstants = {
originalLang: MarkdownLang | undefined;
@@ -50,7 +52,8 @@ export type LangConstants = {
| "json"
| "ini"
| "makefile"
- | "cmake";
+ | "cmake"
+ | "dart";
} & (
| {
// terminal/editor.tsx でimportする mode-xxxx.js のファイル名と、AceEditorの mode プロパティの値と対応する
@@ -63,7 +66,8 @@ export type LangConstants = {
| "typescript"
| "json"
| "csv"
- | "text";
+ | "text"
+ | "dart";
tabSize: number;
}
| {
@@ -158,6 +162,14 @@ export function langConstants(lang: MarkdownLang | undefined): LangConstants {
tabSize: 4,
runtime: "rust",
};
+ case "dart":
+ return {
+ originalLang: lang,
+ rsh: "dart",
+ ace: "dart",
+ tabSize: 2,
+ runtime: "dart",
+ };
case "bash":
case "sh":
return { originalLang: lang, rsh: "bash" };
@@ -198,3 +210,4 @@ export function langConstants(lang: MarkdownLang | undefined): LangConstants {
return { originalLang: lang };
}
}
+
diff --git a/packages/runtime/tests/fileExecution.ts b/packages/runtime/tests/fileExecution.ts
index ee1b9617..88542853 100644
--- a/packages/runtime/tests/fileExecution.ts
+++ b/packages/runtime/tests/fileExecution.ts
@@ -20,6 +20,7 @@ export const fileExecutionTests: Record<
rust: ["test.rs", `fn main() {\n println!("${msg}");\n}\n`],
javascript: ["test.js", `console.log("${msg}")`],
typescript: ["test.ts", `console.log("${msg}")`],
+ dart: ["main.dart", `void main() {\n print("${msg}");\n}\n`],
} satisfies Record
)[lang];
if (!filename || !code) return null;
@@ -53,6 +54,10 @@ export const fileExecutionTests: Record<
rust: ["test_error.rs", `fn main() {\n panic!("${errorMsg}");\n}\n`],
javascript: ["test_error.js", `throw new Error("${errorMsg}");\n`],
typescript: ["test_error.ts", `throw new Error("${errorMsg}");\n`],
+ dart: [
+ "test_error.dart",
+ `void main() {\n throw Exception("${errorMsg}");\n}\n`,
+ ],
} satisfies Record
)[lang];
if (!filename || !code) return null;
@@ -114,6 +119,7 @@ export const fileExecutionTests: Record<
],
javascript: [null, null],
typescript: [null, null],
+ dart: [null, null],
} satisfies Record<
RuntimeLang,
[Record, string[]] | [null, null]
@@ -148,6 +154,7 @@ export const fileExecutionTests: Record<
rust: [null, null],
javascript: [null, null],
typescript: [null, null],
+ dart: [null, null],
} satisfies Record
)[lang];
if (!filename || !code) return null;
diff --git a/packages/runtime/tests/repl.ts b/packages/runtime/tests/repl.ts
index e47d5da3..999ff2b4 100644
--- a/packages/runtime/tests/repl.ts
+++ b/packages/runtime/tests/repl.ts
@@ -19,6 +19,7 @@ export const replTests: Record TestBody | null> =
rust: null,
javascript: `console.log("${msg}")`,
typescript: null,
+ dart: null,
} satisfies Record
)[lang];
if (!printCode) return null;
@@ -49,6 +50,7 @@ export const replTests: Record TestBody | null> =
`console.log(${varName})`,
],
typescript: [null, null],
+ dart: [null, null],
} satisfies Record
)[lang];
if (!setIntVarCode || !printIntVarCode) return null;
@@ -87,6 +89,7 @@ export const replTests: Record TestBody | null> =
rust: null,
javascript: `throw new Error("${errorMsg}")`,
typescript: null,
+ dart: null,
} satisfies Record
)[lang];
if (!errorCode) return null;
@@ -118,6 +121,7 @@ export const replTests: Record TestBody | null> =
`console.log(testVar)`,
],
typescript: [null, null, null],
+ dart: [null, null, null],
} satisfies Record
)[lang];
if (!setIntVarCode || !infLoopCode || !printIntVarCode) return null;
@@ -168,6 +172,7 @@ export const replTests: Record TestBody | null> =
rust: null,
javascript: null,
typescript: null,
+ dart: null,
} satisfies Record
)[lang];
if (!writeCode) return null;
diff --git a/packages/runtime/tests/utils.ts b/packages/runtime/tests/utils.ts
index f9878cb0..15c98d29 100644
--- a/packages/runtime/tests/utils.ts
+++ b/packages/runtime/tests/utils.ts
@@ -9,6 +9,7 @@ export const RUNTIME_TIMEOUTS: Record = {
typescript: 2000,
cpp: 10000,
rust: 20000,
+ dart: 15000,
};
export async function waitForRuntimeReady(
From bab04f9497b0bbac8c9629558c959e7589516920 Mon Sep 17 00:00:00 2001
From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com>
Date: Mon, 3 Aug 2026 02:59:41 +0900
Subject: [PATCH 2/6] =?UTF-8?q?DartPad=20=E3=81=AE=E9=9D=99=E7=9A=84?=
=?UTF-8?q?=E8=A7=A3=E6=9E=90=20API=E3=81=AE=E5=91=BC=E3=81=B3=E5=87=BA?=
=?UTF-8?q?=E3=81=97=E5=87=A6=E7=90=86=E3=82=92=E8=BF=BD=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
`performAnalysis` の追加
- 解析結果に含まれるエラー・警告・情報(`issues`)を、行・列番号および修正提案(`correction`)を含めたフォーマットで出力コールバック (`onOutput`) に渡します。
---
packages/runtime/src/dart/runtime.tsx | 71 ++++++++++++++++++++++++---
1 file changed, 64 insertions(+), 7 deletions(-)
diff --git a/packages/runtime/src/dart/runtime.tsx b/packages/runtime/src/dart/runtime.tsx
index dabf52fa..13698da8 100644
--- a/packages/runtime/src/dart/runtime.tsx
+++ b/packages/runtime/src/dart/runtime.tsx
@@ -26,6 +26,25 @@ interface DartVersionResponse {
flutterVersion?: string;
}
+interface AnalysisIssue {
+ kind: "error" | "warning" | "info";
+ message: string;
+ location: {
+ charStart: number;
+ charLength: number;
+ line: number;
+ column: number;
+ };
+ code?: string;
+ correction?: string;
+ url?: string;
+}
+
+interface AnalysisResponse {
+ issues: AnalysisIssue[];
+ imports?: unknown[];
+}
+
const versionFetcher = async (url: string): Promise => {
const res = await fetch(url);
if (!res.ok) {
@@ -74,6 +93,41 @@ export function DartProvider({ children }: { children: ReactNode }) {
);
}
+async function performAnalysis(
+ source: string,
+ onOutput: (output: ReplOutput | UpdatedFile) => void
+): Promise {
+ try {
+ const res = await fetch(`${DART_PAD_API_BASE}/analyze`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ source }),
+ });
+
+ if (!res.ok) return;
+
+ const data: AnalysisResponse = await res.json();
+ if (Array.isArray(data.issues)) {
+ for (const issue of data.issues) {
+ const line = issue.location?.line ?? 1;
+ const column = issue.location?.column ?? 1;
+ const kindStr = (issue.kind || "info").toUpperCase();
+ const correctionStr = issue.correction ? ` (${issue.correction})` : "";
+ const formattedMsg = `[ANALYZER ${kindStr}] line ${line}:${column} - ${issue.message}${correctionStr}`;
+
+ onOutput({
+ type: issue.kind === "error" ? "error" : "stderr",
+ message: formattedMsg,
+ });
+ }
+ }
+ } catch (err) {
+ console.warn("Failed to perform Dart static analysis:", err);
+ }
+}
+
export function useDart(): RuntimeContext {
const { init: dartInit, ready, dartVersion } = useContext(DartContext);
const onErrorRef = useRef(undefined);
@@ -109,13 +163,16 @@ export function useDart(): RuntimeContext {
}
try {
- const response = await fetch(`${DART_PAD_API_BASE}/compileNewDDC`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({ source }),
- });
+ const [_, response] = await Promise.all([
+ performAnalysis(source, onOutput),
+ fetch(`${DART_PAD_API_BASE}/compileNewDDC`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ source }),
+ }),
+ ]);
if (!response.ok) {
const errorText = await response.text();
From 0147fe2f65609b86e7650ed6659a593a2c87aba3 Mon Sep 17 00:00:00 2001
From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com>
Date: Mon, 3 Aug 2026 04:32:17 +0900
Subject: [PATCH 3/6] =?UTF-8?q?interrupt=E5=AE=9F=E8=A3=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/runtime/src/dart/runtime.tsx | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/packages/runtime/src/dart/runtime.tsx b/packages/runtime/src/dart/runtime.tsx
index 13698da8..b94bcdac 100644
--- a/packages/runtime/src/dart/runtime.tsx
+++ b/packages/runtime/src/dart/runtime.tsx
@@ -131,6 +131,7 @@ async function performAnalysis(
export function useDart(): RuntimeContext {
const { init: dartInit, ready, dartVersion } = useContext(DartContext);
const onErrorRef = useRef(undefined);
+ const activeIframeRef = useRef(null);
const init = useCallback(
(onError?: RuntimeErrorHandler) => {
@@ -140,6 +141,15 @@ export function useDart(): RuntimeContext {
[dartInit]
);
+ const interrupt = useCallback(() => {
+ if (activeIframeRef.current) {
+ if (activeIframeRef.current.parentNode) {
+ activeIframeRef.current.parentNode.removeChild(activeIframeRef.current);
+ }
+ activeIframeRef.current = null;
+ }
+ }, []);
+
const runFiles = useCallback(
async (
filenames: string[],
@@ -201,12 +211,16 @@ export function useDart(): RuntimeContext {
const iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
+ activeIframeRef.current = iframe;
let resolved = false;
const cleanup = () => {
if (resolved) return;
resolved = true;
window.removeEventListener("message", handleMessage);
+ if (activeIframeRef.current === iframe) {
+ activeIframeRef.current = null;
+ }
if (iframe.parentNode) {
iframe.parentNode.removeChild(iframe);
}
@@ -346,6 +360,7 @@ export function useDart(): RuntimeContext {
init,
ready,
runFiles,
+ interrupt,
getCommandlineStr,
runtimeInfo,
};
From 00f7bf767bf77f62b7646bd1176907af9c151c2f Mon Sep 17 00:00:00 2001
From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com>
Date: Fri, 7 Aug 2026 03:50:31 +0900
Subject: [PATCH 4/6] =?UTF-8?q?html=E3=82=92=E5=88=86=E9=9B=A2=E3=80=81req?=
=?UTF-8?q?uire.js=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6=E3=81=AFcdn?=
=?UTF-8?q?=E3=82=92=E4=BD=BF=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/runtime/src/dart/dart-runner.html | 130 +++++++++++++++++++++
packages/runtime/src/dart/runtime.tsx | 110 +++--------------
2 files changed, 144 insertions(+), 96 deletions(-)
create mode 100644 packages/runtime/src/dart/dart-runner.html
diff --git a/packages/runtime/src/dart/dart-runner.html b/packages/runtime/src/dart/dart-runner.html
new file mode 100644
index 00000000..b5d80e01
--- /dev/null
+++ b/packages/runtime/src/dart/dart-runner.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/runtime/src/dart/runtime.tsx b/packages/runtime/src/dart/runtime.tsx
index b94bcdac..3db0e63a 100644
--- a/packages/runtime/src/dart/runtime.tsx
+++ b/packages/runtime/src/dart/runtime.tsx
@@ -17,9 +17,9 @@ import {
RuntimeInfo,
UpdatedFile,
} from "../interface";
+import dartRunnerHtml from "./dart-runner.html?raw";
const DART_PAD_API_BASE = "https://stable.api.dartpad.dev/api/v3";
-const DART_PAD_ARTIFACTS_BASE = "https://stable.api.dartpad.dev/artifacts";
interface DartVersionResponse {
dartVersion?: string;
@@ -189,8 +189,7 @@ export function useDart(): RuntimeContext {
onOutput({
type: "error",
message:
- errorText ||
- `Compilation failed with status ${response.status}`,
+ errorText || `Compilation failed with status ${response.status}`,
});
return;
}
@@ -210,6 +209,7 @@ export function useDart(): RuntimeContext {
await new Promise((resolve) => {
const iframe = document.createElement("iframe");
iframe.style.display = "none";
+ iframe.srcdoc = dartRunnerHtml;
document.body.appendChild(iframe);
activeIframeRef.current = iframe;
@@ -234,11 +234,9 @@ export function useDart(): RuntimeContext {
if (msgData.type === "stdout") {
onOutput({ type: "stdout", message: String(msgData.message) });
- } else if (msgData.type === "stderr") {
- onOutput({ type: "stderr", message: String(msgData.message) });
} else if (msgData.type === "done") {
cleanup();
- } else if (msgData.type === "error") {
+ } else if (msgData.type === "jserr") {
onOutput({ type: "error", message: String(msgData.message) });
cleanup();
}
@@ -246,96 +244,16 @@ export function useDart(): RuntimeContext {
window.addEventListener("message", handleMessage);
- const iframeDoc = iframe.contentDocument;
- if (!iframeDoc) {
- onOutput({
- type: "error",
- message: "Failed to access iframe document.",
- });
- cleanup();
- return;
- }
-
- const htmlContent = `
-
-
-
-
-
-
-
-`;
-
- iframeDoc.open();
- iframeDoc.write(htmlContent);
- iframeDoc.close();
-
- setTimeout(() => {
- cleanup();
- }, 15000);
+ // iframeが読み込まれたら、コンパイル済みのコードを送信して実行させる
+ iframe.onload = () => {
+ iframe.contentWindow?.postMessage(
+ {
+ type: "EXECUTE_DART",
+ code: jsCode,
+ },
+ "*"
+ );
+ };
});
} catch (error) {
onErrorRef.current?.(error);
From 6e5b52fb8f33af8a606180bdf356007804cb3f3f Mon Sep 17 00:00:00 2001
From: na-trium-144 <100704180+na-trium-144@users.noreply.github.com>
Date: Fri, 14 Aug 2026 05:30:53 +0000
Subject: [PATCH 5/6] docs: add Dart tutorial with internal term links
---
packages/runtime/src/dart/runtime.tsx | 2 +-
public/docs/dart/0-intro/-intro.md | 5 ++
public/docs/dart/0-intro/1-0-features.md | 34 +++++++
public/docs/dart/0-intro/2-0-flutter.md | 40 +++++++++
public/docs/dart/0-intro/3-0-install.md | 64 +++++++++++++
public/docs/dart/0-intro/4-0-main.md | 57 ++++++++++++
public/docs/dart/1-basics/-intro.md | 4 +
public/docs/dart/1-basics/1-0-variables.md | 62 +++++++++++++
.../dart/1-basics/1-1-var-dynamic-object.md | 51 +++++++++++
public/docs/dart/1-basics/1-2-final-const.md | 63 +++++++++++++
.../docs/dart/1-basics/2-0-builtin-types.md | 89 ++++++++++++++++++
public/docs/dart/1-basics/2-1-operators.md | 85 ++++++++++++++++++
public/docs/dart/1-basics/3-0-summary.md | 18 ++++
public/docs/dart/1-basics/3-1-practice1.md | 26 ++++++
public/docs/dart/1-basics/3-2-practice2.md | 26 ++++++
public/docs/dart/10-async-stream/-intro.md | 5 ++
.../10-async-stream/1-0-stream-concepts.md | 51 +++++++++++
.../dart/10-async-stream/2-0-await-for.md | 67 ++++++++++++++
.../10-async-stream/3-0-stream-controller.md | 56 ++++++++++++
.../10-async-stream/4-0-async-generator.md | 51 +++++++++++
.../docs/dart/10-async-stream/5-0-summary.md | 17 ++++
.../dart/10-async-stream/5-1-practice1.md | 28 ++++++
.../dart/10-async-stream/5-2-practice2.md | 28 ++++++
public/docs/dart/11-error-handling/-intro.md | 6 ++
.../dart/11-error-handling/1-0-try-catch.md | 65 ++++++++++++++
.../docs/dart/11-error-handling/2-0-assert.md | 49 ++++++++++
.../11-error-handling/3-0-result-pattern.md | 70 +++++++++++++++
.../dart/11-error-handling/4-0-summary.md | 16 ++++
.../dart/11-error-handling/4-1-practice1.md | 29 ++++++
.../dart/11-error-handling/4-2-practice2.md | 29 ++++++
.../dart/12-concurrency-isolate/-intro.md | 7 ++
.../1-0-single-thread-model.md | 42 +++++++++
.../2-0-isolate-intro.md | 54 +++++++++++
.../3-0-isolate-ports.md | 74 +++++++++++++++
.../12-concurrency-isolate/4-0-summary.md | 22 +++++
.../12-concurrency-isolate/4-1-practice1.md | 29 ++++++
.../12-concurrency-isolate/4-2-practice2.md | 30 +++++++
public/docs/dart/2-null-safety/-intro.md | 6 ++
public/docs/dart/2-null-safety/1-0-types.md | 67 ++++++++++++++
.../dart/2-null-safety/2-0-null-assertion.md | 43 +++++++++
.../2-null-safety/3-0-null-aware-operators.md | 83 +++++++++++++++++
public/docs/dart/2-null-safety/4-0-late.md | 79 ++++++++++++++++
public/docs/dart/2-null-safety/5-0-summary.md | 21 +++++
.../docs/dart/2-null-safety/5-1-practice1.md | 26 ++++++
.../docs/dart/2-null-safety/5-2-practice2.md | 26 ++++++
public/docs/dart/3-functions/-intro.md | 6 ++
.../docs/dart/3-functions/1-0-first-class.md | 78 ++++++++++++++++
.../docs/dart/3-functions/2-0-parameters.md | 40 +++++++++
.../dart/3-functions/2-1-named-positional.md | 69 ++++++++++++++
.../3-functions/3-0-anonymous-closures.md | 79 ++++++++++++++++
public/docs/dart/3-functions/4-0-summary.md | 18 ++++
public/docs/dart/3-functions/4-1-practice1.md | 30 +++++++
public/docs/dart/3-functions/4-2-practice2.md | 27 ++++++
.../docs/dart/4-collections-control/-intro.md | 6 ++
.../4-collections-control/1-0-collections.md | 88 ++++++++++++++++++
.../2-0-collection-features.md | 87 ++++++++++++++++++
.../4-collections-control/3-0-higher-order.md | 76 ++++++++++++++++
.../dart/4-collections-control/4-0-summary.md | 17 ++++
.../4-collections-control/4-1-practice1.md | 32 +++++++
.../4-collections-control/4-2-practice2.md | 34 +++++++
public/docs/dart/5-records-patterns/-intro.md | 6 ++
.../dart/5-records-patterns/1-0-records.md | 69 ++++++++++++++
.../5-records-patterns/2-0-destructuring.md | 63 +++++++++++++
.../3-0-switch-expressions.md | 81 +++++++++++++++++
.../dart/5-records-patterns/4-0-guards.md | 47 ++++++++++
.../dart/5-records-patterns/5-0-summary.md | 17 ++++
.../dart/5-records-patterns/5-1-practice1.md | 27 ++++++
.../dart/5-records-patterns/5-2-practice2.md | 30 +++++++
public/docs/dart/6-classes/-intro.md | 6 ++
public/docs/dart/6-classes/1-0-classes.md | 52 +++++++++++
.../docs/dart/6-classes/2-0-constructors.md | 68 ++++++++++++++
.../dart/6-classes/3-0-initializer-super.md | 76 ++++++++++++++++
.../4-0-encapsulation-getter-setter.md | 71 +++++++++++++++
.../6-classes/5-0-factory-constructors.md | 90 +++++++++++++++++++
public/docs/dart/6-classes/6-0-summary.md | 18 ++++
public/docs/dart/6-classes/6-1-practice1.md | 29 ++++++
public/docs/dart/6-classes/6-2-practice2.md | 29 ++++++
public/docs/dart/7-class-extension/-intro.md | 5 ++
.../1-0-extends-implements.md | 66 ++++++++++++++
.../docs/dart/7-class-extension/2-0-mixins.md | 62 +++++++++++++
.../3-0-extension-methods.md | 56 ++++++++++++
.../7-class-extension/4-0-enhanced-enums.md | 56 ++++++++++++
.../dart/7-class-extension/5-0-summary.md | 17 ++++
.../dart/7-class-extension/5-1-practice1.md | 28 ++++++
.../dart/7-class-extension/5-2-practice2.md | 28 ++++++
public/docs/dart/8-class-modifiers/-intro.md | 5 ++
.../8-class-modifiers/1-0-sealed-classes.md | 68 ++++++++++++++
.../8-class-modifiers/2-0-other-modifiers.md | 61 +++++++++++++
.../8-class-modifiers/3-0-domain-modeling.md | 72 +++++++++++++++
.../dart/8-class-modifiers/4-0-summary.md | 18 ++++
.../dart/8-class-modifiers/4-1-practice1.md | 32 +++++++
.../dart/8-class-modifiers/4-2-practice2.md | 28 ++++++
public/docs/dart/9-async-future/-intro.md | 5 ++
.../dart/9-async-future/1-0-event-loop.md | 44 +++++++++
public/docs/dart/9-async-future/2-0-future.md | 57 ++++++++++++
.../dart/9-async-future/3-0-async-await.md | 75 ++++++++++++++++
.../4-0-async-error-handling.md | 60 +++++++++++++
.../docs/dart/9-async-future/5-0-summary.md | 18 ++++
.../docs/dart/9-async-future/5-1-practice1.md | 29 ++++++
.../docs/dart/9-async-future/5-2-practice2.md | 29 ++++++
public/docs/dart/index.yml | 42 +++++++++
101 files changed, 4228 insertions(+), 1 deletion(-)
create mode 100644 public/docs/dart/0-intro/-intro.md
create mode 100644 public/docs/dart/0-intro/1-0-features.md
create mode 100644 public/docs/dart/0-intro/2-0-flutter.md
create mode 100644 public/docs/dart/0-intro/3-0-install.md
create mode 100644 public/docs/dart/0-intro/4-0-main.md
create mode 100644 public/docs/dart/1-basics/-intro.md
create mode 100644 public/docs/dart/1-basics/1-0-variables.md
create mode 100644 public/docs/dart/1-basics/1-1-var-dynamic-object.md
create mode 100644 public/docs/dart/1-basics/1-2-final-const.md
create mode 100644 public/docs/dart/1-basics/2-0-builtin-types.md
create mode 100644 public/docs/dart/1-basics/2-1-operators.md
create mode 100644 public/docs/dart/1-basics/3-0-summary.md
create mode 100644 public/docs/dart/1-basics/3-1-practice1.md
create mode 100644 public/docs/dart/1-basics/3-2-practice2.md
create mode 100644 public/docs/dart/10-async-stream/-intro.md
create mode 100644 public/docs/dart/10-async-stream/1-0-stream-concepts.md
create mode 100644 public/docs/dart/10-async-stream/2-0-await-for.md
create mode 100644 public/docs/dart/10-async-stream/3-0-stream-controller.md
create mode 100644 public/docs/dart/10-async-stream/4-0-async-generator.md
create mode 100644 public/docs/dart/10-async-stream/5-0-summary.md
create mode 100644 public/docs/dart/10-async-stream/5-1-practice1.md
create mode 100644 public/docs/dart/10-async-stream/5-2-practice2.md
create mode 100644 public/docs/dart/11-error-handling/-intro.md
create mode 100644 public/docs/dart/11-error-handling/1-0-try-catch.md
create mode 100644 public/docs/dart/11-error-handling/2-0-assert.md
create mode 100644 public/docs/dart/11-error-handling/3-0-result-pattern.md
create mode 100644 public/docs/dart/11-error-handling/4-0-summary.md
create mode 100644 public/docs/dart/11-error-handling/4-1-practice1.md
create mode 100644 public/docs/dart/11-error-handling/4-2-practice2.md
create mode 100644 public/docs/dart/12-concurrency-isolate/-intro.md
create mode 100644 public/docs/dart/12-concurrency-isolate/1-0-single-thread-model.md
create mode 100644 public/docs/dart/12-concurrency-isolate/2-0-isolate-intro.md
create mode 100644 public/docs/dart/12-concurrency-isolate/3-0-isolate-ports.md
create mode 100644 public/docs/dart/12-concurrency-isolate/4-0-summary.md
create mode 100644 public/docs/dart/12-concurrency-isolate/4-1-practice1.md
create mode 100644 public/docs/dart/12-concurrency-isolate/4-2-practice2.md
create mode 100644 public/docs/dart/2-null-safety/-intro.md
create mode 100644 public/docs/dart/2-null-safety/1-0-types.md
create mode 100644 public/docs/dart/2-null-safety/2-0-null-assertion.md
create mode 100644 public/docs/dart/2-null-safety/3-0-null-aware-operators.md
create mode 100644 public/docs/dart/2-null-safety/4-0-late.md
create mode 100644 public/docs/dart/2-null-safety/5-0-summary.md
create mode 100644 public/docs/dart/2-null-safety/5-1-practice1.md
create mode 100644 public/docs/dart/2-null-safety/5-2-practice2.md
create mode 100644 public/docs/dart/3-functions/-intro.md
create mode 100644 public/docs/dart/3-functions/1-0-first-class.md
create mode 100644 public/docs/dart/3-functions/2-0-parameters.md
create mode 100644 public/docs/dart/3-functions/2-1-named-positional.md
create mode 100644 public/docs/dart/3-functions/3-0-anonymous-closures.md
create mode 100644 public/docs/dart/3-functions/4-0-summary.md
create mode 100644 public/docs/dart/3-functions/4-1-practice1.md
create mode 100644 public/docs/dart/3-functions/4-2-practice2.md
create mode 100644 public/docs/dart/4-collections-control/-intro.md
create mode 100644 public/docs/dart/4-collections-control/1-0-collections.md
create mode 100644 public/docs/dart/4-collections-control/2-0-collection-features.md
create mode 100644 public/docs/dart/4-collections-control/3-0-higher-order.md
create mode 100644 public/docs/dart/4-collections-control/4-0-summary.md
create mode 100644 public/docs/dart/4-collections-control/4-1-practice1.md
create mode 100644 public/docs/dart/4-collections-control/4-2-practice2.md
create mode 100644 public/docs/dart/5-records-patterns/-intro.md
create mode 100644 public/docs/dart/5-records-patterns/1-0-records.md
create mode 100644 public/docs/dart/5-records-patterns/2-0-destructuring.md
create mode 100644 public/docs/dart/5-records-patterns/3-0-switch-expressions.md
create mode 100644 public/docs/dart/5-records-patterns/4-0-guards.md
create mode 100644 public/docs/dart/5-records-patterns/5-0-summary.md
create mode 100644 public/docs/dart/5-records-patterns/5-1-practice1.md
create mode 100644 public/docs/dart/5-records-patterns/5-2-practice2.md
create mode 100644 public/docs/dart/6-classes/-intro.md
create mode 100644 public/docs/dart/6-classes/1-0-classes.md
create mode 100644 public/docs/dart/6-classes/2-0-constructors.md
create mode 100644 public/docs/dart/6-classes/3-0-initializer-super.md
create mode 100644 public/docs/dart/6-classes/4-0-encapsulation-getter-setter.md
create mode 100644 public/docs/dart/6-classes/5-0-factory-constructors.md
create mode 100644 public/docs/dart/6-classes/6-0-summary.md
create mode 100644 public/docs/dart/6-classes/6-1-practice1.md
create mode 100644 public/docs/dart/6-classes/6-2-practice2.md
create mode 100644 public/docs/dart/7-class-extension/-intro.md
create mode 100644 public/docs/dart/7-class-extension/1-0-extends-implements.md
create mode 100644 public/docs/dart/7-class-extension/2-0-mixins.md
create mode 100644 public/docs/dart/7-class-extension/3-0-extension-methods.md
create mode 100644 public/docs/dart/7-class-extension/4-0-enhanced-enums.md
create mode 100644 public/docs/dart/7-class-extension/5-0-summary.md
create mode 100644 public/docs/dart/7-class-extension/5-1-practice1.md
create mode 100644 public/docs/dart/7-class-extension/5-2-practice2.md
create mode 100644 public/docs/dart/8-class-modifiers/-intro.md
create mode 100644 public/docs/dart/8-class-modifiers/1-0-sealed-classes.md
create mode 100644 public/docs/dart/8-class-modifiers/2-0-other-modifiers.md
create mode 100644 public/docs/dart/8-class-modifiers/3-0-domain-modeling.md
create mode 100644 public/docs/dart/8-class-modifiers/4-0-summary.md
create mode 100644 public/docs/dart/8-class-modifiers/4-1-practice1.md
create mode 100644 public/docs/dart/8-class-modifiers/4-2-practice2.md
create mode 100644 public/docs/dart/9-async-future/-intro.md
create mode 100644 public/docs/dart/9-async-future/1-0-event-loop.md
create mode 100644 public/docs/dart/9-async-future/2-0-future.md
create mode 100644 public/docs/dart/9-async-future/3-0-async-await.md
create mode 100644 public/docs/dart/9-async-future/4-0-async-error-handling.md
create mode 100644 public/docs/dart/9-async-future/5-0-summary.md
create mode 100644 public/docs/dart/9-async-future/5-1-practice1.md
create mode 100644 public/docs/dart/9-async-future/5-2-practice2.md
create mode 100644 public/docs/dart/index.yml
diff --git a/packages/runtime/src/dart/runtime.tsx b/packages/runtime/src/dart/runtime.tsx
index 3db0e63a..0408ca5f 100644
--- a/packages/runtime/src/dart/runtime.tsx
+++ b/packages/runtime/src/dart/runtime.tsx
@@ -173,7 +173,7 @@ export function useDart(): RuntimeContext {
}
try {
- const [_, response] = await Promise.all([
+ const [, response] = await Promise.all([
performAnalysis(source, onOutput),
fetch(`${DART_PAD_API_BASE}/compileNewDDC`, {
method: "POST",
diff --git a/public/docs/dart/0-intro/-intro.md b/public/docs/dart/0-intro/-intro.md
new file mode 100644
index 00000000..4349a8a7
--- /dev/null
+++ b/public/docs/dart/0-intro/-intro.md
@@ -0,0 +1,5 @@
+他のプログラミング言語の経験がある皆さん、[[Dart]]の世界へようこそ。
+
+DartはGoogleによって開発された、クライアントサイド(モバイル・Web・デスクトップ)およびサーバーサイドで幅広く活用されているモダンなオブジェクト指向言語です。特にクロスプラットフォームフレームワークである[[Flutter]]の開発言語として急速に普及しました。
+
+この章では、Dartがどのような言語思想で作られ、どのような特徴を持っているかを概観し、Dartプログラムのエントリーポイントとなる [[`main`関数]] の書き方を学びます。
diff --git a/public/docs/dart/0-intro/1-0-features.md b/public/docs/dart/0-intro/1-0-features.md
new file mode 100644
index 00000000..beac672d
--- /dev/null
+++ b/public/docs/dart/0-intro/1-0-features.md
@@ -0,0 +1,34 @@
+---
+id: dart-intro-features
+title: Dartの特徴(JIT/AOTコンパイル、UI最適化言語)
+level: 2
+question:
+ - JITコンパイルとAOTコンパイルの両方をサポートしているメリットは何ですか?
+ - なぜDartはUI開発に最適化された言語と言われるのですか?
+ - JavaScriptやTypeScriptと比べたDartの強みは何ですか?
+term:
+ - Dart
+ - JITコンパイル
+ - AOTコンパイル
+ - JIT
+ - AOT
+---
+
+## Dartの特徴(JIT/AOTコンパイル、UI最適化言語)
+
+[[Dart]]は、美しく高速なユーザーインターフェース(UI)を構築するために設計された、オブジェクト指向の型安全なプログラミング言語です。
+
+### 1. JITとAOTのハイブリッドな実行基盤
+
+Dart最大の特徴の1つは、**[[JITコンパイル]](Just-In-Time)** と **[[AOTコンパイル]](Ahead-Of-Time)** の両方に対応している点です。
+
+* **開発時(JIT)**: ソースコードを実行時に即座に解釈・コンパイルします。これにより、コード変更を瞬時にアプリへ反映する**ホットリロード(Hot Reload)**が可能になり、開発サイクルが劇的に高速化します。
+* **リリース時(AOT)**: 各プラットフォーム(ARMやx86のネイティブ機械語、あるいは最適化されたJavaScript/WebAssembly)へ事前にコンパイルします。起動の速さとなめらかな描画フレームレート(60fps / 120fps)を実現します。
+
+### 2. UI構築に最適化された言語機能
+
+Dartはユーザーインターフェースのツリー構造を宣言的に記述しやすくするため、言語仕様レベルで多くの工夫が施されています。
+
+* **オブジェクト生成時の `new` 省略**: ネストしたUIコンポーネントをスッキリ記述できます。
+* **コレクション要素内の制御構文**: 配列やリストの内部で直接 `if` や `for`、スプレッド演算子(`...`)が使えます([[./4]]で学習)。
+* **健全な型システムと[[Null Safety]]**: 実行時クラッシュの原因となりやすいNull関連エラーをコンパイル時に検知します([[./2]]で学習)。
diff --git a/public/docs/dart/0-intro/2-0-flutter.md b/public/docs/dart/0-intro/2-0-flutter.md
new file mode 100644
index 00000000..1ff34125
--- /dev/null
+++ b/public/docs/dart/0-intro/2-0-flutter.md
@@ -0,0 +1,40 @@
+---
+id: dart-intro-flutter
+title: DartとFlutter
+level: 2
+question:
+ - DartとFlutterの関係はどうなっていますか?
+ - Flutter以外の場所でもDartは使えますか?
+ - Dart単体でサーバーサイドアプリケーションを書くことはできますか?
+term:
+ - Flutter
+ - フラッター
+ - マルチプラットフォーム
+---
+
+## DartとFlutter
+
+[[Dart]]の存在を語る上で欠かせないのが、UIフレームワークである **[[Flutter]]** です。
+
+Flutterは、単一のコードベースからiOS、Android、Web、macOS、Windows、Linux向けの高性能なアプリケーションをビルドできる[[マルチプラットフォーム]]フレームワークです。
+
+```
++-------------------------------------------------------------+
+| Flutter Framework (Dart製UIライブラリ) |
+| (Widgets, Rendering, Animation, Material, Cupertino) |
++-------------------------------------------------------------+
+| Dart Platform (言語・ランタイム・標準ライブラリ) |
+| (Core, Async, Collections, Math, I/O, Isolates) |
++-------------------------------------------------------------+
+| Flutter Engine (C++ / Skia・Impeller) |
++-------------------------------------------------------------+
+```
+
+### DartがFlutterに選ばれた理由
+
+1. **高速な開発体験**: JITによるミリ秒単位のステートフル・ホットリロード。
+2. **高い実行時パフォーマンス**: AOTコンパイルによるネイティブバイナリの生成と、UIの頻繁なオブジェクト生成・破棄に特化した世代別ガベージコレクション。
+3. **宣言的UIとの親和性**: 特別なマークアップ言語(XMLやJSXなど)を必要とせず、Dart言語そのものでUIツリーをきれいに記述可能。
+
+> [!NOTE]
+> DartはFlutter専用言語ではありません。`dart:io` や `shelf` などのライブラリを用いてCLIツールやバックエンドAPIサーバーの開発にも活用されています。
diff --git a/public/docs/dart/0-intro/3-0-install.md b/public/docs/dart/0-intro/3-0-install.md
new file mode 100644
index 00000000..a34f1470
--- /dev/null
+++ b/public/docs/dart/0-intro/3-0-install.md
@@ -0,0 +1,64 @@
+---
+id: dart-intro-install
+title: Dartのインストール
+level: 2
+question:
+ - FlutterをインストールすればDart SDKも一緒に含まれますか?
+ - Dart公式のパッケージマネージャは何ですか?
+ - pubspec.yaml とは何をするファイルですか?
+term:
+ - Dart SDK
+ - dart コマンド
+ - pub
+ - pubspec.yaml
+---
+
+## Dartのインストール
+
+ローカル環境で[[Dart]]を動作させるには、**[[Dart SDK]]** をインストールします。
+
+> [!TIP]
+> 既に [[Flutter]] をインストールしている場合、Flutter SDKにDart SDKがバンドルされているため、個別のDartインストールは不要です。
+
+### 1. インストール方法
+
+* **macOS (Homebrew)**:
+ ```bash
+ brew tap dart-lang/dart
+ brew install dart
+ ```
+* **Windows (Chocolatey / Scoop / Winget)**:
+ ```bash
+ winget install Dart.Dart-SDK
+ ```
+* **Linux (apt)**:
+ ```bash
+ sudo apt-get install dart
+ ```
+
+### 2. インストールの確認
+
+ターミナルで `dart` コマンドを実行し、バージョンが表示されるか確認します。
+
+```bash
+$ dart --version
+Dart SDK version: 3.x.x
+```
+
+### 3. プロジェクトの作成と実行
+
+Dartでは、プロジェクト作成や依存関係管理、コード整形、テストなどのツールチェーンがすべて `dart` コマンドに統合されています。
+
+```bash
+# 新しいコンソールプロジェクトを作成
+$ dart create my_dart_app
+
+# プロジェクトディレクトリへ移動
+$ cd my_dart_app
+
+# プログラムの実行
+$ dart run
+Hello world: 42!
+```
+
+Dartのプロジェクト構成やライブラリの依存管理は、プロジェクトルートにある `pubspec.yaml` ファイルで行います。
diff --git a/public/docs/dart/0-intro/4-0-main.md b/public/docs/dart/0-intro/4-0-main.md
new file mode 100644
index 00000000..10efad13
--- /dev/null
+++ b/public/docs/dart/0-intro/4-0-main.md
@@ -0,0 +1,57 @@
+---
+id: dart-intro-main
+title: 'エントリーポイント: main() 関数'
+level: 2
+question:
+ - main関数の戻り値型はvoid以外も使えますか?
+ - コマンドライン引数をmain関数で受け取るにはどうすればよいですか?
+ - print関数で改行なしの出力を行うことはできますか?
+term:
+ - main関数
+ - main()
+ - print
+ - print関数
+---
+
+## エントリーポイント: `main()` 関数
+
+C言語、Java、Rustなどと同様に、[[Dart]]プログラムはトップレベルの **[[main関数]](`main()`)** から実行が始まります。
+
+まずは最もシンプルな "Hello, World!" プログラムを見てみましょう。
+
+```dart:hello_world.dart
+void main() {
+ print('Hello, Dart!');
+}
+```
+
+```dart-exec:hello_world.dart
+Hello, Dart!
+```
+
+### コードの解説
+
+* `void`: `main` 関数が値を返さないことを表します。
+* `main()`: アプリケーションのエントリーポイントとなる関数名です。
+* `print(...)`: 文字列などのオブジェクトを標準出力に出力し、末尾に改行を追加します。
+* `;` (セミコロン): Dartでは各ステートメントの末尾にセミコロンが必須です。
+
+### コマンドライン引数の受け取り
+
+外部からの引数を受け取る場合は、引数に `List args` を指定します。
+
+```dart:args_example.dart
+void main(List args) {
+ if (args.isEmpty) {
+ print('引数が渡されていません。');
+ } else {
+ print('受け取った引数: $args');
+ }
+}
+```
+
+```dart-exec:args_example.dart
+引数が渡されていません。
+```
+
+次の [[./1]] では、Dartの型システム、変数宣言、および基本的な演算子について詳しく学んでいきます。
diff --git a/public/docs/dart/1-basics/-intro.md b/public/docs/dart/1-basics/-intro.md
new file mode 100644
index 00000000..5131fee1
--- /dev/null
+++ b/public/docs/dart/1-basics/-intro.md
@@ -0,0 +1,4 @@
+この章では、[[Dart]]の基本的な文法と型システムについて学びます。
+
+Dartは静的型付け言語ですが、優れた[[型推論]]を備えており、冗長な型記述を避けつつ型安全性を保つことができます。
+また、他の言語とは一味違う `var`, `dynamic`, `Object`, `final`, `const` などのキーワードの使い分けを理解することで、堅牢で読みやすいコードの土台を築きます。
diff --git a/public/docs/dart/1-basics/1-0-variables.md b/public/docs/dart/1-basics/1-0-variables.md
new file mode 100644
index 00000000..af04e9a8
--- /dev/null
+++ b/public/docs/dart/1-basics/1-0-variables.md
@@ -0,0 +1,62 @@
+---
+id: dart-basics-variables
+title: 変数宣言と型推論
+level: 2
+question:
+ - 型を明示する場合とvarを使う場合の使い分けの目安はありますか?
+ - 初期化せずに変数宣言したときの初期値は何ですか?
+ - Dartで変数名に使える命名規則はどうなっていますか?
+term:
+ - 変数
+ - 変数宣言
+ - 型推論
+---
+
+## 変数宣言と型推論
+
+[[Dart]]は静的型付け言語ですが、初期値から型を自動で推論する **[[型推論]]** を強力にサポートしています。
+
+変数を宣言する方法は、主に以下の2通りがあります。
+
+### 1. `var` による型推論
+
+初期値が存在する場合、`var` キーワードを使うとコンパイラが自動的に型を決定します。
+
+```dart:variables_intro.dart
+void main() {
+ var name = 'Dart'; // String 型と推論される
+ var version = 3; // int 型と推論される
+
+ print('$name のバージョン: $version');
+}
+```
+
+```dart-exec:variables_intro.dart
+Dart のバージョン: 3
+```
+
+一度型が推論された変数に、異なる型の値を代入しようとするとコンパイルエラーになります。
+
+```dart
+var score = 100;
+// score = '満点'; // コンパイルエラー: A value of type 'String' can't be assigned to a variable of type 'int'.
+```
+
+### 2. 型を明示する宣言
+
+型を明示的に記述することも可能です。変数の意図をコード上で強調したい場合や、初期値を後から代入する場合に使われます。
+
+```dart:type_explicit.dart
+void main() {
+ String message = 'Hello';
+ int count = 10;
+ double price = 99.9;
+ bool isActive = true;
+
+ print('$message: $count 件, 価格: $price 円, 有効: $isActive');
+}
+```
+
+```dart-exec:type_explicit.dart
+Hello: 10 件, 価格: 99.9 円, 有効: true
+```
diff --git a/public/docs/dart/1-basics/1-1-var-dynamic-object.md b/public/docs/dart/1-basics/1-1-var-dynamic-object.md
new file mode 100644
index 00000000..010ead1b
--- /dev/null
+++ b/public/docs/dart/1-basics/1-1-var-dynamic-object.md
@@ -0,0 +1,51 @@
+---
+id: dart-basics-var-dynamic-object
+title: 'var、dynamic、Object の違い'
+level: 3
+question:
+ - dynamicとObjectの違いは何ですか?
+ - dynamic型を使うべきシチュエーションはどのようなときですか?
+ - varで宣言した変数を初期化しなかった場合はどうなりますか?
+term:
+ - var
+ - dynamic
+ - Object
+ - 動的型
+---
+
+### `var`、`dynamic`、`Object` の違い
+
+Dartには一見似ているように思える `var`, `dynamic`, `Object` というキーワードが存在します。これらは型安全性において決定的な違いがあります。
+
+| キーワード | 静的型チェック | 別の型の再代入 | メンバーアクセス |
+| :--- | :--- | :--- | :--- |
+| **`var` (初期化あり)** | あり (初期値から固定) | 不可 | 推論された型のメソッドのみ |
+| **`dynamic`** | なし (実行時に解決) | 可能 | なんでも呼べる (存在しなければ実行時エラー) |
+| **`Object` / `Object?`** | あり (すべての型の基底) | 可能 | `Object` が持つメソッド (`toString()` 等) のみ |
+
+```dart:dynamic_vs_object.dart
+void main() {
+ // 1. dynamic: 静的型チェックを完全にバイパスする
+ dynamic value = 'Hello';
+ print('dynamic: ${value.length}'); // 実行可能
+ value = 123; // 異なる型の再代入もOK
+ print('dynamic(int): $value');
+
+ // 2. Object: すべての非Nullオブジェクトの基底クラス (型安全)
+ Object obj = 'World';
+ // print(obj.length); // コンパイルエラー: Object型には length プロパティがない
+ if (obj is String) {
+ // 型チェック (is) を通すとスマートキャストされる
+ print('Object(String): ${obj.length}');
+ }
+}
+```
+
+```dart-exec:dynamic_vs_object.dart
+dynamic: 5
+dynamic(int): 123
+Object(String): 5
+```
+
+> [!WARNING]
+> `dynamic` は実行時までエラーが発覚しないため、JSONのデコードなど型が未知の境界領域以外では極力使用を避け、型安全なコードを心がけましょう。
diff --git a/public/docs/dart/1-basics/1-2-final-const.md b/public/docs/dart/1-basics/1-2-final-const.md
new file mode 100644
index 00000000..8a11ec58
--- /dev/null
+++ b/public/docs/dart/1-basics/1-2-final-const.md
@@ -0,0 +1,63 @@
+---
+id: dart-basics-final-const
+title: final と const の使い分け
+level: 3
+question:
+ - finalとconstの最も重要な違いは何ですか?
+ - DateTime.now()をconstに代入できないのはなぜですか?
+ - constコンストラクタを使うとFlutterでパフォーマンスが上がるのはなぜですか?
+term:
+ - final
+ - const
+ - コンパイル時定数
+ - 不変
+---
+
+### `final` と `const` の使い分け
+
+Dartで値の再代入を禁止する変数(定数)を宣言するには、`final` または `const` を使用します。
+
+### 1. `final`: 実行時定数(一度だけ代入可能)
+
+`final` で宣言された変数は、**実行時** に値が決まる定数です。一度代入した後は変更できません。
+
+```dart
+final currentTime = DateTime.now(); // 実行時の現在時刻を代入可能
+// currentTime = DateTime.now(); // エラー: 再代入不可
+```
+
+### 2. `const`: コンパイル時定数
+
+`const` は、**コンパイル時** に値が完全に確定している定数です。
+
+```dart
+const double pi = 3.1415926535;
+const int secondsInMinute = 60;
+// const currentTime = DateTime.now(); // コンパイルエラー: 実行時にしか決まらない
+```
+
+### 比較コード例
+
+```dart:final_const.dart
+void main() {
+ final now = DateTime.now();
+ const maxItems = 100;
+
+ // constリストは内容の変更も不可(ディープイミュータブル)
+ const list = [1, 2, 3];
+ // list.add(4); // 実行時エラー (Unsupported operation)
+
+ print('現在時刻 (final): $now');
+ print('最大件数 (const): $maxItems');
+ print('定数リスト: $list');
+}
+```
+
+```dart-exec:final_const.dart
+現在時刻 (final): 2026-08-14 05:20:00.000
+最大件数 (const): 100
+定数リスト: [1, 2, 3]
+```
+
+> [!TIP]
+> Flutterでは、不変なWidgetの生成に `const` を付与することで、フレーム再描画時にインスタンスが再生成されるのを防ぎ、メモリ消費とレンダリング負荷を大幅に削減できます。
diff --git a/public/docs/dart/1-basics/2-0-builtin-types.md b/public/docs/dart/1-basics/2-0-builtin-types.md
new file mode 100644
index 00000000..c8a49dfe
--- /dev/null
+++ b/public/docs/dart/1-basics/2-0-builtin-types.md
@@ -0,0 +1,89 @@
+---
+id: dart-basics-builtin-types
+title: 組み込み型と文字列操作
+level: 2
+question:
+ - int型とdouble型の共通の親クラスは何ですか?
+ - Dartで文字列補間(String Interpolation)はどう書きますか?
+ - 複数行の文字列(ヒアドキュメント)はどう定義しますか?
+term:
+ - 組み込み型
+ - int
+ - double
+ - num
+ - String
+ - bool
+ - 文字列補間
+---
+
+## 組み込み型と文字列操作
+
+[[Dart]]のすべての値はオブジェクトであり、数値や真偽値も含めて `Object` を継承しています。
+
+主要な組み込み型には以下があります。
+
+* **`int`**: 任意精度または64ビット符号付き整数。
+* **`double`**: 64ビット倍精度浮動小数点数。
+* **`num`**: `int` と `double` の親クラス。整数と小数の両方を許容したい場合に使用。
+* **`String`**: UTF-16コードユニットのシーケンス。
+* **`bool`**: 真偽値(`true` または `false`)。
+
+### 数値と型変換
+
+```dart:numbers.dart
+void main() {
+ int integer = 42;
+ double decimal = 3.14;
+ num both = 10;
+ both = 2.5; // num型ならdoubleも代入可能
+
+ // 文字列から数値への変換
+ int parsedInt = int.parse('100');
+ double parsedDouble = double.parse('12.34');
+
+ // 数値から文字列への変換
+ String strInt = integer.toString();
+ String fixedDec = decimal.toStringAsFixed(1); // "3.1"
+
+ print('parsed: $parsedInt, $parsedDouble');
+ print('converted: $strInt, $fixedDec');
+}
+```
+
+```dart-exec:numbers.dart
+parsed: 100, 12.34
+converted: 42, 3.1
+```
+
+### 文字列と文字列補間(String Interpolation)
+
+Dartでは、文字列リテラル内に `$変数名` や `${式}` を埋め込むことができます。シングルクォート `'` とダブルクォート `"` のどちらでも記述可能です。
+
+```dart:strings.dart
+void main() {
+ String language = 'Dart';
+ int version = 3;
+
+ // 文字列補間
+ String greeting = 'Welcome to $language $version!';
+ String calc = '1 + 1 = ${1 + 1}';
+
+ // 複数行文字列(トリプルクォート)
+ String multiLine = '''
+1行目のテキスト
+2行目のテキスト
+3行目のテキスト''';
+
+ print(greeting);
+ print(calc);
+ print(multiLine);
+}
+```
+
+```dart-exec:strings.dart
+Welcome to Dart 3!
+1 + 1 = 2
+1行目のテキスト
+2行目のテキスト
+3行目のテキスト
+```
diff --git a/public/docs/dart/1-basics/2-1-operators.md b/public/docs/dart/1-basics/2-1-operators.md
new file mode 100644
index 00000000..0b2d9efa
--- /dev/null
+++ b/public/docs/dart/1-basics/2-1-operators.md
@@ -0,0 +1,85 @@
+---
+id: dart-basics-operators
+title: 基本的な演算子
+level: 2
+question:
+ - 整数除算を行う演算子は何ですか?
+ - is や is! 演算子は何のために使われますか?
+ - 三項演算子やカスケード記法はどのように使いますか?
+term:
+ - 演算子
+ - 算術演算子
+ - 比較演算子
+ - 論理演算子
+ - 型テスト演算子
+ - 整数除算
+---
+
+## 基本的な演算子
+
+Dartには一般的な言語と同様の算術・比較・論理演算子に加えて、Dart特有の便利な演算子があります。
+
+### 1. 算術演算子と整数除算 (`~/`)
+
+通常の除算 `/` は常に `double` を返します。商の整数部分のみを取得したい場合は **`~/`**(整数除算演算子)を使います。
+
+```dart:operators_arithmetic.dart
+void main() {
+ int a = 10;
+ int b = 3;
+
+ print('加算 (+): ${a + b}');
+ print('通常除算 (/): ${a / b}'); // double (3.3333333333333335)
+ print('整数除算 (~/): ${a ~/ b}'); // int (3)
+ print('剰余 (%): ${a % b}'); // int (1)
+}
+```
+
+```dart-exec:operators_arithmetic.dart
+加算 (+): 13
+通常除算 (/): 3.3333333333333335
+整数除算 (~/): 3
+剰余 (%): 1
+```
+
+### 2. 型テスト演算子 (`is`, `is!`, `as`)
+
+オブジェクトが特定の型であるかを判定します。
+
+* `is`: 指定した型であれば `true`
+* `is!`: 指定した型でなければ `true`
+* `as`: 型キャスト(型が合わない場合は実行時エラー)
+
+```dart:type_test.dart
+void main() {
+ Object value = 'Dart Programming';
+
+ if (value is String) {
+ // ifスコープ内では value が String にスマートキャストされる
+ print('文字列の長さ: ${value.length}');
+ }
+
+ if (value is! int) {
+ print('value は int ではありません');
+ }
+}
+```
+
+```dart-exec:type_test.dart
+文字列の長さ: 16
+value は int ではありません
+```
+
+### 3. 三項条件演算子 (`condition ? expr1 : expr2`)
+
+```dart:ternary.dart
+void main() {
+ int score = 85;
+ String result = score >= 60 ? '合格' : '不合格';
+ print('結果: $result');
+}
+```
+
+```dart-exec:ternary.dart
+結果: 合格
+```
diff --git a/public/docs/dart/1-basics/3-0-summary.md b/public/docs/dart/1-basics/3-0-summary.md
new file mode 100644
index 00000000..3109410a
--- /dev/null
+++ b/public/docs/dart/1-basics/3-0-summary.md
@@ -0,0 +1,18 @@
+---
+id: dart-basics-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]の基本構文と型システムの基本を学びました。
+
+* **型推論と変数宣言**: `var` を使うと初期値から静的型が自動推論される。型を明示することも可能。
+* **`dynamic` と `Object`**: `dynamic` は型チェックを無効化し、`Object` は全オブジェクトの基底型として安全に扱える。
+* **`final` と `const`**: `final` は実行時に一度だけ初期化される不変変数、`const` はコンパイル時に確定する完全な定数。
+* **組み込み型**: `int`, `double`, `num`, `String`, `bool` が基本。文字列補間 `${}` が便利。
+* **便利な演算子**: 整数除算 `~/` や型判定 `is` によるスマートキャストを活用する。
+
+次の [[./2]] では、Dartを特徴づける最も重要な機能の1つである **[[Null Safety]]** について詳しく学びます。
diff --git a/public/docs/dart/1-basics/3-1-practice1.md b/public/docs/dart/1-basics/3-1-practice1.md
new file mode 100644
index 00000000..64021081
--- /dev/null
+++ b/public/docs/dart/1-basics/3-1-practice1.md
@@ -0,0 +1,26 @@
+---
+id: dart-basics-practice1
+title: '練習問題1: 変数と定数の使い分け'
+level: 3
+question:
+ - constとfinalを間違えて宣言した場合、コンパイラはどのようなエラーを出しますか?
+ - DateTime.now() の結果をconst変数に代入できない理由を復習したいです。
+---
+
+### 練習問題1: 変数と定数の使い分け
+
+以下の仕様を満たすDartプログラムを作成してください。
+
+1. 円周率を保持する定数 `pi` を `const` で定義(値は `3.14159`)。
+2. 半径を表す変数 `radius` を `var` で定義し、初期値 `5.0` を代入。
+3. 実行時の現在時刻を保持する定数 `createdAt` を `final` で定義(`DateTime.now()` を代入)。
+4. 円の面積($\text{radius} \times \text{radius} \times \pi$)を計算し、`createdAt` と共に文字列補間を使って出力する。
+
+```dart:practice1_1.dart
+void main() {
+ // ここにコードを書いてください
+}
+```
+
+```dart-exec:practice1_1.dart
+```
diff --git a/public/docs/dart/1-basics/3-2-practice2.md b/public/docs/dart/1-basics/3-2-practice2.md
new file mode 100644
index 00000000..6e6872d7
--- /dev/null
+++ b/public/docs/dart/1-basics/3-2-practice2.md
@@ -0,0 +1,26 @@
+---
+id: dart-basics-practice2
+title: '練習問題2: 型変換と計算'
+level: 3
+question:
+ - double.parse() で数値に変換できない文字列を渡すと何が起きますか?
+ - 整数除算 ~/ と通常の除算 / の使い分けを教えてください。
+---
+
+### 練習問題2: 型変換と計算
+
+文字列として受け取った価格と数量から、合計金額と一人あたりの支払額を計算するプログラムを作成してください。
+
+1. 文字列変数 `priceStr = "1280"` と `quantityStr = "3"` を定義する。
+2. それぞれを `int.parse()` で `int` 型に変換する。
+3. 合計金額 `total = price * quantity` を計算する。
+4. 4人で均等に割り勘した場合の「一人あたりの金額(整数部分)」を `~/` 演算子で求め、「余り(端数)」を `%` 演算子で計算して出力する。
+
+```dart:practice1_2.dart
+void main() {
+ // ここにコードを書いてください
+}
+```
+
+```dart-exec:practice1_2.dart
+```
diff --git a/public/docs/dart/10-async-stream/-intro.md b/public/docs/dart/10-async-stream/-intro.md
new file mode 100644
index 00000000..4dcc82f8
--- /dev/null
+++ b/public/docs/dart/10-async-stream/-intro.md
@@ -0,0 +1,5 @@
+[[Future]]が「1回だけ値を返す非同期処理」であるのに対し、**[[Stream]]** は「時間の経過に伴って複数回、非同期に連続して届くデータ(イベント列)」を扱います。
+
+ユーザーのボタンタップ、センサー値の変動、WebSocketによるリアルタイム通信、ファイルのチャンク読み込みなど、現代のリアクティブなアプリ開発においてStreamは不可欠な概念です。
+
+この章では、Streamの購読方法、非同期ジェネレータ(`async*` / `yield`)、および `StreamController` による自作ストリームの制御方法を学びます。
diff --git a/public/docs/dart/10-async-stream/1-0-stream-concepts.md b/public/docs/dart/10-async-stream/1-0-stream-concepts.md
new file mode 100644
index 00000000..1c6b85ca
--- /dev/null
+++ b/public/docs/dart/10-async-stream/1-0-stream-concepts.md
@@ -0,0 +1,51 @@
+---
+id: dart-stream-concepts
+title: Stream の概念(Push型のデータフロー)
+level: 2
+question:
+ - 単一購読ストリームとブロードキャストストリームの違いは何ですか?
+ - Streamはどのようにデータを送信側に要求する(または受信する)のですか?
+ - Streamのリスナー(listen)はどう使いますか?
+term:
+ - Stream
+ - ストリーム
+ - 単一購読ストリーム
+ - ブロードキャストストリーム
+ - listen
+---
+
+## `Stream` の概念(Push型のデータフロー)
+
+**`Stream`** は、非同期に連続して流れてくる一連のデータ(データパイプライン)です。
+
+### 1. 単一購読ストリーム(Single-subscription Stream)
+
+* デフォルトのStream。
+* ライフサイクルの中で**1つのリスナーだけ**が購読できます(例: ファイル読み込み)。
+* 2回以上 `listen()` しようとするとエラーになります。
+
+### 2. ブロードキャストストリーム(Broadcast Stream)
+
+* **複数のリスナー**が同時に購読できます(例: UIのクリックイベント、マウス移動)。
+* `stream.asBroadcastStream()` または `StreamController.broadcast()` で作成します。
+
+```dart:stream_listen.dart
+void main() {
+ // 1から3までのデータを順番に流す Stream
+ final stream = Stream.fromIterable([1, 2, 3]);
+
+ // listen でイベントを購読
+ final subscription = stream.listen(
+ (data) => print('データ受信: $data'),
+ onError: (error) => print('エラー: $error'),
+ onDone: () => print('ストリーム終了 (Done)'),
+ );
+}
+```
+
+```dart-exec:stream_listen.dart
+データ受信: 1
+データ受信: 2
+データ受信: 3
+ストリーム終了 (Done)
+```
diff --git a/public/docs/dart/10-async-stream/2-0-await-for.md b/public/docs/dart/10-async-stream/2-0-await-for.md
new file mode 100644
index 00000000..18732142
--- /dev/null
+++ b/public/docs/dart/10-async-stream/2-0-await-for.md
@@ -0,0 +1,67 @@
+---
+id: dart-stream-await-for
+title: await for によるStreamの購読
+level: 2
+question:
+ - await for ループはいつ終了しますか?
+ - await for の中で break や return を使うとストリームはどうなりますか?
+ - Streamの高階メソッド(map, where, take)と組み合わせる方法は?
+term:
+ - await for
+ - Stream購読
+ - take
+---
+
+## `await for` によるStreamの購読
+
+`async` 関数内では、**`await for` ループ** を使うことで、ストリームからデータが流れてくるたびに同期的な `for-in` ループのように直感的に処理できます。
+
+ストリームが `onDone`(完了)を発行するまでループが継続します。
+
+```dart:await_for_demo.dart
+Future processStream(Stream stream) async {
+ print('--- 処理開始 ---');
+ await for (final value in stream) {
+ print('受信値: $value (2倍: ${value * 2})');
+ }
+ print('--- 全データ受信完了 ---');
+}
+
+void main() async {
+ // 10, 20, 30 を流すストリーム
+ final dataStream = Stream.fromIterable([10, 20, 30]);
+ await processStream(dataStream);
+}
+```
+
+```dart-exec:await_for_demo.dart
+--- 処理開始 ---
+受信値: 10 (2倍: 20)
+受信値: 20 (2倍: 40)
+受信値: 30 (2倍: 60)
+--- 全データ受信完了 ---
+```
+
+### Streamの変換オペレータ
+
+Streamも `List` と同様に `map` や `where`、`take` などのオペレータでパイプライン処理が可能です。
+
+```dart:stream_operators.dart
+void main() async {
+ final stream = Stream.fromIterable([1, 2, 3, 4, 5, 6]);
+
+ final filtered = stream
+ .where((n) => n.isEven)
+ .map((n) => '偶数: $n');
+
+ await for (final item in filtered) {
+ print(item);
+ }
+}
+```
+
+```dart-exec:stream_operators.dart
+偶数: 2
+偶数: 4
+偶数: 6
+```
diff --git a/public/docs/dart/10-async-stream/3-0-stream-controller.md b/public/docs/dart/10-async-stream/3-0-stream-controller.md
new file mode 100644
index 00000000..b439c895
--- /dev/null
+++ b/public/docs/dart/10-async-stream/3-0-stream-controller.md
@@ -0,0 +1,56 @@
+---
+id: dart-stream-controller
+title: StreamController と StreamSubscription
+level: 2
+question:
+ - StreamControllerの sink と stream の役割の違いは何ですか?
+ - StreamSubscription を使って購読を一時停止・再開・解除する方法は?
+ - StreamController を使い終わった後に close() を呼ぶべき理由は何ですか?
+term:
+ - StreamController
+ - StreamSubscription
+ - sink
+ - close
+ - cancel
+---
+
+## `StreamController` と `StreamSubscription`
+
+### 1. `StreamController`: イベントの送信と管理
+
+プログラムの任意の場所からデータを流し込みたい場合、**`StreamController`** を使用します。
+
+* `controller.sink.add(value)`: データをストリームへ送信。
+* `controller.sink.addError(error)`: エラーイベントを送信。
+* `controller.close()`: ストリームの終了(完了)を通知(メモリリーク防止のため必須)。
+* `controller.stream`: 購読用の `Stream` オブジェクト。
+
+```dart:stream_controller_demo.dart
+import 'dart:async';
+
+void main() async {
+ final controller = StreamController();
+
+ // 購読側の設定
+ controller.stream.listen(
+ (message) => print('通知: $message'),
+ onDone: () => print('コントローラ停止'),
+ );
+
+ // イベントの発行
+ controller.sink.add('第1報: サーバー起動');
+ controller.sink.add('第2報: クライアント接続');
+
+ await controller.close(); // ストリームをクローズ
+}
+```
+
+```dart-exec:stream_controller_demo.dart
+通知: 第1報: サーバー起動
+通知: 第2報: クライアント接続
+コントローラ停止
+```
+
+### 2. `StreamSubscription`: 購読の制御
+
+`stream.listen()` の戻り値である `StreamSubscription` オブジェクトを使って、購読の中断・再開や、途中で購読を破棄(`subscription.cancel()`)できます。
diff --git a/public/docs/dart/10-async-stream/4-0-async-generator.md b/public/docs/dart/10-async-stream/4-0-async-generator.md
new file mode 100644
index 00000000..4f44768b
--- /dev/null
+++ b/public/docs/dart/10-async-stream/4-0-async-generator.md
@@ -0,0 +1,51 @@
+---
+id: dart-stream-generator
+title: async* と yield(非同期ジェネレータ関数)
+level: 2
+question:
+ - async* 関数と通常の async 関数の違いは何ですか?
+ - yield と yield* の使い分けはどうなりますか?
+ - 定期的に値を送信するストリームを async* で書く方法は?
+term:
+ - 'async*'
+ - yield
+ - yield*
+ - 非同期ジェネレータ
+---
+
+## `async*` と `yield`(非同期ジェネレータ関数)
+
+**非同期ジェネレータ関数(`async*`)** を使用すると、複数の値を時間をかけて順番に生成・配信する `Stream` を手軽に構築できます。
+
+* 関数宣言に `async*` を付け、戻り値型を `Stream` にします。
+* **`yield 値`**: データを1つストリームへ送出します。
+* **`yield* 別のStream`**: 別のストリームの全イベントをそのまま中継して送出します。
+
+```dart:async_generator.dart
+// 1からcountまで1秒おきにカウントアップする非同期ジェネレータ
+Stream countStream(int max) async* {
+ for (int i = 1; i <= max; i++) {
+ await Future.delayed(const Duration(milliseconds: 50));
+ yield i; // データを1件送出
+ }
+}
+
+void main() async {
+ print('カウントダウン開始');
+ await for (final number in countStream(3)) {
+ print('カウント: $number');
+ }
+ print('完了!');
+}
+```
+
+```dart-exec:async_generator.dart
+カウントダウン開始
+カウント: 1
+カウント: 2
+カウント: 3
+完了!
+```
+
+> [!TIP]
+> `StreamController` を手動で用意して `close()` を呼ぶ必要がないため、データの生成フローが明確な場合は `async*` と `yield` を使うのが最も安全でシンプルです。
diff --git a/public/docs/dart/10-async-stream/5-0-summary.md b/public/docs/dart/10-async-stream/5-0-summary.md
new file mode 100644
index 00000000..20137ef4
--- /dev/null
+++ b/public/docs/dart/10-async-stream/5-0-summary.md
@@ -0,0 +1,17 @@
+---
+id: dart-async-stream-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]のリアクティブな非同期データフローを支える **[[Stream]]** について学びました。
+
+* **Streamの概念**: 時間軸に沿って複数回イベント(データ、エラー、完了)を伝達するパイプライン。
+* **`await for`**: ストリームから流れてくる要素を同期的なループ構文のように直感的に処理できる。
+* **`StreamController`**: `sink` 経由でデータを送信し、任意のタイミングでイベントを発行・クローズできる。
+* **`async*` と `yield`**: 非同期ジェネレータ関数を用いて、シンプルかつクリーンに自作ストリームを生成できる。
+
+次の [[./11]] では、アプリケーションの信頼性を向上させる **エラーハンドリングとResultパターン** について学びます。
diff --git a/public/docs/dart/10-async-stream/5-1-practice1.md b/public/docs/dart/10-async-stream/5-1-practice1.md
new file mode 100644
index 00000000..821c7ef1
--- /dev/null
+++ b/public/docs/dart/10-async-stream/5-1-practice1.md
@@ -0,0 +1,28 @@
+---
+id: dart-async-stream-practice1
+title: '練習問題1: async*を使ったカウントダウンストリーム'
+level: 3
+question:
+ - async* 関数の中でループや条件分岐を組み合わせる方法を教えてください。
+ - ストリームの途中でエラーを発生させたい場合はどう書きますか?
+---
+
+### 練習問題1: async*を使ったカウントダウンストリーム
+
+指定された秒数から0までカウントダウンし、最後に `'発射!'` という文字列を通知するストリームを作成してください。
+
+1. `Stream countdown(int from)` を `async*` で定義する。
+2. `from` から `1` までの数値をループし、50ミリ秒待機しながら `'$i...'` を `yield` する。
+3. ループ終了後に `'発射!'` を `yield` する。
+4. `main()` で `await for` を使って `countdown(3)` を購読し、結果を出力する。
+
+```dart:practice10_1.dart
+// ここに関数を定義してください
+
+void main() async {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice10_1.dart
+```
diff --git a/public/docs/dart/10-async-stream/5-2-practice2.md b/public/docs/dart/10-async-stream/5-2-practice2.md
new file mode 100644
index 00000000..3137a7a5
--- /dev/null
+++ b/public/docs/dart/10-async-stream/5-2-practice2.md
@@ -0,0 +1,28 @@
+---
+id: dart-async-stream-practice2
+title: '練習問題2: StreamControllerを使ったイベント通知'
+level: 3
+question:
+ - StreamControllerでエラーを流す sink.addError の使い方を教えてください。
+ - listen の onError コールバックでエラーを処理する方法を復習したいです。
+---
+
+### 練習問題2: StreamControllerを使ったイベント通知
+
+タスクの進行状況(進捗率: 0〜100%)を通知する進捗トラッカーを実装してください。
+
+1. `StreamController` を作成する。
+2. コントローラのストリームを `listen` し、`'進捗: $percent%'` と出力するリスナーを登録する。
+3. `sink.add` を使って、`25`, `50`, `75`, `100` を順番に送信する。
+4. 送信完了後に `await controller.close()` を呼び出し、ストリームを終了する。
+
+```dart:practice10_2.dart
+import 'dart:async';
+
+void main() async {
+ // ここにコードを書いてください
+}
+```
+
+```dart-exec:practice10_2.dart
+```
diff --git a/public/docs/dart/11-error-handling/-intro.md b/public/docs/dart/11-error-handling/-intro.md
new file mode 100644
index 00000000..b09f34f2
--- /dev/null
+++ b/public/docs/dart/11-error-handling/-intro.md
@@ -0,0 +1,6 @@
+堅牢なアプリケーションを開発するためには、予期せぬ実行時エラーや外部連携の失敗を適切に処理するエラーハンドリング設計が欠かせません。
+
+[[Dart]]には、特定の例外型をピンポイントで捕捉する `on` 節やスタックトレースの取得、開発時の事前条件チェックを行う `assert` 文が用意されています。
+さらにDart 3の `sealed` クラスやレコードを活用することで、例外を投げずに型の戻り値として成功・失敗を明示的に表現する **Result型(Resultパターン)** を美しく実装できます。
+
+この章では、Dartにおける例外処理の基礎から最新の関数型エラーハンドリング手法までを学びます。
diff --git a/public/docs/dart/11-error-handling/1-0-try-catch.md b/public/docs/dart/11-error-handling/1-0-try-catch.md
new file mode 100644
index 00000000..98b4252c
--- /dev/null
+++ b/public/docs/dart/11-error-handling/1-0-try-catch.md
@@ -0,0 +1,65 @@
+---
+id: dart-error-try-catch
+title: try、catch、on、finally とカスタム例外
+level: 2
+question:
+ - Exception と Error の違いは何ですか?
+ - onキーワードを使って特定の例外だけをキャッチする方法は?
+ - rethrowキーワードはどのような場合に使われますか?
+term:
+ - try-catch
+ - Exception
+ - Error
+ - on
+ - rethrow
+ - スタックトレース
+---
+
+## `try`、`catch`、`on`、`finally` とカスタム例外
+
+[[Dart]]の例外システムでは、`Exception`(プログラムで回復可能なエラー)と `Error`(プログラミングミスなどの重大な欠陥)が区別されています。
+
+### 1. `on` による型指定キャッチと `rethrow`
+
+* **`on 例外型`**: 特定の例外クラスのみを捕捉します。
+* **`catch (e, stackTrace)`**: 例外オブジェクトとスタックトレースを受け取ります。
+* **`rethrow`**: キャッチした例外をそのまま上位の呼び出し元へ再スローします。
+
+```dart:exception_handling.dart
+// 1. カスタム例外クラスの定義 (implements Exception)
+class InsufficientFundsException implements Exception {
+ final int currentBalance;
+ final int requestedAmount;
+ InsufficientFundsException(this.currentBalance, this.requestedAmount);
+
+ @override
+ String toString() =>
+ '残高不足エラー: 現在残高 $currentBalance 円 に対し、$requestedAmount 円 の引き落とし要求がありました。';
+}
+
+void processWithdrawal(int balance, int amount) {
+ if (amount > balance) {
+ throw InsufficientFundsException(balance, amount);
+ }
+ print('引き落とし成功: $amount 円');
+}
+
+void main() {
+ try {
+ processWithdrawal(3000, 5000);
+ } on InsufficientFundsException catch (e) {
+ // 特定のカスタム例外を処理
+ print('捕捉: $e');
+ } catch (e, stack) {
+ // その他の未知の例外
+ print('予期せぬエラー: $e');
+ } finally {
+ print('トランザクション終了');
+ }
+}
+```
+
+```dart-exec:exception_handling.dart
+捕捉: 残高不足エラー: 現在残高 3000 円 に対し、$5000 円 の引き落とし要求がありました。
+トランザクション終了
+```
diff --git a/public/docs/dart/11-error-handling/2-0-assert.md b/public/docs/dart/11-error-handling/2-0-assert.md
new file mode 100644
index 00000000..34bf95c2
--- /dev/null
+++ b/public/docs/dart/11-error-handling/2-0-assert.md
@@ -0,0 +1,49 @@
+---
+id: dart-error-assert
+title: assert による開発時のバグ検知
+level: 2
+question:
+ - assert 文は本番リリース時(プロダクションビルド)にも実行されますか?
+ - assert と if-throw の使い分け基準は何ですか?
+ - Flutterでassertが多用されている理由は何ですか?
+term:
+ - assert
+ - アサーション
+ - デバッグ
+---
+
+## `assert` による開発時のバグ検知
+
+**`assert(条件式, 'エラーメッセージ');`** は、開発・デバッグ時(Debug Mode)にのみ実行されるアサーション(前提条件チェック)文です。
+
+* 条件が `true` であれば何も起きません。
+* 条件が `false` の場合、`AssertionError` がスローされ、即座に実行が中断します。
+* **リリースビルド(AOTコンパイルや本番モード)では自動的に完全に無視(コードから削除)される**ため、実行時パフォーマンスに一切影響を与えません。
+
+```dart:assert_demo.dart
+class User {
+ final String name;
+ final int age;
+
+ User(this.name, this.age)
+ : assert(name.isNotEmpty, 'ユーザー名は空にできません'),
+ assert(age >= 0, '年齢は0歳以上である必要があります');
+}
+
+void main() {
+ final validUser = User('Alice', 20);
+ print('ユーザー作成成功: ${validUser.name}');
+
+ // デバッグ実行時、条件を満たさないと AssertionError が発生
+ // final invalidUser = User('', -5);
+}
+```
+
+```dart-exec:assert_demo.dart
+ユーザー作成成功: Alice
+```
+
+> [!NOTE]
+> **使い分けの基準**:
+> * `assert`: プログラマ自身の内部的なミスやAPIの不正利用を開発中に防ぐ目的。
+> * `if-throw`(例外スロー): ユーザー入力エラーやネットワーク遮断など、本番環境でも発生し得る外部要因のエラー処理。
diff --git a/public/docs/dart/11-error-handling/3-0-result-pattern.md b/public/docs/dart/11-error-handling/3-0-result-pattern.md
new file mode 100644
index 00000000..841c2606
--- /dev/null
+++ b/public/docs/dart/11-error-handling/3-0-result-pattern.md
@@ -0,0 +1,70 @@
+---
+id: dart-error-result-pattern
+title: Result型(戻り値で成功/失敗を表現するパターン)
+level: 2
+question:
+ - なぜ例外をthrowする代わりにResult型を使うアプローチが好まれるのですか?
+ - sealedクラスを使ってResult型(Success / Failure)を定義する方法は?
+ - switch式でResult型をハンドリングするメリットは何ですか?
+term:
+ - Result型
+ - Resultパターン
+ - Either
+ - 成功/失敗
+ - 型安全なエラー処理
+---
+
+## Result型(戻り値で成功/失敗を表現するパターン)
+
+例外を `throw` するアプローチは、関数の型シグネチャに「どのような例外が発生し得るか」が現れず、呼び出し側がエラー処理を忘れるリスクがあります。
+
+Dart 3の **`sealed` クラス** を使って **[[Result型]](Result Pattern)** を自作すると、関数の戻り値の型として成功(`Success`)または失敗(`Failure`)を明示できます。
+
+```dart:result_pattern_demo.dart
+// 1. sealed クラスで Result 型を定義
+sealed class Result {
+ const Result();
+}
+
+final class Success extends Result {
+ final T value;
+ const Success(this.value);
+}
+
+final class Failure extends Result {
+ final E error;
+ const Failure(this.error);
+}
+
+// 2. 例外を投げず、Result型を返す安全な除算関数
+Result safeDivide(double a, double b) {
+ if (b == 0) {
+ return const Failure('0 で除算することはできません');
+ }
+ return Success(a / b);
+}
+
+void main() {
+ final results = [
+ safeDivide(10, 2),
+ safeDivide(10, 0),
+ ];
+
+ for (final res in results) {
+ // switch式で網羅的にハンドリング (処理忘れをコンパイル時に防止)
+ final output = switch (res) {
+ Success(:var value) => '計算結果: $value',
+ Failure(:var error) => 'エラー通知: $error',
+ };
+ print(output);
+ }
+}
+```
+
+```dart-exec:result_pattern_demo.dart
+計算結果: 5.0
+エラー通知: 0 で除算することはできません
+```
+
+> [!TIP]
+> Result型を使うことで、呼び出し側は `switch` によるパターンマッチングで結果を取り出すことがコンパイラによって強制され、未処理エラーのバグが根絶されます。
diff --git a/public/docs/dart/11-error-handling/4-0-summary.md b/public/docs/dart/11-error-handling/4-0-summary.md
new file mode 100644
index 00000000..8af9a7f9
--- /dev/null
+++ b/public/docs/dart/11-error-handling/4-0-summary.md
@@ -0,0 +1,16 @@
+---
+id: dart-error-handling-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]のエラーハンドリングとモダンな堅牢設計について学びました。
+
+* **`try-catch-on-finally`**: `on` による型限定の例外捕捉、スタックトレースの取得、`rethrow` による再スロー。
+* **`assert`**: デバッグ時にのみコードの事前条件を検証し、リリース時にはゼロオーバーヘッドで削除されるバグ検知機構。
+* **Resultパターン**: 例外を投げる代わりに `sealed class Result` で成功・失敗を戻り値型として表現し、コンパイラの網羅性チェックを活用する設計。
+
+次の [[./12]] では、Dartチュートリアルの締めくくりとして、**並行処理の仕組みと `Isolate`** について学びます。
diff --git a/public/docs/dart/11-error-handling/4-1-practice1.md b/public/docs/dart/11-error-handling/4-1-practice1.md
new file mode 100644
index 00000000..4c64a3e9
--- /dev/null
+++ b/public/docs/dart/11-error-handling/4-1-practice1.md
@@ -0,0 +1,29 @@
+---
+id: dart-error-handling-practice1
+title: '練習問題1: カスタム例外と適切な例外捕捉'
+level: 3
+question:
+ - 複数の異なるカスタム例外を順番に on 節で捕捉する構文を教えてください。
+ - カスタム例外クラスにエラーコードや詳細プロパティを持たせる方法を教えてください。
+---
+
+### 練習問題1: カスタム例外と適切な例外捕捉
+
+ユーザーのパスワード設定バリデーション関数と、それをテストするコードを作成してください。
+
+1. `class WeakPasswordException implements Exception` を定義し、`final String reason;` を持たせる。
+2. `void validatePassword(String password)` 関数を定義する。
+ * パスワードの長さが8文字未満の場合、`WeakPasswordException('8文字以上である必要があります')` をスローする。
+ * 数字(`0`〜`9`)を含まない場合、`WeakPasswordException('少なくとも1つの数字を含む必要があります')` をスローする。
+3. `main()` でいくつかのテスト用パスワードを渡し、`on WeakPasswordException catch (e)` で捕捉して理由を出力する。
+
+```dart:practice11_1.dart
+// ここにコードを書いてください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice11_1.dart
+```
diff --git a/public/docs/dart/11-error-handling/4-2-practice2.md b/public/docs/dart/11-error-handling/4-2-practice2.md
new file mode 100644
index 00000000..f06c5474
--- /dev/null
+++ b/public/docs/dart/11-error-handling/4-2-practice2.md
@@ -0,0 +1,29 @@
+---
+id: dart-error-handling-practice2
+title: '練習問題2: sealedクラスによるResult型の実装'
+level: 3
+question:
+ - Result型に map や flatMap のような便利メソッドを生やすことはできますか?
+ - 非同期処理 Future> と組み合わせるパターンの使いどころを教えてください。
+---
+
+### 練習問題2: sealedクラスによるResult型の実装
+
+文字列から整数への変換を安全に行う関数 `safeParseInt` を作成してください。
+
+1. 本章で学習した `sealed class Result`(`Success` と `Failure`)を定義する。
+2. `Result safeParseInt(String input)` を作成する。
+ * `int.tryParse(input)` を使い、変換成功時は `Success(value)` を返す。
+ * 失敗時は `Failure('"$input" は有効な整数ではありません')` を返す。
+3. `main()` で `'123'` と `'abc'` を変換し、`switch` 式を使って結果を出力する。
+
+```dart:practice11_2.dart
+// ここにコードを書いてください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice11_2.dart
+```
diff --git a/public/docs/dart/12-concurrency-isolate/-intro.md b/public/docs/dart/12-concurrency-isolate/-intro.md
new file mode 100644
index 00000000..14828989
--- /dev/null
+++ b/public/docs/dart/12-concurrency-isolate/-intro.md
@@ -0,0 +1,7 @@
+[[Dart]]のコードはデフォルトでシングルスレッドのイベントループ上で実行されます。
+しかし、巨大なJSONの解析、画像の加工、複雑な暗号化や統計計算など、CPUを長時間占有する処理をそのまま実行するとUIがカクついてしまいます。
+
+Dartでは、マルチコアCPUの性能をフルに活かして真の並列処理を行うために **[[Isolate]](アイソレート)** という仕組みを提供しています。
+各Isolateは完全に独立したメモリヒープを持っており、スレッド間の共有メモリに起因するデータ競合やデッドロックが原理的に発生しません。
+
+この最終章では、Dartの並行処理アーキテクチャ、手軽に使える `Isolate.run()`、そしてポート通信を用いた高度な並行処理を学びます。
diff --git a/public/docs/dart/12-concurrency-isolate/1-0-single-thread-model.md b/public/docs/dart/12-concurrency-isolate/1-0-single-thread-model.md
new file mode 100644
index 00000000..d6c80a50
--- /dev/null
+++ b/public/docs/dart/12-concurrency-isolate/1-0-single-thread-model.md
@@ -0,0 +1,42 @@
+---
+id: dart-concurrency-single-thread
+title: Dartのシングルスレッドモデルとメモリ空間
+level: 2
+question:
+ - なぜDartは共有メモリスレッドではなくIsolateモデルを採用したのですか?
+ - メモリが分離されていることによるメリットとデメリットは何ですか?
+ - FutureとIsolateの使い分けの基準は何ですか?
+term:
+ - シングルスレッド
+ - 並行処理
+ - メモリ空間
+ - データ競合
+---
+
+## Dartのシングルスレッドモデルとメモリ空間
+
+JavaやC++、C#などの一般的な言語では、複数のスレッドが同一のメモリ空間(ヒープ領域)を共有して動作します。この方式は高速ですが、**データ競合(Data Race)** や **デッドロック(Deadlock)**、複雑なロック(ミューテックス)管理が必要となり、バグの温床になりがちです。
+
+一方、[[Dart]]では **[[Isolate]](隔離されたスレッド)** というモデルを採用しています。
+
+```
++--------------------------------+ +--------------------------------+
+| Main Isolate | | Worker Isolate |
+| | | |
+| +--------------------------+ | | +--------------------------+ |
+| | 独立したメモリヒープ | | | | 独立したメモリヒープ | |
+| +--------------------------+ | | +--------------------------+ |
+| +--------------------------+ | | +--------------------------+ |
+| | 独立したイベントループ | | | | 独立したイベントループ | |
+| +--------------------------+ | | +--------------------------+ |
++---------------+----------------+ +----------------+---------------+
+ | ^
+ | メッセージパッシング (コピー/転送) |
+ +-----------------------------------------+
+```
+
+### Isolateモデルの特徴
+
+1. **完全なメモリ分離**: 1つのIsolate内の変数は、他のIsolateから直接読み書きできません。
+2. **ロックフリー**: メモリが共有されないため、ミューテックスやセマフォなどのロック機構が不要です。
+3. **安全なガベージコレクション**: 他のIsolateを停止させることなく、個々のIsolateが独立してガベージコレクション(GC)を実行できます。
diff --git a/public/docs/dart/12-concurrency-isolate/2-0-isolate-intro.md b/public/docs/dart/12-concurrency-isolate/2-0-isolate-intro.md
new file mode 100644
index 00000000..7c33d185
--- /dev/null
+++ b/public/docs/dart/12-concurrency-isolate/2-0-isolate-intro.md
@@ -0,0 +1,54 @@
+---
+id: dart-concurrency-isolate-run
+title: Isolate の概念と Isolate.run() による別スレッド処理
+level: 2
+question:
+ - Isolate.run() はどのような処理に向いていますか?
+ - Isolate.run() に渡せる関数や引数にどのような制限がありますか?
+ - compute() 関数(Flutter)と Isolate.run() の関係は何ですか?
+term:
+ - Isolate
+ - Isolate.run
+ - アイソレート
+ - ヘビータスク
+---
+
+## `Isolate` の概念と `Isolate.run()` による別スレッド処理
+
+Dart 2.19以降、単発の重い処理を別スレッドで実行して結果を受け取るための非常に手軽なAPI **`Isolate.run()`** が導入されました。
+
+### `Isolate.run()` の使い方
+
+`Isolate.run()` に実行したい関数(トップレベル関数、静的メソッド、あるいはクロージャ)を渡すだけで、自動的に新しいIsolateが立ち上がり、処理が完了すると結果を返して自動終了します。
+
+```dart:isolate_run_demo.dart
+import 'dart:isolate';
+
+// 重い計算処理の例(大きな数値の合計)
+int heavyCalculation(int count) {
+ int total = 0;
+ for (int i = 1; i <= count; i++) {
+ total += i;
+ }
+ return total;
+}
+
+void main() async {
+ print('1. メイン処理開始');
+
+ // 別スレッド (Isolate) で重い処理をバックグラウンド実行
+ final result = await Isolate.run(() => heavyCalculation(1000000));
+
+ print('2. 計算完了: $result');
+ print('3. メイン処理終了');
+}
+```
+
+```dart-exec:isolate_run_demo.dart
+1. メイン処理開始
+2. 計算完了: 500000500000
+3. メイン処理終了
+```
+
+> [!NOTE]
+> `Isolate.run()` に渡す引数や戻り値はメッセージとして転送可能なオブジェクト(基本型、コレクション、または特定条件を満たすオブジェクト)である必要があります。
diff --git a/public/docs/dart/12-concurrency-isolate/3-0-isolate-ports.md b/public/docs/dart/12-concurrency-isolate/3-0-isolate-ports.md
new file mode 100644
index 00000000..26559205
--- /dev/null
+++ b/public/docs/dart/12-concurrency-isolate/3-0-isolate-ports.md
@@ -0,0 +1,74 @@
+---
+id: dart-concurrency-isolate-ports
+title: ポート(ReceivePort、SendPort)による双方向メッセージ通信
+level: 2
+question:
+ - 長時間稼働するバックグラウンドワーカーを作るにはどうしますか?
+ - ReceivePort と SendPort の役割の違いは何ですか?
+ - Isolate.spawn() を使ったワーカーの起動方法は?
+term:
+ - ReceivePort
+ - SendPort
+ - メッセージパッシング
+ - Isolate.spawn
+ - 双方向通信
+---
+
+## ポート(`ReceivePort`、`SendPort`)による双方向メッセージ通信
+
+`Isolate.run()` は単発の処理に適していますが、長時間常駐して継続的にメッセージを送受信するバックグラウンドワーカーを作成する場合は、**`ReceivePort`** と **`SendPort`** による **[[メッセージパッシング]]** を使用します。
+
+* **`ReceivePort`**: メッセージの受信口(`Stream` として機能)。
+* **`SendPort`**: メッセージの送信先アドレス。
+
+```dart:isolate_ports_demo.dart
+import 'dart:isolate';
+
+// ワーカースレッドのエントリーポイント
+void worker(SendPort mainSendPort) {
+ // ワーカー側の受信ポートを作成
+ final workerReceivePort = ReceivePort();
+
+ // ワーカーの送信ポートをメインスレッドに知らせる
+ mainSendPort.send(workerReceivePort.sendPort);
+
+ // メインスレッドからの指示を待機
+ workerReceivePort.listen((message) {
+ if (message is String) {
+ // 処理結果をメインスレッドに返信
+ mainSendPort.send('処理完了: ${message.toUpperCase()}');
+ }
+ });
+}
+
+void main() async {
+ // メイン側の受信ポート
+ final mainReceivePort = ReceivePort();
+
+ // ワーカーIsolateを起動
+ final isolate = await Isolate.spawn(worker, mainReceivePort.sendPort);
+
+ SendPort? workerSendPort;
+
+ // メイン側でメッセージを受信
+ mainReceivePort.listen((message) {
+ if (message is SendPort) {
+ // ワーカーの送信先を受け取ったら指示を送信
+ workerSendPort = message;
+ workerSendPort?.send('hello from main');
+ } else {
+ print('ワーカーからの返信: $message');
+
+ // クリーンアップ
+ mainReceivePort.close();
+ isolate.kill();
+ print('通信完了・Isolate破棄');
+ }
+ });
+}
+```
+
+```dart-exec:isolate_ports_demo.dart
+ワーカーからの返信: 処理完了: HELLO FROM MAIN
+通信完了・Isolate破棄
+```
diff --git a/public/docs/dart/12-concurrency-isolate/4-0-summary.md b/public/docs/dart/12-concurrency-isolate/4-0-summary.md
new file mode 100644
index 00000000..2b12a8f9
--- /dev/null
+++ b/public/docs/dart/12-concurrency-isolate/4-0-summary.md
@@ -0,0 +1,22 @@
+---
+id: dart-concurrency-isolate-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]の並行処理とマルチスレッドアーキテクチャについて学びました。
+
+* **シングルスレッドとIsolate**: メモリ空間を共有しない独立したスレッドモデルにより、データ競合やロックの複雑さを排除。
+* **`Isolate.run()`**: 単発の重いCPU処理(画像処理、暗号化、データ変換など)を数行で別スレッドにオフロード可能。
+* **ポート通信 (`ReceivePort` / `SendPort`)**: メッセージパッシングによって、常駐型ワーカーIsolateと安全に双方向通信ができる。
+
+---
+
+### Dartチュートリアル完走おめでとうございます!
+
+本チュートリアルを通じて、Dartの基本構文からSound Null Safety、関数・クロージャ、コレクション操作、レコードとパターンマッチング、クラス設計、クラス修飾子、非同期処理(Future・Stream)、エラーハンドリング、そして並行処理(Isolate)に至るまで、現代のDart開発に必要な知識を網羅しました。
+
+これらの知識は、[[Flutter]]によるアプリ開発はもちろん、Dartを用いたWeb・サーバーサイド開発の強固な基盤となります。ぜひ学んだ知識を活かして、素晴らしいアプリケーションを作ってみてください!
diff --git a/public/docs/dart/12-concurrency-isolate/4-1-practice1.md b/public/docs/dart/12-concurrency-isolate/4-1-practice1.md
new file mode 100644
index 00000000..610e3ffb
--- /dev/null
+++ b/public/docs/dart/12-concurrency-isolate/4-1-practice1.md
@@ -0,0 +1,29 @@
+---
+id: dart-concurrency-isolate-practice1
+title: '練習問題1: Isolate.run()による重い計算の並行実行'
+level: 3
+question:
+ - Isolate.run() 内で例外が発生した場合、呼び出し側はどう処理すべきですか?
+ - 引数としてクロージャを渡す場合の変数キャプチャの注意点は何ですか?
+---
+
+### 練習問題1: Isolate.run()による重い計算の並行実行
+
+素数の個数を数える計算を `Isolate.run()` を使って別スレッドで実行してください。
+
+1. `bool isPrime(int n)` 関数を作成する(2以上の整数に対し素数判定を行う)。
+2. `int countPrimes(int max)` 関数を作成し、`1` から `max` までの素数の総数をカウントする。
+3. `main()` で `Isolate.run(() => countPrimes(50000))` を呼び出して非同期に結果を待機し、計算された素数の個数を出力する。
+
+```dart:practice12_1.dart
+import 'dart:isolate';
+
+// ここに関数を定義してください
+
+void main() async {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice12_1.dart
+```
diff --git a/public/docs/dart/12-concurrency-isolate/4-2-practice2.md b/public/docs/dart/12-concurrency-isolate/4-2-practice2.md
new file mode 100644
index 00000000..6d3934e4
--- /dev/null
+++ b/public/docs/dart/12-concurrency-isolate/4-2-practice2.md
@@ -0,0 +1,30 @@
+---
+id: dart-concurrency-isolate-practice2
+title: '練習問題2: ポートを使った双方向ワーカーの作成'
+level: 3
+question:
+ - Isolateでエラーが発生したときにメインスレッドに通知する onError ポートの設定方法は?
+ - 複数のワーカーをプールして管理する設計のポイントは何ですか?
+---
+
+### 練習問題2: ポートを使った双方向ワーカーの作成
+
+メインスレッドから渡された文字列を逆順にして返信するワーカーIsolateを作成してください。
+
+1. `void echoWorker(SendPort mainSendPort)` を作成する。
+ * 自身の `ReceivePort` を作成し、その `sendPort` を `mainSendPort` に送信する。
+ * 受信したメッセージが `String` であれば、文字列を逆順(`message.split('').reversed.join()`)にして `mainSendPort` に返信する。
+2. `main()` で `Isolate.spawn(echoWorker, mainReceivePort.sendPort)` を起動し、`'Flutter & Dart'` という文字列を送信して逆順になった文字列を受信・出力する。
+
+```dart:practice12_2.dart
+import 'dart:isolate';
+
+// ここに関数を定義してください
+
+void main() async {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice12_2.dart
+```
diff --git a/public/docs/dart/2-null-safety/-intro.md b/public/docs/dart/2-null-safety/-intro.md
new file mode 100644
index 00000000..b5cbe11b
--- /dev/null
+++ b/public/docs/dart/2-null-safety/-intro.md
@@ -0,0 +1,6 @@
+[[Dart]]はバージョン2.12より **健全なNull Safety(Sound Null Safety)** を言語レベルで導入しました。
+
+現代のプログラミングにおいて、`NullPointerException`(Null参照エラー)は最も頻発するバグの1つです。
+Dartの健全な[[Null Safety]]は、コードを書いている最中やコンパイル時にNullになり得る箇所を厳密に区別し、実行時クラッシュを未然に防ぎます。
+
+この章では、DartのNull Safetyの仕組み、各種Null認識演算子、そして `late` 修飾子の正しい使い方をマスターします。
diff --git a/public/docs/dart/2-null-safety/1-0-types.md b/public/docs/dart/2-null-safety/1-0-types.md
new file mode 100644
index 00000000..1b454a23
--- /dev/null
+++ b/public/docs/dart/2-null-safety/1-0-types.md
@@ -0,0 +1,67 @@
+---
+id: dart-null-safety-types
+title: Nullable型(?)とNon-nullable型
+level: 2
+question:
+ - デフォルトで変数がNull非許容(Non-nullable)であるメリットは何ですか?
+ - Nullableな変数はどのように宣言しますか?
+ - if文でnullチェックした後は自動的にNon-nullableとして扱われますか?
+term:
+ - Null Safety
+ - null safety
+ - ヌル安全
+ - Nullable
+ - Non-nullable
+ - null
+---
+
+## Nullable型(`?`)とNon-nullable型
+
+[[Dart]]の型システムでは、すべての型がデフォルトで **[[Non-nullable]](Null非許容)** です。
+
+値として `null` を許可したい場合のみ、型の後ろに `?` を付けて **[[Nullable]](Null許容)** として明示的に宣言します。
+
+```dart:nullable_basics.dart
+void main() {
+ // 1. Non-nullable型 (デフォルト): null を代入できない
+ String nonNullableText = 'Hello';
+ // nonNullableText = null; // コンパイルエラー!
+
+ // 2. Nullable型 (末尾に ? を付与): null を代入できる
+ String? nullableText = 'Hello';
+ nullableText = null; // OK
+
+ print('nonNullableText: $nonNullableText');
+ print('nullableText: $nullableText');
+}
+```
+
+```dart-exec:nullable_basics.dart
+nonNullableText: Hello
+nullableText: null
+```
+
+### 型プロモーション(スマートキャスト)
+
+Nullableな変数であっても、`if` 文などで `null` でないことをチェック(フロー解析)すると、そのスコープ内では自動的にNon-nullable型へと昇格(プロモート)します。
+
+```dart:flow_analysis.dart
+void printLength(String? text) {
+ if (text != null) {
+ // このブロック内では text は String? ではなく String として扱われる
+ print('文字数: ${text.length}');
+ } else {
+ print('テキストは null です');
+ }
+}
+
+void main() {
+ printLength('Dart Flutter');
+ printLength(null);
+}
+```
+
+```dart-exec:flow_analysis.dart
+文字数: 12
+テキストは null です
+```
diff --git a/public/docs/dart/2-null-safety/2-0-null-assertion.md b/public/docs/dart/2-null-safety/2-0-null-assertion.md
new file mode 100644
index 00000000..80a5c22c
--- /dev/null
+++ b/public/docs/dart/2-null-safety/2-0-null-assertion.md
@@ -0,0 +1,43 @@
+---
+id: dart-null-safety-assertion
+title: Nullアサーション(!)とその危険性
+level: 2
+question:
+ - Nullアサーション演算子 (!) はどのような時に使うべきですか?
+ - ! を付けた変数が実際に null だった場合何が起こりますか?
+ - なぜ可能な限り ! を避けるべきなのですか?
+term:
+ - Nullアサーション
+ - '!演算子'
+ - 実行時例外
+---
+
+## Nullアサーション(`!`)とその危険性
+
+**[[Nullアサーション]]演算子(`!`)** は、コンパイラに対して「この値はNullable型だが、実行時には絶対に `null` ではないとプログラマが保証する」と伝える演算子です。
+
+```dart:null_assertion.dart
+void main() {
+ String? maybeName = 'Alice';
+
+ // maybeName は String? 型だが、! を付けることで String 型として扱える
+ String definiteName = maybeName!;
+ print('名前: $definiteName');
+}
+```
+
+```dart-exec:null_assertion.dart
+名前: Alice
+```
+
+### `!` の危険性: 実行時例外の発生
+
+もし値が `null` であるにもかかわらず `!` を適用した場合、コンパイルは通過しますが、実行時に `TypeError` / `Null check operator used on a null value` 例外が発生してプログラムが強制終了します。
+
+```dart
+String? maybeNull;
+// String forced = maybeNull!; // 実行時クラッシュ!
+```
+
+> [!CAUTION]
+> `!` 演算子は、型推論やフロー解析が及ばない特定の場面(外部ライブラリとの連携など)を除き、安易に使うべきではありません。基本的には後述する **[[Null認識演算子]]** や明示的な `null` チェックを優先しましょう。
diff --git a/public/docs/dart/2-null-safety/3-0-null-aware-operators.md b/public/docs/dart/2-null-safety/3-0-null-aware-operators.md
new file mode 100644
index 00000000..e434cf51
--- /dev/null
+++ b/public/docs/dart/2-null-safety/3-0-null-aware-operators.md
@@ -0,0 +1,83 @@
+---
+id: dart-null-safety-null-aware-operators
+title: 'Null認識演算子(?.、??、??=)'
+level: 2
+question:
+ - ?. 演算子(オプショナルチェーン)の返り値の型は何になりますか?
+ - ?? 演算子(Null合流演算子)はどう使いますか?
+ - ??= 演算子はどのような動作をしますか?
+term:
+ - Null認識演算子
+ - null認識演算子
+ - オプショナルチェーン
+ - '??'
+ - '?.'
+ - '??='
+---
+
+## Null認識演算子(`?.`、`??`、`??=`)
+
+[[Dart]]には、Nullableな値を安全かつ簡潔に処理するための **[[Null認識演算子]](Null-aware operators)** が用意されています。
+
+### 1. 条件付きアクセス演算子 (`?.`)
+
+対象が `null` でなければプロパティやメソッドにアクセスし、`null` であれば `null` を返します。
+
+```dart:null_aware_access.dart
+void main() {
+ String? text;
+ // text が null なので、length にアクセスせず null を返す
+ int? length = text?.length;
+ print('length: $length');
+
+ text = 'Hello';
+ length = text?.length;
+ print('length: $length');
+}
+```
+
+```dart-exec:null_aware_access.dart
+length: null
+length: 5
+```
+
+### 2. Null合流演算子 (`??`)
+
+左辺が `null` でない場合は左辺の値を、左辺が `null` の場合は右辺のデフォルト値を返します(いわゆるElvis演算子やNullish coalescing演算子)。
+
+```dart:null_coalescing.dart
+void main() {
+ String? userName;
+ String displayName = userName ?? '名無しのユーザー';
+ print('表示名: $displayName');
+
+ userName = 'Alice';
+ displayName = userName ?? '名無しのユーザー';
+ print('表示名: $displayName');
+}
+```
+
+```dart-exec:null_coalescing.dart
+表示名: 名無しのユーザー
+表示名: Alice
+```
+
+### 3. Null認識代入演算子 (`??=`)
+
+変数が `null` の場合のみ、右辺の値を代入します。
+
+```dart:null_aware_assignment.dart
+void main() {
+ int? count;
+ count ??= 10; // count は null だったので 10 が代入される
+ print('count: $count');
+
+ count ??= 20; // count は既に 10 なので 20 は代入されない
+ print('count: $count');
+}
+```
+
+```dart-exec:null_aware_assignment.dart
+count: 10
+count: 10
+```
diff --git a/public/docs/dart/2-null-safety/4-0-late.md b/public/docs/dart/2-null-safety/4-0-late.md
new file mode 100644
index 00000000..1405f50f
--- /dev/null
+++ b/public/docs/dart/2-null-safety/4-0-late.md
@@ -0,0 +1,79 @@
+---
+id: dart-null-safety-late
+title: late 修飾子の仕組みと使いどころ
+level: 2
+question:
+ - late修飾子を付けると何が変わりますか?
+ - late変数を初期化前に参照するとどうなりますか?
+ - lateと遅延初期化(Lazy Initialization)の関係は何ですか?
+term:
+ - late
+ - 遅延初期化
+ - late修飾子
+---
+
+## `late` 修飾子の仕組みと使いどころ
+
+**`late` 修飾子** は、Non-nullableな変数の初期化を「宣言時ではなく、後から(あるいは必要になった時に)行う」ことをコンパイラに宣言するキーワードです。
+
+主な用途は以下の2点です。
+
+### 1. 宣言時には値を代入できないNon-nullable変数の初期化
+
+クラスの初期化メソッドやFlutterのライフサイクル(`initState`など)で後から値を設定する場合に使われます。
+
+```dart:late_variables.dart
+class UserProfile {
+ // 宣言時には値がないが、Non-nullableとして扱いたい
+ late String description;
+
+ void setup() {
+ description = 'Dart & Flutter開発者';
+ }
+
+ void printProfile() {
+ print(description);
+ }
+}
+
+void main() {
+ final profile = UserProfile();
+ profile.setup();
+ profile.printProfile();
+}
+```
+
+```dart-exec:late_variables.dart
+Dart & Flutter開発者
+```
+
+> [!WARNING]
+> `late` で宣言した変数を初期化する前にアクセスすると、実行時に `LateInitializationError` がスローされます。
+
+### 2. 遅延初期化(Lazy Initialization)によるパフォーマンス向上
+
+`late` 変数に初期化式を記述すると、その変数に**初めてアクセスされた瞬間**にのみ計算が行われます。重い初期化処理をオンデマンドで実行したい場合に有効です。
+
+```dart:late_lazy.dart
+String heavyComputation() {
+ print('-> 重い計算を実行中...');
+ return '計算結果: 42';
+}
+
+void main() {
+ print('プログラム開始');
+ late String lazyData = heavyComputation(); // この時点ではまだ実行されない
+
+ print('データが必要になりました:');
+ print(lazyData); // ここで初めて heavyComputation が呼ばれる
+ print('二度目の参照: $lazyData'); // 既に計算済みなので再実行はされない
+}
+```
+
+```dart-exec:late_lazy.dart
+プログラム開始
+データが必要になりました:
+-> 重い計算を実行中...
+計算結果: 42
+二度目の参照: 計算結果: 42
+```
diff --git a/public/docs/dart/2-null-safety/5-0-summary.md b/public/docs/dart/2-null-safety/5-0-summary.md
new file mode 100644
index 00000000..24703953
--- /dev/null
+++ b/public/docs/dart/2-null-safety/5-0-summary.md
@@ -0,0 +1,21 @@
+---
+id: dart-null-safety-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]の堅牢性を支える **[[Null Safety]]** について学びました。
+
+* **デフォルトでNon-nullable**: 通常の型は `null` を代入できない。`null` を許容したい場合は `String?` のように `?` を付ける。
+* **型プロモーション**: `if (x != null)` などのチェックを行うと、自動的にNon-nullable型にプロモートされる。
+* **Nullアサーション (`!`)**: 実行時エラーのリスクがあるため、どうしても必要な場合を除き使用を避ける。
+* **Null認識演算子**:
+ * `?.`: `null` でない時だけプロパティ/メソッドを呼び出す。
+ * `??`: `null` の場合のデフォルト値を指定する。
+ * `??=`: 変数が `null` の時だけ代入する。
+* **`late` 修飾子**: Non-nullable変数の初期化を遅延させたり、初回アクセス時の遅延評価(Lazy load)を行う。
+
+次の [[./3]] では、Dartにおける関数、名前付き引数、およびクロージャについて学びます。
diff --git a/public/docs/dart/2-null-safety/5-1-practice1.md b/public/docs/dart/2-null-safety/5-1-practice1.md
new file mode 100644
index 00000000..435247b6
--- /dev/null
+++ b/public/docs/dart/2-null-safety/5-1-practice1.md
@@ -0,0 +1,26 @@
+---
+id: dart-null-safety-practice1
+title: '練習問題1: Null安全なデータ処理'
+level: 3
+question:
+ - nullableなオブジェクトから安全に値を取り出すベストプラクティスは何ですか?
+ - ?? 演算子を複数チェーンさせることはできますか?
+---
+
+### 練習問題1: Null安全なデータ処理
+
+ユーザープロフィールからメールアドレスのドメイン部分を取得し、取得できない場合はデフォルト値を返すプログラムを作成してください。
+
+1. `String? email` を定義し、最初は `'user@example.com'` を代入する。
+2. `email` が `null` の場合は `'ドメイン不明'` を返す安全な処理を書く。
+ * ヒント: `email?.split('@').last ?? 'ドメイン不明'`
+3. 次に `email = null` を代入し、再度同じ処理を実行して `'ドメイン不明'` が出力されることを確認する。
+
+```dart:practice2_1.dart
+void main() {
+ // ここにコードを書いてください
+}
+```
+
+```dart-exec:practice2_1.dart
+```
diff --git a/public/docs/dart/2-null-safety/5-2-practice2.md b/public/docs/dart/2-null-safety/5-2-practice2.md
new file mode 100644
index 00000000..0b503f14
--- /dev/null
+++ b/public/docs/dart/2-null-safety/5-2-practice2.md
@@ -0,0 +1,26 @@
+---
+id: dart-null-safety-practice2
+title: '練習問題2: lateとNull認識演算子の活用'
+level: 3
+question:
+ - late変数をクラス外のトップレベルで定義した場合も遅延評価されますか?
+ - ??= 演算子を使ってキャッシュ処理を書く場合の注意点は何ですか?
+---
+
+### 練習問題2: lateとNull認識演算子の活用
+
+設定マップの初期化と、値の取得・更新を行うプログラムを作成してください。
+
+1. `late String appTitle` を定義し、初回アクセス時に `'My Dart App'` を生成する初期化式を記述する。
+2. `Map? config` 変数を `null` で定義する。
+3. `??=` 演算子を使って、`config` が `null` の場合に `{'theme': 'dark'}` を代入する。
+4. `appTitle` と `config` の中身を出力する。
+
+```dart:practice2_2.dart
+void main() {
+ // ここにコードを書いてください
+}
+```
+
+```dart-exec:practice2_2.dart
+```
diff --git a/public/docs/dart/3-functions/-intro.md b/public/docs/dart/3-functions/-intro.md
new file mode 100644
index 00000000..69d19635
--- /dev/null
+++ b/public/docs/dart/3-functions/-intro.md
@@ -0,0 +1,6 @@
+[[Dart]]において、関数は単なる実行コードのまとまりではなく、真の **[[第一級オブジェクト]]** です。
+
+関数を変数に代入したり、他の関数の引数として渡したり、戻り値として返したりすることができます。
+また、[[Flutter]]のWidgetツリー構築において必須となる「名前付き引数」や「アロー構文」、状態をカプセル化する「クロージャ」など、Dartの関数表現は非常に洗練されています。
+
+この章では、Dartの関数の定義方法、パラメータの柔軟な指定方法、そしてクロージャの仕組みを詳しく学びます。
diff --git a/public/docs/dart/3-functions/1-0-first-class.md b/public/docs/dart/3-functions/1-0-first-class.md
new file mode 100644
index 00000000..09ee80a4
--- /dev/null
+++ b/public/docs/dart/3-functions/1-0-first-class.md
@@ -0,0 +1,78 @@
+---
+id: dart-functions-first-class
+title: 第一級オブジェクトとしての関数とアロー構文
+level: 2
+question:
+ - アロー構文(=>)と通常の関数本体({})の使い分けは何ですか?
+ - Dartで関数の型(Function型)はどのように表現しますか?
+ - トップレベル関数とクラスメソッドに関数の扱いの違いはありますか?
+term:
+ - 第一級オブジェクト
+ - アロー関数
+ - '=>'
+ - 関数型
+ - Function
+---
+
+## 第一級オブジェクトとしての関数とアロー構文
+
+[[Dart]]の関数は **[[第一級オブジェクト]]** であり、`Function` 型の値として変数に代入したり、高階関数の引数として渡すことができます。
+
+### 1. 関数の基本定義
+
+```dart:function_basics.dart
+int add(int a, int b) {
+ return a + b;
+}
+
+void main() {
+ int result = add(3, 5);
+ print('3 + 5 = $result');
+}
+```
+
+```dart-exec:function_basics.dart
+3 + 5 = 8
+```
+
+### 2. アロー構文(`=>`)
+
+関数本体が単一の式(Expression)のみで構成される場合、波括弧 `{ return ...; }` の代わりに **`=>`(アロー構文)** を使って簡潔に記述できます。
+
+```dart:arrow_syntax.dart
+// 通常の関数定義
+int multiplyNormal(int a, int b) {
+ return a * b;
+}
+
+// アロー構文による定義
+int multiplyArrow(int a, int b) => a * b;
+
+void main() {
+ print('multiplyNormal: ${multiplyNormal(4, 5)}');
+ print('multiplyArrow: ${multiplyArrow(4, 5)}');
+}
+```
+
+```dart-exec:arrow_syntax.dart
+multiplyNormal: 20
+multiplyArrow: 20
+```
+
+### 3. 関数を変数に代入する
+
+```dart:first_class.dart
+void main() {
+ // 関数を変数に代入
+ int Function(int, int) operation = (a, b) => a + b;
+ print('変数から呼び出し: ${operation(10, 20)}');
+
+ operation = (a, b) => a * b;
+ print('乗算に変更: ${operation(10, 20)}');
+}
+```
+
+```dart-exec:first_class.dart
+変数から呼び出し: 30
+乗算に変更: 200
+```
diff --git a/public/docs/dart/3-functions/2-0-parameters.md b/public/docs/dart/3-functions/2-0-parameters.md
new file mode 100644
index 00000000..5402b013
--- /dev/null
+++ b/public/docs/dart/3-functions/2-0-parameters.md
@@ -0,0 +1,40 @@
+---
+id: dart-functions-parameters
+title: パラメータ(引数)の種類
+level: 2
+question:
+ - 位置パラメータと名前付きパラメータの混在は可能ですか?
+ - 引数のデフォルト値はどのように指定しますか?
+ - Dartのパラメータ設計のベストプラクティスは何ですか?
+term:
+ - 引数
+ - パラメータ
+ - 位置パラメータ
+ - デフォルト引数
+---
+
+## パラメータ(引数)の種類
+
+[[Dart]]の関数のパラメータには、大きく分けて以下の2つの分類があります。
+
+1. **必須の位置パラメータ(Required Positional Parameters)**:
+ 通常の引数。渡す順番と型が固定されます。
+2. **オプショナルパラメータ(Optional Parameters)**:
+ 省略可能な引数。さらに以下の2種類に分かれます。
+ * **[[名前付き引数]](Named Parameters)**: `{}` で囲む。呼び出し時に `name: value` で指定。
+ * **[[位置指定引数]](Optional Positional Parameters)**: `[]` で囲む。順番通りに省略可能。
+
+```dart:parameter_types.dart
+// 1. 必須の位置引数
+void greet(String name, String message) {
+ print('$nameさん、$message');
+}
+
+void main() {
+ greet('Alice', 'こんにちは');
+}
+```
+
+```dart-exec:parameter_types.dart
+Aliceさん、こんにちは
+```
diff --git a/public/docs/dart/3-functions/2-1-named-positional.md b/public/docs/dart/3-functions/2-1-named-positional.md
new file mode 100644
index 00000000..e19cc71e
--- /dev/null
+++ b/public/docs/dart/3-functions/2-1-named-positional.md
@@ -0,0 +1,69 @@
+---
+id: dart-functions-named-positional
+title: '名前付き引数({})と位置指定引数([])'
+level: 3
+question:
+ - Flutterで名前付き引数が多用される理由は何ですか?
+ - requiredキーワードを付けるとどうなりますか?
+ - 名前付き引数にデフォルト値を設定する方法を教えてください。
+term:
+ - 名前付き引数
+ - 位置指定引数
+ - optional parameter
+ - required
+ - デフォルト値
+---
+
+### 名前付き引数(`{}`)と位置指定引数(`[]`)
+
+### 1. 名前付き引数(Named Parameters)
+
+引数を `{}` で囲むと、呼び出し側で引数名を明示して渡すことができるようになります。引数の順番は自由です。
+
+* デフォルトで省略可能(Nullableか、デフォルト値が必要)。
+* **`required`** を付けると、名前付き引数でありながら省略不可(必須)にできます。
+
+```dart:named_parameters.dart
+// required で必須、デフォルト値付きで省略可能
+void createUser({
+ required String username,
+ String role = 'member',
+ int? age,
+}) {
+ print('ユーザー: $username, 権限: $role, 年齢: ${age ?? "未設定"}');
+}
+
+void main() {
+ // 引数名を指定して呼び出す(順番は自由)
+ createUser(username: 'Alice');
+ createUser(role: 'admin', username: 'Bob', age: 30);
+}
+```
+
+```dart-exec:named_parameters.dart
+ユーザー: Alice, 権限: member, 年齢: 未設定
+ユーザー: Bob, 権限: admin, 年齢: 30
+```
+
+> [!TIP]
+> [[Flutter]]のWidgetコンストラクタはほぼすべて名前付き引数で設計されています。設定項目が多くなってもコードの可読性が損なわれません。
+
+### 2. オプショナルな位置指定引数(Optional Positional Parameters)
+
+引数を `[]` で囲むと、順番通りのオプショナル引数を定義できます。
+
+```dart:optional_positional.dart
+String formatMessage(String from, String msg, [String? appName = 'MyChat']) {
+ return '[$appName] $from: $msg';
+}
+
+void main() {
+ print(formatMessage('Alice', 'Hello'));
+ print(formatMessage('Bob', 'Hi', 'FlutterApp'));
+}
+```
+
+```dart-exec:optional_positional.dart
+[MyChat] Alice: Hello
+[FlutterApp] Bob: Hi
+```
diff --git a/public/docs/dart/3-functions/3-0-anonymous-closures.md b/public/docs/dart/3-functions/3-0-anonymous-closures.md
new file mode 100644
index 00000000..537ad279
--- /dev/null
+++ b/public/docs/dart/3-functions/3-0-anonymous-closures.md
@@ -0,0 +1,79 @@
+---
+id: dart-functions-anonymous-closures
+title: 無名関数とクロージャ
+level: 2
+question:
+ - 無名関数(ラムダ式)の書き方はどのようになりますか?
+ - クロージャ(変数のキャプチャ)とは何ですか?
+ - コレクションのforEachやmapメソッドに渡す無名関数の実例を見たいです。
+term:
+ - 無名関数
+ - 匿名関数
+ - ラムダ式
+ - クロージャ
+ - closure
+ - 変数のキャプチャ
+---
+
+## 無名関数とクロージャ
+
+### 1. 無名関数(Anonymous Functions / Lambdas)
+
+関数名を付けずに定義する関数を **[[無名関数]]** と呼びます。イベントハンドラやコレクションの操作([[./4]]参照)に頻繁に利用されます。
+
+```dart:anonymous_functions.dart
+void main() {
+ final fruits = ['apple', 'banana', 'orange'];
+
+ // (item) { ... } という無名関数を forEach に渡す
+ fruits.forEach((fruit) {
+ print('フルーツ: $fruit');
+ });
+
+ // アロー構文を用いた無名関数
+ fruits.forEach((fruit) => print('UPPER: ${fruit.toUpperCase()}'));
+}
+```
+
+```dart-exec:anonymous_functions.dart
+フルーツ: apple
+フルーツ: banana
+フルーツ: orange
+UPPER: APPLE
+UPPER: BANANA
+UPPER: ORANGE
+```
+
+### 2. クロージャ(Closures)
+
+**[[クロージャ]]** とは、関数が定義されたスコープの外側の変数を「キャプチャ(保持)」し、関数が別のスコープで実行されてもその変数にアクセス・変更できる仕組みです。
+
+```dart:closures.dart
+// カウンター関数を生成する高階関数
+Function makeCounter() {
+ int count = 0; // クロージャによってキャプチャされるローカル変数
+
+ return () {
+ count++;
+ return count;
+ };
+}
+
+void main() {
+ final counter1 = makeCounter();
+ final counter2 = makeCounter();
+
+ print('counter1: ${counter1()}'); // 1
+ print('counter1: ${counter1()}'); // 2
+
+ print('counter2: ${counter2()}'); // 1 (独立した状態を持つ)
+ print('counter1: ${counter1()}'); // 3
+}
+```
+
+```dart-exec:closures.dart
+counter1: 1
+counter1: 2
+counter2: 1
+counter1: 3
+```
diff --git a/public/docs/dart/3-functions/4-0-summary.md b/public/docs/dart/3-functions/4-0-summary.md
new file mode 100644
index 00000000..0107298b
--- /dev/null
+++ b/public/docs/dart/3-functions/4-0-summary.md
@@ -0,0 +1,18 @@
+---
+id: dart-functions-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]の関数システムと表現力について学びました。
+
+* **第一級オブジェクト**: 関数は値として変数に代入したり、関数の引数・戻り値として扱える。
+* **アロー構文 (`=>`)**: 単一式を返す関数を簡潔に書ける。
+* **名前付き引数 (`{}`)**: 呼び出し時に引数名を明示でき、`required` で必須指定、デフォルト値設定が可能。
+* **位置指定引数 (`[]`)**: 順番に従って省略可能なオプショナル引数を定義できる。
+* **無名関数とクロージャ**: コールバック関数を即座に記述でき、外側のスコープの変数を安全にカプセル化(キャプチャ)できる。
+
+次の [[./4]] では、日常の開発で多用する `List`, `Set`, `Map` などのコレクションと強力なコレクション構文について学びます。
diff --git a/public/docs/dart/3-functions/4-1-practice1.md b/public/docs/dart/3-functions/4-1-practice1.md
new file mode 100644
index 00000000..8b4a4cb8
--- /dev/null
+++ b/public/docs/dart/3-functions/4-1-practice1.md
@@ -0,0 +1,30 @@
+---
+id: dart-functions-practice1
+title: '練習問題1: 名前付き引数を持つ計算関数'
+level: 3
+question:
+ - 名前付き引数でデフォルト値とrequiredを組み合わせることはできますか?
+ - 消費税計算のような関数を設計する際のベストプラクティスを教えてください。
+---
+
+### 練習問題1: 名前付き引数を持つ計算関数
+
+商品の税込金額を計算する関数 `calculateTotal` を作成してください。
+
+1. 関数 `calculateTotal` は以下の引数を持ちます。
+ * `price`: 商品本体価格(`int`, 必須の名前付き引数 `required`)
+ * `taxRate`: 消費税率(`double`, デフォルト値 `0.10` の名前付き引数)
+ * `discount`: 割引額(`int`, デフォルト値 `0` の名前付き引数)
+2. 計算式: $(\text{price} - \text{discount}) \times (1.0 + \text{taxRate})$ の整数部分(`~/ 1` または `.toInt()`)を返す。
+3. `main()` 関数で、デフォルト税率での計算と、割引・軽減税率(例: `taxRate: 0.08`)を指定した計算を実行して結果を出力する。
+
+```dart:practice3_1.dart
+// ここに関数を定義してください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice3_1.dart
+```
diff --git a/public/docs/dart/3-functions/4-2-practice2.md b/public/docs/dart/3-functions/4-2-practice2.md
new file mode 100644
index 00000000..4092bc80
--- /dev/null
+++ b/public/docs/dart/3-functions/4-2-practice2.md
@@ -0,0 +1,27 @@
+---
+id: dart-functions-practice2
+title: '練習問題2: カウンタークロージャの作成'
+level: 3
+question:
+ - クロージャでキャプチャされた変数の寿命(ライフタイム)はどうなりますか?
+ - クロージャを引数として受け取る高階関数の作り方を教えてください。
+---
+
+### 練習問題2: カウンタークロージャの作成
+
+指定したステップ数ずつ増加するカスタムカウンターを生成する関数 `createStepCounter` を作成してください。
+
+1. `int Function() createStepCounter(int step)` を定義する。
+2. 内部で初期値 `0` の変数 `current` を保持し、呼び出されるたびに `step` ずつ加算してその値を返す無名関数を返却する。
+3. `main()` でステップ数 `5` のカウンターを作成し、3回呼び出して `5`, `10`, `15` と出力されることを確認する。
+
+```dart:practice3_2.dart
+// ここに関数を定義してください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice3_2.dart
+```
diff --git a/public/docs/dart/4-collections-control/-intro.md b/public/docs/dart/4-collections-control/-intro.md
new file mode 100644
index 00000000..202976cb
--- /dev/null
+++ b/public/docs/dart/4-collections-control/-intro.md
@@ -0,0 +1,6 @@
+[[Dart]]には標準で強力なコレクション(データ構造)が備わっています。
+
+順序付きリスト `List`、重複を許さない集合 `Set`、キーと値のペア `Map` は、いずれも[[ジェネリクス]]によって厳密に型安全です。
+さらにDart独自の特徴として、リストやマップの定義内で直接条件分岐やループを展開できる **コレクション `if` / `for`** や **スプレッド演算子** があり、[[Flutter]]のWidgetツリーを構築する上で不可欠なテクニックとなっています。
+
+この章では、コレクションの基礎から高度なデータ操作・変換までを学びます。
diff --git a/public/docs/dart/4-collections-control/1-0-collections.md b/public/docs/dart/4-collections-control/1-0-collections.md
new file mode 100644
index 00000000..40fa8625
--- /dev/null
+++ b/public/docs/dart/4-collections-control/1-0-collections.md
@@ -0,0 +1,88 @@
+---
+id: dart-collections-types
+title: List、Set、Map とジェネリクス
+level: 2
+question:
+ - List、Set、Map の使い分けの基準は何ですか?
+ - コレクションのリテラル記法はどうなっていますか?
+ - 型推論で要素の型が固定される仕組みを教えてください。
+term:
+ - List
+ - Set
+ - Map
+ - コレクション
+ - ジェネリクス
+---
+
+## `List`、`Set`、`Map` とジェネリクス
+
+[[Dart]]の代表的なコレクション型には、**`List`**、**`Set`**、**`Map`** があります。すべて[[ジェネリクス]](``)に対応しており、要素の型が厳格にチェックされます。
+
+### 1. `List`: 順序付きの配列
+
+角括弧 `[]` を使ってリテラルを定義します。
+
+```dart:list_basics.dart
+void main() {
+ // 型推論により List になる
+ var fruits = ['apple', 'banana', 'orange'];
+
+ fruits.add('grape');
+ print('要素数: ${fruits.length}');
+ print('0番目: ${fruits[0]}');
+ print('全要素: $fruits');
+}
+```
+
+```dart-exec:list_basics.dart
+要素数: 4
+0番目: apple
+全要素: [apple, banana, orange, grape]
+```
+
+### 2. `Set`: 重複のない集合
+
+波括弧 `{}` を使い、要素のみをカンマ区切りで並べます。
+
+```dart:set_basics.dart
+void main() {
+ // Set
+ var numbers = {1, 2, 3, 2, 1};
+ numbers.add(4);
+ numbers.add(3); // 重複は無視される
+
+ print('Setの要素: $numbers');
+ print('2を含むか: ${numbers.contains(2)}');
+}
+```
+
+```dart-exec:set_basics.dart
+Setの要素: {1, 2, 3, 4}
+2を含むか: true
+```
+
+### 3. `Map`: キーと値のペア(連想配列)
+
+波括弧 `{}` を使い、`key: value` 形式で記述します。
+
+```dart:map_basics.dart
+void main() {
+ // Map
+ var scores = {
+ 'Alice': 95,
+ 'Bob': 80,
+ };
+
+ scores['Charlie'] = 88; // 要素の追加・更新
+ print('Aliceの点数: ${scores['Alice']}');
+ print('存在しないキー: ${scores['Dave']}'); // null が返る
+}
+```
+
+```dart-exec:map_basics.dart
+Aliceの点数: 95
+存在しないキー: null
+```
+
+> [!NOTE]
+> 空の波括弧 `{}` はデフォルトで `Map` とみなされます。空のSetを作りたい場合は `{}` や `Set()` のように型を明示します。
diff --git a/public/docs/dart/4-collections-control/2-0-collection-features.md b/public/docs/dart/4-collections-control/2-0-collection-features.md
new file mode 100644
index 00000000..04082aa5
--- /dev/null
+++ b/public/docs/dart/4-collections-control/2-0-collection-features.md
@@ -0,0 +1,87 @@
+---
+id: dart-collections-features
+title: コレクション if、for とスプレッド演算子
+level: 2
+question:
+ - コレクション if と三項演算子の違いは何ですか?
+ - スプレッド演算子 (...) と Null認識スプレッド演算子 (...?) の使い分けは何ですか?
+ - コレクション for を使うとどのようなコードが簡潔になりますか?
+term:
+ - コレクションif
+ - コレクションfor
+ - スプレッド演算子
+ - '...'
+ - '...?'
+---
+
+## コレクション `if`、`for` とスプレッド演算子
+
+[[Dart]]のコレクションリテラル内では、要素の生成ロジックとして `if`、`for`、スプレッド演算子を直接埋め込むことができます。
+
+### 1. コレクション `if`
+
+条件が `true` の場合のみ要素をコレクションに含めます。
+
+```dart:collection_if.dart
+void main() {
+ bool isAdmin = true;
+ bool isGuest = false;
+
+ var navItems = [
+ 'ホーム',
+ 'プロフィール',
+ if (isAdmin) '管理者パネル',
+ if (isGuest) 'ログイン案内',
+ ];
+
+ print(navItems);
+}
+```
+
+```dart-exec:collection_if.dart
+[ホーム, プロフィール, 管理者パネル]
+```
+
+### 2. コレクション `for`
+
+ループを使って複数の要素を動的に展開してコレクションを構築します。
+
+```dart:collection_for.dart
+void main() {
+ var numbers = [1, 2, 3];
+ var stringList = [
+ '#0',
+ for (var n in numbers) '#$n',
+ ];
+
+ print(stringList);
+}
+```
+
+```dart-exec:collection_for.dart
+[#0, #1, #2, #3]
+```
+
+### 3. スプレッド演算子 (`...` / `...?`)
+
+既存のコレクションの全要素を別のコレクション内に展開して埋め込みます。対象が `null` になり得る場合は **`...?`(Null認識スプレッド演算子)** を使用します。
+
+```dart:spread_operator.dart
+void main() {
+ var baseList = [1, 2];
+ List? extraList; // null
+
+ var combined = [
+ 0,
+ ...baseList,
+ ...?extraList, // null なので展開を安全にスキップ
+ 3,
+ ];
+
+ print(combined);
+}
+```
+
+```dart-exec:spread_operator.dart
+[0, 1, 2, 3]
+```
diff --git a/public/docs/dart/4-collections-control/3-0-higher-order.md b/public/docs/dart/4-collections-control/3-0-higher-order.md
new file mode 100644
index 00000000..2c745adf
--- /dev/null
+++ b/public/docs/dart/4-collections-control/3-0-higher-order.md
@@ -0,0 +1,76 @@
+---
+id: dart-collections-higher-order
+title: '高階関数によるデータ変換(map、where、reduce、fold)'
+level: 2
+question:
+ - Iterable と List の関係は何ですか?
+ - map や where の結果を List に変換するにはどうすればよいですか?
+ - reduce と fold の違いは何ですか?
+term:
+ - 高階関数
+ - map
+ - where
+ - reduce
+ - fold
+ - Iterable
+ - toList
+---
+
+## 高階関数によるデータ変換(`map`、`where`、`reduce`、`fold`)
+
+[[Dart]]のコレクション(`Iterable`)には、関数型プログラミングスタイルでデータを操作・集計するための便利な高階メソッドが用意されています。
+
+### 1. `where` (フィルタリング) と `map` (要素変換)
+
+* `where`: 条件を満たす(コールバックが `true` を返す)要素のみを抽出します。
+* `map`: 各要素を変換関数で別の値に写像します。
+* `toList()`: 遅延評価される `Iterable` を `List` に確定します。
+
+```dart:map_where.dart
+void main() {
+ final numbers = [1, 2, 3, 4, 5, 6];
+
+ // 偶数だけを抽出し、それぞれを2乗してListに変換
+ final result = numbers
+ .where((n) => n.isEven)
+ .map((n) => n * n)
+ .toList();
+
+ print('元のリスト: $numbers');
+ print('変換後: $result');
+}
+```
+
+```dart-exec:map_where.dart
+元のリスト: [1, 2, 3, 4, 5, 6]
+変換後: [4, 16, 36]
+```
+
+### 2. `reduce` と `fold` (畳み込み集計)
+
+* `reduce`: リストの先頭要素を初期値として要素を1つの値にまとめます(空リストではエラー)。
+* `fold`: 明示的な初期値を指定して集計を開始します(空リストでも安全、型変換も可能)。
+
+```dart:reduce_fold.dart
+void main() {
+ final numbers = [10, 20, 30, 40];
+
+ // reduce による合計
+ final sum = numbers.reduce((acc, curr) => acc + curr);
+ print('合計 (reduce): $sum');
+
+ // fold による初期値 100 からの加算
+ final totalWithBase = numbers.fold(100, (acc, curr) => acc + curr);
+ print('ベース値付き合計 (fold): $totalWithBase');
+
+ // fold で文字列結合
+ final joined = numbers.fold('値:', (acc, curr) => '$acc $curr');
+ print('文字列 (fold): $joined');
+}
+```
+
+```dart-exec:reduce_fold.dart
+合計 (reduce): 100
+ベース値付き合計 (fold): 200
+文字列 (fold): 値: 10 20 30 40
+```
diff --git a/public/docs/dart/4-collections-control/4-0-summary.md b/public/docs/dart/4-collections-control/4-0-summary.md
new file mode 100644
index 00000000..537f3899
--- /dev/null
+++ b/public/docs/dart/4-collections-control/4-0-summary.md
@@ -0,0 +1,17 @@
+---
+id: dart-collections-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]のコレクションと強力な制御構文について学びました。
+
+* **3大コレクション**: 順序配列の `List`、一意集合の `Set`、キー値ペアの `Map` を提供。
+* **コレクション `if` / `for`**: リテラル宣言の中で条件分岐やループを展開し、宣言的なリスト生成が可能。
+* **スプレッド演算子 (`...`, `...?`)**: コレクション要素の展開や、Null安全なリスト結合を実現。
+* **高階関数**: `where`(絞り込み)、`map`(変換)、`reduce` / `fold`(集計・畳み込み)をチェーンして簡潔にデータ加工ができる。
+
+次の [[./5]] では、Dart 3で導入された目玉機能である **レコード(Records)とパターンマッチング** について学びます。
diff --git a/public/docs/dart/4-collections-control/4-1-practice1.md b/public/docs/dart/4-collections-control/4-1-practice1.md
new file mode 100644
index 00000000..9749141d
--- /dev/null
+++ b/public/docs/dart/4-collections-control/4-1-practice1.md
@@ -0,0 +1,32 @@
+---
+id: dart-collections-practice1
+title: '練習問題1: コレクション操作と条件付き要素追加'
+level: 3
+question:
+ - コレクション if の中で else を使う構文はどう書きますか?
+ - Setから重複を取り除いたListを作成するにはどうすればよいですか?
+---
+
+### 練習問題1: コレクション操作と条件付き要素追加
+
+ユーザー権限と追加オプションに応じたメニュー一覧のリストを生成してください。
+
+1. 以下の変数を定義する。
+ * `bool isPremium = true;`
+ * `List? betaFeatures = ['AIアシスタント', '高速検索'];`
+2. コレクション `if`、コレクション `for`、スプレッド演算子を活用して、以下の要素を持つ `List menu` を生成する。
+ * `'ホーム'`
+ * `'設定'`
+ * `isPremium` が `true` の場合のみ `'プレミアム限定動画'`
+ * `betaFeatures` が `null` でなければその全要素を展開
+ * `'ログアウト'`
+3. `menu` の中身を出力する。
+
+```dart:practice4_1.dart
+void main() {
+ // ここにコードを書いてください
+}
+```
+
+```dart-exec:practice4_1.dart
+```
diff --git a/public/docs/dart/4-collections-control/4-2-practice2.md b/public/docs/dart/4-collections-control/4-2-practice2.md
new file mode 100644
index 00000000..b58fe903
--- /dev/null
+++ b/public/docs/dart/4-collections-control/4-2-practice2.md
@@ -0,0 +1,34 @@
+---
+id: dart-collections-practice2
+title: '練習問題2: 高階関数を使った集計処理'
+level: 3
+question:
+ - foldメソッドの初期値の型と戻り値の型の関係を教えてください。
+ - メソッドチェーンで可読性を保つインデントの書き方を教えてください。
+---
+
+### 練習問題2: 高階関数を使った集計処理
+
+商品データのリストから条件に合う商品を抽出し、合計金額を算出するプログラムを作成してください。
+
+1. 以下の商品リスト(`Map` のリスト)を用意する。
+ ```dart
+ final items = [
+ {'name': 'ノートPC', 'price': 120000, 'inStock': true},
+ {'name': 'マウス', 'price': 3000, 'inStock': false},
+ {'name': 'キーボード', 'price': 15000, 'inStock': true},
+ {'name': 'モニター', 'price': 45000, 'inStock': true},
+ ];
+ ```
+2. `where` を使って在庫がある(`inStock == true`)商品のみに絞り込む。
+3. `map` で各商品の価格(`price` as `int`)を取り出す。
+4. `fold` を使って価格の総額を計算し、`'在庫あり商品の合計金額: xxx 円'` と出力する。
+
+```dart:practice4_2.dart
+void main() {
+ // ここにコードを書いてください
+}
+```
+
+```dart-exec:practice4_2.dart
+```
diff --git a/public/docs/dart/5-records-patterns/-intro.md b/public/docs/dart/5-records-patterns/-intro.md
new file mode 100644
index 00000000..28667857
--- /dev/null
+++ b/public/docs/dart/5-records-patterns/-intro.md
@@ -0,0 +1,6 @@
+[[Dart]] 3.0で導入された最大の機能刷新が、**[[レコード]](Records)** と **[[パターンマッチング]](Pattern Matching)** です。
+
+従来のオブジェクト指向言語では、複数の値をまとめて返したい場合に一時的なデータクラスを定義する必要がありました。
+Dart 3では、型安全かつ軽量なレコード型や、データの形状と値に応じて直感的に分岐・分解できるパターンマッチング、そして式として評価できる `switch` 式が利用可能になりました。
+
+この章では、現代のDart開発においてコードを劇的に簡潔にするこれらの最新機能をマスターします。
diff --git a/public/docs/dart/5-records-patterns/1-0-records.md b/public/docs/dart/5-records-patterns/1-0-records.md
new file mode 100644
index 00000000..f411179d
--- /dev/null
+++ b/public/docs/dart/5-records-patterns/1-0-records.md
@@ -0,0 +1,69 @@
+---
+id: dart-records-intro
+title: レコード(Records)による複数戻り値の実現
+level: 2
+question:
+ - レコードとクラス(Class)の違いは何ですか?
+ - 位置指定フィールドと名前付きフィールドを持つレコードはどう書きますか?
+ - レコードのフィールド値を取得するための構文($1, $2, フィールド名)を教えてください。
+term:
+ - レコード
+ - Records
+ - record
+ - タプル
+---
+
+## レコード(Records)による複数戻り値の実現
+
+**[[レコード]](Records)** は、複数の値を1つにまとめることができる匿名かつ不変(イミュータブル)な集約型(いわゆるタプル)です。
+
+専用のクラスを定義することなく、関数から複数の値を型安全に返すことができます。
+
+### 1. 位置指定フィールド(Positional Fields)
+
+丸括弧 `()` で値を囲むことでレコードを作成します。各フィールドには `$1`, `$2` でアクセスします。
+
+```dart:positional_records.dart
+// (String, int) 型のレコードを返す関数
+(String, int) getUserInfo() {
+ return ('Alice', 25);
+}
+
+void main() {
+ final user = getUserInfo();
+ print('名前 (\$1): ${user.$1}');
+ print('年齢 (\$2): ${user.$2}');
+}
+```
+
+```dart-exec:positional_records.dart
+名前 ($1): Alice
+年齢 ($2): 25
+```
+
+### 2. 名前付きフィールド(Named Fields)
+
+波括弧 `{}` を使うことで、フィールドに名前を付けることができます。
+
+```dart:named_records.dart
+// 名前付きフィールドを持つレコード型
+({String name, int age, bool isAdmin}) getDetailedUser() {
+ return (name: 'Bob', age: 30, isAdmin: true);
+}
+
+void main() {
+ final user = getDetailedUser();
+ print('名前: ${user.name}');
+ print('年齢: ${user.age}');
+ print('管理者: ${user.isAdmin}');
+}
+```
+
+```dart-exec:named_records.dart
+名前: Bob
+年齢: 30
+管理者: true
+```
+
+> [!NOTE]
+> レコードは値の同一性(Equality)を持ちます。同じフィールドと値を持つ2つのレコードは `==` で比較した際に `true` になります。
diff --git a/public/docs/dart/5-records-patterns/2-0-destructuring.md b/public/docs/dart/5-records-patterns/2-0-destructuring.md
new file mode 100644
index 00000000..b1e9e729
--- /dev/null
+++ b/public/docs/dart/5-records-patterns/2-0-destructuring.md
@@ -0,0 +1,63 @@
+---
+id: dart-patterns-destructuring
+title: 分解(Destructuring)によるデータの抽出
+level: 2
+question:
+ - レコードやListから直接変数に分解代入する方法はどう書きますか?
+ - 分解時に一部の値を無視するにはどうすればよいですか?
+ - Mapの分解代入はどのように行いますか?
+term:
+ - パターン分解
+ - 分解代入
+ - Destructuring
+ - ワイルドカード
+---
+
+## 分解(Destructuring)によるデータの抽出
+
+Dart 3のパターン構文を使用すると、レコード、List、Mapなどの複合データ構造を宣言的に分解(**[[分解代入]]**)して個別のローカル変数に抽出できます。
+
+### 1. レコードの分解
+
+```dart:destructure_records.dart
+(String, int) getCoords() => ('Tokyo', 100);
+({int x, int y}) getPoint() => (x: 10, y: 20);
+
+void main() {
+ // 位置レコードの分解
+ final (city, population) = getCoords();
+ print('都市: $city, 人口: $population 万人');
+
+ // 名前付きレコードの分解 (フィールド名と同名の変数にバインド)
+ final (:x, :y) = getPoint();
+ print('座標: x=$x, y=$y');
+}
+```
+
+```dart-exec:destructure_records.dart
+都市: Tokyo, 人口: 100 万人
+座標: x=10, y=20
+```
+
+### 2. List と Map の分解
+
+リストの要素数や中身に一致するパターンを使って値を抽出できます。不要な要素は `_`(ワイルドカード)で無視できます。
+
+```dart:destructure_collections.dart
+void main() {
+ // List の分解
+ final numbers = [1, 2, 3, 4];
+ final [first, second, _, fourth] = numbers;
+ print('1番目: $first, 2番目: $second, 4番目: $fourth');
+
+ // Map の分解
+ final json = {'id': 'user_123', 'status': 'active'};
+ final {'id': String userId, 'status': String userStatus} = json;
+ print('ユーザーID: $userId, ステータス: $userStatus');
+}
+```
+
+```dart-exec:destructure_collections.dart
+1番目: 1, 2番目: 2, 4番目: 4
+ユーザーID: user_123, ステータス: active
+```
diff --git a/public/docs/dart/5-records-patterns/3-0-switch-expressions.md b/public/docs/dart/5-records-patterns/3-0-switch-expressions.md
new file mode 100644
index 00000000..ca17b36b
--- /dev/null
+++ b/public/docs/dart/5-records-patterns/3-0-switch-expressions.md
@@ -0,0 +1,81 @@
+---
+id: dart-patterns-switch
+title: パターンマッチングと switch 式
+level: 2
+question:
+ - switch文とswitch式の違いは何ですか?
+ - switch式での網羅性チェック(Exhaustiveness checking)とは何ですか?
+ - switch式の中でパターンマッチングを使って型判定と値の取り出しを同時に行う方法は?
+term:
+ - パターンマッチング
+ - switch式
+ - 網羅性チェック
+ - switch文
+---
+
+## パターンマッチングと `switch` 式
+
+従来の `switch` 文(Statement)に加え、Dart 3では評価結果の値を返す **`switch` 式(Expression)** が導入されました。
+
+### 1. `switch` 式の基本構文
+
+* `case` や `break` キーワードが不要になり、`パターン => 式` の簡潔な構文になります。
+* すべてのケースが網羅されているかコンパイラが厳密に検証する **[[網羅性チェック]]** が働きます。
+
+```dart:switch_expression.dart
+String describeHttpCode(int statusCode) {
+ return switch (statusCode) {
+ 200 => '成功 (OK)',
+ 400 => '不正なリクエスト (Bad Request)',
+ 404 => '未検出 (Not Found)',
+ 500 => 'サーバーエラー (Internal Server Error)',
+ _ => '不明なステータスコード ($statusCode)', // デフォルトケース
+ };
+}
+
+void main() {
+ print(describeHttpCode(200));
+ print(describeHttpCode(404));
+ print(describeHttpCode(418));
+}
+```
+
+```dart-exec:switch_expression.dart
+成功 (OK)
+未検出 (Not Found)
+不明なステータスコード (418)
+```
+
+### 2. オブジェクトやコレクションのパターンマッチング
+
+`switch` 式の中でデータの形状を検証しながら変数を取り出すことができます。
+
+```dart:pattern_matching_complex.dart
+String formatData(dynamic data) {
+ return switch (data) {
+ // 整数で 0 の場合
+ 0 => 'ゼロ',
+ // 正の整数の場合 (関係演算子パターン)
+ int n && > 0 => '正の整数: $n',
+ // 2要素のリストの場合
+ [var a, var b] => '2要素リスト: ($a, $b)',
+ // 特定のキーを持つマップの場合
+ {'name': String name, 'age': int age} => '名前: $name, 年齢: $age',
+ _ => 'その他のデータ',
+ };
+}
+
+void main() {
+ print(formatData(10));
+ print(formatData(['apple', 'banana']));
+ print(formatData({'name': 'Alice', 'age': 20}));
+ print(formatData(false));
+}
+```
+
+```dart-exec:pattern_matching_complex.dart
+正の整数: 10
+2要素リスト: (apple, banana)
+名前: Alice, 年齢: 20
+その他のデータ
+```
diff --git a/public/docs/dart/5-records-patterns/4-0-guards.md b/public/docs/dart/5-records-patterns/4-0-guards.md
new file mode 100644
index 00000000..0dbdda79
--- /dev/null
+++ b/public/docs/dart/5-records-patterns/4-0-guards.md
@@ -0,0 +1,47 @@
+---
+id: dart-patterns-guards
+title: Guard句(when)を使った条件分岐
+level: 2
+question:
+ - when句(ガード節)はパターンマッチのどの位置に記述しますか?
+ - when句の条件が満たされなかった場合、処理はどう流れますか?
+ - 複雑なビジネスロジックでwhen句を活用する具体例を見たいです。
+term:
+ - Guard句
+ - when
+ - ガード節
+---
+
+## Guard句(`when`)を使った条件分岐
+
+パターンマッチングに **`when` 節(Guard句)** を組み合わせることで、パターンの形状が一致した上でさらに任意のブール条件を課すことができます。
+
+条件が `false` であれば次のマッチング候補へとフォールスルー(移動)します。
+
+```dart:guards_example.dart
+String evaluateScore((String, int) student) {
+ return switch (student) {
+ (var name, var score) when score == 100 => '$nameさん: 満点!素晴らしい!',
+ (var name, var score) when score >= 80 => '$nameさん: 優秀です (点数: $score)',
+ (var name, var score) when score >= 60 => '$nameさん: 合格 (点数: $score)',
+ (var name, var score) => '$nameさん: 要再試験 (点数: $score)',
+ };
+}
+
+void main() {
+ print(evaluateScore(('Alice', 100)));
+ print(evaluateScore(('Bob', 85)));
+ print(evaluateScore(('Charlie', 62)));
+ print(evaluateScore(('Dave', 45)));
+}
+```
+
+```dart-exec:guards_example.dart
+Aliceさん: 満点!素晴らしい!
+Bobさん: 優秀です (点数: 85)
+Charlieさん: 合格 (点数: 62)
+Daveさん: 要再試験 (点数: 45)
+```
+
+> [!TIP]
+> `when` 句を活用することで、ネストした `if-else` 文を平坦で美しい宣言的パターンに置き換えることができます。
diff --git a/public/docs/dart/5-records-patterns/5-0-summary.md b/public/docs/dart/5-records-patterns/5-0-summary.md
new file mode 100644
index 00000000..cd8e0a61
--- /dev/null
+++ b/public/docs/dart/5-records-patterns/5-0-summary.md
@@ -0,0 +1,17 @@
+---
+id: dart-records-patterns-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]] 3で導入された **[[レコード]]** と **[[パターンマッチング]]** について学びました。
+
+* **レコード(Records)**: クラスを自作することなく、複数の値を型安全に返却・グループ化できる軽量なデータ構造。位置指定・名前付きフィールドに対応。
+* **分解(Destructuring)**: レコード、List、Mapなどの複合データから必要な変数だけを一度に抽出できる。
+* **`switch` 式**: 式として評価され、コンパイラによる網羅性チェックが働く安全でコンパクトな条件分岐。
+* **Guard句 (`when`)**: パターンの形状一致に加えて追加のブール条件をスマートに記述できる。
+
+次の [[./6]] では、オブジェクト指向プログラミングの中核である **クラスと各種コンストラクタ** について学びます。
diff --git a/public/docs/dart/5-records-patterns/5-1-practice1.md b/public/docs/dart/5-records-patterns/5-1-practice1.md
new file mode 100644
index 00000000..abf6be6e
--- /dev/null
+++ b/public/docs/dart/5-records-patterns/5-1-practice1.md
@@ -0,0 +1,27 @@
+---
+id: dart-records-patterns-practice1
+title: '練習問題1: レコードを使った座標計算'
+level: 3
+question:
+ - 名前付きフィールドを持つレコードの型注釈はどう書きますか?
+ - レコードの分解代入時に型を明示することはできますか?
+---
+
+### 練習問題1: レコードを使った座標計算
+
+2点間のマンハッタン距離と中点の座標を同時に計算して返す関数を作成してください。
+
+1. 2次元座標を表すレコード型 `({int x, int y})` を引数として2つ受け取る関数 `analyzePoints` を定義する。
+2. 戻り値として、マンハッタン距離 `distance`($|x_1 - x_2| + |y_1 - y_2|$)と中点 `midpoint`(レコード `(double x, double y)`)を含む名前付きレコード `({int distance, (double, double) midpoint})` を返す。
+3. `main()` で `p1 = (x: 0, y: 0)` と `p2 = (x: 4, y: 6)` を渡して呼び出し、分解代入で結果を受け取って出力する。
+
+```dart:practice5_1.dart
+// ここに関数を定義してください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice5_1.dart
+```
diff --git a/public/docs/dart/5-records-patterns/5-2-practice2.md b/public/docs/dart/5-records-patterns/5-2-practice2.md
new file mode 100644
index 00000000..44b2b1cf
--- /dev/null
+++ b/public/docs/dart/5-records-patterns/5-2-practice2.md
@@ -0,0 +1,30 @@
+---
+id: dart-records-patterns-practice2
+title: '練習問題2: switch式とパターンマッチによるコマンドパーサー'
+level: 3
+question:
+ - switch式でListの要素数をチェックするパターンの書き方を教えてください。
+ - when句を使って引数の値のバリデーションを行う例を教えてください。
+---
+
+### 練習問題2: switch式とパターンマッチによるコマンドパーサー
+
+CLIツールに入力された文字列コマンド(引数リスト `List`)を解析する関数 `handleCommand` を作成してください。
+
+1. `handleCommand(List command)` を定義し、`switch` 式を使って以下のパターンを処理する。
+ * `['help']` => `'ヘルプを表示します'`
+ * `['view', var id]` => `'ID: $id の詳細を表示します'`
+ * `['create', var name, var countStr]` when `int.tryParse(countStr) != null` => `'新規作成: $name ($countStr 個)'`
+ * `_` => `'無効なコマンドです'`
+2. `main()` でそれぞれのコマンドパターンを渡し、正しく分岐されることを確認する。
+
+```dart:practice5_2.dart
+// ここに関数を定義してください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice5_2.dart
+```
diff --git a/public/docs/dart/6-classes/-intro.md b/public/docs/dart/6-classes/-intro.md
new file mode 100644
index 00000000..0320f603
--- /dev/null
+++ b/public/docs/dart/6-classes/-intro.md
@@ -0,0 +1,6 @@
+[[Dart]]は純粋なオブジェクト指向プログラミング言語であり、すべてのデータ型はクラスを基盤としています。
+
+Dartのクラス設計には、コードのボイラープレート(定型文)を大幅に削減するための強力な仕組みが揃っています。
+例えば、インスタンス変数の自動初期化糖衣構文(`this.field`)、名前付きコンストラクタ、ライブラリ単位のカプセル化、そしてインスタンス生成ロジックを柔軟に制御できる `factory` コンストラクタなどです。
+
+この章では、Dartにおけるクラスの基礎から実践的なオブジェクトモデリングまでを徹底解説します。
diff --git a/public/docs/dart/6-classes/1-0-classes.md b/public/docs/dart/6-classes/1-0-classes.md
new file mode 100644
index 00000000..bd39ce35
--- /dev/null
+++ b/public/docs/dart/6-classes/1-0-classes.md
@@ -0,0 +1,52 @@
+---
+id: dart-classes-basics
+title: クラスの定義とインスタンス化(newの省略)
+level: 2
+question:
+ - なぜDartではnewキーワードを省略できるのですか?
+ - コンストラクタで this.field を使う構文のメリットは何ですか?
+ - メソッド内で this を明示する必要があるのはどのような場合ですか?
+term:
+ - クラス
+ - class
+ - インスタンス
+ - new
+ - メソッド
+---
+
+## クラスの定義とインスタンス化(`new`の省略)
+
+[[Dart]]でオブジェクトの設計図となる **[[クラス]](`class`)** を定義し、インスタンスを生成する基本的な構文を見てみましょう。
+
+### 1. クラス定義とコンストラクタの糖衣構文
+
+Dartでは、引数をそのままフィールドに代入する場合、`Point(this.x, this.y);` のように宣言するだけで初期化処理が完了します。
+
+```dart:point_class.dart
+class Point {
+ // フィールド(インスタンス変数)
+ final double x;
+ final double y;
+
+ // コンストラクタ(糖衣構文 this.x, this.y)
+ Point(this.x, this.y);
+
+ // メソッド
+ void printCoordinates() {
+ print('Point($x, $y)');
+ }
+}
+
+void main() {
+ // new キーワードは完全に省略可能
+ final p1 = Point(3.0, 4.0);
+ p1.printCoordinates();
+}
+```
+
+```dart-exec:point_class.dart
+Point(3.0, 4.0)
+```
+
+> [!NOTE]
+> Dart 2以降、インスタンス生成時の `new` キーワードは省略するのが公式スタイルガイドの標準です(`new Point(...)` と書くことも文法上は可能ですが、通常は書きません)。
diff --git a/public/docs/dart/6-classes/2-0-constructors.md b/public/docs/dart/6-classes/2-0-constructors.md
new file mode 100644
index 00000000..242b1a5a
--- /dev/null
+++ b/public/docs/dart/6-classes/2-0-constructors.md
@@ -0,0 +1,68 @@
+---
+id: dart-classes-constructors
+title: 様々なコンストラクタ(名前付き、リダイレクト)
+level: 2
+question:
+ - 名前付きコンストラクタはどのような時に便利ですか?
+ - リダイレクトコンストラクタの構文はどう書きますか?
+ - constコンストラクタを定義するための要件は何ですか?
+term:
+ - コンストラクタ
+ - 名前付きコンストラクタ
+ - リダイレクトコンストラクタ
+ - constコンストラクタ
+---
+
+## 様々なコンストラクタ(名前付き、リダイレクト)
+
+Dartでは、1つのクラスに複数の異なる初期化方法を提供するために **[[名前付きコンストラクタ]]** や **[[リダイレクトコンストラクタ]]** を作成できます。
+
+### 1. 名前付きコンストラクタ(Named Constructors)
+
+`ClassName.constructorName(...)` の形式で定義します。JavaやC++のオーバーロードと異なり、コンストラクタの意図が名前によって明確になります。
+
+### 2. リダイレクトコンストラクタ(Redirecting Constructors)
+
+別のコンストラクタに初期化処理を委譲(リダイレクト)するコンストラクタです。コロン `:` に続けて `this(...)` を呼び出します。
+
+### 3. `const` コンストラクタ
+
+すべてのフィールドが `final` で構成されている場合、コンストラクタに `const` を付与してコンパイル時定数インスタンスを生成できます。
+
+```dart:constructors_demo.dart
+class User {
+ final String name;
+ final int age;
+
+ // 基本コンストラクタ (const対応)
+ const User(this.name, this.age);
+
+ // 1. 名前付きコンストラクタ
+ User.guest()
+ : name = 'ゲスト',
+ age = 0;
+
+ // 2. リダイレクトコンストラクタ (基本コンストラクタを呼び出す)
+ User.adult(String name) : this(name, 20);
+
+ void display() {
+ print('ユーザー: $name (年齢: $age)');
+ }
+}
+
+void main() {
+ const u1 = User('Alice', 25);
+ final u2 = User.guest();
+ final u3 = User.adult('Bob');
+
+ u1.display();
+ u2.display();
+ u3.display();
+}
+```
+
+```dart-exec:constructors_demo.dart
+ユーザー: Alice (年齢: 25)
+ユーザー: ゲスト (年齢: 0)
+ユーザー: Bob (年齢: 20)
+```
diff --git a/public/docs/dart/6-classes/3-0-initializer-super.md b/public/docs/dart/6-classes/3-0-initializer-super.md
new file mode 100644
index 00000000..56807135
--- /dev/null
+++ b/public/docs/dart/6-classes/3-0-initializer-super.md
@@ -0,0 +1,76 @@
+---
+id: dart-classes-initializer-super
+title: '初期化子リスト(:)と super の呼び出し'
+level: 2
+question:
+ - 初期化子リストとコンストラクタ本体の実行順序はどうなっていますか?
+ - superパラメータ(super.field)を使うとコードがどう短縮されますか?
+ - 初期化子リスト内でassertを使って引数を検証する方法を教えてください。
+term:
+ - 初期化子リスト
+ - super
+ - superパラメータ
+ - 継承
+---
+
+## 初期化子リスト(`:`)と `super` の呼び出し
+
+### 1. 初期化子リスト(Initializer List)
+
+コンストラクタ本体 `{}` が実行される前に、フィールドの計算や `assert` による引数検証を行うには、引数リストの後にコロン `:` を付けて **[[初期化子リスト]]** を記述します。
+
+```dart:initializer_list.dart
+class Rectangle {
+ final double width;
+ final double height;
+ final double area;
+
+ // 初期化子リストで面積 (area) を事前計算
+ Rectangle(this.width, this.height)
+ : area = width * height,
+ assert(width > 0, 'width は正の数である必要があります'),
+ assert(height > 0, 'height は正の数である必要があります');
+
+ void display() {
+ print('幅: $width, 高さ: $height, 面積: $area');
+ }
+}
+
+void main() {
+ final rect = Rectangle(5.0, 8.0);
+ rect.display();
+}
+```
+
+```dart-exec:initializer_list.dart
+幅: 5.0, 高さ: 8.0, 面積: 40.0
+```
+
+### 2. 親クラスのコンストラクタ呼び出し (`super` / `super.field`)
+
+子クラスのコンストラクタから親クラスのコンストラクタに値を渡すには、初期化子リストで `: super(...)` を呼び出すか、Dart 2.17で追加された **`super.field`(Super Parameters)** を使います。
+
+```dart:super_params.dart
+class Person {
+ final String name;
+ Person(this.name);
+}
+
+class Employee extends Person {
+ final String department;
+
+ // super.name で親クラスのコンストラクタへ引数を直接転送
+ Employee(super.name, this.department);
+
+ void info() => print('社員: $name, 部署: $department');
+}
+
+void main() {
+ final emp = Employee('Charlie', '開発部');
+ emp.info();
+}
+```
+
+```dart-exec:super_params.dart
+社員: Charlie, 部署: 開発部
+```
diff --git a/public/docs/dart/6-classes/4-0-encapsulation-getter-setter.md b/public/docs/dart/6-classes/4-0-encapsulation-getter-setter.md
new file mode 100644
index 00000000..c6b089ac
--- /dev/null
+++ b/public/docs/dart/6-classes/4-0-encapsulation-getter-setter.md
@@ -0,0 +1,71 @@
+---
+id: dart-classes-encapsulation
+title: カプセル化(_ によるプライベート化と get / set)
+level: 2
+question:
+ - Dartには private や public キーワードがないのですか?
+ - アンダースコア _ でプライベート化されるスコープの単位は何ですか?
+ - ゲッター(get)とセッター(set)の構文はどう書きますか?
+term:
+ - カプセル化
+ - プライベート変数
+ - ゲッター
+ - セッター
+ - getter
+ - setter
+ - ライブラリスコープ
+---
+
+## カプセル化(`_` によるプライベート化と `get` / `set`)
+
+### 1. `_` によるプライベート化
+
+[[Dart]]には `public`、`private`、`protected` といったアクセス修飾子キーワードがありません。
+識別子の先頭に **アンダースコア `_`** を付けることで、その要素は **ライブラリ(同一ファイル)プライベート** になります。
+
+> [!IMPORTANT]
+> Dartのプライベート化は「クラス単位」ではなく「ファイル(ライブラリ)単位」です。同一ファイル内であれば別クラスからでも `_` の付いた要素にアクセスできますが、別ファイルから `import` された場合は完全に非公開になります。
+
+### 2. ゲッター(`get`)とセッター(`set`)
+
+プロパティアクセスのように振る舞うメソッドとして、`get` と `set` を定義できます。
+
+```dart:bank_account.dart
+class BankAccount {
+ // プライベートフィールド
+ double _balance = 0.0;
+
+ // ゲッター
+ double get balance => _balance;
+
+ // セッター
+ set balance(double value) {
+ if (value < 0) {
+ print('エラー: 残高を負の値にすることはできません');
+ return;
+ }
+ _balance = value;
+ }
+
+ void deposit(double amount) {
+ if (amount > 0) _balance += amount;
+ }
+}
+
+void main() {
+ final account = BankAccount();
+ account.deposit(5000);
+ print('残高: ${account.balance} 円');
+
+ account.balance = 8000; // セッターの呼び出し
+ print('更新後残高: ${account.balance} 円');
+
+ account.balance = -100; // 不正な値
+}
+```
+
+```dart-exec:bank_account.dart
+残高: 5000.0 円
+更新後残高: 8000.0 円
+エラー: 残高を負の値にすることはできません
+```
diff --git a/public/docs/dart/6-classes/5-0-factory-constructors.md b/public/docs/dart/6-classes/5-0-factory-constructors.md
new file mode 100644
index 00000000..1d0a1aeb
--- /dev/null
+++ b/public/docs/dart/6-classes/5-0-factory-constructors.md
@@ -0,0 +1,90 @@
+---
+id: dart-classes-factory
+title: factory コンストラクタ(シングルトンやJSONパースの実装)
+level: 2
+question:
+ - 通常のコンストラクタと factory コンストラクタの決定的な違いは何ですか?
+ - factory コンストラクタを使ってシングルトンパターンを実装する方法を教えてください。
+ - fromJson などのファクトリメソッドが factory として定義される理由は何ですか?
+term:
+ - factoryコンストラクタ
+ - factory
+ - ファクトリコンストラクタ
+ - シングルトン
+ - fromJson
+---
+
+## `factory` コンストラクタ(シングルトンやJSONパースの実装)
+
+通常のコンストラクタは常にそのクラスの「新しいインスタンス」を生成しますが、**`factory` コンストラクタ** を使うと、コンストラクタ構文でありながら以下の制御が可能になります。
+
+1. 既存のキャッシュ済みインスタンス(**[[シングルトン]]**)を返す。
+2. サブクラスのインスタンスを生成して返す。
+3. 条件に応じたインスタンス生成ロジック(JSONからのデシリアライズなど)をカプセル化する。
+
+### 1. シングルトンパターンの実装
+
+```dart:singleton_demo.dart
+class DatabaseService {
+ final String dbName;
+
+ // プライベートな静的インスタンス
+ static DatabaseService? _instance;
+
+ // プライベートな通常コンストラクタ
+ DatabaseService._internal(this.dbName);
+
+ // factory コンストラクタ: 常に同一のインスタンスを返す
+ factory DatabaseService({String dbName = 'main.db'}) {
+ _instance ??= DatabaseService._internal(dbName);
+ return _instance!;
+ }
+}
+
+void main() {
+ final db1 = DatabaseService();
+ final db2 = DatabaseService();
+
+ print('同一インスタンスか: ${identical(db1, db2)}');
+}
+```
+
+```dart-exec:singleton_demo.dart
+同一インスタンスか: true
+```
+
+### 2. JSONパース用 `fromJson` ファクトリ
+
+```dart:factory_from_json.dart
+class Product {
+ final String id;
+ final String title;
+ final int price;
+
+ const Product({
+ required this.id,
+ required this.title,
+ required this.price,
+ });
+
+ // Map から Product を構築する factory コンストラクタ
+ factory Product.fromJson(Map json) {
+ return Product(
+ id: json['id'] as String,
+ title: json['title'] as String,
+ price: json['price'] as int,
+ );
+ }
+}
+
+void main() {
+ final jsonMap = {'id': 'p_01', 'title': 'メカニカルキーボード', 'price': 14800};
+ final product = Product.fromJson(jsonMap);
+
+ print('商品: ${product.title} (¥${product.price})');
+}
+```
+
+```dart-exec:factory_from_json.dart
+商品: メカニカルキーボード (¥14800)
+```
diff --git a/public/docs/dart/6-classes/6-0-summary.md b/public/docs/dart/6-classes/6-0-summary.md
new file mode 100644
index 00000000..82344dc3
--- /dev/null
+++ b/public/docs/dart/6-classes/6-0-summary.md
@@ -0,0 +1,18 @@
+---
+id: dart-classes-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]のオブジェクト指向の根幹となるクラスとコンストラクタについて学びました。
+
+* **クラスとインスタンス化**: `this.field` による簡潔な初期化が可能で、`new` キーワードは省略するのが標準。
+* **多彩なコンストラクタ**: 名前付きコンストラクタ(`User.guest()`)、リダイレクトコンストラクタ(`: this(...)`)、定数生成のための `const` コンストラクタ。
+* **初期化子リストと `super`**: コロン `:` に続くフィールド事前計算やバリデーション、`super.field` による親クラスへの引数転送。
+* **カプセル化**: アンダースコア `_` でライブラリ単位のプライベート化を実現し、`get` / `set` で安全にプロパティを公開。
+* **`factory` コンストラクタ**: キャッシュ済みインスタンスの返却(シングルトン)や、`fromJson` などのカスタム生成ロジックを実現。
+
+次の [[./7]] では、継承、インターフェース、Mixin、拡張メソッド(Extension)による **クラスの拡張と高度な設計パターン** を学びます。
diff --git a/public/docs/dart/6-classes/6-1-practice1.md b/public/docs/dart/6-classes/6-1-practice1.md
new file mode 100644
index 00000000..a69eecbe
--- /dev/null
+++ b/public/docs/dart/6-classes/6-1-practice1.md
@@ -0,0 +1,29 @@
+---
+id: dart-classes-practice1
+title: '練習問題1: カプセル化されたBankAccountクラス'
+level: 3
+question:
+ - ゲッターのみを定義して読み取り専用プロパティを作るメリットは何ですか?
+ - コンストラクタで初期残高を受け取りつつ、負の値を防ぐにはどうすればよいですか?
+---
+
+### 練習問題1: カプセル化されたBankAccountクラス
+
+口座名義と残高を管理する `BankAccount` クラスを実装してください。
+
+1. プライベート変数 `String _owner` と `int _balance` を持つ。
+2. コンストラクタ `BankAccount(this._owner, this._balance)` を定義する(初期残高が負でないことを `assert` または初期化子リストで確認)。
+3. 読み取り専用ゲッター `owner` と `balance` を定義する。
+4. メソッド `void withdraw(int amount)` を定義し、残高が十分な場合は引き落としを行い、不足している場合は `'残高不足です'` と出力する。
+5. `main()` でインスタンスを生成し、引き落とし処理をテストする。
+
+```dart:practice6_1.dart
+// ここにクラスを定義してください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice6_1.dart
+```
diff --git a/public/docs/dart/6-classes/6-2-practice2.md b/public/docs/dart/6-classes/6-2-practice2.md
new file mode 100644
index 00000000..fd17f5d1
--- /dev/null
+++ b/public/docs/dart/6-classes/6-2-practice2.md
@@ -0,0 +1,29 @@
+---
+id: dart-classes-practice2
+title: '練習問題2: factoryコンストラクタによるJSONパース'
+level: 3
+question:
+ - JSONパースでnullが渡される可能性がある場合の安全な書き方を教えてください。
+ - toString() メソッドをオーバーライドするメリットは何ですか?
+---
+
+### 練習問題2: factoryコンストラクタによるJSONパース
+
+Web APIから受信したユーザー設定データを表す `UserSettings` クラスを実装してください。
+
+1. フィールドとして `final String theme`(テーマ名)と `final bool notificationsEnabled`(通知有無)を持つ。
+2. 通常のコンストラクタ `const UserSettings({required this.theme, required this.notificationsEnabled});` を定義する。
+3. `factory UserSettings.fromJson(Map json)` を実装し、Mapから各プロパティをパースしてインスタンスを返す。
+ * `theme` が未指定の場合は `'light'`、`notificationsEnabled` が未指定の場合は `true` をデフォルト値とする。
+4. `main()` でJSONマップを渡し、パースされた設定内容を出力する。
+
+```dart:practice6_2.dart
+// ここにクラスを定義してください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice6_2.dart
+```
diff --git a/public/docs/dart/7-class-extension/-intro.md b/public/docs/dart/7-class-extension/-intro.md
new file mode 100644
index 00000000..56bf2ee9
--- /dev/null
+++ b/public/docs/dart/7-class-extension/-intro.md
@@ -0,0 +1,5 @@
+[[Dart]]のクラス設計は、単なる単一継承にとどまらず、柔軟で再利用性の高いコード構造を実現するための高度な機能を豊富に備えています。
+
+すべてのクラスが暗黙的にインターフェースとして機能する「暗黙的インターフェース」、多重継承のメリットを安全に享受できる「Mixin(ミキシン)」、既存のSDKクラスに新しいメソッドを生やすことができる「拡張メソッド(Extension)」、そしてメソッドやプロパティを持てる「Enhanced Enum」などです。
+
+この章では、Dartならではのオブジェクト設計のベストプラクティスを学びます。
diff --git a/public/docs/dart/7-class-extension/1-0-extends-implements.md b/public/docs/dart/7-class-extension/1-0-extends-implements.md
new file mode 100644
index 00000000..8bf680c6
--- /dev/null
+++ b/public/docs/dart/7-class-extension/1-0-extends-implements.md
@@ -0,0 +1,66 @@
+---
+id: dart-classes-extends-implements
+title: extends(継承)と implements(インターフェース実装)の違い
+level: 2
+question:
+ - なぜDartには interface キーワードが別途不要だったのですか?
+ - implements を使った場合、親クラスの実装コードは引き継がれますか?
+ - 多重継承が禁止されている一方で implements を複数指定できる理由は何ですか?
+term:
+ - extends
+ - 継承
+ - implements
+ - 暗黙的インターフェース
+ - インターフェース
+ - ''
+---
+
+## `extends`(継承)と `implements`(インターフェース実装)の違い
+
+[[Dart]]では、すべてのクラスが自動的に **[[暗黙的インターフェース]](Implicit Interface)** を定義しています。これにより、任意のクラスを `implements` の対象として利用できます。
+
+### 1. `extends` (単一継承)
+
+親クラスの実装(メソッドの処理やフィールド)をそのまま引き継ぎます。Dartでは多重継承(複数のクラスを `extends` すること)はできません。
+
+### 2. `implements` (インターフェース実装)
+
+親クラスの「型のシグネチャ(メソッド名や引数・戻り値の型)」だけを満たすことを約束します。親クラスの実装コードは**一切引き継がれず、すべてのメソッドを再定義(`@override`)する必要があります**。カンマ区切りで複数のインターフェースを実装可能です。
+
+```dart:extends_implements.dart
+class Animal {
+ void speak() {
+ print('動物が鳴きます');
+ }
+}
+
+// 1. extends: 実装を引き継ぎ、必要に応じてオーバーライド
+class Dog extends Animal {
+ @override
+ void speak() {
+ print('ワンワン!');
+ }
+}
+
+// 2. implements: 型だけを流用し、全メソッドを自前で再実装
+class RobotDog implements Animal {
+ @override
+ void speak() {
+ print('ビープ!ワンワン (電子音)');
+ }
+}
+
+void makeNoise(Animal animal) {
+ animal.speak();
+}
+
+void main() {
+ makeNoise(Dog());
+ makeNoise(RobotDog());
+}
+```
+
+```dart-exec:extends_implements.dart
+ワンワン!
+ビープ!ワンワン (電子音)
+```
diff --git a/public/docs/dart/7-class-extension/2-0-mixins.md b/public/docs/dart/7-class-extension/2-0-mixins.md
new file mode 100644
index 00000000..c6470ca8
--- /dev/null
+++ b/public/docs/dart/7-class-extension/2-0-mixins.md
@@ -0,0 +1,62 @@
+---
+id: dart-classes-mixins
+title: Mixin(mixin、with)による機能の注入
+level: 2
+question:
+ - Mixinと継承の違いは何ですか?
+ - onキーワードを使ってMixinを特定の基底クラスに限定する方法は?
+ - 複数のMixinを with で組み合わせた場合のメソッド解決順序はどうなりますか?
+term:
+ - Mixin
+ - mixin
+ - with
+ - 機能の注入
+ - on
+---
+
+## Mixin(`mixin`、`with`)による機能の注入
+
+**[[Mixin]]** は、クラス階層に縛られることなく、複数のクラス間で実装コード(メソッドやプロパティ)を共有・注入するための仕組みです。
+
+`mixin` キーワードで定義し、クラスに `with` キーワードで適用します。
+
+```dart:mixins_demo.dart
+// 1. ロギング機能を提供する Mixin
+mixin Logger {
+ void log(String message) {
+ print('[LOG ${DateTime.now().hour}:${DateTime.now().minute}] $message');
+ }
+}
+
+// 2. 永続化機能を提供する Mixin
+mixin Serializable {
+ Map toJson();
+}
+
+// クラスに with で複数の Mixin を合成
+class AppUser with Logger, Serializable {
+ final String name;
+ AppUser(this.name);
+
+ void login() {
+ log('ユーザー $name がログインしました');
+ }
+
+ @override
+ Map toJson() => {'name': name};
+}
+
+void main() {
+ final user = AppUser('Alice');
+ user.login();
+ print('JSON: ${user.toJson()}');
+}
+```
+
+```dart-exec:mixins_demo.dart
+[LOG 5:20] ユーザー Alice がログインしました
+JSON: {name: Alice}
+```
+
+> [!TIP]
+> Mixin内で特定のクラスの機能を利用したい場合は、`mixin MyMixin on SomeBaseClass` のように `on` 節を指定して制約をかけることができます。
diff --git a/public/docs/dart/7-class-extension/3-0-extension-methods.md b/public/docs/dart/7-class-extension/3-0-extension-methods.md
new file mode 100644
index 00000000..fd9cc52d
--- /dev/null
+++ b/public/docs/dart/7-class-extension/3-0-extension-methods.md
@@ -0,0 +1,56 @@
+---
+id: dart-classes-extensions
+title: Extension(拡張メソッド)による既存クラスへの機能追加
+level: 2
+question:
+ - 拡張メソッドを使うと標準ライブラリのクラス(Stringやintなど)にメソッドを追加できますか?
+ - 拡張メソッドの定義構文はどう書きますか?
+ - ジェネリクスやゲッターをExtensionで定義することはできますか?
+term:
+ - Extension
+ - 拡張メソッド
+ - extension
+ - extension on
+---
+
+## Extension(拡張メソッド)による既存クラスへの機能追加
+
+**[[Extension]](拡張メソッド)** を使うと、既存のクラス(Dartの組み込み型やサードパーティ製ライブラリのクラス)のソースコードを変更することなく、新しいメソッドやゲッター、演算子を追加できます。
+
+構文は `extension ExtensionName on TargetType { ... }` です。
+
+```dart:extension_methods.dart
+// String クラスに拡張メソッドを追加
+extension StringExtensions on String {
+ // ゲッター: 先頭文字を大文字にする
+ String get capitalize {
+ if (isEmpty) return this;
+ return this[0].toUpperCase() + substring(1);
+ }
+
+ // メソッド: 安全に整数に変換する
+ int? toIntOrNull() => int.tryParse(this);
+}
+
+// List に特化した拡張
+extension NumberListExtension on List {
+ int get sum => fold(0, (a, b) => a + b);
+}
+
+void main() {
+ String word = 'flutter';
+ print('capitalize: ${word.capitalize}');
+
+ String numStr = '42';
+ print('toIntOrNull: ${numStr.toIntOrNull()}');
+
+ List numbers = [10, 20, 30];
+ print('sum: ${numbers.sum}');
+}
+```
+
+```dart-exec:extension_methods.dart
+capitalize: Flutter
+toIntOrNull: 42
+sum: 60
+```
diff --git a/public/docs/dart/7-class-extension/4-0-enhanced-enums.md b/public/docs/dart/7-class-extension/4-0-enhanced-enums.md
new file mode 100644
index 00000000..c6164730
--- /dev/null
+++ b/public/docs/dart/7-class-extension/4-0-enhanced-enums.md
@@ -0,0 +1,56 @@
+---
+id: dart-classes-enhanced-enums
+title: 高機能な列挙型(Enhanced Enum)
+level: 2
+question:
+ - 通常のenumとEnhanced Enumの違いは何ですか?
+ - Enumにフィールドやメソッド、コンストラクタを持たせるにはどう書きますか?
+ - Enhanced Enumとswitch式を組み合わせるメリットは何ですか?
+term:
+ - Enum
+ - 列挙型
+ - Enhanced Enum
+ - enum
+ - enumコンストラクタ
+---
+
+## 高機能な列挙型(Enhanced Enum)
+
+Dart 2.17以降の **[[Enhanced Enum]]** では、列挙型の各値にフィールド(値)、コンストラクタ、ゲッター、メソッドを持たせることができます。
+
+単なる定数の列挙を超えて、型安全で表現力豊かなドメインモデルを簡潔に定義できます。
+
+```dart:enhanced_enums.dart
+enum HttpStatus {
+ ok(200, 'Success'),
+ notFound(404, 'Not Found'),
+ serverError(500, 'Internal Server Error');
+
+ // フィールド
+ final int code;
+ final String description;
+
+ // const コンストラクタ
+ const HttpStatus(this.code, this.description);
+
+ // ゲッター
+ bool get isSuccess => code >= 200 && code < 300;
+
+ // メソッド
+ void log() {
+ print('[$code] $description (成功: $isSuccess)');
+ }
+}
+
+void main() {
+ final status = HttpStatus.notFound;
+ status.log();
+
+ print('HttpStatus.ok isSuccess: ${HttpStatus.ok.isSuccess}');
+}
+```
+
+```dart-exec:enhanced_enums.dart
+[404] Not Found (成功: false)
+HttpStatus.ok isSuccess: true
+```
diff --git a/public/docs/dart/7-class-extension/5-0-summary.md b/public/docs/dart/7-class-extension/5-0-summary.md
new file mode 100644
index 00000000..b430f2cb
--- /dev/null
+++ b/public/docs/dart/7-class-extension/5-0-summary.md
@@ -0,0 +1,17 @@
+---
+id: dart-class-extension-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]の高度なオブジェクト指向設計機能について学びました。
+
+* **`extends` vs `implements`**: `extends` は実装コードを引き継ぎ、`implements` は暗黙的インターフェースの型契約のみを満たす。
+* **Mixin (`mixin`, `with`)**: 継承階層とは直交して、複数クラスへ横断的な機能・振る舞いを注入する。
+* **Extension (`extension on`)**: 既存のクラスを変更することなく、便利メソッドやプロパティを外付けで拡張する。
+* **Enhanced Enum**: フィールド、コンストラクタ、メソッドを持つ高機能な列挙型。
+
+次の [[./8]] では、Dart 3で導入された `sealed`, `base`, `interface`, `final` などの **クラス修飾子** を使った厳密なドメインモデリングを学びます。
diff --git a/public/docs/dart/7-class-extension/5-1-practice1.md b/public/docs/dart/7-class-extension/5-1-practice1.md
new file mode 100644
index 00000000..634a439d
--- /dev/null
+++ b/public/docs/dart/7-class-extension/5-1-practice1.md
@@ -0,0 +1,28 @@
+---
+id: dart-class-extension-practice1
+title: '練習問題1: Mixinを用いたロギング機能の追加'
+level: 3
+question:
+ - Mixinの中で自身を特定のクラス型として扱うにはどうしますか?
+ - クラス名を取得する runtimeType プロパティの使い方を教えてください。
+---
+
+### 練習問題1: Mixinを用いたロギング機能の追加
+
+イベントの発生ログを出力する `PrintableLogger` Mixin を作成し、クラスに適用してください。
+
+1. `mixin PrintableLogger` を定義する。
+ * メソッド `void logEvent(String eventName)` を持ち、`'[${runtimeType}] イベント発生: $eventName'` と出力する。
+2. `class OrderService with PrintableLogger` を定義し、メソッド `void checkout(String itemId)` 内で `logEvent('注文完了: $itemId')` を呼び出す。
+3. `main()` で `OrderService` のインスタンスを作成し、`checkout('item_999')` を実行する。
+
+```dart:practice7_1.dart
+// ここにコードを書いてください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice7_1.dart
+```
diff --git a/public/docs/dart/7-class-extension/5-2-practice2.md b/public/docs/dart/7-class-extension/5-2-practice2.md
new file mode 100644
index 00000000..4b3c11df
--- /dev/null
+++ b/public/docs/dart/7-class-extension/5-2-practice2.md
@@ -0,0 +1,28 @@
+---
+id: dart-class-extension-practice2
+title: '練習問題2: Extensionを用いた文字列ユーティリティ'
+level: 3
+question:
+ - Extensionのスコープ(ライブラリ内でのみ有効かエクスポート可能か)について教えてください。
+ - 拡張メソッド内で元のオブジェクト(this)を変更することはできますか?
+---
+
+### 練習問題2: Extensionを用いた文字列ユーティリティ
+
+`String` クラスに対して、特定の文字列操作を行う拡張メソッドを実装してください。
+
+1. `extension StringUtils on String` を定義する。
+ * ゲッター `bool get isEmail`: 文字列に `@` と `.` が含まれているかを簡易判定する。
+ * メソッド `String mask({int visibleCount = 2})`: 先頭から `visibleCount` 文字だけ残し、以降を `*` でマスクした文字列を返す(文字数が `visibleCount` 以下の場合はそのまま返す)。
+2. `main()` で `'user@example.com'` に対する `isEmail` の判定結果と、`mask()` によるマスク文字列(例: `'us**************'`)を出力する。
+
+```dart:practice7_2.dart
+// ここにコードを書いてください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice7_2.dart
+```
diff --git a/public/docs/dart/8-class-modifiers/-intro.md b/public/docs/dart/8-class-modifiers/-intro.md
new file mode 100644
index 00000000..dca9658a
--- /dev/null
+++ b/public/docs/dart/8-class-modifiers/-intro.md
@@ -0,0 +1,5 @@
+[[Dart]] 3.0では、ライブラリの作者がクラスの継承・実装・インスタンス化の権限をきめ細かく制御できるように、**[[クラス修飾子]](Class Modifiers)** が導入されました。
+
+特に **`sealed` クラス** は、RustのEnumやKotlinのSealed Class、TypeScriptのTagged Union(判別可能なUnion型)に相当する **[[代数的データ型]](ADT)** をDartで美しく実現し、`switch` 式と組み合わせることで網羅性チェックの恩恵を最大限に引き出します。
+
+この章では、`sealed`, `base`, `interface`, `final` 修飾子の役割と、堅牢なドメインモデル設計を学びます。
diff --git a/public/docs/dart/8-class-modifiers/1-0-sealed-classes.md b/public/docs/dart/8-class-modifiers/1-0-sealed-classes.md
new file mode 100644
index 00000000..e38695cb
--- /dev/null
+++ b/public/docs/dart/8-class-modifiers/1-0-sealed-classes.md
@@ -0,0 +1,68 @@
+---
+id: dart-class-modifiers-sealed
+title: sealed クラスによる代数的データ型(ADT)とSwitchの組み合わせ
+level: 2
+question:
+ - sealedクラスを定義する主な目的は何ですか?
+ - sealedクラスのサブクラスはどこで定義する必要がありますか?
+ - switch式でsealedクラスの全パターンを網羅しないとどうなりますか?
+term:
+ - sealed
+ - sealedクラス
+ - 代数的データ型
+ - ADT
+ - 網羅性
+---
+
+## `sealed` クラスによる代数的データ型(ADT)とSwitchの組み合わせ
+
+**`sealed` クラス** は、そのクラスを直接インスタンス化できず(暗黙的に `abstract`)、**サブクラスの定義を同一ライブラリ(同一ファイル)内のみに限定する** 修飾子です。
+
+コンパイラは「そのクラスのサブクラスの全パターン」を完全に把握できるため、`switch` 式で**[[網羅性チェック]]**が働きます。
+
+```dart:sealed_demo.dart
+// 1. sealed クラスでUI状態の基底クラスを定義
+sealed class UiState {}
+
+class InitialState extends UiState {}
+class LoadingState extends UiState {}
+class SuccessState extends UiState {
+ final List data;
+ SuccessState(this.data);
+}
+class ErrorState extends UiState {
+ final String message;
+ ErrorState(this.message);
+}
+
+// 2. switch式で状態に応じたレンダリング文字列を生成
+String render(UiState state) {
+ // 全サブクラスが網羅されているため、default (_) 節が不要!
+ return switch (state) {
+ InitialState() => '待機中...',
+ LoadingState() => '読み込み中...',
+ SuccessState(:var data) => 'データ取得成功: ${data.join(', ')}',
+ ErrorState(:var message) => 'エラー発生: $message',
+ };
+}
+
+void main() {
+ UiState state = LoadingState();
+ print(render(state));
+
+ state = SuccessState(['Dart', 'Flutter']);
+ print(render(state));
+
+ state = ErrorState('ネットワーク接続に失敗しました');
+ print(render(state));
+}
+```
+
+```dart-exec:sealed_demo.dart
+読み込み中...
+データ取得成功: Dart, Flutter
+エラー発生: ネットワーク接続に失敗しました
+```
+
+> [!TIP]
+> 新しい状態(例: `OfflineState`)を後から追加した際、`render` 関数内でそのケースを書き忘れていると、コンパイラがビルド時に「すべてのケースが網羅されていません」と即座にエラーを教えてくれます。
diff --git a/public/docs/dart/8-class-modifiers/2-0-other-modifiers.md b/public/docs/dart/8-class-modifiers/2-0-other-modifiers.md
new file mode 100644
index 00000000..96598b41
--- /dev/null
+++ b/public/docs/dart/8-class-modifiers/2-0-other-modifiers.md
@@ -0,0 +1,61 @@
+---
+id: dart-class-modifiers-base-interface-final
+title: base、interface、final 修飾子の使い分け
+level: 2
+question:
+ - base修飾子を付けると外部パッケージでどのような制約が課されますか?
+ - interface修飾子と通常のclassの違いは何ですか?
+ - final修飾子をクラスに付けた場合、継承や実装はどう制限されますか?
+term:
+ - base
+ - interface修飾子
+ - final修飾子
+ - クラス修飾子
+ - abstract
+---
+
+## `base`、`interface`、`final` 修飾子の使い分け
+
+[[Dart]] 3では、ライブラリ境界外(外部パッケージや別ファイル)からのクラス利用方法を制限するために、以下のクラス修飾子が提供されています。
+
+| 修飾子 | 外部でのインスタンス化 | 外部での `extends` (継承) | 外部での `implements` (実装) | 外部での `with` (Mixin) |
+| :--- | :---: | :---: | :---: | :---: |
+| **`class` (無印)** | ○ | ○ | ○ | × |
+| **`base`** | ○ | **○ (`base` 必須)** | × | × |
+| **`interface`** | ○ | × | **○** | × |
+| **`final`** | ○ | × | × | × |
+| **`sealed`** | × (abstract) | × (同ファイル内のみ) | × (同ファイル内のみ) | × |
+
+### 1. `base`: 継承のみを許可し、暗黙的インターフェースのimplementsを禁止
+
+クラスに新しいメソッドを追加しても、外部のサブクラスが壊れないように設計したい場合に利用します。
+
+```dart
+// 外部ライブラリ側
+base class Vehicle {
+ void move() => print('移動中');
+}
+
+// 利用側
+// class Car implements Vehicle {} // コンパイルエラー: implements 不可
+base class Car extends Vehicle {} // OK (子クラスも base/final/sealed が必要)
+```
+
+### 2. `interface`: 実装(implements)のみを許可し、継承を禁止
+
+APIの型シグネチャのみを提供し、内部実装の継承による依存を防ぎたい場合に利用します。
+
+```dart
+interface class StorageService {
+ void save(String key, String value) {}
+}
+// class LocalStorage extends StorageService {} // エラー: 外部から extends 不可
+class LocalStorage implements StorageService { // OK: implements のみ許可
+ @override
+ void save(String key, String value) => print('Saved $key');
+}
+```
+
+### 3. `final`: 外部からの継承・実装を完全に禁止
+
+クラスの動作を完全に固定し、サブクラス化を一切許さない場合に使用します。
diff --git a/public/docs/dart/8-class-modifiers/3-0-domain-modeling.md b/public/docs/dart/8-class-modifiers/3-0-domain-modeling.md
new file mode 100644
index 00000000..5e862562
--- /dev/null
+++ b/public/docs/dart/8-class-modifiers/3-0-domain-modeling.md
@@ -0,0 +1,72 @@
+---
+id: dart-class-modifiers-domain-modeling
+title: ドメインモデルの堅牢な設計方法
+level: 2
+question:
+ - アプリケーションの状態管理でsealedクラスを活用するベストプラクティスは何ですか?
+ - 不正な状態の表現を型レベルで不可能にするにはどうすればよいですか?
+ - イミュータブルなデータモデルを作るコツを教えてください。
+term:
+ - ドメインモデル
+ - 状態モデリング
+ - イミュータブル
+ - 型安全
+---
+
+## ドメインモデルの堅牢な設計方法
+
+クラス修飾子(特に `sealed`)とDart 3のパターンマッチングを組み合わせることで、**「不正な状態を型レベルで表現不可能にする(Make Impossible States Impossible)」** 堅牢な[[ドメインモデル]]が構築できます。
+
+### 認証状態のモデリング例
+
+フラグ変数(`bool isLoggedIn`, `String? token`, `String? errorMessage`)をバラバラに持つ代わりに、状態そのものを `sealed` クラスの階層として定義します。
+
+```dart:auth_state_modeling.dart
+sealed class AuthState {
+ const AuthState();
+}
+
+class AuthUnauthenticated extends AuthState {
+ const AuthUnauthenticated();
+}
+
+class AuthAuthenticating extends AuthState {
+ const AuthAuthenticating();
+}
+
+class AuthAuthenticated extends AuthState {
+ final String userId;
+ final String token;
+ const AuthAuthenticated({required this.userId, required this.token});
+}
+
+class AuthError extends AuthState {
+ final String errorMessage;
+ const AuthError(this.errorMessage);
+}
+
+void printAuthAction(AuthState state) {
+ final action = switch (state) {
+ AuthUnauthenticated() => 'ログインボタンを表示します',
+ AuthAuthenticating() => 'スピナーを表示して待機します',
+ AuthAuthenticated(:var userId) => 'ユーザー $userId のマイページを表示します',
+ AuthError(:var errorMessage) => 'エラーダイアログを表示: $errorMessage',
+ };
+ print(action);
+}
+
+void main() {
+ AuthState state = const AuthAuthenticating();
+ printAuthAction(state);
+
+ state = const AuthAuthenticated(userId: 'u_777', token: 'jwt_abc123');
+ printAuthAction(state);
+}
+```
+
+```dart-exec:auth_state_modeling.dart
+スピナーを表示して待機します
+ユーザー u_777 のマイページを表示します
+```
+
+この設計により、「ログイン中なのにトークンが `null` である」といった不整合な状態が存在し得なくなり、UIのバグを大幅に減らすことができます。
diff --git a/public/docs/dart/8-class-modifiers/4-0-summary.md b/public/docs/dart/8-class-modifiers/4-0-summary.md
new file mode 100644
index 00000000..06039277
--- /dev/null
+++ b/public/docs/dart/8-class-modifiers/4-0-summary.md
@@ -0,0 +1,18 @@
+---
+id: dart-class-modifiers-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]] 3のクラス修飾子によるモデリングの厳密化について学びました。
+
+* **`sealed` クラス**: 同一ファイル内のみでサブクラス定義を制限し、代数的データ型(ADT)と `switch` 式の完全な網羅性チェックを実現。
+* **`base` 修飾子**: 継承のみを許可し、暗黙的インターフェースとしての `implements` を防ぐ。
+* **`interface` 修飾子**: インターフェース実装(`implements`)のみを許可し、実装の継承を防ぐ。
+* **`final` 修飾子**: 外部からの継承と実装を両方禁止する。
+* **ドメインモデリング**: 状態をフラグではなく型として分割定義し、不正な状態を排除する設計手法。
+
+次の [[./9]] では、Dartのイベント駆動アーキテクチャの中核である **非同期処理の基礎(Futureとasync/await)** を学びます。
diff --git a/public/docs/dart/8-class-modifiers/4-1-practice1.md b/public/docs/dart/8-class-modifiers/4-1-practice1.md
new file mode 100644
index 00000000..04612113
--- /dev/null
+++ b/public/docs/dart/8-class-modifiers/4-1-practice1.md
@@ -0,0 +1,32 @@
+---
+id: dart-class-modifiers-practice1
+title: '練習問題1: sealedクラスを用いたUI状態のモデリング'
+level: 3
+question:
+ - sealedクラスを基底にした場合のジェネリクス型の指定方法はどうなりますか?
+ - switch式で各サブクラスのフィールドをパターンマッチで取り出す際の注意点は?
+---
+
+### 練習問題1: sealedクラスを用いたUI状態のモデリング
+
+天気予報アプリの画面状態を表す `WeatherState` を `sealed` クラスで実装してください。
+
+1. `sealed class WeatherState` を定義する。
+2. 以下のサブクラスを作成する。
+ * `class WeatherInitial extends WeatherState`
+ * `class WeatherLoading extends WeatherState`
+ * `class WeatherSuccess extends WeatherState`: フィールド `final String city`, `final double temperature` を持つ。
+ * `class WeatherFailure extends WeatherState`: フィールド `final String error` を持つ。
+3. `String getWeatherMessage(WeatherState state)` 関数を `switch` 式で実装し、全状態に応じた適切なメッセージ文字列を返す。
+4. `main()` で各状態を作成し、メッセージを出力する。
+
+```dart:practice8_1.dart
+// ここにクラスと関数を定義してください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice8_1.dart
+```
diff --git a/public/docs/dart/8-class-modifiers/4-2-practice2.md b/public/docs/dart/8-class-modifiers/4-2-practice2.md
new file mode 100644
index 00000000..42805fe3
--- /dev/null
+++ b/public/docs/dart/8-class-modifiers/4-2-practice2.md
@@ -0,0 +1,28 @@
+---
+id: dart-class-modifiers-practice2
+title: '練習問題2: クラス修飾子による安全なAPI設計'
+level: 3
+question:
+ - abstract interface class と書くことの意味は何ですか?
+ - baseクラスを継承するクラスに付けなければならない修飾子のルールを復習したいです。
+---
+
+### 練習問題2: クラス修飾子による安全なAPI設計
+
+キャッシュストレージのインターフェースと、基底となるローカルストレージ実装を設計してください。
+
+1. `abstract interface class CacheRepository` を定義し、メソッド `T? get(String key);` と `void set(String key, T value);` を宣言する。
+2. `base class MemoryCacheRepository implements CacheRepository` を実装し、内部の `Map` にデータを保存・取得する処理を実装する。
+3. `final class ExpiringMemoryCache extends MemoryCacheRepository` を定義する。
+4. `main()` で `ExpiringMemoryCache` を生成し、データの追加と取得をテストする。
+
+```dart:practice8_2.dart
+// ここにクラスを定義してください
+
+void main() {
+ // ここで動作確認を行ってください
+}
+```
+
+```dart-exec:practice8_2.dart
+```
diff --git a/public/docs/dart/9-async-future/-intro.md b/public/docs/dart/9-async-future/-intro.md
new file mode 100644
index 00000000..6c4cde33
--- /dev/null
+++ b/public/docs/dart/9-async-future/-intro.md
@@ -0,0 +1,5 @@
+ネットワーク通信、データベース読み書き、ファイルの入出力など、完了までに時間のかかる処理をUIスレッドで同期的に実行すると、アプリ画面がフリーズしてしまいます。
+
+[[Dart]]はシングルスレッドのイベントループモデルを採用しており、処理をブロックすることなく非同期にタスクを実行するための仕組みとして **`Future`** と **`async` / `await`** を提供しています。
+
+この章では、Dartのイベントループの概念から、非同期関数の書き方、エラーハンドリングまでを学びます。
diff --git a/public/docs/dart/9-async-future/1-0-event-loop.md b/public/docs/dart/9-async-future/1-0-event-loop.md
new file mode 100644
index 00000000..a79687e9
--- /dev/null
+++ b/public/docs/dart/9-async-future/1-0-event-loop.md
@@ -0,0 +1,44 @@
+---
+id: dart-async-event-loop
+title: 同期処理と非同期処理の違い(イベントループの概念)
+level: 2
+question:
+ - Dartのシングルスレッドモデルで非同期処理が並行して進む仕組みは何ですか?
+ - イベントキューとマイクロタスクキューの違いは何ですか?
+ - JavaScriptのイベントループとDartのイベントループの違いはありますか?
+term:
+ - イベントループ
+ - マイクロタスク
+ - イベントキュー
+ - 非同期処理
+ - シングルスレッド
+---
+
+## 同期処理と非同期処理の違い(イベントループの概念)
+
+[[Dart]]コードは基本的に単一のスレッド(**[[シングルスレッド]]**)上で動作します。処理が重い計算でスレッドを長時間占有すると、描画やタップ入力がブロックされてしまいます。
+
+Dartはこの問題を **[[イベントループ]](Event Loop)** によって解決しています。
+
+```
+ +----------------------------+
+ | 現在実行中のコード |
+ +-------------+--------------+
+ | (完了)
+ v
++---------------------------+---------------------------+
+| イベントループ (Event Loop) |
+| |
+| 1. マイクロタスクキュー (Microtask Queue) - 最優先 |
+| [ Microtask 1 ] -> [ Microtask 2 ] |
+| |
+| 2. イベントキュー (Event Queue) - 通常の非同期タスク |
+| [ I/O完了 ] -> [ タイマー発火 ] -> [ タップイベント ] |
++-------------------------------------------------------+
+```
+
+1. **実行中タスク**: 現在実行しているDartコードが完了するまで走り切ります。
+2. **マイクロタスクキュー**: 最優先で処理される内部タスクのキュー。
+3. **イベントキュー**: 外部からのI/Oイベント、タイマー、描画リクエスト、UI操作などを処理するキュー。
+
+非同期処理(`Future`)をスケジューリングすると、現在のコードの実行が終わった後、イベントループが順番にそれを取り出して実行します。
diff --git a/public/docs/dart/9-async-future/2-0-future.md b/public/docs/dart/9-async-future/2-0-future.md
new file mode 100644
index 00000000..916662f1
--- /dev/null
+++ b/public/docs/dart/9-async-future/2-0-future.md
@@ -0,0 +1,57 @@
+---
+id: dart-async-future
+title: Future の仕組み
+level: 2
+question:
+ - Futureとは具体的に何を表すオブジェクトですか?
+ - Futureの状態(Uncompleted, Completed with data, Completed with error)について教えてください。
+ - then() と catchError() を使ったコールバック記法はどう書きますか?
+term:
+ - Future
+ - Future.value
+ - Future.delayed
+ - then
+ - コールバック
+---
+
+## `Future` の仕組み
+
+**`Future`** は、「将来のある時点で値 `T` またはエラーを返す非同期処理の結果」を表すオブジェクトです(JavaScriptの `Promise` や Rustの `Future` に相当します)。
+
+### Futureの3つの状態
+
+1. **未完了(Uncompleted)**: 非同期処理が実行中で、まだ結果が出ていない状態。
+2. **完了(Completed with data)**: 処理が正常に完了し、値が得られた状態。
+3. **エラー完了(Completed with error)**: 例外が発生して失敗した状態。
+
+### Futureの生成と `then()` による購読
+
+```dart:future_basics.dart
+Future fetchUserGreeting() {
+ // 100ミリ秒後に完了する Future を生成
+ return Future.delayed(
+ const Duration(milliseconds: 100),
+ () => 'こんにちは、ユーザーさん!',
+ );
+}
+
+void main() {
+ print('1. 処理開始');
+
+ fetchUserGreeting().then((greeting) {
+ print('3. データ受信: $greeting');
+ }).catchError((error) {
+ print('エラー: $error');
+ });
+
+ print('2. メイン関数の同期処理完了');
+}
+```
+
+```dart-exec:future_basics.dart
+1. 処理開始
+2. メイン関数の同期処理完了
+3. データ受信: こんにちは、ユーザーさん!
+```
+
+`then()` コールバックをチェーンするスタイルも可能ですが、コードがネストしやすいため、通常は次に解説する `async` / `await` を使用します。
diff --git a/public/docs/dart/9-async-future/3-0-async-await.md b/public/docs/dart/9-async-future/3-0-async-await.md
new file mode 100644
index 00000000..3c329d80
--- /dev/null
+++ b/public/docs/dart/9-async-future/3-0-async-await.md
@@ -0,0 +1,75 @@
+---
+id: dart-async-async-await
+title: async / await による可読性の高い非同期コード
+level: 2
+question:
+ - asyncキーワードを付けた関数の戻り値型は何になりますか?
+ - awaitキーワードはどこで使用できますか?
+ - Future.waitを使って複数の非同期タスクを並行実行する方法を教えてください。
+term:
+ - async
+ - await
+ - async/await
+ - Future.wait
+ - 並行実行
+---
+
+## `async` / `await` による可読性の高い非同期コード
+
+**`async`** と **`await`** キーワードを使うことで、非同期コードを同期コードと同じような直線的で読みやすいフローで記述できます。
+
+* 関数宣言の後に `async` を付けると、その関数は自動的に `Future` を返す非同期関数になります。
+* `async` 関数内でのみ、`Future` の完了を待機する **`await`** 式が使えます。
+
+```dart:async_await_demo.dart
+Future fetchUserId() async {
+ await Future.delayed(const Duration(milliseconds: 50));
+ return 42;
+}
+
+Future fetchUserName(int id) async {
+ await Future.delayed(const Duration(milliseconds: 50));
+ return 'Alice (ID: $id)';
+}
+
+Future displayUser() async {
+ print('ユーザー情報を取得中...');
+ final id = await fetchUserId();
+ final name = await fetchUserName(id);
+ print('取得完了: $name');
+}
+
+void main() async {
+ await displayUser();
+}
+```
+
+```dart-exec:async_await_demo.dart
+ユーザー情報を取得中...
+取得完了: Alice (ID: 42)
+```
+
+### 複数の非同期処理を並行実行する (`Future.wait`)
+
+互いに依存しない複数の非同期処理を同時に実行したい場合は、`Future.wait` を使います。
+
+```dart:future_wait.dart
+Future fetchPostTitle() async => 'Dart 3の紹介';
+Future fetchLikeCount() async => 128;
+
+void main() async {
+ // 並行して実行し、両方の完了を待つ
+ final results = await Future.wait([
+ fetchPostTitle(),
+ fetchLikeCount(),
+ ]);
+
+ print('タイトル: ${results[0]}');
+ print('いいね数: ${results[1]}');
+}
+```
+
+```dart-exec:future_wait.dart
+タイトル: Dart 3の紹介
+いいね数: 128
+```
diff --git a/public/docs/dart/9-async-future/4-0-async-error-handling.md b/public/docs/dart/9-async-future/4-0-async-error-handling.md
new file mode 100644
index 00000000..a477bd89
--- /dev/null
+++ b/public/docs/dart/9-async-future/4-0-async-error-handling.md
@@ -0,0 +1,60 @@
+---
+id: dart-async-error-handling
+title: 非同期処理のエラーハンドリング(try-catch-finally)
+level: 2
+question:
+ - async/await でのエラーハンドリングは通常の try-catch と同じですか?
+ - 非同期例外を確実に捕捉するための注意点は何ですか?
+ - finally ブロックはどのような場面で活用されますか?
+term:
+ - 非同期エラーハンドリング
+ - catchError
+ - try-catch-finally
+ - try
+ - catch
+ - finally
+---
+
+## 非同期処理のエラーハンドリング(`try-catch-finally`)
+
+`async` / `await` を使った非同期処理では、同期コードと全く同じ **`try-catch-finally`** 構文でエラーを捕捉できます。
+
+```dart:async_try_catch.dart
+Future loadDataFromServer({required bool shouldFail}) async {
+ await Future.delayed(const Duration(milliseconds: 50));
+ if (shouldFail) {
+ throw Exception('ネットワーク接続が切断されました');
+ }
+ return '正常データレスポンス';
+}
+
+Future handleRequest(bool shouldFail) async {
+ try {
+ print('リクエスト送信...');
+ final data = await loadDataFromServer(shouldFail: shouldFail);
+ print('成功: $data');
+ } catch (e) {
+ print('例外をキャッチ: $e');
+ } finally {
+ print('リソースクリーンアップ完了\n');
+ }
+}
+
+void main() async {
+ await handleRequest(false);
+ await handleRequest(true);
+}
+```
+
+```dart-exec:async_try_catch.dart
+リクエスト送信...
+成功: 正常データレスポンス
+リソースクリーンアップ完了
+
+リクエスト送信...
+例外をキャッチ: Exception: ネットワーク接続が切断されました
+リソースクリーンアップ完了
+```
+
+> [!TIP]
+> `await` を付け忘れた `Future` で例外が発生すると、`try-catch` ブロックをすり抜けて未処理の非同期例外(Uncaught asynchronous error)となるため注意してください。
diff --git a/public/docs/dart/9-async-future/5-0-summary.md b/public/docs/dart/9-async-future/5-0-summary.md
new file mode 100644
index 00000000..f39ed56d
--- /dev/null
+++ b/public/docs/dart/9-async-future/5-0-summary.md
@@ -0,0 +1,18 @@
+---
+id: dart-async-future-summary
+title: この章のまとめ
+level: 2
+question: []
+---
+
+## この章のまとめ
+
+この章では、[[Dart]]における非同期処理の基礎について学びました。
+
+* **シングルスレッドとイベントループ**: DartはイベントループによってUIスレッドを止めずに非同期タスクを実行する。
+* **`Future`**: 将来確定する単一の非同期処理結果を表すオブジェクト。
+* **`async` / `await`**: 直感的な構文で非同期コードを同期コードのように直線的に記述できる。
+* **`Future.wait`**: 複数の非同期処理を並行して実行し、すべての完了を待機する。
+* **非同期エラー処理**: `try-catch-finally` 構文で同期処理と同様に例外をハンドリングできる。
+
+次の [[./10]] では、単一の値ではなく「時間の経過とともに連続して発生するイベントのストリーム」を扱う **`Stream`** について学びます。
diff --git a/public/docs/dart/9-async-future/5-1-practice1.md b/public/docs/dart/9-async-future/5-1-practice1.md
new file mode 100644
index 00000000..209bd511
--- /dev/null
+++ b/public/docs/dart/9-async-future/5-1-practice1.md
@@ -0,0 +1,29 @@
+---
+id: dart-async-future-practice1
+title: '練習問題1: 非同期データフェッチのシミュレーション'
+level: 3
+question:
+ - Future.delayed を使ったモック関数の作成方法を教えてください。
+ - 非同期関数が例外をスローした場合の try-catch の動作を復習したいです。
+---
+
+### 練習問題1: 非同期データフェッチのシミュレーション
+
+サーバーからユーザーデータを非同期に取得する関数 `fetchUser` を作成してください。
+
+1. `Future