New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

mdsvex

Package Overview
Dependencies
Maintainers
1
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mdsvex - npm Package Compare versions

Comparing version 0.4.1-beta.5 to 0.4.1-beta.6

src/parsers/svelte.js

26

package.json
{
"name": "mdsvex",
"version": "0.4.1-beta.5",
"version": "0.4.1-beta.6",
"description": "Markdown preprocessor for Svelte",

@@ -15,3 +15,2 @@ "main": "dist/main.cjs.js",

"test:cov": "yarn lint && jest --verbose --coverage",
"postinstall": "patch-package",
"generate_files": "node -r esm ./test/_scripts/generate_markdown_html.js"

@@ -32,6 +31,7 @@ },

"cheap-watch": "^1.0.2",
"eslint": "^6.3.0",
"eslint": "^6.6.0",
"eslint-plugin-import": "^2.18.2",
"esm": "^3.2.25",
"highlight.js": "^9.15.10",
"front-matter": "^3.0.2",
"highlight.js": "^9.16.2",
"jest-diff": "^24.9.0",

@@ -42,3 +42,3 @@ "js-yaml": "^3.13.1",

"postinstall-postinstall": "^2.0.0",
"prettier": "^1.18.2",
"prettier": "^1.19.1",
"prettier-eslint": "^9.0.0",

@@ -51,3 +51,3 @@ "rehype-slug": "^2.0.3",

"remark-frontmatter": "^1.3.2",
"remark-parse": "^7.0.1",
"remark-parse": "^7.0.2",
"remark-rehype": "^5.0.0",

@@ -57,3 +57,3 @@ "remark-slug": "^5.1.2",

"retext-smartypants": "^3.0.3",
"rollup": "^1.20.3",
"rollup": "^1.27.0",
"rollup-plugin-commonjs": "^10.1.0",

@@ -64,7 +64,7 @@ "rollup-plugin-json": "^4.0.0",

"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-svelte": "^5.1.0",
"svelte": "^3.9.1",
"unified": "^8.4.1",
"rollup-plugin-svelte": "^5.1.1",
"svelte": "^3.14.1",
"unified": "^8.4.2",
"yarn": "^1.19.0",
"zora": "^3.0.3"
"zora": "^3.1.4"
},

@@ -74,5 +74,3 @@ "peerDependencies": {

},
"dependencies": {
"patch-package": "^6.2.0"
}
"dependencies": {}
}
import unified from 'unified';
import markdown from 'remark-parse';
import external from 'remark-external-links';
import frontmatter from 'remark-frontmatter';
import remark2rehype from 'remark-rehype';
import hast_to_html from '@starptech/prettyhtml-hast-to-html';
import frontmatter from 'remark-frontmatter';
import visit from 'unist-util-visit';
import retext from 'retext';
import smartypants from 'retext-smartypants';
import external from 'remark-external-links';
import { mdsvex_parser } from './parsers/';
import { mdsvex_transformer } from './transformers/';
import {
parse_yaml,
escape_code,
transform_hast,
smartypants_transformer,
} from './transformers/';

