diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 83d2acb..e216c7b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,7 +17,23 @@ // Add the IDs of extensions you want installed when the container is created. "extensions": [ - "dbaeumer.vscode-eslint" + "dbaeumer.vscode-eslint", + "streetsidesoftware.code-spell-checker", + "github.vscode-codeql", + "docsmsft.docs-markdown", + "github.vscode-pull-request-github", + "eamodio.gitlens", + "yzhang.markdown-all-in-one", + "davidanson.vscode-markdownlint", + "eg2.vscode-npm-script", + "fknop.vscode-npm", + "christian-kohler.npm-intellisense", + "christian-kohler.path-intellisense", + "esbenp.prettier-vscode", + "ms-vscode.vscode-typescript-tslint-plugin", + "visualstudioexptteam.vscodeintellicode", + "ms-vscode.wordcount", + "redhat.vscode-yaml" ], // Use 'forwardPorts' to make a list of ports inside the container available locally. diff --git a/.vscode/settings.json b/.vscode/settings.json index 3361ea9..18262c0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,11 @@ "javascript.format.semicolons": "insert", "javascript.preferences.quoteStyle": "single", "typescript.format.semicolons": "insert", - "typescript.preferences.quoteStyle": "single" + "typescript.preferences.quoteStyle": "single", + "editor.formatOnPaste": true, + "editor.tabSize": 2, + "cSpell.words": [ + "tianhaoz", + "wowlink" + ] } \ No newline at end of file diff --git a/src/index.test.ts b/src/index.test.ts index 1e51fe7..7975158 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,79 +1,81 @@ import { - WowLookupFetchRequest, - WowLookupFetchResponse, - WowUrlConverter, - WowUrlConverterConfig, - WowUrlConvertRequest, - WowUrlConvertResponse, - WowUrlRankingItem + WowLookupFetchRequest, + WowLookupFetchResponse, + WowUrlConverter, + WowUrlConverterConfig, + WowUrlConvertRequest, + WowUrlConvertResponse, + WowUrlRankingItem, } from "."; -describe('Fetcher interface tests', () => { - test('Create request', () => { - const req: WowLookupFetchRequest = { - mappingSource: "github" - }; - expect(req).toBeDefined(); - }); +describe("Fetcher interface tests", () => { + test("Create request", () => { + const req: WowLookupFetchRequest = { + mappingSource: "github", + }; + expect(req).toBeDefined(); + }); - test('Create response', () => { - const res: WowLookupFetchResponse = { - wowMapping: { - 'gh': 'https://github.com' - } - }; - expect(res).toBeDefined(); - }); + test("Create response", () => { + const res: WowLookupFetchResponse = { + wowMapping: { + gh: "https://github.com", + }, + }; + expect(res).toBeDefined(); + }); }); -describe('Converter interface tests', () => { - test('Create request', () => { - const req: WowUrlConvertRequest = { - wowUrl: 'test_wow_url' - }; - expect(req).toBeDefined(); - }); +describe("Converter interface tests", () => { + test("Create request", () => { + const req: WowUrlConvertRequest = { + wowUrl: "test_wow_url", + }; + expect(req).toBeDefined(); + }); - test('Create response', () => { - // TODO(tianhaoz95): add another test to check - // it should fail without searchRanking once the - // field has become required. - const res: WowUrlConvertResponse = { - fullUrl: 'test_full_url', - searchRanking: [] - }; - expect(res).toBeDefined(); - }); + test("Create response", () => { + // TODO(tianhaoz95): add another test to check + // it should fail without searchRanking once the + // field has become required. + const res: WowUrlConvertResponse = { + fullUrl: "test_full_url", + isMatch: true, + postfix: "wowlink", + searchRanking: [], + }; + expect(res).toBeDefined(); + }); - test('Create ranking item', () => { - const rankingItem: WowUrlRankingItem = { - wowUrl: 'test_wow_url', - fullUrl: 'test_full_url', - score: 0.6 - }; - expect(rankingItem).toBeDefined(); - }); + test("Create ranking item", () => { + const rankingItem: WowUrlRankingItem = { + wowUrl: "test_wow_url", + fullUrl: "test_full_url", + score: 0.6, + }; + expect(rankingItem).toBeDefined(); + }); - test('Create config', () => { - const config: WowUrlConverterConfig = { - fetcherResponse: { - wowMapping: {} - } - }; - expect(config).toBeDefined(); - }); + test("Create config", () => { + const config: WowUrlConverterConfig = { + fetcherResponse: { + wowMapping: {}, + }, + }; + expect(config).toBeDefined(); + }); - test('Create converter', () => { - class DummyConverter implements WowUrlConverter { - convert(req: WowUrlConvertRequest): WowUrlConvertResponse { - const res: WowUrlConvertResponse = { - fullUrl: 'test_full_url', - searchRanking: [] - }; - return res; - } + test("Create converter", () => { + class DummyConverter implements WowUrlConverter { + convert(req: WowUrlConvertRequest): WowUrlConvertResponse { + const res: WowUrlConvertResponse = { + fullUrl: "test_full_url", + searchRanking: [], }; - const converter: WowUrlConverter = new DummyConverter(); - expect(converter).toBeDefined(); - }); + return res; + } + } + const converter: WowUrlConverter = new DummyConverter(); + expect(converter).toBeDefined(); + }); }); diff --git a/src/index.ts b/src/index.ts index 6114e11..6b510fb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,40 +1,53 @@ export enum BuiltInLookupFetcherType { - GitHub, - Gist, - LocalFile, - CustomBackend, + /** + * Use a configuration file inside a GitHub + * repository as the translation table. + */ + GitHub, + /** + * TODO(@tianhaoz95): add fetcher implementation + */ + Gist, + /** + * TODO(@tianhaoz95): add fetcher implementation + */ + LocalFile, + /** + * TODO(@tianhaoz95): add fetcher implementation + */ + CustomBackend, } -export interface WowLookupFetchRequest { } +export interface WowLookupFetchRequest {} export interface WowLookupFetchResponse { - wowMapping: Record; + wowMapping: Record; } export interface WowLookupFetcherConfig { - githubUser?: string; - githubRepository?: string; - /** - * The filename of the configuration file inside - * the repository defined by githubUser/githubRepository - * that contains the mapping. - */ - githubConfigFilename?: string; - gistUrl?: string; - localFilename?: string; - customApiEndpoint?: string; + githubUser?: string; + githubRepository?: string; + /** + * The filename of the configuration file inside + * the repository defined by githubUser/githubRepository + * that contains the mapping. + */ + githubConfigFilename?: string; + gistUrl?: string; + localFilename?: string; + customApiEndpoint?: string; } export interface WowLookupFetcher { - fetch(req: WowLookupFetchRequest): Promise; + fetch(req: WowLookupFetchRequest): Promise; } export enum BuiltInWowUrlConverterType { - Basic, + Basic, } export interface WowUrlConvertRequest { - wowUrl: string; + wowUrl: string; } /** @@ -45,54 +58,71 @@ export interface WowUrlConvertRequest { * is a better match for the search query. */ export interface WowUrlRankingItem { - /** - * Typing partial wowUrl will be supported. - * - * For example, if gh/tianhaoz95 is set to my - * GitHub profile, then typing gh/tianhaoz - * should show the correct URL as a potential - * option. - */ - wowUrl: string; - /** - * Potentially the full URL can be matched as - * well. - * - * For example, if gh is mapped to https://github.com, - * although searching github will not match gh, it makes - * sense to match https://github.com. - */ - fullUrl: string; - /** - * The matching score that the search algorithm - * outputs. Although it should already be ranked, - * it will be good to also include the source for - * ranking. - */ - score: number; + /** + * Typing partial wowUrl will be supported. + * + * For example, if gh/tianhaoz95 is set to my + * GitHub profile, then typing gh/tianhaoz + * should show the correct URL as a potential + * option. + */ + wowUrl: string; + /** + * Potentially the full URL can be matched as + * well. + * + * For example, if gh is mapped to https://github.com, + * although searching github will not match gh, it makes + * sense to match https://github.com. + */ + fullUrl: string; + /** + * The matching score that the search algorithm + * outputs. Although it should already be ranked, + * it will be good to also include the source for + * ranking. + */ + score: number; } export interface WowUrlConvertResponse { - fullUrl: string; - /** - * This is used for ranking the potential - * matching URLs when there is no direct - * match. - * - * For backward compatibility, it is marked - * as optional for now, but will become - * required when clients finish migration. - * - * TODO(tianhaoz95): change this to required - * once dependent migration is done. - */ - searchRanking?: WowUrlRankingItem[]; + /** + * This field indicates if the converter think + * that this field is good enough to return to + * the user. + * + * For example, for exact converter, this will + * only be set to true if the if the requested + * short link is exactly the same as one of the + * options, but for search converter, it will + * be true as long as there are some URLs above + * the matching threshold. + * + * TODO(@tianhaoz95): make required after migration. + */ + isMatch?: boolean; + fullUrl: string; + /** + * The postfix of a short link. For example, if + * gh is set to point to https://github.com, it's + * possible to also have a gh/{scopes} to map + * gh/tianhaoz95 to https://github.com/tianhaoz95. + * + * TODO(@tianhaoz95): figure out the for postfix. + */ + postfix?: string; + /** + * This is used for ranking the potential + * matching URLs when there is no direct + * match. + */ + searchRanking?: WowUrlRankingItem[]; } export interface WowUrlConverterConfig { - fetcherResponse: WowLookupFetchResponse; + fetcherResponse: WowLookupFetchResponse; } export interface WowUrlConverter { - convert(req: WowUrlConvertRequest): WowUrlConvertResponse; + convert(req: WowUrlConvertRequest): WowUrlConvertResponse; }