Skip to content

Commit

Permalink
feat: better inline images (#62)
Browse files Browse the repository at this point in the history
* feat: better inline image handling
* chore: break out the typings a bit more
  • Loading branch information
marbemac authored Jun 21, 2021
1 parent 07e734a commit efe0410
Show file tree
Hide file tree
Showing 17 changed files with 1,533 additions and 1,290 deletions.
28 changes: 14 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,38 +53,38 @@
"remark-gfm": "^1.0.0",
"remark-parse": "^9.0.0",
"remark-stringify": "^9.0.1",
"tslib": "^2.2.0",
"tslib": "^2.3.0",
"unified": "^9.2.1",
"unist-util-select": "^4.0.0",
"unist-util-visit": "^3.1.0"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/preset-env": "^7.14.2",
"@babel/preset-typescript": "^7.13.0",
"@babel/core": "^7.14.6",
"@babel/preset-env": "^7.14.5",
"@babel/preset-typescript": "^7.14.5",
"@rollup/plugin-node-resolve": "^13.0.0",
"@stoplight/eslint-config": "^2.0.0",
"@stoplight/scripts": "^9.0.2",
"@stoplight/scripts": "^9.0.5",
"@types/hast": "^2.3.1",
"@types/jest": "^26.0.23",
"@types/lodash": "^4.14.170",
"@types/unist": "^2.0.3",
"@typescript-eslint/eslint-plugin": "^4.25.0",
"@typescript-eslint/parser": "^4.25.0",
"eslint": "^7.27.0",
"eslint-plugin-import": "^2.23.3",
"@typescript-eslint/eslint-plugin": "^4.27.0",
"@typescript-eslint/parser": "^4.27.0",
"eslint": "^7.28.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jest": "^24.3.6",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"glob-fs": "^0.1.7",
"jest": "^27.0.1",
"jest": "^27.0.4",
"lodash": "^4.17.21",
"prettier": "^2.3.0",
"prettier": "^2.3.1",
"remark-html": "^13.0.1",
"ts-jest": "^27.0.0",
"typescript": "^4.2.4"
"ts-jest": "^27.0.3",
"typescript": "^4.3.2"
},
"lint-staged": {
"*.{ts,tsx}$": [
Expand Down
44 changes: 30 additions & 14 deletions src/ast-types/hast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,43 @@ export interface Element extends HAST.Element {
properties?: HAST.Properties;
}

export interface BlockquoteProperties {
theme?: ThemeType;
}

export interface Blockquote extends HAST.Element {
tagName: 'blockquote';

properties?: {
theme: ThemeType;
} & HAST.Properties;
properties?: BlockquoteProperties & HAST.Properties;
}

export interface ImageProperties {
bg?: string;
focus?: 'top' | 'bottom' | 'center' | 'top-right' | 'top-left' | 'default' | 'false';
invertOnDark?: 'true' | 'false';
inline?: 'true' | 'false';
}

export interface Image extends HAST.Element {
tagName: 'img';
properties?: ImageProperties & HAST.Properties;
}

export interface CodeProperties {
title?: string;
lang?: string;
lineNumbers?: 'true' | 'false';
/** stringified json: string[] | string[][] */
highlightLines?: string;
inline?: 'true' | 'false';
live?: 'true' | 'false';
jsonSchema?: 'true' | 'false';
http?: 'true' | 'false';
}

export interface Code extends HAST.Element {
tagName: 'code';

properties?: {
title?: string;
lang?: string;
lineNumbers?: boolean;
highlightLines?: string[] | string[][];
inline?: boolean;
live?: boolean;
jsonSchema?: boolean;
http?: boolean;
} & HAST.Properties;
properties?: CodeProperties & HAST.Properties;
}

export interface Tabs extends HAST.Element {
Expand Down
6 changes: 4 additions & 2 deletions src/ast-types/mdast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export interface Code extends Literal {
highlightLines?: string[] | string[][];
inline?: boolean;
live?: boolean;
jsonSchema?: boolean | 'true' | 'false';
jsonSchema?: boolean;
http?: boolean;
};
}
Expand Down Expand Up @@ -178,7 +178,9 @@ export interface Image extends Node, Resource, Alternative {
// custom
annotations?: {
bg?: string;
focus?: 'top' | 'bottom' | 'center' | 'top-right' | 'top-left';
focus?: 'top' | 'bottom' | 'center' | 'top-right' | 'top-left' | 'default' | false;
invertOnDark?: boolean;
inline?: boolean;
};
}

Expand Down
2 changes: 2 additions & 0 deletions src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { MDAST } from './ast-types';
import {
blockquoteMdast2Hast,
inlineCodeMdast2Hast,
inlineImages,
resolveCodeBlocks,
Resolver,
slug,
Expand Down Expand Up @@ -39,6 +40,7 @@ export const remarkParsePreset: unified.Preset<ParseSettings> = {
unwrapImages,
smdAnnotations,
smdCode,
inlineImages,
inlineCodeMdast2Hast,
blockquoteMdast2Hast,
],
Expand Down
18 changes: 18 additions & 0 deletions src/plugins/run/__tests__/__fixtures__/images/basic-inline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Image in a paragraph: ![should have inline][ecologi_image].

![should NOT have inline][ecologi_image]

[![should have inline][ecologi_image]][ecologi]

<!-- type: tab -->

Tab paragraph one.

![should NOT have inline][ecologi_image]

Tab paragraph two.

<!-- type: tab-end -->

[ecologi]: https://ecologi.com/stoplightinc
[ecologi_image]: https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen
10 changes: 10 additions & 0 deletions src/plugins/run/__tests__/__fixtures__/images/unwrap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Image in a paragraph: ![should NOT unwrap][ecologi_image].

![should unwrap][ecologi_image]

[![should unwrap][ecologi_image]][ecologi]

![should NOT unwrap][ecologi_image] [![should NOT unwrap][ecologi_image]][ecologi]

[ecologi]: https://ecologi.com/stoplightinc
[ecologi_image]: https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen
5 changes: 4 additions & 1 deletion src/plugins/run/__tests__/code.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const prettier = require('prettier');

const prettyParse = (input: string) => {
return prettier.format(
`<>${unified().use(remarkParse).use(remarkParsePreset).use(html).processSync(input).contents}</>`,
`<>${
unified().use(remarkParse).use(remarkParsePreset).use(html, { closeSelfClosing: true }).processSync(input)
.contents
}</>`,
{
parser: 'babel',
},
Expand Down
64 changes: 64 additions & 0 deletions src/plugins/run/__tests__/inline-images.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as fs from 'fs';
import * as path from 'path';
import html from 'remark-html';
import remarkParse from 'remark-parse';
import unified from 'unified';

import { remarkParsePreset } from '../../../parse';

const prettier = require('prettier');

const prettyParse = (input: string) => {
return prettier.format(
`<>${unified()
.use(remarkParse)
.use(remarkParsePreset)
.use(html, { closeSelfClosing: true })
.processSync(input)}</>`,
{
parser: 'babel',
},
);
};

describe('inline-images plugin', () => {
it('should support meta props like title and lineNumbers', () => {
const input = fs.readFileSync(path.join(__dirname, '__fixtures__/images/basic-inline.md'), 'utf8');

expect(prettyParse(input)).toMatchInlineSnapshot(`
"<>
<p>
Image in a paragraph:{\\" \\"}
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should have inline\\"
inline=\\"true\\"
/>
.
</p>
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should NOT have inline\\"
/>
<a href=\\"https://ecologi.com/stoplightinc\\">
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should have inline\\"
inline=\\"true\\"
/>
</a>
<tabs>
<tab type=\\"tab\\">
<p>Tab paragraph one.</p>
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should NOT have inline\\"
/>
<p>Tab paragraph two.</p>
</tab>
</tabs>
</>;
"
`);
});
});
68 changes: 68 additions & 0 deletions src/plugins/run/__tests__/unwrap-images.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as fs from 'fs';
import * as path from 'path';
import html from 'remark-html';
import remarkParse from 'remark-parse';
import unified from 'unified';

import { remarkParsePreset } from '../../../parse';

const prettier = require('prettier');

const prettyParse = (input: string) => {
return prettier.format(
`<>${unified()
.use(remarkParse)
.use(remarkParsePreset)
.use(html, { closeSelfClosing: true })
.processSync(input)}</>`,
{
parser: 'babel',
},
);
};

describe('unwrap-images plugin', () => {
it('should support meta props like title and lineNumbers', () => {
const input = fs.readFileSync(path.join(__dirname, '__fixtures__/images/unwrap.md'), 'utf8');

expect(prettyParse(input)).toMatchInlineSnapshot(`
"<>
<p>
Image in a paragraph:{\\" \\"}
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should NOT unwrap\\"
inline=\\"true\\"
/>
.
</p>
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should unwrap\\"
/>
<a href=\\"https://ecologi.com/stoplightinc\\">
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should unwrap\\"
inline=\\"true\\"
/>
</a>
<p>
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should NOT unwrap\\"
inline=\\"true\\"
/>{\\" \\"}
<a href=\\"https://ecologi.com/stoplightinc\\">
<img
src=\\"https://img.shields.io/badge/Buy%20us%20a%20tree-%F0%9F%8C%B3-lightgreen\\"
alt=\\"should NOT unwrap\\"
inline=\\"true\\"
/>
</a>
</p>
</>;
"
`);
});
});
23 changes: 21 additions & 2 deletions src/plugins/run/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const smdAnnotations: unified.Attacher = function () {
// set annotations if present
if (Object.keys(anno).length > 0) {
Object.assign(children[children.length - 1].data, {
hProperties: anno,
hProperties: normalizeAnnotationsForHast(anno),
});
}

Expand Down Expand Up @@ -189,10 +189,29 @@ function processNode(node: MDAST.Content, annotations?: object): MDAST.Content {
annotations,
data: {
...(node.data || {}),
hProperties: annotations,
hProperties: normalizeAnnotationsForHast(annotations),
},
};
}

return node;
}

// micromark ecosystem passes data through html, and then to react
// HTML does not allow for boolean properties, so here we stringify boolean values so that they can pass through
// the html layer
export function normalizeAnnotationsForHast(annotations?: object) {
if (!annotations) return annotations;

const cleaned = {};
for (const key in annotations) {
const annotation = annotations[key];
if (typeof annotation === 'boolean') {
cleaned[key] = String(annotation);
} else {
cleaned[key] = annotation;
}
}

return cleaned;
}
2 changes: 2 additions & 0 deletions src/plugins/run/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ function handleLegacyAnnotations(annotations: MDAST.Code['annotations']) {
// @ts-expect-error type is no longer part of the typings, it is deprecated
const type = annotations.type;
if (type === 'json_schema') {
// @ts-expect-error
annotations.jsonSchema = 'true';
} else {
annotations[type] = 'true';
Expand All @@ -166,6 +167,7 @@ function handleLegacyAnnotations(annotations: MDAST.Code['annotations']) {
}

if (annotations.hasOwnProperty('json_schema')) {
// @ts-expect-error
annotations.jsonSchema = 'true';
// @ts-expect-error ditto above
delete annotations.json_schema;
Expand Down
1 change: 1 addition & 0 deletions src/plugins/run/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './annotations';
export * from './blockquote';
export * from './code';
export * from './inline-images';
export * from './resolver';
export * from './slug';
export * from './unwrap-images';
Loading

0 comments on commit efe0410

Please sign in to comment.