babel-plugin-mettle 0.1.1 → 0.3.0

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/License CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 maomincoding
3
+ Copyright (c) 2025 maomincoding
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -18,7 +18,7 @@ In your Babel configuration (`.babelrc`, `babel.config.js`, `"babel"` field in p
18
18
 
19
19
  #### `tag=html`
20
20
 
21
- By default, `babel-plugin-mettle` will process all Tagged Templates with a tag function named `html`. To use a different name, use the `tag` option in your Babel configuration:
21
+ By default, `babelPluginMettle` will process all Tagged Templates with a tag function named `html`. To use a different name, use the `tag` option in your Babel configuration:
22
22
 
23
23
  ```js
24
24
  {"plugins":[
@@ -1,284 +1 @@
1
- const MODE_SLASH = 0;
2
- const MODE_TEXT = 1;
3
- const MODE_WHITESPACE = 2;
4
- const MODE_TAGNAME = 3;
5
- const MODE_COMMENT = 4;
6
- const MODE_PROP_SET = 5;
7
- const MODE_PROP_APPEND = 6;
8
- const CHILD_APPEND = 0;
9
- const CHILD_RECURSE = 2;
10
- const TAG_SET = 3;
11
- const PROPS_ASSIGN = 4;
12
- const PROP_SET = MODE_PROP_SET;
13
- const PROP_APPEND = MODE_PROP_APPEND;
14
- const treeify = function (built, fields) {
15
- const _treeify = function (built) {
16
- let tag = '';
17
- let currentProps = null;
18
- const props = [];
19
- const children = [];
20
- for (let i = 1; i < built.length; i++) {
21
- const type = built[i++];
22
- const value = built[i] ? fields[built[i++] - 1] : built[++i];
23
- if (type === TAG_SET) {
24
- tag = value;
25
- } else if (type === PROPS_ASSIGN) {
26
- props.push(value);
27
- currentProps = null;
28
- } else if (type === PROP_SET) {
29
- if (!currentProps) {
30
- currentProps = Object.create(null);
31
- props.push(currentProps);
32
- }
33
- currentProps[built[++i]] = [value];
34
- } else if (type === PROP_APPEND) {
35
- currentProps[built[++i]].push(value);
36
- } else if (type === CHILD_RECURSE) {
37
- children.push(_treeify(value));
38
- } else if (type === CHILD_APPEND) {
39
- children.push(value);
40
- }
41
- }
42
- return {
43
- tag: tag,
44
- props: props,
45
- children: children
46
- };
47
- };
48
- const {
49
- children
50
- } = _treeify(built);
51
- return children.length > 1 ? children : children[0];
52
- };
53
- const build = function (statics) {
54
- let mode = MODE_TEXT;
55
- let buffer = '';
56
- let quote = '';
57
- let current = [0];
58
- let char, propName;
59
- const commit = function (field) {
60
- if (mode === MODE_TEXT && (field || (buffer = buffer.replace(/^\s*\n\s*|\s*\n\s*$/g, '')))) {
61
- current.push(CHILD_APPEND, field, buffer);
62
- } else if (mode === MODE_TAGNAME && (field || buffer)) {
63
- current.push(TAG_SET, field, buffer);
64
- mode = MODE_WHITESPACE;
65
- } else if (mode === MODE_WHITESPACE && buffer === '...' && field) {
66
- current.push(PROPS_ASSIGN, field, 0);
67
- } else if (mode === MODE_WHITESPACE && buffer && !field) {
68
- current.push(PROP_SET, 0, true, buffer);
69
- } else if (mode >= MODE_PROP_SET) {
70
- if (buffer || !field && mode === MODE_PROP_SET) {
71
- current.push(mode, 0, buffer, propName);
72
- mode = MODE_PROP_APPEND;
73
- }
74
- if (field) {
75
- current.push(mode, field, 0, propName);
76
- mode = MODE_PROP_APPEND;
77
- }
78
- }
79
- buffer = '';
80
- };
81
- for (let i = 0; i < statics.length; i++) {
82
- if (i) {
83
- if (mode === MODE_TEXT) {
84
- commit();
85
- }
86
- commit(i);
87
- }
88
- for (let j = 0; j < statics[i].length; j++) {
89
- char = statics[i][j];
90
- if (mode === MODE_TEXT) {
91
- if (char === '<') {
92
- commit();
93
- current = [current];
94
- mode = MODE_TAGNAME;
95
- } else {
96
- buffer += char;
97
- }
98
- } else if (mode === MODE_COMMENT) {
99
- if (buffer === '--' && char === '>') {
100
- mode = MODE_TEXT;
101
- buffer = '';
102
- } else {
103
- buffer = char + buffer[0];
104
- }
105
- } else if (quote) {
106
- if (char === quote) {
107
- quote = '';
108
- } else {
109
- buffer += char;
110
- }
111
- } else if (char === '"' || char === "'") {
112
- quote = char;
113
- } else if (char === '>') {
114
- commit();
115
- mode = MODE_TEXT;
116
- } else if (!mode) ; else if (char === '=') {
117
- mode = MODE_PROP_SET;
118
- propName = buffer;
119
- buffer = '';
120
- } else if (char === '/' && (mode < MODE_PROP_SET || statics[i][j + 1] === '>')) {
121
- commit();
122
- if (mode === MODE_TAGNAME) {
123
- current = current[0];
124
- }
125
- mode = current;
126
- (current = current[0]).push(CHILD_RECURSE, 0, mode);
127
- mode = MODE_SLASH;
128
- } else if (char === ' ' || char === '\t' || char === '\n' || char === '\r') {
129
- // <a disabled>
130
- commit();
131
- mode = MODE_WHITESPACE;
132
- } else {
133
- buffer += char;
134
- }
135
- if (mode === MODE_TAGNAME && buffer === '!--') {
136
- mode = MODE_COMMENT;
137
- current = current[0];
138
- }
139
- }
140
- }
141
- commit();
142
- return current;
143
- };
144
-
145
- /**
146
- * @param {Babel} babel
147
- * @param {object} options
148
- * @param {string} [options.tag=html] The tagged template "tag" function name to process.
149
- */
150
-
151
- function mettleBabelPlugin({
152
- types: t
153
- }, options = {}) {
154
- function patternStringToRegExp(str) {
155
- const parts = str.split('/').slice(1);
156
- const end = parts.pop() || '';
157
- return new RegExp(parts.join('/'), end);
158
- }
159
- function propertyName(key) {
160
- if (t.isValidIdentifier(key)) {
161
- return t.identifier(key);
162
- }
163
- return t.stringLiteral(key);
164
- }
165
- function objectProperties(obj) {
166
- return Object.keys(obj).map(function (key) {
167
- const values = obj[key].map(function (valueOrNode) {
168
- return t.isNode(valueOrNode) ? valueOrNode : t.valueToNode(valueOrNode);
169
- });
170
- let node = values[0];
171
- if (values.length > 1 && !t.isStringLiteral(node) && !t.isStringLiteral(values[1])) {
172
- node = t.binaryExpression('+', t.stringLiteral(''), node);
173
- }
174
- values.slice(1).forEach(function (value) {
175
- node = t.binaryExpression('+', node, value);
176
- });
177
- return t.objectProperty(propertyName(key), node);
178
- });
179
- }
180
- function stringValue(str) {
181
- return t.stringLiteral(str);
182
- }
183
- function createVNode(tag, props, children) {
184
- if (children.elements.length === 1) {
185
- children = children.elements[0];
186
- } else if (children.elements.length === 0) {
187
- children = t.nullLiteral();
188
- }
189
- let key = null;
190
- if (props && props.properties && Array.isArray(props.properties)) {
191
- props.properties.forEach(item => {
192
- if (item.key.type === 'StringLiteral' && item.key.value === 'key') {
193
- key = item.value;
194
- } else if (item.key.type === 'Identifier' && item.key.name === 'key') {
195
- key = item.value;
196
- } else {
197
- key = t.nullLiteral();
198
- }
199
- });
200
- } else {
201
- key = t.nullLiteral();
202
- }
203
- return t.objectExpression([false, t.objectProperty(propertyName('tag'), tag), t.objectProperty(propertyName('props'), props), t.objectProperty(propertyName('children'), children), t.objectProperty(propertyName('key'), key), t.objectProperty(propertyName('el'), t.nullLiteral()), false].filter(Boolean));
204
- }
205
- function spreadNode(args, state) {
206
- if (args.length === 0) {
207
- return t.nullLiteral();
208
- }
209
- if (args.length > 0 && t.isNode(args[0])) {
210
- args.unshift({});
211
- } // 'Object.assign(x)', can be collapsed to 'x'.
212
-
213
- if (args.length === 1) {
214
- return propsNode(args[0]);
215
- } // 'Object.assign({}, x)', can be collapsed to 'x'.
216
-
217
- if (args.length === 2 && !t.isNode(args[0]) && Object.keys(args[0]).length === 0) {
218
- return propsNode(args[1]);
219
- }
220
- const helper = state.addHelper('extends');
221
- return t.callExpression(helper, args.map(propsNode));
222
- }
223
- function propsNode(props) {
224
- return t.isNode(props) ? props : t.objectExpression(objectProperties(props));
225
- }
226
- function transform(node, state) {
227
- if (t.isNode(node)) {
228
- return node;
229
- }
230
- if (typeof node === 'string') {
231
- return stringValue(node);
232
- }
233
- if (typeof node === 'undefined') {
234
- return t.identifier('undefined');
235
- }
236
- const {
237
- tag,
238
- props,
239
- children
240
- } = node;
241
- const newTag = typeof tag === 'string' ? t.stringLiteral(tag) : tag;
242
- const newProps = spreadNode(props, state);
243
- const newChildren = t.arrayExpression(children.map(child => transform(child, state)));
244
- return createVNode(newTag, newProps, newChildren);
245
- }
246
- const tagName = options.tag || 'html';
247
- return {
248
- name: 'mettle',
249
- visitor: {
250
- TaggedTemplateExpression(path, state) {
251
- const tag = path.node.tag.name;
252
- if (tagName[0] === '/' ? patternStringToRegExp(tagName).test(tag) : tag === tagName) {
253
- const statics = path.node.quasi.quasis.map(e => e.value.raw);
254
- const expr = path.node.quasi.expressions;
255
- const tree = treeify(build(statics), expr);
256
- const node = !Array.isArray(tree) ? transform(tree, state) : t.arrayExpression(tree.map(root => transform(root, state)));
257
- path.replaceWith(node);
258
- }
259
- },
260
- CallExpression(path, state) {
261
- const callee = path.node.callee;
262
- const args = path.node.arguments;
263
- const argsArr = Array.from(args);
264
- // The parameter is a template string
265
- if (callee.name === 'tem_h') {
266
- const statics = argsArr[0].quasis.map(e => e.value.raw);
267
- const expr = argsArr[0].expressions;
268
- const tree = treeify(build(statics), expr);
269
- const node = !Array.isArray(tree) ? transform(tree, state) : t.arrayExpression(tree.map(root => transform(root, state)));
270
- path.replaceWith(node);
271
- }
272
- // The parameter is a regular string
273
- else if (callee.name === 'str_h') {
274
- const statics = argsArr[0].extra.rawValue;
275
- const tree = treeify(build([statics]), []);
276
- const node = !Array.isArray(tree) ? transform(tree, state) : t.arrayExpression(tree.map(root => transform(root, state)));
277
- path.replaceWith(node);
278
- }
279
- }
280
- }
281
- };
282
- }
283
-
284
- module.exports = mettleBabelPlugin;
1
+ module.exports=function({types:t}){return{name:"babel-plugin-mettle",visitor:{FunctionDeclaration(n){if(n.node.id&&/^[A-Z]/.test(n.node.id.name)){const e=n.node.body.body.find(n=>t.isReturnStatement(n));if(e&&e.argument){const n=t.functionExpression(null,[],t.blockStatement([t.returnStatement(e.argument)]));e.argument=n}}}}}};
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "babel-plugin-mettle",
3
- "description": "A Babel plugin that compiles the template string in mettle.js into a normal object.",
4
- "version": "0.1.1",
3
+ "description": "",
4
+ "version": "0.3.0",
5
5
  "main": "dist/babel-plugin-mettle.js",
6
- "module": "dist/babel-plugin-mettle.mjs",
7
6
  "scripts": {
8
- "build": "microbundle src/index.js -f es,cjs --target node --no-compress --no-sourcemap"
7
+ "build": "microbundle src/index.js -f cjs --target node --compress --no-sourcemap"
9
8
  },
10
9
  "files": [
11
10
  "dist"
@@ -19,16 +18,13 @@
19
18
  },
20
19
  "homepage": "https://github.com/maomincoding/babel-plugin-mettle#readme",
21
20
  "keywords": [
22
- "Hyperscript Tagged Markup",
23
- "tagged template",
24
- "template literals",
25
21
  "virtual dom",
26
- "hyperscript",
27
22
  "babel",
28
23
  "babel plugin",
29
24
  "babel-plugin",
30
25
  "mettle",
31
26
  "mettle-js",
27
+ "jsx",
32
28
  "babel-plugin-mettle"
33
29
  ],
34
30
  "author": "maomincoding",
@@ -1,284 +0,0 @@
1
- const MODE_SLASH = 0;
2
- const MODE_TEXT = 1;
3
- const MODE_WHITESPACE = 2;
4
- const MODE_TAGNAME = 3;
5
- const MODE_COMMENT = 4;
6
- const MODE_PROP_SET = 5;
7
- const MODE_PROP_APPEND = 6;
8
- const CHILD_APPEND = 0;
9
- const CHILD_RECURSE = 2;
10
- const TAG_SET = 3;
11
- const PROPS_ASSIGN = 4;
12
- const PROP_SET = MODE_PROP_SET;
13
- const PROP_APPEND = MODE_PROP_APPEND;
14
- const treeify = function (built, fields) {
15
- const _treeify = function (built) {
16
- let tag = '';
17
- let currentProps = null;
18
- const props = [];
19
- const children = [];
20
- for (let i = 1; i < built.length; i++) {
21
- const type = built[i++];
22
- const value = built[i] ? fields[built[i++] - 1] : built[++i];
23
- if (type === TAG_SET) {
24
- tag = value;
25
- } else if (type === PROPS_ASSIGN) {
26
- props.push(value);
27
- currentProps = null;
28
- } else if (type === PROP_SET) {
29
- if (!currentProps) {
30
- currentProps = Object.create(null);
31
- props.push(currentProps);
32
- }
33
- currentProps[built[++i]] = [value];
34
- } else if (type === PROP_APPEND) {
35
- currentProps[built[++i]].push(value);
36
- } else if (type === CHILD_RECURSE) {
37
- children.push(_treeify(value));
38
- } else if (type === CHILD_APPEND) {
39
- children.push(value);
40
- }
41
- }
42
- return {
43
- tag: tag,
44
- props: props,
45
- children: children
46
- };
47
- };
48
- const {
49
- children
50
- } = _treeify(built);
51
- return children.length > 1 ? children : children[0];
52
- };
53
- const build = function (statics) {
54
- let mode = MODE_TEXT;
55
- let buffer = '';
56
- let quote = '';
57
- let current = [0];
58
- let char, propName;
59
- const commit = function (field) {
60
- if (mode === MODE_TEXT && (field || (buffer = buffer.replace(/^\s*\n\s*|\s*\n\s*$/g, '')))) {
61
- current.push(CHILD_APPEND, field, buffer);
62
- } else if (mode === MODE_TAGNAME && (field || buffer)) {
63
- current.push(TAG_SET, field, buffer);
64
- mode = MODE_WHITESPACE;
65
- } else if (mode === MODE_WHITESPACE && buffer === '...' && field) {
66
- current.push(PROPS_ASSIGN, field, 0);
67
- } else if (mode === MODE_WHITESPACE && buffer && !field) {
68
- current.push(PROP_SET, 0, true, buffer);
69
- } else if (mode >= MODE_PROP_SET) {
70
- if (buffer || !field && mode === MODE_PROP_SET) {
71
- current.push(mode, 0, buffer, propName);
72
- mode = MODE_PROP_APPEND;
73
- }
74
- if (field) {
75
- current.push(mode, field, 0, propName);
76
- mode = MODE_PROP_APPEND;
77
- }
78
- }
79
- buffer = '';
80
- };
81
- for (let i = 0; i < statics.length; i++) {
82
- if (i) {
83
- if (mode === MODE_TEXT) {
84
- commit();
85
- }
86
- commit(i);
87
- }
88
- for (let j = 0; j < statics[i].length; j++) {
89
- char = statics[i][j];
90
- if (mode === MODE_TEXT) {
91
- if (char === '<') {
92
- commit();
93
- current = [current];
94
- mode = MODE_TAGNAME;
95
- } else {
96
- buffer += char;
97
- }
98
- } else if (mode === MODE_COMMENT) {
99
- if (buffer === '--' && char === '>') {
100
- mode = MODE_TEXT;
101
- buffer = '';
102
- } else {
103
- buffer = char + buffer[0];
104
- }
105
- } else if (quote) {
106
- if (char === quote) {
107
- quote = '';
108
- } else {
109
- buffer += char;
110
- }
111
- } else if (char === '"' || char === "'") {
112
- quote = char;
113
- } else if (char === '>') {
114
- commit();
115
- mode = MODE_TEXT;
116
- } else if (!mode) ; else if (char === '=') {
117
- mode = MODE_PROP_SET;
118
- propName = buffer;
119
- buffer = '';
120
- } else if (char === '/' && (mode < MODE_PROP_SET || statics[i][j + 1] === '>')) {
121
- commit();
122
- if (mode === MODE_TAGNAME) {
123
- current = current[0];
124
- }
125
- mode = current;
126
- (current = current[0]).push(CHILD_RECURSE, 0, mode);
127
- mode = MODE_SLASH;
128
- } else if (char === ' ' || char === '\t' || char === '\n' || char === '\r') {
129
- // <a disabled>
130
- commit();
131
- mode = MODE_WHITESPACE;
132
- } else {
133
- buffer += char;
134
- }
135
- if (mode === MODE_TAGNAME && buffer === '!--') {
136
- mode = MODE_COMMENT;
137
- current = current[0];
138
- }
139
- }
140
- }
141
- commit();
142
- return current;
143
- };
144
-
145
- /**
146
- * @param {Babel} babel
147
- * @param {object} options
148
- * @param {string} [options.tag=html] The tagged template "tag" function name to process.
149
- */
150
-
151
- function mettleBabelPlugin({
152
- types: t
153
- }, options = {}) {
154
- function patternStringToRegExp(str) {
155
- const parts = str.split('/').slice(1);
156
- const end = parts.pop() || '';
157
- return new RegExp(parts.join('/'), end);
158
- }
159
- function propertyName(key) {
160
- if (t.isValidIdentifier(key)) {
161
- return t.identifier(key);
162
- }
163
- return t.stringLiteral(key);
164
- }
165
- function objectProperties(obj) {
166
- return Object.keys(obj).map(function (key) {
167
- const values = obj[key].map(function (valueOrNode) {
168
- return t.isNode(valueOrNode) ? valueOrNode : t.valueToNode(valueOrNode);
169
- });
170
- let node = values[0];
171
- if (values.length > 1 && !t.isStringLiteral(node) && !t.isStringLiteral(values[1])) {
172
- node = t.binaryExpression('+', t.stringLiteral(''), node);
173
- }
174
- values.slice(1).forEach(function (value) {
175
- node = t.binaryExpression('+', node, value);
176
- });
177
- return t.objectProperty(propertyName(key), node);
178
- });
179
- }
180
- function stringValue(str) {
181
- return t.stringLiteral(str);
182
- }
183
- function createVNode(tag, props, children) {
184
- if (children.elements.length === 1) {
185
- children = children.elements[0];
186
- } else if (children.elements.length === 0) {
187
- children = t.nullLiteral();
188
- }
189
- let key = null;
190
- if (props && props.properties && Array.isArray(props.properties)) {
191
- props.properties.forEach(item => {
192
- if (item.key.type === 'StringLiteral' && item.key.value === 'key') {
193
- key = item.value;
194
- } else if (item.key.type === 'Identifier' && item.key.name === 'key') {
195
- key = item.value;
196
- } else {
197
- key = t.nullLiteral();
198
- }
199
- });
200
- } else {
201
- key = t.nullLiteral();
202
- }
203
- return t.objectExpression([false, t.objectProperty(propertyName('tag'), tag), t.objectProperty(propertyName('props'), props), t.objectProperty(propertyName('children'), children), t.objectProperty(propertyName('key'), key), t.objectProperty(propertyName('el'), t.nullLiteral()), false].filter(Boolean));
204
- }
205
- function spreadNode(args, state) {
206
- if (args.length === 0) {
207
- return t.nullLiteral();
208
- }
209
- if (args.length > 0 && t.isNode(args[0])) {
210
- args.unshift({});
211
- } // 'Object.assign(x)', can be collapsed to 'x'.
212
-
213
- if (args.length === 1) {
214
- return propsNode(args[0]);
215
- } // 'Object.assign({}, x)', can be collapsed to 'x'.
216
-
217
- if (args.length === 2 && !t.isNode(args[0]) && Object.keys(args[0]).length === 0) {
218
- return propsNode(args[1]);
219
- }
220
- const helper = state.addHelper('extends');
221
- return t.callExpression(helper, args.map(propsNode));
222
- }
223
- function propsNode(props) {
224
- return t.isNode(props) ? props : t.objectExpression(objectProperties(props));
225
- }
226
- function transform(node, state) {
227
- if (t.isNode(node)) {
228
- return node;
229
- }
230
- if (typeof node === 'string') {
231
- return stringValue(node);
232
- }
233
- if (typeof node === 'undefined') {
234
- return t.identifier('undefined');
235
- }
236
- const {
237
- tag,
238
- props,
239
- children
240
- } = node;
241
- const newTag = typeof tag === 'string' ? t.stringLiteral(tag) : tag;
242
- const newProps = spreadNode(props, state);
243
- const newChildren = t.arrayExpression(children.map(child => transform(child, state)));
244
- return createVNode(newTag, newProps, newChildren);
245
- }
246
- const tagName = options.tag || 'html';
247
- return {
248
- name: 'mettle',
249
- visitor: {
250
- TaggedTemplateExpression(path, state) {
251
- const tag = path.node.tag.name;
252
- if (tagName[0] === '/' ? patternStringToRegExp(tagName).test(tag) : tag === tagName) {
253
- const statics = path.node.quasi.quasis.map(e => e.value.raw);
254
- const expr = path.node.quasi.expressions;
255
- const tree = treeify(build(statics), expr);
256
- const node = !Array.isArray(tree) ? transform(tree, state) : t.arrayExpression(tree.map(root => transform(root, state)));
257
- path.replaceWith(node);
258
- }
259
- },
260
- CallExpression(path, state) {
261
- const callee = path.node.callee;
262
- const args = path.node.arguments;
263
- const argsArr = Array.from(args);
264
- // The parameter is a template string
265
- if (callee.name === 'tem_h') {
266
- const statics = argsArr[0].quasis.map(e => e.value.raw);
267
- const expr = argsArr[0].expressions;
268
- const tree = treeify(build(statics), expr);
269
- const node = !Array.isArray(tree) ? transform(tree, state) : t.arrayExpression(tree.map(root => transform(root, state)));
270
- path.replaceWith(node);
271
- }
272
- // The parameter is a regular string
273
- else if (callee.name === 'str_h') {
274
- const statics = argsArr[0].extra.rawValue;
275
- const tree = treeify(build([statics]), []);
276
- const node = !Array.isArray(tree) ? transform(tree, state) : t.arrayExpression(tree.map(root => transform(root, state)));
277
- path.replaceWith(node);
278
- }
279
- }
280
- }
281
- };
282
- }
283
-
284
- export { mettleBabelPlugin as default };