diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91382c8..708487e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v2 - uses: denoland/setup-deno@v1 with: - deno-version: "1.32.3" + deno-version: "1.34.3" - name: Check fmt run: deno fmt --check - name: Run lint diff --git a/.github/workflows/udd.yml b/.github/workflows/udd.yml index 37df0d9..6626a6e 100644 --- a/.github/workflows/udd.yml +++ b/.github/workflows/udd.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v2 - uses: denoland/setup-deno@v1 with: - deno-version: "1.32.3" + deno-version: "1.34.3" - name: Update dependencies run: > deno run --allow-net --allow-read --allow-write=deps/ diff --git a/browser/dom/__snapshots__/extractCodeFiles.test.ts.snap b/browser/dom/__snapshots__/extractCodeFiles.test.ts.snap index 9bbfb04..6294686 100644 --- a/browser/dom/__snapshots__/extractCodeFiles.test.ts.snap +++ b/browser/dom/__snapshots__/extractCodeFiles.test.ts.snap @@ -1,95 +1,95 @@ export const snapshot = {}; snapshot[`extractCodeFiles 1`] = ` -Map { +Map(5) { "main.cpp" => { - blocks: [ - { - endId: "63b7b1261280f00000c9bc36", - indent: 2, - lines: [ - "#include ", - "", - ], - startId: "63b7b1261280f00000c9bc34", - updated: 1672982822, - }, - { - endId: "63b7b1261280f00000c9bc3c", - indent: 2, - lines: [ - "int main() {", - ' std::cout << "Hello, C++" << "from scrapbox.io" << std::endl;', - "}", - "", - ], - startId: "63b7b1261280f00000c9bc38", - updated: 1672982822, - }, - ], - filename: "main.cpp", - lang: "cpp", - }, + blocks: [ + { + endId: "63b7b1261280f00000c9bc36", + indent: 2, + lines: [ + "#include ", + "", + ], + startId: "63b7b1261280f00000c9bc34", + updated: 1672982822, + }, + { + endId: "63b7b1261280f00000c9bc3c", + indent: 2, + lines: [ + "int main() {", + ' std::cout << "Hello, C++" << "from scrapbox.io" << std::endl;', + "}", + "", + ], + startId: "63b7b1261280f00000c9bc38", + updated: 1672982822, + }, + ], + filename: "main.cpp", + lang: "cpp", + }, "py" => { - blocks: [ - { - endId: "63b7b1261280f00000c9bc2a", - indent: 0, - lines: [ - 'print("Hello World!")', - ], - startId: "63b7b1261280f00000c9bc29", - updated: 1672982822, - }, - ], - filename: "py", - lang: "py", - }, + blocks: [ + { + endId: "63b7b1261280f00000c9bc2a", + indent: 0, + lines: [ + 'print("Hello World!")', + ], + startId: "63b7b1261280f00000c9bc29", + updated: 1672982822, + }, + ], + filename: "py", + lang: "py", + }, "python" => { - blocks: [ - { - endId: "63b7b1261280f00000c9bc31", - indent: 1, - lines: [ - \`console.log("I'm JavaScript");\`, - ], - startId: "63b7b1261280f00000c9bc30", - updated: 1672982822, - }, - ], - filename: "python", - lang: "js", - }, + blocks: [ + { + endId: "63b7b1261280f00000c9bc31", + indent: 1, + lines: [ + \`console.log("I'm JavaScript");\`, + ], + startId: "63b7b1261280f00000c9bc30", + updated: 1672982822, + }, + ], + filename: "python", + lang: "js", + }, "インデント.md" => { - blocks: [ - { - endId: "63b7b1261280f00000c9bc2e", - indent: 1, - lines: [ - "- インデント", - " - インデント", - ], - startId: "63b7b1261280f00000c9bc2c", - updated: 1672982822, - }, - ], - filename: "インデント.md", - lang: "md", - }, + blocks: [ + { + endId: "63b7b1261280f00000c9bc2e", + indent: 1, + lines: [ + "- インデント", + " - インデント", + ], + startId: "63b7b1261280f00000c9bc2c", + updated: 1672982822, + }, + ], + filename: "インデント.md", + lang: "md", + }, "コードブロック.py" => { - blocks: [ - { - endId: "63b7b1261280f00000c9bc27", - indent: 0, - lines: [ - 'print("Hello World!")', - ], - startId: "63b7b1261280f00000c9bc26", - updated: 1672982822, - }, - ], - filename: "コードブロック.py", - lang: "py", - }, + blocks: [ + { + endId: "63b7b1261280f00000c9bc27", + indent: 0, + lines: [ + 'print("Hello World!")', + ], + startId: "63b7b1261280f00000c9bc26", + updated: 1672982822, + }, + ], + filename: "コードブロック.py", + lang: "py", + }, } `; diff --git a/parser/__snapshots__/youtube.test.ts.snap b/parser/__snapshots__/youtube.test.ts.snap index 1f47445..fca7c9a 100644 --- a/parser/__snapshots__/youtube.test.ts.snap +++ b/parser/__snapshots__/youtube.test.ts.snap @@ -4,12 +4,6 @@ snapshot[`youtube links > is 1`] = ` { params: URLSearchParams { [Symbol("[[webidl.brand]]")]: Symbol("[[webidl.brand]]"), - [Symbol(list)]: [ - [ - "v", - "LSvaOcaUQ3Y", - ], - ], [Symbol("url object")]: URL { hash: "", host: "www.youtube.com", @@ -23,6 +17,12 @@ snapshot[`youtube links > is 1`] = ` search: "?v=LSvaOcaUQ3Y", username: "", }, + [Symbol(list)]: [ + [ + "v", + "LSvaOcaUQ3Y", + ], + ], }, pathType: "com", videoId: "LSvaOcaUQ3Y", @@ -34,13 +34,13 @@ snapshot[`youtube links > is 2`] = ` listId: "PLmoRDY8IgE2Okxy4WWdP95RHXOTGzJfQs", params: URLSearchParams { [Symbol("[[webidl.brand]]")]: Symbol("[[webidl.brand]]"), + [Symbol("url object")]: null, [Symbol(list)]: [ [ "list", "PLmoRDY8IgE2Okxy4WWdP95RHXOTGzJfQs", ], ], - [Symbol("url object")]: null, }, pathType: "list", } @@ -50,16 +50,6 @@ snapshot[`youtube links > is 3`] = ` { params: URLSearchParams { [Symbol("[[webidl.brand]]")]: Symbol("[[webidl.brand]]"), - [Symbol(list)]: [ - [ - "v", - "57rdbK4vmKE", - ], - [ - "list", - "PLmoRDY8IgE2Okxy4WWdP95RHXOTGzJfQs", - ], - ], [Symbol("url object")]: URL { hash: "", host: "www.youtube.com", @@ -73,6 +63,16 @@ snapshot[`youtube links > is 3`] = ` search: "?v=57rdbK4vmKE&list=PLmoRDY8IgE2Okxy4WWdP95RHXOTGzJfQs", username: "", }, + [Symbol(list)]: [ + [ + "v", + "57rdbK4vmKE", + ], + [ + "list", + "PLmoRDY8IgE2Okxy4WWdP95RHXOTGzJfQs", + ], + ], }, pathType: "com", videoId: "57rdbK4vmKE", @@ -83,12 +83,6 @@ snapshot[`youtube links > is 4`] = ` { params: URLSearchParams { [Symbol("[[webidl.brand]]")]: Symbol("[[webidl.brand]]"), - [Symbol(list)]: [ - [ - "v", - "nj1cre2e6t0", - ], - ], [Symbol("url object")]: URL { hash: "", host: "music.youtube.com", @@ -102,6 +96,12 @@ snapshot[`youtube links > is 4`] = ` search: "?v=nj1cre2e6t0", username: "", }, + [Symbol(list)]: [ + [ + "v", + "nj1cre2e6t0", + ], + ], }, pathType: "com", videoId: "nj1cre2e6t0", @@ -112,9 +112,8 @@ snapshot[`youtube links > is 5`] = ` { params: URLSearchParams { [Symbol("[[webidl.brand]]")]: Symbol("[[webidl.brand]]"), - [Symbol(list)]: [ - ], [Symbol("url object")]: null, + [Symbol(list)]: [], }, pathType: "dotbe", videoId: "nj1cre2e6t0", diff --git a/rest/__snapshots__/pages.test.ts.snap b/rest/__snapshots__/pages.test.ts.snap index 0d360de..94010c7 100644 --- a/rest/__snapshots__/pages.test.ts.snap +++ b/rest/__snapshots__/pages.test.ts.snap @@ -6,7 +6,7 @@ Request { headers: Headers {}, method: "GET", redirect: "follow", - url: "https://scrapbox.io/api/pages/takker/%E3%83%86%E3%82%B9%E3%83%88%E3%83%9A%E3%83%BC%E3%82%B8?followRe..." + url: "https://scrapbox.io/api/pages/takker/%E3%83%86%E3%82%B9%E3%83%88%E3%83%9A%E3%83%BC%E3%82%B8?followRe"... 9 more characters } `; diff --git a/rest/getCodeBlock.ts b/rest/getCodeBlock.ts new file mode 100644 index 0000000..b0e8261 --- /dev/null +++ b/rest/getCodeBlock.ts @@ -0,0 +1,96 @@ +import type { + NotFoundError, + NotLoggedInError, + NotMemberError, +} from "../deps/scrapbox-rest.ts"; +import { cookie } from "./auth.ts"; +import { makeError } from "./error.ts"; +import { encodeTitleURI } from "../title.ts"; +import { BaseOptions, Result, setDefaults } from "./util.ts"; + +const getCodeBlock_toRequest: GetCodeBlock["toRequest"] = ( + project, + title, + filename, + options, +) => { + const { sid, hostName } = setDefaults(options ?? {}); + const path = `https://${hostName}/api/code/${project}/${ + encodeTitleURI(title) + }/${encodeTitleURI(filename)}`; + + return new Request( + path, + sid ? { headers: { Cookie: cookie(sid) } } : undefined, + ); +}; + +const getCodeBlock_fromResponse: GetCodeBlock["fromResponse"] = async (res) => { + if (!res.ok) { + return makeError(res); + } + return { ok: true, value: await res.text() }; +}; + +export interface GetCodeBlock { + /** /api/code/:project/:title/:filename の要求を組み立てる + * + * @param project 取得したいページのproject名 + * @param title 取得したいページのtitle 大文字小文字は問わない + * @param filename 取得したいコードブロックのファイル名 + * @param options オプション + * @return request + */ + toRequest: ( + project: string, + title: string, + filename: string, + options?: BaseOptions, + ) => Request; + + /** 帰ってきた応答からコードを取得する + * + * @param res 応答 + * @return コード + */ + fromResponse: (res: Response) => Promise< + Result< + string, + NotFoundError | NotLoggedInError | NotMemberError + > + >; + + ( + project: string, + title: string, + filename: string, + options?: BaseOptions, + ): Promise< + Result< + string, + NotFoundError | NotLoggedInError | NotMemberError + > + >; +} + +/** 指定したコードブロック中のテキストを取得する + * + * @param project 取得したいページのproject名 + * @param title 取得したいページのtitle 大文字小文字は問わない + * @param filename 取得したいコードブロックのファイル名 + * @param options オプション + */ +export const getCodeBlock: GetCodeBlock = async ( + project, + title, + filename, + options, +) => { + const { fetch } = setDefaults(options ?? {}); + const req = getCodeBlock_toRequest(project, title, filename, options); + const res = await fetch(req); + return await getCodeBlock_fromResponse(res); +}; + +getCodeBlock.toRequest = getCodeBlock_toRequest; +getCodeBlock.fromResponse = getCodeBlock_fromResponse; diff --git a/rest/mod.ts b/rest/mod.ts index c11c9d1..610f070 100644 --- a/rest/mod.ts +++ b/rest/mod.ts @@ -14,4 +14,5 @@ export * from "./auth.ts"; export * from "./util.ts"; export * from "./error.ts"; export * from "./getCodeBlocks.ts"; +export * from "./getCodeBlock.ts"; export * from "./uploadToGCS.ts";