@nodaro/shared 1.4.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 (665) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +32 -0
  3. package/dist/index.cjs +12506 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +12269 -0
  6. package/dist/index.d.ts +12269 -0
  7. package/dist/index.js +11831 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +54 -0
  10. package/src/__tests__/__snapshots__/prompt-builder-segments.test.ts.snap +65 -0
  11. package/src/__tests__/ai-avatar-pricing.test.ts +321 -0
  12. package/src/__tests__/apply-video-negative-prompt.test.ts +76 -0
  13. package/src/__tests__/attach-columns.test.ts +28 -0
  14. package/src/__tests__/audio-crossfade-curves.test.ts +33 -0
  15. package/src/__tests__/build-model-menu.test.ts +58 -0
  16. package/src/__tests__/character-aspect-defaults.test.ts +142 -0
  17. package/src/__tests__/character-mention-slug.test.ts +199 -0
  18. package/src/__tests__/character-reference-photo-kinds.test.ts +32 -0
  19. package/src/__tests__/character-usage-mode.test.ts +147 -0
  20. package/src/__tests__/character-variant-assets.test.ts +142 -0
  21. package/src/__tests__/character-voice.test.ts +130 -0
  22. package/src/__tests__/cinematic-avatar-pricing.test.ts +119 -0
  23. package/src/__tests__/combine-transitions.test.ts +137 -0
  24. package/src/__tests__/component-types.test.ts +87 -0
  25. package/src/__tests__/condition-variables.test.ts +98 -0
  26. package/src/__tests__/credit-identifiers.test.ts +811 -0
  27. package/src/__tests__/default-video-provider.test.ts +63 -0
  28. package/src/__tests__/entity-image-handle.test.ts +43 -0
  29. package/src/__tests__/entity-variants.test.ts +33 -0
  30. package/src/__tests__/fal-lip-sync-sets.test.ts +31 -0
  31. package/src/__tests__/featured-entities.test.ts +33 -0
  32. package/src/__tests__/film-pricing.test.ts +64 -0
  33. package/src/__tests__/filter-condition.test.ts +285 -0
  34. package/src/__tests__/freecut-protocol.test.ts +35 -0
  35. package/src/__tests__/generate-text-items.test.ts +19 -0
  36. package/src/__tests__/generated-results.test.ts +50 -0
  37. package/src/__tests__/graph-utils.test.ts +618 -0
  38. package/src/__tests__/group-aggregation.test.ts +83 -0
  39. package/src/__tests__/i18n-locale-completeness.test.ts +156 -0
  40. package/src/__tests__/image-critic-node.test.ts +86 -0
  41. package/src/__tests__/image-mask-mode.test.ts +16 -0
  42. package/src/__tests__/image-ref-limit.test.ts +78 -0
  43. package/src/__tests__/inpaint-region.test.ts +24 -0
  44. package/src/__tests__/input-field-map-parity.test.ts +30 -0
  45. package/src/__tests__/json-evaluator.test.ts +289 -0
  46. package/src/__tests__/json-path.test.ts +64 -0
  47. package/src/__tests__/lip-sync-pricing.test.ts +142 -0
  48. package/src/__tests__/list-merge.test.ts +96 -0
  49. package/src/__tests__/list-sort.test.ts +134 -0
  50. package/src/__tests__/llm-models.test.ts +445 -0
  51. package/src/__tests__/location-mention-slug.test.ts +246 -0
  52. package/src/__tests__/locations-coverage-critic-schema.test.ts +92 -0
  53. package/src/__tests__/loop-delimiter.test.ts +39 -0
  54. package/src/__tests__/lottie-slots.test.ts +245 -0
  55. package/src/__tests__/model-catalog-flux2-resolutions.test.ts +21 -0
  56. package/src/__tests__/model-constants-location.test.ts +20 -0
  57. package/src/__tests__/model-constants.test.ts +122 -0
  58. package/src/__tests__/model-tree.test.ts +86 -0
  59. package/src/__tests__/no-internal-imports.test.ts +25 -0
  60. package/src/__tests__/node-default-mappings.test.ts +175 -0
  61. package/src/__tests__/node-mappable-fields.test.ts +7 -0
  62. package/src/__tests__/node-preset-export.test.ts +46 -0
  63. package/src/__tests__/node-preset-extract.test.ts +166 -0
  64. package/src/__tests__/node-refs-canonical.test.ts +54 -0
  65. package/src/__tests__/node-refs-combine.test.ts +54 -0
  66. package/src/__tests__/node-refs.test.ts +187 -0
  67. package/src/__tests__/node-runtime-keys.test.ts +99 -0
  68. package/src/__tests__/object-aspect-defaults.test.ts +59 -0
  69. package/src/__tests__/parameter-node-value.test.ts +137 -0
  70. package/src/__tests__/pinterest-url.test.ts +35 -0
  71. package/src/__tests__/pipeline-chat.test.ts +110 -0
  72. package/src/__tests__/pipeline-validation.test.ts +98 -0
  73. package/src/__tests__/presentation-utils.test.ts +1137 -0
  74. package/src/__tests__/producer-types.test.ts +47 -0
  75. package/src/__tests__/prompt-length-limits.test.ts +156 -0
  76. package/src/__tests__/provider-directive-defaults.test.ts +46 -0
  77. package/src/__tests__/reduce-strategy-registry.test.ts +43 -0
  78. package/src/__tests__/reference-board-templates.test.ts +33 -0
  79. package/src/__tests__/reference-roles.test.ts +36 -0
  80. package/src/__tests__/resolve-field-mappings.test.ts +110 -0
  81. package/src/__tests__/resolve-pipeline-model.test.ts +76 -0
  82. package/src/__tests__/scene-node-types.test.ts +80 -0
  83. package/src/__tests__/scraper-actors.test.ts +67 -0
  84. package/src/__tests__/seedance-2-catalog.test.ts +18 -0
  85. package/src/__tests__/seedance-2-credit-id.test.ts +23 -0
  86. package/src/__tests__/seedance-aspects.test.ts +52 -0
  87. package/src/__tests__/selector.test.ts +1151 -0
  88. package/src/__tests__/settled-with-limit.test.ts +214 -0
  89. package/src/__tests__/social-media-specs.test.ts +129 -0
  90. package/src/__tests__/sub-workflow-validation.test.ts +88 -0
  91. package/src/__tests__/switchx-pricing.test.ts +28 -0
  92. package/src/__tests__/to-connected-references.test.ts +153 -0
  93. package/src/__tests__/utilities.test.ts +541 -0
  94. package/src/__tests__/video-analysis-pricing.test.ts +58 -0
  95. package/src/__tests__/video-analysis.test.ts +63 -0
  96. package/src/__tests__/video-audio-capability.test.ts +204 -0
  97. package/src/__tests__/video-gen-providers.test.ts +28 -0
  98. package/src/__tests__/video-mode-aliases.test.ts +150 -0
  99. package/src/__tests__/video-ref-limits.test.ts +72 -0
  100. package/src/__tests__/video-utils.test.ts +303 -0
  101. package/src/__tests__/voice-changer-models.test.ts +33 -0
  102. package/src/__tests__/workflow-export-strip.test.ts +46 -0
  103. package/src/ai-avatar-pricing.ts +213 -0
  104. package/src/ancestor-refs.ts +48 -0
  105. package/src/animals.ts +231 -0
  106. package/src/audio-crossfade-curves.ts +73 -0
  107. package/src/audio-fx-presets.ts +64 -0
  108. package/src/avatar-payload-validators.ts +214 -0
  109. package/src/caption-styles.ts +31 -0
  110. package/src/character-aspect-defaults.ts +102 -0
  111. package/src/character-facets.ts +37 -0
  112. package/src/character-mention-slug.ts +166 -0
  113. package/src/character-usage-mode.ts +109 -0
  114. package/src/character-variant-assets.ts +121 -0
  115. package/src/character-voice.ts +151 -0
  116. package/src/cinematic-avatar-pricing.ts +111 -0
  117. package/src/clone-utils.ts +46 -0
  118. package/src/combine-transitions.ts +482 -0
  119. package/src/community.ts +112 -0
  120. package/src/component-types.ts +127 -0
  121. package/src/condition-variables.ts +65 -0
  122. package/src/credit-estimators/index.ts +15 -0
  123. package/src/credit-estimators/video-utils.ts +165 -0
  124. package/src/credit-identifiers.ts +304 -0
  125. package/src/entity-approval-types.ts +31 -0
  126. package/src/entity-aspect-defaults.ts +82 -0
  127. package/src/entity-asset-types.ts +296 -0
  128. package/src/entity-image-handle.ts +36 -0
  129. package/src/extra-refs.ts +139 -0
  130. package/src/featured-entities.ts +136 -0
  131. package/src/film-pricing.ts +117 -0
  132. package/src/filter-condition.ts +250 -0
  133. package/src/flux2-pricing.ts +18 -0
  134. package/src/freecut-protocol.ts +52 -0
  135. package/src/furniture.ts +167 -0
  136. package/src/generate-text-items.ts +15 -0
  137. package/src/generated-results.ts +63 -0
  138. package/src/group-aggregation.ts +75 -0
  139. package/src/hint-graph-types.ts +18 -0
  140. package/src/i18n/action-fx.ar.ts +89 -0
  141. package/src/i18n/action-fx.de.ts +89 -0
  142. package/src/i18n/action-fx.es.ts +89 -0
  143. package/src/i18n/action-fx.fr.ts +89 -0
  144. package/src/i18n/action-fx.he.ts +89 -0
  145. package/src/i18n/action-fx.hi.ts +89 -0
  146. package/src/i18n/action-fx.ja.ts +89 -0
  147. package/src/i18n/action-fx.ko.ts +89 -0
  148. package/src/i18n/action-fx.pt-BR.ts +89 -0
  149. package/src/i18n/action-fx.ru.ts +89 -0
  150. package/src/i18n/action-fx.zh-CN.ts +89 -0
  151. package/src/i18n/aesthetic.ar.ts +170 -0
  152. package/src/i18n/aesthetic.de.ts +48 -0
  153. package/src/i18n/aesthetic.es.ts +169 -0
  154. package/src/i18n/aesthetic.fr.ts +52 -0
  155. package/src/i18n/aesthetic.he.ts +169 -0
  156. package/src/i18n/aesthetic.hi.ts +55 -0
  157. package/src/i18n/aesthetic.ja.ts +165 -0
  158. package/src/i18n/aesthetic.ko.ts +169 -0
  159. package/src/i18n/aesthetic.pt-BR.ts +148 -0
  160. package/src/i18n/aesthetic.ru.ts +155 -0
  161. package/src/i18n/aesthetic.zh-CN.ts +172 -0
  162. package/src/i18n/animals.ar.ts +145 -0
  163. package/src/i18n/animals.de.ts +144 -0
  164. package/src/i18n/animals.es.ts +158 -0
  165. package/src/i18n/animals.fr.ts +144 -0
  166. package/src/i18n/animals.he.ts +155 -0
  167. package/src/i18n/animals.hi.ts +157 -0
  168. package/src/i18n/animals.ja.ts +159 -0
  169. package/src/i18n/animals.ko.ts +159 -0
  170. package/src/i18n/animals.pt-BR.ts +157 -0
  171. package/src/i18n/animals.ru.ts +155 -0
  172. package/src/i18n/animals.zh-CN.ts +155 -0
  173. package/src/i18n/atmosphere.ar.ts +49 -0
  174. package/src/i18n/atmosphere.de.ts +47 -0
  175. package/src/i18n/atmosphere.es.ts +50 -0
  176. package/src/i18n/atmosphere.fr.ts +47 -0
  177. package/src/i18n/atmosphere.he.ts +47 -0
  178. package/src/i18n/atmosphere.hi.ts +49 -0
  179. package/src/i18n/atmosphere.ja.ts +49 -0
  180. package/src/i18n/atmosphere.ko.ts +49 -0
  181. package/src/i18n/atmosphere.pt-BR.ts +49 -0
  182. package/src/i18n/atmosphere.ru.ts +47 -0
  183. package/src/i18n/atmosphere.zh-CN.ts +152 -0
  184. package/src/i18n/backdrop.ar.ts +53 -0
  185. package/src/i18n/backdrop.de.ts +46 -0
  186. package/src/i18n/backdrop.es.ts +54 -0
  187. package/src/i18n/backdrop.fr.ts +52 -0
  188. package/src/i18n/backdrop.he.ts +51 -0
  189. package/src/i18n/backdrop.hi.ts +59 -0
  190. package/src/i18n/backdrop.ja.ts +61 -0
  191. package/src/i18n/backdrop.ko.ts +59 -0
  192. package/src/i18n/backdrop.pt-BR.ts +59 -0
  193. package/src/i18n/backdrop.ru.ts +57 -0
  194. package/src/i18n/backdrop.zh-CN.ts +57 -0
  195. package/src/i18n/camera-format.ar.ts +40 -0
  196. package/src/i18n/camera-format.de.ts +37 -0
  197. package/src/i18n/camera-format.es.ts +41 -0
  198. package/src/i18n/camera-format.fr.ts +37 -0
  199. package/src/i18n/camera-format.he.ts +37 -0
  200. package/src/i18n/camera-format.hi.ts +42 -0
  201. package/src/i18n/camera-format.ja.ts +37 -0
  202. package/src/i18n/camera-format.ko.ts +37 -0
  203. package/src/i18n/camera-format.pt-BR.ts +46 -0
  204. package/src/i18n/camera-format.ru.ts +42 -0
  205. package/src/i18n/camera-format.zh-CN.ts +42 -0
  206. package/src/i18n/camera-motions.ar.ts +86 -0
  207. package/src/i18n/camera-motions.de.ts +74 -0
  208. package/src/i18n/camera-motions.es.ts +86 -0
  209. package/src/i18n/camera-motions.fr.ts +86 -0
  210. package/src/i18n/camera-motions.he.ts +86 -0
  211. package/src/i18n/camera-motions.hi.ts +99 -0
  212. package/src/i18n/camera-motions.ja.ts +99 -0
  213. package/src/i18n/camera-motions.ko.ts +99 -0
  214. package/src/i18n/camera-motions.pt-BR.ts +99 -0
  215. package/src/i18n/camera-motions.ru.ts +99 -0
  216. package/src/i18n/camera-motions.zh-CN.ts +99 -0
  217. package/src/i18n/character-fx.ar.ts +72 -0
  218. package/src/i18n/character-fx.de.ts +72 -0
  219. package/src/i18n/character-fx.es.ts +72 -0
  220. package/src/i18n/character-fx.fr.ts +72 -0
  221. package/src/i18n/character-fx.he.ts +72 -0
  222. package/src/i18n/character-fx.hi.ts +72 -0
  223. package/src/i18n/character-fx.ja.ts +72 -0
  224. package/src/i18n/character-fx.ko.ts +72 -0
  225. package/src/i18n/character-fx.pt-BR.ts +72 -0
  226. package/src/i18n/character-fx.ru.ts +72 -0
  227. package/src/i18n/character-fx.zh-CN.ts +72 -0
  228. package/src/i18n/color-look.ar.ts +50 -0
  229. package/src/i18n/color-look.de.ts +47 -0
  230. package/src/i18n/color-look.es.ts +50 -0
  231. package/src/i18n/color-look.fr.ts +50 -0
  232. package/src/i18n/color-look.he.ts +49 -0
  233. package/src/i18n/color-look.hi.ts +52 -0
  234. package/src/i18n/color-look.ja.ts +54 -0
  235. package/src/i18n/color-look.ko.ts +54 -0
  236. package/src/i18n/color-look.pt-BR.ts +54 -0
  237. package/src/i18n/color-look.ru.ts +52 -0
  238. package/src/i18n/color-look.zh-CN.ts +53 -0
  239. package/src/i18n/composition-effects.ar.ts +26 -0
  240. package/src/i18n/composition-effects.de.ts +25 -0
  241. package/src/i18n/composition-effects.es.ts +27 -0
  242. package/src/i18n/composition-effects.fr.ts +25 -0
  243. package/src/i18n/composition-effects.he.ts +25 -0
  244. package/src/i18n/composition-effects.hi.ts +27 -0
  245. package/src/i18n/composition-effects.ja.ts +27 -0
  246. package/src/i18n/composition-effects.ko.ts +27 -0
  247. package/src/i18n/composition-effects.pt-BR.ts +25 -0
  248. package/src/i18n/composition-effects.ru.ts +82 -0
  249. package/src/i18n/composition-effects.zh-CN.ts +25 -0
  250. package/src/i18n/era.ar.ts +37 -0
  251. package/src/i18n/era.de.ts +34 -0
  252. package/src/i18n/era.es.ts +37 -0
  253. package/src/i18n/era.fr.ts +37 -0
  254. package/src/i18n/era.he.ts +36 -0
  255. package/src/i18n/era.hi.ts +39 -0
  256. package/src/i18n/era.ja.ts +41 -0
  257. package/src/i18n/era.ko.ts +39 -0
  258. package/src/i18n/era.pt-BR.ts +41 -0
  259. package/src/i18n/era.ru.ts +121 -0
  260. package/src/i18n/era.zh-CN.ts +39 -0
  261. package/src/i18n/exposure-settings.ar.ts +28 -0
  262. package/src/i18n/exposure-settings.de.ts +26 -0
  263. package/src/i18n/exposure-settings.es.ts +28 -0
  264. package/src/i18n/exposure-settings.fr.ts +29 -0
  265. package/src/i18n/exposure-settings.he.ts +28 -0
  266. package/src/i18n/exposure-settings.hi.ts +31 -0
  267. package/src/i18n/exposure-settings.ja.ts +31 -0
  268. package/src/i18n/exposure-settings.ko.ts +31 -0
  269. package/src/i18n/exposure-settings.pt-BR.ts +31 -0
  270. package/src/i18n/exposure-settings.ru.ts +31 -0
  271. package/src/i18n/exposure-settings.zh-CN.ts +31 -0
  272. package/src/i18n/framing.ar.ts +78 -0
  273. package/src/i18n/framing.de.ts +73 -0
  274. package/src/i18n/framing.es.ts +78 -0
  275. package/src/i18n/framing.fr.ts +78 -0
  276. package/src/i18n/framing.he.ts +77 -0
  277. package/src/i18n/framing.hi.ts +82 -0
  278. package/src/i18n/framing.ja.ts +84 -0
  279. package/src/i18n/framing.ko.ts +82 -0
  280. package/src/i18n/framing.pt-BR.ts +84 -0
  281. package/src/i18n/framing.ru.ts +82 -0
  282. package/src/i18n/framing.zh-CN.ts +82 -0
  283. package/src/i18n/furniture.ar.ts +92 -0
  284. package/src/i18n/furniture.de.ts +93 -0
  285. package/src/i18n/furniture.es.ts +101 -0
  286. package/src/i18n/furniture.fr.ts +93 -0
  287. package/src/i18n/furniture.he.ts +101 -0
  288. package/src/i18n/furniture.hi.ts +101 -0
  289. package/src/i18n/furniture.ja.ts +101 -0
  290. package/src/i18n/furniture.ko.ts +101 -0
  291. package/src/i18n/furniture.pt-BR.ts +101 -0
  292. package/src/i18n/furniture.ru.ts +101 -0
  293. package/src/i18n/furniture.zh-CN.ts +101 -0
  294. package/src/i18n/held-prop.ar.ts +74 -0
  295. package/src/i18n/held-prop.de.ts +65 -0
  296. package/src/i18n/held-prop.es.ts +83 -0
  297. package/src/i18n/held-prop.fr.ts +74 -0
  298. package/src/i18n/held-prop.he.ts +73 -0
  299. package/src/i18n/held-prop.hi.ts +82 -0
  300. package/src/i18n/held-prop.ja.ts +84 -0
  301. package/src/i18n/held-prop.ko.ts +84 -0
  302. package/src/i18n/held-prop.pt-BR.ts +84 -0
  303. package/src/i18n/held-prop.ru.ts +82 -0
  304. package/src/i18n/held-prop.zh-CN.ts +82 -0
  305. package/src/i18n/index.ts +208 -0
  306. package/src/i18n/instrumentation.ar.ts +195 -0
  307. package/src/i18n/instrumentation.de.ts +195 -0
  308. package/src/i18n/instrumentation.es.ts +195 -0
  309. package/src/i18n/instrumentation.fr.ts +195 -0
  310. package/src/i18n/instrumentation.he.ts +195 -0
  311. package/src/i18n/instrumentation.hi.ts +195 -0
  312. package/src/i18n/instrumentation.ja.ts +195 -0
  313. package/src/i18n/instrumentation.ko.ts +195 -0
  314. package/src/i18n/instrumentation.pt-BR.ts +195 -0
  315. package/src/i18n/instrumentation.ru.ts +195 -0
  316. package/src/i18n/instrumentation.zh-CN.ts +195 -0
  317. package/src/i18n/lens.ar.ts +24 -0
  318. package/src/i18n/lens.de.ts +24 -0
  319. package/src/i18n/lens.es.ts +24 -0
  320. package/src/i18n/lens.fr.ts +24 -0
  321. package/src/i18n/lens.he.ts +24 -0
  322. package/src/i18n/lens.hi.ts +24 -0
  323. package/src/i18n/lens.ja.ts +24 -0
  324. package/src/i18n/lens.ko.ts +24 -0
  325. package/src/i18n/lens.pt-BR.ts +24 -0
  326. package/src/i18n/lens.ru.ts +25 -0
  327. package/src/i18n/lens.zh-CN.ts +24 -0
  328. package/src/i18n/lighting.ar.ts +86 -0
  329. package/src/i18n/lighting.de.ts +84 -0
  330. package/src/i18n/lighting.es.ts +89 -0
  331. package/src/i18n/lighting.fr.ts +84 -0
  332. package/src/i18n/lighting.he.ts +88 -0
  333. package/src/i18n/lighting.hi.ts +90 -0
  334. package/src/i18n/lighting.ja.ts +90 -0
  335. package/src/i18n/lighting.ko.ts +90 -0
  336. package/src/i18n/lighting.pt-BR.ts +90 -0
  337. package/src/i18n/lighting.ru.ts +88 -0
  338. package/src/i18n/lighting.zh-CN.ts +92 -0
  339. package/src/i18n/loop-subject.ar.ts +39 -0
  340. package/src/i18n/loop-subject.de.ts +39 -0
  341. package/src/i18n/loop-subject.es.ts +39 -0
  342. package/src/i18n/loop-subject.fr.ts +39 -0
  343. package/src/i18n/loop-subject.he.ts +39 -0
  344. package/src/i18n/loop-subject.hi.ts +39 -0
  345. package/src/i18n/loop-subject.ja.ts +39 -0
  346. package/src/i18n/loop-subject.ko.ts +39 -0
  347. package/src/i18n/loop-subject.pt-BR.ts +39 -0
  348. package/src/i18n/loop-subject.ru.ts +39 -0
  349. package/src/i18n/loop-subject.zh-CN.ts +39 -0
  350. package/src/i18n/materials.ar.ts +80 -0
  351. package/src/i18n/materials.de.ts +80 -0
  352. package/src/i18n/materials.es.ts +87 -0
  353. package/src/i18n/materials.fr.ts +80 -0
  354. package/src/i18n/materials.he.ts +86 -0
  355. package/src/i18n/materials.hi.ts +86 -0
  356. package/src/i18n/materials.ja.ts +88 -0
  357. package/src/i18n/materials.ko.ts +88 -0
  358. package/src/i18n/materials.pt-BR.ts +88 -0
  359. package/src/i18n/materials.ru.ts +86 -0
  360. package/src/i18n/materials.zh-CN.ts +86 -0
  361. package/src/i18n/mood.ar.ts +61 -0
  362. package/src/i18n/mood.de.ts +61 -0
  363. package/src/i18n/mood.es.ts +66 -0
  364. package/src/i18n/mood.fr.ts +61 -0
  365. package/src/i18n/mood.he.ts +64 -0
  366. package/src/i18n/mood.hi.ts +66 -0
  367. package/src/i18n/mood.ja.ts +66 -0
  368. package/src/i18n/mood.ko.ts +66 -0
  369. package/src/i18n/mood.pt-BR.ts +64 -0
  370. package/src/i18n/mood.ru.ts +64 -0
  371. package/src/i18n/mood.zh-CN.ts +64 -0
  372. package/src/i18n/music-genre.ar.ts +302 -0
  373. package/src/i18n/music-genre.de.ts +302 -0
  374. package/src/i18n/music-genre.es.ts +302 -0
  375. package/src/i18n/music-genre.fr.ts +302 -0
  376. package/src/i18n/music-genre.he.ts +302 -0
  377. package/src/i18n/music-genre.hi.ts +302 -0
  378. package/src/i18n/music-genre.ja.ts +302 -0
  379. package/src/i18n/music-genre.ko.ts +302 -0
  380. package/src/i18n/music-genre.pt-BR.ts +302 -0
  381. package/src/i18n/music-genre.ru.ts +302 -0
  382. package/src/i18n/music-genre.zh-CN.ts +302 -0
  383. package/src/i18n/music-mood.ar.ts +75 -0
  384. package/src/i18n/music-mood.de.ts +75 -0
  385. package/src/i18n/music-mood.es.ts +75 -0
  386. package/src/i18n/music-mood.fr.ts +75 -0
  387. package/src/i18n/music-mood.he.ts +75 -0
  388. package/src/i18n/music-mood.hi.ts +75 -0
  389. package/src/i18n/music-mood.ja.ts +75 -0
  390. package/src/i18n/music-mood.ko.ts +75 -0
  391. package/src/i18n/music-mood.pt-BR.ts +75 -0
  392. package/src/i18n/music-mood.ru.ts +75 -0
  393. package/src/i18n/music-mood.zh-CN.ts +75 -0
  394. package/src/i18n/person.ar.ts +638 -0
  395. package/src/i18n/person.de.ts +629 -0
  396. package/src/i18n/person.es.ts +645 -0
  397. package/src/i18n/person.fr.ts +621 -0
  398. package/src/i18n/person.he.ts +656 -0
  399. package/src/i18n/person.hi.ts +654 -0
  400. package/src/i18n/person.ja.ts +662 -0
  401. package/src/i18n/person.ko.ts +662 -0
  402. package/src/i18n/person.pt-BR.ts +656 -0
  403. package/src/i18n/person.ru.ts +656 -0
  404. package/src/i18n/person.zh-CN.ts +656 -0
  405. package/src/i18n/photo-genre.ar.ts +58 -0
  406. package/src/i18n/photo-genre.de.ts +52 -0
  407. package/src/i18n/photo-genre.es.ts +64 -0
  408. package/src/i18n/photo-genre.fr.ts +58 -0
  409. package/src/i18n/photo-genre.he.ts +62 -0
  410. package/src/i18n/photo-genre.hi.ts +63 -0
  411. package/src/i18n/photo-genre.ja.ts +65 -0
  412. package/src/i18n/photo-genre.ko.ts +63 -0
  413. package/src/i18n/photo-genre.pt-BR.ts +65 -0
  414. package/src/i18n/photo-genre.ru.ts +63 -0
  415. package/src/i18n/photo-genre.zh-CN.ts +63 -0
  416. package/src/i18n/photographer.ar.ts +75 -0
  417. package/src/i18n/photographer.de.ts +74 -0
  418. package/src/i18n/photographer.es.ts +77 -0
  419. package/src/i18n/photographer.fr.ts +77 -0
  420. package/src/i18n/photographer.he.ts +78 -0
  421. package/src/i18n/photographer.hi.ts +80 -0
  422. package/src/i18n/photographer.ja.ts +84 -0
  423. package/src/i18n/photographer.ko.ts +84 -0
  424. package/src/i18n/photographer.pt-BR.ts +83 -0
  425. package/src/i18n/photographer.ru.ts +78 -0
  426. package/src/i18n/photographer.zh-CN.ts +78 -0
  427. package/src/i18n/pose.ar.ts +95 -0
  428. package/src/i18n/pose.de.ts +96 -0
  429. package/src/i18n/pose.es.ts +104 -0
  430. package/src/i18n/pose.fr.ts +96 -0
  431. package/src/i18n/pose.he.ts +104 -0
  432. package/src/i18n/pose.hi.ts +104 -0
  433. package/src/i18n/pose.ja.ts +104 -0
  434. package/src/i18n/pose.ko.ts +104 -0
  435. package/src/i18n/pose.pt-BR.ts +104 -0
  436. package/src/i18n/pose.ru.ts +104 -0
  437. package/src/i18n/pose.zh-CN.ts +104 -0
  438. package/src/i18n/post-process-effects.ar.ts +25 -0
  439. package/src/i18n/post-process-effects.de.ts +24 -0
  440. package/src/i18n/post-process-effects.es.ts +26 -0
  441. package/src/i18n/post-process-effects.fr.ts +24 -0
  442. package/src/i18n/post-process-effects.he.ts +24 -0
  443. package/src/i18n/post-process-effects.hi.ts +26 -0
  444. package/src/i18n/post-process-effects.ja.ts +26 -0
  445. package/src/i18n/post-process-effects.ko.ts +26 -0
  446. package/src/i18n/post-process-effects.pt-BR.ts +24 -0
  447. package/src/i18n/post-process-effects.ru.ts +24 -0
  448. package/src/i18n/post-process-effects.zh-CN.ts +24 -0
  449. package/src/i18n/render-quality.ar.ts +34 -0
  450. package/src/i18n/render-quality.de.ts +30 -0
  451. package/src/i18n/render-quality.es.ts +35 -0
  452. package/src/i18n/render-quality.fr.ts +34 -0
  453. package/src/i18n/render-quality.he.ts +33 -0
  454. package/src/i18n/render-quality.hi.ts +39 -0
  455. package/src/i18n/render-quality.ja.ts +39 -0
  456. package/src/i18n/render-quality.ko.ts +39 -0
  457. package/src/i18n/render-quality.pt-BR.ts +37 -0
  458. package/src/i18n/render-quality.ru.ts +37 -0
  459. package/src/i18n/render-quality.zh-CN.ts +37 -0
  460. package/src/i18n/seasons.ar.ts +10 -0
  461. package/src/i18n/seasons.de.ts +10 -0
  462. package/src/i18n/seasons.es.ts +10 -0
  463. package/src/i18n/seasons.fr.ts +10 -0
  464. package/src/i18n/seasons.he.ts +10 -0
  465. package/src/i18n/seasons.hi.ts +10 -0
  466. package/src/i18n/seasons.ja.ts +10 -0
  467. package/src/i18n/seasons.ko.ts +10 -0
  468. package/src/i18n/seasons.pt-BR.ts +10 -0
  469. package/src/i18n/seasons.ru.ts +10 -0
  470. package/src/i18n/seasons.zh-CN.ts +10 -0
  471. package/src/i18n/setting.ar.ts +73 -0
  472. package/src/i18n/setting.de.ts +73 -0
  473. package/src/i18n/setting.es.ts +77 -0
  474. package/src/i18n/setting.fr.ts +73 -0
  475. package/src/i18n/setting.he.ts +76 -0
  476. package/src/i18n/setting.hi.ts +76 -0
  477. package/src/i18n/setting.ja.ts +78 -0
  478. package/src/i18n/setting.ko.ts +76 -0
  479. package/src/i18n/setting.pt-BR.ts +78 -0
  480. package/src/i18n/setting.ru.ts +76 -0
  481. package/src/i18n/setting.zh-CN.ts +76 -0
  482. package/src/i18n/style.ar.ts +55 -0
  483. package/src/i18n/style.de.ts +54 -0
  484. package/src/i18n/style.es.ts +54 -0
  485. package/src/i18n/style.fr.ts +54 -0
  486. package/src/i18n/style.he.ts +54 -0
  487. package/src/i18n/style.hi.ts +54 -0
  488. package/src/i18n/style.ja.ts +54 -0
  489. package/src/i18n/style.ko.ts +54 -0
  490. package/src/i18n/style.pt-BR.ts +56 -0
  491. package/src/i18n/style.ru.ts +54 -0
  492. package/src/i18n/style.zh-CN.ts +54 -0
  493. package/src/i18n/styling.ar.ts +295 -0
  494. package/src/i18n/styling.de.ts +285 -0
  495. package/src/i18n/styling.es.ts +317 -0
  496. package/src/i18n/styling.fr.ts +285 -0
  497. package/src/i18n/styling.he.ts +307 -0
  498. package/src/i18n/styling.hi.ts +323 -0
  499. package/src/i18n/styling.ja.ts +317 -0
  500. package/src/i18n/styling.ko.ts +311 -0
  501. package/src/i18n/styling.pt-BR.ts +301 -0
  502. package/src/i18n/styling.ru.ts +301 -0
  503. package/src/i18n/styling.zh-CN.ts +307 -0
  504. package/src/i18n/temporal.ar.ts +31 -0
  505. package/src/i18n/temporal.de.ts +24 -0
  506. package/src/i18n/temporal.es.ts +27 -0
  507. package/src/i18n/temporal.fr.ts +28 -0
  508. package/src/i18n/temporal.he.ts +31 -0
  509. package/src/i18n/temporal.hi.ts +31 -0
  510. package/src/i18n/temporal.ja.ts +31 -0
  511. package/src/i18n/temporal.ko.ts +31 -0
  512. package/src/i18n/temporal.pt-BR.ts +31 -0
  513. package/src/i18n/temporal.ru.ts +31 -0
  514. package/src/i18n/temporal.zh-CN.ts +31 -0
  515. package/src/i18n/transitions.ar.ts +97 -0
  516. package/src/i18n/transitions.de.ts +97 -0
  517. package/src/i18n/transitions.es.ts +97 -0
  518. package/src/i18n/transitions.fr.ts +97 -0
  519. package/src/i18n/transitions.he.ts +97 -0
  520. package/src/i18n/transitions.hi.ts +97 -0
  521. package/src/i18n/transitions.ja.ts +97 -0
  522. package/src/i18n/transitions.ko.ts +97 -0
  523. package/src/i18n/transitions.pt-BR.ts +97 -0
  524. package/src/i18n/transitions.ru.ts +97 -0
  525. package/src/i18n/transitions.zh-CN.ts +97 -0
  526. package/src/i18n/types.ts +158 -0
  527. package/src/i18n/vehicles.ar.ts +137 -0
  528. package/src/i18n/vehicles.de.ts +125 -0
  529. package/src/i18n/vehicles.es.ts +138 -0
  530. package/src/i18n/vehicles.fr.ts +125 -0
  531. package/src/i18n/vehicles.he.ts +136 -0
  532. package/src/i18n/vehicles.hi.ts +138 -0
  533. package/src/i18n/vehicles.ja.ts +138 -0
  534. package/src/i18n/vehicles.ko.ts +138 -0
  535. package/src/i18n/vehicles.pt-BR.ts +136 -0
  536. package/src/i18n/vehicles.ru.ts +136 -0
  537. package/src/i18n/vehicles.zh-CN.ts +136 -0
  538. package/src/i18n/voice-character.ar.ts +126 -0
  539. package/src/i18n/voice-character.de.ts +126 -0
  540. package/src/i18n/voice-character.es.ts +126 -0
  541. package/src/i18n/voice-character.fr.ts +126 -0
  542. package/src/i18n/voice-character.he.ts +126 -0
  543. package/src/i18n/voice-character.hi.ts +126 -0
  544. package/src/i18n/voice-character.ja.ts +126 -0
  545. package/src/i18n/voice-character.ko.ts +126 -0
  546. package/src/i18n/voice-character.pt-BR.ts +126 -0
  547. package/src/i18n/voice-character.ru.ts +126 -0
  548. package/src/i18n/voice-character.zh-CN.ts +126 -0
  549. package/src/i18n/voice-delivery.ar.ts +77 -0
  550. package/src/i18n/voice-delivery.de.ts +77 -0
  551. package/src/i18n/voice-delivery.es.ts +77 -0
  552. package/src/i18n/voice-delivery.fr.ts +77 -0
  553. package/src/i18n/voice-delivery.he.ts +77 -0
  554. package/src/i18n/voice-delivery.hi.ts +77 -0
  555. package/src/i18n/voice-delivery.ja.ts +77 -0
  556. package/src/i18n/voice-delivery.ko.ts +77 -0
  557. package/src/i18n/voice-delivery.pt-BR.ts +77 -0
  558. package/src/i18n/voice-delivery.ru.ts +77 -0
  559. package/src/i18n/voice-delivery.zh-CN.ts +77 -0
  560. package/src/i18n/weapons.ar.ts +115 -0
  561. package/src/i18n/weapons.de.ts +114 -0
  562. package/src/i18n/weapons.es.ts +116 -0
  563. package/src/i18n/weapons.fr.ts +103 -0
  564. package/src/i18n/weapons.he.ts +114 -0
  565. package/src/i18n/weapons.hi.ts +116 -0
  566. package/src/i18n/weapons.ja.ts +116 -0
  567. package/src/i18n/weapons.ko.ts +116 -0
  568. package/src/i18n/weapons.pt-BR.ts +114 -0
  569. package/src/i18n/weapons.ru.ts +114 -0
  570. package/src/i18n/weapons.zh-CN.ts +114 -0
  571. package/src/image-critic-node.ts +61 -0
  572. package/src/image-critic-types.ts +40 -0
  573. package/src/index.ts +866 -0
  574. package/src/inject-upstream.ts +15 -0
  575. package/src/inpaint-region.ts +51 -0
  576. package/src/json-evaluator.ts +732 -0
  577. package/src/json-path.ts +52 -0
  578. package/src/lip-sync-pricing.ts +90 -0
  579. package/src/list-merge.ts +40 -0
  580. package/src/list-sort.ts +122 -0
  581. package/src/list-source-resolver.ts +50 -0
  582. package/src/llm-models.ts +245 -0
  583. package/src/location-mention-slug.ts +291 -0
  584. package/src/location-preset-catalog-map.ts +128 -0
  585. package/src/loop-delimiter.ts +73 -0
  586. package/src/lora-routing.ts +95 -0
  587. package/src/lottie-overlay-catalog.ts +175 -0
  588. package/src/lottie-slots.ts +309 -0
  589. package/src/model-catalog.ts +2386 -0
  590. package/src/model-constants.ts +1910 -0
  591. package/src/model-tree.ts +120 -0
  592. package/src/monetization.ts +15 -0
  593. package/src/multi-pick.ts +42 -0
  594. package/src/node-default-mappings.ts +262 -0
  595. package/src/node-mappable-fields.ts +70 -0
  596. package/src/node-preset-export.ts +56 -0
  597. package/src/node-preset-extract.ts +147 -0
  598. package/src/node-refs.ts +253 -0
  599. package/src/node-runtime-keys.ts +117 -0
  600. package/src/object-aspect-defaults.ts +72 -0
  601. package/src/object-picker-types.ts +22 -0
  602. package/src/parameter-node-value.ts +284 -0
  603. package/src/pinterest-url.ts +28 -0
  604. package/src/pipeline-chat.ts +72 -0
  605. package/src/pipeline-defaults.ts +318 -0
  606. package/src/pipeline-events.ts +162 -0
  607. package/src/pipeline-state-types.ts +196 -0
  608. package/src/pipeline-types.ts +647 -0
  609. package/src/pipeline-validation.ts +87 -0
  610. package/src/presentation-types.ts +23 -0
  611. package/src/presentation-utils.ts +397 -0
  612. package/src/producer-types.ts +188 -0
  613. package/src/progress-curve.ts +99 -0
  614. package/src/provider-directive-defaults.ts +69 -0
  615. package/src/reduce-strategy-registry.ts +121 -0
  616. package/src/reference-board-templates.ts +81 -0
  617. package/src/reference-roles.ts +153 -0
  618. package/src/reference-sheet/__tests__/board-to-column.test.ts +20 -0
  619. package/src/reference-sheet/__tests__/catalog.test.ts +50 -0
  620. package/src/reference-sheet/__tests__/cost.test.ts +38 -0
  621. package/src/reference-sheet/__tests__/no-drift.test.ts +28 -0
  622. package/src/reference-sheet/__tests__/panel-plan.test.ts +61 -0
  623. package/src/reference-sheet/__tests__/panel-prompts.test.ts +17 -0
  624. package/src/reference-sheet/__tests__/plan-generation.test.ts +72 -0
  625. package/src/reference-sheet/__tests__/presets.test.ts +54 -0
  626. package/src/reference-sheet/__tests__/types.test.ts +24 -0
  627. package/src/reference-sheet/catalog.ts +144 -0
  628. package/src/reference-sheet/cost.ts +37 -0
  629. package/src/reference-sheet/credit-id.ts +7 -0
  630. package/src/reference-sheet/index.ts +8 -0
  631. package/src/reference-sheet/panel-plan.ts +65 -0
  632. package/src/reference-sheet/panel-prompts.ts +14 -0
  633. package/src/reference-sheet/plan-generation.ts +79 -0
  634. package/src/reference-sheet/presets.ts +77 -0
  635. package/src/reference-sheet/types.ts +92 -0
  636. package/src/repeat-types.ts +97 -0
  637. package/src/resolve-field-mappings.ts +119 -0
  638. package/src/route-filter.ts +80 -0
  639. package/src/scene-helper-types.ts +249 -0
  640. package/src/scene-node-types.ts +281 -0
  641. package/src/scraper-actors.ts +57 -0
  642. package/src/scraper-output-schemas.ts +25 -0
  643. package/src/seasons.ts +45 -0
  644. package/src/selector.ts +864 -0
  645. package/src/settled-with-limit.ts +42 -0
  646. package/src/shot-element.ts +43 -0
  647. package/src/social-media-specs.ts +121 -0
  648. package/src/social-post.ts +24 -0
  649. package/src/sub-workflow-validation.ts +78 -0
  650. package/src/supported-fonts.ts +40 -0
  651. package/src/surround.ts +113 -0
  652. package/src/switchx-pricing.ts +33 -0
  653. package/src/text-separators.ts +59 -0
  654. package/src/to-connected-references.ts +77 -0
  655. package/src/types.ts +272 -0
  656. package/src/variant-job-id.ts +17 -0
  657. package/src/vehicles.ts +213 -0
  658. package/src/video-analysis-pricing.ts +74 -0
  659. package/src/video-analysis.ts +127 -0
  660. package/src/video-duration.ts +25 -0
  661. package/src/voice-changer-models.ts +36 -0
  662. package/src/voice-matcher-types.ts +37 -0
  663. package/src/voices.ts +92 -0
  664. package/src/weapons.ts +190 -0
  665. package/src/workflow-export.ts +153 -0
