Skip to content

Commit

Permalink
🐌 Fix slug generation for .myst.json files (#1473)
Browse files Browse the repository at this point in the history
  • Loading branch information
agoose77 authored Aug 21, 2024
1 parent b994564 commit fab598e
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/spicy-dingos-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'myst-cli': patch
---

Fix slug generation for JSON paths
3 changes: 2 additions & 1 deletion packages/myst-cli/src/build/utils/defaultNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { ExportFormats } from 'myst-frontmatter';
import type { ISession } from '../../session/types.js';
import { selectPageSlug } from '../../store/selectors.js';
import { createSlug } from '../../utils/fileInfo.js';
import { parseFilePath } from '../../utils/resolveExtension.js';

/**
* Get default filename for saving export.
*
* This uses the project slug if available, or creates a new slug from the filename otherwise.
*/
export function getDefaultExportFilename(session: ISession, file: string, projectPath?: string) {
const { name } = path.parse(file);
const { name } = parseFilePath(file);
const slugFromProject = projectPath
? selectPageSlug(session.store.getState(), projectPath, file)
: undefined;
Expand Down
16 changes: 5 additions & 11 deletions packages/myst-cli/src/process/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { castSession } from '../session/cache.js';
import { warnings, watch } from '../store/reducers.js';
import type { PreRendererData, RendererData } from '../transforms/types.js';
import { logMessagesFromVFile } from '../utils/logging.js';
import { parseFilePath } from '../utils/resolveExtension.js';
import { addWarningForFile } from '../utils/addWarningForFile.js';
import { loadBibTeXCitationRenderers } from './citations.js';
import { parseMyst } from './myst.js';
Expand Down Expand Up @@ -233,7 +234,7 @@ export async function loadFile(
session.log.debug(toc(`loadFile: ${file} already loaded.`));
return cache.$getMdast(file)?.pre;
}
const ext = extension || path.extname(file).toLowerCase();
const ext = extension || parseFilePath(file).ext.toLowerCase();
let loadResult: LoadFileResult | undefined;
switch (ext) {
case '.md': {
Expand All @@ -258,16 +259,9 @@ export async function loadFile(
});
break;
}
case '.json': {
if (file.endsWith('.myst.json')) {
loadResult = loadMySTJSON(session, content, file);
break;
}
// This MUST be the final case before `default`, as
// we rely on falling through to the `default` case if
// a non-MyST JSON file is encountered here
//
// falls through
case '.myst.json': {
loadResult = loadMySTJSON(session, content, file);
break;
}
default:
addWarningForFile(session, file, 'Unrecognized extension', 'error', {
Expand Down
4 changes: 2 additions & 2 deletions packages/myst-cli/src/utils/fileInfo.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'node:path';
import type { PageSlugs } from '../project/types.js';
import { parseFilePath } from './resolveExtension.js';

function input2name(input: string, allowed: RegExp, join: string) {
let name = ${input}`
Expand Down Expand Up @@ -54,7 +54,7 @@ export function createTitle(s: string): string {
}

export function fileInfo(file: string, pageSlugs: PageSlugs): { slug: string; title: string } {
const { name } = path.parse(file);
const { name } = parseFilePath(file);
let slug = createSlug(name);
const title = createTitle(name);
if (pageSlugs[slug]) {
Expand Down
12 changes: 11 additions & 1 deletion packages/myst-cli/src/utils/resolveExtension.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it, beforeEach, vi } from 'vitest';
import memfs from 'memfs';
import { isValidFile, resolveExtension } from './resolveExtension';
import { isValidFile, resolveExtension, parseFilePath } from './resolveExtension';

vi.mock('fs', () => ({ ['default']: memfs.fs }));

Expand Down Expand Up @@ -76,3 +76,13 @@ describe('isValidFile', () => {
expect(isValidFile(f)).toBe(false);
});
});

describe('parseFilePath', () => {
it.each([
['/tmp/foo/bar.md', { dir: '/tmp/foo', name: 'bar', ext: '.md' }],
['/tmp/foo/bar/bat.txt', { dir: '/tmp/foo/bar', name: 'bat', ext: '.txt' }],
['/tmp/baz.myst.json', { dir: '/tmp', name: 'baz', ext: '.myst.json' }],
])('%s parses properly', (path, result) => {
expect(parseFilePath(path)).toEqual(result);
});
});
20 changes: 20 additions & 0 deletions packages/myst-cli/src/utils/resolveExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,26 @@ export function isValidFile(file: string): boolean {
return VALID_FILE_EXTENSIONS.some((ext) => lowerCasePath.endsWith(ext));
}

/**
* Parse a file path into its constituent parts
*
* Handles multi-dot extensions
*/
export function parseFilePath(file: string): {
dir: string;
name: string;
ext: string;
} {
const { dir, base, ext: baseExt, name: baseName } = path.parse(file);
for (const ext of VALID_FILE_EXTENSIONS) {
if (base.endsWith(ext)) {
const name = base.slice(0, base.length - ext.length);
return { dir, name, ext };
}
}
return { dir, name: baseName, ext: baseExt };
}

/**
* Given a file with resolved path and filename, match to md, ipynb, or tex files
*
Expand Down

0 comments on commit fab598e

Please sign in to comment.