@fluffjs/cli 0.4.4 → 0.5.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/BabelHelpers.js +8 -5
- package/Cli.d.ts +9 -5
- package/Cli.js +218 -155
- package/CodeGenerator.d.ts +19 -10
- package/CodeGenerator.js +146 -106
- package/ComponentCompiler.d.ts +19 -3
- package/ComponentCompiler.js +175 -47
- package/DevServer.d.ts +6 -4
- package/DevServer.js +102 -23
- package/DomPreProcessor.js +22 -40
- package/IndexHtmlTransformer.js +20 -28
- package/PluginLoader.d.ts +22 -0
- package/PluginLoader.js +286 -0
- package/PluginManager.d.ts +39 -0
- package/PluginManager.js +209 -0
- package/TemplateParser.d.ts +5 -0
- package/TemplateParser.js +55 -0
- package/babel-plugin-directive.d.ts +12 -0
- package/babel-plugin-directive.js +78 -0
- package/babel-plugin-reactive.js +19 -14
- package/fluff-esbuild-plugin.js +66 -22
- package/interfaces/ClassTransformContext.d.ts +8 -0
- package/interfaces/ClassTransformContext.js +1 -0
- package/interfaces/CodeGenContext.d.ts +9 -0
- package/interfaces/CodeGenContext.js +1 -0
- package/interfaces/DiscoveryInfo.d.ts +15 -0
- package/interfaces/DiscoveryInfo.js +1 -0
- package/interfaces/EntryPointContext.d.ts +6 -0
- package/interfaces/EntryPointContext.js +1 -0
- package/interfaces/FluffConfigInterface.d.ts +2 -0
- package/interfaces/FluffPlugin.d.ts +26 -0
- package/interfaces/FluffPlugin.js +1 -0
- package/interfaces/FluffPluginOptions.d.ts +3 -0
- package/interfaces/FluffTarget.d.ts +1 -0
- package/interfaces/HtmlTransformOptions.d.ts +2 -0
- package/interfaces/PluginCustomTable.d.ts +6 -0
- package/interfaces/PluginCustomTable.js +1 -0
- package/interfaces/PluginHookDependency.d.ts +5 -0
- package/interfaces/PluginHookDependency.js +1 -0
- package/interfaces/PluginHookName.d.ts +2 -0
- package/interfaces/PluginHookName.js +1 -0
- package/interfaces/ScopeElementConfig.d.ts +5 -0
- package/interfaces/ScopeElementConfig.js +1 -0
- package/interfaces/index.d.ts +8 -0
- package/package.json +5 -3
- package/PeerDependencies.d.ts +0 -6
- package/PeerDependencies.js +0 -7
package/TemplateParser.js
CHANGED
|
@@ -10,10 +10,14 @@ export class TemplateParser {
|
|
|
10
10
|
templateRefs = new Set();
|
|
11
11
|
scopeStack = [];
|
|
12
12
|
getterDependencyMap = new Map();
|
|
13
|
+
scopeElements = [];
|
|
13
14
|
testYieldBeforeGetterDepsLookup = null;
|
|
14
15
|
setGetterDependencyMap(map) {
|
|
15
16
|
this.getterDependencyMap = map;
|
|
16
17
|
}
|
|
18
|
+
setScopeElements(configs) {
|
|
19
|
+
this.scopeElements = configs;
|
|
20
|
+
}
|
|
17
21
|
__setTestYieldBeforeGetterDepsLookup(callback) {
|
|
18
22
|
this.testYieldBeforeGetterDepsLookup = callback;
|
|
19
23
|
}
|
|
@@ -193,8 +197,59 @@ export class TemplateParser {
|
|
|
193
197
|
else if (tagName === 'x-fluff-text') {
|
|
194
198
|
return this.processTextElement(element);
|
|
195
199
|
}
|
|
200
|
+
const scopeConfig = this.findScopeElementConfig(element);
|
|
201
|
+
if (scopeConfig) {
|
|
202
|
+
return this.processScopedElement(element, scopeConfig);
|
|
203
|
+
}
|
|
196
204
|
return this.processRegularElement(element);
|
|
197
205
|
}
|
|
206
|
+
findScopeElementConfig(element) {
|
|
207
|
+
for (const config of this.scopeElements) {
|
|
208
|
+
if (element.tagName === config.tagName && this.getAttr(element, config.letAttribute) !== null) {
|
|
209
|
+
return config;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
async processScopedElement(element, config) {
|
|
215
|
+
const scopeVariable = this.getAttr(element, config.letAttribute) ?? '';
|
|
216
|
+
const bindings = [];
|
|
217
|
+
const attributes = {};
|
|
218
|
+
let hasBindings = false;
|
|
219
|
+
for (const attr of element.attrs) {
|
|
220
|
+
if (attr.name === config.letAttribute) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (attr.name.startsWith('x-fluff-attrib-')) {
|
|
224
|
+
const bindingInfo = await this.parseBindingAttribute(attr.value);
|
|
225
|
+
if (bindingInfo) {
|
|
226
|
+
bindings.push(bindingInfo);
|
|
227
|
+
hasBindings = true;
|
|
228
|
+
if (bindingInfo.binding === 'ref') {
|
|
229
|
+
this.templateRefs.add(bindingInfo.name);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
attributes[attr.name] = attr.value;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
this.pushScope(scopeVariable.split(',').map(v => v.trim()).filter(v => v.length > 0));
|
|
238
|
+
const children = await this.processNodes(element.childNodes ?? []);
|
|
239
|
+
this.popScope();
|
|
240
|
+
const node = {
|
|
241
|
+
type: 'element',
|
|
242
|
+
tagName: element.tagName,
|
|
243
|
+
attributes,
|
|
244
|
+
bindings,
|
|
245
|
+
children,
|
|
246
|
+
namespaceURI: element.namespaceURI
|
|
247
|
+
};
|
|
248
|
+
if (hasBindings) {
|
|
249
|
+
node.id = `l${this.bindingId++}`;
|
|
250
|
+
}
|
|
251
|
+
return node;
|
|
252
|
+
}
|
|
198
253
|
async processForElement(element) {
|
|
199
254
|
const iterator = this.getAttr(element, 'x-fluff-iterator') ?? 'item';
|
|
200
255
|
const iterableRaw = this.getAttr(element, 'x-fluff-iterable') ?? '';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PluginObj } from '@babel/core';
|
|
2
|
+
export interface DirectiveMetadata {
|
|
3
|
+
selector: string;
|
|
4
|
+
className: string;
|
|
5
|
+
}
|
|
6
|
+
interface BabelPluginDirectiveState {
|
|
7
|
+
filename?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const directiveMetadataMap: Map<string, DirectiveMetadata>;
|
|
10
|
+
export default function directivePlugin(): PluginObj<BabelPluginDirectiveState>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=babel-plugin-directive.d.ts.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { types as t } from '@babel/core';
|
|
2
|
+
export const directiveMetadataMap = new Map();
|
|
3
|
+
function getDecoratorName(decorator) {
|
|
4
|
+
if (t.isCallExpression(decorator.expression) && t.isIdentifier(decorator.expression.callee)) {
|
|
5
|
+
return decorator.expression.callee.name;
|
|
6
|
+
}
|
|
7
|
+
if (t.isIdentifier(decorator.expression)) {
|
|
8
|
+
return decorator.expression.name;
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
export default function directivePlugin() {
|
|
13
|
+
return {
|
|
14
|
+
name: 'babel-plugin-directive', visitor: {
|
|
15
|
+
ClassDeclaration(path, state) {
|
|
16
|
+
const decorators = path.node.decorators ?? [];
|
|
17
|
+
const directiveDecorator = decorators.find(dec => {
|
|
18
|
+
if (t.isCallExpression(dec.expression)) {
|
|
19
|
+
const { callee } = dec.expression;
|
|
20
|
+
return t.isIdentifier(callee) && callee.name === 'Directive';
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
});
|
|
24
|
+
if (!directiveDecorator)
|
|
25
|
+
return;
|
|
26
|
+
if (!t.isCallExpression(directiveDecorator.expression))
|
|
27
|
+
return;
|
|
28
|
+
const args = directiveDecorator.expression.arguments;
|
|
29
|
+
if (args.length === 0)
|
|
30
|
+
return;
|
|
31
|
+
const [configArg] = args;
|
|
32
|
+
if (!t.isObjectExpression(configArg))
|
|
33
|
+
return;
|
|
34
|
+
const metadata = {};
|
|
35
|
+
if (path.node.id) {
|
|
36
|
+
metadata.className = path.node.id.name;
|
|
37
|
+
}
|
|
38
|
+
for (const prop of configArg.properties) {
|
|
39
|
+
if (!t.isObjectProperty(prop))
|
|
40
|
+
continue;
|
|
41
|
+
if (!t.isIdentifier(prop.key))
|
|
42
|
+
continue;
|
|
43
|
+
const key = prop.key.name;
|
|
44
|
+
const { value } = prop;
|
|
45
|
+
if (key === 'selector' && t.isStringLiteral(value)) {
|
|
46
|
+
metadata.selector = value.value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const filename = state.filename ?? 'unknown';
|
|
50
|
+
if (metadata.selector && metadata.className) {
|
|
51
|
+
directiveMetadataMap.set(filename, {
|
|
52
|
+
selector: metadata.selector,
|
|
53
|
+
className: metadata.className
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const hostElementProps = [];
|
|
57
|
+
const classBody = path.node.body.body;
|
|
58
|
+
for (const member of classBody) {
|
|
59
|
+
if (!t.isClassProperty(member))
|
|
60
|
+
continue;
|
|
61
|
+
if (!t.isIdentifier(member.key))
|
|
62
|
+
continue;
|
|
63
|
+
const memberDecorators = member.decorators ?? [];
|
|
64
|
+
const hostElementDecIdx = memberDecorators.findIndex(dec => getDecoratorName(dec) === 'HostElement');
|
|
65
|
+
if (hostElementDecIdx !== -1) {
|
|
66
|
+
hostElementProps.push(member.key.name);
|
|
67
|
+
memberDecorators.splice(hostElementDecIdx, 1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (hostElementProps.length > 0) {
|
|
71
|
+
const assignments = hostElementProps.map(propName => t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier(propName)), t.identifier('hostElement'))));
|
|
72
|
+
const setHostElementMethod = t.classMethod('method', t.identifier('__assignHostElementProps'), [t.identifier('hostElement')], t.blockStatement(assignments), false, false);
|
|
73
|
+
classBody.push(setHostElementMethod);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
package/babel-plugin-reactive.js
CHANGED
|
@@ -356,6 +356,20 @@ export default function reactivePlugin() {
|
|
|
356
356
|
propsToRemove.push(memberPath);
|
|
357
357
|
privateFields.push(privateField);
|
|
358
358
|
}
|
|
359
|
+
const reactiveProps = state.reactiveProperties ?? new Set();
|
|
360
|
+
const constructorStatements = [];
|
|
361
|
+
for (const { propName, className, privateName } of classHostBindingDefs) {
|
|
362
|
+
constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('__defineClassHostBinding')), [t.stringLiteral(propName), t.stringLiteral(className), t.stringLiteral(privateName)])));
|
|
363
|
+
}
|
|
364
|
+
const initHostBindingsStatements = [];
|
|
365
|
+
for (const { updateMethodName, watchedProps } of getterHostBindingUpdates) {
|
|
366
|
+
initHostBindingsStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier(updateMethodName)), [])));
|
|
367
|
+
for (const prop of watchedProps) {
|
|
368
|
+
if (reactiveProps.has(prop)) {
|
|
369
|
+
initHostBindingsStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('__baseSubscriptions')), t.identifier('push')), [t.callExpression(t.memberExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier(`__${prop}`)), t.identifier('onChange')), t.identifier('subscribe')), [t.arrowFunctionExpression([], t.callExpression(t.memberExpression(t.thisExpression(), t.identifier(updateMethodName)), []))])])));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
359
373
|
for (const p of propsToRemove) {
|
|
360
374
|
p.remove();
|
|
361
375
|
}
|
|
@@ -398,19 +412,6 @@ export default function reactivePlugin() {
|
|
|
398
412
|
}
|
|
399
413
|
}
|
|
400
414
|
}
|
|
401
|
-
const reactiveProps = state.reactiveProperties ?? new Set();
|
|
402
|
-
const constructorStatements = [];
|
|
403
|
-
for (const { propName, className, privateName } of classHostBindingDefs) {
|
|
404
|
-
constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('__defineClassHostBinding')), [t.stringLiteral(propName), t.stringLiteral(className), t.stringLiteral(privateName)])));
|
|
405
|
-
}
|
|
406
|
-
for (const { updateMethodName, watchedProps } of getterHostBindingUpdates) {
|
|
407
|
-
constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier(updateMethodName)), [])));
|
|
408
|
-
for (const prop of watchedProps) {
|
|
409
|
-
if (reactiveProps.has(prop)) {
|
|
410
|
-
constructorStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('__baseSubscriptions')), t.identifier('push')), [t.callExpression(t.memberExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier(`__${prop}`)), t.identifier('onChange')), t.identifier('subscribe')), [t.arrowFunctionExpression([], t.callExpression(t.memberExpression(t.thisExpression(), t.identifier(updateMethodName)), []))])])));
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
415
|
for (const { propName, privateName } of propertyHostBindingInits) {
|
|
415
416
|
constructorStatements.push(t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier(propName)), t.memberExpression(t.thisExpression(), t.identifier(privateName)))));
|
|
416
417
|
}
|
|
@@ -477,7 +478,7 @@ export default function reactivePlugin() {
|
|
|
477
478
|
}
|
|
478
479
|
const handlerFn = t.arrowFunctionExpression([t.identifier('__ev')], t.blockStatement([handlerBody]));
|
|
479
480
|
if (target === 'this') {
|
|
480
|
-
|
|
481
|
+
initHostBindingsStatements.push(t.expressionStatement(t.callExpression(t.memberExpression(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('__getHostElement')), []), t.identifier('addEventListener')), [
|
|
481
482
|
t.stringLiteral(baseEvent),
|
|
482
483
|
handlerFn
|
|
483
484
|
])));
|
|
@@ -493,6 +494,10 @@ export default function reactivePlugin() {
|
|
|
493
494
|
globalListenerCleanups.push(t.expressionStatement(t.callExpression(t.memberExpression(target === 'document' ? t.identifier('document') : t.identifier('window'), t.identifier('removeEventListener')), [t.stringLiteral(baseEvent), t.memberExpression(t.thisExpression(), t.identifier(handlerPropName))])));
|
|
494
495
|
}
|
|
495
496
|
}
|
|
497
|
+
if (initHostBindingsStatements.length > 0) {
|
|
498
|
+
const initHostBindingsMethod = t.classMethod('method', t.identifier('__initHostBindings'), [], t.blockStatement(initHostBindingsStatements));
|
|
499
|
+
path.unshiftContainer('body', initHostBindingsMethod);
|
|
500
|
+
}
|
|
496
501
|
if (constructorStatements.length > 0) {
|
|
497
502
|
const constructor = path.node.body.find((m) => t.isClassMethod(m) && m.kind === 'constructor');
|
|
498
503
|
if (constructor) {
|
package/fluff-esbuild-plugin.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { parse } from '@babel/parser';
|
|
2
|
+
import * as t from '@babel/types';
|
|
1
3
|
import * as fs from 'fs';
|
|
2
4
|
import * as path from 'path';
|
|
3
5
|
import { fileURLToPath } from 'url';
|
|
4
|
-
import { parse } from '@babel/parser';
|
|
5
|
-
import * as t from '@babel/types';
|
|
6
6
|
import { generate } from './BabelHelpers.js';
|
|
7
7
|
import { CodeGenerator } from './CodeGenerator.js';
|
|
8
8
|
import { ComponentCompiler } from './ComponentCompiler.js';
|
|
@@ -31,11 +31,10 @@ function getEntryPointPath(build) {
|
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
33
|
function detectDecorators(source) {
|
|
34
|
-
const result = { hasComponent: false, hasPipe: false };
|
|
34
|
+
const result = { hasComponent: false, hasDirective: false, hasPipe: false };
|
|
35
35
|
try {
|
|
36
36
|
const ast = parse(source, {
|
|
37
|
-
sourceType: 'module',
|
|
38
|
-
plugins: ['typescript', 'decorators']
|
|
37
|
+
sourceType: 'module', plugins: ['typescript', 'decorators']
|
|
39
38
|
});
|
|
40
39
|
for (const node of ast.program.body) {
|
|
41
40
|
if (t.isClassDeclaration(node) && node.decorators) {
|
|
@@ -44,6 +43,8 @@ function detectDecorators(source) {
|
|
|
44
43
|
const { name } = decorator.expression.callee;
|
|
45
44
|
if (name === 'Component')
|
|
46
45
|
result.hasComponent = true;
|
|
46
|
+
if (name === 'Directive')
|
|
47
|
+
result.hasDirective = true;
|
|
47
48
|
if (name === 'Pipe')
|
|
48
49
|
result.hasPipe = true;
|
|
49
50
|
}
|
|
@@ -55,6 +56,8 @@ function detectDecorators(source) {
|
|
|
55
56
|
const { name } = decorator.expression.callee;
|
|
56
57
|
if (name === 'Component')
|
|
57
58
|
result.hasComponent = true;
|
|
59
|
+
if (name === 'Directive')
|
|
60
|
+
result.hasDirective = true;
|
|
58
61
|
if (name === 'Pipe')
|
|
59
62
|
result.hasPipe = true;
|
|
60
63
|
}
|
|
@@ -66,6 +69,8 @@ function detectDecorators(source) {
|
|
|
66
69
|
const { name } = decorator.expression.callee;
|
|
67
70
|
if (name === 'Component')
|
|
68
71
|
result.hasComponent = true;
|
|
72
|
+
if (name === 'Directive')
|
|
73
|
+
result.hasDirective = true;
|
|
69
74
|
if (name === 'Pipe')
|
|
70
75
|
result.hasPipe = true;
|
|
71
76
|
}
|
|
@@ -82,20 +87,35 @@ export function fluffPlugin(options) {
|
|
|
82
87
|
const fluffSrcPath = findFluffSourcePath();
|
|
83
88
|
const compiledCache = new Map();
|
|
84
89
|
let entryPointPath = null;
|
|
90
|
+
const { pluginManager } = options;
|
|
91
|
+
if (pluginManager) {
|
|
92
|
+
compiler.setPluginManager(pluginManager);
|
|
93
|
+
}
|
|
85
94
|
// noinspection JSUnusedGlobalSymbols
|
|
86
95
|
return {
|
|
87
|
-
name: 'fluff',
|
|
88
|
-
setup(build) {
|
|
96
|
+
name: 'fluff', setup(build) {
|
|
89
97
|
entryPointPath = getEntryPointPath(build);
|
|
90
98
|
build.onStart(async () => {
|
|
91
99
|
CodeGenerator.resetGlobalState();
|
|
92
100
|
compiledCache.clear();
|
|
93
101
|
const componentPaths = await compiler.discoverComponents(options.srcDir);
|
|
102
|
+
if (pluginManager?.hasPlugins) {
|
|
103
|
+
await pluginManager.runAfterDiscovery({
|
|
104
|
+
components: componentPaths.flatMap(p => {
|
|
105
|
+
const metadata = compiler.getComponentMetadata(p);
|
|
106
|
+
return metadata ? [{ filePath: p, metadata }] : [];
|
|
107
|
+
}),
|
|
108
|
+
directives: compiler.getDirectivePaths()
|
|
109
|
+
.flatMap(p => {
|
|
110
|
+
const metadata = compiler.getDirectiveMetadata(p);
|
|
111
|
+
return metadata ? [{ filePath: p, metadata }] : [];
|
|
112
|
+
})
|
|
113
|
+
});
|
|
114
|
+
}
|
|
94
115
|
for (const componentPath of componentPaths) {
|
|
95
116
|
const result = await compiler.compileComponentForBundle(componentPath, options.minify, options.sourcemap, options.skipDefine, options.production);
|
|
96
117
|
compiledCache.set(componentPath, {
|
|
97
|
-
code: result.code,
|
|
98
|
-
watchFiles: result.watchFiles
|
|
118
|
+
code: result.code, watchFiles: result.watchFiles
|
|
99
119
|
});
|
|
100
120
|
}
|
|
101
121
|
});
|
|
@@ -120,40 +140,64 @@ export function fluffPlugin(options) {
|
|
|
120
140
|
watchFiles: result.watchFiles
|
|
121
141
|
};
|
|
122
142
|
}
|
|
143
|
+
if (decorators.hasDirective) {
|
|
144
|
+
const result = await compiler.compileDirectiveForBundle(args.path, options.sourcemap, options.production);
|
|
145
|
+
return {
|
|
146
|
+
contents: result.code, loader: 'js', resolveDir: path.dirname(args.path)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
123
149
|
if (decorators.hasPipe) {
|
|
124
150
|
const transformed = await compiler.transformPipeDecorators(source, args.path);
|
|
125
151
|
DecoratorValidator.validate(transformed, args.path);
|
|
126
152
|
return {
|
|
127
|
-
contents: transformed,
|
|
128
|
-
loader: 'ts',
|
|
129
|
-
resolveDir: path.dirname(args.path)
|
|
153
|
+
contents: transformed, loader: 'ts', resolveDir: path.dirname(args.path)
|
|
130
154
|
};
|
|
131
155
|
}
|
|
132
156
|
if (!entryPointPath || args.path !== entryPointPath) {
|
|
133
157
|
return null;
|
|
134
158
|
}
|
|
135
159
|
const ast = parse(source, {
|
|
136
|
-
sourceType: 'module',
|
|
137
|
-
plugins: ['typescript', 'decorators']
|
|
160
|
+
sourceType: 'module', plugins: ['typescript', 'decorators']
|
|
138
161
|
});
|
|
139
162
|
const exprTableImport = t.importDeclaration([], t.stringLiteral(VIRTUAL_EXPR_TABLE_ID));
|
|
140
163
|
ast.program.body.unshift(exprTableImport);
|
|
141
164
|
const output = generate(ast, { compact: false });
|
|
142
165
|
return {
|
|
143
|
-
contents: output.code,
|
|
144
|
-
loader: 'ts',
|
|
145
|
-
resolveDir: path.dirname(args.path)
|
|
166
|
+
contents: output.code, loader: 'ts', resolveDir: path.dirname(args.path)
|
|
146
167
|
};
|
|
147
168
|
});
|
|
148
169
|
build.onResolve({ filter: new RegExp(`^${VIRTUAL_EXPR_TABLE_ID.replace('/', '\\/')}$`) }, () => {
|
|
149
170
|
return { path: VIRTUAL_EXPR_TABLE_ID, namespace: 'fluff-virtual' };
|
|
150
171
|
});
|
|
151
|
-
build.onLoad({ filter: /.*/, namespace: 'fluff-virtual' }, () => {
|
|
152
|
-
const
|
|
172
|
+
build.onLoad({ filter: /.*/, namespace: 'fluff-virtual' }, async () => {
|
|
173
|
+
const directivePaths = compiler.getDirectivePaths();
|
|
174
|
+
const directiveImports = directivePaths.map(p => `import '${p}';`)
|
|
175
|
+
.join('\n');
|
|
176
|
+
const exprTable = CodeGenerator.generateGlobalExprTable(pluginManager);
|
|
177
|
+
let runtimeImports = '';
|
|
178
|
+
if (pluginManager?.hasPlugins) {
|
|
179
|
+
const imports = pluginManager.collectRuntimeImports();
|
|
180
|
+
runtimeImports = imports.map(imp => `import '${imp}';`)
|
|
181
|
+
.join('\n');
|
|
182
|
+
}
|
|
183
|
+
let globalStylesCode = '';
|
|
184
|
+
if (options.globalStylesCss) {
|
|
185
|
+
const escapedCss = options.globalStylesCss.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
|
|
186
|
+
globalStylesCode = 'import { FluffElement } from \'@fluffjs/fluff\';\n' +
|
|
187
|
+
'const __fluffGlobalSheet = new CSSStyleSheet();\n' +
|
|
188
|
+
`__fluffGlobalSheet.replaceSync(\`${escapedCss}\`);\n` +
|
|
189
|
+
'FluffElement.__addGlobalStyleSheet(__fluffGlobalSheet);\n';
|
|
190
|
+
}
|
|
191
|
+
let entryContent = directiveImports + '\n' + runtimeImports + '\n' + globalStylesCode + (exprTable || '');
|
|
192
|
+
if (pluginManager?.hasPlugins) {
|
|
193
|
+
const entryAst = parse(entryContent, { sourceType: 'module' });
|
|
194
|
+
await pluginManager.runModifyEntryPoint({
|
|
195
|
+
program: entryAst.program, srcDir: options.srcDir
|
|
196
|
+
});
|
|
197
|
+
entryContent = generate(entryAst, { compact: false }).code;
|
|
198
|
+
}
|
|
153
199
|
return {
|
|
154
|
-
contents:
|
|
155
|
-
loader: 'js',
|
|
156
|
-
resolveDir: options.srcDir
|
|
200
|
+
contents: entryContent, loader: 'js', resolveDir: options.srcDir
|
|
157
201
|
};
|
|
158
202
|
});
|
|
159
203
|
if (fluffSrcPath) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type * as t from '@babel/types';
|
|
2
|
+
import type { ComponentMetadata } from './ComponentMetadata.js';
|
|
3
|
+
export interface ClassTransformContext {
|
|
4
|
+
ast: t.File;
|
|
5
|
+
filePath: string;
|
|
6
|
+
metadata: ComponentMetadata;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=ClassTransformContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type * as parse5 from 'parse5';
|
|
2
|
+
import type { CompactBinding } from '../CodeGenerator.js';
|
|
3
|
+
export interface CodeGenContext {
|
|
4
|
+
componentSelector: string;
|
|
5
|
+
generatedFragment: parse5.DefaultTreeAdapterMap['documentFragment'];
|
|
6
|
+
markerConfigs: Map<number, unknown>;
|
|
7
|
+
bindingsMap: Map<string, CompactBinding[]>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=CodeGenContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ComponentMetadata } from './ComponentMetadata.js';
|
|
2
|
+
import type { DirectiveMetadata } from '../babel-plugin-directive.js';
|
|
3
|
+
export interface DiscoveryInfo {
|
|
4
|
+
components: ComponentDiscoveryEntry[];
|
|
5
|
+
directives: DirectiveDiscoveryEntry[];
|
|
6
|
+
}
|
|
7
|
+
export interface ComponentDiscoveryEntry {
|
|
8
|
+
filePath: string;
|
|
9
|
+
metadata: ComponentMetadata;
|
|
10
|
+
}
|
|
11
|
+
export interface DirectiveDiscoveryEntry {
|
|
12
|
+
filePath: string;
|
|
13
|
+
metadata: DirectiveMetadata;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=DiscoveryInfo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type * as parse5 from 'parse5';
|
|
2
|
+
import type { FluffConfig } from './FluffConfigInterface.js';
|
|
3
|
+
import type { DiscoveryInfo } from './DiscoveryInfo.js';
|
|
4
|
+
import type { ParsedTemplate } from './ParsedTemplate.js';
|
|
5
|
+
import type { CodeGenContext } from './CodeGenContext.js';
|
|
6
|
+
import type { ClassTransformContext } from './ClassTransformContext.js';
|
|
7
|
+
import type { EntryPointContext } from './EntryPointContext.js';
|
|
8
|
+
import type { PluginHookName } from './PluginHookName.js';
|
|
9
|
+
import type { PluginCustomTable } from './PluginCustomTable.js';
|
|
10
|
+
import type { ScopeElementConfig } from './ScopeElementConfig.js';
|
|
11
|
+
export interface FluffPlugin {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
dependencies?: Partial<Record<PluginHookName, string[]>>;
|
|
14
|
+
afterConfig?: (config: FluffConfig, pluginConfig: Record<string, unknown>) => void | Promise<void>;
|
|
15
|
+
afterDiscovery?: (discovery: DiscoveryInfo) => void | Promise<void>;
|
|
16
|
+
beforeTemplatePreProcess?: (fragment: parse5.DefaultTreeAdapterMap['documentFragment'], componentSelector: string) => void | Promise<void>;
|
|
17
|
+
afterTemplateParse?: (template: ParsedTemplate, componentSelector: string) => void | Promise<void>;
|
|
18
|
+
afterCodeGeneration?: (context: CodeGenContext) => void | Promise<void>;
|
|
19
|
+
beforeClassTransform?: (context: ClassTransformContext) => void | Promise<void>;
|
|
20
|
+
modifyEntryPoint?: (context: EntryPointContext) => void | Promise<void>;
|
|
21
|
+
modifyIndexHtml?: (document: parse5.DefaultTreeAdapterMap['document']) => void | Promise<void>;
|
|
22
|
+
registerRuntimeImports?: () => string[];
|
|
23
|
+
registerCustomTables?: () => PluginCustomTable[];
|
|
24
|
+
registerScopeElements?: () => ScopeElementConfig[];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=FluffPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PluginManager } from '../PluginManager.js';
|
|
1
2
|
export interface FluffPluginOptions {
|
|
2
3
|
srcDir: string;
|
|
3
4
|
outDir?: string;
|
|
@@ -5,5 +6,7 @@ export interface FluffPluginOptions {
|
|
|
5
6
|
sourcemap?: boolean;
|
|
6
7
|
skipDefine?: boolean;
|
|
7
8
|
production?: boolean;
|
|
9
|
+
pluginManager?: PluginManager;
|
|
10
|
+
globalStylesCss?: string;
|
|
8
11
|
}
|
|
9
12
|
//# sourceMappingURL=FluffPluginOptions.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PluginManager } from '../PluginManager.js';
|
|
1
2
|
export interface HtmlTransformOptions {
|
|
2
3
|
jsBundle: string;
|
|
3
4
|
cssBundle?: string;
|
|
@@ -6,5 +7,6 @@ export interface HtmlTransformOptions {
|
|
|
6
7
|
gzScriptTag?: boolean;
|
|
7
8
|
minify?: boolean;
|
|
8
9
|
liveReload?: boolean;
|
|
10
|
+
pluginManager?: PluginManager;
|
|
9
11
|
}
|
|
10
12
|
//# sourceMappingURL=HtmlTransformOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export type PluginHookName = 'afterConfig' | 'afterDiscovery' | 'beforeTemplatePreProcess' | 'afterTemplateParse' | 'afterCodeGeneration' | 'beforeClassTransform' | 'modifyEntryPoint' | 'modifyIndexHtml' | 'registerRuntimeImports' | 'registerCustomTables' | 'registerScopeElements';
|
|
2
|
+
//# sourceMappingURL=PluginHookName.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/interfaces/index.d.ts
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
export type { BindingInfo } from './BindingInfo.js';
|
|
2
2
|
export type { BreakNode } from './BreakNode.js';
|
|
3
3
|
export type { BundleOptions } from './BundleOptions.js';
|
|
4
|
+
export type { ClassTransformContext } from './ClassTransformContext.js';
|
|
4
5
|
export type { CliOptions } from './CliOptions.js';
|
|
5
6
|
export type { ClassTransformOptions } from './ClassTransformOptions.js';
|
|
7
|
+
export type { CodeGenContext } from './CodeGenContext.js';
|
|
6
8
|
export type { CommentNode } from './CommentNode.js';
|
|
7
9
|
export type { CompileResult } from './CompileResult.js';
|
|
8
10
|
export type { CompilerOptions } from './CompilerOptions.js';
|
|
11
|
+
export type { ComponentDiscoveryEntry, DirectiveDiscoveryEntry, DiscoveryInfo } from './DiscoveryInfo.js';
|
|
9
12
|
export type { ComponentInfo } from './ComponentInfo.js';
|
|
10
13
|
export type { ComponentMetadata } from './ComponentMetadata.js';
|
|
11
14
|
export type { ControlFlow, SwitchCaseOld } from './ControlFlow.js';
|
|
12
15
|
export type { ControlFlowNode } from './ControlFlowNode.js';
|
|
13
16
|
export type { ElementNode } from './ElementNode.js';
|
|
17
|
+
export type { EntryPointContext } from './EntryPointContext.js';
|
|
14
18
|
export type { FluffConfig } from './FluffConfigInterface.js';
|
|
19
|
+
export type { FluffPlugin } from './FluffPlugin.js';
|
|
15
20
|
export type { FluffPluginOptions } from './FluffPluginOptions.js';
|
|
16
21
|
export type { FluffTarget } from './FluffTarget.js';
|
|
17
22
|
export type { ForNode } from './ForNode.js';
|
|
18
23
|
export type { HtmlTransformOptions } from './HtmlTransformOptions.js';
|
|
24
|
+
export type { PluginCustomTable } from './PluginCustomTable.js';
|
|
25
|
+
export type { PluginHookName } from './PluginHookName.js';
|
|
19
26
|
export type { IfBranch } from './IfBranch.js';
|
|
20
27
|
export type { IfNode } from './IfNode.js';
|
|
21
28
|
export type { ImportTransformOptions } from './ImportTransformOptions.js';
|
|
@@ -24,6 +31,7 @@ export type { ParsedTemplate } from './ParsedTemplate.js';
|
|
|
24
31
|
export type { ParsedTemplateOld } from './ParsedTemplateOld.js';
|
|
25
32
|
export type { PropertyChain } from './PropertyChain.js';
|
|
26
33
|
export type { Scope } from './Scope.js';
|
|
34
|
+
export type { ScopeElementConfig } from './ScopeElementConfig.js';
|
|
27
35
|
export type { ServeOptions } from './ServeOptions.js';
|
|
28
36
|
export type { SwitchCase } from './SwitchCase.js';
|
|
29
37
|
export type { SwitchNode } from './SwitchNode.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluffjs/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -40,12 +40,14 @@
|
|
|
40
40
|
"picomatch": "^4.0.2",
|
|
41
41
|
"postcss": "^8.5.6",
|
|
42
42
|
"source-map": "^0.7.6",
|
|
43
|
-
"tslib": "^2.3.0"
|
|
43
|
+
"tslib": "^2.3.0",
|
|
44
|
+
"ws": "^8.19.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@types/he": "^1.2.3",
|
|
47
48
|
"@types/http-proxy": "^1.17.16",
|
|
48
|
-
"@types/jsesc": "^3.0.3"
|
|
49
|
+
"@types/jsesc": "^3.0.3",
|
|
50
|
+
"@types/ws": "^8.18.1"
|
|
49
51
|
},
|
|
50
52
|
"publishConfig": {
|
|
51
53
|
"access": "public"
|
package/PeerDependencies.d.ts
DELETED