@aurodesignsystem-dev/auro-library 0.0.0-pr187.0

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.
Files changed (43) hide show
  1. package/.husky/commit-msg +4 -0
  2. package/.husky/pre-commit +4 -0
  3. package/.tool-versions +1 -0
  4. package/CHANGELOG.md +664 -0
  5. package/LICENSE +201 -0
  6. package/README.md +235 -0
  7. package/bin/generateDocs.mjs +210 -0
  8. package/bin/generateDocs_index.mjs +210 -0
  9. package/package.json +92 -0
  10. package/scripts/build/generateDocs.mjs +24 -0
  11. package/scripts/build/generateReadme.mjs +60 -0
  12. package/scripts/build/generateWcaComponent.mjs +43 -0
  13. package/scripts/build/postCss.mjs +66 -0
  14. package/scripts/build/postinstall.mjs +31 -0
  15. package/scripts/build/pre-commit.mjs +17 -0
  16. package/scripts/build/prepWcaCompatibleCode.mjs +19 -0
  17. package/scripts/build/processors/defaultDocsProcessor.mjs +83 -0
  18. package/scripts/build/processors/defaultDotGithubSync.mjs +83 -0
  19. package/scripts/build/staticStyles-template.js +2 -0
  20. package/scripts/build/syncGithubFiles.mjs +25 -0
  21. package/scripts/build/versionWriter.js +26 -0
  22. package/scripts/runtime/FocusTrap/FocusTrap.mjs +194 -0
  23. package/scripts/runtime/FocusTrap/index.mjs +1 -0
  24. package/scripts/runtime/FocusTrap/test/FocusTrap.test.js +168 -0
  25. package/scripts/runtime/Focusables/Focusables.mjs +157 -0
  26. package/scripts/runtime/Focusables/index.mjs +1 -0
  27. package/scripts/runtime/Focusables/test/Focusables.test.js +165 -0
  28. package/scripts/runtime/dateUtilities/baseDateUtilities.mjs +58 -0
  29. package/scripts/runtime/dateUtilities/dateConstraints.mjs +11 -0
  30. package/scripts/runtime/dateUtilities/dateFormatter.mjs +104 -0
  31. package/scripts/runtime/dateUtilities/dateUtilities.mjs +218 -0
  32. package/scripts/runtime/dateUtilities/index.mjs +26 -0
  33. package/scripts/runtime/dependencyTagVersioning.mjs +42 -0
  34. package/scripts/runtime/floatingUI.mjs +646 -0
  35. package/scripts/test-plugin/iterateWithA11Check.mjs +82 -0
  36. package/scripts/utils/auroFileHandler.mjs +70 -0
  37. package/scripts/utils/auroLibraryUtils.mjs +206 -0
  38. package/scripts/utils/auroTemplateFiller.mjs +178 -0
  39. package/scripts/utils/logger.mjs +73 -0
  40. package/scripts/utils/runtimeUtils.mjs +70 -0
  41. package/scripts/utils/sharedFileProcessorUtils.mjs +270 -0
  42. package/shellScripts/README.md +58 -0
  43. package/shellScripts/automation.sh +104 -0
