Skip to content

Commit

Permalink
πŸ“ Add enumerated ruleId to all errors/warnings in the redux store (#…
Browse files Browse the repository at this point in the history
…616)

* πŸ“€ Export buildHtml function

* πŸ“ Add ruleId to file warnings in redux store

* πŸ“ Add rules to myst-cli errors/warnings

* 🍿 Changeset

* πŸ”§ Fix vfile in tests

* πŸ“ Add rules to citation updates

* 🧹 Lint cleanup
  • Loading branch information
fwkoch committed Sep 25, 2023
1 parent 757f1fe commit b74fb3c
Show file tree
Hide file tree
Showing 71 changed files with 907 additions and 257 deletions.
7 changes: 7 additions & 0 deletions .changeset/brown-countries-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'myst-transforms': patch
'myst-common': patch
'myst-cli': patch
---

Add ruleId to file warnings in redux store
17 changes: 17 additions & 0 deletions .changeset/healthy-news-travel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'myst-directives': patch
'myst-transforms': patch
'myst-cli-utils': patch
'jats-to-myst': patch
'myst-to-docx': patch
'myst-to-jats': patch
'myst-common': patch
'myst-parser': patch
'myst-to-tex': patch
'tex-to-myst': patch
'myst-roles': patch
'myst-to-md': patch
'myst-cli': patch
---

Add ruleIds to all errors/warnings across myst-cli
5 changes: 4 additions & 1 deletion packages/jats-to-myst/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { doi } from 'doi-utils';
import type { Plugin } from 'unified';
import { VFile } from 'vfile';
import type { MessageInfo, GenericNode, GenericParent } from 'myst-common';
import { toText, copyNode, fileError } from 'myst-common';
import { toText, copyNode, fileError, RuleId } from 'myst-common';
import { select, selectAll } from 'unist-util-select';
import { u } from 'unist-builder';
import { RefType } from 'jats-tags';
Expand Down Expand Up @@ -376,6 +376,7 @@ export class JatsParser implements IJatsParser {
...opts,
node,
source: source ? `jats-to-myst:${source}` : 'jats-to-myst',
ruleId: RuleId.jatsParses,
});
}

Expand All @@ -384,6 +385,7 @@ export class JatsParser implements IJatsParser {
...opts,
node,
source: source ? `jats-to-myst:${source}` : 'jats-to-myst',
ruleId: RuleId.jatsParses,
});
}

