Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 36 additions & 33 deletions packages/myst-cli/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,31 +179,40 @@ async function getValidatedConfigsFromFile(
const projectOpts = configValidationOpts(vfile, 'config.project', RuleId.validProjectConfig);
let extend: string[] | undefined;
if (conf.extend) {
extend = await Promise.all(
(
validateList(
conf.extend,
{ coerce: true, ...incrementOptions('extend', opts) },
(item, index) => {
return validateString(item, incrementOptions(`extend.${index}`, opts));
},
) ?? []
).map(async (extendFile) => {
const resolvedFile = await resolveToAbsolute(session, dirname(file), extendFile, {
allowRemote: true,
});
return resolvedFile;
}),
);
const extendItems =
validateList(
conf.extend,
{ coerce: true, ...incrementOptions('extend', opts) },
(item, index) => {
return validateString(item, incrementOptions(`extend.${index}`, opts));
},
) ?? [];

extend = (
await Promise.all(
extendItems.map(async (extendFile) => {
try {
return await resolveToAbsolute(session, dirname(file), extendFile, {
allowRemote: true,
});
} catch (err) {
throw new Error(
`Unable to locate config file during "config.extend" resolution: ${extendFile}`,
);
}
}),
)
).filter((foo) => foo) as any;
stack = [...(stack ?? []), file];
await Promise.all(
(extend ?? []).map(async (extFile) => {
if (stack?.includes(extFile)) {
fileError(vfile, 'Circular dependency encountered during "config.extend" resolution', {
ruleId: RuleId.validConfigStructure,
note: [...stack, extFile].map((f) => resolveToRelative(session, '.', f)).join(' > '),
});
return;
const path = [...stack, extFile]
.map((f) => resolveToRelative(session, '.', f))
.join(' > ');
throw new Error(
`Circular dependency encountered during "config.extend" resolution: ${path}`,
);
}
const { site: extSite, project: extProject } = await getValidatedConfigsFromFile(
session,
Expand Down Expand Up @@ -297,7 +306,6 @@ export async function resolveToAbsolute(
allowRemote?: boolean;
},
) {
let message: string | undefined;
if (opts?.allowRemote && isUrl(relativePath)) {
const cacheFilename = `config-item-${computeHash(relativePath)}${extname(new URL(relativePath).pathname)}`;
if (!loadFromCache(session, cacheFilename, { maxAge: 30 })) {
Expand All @@ -306,10 +314,10 @@ export async function resolveToAbsolute(
if (resp.ok) {
writeToCache(session, cacheFilename, Buffer.from(await resp.arrayBuffer()));
} else {
message = `Bad response from config URL: ${relativePath}`;
throw new Error(`Bad response from config URL: ${relativePath}`);
}
} catch {
message = `Error fetching config URL: ${relativePath}`;
throw new Error(`Error fetching config URL: ${relativePath}`);
}
}
relativePath = cachePath(session, cacheFilename);
Expand All @@ -319,12 +327,10 @@ export async function resolveToAbsolute(
if (opts?.allowNotExist || fs.existsSync(absPath)) {
return absPath;
}
message = message ?? `Does not exist as local path: ${absPath}`;
throw new Error(`Does not exist as local path: ${absPath}`);
} catch {
message = message ?? `Unable to resolve as local path: ${relativePath}`;
throw new Error(`Unable to resolve as local path: ${relativePath}`);
}
session.log.debug(message);
return relativePath;
}

function resolveToRelative(
Expand All @@ -335,18 +341,15 @@ function resolveToRelative(
allowNotExist?: boolean;
},
) {
let message: string;
try {
if (opts?.allowNotExist || fs.existsSync(absPath)) {
// If it is the same path, use a '.'
return relative(basePath, absPath) || '.';
}
message = `Does not exist as local path: ${absPath}`;
throw new Error(`Does not exist as local path: ${absPath}`);
} catch {
message = `Unable to resolve as relative path: ${absPath}`;
throw new Error(`Unable to resolve as relative path: ${absPath}`);
}
session.log.debug(message);
return absPath;
}

async function resolveSiteConfigPaths(
Expand Down
1 change: 1 addition & 0 deletions packages/myst-common/src/rule-severities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { RuleId } from './ruleids.js';
export const RULE_DEFAULT_SEVERITY: Record<RuleId, 'error' | 'warn'> = {
// Frontmatter rules
[RuleId.validConfigStructure]: 'error', // fileError, validationOpts in packages/myst-cli/src/config.ts
[RuleId.locateExtendedConfig]: 'error', // fileError in packages/myst-cli/src/config.ts
[RuleId.siteConfigExists]: 'error', // addWarningForFile in packages/myst-cli/src/config.ts
[RuleId.projectConfigExists]: 'warn', // addWarningForFile in packages/myst-cli/src/project/load.ts
[RuleId.validSiteConfig]: 'error', // Uses both error (2×) and warn (1×); addWarningForFile, validationOpts in packages/myst-cli/src/bu...
Expand Down
2 changes: 2 additions & 0 deletions packages/myst-common/src/ruleids.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export enum RuleId {
// Frontmatter rules
validConfigStructure = 'valid-config-structure',
locateExtendedConfig = 'locate-extended-config',
siteConfigExists = 'site-config-exists',
projectConfigExists = 'project-config-exists',
validSiteConfig = 'valid-site-config',
Expand Down Expand Up @@ -113,6 +114,7 @@ export enum RuleId {
export const RULE_ID_DESCRIPTIONS: Record<RuleId, string> = {
// Frontmatter rules
[RuleId.validConfigStructure]: 'Configuration file structure is valid and can be parsed',
[RuleId.locateExtendedConfig]: 'Extending configuration file can be located.',
[RuleId.siteConfigExists]: 'Site configuration is found in project',
[RuleId.projectConfigExists]: 'Project configuration file exists in the directory',
[RuleId.validSiteConfig]: 'Site configuration passes validation',
Expand Down
Loading