├── .gitignore ├── LICENSE ├── README.md ├── __src ├── converter │ └── index.js ├── index.js ├── parser │ ├── get-component-type.js │ ├── index.js │ ├── jsx2js.js │ ├── parser-markdown.js │ └── smart-join.js ├── test.js └── vite │ └── index.js ├── __v2 ├── _test.js ├── clean.js ├── hast.js ├── html2js.js ├── index.js ├── pre-parse │ └── clean-md.js ├── readme.md ├── test.js ├── transformers │ └── vite │ │ └── index.js ├── transpiler │ ├── get-component-type.js │ ├── import-plugin.js │ ├── index.js │ ├── jsx2js.js │ └── process-text.js └── utils │ ├── is-object.js │ └── split-between.js ├── package-lock.json ├── package.json ├── preview ├── Hi.js ├── InteractiveBlock.js ├── Scene.js ├── __main2.js ├── index.html ├── main.js ├── package-lock.json ├── package.json ├── public │ └── vite.svg ├── src │ └── pages │ │ ├── [blog] │ │ ├── [lang] │ │ │ └── index.js │ │ └── index.js │ │ ├── about.js │ │ ├── articles │ │ ├── [data] │ │ │ └── [color] │ │ │ │ └── index.js │ │ └── a1.js │ │ ├── index.js │ │ └── me.js ├── test.mdz ├── test.mdz.__ └── vite.config.js ├── rollup.config.js └── src ├── bundlers └── vite.js ├── example.md ├── index.js ├── test.js ├── transpiler ├── index.js ├── parser.js ├── process.js └── transpile.js └── utils ├── component-type.js ├── hyperscript.js ├── index.js ├── parse-yml.js └── process-attributes.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ZAKARIA ELALAOUI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!NOTE] 2 | > This project is part of the [ZikoJS](https://github.com/zakarialaoui10/ziko.js) ecosystem. 3 | 4 | # MDZjs 5 | A Markdown preprocessor for Zikojs. Markdown in Zikojs. 6 | It combines the simplicity of Markdown syntax with the power and flexibility of ***Javascript*** 7 | 8 | ## Install 9 | ```bash 10 | npm i mdzjs 11 | ``` 12 | 13 | ## Config 14 | ```js 15 | import {defineConfig} from "vite" 16 | import MDZ from "mdzjs/vite" 17 | export default defineConfig({ 18 | plugins : [ 19 | MDZ() 20 | ] 21 | }) 22 | ``` 23 | 24 | ## Usage 25 | 26 | *Article.mdz :* 27 | 28 | ```js 29 | --- 30 | title : MDZ 31 | name : world 32 | __props__ : 33 | background : tomato 34 | data : [] 35 | --- 36 | import data from "./data.js"; 37 | import InteractiveComponent from "./InteractiveComponent.js"; 38 | 39 | # Hello {name} 40 | 41 | 42 | 43 | ``` 44 | 45 | ```js 46 | // main.js 47 | import Article,{title} from "./Article.mdz" 48 | ``` 49 | 50 | ## Features 51 | - **Simple Integration :** Write Markdown as usual, and inject Zikojs elements wherever needed. 52 | - **Extensible :** Create custom interactive components using Zikojs and use them in any Markdown file. 53 | - **Reusable :** MDZ exports a default functional component, allowing you to call it multiple times with different data, enabling dynamic and versatile use. 54 | - **Frontmatter Support :** Use `YAML` syntax in to include metadata like titles, descriptions, or configurations in your Markdown files, and define props to pass data dynamically to Zikojs components. 55 | 56 | - **Markdown :** Use standard Markdown syntax for writing content. 57 | - **JSX Syntax :** Write components in JSX within Markdown, enabling easy integration of Zikojs elements with JavaScript and HTML.. 58 | - **Props :** Pass data to components through props, enabling dynamic rendering and customization of content within your Markdown files. 59 | - **ESM :** Supports ECMAScript Modules (ESM), allowing you to import and export modules 60 | - **Expressions :** MDZjs lets you use JS expressions inside curly braces, like Hello {name}. 61 | These expressions can be full JS programs, as long as they evaluate to something renderable. For example, you can use an IIFE like this: 62 | ```js 63 | Hello {(()=>{ 64 | const names = ["world", "everyone"]; 65 | const {length} = names 66 | return names[Math.floor(Math.random()*length)] 67 | })()} 68 | ``` 69 | - **Internal scripts :** Include JS logic that runs alongside MDZjs components but isn't rendered in the output. 70 | They can initialize variables or perform side effects... 71 | 72 | ```html 73 | 82 | ``` 83 | - **Interleaving :** You can use inline markdown elements inside HTML or Zikojs Components 84 | 85 | ```html 86 |
87 | ***Hello {name}*** 88 |
89 | ``` 90 | # ⭐️ Show your support 91 | 92 | If you appreciate the project, kindly demonstrate your support by giving it a star!
93 | 94 | [![Star](https://img.shields.io/github/stars/zakarialaoui10/mdzjs?style=social)](https://github.com/zakarialaoui10/mdzjs) 95 | 96 | # License 97 | This projet is licensed under the terms of MIT License 98 | -------------------------------------------------------------------------------- /__src/converter/index.js: -------------------------------------------------------------------------------- 1 | import { parseMDZ } from "../parser/index.js" 2 | const getZikoScript=(MDZ)=>{ 3 | let {modules,attributes,components}=parseMDZ(MDZ) 4 | return ` 5 | import {Flex, HTMLWrapper} from "ziko"; 6 | ${modules?.join(";\n")}; 7 | 8 | export const attributes = ${JSON.stringify(attributes)} 9 | 10 | export default ()=> Flex( 11 | ${components.join(",\n ")} 12 | ).vertical(0, "space-around") 13 | ` 14 | } 15 | export{ 16 | getZikoScript 17 | } -------------------------------------------------------------------------------- /__src/index.js: -------------------------------------------------------------------------------- 1 | export {parseMDZ} from "./parser/index.js" 2 | export {MDZ} from "./vite/index.js" -------------------------------------------------------------------------------- /__src/parser/get-component-type.js: -------------------------------------------------------------------------------- 1 | function getComponentType(component) { 2 | const trimmedComponent = component.trim(); 3 | const tagRegex = /^<([a-zA-Z][a-z0-9]*)/; 4 | const match = trimmedComponent.match(tagRegex); 5 | if (match) { 6 | const tagName = match[1]; 7 | if (tagName[0] === tagName[0].toUpperCase()) { 8 | return "jsx"; 9 | } else { 10 | return "html"; 11 | } 12 | } 13 | return "unknown"; 14 | } 15 | export{ 16 | getComponentType 17 | } -------------------------------------------------------------------------------- /__src/parser/index.js: -------------------------------------------------------------------------------- 1 | import { smartJoin } from './smart-join.js'; 2 | import { jsx2js } from './jsx2js.js'; 3 | import { getComponentType } from './get-component-type.js'; 4 | import { parseMarkdown } from './parser-markdown.js'; 5 | function parseMDZ(markdown) { 6 | const { body, attributes } = parseMarkdown(markdown.trim("")); 7 | const {modules, ...props} = attributes 8 | let JSXIndexesBefore = [], JSXIndexesAfter = []; 9 | const Output = body.split("\n").filter((n) => n !== ""); 10 | Output.filter((n, i) => { 11 | if (getComponentType(n) === "jsx") JSXIndexesBefore.push(i); 12 | }); 13 | const JoinedTags = smartJoin(Output, JSXIndexesBefore); 14 | JoinedTags.filter((n, i) => { 15 | if (getComponentType(n) === "jsx") JSXIndexesAfter.push(i); 16 | }); 17 | let components = []; 18 | JoinedTags.forEach((n, i) => { 19 | if (JSXIndexesAfter.includes(i)) components.push(jsx2js(n)); 20 | else components.push(`HTMLWrapper("${n}")`); 21 | }); 22 | return{ 23 | components, 24 | modules, 25 | attributes : props 26 | } 27 | } 28 | export{ 29 | parseMDZ 30 | } -------------------------------------------------------------------------------- /__src/parser/jsx2js.js: -------------------------------------------------------------------------------- 1 | function jsx2js(component) { 2 | const regex = /<(\w+)([^>]*)\/?>/; 3 | const match = component.match(regex); 4 | if (!match) { 5 | throw new Error("Invalid component format"); 6 | } 7 | const componentName = match[1]; 8 | const attributesString = match[2]; 9 | const attributes = {}; 10 | const attrRegex = /(\w+)="([^"]*)"/g; 11 | let attrMatch; 12 | while ((attrMatch = attrRegex.exec(attributesString)) !== null) { 13 | attributes[attrMatch[1]] = attrMatch[2]; 14 | } 15 | const attributesArray = Object.entries(attributes).map(([key, value]) => { 16 | return `${key}:${JSON.stringify(value)}`; 17 | }); 18 | const attributesStringFormatted = attributesArray.join(','); 19 | return `${componentName}({${attributesStringFormatted}})`; 20 | } 21 | export{ 22 | jsx2js 23 | } -------------------------------------------------------------------------------- /__src/parser/parser-markdown.js: -------------------------------------------------------------------------------- 1 | import { marked } from 'marked'; 2 | import fm from 'front-matter'; 3 | 4 | function parseMarkdown(markdown) { 5 | let FMProps = {}; 6 | function preprocess(markdown) { 7 | const { attributes, body } = fm(markdown); 8 | FMProps = { ...attributes }; 9 | return body; 10 | } 11 | marked.use({ hooks: { preprocess } }); 12 | const body = marked.parse(markdown); 13 | return { body, attributes: FMProps }; 14 | } 15 | 16 | export{ 17 | parseMarkdown, 18 | } -------------------------------------------------------------------------------- /__src/parser/smart-join.js: -------------------------------------------------------------------------------- 1 | function smartJoin(strings = [], indexes = []) { 2 | const result = []; 3 | let lastIndex = 0; 4 | indexes.forEach(index => { 5 | if (index > lastIndex) { 6 | result.push(strings.slice(lastIndex, index).join('')); 7 | } 8 | result.push(strings[index]); 9 | lastIndex = index + 1; 10 | }); 11 | if (lastIndex < strings.length) { 12 | result.push(...strings.slice(lastIndex)); 13 | } 14 | return result; 15 | } 16 | export { 17 | smartJoin 18 | } -------------------------------------------------------------------------------- /__src/test.js: -------------------------------------------------------------------------------- 1 | import { getZikoScript } from "./converter/index.js"; 2 | const markdownContent = ` 3 | --- 4 | modules: 5 | - import Component from "./Component" 6 | - import OtherComponent from "./OtherComponent" 7 | - import OtherComonenetWithProps from "./OtherComonenetWithProps" 8 | title: MDZ 9 | --- 10 | Para 11 | [Link](#hi) 12 | 13 | 14 | 15 | line2 16 | 17 | 18 | 19 | `; 20 | const script = getZikoScript(markdownContent); 21 | console.log(script) -------------------------------------------------------------------------------- /__src/vite/index.js: -------------------------------------------------------------------------------- 1 | import { getZikoScript } from "../converter/index.js"; 2 | export function MDZ(){ 3 | return { 4 | name: 'MDZ', 5 | transform(src, id) { 6 | if (id.endsWith('.mdz')) { 7 | console.log(src) 8 | return { 9 | code: getZikoScript(src), 10 | map: null, 11 | }; 12 | } 13 | }, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /__v2/_test.js: -------------------------------------------------------------------------------- 1 | import { transpileMDZ } from "./transpiler/index.js"; 2 | 3 | let cos = Math.cos 4 | const Markdown = `--- 5 | title: "Example Page" 6 | author: "John Doe" 7 | count : 10 8 | __Props__ : { 9 | color : "red", 10 | id : 10 11 | } 12 | --- 13 | 14 | import Button from './Button.js'; 15 | 16 | import {cos} from "ziko"; 17 | 18 | # Hello World 19 |