Skip to content

Commit

Permalink
Allow and replace process.env.SHOW_NEXT_RELEASE in TypeScript files…
Browse files Browse the repository at this point in the history
… for the website (#7990)
  • Loading branch information
emmatown committed Oct 11, 2022
1 parent f50d408 commit 3c209b4
Show file tree
Hide file tree
Showing 11 changed files with 308 additions and 16 deletions.
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ coverage
**/.next
**/.keystone
**/__generated__
docs/
docs/**/*.md
docs/public/assets/*.js
.keystone/tests
prisma-utils/src/generated
nexus-typegen.ts
Expand Down
3 changes: 2 additions & 1 deletion docs/markdoc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { isNonEmptyArray } from 'emery/guards';
import { assert } from 'emery/assertions';
import { load } from 'js-yaml';
import { baseMarkdocConfig } from './config';
import { showNextReleaseWithoutReplacement } from './show-next-release';

export function printValidationError(error: ValidateError) {
const location = error.error.location || error.location;
Expand Down Expand Up @@ -47,7 +48,7 @@ export async function readDocContent(filepath: string): Promise<DocContent> {
const markdocConfig: Config = {
...baseMarkdocConfig,
variables: {
nextRelease: !!process.env.SHOW_NEXT_RELEASE,
nextRelease: showNextReleaseWithoutReplacement,
},
};

Expand Down
2 changes: 2 additions & 0 deletions docs/markdoc/show-next-release.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// @skipShowNextReleaseReplacement
export const showNextReleaseWithoutReplacement = !!process.env.SHOW_NEXT_RELEASE;
7 changes: 5 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
"build": "yarn validate-links && next build && yarn sitemap",
"start": "next start -p 8000",
"sitemap": "next-sitemap",
"validate-links": "tsx validate-links.ts",
"remove-conditionals": "tsx remove-conditionals.ts"
"validate-links": "tsx scripts/validate-links.ts",
"remove-conditionals": "tsx scripts/replace-show-next-release/index.ts"
},
"dependencies": {
"@babel/core": "^7.16.0",
"@babel/runtime": "^7.16.3",
"@codemod/core": "^2.0.1",
"@emotion/cache": "11.10.3",
"@emotion/css": "^11.7.1",
"@emotion/react": "^11.7.1",
Expand Down Expand Up @@ -46,6 +48,7 @@
"markdown-it": "^13.0.1",
"next": "^12.2.4",
"next-compose-plugins": "^2.2.1",
"prettier": "^2.5.0",
"prism-react-renderer": "^1.2.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import fs from 'fs/promises';
import { ValidateError } from '@markdoc/markdoc';
import { loadAllMarkdoc } from './markdoc/load-all';
import { printValidationError } from './markdoc';
import { removeNextReleaseConditions } from './markdoc/remove-next-release-conditions';
import globby from 'globby';
import { loadAllMarkdoc } from '../../markdoc/load-all';
import { printValidationError } from '../../markdoc';
import { removeNextReleaseConditions } from './markdoc';
import { replaceShowNextRelease } from './typescript';

(async () => {
async function updateTsFiles() {
const files = await globby('**/*.{ts,tsx}');
await Promise.all(
files.map(async file => {
const source = await fs.readFile(file, 'utf8');
if (
!source.includes('process.env.SHOW_NEXT_RELEASE') ||
source.includes('// @skipShowNextReleaseReplacement')
) {
return;
}
const newSource = await replaceShowNextRelease(file, source);
await fs.writeFile(file, newSource);
})
);
}

async function updateMarkdocFiles() {
const docs = await loadAllMarkdoc();
const allErrors: ValidateError[] = [];
await Promise.all(
Expand All @@ -25,4 +44,8 @@ import { removeNextReleaseConditions } from './markdoc/remove-next-release-condi
}
process.exitCode = 1;
}
}

(async () => {
await Promise.all([updateTsFiles(), updateMarkdocFiles()]);
})();
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { removeNextReleaseConditions } from './remove-next-release-conditions';
import { removeNextReleaseConditions } from './markdoc';

