xiangjsoncraft 1.2.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/create.js ADDED
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import inquirer from 'inquirer';
6
+ import chalk from 'chalk';
7
+ import ora from 'ora';
8
+
9
+ // 解决 ESModule __dirname 问题
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ // 框架根目录
14
+ const frameworkRoot = path.resolve(__dirname, '..');
15
+ // 模板目录
16
+ const templateDir = path.join(frameworkRoot, 'template');
17
+
18
+ // 欢迎信息
19
+ console.log(chalk.blue(`
20
+ ┌─────────────────────────────────┐
21
+ │ XiangJsonCraft 2.0.1 │
22
+ │ Write JSON, Get a Website │
23
+ └─────────────────────────────────┘
24
+ `));
25
+
26
+ // 第一步:获取项目名称(从命令行参数)
27
+ const args = process.argv.slice(2);
28
+ let projectName = args[0] || 'xiangjsoncraft-app';
29
+
30
+ // 第二步:确认创建项目
31
+ const confirmAnswers = await inquirer.prompt([
32
+ {
33
+ type: 'confirm',
34
+ name: 'confirmCreate',
35
+ message: `是否要创建项目「${projectName}」?`,
36
+ default: true
37
+ }
38
+ ]);
39
+
40
+ if (!confirmAnswers.confirmCreate) {
41
+ console.log(chalk.yellow('✅ 项目创建已取消'));
42
+ process.exit(0);
43
+ }
44
+
45
+ // 第三步:选择模板(仅保留基础模板,确保核心功能)
46
+ const templateAnswers = await inquirer.prompt([
47
+ {
48
+ type: 'list',
49
+ name: 'template',
50
+ message: '请选择项目模板:',
51
+ choices: [
52
+ { name: '基础模板(快速上手)', value: 'basic' }
53
+ ],
54
+ default: 'basic'
55
+ }
56
+ ]);
57
+
58
+ // 第四步:创建项目
59
+ const spinner = ora('正在创建项目...').start();
60
+ try {
61
+ // 项目目标目录
62
+ const projectDir = path.resolve(process.cwd(), projectName);
63
+
64
+ // 检查目录是否已存在
65
+ if (fs.existsSync(projectDir)) {
66
+ spinner.fail(chalk.red('❌ 项目目录已存在,请删除后重试'));
67
+ process.exit(1);
68
+ }
69
+
70
+ // 1. 创建项目目录
71
+ fs.ensureDirSync(projectDir);
72
+
73
+ // 2. 生成 package.json(修复本地路径依赖问题)
74
+ const packageJson = {
75
+ "name": projectName,
76
+ "version": "1.0.0",
77
+ "description": "XiangJsonCraft 项目",
78
+ "type": "module",
79
+ "scripts": {
80
+ "start": "npx serve .",
81
+ "test": "echo \"Error: no test specified\" && exit 1"
82
+ },
83
+ "dependencies": {
84
+ // 指向 npm 仓库版本,而非本地路径
85
+ "xiangjsoncraft": "^2.0.1"
86
+ },
87
+ "license": "MIT"
88
+ };
89
+ fs.writeJsonSync(path.join(projectDir, 'package.json'), packageJson, { spaces: 2 });
90
+
91
+ // 3. 生成核心文件(解决空壳问题)
92
+ // 3.1 生成 index.html(核心入口)
93
+ const indexHtml = `<!DOCTYPE html>
94
+ <html lang="zh-CN">
95
+ <head>
96
+ <meta charset="UTF-8">
97
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
98
+ <title>${projectName} - XiangJsonCraft 2.0</title>
99
+ <!-- 引入框架核心 -->
100
+ <script src="./node_modules/xiangjsoncraft/dist/xiangjsoncraft.umd.js"></script>
101
+ </head>
102
+ <body>
103
+ <div id="app"></div>
104
+ <!-- 引入配置文件 -->
105
+ <script type="module">
106
+ import config from './config.json' assert { type: 'json' };
107
+ // 渲染 JSON 配置
108
+ window.XiangJsonCraft.render(config, document.getElementById('app'));
109
+ </script>
110
+ </body>
111
+ </html>`;
112
+ fs.writeFileSync(path.join(projectDir, 'index.html'), indexHtml);
113
+
114
+ // 3.2 生成 config.json(核心配置文件)
115
+ const configJson = {
116
+ "framework": "XiangJsonCraft 2.0.1",
117
+ "styles": {
118
+ "body": {
119
+ "backgroundColor": "#f0f4f8",
120
+ "minHeight": "100vh",
121
+ "margin": "0",
122
+ "padding": "20px",
123
+ "fontFamily": "Arial, sans-serif"
124
+ },
125
+ "#app": {
126
+ "maxWidth": "1200px",
127
+ "margin": "0 auto"
128
+ },
129
+ ".app-title": {
130
+ "fontSize": "2rem",
131
+ "color": "#2d3748",
132
+ "textAlign": "center",
133
+ "marginBottom": "40px"
134
+ },
135
+ ".app-desc": {
136
+ "fontSize": "1.2rem",
137
+ "color": "#4a5568",
138
+ "textAlign": "center"
139
+ }
140
+ },
141
+ "content": {
142
+ ".app-title": {
143
+ "value": "欢迎使用 XiangJsonCraft 2.0.1",
144
+ "isHtml": false
145
+ },
146
+ ".app-desc": {
147
+ "value": "零CSS零JS、纯JSON驱动的轻量前端框架",
148
+ "isHtml": false
149
+ }
150
+ }
151
+ };
152
+ fs.writeJsonSync(path.join(projectDir, 'config.json'), configJson, { spaces: 2 });
153
+
154
+ // 3.3 生成 README.md(使用说明)
155
+ const readmeMd = `# ${projectName}
156
+ 基于 XiangJsonCraft 2.0.1 的项目
157
+
158
+ ## 快速开始
159
+ 1. 安装依赖:
160
+ npm install
161
+
162
+ 2. 启动开发服务器:
163
+ npm run start
164
+
165
+ 3. 自定义项目:
166
+ 修改 config.json 文件(所有样式/内容/交互都在这里配置)
167
+
168
+ ## 核心特性
169
+ - 纯 JSON 驱动,无需编写 CSS/JS
170
+ - 响应式布局,适配所有设备
171
+ - 实时热更新,修改配置立即生效
172
+ - 零配置部署,直接上传文件即可发布
173
+ `;
174
+ fs.writeFileSync(path.join(projectDir, 'README.md'), readmeMd);
175
+
176
+ spinner.succeed(chalk.green(`✅ 项目「${projectName}」创建成功!`));
177
+
178
+ // 第五步:安装依赖提示
179
+ const installAnswers = await inquirer.prompt([
180
+ {
181
+ type: 'confirm',
182
+ name: 'confirmInstall',
183
+ message: '是否立即安装项目依赖?',
184
+ default: true
185
+ }
186
+ ]);
187
+
188
+ if (installAnswers.confirmInstall) {
189
+ const installSpinner = ora('正在安装依赖...').start();
190
+ try {
191
+ // 切换到项目目录执行安装
192
+ const { execSync } = await import('child_process');
193
+ execSync('npm install --legacy-peer-deps', {
194
+ cwd: projectDir,
195
+ stdio: 'ignore'
196
+ });
197
+ installSpinner.succeed(chalk.green('✅ 依赖安装成功!'));
198
+ } catch (err) {
199
+ installSpinner.fail(chalk.yellow('⚠️ 依赖安装失败,请手动进入项目目录执行 npm install --legacy-peer-deps'));
200
+ }
201
+ }
202
+
203
+ // 输出使用指南
204
+ console.log(chalk.cyan(`
205
+ 使用指南
206
+ 1. 进入项目目录:
207
+ cd ${projectName}
208
+ 2. 启动开发服务器:
209
+ npm run start
210
+ 3. 自定义项目:
211
+ 修改 config.json 文件(所有样式/内容/交互都在这里配置)
212
+ 4. 部署上线:
213
+ 直接将项目文件上传到服务器即可,无需打包
214
+
215
+ 📚 官方文档:https://github.com/dxiangwiki/xiangjsoncraft
216
+ 💡 提示:必须使用本地服务器运行,不能直接打开HTML文件!
217
+ `));
218
+
219
+ } catch (err) {
220
+ spinner.fail(chalk.red(`❌ 项目创建失败:${err.message}`));
221
+ process.exit(1);
222
+ }
@@ -1,82 +1 @@
1
- (function(g,f){typeof exports==='object'&&typeof module!=='undefined'?f(exports):typeof define==='function'&&define.amd?define(['exports'],f):(g=typeof globalThis!=='undefined'?globalThis:g||self,f(g.XiangJsonCraft={}));})(this,(function(exports){'use strict';// 封装通用JSON样式渲染函数,支持任意CSS选择器、HTML内容、媒体查询(v1.1.0核心功能)
2
- function renderJsonStyles() {
3
- // 核心原则:本地config.json永远最高优先级,加载失败再用CDN官方配置
4
- const localConfigUrl = './config.json'; // 本地用户自定义配置
5
- const cdnConfigUrl = 'https://cdn.jsdelivr.net/npm/xiangjsoncraft@1.1.1/config.json'; // CDN兜底配置
6
-
7
- // 先尝试加载本地config.json
8
- fetch(localConfigUrl)
9
- .then(response => {
10
- // 本地配置存在(状态码200),则使用本地配置
11
- if (response.ok) {
12
- console.log('🔧 检测到本地config.json,优先加载用户自定义配置');
13
- return response.json();
14
- }
15
- // 本地配置不存在/加载失败,切换到CDN兜底配置
16
- console.log('ℹ️ 本地未检测到config.json,加载CDN官方示例配置');
17
- return fetch(cdnConfigUrl).then(res => {
18
- if (!res.ok) throw new Error('CDN官方配置加载失败');
19
- return res.json();
20
- });
21
- })
22
- .then(config => {
23
- // 获取或创建样式块,避免重复创建
24
- const styleBlock = document.getElementById('dynamic-styles') || createStyleBlock();
25
- if (!styleBlock) return console.error('❌ 样式块创建失败,无法渲染样式');
26
-
27
- // 生成CSS规则
28
- let cssRules = '';
29
-
30
- // 处理所有选择器样式(支持任意CSS选择器、媒体查询)
31
- if (config.styles && typeof config.styles === 'object' && Object.keys(config.styles).length > 0) {
32
- // 遍历所有选择器(类、ID、伪类、媒体查询等)
33
- Object.entries(config.styles).forEach(([selector, styles]) => {
34
- // 过滤空样式,避免无效CSS
35
- if (!styles || typeof styles !== 'object') return;
36
- // 生成该选择器的所有样式属性
37
- const styleProperties = Object.entries(styles)
38
- .map(([prop, value]) => {
39
- // 过滤空属性,驼峰式属性名转换为CSS标准格式
40
- if (!prop || value === undefined || value === null) return '';
41
- const cssProp = prop.replaceCamelCase();
42
- return `${cssProp}: ${value};`;
43
- })
44
- .filter(Boolean) // 移除空属性
45
- .join('\n ');
46
-
47
- // 仅当有样式属性时,添加到CSS规则
48
- if (styleProperties) {
49
- cssRules += `${selector} {\n ${styleProperties}\n}\n\n`;
50
- }
51
- });
52
- }
53
-
54
- // 应用生成的CSS规则到样式块
55
- if (cssRules) {
56
- styleBlock.innerHTML = cssRules;
57
- }
58
-
59
- // 处理内容配置(支持纯文本/HTML内容,通过isHtml标识)
60
- if (config.content && typeof config.content === 'object' && Object.keys(config.content).length > 0) {
61
- Object.entries(config.content).forEach(([selector, content]) => {
62
- // 过滤无效选择器和内容
63
- if (!selector || !content || !content.hasOwnProperty('value')) return;
64
- const elements = document.querySelectorAll(selector);
65
- elements.forEach(el => {
66
- if (!el) return;
67
- // 支持HTML内容或纯文本,默认纯文本
68
- if (content.isHtml) {
69
- el.innerHTML = content.value;
70
- } else {
71
- el.textContent = content.value;
72
- }
73
- });
74
- });
75
- }
76
-
77
- console.log('✅ XiangJsonCraft v1.1.1 渲染成功!');
78
- })
79
- .catch(error => {
80
- console.error('❌ XiangJsonCraft 处理配置时出错:', error.message);
81
- });
82
- }exports.renderJsonStyles=renderJsonStyles;}));
1
+ !function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).XiangJsonCraft={})}(this,function(n){"use strict";function e(){const n=n=>{console.error(chalk?.red(`❌ XiangJsonCraft 2.0 错误: ${n}`)||`❌ XiangJsonCraft 2.0 错误: ${n}`)};fetch("./config.json").then(async n=>{if(!n.ok)throw new Error("配置文件加载失败,请检查config.json是否存在");return n.json()}).then(e=>{if("object"!=typeof e||null===e||Array.isArray(e))return n("config.json 格式错误,必须是标准JSON对象");const t=document.getElementById("xiangjsoncraft-styles")||function(){const n=document.createElement("style");return n.id="xiangjsoncraft-styles",document.head.insertBefore(n,document.head.firstChild),n}(),{styles:r={}}=e;let o="";Object.entries(r).forEach(([n,e])=>{const t=String(n).trim();if(!t||"object"!=typeof e||null===e||Array.isArray(e))return;const r=Object.entries(e).map(([n,e])=>{const t=String(n).trim();if(!t||null==e||""===String(e).trim())return"";return`${t.replaceCamelCase()}: ${String(e).trim()};`}).filter(Boolean).join("\n ");r&&(o+=`${t} {\n ${r}\n}\n\n`)}),o&&(t.innerHTML=o);const{content:i={}}=e;Object.entries(i).forEach(([n,e])=>{const t=String(n).trim();if(!t||"object"!=typeof e||null===e||Array.isArray(e))return;if(!e.hasOwnProperty("value"))return;const r=document.querySelectorAll(t);if(0===r.length)return;const{value:o,isHtml:i=!1}=e,s=String(o).trim();r.forEach(n=>{i?n.innerHTML=s:n.textContent=s})}),console.log(chalk?.green("✅ XiangJsonCraft 2.0 渲染成功!")||"✅ XiangJsonCraft 2.0 渲染成功!"),console.log(chalk?.blue("ℹ️ 修改config.json后刷新页面即可生效")||"ℹ️ 修改config.json后刷新页面即可生效")}).catch(e=>{n(e.message)})}String.prototype.replaceCamelCase=function(n="-"){return this.replace(/[A-Z]/g,e=>`${n}${e.toLowerCase()}`)},"undefined"!=typeof window&&(window.XiangJsonCraft={renderJsonStyles:e,version:"2.0.0"}),n.renderJsonStyles=e});
package/package.json CHANGED
@@ -1,33 +1,56 @@
1
1
  {
2
2
  "name": "xiangjsoncraft",
3
- "version": "1.2.0",
4
- "description": "简单而强大的JSON配置与HTML页面渲染工具,支持任意CSS选择器、响应式设计、HTML内容动态注入,轻量无依赖",
5
- "main": "dist/xiangjsoncraft.cjs.js",
6
- "module": "dist/xiangjsoncraft.esm.js",
7
- "browser": "dist/xiangjsoncraft.umd.js",
3
+ "version": "2.0.1",
4
+ "description": "零CSS零JS、纯JSON驱动的轻量前端框架 | Write JSON, Get a Website",
5
+ "type": "module",
6
+ "bin": {
7
+ "xiangjsoncraft": "./bin/create.js",
8
+ "create-xiangjsoncraft": "./bin/create.js"
9
+ },
10
+ "main": "./dist/xiangjsoncraft.umd.js",
11
+ "module": "./src/renderJson.js",
8
12
  "files": [
13
+ "bin",
9
14
  "dist",
10
- "renderJson.js",
11
- "config.json",
12
- "README.md",
13
- "LICENSE"
15
+ "src",
16
+ "template",
17
+ "rollup.config.js",
18
+ "README.md"
14
19
  ],
15
- "scripts": {
16
- "build": "rollup -c",
17
- "dev": "npx serve ."
18
- },
19
- "devDependencies": {
20
- "rollup": "^4.12.0"
21
- },
22
20
  "keywords": [
23
- "json-render",
24
- "dynamic-css",
25
- "html-render",
26
- "json-config",
27
- "frontend-tool",
28
- "xiangjsoncraft"
21
+ "json",
22
+ "framework",
23
+ "no-css",
24
+ "no-js",
25
+ "low-code",
26
+ "轻量框架",
27
+ "json驱动",
28
+ "可视化配置",
29
+ "前端零代码"
29
30
  ],
30
- "author": "董翔 <3631247406@qq.com>",
31
+ "author": "",
31
32
  "license": "MIT",
32
- "homepage": "https://www.npmjs.com/package/xiangjsoncraft"
33
- }
33
+ "dependencies": {
34
+ "chalk": "^5.3.0",
35
+ "commander": "^12.0.0",
36
+ "fs-extra": "^11.2.0",
37
+ "inquirer": "^9.2.16",
38
+ "ora": "^8.0.1"
39
+ },
40
+ "devDependencies": {
41
+ "@rollup/plugin-terser": "^0.4.4",
42
+ "rollup": "^4.9.6"
43
+ },
44
+ "scripts": {
45
+ "build": "npx rollup -c rollup.config.js",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/dxiangwiki/xiangjsoncraft.git"
51
+ },
52
+ "homepage": "https://github.com/dxiangwiki/xiangjsoncraft",
53
+ "bugs": {
54
+ "url": "https://github.com/dxiangwiki/xiangjsoncraft/issues"
55
+ }
56
+ }
@@ -0,0 +1,21 @@
1
+ import terser from '@rollup/plugin-terser'; // 替换原来的 rollup-plugin-terser
2
+ export default {
3
+ input: 'src/renderJson.js',
4
+ output: {
5
+ file: 'dist/xiangjsoncraft.umd.js',
6
+ format: 'umd',
7
+ name: 'XiangJsonCraft',
8
+ compact: true
9
+ },
10
+ plugins: [
11
+ terser({
12
+ compress: {
13
+ drop_console: false,
14
+ pure_funcs: []
15
+ },
16
+ format: {
17
+ comments: false
18
+ }
19
+ })
20
+ ]
21
+ };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * XiangJsonCraft 2.0 核心渲染逻辑
3
+ * 纯JSON驱动的前端框架核心 - Write JSON, Get a Website
4
+ * @version 2.0.0
5
+ */
6
+
7
+ // 驼峰转短横线(CSS属性名转换)
8
+ String.prototype.replaceCamelCase = function (separator = '-') {
9
+ return this.replace(/[A-Z]/g, (match) => `${separator}${match.toLowerCase()}`);
10
+ };
11
+
12
+ // 创建唯一样式块
13
+ function createStyleBlock() {
14
+ const style = document.createElement('style');
15
+ style.id = 'xiangjsoncraft-styles';
16
+ document.head.insertBefore(style, document.head.firstChild);
17
+ return style;
18
+ }
19
+
20
+ // 核心渲染函数
21
+ export function renderJsonStyles() {
22
+ // 配置文件路径(固定与HTML同目录)
23
+ const CONFIG_PATH = './config.json';
24
+
25
+ // 错误处理
26
+ const handleError = (msg) => {
27
+ console.error(chalk?.red(`❌ XiangJsonCraft 2.0 错误: ${msg}`) || `❌ XiangJsonCraft 2.0 错误: ${msg}`);
28
+ };
29
+
30
+ // 加载配置并渲染
31
+ fetch(CONFIG_PATH)
32
+ .then(async (res) => {
33
+ if (!res.ok) throw new Error('配置文件加载失败,请检查config.json是否存在');
34
+ return res.json();
35
+ })
36
+ .then((config) => {
37
+ // 配置校验
38
+ if (typeof config !== 'object' || config === null || Array.isArray(config)) {
39
+ return handleError('config.json 格式错误,必须是标准JSON对象');
40
+ }
41
+
42
+ // 1. 渲染样式
43
+ const styleBlock = document.getElementById('xiangjsoncraft-styles') || createStyleBlock();
44
+ const { styles = {} } = config;
45
+ let cssRules = '';
46
+
47
+ // 生成CSS规则
48
+ Object.entries(styles).forEach(([selector, styleObj]) => {
49
+ const selectorStr = String(selector).trim();
50
+ if (!selectorStr || typeof styleObj !== 'object' || styleObj === null || Array.isArray(styleObj)) return;
51
+
52
+ const styleProps = Object.entries(styleObj)
53
+ .map(([prop, value]) => {
54
+ const propStr = String(prop).trim();
55
+ if (!propStr || value === undefined || value === null || String(value).trim() === '') return '';
56
+ const cssProp = propStr.replaceCamelCase();
57
+ const cssValue = String(value).trim();
58
+ return `${cssProp}: ${cssValue};`;
59
+ })
60
+ .filter(Boolean)
61
+ .join('\n ');
62
+
63
+ if (styleProps) {
64
+ cssRules += `${selectorStr} {\n ${styleProps}\n}\n\n`;
65
+ }
66
+ });
67
+
68
+ // 注入样式
69
+ if (cssRules) {
70
+ styleBlock.innerHTML = cssRules;
71
+ }
72
+
73
+ // 2. 渲染内容
74
+ const { content = {} } = config;
75
+ Object.entries(content).forEach(([selector, contentObj]) => {
76
+ const selectorStr = String(selector).trim();
77
+ if (!selectorStr || typeof contentObj !== 'object' || contentObj === null || Array.isArray(contentObj)) return;
78
+ if (!contentObj.hasOwnProperty('value')) return;
79
+
80
+ const targetNodes = document.querySelectorAll(selectorStr);
81
+ if (targetNodes.length === 0) return;
82
+
83
+ const { value, isHtml = false } = contentObj;
84
+ const contentValue = String(value).trim();
85
+
86
+ targetNodes.forEach((node) => {
87
+ if (isHtml) {
88
+ node.innerHTML = contentValue;
89
+ } else {
90
+ node.textContent = contentValue;
91
+ }
92
+ });
93
+ });
94
+
95
+ // 渲染成功提示
96
+ console.log(chalk?.green('✅ XiangJsonCraft 2.0 渲染成功!') || '✅ XiangJsonCraft 2.0 渲染成功!');
97
+ console.log(chalk?.blue('ℹ️ 修改config.json后刷新页面即可生效') || 'ℹ️ 修改config.json后刷新页面即可生效');
98
+
99
+ })
100
+ .catch((err) => {
101
+ handleError(err.message);
102
+ });
103
+ }
104
+
105
+ // 暴露全局变量(兼容非模块化环境)
106
+ if (typeof window !== 'undefined') {
107
+ window.XiangJsonCraft = {
108
+ renderJsonStyles,
109
+ version: '2.0.0'
110
+ };
111
+ }