@fluffjs/cli 0.0.8 → 0.1.1

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 +7 -10
  4. package/Cli.js +139 -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 +193 -257
  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 +17 -0
  22. package/Parse5Helpers.js +95 -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 -13
  30. package/babel-plugin-component.js +7 -0
  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 +9 -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 +8 -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 +10 -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
@@ -0,0 +1,24 @@
1
+ import type * as t from '@babel/types';
2
+ import type * as parse5 from 'parse5';
3
+ export type Parse5Node = parse5.DefaultTreeAdapterMap['node'];
4
+ export type Parse5Element = parse5.DefaultTreeAdapterMap['element'];
5
+ export type Parse5TextNode = parse5.DefaultTreeAdapterMap['textNode'];
6
+ export type Parse5CommentNode = parse5.DefaultTreeAdapterMap['commentNode'];
7
+ export type Parse5DocumentFragment = parse5.DefaultTreeAdapterMap['documentFragment'];
8
+ export type Parse5Document = parse5.DefaultTreeAdapterMap['document'];
9
+ export type Parse5ChildNode = parse5.DefaultTreeAdapterMap['childNode'];
10
+ export type Parse5ParentNode = Parse5DocumentFragment | Parse5Element | Parse5Document;
11
+ export declare class Typeguards {
12
+ static isElement(node: Parse5Node): node is Parse5Element;
13
+ static isTextNode(node: Parse5Node): node is Parse5TextNode;
14
+ static isCommentNode(node: Parse5Node): node is Parse5CommentNode;
15
+ static isDocumentFragment(value: unknown): value is Parse5DocumentFragment;
16
+ static isDocumentFragmentLike(value: unknown): value is Parse5DocumentFragment;
17
+ static isRecord(value: unknown): value is Record<string, unknown>;
18
+ static isBabelNode(value: unknown): value is t.Node;
19
+ static isAttrsRecord(value: unknown): value is Record<string, {
20
+ startOffset: number;
21
+ endOffset: number;
22
+ }>;
23
+ }
24
+ //# sourceMappingURL=Typeguards.d.ts.map
package/Typeguards.js ADDED
@@ -0,0 +1,30 @@
1
+ export class Typeguards {
2
+ static isElement(node) {
3
+ return 'tagName' in node;
4
+ }
5
+ static isTextNode(node) {
6
+ return node.nodeName === '#text' && 'value' in node;
7
+ }
8
+ static isCommentNode(node) {
9
+ return node.nodeName === '#comment';
10
+ }
11
+ static isDocumentFragment(value) {
12
+ if (typeof value !== 'object' || value === null || !('childNodes' in value) || !('nodeName' in value)) {
13
+ return false;
14
+ }
15
+ const nodeNameValue = value.nodeName;
16
+ return nodeNameValue === '#document-fragment';
17
+ }
18
+ static isDocumentFragmentLike(value) {
19
+ return typeof value === 'object' && value !== null && 'childNodes' in value && 'nodeName' in value;
20
+ }
21
+ static isRecord(value) {
22
+ return value !== null && typeof value === 'object';
23
+ }
24
+ static isBabelNode(value) {
25
+ return value !== null && typeof value === 'object' && 'type' in value;
26
+ }
27
+ static isAttrsRecord(value) {
28
+ return value !== null && typeof value === 'object';
29
+ }
30
+ }
@@ -1,20 +1,5 @@
1
1
  import type { PluginObj } from '@babel/core';
2
- export interface ClassTransformOptions {
3
- className: string;
4
- originalSuperClass?: string;
5
- newSuperClass?: string;
6
- injectMethods?: {
7
- name: string;
8
- body: string;
9
- }[];
10
- }
11
- interface PluginState {
12
- opts: ClassTransformOptions;
13
- }
14
- export default function classTransformPlugin(): PluginObj<PluginState>;
15
- export declare function injectMethodBodies(code: string, methods: {
16
- name: string;
17
- body: string;
18
- }[]): string;
19
- export {};
2
+ import type { BabelPluginClassTransformState } from './interfaces/BabelPluginClassTransformState.js';
3
+ export type { ClassTransformOptions } from './interfaces/ClassTransformOptions.js';
4
+ export default function classTransformPlugin(): PluginObj<BabelPluginClassTransformState>;
20
5
  //# sourceMappingURL=babel-plugin-class-transform.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { types as t } from '@babel/core';
