@bigbinary/neeto-playwright-commons 1.8.48 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ import { complement, startsWith } from "ramda";
2
+
3
+ export const REMARK_NODE_TYPES = {
4
+ HTML: "html",
5
+ PARAGRAPH: "paragraph",
6
+ CODE: "code",
7
+ HEADING: "heading",
8
+ TEXT: "text",
9
+ INLINE_CODE: "inlineCode",
10
+ };
11
+
12
+ export const BABEL_NODE_TYPES = { IDENTIFIER: "Identifier" };
13
+
14
+ export const SUBHEADING_PATTERN = { type: REMARK_NODE_TYPES.HEADING, depth: 2 };
15
+ export const HTML_PATTERN = { type: REMARK_NODE_TYPES.HTML };
16
+ export const IMG_PATTERN = {
17
+ type: REMARK_NODE_TYPES.HTML,
18
+ value: startsWith("<img"),
19
+ };
20
+ export const CODE_PATTERN = { type: REMARK_NODE_TYPES.CODE };
21
+ export const PARAGRAPH_PATTERN = { type: REMARK_NODE_TYPES.PARAGRAPH };
22
+ export const HTML_EXCEPT_IMG_PATTERN = {
23
+ type: REMARK_NODE_TYPES.HTML,
24
+ value: complement(startsWith("<img")),
25
+ };
26
+ export const INLINE_CODE_PATTERN = { type: REMARK_NODE_TYPES.INLINE_CODE };
27
+ export const TEXT_PATTERN = { type: REMARK_NODE_TYPES.TEXT };
28
+ export const DOCS_FOLDER_NAME = "docs";
29
+ export const TYPES_FOLDER_NAME = "typeTemplates";
30
+ export const EXPORTED_TYPES_FOLDER_NAME = "."; // root
31
+
32
+ export const JSDOC_IMG_HEIGHT = "200";
33
+ export const JSDOC_IMG_WIDTH = "300";
34
+
35
+ export const DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT = "\n *\n";
36
+ export const LINE_BREAK = "\n";
37
+ export const JSDOC_EXAMPLE_TAG = "@example ";
38
+ export const JSDOC_END_EXAMPLE_TAG = "@endexample";
39
+ export const ASTERISK = "*";
40
+ export const ASTERISK_WITH_SPACES = " * ";
41
+ export const WHITESPACE_PARENTHESIS_REGEX = /[\s()]/g;
@@ -0,0 +1,67 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ import _generate from "@babel/generator";
5
+ import _traverse from "@babel/traverse";
6
+ import * as babelTypes from "@babel/types";
7
+
8
+ import {
9
+ DOCS_FOLDER_NAME,
10
+ EXPORTED_TYPES_FOLDER_NAME,
11
+ TYPES_FOLDER_NAME,
12
+ } from "./constants.mjs";
13
+ import {
14
+ buildEntityTitleToEntityDescMap,
15
+ getFileContent,
16
+ getFileNameList,
17
+ parseMarkdown,
18
+ parseTypeFile,
19
+ syncTypeFiles,
20
+ defaultTypeFileTraverser,
21
+ } from "./utils.mjs";
22
+
23
+ const traverse = _traverse.default;
24
+ const generate = _generate.default;
25
+
26
+ const buildJsdoc = ({
27
+ customTypeFileTraverser = defaultTypeFileTraverser,
28
+ exportedTypesFolderName = EXPORTED_TYPES_FOLDER_NAME,
29
+ } = {}) => {
30
+ const fileNamesInsideDocs = getFileNameList(path.resolve(DOCS_FOLDER_NAME));
31
+ const typeFileNames = fs.readdirSync(path.resolve(TYPES_FOLDER_NAME));
32
+
33
+ syncTypeFiles(exportedTypesFolderName);
34
+
35
+ const entityTitleToDescMapOfAllFiles = {};
36
+
37
+ fileNamesInsideDocs.forEach(docFileName => {
38
+ const fileContent = getFileContent(docFileName);
39
+ const markdownAST = parseMarkdown(fileContent);
40
+
41
+ buildEntityTitleToEntityDescMap(
42
+ markdownAST.children,
43
+ entityTitleToDescMapOfAllFiles
44
+ );
45
+ });
46
+
47
+ // eslint-disable-next-line consistent-return
48
+ typeFileNames.forEach(typeFileName => {
49
+ const typeFileContent = getFileContent(
50
+ path.join(exportedTypesFolderName, typeFileName)
51
+ );
52
+ const typeFileAST = parseTypeFile(typeFileContent);
53
+
54
+ customTypeFileTraverser({
55
+ typeFileName: `${exportedTypesFolderName}/${typeFileName}`,
56
+ typeFileAST,
57
+ entityTitleToDescMapOfAllFiles,
58
+ babelTraverse: traverse,
59
+ babelCodeGenerator: generate,
60
+ babelTypes,
61
+ });
62
+ });
63
+
64
+ console.log("Successfully added JSDoc comments to type files.");
65
+ };
66
+
67
+ export default buildJsdoc;
@@ -0,0 +1,228 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ import * as babelParser from "@babel/parser";
5
+ import { mergeLeft } from "ramda";
6
+ import remarkParse from "remark-parse";
7
+ import { unified } from "unified";
8
+
9
+ import {
10
+ ASTERISK,
11
+ ASTERISK_WITH_SPACES,
12
+ CODE_PATTERN,
13
+ DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT,
14
+ HTML_EXCEPT_IMG_PATTERN,
15
+ IMG_PATTERN,
16
+ JSDOC_EXAMPLE_TAG,
17
+ JSDOC_END_EXAMPLE_TAG,
18
+ JSDOC_IMG_HEIGHT,
19
+ JSDOC_IMG_WIDTH,
20
+ LINE_BREAK,
21
+ PARAGRAPH_PATTERN,
22
+ SUBHEADING_PATTERN,
23
+ TYPES_FOLDER_NAME,
24
+ WHITESPACE_PARENTHESIS_REGEX,
25
+ } from "./constants.mjs";
26
+ import * as babelTypes from "@babel/types";
27
+ import _traverse from "@babel/traverse";
28
+ import _generate from "@babel/generator";
29
+
30
+ import { matches } from "@bigbinary/neeto-cist";
31
+
32
+ const traverse = _traverse.default;
33
+ const generate = _generate.default;
34
+
35
+ const removeWhiteSpaceAndParentheses = string =>
36
+ string.replace(WHITESPACE_PARENTHESIS_REGEX, "");
37
+
38
+ const addLeadingCommentForTextWithLineBreaks = ({
39
+ text,
40
+ addCommentForFirstItem = true,
41
+ addDoubleLineBreaks = true,
42
+ }) => {
43
+ if (!hasLineBreaks(text)) return addLeadingComment(text);
44
+ const joinString = addDoubleLineBreaks
45
+ ? DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT
46
+ : LINE_BREAK;
47
+
48
+ return text
49
+ .split(LINE_BREAK)
50
+ .map((item, idx) => {
51
+ if (!addCommentForFirstItem && idx === 0) return item;
52
+
53
+ return addLeadingComment(item);
54
+ })
55
+ .join(joinString);
56
+ };
57
+
58
+ const addLeadingComment = (text, trimWhiteSpace = false) =>
59
+ (trimWhiteSpace ? ASTERISK : ASTERISK_WITH_SPACES) + text;
60
+
61
+ const transformCode = node => {
62
+ let text = "";
63
+ text += addLeadingComment(JSDOC_EXAMPLE_TAG);
64
+ text += DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT;
65
+ text += addLeadingCommentForTextWithLineBreaks({
66
+ text: removeCommentTags(node.value),
67
+ addDoubleLineBreaks: false,
68
+ });
69
+ text += LINE_BREAK;
70
+ text += addLeadingComment(JSDOC_END_EXAMPLE_TAG);
71
+ text += LINE_BREAK;
72
+
73
+ return text;
74
+ };
75
+
76
+ const hasLineBreaks = text => text?.includes(LINE_BREAK);
77
+
78
+ const getParagraphChildrenText = node => {
79
+ const children = node.children;
80
+ if (children.length === 1) return children[0].value;
81
+
82
+ return children.map(child => child.value || child.children[0].value).join("");
83
+ };
84
+
85
+ const transformParagraph = node => {
86
+ let text = "";
87
+ text += ASTERISK_WITH_SPACES;
88
+ const childrenText = getParagraphChildrenText(node);
89
+
90
+ if (hasLineBreaks(childrenText)) {
91
+ text += addLeadingCommentForTextWithLineBreaks({
92
+ text: childrenText,
93
+ addCommentForFirstItem: false,
94
+ });
95
+ } else {
96
+ text += childrenText;
97
+ }
98
+ text += DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT;
99
+
100
+ return text;
101
+ };
102
+
103
+ const transformImg = node => {
104
+ const { src, alt } = parseImgTag(node.value);
105
+ let text = ASTERISK_WITH_SPACES;
106
+ text += `![${alt}](${src}|height=${JSDOC_IMG_HEIGHT}|width=${JSDOC_IMG_WIDTH})`;
107
+ text += DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT;
108
+
109
+ return text;
110
+ };
111
+
112
+ const transformNodesToText = nodes => {
113
+ let text = DOUBLE_LINE_BREAK_WITH_LEADING_COMMENT;
114
+
115
+ nodes.forEach(node => {
116
+ if (matches(CODE_PATTERN, node)) {
117
+ text += transformCode(node);
118
+ } else if (matches(IMG_PATTERN, node)) {
119
+ text += transformImg(node);
120
+ } else if (matches(PARAGRAPH_PATTERN, node)) {
121
+ text += transformParagraph(node);
122
+ }
123
+ });
124
+
125
+ return addLeadingComment(text, true);
126
+ };
127
+
128
+ const parseImgTag = imgTagStr =>
129
+ imgTagStr.split(" ").reduce((acc, item) => {
130
+ let [attrName, attrValue] = item.split("=");
131
+ attrValue = attrValue?.replaceAll(">", "").replaceAll('"', "");
132
+
133
+ return mergeLeft({ [attrName]: attrValue }, acc);
134
+ }, {});
135
+
136
+ const removeCommentTags = str => str.replaceAll("/*", "").replaceAll("*/", "");
137
+
138
+ export const parseTypeFile = typeFileContent =>
139
+ babelParser.parse(typeFileContent, {
140
+ sourceType: "module",
141
+ plugins: [["typescript", { dts: true }]],
142
+ });
143
+
144
+ export const buildEntityTitleToEntityDescMap = (nodes, map) => {
145
+ nodes.forEach((node, idx) => {
146
+ if (!matches(SUBHEADING_PATTERN, node)) return;
147
+
148
+ const entityName = removeWhiteSpaceAndParentheses(node.children[0].value);
149
+ const entityRightSiblings = [];
150
+
151
+ for (let i = idx + 1; i < nodes.length; i++) {
152
+ const siblingNode = nodes[i];
153
+
154
+ if (matches(HTML_EXCEPT_IMG_PATTERN, siblingNode)) continue;
155
+
156
+ if (matches(SUBHEADING_PATTERN, siblingNode)) break;
157
+
158
+ entityRightSiblings.push(siblingNode);
159
+ }
160
+ const entityRightSiblingsText = transformNodesToText(entityRightSiblings);
161
+ map[entityName] = entityRightSiblingsText;
162
+ });
163
+ };
164
+
165
+ export const syncTypeFiles = exportedTypesFolderName => {
166
+ const sourceDir = path.resolve(TYPES_FOLDER_NAME);
167
+ const destDir = path.resolve(exportedTypesFolderName);
168
+
169
+ fs.cpSync(sourceDir, destDir, { recursive: true });
170
+ };
171
+
172
+ export const getFileNameList = dirPath => {
173
+ let files = [];
174
+ const items = fs.readdirSync(dirPath, { withFileTypes: true });
175
+
176
+ for (const item of items) {
177
+ if (item.isDirectory()) {
178
+ files = [...files, ...getFileNameList(path.join(dirPath, item.name))];
179
+ } else {
180
+ files.push(path.join(dirPath, item.name));
181
+ }
182
+ }
183
+
184
+ return files;
185
+ };
186
+
187
+ export const getFileContent = fileName =>
188
+ fs.readFileSync(path.resolve(fileName), "utf8").toString();
189
+
190
+ export const parseMarkdown = fileContent =>
191
+ unified().use(remarkParse).parse(fileContent);
192
+
193
+ export const defaultTypeFileTraverser = options => {
194
+ traverse(options.typeFileAST, {
195
+ VariableDeclaration: ({ node }) =>
196
+ handleNode({
197
+ node,
198
+ options,
199
+ extractEntityName: findVariableDeclarationName,
200
+ }),
201
+ ClassProperty: ({ node }) =>
202
+ handleNode({ node, options, extractEntityName: findClassPropertyName }),
203
+ });
204
+ };
205
+
206
+ export const findVariableDeclarationName = node =>
207
+ node?.declarations?.[0]?.id?.name || node?.declaration?.id?.name;
208
+
209
+ export const findClassPropertyName = node => node?.key?.name;
210
+
211
+ export const handleNode = ({
212
+ node,
213
+ extractEntityName,
214
+ options: { entityTitleToDescMapOfAllFiles, typeFileName, typeFileAST },
215
+ }) => {
216
+ const entityName = extractEntityName(node);
217
+ const entityDesc = entityTitleToDescMapOfAllFiles[entityName];
218
+
219
+ if (!entityName || !entityDesc) {
220
+ return;
221
+ }
222
+
223
+ babelTypes.addComment(node, "leading", entityDesc);
224
+
225
+ const { code } = generate(typeFileAST, {});
226
+
227
+ fs.writeFileSync(path.resolve(typeFileName), code);
228
+ };
package/index.cjs.js CHANGED
@@ -72,6 +72,25 @@ var require$$1__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$1$2);
72
72
  var require$$4__default = /*#__PURE__*/_interopDefaultLegacy(require$$4$1);
