aberlaas-readme 2.18.1 → 2.20.1

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/lib/main.js CHANGED
@@ -1,180 +1,194 @@
1
- import path from 'node:path';
2
1
  import { _, pMap } from 'golgoth';
2
+ import { consoleWarn, exists, firostError, read, write } from 'firost';
3
+ import { hostGitPath, hostGitRoot } from 'aberlaas-helper';
3
4
  import dedent from 'dedent';
4
- import { absolute, exists, glob, read, readJson, write } from 'firost';
5
5
  import frontMatter from 'front-matter';
6
- import helper from 'aberlaas-helper';
6
+ import Gilmore from 'gilmore';
7
7
 
8
- export default {
9
- /**
10
- * Update the main README.md based on the template and the documentation
11
- * @param {object} cliArgs CLI Argument object, as created by minimist
12
- * @param {string} cliArgs.template Path to the template (default to
13
- * .github/README.template.md
14
- * @param {string} cliArgs.docs Path to the documentation folder
15
- * @param {string} cliArgs.lib Path to the library folder
16
- * @param {string} cliArgs.output List of files to output. Default to
17
- * README at the root, and next to package.json
18
- */
19
- async run(cliArgs) {
20
- const template = await this.getTemplate(cliArgs);
8
+ export let __;
21
9
 
22
- const packageData = await this.getPackageData(cliArgs);
23
- const docsData = await this.getDocsData(cliArgs);
24
- const data = { package: packageData, ...docsData };
10
+ const TEMPLATE_PATH = '.README.template.md';
25
11
 
26
- const output = await this.getReadmes(cliArgs);
12
+ /**
13
+ * Update the various README.md files based on the template
14
+ * @param {object} cliArgs CLI Argument object, as created by minimist
15
+ * @param {string} cliArgs.template Path to the template (default to .README.template.md)
16
+ * @param {Array} cliArgs._ List of files that changed (passed by lint-staged)
17
+ * @param {boolean} cliArgs.addToGit Whether to add generated files to git staging area
18
+ */
19
+ export async function run(cliArgs = {}) {
20
+ await __.warnIfDeprecatedTemplate();
21
+ await __.ensureTemplateExists();
27
22
 
28
- const content = await this.convert(template, data);
29
- // console.info({ template, data, docsData });
23
+ // Get all template data (inputs, outputs, body)
24
+ const templateData = await __.getTemplateData();
30
25
 
31
- await pMap(output, async (filepath) => {
32
- await write(content, filepath);
33
- });
34
- },
26
+ // Stop if the passed args do not require a regeneration
27
+ if (!__.shouldContinue(cliArgs?._, templateData)) {
28
+ return;
29
+ }
30
+
31
+ // Regenerate the READMEs
32
+ await __.generateAndWrite(templateData);
33
+
34
+ // Add generated files to git staging area if requested
35
+ if (cliArgs['add-to-git']) {
36
+ await __.addToGit(templateData);
37
+ }
38
+ }
39
+
40
+ __ = {
35
41
  /**
36
- * Returns the content of the template
37
- * @param {object} cliArgs CLI Argument object, as created by minimist
38
- * @param {string} cliArgs.template Path to the template
39
- * Will default to .github/README.template.md in the host, or fallback to
40
- * a default value in aberllas
41
- * @returns {string} Template content
42
+ * Warns the user if they are using the deprecated README template location.
42
43
  */
43
- async getTemplate(cliArgs = {}) {
44
- if (cliArgs.template) {
45
- const customTemplate = helper.hostPath(cliArgs.template);
46
- if (await exists(customTemplate)) {
47
- return await read(customTemplate);
48
- }
44
+ async warnIfDeprecatedTemplate() {
45
+ const oldTemplate = hostGitPath('.github/README.template.md');
46
+ if (!(await exists(oldTemplate))) {
47
+ return;
49
48
  }
50
49
 
51
- const hostDefaultTemplate = helper.hostPath('.github/README.template.md');
52
- if (await exists(hostDefaultTemplate)) {
53
- return await read(hostDefaultTemplate);
54
- }
55
-
56
- const aberlaasDefaultTemplate = absolute('../templates/README.md');
57
- return await read(aberlaasDefaultTemplate);
50
+ __.consoleWarn('aberlaas: Readme template location has changed.');
51
+ __.consoleWarn(
52
+ 'Please move ./.github/README.template.md to ./.README.template.md',
53
+ );
58
54
  },
55
+
59
56
  /**
60
- * Returns the content of the library package.json
61
- * @param {object} cliArgs CLI Argument object, as created by minimist
62
- * Will default search in cliArgs.lib, ./lib, or the root
63
- * @returns {object} package.json content
57
+ * Ensures that the template file exists at the expected location.
64
58
  */
65
- async getPackageData(cliArgs = {}) {
66
- const packagePath = await this.getPackagePath(cliArgs);
67
- return await readJson(packagePath);
59
+ async ensureTemplateExists() {
60
+ const templatePath = hostGitPath(TEMPLATE_PATH);
61
+ if (await exists(templatePath)) {
62
+ return;
63
+ }
64
+ throw firostError(
65
+ 'ABERLAAS_README_MISSING_TEMPLATE',
66
+ `README template not found at ${TEMPLATE_PATH}`,
67
+ );
68
68
  },
69
+
69
70
  /**
70
- * Returns the path to the package.json
71
- * @param {object} cliArgs CLI Argument object, as created by minimist
72
- * Will default search in cliArgs.lib, ./lib, or the root
73
- * @returns {object} package.json content
71
+ * Extracts and processes template data including inputs, outputs, and body content.
72
+ * Uses the static TEMPLATE_PATH constant.
73
+ * @returns {object} Object containing processed inputs array, outputs array, and template body content
74
74
  */
75
- async getPackagePath(cliArgs = {}) {
76
- const libFolder = helper.hostPath(cliArgs.lib || './lib');
77
- let packagePath = path.resolve(libFolder, 'package.json');
78
-
79
- if (await exists(packagePath)) {
80
- return packagePath;
75
+ async getTemplateData() {
76
+ const templatePath = hostGitPath(TEMPLATE_PATH);
77
+ const rawContent = await read(templatePath);
78
+ const parsed = frontMatter(rawContent);
79
+
80
+ // Template content
81
+ const body = parsed.body;
82
+
83
+ // Outputs from frontmatter
84
+ const outputs = _.map(parsed.attributes.outputs, hostGitPath);
85
+
86
+ // Ensure outputs are defined
87
+ if (_.isEmpty(outputs)) {
88
+ throw firostError(
89
+ 'ABERLAAS_README_MISSING_OUTPUTS',
90
+ `File ${TEMPLATE_PATH} is missing an outputs: key in its frontmatter`,
91
+ );
81
92
  }
82
93
 
83
- return helper.hostPath('package.json');
84
- },
85
- /**
86
- * Returns all documentation as an object
87
- * @param {object} cliArgs CLI Argument object, as created by minimist
88
- * @param {string} cliArgs.docs Path to the documentation directory
89
- * Will default to ./docs/src
90
- * @returns {object} Documentation content
91
- */
92
- async getDocsData(cliArgs = {}) {
93
- const docsPath = helper.hostPath(cliArgs.docs || './docs/src');
94
- const mdFiles = await glob(`${docsPath}/**/*.md`);
95
- const docsData = {};
96
- await pMap(mdFiles, async (filepath) => {
97
- // Convert filepath to a (nested) dot key
98
- const key = _.chain(path.relative(docsPath, filepath))
99
- .replace(/\.md$/, '')
100
- .replace(/\//g, '.')
101
- .value();
102
-
103
- // Grab the content, excluding front-matter
104
- const rawContent = await read(filepath);
105
- const { body } = frontMatter(rawContent);
106
- _.set(docsData, key, body);
94
+ // Inputs
95
+ const fileRegexp = /{file:(?<filepath>[^}]+)}/gm;
96
+ const matches = Array.from(body.matchAll(fileRegexp));
97
+ const inputs = _.chain(matches)
98
+ .map((match) => match.groups.filepath)
99
+ .map((filepath) => {
100
+ return {
101
+ match: filepath,
102
+ filepath: hostGitPath(filepath),
103
+ };
104
+ })
105
+ .value();
106
+
107
+ // Ensure all inputs actually exist
108
+ await pMap(inputs, async (input) => {
109
+ const { match, filepath } = input;
110
+ if (await exists(filepath)) {
111
+ return;
112
+ }
113
+ throw firostError(
114
+ 'ABERLAAS_README_MISSING_INPUT',
115
+ `Unable to find file to include for {file:${match}} in ${TEMPLATE_PATH}`,
116
+ );
107
117
  });
108
- return docsData;
118
+
119
+ return {
120
+ inputs,
121
+ outputs,
122
+ body,
123
+ };
109
124
  },
125
+
110
126
  /**
111
- * Returns path to all README.md to write
112
- * @param {object} cliArgs CLI Argument object, as created by minimist
113
- * @param {string} cliArgs.output Comma-separated list of output path
114
- * Will default to a README.md at the git root, and one in the module code
115
- * (./lib by default)
116
- * @returns {Array} List of paths to write the READMEs
127
+ * Determines if the README generation should continue based on changed files.
128
+ * If none of the changed files are used as inputs, or outputs of the readme,
129
+ * we should stop
130
+ * @param {Array} cliFiles List of passed files
131
+ * @param {object} templateData Template data containing inputs, outputs, and body
132
+ * @returns {boolean} True if generation should continue, false otherwise
117
133
  */
118
- async getReadmes(cliArgs = {}) {
119
- // Custom --output passed as a comma-separated list
120
- if (cliArgs.output) {
121
- return _.chain(cliArgs.output)
122
- .split(',')
123
- .map((filepath) => {
124
- return helper.hostPath(filepath);
125
- })
126
- .sort()
127
- .value();
134
+ shouldContinue(cliFiles, templateData) {
135
+ // If no files passed, always continue
136
+ if (_.isEmpty(cliFiles)) {
137
+ return true;
128
138
  }
129
139
 
130
- // README.md at the git root for GitHub
131
- const hostReadmePath = helper.hostPath('README.md');
140
+ // Build list of files that would trigger a README regeneration
141
+ const templatePath = hostGitPath(TEMPLATE_PATH);
142
+ const filesTriggeringChange = [
143
+ ..._.map(templateData.inputs, 'filepath'),
144
+ templatePath,
145
+ ];
132
146
 
133
- // README.md in the module folder for npm/yarn
134
- const packagePath = await this.getPackagePath(cliArgs);
135
- const moduleReadmePath = path.resolve(
136
- path.dirname(packagePath),
137
- 'README.md',
138
- );
147
+ const changedFiles = _.map(cliFiles, (filepath) => hostGitPath(filepath));
139
148
 
140
- const readmes = _.uniq([hostReadmePath, moduleReadmePath]);
141
- return readmes;
149
+ // Stop if no relevant files changed
150
+ const intersection = _.intersection(changedFiles, filesTriggeringChange);
151
+ return !_.isEmpty(intersection);
142
152
  },
153
+
143
154
  /**
144
- * Convert a source string by replace {key} with the matching keys of data
145
- * @param {string} source The source string
146
- * @param {object} data The data object to use to compile
147
- * @returns {string} The converted string
155
+ * Generates the README content and writes it to all output files.
156
+ * @param {object} templateData Template data containing inputs, outputs, and body
148
157
  */
149
- convert(source, data) {
150
- const regexp = /{(?<key>.*?)}/gm;
151
- const matches = Array.from(source.matchAll(regexp));
158
+ async generateAndWrite(templateData) {
159
+ const { inputs, outputs, body } = templateData;
152
160
 
153
- let convertedSource = dedent`
161
+ // Generate content by wrapping template and replacing placeholders
162
+ let content = dedent`
154
163
  <!--
155
- This page was automatically generated by aberlaas readme.
156
- DO NOT EDIT IT MANUALLY.
164
+ This file was automatically generated by 'aberlaas readme' from ${TEMPLATE_PATH}
165
+ DO NOT EDIT MANUALLY
157
166
  -->
167
+ ${body}
168
+ `;
158
169
 
159
- ${source}`;
170
+ await pMap(inputs, async (input) => {
171
+ const { match, filepath } = input;
172
+ const includedContent = await read(filepath);
173
+ content = _.replace(content, `{file:${match}}`, includedContent);
174
+ });
160
175
 
161
- _.each(matches, (match) => {
162
- const key = match.groups.key;
163
- convertedSource = convertedSource.replace(
164
- `{${key}}`,
165
- _.get(data, key, ''),
166
- );
176
+ // Write to all output files
177
+ await pMap(outputs, async (outputPath) => {
178
+ await write(content, outputPath);
167
179
  });
168
- return convertedSource;
169
180
  },
181
+
170
182
  /**
171
- * Read a file from disk, removing its front-matter if it has one
172
- * @param {string} filepath Path to the file
173
- * @returns {string} File content, stripped of front-matter
183
+ * Adds generated README files to git staging area
184
+ * @param {object} templateData Template data containing outputs
174
185
  */
175
- async read(filepath) {
176
- const source = await this.__read(filepath);
177
- const { body } = frontMatter(source);
178
- return body;
186
+ async addToGit(templateData) {
187
+ const { outputs } = templateData;
188
+ const repo = new Gilmore(hostGitRoot());
189
+ await repo.add(outputs);
179
190
  },
191
+ consoleWarn,
180
192
  };
193
+
194
+ export default { run };
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "aberlaas-readme",
3
3
  "type": "module",
4
+ "sideEffects": false,
4
5
  "description": "aberlaas readme helper: Write and synchronize README",
5
- "version": "2.18.1",
6
+ "version": "2.20.1",
6
7
  "repository": "pixelastic/aberlaas",
7
8
  "homepage": "https://projects.pixelastic.com/aberlaas/",
8
9
  "author": "Tim Carry (@pixelastic)",
9
10
  "license": "MIT",
10
11
  "files": [
11
- "lib/*.js",
12
- "templates/"
12
+ "lib/*.js"
13
13
  ],
14
14
  "exports": {
15
15
  ".": "./lib/main.js"
@@ -18,27 +18,25 @@
18
18
  "engines": {
19
19
  "node": ">=18.18.0"
20
20
  },
21
- "scripts": {
22
- "build": "../../scripts/local/build",
23
- "build:prod": "../../scripts/local/build-prod",
24
- "cms": "../../scripts/local/cms",
25
- "serve": "../../scripts/local/serve",
26
- "ci": "../../scripts/local/ci",
27
- "release": "../../scripts/local/release",
28
- "update-dependencies": "node ../../scripts/meta/update-dependencies.js",
29
- "test:meta": "../../scripts/local/test-meta",
30
- "test": "../../scripts/local/test",
31
- "test:watch": "../../scripts/local/test-watch",
32
- "compress": "../../scripts/local/compress",
33
- "lint": "../../scripts/local/lint",
34
- "lint:fix": "../../scripts/local/lint-fix"
35
- },
36
21
  "dependencies": {
37
- "aberlaas-helper": "^2.18.1",
38
- "dedent": "1.5.3",
39
- "firost": "5.2.1",
22
+ "aberlaas-helper": "workspace:*",
23
+ "dedent": "1.7.1",
24
+ "firost": "5.5.1",
40
25
  "front-matter": "4.0.2",
26
+ "gilmore": "1.2.0",
41
27
  "golgoth": "3.0.0"
42
28
  },
43
- "gitHead": "00b60dcf9aebab442a809ccc81942005d87d1b5c"
29
+ "scripts": {
30
+ "build": "cd ../docs && yarn run build",
31
+ "build:prod": "cd ../docs && yarn run build:prod",
32
+ "cms": "cd ../docs && yarn run cms",
33
+ "serve": "cd ../docs && yarn run serve",
34
+ "release": "cd ../.. && ./scripts/release",
35
+ "test:meta": "cd ../.. && ./scripts/test-meta",
36
+ "test": "cd ../.. && ./scripts/test",
37
+ "test:watch": "cd ../.. && ./scripts/test-watch",
38
+ "compress": "cd ../.. && ./scripts/compress",
39
+ "lint": "cd ../.. && ./scripts/lint",
40
+ "lint:fix": "cd ../.. && ./scripts/lint-fix"
41
+ }
44
42
  }
@@ -1 +0,0 @@
1
- aberlaas template