2
+ import { parseMethodBody } from './BabelHelpers.js';
2
3
  export default function classTransformPlugin() {
3
4
  return {
4
5
  name: 'babel-plugin-class-transform', visitor: {
@@ -16,9 +17,8 @@ export default function classTransformPlugin() {
16
17
  if (injectMethods && injectMethods.length > 0) {
17
18
  const newMethods = [];
18
19
  for (const method of injectMethods) {
19
- const methodNode = t.classMethod('method', t.identifier(method.name), [], t.blockStatement([
20
- t.expressionStatement(t.identifier(`__INJECT_${method.name}__`))
21
- ]));
20
+ const bodyStatements = parseMethodBody(method.body);
21
+ const methodNode = t.classMethod('method', t.identifier(method.name), [], t.blockStatement(bodyStatements));
22
22
  newMethods.push(methodNode);
23
23
  }
24
24
  for (const method of newMethods.reverse()) {
@@ -30,11 +30,3 @@ export default function classTransformPlugin() {
30
30
  }
31
31
  };
32
32
  }
33
- export function injectMethodBodies(code, methods) {
34
- let result = code;
35
- for (const method of methods) {
36
- const placeholder = `__INJECT_${method.name}__;`;
37
- result = result.replace(placeholder, method.body);
38
- }
39
- return result;
40
- }
@@ -1,16 +1,7 @@
1
1
  import type { PluginObj } from '@babel/core';
2
- export interface ComponentMetadata {
3
- selector: string;
4
- templateUrl?: string;
5
- template?: string;
6
- styleUrl?: string;
7
- styles?: string;
8
- className: string;
9
- }
2
+ import type { BabelPluginComponentState } from './interfaces/BabelPluginComponentState.js';
3
+ import type { ComponentMetadata } from './interfaces/ComponentMetadata.js';
4
+ export type { ComponentMetadata } from './interfaces/ComponentMetadata.js';
10
5
  export declare const componentMetadataMap: Map<string, ComponentMetadata>;
11
- interface PluginState {
12
- filename?: string;
13
- }
14
- export default function componentPlugin(): PluginObj<PluginState>;
15
- export {};
6
+ export default function componentPlugin(): PluginObj<BabelPluginComponentState>;
16
7
  //# sourceMappingURL=babel-plugin-component.d.ts.map
@@ -16,6 +16,13 @@ export default function componentPlugin() {
16
16
  return;
17
17
  if (!t.isCallExpression(componentDecorator.expression))
18
18
  return;
19
+ const { superClass } = path.node;
20
+ if (!superClass || !t.isIdentifier(superClass) || superClass.name !== 'HTMLElement') {
21
+ const className = path.node.id?.name ?? 'Unknown';
22
+ const filename = state.filename ?? 'unknown';
23
+ throw path.buildCodeFrameError(`Component class '${className}' must extend HTMLElement.\n` +
24
+ `Add 'extends HTMLElement' to the class declaration in ${filename}`);
25
+ }
19
26
  const args = componentDecorator.expression.arguments;
20
27
  if (args.length === 0)
21
28
  return;
@@ -1,13 +1,5 @@
1
1
  import type { PluginObj } from '@babel/core';
2
- export interface ImportTransformOptions {
3
- removeImportsFrom?: string[];
4
- removeDecorators?: string[];
5
- pathReplacements?: Record<string, string>;
6
- addJsExtension?: boolean;
7
- }
8
- interface PluginState {
9
- opts: ImportTransformOptions;
10
- }
11
- export default function importsPlugin(): PluginObj<PluginState>;
12
- export {};
2
+ import type { BabelPluginImportsState } from './interfaces/BabelPluginImportsState.js';
3
+ export type { ImportTransformOptions } from './interfaces/ImportTransformOptions.js';
4
+ export default function importsPlugin(): PluginObj<BabelPluginImportsState>;
13
5
  //# sourceMappingURL=babel-plugin-imports.d.ts.map
@@ -1,15 +1,7 @@
1
1
  import { types as t } from '@babel/core';
2
- function getDecoratorName(decorator) {
3
- const expr = decorator.expression;
4
- if (t.isCallExpression(expr) && t.isIdentifier(expr.callee)) {
5
- return expr.callee.name;
6
- }
7
- if (t.isIdentifier(expr)) {
8
- return expr.name;
9
- }
10
- return null;
11
- }
2
+ import { filterDecoratorsFromNode } from './BabelHelpers.js';
12
3
  export default function importsPlugin() {
4
+ // noinspection JSUnusedGlobalSymbols
13
5
  return {
14
6
  name: 'babel-plugin-imports', visitor: {
15
7
  ImportDeclaration(path, state) {
@@ -39,37 +31,19 @@ export default function importsPlugin() {
39
31
  const { removeDecorators } = state.opts ?? {};
40
32
  if (!removeDecorators?.length)
41
33
  return;
42
- const { decorators } = path.node;
43
- if (!decorators)
44
- return;
45
- path.node.decorators = decorators.filter(dec => {
46
- const name = getDecoratorName(dec);
47
- return !name || !removeDecorators.includes(name);
48
- });
34
+ filterDecoratorsFromNode(path.node, removeDecorators);
49
35
  },
50
36
  ClassProperty(path, state) {
51
37
  const { removeDecorators } = state.opts ?? {};
52
38
  if (!removeDecorators?.length)
53
39
  return;
54
- const { decorators } = path.node;
55
- if (!decorators)
56
- return;
57
- path.node.decorators = decorators.filter(dec => {
58
- const name = getDecoratorName(dec);
59
- return !name || !removeDecorators.includes(name);
60
- });
40
+ filterDecoratorsFromNode(path.node, removeDecorators);
61
41
  },
62
42
  ClassMethod(path, state) {
63
43
  const { removeDecorators } = state.opts ?? {};
64
44
  if (!removeDecorators?.length)
65
45
  return;
66
- const { decorators } = path.node;
67
- if (!decorators)
68
- return;
69
- path.node.decorators = decorators.filter(dec => {
70
- const name = getDecoratorName(dec);
71
- return !name || !removeDecorators.includes(name);
72
- });
46
+ filterDecoratorsFromNode(path.node, removeDecorators);
73
47
  }
74
48
  }
75
49
  };
@@ -1,22 +1,5 @@
1
1
  import type { PluginObj } from '@babel/core';
2
- import { types as t } from '@babel/core';
3
- interface WatchInfo {
4
- methodName: string;
5
- watchedProps: string[];
6
- }
7
- interface WatchCallInfo {
8
- propName: string;
9
- watchedProps: string[];
10
- callbackArg: t.Expression | t.SpreadElement | t.JSXNamespacedName | t.ArgumentPlaceholder;
11
- }
12
- interface PluginState {
13
- filename?: string;
14
- needsPropertyImport?: boolean;
15
- reactiveProperties?: Set<string>;
16
- watchMethods?: WatchInfo[];
17
- watchCalls?: WatchCallInfo[];
18
- }
2
+ import type { BabelPluginReactiveState } from './interfaces/BabelPluginReactiveState.js';
19
3
  export declare const reactivePropertiesMap: Map<string, Set<string>>;
20
- export default function reactivePlugin(): PluginObj<PluginState>;
21
- export {};
4
+ export default function reactivePlugin(): PluginObj<BabelPluginReactiveState>;
22
5
  //# sourceMappingURL=babel-plugin-reactive.d.ts.map
@@ -1,6 +1,8 @@
1
1
  import { types as t } from '@babel/core';
2
+ import { buildHostBindingUpdateStatement, findDecoratorIndex, getDecoratorName } from './BabelHelpers.js';
2
3
  export const reactivePropertiesMap = new Map();
3
4
  export default function reactivePlugin() {
5
+ // noinspection JSUnusedGlobalSymbols
4
6
  return {
5
7
  name: 'babel-plugin-reactive', visitor: {
6
8
  Program: {
@@ -73,12 +75,7 @@ export default function reactivePlugin() {
73
75
  if (memberPath.isClassMethod()) {
74
76
  const methodNode = memberPath.node;
75
77
  const decorators = methodNode.decorators ?? [];
76
- const hostListenerIndex = decorators.findIndex(dec => {
77
- if (t.isCallExpression(dec.expression) && t.isIdentifier(dec.expression.callee)) {
78
- return dec.expression.callee.name === 'HostListener';
79
- }
80
- return false;
81
- });
78
+ const hostListenerIndex = findDecoratorIndex(decorators, 'HostListener');
82
79
  if (hostListenerIndex >= 0) {
83
80
  const hostListenerDecorator = decorators[hostListenerIndex];
84
81
  if (t.isCallExpression(hostListenerDecorator.expression)) {
@@ -94,12 +91,7 @@ export default function reactivePlugin() {
94
91
  }
95
92
  decorators.splice(hostListenerIndex, 1);
96
93
  }
97
- const pipeDecoratorIndex = decorators.findIndex(dec => {
98
- if (t.isCallExpression(dec.expression) && t.isIdentifier(dec.expression.callee)) {
99
- return dec.expression.callee.name === 'Pipe';
100
- }
101
- return false;
102
- });
94
+ const pipeDecoratorIndex = findDecoratorIndex(decorators, 'Pipe');
103
95
  if (pipeDecoratorIndex >= 0) {
104
96
  const pipeDecorator = decorators[pipeDecoratorIndex];
105
97
  if (t.isCallExpression(pipeDecorator.expression)) {
@@ -115,12 +107,7 @@ export default function reactivePlugin() {
115
107
  }
116
108
  decorators.splice(pipeDecoratorIndex, 1);
117
109
  }
118
- const watchDecoratorIndex = decorators.findIndex(dec => {
119
- if (t.isCallExpression(dec.expression) && t.isIdentifier(dec.expression.callee)) {
120
- return dec.expression.callee.name === 'Watch';
121
- }
122
- return false;
123
- });
110
+ const watchDecoratorIndex = findDecoratorIndex(decorators, 'Watch');
124
111
  if (watchDecoratorIndex >= 0) {
125
112
  const watchDecorator = decorators[watchDecoratorIndex];
126
113
  if (t.isCallExpression(watchDecorator.expression)) {
@@ -137,12 +124,7 @@ export default function reactivePlugin() {
137
124
  decorators.splice(watchDecoratorIndex, 1);
138
125
  }
139
126
  if (methodNode.kind === 'get') {
140
- const hostBindingIndex = decorators.findIndex(dec => {
141
- if (t.isCallExpression(dec.expression) && t.isIdentifier(dec.expression.callee)) {
142
- return dec.expression.callee.name === 'HostBinding';
143
- }
144
- return false;
145
- });
127
+ const hostBindingIndex = findDecoratorIndex(decorators, 'HostBinding');
146
128
  if (hostBindingIndex >= 0) {
147
129
  const hostBindingDecorator = decorators[hostBindingIndex];
148
130
  if (t.isCallExpression(hostBindingDecorator.expression)) {
@@ -150,25 +132,7 @@ export default function reactivePlugin() {
150
132
  if (args.length > 0 && t.isStringLiteral(args[0]) && t.isIdentifier(methodNode.key)) {
151
133
  const hostProperty = args[0].value;
152
134
  const getterName = methodNode.key.name;
153
- let updateStatement = t.emptyStatement();
154
- if (hostProperty.startsWith('class.')) {
155
- const className = hostProperty.slice(6);
156
- updateStatement = t.ifStatement(t.identifier('__v'), t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('classList')), t.identifier('add')), [t.stringLiteral(className)])), t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('classList')), t.identifier('remove')), [t.stringLiteral(className)])));
157
- }
158
- else if (hostProperty.startsWith('attr.')) {
159
- const attrName = hostProperty.slice(5);
160
- updateStatement = t.ifStatement(t.binaryExpression('!=', t.identifier('__v'), t.nullLiteral()), t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('setAttribute')), [
161
- t.stringLiteral(attrName),
162
- t.callExpression(t.identifier('String'), [t.identifier('__v')])
163
- ])), t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('removeAttribute')), [t.stringLiteral(attrName)])));
164
- }
165
- else if (hostProperty.startsWith('style.')) {
166
- const styleProp = hostProperty.slice(6);
167
- updateStatement = t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('style')), t.identifier(styleProp)), t.logicalExpression('||', t.identifier('__v'), t.stringLiteral(''))));
168
- }
169
- else {
170
- updateStatement = t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier(hostProperty)), t.identifier('__v')));
171
- }
135
+ const updateStatement = buildHostBindingUpdateStatement(hostProperty);
172
136
  const updateMethod = t.classMethod('method', t.identifier(`__updateHostBinding_${getterName}`), [], t.blockStatement([
173
137
  t.variableDeclaration('const', [t.variableDeclarator(t.identifier('__v'), t.memberExpression(t.thisExpression(), t.identifier(getterName)))]),
174
138
  updateStatement
@@ -186,12 +150,7 @@ export default function reactivePlugin() {
186
150
  continue;
187
151
  const propNode = memberPath.node;
188
152
  const decorators = propNode.decorators ?? [];
189
- const hostBindingDecoratorIndex = decorators.findIndex(dec => {
190
- if (t.isCallExpression(dec.expression) && t.isIdentifier(dec.expression.callee)) {
191
- return dec.expression.callee.name === 'HostBinding';
192
- }
193
- return false;
194
- });
153
+ const hostBindingDecoratorIndex = findDecoratorIndex(decorators, 'HostBinding');
195
154
  if (hostBindingDecoratorIndex >= 0) {
196
155
  const hostBindingDecorator = decorators[hostBindingDecoratorIndex];
197
156
  if (t.isCallExpression(hostBindingDecorator.expression)) {
@@ -205,25 +164,7 @@ export default function reactivePlugin() {
205
164
  const getter = t.classMethod('get', t.identifier(propName), [], t.blockStatement([
206
165
  t.returnStatement(t.memberExpression(t.thisExpression(), t.identifier(privateName)))
207
166
  ]));
208
- let updateStatement = t.emptyStatement();
209
- if (hostProperty.startsWith('class.')) {
210
- const className = hostProperty.slice(6);
211
- updateStatement = t.ifStatement(t.identifier('__v'), t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('classList')), t.identifier('add')), [t.stringLiteral(className)])), t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('classList')), t.identifier('remove')), [t.stringLiteral(className)])));
212
- }
213
- else if (hostProperty.startsWith('attr.')) {
214
- const attrName = hostProperty.slice(5);
215
- updateStatement = t.ifStatement(t.binaryExpression('!=', t.identifier('__v'), t.nullLiteral()), t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('setAttribute')), [
216
- t.stringLiteral(attrName),
217
- t.callExpression(t.identifier('String'), [t.identifier('__v')])
218
- ])), t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('removeAttribute')), [t.stringLiteral(attrName)])));
219
- }
220
- else if (hostProperty.startsWith('style.')) {
221
- const styleProp = hostProperty.slice(6);
222
- updateStatement = t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier('style')), t.identifier(styleProp)), t.logicalExpression('||', t.identifier('__v'), t.stringLiteral(''))));
223
- }
224
- else {
225
- updateStatement = t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier(hostProperty)), t.identifier('__v')));
226
- }
167
+ const updateStatement = buildHostBindingUpdateStatement(hostProperty);
227
168
  const setter = t.classMethod('set', t.identifier(propName), [t.identifier('__v')], t.blockStatement([
228
169
  t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier(privateName)), t.identifier('__v'))),
