@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.
Files changed (142) hide show
  1. package/BabelHelpers.d.ts +26 -0
  2. package/BabelHelpers.js +65 -0
  3. package/Cli.d.ts +5 -10
  4. package/Cli.js +123 -52
  5. package/CodeGenerator.d.ts +53 -39
  6. package/CodeGenerator.js +330 -725
  7. package/ComponentCompiler.d.ts +14 -16
  8. package/ComponentCompiler.js +207 -249
  9. package/DomPreProcessor.d.ts +36 -0
  10. package/DomPreProcessor.js +645 -0
  11. package/ErrorHelpers.d.ts +5 -0
  12. package/ErrorHelpers.js +8 -0
  13. package/ExpressionTransformer.d.ts +38 -28
  14. package/ExpressionTransformer.js +558 -230
  15. package/Generator.d.ts +1 -5
  16. package/Generator.js +128 -67
  17. package/GetterDependencyExtractor.d.ts +4 -0
  18. package/GetterDependencyExtractor.js +73 -0
  19. package/IndexHtmlTransformer.d.ts +6 -7
  20. package/IndexHtmlTransformer.js +82 -88
  21. package/Parse5Helpers.d.ts +16 -0
  22. package/Parse5Helpers.js +81 -0
  23. package/TemplateParser.d.ts +39 -21
  24. package/TemplateParser.js +462 -268
  25. package/Typeguards.d.ts +24 -0
  26. package/Typeguards.js +30 -0
  27. package/babel-plugin-class-transform.d.ts +3 -18
  28. package/babel-plugin-class-transform.js +3 -11
  29. package/babel-plugin-component.d.ts +4 -11
  30. package/babel-plugin-component.js +23 -2
  31. package/babel-plugin-imports.d.ts +3 -11
  32. package/babel-plugin-imports.js +5 -31
  33. package/babel-plugin-reactive.d.ts +2 -19
  34. package/babel-plugin-reactive.js +21 -76
  35. package/bin.js +2 -2
  36. package/fluff-esbuild-plugin.d.ts +2 -5
  37. package/fluff-esbuild-plugin.js +4 -1
  38. package/index.d.ts +6 -2
  39. package/index.js +1 -1
  40. package/interfaces/BabelPluginClassTransformState.d.ts +5 -0
  41. package/interfaces/BabelPluginComponentState.d.ts +4 -0
  42. package/interfaces/BabelPluginComponentState.js +1 -0
  43. package/interfaces/BabelPluginImportsState.d.ts +5 -0
  44. package/interfaces/BabelPluginImportsState.js +1 -0
  45. package/interfaces/BabelPluginReactiveState.d.ts +13 -0
  46. package/interfaces/BabelPluginReactiveState.js +1 -0
  47. package/interfaces/BabelPluginReactiveWatchCallInfo.d.ts +7 -0
  48. package/interfaces/BabelPluginReactiveWatchCallInfo.js +1 -0
  49. package/interfaces/BabelPluginReactiveWatchInfo.d.ts +5 -0
  50. package/interfaces/BabelPluginReactiveWatchInfo.js +1 -0
  51. package/interfaces/BabelToken.d.ts +8 -0
  52. package/interfaces/BabelToken.js +1 -0
  53. package/interfaces/BindingInfo.d.ts +12 -0
  54. package/interfaces/BindingInfo.js +1 -0
  55. package/interfaces/BreakMarkerConfig.d.ts +4 -0
  56. package/interfaces/BreakMarkerConfig.js +1 -0
  57. package/interfaces/BreakNode.d.ts +4 -0
  58. package/interfaces/BreakNode.js +1 -0
  59. package/interfaces/BundleOptions.d.ts +8 -0
  60. package/interfaces/BundleOptions.js +1 -0
  61. package/interfaces/ClassTransformOptions.d.ts +10 -0
  62. package/interfaces/ClassTransformOptions.js +1 -0
  63. package/interfaces/CliOptions.d.ts +6 -0
  64. package/interfaces/CliOptions.js +1 -0
  65. package/interfaces/CommentNode.d.ts +5 -0
  66. package/interfaces/CommentNode.js +1 -0
  67. package/interfaces/CompileResult.d.ts +6 -0
  68. package/interfaces/CompileResult.js +1 -0
  69. package/interfaces/CompilerOptions.d.ts +6 -0
  70. package/interfaces/CompilerOptions.js +1 -0
  71. package/interfaces/ComponentInfo.d.ts +8 -0
  72. package/interfaces/ComponentInfo.js +1 -0
  73. package/interfaces/ComponentMetadata.d.ts +9 -0
  74. package/interfaces/ComponentMetadata.js +1 -0
  75. package/interfaces/ControlFlow.d.ts +19 -0
  76. package/interfaces/ControlFlow.js +1 -0
  77. package/interfaces/ControlFlowNode.d.ts +6 -0
  78. package/interfaces/ControlFlowNode.js +1 -0
  79. package/interfaces/ControlFlowParseResult.d.ts +10 -0
  80. package/interfaces/ControlFlowParseResult.js +1 -0
  81. package/interfaces/ElementNode.d.ts +11 -0
  82. package/interfaces/ElementNode.js +1 -0
  83. package/interfaces/FluffConfigInterface.d.ts +7 -0
  84. package/interfaces/FluffConfigInterface.js +1 -0
  85. package/interfaces/FluffPluginOptions.d.ts +9 -0
  86. package/interfaces/FluffPluginOptions.js +1 -0
  87. package/interfaces/FluffTarget.d.ts +15 -0
  88. package/interfaces/FluffTarget.js +1 -0
  89. package/interfaces/ForMarkerConfig.d.ts +9 -0
  90. package/interfaces/ForMarkerConfig.js +1 -0
  91. package/interfaces/ForNode.d.ts +13 -0
  92. package/interfaces/ForNode.js +1 -0
  93. package/interfaces/GeneratorOptions.d.ts +5 -0
  94. package/interfaces/GeneratorOptions.js +1 -0
  95. package/interfaces/HtmlTransformOptions.d.ts +9 -0
  96. package/interfaces/HtmlTransformOptions.js +1 -0
  97. package/interfaces/IfBranch.d.ts +8 -0
  98. package/interfaces/IfBranch.js +1 -0
  99. package/interfaces/IfMarkerConfig.d.ts +8 -0
  100. package/interfaces/IfMarkerConfig.js +1 -0
  101. package/interfaces/IfNode.d.ts +7 -0
  102. package/interfaces/IfNode.js +1 -0
  103. package/interfaces/ImportTransformOptions.d.ts +7 -0
  104. package/interfaces/ImportTransformOptions.js +1 -0
  105. package/interfaces/InterpolationNode.d.ts +12 -0
  106. package/interfaces/InterpolationNode.js +1 -0
  107. package/interfaces/ParsedTemplate.d.ts +6 -0
  108. package/interfaces/ParsedTemplate.js +1 -0
  109. package/interfaces/ParsedTemplateOld.d.ts +9 -0
  110. package/interfaces/ParsedTemplateOld.js +1 -0
  111. package/interfaces/PropertyChain.d.ts +2 -0
  112. package/interfaces/PropertyChain.js +1 -0
  113. package/interfaces/Scope.d.ts +5 -0
  114. package/interfaces/Scope.js +1 -0
  115. package/interfaces/ServeOptions.d.ts +5 -0
  116. package/interfaces/ServeOptions.js +1 -0
  117. package/interfaces/SwitchCase.d.ts +8 -0
  118. package/interfaces/SwitchCase.js +1 -0
  119. package/interfaces/SwitchMarkerConfig.d.ts +11 -0
  120. package/interfaces/SwitchMarkerConfig.js +1 -0
  121. package/interfaces/SwitchNode.d.ts +10 -0
  122. package/interfaces/SwitchNode.js +1 -0
  123. package/interfaces/TemplateBinding.d.ts +10 -0
  124. package/interfaces/TemplateBinding.js +1 -0
  125. package/interfaces/TemplateNode.d.ts +7 -0
  126. package/interfaces/TemplateNode.js +1 -0
  127. package/interfaces/TextMarkerConfig.d.ts +10 -0
  128. package/interfaces/TextMarkerConfig.js +1 -0
  129. package/interfaces/TextNode.d.ts +5 -0
  130. package/interfaces/TextNode.js +1 -0
  131. package/interfaces/TokenizeResult.d.ts +6 -0
  132. package/interfaces/TokenizeResult.js +1 -0
  133. package/interfaces/TransformOptions.d.ts +11 -0
  134. package/interfaces/TransformOptions.js +1 -0
  135. package/interfaces/index.d.ts +34 -0
  136. package/interfaces/index.js +1 -0
  137. package/package.json +9 -1
  138. package/types/FluffConfig.d.ts +5 -27
  139. package/ControlFlowParser.d.ts +0 -55
  140. package/ControlFlowParser.js +0 -279
  141. package/types.d.ts +0 -46
  142. /package/{types.js → interfaces/BabelPluginClassTransformState.js} +0 -0
