@aurodesignsystem/auro-library 2.7.0 → 2.9.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/.tool-versions +1 -0
- package/CHANGELOG.md +20 -0
- package/package.json +2 -1
- package/scripts/build/auroFileHandler.mjs +67 -0
- package/scripts/build/auroTemplateFiller.mjs +169 -0
- package/scripts/build/generateDocs.mjs +214 -168
- package/scripts/runtime/floatingUI.mjs +141 -0
- package/scripts/utils/auroLibraryUtils.mjs +21 -1
- package/scripts/utils/logger.js +73 -0
package/.tool-versions
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nodejs 20.12.1
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Semantic Release Automated Changelog
|
|
2
2
|
|
|
3
|
+
# [2.9.0](https://github.com/AlaskaAirlines/auro-library/compare/v2.8.0...v2.9.0) (2024-10-07)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* add matchWord to md magic config ([372cb28](https://github.com/AlaskaAirlines/auro-library/commit/372cb28a1c9eb0bd5f1014a4a8a9e6415cf659e5))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add handlebars template support ([bc3851d](https://github.com/AlaskaAirlines/auro-library/commit/bc3851dd87eb907927a3e2e22de53013c5e4e958))
|
|
14
|
+
* add new processing paradigm ([9a1dd25](https://github.com/AlaskaAirlines/auro-library/commit/9a1dd254e1288a6c7873b145a62087a37233a641))
|
|
15
|
+
|
|
16
|
+
# [2.8.0](https://github.com/AlaskaAirlines/auro-library/compare/v2.7.0...v2.8.0) (2024-09-19)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* add runtime script for Floating UI [#65](https://github.com/AlaskaAirlines/auro-library/issues/65) ([e180fcb](https://github.com/AlaskaAirlines/auro-library/commit/e180fcb319e9ab6673765041b5a96057e562bd60))
|
|
22
|
+
|
|
3
23
|
# [2.7.0](https://github.com/AlaskaAirlines/auro-library/compare/v2.6.3...v2.7.0) (2024-08-21)
|
|
4
24
|
|
|
5
25
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurodesignsystem/auro-library",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "This repository holds shared scripts, utilities, and workflows utilized across repositories along the Auro Design System.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"url": "https://github.com/AlaskaAirlines/auro-library/issues"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
+
"handlebars": "^4.7.8",
|
|
77
78
|
"markdown-magic": "^2.6.1",
|
|
78
79
|
"npm-run-all": "^4.1.5"
|
|
79
80
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
|
|
3
|
+
import {Logger} from "../utils/logger.mjs";
|
|
4
|
+
|
|
5
|
+
export class AuroFileHandler {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Check if a file exists.
|
|
9
|
+
* @param {string} filePath - The file path to check.
|
|
10
|
+
* @returns {Promise<boolean>}
|
|
11
|
+
*/
|
|
12
|
+
static async exists(filePath) {
|
|
13
|
+
try {
|
|
14
|
+
await fs.access(filePath);
|
|
15
|
+
return true;
|
|
16
|
+
// eslint-disable-next-line no-unused-vars
|
|
17
|
+
} catch (_err) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Try to read a file and return its contents.
|
|
24
|
+
* @param {string} filePath - The file path to read.
|
|
25
|
+
* @returns {Promise<null|string>}
|
|
26
|
+
*/
|
|
27
|
+
static async tryReadFile(filePath) {
|
|
28
|
+
try {
|
|
29
|
+
return await fs.readFile(filePath, {encoding: 'utf-8'});
|
|
30
|
+
} catch (err) {
|
|
31
|
+
Logger.error(`Error reading file: ${filePath}, ${err.message}`);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Try to write a file with the given contents.
|
|
38
|
+
* @param {string} filePath - The file path to write to.
|
|
39
|
+
* @param {string} fileContents - The contents to write to the file.
|
|
40
|
+
* @returns {Promise<boolean>}
|
|
41
|
+
*/
|
|
42
|
+
static async tryWriteFile(filePath, fileContents) {
|
|
43
|
+
try {
|
|
44
|
+
await fs.writeFile(filePath, fileContents, {encoding: 'utf-8'});
|
|
45
|
+
return true;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
Logger.error(`Error writing file: ${filePath}, ${err.message}`);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Try to copy a file from one location to another.
|
|
54
|
+
* @param {string} source - The source file path.
|
|
55
|
+
* @param {string} destination - The destination file path.
|
|
56
|
+
* @returns {Promise<boolean>}
|
|
57
|
+
*/
|
|
58
|
+
static async tryCopyFile(source, destination) {
|
|
59
|
+
try {
|
|
60
|
+
await fs.copyFile(source, destination);
|
|
61
|
+
return true;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
Logger.error(`Error copying file: ${source}, ${err.message}`);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
|
|
59
|
+
this.values = {
|
|
60
|
+
'npm': pName.substring(npmStart, namespaceStart),
|
|
61
|
+
'namespace': pName.substring(namespaceStart + 1, nameStart),
|
|
62
|
+
'namespaceCap': pName.substring(namespaceStart + 1)[0].toUpperCase() + pName.substring(namespaceStart + 2, nameStart),
|
|
63
|
+
'name': pName.substring(nameStart + 1),
|
|
64
|
+
'nameCap': pName.substring(nameStart + 1)[0].toUpperCase() + pName.substring(nameStart + 2),
|
|
65
|
+
'version': pVersion,
|
|
66
|
+
'tokensVersion': pdtVersion,
|
|
67
|
+
wcssVersion
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {string} template
|
|
73
|
+
* @param {ExtractedNames} values
|
|
74
|
+
* @return {string}
|
|
75
|
+
*/
|
|
76
|
+
replaceTemplateValues(template) {
|
|
77
|
+
const compileResult = Handlebars.compile(template);
|
|
78
|
+
|
|
79
|
+
// replace all handlebars placeholders FIRST, then apply legacy replacements
|
|
80
|
+
let result = compileResult({
|
|
81
|
+
// TODO: consider replacing some of these with handlebars helpers
|
|
82
|
+
name: this.values.name,
|
|
83
|
+
Name: this.values.nameCap,
|
|
84
|
+
namespace: this.values.namespace,
|
|
85
|
+
Namespace: this.values.namespaceCap,
|
|
86
|
+
Version: this.values.version,
|
|
87
|
+
dtVersion: this.values.tokensVersion,
|
|
88
|
+
wcssVersion: this.values.wcssVersion
|
|
89
|
+
}, {
|
|
90
|
+
helpers: {
|
|
91
|
+
'capitalize': (str) => str.charAt(0).toUpperCase() + str.slice(1),
|
|
92
|
+
'withAuroNamespace': (str) => `auro-${str}`,
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Old legacy template variables. We used to use `[varName]` and are now using handlebars `{{varName}}`.
|
|
98
|
+
* @type {[{pattern: RegExp, replacement: string},{pattern: RegExp, replacement: string},{pattern: RegExp, replacement: string},{pattern: RegExp, replacement: string},{pattern: RegExp, replacement: string},null,null,null]}
|
|
99
|
+
*/
|
|
100
|
+
const legacyTemplateVariables = [
|
|
101
|
+
{
|
|
102
|
+
pattern: /\[npm\]/gu,
|
|
103
|
+
replacement: this.values.npm
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
pattern: /\[name\](?!\()/gu,
|
|
107
|
+
replacement: this.values.name
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
pattern: /\[Name\](?!\()/gu,
|
|
111
|
+
replacement: this.values.nameCap
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
pattern: /\[namespace\]/gu,
|
|
115
|
+
replacement: this.values.namespace
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
pattern: /\[Namespace\]/gu,
|
|
119
|
+
replacement: this.values.namespaceCap
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
pattern: /\[Version\]/gu,
|
|
123
|
+
replacement: this.values.version
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
pattern: /\[dtVersion\]/gu,
|
|
127
|
+
replacement: this.values.tokensVersion
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
pattern: /\[wcssVersion\]/gu,
|
|
131
|
+
replacement: this.values.wcssVersion
|
|
132
|
+
}
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Replace legacy placeholder strings.
|
|
137
|
+
*/
|
|
138
|
+
for (const { pattern, replacement } of legacyTemplateVariables) {
|
|
139
|
+
result = result.replace(pattern, replacement);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Cleanup line breaks.
|
|
144
|
+
*/
|
|
145
|
+
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.
|
|
146
|
+
result = result.replace(/>(\r\n|\r|\n){2,}/g, '>\r\n'); // Remove empty lines directly after a closing html tag.
|
|
147
|
+
result = result.replace(/>(\r\n|\r|\n)```/g, '>\r\n\r\n```'); // Ensure an empty line before code samples.
|
|
148
|
+
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.
|
|
149
|
+
result = result.replace(/([^(\r\n|\r|\n)])(\r?\n|\r(?!\n))+#/g, "$1\r\n\r\n#"); // Ensure empty line before header sections.
|
|
150
|
+
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
*
|
|
157
|
+
* @param {string} content
|
|
158
|
+
*/
|
|
159
|
+
formatApiTable(content) {
|
|
160
|
+
let result = `${content}`;
|
|
161
|
+
|
|
162
|
+
result = result
|
|
163
|
+
.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>`)
|
|
164
|
+
.replace(/\r\n|\r|\n\|\s`([a-zA-Z]*)`/g, '\r\n| [$1](#$1)')
|
|
165
|
+
.replace(/\| \[\]\(#\)/g, "");
|
|
166
|
+
|
|
167
|
+
return result
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -1,229 +1,275 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import https from 'https';
|
|
2
|
+
import * as mdMagic from 'markdown-magic';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
5
4
|
import { fileURLToPath } from 'url';
|
|
6
5
|
|
|
7
6
|
import AuroLibraryUtils from "../utils/auroLibraryUtils.mjs";
|
|
7
|
+
import { AuroTemplateFiller } from "./auroTemplateFiller.mjs";
|
|
8
|
+
import { AuroFileHandler } from "./auroFileHandler.mjs";
|
|
9
|
+
import {Logger} from "../utils/logger.mjs";
|
|
8
10
|
|
|
9
|
-
const auroLibraryUtils = new AuroLibraryUtils();
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
// This JSDoc type trickery is here so you get "decent enough" auto complete
|
|
13
|
+
/** @type {typeof import('markdown-magic').markdownMagic} */
|
|
14
|
+
const applyMarkdownMagic = mdMagic.default
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Optional output configuration
|
|
18
|
+
* @typedef {object} OutputConfig
|
|
19
|
+
* @property {string} [directory] - Change output path of new content. Default behavior is replacing the original file
|
|
20
|
+
* @property {boolean} [removeComments = false] - Remove comments from output. Default is false.
|
|
21
|
+
* @property {function} [pathFormatter] - Custom function for altering output paths
|
|
22
|
+
* @property {boolean} [applyTransformsToSource = false] - Apply transforms to source file. Default is true. This is for when outputDir is set.
|
|
23
|
+
*/
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Configuration for markdown magic
|
|
27
|
+
*
|
|
28
|
+
* Below is the main config for `markdown-magic` - copy-pasted directly from the library
|
|
29
|
+
*
|
|
30
|
+
* @typedef {object} MarkdownMagicOptions
|
|
31
|
+
* @property {FilePathsOrGlobs} [files] - Files to process.
|
|
32
|
+
* @property {Array} [transforms = defaultTransforms] - Custom commands to transform block contents, see transforms & custom transforms sections below.
|
|
33
|
+
* @property {OutputConfig} [output] - Output configuration
|
|
34
|
+
* @property {SyntaxType} [syntax = 'md'] - Syntax to parse
|
|
35
|
+
* @property {string} [open = 'doc-gen'] - Opening match word
|
|
36
|
+
* @property {string} [close = 'end-doc-gen'] - Closing match word. If not defined will be same as opening word.
|
|
37
|
+
* @property {string} [cwd = process.cwd() ] - Current working directory. Default process.cwd()
|
|
38
|
+
* @property {boolean} [outputFlatten] - Flatten files that are output
|
|
39
|
+
* @property {boolean} [useGitGlob] - Use git glob for LARGE file directories
|
|
40
|
+
* @property {boolean} [dryRun = false] - See planned execution of matched blocks
|
|
41
|
+
* @property {boolean} [debug = false] - See debug details
|
|
42
|
+
* @property {boolean} [silent = false] - Silence all console output
|
|
43
|
+
* @property {boolean} [applyTransformsToSource = true] - Apply transforms to source file. Default is true.
|
|
44
|
+
* @property {boolean} [failOnMissingTransforms = false] - Fail if transform functions are missing. Default skip blocks.
|
|
45
|
+
* @property {boolean} [failOnMissingRemote = true] - Fail if remote file is missing.
|
|
46
|
+
*/
|
|
18
47
|
|
|
19
|
-
function generateReadmeUrl() {
|
|
20
|
-
let nameExtractionData = nameExtraction();
|
|
21
|
-
let esmString = '';
|
|
22
48
|
|
|
23
|
-
|
|
24
|
-
|
|
49
|
+
// Config
|
|
50
|
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
51
|
+
|
|
52
|
+
/** @type {MarkdownMagicOptions} */
|
|
53
|
+
export const MD_MAGIC_CONFIG = {
|
|
54
|
+
matchWord: "AURO-GENERATED-CONTENT",
|
|
55
|
+
output: {
|
|
56
|
+
directory: "./",
|
|
57
|
+
applyTransformsToSource: true
|
|
25
58
|
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Initialize utility services
|
|
62
|
+
export const auroLibraryUtils = new AuroLibraryUtils();
|
|
63
|
+
export const templateFiller = new AuroTemplateFiller();
|
|
64
|
+
export const auroFileHandler = new AuroFileHandler();
|
|
65
|
+
|
|
66
|
+
// List of components that do not support ESM to determine which README to use
|
|
67
|
+
export const nonEsmComponents = ['combobox', 'datepicker', 'menu', 'pane', 'select'];
|
|
26
68
|
|
|
27
|
-
return 'https://raw.githubusercontent.com/AlaskaAirlines/WC-Generator/master/componentDocs/README' + esmString + '.md';
|
|
28
|
-
}
|
|
29
69
|
|
|
70
|
+
// Local utils
|
|
30
71
|
/**
|
|
31
|
-
*
|
|
72
|
+
*
|
|
73
|
+
* @param {string} pathLike - Please include the preceding slash! Like so: `/docTemplates/README.md`
|
|
74
|
+
* @return {string}
|
|
32
75
|
*/
|
|
76
|
+
export function fromAuroComponentRoot(pathLike) {
|
|
77
|
+
const currentDir = fileURLToPath(new URL('.', import.meta.url))
|
|
78
|
+
return path.join(currentDir, `${auroLibraryUtils.projectRootFromBuildScriptDir}${pathLike}`)
|
|
79
|
+
}
|
|
33
80
|
|
|
34
|
-
function nameExtraction() {
|
|
35
|
-
let packageJson = fs.readFileSync('package.json', 'utf8', function(err, data) {
|
|
36
|
-
if (err) {
|
|
37
|
-
console.log('ERROR: Unable to read package.json file', err);
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
81
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
let pName = packageJson.name;
|
|
44
|
-
let pVersion = packageJson.version;
|
|
45
|
-
let pdtVersion = packageJson.peerDependencies['\@aurodesignsystem/design-tokens'].substring(1);
|
|
46
|
-
let wcssVersion = packageJson.peerDependencies['\@aurodesignsystem/webcorestylesheets'].substring(1);
|
|
47
|
-
|
|
48
|
-
let npmStart = pName.indexOf('@');
|
|
49
|
-
let namespaceStart = pName.indexOf('/');
|
|
50
|
-
let nameStart = pName.indexOf('-');
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
'npm': pName.substring(npmStart, namespaceStart),
|
|
54
|
-
'namespace': pName.substring(namespaceStart + 1, nameStart),
|
|
55
|
-
'namespaceCap': pName.substring(namespaceStart + 1)[0].toUpperCase() + pName.substring(namespaceStart + 2, nameStart),
|
|
56
|
-
'name': pName.substring(nameStart + 1),
|
|
57
|
-
'nameCap': pName.substring(nameStart + 1)[0].toUpperCase() + pName.substring(nameStart + 2),
|
|
58
|
-
'version': pVersion,
|
|
59
|
-
'tokensVersion': pdtVersion,
|
|
60
|
-
'wcssVersion': wcssVersion
|
|
61
|
-
};
|
|
62
|
-
}
|
|
82
|
+
// External assets
|
|
83
|
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
63
84
|
|
|
64
85
|
/**
|
|
65
|
-
*
|
|
86
|
+
* @param {string} tag - the release version tag to use instead of master
|
|
87
|
+
* @param {string} [variantOverride] - override the variant string
|
|
88
|
+
* @return {string}
|
|
66
89
|
*/
|
|
90
|
+
export function generateReadmeUrl(tag = 'master', variantOverride = '') {
|
|
91
|
+
// LEGACY CODE FOR NON-ESM COMPONENTS
|
|
67
92
|
|
|
68
|
-
|
|
69
|
-
let
|
|
70
|
-
let result = content;
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Replace placeholder strings
|
|
74
|
-
*/
|
|
75
|
-
result = result.replace(/\[npm]/g, nameExtractionData.npm);
|
|
76
|
-
result = result.replace(/\[name](?!\()/g, nameExtractionData.name);
|
|
77
|
-
result = result.replace(/\[Name](?!\()/g, nameExtractionData.nameCap);
|
|
78
|
-
result = result.replace(/\[namespace]/g, nameExtractionData.namespace);
|
|
79
|
-
result = result.replace(/\[Namespace]/g, nameExtractionData.namespaceCap);
|
|
80
|
-
result = result.replace(/\[Version]/g, nameExtractionData.version);
|
|
81
|
-
result = result.replace(/\[dtVersion]/g, nameExtractionData.tokensVersion);
|
|
82
|
-
result = result.replace(/\[wcssVersion]/g, nameExtractionData.wcssVersion);
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Cleanup line breaks
|
|
86
|
-
*/
|
|
87
|
-
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.
|
|
88
|
-
result = result.replace(/>(\r\n|\r|\n){2,}/g, '>\r\n'); // Remove empty lines directly after a closing html tag.
|
|
89
|
-
result = result.replace(/>(\r\n|\r|\n)```/g, '>\r\n\r\n```'); // Ensure an empty line before code samples.
|
|
90
|
-
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.
|
|
91
|
-
result = result.replace(/([^(\r\n|\r|\n)])(\r?\n|\r(?!\n))+#/g, "$1\r\n\r\n#"); // Ensure empty line before header sections.
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Write the result to the destination file
|
|
95
|
-
*/
|
|
96
|
-
fs.writeFileSync(destination, result, { encoding: 'utf8'});
|
|
97
|
-
}
|
|
93
|
+
const nameExtractionData = templateFiller.values;
|
|
94
|
+
let variantString = '';
|
|
98
95
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
if (!nonEsmComponents.includes(nameExtractionData.name)) {
|
|
97
|
+
variantString = '_esm';
|
|
98
|
+
}
|
|
102
99
|
|
|
103
|
-
|
|
100
|
+
// END LEGACY CODE
|
|
104
101
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
.replace(/\| \[\]\(#\)/g, "");
|
|
102
|
+
if (variantOverride !== '') {
|
|
103
|
+
variantString = variantOverride;
|
|
104
|
+
}
|
|
109
105
|
|
|
110
|
-
|
|
106
|
+
const baseRepoUrl = 'https://raw.githubusercontent.com/AlaskaAirlines/WC-Generator'
|
|
107
|
+
if (tag !== 'master') {
|
|
108
|
+
return `${baseRepoUrl}/refs/tags/${tag}/componentDocs/README` + variantString + '.md';
|
|
109
|
+
}
|
|
111
110
|
|
|
112
|
-
|
|
113
|
-
formatTemplateFileContents(data, './demo/api.md');
|
|
114
|
-
});
|
|
111
|
+
return `${baseRepoUrl}/master/componentDocs/README` + variantString + '.md';
|
|
115
112
|
}
|
|
116
113
|
|
|
114
|
+
// Main Markdown magic processors
|
|
115
|
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
116
|
+
|
|
117
117
|
/**
|
|
118
|
-
*
|
|
118
|
+
* This is the expected object type when passing something other than a string.
|
|
119
|
+
* @typedef {Object} InputFileType
|
|
120
|
+
* @property {string} remoteUrl - The remote template to fetch
|
|
121
|
+
* @property {string} fileName - Path including file name to store
|
|
122
|
+
* @property {boolean} [overwrite] - Default is true. Choose to overwrite the file if it exists
|
|
119
123
|
*/
|
|
120
124
|
|
|
121
|
-
function processReadme() {
|
|
122
|
-
const callback = function(updatedContent, outputConfig) {
|
|
123
|
-
|
|
124
|
-
if (fs.existsSync('./README.md')) {
|
|
125
|
-
fs.readFile('./README.md', 'utf8', function(err, data) {
|
|
126
|
-
formatTemplateFileContents(data, './README.md');
|
|
127
|
-
});
|
|
128
|
-
} else {
|
|
129
|
-
console.log('ERROR: ./README.md file is missing');
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
125
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
/**
|
|
127
|
+
* @typedef {Object} FileProcessorConfig
|
|
128
|
+
* @property {string | InputFileType} input - path to input file, including filename
|
|
129
|
+
* @property {string} output - path to output file, including filename
|
|
130
|
+
* @property {Partial<MarkdownMagicOptions>} [mdMagicConfig] - extra configuration options for md magic
|
|
131
|
+
* @property {Array<(contents: string) => string>} [postProcessors] - extra processor functions to run on content
|
|
132
|
+
*/
|
|
137
133
|
|
|
138
|
-
const markdownPath = path.join(__dirname, './../../../../../docTemplates/README.md');
|
|
139
134
|
|
|
140
|
-
|
|
141
|
-
|
|
135
|
+
// Individual file processing steps
|
|
136
|
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
142
137
|
|
|
143
138
|
/**
|
|
144
|
-
*
|
|
139
|
+
* Optionally retrieve a remote file using a provided configuration.
|
|
140
|
+
* @param {InputFileType} input - the input file configuration
|
|
141
|
+
* @return {Promise<void>}
|
|
145
142
|
*/
|
|
143
|
+
export async function optionallyRetrieveRemoteFile(input) {
|
|
144
|
+
const bareFileName = input.fileName
|
|
145
|
+
const shouldOverwrite = input.overwrite ?? true
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
});
|
|
154
|
-
} else {
|
|
155
|
-
console.log('ERROR: ./demo/index.md file is missing');
|
|
156
|
-
}
|
|
157
|
-
};
|
|
147
|
+
// If the file exists and overwrite is false, skip fetching
|
|
148
|
+
if (await AuroFileHandler.exists(input.fileName) && !shouldOverwrite) {
|
|
149
|
+
Logger.warn(`NOTICE: Using existing "${bareFileName}" file since overwrite is FALSE`);
|
|
150
|
+
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
158
153
|
|
|
159
|
-
|
|
160
|
-
matchWord: 'AURO-GENERATED-CONTENT',
|
|
161
|
-
outputDir: './demo'
|
|
162
|
-
};
|
|
154
|
+
Logger.log(`Retrieving latest "${bareFileName}" file...`);
|
|
163
155
|
|
|
164
|
-
|
|
156
|
+
// 0b. Attempt to populate from remote file
|
|
157
|
+
const contents = await fetch(input.remoteUrl, {
|
|
158
|
+
redirect: 'follow'
|
|
159
|
+
}).then(r => r.text());
|
|
165
160
|
|
|
166
|
-
|
|
161
|
+
// 0c. Write remote contents to local folder as cache
|
|
162
|
+
await AuroFileHandler.tryWriteFile(input.fileName, contents);
|
|
167
163
|
}
|
|
168
164
|
|
|
165
|
+
|
|
169
166
|
/**
|
|
170
|
-
*
|
|
167
|
+
* Run markdown magic on a file.
|
|
168
|
+
* @param {string} input
|
|
169
|
+
* @param {string} output
|
|
170
|
+
* @param {Partial<MarkdownMagicOptions>} [extraMdMagicConfig] - extra configuration options for md magic
|
|
171
|
+
* @return {Promise<void>}
|
|
171
172
|
*/
|
|
173
|
+
export async function runMarkdownMagicOnFile(input, output, extraMdMagicConfig = {}) {
|
|
174
|
+
await applyMarkdownMagic(output, {
|
|
175
|
+
...MD_MAGIC_CONFIG,
|
|
176
|
+
...extraMdMagicConfig
|
|
177
|
+
});
|
|
178
|
+
}
|
|
172
179
|
|
|
173
|
-
function processApiExamples() {
|
|
174
|
-
const callback = function(updatedContent, outputConfig) {
|
|
175
|
-
if (fs.existsSync('./demo/api.md')) {
|
|
176
|
-
fs.readFile('./demo/api.md', 'utf8', function(err, data) {
|
|
177
|
-
formatApiTableContents(data, './demo/api.md');
|
|
178
|
-
});
|
|
179
|
-
} else {
|
|
180
|
-
console.log('ERROR: ./demo/api.md file is missing');
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const config = {
|
|
185
|
-
matchWord: 'AURO-GENERATED-CONTENT',
|
|
186
|
-
outputDir: './demo'
|
|
187
|
-
};
|
|
188
180
|
|
|
189
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Process the content of a file.
|
|
183
|
+
*
|
|
184
|
+
* This is a high level function that performs the following via lower functions:
|
|
185
|
+
* - Read contents of file
|
|
186
|
+
* - Run "markdown-magic" on file contents (optional, *.md specific)
|
|
187
|
+
* - Run template variable replacement on file contents
|
|
188
|
+
* @param {FileProcessorConfig} config - the config for this file
|
|
189
|
+
*/
|
|
190
|
+
export async function processContentForFile(config) {
|
|
191
|
+
const { input: rawInput, output, mdMagicConfig } = config
|
|
190
192
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
+
// Helper vars
|
|
194
|
+
const derivedInputPath = typeof rawInput === 'string' ? rawInput : rawInput.fileName;
|
|
195
|
+
const segments = derivedInputPath.split("/")
|
|
196
|
+
const bareFileName = segments[segments.length - 1]
|
|
193
197
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
198
|
+
// 0. Optionally retrieve a remote file
|
|
199
|
+
if (typeof rawInput === 'object') {
|
|
200
|
+
await optionallyRetrieveRemoteFile(rawInput);
|
|
201
|
+
}
|
|
197
202
|
|
|
198
|
-
|
|
199
|
-
if (!
|
|
200
|
-
|
|
203
|
+
// 1. Copy input or local input cache to output
|
|
204
|
+
if (!await AuroFileHandler.tryCopyFile(derivedInputPath, output)) {
|
|
205
|
+
throw new Error(`Error copying "${bareFileName}" file to output ${output}`);
|
|
201
206
|
}
|
|
202
207
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
console.log('ERROR: Unable to create README.md file.', err);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
208
|
+
// 2. If the file is a Markdown file, run markdown magic to inject contents and perform replacements
|
|
209
|
+
if (output.endsWith(".md")) {
|
|
210
|
+
await runMarkdownMagicOnFile(derivedInputPath, output, mdMagicConfig);
|
|
209
211
|
}
|
|
210
212
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
// 3a. Read the output file contents
|
|
214
|
+
let fileContents = await fs.readFile(output, {encoding: 'utf-8'});
|
|
213
215
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
});
|
|
216
|
+
// 3b. Replace template variables in output file
|
|
217
|
+
fileContents = templateFiller.replaceTemplateValues(fileContents);
|
|
217
218
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
219
|
+
// 3c. Run any post-processors
|
|
220
|
+
if (config.postProcessors) {
|
|
221
|
+
for (const processor of config.postProcessors) {
|
|
222
|
+
fileContents = processor(fileContents)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 3d. Write the final file contents
|
|
227
|
+
if (!await AuroFileHandler.tryWriteFile(output, fileContents)) {
|
|
228
|
+
throw new Error(`Error writing "${bareFileName}" file to output ${output}`);
|
|
229
|
+
}
|
|
221
230
|
}
|
|
222
231
|
|
|
232
|
+
// Finally, the main function
|
|
233
|
+
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
234
|
+
|
|
223
235
|
/**
|
|
224
|
-
*
|
|
236
|
+
*
|
|
237
|
+
* @param {string} remoteReadmeVersion - the release version tag to use instead of master
|
|
238
|
+
* @param {string} [readmeVariant] - the release version tag to use instead of master
|
|
239
|
+
* @return {Promise<void>}
|
|
225
240
|
*/
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
241
|
+
export async function processDocFiles(remoteReadmeVersion = 'master', readmeVariant = undefined) {
|
|
242
|
+
// setup
|
|
243
|
+
await templateFiller.extractNames();
|
|
244
|
+
|
|
245
|
+
// process
|
|
246
|
+
// README.md
|
|
247
|
+
|
|
248
|
+
await processContentForFile({
|
|
249
|
+
input: {
|
|
250
|
+
remoteUrl: generateReadmeUrl(remoteReadmeVersion, readmeVariant),
|
|
251
|
+
fileName: fromAuroComponentRoot(`/docTemplates/README.md`),
|
|
252
|
+
},
|
|
253
|
+
output: fromAuroComponentRoot("/README.md")
|
|
254
|
+
})
|
|
229
255
|
|
|
256
|
+
// Demo MD file
|
|
257
|
+
await processContentForFile({
|
|
258
|
+
input: fromAuroComponentRoot("/docs/partials/index.md"),
|
|
259
|
+
output: fromAuroComponentRoot("/demo/index.md"),
|
|
260
|
+
mdMagicConfig: {
|
|
261
|
+
output: {
|
|
262
|
+
directory: fromAuroComponentRoot("/demo")
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
// API MD file
|
|
268
|
+
await processContentForFile({
|
|
269
|
+
input: fromAuroComponentRoot("/docs/partials/api.md"),
|
|
270
|
+
output: fromAuroComponentRoot("/demo/api.md"),
|
|
271
|
+
postProcessors: [
|
|
272
|
+
templateFiller.formatApiTable
|
|
273
|
+
]
|
|
274
|
+
})
|
|
275
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/* eslint-disable line-comment-position, no-inline-comments */
|
|
2
|
+
|
|
3
|
+
import {computePosition, offset, autoPlacement, flip} from '@floating-ui/dom';
|
|
4
|
+
|
|
5
|
+
export default class AuroFloatingUI {
|
|
6
|
+
bibUpdate(element) {
|
|
7
|
+
this.position(element, element.trigger, element.bib);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
position(element, referenceEl, floatingEl) {
|
|
11
|
+
const middleware = [offset(element.floaterConfig.offset || 0)];
|
|
12
|
+
|
|
13
|
+
if (element.floaterConfig.flip) {
|
|
14
|
+
middleware.push(flip());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (element.floaterConfig.autoPlacement) {
|
|
18
|
+
middleware.push(autoPlacement());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
computePosition(referenceEl, floatingEl, {
|
|
22
|
+
placement: element.floaterConfig.placement || 'bottom',
|
|
23
|
+
middleware: middleware || []
|
|
24
|
+
}).then(({x, y}) => { // eslint-disable-line id-length
|
|
25
|
+
Object.assign(floatingEl.style, {
|
|
26
|
+
left: `${x}px`,
|
|
27
|
+
top: `${y}px`,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
showBib(element) {
|
|
33
|
+
if (!element.disabled && !element.isPopoverVisible) {
|
|
34
|
+
// First, close any other dropdown that is already open
|
|
35
|
+
if (document.expandedAuroDropdown) {
|
|
36
|
+
// document.expandedAuroDropdown.hideBib();
|
|
37
|
+
this.hideBib(document.expandedAuroDropdown);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
document.expandedAuroDropdown = this;
|
|
41
|
+
|
|
42
|
+
// Then, show this dropdown
|
|
43
|
+
element.bib.style.display = 'block';
|
|
44
|
+
this.bibUpdate(element);
|
|
45
|
+
element.isPopoverVisible = true; // does Floating UI already surface this?
|
|
46
|
+
element.trigger.setAttribute('aria-expanded', true);
|
|
47
|
+
|
|
48
|
+
// wrap this so we can clean it up when the bib is hidden
|
|
49
|
+
// document.querySelector('body').addEventListener('click', (evt) => {
|
|
50
|
+
// if (!evt.composedPath().includes(this)) {
|
|
51
|
+
// this.hideBib();
|
|
52
|
+
// }
|
|
53
|
+
// });
|
|
54
|
+
if (!element.noHideOnThisFocusLoss && !element.hasAttribute('noHideOnThisFocusLoss')) {
|
|
55
|
+
document.activeElement.addEventListener('focusout', () => {
|
|
56
|
+
if (document.activeElement !== document.querySelector('body') && !element.contains(document.activeElement)) {
|
|
57
|
+
this.hideBib(element);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
document.querySelector('body').addEventListener('click', (evt) => {
|
|
62
|
+
if (!evt.composedPath().includes(element)) {
|
|
63
|
+
this.hideBib(element);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
hideBib(element) {
|
|
71
|
+
if (element.isPopoverVisible && !element.disabled && !element.noToggle) { // do we really want noToggle here?
|
|
72
|
+
element.bib.style.display = ''; // should this be unset or none?
|
|
73
|
+
element.isPopoverVisible = false;
|
|
74
|
+
element.trigger.setAttribute('aria-expanded', false);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
configure(element) {
|
|
79
|
+
element.trigger = element.shadowRoot.querySelector('#trigger');
|
|
80
|
+
element.bib = element.shadowRoot.querySelector('#bib');
|
|
81
|
+
|
|
82
|
+
element.trigger.addEventListener('click', (event) => this.handleEvent(event, element));
|
|
83
|
+
element.trigger.addEventListener('mouseenter', (event) => this.handleEvent(event, element));
|
|
84
|
+
element.trigger.addEventListener('mouseleave', (event) => this.handleEvent(event, element));
|
|
85
|
+
element.trigger.addEventListener('focus', (event) => this.handleEvent(event, element));
|
|
86
|
+
element.trigger.addEventListener('blur', (event) => this.handleEvent(event, element));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
handleClick(element) {
|
|
90
|
+
if (this.isPopoverVisible) {
|
|
91
|
+
this.hideBib(element);
|
|
92
|
+
} else {
|
|
93
|
+
this.showBib(element);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// should this be left in dropdown?
|
|
97
|
+
const event = new CustomEvent('auroDropdown-triggerClick', {
|
|
98
|
+
composed: true,
|
|
99
|
+
details: {
|
|
100
|
+
expanded: this.isPopoverVisible
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
element.dispatchEvent(event);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
handleEvent(event, element) {
|
|
108
|
+
if (!element.disableEventShow) {
|
|
109
|
+
switch (event.type) {
|
|
110
|
+
case 'mouseenter':
|
|
111
|
+
if (element.hoverToggle) {
|
|
112
|
+
this.showBib(element);
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
case 'mouseleave':
|
|
116
|
+
if (element.hoverToggle) {
|
|
117
|
+
this.hideBib(element);
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
case 'focus':
|
|
121
|
+
if (element.focusShow) {
|
|
122
|
+
// this needs to better handle clicking that gives focus - currently it shows and then immediately hides the bib
|
|
123
|
+
this.showBib(element);
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
case 'blur':
|
|
127
|
+
// this likely needs to be improved to handle focus within the bib for datepicker
|
|
128
|
+
if (!element.noHideOnThisFocusLoss && !element.hasAttribute('noHideOnThisFocusLoss')) { // why do we have to do both here?
|
|
129
|
+
this.hideBib(element);
|
|
130
|
+
}
|
|
131
|
+
break;
|
|
132
|
+
case 'click':
|
|
133
|
+
this.handleClick(element);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
// do nothing
|
|
137
|
+
// add cases for show and toggle by keyboard space and enter key - maybe this is handled already?
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -6,10 +6,16 @@
|
|
|
6
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
7
|
|
|
8
8
|
import * as fs from 'fs';
|
|
9
|
+
import fsAsync from 'node:fs/promises';
|
|
9
10
|
import * as path from 'path';
|
|
10
11
|
import chalk from 'chalk';
|
|
11
12
|
|
|
12
13
|
export default class AuroLibraryUtils {
|
|
14
|
+
PROJECT_ROOT_FROM_SCRIPTS__BUILD = "./../../../../.."
|
|
15
|
+
|
|
16
|
+
get projectRootFromBuildScriptDir() {
|
|
17
|
+
return this.PROJECT_ROOT_FROM_SCRIPTS__BUILD
|
|
18
|
+
}
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
21
|
* Copies and pastes all files in a source directory into a destination directory.
|
|
@@ -73,7 +79,7 @@ export default class AuroLibraryUtils {
|
|
|
73
79
|
/**
|
|
74
80
|
* Logs out messages in a readable format.
|
|
75
81
|
* @param {String} message - Message to be logged.
|
|
76
|
-
* @param {
|
|
82
|
+
* @param {"info" | "success" | "error"} status - Status that determines the color of the logged message.
|
|
77
83
|
* @param {Boolean} section - If true, adds a box around the message for readability.
|
|
78
84
|
*/
|
|
79
85
|
auroLogger(message, status, section) {
|
|
@@ -185,5 +191,19 @@ export default class AuroLibraryUtils {
|
|
|
185
191
|
*/
|
|
186
192
|
fs.writeFileSync(destination, result, { encoding: 'utf8'});
|
|
187
193
|
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Check if a file or directory exists.
|
|
197
|
+
* @param filePath
|
|
198
|
+
* @return {Promise<boolean>}
|
|
199
|
+
*/
|
|
200
|
+
async existsAsync(filePath) {
|
|
201
|
+
try {
|
|
202
|
+
await fsAsync.access(filePath);
|
|
203
|
+
return true;
|
|
204
|
+
} catch {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
188
208
|
}
|
|
189
209
|
|
|
@@ -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
|
+
}
|