Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"plugins": ["@trivago/prettier-plugin-sort-imports"],
"printWidth": 80,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming this is configuring line width: is 80 the convention? We've been using 88 or 100, because 80 was a bit too restrictive/short

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not sure what is considered standard, It's 80 in cell-catalog. I'm looking around now and seeing 100 some places (BFF), and 120 in other (vole-app, tfe), so 80 does seem small.

I might just go ahead with this for now and I'm happy to revisit it later. I do wonder if style/formatting guidelines are a good topic for reusable workflows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for pre-commit hooks we can attach it. POC for that is ongoing in cell-catalog we are trying to get lefthook to work in place of husky as it's friendlier to polyglot repos.

"tabWidth": 4,
"importOrder": ["^react", "^gatsby", "^[^./]", "^[./]"],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true
}
122 changes: 61 additions & 61 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const read = (p) => fs.readFileSync(path.join(__dirname, p), 'utf8')
* They serve as single source of truth, can be added/edited via CMS,
* and are referenced by other markdown files.
*/
const DATA_ONLY_PAGES = ['software', 'dataset', 'allenite', 'program']
const DATA_ONLY_PAGES = ["software", "dataset", "allenite", "program"];

exports.createSchemaCustomization = ({ actions, schema }) => {
const { createTypes } = actions
Expand Down Expand Up @@ -60,57 +60,55 @@ exports.createSchemaCustomization = ({ actions, schema }) => {
* functions where possible
*/
exports.createResolvers = ({ createResolvers }) => {
createResolvers({
MarkdownRemark: {
fields: {
resolve: (source) => ({
slug: source.fields?.slug || '/',
}),
},
},
MarkdownRemark: {
fields: {
resolve: (source) => ({
slug: source.fields?.slug || '/',
}),
},
},
Frontmatter: {
description: {
resolve: (source) =>
stringWithDefault(source.description, 'No description provided.'),
},
title: {
resolve: (source) =>
stringWithDefault(source.title, 'No title provided.'),
},
materialsAndMethods: {
resolve: (source) => {
const raw = source.materialsAndMethods
const current = {
dataset: null,
cellLines: [],
protocols: [],
software: [],
}

if (!raw || typeof raw !== 'object') {
return current
}

const resolvedDatasetSlug = resolveSlug(raw.dataset, DATASET_PATH)
current.dataset = resolvedDatasetSlug
current.cellLines = resolveToArray(raw.cellLines)
current.protocols = resolveToArray(raw.protocols)
current.software = resolveSoftwareTools(raw.software)
current.software = resolveSoftwareTools(raw.software)

return current
createResolvers({
MarkdownRemark: {
fields: {
resolve: (source) => ({
slug: source.fields?.slug || "/",
}),
},
},
},
},
})
}
Frontmatter: {
description: {
resolve: (source) =>
stringWithDefault(
source.description,
"No description provided.",
),
},
title: {
resolve: (source) =>
stringWithDefault(source.title, "No title provided."),
},
materialsAndMethods: {
resolve: (source) => {
const raw = source.materialsAndMethods;
const current = {
dataset: null,
cellLines: [],
protocols: [],
software: [],
};

if (!raw || typeof raw !== "object") {
return current;
}

const resolvedDatasetSlug = resolveSlug(
raw.dataset,
DATASET_PATH,
);
current.dataset = resolvedDatasetSlug;
current.cellLines = resolveToArray(raw.cellLines);
current.protocols = resolveToArray(raw.protocols);
current.software = resolveSoftwareTools(raw.software);

return current;
},
},
},
});
};

/**
* Create pages for markdown files based on their templateKey frontmatter.
Expand Down Expand Up @@ -161,16 +159,18 @@ exports.createPages = ({ actions, graphql }) => {
return
}

createPage({
path: edge.node.fields.slug,
tags: edge.node.frontmatter.tags,
component: path.resolve(`src/templates/${String(templateKey)}.tsx`),
// additional data can be passed via context
context: {
id,
},
})
})
createPage({
path: edge.node.fields.slug,
tags: edge.node.frontmatter.tags,
component: path.resolve(
`src/templates/${String(templateKey)}.tsx`,
),
// additional data can be passed via context
context: {
id,
},
});
});

// Tag pages:
let tags = []
Expand Down
2 changes: 1 addition & 1 deletion gatsbyutils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ const SOFTWARE_PATH = `software`;
module.exports = {
DATASET_PATH,
SOFTWARE_PATH,
};
};
6 changes: 3 additions & 3 deletions gatsbyutils/gatsby-resolver-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const resolveSoftwareTools = (rawSoftware) => {
softwareTool: resolveSlug(item.softwareTool, SOFTWARE_PATH),
customDescription: stringWithDefault(
item.customDescription,
null
null,
),
};
}
Expand All @@ -66,7 +66,7 @@ const resolveSlug = (id, directory) => {
if (!id) return null;
const slugPart = slugify(id, { lower: true, strict: true }).replace(
/^\/+|\/+$/g,
""
"",
); // Slugify and remove leading/trailing slashes
return `/${directory}/${slugPart}/`;
};
Expand All @@ -76,4 +76,4 @@ module.exports = {
resolveToArray,
resolveSlug,
resolveSoftwareTools,
};
};
87 changes: 45 additions & 42 deletions gatsbyutils/test/gatsby-resolver-utils.test.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,112 @@
import { describe, it, expect } from 'vitest';
import { resolveSlug, resolveSoftwareTools } from '../gatsby-resolver-utils';
import { DATASET_PATH, SOFTWARE_PATH } from '../constants';
import { describe, expect, it } from "vitest";

describe('resolveSlug', () => {
it('should return null when id is falsy', () => {
expect(resolveSlug(null, 'software')).toBe(null);
expect(resolveSlug(undefined, 'software')).toBe(null);
expect(resolveSlug('', 'software')).toBe(null);
import { DATASET_PATH, SOFTWARE_PATH } from "../constants";
import { resolveSlug, resolveSoftwareTools } from "../gatsby-resolver-utils";

describe("resolveSlug", () => {
it("should return null when id is falsy", () => {
expect(resolveSlug(null, "software")).toBe(null);
expect(resolveSlug(undefined, "software")).toBe(null);
expect(resolveSlug("", "software")).toBe(null);
});

it('should build a slug from id and directory', () => {
it("should build a slug from id and directory", () => {
expect(resolveSlug("released-emt-dataset", DATASET_PATH)).toBe(
"/dataset/released-emt-dataset/"
"/dataset/released-emt-dataset/",
);
});

it('should slugify the id to lowercase', () => {
it("should slugify the id to lowercase", () => {
expect(resolveSlug("UPPERCASE", DATASET_PATH)).toBe(
"/dataset/uppercase/"
"/dataset/uppercase/",
);
});

it('should handle special characters in id', () => {
it("should handle special characters in id", () => {
expect(resolveSlug("Tool & Library", SOFTWARE_PATH)).toBe(
"/software/tool-and-library/"
"/software/tool-and-library/",
);
expect(resolveSlug("Some/Path/Name", SOFTWARE_PATH)).toBe(
"/software/somepathname/"
"/software/somepathname/",
);
});

it('should handle ids with leading/trailing spaces', () => {
expect(resolveSlug(' trimmed ', 'software')).toBe('/software/trimmed/');
it("should handle ids with leading/trailing spaces", () => {
expect(resolveSlug(" trimmed ", "software")).toBe(
"/software/trimmed/",
);
});
});

describe('resolveSoftwareTools', () => {
it('should return empty array for non-array inputs', () => {
describe("resolveSoftwareTools", () => {
it("should return empty array for non-array inputs", () => {
expect(resolveSoftwareTools(null)).toEqual([]);
expect(resolveSoftwareTools(undefined)).toEqual([]);
expect(resolveSoftwareTools('string')).toEqual([]);
expect(resolveSoftwareTools("string")).toEqual([]);
expect(resolveSoftwareTools({})).toEqual([]);
expect(resolveSoftwareTools(123)).toEqual([]);
});

it('should return empty array for empty array', () => {
it("should return empty array for empty array", () => {
expect(resolveSoftwareTools([])).toEqual([]);
});

it('should filter out invalid items', () => {
const input = [null, undefined, 'string', {}, { other: 'prop' }];
it("should filter out invalid items", () => {
const input = [null, undefined, "string", {}, { other: "prop" }];
expect(resolveSoftwareTools(input)).toEqual([]);
});

it('should transform valid items with softwareTool', () => {
const input = [{ softwareTool: 'Simularium' }];
it("should transform valid items with softwareTool", () => {
const input = [{ softwareTool: "Simularium" }];
expect(resolveSoftwareTools(input)).toEqual([
{
softwareTool: '/software/simularium/',
softwareTool: "/software/simularium/",
customDescription: null,
},
]);
});

it('should preserve customDescription when provided', () => {
it("should preserve customDescription when provided", () => {
const input = [
{
softwareTool: 'Simularium',
customDescription: 'Custom description here',
softwareTool: "Simularium",
customDescription: "Custom description here",
},
];
expect(resolveSoftwareTools(input)).toEqual([
{
softwareTool: '/software/simularium/',
customDescription: 'Custom description here',
softwareTool: "/software/simularium/",
customDescription: "Custom description here",
},
]);
});

it('should return null for empty customDescription', () => {
const input = [{ softwareTool: 'Simularium', customDescription: '' }];
it("should return null for empty customDescription", () => {
const input = [{ softwareTool: "Simularium", customDescription: "" }];
expect(resolveSoftwareTools(input)).toEqual([
{
softwareTool: '/software/simularium/',
softwareTool: "/software/simularium/",
customDescription: null,
},
]);
});

it('should handle mixed valid and invalid items', () => {
it("should handle mixed valid and invalid items", () => {
const input = [
null,
{ softwareTool: 'Simularium' },
{ other: 'invalid' },
{ softwareTool: 'TFE', customDescription: 'Time explorer' },
{ softwareTool: "Simularium" },
{ other: "invalid" },
{ softwareTool: "TFE", customDescription: "Time explorer" },
];
expect(resolveSoftwareTools(input)).toEqual([
{
softwareTool: '/software/simularium/',
softwareTool: "/software/simularium/",
customDescription: null,
},
{
softwareTool: '/software/tfe/',
customDescription: 'Time explorer',
softwareTool: "/software/tfe/",
customDescription: "Time explorer",
},
]);
});
});
});
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@
"build": "npm run clean && gatsby build",
"develop": "npm run clean && gatsby develop",
"serve": "gatsby serve",
"format": "prettier --trailing-comma es5 --no-semi --single-quote --write \"{gatsby-*.js,src/**/*.js}\"",
"format": "prettier \"{src,gatsbyutils,netlify}/**/*.{ts,tsx,js,jsx}\" gatsby-*.js --write",
"formatCheck": "prettier \"{src,gatsbyutils,netlify}/**/*.{ts,tsx,js,jsx}\" gatsby-*.js --check",
"test": "vitest",
"dev": "npx concurrently \"npx netlify-cms-proxy-server\" \"npm start -- --progress\""
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
"@types/antd": "^1.0.0",
"@types/node": "^20.11.20",
"@types/react": "^18.2.59",
Expand All @@ -62,7 +64,7 @@
"gatsby-plugin-postcss": "^6.13.1",
"netlify-cli": "^17.15.7",
"postcss": "^8.4.35",
"prettier": "^2.0.5",
"prettier": "^3.8.1",
"typescript": "^5.3.3",
"typescript-plugin-css-modules": "^5.1.0"
},
Expand Down
Loading