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;
+}