@gannochenko/staticstripes 0.0.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 (86) hide show
  1. package/.prettierrc +8 -0
  2. package/Makefile +69 -0
  3. package/dist/asset-manager.d.ts +16 -0
  4. package/dist/asset-manager.d.ts.map +1 -0
  5. package/dist/asset-manager.js +50 -0
  6. package/dist/asset-manager.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +257 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/container-renderer.d.ts +21 -0
  12. package/dist/container-renderer.d.ts.map +1 -0
  13. package/dist/container-renderer.js +149 -0
  14. package/dist/container-renderer.js.map +1 -0
  15. package/dist/expression-parser.d.ts +63 -0
  16. package/dist/expression-parser.d.ts.map +1 -0
  17. package/dist/expression-parser.js +145 -0
  18. package/dist/expression-parser.js.map +1 -0
  19. package/dist/ffmpeg.d.ts +375 -0
  20. package/dist/ffmpeg.d.ts.map +1 -0
  21. package/dist/ffmpeg.js +997 -0
  22. package/dist/ffmpeg.js.map +1 -0
  23. package/dist/ffprobe.d.ts +2 -0
  24. package/dist/ffprobe.d.ts.map +1 -0
  25. package/dist/ffprobe.js +31 -0
  26. package/dist/ffprobe.js.map +1 -0
  27. package/dist/html-parser.d.ts +56 -0
  28. package/dist/html-parser.d.ts.map +1 -0
  29. package/dist/html-parser.js +208 -0
  30. package/dist/html-parser.js.map +1 -0
  31. package/dist/html-project-parser.d.ts +169 -0
  32. package/dist/html-project-parser.d.ts.map +1 -0
  33. package/dist/html-project-parser.js +954 -0
  34. package/dist/html-project-parser.js.map +1 -0
  35. package/dist/index.d.ts +6 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +18 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/label-generator.d.ts +35 -0
  40. package/dist/label-generator.d.ts.map +1 -0
  41. package/dist/label-generator.js +69 -0
  42. package/dist/label-generator.js.map +1 -0
  43. package/dist/project.d.ts +29 -0
  44. package/dist/project.d.ts.map +1 -0
  45. package/dist/project.js +137 -0
  46. package/dist/project.js.map +1 -0
  47. package/dist/sample-sequences.d.ts +5 -0
  48. package/dist/sample-sequences.d.ts.map +1 -0
  49. package/dist/sample-sequences.js +199 -0
  50. package/dist/sample-sequences.js.map +1 -0
  51. package/dist/sample-streams.d.ts +2 -0
  52. package/dist/sample-streams.d.ts.map +1 -0
  53. package/dist/sample-streams.js +109 -0
  54. package/dist/sample-streams.js.map +1 -0
  55. package/dist/sequence.d.ts +21 -0
  56. package/dist/sequence.d.ts.map +1 -0
  57. package/dist/sequence.js +269 -0
  58. package/dist/sequence.js.map +1 -0
  59. package/dist/stream.d.ts +135 -0
  60. package/dist/stream.d.ts.map +1 -0
  61. package/dist/stream.js +779 -0
  62. package/dist/stream.js.map +1 -0
  63. package/dist/type.d.ts +73 -0
  64. package/dist/type.d.ts.map +1 -0
  65. package/dist/type.js +3 -0
  66. package/dist/type.js.map +1 -0
  67. package/eslint.config.js +44 -0
  68. package/package.json +50 -0
  69. package/src/asset-manager.ts +55 -0
  70. package/src/cli.ts +306 -0
  71. package/src/container-renderer.ts +190 -0
  72. package/src/expression-parser.test.ts +459 -0
  73. package/src/expression-parser.ts +199 -0
  74. package/src/ffmpeg.ts +1403 -0
  75. package/src/ffprobe.ts +29 -0
  76. package/src/html-parser.ts +221 -0
  77. package/src/html-project-parser.ts +1195 -0
  78. package/src/index.ts +9 -0
  79. package/src/label-generator.ts +74 -0
  80. package/src/project.ts +180 -0
  81. package/src/sample-sequences.ts +225 -0
  82. package/src/sample-streams.ts +142 -0
  83. package/src/sequence.ts +330 -0
  84. package/src/stream.ts +1012 -0
  85. package/src/type.ts +81 -0
  86. package/tsconfig.json +24 -0
