@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.
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +4 -0
- package/.tool-versions +1 -0
- package/CHANGELOG.md +664 -0
- package/LICENSE +201 -0
- package/README.md +235 -0
- package/bin/generateDocs.mjs +210 -0
- package/bin/generateDocs_index.mjs +210 -0
- package/package.json +92 -0
- package/scripts/build/generateDocs.mjs +24 -0
- package/scripts/build/generateReadme.mjs +60 -0
- package/scripts/build/generateWcaComponent.mjs +43 -0
- package/scripts/build/postCss.mjs +66 -0
- package/scripts/build/postinstall.mjs +31 -0
- package/scripts/build/pre-commit.mjs +17 -0
- package/scripts/build/prepWcaCompatibleCode.mjs +19 -0
- package/scripts/build/processors/defaultDocsProcessor.mjs +83 -0
- package/scripts/build/processors/defaultDotGithubSync.mjs +83 -0
- package/scripts/build/staticStyles-template.js +2 -0
- package/scripts/build/syncGithubFiles.mjs +25 -0
- package/scripts/build/versionWriter.js +26 -0
- package/scripts/runtime/FocusTrap/FocusTrap.mjs +194 -0
- package/scripts/runtime/FocusTrap/index.mjs +1 -0
- package/scripts/runtime/FocusTrap/test/FocusTrap.test.js +168 -0
- package/scripts/runtime/Focusables/Focusables.mjs +157 -0
- package/scripts/runtime/Focusables/index.mjs +1 -0
- package/scripts/runtime/Focusables/test/Focusables.test.js +165 -0
- package/scripts/runtime/dateUtilities/baseDateUtilities.mjs +58 -0
- package/scripts/runtime/dateUtilities/dateConstraints.mjs +11 -0
- package/scripts/runtime/dateUtilities/dateFormatter.mjs +104 -0
- package/scripts/runtime/dateUtilities/dateUtilities.mjs +218 -0
- package/scripts/runtime/dateUtilities/index.mjs +26 -0
- package/scripts/runtime/dependencyTagVersioning.mjs +42 -0
- package/scripts/runtime/floatingUI.mjs +646 -0
- package/scripts/test-plugin/iterateWithA11Check.mjs +82 -0
- package/scripts/utils/auroFileHandler.mjs +70 -0
- package/scripts/utils/auroLibraryUtils.mjs +206 -0
- package/scripts/utils/auroTemplateFiller.mjs +178 -0
- package/scripts/utils/logger.mjs +73 -0
- package/scripts/utils/runtimeUtils.mjs +70 -0
- package/scripts/utils/sharedFileProcessorUtils.mjs +270 -0
- package/shellScripts/README.md +58 -0
- 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
|
+
|