@@ -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
- export interface CompileResult {
4
- code: string;
5
- map?: string;
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 readonly parser;
11
- private readonly generator;
12
- constructor();
13
- registerComponent(selector: string): void;
14
- discoverComponents(demoDir: string): Promise<void>;
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
- copyLighterLib(srcDir: string, distDir: string): Promise<void>;
20
+ private createComponentSourceMap;
21
+ private addFluffImport;
22
+ private appendCode;
23
+ private addBindingsMap;
24
+ private addCustomElementsDefine;
27
25
  }
28
26
  //# sourceMappingURL=ComponentCompiler.d.ts.map
@@ -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, { injectMethodBodies } from './babel-plugin-class-transform.js';
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
- parser;
16
- generator;
17
- constructor() {
18
- this.parser = new TemplateParser();
19
- this.generator = new CodeGenerator();
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
- registerComponent(selector) {
22
- this.componentSelectors.add(selector);
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(demoDir) {
25
- const files = fs.readdirSync(demoDir)
26
- .filter(f => f.endsWith('.component.ts'));
27
- for (const file of files) {
28
- const filePath = path.join(demoDir, file);
29
- const content = fs.readFileSync(filePath, 'utf-8');
30
- const metadata = await this.extractComponentMetadata(content, filePath);
31
- if (metadata?.selector) {
32
- this.componentSelectors.add(metadata.selector);
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 compileComponent(filePath) {
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
- const templatePath = path.resolve(componentDir, templateUrl);
55
- const templateHtml = fs.readFileSync(templatePath, 'utf-8');
56
- let styles = '';
57
- if (styleUrl) {
58
- const stylePath = path.resolve(componentDir, styleUrl);
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
- const { html, bindings, controlFlows, templateRefs } = this.parser.parse(templateHtml);
64
- this.generator.setTemplateRefs(templateRefs);
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
- templateHtml = await minifyHtml(templateHtml, {
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 { html, bindings, controlFlows, templateRefs } = this.parser.parse(templateHtml);
120
- generator.setTemplateRefs(templateRefs);
121
- const renderMethod = generator.generateRenderMethod(html, styles);
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 = 'import { FluffElement } from \'@fluffjs/fluff\';\n' + result;
130
- result += `\ncustomElements.define('${selector}', ${className});\n`;
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 = [templatePath];
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
- const message = e instanceof Error ? e.message : String(e);
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
- try {
185
- const importOptions = {
186
- removeImportsFrom: ['lighter'],
187
- removeDecorators: ['Component', 'Input', 'Output'],
188
- pathReplacements: {},
189
- addJsExtension: false
190
- };
191
- const result = await babel.transformAsync(code, {
192
- filename: filePath, presets: [
193
- ['@babel/preset-typescript', { isTSX: false, allExtensions: true }]
194
- ], plugins: [
195
- ['@babel/plugin-syntax-decorators', { version: '2023-11' }], [importsPlugin, importOptions]
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
- try {
210
- const result = await babel.transformAsync(code, {
211
- filename: filePath, presets: [
212
- ['@babel/preset-typescript', { isTSX: false, allExtensions: true }]
213
- ], plugins: [
214
- ['@babel/plugin-syntax-decorators', { version: '2023-11' }], reactivePlugin
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
- const message = e instanceof Error ? e.message : String(e);
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 babel.transformAsync(code, {
244
- filename: filePath, presets: [
245
- ['@babel/preset-typescript', { isTSX: false, allExtensions: true }]
246
- ], plugins: [
247
- ['@babel/plugin-syntax-decorators', { version: '2023-11' }], componentPlugin
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
- const message = e instanceof Error ? e.message : String(e);
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
- try {
286
- const result = await babel.transformAsync(code, {
287
- filename: filePath, plugins: [
288
- [classTransformPlugin, options]
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
- try {
305
- const importOptions = {
306
- pathReplacements: {
307
- '@/fluff-lib/': '../'
308
- }, addJsExtension: true
309
- };
310
- const result = await babel.transformAsync(code, {
311
- filename: filePath, presets: [
312
- ['@babel/preset-typescript', { isTSX: false, allExtensions: true }]
313
- ], plugins: [
314
- [importsPlugin, importOptions]
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 copyLighterLib(srcDir, distDir) {
328
- const lighterLibSrc = path.join(srcDir, 'fluff-lib');
329
- const lighterLibDist = path.join(distDir, 'fluff-lib');
330
- if (!fs.existsSync(lighterLibDist)) {
331
- fs.mkdirSync(lighterLibDist, { recursive: true });
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
- const dirs = ['utils', 'runtime', 'interfaces', 'enums', 'decorators'];
334
- for (const dir of dirs) {
335
- const srcPath = path.join(lighterLibSrc, dir);
336
- const distPath = path.join(lighterLibDist, dir);
337
- if (fs.existsSync(srcPath)) {
338
- if (!fs.existsSync(distPath)) {
339
- fs.mkdirSync(distPath, { recursive: true });
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