73
73
  var require$$3__default$2 = /*#__PURE__*/_interopDefaultLegacy(require$$3$2);
74
74
 
75
+ const NEETO_FILTERS_SELECTORS = {
76
+ emailSelectContainer: "email-select-container-wrapper",
77
+ filterPaneHeading: "neeto-filters-pane-header",
78
+ neetoFiltersEmailBlock: "neeto-filters-email-block",
79
+ neetoFiltersRoleBlock: "neeto-filters-role-block",
80
+ neetoFiltersBarClearButton: "neeto-filters-bar-clear-btn",
81
+ neetoFiltersNameFilterField: "neeto-filters-name-filter",
82
+ neetoFilterNameBlock: "neeto-filters-name-block",
83
+ roleSelectContainer: "role-select-container-wrapper",
84
+ filterButton: "neeto-filters-toggle-btn",
85
+ filtersClearButton: "neeto-filters-clear-btn",
86
+ filterDoneButton: "neeto-filters-done-btn",
87
+ filteredMembersCount: "ntm-filtered-members-count",
88
+ allMenubarBlock: "ntm-members-menubar-all-block",
89
+ filtersEmailFilter: "neeto-filters-email-filter",
90
+ paneModalCrossIcon: "neeto-filters-close-button",
91
+ searchTermBlock: "neeto-filters-search-term-block",
92
+ };
93
+
75
94
  const ENVIRONMENT = {
76
95
  development: "development",
77
96
  staging: "staging",
@@ -2632,6 +2651,16 @@ class CustomCommands {
2632
2651
  ? Promise.all(values.map(value => verifyEachFieldValue(value)))
2633
2652
  : verifyEachFieldValue(values);
2634
2653
  };
2654
+ this.searchAndVerify = async ({ searchTerm, searchInputSelector = COMMON_SELECTORS.inputField, countSelector, countText, }) => {
2655
+ await test$1.expect(async () => {
2656
+ await this.page.getByTestId(searchInputSelector).fill(searchTerm);
2657
+ await test$1.expect(this.page.getByTestId(NEETO_FILTERS_SELECTORS.searchTermBlock)).toBeVisible();
2658
+ await this.page.reload({ waitUntil: "load" });
2659
+ await test$1.expect(this.page.getByTestId(COMMON_SELECTORS.pageLoader)).toBeHidden({ timeout: 10000 });
2660
+ await test$1.expect(this.page.getByRole("cell", { name: searchTerm })).toBeVisible();
2661
+ await test$1.expect(this.page.getByTestId(countSelector)).toContainText(countText);
2662
+ }).toPass({ timeout: 15000 });
2663
+ };
2635
2664
  this.page = page;
2636
2665
  this.responses = [];
2637
2666
  this.request = request;
@@ -13822,24 +13851,6 @@ const NEETO_EDITOR_SELECTORS = {
13822
13851
  submitLinkButton: "neeto-editor-add-link",
13823
13852
  };
13824
13853
 
13825
- const NEETO_FILTERS_SELECTORS = {
13826
- emailSelectContainer: "email-select-container-wrapper",
13827
- filterPaneHeading: "neeto-filters-pane-header",
13828
- neetoFiltersEmailBlock: "neeto-filters-email-block",
13829
- neetoFiltersRoleBlock: "neeto-filters-role-block",
13830
- neetoFiltersBarClearButton: "neeto-filters-bar-clear-btn",
13831
- neetoFiltersNameFilterField: "neeto-filters-name-filter",
13832
- neetoFilterNameBlock: "neeto-filters-name-block",
13833
- roleSelectContainer: "role-select-container-wrapper",
13834
- filterButton: "neeto-filters-toggle-btn",
13835
- filtersClearButton: "neeto-filters-clear-btn",
13836
- filterDoneButton: "neeto-filters-done-btn",
13837
- filteredMembersCount: "ntm-filtered-members-count",
13838
- allMenubarBlock: "ntm-members-menubar-all-block",
13839
- filtersEmailFilter: "neeto-filters-email-filter",
13840
- paneModalCrossIcon: "neeto-filters-close-button",
13841
- };
13842
-
13843
13854
  const MEMBER_SELECTORS = {
13844
13855
  membersTab: "members-nav-tab",
13845
13856
  newButton: "ntm-add-member-button",