@@ -0,0 +1,199 @@
1
+ import { Expression, Parser } from 'expr-eval';
2
+
3
+ export type TimeData = {
4
+ start: number; // when fragment starts in timeline (milliseconds)
5
+ end: number; // when fragment ends (milliseconds)
6
+ duration: number; // fragment duration (milliseconds)
7
+ };
8
+
9
+ export type FragmentData = {
10
+ time: TimeData;
11
+ };
12
+
13
+ /**
14
+ * Context available for expression evaluation
15
+ * Contains fragment data with runtime timing information
16
+ */
17
+ export type ExpressionContext = {
18
+ fragments: Map<string, FragmentData>;
19
+ };
20
+
21
+ /**
22
+ * Compiled expression that can be evaluated with runtime context
23
+ */
24
+ export type CompiledExpression = {
25
+ original: string;
26
+ expression: Expression;
27
+ };
28
+
29
+ /**
30
+ * Parses a calc() expression into a compiled expression for later evaluation
31
+ *
32
+ * Supported syntax:
33
+ * - Fragment references: #fragment_id.property.path
34
+ * - Math operations: +, -, *, /, parentheses
35
+ * - Constants: numeric values
36
+ *
37
+ * Examples:
38
+ * - calc(-1 * #ending_screen.time.start)
39
+ * - calc(#intro.time.duration + 1000)
40
+ * - calc((#scene1.time.start + #scene2.time.end) / 2)
41
+ *
42
+ * @param expression - The expression string to parse
43
+ * @returns Compiled expression that can be evaluated later
44
+ */
45
+ export function parseExpression(expression: string): CompiledExpression {
46
+ const parser = new Parser();
47
+
48
+ // Transform expression to replace fragment references with variable names
49
+ // Convert: calc(-1 * #ending_screen.time.start)
50
+ // To: -1 * ending_screen_time_start
51
+ const transformed = transformExpressionToVariables(expression);
52
+
53
+ try {
54
+ // Parse into Expression object
55
+ const expr = parser.parse(transformed);
56
+ return {
57
+ original: expression,
58
+ expression: expr,
59
+ };
60
+ } catch (error) {
61
+ throw new Error(
62
+ `Failed to parse expression "${expression}": ${error instanceof Error ? error.message : String(error)}`,
63
+ );
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Evaluates a compiled expression with runtime context
69
+ *
70
+ * @param compiled - Compiled expression from parseExpression()
71
+ * @param context - Context containing fragment data
72
+ * @returns Evaluated numeric result (in milliseconds)
73
+ */
74
+ export function evaluateCompiledExpression(
75
+ compiled: CompiledExpression,
76
+ context: ExpressionContext,
77
+ ): number {
78
+ // Build evaluation context by resolving all fragment references
79
+ // Convert fragment references to flat variable names
80
+ const evalContext: Record<string, number> = {};
81
+
82
+ // Extract all fragment references from the original expression
83
+ const fragmentRefs = compiled.original.matchAll(
84
+ /#(\w+)\.([\w.]+?)(?=\s|[+\-*/)]|$)/g,
85
+ );
86
+
87
+ for (const match of fragmentRefs) {
88
+ const id = match[1];
89
+ const prop = match[2];
90
+ const varName = `${id}_${prop.replace(/\./g, '_')}`;
91
+
92
+ // Resolve fragment value
93
+ const fragment = context.fragments.get(id);
94
+ if (!fragment) {
95
+ throw new Error(
96
+ `Fragment with id "${id}" not found in expression: ${compiled.original}`,
97
+ );
98
+ }
99
+
100
+ // Navigate property path (e.g., "time.start" -> fragment.time.start)
101
+ const parts = prop.split('.');
102
+ let value: any = fragment;
103
+ for (const part of parts) {
104
+ value = value[part];
105
+ if (value === undefined) {
106
+ throw new Error(
107
+ `Property "${prop}" not found on fragment "${id}" in expression: ${compiled.original}`,
108
+ );
109
+ }
110
+ }
111
+
112
+ evalContext[varName] = value;
113
+ }
114
+
115
+ try {
116
+ // Evaluate with resolved context
117
+ return compiled.expression.evaluate(evalContext);
118
+ } catch (error) {
119
+ throw new Error(
120
+ `Failed to evaluate expression "${compiled.original}": ${error instanceof Error ? error.message : String(error)}`,
121
+ );
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Transforms calc() expression syntax to use variable names instead of fragment references
127
+ * and converts time units to milliseconds
128
+ * @param expression - Original expression
129
+ * @returns Transformed expression
130
+ *
131
+ * Example: calc(url(#ending_screen.time.start) + 5s)
132
+ * -> ending_screen_time_start + 5000
133
+ */
134
+ function transformExpressionToVariables(expression: string): string {
135
+ let transformed = expression
136
+ // Remove calc() wrapper
137
+ .replace(/calc\(/g, '(')
138
+ // Convert fragment references: url(#id.prop.path) -> id_prop_path
139
+ .replace(/url\(#(\w+)\.([\w.]+?)\)/g, (_, id, prop) => {
140
+ return `${id}_${prop.replace(/\./g, '_')}`;
141
+ })
142
+ // Convert time units to milliseconds
143
+ // Match numbers with 's' suffix (seconds): 5s -> 5000
144
+ .replace(/(\d+(?:\.\d+)?)s(?!\w)/g, (_, num) => {
145
+ return String(parseFloat(num) * 1000);
146
+ })
147
+ // Match numbers with 'ms' suffix (milliseconds): 5000ms -> 5000
148
+ .replace(/(\d+(?:\.\d+)?)ms(?!\w)/g, (_, num) => {
149
+ return String(parseFloat(num));
150
+ });
151
+
152
+ return transformed;
153
+ }
154
+
155
+ /**
156
+ * Checks if a string contains a calc() expression
157
+ * @param value - String to check
158
+ * @returns True if value contains calc()
159
+ */
160
+ export function isCalcExpression(value: string): boolean {
161
+ return typeof value === 'string' && value.trim().startsWith('calc(');
162
+ }
163
+
164
+ /**
165
+ * Parses a value into either a number or a compiled expression for later evaluation
166
+ * Use this during HTML parsing to compile expressions once
167
+ * @param value - Value to parse (number or calc expression string)
168
+ * @returns Number or CompiledExpression
169
+ */
170
+ export function parseValueLazy(
171
+ value: number | string,
172
+ ): number | CompiledExpression {
173
+ if (typeof value === 'number') {
174
+ return value;
175
+ }
176
+
177
+ if (isCalcExpression(value)) {
178
+ return parseExpression(value);
179
+ }
180
+
181
+ // Try to parse as plain number
182
+ const parsed = parseFloat(value);
183
+ if (!isNaN(parsed)) {
184
+ return parsed;
185
+ }
186
+
187
+ throw new Error(
188
+ `Invalid value: "${value}". Expected number or calc() expression`,
189
+ );
190
+ }
191
+
192
+ export function calculateFinalValue(
193
+ value: number | CompiledExpression,
194
+ context: ExpressionContext,
195
+ ) {
196
+ return typeof value === 'number'
197
+ ? value
198
+ : evaluateCompiledExpression(value, context);
199
+ }