@@ -36,162 +37,2 @@ function stringify(options = {}) {

function smartypants_processor(options = {}) {
const processor = retext().use(smartypants, options);
function transformer(tree) {
visit(tree, 'text', node => {
node.value = String(processor.processSync(node.value));
});
}
return transformer;
}
const entites = [
[/</g, '&lt;'],
[/>/g, '&gt;'],
[/{/g, '&#123;'],
[/}/g, '&#125;'],
];
function code() {
function transformer(tree) {
visit(tree, 'code', node => {
for (let i = 0; i < entites.length; i += 1) {
node.value = node.value.replace(entites[i][0], entites[i][1]);
}
});
}
return transformer;
}
const attrs = `(?:\\s{0,1}[a-zA-z]+=(?:"){0,1}[a-zA-Z0-9]+(?:"){0,1})*`;
const RE_MODULE_SCRIPT = new RegExp(
`^(<script` +
attrs +
`(?:\\s{0,1}(?:context)+=(?:"){0,1}(?:module)+(?:"){0,1}){1,}` +
attrs +
`>)[^]+?<\\/script>`
);
const RE_SCRIPT = new RegExp(`^(<script` + attrs + `>)[^]+?<\\/script>`);
const RE_STYLES = new RegExp(`^(<style` + attrs + `>)[^]+?<\\/style>`);
function html(layout) {
function transformer(tree) {
visit(tree, 'element', node => {
if (node.tagName === 'a' && node.properties.href) {
node.properties.href = node.properties.href
.replace(/%7B/g, '{')
.replace(/%7D/g, '}');
}
if (node.tagName === 'img' && node.properties.src) {
node.properties.src = node.properties.src
.replace(/%7B/g, '{')
.replace(/%7D/g, '}');
}
});
if (!layout) return;
// breaks positioning
visit(tree, 'root', node => {
const nodes = [];
const instances = {
match: false,
nodes: [],
};
const modules = {
match: false,
nodes: [],
};
const styles = {
match: false,
nodes: [],
};
// don't even ask
children: for (let i = 0; i < node.children.length; i += 1) {
if (node.children[i].type != 'raw' || !node.children[i].value) {
nodes.push(node.children[i]);
continue children;
}
let start = 0;
let depth = 0;
let started = false;
for (let c = 0; c < node.children[i].value.length; c += 1) {
if (
node.children[i].value[c] === '<' &&
node.children[i].value[c + 1] !== '/'
) {
depth += 1;
started = true;
}
if (
node.children[i].value[c] === '<' &&
node.children[i].value[c + 1] === '/'
)
depth -= 1;
if (started && depth === 0) {
if (node.children[i].value[c] === '>') {
const value = node.children[i].value
.substring(start, c + 1)
.trim();
let match;
if ((match = RE_MODULE_SCRIPT.exec(value))) {
modules.match = match;
modules.nodes.push({ type: 'raw', meta: 'module', value });
} else if ((match = RE_SCRIPT.exec(value))) {
instances.match = match;
instances.nodes.push({ type: 'raw', meta: 'instance', value });
} else if ((match = RE_STYLES.exec(value))) {
styles.match = match;
styles.nodes.push({ type: 'raw', meta: 'style', value });
} else {
nodes.push({ type: 'raw', value });
}
start = c + 1;
started = false;
}
}
}
}
const _import = `import Layout_MDSVEX_DEFAULT from '${layout}';`;
if (!instances.match) {
instances.nodes.push({
type: 'raw',
value: `\n<script>\n ${_import}\n</script>\n`,
});
} else {
instances.nodes[0].value = instances.nodes[0].value.replace(
instances.match[1],
`${instances.match[1]}\n ${_import}`
);
}
// please clean this up
node.children = [
...modules.nodes,
{ type: 'raw', value: '\n' },
...instances.nodes,
{ type: 'raw', value: '\n' },
...styles.nodes,
{ type: 'raw', value: '\n' },
{ type: 'raw', value: '<Layout_MDSVEX_DEFAULT>' },
...nodes,
{ type: 'raw', value: '</Layout_MDSVEX_DEFAULT>' },
];
});
}
return transformer;
}
export function transform({

@@ -205,11 +46,11 @@ remarkPlugins = [],

.use(markdown)
.use(mdsvex_parser)
.use(external, { target: false, rel: ['nofollow'] })
.use(code)
.use(escape_code)
.use(frontmatter)
.use(mdsvex_parser)
.use(mdsvex_transformer);
.use(parse_yaml);
if (smartypants) {
toMDAST.use(
smartypants_processor,
smartypants_transformer,
typeof smartypants === 'boolean' ? {} : smartypants

@@ -219,4 +60,2 @@ );

// plugins : [ [plugin, opts] ] | [ plugin ]
apply_plugins(remarkPlugins, toMDAST);

@@ -229,3 +68,3 @@

})
.use(html, layout);
.use(transform_hast, { layout });

@@ -257,2 +96,9 @@ apply_plugins(rehypePlugins, toHAST);

} = defaults) => {
const parser = transform({
remarkPlugins,
rehypePlugins,
smartypants,
layout,
});
return {

@@ -262,9 +108,2 @@ markup: async ({ content, filename }) => {

const parser = transform({
remarkPlugins,
rehypePlugins,
smartypants,
layout,
});
const parsed = await parser.process(content);

@@ -271,0 +110,0 @@

@@ -1,3 +0,3 @@

import { parse_svelte_tag } from './svelte_tags';
import { parse_svelte_block } from './svelte_blocks';
import { parse_svelte_tag } from './svelte';
import { parse_svelte_block } from './svelte';
import { blockHtml } from './html_block';

@@ -4,0 +4,0 @@

@@ -0,5 +1,10 @@

import retext from 'retext';
import smartypants from 'retext-smartypants';
import visit from 'unist-util-visit';
import yaml from 'js-yaml';
import { parse } from 'svelte/compiler';
export function mdsvex_transformer() {
// extract the yaml from 'yaml' nodes and put them in the vfil for later use
export function parse_yaml() {
return transformer;

@@ -10,3 +15,3 @@

try {
vFile.data = yaml.safeLoad(node.value);
vFile.data.fm = yaml.safeLoad(node.value);
} catch (e) {

@@ -16,4 +21,223 @@ vFile.messages.push(['YAML failed to parse', e]);

});
return tree;
}
}
// in code nodes replace the character witrh the html entities
// maybe I'll need more of these
const entites = [
[/</g, '&lt;'],
[/>/g, '&gt;'],
[/{/g, '&#123;'],
[/}/g, '&#125;'],
];
export function escape_code() {
function transformer(tree) {
visit(tree, 'code', node => {
for (let i = 0; i < entites.length; i += 1) {
node.value = node.value.replace(entites[i][0], entites[i][1]);
}
});
}
return transformer;
}
// special case - process nodes with retext and smarypants
// retext plugins can't work generally due to the difficulties in converting between the two trees
export function smartypants_transformer(options = {}) {
const processor = retext().use(smartypants, options);
function transformer(tree) {
visit(tree, 'text', node => {
node.value = String(processor.processSync(node.value));
});
}
return transformer;
}
// regex for scripts and attributes
const attrs = `(?:\\s{0,1}[a-zA-z]+=(?:"){0,1}[a-zA-Z0-9]+(?:"){0,1})*`;
const context = `(?:\\s{0,1}context)=(?:"){0,1}module(?:"){0,1}`;
const RE_BLANK = /^\n+$|^\s+$/;
const RE_SCRIPT = new RegExp(`^(<script` + attrs + `>)`);
const RE_MODULE_SCRIPT = new RegExp(
`^(<script` + attrs + context + attrs + `>)`
);
export function transform_hast({ layout }) {
return transformer;
function transformer(tree, vFile) {
// we need to keep { and } intact for svelte, so reverse the escaping in links and images
visit(tree, 'element', node => {
if (node.tagName === 'a' && node.properties.href) {
node.properties.href = node.properties.href
.replace(/%7B/g, '{')
.replace(/%7D/g, '}');
}
if (node.tagName === 'img' && node.properties.src) {
node.properties.src = node.properties.src
.replace(/%7B/g, '{')
.replace(/%7D/g, '}');
}
});
// the rest only applies to layouts and front matter
// this currently breaks position data svelte preprocessors don't currently support sourcemaps
// i'll fix this when they do
if (!layout && !vFile.data.fm) return;
visit(tree, 'root', node => {
// since we are wrapping and replacing we need to keep track of the different component 'parts'
// many special tags cannot be wrapped nor can style or script tags
const parts = {
special: [],
html: [],
instance: [],
module: [],
css: [],
};
// iterate through all top level child nodes and assign them to the correct 'part'
// anything that is a normal HAST node gets stored as HTML untouched
// everything else gets parsed by the svelte parser
children: for (let i = 0; i < node.children.length; i += 1) {
if (
(node.children[i].type !== 'raw' &&
(node.children[i].type === 'text' &&
RE_BLANK.exec(node.children[i].value))) ||
!node.children[i].value
) {
if (
!parts.html[parts.html.length - 1] ||
!(
RE_BLANK.exec(node.children[i].value) &&
RE_BLANK.exec(parts.html[parts.html.length - 1].value)
)
) {
parts.html.push(node.children[i]);
}
continue children;
}
const result = parse(node.children[i].value);
// svelte special tags that have to be top level
const _parts = result.html.children.map(v => {
if (
v.type === 'Options' ||
v.type === 'Head' ||
v.type === 'Window' ||
v.type === 'Body'
) {
return ['special', v.start, v.end];
} else {
return ['html', v.start, v.end];
}
});
// module scripts
if (result.module) {
_parts.push(['module', result.module.start, result.module.end]);
}
// style elements
if (result.css) {
_parts.push(['css', result.css.start, result.css.end]);
}
// instance scripts
if (result.instance) {
_parts.push(['instance', result.instance.start, result.instance.end]);
}
// sort them to ensure the array is in the order they appear in the source, no gaps
// this might not be necessary any more, i forget
const sorted = _parts.sort((a, b) => a[1] - b[1]);
// push the nodes into the correct 'part' since they are sorted everything should be in the correct order
sorted.forEach(next => {
parts[next[0]].push({
type: 'raw',
value: node.children[i].value.substring(next[1], next[2]),
});
});
}
const { special, html, instance, module: _module, css } = parts;
const fm =
vFile.data.fm &&
`export const metadata = ${JSON.stringify(vFile.data.fm)};`;
const _layout =
vFile.data.fm && vFile.data.fm.layout ? vFile.data.fm.layout : layout;
const layout_import =
_layout && `import Layout_MDSVEX_DEFAULT from '${_layout}';`;
// add the layout if w are using one, resuing the existing script if one exists
if (_layout && !instance[0]) {
instance.push({
type: 'raw',
value: `\n<script>\n\t${layout_import}\n</script>\n`,
});
} else if (_layout) {
instance[0].value = instance[0].value.replace(
RE_SCRIPT,
`$1\n\t${layout_import}`
);
}
// inject the frontmatter into the module script if there is any, resuing the existing module script if one exists
if (!_module[0] && fm) {
_module.push({
type: 'raw',
value: `<script context="module">\n\t${fm}\n</script>`,
});
} else if (fm) {
_module[0].value = _module[0].value.replace(
RE_MODULE_SCRIPT,
`$1\n\t${fm}`
);
}
// smoosh it all together in an order that makes sense,
// if using a layout we only wrap the html and nothing else
node.children = [
..._module,
{ type: 'raw', value: _module[0] ? '\n' : '' },
...instance,
{ type: 'raw', value: instance[0] ? '\n' : '' },
...css,
{ type: 'raw', value: css[0] ? '\n' : '' },
...special,
{ type: 'raw', value: special[0] ? '\n' : '' },
{
type: 'raw',
value: _layout
? `<Layout_MDSVEX_DEFAULT${fm ? ' {...metadata}' : ''}>`
: '',
},
{ type: 'raw', value: '\n' },
...html,
{ type: 'raw', value: '\n' },
{ type: 'raw', value: _layout ? '</Layout_MDSVEX_DEFAULT>' : '' },
];
});
}
}

@@ -20,3 +20,6 @@ import {

const printBailout = message => {
print('Bail out! Unhandled error.', message);
// console.log(message);
console.log(bgRed('Bail out! Unhandled error.'));
console.log(message.data.stack);
//print('Bail out! Unhandled error.', message.data, message.offset);
};

@@ -50,3 +53,2 @@

const output = [];
for await (const message of stream) {

@@ -66,3 +68,3 @@ output.push(message);

for (let i = 0; i < output.length; i++) {
if (output[i].type === 'BAILOUT') printBailout();
if (output[i].type === 'BAIL_OUT') printBailout(output[i]);
// directory

@@ -69,0 +71,0 @@ if (output[i].offset === 0) {

@@ -15,2 +15,3 @@ const { createHarness } = require('zora');

run(test, opts);
report(harness);

@@ -17,0 +18,0 @@ };

@@ -210,9 +210,9 @@ import { mdsvex } from '../../src/';

`
<script>
import Layout_MDSVEX_DEFAULT from 'path/to/layout';
import Layout_MDSVEX_DEFAULT from 'path/to/layout';
</script>
<Layout_MDSVEX_DEFAULT><h1>hello</h1></Layout_MDSVEX_DEFAULT>`,
<Layout_MDSVEX_DEFAULT>
<h1>hello</h1>
</Layout_MDSVEX_DEFAULT>`,
output.code

@@ -241,7 +241,70 @@ );

t.equal(
`
`<script>
import Layout_MDSVEX_DEFAULT from 'path/to/layout';
export let x = 1;
</script>
<style>
h1 {
color: pink;
}
</style>
<Layout_MDSVEX_DEFAULT>
<h1>hello</h1>
</Layout_MDSVEX_DEFAULT>`,
output.code
);
});
test('custom layouts should work - when there are script tags with random attributes', async t => {
const output = await mdsvex({ layout: 'path/to/layout' }).markup({
content: `
<script type="ts" lang=whatever thing="whatsit" doodaa=thingamabob>
export let x = 1;
</script>
# hello
<style>
h1 {
color: pink;
}
</style>
`,
filename: 'file.svexy',
});
t.equal(
`<script type="ts" lang=whatever thing="whatsit" doodaa=thingamabob>
import Layout_MDSVEX_DEFAULT from 'path/to/layout';
export let x = 1;
</script>
<style>
h1 {
color: pink;
}
</style>
<Layout_MDSVEX_DEFAULT>
<h1>hello</h1>
</Layout_MDSVEX_DEFAULT>`,
output.code
);
});
test('custom layouts should work - when everything is in a random order', async t => {
const output = await mdsvex({ layout: 'path/to/layout' }).markup({
content: `
# hello
<script>
import Layout_MDSVEX_DEFAULT from 'path/to/layout';
export let x = 1;
</script>
hello friends
<svelte:window />
<style>

@@ -252,4 +315,23 @@ h1 {

</style>
boo boo boo
`,
filename: 'file.svexy',
});
t.equal(
`<script>
import Layout_MDSVEX_DEFAULT from 'path/to/layout';
export let x = 1;
</script>
<style>
h1 {
color: pink;
}
</style>
<svelte:window />
<Layout_MDSVEX_DEFAULT>
<h1>hello</h1>
<p>hello friends</p>
<p>boo boo boo</p>
</Layout_MDSVEX_DEFAULT>`,

@@ -259,2 +341,230 @@ output.code

});
test('YAML front-matter should be injected into the component module script', async t => {
const output = await mdsvex().markup({
content: `---
string: value
string2: 'value2'
array: [1, 2, 3]
number: 999
---
# hello
`,
filename: 'file.svexy',
});
t.equal(
`<script context="module">
export const metadata = {"string":"value","string2":"value2","array":[1,2,3],"number":999};
</script>
<h1>hello</h1>
`,
output.code
);
});
test('YAML front-matter should be injected into the component module script - even if there is already a module script', async t => {
const output = await mdsvex().markup({
content: `---
string: value
string2: 'value2'
array: [1, 2, 3]
number: 999
---
<script context="module">
let thing = 27;
</script>
# hello
`,
filename: 'file.svexy',
});
t.equal(
`<script context="module">
export const metadata = {"string":"value","string2":"value2","array":[1,2,3],"number":999};
let thing = 27;
</script>
<h1>hello</h1>
`,
output.code
);
});
test('YAML front-matter should be injected into the component module script - even if there is already a module script with unquoted attributes', async t => {
const output = await mdsvex().markup({
content: `---
string: value
string2: 'value2'
array: [1, 2, 3]
number: 999
---
<script context=module>
let thing = 27;
</script>
# hello
`,
filename: 'file.svexy',
});
t.equal(
`<script context=module>
export const metadata = {"string":"value","string2":"value2","array":[1,2,3],"number":999};
let thing = 27;
</script>
<h1>hello</h1>
`,
output.code
);
});
test('YAML front-matter should be injected into the component module script - even if there is already a module script with random attributes', async t => {
const output = await mdsvex().markup({
content: `---
string: value
string2: 'value2'
array: [1, 2, 3]
number: 999
---
<script type="ts" lang=whatever context=module thing="whatsit" doodaa=thingamabob>
let thing = 27;
</script>
# hello
`,
filename: 'file.svexy',
});
t.equal(
`<script type="ts" lang=whatever context=module thing="whatsit" doodaa=thingamabob>
export const metadata = {"string":"value","string2":"value2","array":[1,2,3],"number":999};
let thing = 27;
</script>
<h1>hello</h1>
`,
output.code
);
});
test('YAML front-matter should be injected passed to custom layouts', async t => {
const output = await mdsvex({ layout: 'path/to/layout' }).markup({
content: `---
string: value
string2: 'value2'
array: [1, 2, 3]
number: 999
---
<script context="module">
let thing = 27;
</script>
# hello
`,
filename: 'file.svexy',
});
t.equal(
`<script context="module">
export const metadata = {"string":"value","string2":"value2","array":[1,2,3],"number":999};
let thing = 27;
</script>
<script>
import Layout_MDSVEX_DEFAULT from 'path/to/layout';
</script>
<Layout_MDSVEX_DEFAULT {...metadata}>
<h1>hello</h1>
</Layout_MDSVEX_DEFAULT>`,
output.code
);
});
test('Custom layout can be set via frontmatter', async t => {
const output = await mdsvex().markup({
content: `---
layout: ./path/to/layout
string: value
string2: 'value2'
array: [1, 2, 3]
number: 999
---
<script context="module">
let thing = 27;
</script>
# hello
`,
filename: 'file.svexy',
});
t.equal(
`<script context="module">
export const metadata = {"layout":"./path/to/layout","string":"value","string2":"value2","array":[1,2,3],"number":999};
let thing = 27;
</script>
<script>
import Layout_MDSVEX_DEFAULT from './path/to/layout';
</script>
<Layout_MDSVEX_DEFAULT {...metadata}>
<h1>hello</h1>
</Layout_MDSVEX_DEFAULT>`,
output.code
);
});
test('layouts provided via frontmatter should overwrite defaults', async t => {
const output = await mdsvex({ layout: 'other/path/to/layout' }).markup({
content: `---
layout: ./path/to/layout
string: value
string2: 'value2'
array: [1, 2, 3]
number: 999
---
<script context="module">
let thing = 27;
</script>
# hello
`,
filename: 'file.svexy',
});
t.equal(
`<script context="module">
export const metadata = {"layout":"./path/to/layout","string":"value","string2":"value2","array":[1,2,3],"number":999};
let thing = 27;
</script>
<script>
import Layout_MDSVEX_DEFAULT from './path/to/layout';
</script>
<Layout_MDSVEX_DEFAULT {...metadata}>
<h1>hello</h1>
</Layout_MDSVEX_DEFAULT>`,
output.code
);
});
}

@@ -10,3 +10,2 @@ import { parse_svelte_block } from '../../src/parsers';

export default function(test) {
// console.log(test);
const svelte_blocks = [

@@ -95,3 +94,2 @@ [

});
// console.log('boo', name);
}

@@ -10,3 +10,2 @@ import { parse_svelte_tag } from '../../src/parsers';

export default function(test) {
// console.log(test);
const svelte_tags = [

@@ -13,0 +12,0 @@ ['component', 'svelte:component'],

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc