@htmlplus/element 0.4.4 → 0.4.5

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.
@@ -1,9 +1,9 @@
1
1
  import { Context } from '../../types/index.js';
2
- export declare type ExternalOptions = {
3
- source?: (context: Context) => string;
2
+ export declare type AssetsOptions = {
4
3
  destination: (context: Context) => string;
4
+ source?: (context: Context) => string;
5
5
  };
6
- export declare const external: (options: ExternalOptions) => {
6
+ export declare const assets: (options: AssetsOptions) => {
7
7
  name: string;
8
8
  next: (context: Context) => void;
9
9
  };
@@ -0,0 +1,26 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ const defaults = {
4
+ destination(context) {
5
+ return `assets/${context.fileName}`;
6
+ },
7
+ source(context) {
8
+ return path.join(context.directoryPath, 'assets');
9
+ }
10
+ };
11
+ export const assets = (options) => {
12
+ const name = 'assets';
13
+ options = Object.assign({}, defaults, options);
14
+ const next = (context) => {
15
+ var _a, _b;
16
+ const destination = (_a = options.destination) === null || _a === void 0 ? void 0 : _a.call(options, context);
17
+ const source = (_b = options.source) === null || _b === void 0 ? void 0 : _b.call(options, context);
18
+ if (!source)
19
+ return;
20
+ if (!fs.existsSync(source))
21
+ return;
22
+ fs.copySync(source, destination);
23
+ context.assets = source;
24
+ };
25
+ return { name, next };
26
+ };
@@ -1,7 +1,7 @@
1
1
  import t from '@babel/types';
2
2
  import { pascalCase } from 'change-case';
3
3
  import * as CONSTANTS from '../../constants/index.js';
4
- import { print, visitor } from '../utils/index.js';
4
+ import { addDependency, print, visitor } from '../utils/index.js';
5
5
  const defaults = {
6
6
  typings: true
7
7
  };
@@ -11,26 +11,43 @@ export const customElement = (options) => {
11
11
  options = Object.assign({}, defaults, options);
12
12
  const next = (context) => {
13
13
  const ast = t.cloneNode(context.fileAST, true);
14
+ // attach style mapper for 'style' attribute
15
+ visitor(ast, {
16
+ JSXAttribute(path) {
17
+ const { name, value } = path.node;
18
+ if (name.name != 'style')
19
+ return;
20
+ if (!value)
21
+ return;
22
+ if (value.type != 'JSXExpressionContainer')
23
+ return;
24
+ const local = addDependency(ast, CONSTANTS.PACKAGE_NAME, CONSTANTS.UTILS_STYLE_MAP);
25
+ path.replaceWith(t.jsxAttribute(t.jsxIdentifier('style'), t.jsxExpressionContainer(t.callExpression(t.identifier(local), [value.expression]))));
26
+ path.skip();
27
+ }
28
+ });
14
29
  // TODO
15
30
  visitor(ast, {
16
31
  ClassDeclaration(path) {
17
- if (path.node.id.name != context.className)
32
+ const { body, id } = path.node;
33
+ if (id.name != context.className)
18
34
  return;
19
- path.node.body.body.unshift(t.classProperty(t.identifier('uhtml')));
35
+ body.body.unshift(t.classProperty(t.identifier('uhtml')));
20
36
  }
21
37
  });
22
- // replace className
38
+ // replace 'className' attribute to 'class'
23
39
  visitor(ast, {
24
40
  JSXAttribute(path) {
25
- if (path.node.name.name != 'className')
41
+ const { name, value } = path.node;
42
+ if (name.name != 'className')
26
43
  return;
27
44
  const hasClass = path.parentPath.node.attributes.some((attribute) => attribute.name.name == 'class');
28
45
  if (hasClass)
29
46
  return path.remove();
30
- path.replaceWith(t.jsxAttribute(t.jsxIdentifier('class'), path.node.value));
47
+ path.replaceWith(t.jsxAttribute(t.jsxIdentifier('class'), value));
31
48
  }
32
49
  });
33
- // jsx to uhtml syntax
50
+ // TODO: convert 'jsx' to 'uhtml' syntax
34
51
  visitor(ast, {
35
52
  JSXAttribute: {
36
53
  exit(path) {
@@ -81,9 +98,10 @@ export const customElement = (options) => {
81
98
  // attach members
82
99
  visitor(ast, {
83
100
  ClassDeclaration(path) {
84
- if (path.node.id.name != context.className)
101
+ const { body, id } = path.node;
102
+ if (id.name != context.className)
85
103
  return;
86
- path.node.body.body.unshift(t.classProperty(t.identifier(CONSTANTS.STATIC_MEMBERS), t.objectExpression([
104
+ body.body.unshift(t.classProperty(t.identifier(CONSTANTS.STATIC_MEMBERS), t.objectExpression([
87
105
  ...context.classProperties.map((property) => {
88
106
  var _a, _b;
89
107
  const type = (_b = (_a = property.typeAnnotation) === null || _a === void 0 ? void 0 : _a.typeAnnotation) === null || _b === void 0 ? void 0 : _b.type;
@@ -117,7 +135,8 @@ export const customElement = (options) => {
117
135
  if (options === null || options === void 0 ? void 0 : options.typings) {
118
136
  visitor(ast, {
119
137
  Program(path) {
120
- path.node.body.push(t.exportNamedDeclaration(t.tsInterfaceDeclaration(
138
+ const { body } = path.node;
139
+ body.push(t.exportNamedDeclaration(t.tsInterfaceDeclaration(
121
140
  // TODO
122
141
  t.identifier(context.componentClassName + 'JSX'), null, [], t.tsInterfaceBody([
123
142
  ...context.classProperties.map((property) => Object.assign(t.tSPropertySignature(property.key, property.typeAnnotation), {
@@ -136,7 +155,7 @@ export const customElement = (options) => {
136
155
  });
137
156
  })
138
157
  ]))));
139
- path.node.body.push(Object.assign(t.tsModuleDeclaration(t.identifier('global'), t.tsModuleBlock([
158
+ body.push(Object.assign(t.tsModuleDeclaration(t.identifier('global'), t.tsModuleBlock([
140
159
  t.tsInterfaceDeclaration(t.identifier(context.componentInterfaceName), null, [
141
160
  t.tSExpressionWithTypeArguments(t.identifier('HTMLElement')) // TODO
142
161
  ], t.tsInterfaceBody([
@@ -177,10 +196,8 @@ export const customElement = (options) => {
177
196
  }
178
197
  });
179
198
  }
199
+ // TODO
180
200
  context.script = print(ast);
181
201
  };
182
- return {
183
- name,
184
- next
185
- };
202
+ return { name, next };
186
203
  };
@@ -15,8 +15,8 @@ const defaults = {
15
15
  };
16
16
  export const customElementReact = (options) => {
17
17
  const name = 'customElementReact';
18
+ options = Object.assign({}, defaults, options);
18
19
  const finish = (global) => {
19
- options = Object.assign(Object.assign({}, defaults), options);
20
20
  // TODO
21
21
  const globalNew = {
22
22
  contexts: global.contexts.reduce((previous, current) => (Object.assign(Object.assign({}, previous), { [current.filePath]: current })), {}),
@@ -126,8 +126,5 @@ export const customElementReact = (options) => {
126
126
  renderTemplate(patterns, options.destination, config)(globalNew);
127
127
  }
128
128
  };
129
- return {
130
- name,
131
- finish
132
- };
129
+ return { name, finish };
133
130
  };
@@ -1,10 +1,8 @@
1
- import { Context } from '../../types/index.js';
1
+ import { Global } from '../../types/index.js';
2
2
  export interface DocumentOptions {
3
3
  destination: string;
4
4
  }
5
5
  export declare const document: (options: DocumentOptions) => {
6
6
  name: string;
7
- start: (global: any) => void;
8
- next: (context: Context, global: any) => void;
9
- finish: (global: any) => void;
7
+ finish: (global: Global) => void;
10
8
  };
@@ -1,254 +1,247 @@
1
1
  import { capitalCase, paramCase } from 'change-case';
2
- import fs from 'fs';
2
+ import fs from 'fs-extra';
3
3
  import glob from 'glob';
4
4
  import path from 'path';
5
5
  import { getInitializer, getTag, getTags, getTypeReference, hasTag, parseTag, print } from '../utils/index.js';
6
+ const defaults = {};
6
7
  export const document = (options) => {
7
8
  const name = 'document';
8
- const start = (global) => {
9
- global.document = {
9
+ options = Object.assign({}, defaults, options);
10
+ const finish = (global) => {
11
+ var _a;
12
+ const json = {
10
13
  components: []
11
14
  };
12
- };
13
- const next = (context, global) => {
14
- var _a;
15
- const events = context.classEvents.map((event) => {
16
- var _a, _b, _c;
17
- const isCancelable = (() => {
18
- if (!event.decorators)
19
- return false;
20
- try {
21
- for (const decorator of event.decorators) {
22
- for (const argument of decorator.expression['arguments']) {
23
- for (const property of argument.properties) {
24
- if (property.key.name != 'cancelable')
25
- continue;
26
- if (property.value.type != 'BooleanLiteral')
27
- continue;
28
- if (!property.value.value)
29
- continue;
30
- return true;
15
+ for (const context of global.contexts) {
16
+ const events = context.classEvents.map((event) => {
17
+ var _a, _b, _c;
18
+ const isCancelable = (() => {
19
+ if (!event.decorators)
20
+ return false;
21
+ try {
22
+ for (const decorator of event.decorators) {
23
+ for (const argument of decorator.expression['arguments']) {
24
+ for (const property of argument.properties) {
25
+ if (property.key.name != 'cancelable')
26
+ continue;
27
+ if (property.value.type != 'BooleanLiteral')
28
+ continue;
29
+ if (!property.value.value)
30
+ continue;
31
+ return true;
32
+ }
31
33
  }
32
34
  }
33
35
  }
34
- }
35
- catch (_a) { }
36
- return false;
37
- })();
38
- const description = (_a = getTags(event).find((tag) => !tag.key)) === null || _a === void 0 ? void 0 : _a.value;
39
- const detail = print((_b = event.typeAnnotation) === null || _b === void 0 ? void 0 : _b['typeAnnotation']);
40
- const detailReference = getTypeReference(context.fileAST, (_c = event.typeAnnotation) === null || _c === void 0 ? void 0 : _c['typeAnnotation'].typeParameters.params[0]);
41
- const isExperimental = hasTag(event, 'experimental');
42
- const isModel = hasTag(event, 'model');
43
- const name = event.key['name'];
44
- const tags = getTags(event);
45
- return {
46
- description,
47
- detail,
48
- detailReference,
49
- isCancelable,
50
- isExperimental,
51
- isModel,
52
- name,
53
- tags
54
- };
55
- });
56
- const group = (_a = getTag(context.class, 'group')) === null || _a === void 0 ? void 0 : _a.value;
57
- const isDeprecated = hasTag(context.class, 'deprecated');
58
- const isExperimental = hasTag(context.class, 'experimental');
59
- const lastModified = glob
60
- .sync(path.join(context.directoryPath, '**/*.*'))
61
- .map((file) => fs.statSync(file).mtime)
62
- .sort((a, b) => (a > b ? 1 : -1))
63
- .pop();
64
- const methods = context.classMethods.map((method) => {
65
- var _a, _b, _c;
66
- const description = (_a = getTags(method).find((tag) => !tag.key)) === null || _a === void 0 ? void 0 : _a.value;
67
- const isAsync = method.async;
68
- const isDeprecated = hasTag(method, 'deprecated');
69
- const isExperimental = hasTag(method, 'experimental');
70
- const name = method.key['name'];
71
- const returns = print((_b = method.returnType) === null || _b === void 0 ? void 0 : _b['typeAnnotation']) || 'void';
72
- const returnsReference = getTypeReference(context.fileAST, (_c = method.returnType) === null || _c === void 0 ? void 0 : _c['typeAnnotation']);
73
- const tags = getTags(method);
74
- // TODO
75
- const parameters = method.params.map((param) => {
36
+ catch (_a) { }
37
+ return false;
38
+ })();
39
+ const description = (_a = getTags(event).find((tag) => !tag.key)) === null || _a === void 0 ? void 0 : _a.value;
40
+ const detail = print((_b = event.typeAnnotation) === null || _b === void 0 ? void 0 : _b['typeAnnotation']);
41
+ const detailReference = getTypeReference(context.fileAST, (_c = event.typeAnnotation) === null || _c === void 0 ? void 0 : _c['typeAnnotation'].typeParameters.params[0]);
42
+ const isExperimental = hasTag(event, 'experimental');
43
+ const isModel = hasTag(event, 'model');
44
+ const name = event.key['name'];
45
+ const tags = getTags(event);
46
+ return {
47
+ description,
48
+ detail,
49
+ detailReference,
50
+ isCancelable,
51
+ isExperimental,
52
+ isModel,
53
+ name,
54
+ tags
55
+ };
56
+ });
57
+ const group = (_a = getTag(context.class, 'group')) === null || _a === void 0 ? void 0 : _a.value;
58
+ const isDeprecated = hasTag(context.class, 'deprecated');
59
+ const isExperimental = hasTag(context.class, 'experimental');
60
+ const lastModified = glob
61
+ .sync(path.join(context.directoryPath, '**/*.*'))
62
+ .map((file) => fs.statSync(file).mtime)
63
+ .sort((a, b) => (a > b ? 1 : -1))
64
+ .pop();
65
+ const methods = context.classMethods.map((method) => {
76
66
  var _a, _b, _c;
77
- return ({
78
- description: (_a = getTags(method, 'param')
79
- .map((tag) => parseTag(tag, ' '))
80
- .find((tag) => tag.name == param['name'])) === null || _a === void 0 ? void 0 : _a.description,
81
- isOptional: !!param['optional'],
82
- name: param['name'],
83
- type: print((_b = param === null || param === void 0 ? void 0 : param['typeAnnotation']) === null || _b === void 0 ? void 0 : _b.typeAnnotation) || undefined,
84
- typeReference: getTypeReference(context.fileAST, (_c = param === null || param === void 0 ? void 0 : param['typeAnnotation']) === null || _c === void 0 ? void 0 : _c.typeAnnotation)
67
+ const description = (_a = getTags(method).find((tag) => !tag.key)) === null || _a === void 0 ? void 0 : _a.value;
68
+ const isAsync = method.async;
69
+ const isDeprecated = hasTag(method, 'deprecated');
70
+ const isExperimental = hasTag(method, 'experimental');
71
+ const name = method.key['name'];
72
+ const returns = print((_b = method.returnType) === null || _b === void 0 ? void 0 : _b['typeAnnotation']) || 'void';
73
+ const returnsReference = getTypeReference(context.fileAST, (_c = method.returnType) === null || _c === void 0 ? void 0 : _c['typeAnnotation']);
74
+ const tags = getTags(method);
75
+ // TODO
76
+ const parameters = method.params.map((param) => {
77
+ var _a, _b, _c;
78
+ return ({
79
+ description: (_a = getTags(method, 'param')
80
+ .map((tag) => parseTag(tag, ' '))
81
+ .find((tag) => tag.name == param['name'])) === null || _a === void 0 ? void 0 : _a.description,
82
+ isOptional: !!param['optional'],
83
+ name: param['name'],
84
+ type: print((_b = param === null || param === void 0 ? void 0 : param['typeAnnotation']) === null || _b === void 0 ? void 0 : _b.typeAnnotation) || undefined,
85
+ typeReference: getTypeReference(context.fileAST, (_c = param === null || param === void 0 ? void 0 : param['typeAnnotation']) === null || _c === void 0 ? void 0 : _c.typeAnnotation)
86
+ });
85
87
  });
88
+ const signature = [
89
+ method.key['name'],
90
+ '(',
91
+ parameters
92
+ .map((parameter) => {
93
+ var _a;
94
+ let string = '';
95
+ string += parameter.name;
96
+ string += parameter.isOptional ? '?' : '';
97
+ string += parameter.type ? ': ' : '';
98
+ string += (_a = parameter.type) !== null && _a !== void 0 ? _a : '';
99
+ return string;
100
+ })
101
+ .join(', '),
102
+ ')',
103
+ ' => ',
104
+ returns
105
+ ].join('');
106
+ return {
107
+ description,
108
+ isAsync,
109
+ isDeprecated,
110
+ isExperimental,
111
+ name,
112
+ returns,
113
+ returnsReference,
114
+ tags,
115
+ parameters,
116
+ signature
117
+ };
86
118
  });
87
- const signature = [
88
- method.key['name'],
89
- '(',
90
- parameters
91
- .map((parameter) => {
92
- var _a;
93
- let string = '';
94
- string += parameter.name;
95
- string += parameter.isOptional ? '?' : '';
96
- string += parameter.type ? ': ' : '';
97
- string += (_a = parameter.type) !== null && _a !== void 0 ? _a : '';
98
- return string;
99
- })
100
- .join(', '),
101
- ')',
102
- ' => ',
103
- returns
104
- ].join('');
105
- return {
106
- description,
107
- isAsync,
108
- isDeprecated,
109
- isExperimental,
110
- name,
111
- returns,
112
- returnsReference,
113
- tags,
114
- parameters,
115
- signature
116
- };
117
- });
118
- const parts = getTags(context.class, 'part').map((tag) => parseTag(tag));
119
- const properties = context.classProperties.map((property) => {
120
- var _a, _b, _c;
121
- const attribute = paramCase(property.key['name']);
122
- const description = (_a = getTags(property).find((tag) => !tag.key)) === null || _a === void 0 ? void 0 : _a.value;
123
- // TODO
124
- const hasReflect = (() => {
125
- if (!property.decorators)
126
- return false;
127
- try {
128
- for (const decorator of property.decorators) {
129
- for (const argument of decorator.expression['arguments']) {
130
- for (const property of argument.properties) {
131
- if (property.key.name != 'reflect')
132
- continue;
133
- if (property.value.type != 'BooleanLiteral')
134
- continue;
135
- if (!property.value.value)
136
- continue;
137
- return true;
119
+ const parts = getTags(context.class, 'part').map((tag) => parseTag(tag));
120
+ const properties = context.classProperties.map((property) => {
121
+ var _a, _b, _c;
122
+ const attribute = paramCase(property.key['name']);
123
+ const description = (_a = getTags(property).find((tag) => !tag.key)) === null || _a === void 0 ? void 0 : _a.value;
124
+ // TODO
125
+ const hasReflect = (() => {
126
+ if (!property.decorators)
127
+ return false;
128
+ try {
129
+ for (const decorator of property.decorators) {
130
+ for (const argument of decorator.expression['arguments']) {
131
+ for (const property of argument.properties) {
132
+ if (property.key.name != 'reflect')
133
+ continue;
134
+ if (property.value.type != 'BooleanLiteral')
135
+ continue;
136
+ if (!property.value.value)
137
+ continue;
138
+ return true;
139
+ }
138
140
  }
139
141
  }
140
142
  }
143
+ catch (_a) { }
144
+ return false;
145
+ })();
146
+ // TODO
147
+ const initializer = getInitializer(property.value);
148
+ const isDeprecated = hasTag(property, 'deprecated');
149
+ const isExperimental = hasTag(property, 'experimental');
150
+ const isModel = hasTag(property, 'model');
151
+ const isRequired = !property.optional;
152
+ const name = property.key['name'];
153
+ const tags = getTags(property);
154
+ const type = print((_b = property.typeAnnotation) === null || _b === void 0 ? void 0 : _b['typeAnnotation']);
155
+ const typeReference = getTypeReference(context.fileAST, (_c = property.typeAnnotation) === null || _c === void 0 ? void 0 : _c['typeAnnotation']);
156
+ return {
157
+ attribute,
158
+ description,
159
+ hasReflect,
160
+ initializer,
161
+ isDeprecated,
162
+ isExperimental,
163
+ isModel,
164
+ isRequired,
165
+ name,
166
+ tags,
167
+ type,
168
+ typeReference
169
+ };
170
+ });
171
+ const readme = (() => {
172
+ try {
173
+ const source = path.join(context.directoryPath, `${context.fileName}.md`);
174
+ return fs.readFileSync(source, 'utf8');
141
175
  }
142
176
  catch (_a) { }
143
- return false;
144
177
  })();
178
+ const readmeDescription = (() => {
179
+ const content = readme || '';
180
+ if (!content.startsWith('# '))
181
+ return '';
182
+ const sections = content.split('\n');
183
+ for (let i = 1; i < sections.length; i++) {
184
+ const section = sections[i].trim();
185
+ if (!section)
186
+ continue;
187
+ return section;
188
+ }
189
+ return '';
190
+ })();
191
+ const slots = getTags(context.class, 'slot').map((tag) => parseTag(tag));
145
192
  // TODO
146
- const initializer = getInitializer(property.value);
147
- const isDeprecated = hasTag(property, 'deprecated');
148
- const isExperimental = hasTag(property, 'experimental');
149
- const isModel = hasTag(property, 'model');
150
- const isRequired = !property.optional;
151
- const name = property.key['name'];
152
- const tags = getTags(property);
153
- const type = print((_b = property.typeAnnotation) === null || _b === void 0 ? void 0 : _b['typeAnnotation']);
154
- const typeReference = getTypeReference(context.fileAST, (_c = property.typeAnnotation) === null || _c === void 0 ? void 0 : _c['typeAnnotation']);
155
- return {
156
- attribute,
157
- description,
158
- hasReflect,
159
- initializer,
193
+ const styles = (() => {
194
+ if (!context.stylePath)
195
+ return [];
196
+ return fs
197
+ .readFileSync(context.stylePath, 'utf8')
198
+ .split('@prop')
199
+ .slice(1)
200
+ .map((section) => {
201
+ var _a;
202
+ let [description, name] = section.split(/\n/);
203
+ name = name.split(':').slice(0, -1).join(':').trim();
204
+ description = description.trim();
205
+ let [initializer] = ((_a = context.styleParsed) === null || _a === void 0 ? void 0 : _a.split(name).slice(1, 2)) || [];
206
+ if (initializer)
207
+ initializer = initializer.split(/;|}/)[0].replace(':', '').trim();
208
+ return {
209
+ description,
210
+ initializer,
211
+ name
212
+ };
213
+ });
214
+ })();
215
+ const tag = context.componentTag;
216
+ const tags = getTags(context.class);
217
+ const title = capitalCase(context.componentKey);
218
+ json.components.push({
219
+ // TODO
220
+ // main
221
+ // development
222
+ // source
223
+ events,
224
+ group,
160
225
  isDeprecated,
161
226
  isExperimental,
162
- isModel,
163
- isRequired,
164
- name,
227
+ key: context.componentKey,
228
+ lastModified,
229
+ methods,
230
+ parts,
231
+ properties,
232
+ readme,
233
+ readmeDescription,
234
+ slots,
235
+ styles,
236
+ tag,
165
237
  tags,
166
- type,
167
- typeReference
168
- };
169
- });
170
- const readme = (() => {
171
- try {
172
- const source = path.join(context.directoryPath, `${context.fileName}.md`);
173
- return fs.readFileSync(source, 'utf8');
174
- }
175
- catch (_a) { }
176
- })();
177
- const readmeDescription = (() => {
178
- const content = readme || '';
179
- if (!content.startsWith('# '))
180
- return '';
181
- const sections = content.split('\n');
182
- for (let i = 1; i < sections.length; i++) {
183
- const section = sections[i].trim();
184
- if (!section)
185
- continue;
186
- return section;
187
- }
188
- return '';
189
- })();
190
- const slots = getTags(context.class, 'slot').map((tag) => parseTag(tag));
191
- // TODO
192
- const styles = (() => {
193
- if (!context.stylePath)
194
- return [];
195
- return fs
196
- .readFileSync(context.stylePath, 'utf8')
197
- .split('@prop')
198
- .slice(1)
199
- .map((section) => {
200
- var _a;
201
- let [description, name] = section.split(/\n/);
202
- name = name.split(':').slice(0, -1).join(':').trim();
203
- description = description.trim();
204
- let [initializer] = ((_a = context.styleParsed) === null || _a === void 0 ? void 0 : _a.split(name).slice(1, 2)) || [];
205
- if (initializer)
206
- initializer = initializer.split(/;|}/)[0].replace(':', '').trim();
207
- return {
208
- description,
209
- initializer,
210
- name
211
- };
238
+ title
212
239
  });
213
- })();
214
- const tag = context.componentTag;
215
- const tags = getTags(context.class);
216
- const title = capitalCase(context.componentKey);
217
- global.document.components.push({
218
- // TODO
219
- // main
220
- // development
221
- // source
222
- events,
223
- group,
224
- isDeprecated,
225
- isExperimental,
226
- key: context.componentKey,
227
- lastModified,
228
- methods,
229
- parts,
230
- properties,
231
- readme,
232
- readmeDescription,
233
- slots,
234
- styles,
235
- tag,
236
- tags,
237
- title
238
- });
239
- };
240
- const finish = (global) => {
240
+ }
241
+ json.components = json.components.sort((a, b) => (a.title > b.title ? 1 : -1));
241
242
  const dirname = path.dirname(options.destination);
242
- global.document.components = global.document.components.sort((a, b) => (a.title > b.title ? 1 : -1));
243
- if (!fs.existsSync(dirname))
244
- fs.mkdirSync(dirname, { recursive: true });
245
- JSON.stringify(global.document, null, 2);
246
- fs.writeFileSync(options.destination, JSON.stringify(global.document, null, 2), 'utf8');
247
- };
248
- return {
249
- name,
250
- start,
251
- next,
252
- finish
243
+ fs.ensureDirSync(dirname);
244
+ fs.writeJSONSync(options.destination, json, { encoding: 'utf8', spaces: 2 });
253
245
  };
246
+ return { name, finish };
254
247
  };
@@ -3,8 +3,10 @@ import { pascalCase, paramCase } from 'change-case';
3
3
  import path from 'path';
4
4
  import * as CONSTANTS from '../../constants/index.js';
5
5
  import { hasDecorator, visitor } from '../utils/index.js';
6
+ const defaults = {};
6
7
  export const extract = (options) => {
7
8
  const name = 'extract';
9
+ options = Object.assign({}, defaults, options);
8
10
  const next = (context) => {
9
11
  var _a, _b;
10
12
  visitor(context.fileAST, {
@@ -44,8 +46,10 @@ export const extract = (options) => {
44
46
  return;
45
47
  (_a = context.customElementNames) !== null && _a !== void 0 ? _a : (context.customElementNames = []);
46
48
  context.customElementNames.push(name);
47
- context.customElementNames = context.customElementNames.filter((item, index, items) => items.indexOf(item) === index).sort();
48
- },
49
+ context.customElementNames = context.customElementNames
50
+ .filter((item, index, items) => items.indexOf(item) === index)
51
+ .sort();
52
+ }
49
53
  });
50
54
  context.directoryPath = path.dirname(context.filePath);
51
55
  context.directoryName = path.basename(context.directoryPath);
@@ -65,8 +69,5 @@ export const extract = (options) => {
65
69
  context.classHasUnmount = (context.classMembers || []).some((member) => member['key'].name == CONSTANTS.LIFECYCLE_DISCONNECTED);
66
70
  context.classRender = (context.classMembers || []).find((member) => member['key'].name == CONSTANTS.METHOD_RENDER);
67
71
  };
68
- return {
69
- name,
70
- next
71
- };
72
+ return { name, next };
72
73
  };
@@ -1,7 +1,7 @@
1
+ export * from './assets.js';
1
2
  export * from './customElementReact/index.js';
2
3
  export * from './customElement.js';
3
4
  export * from './document.js';
4
- export * from './external.js';
5
5
  export * from './extract.js';
6
6
  export * from './parse.js';
7
7
  export * from './read.js';
@@ -1,7 +1,7 @@
1
+ export * from './assets.js';
1
2
  export * from './customElementReact/index.js';
2
3
  export * from './customElement.js';
3
4
  export * from './document.js';
4
- export * from './external.js';
5
5
  export * from './extract.js';
6
6
  export * from './parse.js';
7
7
  export * from './read.js';
@@ -9,8 +9,5 @@ export const parse = () => {
9
9
  plugins: ['jsx', 'typescript', 'decorators-legacy']
10
10
  });
11
11
  };
12
- return {
13
- name,
14
- next
15
- };
12
+ return { name, next };
16
13
  };
@@ -1,13 +1,9 @@
1
- import fs from 'fs';
1
+ import fs from 'fs-extra';
2
2
  export const read = () => {
3
3
  const name = 'read';
4
4
  const next = (context) => {
5
- if (!!context.fileContent)
6
- return;
7
- context.fileContent = fs.readFileSync(context.filePath, 'utf8');
8
- };
9
- return {
10
- name,
11
- next
5
+ var _a;
6
+ context.fileContent = (_a = context.fileContent) !== null && _a !== void 0 ? _a : fs.readFileSync(context.filePath, 'utf8');
12
7
  };
8
+ return { name, next };
13
9
  };
@@ -1,8 +1,6 @@
1
1
  import { Context } from '../../types/index.js';
2
2
  export declare type StyleOptions = {
3
- extensions?: Array<string>;
4
- directory?: (context: Context) => string;
5
- filename?: (context: Context) => string;
3
+ references?: (context: Context) => string[];
6
4
  };
7
5
  export declare const style: (options: StyleOptions) => {
8
6
  name: string;
@@ -1,36 +1,34 @@
1
1
  import t from '@babel/types';
2
- import fs from 'fs';
2
+ import fs from 'fs-extra';
3
3
  import path from 'path';
4
4
  import * as CONSTANTS from '../../constants/index.js';
5
+ import { addDependency } from '../utils/index.js';
5
6
  const defaults = {
6
- extensions: ['scss', 'css'],
7
- directory(context) {
8
- return context.directoryPath;
9
- },
10
- filename(context) {
11
- return context.fileName;
7
+ references(context) {
8
+ return [
9
+ path.join(context.directoryPath, `${context.fileName}.css`),
10
+ path.join(context.directoryPath, `${context.fileName}.less`),
11
+ path.join(context.directoryPath, `${context.fileName}.sass`),
12
+ path.join(context.directoryPath, `${context.fileName}.scss`),
13
+ path.join(context.directoryPath, `${context.fileName}.styl`)
14
+ ];
12
15
  }
13
16
  };
14
17
  export const style = (options) => {
15
18
  const name = 'style';
16
- options = Object.assign(Object.assign({}, defaults), options);
19
+ options = Object.assign({}, defaults, options);
17
20
  const next = (context) => {
18
- const filename = options.filename(context);
19
- const directory = options.directory(context);
20
- for (let extension of options.extensions) {
21
- const stylePath = path.join(directory, `${filename}.${extension}`);
22
- if (!fs.existsSync(stylePath))
21
+ const references = options.references(context);
22
+ for (const reference of references) {
23
+ if (!fs.existsSync(reference))
23
24
  continue;
24
- context.stylePath = stylePath;
25
- break;
25
+ context.stylePath = reference;
26
26
  }
27
27
  if (!context.stylePath)
28
28
  return;
29
- context.fileAST.program.body.unshift(t.importDeclaration([t.importDefaultSpecifier(t.identifier('AUTO_IMPORT_STYLE'))], t.stringLiteral(context.stylePath)));
30
- context.class.body.body.unshift(t.classProperty(t.identifier(CONSTANTS.STATIC_STYLES), t.identifier('AUTO_IMPORT_STYLE'), undefined, null, undefined, true));
31
- };
32
- return {
33
- name,
34
- next
29
+ const local = addDependency(context.fileAST, context.stylePath, 'AUTO_IMPORT_STYLE', undefined, true);
30
+ const property = t.classProperty(t.identifier(CONSTANTS.STATIC_STYLES), t.identifier(local), undefined, null, undefined, true);
31
+ context.class.body.body.unshift(property);
35
32
  };
33
+ return { name, next };
36
34
  };
@@ -33,8 +33,5 @@ export const validate = () => {
33
33
  });
34
34
  context.isInvalid = !hasValidImport || !hasValidExport;
35
35
  };
36
- return {
37
- name,
38
- next
39
- };
36
+ return { name, next };
40
37
  };
@@ -0,0 +1,8 @@
1
+ import { Global } from '../../types/index.js';
2
+ export interface VisualStudioCodeOptions {
3
+ destination: string;
4
+ }
5
+ export declare const visualStudioCode: (options: VisualStudioCodeOptions) => {
6
+ name: string;
7
+ finish: (global: Global) => void;
8
+ };
@@ -0,0 +1,28 @@
1
+ const defaults = {};
2
+ export const visualStudioCode = (options) => {
3
+ const name = 'visualStudioCode';
4
+ options = Object.assign({}, defaults, options);
5
+ const finish = (global) => {
6
+ // TODO
7
+ // {
8
+ // version: 1.1,
9
+ // tags: [
10
+ // {
11
+ // name: context.componentKey,
12
+ // description: {
13
+ // kind: 'markdown',
14
+ // value: description
15
+ // },
16
+ // attributes: properties,
17
+ // references: [
18
+ // {
19
+ // name: 'Source code',
20
+ // url: `https://github.com/htmlplus/core/tree/main/src/components/${context.directoryName}/${context.fileName}.tsx`
21
+ // }
22
+ // ]
23
+ // }
24
+ // ]
25
+ // };
26
+ };
27
+ return { name, finish };
28
+ };
@@ -1,9 +1,9 @@
1
1
  import { Global } from '../../types/index.js';
2
2
  export interface WebTypesOptions {
3
3
  destination: string;
4
- docUrl: () => string;
5
4
  packageName: string;
6
5
  packageVersion: string;
6
+ docUrl: () => string;
7
7
  }
8
8
  export declare const webTypes: (options: WebTypesOptions) => {
9
9
  name: string;
@@ -1,9 +1,11 @@
1
1
  import { camelCase, paramCase } from 'change-case';
2
- import fs from 'fs';
2
+ import fs from 'fs-extra';
3
3
  import path from 'path';
4
4
  import { getTags, print } from '../utils/index.js';
5
+ const defaults = {};
5
6
  export const webTypes = (options) => {
6
7
  const name = 'webTypes';
8
+ options = Object.assign({}, defaults, options);
7
9
  const finish = (global) => {
8
10
  const json = {
9
11
  '$schema': 'http://json.schemastore.org/web-types',
@@ -70,13 +72,8 @@ export const webTypes = (options) => {
70
72
  }
71
73
  };
72
74
  const dirname = path.dirname(options.destination);
73
- if (!fs.existsSync(dirname))
74
- fs.mkdirSync(dirname, { recursive: true });
75
- const raw = JSON.stringify(json, null, 2);
76
- fs.writeFileSync(options.destination, raw, 'utf8');
77
- };
78
- return {
79
- name,
80
- finish
75
+ fs.ensureDirSync(dirname);
76
+ fs.writeJSONSync(options.destination, json, { encoding: 'utf8', spaces: 2 });
81
77
  };
78
+ return { name, finish };
82
79
  };
@@ -0,0 +1,2 @@
1
+ import { File } from '@babel/types';
2
+ export declare const addDependency: (file: File, source: string, imported: string, local?: string, isDefault?: boolean) => string;
@@ -0,0 +1,41 @@
1
+ import t from '@babel/types';
2
+ import { visitor } from './visitor.js';
3
+ export const addDependency = (file, source, imported, local, isDefault) => {
4
+ let node;
5
+ visitor(file, {
6
+ ImportDeclaration(path) {
7
+ if (path.node.source.value != source)
8
+ return;
9
+ node = path.node;
10
+ }
11
+ });
12
+ let specifier = node === null || node === void 0 ? void 0 : node.specifiers.find((specifier) => {
13
+ var _a;
14
+ if (isDefault) {
15
+ return specifier.type == 'ImportDefaultSpecifier';
16
+ }
17
+ else {
18
+ return ((_a = specifier.imported) === null || _a === void 0 ? void 0 : _a.name) == imported;
19
+ }
20
+ });
21
+ if (specifier)
22
+ return specifier.local.name;
23
+ if (isDefault) {
24
+ specifier = t.importDefaultSpecifier(t.identifier(imported));
25
+ }
26
+ else {
27
+ specifier = t.importSpecifier(t.identifier(local !== null && local !== void 0 ? local : imported), t.identifier(imported));
28
+ }
29
+ if (node) {
30
+ if (isDefault) {
31
+ node.specifiers.unshift(specifier);
32
+ }
33
+ else {
34
+ node.specifiers.push(specifier);
35
+ }
36
+ }
37
+ else {
38
+ file.program.body.unshift(t.importDeclaration([specifier], t.stringLiteral(source)));
39
+ }
40
+ return isDefault ? imported : local !== null && local !== void 0 ? local : imported;
41
+ };
@@ -1,5 +1,5 @@
1
1
  import { parse } from '@babel/parser';
2
- import fs from 'fs';
2
+ import fs from 'fs-extra';
3
3
  import { dirname, resolve } from 'path';
4
4
  import { visitor } from './visitor.js';
5
5
  // TODO: return type
@@ -1,4 +1,5 @@
1
1
  export * from './__dirname.js';
2
+ export * from './addDependency.js';
2
3
  export * from './getInitializer.js';
3
4
  export * from './getType.js';
4
5
  export * from './getTypeReference.js';
@@ -1,4 +1,5 @@
1
1
  export * from './__dirname.js';
2
+ export * from './addDependency.js';
2
3
  export * from './getInitializer.js';
3
4
  export * from './getType.js';
4
5
  export * from './getTypeReference.js';
@@ -1,4 +1,4 @@
1
- import fs from 'fs';
1
+ import fs from 'fs-extra';
2
2
  export const isDirectoryEmpty = (directory) => {
3
3
  try {
4
4
  const files = fs.readdirSync(directory);
@@ -1,5 +1,5 @@
1
1
  import glob from 'fast-glob';
2
- import fs from 'fs';
2
+ import fs from 'fs-extra';
3
3
  import handlebars from 'handlebars';
4
4
  import path from 'path';
5
5
  export const renderTemplate = (source, destination, options) => (context) => {
@@ -17,9 +17,7 @@ export const renderTemplate = (source, destination, options) => (context) => {
17
17
  const directory = path.dirname(to);
18
18
  const raw = fs.readFileSync(from, 'utf8');
19
19
  const template = handlebars.compile(raw)(context);
20
- if (!fs.existsSync(directory)) {
21
- fs.mkdirSync(directory, { recursive: true });
22
- }
20
+ fs.ensureDirSync(directory);
23
21
  fs.writeFileSync(to, template, 'utf8');
24
22
  }
25
23
  };
@@ -20,3 +20,4 @@ export declare const TYPE_DATE = "date";
20
20
  export declare const TYPE_FUNCTION = "function";
21
21
  export declare const TYPE_STRING = "string";
22
22
  export declare const TYPE_NUMBER = "number";
23
+ export declare const UTILS_STYLE_MAP = "styles";
@@ -27,3 +27,5 @@ export const TYPE_DATE = 'date';
27
27
  export const TYPE_FUNCTION = 'function';
28
28
  export const TYPE_STRING = 'string';
29
29
  export const TYPE_NUMBER = 'number';
30
+ // utils
31
+ export const UTILS_STYLE_MAP = 'styles';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htmlplus/element",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "license": "MIT",
5
5
  "author": "Masood Abdolian <m.abdolian@gmail.com>",
6
6
  "description": "Compiler of HTMLPlus",
@@ -41,7 +41,6 @@
41
41
  "fast-glob": "^3.2.11",
42
42
  "fs-extra": "^10.1.0",
43
43
  "handlebars": "^4.7.7",
44
- "listr2": "^5.0.1",
45
44
  "ora": "^6.1.2",
46
45
  "typescript": "^4.7.4"
47
46
  },
@@ -1,5 +1,6 @@
1
1
  import { ClassBody, ClassDeclaration, ClassMethod, ClassProperty, File } from '@babel/types';
2
2
  export interface Context {
3
+ assets?: string;
3
4
  customElementNames?: Array<string>;
4
5
  dependencies?: Array<Context>;
5
6
  dependenciesUnresolved?: Array<string>;
@@ -1,25 +0,0 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
- const defaults = {
4
- source(context) {
5
- return path.join(context.directoryPath, 'external');
6
- },
7
- destination(context) {
8
- return '';
9
- }
10
- };
11
- export const external = (options) => {
12
- const name = 'external';
13
- options = Object.assign(Object.assign({}, defaults), options);
14
- const next = (context) => {
15
- var _a;
16
- const source = (_a = options.source) === null || _a === void 0 ? void 0 : _a.call(options, context);
17
- if (!source || !fs.existsSync(source))
18
- return;
19
- fs.copySync(source, options.destination(context));
20
- };
21
- return {
22
- name,
23
- next
24
- };
25
- };
@@ -1,11 +0,0 @@
1
- import { Context } from '../../types/index.js';
2
- export interface VscodeOptions {
3
- dist: string;
4
- prefix: string;
5
- }
6
- export declare const vscode: (options: VscodeOptions) => {
7
- name: string;
8
- start: (global: any) => void;
9
- next: (context: Context, global: any) => void;
10
- finish: (global: any) => void;
11
- };
@@ -1,83 +0,0 @@
1
- import { paramCase } from 'change-case';
2
- import fs from 'fs';
3
- import path from 'path';
4
- import { getTags, getType, printType } from '../utils/index.js';
5
- export const vscode = (options) => {
6
- const name = 'vscode';
7
- const start = (global) => {
8
- global.vscode = {
9
- version: 1.1,
10
- tags: []
11
- };
12
- };
13
- const next = (context, global) => {
14
- const readme = (() => {
15
- try {
16
- const source = path.resolve(context.directoryPath || '', `${context.fileName}.md`);
17
- return fs.readFileSync(source, 'utf8');
18
- }
19
- catch (_a) { }
20
- })();
21
- const description = (() => {
22
- const content = readme || '';
23
- if (!content.startsWith('# '))
24
- return '';
25
- const sections = content.split('\n');
26
- for (let i = 1; i < sections.length; i++) {
27
- const section = sections[i].trim();
28
- if (!section)
29
- continue;
30
- return section;
31
- }
32
- return '';
33
- })();
34
- const properties = (context.classProperties || []).map((property) => {
35
- var _a;
36
- const name = paramCase(property.key['name']);
37
- const description = (_a = getTags(property).find((tag) => !tag.key)) === null || _a === void 0 ? void 0 : _a.value;
38
- const attribute = {
39
- name,
40
- description
41
- };
42
- // TODO
43
- let { members = [] } = (() => {
44
- const ast = getType(context.fileAST, (property.typeAnnotation || {})['typeAnnotation'], {
45
- directory: context.directoryPath
46
- });
47
- return printType(ast);
48
- })();
49
- // TODO
50
- members = members.filter((member) => member.key !== member.type).map((member) => ({ name: member.key }));
51
- if (members.length)
52
- attribute.values = members;
53
- return attribute;
54
- });
55
- global.vscode.tags.push({
56
- name: context.componentKey,
57
- description: {
58
- kind: 'markdown',
59
- value: description
60
- },
61
- attributes: properties,
62
- references: [
63
- {
64
- name: 'Source code',
65
- url: `https://github.com/htmlplus/core/tree/main/src/components/${context.directoryName}/${context.fileName}.tsx`
66
- }
67
- ]
68
- });
69
- };
70
- const finish = (global) => {
71
- global.vscode.tags = global.vscode.tags.sort((a, b) => (a.name > b.name ? 1 : -1));
72
- // TODO
73
- // fs.ensureDirSync(path.dirname(options.dist));
74
- // TODO
75
- // fs.writeJSONSync(options.dist, global.vscode, { replacer: null, spaces: 2 });
76
- };
77
- return {
78
- name,
79
- start,
80
- next,
81
- finish
82
- };
83
- };