229
170
  updateStatement
@@ -236,12 +177,7 @@ export default function reactivePlugin() {
236
177
  }
237
178
  continue;
238
179
  }
239
- const viewChildDecoratorIndex = decorators.findIndex(dec => {
240
- if (t.isCallExpression(dec.expression) && t.isIdentifier(dec.expression.callee)) {
241
- return dec.expression.callee.name === 'ViewChild';
242
- }
243
- return false;
244
- });
180
+ const viewChildDecoratorIndex = findDecoratorIndex(decorators, 'ViewChild');
245
181
  if (viewChildDecoratorIndex >= 0) {
246
182
  const viewChildDecorator = decorators[viewChildDecoratorIndex];
247
183
  if (t.isCallExpression(viewChildDecorator.expression)) {
@@ -260,7 +196,7 @@ export default function reactivePlugin() {
260
196
  }
261
197
  const reactiveDecoratorIndices = [];
262
198
  for (const [idx, dec] of decorators.entries()) {
263
- const name = t.isCallExpression(dec.expression) && t.isIdentifier(dec.expression.callee) ? dec.expression.callee.name : t.isIdentifier(dec.expression) ? dec.expression.name : null;
199
+ const name = getDecoratorName(dec);
264
200
  if (name === 'Reactive' || name === 'Input') {
265
201
  reactiveDecoratorIndices.push(idx);
266
202
  }
@@ -277,7 +213,16 @@ export default function reactivePlugin() {
277
213
  const initialValue = propNode.value ?? t.identifier('undefined');
278
214
  state.needsPropertyImport = true;
279
215
  state.reactiveProperties?.add(propName);
280
- const privateField = t.classProperty(t.identifier(privateName), t.newExpression(t.identifier('Property'), [initialValue]));
216
+ const isProduction = state.opts?.production ?? false;
217
+ const propertyArgs = isProduction
218
+ ? [initialValue]
219
+ : [
220
+ t.objectExpression([
221
+ t.objectProperty(t.identifier('initialValue'), initialValue),
222
+ t.objectProperty(t.identifier('propertyName'), t.stringLiteral(propName))
223
+ ])
224
+ ];
225
+ const privateField = t.classProperty(t.identifier(privateName), t.newExpression(t.identifier('Property'), propertyArgs));
281
226
  const getter = t.classMethod('get', t.identifier(propName), [], t.blockStatement([
282
227
  t.returnStatement(t.callExpression(t.memberExpression(t.memberExpression(t.thisExpression(), t.identifier(privateName)), t.identifier('getValue')), []))
283
228
  ]));
package/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { Cli, parseArgs } from './Cli.js';
3
- const { options, args } = parseArgs(process.argv.slice(2));
2
+ import { Cli } from './Cli.js';
3
+ const { options, args } = Cli.parseArgs(process.argv.slice(2));
4
4
  const cli = new Cli(options);
5
5
  cli.run(args)
6
6
  .catch((error) => {
@@ -1,8 +1,5 @@
1
1
  import type { Plugin } from 'esbuild';
2
- export interface FluffPluginOptions {
3
- srcDir: string;
4
- minify?: boolean;
5
- sourcemap?: boolean;
6
- }
2
+ import type { FluffPluginOptions } from './interfaces/FluffPluginOptions.js';
3
+ export type { FluffPluginOptions } from './interfaces/FluffPluginOptions.js';
7
4
  export declare function fluffPlugin(options: FluffPluginOptions): Plugin;
8
5
  //# sourceMappingURL=fluff-esbuild-plugin.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { CodeGenerator } from './CodeGenerator.js';
4
5
  import { ComponentCompiler } from './ComponentCompiler.js';
5
6
  function findFluffSourcePath() {
6
7
  const thisFile = fileURLToPath(import.meta.url);
@@ -17,17 +18,19 @@ export function fluffPlugin(options) {
17
18
  const compiler = new ComponentCompiler();
18
19
  let componentsDiscovered = false;
19
20
  const fluffSrcPath = findFluffSourcePath();
21
+ // noinspection JSUnusedGlobalSymbols
20
22
  return {
21
23
  name: 'fluff',
22
24
  setup(build) {
23
25
  build.onStart(async () => {
26
+ CodeGenerator.resetGlobalState();
24
27
  if (!componentsDiscovered) {
25
28
  await compiler.discoverComponents(options.srcDir);
26
29
  componentsDiscovered = true;
27
30
  }
28
31
  });
29
32
  build.onLoad({ filter: /\.component\.ts$/ }, async (args) => {
30
- const result = await compiler.compileComponentForBundle(args.path, options.minify, options.sourcemap);
33
+ const result = await compiler.compileComponentForBundle(args.path, options.minify, options.sourcemap, options.skipDefine, options.production);
31
34
  return {
32
35
  contents: result.code,
33
36
  loader: 'js',
package/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  export { ComponentCompiler } from './ComponentCompiler.js';
2
2
  export { TemplateParser } from './TemplateParser.js';
3
3
  export { CodeGenerator } from './CodeGenerator.js';
4
- export { Cli, parseArgs } from './Cli.js';
5
- export type * from './types.js';
4
+ export { Cli } from './Cli.js';
5
+ export type { ComponentInfo } from './interfaces/ComponentInfo.js';
6
+ export type { CompilerOptions } from './interfaces/CompilerOptions.js';
7
+ export type { ControlFlow, SwitchCaseOld } from './interfaces/ControlFlow.js';
8
+ export type { ParsedTemplateOld } from './interfaces/ParsedTemplateOld.js';
9
+ export type { TemplateBinding } from './interfaces/TemplateBinding.js';
6
10
  export type * from './types/FluffConfig.js';
7
11
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { ComponentCompiler } from './ComponentCompiler.js';
2
2
  export { TemplateParser } from './TemplateParser.js';
3
3
  export { CodeGenerator } from './CodeGenerator.js';
4
- export { Cli, parseArgs } from './Cli.js';
4
+ export { Cli } from './Cli.js';
@@ -0,0 +1,5 @@
1
+ import type { ClassTransformOptions } from './ClassTransformOptions.js';
2
+ export interface BabelPluginClassTransformState {
3
+ opts: ClassTransformOptions;
4
+ }
5
+ //# sourceMappingURL=BabelPluginClassTransformState.d.ts.map
@@ -0,0 +1,4 @@
1
+ export interface BabelPluginComponentState {
2
+ filename?: string;
3
+ }
4
+ //# sourceMappingURL=BabelPluginComponentState.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { ImportTransformOptions } from './ImportTransformOptions.js';
2
+ export interface BabelPluginImportsState {
3
+ opts: ImportTransformOptions;
4
+ }
5
+ //# sourceMappingURL=BabelPluginImportsState.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { BabelPluginReactiveWatchCallInfo } from './BabelPluginReactiveWatchCallInfo.js';
2
+ import type { BabelPluginReactiveWatchInfo } from './BabelPluginReactiveWatchInfo.js';
3
+ export interface BabelPluginReactiveState {
4
+ filename?: string;
5
+ needsPropertyImport?: boolean;
6
+ reactiveProperties?: Set<string>;
7
+ watchMethods?: BabelPluginReactiveWatchInfo[];
8
+ watchCalls?: BabelPluginReactiveWatchCallInfo[];
9
+ opts?: {
10
+ production?: boolean;
11
+ };
12
+ }
13
+ //# sourceMappingURL=BabelPluginReactiveState.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { types as t } from '@babel/core';
2
+ export interface BabelPluginReactiveWatchCallInfo {
3
+ propName: string;
4
+ watchedProps: string[];
5
+ callbackArg: t.Expression | t.SpreadElement | t.JSXNamespacedName | t.ArgumentPlaceholder;
6
+ }
7
+ //# sourceMappingURL=BabelPluginReactiveWatchCallInfo.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ export interface BabelPluginReactiveWatchInfo {
2
+ methodName: string;
3
+ watchedProps: string[];
4
+ }
5
+ //# sourceMappingURL=BabelPluginReactiveWatchInfo.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ export interface BabelToken {
2
+ type: {
3
+ label: string;
4
+ };
5
+ start: number;
6
+ end: number;
7
+ }
8
+ //# sourceMappingURL=BabelToken.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { PropertyChain } from './PropertyChain.js';
2
+ export interface BindingInfo {
3
+ name: string;
4
+ binding: 'property' | 'event' | 'two-way' | 'class' | 'style' | 'ref';
5
+ expression?: string;
6
+ exprId?: number;
7
+ handlerId?: number;
8
+ targetProp?: string;
9
+ deps?: PropertyChain[];
10
+ subscribe?: string;
11
+ }
12
+ //# sourceMappingURL=BindingInfo.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ export interface BreakMarkerConfig {
2
+ type: 'break';
3
+ }
4
+ //# sourceMappingURL=BreakMarkerConfig.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ export interface BreakNode {
2
+ type: 'break';
3
+ }
4
+ //# sourceMappingURL=BreakNode.d.ts.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ export interface BundleOptions {
2
+ minify?: boolean;
3
+ splitting?: boolean;
4
+ target?: string;
5
+ gzip?: boolean;
6
+ gzScriptTag?: boolean;
7
+ external?: string[];
8
+ }
9
+ //# sourceMappingURL=BundleOptions.d.ts.map
@@ -0,0 +1 @@
1
+ export {};