@@ -0,0 +1,732 @@
1
+ // --- Types ---
2
+
3
+ export type FilterOperator =
4
+ | "equals" | "not_equals"
5
+ | "contains" | "not_contains"
6
+ | "starts_with" | "ends_with"
7
+ | "greater_than" | "less_than"
8
+ | "is_empty" | "is_not_empty"
9
+ | "matches_regex"
10
+ | "in_list"
11
+
12
+ export interface JsonFilter {
13
+ id: string
14
+ field: string
15
+ operator: FilterOperator
16
+ value: string | string[]
17
+ }
18
+
19
+ export type JsonEvalResult =
20
+ | { ok: true; value: unknown }
21
+ | { ok: false; error: string }
22
+
23
+ // --- Helpers ---
24
+
25
+ const BARE_IDENT = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/
26
+
27
+ function escapeString(v: string): string {
28
+ return v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
29
+ }
30
+
31
+ function fieldRef(field: string): string {
32
+ return BARE_IDENT.test(field) ? `.${field}` : `.["${escapeString(field)}"]`
33
+ }
34
+
35
+ function coerceValue(v: string): string {
36
+ const trimmed = v.trim()
37
+ if (trimmed === "" || trimmed === "Infinity" || trimmed === "-Infinity" || trimmed === "NaN") return `"${trimmed}"`
38
+ const n = Number(trimmed)
39
+ return Number.isFinite(n) ? String(n) : `"${escapeString(trimmed)}"`
40
+ }
41
+
42
+ function buildFilterExpr(f: JsonFilter): string {
43
+ const ref = fieldRef(f.field)
44
+ switch (f.operator) {
45
+ case "equals": return `select(${ref} == ${coerceValue(f.value as string)})`
46
+ case "not_equals": return `select(${ref} != ${coerceValue(f.value as string)})`
47
+ case "contains": return `select(${ref} | contains("${escapeString(f.value as string)}"))`
48
+ case "not_contains": return `select(${ref} | contains("${escapeString(f.value as string)}") | not)`
49
+ case "starts_with": return `select(${ref} | startswith("${escapeString(f.value as string)}"))`
50
+ case "ends_with": return `select(${ref} | endswith("${escapeString(f.value as string)}"))`
51
+ case "greater_than": {
52
+ const n = Number((f.value as string).trim())
53
+ if (!Number.isFinite(n)) return `select(${ref} > 0)`
54
+ return `select(${ref} > ${n})`
55
+ }
56
+ case "less_than": {
57
+ const n = Number((f.value as string).trim())
58
+ if (!Number.isFinite(n)) return `select(${ref} < 0)`
59
+ return `select(${ref} < ${n})`
60
+ }
61
+ case "is_empty": return `select(${ref} == null or ${ref} == "")`
62
+ case "is_not_empty": return `select(${ref} != null and ${ref} != "")`
63
+ case "matches_regex": return `select(${ref} | test("${escapeString(f.value as string)}"))`
64
+ case "in_list": {
65
+ // Tolerate string form: users can switch operator to "in_list" while the
66
+ // previous operator's string value is still in place. Comma-split so the
67
+ // config panel's "a, b, c" shape works before it's persisted as an array.
68
+ const raw = Array.isArray(f.value)
69
+ ? f.value
70
+ : String(f.value ?? "").split(",").map((s) => s.trim()).filter(Boolean)
71
+ if (raw.length === 0) return `select(false)`
72
+ const items = raw.map((v) => `${ref} == ${coerceValue(v)}`)
73
+ return `select(${items.join(" or ")})`
74
+ }
75
+ default: return `select(true)`
76
+ }
77
+ }
78
+
79
+ // --- Public API ---
80
+
81
+ export function buildExpressionFromVisual(config: {
82
+ inputPath?: string
83
+ filters?: JsonFilter[]
84
+ projections?: string[]
85
+ }): string {
86
+ const { inputPath, filters = [], projections = [] } = config
87
+ const hasFilters = filters.length > 0
88
+ const hasProjections = projections.length > 0
89
+ const hasPath = !!inputPath && inputPath.trim().length > 0
90
+
91
+ // Stage 1: path
92
+ let path = hasPath ? `.${inputPath}` : "."
93
+
94
+ // Append [] if filters or projections exist
95
+ if (hasFilters || hasProjections) {
96
+ path += "[]"
97
+ }
98
+
99
+ // If nothing configured, return identity
100
+ if (!hasPath && !hasFilters && !hasProjections) return "."
101
+
102
+ const parts: string[] = [path]
103
+
104
+ // Stage 2: filters (AND via separate select pipes)
105
+ for (const f of filters) {
106
+ parts.push(buildFilterExpr(f))
107
+ }
108
+
109
+ // Stage 3: projections
110
+ if (hasProjections) {
111
+ const fields = projections.map((p) => {
112
+ if (BARE_IDENT.test(p)) return p
113
+ return `"${p}": .["${p}"]`
114
+ })
115
+ parts.push(`{${fields.join(", ")}}`)
116
+ }
117
+
118
+ return parts.join(" | ")
119
+ }
120
+
121
+ // --- Tokenizer ---
122
+
123
+ type TokType =
124
+ | "DOT" | "PIPE" | "LBRACE" | "RBRACE" | "LBRACKET" | "RBRACKET"
125
+ | "LPAREN" | "RPAREN" | "COMMA" | "COLON"
126
+ | "EMPTY_ITER" // []
127
+ | "INDEX" // [N] or [-N]
128
+ | "BRACKET_KEY" // ["str"]
129
+ | "IDENT" // bare identifier or keyword
130
+ | "STRING" // "..."
131
+ | "NUMBER" // 42 / 3.14
132
+ | "OP" // == != > < >= <=
133
+
134
+ interface Token { type: TokType; value: string | number }
135
+
136
+ function tokenize(expr: string): Token[] {
137
+ const tokens: Token[] = []
138
+ let i = 0
139
+
140
+ while (i < expr.length) {
141
+ // whitespace
142
+ if (/\s/.test(expr[i])) { i++; continue }
143
+
144
+ const ch = expr[i]
145
+
146
+ // single-char structural
147
+ if (ch === ".") { tokens.push({ type: "DOT", value: "." }); i++; continue }
148
+ if (ch === "|") { tokens.push({ type: "PIPE", value: "|" }); i++; continue }
149
+ if (ch === "{") { tokens.push({ type: "LBRACE", value: "{" }); i++; continue }
150
+ if (ch === "}") { tokens.push({ type: "RBRACE", value: "}" }); i++; continue }
151
+ if (ch === "(") { tokens.push({ type: "LPAREN", value: "(" }); i++; continue }
152
+ if (ch === ")") { tokens.push({ type: "RPAREN", value: ")" }); i++; continue }
153
+ if (ch === ",") { tokens.push({ type: "COMMA", value: "," }); i++; continue }
154
+ if (ch === ":") { tokens.push({ type: "COLON", value: ":" }); i++; continue }
155
+
156
+ // bracket forms: [], [N], [-N], ["str"]
157
+ if (ch === "[") {
158
+ const rest = expr.slice(i)
159
+ // ["str"]
160
+ const bkStr = rest.match(/^\["((?:[^"\\]|\\.)*)"\]/)
161
+ if (bkStr) {
162
+ const unescaped = bkStr[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\").replace(/\\n/g, "\n").replace(/\\t/g, "\t")
163
+ tokens.push({ type: "BRACKET_KEY", value: unescaped })
164
+ i += bkStr[0].length; continue
165
+ }
166
+ // []
167
+ const bkEmpty = rest.match(/^\[\]/)
168
+ if (bkEmpty) {
169
+ tokens.push({ type: "EMPTY_ITER", value: "[]" })
170
+ i += 2; continue
171
+ }
172
+ // [-N] or [N]
173
+ const bkIdx = rest.match(/^\[-?(\d+)\]/)
174
+ if (bkIdx) {
175
+ const raw = rest.match(/^\[(-?\d+)\]/)!
176
+ tokens.push({ type: "INDEX", value: parseInt(raw[1], 10) })
177
+ i += raw[0].length; continue
178
+ }
179
+ // standalone [ (for parser completeness — treated as error later)
180
+ tokens.push({ type: "LBRACKET", value: "[" }); i++; continue
181
+ }
182
+
183
+ // two-char operators
184
+ if (i + 1 < expr.length) {
185
+ const two = expr.slice(i, i + 2)
186
+ if (two === "==" || two === "!=" || two === ">=" || two === "<=") {
187
+ tokens.push({ type: "OP", value: two }); i += 2; continue
188
+ }
189
+ }
190
+ if (ch === ">" || ch === "<") {
191
+ tokens.push({ type: "OP", value: ch }); i++; continue
192
+ }
193
+
194
+ // string literal
195
+ if (ch === '"') {
196
+ let s = ""
197
+ i++ // skip opening "
198
+ while (i < expr.length && expr[i] !== '"') {
199
+ if (expr[i] === "\\") {
200
+ i++
201
+ const esc = expr[i]
202
+ if (esc === '"') s += '"'
203
+ else if (esc === "\\") s += "\\"
204
+ else if (esc === "n") s += "\n"
205
+ else if (esc === "t") s += "\t"
206
+ else s += esc
207
+ } else {
208
+ s += expr[i]
209
+ }
210
+ i++
211
+ }
212
+ if (expr[i] !== '"') throw new Error("Unterminated string literal")
213
+ i++ // skip closing "
214
+ tokens.push({ type: "STRING", value: s }); continue
215
+ }
216
+
217
+ // number
218
+ if (/[0-9]/.test(ch) || (ch === "-" && /[0-9]/.test(expr[i + 1] ?? ""))) {
219
+ const m = expr.slice(i).match(/^-?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/)
220
+ if (m) {
221
+ const n = Number(m[0])
222
+ if (!Number.isFinite(n)) throw new Error(`Invalid number: ${m[0]}`)
223
+ tokens.push({ type: "NUMBER", value: n })
224
+ i += m[0].length; continue
225
+ }
226
+ }
227
+
228
+ // identifier / keyword
229
+ const idm = expr.slice(i).match(/^[a-zA-Z_$][a-zA-Z0-9_$]*/)
230
+ if (idm) {
231
+ tokens.push({ type: "IDENT", value: idm[0] })
232
+ i += idm[0].length; continue
233
+ }
234
+
235
+ throw new Error(`Unexpected character '${ch}' at position ${i}`)
236
+ }
237
+
238
+ return tokens
239
+ }
240
+
241
+ // --- AST Node Types ---
242
+
243
+ type AstNode =
244
+ | { k: "identity" }
245
+ | { k: "dot"; field: string }
246
+ | { k: "bracket"; key: string }
247
+ | { k: "iterate" }
248
+ | { k: "index"; index: number }
249
+ | { k: "pipe"; left: AstNode; right: AstNode }
250
+ | { k: "select"; cond: AstNode }
251
+ | { k: "object"; fields: Array<{ key: string; valueExpr: AstNode | null }> }
252
+ | { k: "compare"; op: string; left: AstNode; right: AstNode }
253
+ | { k: "bool"; op: "and" | "or"; left: AstNode; right: AstNode }
254
+ | { k: "not" }
255
+ | { k: "func"; name: string; arg: string }
256
+ | { k: "literal"; value: string | number }
257
+ | { k: "path"; steps: AstNode[] } // chained dot/bracket/iterate/index
258
+
259
+ // --- Parser ---
260
+
261
+ class Parser {
262
+ private pos = 0
263
+ constructor(private tokens: Token[]) {}
264
+
265
+ private peek(): Token | undefined { return this.tokens[this.pos] }
266
+ private eat(): Token {
267
+ const t = this.tokens[this.pos++]
268
+ if (!t) throw new Error("Unexpected end of expression")
269
+ return t
270
+ }
271
+ private expect(type: TokType): Token {
272
+ const t = this.eat()
273
+ if (t.type !== type) throw new Error(`Expected ${type}, got ${t.type} ('${t.value}')`)
274
+ return t
275
+ }
276
+ private at(type: TokType): boolean { return this.peek()?.type === type }
277
+ private atIdent(v: string): boolean { return this.peek()?.type === "IDENT" && this.peek()?.value === v }
278
+ private done(): boolean { return this.pos >= this.tokens.length }
279
+
280
+ parse(): AstNode {
281
+ const node = this.parsePipe()
282
+ if (!this.done()) throw new Error(`Unexpected token '${this.peek()!.value}' at position ${this.pos}`)
283
+ return node
284
+ }
285
+
286
+ private parsePipe(): AstNode {
287
+ let left = this.parseBoolExpr()
288
+ while (this.at("PIPE")) {
289
+ this.eat() // consume |
290
+ const right = this.parseBoolExpr()
291
+ left = { k: "pipe", left, right }
292
+ }
293
+ return left
294
+ }
295
+
296
+ private parseBoolExpr(): AstNode {
297
+ let left = this.parseCompare()
298
+ while (this.atIdent("and") || this.atIdent("or")) {
299
+ const op = this.eat().value as "and" | "or"
300
+ const right = this.parseCompare()
301
+ left = { k: "bool", op, left, right }
302
+ }
303
+ return left
304
+ }
305
+
306
+ private parseCompare(): AstNode {
307
+ const left = this.parseAtom()
308
+ if (this.at("OP")) {
309
+ const op = this.eat().value as string
310
+ const right = this.parseAtom()
311
+ return { k: "compare", op, left, right }
312
+ }
313
+ return left
314
+ }
315
+
316
+ // parseAtom handles all leaf-level filter constructs
317
+ private parseAtom(): AstNode {
318
+ // select(...)
319
+ if (this.atIdent("select")) {
320
+ this.eat()
321
+ this.expect("LPAREN")
322
+ // Allow full pipe expressions inside select (e.g., select(.name | contains("x")))
323
+ const cond = this.parsePipe()
324
+ this.expect("RPAREN")
325
+ return { k: "select", cond }
326
+ }
327
+ // not (postfix — standalone in pipe context)
328
+ if (this.atIdent("not")) {
329
+ this.eat()
330
+ return { k: "not" }
331
+ }
332
+ // object construction
333
+ if (this.at("LBRACE")) {
334
+ return this.parseObjectCtor()
335
+ }
336
+ // string function calls (contains, startswith, endswith, test) with arg
337
+ if (this.at("IDENT")) {
338
+ const name = this.peek()!.value as string
339
+ if (["contains", "startswith", "endswith", "test"].includes(name)) {
340
+ // look ahead for (
341
+ if (this.tokens[this.pos + 1]?.type === "LPAREN") {
342
+ this.eat() // name
343
+ this.eat() // (
344
+ const argTok = this.eat()
345
+ if (argTok.type !== "STRING") throw new Error(`${name}() argument must be a string`)
346
+ this.expect("RPAREN")
347
+ return { k: "func", name, arg: argTok.value as string }
348
+ }
349
+ }
350
+ }
351
+ // parenthesised expression
352
+ if (this.at("LPAREN")) {
353
+ this.eat()
354
+ const inner = this.parseBoolExpr()
355
+ this.expect("RPAREN")
356
+ return inner
357
+ }
358
+ // literals and paths
359
+ if (this.at("STRING")) {
360
+ return { k: "literal", value: this.eat().value as string }
361
+ }
362
+ if (this.at("NUMBER")) {
363
+ return { k: "literal", value: this.eat().value as number }
364
+ }
365
+ return this.parsePath()
366
+ }
367
+
368
+ private parsePath(): AstNode {
369
+ if (!this.at("DOT")) throw new Error(`Expected path starting with '.', got '${this.peek()?.value ?? "EOF"}'`)
370
+ this.eat() // consume .
371
+
372
+ // bare "." — identity
373
+ const steps: AstNode[] = []
374
+
375
+ // after dot, there may be an identifier or a bracket form
376
+ if (this.at("IDENT") && !["select","not","contains","startswith","endswith","test","and","or","null","true","false"].includes(this.peek()!.value as string)) {
377
+ steps.push({ k: "dot", field: this.eat().value as string })
378
+ } else if (this.at("BRACKET_KEY")) {
379
+ steps.push({ k: "bracket", key: this.eat().value as string })
380
+ } else if (this.at("EMPTY_ITER")) {
381
+ this.eat()
382
+ steps.push({ k: "iterate" })
383
+ } else if (this.at("INDEX")) {
384
+ steps.push({ k: "index", index: this.eat().value as number })
385
+ } else {
386
+ // just "."
387
+ if (steps.length === 0) return { k: "identity" }
388
+ }
389
+
390
+ // chain more accesses: .foo.bar, .foo[0], .foo[]
391
+ while (true) {
392
+ if (this.at("DOT")) {
393
+ this.eat()
394
+ if (this.at("IDENT") && !["select","not","contains","startswith","endswith","test","and","or"].includes(this.peek()!.value as string)) {
395
+ steps.push({ k: "dot", field: this.eat().value as string })
396
+ } else if (this.at("BRACKET_KEY")) {
397
+ steps.push({ k: "bracket", key: this.eat().value as string })
398
+ } else if (this.at("EMPTY_ITER")) {
399
+ this.eat(); steps.push({ k: "iterate" })
400
+ } else if (this.at("INDEX")) {
401
+ steps.push({ k: "index", index: this.eat().value as number })
402
+ } else {
403
+ // trailing dot — treat as identity at end (shouldn't normally happen)
404
+ break
405
+ }
406
+ } else if (this.at("BRACKET_KEY")) {
407
+ steps.push({ k: "bracket", key: this.eat().value as string })
408
+ } else if (this.at("EMPTY_ITER")) {
409
+ this.eat(); steps.push({ k: "iterate" })
410
+ } else if (this.at("INDEX")) {
411
+ steps.push({ k: "index", index: this.eat().value as number })
412
+ } else {
413
+ break
414
+ }
415
+ }
416
+
417
+ if (steps.length === 0) return { k: "identity" }
418
+ if (steps.length === 1) return steps[0]
419
+ return { k: "path", steps }
420
+ }
421
+
422
+ private parseObjectCtor(): AstNode {
423
+ this.eat() // {
424
+ const fields: Array<{ key: string; valueExpr: AstNode | null }> = []
425
+
426
+ while (!this.at("RBRACE") && !this.done()) {
427
+ let key: string
428
+ let valueExpr: AstNode | null = null
429
+
430
+ if (this.at("IDENT")) {
431
+ key = this.eat().value as string
432
+ if (this.at("COLON")) {
433
+ this.eat() // :
434
+ valueExpr = this.parsePipe()
435
+ }
436
+ // else shorthand: {name} => {name: .name}
437
+ } else if (this.at("STRING")) {
438
+ key = this.eat().value as string
439
+ this.expect("COLON")
440
+ valueExpr = this.parsePipe()
441
+ } else {
442
+ throw new Error(`Expected field name in object constructor, got '${this.peek()?.value}'`)
443
+ }
444
+
445
+ fields.push({ key, valueExpr })
446
+ if (this.at("COMMA")) this.eat()
447
+ }
448
+
449
+ this.expect("RBRACE")
450
+ return { k: "object", fields }
451
+ }
452
+ }
453
+
454
+ // --- Evaluator ---
455
+
456
+ // Sentinel to represent "this item was dropped by select"
457
+ const DROPPED = Symbol("DROPPED")
458
+ // Sentinel to track that we're in iterate mode (stream of items)
459
+ type EvalValue = unknown | typeof DROPPED
460
+
461
+ function isTruthy(v: unknown): boolean {
462
+ if (v === null || v === undefined || v === false || v === 0 || v === "") return false
463
+ return true
464
+ }
465
+
466
+ // --- Per-call evaluation context ---
467
+
468
+ interface EvalCtx {
469
+ expandedArrays: WeakSet<object>
470
+ objectSourcedArrays: WeakSet<object>
471
+ regexCache: Map<string, RegExp>
472
+ }
473
+
474
+ function evalNode(node: AstNode, input: unknown, ctx: EvalCtx): EvalValue | EvalValue[] {
475
+ switch (node.k) {
476
+ case "identity":
477
+ return input
478
+
479
+ case "dot": {
480
+ if (input === null || input === undefined) return null
481
+ if (typeof input !== "object" || Array.isArray(input)) {
482
+ throw new Error(`Cannot access field '.${node.field}' on ${Array.isArray(input) ? "array" : typeof input}`)
483
+ }
484
+ const obj = input as Record<string, unknown>
485
+ if (!(node.field in obj)) {
486
+ const available = Object.keys(obj).join(", ")
487
+ throw new Error(`Field '${node.field}' not found. Available fields: ${available || "(none)"}`)
488
+ }
489
+ return obj[node.field]
490
+ }
491
+
492
+ case "bracket": {
493
+ if (input === null || input === undefined) return null
494
+ if (typeof input !== "object" || Array.isArray(input)) {
495
+ throw new Error(`Cannot bracket-access on ${Array.isArray(input) ? "array" : typeof input}`)
496
+ }
497
+ const obj = input as Record<string, unknown>
498
+ if (!(node.key in obj)) {
499
+ const available = Object.keys(obj).join(", ")
500
+ throw new Error(`Field '${node.key}' not found. Available fields: ${available || "(none)"}`)
501
+ }
502
+ return obj[node.key]
503
+ }
504
+
505
+ case "index": {
506
+ if (!Array.isArray(input)) throw new Error(`Cannot index non-array with .[${node.index}]`)
507
+ const idx = node.index < 0 ? input.length + node.index : node.index
508
+ return idx >= 0 && idx < input.length ? input[idx] : null
509
+ }
510
+
511
+ case "iterate": {
512
+ if (Array.isArray(input)) {
513
+ return input // return as array — caller handles fan-out
514
+ }
515
+ if (typeof input === "object" && input !== null) {
516
+ // treat object as single-item sequence per spec
517
+ const arr = [input]
518
+ ctx.objectSourcedArrays.add(arr)
519
+ return arr
520
+ }
521
+ throw new Error(`Cannot iterate over ${typeof input}`)
522
+ }
523
+
524
+ case "path": {
525
+ let cur: unknown = input
526
+ for (let i = 0; i < node.steps.length; i++) {
527
+ const step = node.steps[i]
528
+ const res = evalNode(step, cur, ctx)
529
+ // if a step returns an array (from iterate), fan out remaining steps
530
+ if (step.k === "iterate" && Array.isArray(res)) {
531
+ const wasObjSourced = ctx.objectSourcedArrays.has(res as object)
532
+ // fan out remaining steps over each element
533
+ const remaining = node.steps.slice(i + 1)
534
+ if (remaining.length === 0) return res
535
+ const fanned: unknown[] = []
536
+ for (const item of res) {
537
+ const subNode: AstNode = remaining.length === 1 ? remaining[0] : { k: "path", steps: remaining }
538
+ const subRes = evalNode(subNode, item, ctx)
539
+ if (Array.isArray(subRes)) fanned.push(...subRes)
540
+ else if (subRes !== DROPPED) fanned.push(subRes)
541
+ }
542
+ return markExpanded(fanned, wasObjSourced, ctx)
543
+ }
544
+ cur = res
545
+ }
546
+ return cur
547
+ }
548
+
549
+ case "pipe": {
550
+ // Evaluate left side; if it produces an array (from iterate), fan-out over right side
551
+ const leftVal = evalNode(node.left, input, ctx)
552
+
553
+ // Check if left side was an iterate that produced array expansion
554
+ const leftIsExpanded = isExpandedArray(node.left, leftVal, ctx)
555
+
556
+ if (leftIsExpanded && Array.isArray(leftVal)) {
557
+ const wasObjectSourced = ctx.objectSourcedArrays.has(leftVal as object)
558
+ const results: unknown[] = []
559
+ for (const item of leftVal) {
560
+ const r = evalNode(node.right, item, ctx)
561
+ if (r === DROPPED) continue
562
+ if (Array.isArray(r) && isExpandedArray(node.right, r, ctx)) {
563
+ results.push(...r)
564
+ } else if (r !== DROPPED) {
565
+ results.push(r)
566
+ }
567
+ }
568
+ // mark as expanded, preserving object-sourced flag
569
+ return markExpanded(results, wasObjectSourced, ctx)
570
+ }
571
+
572
+ if (leftVal === DROPPED) return DROPPED
573
+
574
+ // scalar left — apply right once
575
+ return evalNode(node.right, leftVal, ctx)
576
+ }
577
+
578
+ case "select": {
579
+ const condVal = evalNode(node.cond, input, ctx)
580
+ // If condition is a pipe that produced an expanded array (e.g., select(.name | contains("x"))),
581
+ // the truthiness is based on the final scalar result (the pipe's output).
582
+ // An expanded array here means the condition pipeline returned array results — use last item.
583
+ if (Array.isArray(condVal) && ctx.expandedArrays.has(condVal)) {
584
+ const last = condVal[condVal.length - 1]
585
+ return isTruthy(last) ? input : DROPPED
586
+ }
587
+ return isTruthy(condVal as unknown) ? input : DROPPED
588
+ }
589
+
590
+ case "not": {
591
+ return !isTruthy(input)
592
+ }
593
+
594
+ case "object": {
595
+ const result: Record<string, unknown> = {}
596
+ for (const { key, valueExpr } of node.fields) {
597
+ let fieldVal: unknown
598
+ if (valueExpr === null) {
599
+ // shorthand: {name} => .name
600
+ fieldVal = evalNode({ k: "dot", field: key }, input, ctx)
601
+ } else {
602
+ fieldVal = evalNode(valueExpr, input, ctx)
603
+ }
604
+ if (fieldVal === DROPPED) return DROPPED
605
+ result[key] = fieldVal
606
+ }
607
+ return result
608
+ }
609
+
610
+ case "compare": {
611
+ const lv = evalNode(node.left, input, ctx) as unknown
612
+ const rv = evalNode(node.right, input, ctx) as unknown
613
+ switch (node.op) {
614
+ case "==": return lv === rv
615
+ case "!=": return lv !== rv
616
+ case ">": return typeof lv === "number" && typeof rv === "number" ? lv > rv : false
617
+ case "<": return typeof lv === "number" && typeof rv === "number" ? lv < rv : false
618
+ case ">=": return typeof lv === "number" && typeof rv === "number" ? lv >= rv : false
619
+ case "<=": return typeof lv === "number" && typeof rv === "number" ? lv <= rv : false
620
+ default: return false
621
+ }
622
+ }
623
+
624
+ case "bool": {
625
+ const lv = evalNode(node.left, input, ctx)
626
+ if (node.op === "and") {
627
+ if (!isTruthy(lv as unknown)) return false
628
+ return isTruthy(evalNode(node.right, input, ctx) as unknown)
629
+ } else {
630
+ if (isTruthy(lv as unknown)) return true
631
+ return isTruthy(evalNode(node.right, input, ctx) as unknown)
632
+ }
633
+ }
634
+
635
+ case "func": {
636
+ if (typeof input !== "string") throw new Error(`${node.name}() requires a string input`)
637
+ switch (node.name) {
638
+ case "contains": return input.includes(node.arg)
639
+ case "startswith": return input.startsWith(node.arg)
640
+ case "endswith": return input.endsWith(node.arg)
641
+ case "test": {
642
+ let re = ctx.regexCache.get(node.arg)
643
+ if (!re) {
644
+ if (/(\([^)]*[+*][^)]*\))[+*]/.test(node.arg)) {
645
+ throw new Error("Regex pattern too complex — avoid nested quantifiers")
646
+ }
647
+ re = new RegExp(node.arg)
648
+ ctx.regexCache.set(node.arg, re)
649
+ }
650
+ return re.test(input.slice(0, 100000))
651
+ }
652
+ default: throw new Error(`Unknown function: ${node.name}`)
653
+ }
654
+ }
655
+
656
+ case "literal":
657
+ return node.value
658
+
659
+ default: {
660
+ const _exhaustive: never = node
661
+ throw new Error(`Unknown AST node`)
662
+ }
663
+ }
664
+ }
665
+
666
+ // --- Expanded array tracking ---
667
+ // expandedArrays: arrays produced by iterate fan-out (pipe needs to fan-out over them)
668
+ // objectSourcedArrays: expanded arrays whose origin was object iteration (unwrap at output)
669
+
670
+ function markExpanded(arr: unknown[], objectSourced: boolean, ctx: EvalCtx): unknown[] {
671
+ ctx.expandedArrays.add(arr)
672
+ if (objectSourced) ctx.objectSourcedArrays.add(arr)
673
+ return arr
674
+ }
675
+
676
+ function isExpandedArray(node: AstNode, val: unknown, ctx: EvalCtx): boolean {
677
+ if (!Array.isArray(val)) return false
678
+ // If left side is an iterate node directly, it's always expanded
679
+ if (node.k === "iterate") return true
680
+ // If left side is a path ending in iterate, check the last step
681
+ if (node.k === "path") {
682
+ const last = node.steps[node.steps.length - 1]
683
+ if (last?.k === "iterate") return true
684
+ }
685
+ // If left side is a pipe that produced an expanded array
686
+ if (node.k === "pipe") return ctx.expandedArrays.has(val as object)
687
+ // Check WeakSet
688
+ return ctx.expandedArrays.has(val as object)
689
+ }
690
+
691
+ // --- Public API ---
692
+
693
+ export function jsonResultToList(value: unknown): string[] {
694
+ if (Array.isArray(value)) {
695
+ return value.map((v) => typeof v === "string" ? v : JSON.stringify(v))
696
+ }
697
+ if (value !== null && value !== undefined) {
698
+ return [typeof value === "string" ? value : JSON.stringify(value)]
699
+ }
700
+ return []
701
+ }
702
+
703
+ export function evaluateJsonExpression(input: unknown, expression: string): JsonEvalResult {
704
+ try {
705
+ const tokens = tokenize(expression)
706
+ const ast = new Parser(tokens).parse()
707
+ const ctx: EvalCtx = {
708
+ expandedArrays: new WeakSet(),
709
+ objectSourcedArrays: new WeakSet(),
710
+ regexCache: new Map(),
711
+ }
712
+ const raw = evalNode(ast, input, ctx)
713
+
714
+ // If result is an expanded array (from iterate fan-out):
715
+ if (Array.isArray(raw) && isExpandedArray(ast, raw, ctx)) {
716
+ // Object-sourced: spec says treat as single-element sequence — unwrap (0 items → null, 1 → item)
717
+ // Array-sourced: always return as array (jq model)
718
+ const isObjSourced = ctx.objectSourcedArrays.has(raw as object)
719
+ if (isObjSourced) {
720
+ if (raw.length === 0) return { ok: true, value: null }
721
+ if (raw.length === 1) return { ok: true, value: raw[0] }
722
+ }
723
+ if (raw.length === 0) return { ok: true, value: [] }
724
+ return { ok: true, value: raw }
725
+ }
726
+ // Non-expanded: return as-is
727
+ return { ok: true, value: raw === DROPPED ? [] : raw }
728
+ } catch (err) {
729
+ const msg = err instanceof Error ? err.message : String(err)
730
+ return { ok: false, error: msg }
731
+ }
732
+ }