@aurodesignsystem/auro-library 2.11.0 → 3.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Semantic Release Automated Changelog
2
2
 
3
+ # [3.0.0](https://github.com/AlaskaAirlines/auro-library/compare/v2.11.0...v3.0.0) (2024-11-05)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * add missing logger import ([8258705](https://github.com/AlaskaAirlines/auro-library/commit/8258705385b20950dba442a59fa41b56052955bf))
9
+ * sourcery feedback - change tag detection ([51b134f](https://github.com/AlaskaAirlines/auro-library/commit/51b134fea57c79e9625b6053296049c19959595a))
10
+
11
+
12
+ ### Features
13
+
14
+ * add more consistent "component root" path generator ([c88f5a8](https://github.com/AlaskaAirlines/auro-library/commit/c88f5a8018fcbcbc1deefa35a0152c1696681957))
15
+ * add syncGithubFiles.mjs script ([207009d](https://github.com/AlaskaAirlines/auro-library/commit/207009d000565566aed4687ed45ee7e286528856))
16
+ * **build:** new script that generate extended component files for `wca` to be able to analyze [#85](https://github.com/AlaskaAirlines/auro-library/issues/85) ([ae8e6ab](https://github.com/AlaskaAirlines/auro-library/commit/ae8e6ab41db40df05f53562e14692a943c37d796))
17
+ * change API for generateReadmeURL and processDocs ([a1a975c](https://github.com/AlaskaAirlines/auro-library/commit/a1a975c0d9020bdd71c9da0bf165777c54801e8b))
18
+
19
+
20
+ ### BREAKING CHANGES
21
+
22
+ * `processDocFiles` no longer accepts individual config arguments
23
+
3
24
  # [2.11.0](https://github.com/AlaskaAirlines/auro-library/compare/v2.10.1...v2.11.0) (2024-11-01)
4
25
 
5
26
 
package/README.md CHANGED
@@ -3,10 +3,10 @@
3
3
  <!-- AURO-GENERATED-CONTENT:START (FILE:src=./../docs/partials/description.md) -->
4
4
  <!-- The below content is automatically added from ./../docs/partials/description.md -->
5
5
  This repository holds shared scripts, utilities, and workflows utilized across repositories along the Auro Design System.
6
- <!-- AURO-GENERATED-CONTENT:END -->
7
-
8
- ## Scripts
9
-
6
+ <!-- AURO-GENERATED-CONTENT:END -->
7
+
8
+ ## Scripts
9
+
10
10
  ### Publish Surge Demo
11
11
 
12
12
  <!-- AURO-GENERATED-CONTENT:START (FILE:src=./../docs/partials/publishDemo.md) -->
@@ -28,8 +28,9 @@ name: Deploy Demo
28
28
 
29
29
  on:
30
30
  pull_request:
31
- branches: [ main ]
32
-
31
+ branches: [ main ]
32
+
33
+
33
34
  jobs:
34
35
  call-publish-demo-workflow:
35
36
  uses: AlaskaAirlines/auro-library/.github/workflows/publishDemo.yml@main
@@ -43,13 +44,14 @@ Afterwards you will want to make sure to update the script tags you want replace
43
44
 
44
45
  ```diff
45
46
  -- <script type="module" src="../index.js"></script>
46
- ++ <script type="module" src="../index.js" data-demo-script="true"></script>
47
- ```
47
+ ++ <script type="module" src="../index.js" data-demo-script="true"></script>
48
+ ```
48
49
 
49
50
  > Note: If you fail to do this, the components will fail to register in your demo.
50
- <!-- AURO-GENERATED-CONTENT:END -->
51
- ---
52
-
51
+ <!-- AURO-GENERATED-CONTENT:END -->
52
+
53
+ ---
54
+
53
55
  ### Surge Demo Teardown
54
56
 
55
57
  <!-- AURO-GENERATED-CONTENT:START (FILE:src=./../docs/partials/demoTeardown.md) -->
@@ -59,19 +61,20 @@ This workflow works to automatically delete and clear any surge demos that have
59
61
  > Note: This workflow executes on a monthly cronjob on the first of each month.
60
62
 
61
63
  In order to clear all our surge projects we rely on [this GitHub Action](https://github.com/marketplace/actions/surge-sh-teardown) to handle the deletion logic.
62
- <!-- AURO-GENERATED-CONTENT:END -->
63
- ---
64
-
64
+ <!-- AURO-GENERATED-CONTENT:END -->
65
+
66
+ ---
67
+
65
68
  ### Dependency Tag Versioning
66
69
 
67
70
  <!-- AURO-GENERATED-CONTENT:START (FILE:src=./../docs/partials/dependencyTagVersioning.md) -->
68
71
  <!-- The below content is automatically added from ./../docs/partials/dependencyTagVersioning.md -->
69
72
  This is a two part utility for the purpose of generating a custom string for dependency component tag naming. This is important to prevent [version conflicts](https://www.thinktecture.com/en/web-components/web-components-flaws/#elementor-toc__heading-anchor-0) when multiple versions of a given Auro component may be loaded on a single page.
70
73
 
71
- _Note: The example configuration used below in all code samples assumes `auro-dropdown` is the dependency component. Substitute any Auro component in the example code as needed._
72
-
73
- #### Part 1: The Build
74
-
74
+ _Note: The example configuration used below in all code samples assumes `auro-dropdown` is the dependency component. Substitute any Auro component in the example code as needed._
75
+
76
+ #### Part 1: The Build
77
+
75
78
  ##### Configuration
76
79
 
77
80
  1. Create a new file `./scripts/version.js` with the following content:
@@ -92,8 +95,8 @@ versionWriter.writeDepVersionFile('@aurodesignsystem/auro-dropdown'); // duplica
92
95
 
93
96
  ```json
94
97
  "build": "npm-run-all build:version ... etc.",
95
- ```
96
-
98
+ ```
99
+
97
100
  ##### Execution
98
101
 
99
102
  Once configuration is complete, execute `npm run build`. This must be done once before `npm run dev` when developing locally. When Auro dependencies are initially installed or updated to new versions then `npm run build:version` or a complete `npm run build` must be executed.
@@ -111,10 +114,10 @@ versionWriter.writeDepVersionFile('@aurodesignsystem/auro-dropdown');
111
114
  Will result in:
112
115
  - A new file created: `./src/dropdownVersion.js`
113
116
  - File content will export the version of the component installed. In this case:
114
- `export default '1.0.0'`
115
-
116
- #### Part 2: The Runtime
117
-
117
+ `export default '1.0.0'`
118
+
119
+ #### Part 2: The Runtime
120
+
118
121
  ##### Configuration
119
122
 
120
123
  In the main component JS file located in the `./src` directory add the following:
@@ -139,8 +142,8 @@ In the component properties add the following:
139
142
  * @private
140
143
  */
141
144
  dropdownTag: { type: Object }
142
- ```
143
-
145
+ ```
146
+
144
147
  ##### Usage
145
148
 
146
149
  The new dynamically named version of `auro-dropdown` may now be used in your component template as follows:
@@ -160,11 +163,11 @@ When the component is rendered during runtime the DOM will now show up as follow
160
163
  ```html
161
164
  <div>
162
165
  <auro-dropdown_1_0_0></auro-dropdown_1_0_0>
163
- </div>
164
- ```
166
+ </div>
167
+ ```
168
+
169
+ _Note: the numbers attached in the tag name will match the version of the dependency that was installed._
165
170
 
166
- _Note: the numbers attached in the tag name will match the version of the dependency that was installed._
167
-
168
171
  ##### Accessing the dynamically named element with JS
169
172
 
170
173
  The dynamic component is accessible using a the following string in a JS query selector:
@@ -177,18 +180,18 @@ firstUpdated() {
177
180
  this.dropdown = this.shadowRoot.querySelector(this.dropdownTag._$litStatic$);
178
181
  };
179
182
  ```
180
- <!-- AURO-GENERATED-CONTENT:END -->
181
- ---
182
-
183
+ <!-- AURO-GENERATED-CONTENT:END -->
184
+
185
+ ---
186
+
183
187
  ### Sync All Templates
184
188
 
185
189
  <!-- AURO-GENERATED-CONTENT:START (FILE:src=./../docs/partials/syncAllTemplates.md) -->
186
- <!-- The below content is automatically added from ./../docs/partials/syncAllTemplates.md -->
187
-
190
+ <!-- The below content is automatically added from ./../docs/partials/syncAllTemplates.md -->
188
191
  ### How to Run the `syncAllTemplates.mjs` Script
189
192
 
190
- To run the `syncAllTemplates.mjs` script, you will need to add a new node script into the linked component and point that to the `syncAllTemplates.mjs` file. You can individually run the workflow configurations by pointing to the `syncAllTemplates.mjs` file and adding a `--github` parameter after the path. The same can be done for the linter configurations by adding a `--linters` parameter.
191
-
193
+ To run the `syncAllTemplates.mjs` script, you will need to add a new node script into the linked component and point that to the `syncAllTemplates.mjs` file. You can individually run the workflow configurations by pointing to the `syncAllTemplates.mjs` file and adding a `--github` parameter after the path. The same can be done for the linter configurations by adding a `--linters` parameter.
194
+
192
195
  #### Example Calls
193
196
 
194
197
  ```
@@ -205,4 +208,28 @@ To run the `syncAllTemplates.mjs` script, you will need to add a new node script
205
208
  // Only sync linter configuration templates
206
209
  "syncTemplates": "./node_modules/@aurodesignsystem/auro-library/scripts/config/syncAllTemplates.mjs --linters"
207
210
  ```
208
- <!-- AURO-GENERATED-CONTENT:END -->
211
+ <!-- AURO-GENERATED-CONTENT:END -->
212
+
213
+
214
+ ---
215
+
216
+ ### Prep to build api.md
217
+
218
+ <!-- AURO-GENERATED-CONTENT:START (FILE:src=./../docs/partials/generateWcaComponent.md) -->
219
+ <!-- The below content is automatically added from ./../docs/partials/generateWcaComponent.md -->
220
+ # How to Run the `generateWcaComponent.mjs` Script
221
+
222
+ To run the `generateWcaComponent.mjs` script, you need to provide the file paths for the components you want to process with WCA. This script should be executed only once after adding a new component to the project. Upon running the script, `.js` files will be generated in the `scripts/wca` folder.
223
+
224
+ ## Example Calls
225
+
226
+ ```json
227
+ // Common case: 1 component in 1 project
228
+ "build:api:prepare": "node ./node_modules/@aurodesignsystem/auro-library/scripts/generateWcaComponent.mjs 'src/auro-flight.js'"
229
+ ```
230
+
231
+ ```
232
+ // multiple components in 1 project
233
+ "build:api:prepare": "node ./node_modules/@aurodesignsystem/auro-library/scripts/config/syncAllTemplates.mjs 'src/auro-flight*.js'"
234
+ ```
235
+ <!-- AURO-GENERATED-CONTENT:END -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurodesignsystem/auro-library",
3
- "version": "2.11.0",
3
+ "version": "3.0.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",
@@ -1,285 +1,24 @@
1
- import path from 'path';
2
- import * as mdMagic from 'markdown-magic';
3
- import fs from 'node:fs/promises';
4
- import { fileURLToPath } from 'url';
1
+ // ------------------------------------------------------
2
+ // Docs Generation
3
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ //
5
+ // This script will generate the docs for the component
6
+ // based on example HTML, markdown files, and more.
7
+ //
8
+ // The actions in this file live in:
9
+ // scripts/build/processors/defaultDocsProcessor.mjs
10
+ //
11
+ // This script is intended to be run AS-IS without modification.
12
+ // To run a different processor, please see the defaultDocsProcessor.mjs file
13
+ // and re-create in your repo OR add a new processor file.
14
+ // ------------------------------------------------------
5
15
 
6
- import AuroLibraryUtils from "../utils/auroLibraryUtils.mjs";
7
- import { AuroTemplateFiller } from "./auroTemplateFiller.mjs";
8
- import { AuroFileHandler } from "./auroFileHandler.mjs";
9
16
  import {Logger} from "../utils/logger.mjs";
17
+ import {processDocFiles} from "./processors/defaultDocsProcessor.mjs";
10
18
 
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
15
-
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
- */
24
-
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 {string} matchWord - [v2-only] string to match for variables
32
- * @property {FilePathsOrGlobs} [files] - Files to process.
33
- * @property {Array} [transforms = defaultTransforms] - Custom commands to transform block contents, see transforms & custom transforms sections below.
34
- * @property {OutputConfig} [output] - Output configuration
35
- * @property {SyntaxType} [syntax = 'md'] - Syntax to parse
36
- * @property {string} [open = 'doc-gen'] - Opening match word
37
- * @property {string} [close = 'end-doc-gen'] - Closing match word. If not defined will be same as opening word.
38
- * @property {string} [cwd = process.cwd() ] - Current working directory. Default process.cwd()
39
- * @property {boolean} [outputFlatten] - Flatten files that are output
40
- * @property {boolean} [useGitGlob] - Use git glob for LARGE file directories
41
- * @property {boolean} [dryRun = false] - See planned execution of matched blocks
42
- * @property {boolean} [debug = false] - See debug details
43
- * @property {boolean} [silent = false] - Silence all console output
44
- * @property {boolean} [applyTransformsToSource = true] - Apply transforms to source file. Default is true.
45
- * @property {boolean} [failOnMissingTransforms = false] - Fail if transform functions are missing. Default skip blocks.
46
- * @property {boolean} [failOnMissingRemote = true] - Fail if remote file is missing.
47
- */
48
-
49
-
50
- // Config
51
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52
-
53
- /** @type {MarkdownMagicOptions} */
54
- export const MD_MAGIC_CONFIG = {
55
- matchWord: "AURO-GENERATED-CONTENT",
56
- output: {
57
- directory: "./",
58
- applyTransformsToSource: true
59
- }
60
- };
61
-
62
- // Initialize utility services
63
- export const auroLibraryUtils = new AuroLibraryUtils();
64
- export const templateFiller = new AuroTemplateFiller();
65
- export const auroFileHandler = new AuroFileHandler();
66
-
67
- // List of components that do not support ESM to determine which README to use
68
- export const nonEsmComponents = ['combobox', 'datepicker', 'menu', 'pane', 'select'];
69
-
70
-
71
- // Local utils
72
- /**
73
- *
74
- * @param {string} pathLike - Please include the preceding slash! Like so: `/docTemplates/README.md`
75
- * @return {string}
76
- */
77
- export function fromAuroComponentRoot(pathLike) {
78
- const currentDir = fileURLToPath(new URL('.', import.meta.url))
79
- return path.join(currentDir, `${auroLibraryUtils.projectRootFromBuildScriptDir}${pathLike}`)
80
- }
81
-
82
-
83
- // External assets
84
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85
-
86
- /**
87
- * @param {string} tag - the release version tag to use instead of master
88
- * @param {string} [variantOverride] - override the variant string
89
- * @return {string}
90
- */
91
- export function generateReadmeUrl(tag = 'master', variantOverride = '') {
92
- // LEGACY CODE FOR NON-ESM COMPONENTS
93
-
94
- const nameExtractionData = templateFiller.values;
95
- let variantString = '';
96
-
97
- if (!nonEsmComponents.includes(nameExtractionData.name)) {
98
- variantString = '_esm';
99
- }
100
-
101
- // END LEGACY CODE
102
-
103
- if (variantOverride !== '') {
104
- variantString = variantOverride;
105
- }
106
-
107
- const baseRepoUrl = 'https://raw.githubusercontent.com/AlaskaAirlines/WC-Generator'
108
- if (tag !== 'master') {
109
- return `${baseRepoUrl}/refs/tags/${tag}/componentDocs/README` + variantString + '.md';
110
- }
111
-
112
- return `${baseRepoUrl}/master/componentDocs/README` + variantString + '.md';
113
- }
114
-
115
- // Main Markdown magic processors
116
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117
-
118
- /**
119
- * This is the expected object type when passing something other than a string.
120
- * @typedef {Object} InputFileType
121
- * @property {string} remoteUrl - The remote template to fetch
122
- * @property {string} fileName - Path including file name to store
123
- * @property {boolean} [overwrite] - Default is true. Choose to overwrite the file if it exists
124
- */
125
-
126
-
127
- /**
128
- * @typedef {Object} FileProcessorConfig
129
- * @property {string | InputFileType} input - path to input file, including filename
130
- * @property {string} output - path to output file, including filename
131
- * @property {Partial<MarkdownMagicOptions>} [mdMagicConfig] - extra configuration options for md magic
132
- * @property {Array<(contents: string) => string>} [postProcessors] - extra processor functions to run on content
133
- */
134
-
135
-
136
- // Individual file processing steps
137
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
138
-
139
- /**
140
- * Retrieve a remote file using a provided configuration and store at a local path.
141
- * @param {InputFileType} input - the input file configuration
142
- * @return {Promise<void>}
143
- */
144
- export async function retrieveRemoteFileCopy(input) {
145
- const bareFileName = input.fileName
146
-
147
- Logger.log(`Retrieving latest "${bareFileName}" file...`);
148
-
149
- // 0b. Attempt to populate from remote file
150
- const contents = await fetch(input.remoteUrl, {
151
- redirect: 'follow'
152
- }).then(r => r.text());
153
-
154
- // 0c. Write remote contents to local folder as cache
155
- await AuroFileHandler.tryWriteFile(input.fileName, contents);
156
- }
157
-
158
-
159
- /**
160
- * Run markdown magic on a file.
161
- * @param {string} input
162
- * @param {string} output
163
- * @param {Partial<MarkdownMagicOptions>} [extraMdMagicConfig] - extra configuration options for md magic
164
- * @return {Promise<void>}
165
- */
166
- export async function runMarkdownMagicOnFile(input, output, extraMdMagicConfig = {}) {
167
- await applyMarkdownMagic(output, {
168
- ...MD_MAGIC_CONFIG,
169
- ...extraMdMagicConfig
19
+ processDocFiles().then(() => {
20
+ Logger.log('Docs processed successfully');
21
+ }).
22
+ catch((err) => {
23
+ Logger.error(`Error processing docs: ${err.message}`);
170
24
  });
171
- }
172
-
173
-
174
- /**
175
- * Optionally copy a file to a new location.
176
- * @param {string} input - the input file path
177
- * @param {string} output - the output file path
178
- * @param {boolean} overwrite - whether to overwrite the file if it exists (default is true)
179
- * @return {Promise<void>}
180
- */
181
- export async function optionallyCopyFile(input, output, overwrite = true) {
182
- if (await AuroFileHandler.exists(output) && !overwrite) {
183
- return;
184
- }
185
-
186
- if (!await AuroFileHandler.tryCopyFile(input, output)) {
187
- throw new Error(`Error copying "${input}" file to output ${output}`);
188
- }
189
- }
190
-
191
- /**
192
- * Process the content of a file.
193
- *
194
- * This is a high level function that performs the following via lower functions:
195
- * - Read contents of file
196
- * - Run "markdown-magic" on file contents (optional, *.md specific)
197
- * - Run template variable replacement on file contents
198
- * @param {FileProcessorConfig} config - the config for this file
199
- */
200
- export async function processContentForFile(config) {
201
- const { input: rawInput, output, mdMagicConfig } = config
202
-
203
- // Helper vars
204
- const derivedInputPath = typeof rawInput === 'string' ? rawInput : rawInput.fileName;
205
- const segments = derivedInputPath.split("/")
206
- const bareFileName = segments[segments.length - 1]
207
-
208
- // 0. Optionally retrieve a remote file
209
- if (typeof rawInput === 'object') {
210
- await retrieveRemoteFileCopy(rawInput);
211
- }
212
-
213
- // 1. Copy input or local input cache to output
214
- await optionallyCopyFile(derivedInputPath, output, rawInput.overwrite ?? true);
215
-
216
- // 2. If the file is a Markdown file, run markdown magic to inject contents and perform replacements
217
- if (output.endsWith(".md")) {
218
- await runMarkdownMagicOnFile(derivedInputPath, output, mdMagicConfig);
219
- }
220
-
221
- // 3a. Read the output file contents
222
- let fileContents = await fs.readFile(output, {encoding: 'utf-8'});
223
-
224
- // 3b. Replace template variables in output file
225
- fileContents = templateFiller.replaceTemplateValues(fileContents);
226
-
227
- // 3c. Run any post-processors
228
- if (config.postProcessors) {
229
- for (const processor of config.postProcessors) {
230
- fileContents = processor(fileContents)
231
- }
232
- }
233
-
234
- // 3d. Write the final file contents
235
- if (!await AuroFileHandler.tryWriteFile(output, fileContents)) {
236
- throw new Error(`Error writing "${bareFileName}" file to output ${output}`);
237
- }
238
- }
239
-
240
- // Finally, the main function
241
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
242
-
243
- /**
244
- *
245
- * @param {string} remoteReadmeVersion - the release version tag to use instead of master
246
- * @param {string} [readmeVariant] - the release version tag to use instead of master
247
- * @return {Promise<void>}
248
- */
249
- export async function processDocFiles(remoteReadmeVersion = 'master', readmeVariant = undefined) {
250
- // setup
251
- await templateFiller.extractNames();
252
-
253
- // process
254
- // README.md
255
-
256
- Logger.warn('WARNING: overwrite is set to FALSE for README.md - please update this when template changes are merged');
257
- await processContentForFile({
258
- input: {
259
- remoteUrl: generateReadmeUrl(remoteReadmeVersion, readmeVariant),
260
- fileName: fromAuroComponentRoot(`/docTemplates/README.md`),
261
- overwrite: false
262
- },
263
- output: fromAuroComponentRoot("/README.md")
264
- })
265
-
266
- // Demo MD file
267
- await processContentForFile({
268
- input: fromAuroComponentRoot("/docs/partials/index.md"),
269
- output: fromAuroComponentRoot("/demo/index.md"),
270
- mdMagicConfig: {
271
- output: {
272
- directory: fromAuroComponentRoot("/demo")
273
- }
274
- }
275
- })
276
-
277
- // API MD file
278
- await processContentForFile({
279
- input: fromAuroComponentRoot("/docs/partials/api.md"),
280
- output: fromAuroComponentRoot("/demo/api.md"),
281
- postProcessors: [
282
- templateFiller.formatApiTable
283
- ]
284
- })
285
- }
@@ -0,0 +1,43 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import glob from 'glob';
4
+ import util from 'util';
5
+ import getTemplatedComponentCode from './prepWcaCompatibleCode.mjs';
6
+
7
+ const promisifiedGlob = util.promisify(glob);
8
+
9
+ const WAC_DIR = path.resolve(process.cwd(), './scripts/wca');
10
+
11
+ async function globPath(sources) {
12
+ try {
13
+ const fileArrays = await Promise.all(
14
+ sources.map(source => promisifiedGlob(source))
15
+ );
16
+ return fileArrays.flat();
17
+ } catch (err) {
18
+ console.error('Error processing glob patterns:', err);
19
+ throw err; // Re-throw to handle failure at caller
20
+ }
21
+ }
22
+
23
+ async function createExtendsFile(filePaths) {
24
+ if (!fs.existsSync(WAC_DIR)) {
25
+ await fs.promises.mkdir(WAC_DIR, { recursive: true });
26
+ }
27
+
28
+ for (const filePath of filePaths) {
29
+ const resolvedPath = path.resolve(process.cwd(), filePath);
30
+ const fileContent = await fs.promises.readFile(resolvedPath, 'utf-8',);
31
+ const newPath = path.resolve(WAC_DIR, `${path.basename(filePath)}`);
32
+ const newCode = getTemplatedComponentCode(fileContent, path.relative(WAC_DIR, filePath));
33
+ await fs.promises.writeFile(newPath, newCode);
34
+ }
35
+ }
36
+
37
+ async function main() {
38
+ // files to analyze
39
+ const filePaths = await globPath(process.argv.slice(2));
40
+ await createExtendsFile(filePaths);
41
+ }
42
+
43
+ main();
@@ -0,0 +1,19 @@
1
+ export default (code, sourcePath) => {
2
+ const defaultTag = (code.match(/static register\(name \= (.+)\)/) || code.match(/customElements.get\((.+?)\)/))[1];
3
+ const className = code.match(/export class (.+) extends/)?.[1];
4
+ const classDesc = code.match(/\/\*\*((.|\n)*?)\*\//)?.[1] || '';
5
+
6
+ if (!defaultTag || !className) {
7
+ return code;
8
+ }
9
+ return `
10
+ import { ${className} } from '${sourcePath}';
11
+
12
+ /**${classDesc}*/
13
+ class ${className}WCA extends ${className} {}
14
+
15
+ if (!customElements.get(${defaultTag})) {
16
+ customElements.define(${defaultTag}, ${className}WCA);
17
+ }
18
+ `;
19
+ };
@@ -0,0 +1,83 @@
1
+ import {Logger} from "../../utils/logger.mjs";
2
+ import {
3
+ fromAuroComponentRoot,
4
+ generateReadmeUrl,
5
+ processContentForFile,
6
+ templateFiller
7
+ } from "../../utils/sharedFileProcessorUtils.mjs";
8
+
9
+ /**
10
+ * Processor config object.
11
+ * @typedef {Object} ProcessorConfig
12
+ * @property {boolean} [overwriteLocalCopies=true] - The release version tag to use instead of master.
13
+ * @property {string} [remoteReadmeVersion="master"] - The release version tag to use instead of master.
14
+ * @property {string} [remoteReadmeVariant=""] - The variant string to use for the README source.
15
+ * (like "_esm" to make README_esm.md).
16
+ */
17
+
18
+
19
+ /**
20
+ * @param {ProcessorConfig} config - The configuration for this processor.
21
+ */
22
+ export const defaultDocsProcessorConfig = {
23
+ overwriteLocalCopies: true,
24
+ remoteReadmeVersion: "master",
25
+ // eslint-disable-next-line no-warning-comments
26
+ // TODO: remove this variant when all components are updated to use latest auro-library
27
+ // AND the default README.md is updated to use the new paths
28
+ readmeVariant: "_updated_paths"
29
+ };
30
+
31
+ /**
32
+ * @param {ProcessorConfig} config - The configuration for this processor.
33
+ * @returns {import('../utils/sharedFileProcessorUtils').FileProcessorConfig[]}
34
+ */
35
+ export const fileConfigs = (config = defaultDocsProcessorConfig) => [
36
+ // README.md
37
+ {
38
+ identifier: 'README.md',
39
+ input: {
40
+ remoteUrl: generateReadmeUrl(config.remoteReadmeVersion, config.remoteReadmeVariant),
41
+ fileName: fromAuroComponentRoot(`/docTemplates/README.md`),
42
+ overwrite: config.overwriteLocalCopies
43
+ },
44
+ output: fromAuroComponentRoot("/README.md")
45
+ },
46
+ // index.md
47
+ {
48
+ identifier: 'index.md',
49
+ input: fromAuroComponentRoot("/docs/partials/index.md"),
50
+ output: fromAuroComponentRoot("/demo/index.md"),
51
+ mdMagicConfig: {
52
+ output: {
53
+ directory: fromAuroComponentRoot("/demo")
54
+ }
55
+ }
56
+ },
57
+ // api.md
58
+ {
59
+ identifier: 'api.md',
60
+ input: fromAuroComponentRoot("/docs/partials/api.md"),
61
+ output: fromAuroComponentRoot("/demo/api.md"),
62
+ postProcessors: [templateFiller.formatApiTable],
63
+ }
64
+ ];
65
+
66
+ /**
67
+ *
68
+ * @param {ProcessorConfig} config - The configuration for this processor.
69
+ * @return {Promise<void>}
70
+ */
71
+ export async function processDocFiles(config = defaultDocsProcessorConfig) {
72
+ // setup
73
+ await templateFiller.extractNames();
74
+
75
+ for (const fileConfig of fileConfigs(config)) {
76
+ try {
77
+ // eslint-disable-next-line no-await-in-loop
78
+ await processContentForFile(fileConfig);
79
+ } catch (err) {
80
+ Logger.error(`Error processing ${fileConfig.identifier}: ${err.message}`);
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,83 @@
1
+ import {Logger} from "../../utils/logger.mjs";
2
+ import {
3
+ fromAuroComponentRoot,
4
+ generateWCGeneratorUrl,
5
+ processContentForFile,
6
+ templateFiller
7
+ } from "../../utils/sharedFileProcessorUtils.mjs";
8
+
9
+ /**
10
+ * Processor config object.
11
+ * @typedef {Object} ProcessorConfig
12
+ * @property {boolean} [overwriteLocalCopies=true] - The release version tag to use instead of master.
13
+ * @property {string} [generatorTemplateVersion="master"] - The release version tag to use instead of master.
14
+ * (like "_esm" to make README_esm.md).
15
+ */
16
+
17
+ const DOT_GITHUB_PATH = '.github';
18
+ const ISSUE_TEMPLATE_PATH = `${DOT_GITHUB_PATH}/ISSUE_TEMPLATE`;
19
+
20
+ /**
21
+ * @type {ProcessorConfig} config - The default configuration for this processor.
22
+ */
23
+ const defaultGitHubSyncConfig = {
24
+ overwriteLocalCopies: true,
25
+ generatorTemplateVersion: "master",
26
+ };
27
+
28
+ /**
29
+ * @param {ProcessorConfig} config - The configuration for this processor.
30
+ * @returns {import('../utils/sharedFileProcessorUtils').FileProcessorConfig[]}
31
+ */
32
+ const defaultGitHubTemplateFiles = (config = defaultGitHubSyncConfig) => [
33
+ // bug_report.yml
34
+ {
35
+ identifier: 'bug_report.yml',
36
+ input: {
37
+ remoteUrl: generateWCGeneratorUrl(config.generatorTemplateVersion, `templates/${ISSUE_TEMPLATE_PATH}/bug_report.yml`),
38
+ fileName: fromAuroComponentRoot(`docTemplates/${ISSUE_TEMPLATE_PATH}/bug_report.yml`),
39
+ overwrite: config.overwriteLocalCopies
40
+ },
41
+ output: fromAuroComponentRoot(`${ISSUE_TEMPLATE_PATH}/bug_report.yml`)
42
+ },
43
+ // config.yml
44
+ {
45
+ identifier: 'config.yml',
46
+ input: {
47
+ remoteUrl: generateWCGeneratorUrl(config.generatorTemplateVersion, `templates/${ISSUE_TEMPLATE_PATH}/config.yml`),
48
+ fileName: fromAuroComponentRoot(`docTemplates/${ISSUE_TEMPLATE_PATH}/config.yml`),
49
+ overwrite: config.overwriteLocalCopies
50
+ },
51
+ output: fromAuroComponentRoot(`${ISSUE_TEMPLATE_PATH}/config.yml`)
52
+ },
53
+ // PULL_REQUEST_TEMPLATE.md
54
+ {
55
+ identifier: 'PULL_REQUEST_TEMPLATE.md',
56
+ input: {
57
+ remoteUrl: generateWCGeneratorUrl(config.generatorTemplateVersion, `templates/${DOT_GITHUB_PATH}/PULL_REQUEST_TEMPLATE.md`),
58
+ fileName: fromAuroComponentRoot(`docTemplates/${DOT_GITHUB_PATH}/PULL_REQUEST_TEMPLATE.md`),
59
+ overwrite: config.overwriteLocalCopies
60
+ },
61
+ output: fromAuroComponentRoot(`${DOT_GITHUB_PATH}/PULL_REQUEST_TEMPLATE.md`)
62
+ },
63
+ ];
64
+
65
+ /**
66
+ *
67
+ * @param {ProcessorConfig} config - The configuration for this processor.
68
+ * @return {Promise<void>}
69
+ */
70
+ export async function syncGithubFiles(config = defaultGitHubSyncConfig) {
71
+ // setup
72
+ await templateFiller.extractNames();
73
+
74
+ for (const file of defaultGitHubTemplateFiles(config)) {
75
+ try {
76
+ Logger.log(`Processing file: ${file.identifier}`);
77
+ // eslint-disable-next-line no-await-in-loop
78
+ await processContentForFile(file);
79
+ } catch (error) {
80
+ Logger.error(`Error processing file: ${file.identifier}, ${error.message}`);
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,25 @@
1
+ // ------------------------------------------------------
2
+ // GitHub Config Sync
3
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ //
5
+ // This script will synchronize shared GitHub config
6
+ // files to the local repo (eventually, anything that lives
7
+ // in the .github directory).
8
+ //
9
+ // The actions in this file live in:
10
+ // scripts/build/processors/defaultDotGithubSync.mjs
11
+ //
12
+ // This script is intended to be run AS-IS without modification.
13
+ // To run a different processor, please see the defaultDotGithubSync.mjs file
14
+ // and re-create in your repo OR add a new processor file.
15
+ // ------------------------------------------------------
16
+
17
+ import {syncGithubFiles} from "./processors/defaultDotGithubSync.mjs";
18
+ import {Logger} from "../utils/logger.mjs";
19
+
20
+ syncGithubFiles().then(() => {
21
+ Logger.log('Docs processed successfully');
22
+ }).
23
+ catch((err) => {
24
+ Logger.error(`Error processing docs: ${err.message}`);
25
+ });
@@ -6,15 +6,30 @@
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';
10
9
  import * as path from 'path';
11
10
  import chalk from 'chalk';
11
+ import {Logger} from "./logger.mjs";
12
12
 
13
13
  export default class AuroLibraryUtils {
14
- PROJECT_ROOT_FROM_SCRIPTS__BUILD = "./../../../../.."
14
+ getDirname() {
15
+ if (typeof __dirname === 'undefined') {
16
+ Logger.warn('Unable to determine project root as __dirname is not defined. Assuming current directory is okay!', true);
17
+ return '';
18
+ }
19
+
20
+ // eslint-disable-next-line no-undef
21
+ return __dirname;
22
+ }
23
+
24
+ get getProjectRootPath() {
25
+ const currentDir = this.getDirname();
26
+
27
+ if (!currentDir.includes('node_modules')) {
28
+ Logger.warn(`Unable to determine best project root as node_modules \nis not in the directory path.\n\nAssuming - "${currentDir}"`, true);
29
+ return currentDir;
30
+ }
15
31
 
16
- get projectRootFromBuildScriptDir() {
17
- return this.PROJECT_ROOT_FROM_SCRIPTS__BUILD
32
+ return currentDir.split('node_modules')[0];
18
33
  }
19
34
 
20
35
  /**
@@ -147,8 +162,8 @@ export default class AuroLibraryUtils {
147
162
  'name': pName.substring(nameStart + 1),
148
163
  'nameCap': pName.substring(nameStart + 1)[0].toUpperCase() + pName.substring(nameStart + 2),
149
164
  'version': packageJson.version,
150
- 'tokensVersion': packageJson.peerDependencies['\@aurodesignsystem/design-tokens'].substring(1),
151
- 'wcssVersion': packageJson.peerDependencies['\@aurodesignsystem/webcorestylesheets'].substring(1)
165
+ 'tokensVersion': packageJson.peerDependencies['@aurodesignsystem/design-tokens'].substring(1),
166
+ 'wcssVersion': packageJson.peerDependencies['@aurodesignsystem/webcorestylesheets'].substring(1)
152
167
 
153
168
  };
154
169
  }
@@ -191,19 +206,5 @@ export default class AuroLibraryUtils {
191
206
  */
192
207
  fs.writeFileSync(destination, result, { encoding: 'utf8'});
193
208
  }
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
- }
208
209
  }
209
210
 
@@ -0,0 +1,258 @@
1
+ import path from 'path';
2
+ import * as mdMagic from 'markdown-magic';
3
+ import fs from 'node:fs/promises';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ import AuroLibraryUtils from "./auroLibraryUtils.mjs";
7
+ import { AuroTemplateFiller } from "./auroTemplateFiller.mjs";
8
+ import { AuroFileHandler } from "./auroFileHandler.mjs";
9
+ import {Logger} from "./logger.mjs";
10
+
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
15
+
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
+ */
24
+
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 {string} matchWord - [v2-only] string to match for variables
32
+ * @property {FilePathsOrGlobs} [files] - Files to process.
33
+ * @property {Array} [transforms = defaultTransforms] - Custom commands to transform block contents, see transforms & custom transforms sections below.
34
+ * @property {OutputConfig} [output] - Output configuration
35
+ * @property {SyntaxType} [syntax = 'md'] - Syntax to parse
36
+ * @property {string} [open = 'doc-gen'] - Opening match word
37
+ * @property {string} [close = 'end-doc-gen'] - Closing match word. If not defined will be same as opening word.
38
+ * @property {string} [cwd = process.cwd() ] - Current working directory. Default process.cwd()
39
+ * @property {boolean} [outputFlatten] - Flatten files that are output
40
+ * @property {boolean} [useGitGlob] - Use git glob for LARGE file directories
41
+ * @property {boolean} [dryRun = false] - See planned execution of matched blocks
42
+ * @property {boolean} [debug = false] - See debug details
43
+ * @property {boolean} [silent = false] - Silence all console output
44
+ * @property {boolean} [applyTransformsToSource = true] - Apply transforms to source file. Default is true.
45
+ * @property {boolean} [failOnMissingTransforms = false] - Fail if transform functions are missing. Default skip blocks.
46
+ * @property {boolean} [failOnMissingRemote = true] - Fail if remote file is missing.
47
+ */
48
+
49
+
50
+ // Config
51
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52
+
53
+ /** @type {MarkdownMagicOptions} */
54
+ export const MD_MAGIC_CONFIG = {
55
+ matchWord: "AURO-GENERATED-CONTENT",
56
+ output: {
57
+ directory: "./",
58
+ applyTransformsToSource: true
59
+ }
60
+ };
61
+
62
+ // Initialize utility services
63
+ export const auroLibraryUtils = new AuroLibraryUtils();
64
+ export const templateFiller = new AuroTemplateFiller();
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'];
68
+
69
+
70
+ // Local utils
71
+ /**
72
+ *
73
+ * @param {string} pathLike - Please include the preceding slash! Like so: `/docTemplates/README.md`
74
+ * @return {string}
75
+ */
76
+ // TODO: test this in auro-flight before merging to main
77
+ export function fromAuroComponentRoot(pathLike) {
78
+ const currentDir = fileURLToPath(new URL('.', import.meta.url))
79
+ return path.join(currentDir, `${auroLibraryUtils.getProjectRootPath}${pathLike}`)
80
+ }
81
+
82
+
83
+ // External assets
84
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85
+
86
+ /**
87
+ * Generate a URL for the WC Generator README file.
88
+ * @param {string} branchOrTag
89
+ * @param {string} fileNameWithPath
90
+ * @return {string}
91
+ */
92
+ export function generateWCGeneratorUrl(branchOrTag, fileNameWithPath) {
93
+ const baseRepoUrl = 'https://raw.githubusercontent.com/AlaskaAirlines/WC-Generator'
94
+
95
+ // check if tag starts with 'vX' since our tags are `v4.0.0`
96
+ const isTag = branchOrTag.startsWith('v') &&
97
+ /^\d+\.\d+\.\d+(-.*)?$/.test(branchOrTag.slice(1));
98
+
99
+ if (isTag) {
100
+ return `${baseRepoUrl}/refs/tags/${branchOrTag}/${fileNameWithPath}`;
101
+ }
102
+
103
+ if (branchOrTag !== 'master') {
104
+ return `${baseRepoUrl}/refs/heads/${branchOrTag}/${fileNameWithPath}`;
105
+ }
106
+
107
+ return `${baseRepoUrl}/master/${fileNameWithPath}`;
108
+ }
109
+
110
+ /**
111
+ * @param {string} branchOrTag - the git branch or tag to use for the README source
112
+ * @param {string} [variantOverride] - override the variant string
113
+ * @return {string}
114
+ */
115
+ export function generateReadmeUrl(branchOrTag = 'master', variantOverride = '') {
116
+ // LEGACY CODE FOR NON-ESM COMPONENTS
117
+
118
+ const nameExtractionData = templateFiller.values;
119
+ let variantString = '';
120
+
121
+ if (!nonEsmComponents.includes(nameExtractionData.name)) {
122
+ variantString = '_esm';
123
+ }
124
+
125
+ // END LEGACY CODE
126
+
127
+ if (variantOverride !== '') {
128
+ variantString = variantOverride;
129
+ }
130
+
131
+ return generateWCGeneratorUrl(branchOrTag, `componentDocs/README${variantString}.md`);
132
+ }
133
+
134
+ // Main Markdown magic processors
135
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
136
+
137
+ /**
138
+ * This is the expected object type when passing something other than a string.
139
+ * @typedef {Object} InputFileType
140
+ * @property {string} remoteUrl - The remote template to fetch
141
+ * @property {string} fileName - Path including file name to store
142
+ * @property {boolean} [overwrite] - Default is true. Choose to overwrite the file if it exists
143
+ */
144
+
145
+
146
+ /**
147
+ * @typedef {Object} FileProcessorConfig
148
+ * @property {string} identifier - A unique identifier for this file (used for logging).
149
+ * @property {string | InputFileType} input - path to an input file, including filename
150
+ * @property {string} output - path to an output file, including filename
151
+ * @property {Partial<MarkdownMagicOptions>} [mdMagicConfig] - extra configuration options for md magic
152
+ * @property {Array<(contents: string) => string>} [postProcessors] - extra processor functions to run on content
153
+ */
154
+
155
+
156
+ // Individual file processing steps
157
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
158
+
159
+ /**
160
+ * Retrieve a remote file using a provided configuration and store at a local path.
161
+ * @param {InputFileType} input - the input file configuration
162
+ * @return {Promise<void>}
163
+ */
164
+ export async function retrieveRemoteFileCopy(input) {
165
+ const bareFileName = input.fileName
166
+
167
+ Logger.log(`Retrieving latest "${bareFileName}" file...`);
168
+
169
+ // 0b. Attempt to populate from remote file
170
+ const contents = await fetch(input.remoteUrl, {
171
+ redirect: 'follow'
172
+ }).then(r => r.text());
173
+
174
+ // 0c. Write remote contents to local folder as cache
175
+ await AuroFileHandler.tryWriteFile(input.fileName, contents);
176
+ }
177
+
178
+
179
+ /**
180
+ * Run markdown magic on a file.
181
+ * @param {string} input
182
+ * @param {string} output
183
+ * @param {Partial<MarkdownMagicOptions>} [extraMdMagicConfig] - extra configuration options for md magic
184
+ * @return {Promise<void>}
185
+ */
186
+ export async function runMarkdownMagicOnFile(input, output, extraMdMagicConfig = {}) {
187
+ await applyMarkdownMagic(output, {
188
+ ...MD_MAGIC_CONFIG,
189
+ ...extraMdMagicConfig
190
+ });
191
+ }
192
+
193
+
194
+ /**
195
+ * Optionally copy a file to a new location.
196
+ * @param {string} input - the input file path
197
+ * @param {string} output - the output file path
198
+ * @param {boolean} overwrite - whether to overwrite the file if it exists (default is true)
199
+ * @return {Promise<void>}
200
+ */
201
+ export async function optionallyCopyFile(input, output, overwrite = true) {
202
+ if (await AuroFileHandler.exists(output) && !overwrite) {
203
+ return;
204
+ }
205
+
206
+ if (!await AuroFileHandler.tryCopyFile(input, output)) {
207
+ throw new Error(`Error copying "${input}" file to output ${output}`);
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Process the content of a file.
213
+ *
214
+ * This is a high level function that performs the following via lower functions:
215
+ * - Read contents of file
216
+ * - Run "markdown-magic" on file contents (optional, *.md specific)
217
+ * - Run template variable replacement on file contents
218
+ * @param {FileProcessorConfig} config - the config for this file
219
+ */
220
+ export async function processContentForFile(config) {
221
+ const { input: rawInput, output, mdMagicConfig } = config
222
+
223
+ // Helper vars
224
+ const derivedInputPath = typeof rawInput === 'string' ? rawInput : rawInput.fileName;
225
+ const segments = derivedInputPath.split("/")
226
+ const bareFileName = segments[segments.length - 1]
227
+
228
+ // 0. Optionally retrieve a remote file
229
+ if (typeof rawInput === 'object') {
230
+ await retrieveRemoteFileCopy(rawInput);
231
+ }
232
+
233
+ // 1. Copy input or local input cache to output
234
+ await optionallyCopyFile(derivedInputPath, output, rawInput.overwrite ?? true);
235
+
236
+ // 2. If the file is a Markdown file, run markdown magic to inject contents and perform replacements
237
+ if (output.endsWith(".md")) {
238
+ await runMarkdownMagicOnFile(derivedInputPath, output, mdMagicConfig);
239
+ }
240
+
241
+ // 3a. Read the output file contents
242
+ let fileContents = await fs.readFile(output, {encoding: 'utf-8'});
243
+
244
+ // 3b. Replace template variables in output file
245
+ fileContents = templateFiller.replaceTemplateValues(fileContents);
246
+
247
+ // 3c. Run any post-processors
248
+ if (config.postProcessors) {
249
+ for (const processor of config.postProcessors) {
250
+ fileContents = processor(fileContents)
251
+ }
252
+ }
253
+
254
+ // 3d. Write the final file contents
255
+ if (!await AuroFileHandler.tryWriteFile(output, fileContents)) {
256
+ throw new Error(`Error writing "${bareFileName}" file to output ${output}`);
257
+ }
258
+ }
File without changes
File without changes