Skip to content

Commit fa9a2cc

Browse files
authored
fix(docs): add overwriteExisting option for flexible README overwrite behaviour (#6249)
* fix(docs): add overwriteExisting option for flexible README overwrite behaviour On the `docs-readme` output target, a new `overwriteExisting` option allows developers to control how existing README files are handled when writing to a custom path. This adds flexibility to either: - Always overwrite the full README (`true`), - Only write the full README if no file exists (`'if-missing'`), or - Preserve existing custom content (**default** `false`). Now, `docs-readme` treats the component `readme.md` files as the canonical source for manually-entered custom content when overwriting READMEs. This ensures that custom content is preserved unless explicitly overwritten. For example, when using the `'if-missing'` flag, a project that writes component readmes into a documentation library folder can maintain consistent, idempotent output across local builds and CI environments. Custom edits to the destination files will be maintained, while files without customisation will be fully exported. Fixes #6248 * test(docs-readme): add coverage for overwriteExisting behaviours Adds tests covering all `overwriteExisting` modes on the `docs-readme` output target: - Always overwrite (`true`) - Overwrite if missing (`'if-missing'`) with and without a destination file - Never overwrite (`false`) - Default behaviour (`undefined`), which treats missing values as `false` Tests confirm that manual content is preserved when appropriate, new files are correctly generated when missing, and behaviour matches the original fix for #5400. Also validates idempotent output across multiple overwriting scenarios. Related to the fix for #6248. * test(docs-readme): revamp overwrite test for consistent test state Added `copy-readme.js` to copy the supplemental README over the known README result to ensure the file is in a consistent state before the test begins. This approach verifies whether the `docs-readme` output target correctly overwrites the file as expected during the test process. * refactor(copy-readme): normalize formatting with Prettier
1 parent 8df2970 commit fa9a2cc

File tree

12 files changed

+204
-12
lines changed

12 files changed

+204
-12
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,7 @@ test/wdio/test-components-no-external-runtime
5959
test/wdio/www-global-script/
6060
test/wdio/www-prerender-script
6161
test/wdio/www-invisible-prehydration/
62-
test/wdio/test-ts-target-output
62+
test/wdio/test-ts-target-output
63+
64+
# readme file from docs-readme that is expected to be missing so it will be emitted in full
65+
test/docs-readme/custom-readme-output-overwrite-if-missing-missing/components/styleurls-component/readme.md

scripts/test/copy-readme.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* This script copies a supplemental README file to the location where it will be overwritten
3+
* during the `docs-readme` output target test. The purpose of this step is to ensure that
4+
* the file is in a known state before the test runs, avoiding issues with Git detecting
5+
* unexpected changes to the file.
6+
*
7+
* Context:
8+
* - During the `docs-readme` tests, a README file is overwritten as part of the test process.
9+
* - The expected result of the test must be tracked by Git; otherwise, Git will detect a "dirty"
10+
* state and the test will fail.
11+
* - This behaviour can be used to our advantage: if the file is overwritten with the supplemental
12+
* file but not overwritten back to the expected result, Git will detect a dirty state, causing
13+
* the test to fail. This ensures that the correct action is taken by the code being tested.
14+
*
15+
* Usage:
16+
* - This script is executed as part of the `prepare.readmes` npm script.
17+
* - It copies `readme-supplemental.md` to `readme.md` in the appropriate directory.
18+
*/
19+
20+
const fs = require('fs');
21+
const path = require('path');
22+
23+
// Define source and destination paths
24+
const src = path.resolve(
25+
__dirname,
26+
'../../test/docs-readme/custom-readme-output-overwrite/components/styleurls-component/readme-supplemental.md',
27+
);
28+
const dest = path.resolve(
29+
__dirname,
30+
'../../test/docs-readme/custom-readme-output-overwrite/components/styleurls-component/readme.md',
31+
);
32+
33+
// Copy the file
34+
try {
35+
fs.copyFileSync(src, dest);
36+
console.log(`Copied ${src} to ${dest}`);
37+
} catch (err) {
38+
console.error(`Error copying file: ${err.message}`);
39+
process.exit(1);
40+
}

src/compiler/docs/readme/output-docs.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,23 @@ export const generateReadme = async (
4747
const readmeOutputPath = join(readmeOutput.dir, relativeReadmePath);
4848

4949
const currentReadmeContent =
50-
normalizePath(readmeOutput.dir) !== normalizePath(config.srcDir)
51-
? // The user set a custom `.dir` property, which is where we're going
52-
// to write the updated README. We need to read the non-automatically
53-
// generated content from that file and preserve that.
54-
await getUserReadmeContent(compilerCtx, readmeOutputPath)
55-
: userContent;
50+
readmeOutput.overwriteExisting === true
51+
? // Overwrite explicitly requested: always use the provided user content.
52+
userContent
53+
: normalizePath(readmeOutput.dir) !== normalizePath(config.srcDir)
54+
? (readmeOutput.overwriteExisting === 'if-missing' &&
55+
// Validate a file exists at the output path
56+
(await compilerCtx.fs.access(readmeOutputPath))) ||
57+
// False and undefined case: follow the changes made in #5648
58+
(readmeOutput.overwriteExisting ?? false) === false
59+
? // Existing file found: The user set a custom `.dir` property, which is
60+
// where we're going to write the updated README. We need to read the
61+
// non-automatically generated content from that file and preserve that.
62+
await getUserReadmeContent(compilerCtx, readmeOutputPath)
63+
: // No existing file found: use the provided user content.
64+
userContent
65+
: // Default case: writing to srcDir, so use the provided user content.
66+
userContent;
5667

5768
const readmeContent = generateMarkdown(currentReadmeContent, docsData, cmps, readmeOutput, config);
5869

src/declarations/stencil-public-compiler.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2382,6 +2382,17 @@ export interface OutputTargetDocsReadme extends OutputTargetBase {
23822382
*/
23832383
dir?: string;
23842384
dependencies?: boolean;
2385+
/**
2386+
* Controls how READMEs are written to the destination directory.
2387+
*
2388+
* - `true`: Always overwrite the destination README with the full content.
2389+
* - `false` (default): Only update the autogenerated content, preserving existing custom content above it.
2390+
* - `'if-missing'`: Write the full README only if no file exists at the destination.
2391+
*
2392+
* This option enables workflows requiring consistent, idempotent output across builds,
2393+
* and supports setups where custom documentation may need to coexist or vary between environments.
2394+
*/
2395+
overwriteExisting?: boolean | 'if-missing';
23852396
footer?: string;
23862397
strict?: boolean;
23872398
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# styleurls-component
2+
3+
This file is in a custom location, set with `.dir` on the `docs-readme` OT and `overwriteExisting` set to `if-missing`. It is a supplemental due to this test requiring the `readme` file to not exist so it will be created by the `docs-readme` output target.
4+
5+
When the test is run the `readme.md` should be created.
6+
7+
The content of that readme should match the content of the readme beside the component.
8+
9+
This is a regression test for the issue reported in stenciljs/core#6248.
10+
11+
<!-- Auto Generated Below -->
12+
13+
14+
## CSS Custom Properties
15+
16+
| Name | Description |
17+
| ------- | ------------ |
18+
| `--one` | Property One |
19+
| `--two` | Property Two |
20+
21+
22+
----------------------------------------------
23+
24+
*Built with [StencilJS](https://stenciljs.com/)*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# styleurls-component
2+
3+
This file is in a custom location, set with `.dir` on the `docs-readme` OT and `overwriteExisting` set to `if-missing`.
4+
5+
The content here above the 'auto-generation' comment _shouldn't be overwritten since this file **is not missing**_.
6+
7+
This is a regression test for the issue reported in stenciljs/core#6248.
8+
9+
<!-- Auto Generated Below -->
10+
11+
12+
## CSS Custom Properties
13+
14+
| Name | Description |
15+
| ------- | ------------ |
16+
| `--one` | Property One |
17+
| `--two` | Property Two |
18+
19+
20+
----------------------------------------------
21+
22+
*Built with [StencilJS](https://stenciljs.com/)*
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# styleurls-component
2+
3+
This file is in a custom location, set with `.dir` on the `docs-readme` OT and `overwriteExisting` set to `false`.
4+
5+
The content here above the 'auto-generation' comment _shouldn't be overwritten_.
6+
7+
This is a regression test for the issue reported in stenciljs/core#6248.
8+
9+
<!-- Auto Generated Below -->
10+
11+
12+
## CSS Custom Properties
13+
14+
| Name | Description |
15+
| ------- | ------------ |
16+
| `--one` | Property One |
17+
| `--two` | Property Two |
18+
19+
20+
----------------------------------------------
21+
22+
*Built with [StencilJS](https://stenciljs.com/)*
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# styleurls-component
2+
3+
This file is in a custom location, set with `.dir` on the `docs-readme` OT and `overwriteExisting` set to `true`.
4+
5+
The content here above the 'auto-generation' comment _should be overwritten_. It is copied into place by the `copy-readme.js` script before the `build` is performed and is expected to be overwritten by the version located beside the component, which is checked into Git here for a static reference. If it is not overwritten, the test will fail, indicating an issue with the overwrite process.
6+
7+
This is a regression test for the issue reported in stenciljs/core#6248.
8+
9+
<!-- Auto Generated Below -->
10+
11+
## CSS Custom Properties
12+
13+
| Name | Description |
14+
| ------- | ------------ |
15+
| `--one` | Property One |
16+
| `--two` | Property Two |
17+
18+
---
19+
20+
_Built with [StencilJS](https://stenciljs.com/)_
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# styleurls-component
2+
3+
This file is the original readme that is beside the component.
4+
5+
<!-- Auto Generated Below -->
6+
7+
8+
## CSS Custom Properties
9+
10+
| Name | Description |
11+
| ------- | ------------ |
12+
| `--one` | Property One |
13+
| `--two` | Property Two |
14+
15+
16+
----------------------------------------------
17+
18+
*Built with [StencilJS](https://stenciljs.com/)*

test/docs-readme/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
"dist/"
77
],
88
"scripts": {
9-
"build": "node ../../bin/stencil build",
10-
"build.dev": "node ../../bin/stencil build --dev",
9+
"prepare.readmes": "node ../../scripts/test/copy-readme.js",
10+
"build": "npm run prepare.readmes && node ../../bin/stencil build",
11+
"build.dev": "npm run prepare.readmes && node ../../bin/stencil build --dev",
1112
"start": "node ../../bin/stencil build --dev --watch --serve",
12-
"test": "node ../../bin/stencil test --spec --e2e",
13-
"test.watch": "node ../../bin/stencil test --spec --e2e --watch",
13+
"test": "npm run prepare.readmes && node ../../bin/stencil test --spec --e2e",
14+
"test.watch": "npm run prepare.readmes && node ../../bin/stencil test --spec --e2e --watch",
1415
"generate": "node ../../bin/stencil generate"
1516
},
1617
"license": "MIT"

test/docs-readme/src/components/styleurls-component/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# styleurls-component
22

3-
3+
This file is the original readme that is beside the component.
44

55
<!-- Auto Generated Below -->
66

test/docs-readme/stencil.config.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,25 @@ export const config: Config = {
1313
type: 'docs-readme',
1414
dir: 'custom-readme-output',
1515
},
16+
{
17+
type: 'docs-readme',
18+
dir: 'custom-readme-output-overwrite',
19+
overwriteExisting: true,
20+
},
21+
{
22+
type: 'docs-readme',
23+
dir: 'custom-readme-output-overwrite-if-missing-missing',
24+
overwriteExisting: 'if-missing',
25+
},
26+
{
27+
type: 'docs-readme',
28+
dir: 'custom-readme-output-overwrite-if-missing-not-missing',
29+
overwriteExisting: 'if-missing',
30+
},
31+
{
32+
type: 'docs-readme',
33+
dir: 'custom-readme-output-overwrite-never',
34+
overwriteExisting: false,
35+
},
1636
],
1737
};

0 commit comments

Comments
 (0)