@@ -0,0 +1,82 @@
1
+ import { expect } from '@open-wc/testing';
2
+
3
+ let originalIt;
4
+ async function checkElementAccessibility(element) {
5
+ // test only when this element is meaningful.
6
+ if (element.children.length || element.attributes.length) {
7
+ await expect(element).to.be.accessible();
8
+ }
9
+ }
10
+
11
+ function aIt(desc, action) {
12
+ const actionWithA11y = async () => {
13
+ const result = await action();
14
+
15
+ let rootElement;
16
+ if (typeof result === 'string') {
17
+ rootElement = document.querySelector(result);
18
+ } else if (result instanceof Element) {
19
+ rootElement = result;
20
+ } else {
21
+ // fallback incase `action()` didnt return the created node.
22
+ // The framework injdect any elements that are created during `action()` to first `div` layer under `body`.
23
+ // this `div` will get cleared after the iteration.
24
+ rootElement = document.body.querySelector('div');
25
+ }
26
+
27
+ if (rootElement) {
28
+ await checkElementAccessibility(rootElement);
29
+ }
30
+
31
+ const children = [...document.body.children];
32
+ for (let child of children) {
33
+ if (child !== rootElement) {
34
+ // when the iteration's element uses `floatingUI`, there will be an extra child under `body`.
35
+ if (
36
+ child.hasAttribute("auro-dropdownbib") ||
37
+ child.hasAttribute("auro-floater-bib")
38
+ ) {
39
+ // test `floatingUI.bib`
40
+ await checkElementAccessibility(child);
41
+ }
42
+ }
43
+ }
44
+ };
45
+
46
+ originalIt(desc, actionWithA11y);
47
+ }
48
+
49
+ /**
50
+ * Usage Example
51
+ *
52
+ * import { getAccessibleIt } from "@aurodesignsystem/auro-library/scripts/test-plugin/iterateWithA11Check.mjs";
53
+ *
54
+ * it = getAccessibleIt();
55
+ *
56
+ * OR
57
+ *
58
+ * import { getAccessibleIt } from "@aurodesignsystem/auro-library/scripts/test-plugin/iterateWithA11Check.mjs";
59
+ *
60
+ * aIt = getAccessibleIt();
61
+ *
62
+ * describe('test', () => {
63
+ * aIt('description', () => {
64
+ * ...
65
+ * }
66
+ * });
67
+ */
68
+ export function getAccessibleIt() {
69
+ originalIt ??= it;
70
+ return aIt;
71
+ }
72
+
73
+ /**
74
+ * Usage Example
75
+ *
76
+ * import { useAccessibleIt } from "@aurodesignsystem/auro-library/scripts/test-plugin/iterateWithA11Check.mjs";
77
+ * useAccessibleIt();
78
+ */
79
+ export function useAccessibleIt() {
80
+ originalIt ??= it;
81
+ it = aIt;
82
+ }
@@ -0,0 +1,70 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ import {Logger} from "../utils/logger.mjs";
5
+
6
+ export class AuroFileHandler {
7
+
8
+ /**
9
+ * Check if a file exists.
10
+ * @param {string} filePath - The file path to check.
11
+ * @returns {Promise<boolean>}
12
+ */
13
+ static async exists(filePath) {
14
+ try {
15
+ await fs.access(filePath);
16
+ return true;
17
+ // eslint-disable-next-line no-unused-vars
18
+ } catch (_err) {
19
+ return false;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Try to read a file and return its contents.
25
+ * @param {string} filePath - The file path to read.
26
+ * @returns {Promise<null|string>}
27
+ */
28
+ static async tryReadFile(filePath) {
29
+ try {
30
+ return await fs.readFile(filePath, {encoding: 'utf-8'});
31
+ } catch (err) {
32
+ Logger.error(`Error reading file: ${filePath}, ${err.message}`);
33
+ return null;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Try to write a file with the given contents.
39
+ * @param {string} filePath - The file path to write to.
40
+ * @param {string} fileContents - The contents to write to the file.
41
+ * @returns {Promise<boolean>}
42
+ */
43
+ static async tryWriteFile(filePath, fileContents) {
44
+ try {
45
+ const dirname = path.dirname(filePath);
46
+ await fs.mkdir(dirname, {recursive: true});
47
+ await fs.writeFile(filePath, fileContents, {encoding: 'utf-8'});
48
+ return true;
49
+ } catch (err) {
50
+ Logger.error(`Error writing file: ${filePath}, ${err.message}`);
51
+ return false;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Try to copy a file from one location to another.
57
+ * @param {string} source - The source file path.
58
+ * @param {string} destination - The destination file path.
59
+ * @returns {Promise<boolean>}
60
+ */
61
+ static async tryCopyFile(source, destination) {
62
+ try {
63
+ await fs.copyFile(source, destination);
64
+ return true;
65
+ } catch (err) {
66
+ Logger.error(`Error copying file: ${source}, ${err.message}`);
67
+ return false;
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,206 @@
1
+ // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
2
+ // See LICENSE in the project root for license information.
3
+
4
+ // ---------------------------------------------------------------------
5
+
6
+ /* eslint-disable arrow-parens, line-comment-position, no-console, no-inline-comments, no-magic-numbers, prefer-arrow-callback, require-unicode-regexp, jsdoc/require-description-complete-sentence, prefer-named-capture-group */
7
+
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import chalk from 'chalk';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ import {Logger} from "./logger.mjs";
14
+
15
+ export default class AuroLibraryUtils {
16
+ getDirname() {
17
+ return fileURLToPath(import.meta.url);
18
+ }
19
+
20
+ get getProjectRootPath() {
21
+ const currentDir = this.getDirname();
22
+
23
+ if (!currentDir.includes('node_modules')) {
24
+ Logger.warn(`Unable to determine best project root as node_modules \nis not in the directory path.\n\nAssuming - "${currentDir}"`, true);
25
+ return currentDir;
26
+ }
27
+
28
+ return currentDir.split('node_modules')[0];
29
+ }
30
+
31
+ /**
32
+ * Copies and pastes all files in a source directory into a destination directory.
33
+ * @param {String} srcDir - File path of directory to copy from.
34
+ * @param {String} destDir - File path of directory to paste files into.
35
+ * @param {Boolean} removeFiles - If true, removes all files in destination directory before pasting files.
36
+ */
37
+ copyDirectory(srcDir, destDir, removeFiles) {
38
+ if (!fs.existsSync(srcDir)) {
39
+ this.auroLogger(`Source directory ${srcDir} does not exist`, 'error', false);
40
+ } else {
41
+ // Removes all files from directory
42
+ if (removeFiles && fs.existsSync(destDir)) {
43
+ const destFiles = fs.readdirSync(destDir);
44
+
45
+ let filesRemoved = 0;
46
+
47
+ destFiles.forEach(file => {
48
+ const filePath = path.join(destDir, file);
49
+ fs.unlinkSync(filePath);
50
+ this.auroLogger(`Removed file: ${file}`, 'success', false);
51
+
52
+ filesRemoved += 1;
53
+ });
54
+
55
+ if (filesRemoved > 0) {
56
+ this.auroLogger(`Removed ${filesRemoved} files`, 'success', false);
57
+ }
58
+ }
59
+
60
+ // Creates destination directory if it does not exist
61
+ if (!fs.existsSync(destDir)) {
62
+ fs.mkdirSync(destDir);
63
+ }
64
+
65
+ // All files from source directory
66
+ const files = fs.readdirSync(srcDir);
67
+
68
+ // Copies over all files from source directory to destination directory
69
+ files.forEach(file => {
70
+ const sourceFilePath = path.join(srcDir, file);
71
+ const destFilePath = path.join(destDir, file);
72
+
73
+ const stat = fs.statSync(sourceFilePath);
74
+
75
+ if (stat.isDirectory()) {
76
+ this.copyDirectory(srcDir, destDir, removeFiles);
77
+ } else {
78
+ fs.copyFileSync(sourceFilePath, destFilePath);
79
+
80
+ fs.readFile(destFilePath, 'utf8', (err, data) => {
81
+ this.formatFileContents(data, destFilePath);
82
+ });
83
+
84
+ this.auroLogger(`Copied file: ${file}`, 'success');
85
+ }
86
+ });
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Logs out messages in a readable format.
92
+ * @param {String} message - Message to be logged.
93
+ * @param {"info" | "success" | "error"} status - Status that determines the color of the logged message.
94
+ * @param {Boolean} section - If true, adds a box around the message for readability.
95
+ */
96
+ auroLogger(message, status, section) {
97
+ if (status) {
98
+ const infoColor = '#0096FF'; // blue
99
+ const successColor = '#4CBB17'; // green
100
+ const errorColor = '#ff0000'; // red
101
+
102
+ let color = undefined; // eslint-disable-line no-undef-init
103
+
104
+ if (status === 'info') {
105
+ color = infoColor;
106
+ } else if (status === 'success') {
107
+ color = successColor;
108
+ } else if (status === 'error') {
109
+ color = errorColor;
110
+ }
111
+
112
+ if (section) {
113
+ console.log(chalk.hex(color)(`╭ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ──────────────────────────────╮\n`));
114
+ }
115
+
116
+ console.log(chalk.hex(color)(message));
117
+
118
+ if (section) {
119
+ console.log(chalk.hex(color)('\n╰─────────────────────────────── ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯'));
120
+ }
121
+ } else {
122
+ if (section) {
123
+ console.log(`╭ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ──────────────────────────────╮\n`);
124
+ }
125
+
126
+ console.log(message);
127
+
128
+ if (section) {
129
+ console.log(`\n╰─────────────────────────────── ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯`);
130
+ }
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Extracts NPM VERSION, BRANCH NAME, NPM, NAMESPACE, and NAME from package.json.
136
+ * @returns {Object} result - Object containing data from package.json.
137
+ */
138
+ nameExtraction() {
139
+ let packageJson = fs.readFileSync('package.json', 'utf8', function(err) {
140
+ if (err) {
141
+ console.log('ERROR: Unable to read package.json file', err);
142
+ }
143
+ });
144
+
145
+ packageJson = JSON.parse(packageJson);
146
+
147
+ const pName = packageJson.name;
148
+ const npmStart = pName.indexOf('@');
149
+ const namespaceStart = pName.indexOf('/');
150
+ const nameStart = pName.indexOf('-');
151
+
152
+ return {
153
+ 'abstractNodeVersion': packageJson.engines.node.substring(2),
154
+ 'branchName': packageJson.release.branch,
155
+ 'npm': pName.substring(npmStart, namespaceStart),
156
+ 'namespace': pName.substring(namespaceStart + 1, nameStart),
157
+ 'namespaceCap': pName.substring(namespaceStart + 1)[0].toUpperCase() + pName.substring(namespaceStart + 2, nameStart),
158
+ 'name': pName.substring(nameStart + 1),
159
+ 'nameCap': pName.substring(nameStart + 1)[0].toUpperCase() + pName.substring(nameStart + 2),
160
+ 'version': packageJson.version,
161
+ 'tokensVersion': packageJson.peerDependencies['@aurodesignsystem/design-tokens'].substring(1),
162
+ 'wcssVersion': packageJson.peerDependencies['@aurodesignsystem/webcorestylesheets'].substring(1)
163
+
164
+ };
165
+ }
166
+
167
+ /**
168
+ * Replace all instances of [abstractNodeVersion], [branchName], [npm], [name], [Name], [namespace] and [Namespace] accordingly.
169
+ * @param {String} content - The content to be formatted.
170
+ * @param {String} destination - The location to write the formatted content.
171
+ * @returns {void}
172
+ */
173
+ formatFileContents(content, destination) {
174
+ const nameExtractionData = this.nameExtraction();
175
+ let result = content;
176
+
177
+ /**
178
+ * Replace placeholder strings.
179
+ */
180
+ result = result.replace(/\[abstractNodeVersion]/g, nameExtractionData.abstractNodeVersion);
181
+ result = result.replace(/\[branchName]/g, nameExtractionData.branchName);
182
+ result = result.replace(/\[npm]/g, nameExtractionData.npm);
183
+ result = result.replace(/\[name](?!\()/g, nameExtractionData.name);
184
+ result = result.replace(/\[Name](?!\()/g, nameExtractionData.nameCap);
185
+ result = result.replace(/\[namespace]/g, nameExtractionData.namespace);
186
+ result = result.replace(/\[Namespace]/g, nameExtractionData.namespaceCap);
187
+ result = result.replace(/\[Version]/g, nameExtractionData.version);
188
+ result = result.replace(/\[dtVersion]/g, nameExtractionData.tokensVersion);
189
+ result = result.replace(/\[wcssVersion]/g, nameExtractionData.wcssVersion);
190
+
191
+ /**
192
+ * Cleanup line breaks.
193
+ */
194
+ result = result.replace(/(\r\n|\r|\n)[\s]+(\r\n|\r|\n)/g, '\r\n\r\n'); // Replace lines containing only whitespace with a carriage return.
195
+ result = result.replace(/>(\r\n|\r|\n){2,}/g, '>\r\n'); // Remove empty lines directly after a closing html tag.
196
+ result = result.replace(/>(\r\n|\r|\n)```/g, '>\r\n\r\n```'); // Ensure an empty line before code samples.
197
+ result = result.replace(/>(\r\n|\r|\n){2,}```(\r\n|\r|\n)/g, '>\r\n```\r\n'); // Ensure no empty lines before close of code sample.
198
+ result = result.replace(/([^(\r\n|\r|\n)])(\r?\n|\r(?!\n))+#/g, "$1\r\n\r\n#"); // Ensure empty line before header sections.
199
+
200
+ /**
201
+ * Write the result to the destination file.
202
+ */
203
+ fs.writeFileSync(destination, result, { encoding: 'utf8'});
204
+ }
205
+ }
206
+
@@ -0,0 +1,178 @@
1
+ // eslint-disable
2
+ import Handlebars from "handlebars"
3
+ import fs from "node:fs/promises";
4
+
5
+ // declare package.json type with jsdoc
6
+ /**
7
+ * @typedef {Object} ExamplePackageJson
8
+ * @property {string} name - Name of the package.
9
+ * @property {string} version - Version of the package.
10
+ * @property {Record<string, string>} peerDependencies - Peer dependencies of the package.
11
+ */
12
+
13
+ // declare extracted names type with jsdoc
14
+ /**
15
+ * @typedef {Object} ExtractedNames
16
+ * @property {string} npm - NPM of the package.
17
+ * @property {string} namespace - Namespace of the package.
18
+ * @property {string} namespaceCap - Capitalized namespace of the package.
19
+ * @property {string} name - Name of the package.
20
+ * @property {string} nameCap - Capitalized name of the package.
21
+ * @property {string} version - Version of the package.
22
+ * @property {string} tokensVersion - Version of the design tokens.
23
+ * @property {string} wcssVersion - Version of the webcorestylesheets.
24
+ */
25
+
26
+
27
+ export class AuroTemplateFiller {
28
+ static designTokenPackage = '@aurodesignsystem/design-tokens';
29
+ static webCoreStylesheetsPackage = '@aurodesignsystem/webcorestylesheets';
30
+
31
+ constructor () {
32
+ /** @type {ExtractedNames} */
33
+ this.values = null;
34
+ }
35
+
36
+ async prepare() {
37
+ await this.extractNames()
38
+ }
39
+
40
+ /**
41
+ * Extract various data for filling template files from the package.json file.
42
+ * @returns {Promise<ExtractedNames>}
43
+ */
44
+ async extractNames() {
45
+ const packageJsonData = await fs.readFile('package.json', 'utf8');
46
+
47
+ /** @type {ExamplePackageJson} */
48
+ const parsedPackageJson = JSON.parse(packageJsonData);
49
+
50
+ const pName = parsedPackageJson.name;
51
+ const pVersion = parsedPackageJson.version;
52
+ const pdtVersion = parsedPackageJson.peerDependencies?.[AuroTemplateFiller.designTokenPackage].substring(1) ?? '';
53
+ const wcssVersion = parsedPackageJson.peerDependencies?.[AuroTemplateFiller.webCoreStylesheetsPackage].substring(1) ?? '';
54
+
55
+ const npmStart = pName.indexOf('@');
56
+ const namespaceStart = pName.indexOf('/');
57
+ const nameStart = pName.indexOf('-');
58
+ const packageNamespace = pName.substring(namespaceStart + 1, nameStart);
59
+
60
+ if (nameStart === -1) {
61
+ throw new Error(`No name can be derived from package.json "name" field: '${pName}'. Expected pattern with \`-\` split like [\`@aurodesignsystem/auro-component\` or \`@aurodesignsystem/eslint-config\`, etc.]`);
62
+ }
63
+
64
+ this.values = {
65
+ 'npm': pName.substring(npmStart, namespaceStart),
66
+ 'namespace': packageNamespace,
67
+ 'namespaceCap': pName.substring(namespaceStart + 1)[0].toUpperCase() + pName.substring(namespaceStart + 2, nameStart),
68
+ 'name': pName.substring(nameStart + 1),
69
+ 'nameCap': pName.substring(nameStart + 1)[0].toUpperCase() + pName.substring(nameStart + 2),
70
+ 'version': pVersion,
71
+ 'tokensVersion': pdtVersion,
72
+ wcssVersion
73
+ };
74
+ }
75
+
76
+ /**
77
+ * @param {string} template - The string to use to run variable replacement
78
+ * @param {object} extraVars - Additional variables to use in the template
79
+ * @return {string}
80
+ */
81
+ replaceTemplateValues(template, extraVars = {}) {
82
+ const compileResult = Handlebars.compile(template);
83
+
84
+ // replace all handlebars placeholders FIRST, then apply legacy replacements
85
+ let result = compileResult({
86
+ // TODO: consider replacing some of these with handlebars helpers
87
+ name: this.values.name,
88
+ Name: this.values.nameCap,
89
+ namespace: this.values.namespace,
90
+ Namespace: this.values.namespaceCap,
91
+ Version: this.values.version,
92
+ dtVersion: this.values.tokensVersion,
93
+ wcssVersion: this.values.wcssVersion,
94
+ ...extraVars
95
+ }, {
96
+ helpers: {
97
+ 'capitalize': (str) => str.charAt(0).toUpperCase() + str.slice(1),
98
+ // Hard codes `auro-*` with whatever string is passed in.
99
+ 'withAuroNamespace': (str) => `auro-${str}`,
100
+ // Recreats the string from package.json: auro-component, eslint-config, etc.
101
+ 'packageName': () => `${this.values['namespace']}-${this.values['name']}`
102
+ }
103
+ })
104
+
105
+ /**
106
+ * Old legacy template variables. We used to use `[varName]` and are now using handlebars `{{varName}}`.
107
+ * @type {[{pattern: RegExp, replacement: string},{pattern: RegExp, replacement: string},{pattern: RegExp, replacement: string},{pattern: RegExp, replacement: string},{pattern: RegExp, replacement: string},null,null,null]}
108
+ */
109
+ const legacyTemplateVariables = [
110
+ {
111
+ pattern: /\[npm\]/gu,
112
+ replacement: this.values.npm
113
+ },
114
+ {
115
+ pattern: /\[name\](?!\()/gu,
116
+ replacement: this.values.name
117
+ },
118
+ {
119
+ pattern: /\[Name\](?!\()/gu,
120
+ replacement: this.values.nameCap
121
+ },
122
+ {
123
+ pattern: /\[namespace\]/gu,
124
+ replacement: this.values.namespace
125
+ },
126
+ {
127
+ pattern: /\[Namespace\]/gu,
128
+ replacement: this.values.namespaceCap
129
+ },
130
+ {
131
+ pattern: /\[Version\]/gu,
132
+ replacement: this.values.version
133
+ },
134
+ {
135
+ pattern: /\[dtVersion\]/gu,
136
+ replacement: this.values.tokensVersion
137
+ },
138
+ {
139
+ pattern: /\[wcssVersion\]/gu,
140
+ replacement: this.values.wcssVersion
141
+ }
142
+ ];
143
+
144
+ /**
145
+ * Replace legacy placeholder strings.
146
+ */
147
+ for (const { pattern, replacement } of legacyTemplateVariables) {
148
+ result = result.replace(pattern, replacement);
149
+ }
150
+
151
+ /**
152
+ * Cleanup line breaks.
153
+ */
154
+ result = result.replace(/(\r\n|\r|\n)[\s]+(\r\n|\r|\n)/g, '\r\n\r\n'); // Replace lines containing only whitespace with a carriage return.
155
+ result = result.replace(/>(\r\n|\r|\n){2,}/g, '>\r\n'); // Remove empty lines directly after a closing html tag.
156
+ result = result.replace(/>(\r\n|\r|\n)```/g, '>\r\n\r\n```'); // Ensure an empty line before code samples.
157
+ result = result.replace(/>(\r\n|\r|\n){2,}```(\r\n|\r|\n)/g, '>\r\n```\r\n'); // Ensure no empty lines before close of code sample.
158
+ result = result.replace(/([^(\r\n|\r|\n)])(\r?\n|\r(?!\n))+#/g, "$1\r\n\r\n#"); // Ensure empty line before header sections.
159
+
160
+ return result;
161
+ }
162
+
163
+
164
+ /**
165
+ *
166
+ * @param {string} content
167
+ */
168
+ formatApiTable(content) {
169
+ let result = `${content}`;
170
+
171
+ result = result
172
+ .replace(/\r\n|\r|\n####\s`([a-zA-Z]*)`/g, `\r\n#### <a name="$1"></a>\`$1\`<a href="#" style="float: right; font-size: 1rem; font-weight: 100;">back to top</a>`)
173
+ .replace(/\r\n|\r|\n\|\s`([a-zA-Z]*)`/g, '\r\n| [$1](#$1)')
174
+ .replace(/\| \[\]\(#\)/g, "");
175
+
176
+ return result
177
+ }
178
+ }
@@ -0,0 +1,73 @@
1
+ /* eslint-disable no-inline-comments, no-console, line-comment-position */
2
+
3
+ import chalk from 'chalk';
4
+
5
+ export class Logger {
6
+
7
+ /**
8
+ * Logs out messages in a readable format.
9
+ * @param {String} message - Message to be logged.
10
+ * @param {false | "info" | "success" | "error" | "warn"} status - Status that determines the color of the logged message.
11
+ * @param {Boolean} section - If true, adds a box around the message for readability.
12
+ */
13
+ static auroLogger(message, status, section) {
14
+ if (status !== false) {
15
+ const infoColor = '#0096FF'; // blue
16
+ const successColor = '#4CBB17'; // green
17
+ const errorColor = '#ff0000'; // red
18
+ const warningColor = '#FFA500'; // orange
19
+
20
+ let color = undefined; // eslint-disable-line no-undef-init
21
+
22
+ if (status === 'info') {
23
+ color = infoColor;
24
+ } else if (status === 'success') {
25
+ color = successColor;
26
+ } else if (status === 'error') {
27
+ color = errorColor;
28
+ } else if (status === 'warn') {
29
+ color = warningColor;
30
+ }
31
+
32
+ if (section) {
33
+ console.log(chalk.hex(color)(`╭ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ──────────────────────────────╮\n`));
34
+ }
35
+
36
+ console.log(chalk.hex(color)(message));
37
+
38
+ if (section) {
39
+ console.log(chalk.hex(color)('\n╰─────────────────────────────── ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯'));
40
+ }
41
+ } else {
42
+ if (section) {
43
+ console.log(`╭ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ──────────────────────────────╮\n`);
44
+ }
45
+
46
+ console.log(message);
47
+
48
+ if (section) {
49
+ console.log(`\n╰─────────────────────────────── ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯`);
50
+ }
51
+ }
52
+ }
53
+
54
+ static log(message, section = false) {
55
+ Logger.auroLogger(message, false, section);
56
+ }
57
+
58
+ static info(message, section = false) {
59
+ Logger.auroLogger(message, "info", section);
60
+ }
61
+
62
+ static warn(message, section = false) {
63
+ Logger.auroLogger(message, "warn", section);
64
+ }
65
+
66
+ static success(message, section = false) {
67
+ Logger.auroLogger(message, "success", section);
68
+ }
69
+
70
+ static error(message, section = false) {
71
+ Logger.auroLogger(message, "error", section);
72
+ }
73
+ }
@@ -0,0 +1,70 @@
1
+ // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
2
+ // See LICENSE in the project root for license information.
3
+
4
+ // ---------------------------------------------------------------------
5
+
6
+ /* eslint-disable line-comment-position, no-inline-comments, no-confusing-arrow, no-nested-ternary, implicit-arrow-linebreak */
7
+
8
+ export default class AuroLibraryRuntimeUtils {
9
+
10
+ /* eslint-disable jsdoc/require-param */
11
+
12
+ /**
13
+ * This will register a new custom element with the browser.
14
+ * @param {String} name - The name of the custom element.
15
+ * @param {Object} componentClass - The class to register as a custom element.
16
+ * @returns {void}
17
+ */
18
+ registerComponent(name, componentClass) {
19
+ if (!customElements.get(name)) {
20
+ customElements.define(name, class extends componentClass {});
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Finds and returns the closest HTML Element based on a selector.
26
+ * @returns {void}
27
+ */
28
+ closestElement(
29
+ selector, // selector like in .closest()
30
+ base = this, // extra functionality to skip a parent
31
+ __Closest = (el, found = el && el.closest(selector)) =>
32
+ !el || el === document || el === window
33
+ ? null // standard .closest() returns null for non-found selectors also
34
+ : found
35
+ ? found // found a selector INside this element
36
+ : __Closest(el.getRootNode().host) // recursion!! break out to parent DOM
37
+ ) {
38
+ return __Closest(base);
39
+ }
40
+ /* eslint-enable jsdoc/require-param */
41
+
42
+ /**
43
+ * If the element passed is registered with a different tag name than what is passed in, the tag name is added as an attribute to the element.
44
+ * @param {Object} elem - The element to check.
45
+ * @param {String} tagName - The name of the Auro component to check for or add as an attribute.
46
+ * @returns {void}
47
+ */
48
+ handleComponentTagRename(elem, tagName) {
49
+ const tag = tagName.toLowerCase();
50
+ const elemTag = elem.tagName.toLowerCase();
51
+
52
+ if (elemTag !== tag) {
53
+ elem.setAttribute(tag, true);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Validates if an element is a specific Auro component.
59
+ * @param {Object} elem - The element to validate.
60
+ * @param {String} tagName - The name of the Auro component to check against.
61
+ * @returns {Boolean} - Returns true if the element is the specified Auro component.
62
+ */
63
+ elementMatch(elem, tagName) {
64
+ const tag = tagName.toLowerCase();
65
+ const elemTag = elem.tagName.toLowerCase();
66
+
67
+ return elemTag === tag || elem.hasAttribute(tag);
68
+ }
69
+ }
70
+