Convert gr-formatted-text to TypeScript Change-Id: I65dffda16b0f04ae5432e8437cb800ac6ca0a8c8
diff --git a/polygerrit-ui/app/constants/constants.ts b/polygerrit-ui/app/constants/constants.ts index 7170079..e642373 100644 --- a/polygerrit-ui/app/constants/constants.ts +++ b/polygerrit-ui/app/constants/constants.ts
@@ -160,3 +160,40 @@ LEFT = 'left', RIGHT = 'right', } + +/** + * The type in ConfigParameterInfo entity. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-parameter-info + */ +export enum ConfigParameterInfoType { + STRING = 'STRING', + INT = 'INT', + LONG = 'LONG', + BOOLEAN = 'BOOLEAN', + LIST = 'LIST', + ARRAY = 'ARRAY', +} + +/** + * All supported submit types. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#submit-type-info + */ +export enum SubmitType { + MERGE_IF_NECESSARY = 'MERGE_IF_NECESSARY', + FAST_FORWARD_ONLY = 'FAST_FORWARD_ONLY', + REBASE_IF_NECESSARY = 'REBASE_IF_NECESSARY', + REBASE_ALWAYS = 'REBASE_ALWAYS', + MERGE_ALWAYS = 'MERGE_ALWAYS ', + CHERRY_PICK = 'CHERRY_PICK', + INHERIT = 'INHERIT', +} + +/* + * Enum for possible configured value in InheritedBooleanInfo. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#inherited-boolean-info + */ +export enum InheritedBooleanInfoConfiguredValue { + TRUE = 'TRUE', + FALSE = 'FALSE', + INHERITED = 'INHERITED', +}
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts index 08c7897..b55c9a9 100644 --- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts +++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts
@@ -30,6 +30,7 @@ CommitId, Hashtag, UrlEncodedCommentId, + CommentLinks, } from '../../../types/common'; // Navigation parameters object format: @@ -117,7 +118,7 @@ const uninitializedMapCommentLinks: MapCommentLinksCallback = () => { uninitialized(); - return []; + return {}; }; // TODO(TS): PatchSetNum type express an API type, it is not good to add @@ -345,15 +346,7 @@ params: GenerateWebLinksParameters ) => WebLink[] | WebLink; -export interface Pattern { - enabled: boolean | null; - match: string; - html?: string; - link?: string; -} - -// TODO(TS): type is not clear until more code converted to a typescript. -export type MapCommentLinksCallback = (patterns: Pattern[]) => Pattern[]; +export type MapCommentLinksCallback = (patterns: CommentLinks) => CommentLinks; export interface WebLink { label: string;
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts index 862c48c..f8d414e 100644 --- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts +++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -14,44 +14,55 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import '../gr-linked-text/gr-linked-text.js'; -import '../../../styles/shared-styles.js'; -import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js'; -import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; -import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js'; -import {PolymerElement} from '@polymer/polymer/polymer-element.js'; -import {htmlTemplate} from './gr-formatted-text_html.js'; +import '../gr-linked-text/gr-linked-text'; +import '../../../styles/shared-styles'; +import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners'; +import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin'; +import {PolymerElement} from '@polymer/polymer/polymer-element'; +import {customElement, property} from '@polymer/decorators/lib/decorators'; +import {htmlTemplate} from './gr-formatted-text_html'; +import {CommentLinks} from '../../../types/common'; -// eslint-disable-next-line no-unused-vars -const QUOTE_MARKER_PATTERN = /\n\s?>\s/g; const CODE_MARKER_PATTERN = /^(`{1,3})([^`]+?)\1$/; -/** @extends PolymerElement */ -class GrFormattedText extends GestureEventListeners( - LegacyElementMixin( - PolymerElement)) { - static get template() { return htmlTemplate; } +interface Block { + type: string; + text?: string; + blocks?: Block[]; + items?: string[]; +} - static get is() { return 'gr-formatted-text'; } +declare global { + interface HTMLElementTagNameMap { + 'gr-formatted-text': GrFormattedText; + } +} - static get properties() { - return { - content: { - type: String, - observer: '_contentChanged', - }, - config: Object, - noTrailingMargin: { - type: Boolean, - value: false, - }, - }; +export interface GrFormattedText { + $: { + container: HTMLElement; + }; +} + +@customElement('gr-formatted-text') +export class GrFormattedText extends GestureEventListeners( + LegacyElementMixin(PolymerElement) +) { + static get template() { + return htmlTemplate; } + @property({type: String, observer: '_contentChanged'}) + content?: string; + + @property({type: Object}) + config?: CommentLinks; + + @property({type: Boolean}) + noTrailingMargin = false; + static get observers() { - return [ - '_contentOrConfigChanged(content, config)', - ]; + return ['_contentOrConfigChanged(content, config)']; } /** @override */ @@ -62,19 +73,19 @@ } } - _contentChanged(content) { + _contentChanged(content: string) { // In the case where the config may not be set (perhaps due to the // request for it still being in flight), set the content anyway to // prevent waiting on the config to display the text. - if (this.config) { return; } + if (this.config) return; this._contentOrConfigChanged(content); } /** * Given a source string, update the DOM inside #container. */ - _contentOrConfigChanged(content) { - const container = dom(this.$.container); + _contentOrConfigChanged(content?: string) { + const container = this.$.container; // Remove existing content. while (container.firstChild) { @@ -106,12 +117,9 @@ * list of blocks contained in the quote. * * NOTE: Strings appearing in all block objects are NOT escaped. - * - * @param {string} content - * @return {!Array<!Object>} */ - _computeBlocks(content) { - if (!content) { return []; } + _computeBlocks(content?: string): Block[] { + if (!content) return []; const result = []; const lines = content.replace(/[\s\n\r\t]+$/g, '').split('\n'); @@ -123,7 +131,7 @@ if (this._isCodeMarkLine(lines[i])) { // handle multi-line code - let nextI = i+1; + let nextI = i + 1; while (!this._isCodeMarkLine(lines[nextI]) && nextI < lines.length) { nextI++; } @@ -131,7 +139,7 @@ if (this._isCodeMarkLine(lines[nextI])) { result.push({ type: 'code', - text: lines.slice(i+1, nextI).join('\n'), + text: lines.slice(i + 1, nextI).join('\n'), }); i = nextI; continue; @@ -143,7 +151,7 @@ if (this._isSingleLineCode(lines[i])) { // no guard check as _isSingleLineCode tested on the pattern - const codeContent = lines[i].match(CODE_MARKER_PATTERN)[2]; + const codeContent = lines[i].match(CODE_MARKER_PATTERN)![2]; result.push({type: 'code', text: codeContent}); } else if (this._isList(lines[i])) { let nextI = i + 1; @@ -157,8 +165,9 @@ while (this._isQuote(lines[nextI])) { nextI++; } - const blockLines = lines.slice(i, nextI) - .map(l => l.replace(/^[ ]?>[ ]?/, '')); + const blockLines = lines + .slice(i, nextI) + .map(l => l.replace(/^[ ]?>[ ]?/, '')); result.push({ type: 'quote', blocks: this._computeBlocks(blockLines.join('\n')), @@ -167,8 +176,10 @@ } else if (this._isPreFormat(lines[i])) { let nextI = i + 1; // include pre or all regular lines but stop at next new line - while (this._isPreFormat(lines[nextI]) - || (this._isRegularLine(lines[nextI]) && lines[nextI].length)) { + while ( + this._isPreFormat(lines[nextI]) || + (this._isRegularLine(lines[nextI]) && lines[nextI].length) + ) { nextI++; } result.push({ @@ -202,58 +213,56 @@ * * TODO(taoalpha): maybe we should also support nested list * - * @param {!Array<string>} lines The block containing the list. + * @param lines The block containing the list. */ - _makeList(lines) { - const block = {type: 'list', items: []}; - let line; - + _makeList(lines: string[]) { + const items = []; for (let i = 0; i < lines.length; i++) { - line = lines[i]; + let line = lines[i]; line = line.substring(1).trim(); - block.items.push(line); + items.push(line); } - return block; + return {type: 'list', items}; } - _isRegularLine(line) { + _isRegularLine(line: string) { // line can not be recognized by existing patterns if (line === undefined) return false; - return !this._isQuote(line) && !this._isCodeMarkLine(line) - && !this._isSingleLineCode(line) && !this._isList(line) && - !this._isPreFormat(line); + return ( + !this._isQuote(line) && + !this._isCodeMarkLine(line) && + !this._isSingleLineCode(line) && + !this._isList(line) && + !this._isPreFormat(line) + ); } - _isQuote(line) { + _isQuote(line: string) { return line && (line.startsWith('> ') || line.startsWith(' > ')); } - _isCodeMarkLine(line) { + _isCodeMarkLine(line: string) { return line && line.trim() === '```'; } - _isSingleLineCode(line) { + _isSingleLineCode(line: string) { return line && CODE_MARKER_PATTERN.test(line); } - _isPreFormat(line) { + _isPreFormat(line: string) { return line && /^[ \t]/.test(line); } - _isList(line) { + _isList(line: string) { return line && /^[-*] /.test(line); } - /** - * @param {string} content - * @param {boolean=} opt_isPre - */ - _makeLinkedText(content, opt_isPre) { + _makeLinkedText(content = '', isPre?: boolean) { const text = document.createElement('gr-linked-text'); text.config = this.config; text.content = content; text.pre = true; - if (opt_isPre) { + if (isPre) { text.classList.add('pre'); } return text; @@ -261,11 +270,8 @@ /** * Map an array of block objects to an array of DOM nodes. - * - * @param {!Array<!Object>} blocks - * @return {!Array<!HTMLElement>} */ - _computeNodes(blocks) { + _computeNodes(blocks: Block[]): HTMLElement[] { return blocks.map(block => { if (block.type === 'paragraph') { const p = document.createElement('p'); @@ -275,7 +281,7 @@ if (block.type === 'quote') { const bq = document.createElement('blockquote'); - for (const node of this._computeNodes(block.blocks)) { + for (const node of this._computeNodes(block.blocks || [])) { if (node) bq.appendChild(node); } return bq; @@ -283,7 +289,7 @@ if (block.type === 'code') { const code = document.createElement('code'); - code.textContent = block.text; + code.textContent = block.text || ''; return code; } @@ -293,7 +299,8 @@ if (block.type === 'list') { const ul = document.createElement('ul'); - for (const item of block.items) { + const items = block.items || []; + for (const item of items) { const li = document.createElement('li'); li.appendChild(this._makeLinkedText(item)); ul.appendChild(li); @@ -302,9 +309,7 @@ } console.warn('Unrecognized type.'); - return; + return document.createElement('span'); }); } } - -customElements.define(GrFormattedText.is, GrFormattedText);
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.ts b/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.ts index 1bc19cd..ec6b6ab 100644 --- a/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.ts +++ b/polygerrit-ui/app/elements/shared/gr-linked-text/link-text-parser.ts
@@ -16,7 +16,7 @@ */ import {getBaseUrl} from '../../../utils/url-util'; -import {Pattern} from '../../core/gr-navigation/gr-navigation'; +import {CommentLinkInfo} from '../../../types/common'; /** * Pattern describing URLs with supported protocols. @@ -32,7 +32,7 @@ html: HTMLAnchorElement | DocumentFragment; } -export type LinkTextParserConfig = Pattern[]; +export type LinkTextParserConfig = {[name: string]: CommentLinkInfo}; export class GrLinkTextParser { private readonly baseUrl = getBaseUrl(); @@ -325,7 +325,7 @@ // We suppose, that prefixText just a single word // before link and add this word as is, without processing // any patterns in it. - this.parseLinks(prefixText, []); + this.parseLinks(prefixText, {}); text = text.substring(prefixText.length); href = href.substring(prefixText.length); }
diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts index 0a6885a..21e3600 100644 --- a/polygerrit-ui/app/types/common.ts +++ b/polygerrit-ui/app/types/common.ts
@@ -25,6 +25,9 @@ RequirementStatus, ReviewerState, RevisionKind, + SubmitType, + InheritedBooleanInfoConfiguredValue, + ConfigParameterInfoType, } from '../constants/constants'; export type BrandType<T, BrandName extends string> = T & @@ -79,7 +82,6 @@ export type ChangeInfoId = BrandType<string, '_changeInfoId'>; export type Hashtag = BrandType<string, '_hashtag'>; export type StarLabel = BrandType<string, '_startLabel'>; -export type SubmitType = BrandType<string, '_submitType'>; export type CommitId = BrandType<string, '_commitId'>; // The UUID of the group @@ -1110,3 +1112,96 @@ _width: number; _height: number; } + +/** + * A boolean value that can also be inherited. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#inherited-boolean-info + */ +export interface InheritedBooleanInfo { + value: string; + configured_value: InheritedBooleanInfoConfiguredValue; + inherited_value?: string; +} + +/** + * The MaxObjectSizeLimitInfo entity contains information about themax object + * size limit of a project. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#max-object-size-limit-info + */ +export interface MaxObjectSizeLimitInfo { + value?: number; + configured_value?: string; + summary?: string; +} + +/** + * Information about the default submittype of a project, taking into account + * project inheritance. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#submit-type-info + */ +export interface SubmitTypeInfo { + value: Exclude<SubmitType, SubmitType.INHERIT>; + configured_value: SubmitType; + inherited_value: Exclude<SubmitType, SubmitType.INHERIT>; +} + +/** + * The CommentLinkInfo entity describes acommentlink. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#commentlink-info + */ +export interface CommentLinkInfo { + match: string; + link?: string; + enabled?: boolean; + html?: string; +} + +/** + * The ConfigParameterInfo entity describes a project configurationparameter. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-parameter-info + */ +export interface ConfigParameterInfo { + display_name?: string; + description?: string; + warning?: string; + type: ConfigParameterInfoType; + value?: string; + values?: string[]; + editable?: boolean; + permitted_values?: string[]; + inheritable?: boolean; + configured_value?: string; + inherited_value?: string; +} + +export interface CommentLinks { + [name: string]: CommentLinkInfo; +} + +/** + * The ConfigInfo entity contains information about the effective + * projectconfiguration. + * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-info + */ +export interface ConfigInfo { + description?: string; + use_contributor_agreements?: InheritedBooleanInfo; + use_content_merge?: InheritedBooleanInfo; + use_signed_off_by?: InheritedBooleanInfo; + create_new_change_for_all_not_in_target?: InheritedBooleanInfo; + require_change_id?: InheritedBooleanInfo; + enable_signed_push?: InheritedBooleanInfo; + require_signed_push?: InheritedBooleanInfo; + reject_implicit_merges?: InheritedBooleanInfo; + private_by_default: InheritedBooleanInfo; + work_in_progress_by_default: InheritedBooleanInfo; + max_object_size_limit: MaxObjectSizeLimitInfo; + default_submit_type: SubmitTypeInfo; + submit_type: SubmitType; + match_author_to_committer_date?: InheritedBooleanInfo; + state?: ProjectState; + commentlinks: CommentLinks; + plugin_config?: ConfigParameterInfo; + actions?: {[viewName: string]: ActionInfo}; + reject_empty_commit?: InheritedBooleanInfo; +}