@fluffjs/cli 0.0.7 → 0.1.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.d.ts +26 -0
- package/BabelHelpers.js +65 -0
- package/Cli.d.ts +5 -10
- package/Cli.js +123 -52
- package/CodeGenerator.d.ts +53 -39
- package/CodeGenerator.js +330 -725
- package/ComponentCompiler.d.ts +14 -16
- package/ComponentCompiler.js +207 -249
- package/DomPreProcessor.d.ts +36 -0
- package/DomPreProcessor.js +645 -0
- package/ErrorHelpers.d.ts +5 -0
- package/ErrorHelpers.js +8 -0
- package/ExpressionTransformer.d.ts +38 -28
- package/ExpressionTransformer.js +558 -230
- package/Generator.d.ts +1 -5
- package/Generator.js +128 -67
- package/GetterDependencyExtractor.d.ts +4 -0
- package/GetterDependencyExtractor.js +73 -0
- package/IndexHtmlTransformer.d.ts +6 -7
- package/IndexHtmlTransformer.js +82 -88
- package/Parse5Helpers.d.ts +16 -0
- package/Parse5Helpers.js +81 -0
- package/TemplateParser.d.ts +39 -21
- package/TemplateParser.js +462 -268
- package/Typeguards.d.ts +24 -0
- package/Typeguards.js +30 -0
- package/babel-plugin-class-transform.d.ts +3 -18
- package/babel-plugin-class-transform.js +3 -11
- package/babel-plugin-component.d.ts +4 -11
- package/babel-plugin-component.js +23 -2
- package/babel-plugin-imports.d.ts +3 -11
- package/babel-plugin-imports.js +5 -31
- package/babel-plugin-reactive.d.ts +2 -19
- package/babel-plugin-reactive.js +21 -76
- package/bin.js +2 -2
- package/fluff-esbuild-plugin.d.ts +2 -5
- package/fluff-esbuild-plugin.js +4 -1
- package/index.d.ts +6 -2
- package/index.js +1 -1
- package/interfaces/BabelPluginClassTransformState.d.ts +5 -0
- package/interfaces/BabelPluginComponentState.d.ts +4 -0
- package/interfaces/BabelPluginComponentState.js +1 -0
- package/interfaces/BabelPluginImportsState.d.ts +5 -0
- package/interfaces/BabelPluginImportsState.js +1 -0
- package/interfaces/BabelPluginReactiveState.d.ts +13 -0
- package/interfaces/BabelPluginReactiveState.js +1 -0
- package/interfaces/BabelPluginReactiveWatchCallInfo.d.ts +7 -0
- package/interfaces/BabelPluginReactiveWatchCallInfo.js +1 -0
- package/interfaces/BabelPluginReactiveWatchInfo.d.ts +5 -0
- package/interfaces/BabelPluginReactiveWatchInfo.js +1 -0
- package/interfaces/BabelToken.d.ts +8 -0
- package/interfaces/BabelToken.js +1 -0
- package/interfaces/BindingInfo.d.ts +12 -0
- package/interfaces/BindingInfo.js +1 -0
- package/interfaces/BreakMarkerConfig.d.ts +4 -0
- package/interfaces/BreakMarkerConfig.js +1 -0
- package/interfaces/BreakNode.d.ts +4 -0
- package/interfaces/BreakNode.js +1 -0
- package/interfaces/BundleOptions.d.ts +8 -0
- package/interfaces/BundleOptions.js +1 -0
- package/interfaces/ClassTransformOptions.d.ts +10 -0
- package/interfaces/ClassTransformOptions.js +1 -0
- package/interfaces/CliOptions.d.ts +6 -0
- package/interfaces/CliOptions.js +1 -0
- package/interfaces/CommentNode.d.ts +5 -0
- package/interfaces/CommentNode.js +1 -0
- package/interfaces/CompileResult.d.ts +6 -0
- package/interfaces/CompileResult.js +1 -0
- package/interfaces/CompilerOptions.d.ts +6 -0
- package/interfaces/CompilerOptions.js +1 -0
- package/interfaces/ComponentInfo.d.ts +8 -0
- package/interfaces/ComponentInfo.js +1 -0
- package/interfaces/ComponentMetadata.d.ts +9 -0
- package/interfaces/ComponentMetadata.js +1 -0
- package/interfaces/ControlFlow.d.ts +19 -0
- package/interfaces/ControlFlow.js +1 -0
- package/interfaces/ControlFlowNode.d.ts +6 -0
- package/interfaces/ControlFlowNode.js +1 -0
- package/interfaces/ControlFlowParseResult.d.ts +10 -0
- package/interfaces/ControlFlowParseResult.js +1 -0
- package/interfaces/ElementNode.d.ts +11 -0
- package/interfaces/ElementNode.js +1 -0
- package/interfaces/FluffConfigInterface.d.ts +7 -0
- package/interfaces/FluffConfigInterface.js +1 -0
- package/interfaces/FluffPluginOptions.d.ts +9 -0
- package/interfaces/FluffPluginOptions.js +1 -0
- package/interfaces/FluffTarget.d.ts +15 -0
- package/interfaces/FluffTarget.js +1 -0
- package/interfaces/ForMarkerConfig.d.ts +9 -0
- package/interfaces/ForMarkerConfig.js +1 -0
- package/interfaces/ForNode.d.ts +13 -0
- package/interfaces/ForNode.js +1 -0
- package/interfaces/GeneratorOptions.d.ts +5 -0
- package/interfaces/GeneratorOptions.js +1 -0
- package/interfaces/HtmlTransformOptions.d.ts +9 -0
- package/interfaces/HtmlTransformOptions.js +1 -0
- package/interfaces/IfBranch.d.ts +8 -0
- package/interfaces/IfBranch.js +1 -0
- package/interfaces/IfMarkerConfig.d.ts +8 -0
- package/interfaces/IfMarkerConfig.js +1 -0
- package/interfaces/IfNode.d.ts +7 -0
- package/interfaces/IfNode.js +1 -0
- package/interfaces/ImportTransformOptions.d.ts +7 -0
- package/interfaces/ImportTransformOptions.js +1 -0
- package/interfaces/InterpolationNode.d.ts +12 -0
- package/interfaces/InterpolationNode.js +1 -0
- package/interfaces/ParsedTemplate.d.ts +6 -0
- package/interfaces/ParsedTemplate.js +1 -0
- package/interfaces/ParsedTemplateOld.d.ts +9 -0
- package/interfaces/ParsedTemplateOld.js +1 -0
- package/interfaces/PropertyChain.d.ts +2 -0
- package/interfaces/PropertyChain.js +1 -0
- package/interfaces/Scope.d.ts +5 -0
- package/interfaces/Scope.js +1 -0
- package/interfaces/ServeOptions.d.ts +5 -0
- package/interfaces/ServeOptions.js +1 -0
- package/interfaces/SwitchCase.d.ts +8 -0
- package/interfaces/SwitchCase.js +1 -0
- package/interfaces/SwitchMarkerConfig.d.ts +11 -0
- package/interfaces/SwitchMarkerConfig.js +1 -0
- package/interfaces/SwitchNode.d.ts +10 -0
- package/interfaces/SwitchNode.js +1 -0
- package/interfaces/TemplateBinding.d.ts +10 -0
- package/interfaces/TemplateBinding.js +1 -0
- package/interfaces/TemplateNode.d.ts +7 -0
- package/interfaces/TemplateNode.js +1 -0
- package/interfaces/TextMarkerConfig.d.ts +10 -0
- package/interfaces/TextMarkerConfig.js +1 -0
- package/interfaces/TextNode.d.ts +5 -0
- package/interfaces/TextNode.js +1 -0
- package/interfaces/TokenizeResult.d.ts +6 -0
- package/interfaces/TokenizeResult.js +1 -0
- package/interfaces/TransformOptions.d.ts +11 -0
- package/interfaces/TransformOptions.js +1 -0
- package/interfaces/index.d.ts +34 -0
- package/interfaces/index.js +1 -0
- package/package.json +9 -1
- package/types/FluffConfig.d.ts +5 -27
- package/ControlFlowParser.d.ts +0 -55
- package/ControlFlowParser.js +0 -279
- package/types.d.ts +0 -46
- /package/{types.js → interfaces/BabelPluginClassTransformState.js} +0 -0
package/ComponentCompiler.d.ts
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
import type { ClassTransformOptions } from './babel-plugin-class-transform.js';
|
|
2
2
|
import type { ComponentMetadata } from './babel-plugin-component.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
watchFiles?: string[];
|
|
7
|
-
}
|
|
3
|
+
import type { CompileResult } from './interfaces/CompileResult.js';
|
|
4
|
+
import { TemplateParser } from './TemplateParser.js';
|
|
5
|
+
export type { CompileResult } from './interfaces/CompileResult.js';
|
|
8
6
|
export declare class ComponentCompiler {
|
|
9
7
|
private readonly componentSelectors;
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
compileComponent(filePath: string): Promise<string>;
|
|
16
|
-
compileComponentForBundle(filePath: string, minify?: boolean, sourcemap?: boolean): Promise<CompileResult>;
|
|
8
|
+
private getReactivePropsForFile;
|
|
9
|
+
protected createTemplateParser(_filePath: string): TemplateParser;
|
|
10
|
+
private runBabelTransform;
|
|
11
|
+
discoverComponents(dir: string): Promise<void>;
|
|
12
|
+
compileComponentForBundle(filePath: string, minify?: boolean, sourcemap?: boolean, skipDefine?: boolean, production?: boolean): Promise<CompileResult>;
|
|
17
13
|
stripTypeScriptWithSourceMap(code: string, filePath: string, sourcemap?: boolean): Promise<CompileResult>;
|
|
18
|
-
private createComponentSourceMap;
|
|
19
14
|
transformImportsForBundle(code: string, filePath: string): Promise<string>;
|
|
20
|
-
transformReactiveProperties(code: string, filePath?: string): Promise<string>;
|
|
15
|
+
transformReactiveProperties(code: string, filePath?: string, production?: boolean): Promise<string>;
|
|
21
16
|
stripTypeScript(code: string, filePath?: string): Promise<string>;
|
|
22
17
|
extractComponentMetadata(code: string, filePath: string): Promise<ComponentMetadata | null>;
|
|
23
|
-
transformImportsAndDecorators(code: string, filePath: string): Promise<string>;
|
|
24
18
|
transformClass(code: string, filePath: string, options: ClassTransformOptions): Promise<string>;
|
|
25
19
|
transformLibraryImports(code: string, filePath: string): Promise<string>;
|
|
26
|
-
|
|
20
|
+
private createComponentSourceMap;
|
|
21
|
+
private addFluffImport;
|
|
22
|
+
private appendCode;
|
|
23
|
+
private addBindingsMap;
|
|
24
|
+
private addCustomElementsDefine;
|
|
27
25
|
}
|
|
28
26
|
//# sourceMappingURL=ComponentCompiler.d.ts.map
|
package/ComponentCompiler.js
CHANGED
|
@@ -1,139 +1,163 @@
|
|
|
1
1
|
import * as babel from '@babel/core';
|
|
2
|
+
import { parse } from '@babel/parser';
|
|
3
|
+
import * as t from '@babel/types';
|
|
2
4
|
import * as esbuild from 'esbuild';
|
|
3
5
|
import * as fs from 'fs';
|
|
4
6
|
import { minify as minifyHtml } from 'html-minifier-terser';
|
|
5
7
|
import * as path from 'path';
|
|
6
8
|
import { SourceMapConsumer, SourceMapGenerator } from 'source-map';
|
|
7
|
-
import classTransformPlugin
|
|
9
|
+
import classTransformPlugin from './babel-plugin-class-transform.js';
|
|
8
10
|
import componentPlugin, { componentMetadataMap } from './babel-plugin-component.js';
|
|
9
11
|
import importsPlugin from './babel-plugin-imports.js';
|
|
10
12
|
import reactivePlugin, { reactivePropertiesMap } from './babel-plugin-reactive.js';
|
|
13
|
+
import { generate } from './BabelHelpers.js';
|
|
11
14
|
import { CodeGenerator } from './CodeGenerator.js';
|
|
15
|
+
import { ErrorHelpers } from './ErrorHelpers.js';
|
|
16
|
+
import { GetterDependencyExtractor } from './GetterDependencyExtractor.js';
|
|
12
17
|
import { TemplateParser } from './TemplateParser.js';
|
|
13
18
|
export class ComponentCompiler {
|
|
14
19
|
componentSelectors = new Set();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
getReactivePropsForFile(filePath) {
|
|
21
|
+
const direct = reactivePropertiesMap.get(filePath);
|
|
22
|
+
if (direct) {
|
|
23
|
+
return direct;
|
|
24
|
+
}
|
|
25
|
+
for (const [key, value] of reactivePropertiesMap.entries()) {
|
|
26
|
+
if (key === filePath || key.endsWith(filePath) || filePath.endsWith(key)) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return new Set();
|
|
20
31
|
}
|
|
21
|
-
|
|
22
|
-
|
|
32
|
+
createTemplateParser(_filePath) {
|
|
33
|
+
return new TemplateParser();
|
|
34
|
+
}
|
|
35
|
+
async runBabelTransform(code, filePath, options) {
|
|
36
|
+
try {
|
|
37
|
+
const presets = options.useTypeScriptPreset
|
|
38
|
+
? [['@babel/preset-typescript', { isTSX: false, allExtensions: true }]]
|
|
39
|
+
: [];
|
|
40
|
+
const plugins = options.useDecoratorSyntax
|
|
41
|
+
? [['@babel/plugin-syntax-decorators', { version: '2023-11' }], ...options.plugins]
|
|
42
|
+
: options.plugins;
|
|
43
|
+
const parserOpts = options.useDecoratorSyntax
|
|
44
|
+
? { plugins: ['typescript', 'decorators'] }
|
|
45
|
+
: options.useTypeScriptPreset
|
|
46
|
+
? { plugins: ['typescript'] }
|
|
47
|
+
: undefined;
|
|
48
|
+
const result = await babel.transformAsync(code, {
|
|
49
|
+
filename: filePath,
|
|
50
|
+
presets,
|
|
51
|
+
plugins,
|
|
52
|
+
parserOpts
|
|
53
|
+
});
|
|
54
|
+
return result?.code ?? code;
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
console.error(`${options.errorContext} in ${filePath}:`, ErrorHelpers.getErrorMessage(e));
|
|
58
|
+
return code;
|
|
59
|
+
}
|
|
23
60
|
}
|
|
24
|
-
async discoverComponents(
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
|
|
61
|
+
async discoverComponents(dir) {
|
|
62
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
const fullPath = path.join(dir, entry.name);
|
|
65
|
+
if (entry.isDirectory()) {
|
|
66
|
+
await this.discoverComponents(fullPath);
|
|
67
|
+
}
|
|
68
|
+
else if (entry.name.endsWith('.component.ts')) {
|
|
69
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
70
|
+
const metadata = await this.extractComponentMetadata(content, fullPath);
|
|
71
|
+
if (metadata?.selector) {
|
|
72
|
+
this.componentSelectors.add(metadata.selector);
|
|
73
|
+
}
|
|
33
74
|
}
|
|
34
75
|
}
|
|
35
76
|
}
|
|
36
|
-
async
|
|
77
|
+
async compileComponentForBundle(filePath, minify, sourcemap, skipDefine, production) {
|
|
37
78
|
let source = fs.readFileSync(filePath, 'utf-8');
|
|
38
79
|
const componentDir = path.dirname(filePath);
|
|
80
|
+
const parser = this.createTemplateParser(filePath);
|
|
81
|
+
reactivePropertiesMap.delete(filePath);
|
|
39
82
|
if (source.includes('@Reactive') || source.includes('@Input')) {
|
|
40
|
-
source = await this.transformReactiveProperties(source, filePath);
|
|
41
|
-
const reactiveProps = reactivePropertiesMap.get(filePath);
|
|
42
|
-
if (reactiveProps) {
|
|
43
|
-
this.generator.setReactiveProperties(reactiveProps);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
this.generator.setReactiveProperties(new Set());
|
|
83
|
+
source = await this.transformReactiveProperties(source, filePath, production);
|
|
48
84
|
}
|
|
49
85
|
const metadata = await this.extractComponentMetadata(source, filePath);
|
|
50
86
|
if (!metadata) {
|
|
51
|
-
return source;
|
|
87
|
+
return { code: source };
|
|
52
88
|
}
|
|
53
|
-
const { selector, templateUrl, styleUrl, className } = metadata;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (fs.existsSync(stylePath)) {
|
|
60
|
-
styles = fs.readFileSync(stylePath, 'utf-8');
|
|
61
|
-
}
|
|
89
|
+
const { selector, templateUrl, template, styleUrl, styles: inlineStyles, className } = metadata;
|
|
90
|
+
let templateHtml = '';
|
|
91
|
+
let templatePath = null;
|
|
92
|
+
if (templateUrl) {
|
|
93
|
+
templatePath = path.resolve(componentDir, templateUrl);
|
|
94
|
+
templateHtml = fs.readFileSync(templatePath, 'utf-8');
|
|
62
95
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const renderMethod = this.generator.generateRenderMethod(html, styles);
|
|
66
|
-
const bindingsSetup = this.generator.generateBindingsSetup(bindings, controlFlows);
|
|
67
|
-
let result = await this.transformImportsAndDecorators(source, filePath);
|
|
68
|
-
result = await this.transformClass(result, filePath, {
|
|
69
|
-
className, originalSuperClass: 'HTMLElement', newSuperClass: 'FluffElement', injectMethods: [
|
|
70
|
-
{ name: '__render', body: renderMethod }, { name: '__setupBindings', body: bindingsSetup }
|
|
71
|
-
]
|
|
72
|
-
});
|
|
73
|
-
result = 'import { FluffElement } from \'./fluff-lib/runtime/FluffElement.js\';\n' + result;
|
|
74
|
-
result += `\ncustomElements.define('${selector}', ${className});\n`;
|
|
75
|
-
result = await this.stripTypeScript(result, filePath);
|
|
76
|
-
return result;
|
|
77
|
-
}
|
|
78
|
-
async compileComponentForBundle(filePath, minify, sourcemap) {
|
|
79
|
-
let source = fs.readFileSync(filePath, 'utf-8');
|
|
80
|
-
const componentDir = path.dirname(filePath);
|
|
81
|
-
const generator = new CodeGenerator();
|
|
82
|
-
if (source.includes('@Reactive') || source.includes('@Input')) {
|
|
83
|
-
source = await this.transformReactiveProperties(source, filePath);
|
|
84
|
-
const reactiveProps = reactivePropertiesMap.get(filePath);
|
|
85
|
-
if (reactiveProps) {
|
|
86
|
-
generator.setReactiveProperties(reactiveProps);
|
|
87
|
-
}
|
|
96
|
+
else if (template) {
|
|
97
|
+
templateHtml = template;
|
|
88
98
|
}
|
|
89
99
|
else {
|
|
90
|
-
generator.setReactiveProperties(new Set());
|
|
91
|
-
}
|
|
92
|
-
const metadata = await this.extractComponentMetadata(source, filePath);
|
|
93
|
-
if (!metadata) {
|
|
94
100
|
return { code: source };
|
|
95
101
|
}
|
|
96
|
-
const { selector, templateUrl, styleUrl, className } = metadata;
|
|
97
|
-
const templatePath = path.resolve(componentDir, templateUrl);
|
|
98
|
-
let templateHtml = fs.readFileSync(templatePath, 'utf-8');
|
|
99
102
|
const stylePath = styleUrl ? path.resolve(componentDir, styleUrl) : null;
|
|
100
103
|
let styles = '';
|
|
101
104
|
if (stylePath && fs.existsSync(stylePath)) {
|
|
102
105
|
styles = fs.readFileSync(stylePath, 'utf-8');
|
|
103
106
|
}
|
|
107
|
+
else if (inlineStyles) {
|
|
108
|
+
styles = inlineStyles;
|
|
109
|
+
}
|
|
110
|
+
if (minify && styles) {
|
|
111
|
+
const cssResult = await esbuild.transform(styles, {
|
|
112
|
+
loader: 'css', minify: true
|
|
113
|
+
});
|
|
114
|
+
styles = cssResult.code;
|
|
115
|
+
}
|
|
116
|
+
const reactiveProps = this.getReactivePropsForFile(filePath);
|
|
117
|
+
const getterDepMap = GetterDependencyExtractor.extractGetterDependencyMap(source, reactiveProps);
|
|
118
|
+
parser.setGetterDependencyMap(getterDepMap);
|
|
119
|
+
const parsed = await parser.parse(templateHtml);
|
|
120
|
+
parser.setGetterDependencyMap(new Map());
|
|
121
|
+
const gen = new CodeGenerator(this.componentSelectors, selector);
|
|
122
|
+
let generatedHtml = gen.generateHtml(parsed);
|
|
104
123
|
if (minify) {
|
|
105
|
-
|
|
124
|
+
generatedHtml = await minifyHtml(generatedHtml, {
|
|
106
125
|
collapseWhitespace: true,
|
|
107
126
|
removeComments: true,
|
|
108
127
|
removeRedundantAttributes: true,
|
|
109
128
|
removeEmptyAttributes: true
|
|
110
129
|
});
|
|
111
|
-
if (styles) {
|
|
112
|
-
const cssResult = await esbuild.transform(styles, {
|
|
113
|
-
loader: 'css',
|
|
114
|
-
minify: true
|
|
115
|
-
});
|
|
116
|
-
styles = cssResult.code;
|
|
117
|
-
}
|
|
118
130
|
}
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
const bindingsSetup = generator.generateBindingsSetup(bindings, controlFlows);
|
|
131
|
+
const markerConfigJson = gen.getMarkerConfigJson();
|
|
132
|
+
const renderMethod = gen.generateRenderMethodFromHtml(generatedHtml, styles, markerConfigJson);
|
|
133
|
+
const bindingsSetup = gen.generateBindingsSetup();
|
|
123
134
|
let result = await this.transformImportsForBundle(source, filePath);
|
|
124
135
|
result = await this.transformClass(result, filePath, {
|
|
125
136
|
className, originalSuperClass: 'HTMLElement', newSuperClass: 'FluffElement', injectMethods: [
|
|
126
137
|
{ name: '__render', body: renderMethod }, { name: '__setupBindings', body: bindingsSetup }
|
|
127
138
|
]
|
|
128
139
|
});
|
|
129
|
-
result =
|
|
130
|
-
|
|
140
|
+
result = this.addFluffImport(result);
|
|
141
|
+
const exprAssignments = gen.generateExpressionAssignments();
|
|
142
|
+
if (exprAssignments) {
|
|
143
|
+
result = this.appendCode(result, exprAssignments);
|
|
144
|
+
}
|
|
145
|
+
const bindingsMap = gen.getBindingsMap();
|
|
146
|
+
if (Object.keys(bindingsMap).length > 0) {
|
|
147
|
+
result = this.addBindingsMap(result, className, bindingsMap);
|
|
148
|
+
}
|
|
149
|
+
if (!skipDefine) {
|
|
150
|
+
result = this.addCustomElementsDefine(result, selector, className);
|
|
151
|
+
}
|
|
131
152
|
const tsResult = await this.stripTypeScriptWithSourceMap(result, filePath, sourcemap);
|
|
132
|
-
const watchFiles = [
|
|
153
|
+
const watchFiles = [];
|
|
154
|
+
if (templatePath) {
|
|
155
|
+
watchFiles.push(templatePath);
|
|
156
|
+
}
|
|
133
157
|
if (stylePath && fs.existsSync(stylePath)) {
|
|
134
158
|
watchFiles.push(stylePath);
|
|
135
159
|
}
|
|
136
|
-
if (sourcemap && tsResult.map) {
|
|
160
|
+
if (sourcemap && tsResult.map && templatePath) {
|
|
137
161
|
const finalMap = await this.createComponentSourceMap(tsResult.code, tsResult.map, filePath, templatePath, stylePath);
|
|
138
162
|
return { code: tsResult.code, map: finalMap, watchFiles };
|
|
139
163
|
}
|
|
@@ -151,78 +175,31 @@ export class ComponentCompiler {
|
|
|
151
175
|
return { code: result.code, map: result.map };
|
|
152
176
|
}
|
|
153
177
|
catch (e) {
|
|
154
|
-
|
|
155
|
-
console.error(`Error transforming ${filePath}:`, message);
|
|
178
|
+
console.error(`Error transforming ${filePath}:`, ErrorHelpers.getErrorMessage(e));
|
|
156
179
|
return { code };
|
|
157
180
|
}
|
|
158
181
|
}
|
|
159
|
-
async createComponentSourceMap(code, esbuildMap, componentPath, templatePath, stylePath) {
|
|
160
|
-
const consumer = await new SourceMapConsumer(JSON.parse(esbuildMap));
|
|
161
|
-
const generator = new SourceMapGenerator({
|
|
162
|
-
file: path.basename(componentPath)
|
|
163
|
-
.replace('.ts', '.js')
|
|
164
|
-
});
|
|
165
|
-
generator.setSourceContent(componentPath, fs.readFileSync(componentPath, 'utf-8'));
|
|
166
|
-
generator.setSourceContent(templatePath, fs.readFileSync(templatePath, 'utf-8'));
|
|
167
|
-
if (stylePath && fs.existsSync(stylePath)) {
|
|
168
|
-
generator.setSourceContent(stylePath, fs.readFileSync(stylePath, 'utf-8'));
|
|
169
|
-
}
|
|
170
|
-
consumer.eachMapping(mapping => {
|
|
171
|
-
if (mapping.source) {
|
|
172
|
-
generator.addMapping({
|
|
173
|
-
generated: { line: mapping.generatedLine, column: mapping.generatedColumn },
|
|
174
|
-
original: { line: mapping.originalLine, column: mapping.originalColumn },
|
|
175
|
-
source: mapping.source,
|
|
176
|
-
name: mapping.name ?? undefined
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
consumer.destroy();
|
|
181
|
-
return generator.toString();
|
|
182
|
-
}
|
|
183
182
|
async transformImportsForBundle(code, filePath) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
], parserOpts: {
|
|
197
|
-
plugins: ['typescript', 'decorators']
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
return result?.code ?? code;
|
|
201
|
-
}
|
|
202
|
-
catch (e) {
|
|
203
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
204
|
-
console.error(`Failed to transform imports in ${filePath}:`, message);
|
|
205
|
-
return code;
|
|
206
|
-
}
|
|
183
|
+
const importOptions = {
|
|
184
|
+
removeImportsFrom: ['lighter'],
|
|
185
|
+
removeDecorators: ['Component', 'Input', 'Output'],
|
|
186
|
+
pathReplacements: {},
|
|
187
|
+
addJsExtension: false
|
|
188
|
+
};
|
|
189
|
+
return this.runBabelTransform(code, filePath, {
|
|
190
|
+
useTypeScriptPreset: true,
|
|
191
|
+
useDecoratorSyntax: true,
|
|
192
|
+
plugins: [[importsPlugin, importOptions]],
|
|
193
|
+
errorContext: 'Failed to transform imports'
|
|
194
|
+
});
|
|
207
195
|
}
|
|
208
|
-
async transformReactiveProperties(code, filePath = 'file.ts') {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
], parserOpts: {
|
|
216
|
-
plugins: ['typescript', 'decorators']
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
return result?.code ?? code;
|
|
220
|
-
}
|
|
221
|
-
catch (e) {
|
|
222
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
223
|
-
console.error(`Babel transform error in ${filePath}:`, message);
|
|
224
|
-
return code;
|
|
225
|
-
}
|
|
196
|
+
async transformReactiveProperties(code, filePath = 'file.ts', production) {
|
|
197
|
+
return this.runBabelTransform(code, filePath, {
|
|
198
|
+
useTypeScriptPreset: true,
|
|
199
|
+
useDecoratorSyntax: true,
|
|
200
|
+
plugins: [[reactivePlugin, { production: production ?? false }]],
|
|
201
|
+
errorContext: 'Babel transform error'
|
|
202
|
+
});
|
|
226
203
|
}
|
|
227
204
|
async stripTypeScript(code, filePath = 'file.ts') {
|
|
228
205
|
try {
|
|
@@ -232,123 +209,104 @@ export class ComponentCompiler {
|
|
|
232
209
|
return result.code;
|
|
233
210
|
}
|
|
234
211
|
catch (e) {
|
|
235
|
-
|
|
236
|
-
console.error(`Error transforming ${filePath}:`, message);
|
|
212
|
+
console.error(`Error transforming ${filePath}:`, ErrorHelpers.getErrorMessage(e));
|
|
237
213
|
return code;
|
|
238
214
|
}
|
|
239
215
|
}
|
|
240
216
|
async extractComponentMetadata(code, filePath) {
|
|
241
217
|
try {
|
|
242
218
|
componentMetadataMap.delete(filePath);
|
|
243
|
-
await
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
], parserOpts: {
|
|
249
|
-
plugins: ['typescript', 'decorators']
|
|
250
|
-
}
|
|
219
|
+
await this.runBabelTransform(code, filePath, {
|
|
220
|
+
useTypeScriptPreset: true,
|
|
221
|
+
useDecoratorSyntax: true,
|
|
222
|
+
plugins: [componentPlugin],
|
|
223
|
+
errorContext: 'Failed to extract component metadata'
|
|
251
224
|
});
|
|
252
225
|
return componentMetadataMap.get(filePath) ?? null;
|
|
253
226
|
}
|
|
254
227
|
catch (e) {
|
|
255
|
-
|
|
256
|
-
console.error(`Failed to extract component metadata from ${filePath}:`, message);
|
|
228
|
+
console.error(`Failed to extract component metadata from ${filePath}:`, ErrorHelpers.getErrorMessage(e));
|
|
257
229
|
return null;
|
|
258
230
|
}
|
|
259
231
|
}
|
|
260
|
-
async transformImportsAndDecorators(code, filePath) {
|
|
261
|
-
try {
|
|
262
|
-
const importOptions = {
|
|
263
|
-
removeImportsFrom: ['lighter'], removeDecorators: ['Component', 'Input', 'Output'], pathReplacements: {
|
|
264
|
-
'@/fluff-lib/': './fluff-lib/'
|
|
265
|
-
}, addJsExtension: true
|
|
266
|
-
};
|
|
267
|
-
const result = await babel.transformAsync(code, {
|
|
268
|
-
filename: filePath, presets: [
|
|
269
|
-
['@babel/preset-typescript', { isTSX: false, allExtensions: true }]
|
|
270
|
-
], plugins: [
|
|
271
|
-
['@babel/plugin-syntax-decorators', { version: '2023-11' }], [importsPlugin, importOptions]
|
|
272
|
-
], parserOpts: {
|
|
273
|
-
plugins: ['typescript', 'decorators']
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
return result?.code ?? code;
|
|
277
|
-
}
|
|
278
|
-
catch (e) {
|
|
279
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
280
|
-
console.error(`Failed to transform imports in ${filePath}:`, message);
|
|
281
|
-
return code;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
232
|
async transformClass(code, filePath, options) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
let transformed = result?.code ?? code;
|
|
292
|
-
if (options.injectMethods) {
|
|
293
|
-
transformed = injectMethodBodies(transformed, options.injectMethods);
|
|
294
|
-
}
|
|
295
|
-
return transformed;
|
|
296
|
-
}
|
|
297
|
-
catch (e) {
|
|
298
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
299
|
-
console.error(`Failed to transform class in ${filePath}:`, message);
|
|
300
|
-
return code;
|
|
301
|
-
}
|
|
233
|
+
return this.runBabelTransform(code, filePath, {
|
|
234
|
+
useTypeScriptPreset: false,
|
|
235
|
+
useDecoratorSyntax: false,
|
|
236
|
+
plugins: [[classTransformPlugin, options]],
|
|
237
|
+
errorContext: 'Failed to transform class'
|
|
238
|
+
});
|
|
302
239
|
}
|
|
303
240
|
async transformLibraryImports(code, filePath) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
], parserOpts: {
|
|
316
|
-
plugins: ['typescript']
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
return result?.code ?? code;
|
|
320
|
-
}
|
|
321
|
-
catch (e) {
|
|
322
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
323
|
-
console.error(`Failed to transform library imports in ${filePath}:`, message);
|
|
324
|
-
return code;
|
|
325
|
-
}
|
|
241
|
+
const importOptions = {
|
|
242
|
+
pathReplacements: {
|
|
243
|
+
'@/fluff-lib/': '../'
|
|
244
|
+
}, addJsExtension: true
|
|
245
|
+
};
|
|
246
|
+
return this.runBabelTransform(code, filePath, {
|
|
247
|
+
useTypeScriptPreset: true,
|
|
248
|
+
useDecoratorSyntax: false,
|
|
249
|
+
plugins: [[importsPlugin, importOptions]],
|
|
250
|
+
errorContext: 'Failed to transform library imports'
|
|
251
|
+
});
|
|
326
252
|
}
|
|
327
|
-
async
|
|
328
|
-
const
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
253
|
+
async createComponentSourceMap(code, esbuildMap, componentPath, templatePath, stylePath) {
|
|
254
|
+
const consumer = await new SourceMapConsumer(JSON.parse(esbuildMap));
|
|
255
|
+
const generator = new SourceMapGenerator({
|
|
256
|
+
file: path.basename(componentPath)
|
|
257
|
+
.replace('.ts', '.js')
|
|
258
|
+
});
|
|
259
|
+
generator.setSourceContent(componentPath, fs.readFileSync(componentPath, 'utf-8'));
|
|
260
|
+
generator.setSourceContent(templatePath, fs.readFileSync(templatePath, 'utf-8'));
|
|
261
|
+
if (stylePath && fs.existsSync(stylePath)) {
|
|
262
|
+
generator.setSourceContent(stylePath, fs.readFileSync(stylePath, 'utf-8'));
|
|
332
263
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
const files = fs.readdirSync(srcPath)
|
|
342
|
-
.filter(f => f.endsWith('.ts'));
|
|
343
|
-
for (const file of files) {
|
|
344
|
-
const fullPath = path.join(srcPath, file);
|
|
345
|
-
let content = fs.readFileSync(fullPath, 'utf-8');
|
|
346
|
-
content = await this.transformLibraryImports(content, fullPath);
|
|
347
|
-
content = await this.stripTypeScript(content, fullPath);
|
|
348
|
-
const outFile = file.replace('.ts', '.js');
|
|
349
|
-
fs.writeFileSync(path.join(distPath, outFile), content);
|
|
350
|
-
}
|
|
264
|
+
consumer.eachMapping(mapping => {
|
|
265
|
+
if (mapping.source) {
|
|
266
|
+
generator.addMapping({
|
|
267
|
+
generated: { line: mapping.generatedLine, column: mapping.generatedColumn },
|
|
268
|
+
original: { line: mapping.originalLine, column: mapping.originalColumn },
|
|
269
|
+
source: mapping.source,
|
|
270
|
+
name: mapping.name ?? undefined
|
|
271
|
+
});
|
|
351
272
|
}
|
|
273
|
+
});
|
|
274
|
+
consumer.destroy();
|
|
275
|
+
return generator.toString();
|
|
276
|
+
}
|
|
277
|
+
addFluffImport(code) {
|
|
278
|
+
const ast = parse(code, { sourceType: 'module' });
|
|
279
|
+
const importSpecifiers = [
|
|
280
|
+
t.importSpecifier(t.identifier('FluffBase'), t.identifier('FluffBase')),
|
|
281
|
+
t.importSpecifier(t.identifier('FluffElement'), t.identifier('FluffElement')),
|
|
282
|
+
t.importSpecifier(t.identifier('MarkerManager'), t.identifier('MarkerManager'))
|
|
283
|
+
];
|
|
284
|
+
const importDecl = t.importDeclaration(importSpecifiers, t.stringLiteral('@fluffjs/fluff'));
|
|
285
|
+
ast.program.body.unshift(importDecl);
|
|
286
|
+
return generate(ast, { compact: false }).code;
|
|
287
|
+
}
|
|
288
|
+
appendCode(code, additionalCode) {
|
|
289
|
+
const ast = parse(code, { sourceType: 'module' });
|
|
290
|
+
const additionalAst = parse(additionalCode, { sourceType: 'module' });
|
|
291
|
+
ast.program.body.push(...additionalAst.program.body);
|
|
292
|
+
return generate(ast, { compact: false }).code;
|
|
293
|
+
}
|
|
294
|
+
addBindingsMap(code, className, bindingsMap) {
|
|
295
|
+
const ast = parse(code, { sourceType: 'module' });
|
|
296
|
+
const jsonStr = JSON.stringify(bindingsMap);
|
|
297
|
+
const valueAst = parse(`(${jsonStr})`, { sourceType: 'module' });
|
|
298
|
+
const [valueStmt] = valueAst.program.body;
|
|
299
|
+
if (!t.isExpressionStatement(valueStmt)) {
|
|
300
|
+
return code;
|
|
352
301
|
}
|
|
302
|
+
const assignment = t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier(className), t.identifier('__bindings')), valueStmt.expression));
|
|
303
|
+
ast.program.body.push(assignment);
|
|
304
|
+
return generate(ast, { compact: false }).code;
|
|
305
|
+
}
|
|
306
|
+
addCustomElementsDefine(code, selector, className) {
|
|
307
|
+
const ast = parse(code, { sourceType: 'module' });
|
|
308
|
+
const defineCall = t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('customElements'), t.identifier('define')), [t.stringLiteral(selector), t.identifier(className)]));
|
|
309
|
+
ast.program.body.push(defineCall);
|
|
310
|
+
return generate(ast, { compact: false }).code;
|
|
353
311
|
}
|
|
354
312
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare class DomPreProcessor {
|
|
2
|
+
private readonly stack;
|
|
3
|
+
private source;
|
|
4
|
+
private rootFragment;
|
|
5
|
+
private readonly elementStack;
|
|
6
|
+
process(html: string): Promise<string>;
|
|
7
|
+
private handleStartTag;
|
|
8
|
+
private transformAttribute;
|
|
9
|
+
private convertInterpolationToExpression;
|
|
10
|
+
private handleEndTag;
|
|
11
|
+
private handleText;
|
|
12
|
+
private appendNode;
|
|
13
|
+
private appendText;
|
|
14
|
+
private appendDoctype;
|
|
15
|
+
private findNextSpecial;
|
|
16
|
+
private parseInterpolation;
|
|
17
|
+
private parseControlFlow;
|
|
18
|
+
private parseExpressionBlockCore;
|
|
19
|
+
private parseSimpleBlockCore;
|
|
20
|
+
private parseIfStatement;
|
|
21
|
+
private parseElseIfStatement;
|
|
22
|
+
private parseElseStatement;
|
|
23
|
+
private parseForStatement;
|
|
24
|
+
private parseSwitchStatement;
|
|
25
|
+
private parseCaseStatement;
|
|
26
|
+
private parseDefaultStatement;
|
|
27
|
+
private parseEmptyStatement;
|
|
28
|
+
private parseSimpleStatement;
|
|
29
|
+
private parseFallthroughStatement;
|
|
30
|
+
private parseBreakStatement;
|
|
31
|
+
private parseForContent;
|
|
32
|
+
private skipWhitespace;
|
|
33
|
+
private handleComment;
|
|
34
|
+
private getOriginalAttributeName;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=DomPreProcessor.d.ts.map
|