test('removes if', () => {
const content = `## Heading 1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Markdoc from '@markdoc/markdoc';
import { baseMarkdocConfig } from './config';
import { baseMarkdocConfig } from '../../markdoc/config';

const pattern =
/{%\s+if\s+\$nextRelease\s+%}\s*([^]+?)\s*(?:{%\s+else\s+\/%}[^]*?)?{%\s+\/if\s+%}/g;
Expand Down
112 changes: 112 additions & 0 deletions docs/scripts/replace-show-next-release/typescript.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { replaceShowNextRelease } from './typescript';
test('no usage', async () => {
expect(await replaceShowNextRelease('a.ts', "const a = 'something';")).toMatchInlineSnapshot(`
"const a = 'something';
"
`);
});
test('assignment to variable', async () => {
expect(await replaceShowNextRelease('a.ts', 'const a = process.env.SHOW_NEXT_RELEASE;'))
.toMatchInlineSnapshot(`
"const a = '1';
"
`);
});
test('basic if statement', async () => {
expect(
await replaceShowNextRelease(
'a.ts',
`
function a() {
if (process.env.SHOW_NEXT_RELEASE) {
console.log('yes')
} else {
console.log('other')
}
}
`
)
).toMatchInlineSnapshot(`
"function a() {
console.log('yes');
}
"
`);
});
test('conditional expression', async () => {
expect(
await replaceShowNextRelease(
'a.ts',
`
function a() {
const a = process.env.SHOW_NEXT_RELEASE ? 'new release' : 'old';
}
`
)
).toMatchInlineSnapshot(`
"function a() {
const a = 'new release';
}
"
`);
});
test('conditional expression in jsx', async () => {
expect(
await replaceShowNextRelease(
'a.tsx',
`
function MyThing() {
return <div>something {process.env.SHOW_NEXT_RELEASE ? 'next release' : 'previous release'} other</div>
}
`
)
).toMatchInlineSnapshot(`
"function MyThing() {
return <div>something {'next release'} other</div>;
}
"
`);
});
test('conditional expression in jsx with jsx in consequent', async () => {
expect(
await replaceShowNextRelease(
'a.tsx',
`
function MyThing() {
return <div>something {process.env.SHOW_NEXT_RELEASE ? <div>new release</div>: 'previous release'} other</div>
}
`
)
).toMatchInlineSnapshot(`
"function MyThing() {
return (
<div>
something <div>new release</div> other
</div>
);
}
"
`);
});

test('&&', async () => {
expect(
await replaceShowNextRelease(
'a.tsx',
`
function MyThing() {
return <div>something {process.env.SHOW_NEXT_RELEASE && <div>new release</div>} other</div>
}
`
)
).toMatchInlineSnapshot(`
"function MyThing() {
return (
<div>
something <div>new release</div> other
</div>
);
}
"
`);
});
75 changes: 75 additions & 0 deletions docs/scripts/replace-show-next-release/typescript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// @codemod/core is basically @babel/core but it uses recast to preserve formatting/comments better
import { transform } from '@codemod/core';
import { NodePath, Node, types } from '@babel/core';
import prettier from 'prettier';

function truthyConditionalExpression(path: NodePath<Node>) {
if (path.parentPath?.isConditionalExpression() && path.parentKey === 'test') {
return { consequent: path.parentPath.node.consequent, path: path.parentPath };
}
if (
path.parentPath?.isLogicalExpression() &&
path.parentKey === 'left' &&
path.parentPath.node.operator === '&&'
) {
return { consequent: path.parentPath.node.right, path: path.parentPath };
}
}

export async function replaceShowNextRelease(filename: string, source: string) {
const transformed = transform(source, {
parserOpts: { plugins: filename.endsWith('.tsx') ? ['typescript', 'jsx'] : ['typescript'] },
plugins: [
{
visitor: {
MemberExpression(path) {
const { node } = path;
if (
!(
!node.computed &&
node.property.type === 'Identifier' &&
node.property.name === 'SHOW_NEXT_RELEASE' &&
node.object.type === 'MemberExpression' &&
!node.object.computed &&
node.object.property.type === 'Identifier' &&
node.object.property.name === 'env' &&
node.object.object.type === 'Identifier' &&
node.object.object.name === 'process'
)
) {
return;
}
if (
path.parentPath.isIfStatement() &&
path.parentKey === 'test' &&
path.parentPath.node.consequent.type === 'BlockStatement'
) {
path.parentPath.replaceWithMultiple(path.parentPath.node.consequent.body);
return;
}

const conditional = truthyConditionalExpression(path);
if (conditional) {
if (
conditional.path.parentPath?.isJSXExpressionContainer() &&
conditional.consequent.type === 'JSXElement'
) {
conditional.path.parentPath.replaceWith(conditional.consequent);
return;
}
conditional.path.replaceWith(conditional.consequent);
return;
}
path.replaceWith(types.stringLiteral('1'));
},
},
},
],
babelrc: false,
configFile: false,
babelrcRoots: false,
filename,
});
const config = await prettier.resolveConfig(filename);
return prettier.format(transformed!.code!, { filepath: filename, ...config });
}
6 changes: 3 additions & 3 deletions docs/validate-links.ts → docs/scripts/validate-links.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Markdoc from '@markdoc/markdoc';
import { getIdForHeading, baseMarkdocConfig, Pages } from './markdoc/config';
import { printValidationError } from './markdoc';
import { loadAllMarkdoc } from './markdoc/load-all';
import { getIdForHeading, baseMarkdocConfig, Pages } from '../markdoc/config';
import { printValidationError } from '../markdoc';
import { loadAllMarkdoc } from '../markdoc/load-all';

// for the things that aren't Markdoc that are linked from Markdoc
const NON_MARKDOWN_PAGES = [
Expand Down
Loading

1 comment on commit 3c209b4

@vercel
Copy link

@vercel vercel bot commented on 3c209b4 Oct 11, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.