Expand Down Expand Up @@ -417,6 +419,7 @@ export class JatsParser implements IJatsParser {
this.unhandled.push(child.type);
fileError(this.file, `Unhandled JATS conversion for node of "${child.type}"`, {
source: 'myst-to-jats',
ruleId: RuleId.jatsParses,
});
}
});
Expand Down
4 changes: 2 additions & 2 deletions packages/jats-to-myst/src/transforms/admonitions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Plugin } from 'unified';
import type { Heading } from 'myst-spec';
import type { GenericParent } from 'myst-common';
import { fileWarn } from 'myst-common';
import { RuleId, fileWarn } from 'myst-common';
import { select, selectAll } from 'unist-util-select';
import { remove } from 'unist-util-remove';
import { Tags } from 'jats-tags';
Expand All @@ -14,7 +14,7 @@ export function admonitionTransform(tree: GenericParent, file: VFile) {
captions.forEach((caption) => {
const title = select(Tags.title, caption) as GenericParent;
if (!title) {
fileWarn(file, '', { node: caption });
fileWarn(file, '', { node: caption, ruleId: RuleId.jatsParses });
return;
}
caption.type = 'admonitionTitle';
Expand Down
37 changes: 29 additions & 8 deletions packages/myst-cli-utils/src/filesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ export function writeFileToFolder(
*
* If hashed file already exists, this does nothing
*/
export function hashAndCopyStaticFile(session: ISession, file: string, writeFolder: string) {
export function hashAndCopyStaticFile(
session: ISession,
file: string,
writeFolder: string,
errorLogFn?: (m: string) => void,
) {
const { name, ext } = path.parse(file);
const fd = fs.openSync(file, 'r');
const { mtime, size } = fs.fstatSync(fd);
Expand All @@ -42,7 +47,8 @@ export function hashAndCopyStaticFile(session: ISession, file: string, writeFold
fs.copyFileSync(file, destination);
session.log.debug(`File successfully copied: ${file}`);
} catch {
session.log.error(`Error copying file: ${file}`);
const message = `Error copying file to ${writeFolder}`;
errorLogFn ? errorLogFn(message) : session.log.error(message);
return undefined;
}
}
Expand All @@ -54,10 +60,17 @@ export function hashAndCopyStaticFile(session: ISession, file: string, writeFold
*
* If "file" is not inside "from" folder, the file is not copied.
*/
export function copyFileMaintainPath(session: ISession, file: string, from: string, to: string) {
export function copyFileMaintainPath(
session: ISession,
file: string,
from: string,
to: string,
errorLogFn?: (m: string) => void,
) {
// File must be inside "from" folder
if (!path.resolve(file).startsWith(path.resolve(from))) {
session.log.error(`Cannot include files outside of 'from' directory: ${file}\n\n`);
const message = `Cannot include files outside of 'from' directory: ${file}\n\n`;
errorLogFn ? errorLogFn(message) : session.log.error(message);
return undefined;
}
const destination = path.resolve(to, path.relative(from, file));
Expand All @@ -68,7 +81,8 @@ export function copyFileMaintainPath(session: ISession, file: string, from: stri
session.log.debug(`File successfully copied: ${file}`);
return destination;
} catch {
session.log.error(`Error copying file: ${file}`);
const message = `Error copying file to: ${to}`;
errorLogFn ? errorLogFn(message) : session.log.error(message);
return undefined;
}
}
Expand All @@ -78,10 +92,16 @@ export function copyFileMaintainPath(session: ISession, file: string, from: stri
*
* If a file already exists with the basename of "file" inside "to" directory, it is not copied.
*/
export function copyFileToFolder(session: ISession, file: string, to: string) {
export function copyFileToFolder(
session: ISession,
file: string,
to: string,
errorLogFn?: (m: string) => void,
) {
const destination = path.join(to, path.basename(file));
if (fs.existsSync(destination)) {
session.log.error(`File already exists with name: ${path.basename(file)}`);
const message = `File already exists with name: ${path.basename(file)}`;
errorLogFn ? errorLogFn(message) : session.log.error(message);
}
const destinationFolder = path.dirname(destination);
try {
Expand All @@ -90,7 +110,8 @@ export function copyFileToFolder(session: ISession, file: string, to: string) {
session.log.debug(`File successfully copied: ${file}`);
return destination;
} catch {
session.log.error(`Error copying file: ${file}`);
const message = `Error copying file to: ${to}`;
errorLogFn ? errorLogFn(message) : session.log.error(message);
return undefined;
}
}
3 changes: 2 additions & 1 deletion packages/myst-cli/src/build/clean.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fs from 'node:fs';
import path from 'node:path';
import chalk from 'chalk';
import inquirer from 'inquirer';
import { ExportFormats } from 'myst-frontmatter';
import type { ISession } from '../session/index.js';
Expand Down Expand Up @@ -150,7 +151,7 @@ export async function clean(session: ISession, files: string[], opts: CleanOptio
}
pathsToDelete = deduplicatePaths(pathsToDelete.filter((p) => fs.existsSync(p))).sort();
if (pathsToDelete.length === 0) {
session.log.warn(`🧹 Your folders are already so clean! ✨`);
session.log.info(chalk.yellow(`🧹 Your folders are already so clean! ✨`));
return;
}
session.log.info(`Deleting all the following paths:\n\n - ${pathsToDelete.join('\n - ')}\n`);
Expand Down
1 change: 1 addition & 0 deletions packages/myst-cli/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './site/index.js';
export * from './tex/index.js';
export * from './types.js';
export * from './utils/index.js';
export * from './html/index.js';
83 changes: 69 additions & 14 deletions packages/myst-cli/src/build/meca/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import AdmZip from 'adm-zip';
import { glob } from 'glob';
import mime from 'mime-types';
import { copyFileMaintainPath, copyFileToFolder, isDirectory, tic } from 'myst-cli-utils';
import { RuleId, fileError, fileWarn } from 'myst-common';
import { ExportFormats } from 'myst-frontmatter';
import type { LinkTransformer } from 'myst-transforms';
import { selectAll } from 'unist-util-select';
import { VFile } from 'vfile';
import { js2xml } from 'xml-js';
import { findCurrentProjectAndLoad } from '../../config.js';
import { loadFile } from '../../process/index.js';
Expand All @@ -15,7 +17,7 @@ import { loadProjectFromDisk, writeTocFromProject } from '../../project/index.js
import { castSession } from '../../session/index.js';
import type { ISession } from '../../session/types.js';
import { selectors } from '../../store/index.js';
import { createTempFolder } from '../../utils/index.js';
import { createTempFolder, logMessagesFromVFile } from '../../utils/index.js';
import { runJatsExport } from '../jats/single.js';
import type { ExportWithOutput, ExportOptions } from '../types.js';
import {
Expand Down Expand Up @@ -67,6 +69,7 @@ async function copyFilesFromConfig(
projectPath: string,
mecaFolder: string,
manifestItems: ManifestItem[],
errorLogFn: (m: string) => void,
) {
const projConfig = selectors.selectLocalProjectConfig(session.store.getState(), projectPath);
const entries: { itemType: string; entry: string }[] = [
Expand All @@ -91,6 +94,7 @@ async function copyFilesFromConfig(
match,
projectPath,
bundleFolder(mecaFolder),
errorLogFn,
);
addManifestItem(manifestItems, itemType, mecaFolder, destination);
});
Expand All @@ -108,6 +112,7 @@ async function copyDependentFiles(
projectPath: string,
mecaFolder: string,
manifestItems: ManifestItem[],
errorLogFn: (m: string) => void,
) {
const cache = castSession(session);
if (!cache.$mdast[sourceFile]) {
Expand All @@ -127,7 +132,13 @@ async function copyDependentFiles(
.map((file) => path.resolve(path.dirname(sourceFile), file))
.filter((file) => fs.existsSync(file));
filesToCopy.forEach((file) => {
const dependency = copyFileMaintainPath(session, file, projectPath, bundleFolder(mecaFolder));
const dependency = copyFileMaintainPath(
session,
file,
projectPath,
bundleFolder(mecaFolder),
errorLogFn,
);
addManifestItem(manifestItems, 'article-source', mecaFolder, dependency);
});
}
Expand Down Expand Up @@ -188,6 +199,11 @@ export async function runMecaExport(
) {
const toc = tic();
const { output, article } = exportOptions;
const vfile = new VFile();
vfile.path = output;
const fileCopyErrorLogFn = (m: string) => {
fileError(vfile, m, { ruleId: RuleId.mecaFilesCopied });
};
if (clean) cleanOutput(session, output);
const mecaFolder = createTempFolder(session);
const manifestItems: ManifestItem[] = [];
Expand Down Expand Up @@ -222,28 +238,43 @@ export async function runMecaExport(
});
}
} else if (jatsExports.length === 0) {
session.log.warn(`No JATS export found for inclusion with MECA bundle`);
fileWarn(vfile, `No JATS export found for inclusion with MECA bundle`, {
ruleId: RuleId.mecaIncludesJats,
});
} else if (jatsExports.length > 1) {
session.log.warn(
fileWarn(
vfile,
`Multiple JATS exports found for inclusion with MECA bundle\nConventionally, MECA should only have one JATS article`,
{
ruleId: RuleId.mecaIncludesJats,
},
);
}
// Copy any existing JATS exports (and dependent files)
jatsExports.forEach(({ output: jatsOutput }) => {
if (!fs.existsSync(jatsOutput)) {
session.log.warn(
fileWarn(
vfile,
`Other exports must be built prior to building MECA bundle\nTo resolve this, run: myst build --all`,
{
ruleId: RuleId.mecaExportsBuilt,
},
);
}
const jatsDest = copyFileToFolder(session, jatsOutput, mecaFolder);
const jatsDest = copyFileToFolder(session, jatsOutput, mecaFolder, fileCopyErrorLogFn);
if (jatsDest) {
addManifestItem(manifestItems, 'article-metadata', mecaFolder, jatsDest);
}
const jatsFiles = path.join(path.dirname(jatsOutput), 'files');
if (fs.existsSync(jatsFiles)) {
fs.readdirSync(jatsFiles).forEach((file) => {
const sourceFile = path.join(jatsFiles, file);
const fileDest = copyFileToFolder(session, sourceFile, path.join(mecaFolder, 'files'));
const fileDest = copyFileToFolder(
session,
sourceFile,
path.join(mecaFolder, 'files'),
fileCopyErrorLogFn,
);
addManifestItem(manifestItems, 'article-supporting-file', mecaFolder, fileDest);
});
}
Expand All @@ -259,11 +290,20 @@ export async function runMecaExport(
);
manuscriptExports.forEach(({ output: manuscriptOutput }) => {
if (!fs.existsSync(manuscriptOutput)) {
session.log.warn(
fileWarn(
vfile,
`Other exports must be built prior to building MECA bundle\nTo resolve this, run: myst build --all`,
{
ruleId: RuleId.mecaExportsBuilt,
},
);
}
const manuscriptDest = copyFileToFolder(session, manuscriptOutput, mecaFolder);
const manuscriptDest = copyFileToFolder(
session,
manuscriptOutput,
mecaFolder,
fileCopyErrorLogFn,
);
addManifestItem(manifestItems, 'manuscript', mecaFolder, manuscriptDest);
});
const project = projectPath
Expand All @@ -277,13 +317,14 @@ export async function runMecaExport(
selectors.selectLocalConfigFile(session.store.getState(), projectPath),
projectPath,
bundle,
fileCopyErrorLogFn,
);
addManifestItem(manifestItems, 'article-source', mecaFolder, configDest);
// Copy requirements and resources
await copyFilesFromConfig(session, projectPath, mecaFolder, manifestItems);
await copyFilesFromConfig(session, projectPath, mecaFolder, manifestItems, fileCopyErrorLogFn);
// Copy table of contents or write one if it does not exist
if (fs.existsSync(path.join(projectPath, '_toc.yml'))) {
copyFileToFolder(session, path.join(projectPath, '_toc.yml'), bundle);
copyFileToFolder(session, path.join(projectPath, '_toc.yml'), bundle, fileCopyErrorLogFn);
} else {
writeTocFromProject(project, bundle);
}
Expand All @@ -304,13 +345,26 @@ export async function runMecaExport(
];
await Promise.all(
projectPages.map(async ({ page, itemType }) => {
const pageDest = copyFileMaintainPath(session, page, projectPath, bundle);
const pageDest = copyFileMaintainPath(
session,
page,
projectPath,
bundle,
fileCopyErrorLogFn,
);
addManifestItem(manifestItems, itemType, mecaFolder, pageDest);
await copyDependentFiles(session, page, projectPath, mecaFolder, manifestItems);
await copyDependentFiles(
session,
page,
projectPath,
mecaFolder,
manifestItems,
fileCopyErrorLogFn,
);
}),
);
} else if (article) {
const articleDest = copyFileToFolder(session, article, bundle);
const articleDest = copyFileToFolder(session, article, bundle, fileCopyErrorLogFn);
addManifestItem(manifestItems, 'article-source', mecaFolder, articleDest);
}
if (fs.existsSync(bundle)) {
Expand All @@ -326,6 +380,7 @@ export async function runMecaExport(
const zip = new AdmZip();
zip.addLocalFolder(mecaFolder);
zip.writeZip(output);
logMessagesFromVFile(session, vfile);
session.log.info(toc(`🀐 MECA output copied and zipped to ${output} in %s`));
}

Expand Down

0 comments on commit b74fb3c

Please sign in to comment.