diff --git a/api/response.ts b/api/response.ts index 059b287..9aee547 100644 --- a/api/response.ts +++ b/api/response.ts @@ -1,23 +1,23 @@ import { Omit } from "../utils.ts"; -import { Line } from "../base.ts"; -import { NotFoundError, NotMemberError } from "./error.ts"; +import { + CommitId, + Line, + Page as PageBase, + PageId, + ProjectId, + StringLc, + UserId, +} from "../base.ts"; /** 関連ページのメタデータ */ -export interface RelatedPage { - /** ページのid */ id: string; - /** ページのタイトル */ title: string; - /** ページのタイトルを小文字にして、` `を`_`に変換したもの */ titleLc: string; - /** ページのサムネイル画像 */ image: string; - /** ページのサムネイル本文。最大5行 */ descriptions: string[]; - /** ページ内のリンク */ linksLc: string[]; +export interface RelatedPage extends PageBase { + /** ページ内のリンク */ linksLc: StringLc[]; /** おそらく被リンク数 */ linked: number; - /** ページの最終更新日時 */ updated: number; - /** おそらくページの閲覧日時 */ accessed: number; } /** user information */ export interface User { - /** user id */ id: string; + id: UserId; /** user name */ name: string; /** user display name */ displayName: string; /** profile image URL */ photo: string; @@ -33,21 +33,12 @@ export interface UserInfo extends User { } /** summary of page information */ -export interface PageSummary { - /** ページのid */ id: string; - /** ページのタイトル */ title: string; - /** ページのサムネイル画像 - * 存在しなければ`null` - */ - image: string | null; - /** ページのサムネイル本文。最大5行 */ descriptions: string[]; +export interface PageSummary extends PageBase { /** ピン留めされていたら1, されていなかったら0 */ pin: 0 | 1; /** ページの閲覧回数 */ views: number; /** おそらく被リンク数 */ linked: number; - /** 最新の編集コミットid */ commitId: string; + /** 最新の編集コミットid */ commitId: CommitId; /** ページの作成日時 */ created: number; - /** ページの最終更新日時 */ updated: number; - /** Date last visitedに使われる最終アクセス日時 */ accessed: number; /** page rank */ pageRank: number; /** Page historyの最終生成日時 */ snapshotCreated: number | null; } @@ -74,20 +65,17 @@ export interface Page extends PageSummary { } /** the response type of https://scrpabox.io/api/pages/:projectname */ -export type PageListResponse = - | NotFoundError - | NotMemberError - | { - /** data取得先のproject名 */ projectName: string; - /** parameterに渡したskipと同じ */ skip: number; - /** parameterに渡したlimitと同じ */ limit: number; - /** projectの全ページ数 (中身のないページを除く) */ count: number; - /** 取得できたページ情報 */ pages: PageSummary[]; - }; +export interface PageList { + /** data取得先のproject名 */ projectName: string; + /** parameterに渡したskipと同じ */ skip: number; + /** parameterに渡したlimitと同じ */ limit: number; + /** projectの全ページ数 (中身のないページを除く) */ count: number; + /** 取得できたページ情報 */ pages: PageSummary[]; +} -/** project basic information */ -export interface Project { - id: string; +/** project information which isn't joined */ +export interface NotMemberProject { + id: ProjectId; name: string; displayName: string; publicVisible: boolean; @@ -98,83 +86,72 @@ export interface Project { image?: string; created: number; updated: number; - isMember: boolean; - plan?: string; + isMember: false; +} + +/** project information which is joined */ +export interface MemberProject extends Omit { + isMember: true; + plan?: string | null; + users: UserInfo[]; + admins: UserId[]; + owner: UserId; + trialing: boolean; + trialMaxPages: number; + skipPayment: boolean; + uploadFileTo: "gcs"; + uploadImaegTo: "gyazo" | "gcs"; + emailAddressPatterns: string[]; + backuped: number | null; +} + +export interface GuestUser { + isGuest: true; + csrfToken: string; } -/** the response type of https://scrpabox.io/api/projects/:projectname */ -export type ProjectResponse = - | NotFoundError - | NotMemberError - | ( - & Omit, "plan"> - & ({ isMember: false } | { - isMember: true; - plan?: string | null; - users: UserInfo[]; - admins: string[]; - owner: string; - trialing: boolean; - trialMaxPages: number; - skipPayment: boolean; - uploadFileTo: "gcs"; - uploadImaegTo: "gyazo" | "gcs"; - emailAddressPatterns: string[]; - backuped: number | null; - }) - ); +export interface MemberUser extends UserInfo { + isGuest: false; + csrfToken: string; + config: { + userScript: boolean; + emacsBinding: boolean; + }; +} /** the response type of https://scrapbox.io/api/users/me */ -export type UserResponse = - | { - isGuest: true; - csrfToken: string; - } - | ({ - isGuest: false; - csrfToken: string; - config: { - userScript: boolean; - emacsBinding: boolean; - }; - } & UserInfo); +export type UserResponse = GuestUser | MemberUser; /** the response type of https://scrapbox.io/api/pages/:projectname/search/titles */ -export type LinksResponse = - | NotFoundError - | NotMemberError - | { - message: "Invalid pageId"; - } - | { - /** page id */ id: string; - /** page title */ title: string; - /** 画像が存在するかどうか */ hasIcon: boolean; - /** ページの更新日時 */ updated: number; - /** ページ内のリンク */ links: string[]; - }[]; +export interface SearchedTitle { + id: PageId; + /** page title */ title: string; + /** 画像が存在するかどうか */ hasIcon: boolean; + /** ページの更新日時 */ updated: number; + /** ページ内のリンク */ links: string[]; +} -export type ProjectBackup = { +export interface ProjectBackup { name: string; displayName: string; exported: number; pages: { - id: string; + id: PageId; title: string; created: number; updated: number; lines: string[]; }; -}; -export type ProjectBackupWithMetadata = { +} +export interface ProjectBackupWithMetadata { name: string; displayName: string; exported: number; pages: { - id: string; + id: PageId; title: string; created: number; updated: number; - lines: { text: string; updated: number; created: number }[]; + lines: Omit[]; }; -}; +} diff --git a/base.ts b/base.ts index 2e81319..b78698a 100644 --- a/base.ts +++ b/base.ts @@ -1,8 +1,41 @@ /** scrapboxの行のメタデータ */ export interface Line { - /** 行のid */ id: string; + /** 行のid */ id: LineId; /** 行のテキスト */ text: string; - /** 一番最後に行を編集した人のid */ userId: string; + /** 一番最後に行を編集した人のid */ userId: UserId; /** 行の作成日時 */ created: number; /** 行の最終更新日時 */ updated: number; } + +/** basic information about a page */ +export interface Page { + /** the id of a page */ id: PageId; + /** the title of a page */ title: string; + /** the thumbnail URL of a page if exists + * + * set to `null` if not exists + */ + image: string | null; + /** the thumbnail text of a page. + * the maximum number of lines is 5. + * */ descriptions: string[]; + /** ページの最終更新日時 */ updated: number; + /** Date last visitedに使われる最終アクセス日時 */ accessed: number; +} + +/** the user id */ +export type UserId = string; +/** the line id */ +export type LineId = string; +/** the commit id */ +export type CommitId = string; +/** the page id */ +export type PageId = string; +/** the project id */ +export type ProjectId = string; +/** the formatted string + * + * format rule: + * - UPPER CASE -> upper_case + */ +export type StringLc = string; diff --git a/userscript.ts b/userscript.ts index 6a5eec0..176ae5a 100644 --- a/userscript.ts +++ b/userscript.ts @@ -1,4 +1,5 @@ import { ParsedLine } from "./userscript/blocks.ts"; +import { StringLc } from "./base.ts"; export type Layout = | "list" @@ -33,22 +34,8 @@ export type Scrapbox = addSeparator: () => void; removeAllItems: () => void; }; - addListener: (type: string, listener: () => void) => void; - on: (type: string, listener: () => void) => void; - removeListener: (type: string, listener: () => void) => void; - off: (type: string, listener: () => void) => void; - removeAllListeners: (type?: string) => void; - once: (type: string, listener: () => void) => void; - prependListener: (type: string, listener: () => void) => void; - prependOnceListener: (type: string, listener: () => void) => void; - listeners: (type: string) => (() => void)[]; - rawListeners: (type: string) => (() => void)[]; - listenerCount: (type: string) => number; - emit: (type: string) => void; - eventNames: () => string[]; - getMexListeners: () => number; - setMexListeners: (length: number) => void; } + & UserScriptEvents & ({ Layout: | "list" @@ -73,29 +60,61 @@ export type Scrapbox = }; }); -export type PageBrief = { - exists: boolean; - hasIcon?: boolean; - id: string; - title: string; - titleLc: string; - updated: number; -}; +export interface UserScriptEvents { + addListener: (type: string, listener: () => void) => void; + on: (type: string, listener: () => void) => void; + removeListener: (type: string, listener: () => void) => void; + off: (type: string, listener: () => void) => void; + removeAllListeners: (type?: string) => void; + once: (type: string, listener: () => void) => void; + prependListener: (type: string, listener: () => void) => void; + prependOnceListener: (type: string, listener: () => void) => void; + listeners: (type: string) => (() => void)[]; + rawListeners: (type: string) => (() => void)[]; + listenerCount: (type: string) => number; + emit: (type: string) => void; + eventNames: () => string[]; + getMexListeners: () => number; + setMexListeners: (length: number) => void; +} +export interface PageBrief { + /** true when the page has contents */ exists: boolean; + /** whether the page contains any image */ hasIcon?: boolean; + /** the page id */ id: string; + /** the page title */ title: string; + titleLc: StringLc; + /** updated time */ updated: number; +} -type TimeStamp = { +export interface TimeStamp { + /** Add a timestamp format to Scrapbox + * + * @param format a format of timestamp. this follow the moment.js format. You can set a function which returns any string + */ addFormat: (format: string | (() => string)) => void; + /** Remove all timestamp formats from Scrapbox + * + * These include default formats + */ removeAllFormat: () => void; -}; +} -type AddItemProps = { - title: string | (() => string); +export interface AddItemProps { + /** the title of a menu item */ title: string | (() => string); + /** the URL of an image which views on the left of the title */ image?: string; + /** the event listener which is executed when the menu item is clicked */ onClick: () => void; -}; -type PageMenu = { +} +export interface PageMenu { + /** Add a menu item to a particular Page Menu button + * + * @param props information used for a menu item + */ addItem: ( props: AddItemProps, ) => void; + /** Add a separator to a particular Page Menu button */ addSeparator: () => void; removeAllItems: () => void; menuName: string; @@ -109,8 +128,9 @@ type PageMenu = { items: (AddItemProps & { separator: boolean })[]; } >; -}; +} +/** built-in UserScript events */ export type eventName = | "lines:changed" | "page:changed" diff --git a/userscript/blocks.ts b/userscript/blocks.ts index 64ef814..9835606 100644 --- a/userscript/blocks.ts +++ b/userscript/blocks.ts @@ -1,12 +1,9 @@ import { Node, NodeWithoutIndent } from "./nodes.ts"; +import { Line } from "../base.ts"; export type ParsedLine = + & Line & { - text: string; - id: string; - userId: string; - updated: number; - created: number; section: { number: number; start: boolean; @@ -32,20 +29,24 @@ export type ParsedLine = nodes: Node[]; }); -export type CodeBlock = { - lang: string; - filename?: string; - indent: number; - start: boolean; - end: boolean; -}; -export type TableBlock = { - title: string; - cells: string[]; - indent: number; - start: boolean; - end: boolean; -}; +/** the type which represents a line in a block */ +export interface Block { + /** the number of indents */ indent: number; + /** is the start line of this block */ start: boolean; + /** is the end line of this block */ end: boolean; +} + +/** the type which represents a line in a code block */ +export interface CodeBlock extends Block { + /** the language of the code block */ lang: string; + /** the file name of the code block */ filename?: string; +} + +/** the type which represents a line in a table block */ +export interface TableBlock extends Block { + /** the title of the table block */ title: string; + /** cells included in the present line */ cells: string[]; +} export type Helpfeel = { prefix: "?"; entry: string;