Skip to content

Commit 1fb613f

Browse files
kennethkalmerclaude
andcommitted
Remove textile and ERB processing code
Remove all code that processes textile files and ERB templates from the build pipeline. Textile content files remain in the repository but are no longer parsed or rendered. Changes: - Remove textile-js imports and usage from createPages and onCreateNode - Remove ERB processing from pre-parser pipeline - Remove textile-partials handling from transform utilities - Update parser steps to remove ERB and textile workarounds After this commit, the build generates 241 MDX pages with no textile processing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 980ce59 commit 1fb613f

File tree

6 files changed

+5
-272
lines changed

6 files changed

+5
-272
lines changed

data/cli-functionality/parser-steps/pre-parser.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { removeExternalClassFromLinks } from '../../transform/pre-parser/remove-external-class-from-links';
2-
import { replaceERB } from '../../transform/pre-parser/erbjs';
32
import { addMinimizedIndent, addMinimizeForHeadings, stripComments } from '../../transform/pre-parser/semantic';
4-
import { removeNewlinesBeforeClosingTags, recursivelyProcessDivs } from '../../transform/pre-parser';
3+
import { removeNewlinesBeforeClosingTags } from '../../transform/pre-parser';
54
import {
65
addLanguageSupportForBlockQuotes,
76
addLanguageSupportForGithubStyleCode,
@@ -17,10 +16,6 @@ export const preParserSteps: Step[] = [
1716
{
1817
fn: removeExternalClassFromLinks,
1918
},
20-
{
21-
fn: replaceERB,
22-
description: `Replaces Ruby templating code`,
23-
},
2419
{
2520
fn: stripComments,
2621
},
@@ -56,8 +51,4 @@ export const preParserSteps: Step[] = [
5651
{
5752
fn: addLanguageSupportForHeadings,
5853
},
59-
{
60-
fn: recursivelyProcessDivs,
61-
description: `Divs across multiple lines pose an issue for textile-js.\nWe detect these divs and process the internal textile separately, marking it as 'notextile' in the process.`,
62-
},
6354
];

data/createPages/index.ts

Lines changed: 0 additions & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import path from 'path';
2-
import textile from 'textile-js';
32
import { identity } from 'lodash';
43
import { safeFileExists } from './safeFileExists';
5-
import { flattenContentOrderedList, maybeRetrievePartial } from '../transform';
6-
import { postParser } from '../transform/post-parser';
7-
import { htmlParser } from '../html-parser';
84
import { createLanguagePageVariants } from './createPageVariants';
95
import { LATEST_ABLY_API_VERSION_STRING } from '../transform/constants';
106
import { createContentMenuDataFromPage } from './createContentMenuDataFromPage';
@@ -20,59 +16,6 @@ const documentTemplate = path.resolve(`src/templates/document.tsx`);
2016
const apiReferenceTemplate = path.resolve(`src/templates/apiReference.tsx`);
2117
const examplesTemplate = path.resolve(`src/templates/examples.tsx`);
2218

23-
interface Edge {
24-
node: {
25-
slug: string;
26-
version?: string;
27-
contentOrderedList: Array<{
28-
data: string;
29-
type: string;
30-
}>;
31-
meta?: {
32-
redirect_from?: string[];
33-
};
34-
};
35-
}
36-
37-
interface DocumentQueryResult {
38-
allError: {
39-
nodes: {
40-
message: string;
41-
}[];
42-
};
43-
allFileHtml: {
44-
edges: {
45-
node: {
46-
slug: string;
47-
contentOrderedList: {
48-
data: string;
49-
type: string;
50-
}[];
51-
meta: {
52-
redirect_from?: string[];
53-
};
54-
};
55-
}[];
56-
};
57-
}
58-
59-
interface ApiReferenceQueryResult {
60-
allFileHtml: {
61-
edges: {
62-
node: {
63-
slug: string;
64-
contentOrderedList: {
65-
data: string;
66-
type: string;
67-
}[];
68-
meta: {
69-
redirect_from?: string[];
70-
};
71-
};
72-
}[];
73-
};
74-
}
75-
7619
interface ExampleQueryResult {
7720
allExampleFile: {
7821
nodes: {
@@ -102,82 +45,6 @@ interface MdxRedirectsQueryResult {
10245
}
10346

10447
export const createPages: GatsbyNode['createPages'] = async ({ graphql, actions: { createPage, createRedirect } }) => {
105-
/**
106-
* It's not ideal to have:
107-
* * the reusable function `documentCreator` defined inline like this
108-
* * so much of `documentCreator` being imperative processing of data
109-
* - but Gatsby throws horrible unrelated errors (from onCreateNode) if
110-
* you try to extract any of this functionality into an independent composable
111-
* and testable function.
112-
*/
113-
114-
// DOCUMENT TEMPLATE
115-
const documentResult = await graphql<DocumentQueryResult>(`
116-
query {
117-
allError {
118-
nodes {
119-
message
120-
}
121-
}
122-
allFileHtml(filter: { articleType: { eq: "document" } }) {
123-
edges {
124-
node {
125-
slug
126-
contentOrderedList {
127-
data
128-
type
129-
}
130-
meta {
131-
redirect_from
132-
}
133-
}
134-
}
135-
}
136-
}
137-
`);
138-
139-
/**
140-
* We could log here, the reason we don't right now is that the error should already have been caught and logged.
141-
* Because Gatsby spawns a bunch of async processes during the onCreateNode step, though, and errors don't prevent
142-
* the onCreateNode processes from continuing, the workaround is to create Error nodes and then quit when we get
143-
* to the next synchronous stage in the Gatsby pipeline if any Error nodes exist.
144-
* It's an awkward solution and an alternative would be welcome, I'm not sure what we would do instead though.
145-
* We could log only during createPages and never during onCreateNode, but then if there's an error that does manage
146-
* to crash Gatsby somehow or the Error Node is broken, we wouldn't see the output.
147-
*
148-
* For context:
149-
* The original ticket here was EDX-21. When I originally detected missing meta descriptions, I wanted to
150-
* console.warn and continue just so editors could see the error. However it was decided that it should be a
151-
* requirement to always have a meta description, so the app had to avoid building while still throwing & logging
152-
* an error when a page didn't have a meta description.
153-
*/
154-
if (documentResult.data?.allError.nodes && documentResult.data.allError.nodes.length > 0) {
155-
process.exit(1);
156-
}
157-
158-
// API REFERENCES TEMPLATE
159-
const apiReferenceResult = await graphql<ApiReferenceQueryResult>(`
160-
query {
161-
allFileHtml(filter: { articleType: { eq: "apiReference" } }) {
162-
edges {
163-
node {
164-
slug
165-
contentOrderedList {
166-
data
167-
type
168-
}
169-
meta {
170-
redirect_from
171-
}
172-
}
173-
}
174-
}
175-
}
176-
`);
177-
178-
// Query partials used in textile files
179-
const retrievePartialFromGraphQL = maybeRetrievePartial(graphql);
180-
18148
// Query our examples
18249
const examplesResult = await graphql<ExampleQueryResult>(`
18350
query {
@@ -212,83 +79,13 @@ export const createPages: GatsbyNode['createPages'] = async ({ graphql, actions:
21279
}
21380
`);
21481

215-
const documentCreator =
216-
(documentTemplate: string) =>
217-
async (edge: Edge): Promise<string> => {
218-
const content = flattenContentOrderedList(
219-
await Promise.all(edge.node.contentOrderedList.map(retrievePartialFromGraphQL)),
220-
)
221-
.map((content: { data: unknown }) => (content.data ? content.data : ''))
222-
.join('\n');
223-
224-
const postParsedContent = postParser(textile(content));
225-
const contentOrderedList = htmlParser(postParsedContent);
226-
const contentMenu = contentOrderedList.map((item) => createContentMenuDataFromPage(item));
227-
const [languages, contentMenuObject] = createLanguagePageVariants(identity, documentTemplate)(
228-
contentOrderedList,
229-
edge.node.slug,
230-
);
231-
232-
contentMenuObject[DEFAULT_LANGUAGE] = contentMenu;
233-
234-
const slug = edge.node.slug;
235-
const script = safeFileExists(`static/scripts/${slug}.js`);
236-
const pagePath = `/docs/${slug}`;
237-
238-
const redirectFromList = edge.node.meta?.redirect_from;
239-
240-
if (redirectFromList) {
241-
redirectFromList.forEach((redirectFrom) => {
242-
const redirectFromUrl = new URL(redirectFrom, siteMetadata.siteUrl);
243-
244-
if (!redirectFromUrl.hash) {
245-
// We need to be prefix aware just like Gatsby's internals so it works
246-
// with nginx redirects
247-
writeRedirect(redirectFrom, pagePath);
248-
}
249-
250-
createRedirect({
251-
fromPath: redirectFrom,
252-
toPath: pagePath,
253-
isPermanent: true,
254-
force: true,
255-
redirectInBrowser: true,
256-
});
257-
});
258-
}
259-
260-
createPage({
261-
path: pagePath,
262-
component: documentTemplate,
263-
context: {
264-
slug,
265-
version: edge.node.version ?? LATEST_ABLY_API_VERSION_STRING,
266-
language: DEFAULT_LANGUAGE,
267-
languages,
268-
contentOrderedList,
269-
contentMenu: contentMenuObject,
270-
script,
271-
layout: { leftSidebar: true, rightSidebar: true, searchBar: true, template: 'base' },
272-
},
273-
});
274-
return slug;
275-
};
276-
27782
createRedirect({
27883
fromPath: '/',
27984
toPath: '/docs',
28085
isPermanent: true,
28186
redirectInBrowser: true,
28287
});
28388

284-
if (!documentResult.data) {
285-
throw new Error('Document result is undefined');
286-
}
287-
288-
if (!apiReferenceResult.data) {
289-
throw new Error('API reference result is undefined');
290-
}
291-
29289
if (!mdxRedirectsResult.data) {
29390
throw new Error('MDX redirects result is undefined');
29491
}
@@ -355,8 +152,6 @@ export const createPages: GatsbyNode['createPages'] = async ({ graphql, actions:
355152
};
356153

357154
await Promise.all([
358-
...documentResult.data.allFileHtml.edges.map(documentCreator(documentTemplate)),
359-
...apiReferenceResult.data.allFileHtml.edges.map(documentCreator(apiReferenceTemplate)),
360155
...examples.map(exampleCreator),
361156
...mdxRedirectsResult.data.allMdx.nodes.map(mdxRedirectCreator),
362157
]);

data/onCreateNode/index.ts

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { GatsbyNode, Node } from 'gatsby';
2-
import { transformNanocTextiles, makeTypeFromParentType, createNodesFromPath } from '../transform';
32

43
export const onCreateNode: GatsbyNode['onCreateNode'] = async ({
54
node,
@@ -8,34 +7,6 @@ export const onCreateNode: GatsbyNode['onCreateNode'] = async ({
87
createNodeId,
98
createContentDigest,
109
}) => {
11-
const createChildNode = ({ parent, child }: { parent: Node; child: Node }) => {
12-
createNode(child);
13-
createParentChildLink({ parent, child });
14-
};
15-
16-
if (node.extension === 'textile') {
17-
const content = await loadNodeContent(node);
18-
try {
19-
transformNanocTextiles(node, content, createNodeId(`${node.id} >>> HTML`), makeTypeFromParentType('Html')(node), {
20-
createContentDigest,
21-
createNodesFromPath: createNodesFromPath('DocumentPath', { createNode, createNodeId, createContentDigest }),
22-
createNodeId,
23-
})(createChildNode);
24-
} catch (error: unknown) {
25-
const errorMessage = error instanceof Error ? error.message : String(error);
26-
const ErrorNode = {
27-
id: createNodeId(`${errorMessage} >>> Error`),
28-
message: errorMessage,
29-
internal: {
30-
contentDigest: createContentDigest(errorMessage),
31-
type: 'Error',
32-
},
33-
};
34-
createNode(ErrorNode);
35-
console.error('Error at relative path:\n', node.relativePath ? `${node.relativePath}\n` : '\n', errorMessage);
36-
}
37-
}
38-
3910
if (node.sourceInstanceName === 'how-tos') {
4011
// We derive the name of the how-to from the path
4112
const [tutorialName, src, ...paths] = (node.relativePath as string).split('/');

data/transform/index.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,6 @@ const transformNanocTextiles =
9393
return;
9494
}
9595

96-
if (node.sourceInstanceName === 'textile-partials') {
97-
content = `${content}\n`;
98-
}
9996
const preTextileTransform = preParser(content);
10097
const { data, frontmatterMeta } = splitDataAndMetaData(preTextileTransform);
10198

@@ -139,14 +136,8 @@ const transformNanocTextiles =
139136
type,
140137
mediaType: 'text/html',
141138
};
142-
if (node.sourceInstanceName === 'textile-partials') {
143-
newNodeInternals.type = `${type}Partial`;
144-
newNodeData.relativePath = node.relativePath;
145-
} else {
146-
createNodesFromPath(node.relativePath.replace(/\.[^/.]+$/, ''));
147-
// Partials should never have a slug, every other page type needs one.
148-
newNodeData.slug = slug;
149-
}
139+
createNodesFromPath(node.relativePath.replace(/\.[^/.]+$/, ''));
140+
newNodeData.slug = slug;
150141

151142
const htmlNode = {
152143
...newNodeData,

data/transform/parser-enhancements/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { addHyphenListSupport } = require('../pre-parser/textile-js-workarounds/add-hyphen-list-support');
1+
// textile workarounds removed
22
const { addDates } = require('./add-dates');
33
const { addSpecAnchorLinks } = require('./spec-anchor-links');
44

data/transform/pre-parser/index.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import { compose } from 'lodash/fp';
2-
import textile from 'textile-js';
3-
import { replaceERB } from './erbjs';
42
import {
53
convertJSAllToNodeAndJavaScript,
64
convertBlangBlocksToTokens,
@@ -11,23 +9,12 @@ import {
119
addLanguageSupportForHeadings,
1210
} from './language';
1311
import { stripComments, addMinimizeForHeadings, addMinimizedIndent } from './semantic';
14-
import { textileJSCompatibility } from './textile-js-workarounds';
1512

16-
// Newlines before closing tags inhibit textile-js' ability to correctly parse HTML
13+
// Newlines before closing tags can affect HTML parsing
1714
export const removeNewlinesBeforeClosingTags: StringTransformation = (content) =>
1815
content.replace(/\n+(<\/\w+>)/g, '$1');
1916

20-
// Jest has difficulty with resolving recursively-composed functions from different files
21-
// so we define this textile-js-workaround here.
22-
export const recursivelyProcessDivs: StringTransformation = (content) =>
23-
content.replace(/\n<div([^<>]*?)>\n(.*?)<\/div>/gms, (_match, p1, p2) => {
24-
return `\n<notextile><div${p1}>${textile(preParser(p2)).replace(/\n/g, '')}</div></notextile>`;
25-
});
26-
2717
export const preParser = compose(
28-
// Textile compatibility must follow all other changes
29-
textileJSCompatibility,
30-
recursivelyProcessDivs,
3118
// Language operations
3219
addLanguageSupportForHeadings,
3320
addLanguageSupportForBlockQuotes,
@@ -41,6 +28,4 @@ export const preParser = compose(
4128
addMinimizeForHeadings,
4229
removeNewlinesBeforeClosingTags,
4330
stripComments,
44-
// ERB to JS
45-
replaceERB,
4631
);

0 commit comments

Comments
 (0)